I use execvp to compile a program with error. But then error message pop on my terminal screen which should not happen because if execvp fails, it will only let child return with exit status. I do not understand why my terminal will actually show the error message?
My command array: {gcc, studentcode.c, ourtest3.c, -o, ourtest3.x, NULL} and in ourtest3.c, I made several errors on purpose. My calling function is like this:
commands = {"gcc", "studentcode.c", "ourtest3.c", "-o", "ourtest3.x", NULL};
int compile_program(Char** commands) {
pid_t pid;
int status;
pid = safe_fork();
if (pid == 0) { /*Child*/
if (execvp(commands[0], commands) < 0) {
exit(0);
}
} else { /*Parent*/
if (wait(&status) == -1) {
return 0;
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
return 1;
}
} else {
return 0;
}
}
return 1;
}
ourtest3.c is this:
#include <stdio.h>
#include <assert.h>
#include "studentcode.h"
int main(void) {
assert(product(2, 16) == 32
printf("The student code in public07.studentcode.c works on its ");
printf("third test!\n");
return 0;
}
My program should have ended normally with return value 0, but instead, on my terminal window, it shows that
ourtest3.c: In function 'main':
ourtest3.c:19:0: error: unterminated argument list invoking macro "assert"
ourtest3.c:13:3: error: 'assert' undeclared (first use in this function)
ourtest3.c:13:3: note: each undeclared identifier is reported only once for each function it appears in
ourtest3.c:13:3: error: expected ';' at end of input
ourtest3.c:13:3: error: expected declaration or statement at end of input
If you want to change the stdin, stout, and stderr of a process, you need to do that. Otherwise, it just inherits them from its parent. After fork
and before execvp
, you probably want to open
/dev/null
and dup
it onto file descriptors 0 and 1.
Here's some ugly code with no error checking:
if (pid == 0) { /*Child*/
/* Redirect stdin and stderr to /dev/null */
int fd = open ("/dev/null", O_RDONLY);
dup2(STDIN_FILENO, fd);
dup2(STDERR_FILENO, fd);
close(fd);
if (execvp(commands[0], commands) < 0) {
_exit(0);
}
You can also redirect them to files or pipes if you want the parent to have access to the child's output.
Note the call to _exit
. Do not get in the habit of calling exit
from failing children. That has caused bugs with serious security implications in the past. Imagine if your process has something it's going to do when it exit
s (such as flush a buffer to a terminal or network connection). By calling exit
in the child, you do that thing twice. You might think that you know that you have no such thing, but you can't possibly know that (in general) because you have no idea what your libraries might be doing internally.