So I have a c program called "hello.c" that does nothing but "exit(2)" at the end. And I tried to run it in my child process, and then pass the return value into my parent process and print the appropriate messages. But somehow the program always exit at 0 and print the "exit at 0" message. Can someone tell me why?
pid_t pid;
int status;
pid = fork();
if (pid == -1){
perror("fork");
exit(1);
}
if (pid >0){
/*abusive parents*/
waitpid(pid, &status, 0);
if(WEXITSTATUS(status)==3){
printf("exit at 3\n");
}
if(WEXITSTATUS(status)==2){
printf("exit at 2\n");
}
if(!(WEXITSTATUS(status))){
printf("exit at 0\n");
}
}
else{
/*stupid child*/
execlp("hello.c",NULL);
}
return 0;}
Here is the hello.c:
int main(void){
int teemo=0;
exit(2);
}
You cannot run a C source file, you need to compile (and link) it to generate an executable file, and run this file. Therefore, you should do something like
Compiling hello.c first (I suppose you are using gcc)
gcc -o hello hello.c
Runing hello in your first program like this
execlp("./hello", "hello", NULL);
Then you should get what you expected.
(Not only) to better understand what is happeing in your code, add error checking.
In your specific case add it at least to the call to execlp(). To do so first have a look at exec*()s documentation:
RETURN VALUE
The exec() functions only return if an error has have occurred. The return value is -1, and errno is set to indicate the error.
And then enhance your code to cover this case:
...
}
else /* child */
{
if (-1 == execlp("hello.c"))
{
perror("execlp() failed");
return 1;
}
}
return 0;
}
You will observer an error message regarding the call to execlp().
This dues to hello.c most probably not being an executable, but an ordinary text file, C-source.
Looking at the documentation closer one reads:
The list of
arguments must be terminated by a null pointer, and, since these are
variadic functions, this pointer must be cast (char *) NULL.
From this we learn that a call to the execl*() members of the exec*() family of functions shall always end like this:
execlp(..., (char *) NULL)
Just to add why its returning zero always in this case
This is because when execlp was failing and returning -1, parent process was using return value at the end of the main function i.e. 0 in this case. If you change this to 2 or 3 you will see program hitting that code with if check ==3 or ==2.
Related
Why when i execute this code inside a function in c
int Pandoc(char *file)
{
//printf("Pandoc is trying to convert the file...\n");
// Forking
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("Fork Error");
}
// child process because return value zero
else if (pid == 0)
{
//printf("Hello from Child!\n");
// Pandoc will run here.
//calling pandoc
// argv array for: ls -l
// Just like in main, the argv array must be NULL terminated.
// try to run ./a.out -x -y, it will work
char *output = replaceWord(file, ".md", ".html");
//checking if the file exists
char *ls_args[] = {"pandoc", file, "-o", output, NULL};
// ^
// use the name ls
// rather than the
// path to /bin/ls
// Little explaination
// The primary difference between execv and execvp is that with execv you have to provide the full path to the binary file (i.e., the program).
// With execvp, you do not need to specify the full path because execvp will search the local environment variable PATH for the executable.
if(file_exist(output)){execvp(ls_args[0], ls_args);}
else
{
//Error Handeler
fprintf(stdout, "pandoc should failed with exit 42\n");
exit(42);
printf( "hello\n");
}
}
return 0;
}
I get 0 as a returned value?
EDIT:
Edit:
So here i changed the return value of the main to 5.
The exit value for my function above to 42 (idk why tho)
It gives me 5 as an output.. no idea whats hapening.
I shouldve mentionned that i use fork() in my code.. Maybe its the reason.
I think that my exit shut off the child process but the main continiues.. so thats why its giving me the returned value inside of my main and not the exit one.
Your child process exits with an exotic value, but your main process always exits with 0, and that's what determines $?.
If you want $? to be the exit value of the child process, you'll have to wait() for it, retrieve the child's exit code, and then exit your main process with it.
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 exits (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.
I'm having a problem with fork running in a function I'm using to create a terminal for a school project.
This function is called to handle the user input when they type in a command:
void handleExternalCommands(char ** arr)
{
pid_t pid;
pid = fork();
printf("pid is ", (long) pid);
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
int status = execvp(arr[0], arr);
printf("im in the child process");
if (status == -1)
{
// error handle
}
}
wait();
}
However, no matter what I type in, I can't actually make it inside of the if statement. If I try to find out what's going on with pid by using:
printf(pid);
I get a segmentation fault error?
Thanks for your help in advance, everyone.
UPDATE:
I've changed the code to what it is above. Printing the pid only happens once and it prints nothing: "pid is "
If the execvp() works, the printf() is never executed. You'd only see the message from printf() if (a) you added a newline to the end and (b) the execvp() failed. (OK: you might see it eventually even without a newline, but the newline is a good idea.)
Move the printf() to before the execvp() and (definitely) add the newline and you should see the information. See also printf() anomaly after fork(), but note you are running into a different consequence of not terminating printf() output with newlines.
As to printf(pid) crashing, you need to read the manual on printf()
and add compiler options so you get told about erroneous use.
You probably need:
printf("PID %d\n", pid);
That assumes that pid_t is sufficiently compatible with int not to run into trouble — a moderately safe assumption, but one which can be avoided by writing:
printf("PID %d\n", (int)pid);
(or use int pid; as the definition). But the key point is that you need to use printf() correctly, and execvp() does not return unless it fails.
I'm trying to use fork() and exec() to run another program that resides in the same directery. The compiler is not complaining, but the program I am trying to call using execl() is not being run. Any tips? Thank you!
pid = fork();
if (pid == -1) {
fprintf (stderr, "Error\n");
exit(1);
}
else if (pid > 0) {
wait(&status);
}
else {
execl("./expo.c", "./expo", x, n, (char*) NULL);
_exit(EXIT_FAILURE);
}
I have tried a few different versions of exec() as well and none have worked.
EDIT:
I have changed to execl("expo","expo",&x,&n,(char*)NULL); , though I am still unsure why this works based on the man pages. The man page says the first argument should be a path, not just the executable. Also, why do I not need ./ for the second argument if I would need that to run that executable in the terminal?
I have got everything working correctly, here is what I changed. Instead of casting the arguments (x and n) into ints then passing them to the child, I passed them as chars and then casted them as ints in the child process.
if(pid==-1){
fprintf (stderr, "Error\n");
exit(1);
}
else if(pid>0){
wait(&status);
}
else{
const char *x=argv[1];
const char *n=argv[2];
execl("expo","expo",x,n,(char*)NULL);
perror("execl() failure!\n");
exit(EXIT_FAILURE);
}
I have this code;
pid_t process;
process = fork();
if (process < 0){
//fork error
perror("fork");
exit(EXIT_FAILURE);
}
if (process == 0){
//i try here the execl
execl ("process.c", "process" , n, NULL);
}
else {
wait(NULL);
}
I don't know if this use of fork() and exec() combined is correct. When I try to run the program from the bash I do not receive any result, so I thought it could be a problem in this part of code.
Thanks.
One problem is that
if (process = 0){
should read
if (process == 0){
Otherwise you're assigning zero to process and only calling execl if result is non-zero (i.e. never).
Also, you're trying to exec something called process.c. There's no doubt that one could have an executable called process.c. However, conventionally names ending in .c are given to C source code files. If process.c is indeed a C file, you need to compile and link it first.
Once you've built the executable, you need to either place it somewhere on $PATH or specify its full path to execle(). In many Unix environments placing it in the current directory won't be enough.
Finally, it's unclear what n is in the execle() call, but the name hints at a numeric variable. You need to make sure that it's a string and not, for example, an integer.
Well as per the answers and comments above your code should look somewhat like this
pid_t process;
process = vfork(); //if your sole aim lies in creating a child that will ultimately call exec family functions then its advisable to use vfork
if (process < 0)
{
//fork error
perror("fork");
exit(EXIT_FAILURE);
}
if (process == 0)
{
//i try here the execl
char N[MAX_DIGITS];//A correction here
itoa(n,N);//write this function yourself
execl ("process", "process" , N, NULL);// Here process is the name of the executable N is your original argument
fprintf(stderr,"execl failed\n");//check for error in execl
}
else
{
wait(NULL);
}
Notice the use of vfork instead of fork.Its because it would be much more efficient.The reason could be found here