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.
Related
I am creating a simple Linux command shell in C. I am having trouble understanding where my code is having problems. "commands" is a list of strings of Linux commands that I want to be executed concurrently as the children processes of one parent. When all are done executing, I want the parent to exit the function. However, when I call exit(0), the for loop continues and parses the current command again, causing the args to be executed again in execvp. Am I using fork() and wait() correctly here? I have tried using waitpid() as well with no luck.
void executeShell(char** commands){
char **arr = commands;
char *c;
pid_t pid, wpid;
int status = 0;
for (c = *arr; c; c=*++arr){
// printf("%d-\n", strcmp(command, "exit"));
if (strcmp(c, "exit") == 0){
EXIT = 1;
return;
}
printf("Running command \'%s\'...\n", c);
char** args = parseStringToTokenArray(c, " ");
free(args);
/* fork and execute the command */
pid = fork();
if(pid < 0){
perror("fork() error\n");
return;
}
/* child process executes command */
else if (pid == 0){
/* 'cd' is not a part of /bin library so handle it manually */
if (strcmp(args[0], "cd") == 0){
changeDirectory(args[1]);
}
else if (strcmp(args[0], "sdir") == 0){
searchDirectory(args[1]);
}else{
/* parse commands with arguments */
execvp(args[0], args);//execute the command
}
exit(0);// <-----command is finished, so why no exit?
}
}
/* wait for children to complete */
while((wpid = wait(&status)) > 0);
}
If execvp succeeds, the entire child process address space is replaced by the program invoked by execvp(). This means that the exit(0) will only ever be invoked following your two special cases i.e. cd and sdir. As far as your code is concerned execvp() should never return, unless there is an error.
A further problem is that you free args immediately after allocating it and then go on to use it in your child processes. This is undefined behaviour.
The only problem I see with your wait code is that, if any of the children block waiting for user input, the parent will block waiting for the child to exit.
The cd code, has no effect on any process except the child in which it is executed. The parent's current directory is not affected. As you state in the comments, this can bet fixed by handling cd in the parent without forking.
I have to develop my own C function system. To do that, I use the call-system fork to create a child process and it has to execute the command given to system, calling exec.
What I've wrote seems to work fine (it compiles and executes without any error).
The problem concerns my function system's return (called mySystem in my code). For example, in my child process, if I give an nonexistent shell to exec (the latter returns -1), my child process stops with an exit code of -1 because I told it to do that. But : my parent process, which retrieves this exit code thanks to a wait(&status), returns... 255 and not -1 !
I don't understand why. I paid attention to use the macro WEXISTATUS in my mySystem's return.
Could you help me to know why my parent process doesn't return -1 (the exit code of its child process) please ? Thank you in advance.
My src (there are a lot of comments) :
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
pid_t pid;
int mySystem(char*);
int main(int argc, char* argv[]) {
int result = mySystem("ls");
fprintf(stdout, "%i", result);
return 0;
}
int mySystem(char* command) {
pid = fork();
if(pid == -1) {
perror("Fork");
return -1; // An error occurred => return -1
} else if (pid == 0) { // The child process will do the following
execl("BLABLABLABLA MAUVAIS SHELL BLABLABLAA", "sh", "-c", command, NULL); // If this call doesn't fail, the following lines are not read
perror("Exec"); // If (and only if) execl couldn't be called (bad shell's path, etc.)...
exit(-1); // ..., we stop the child process and this one has an exit code equaled to -1
}
/*
* NOW, the child process ended because... :
* 1. Either because of our "exit(-1)" after the "perror" (our source-code)
* 2. OR because of an "exit(-1") of the command passed into the execl (source-code of the execl's command)
* 3. OR because of the "exit(0)" of the command passed into the execl (source-code of the execl's command)
*/
// The parent process will execute the following lines (child process ended)
int status = -1;
if(wait(&status) == -1) { // We store into the var 'status' the exit code of the child process : -1 or 0
perror("Wait"); // Note that because we have only one process child, we don't need to do : while(wait(&status) > 0) {;;}
return -1;
}
return WEXITSTATUS(status); // Our function mySystem returns this exit code
}
Look at the following picture:
Where each of the 2 blocks is 8 bits (so total 16 bits).
Now you pass exit(-1) which in binary using 8 bits is: 11111111 (the two-complement) that's why you get 255 using WEXITSTATUS(status).
Another example to be clear: let's suppose to call exit(-6), -6 in binary two-complement is 11111010 that correspond to 250, if you make your program run you will see 250 printed on stdout.
I am attempting to use fork/execvp to execute another program from within my C program. It is working, however before ls outputs the contents of my directory I am getting several hundred lines of:
ls: cannot access : No such file or directory
Followed by the correct listing of the files in the directory. I am passing to execvp:
char **argv = {"ls", "/home/school/"};
char *command = "ls";
For some reason when I use the path "/home/school" it cannot find the directory. Does anyone know why that is happening and why ls is saying it cannot access?
PID = fork();
i = 0;
if(i == numArgs) { doneFlag = 1; }
if (PID == 0){//child process
execvp(command, argv);//needs error checking
}
else if(PID > 0){
wait(PID, 0, 0);//wait for child process to finish execution
}
else if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
The execv and execvp functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program.
The first argument should point to the file name associated with the file being executed.
The array of pointers must be terminated by a NULL pointer. Append a 0 or NULL at the end of argv*.
The char** argument passed in execvp() must be terminated by NULL.
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.
I am a little confused about how to handle errors from execvp(). My code so far looks like this:
int pid = fork();
if (pid < 0) {
// handle error.
}
else if (pid == 0) {
int status = execvp(myCommand,myArgumentVector); // status should be -1 because execvp
// only returns when an error occurs
// We only reach this point as a result of failure from execvp
exit(/* What goes here? */);
}
else {
int status;
int waitedForPid = waitpid(pid,&status,0);
//...
}
There are three cases I'm trying to address:
myCommand,myArgumentVector are valid and the command executes correctly.
myCommand,myArgumentVector are valid parameters, but something goes wrong in the execution of myCommand.
myCommand,myArgumentVector are invalid parameters (e.g. myCommand cannot be found) and the execvp() call fails.
My primary concern is that the parent process will have all the information it needs in order to handle the child's error correctly, and I'm not entirely sure how to do that.
In the first case, the program presumably ended with an exit status of 0. This means that if I were to call WIFEXITED(status) in the macro, I should get true. I think this should work fine.
In the second case, the program presumably ended with an exit status other than 0. This means that if I were to call WEXITSTATUS(status) I should get the specific exit status of the child invocation of myCommand (please advise if this is incorrect).
The third case is causing me a lot of confusion. So if execvp() fails then the error is stored in the global variable errno. But this global variable is only accessible from the child process; the parent as an entirely separate process I don't think can see it. Does this mean that I should be calling exit(errno)? Or am I supposed to be doing something else here? Also, if I call exit(errno) how can I get the value of errno back from status in the parent?
My grasp is still a little tenuous so what I'm looking for is either confirmation or correction in my understanding of how to handle these three cases.
Here is a simple code that I've tried.
if(fork() == 0){
//do child stuff here
execvp(cmd,arguments); /*since you want to return errno to parent
do a simple exit call with the errno*/
exit(errno);
}
else{
//parent stuff
int status;
wait(&status); /*you made a exit call in child you
need to wait on exit status of child*/
if(WIFEXITED(status))
printf("child exited with = %d\n",WEXITSTATUS(status));
//you should see the errno here
}
In case 1, the execvp() does not return. The status returned to the parent process will be the exit status of the child — what it supplies to exit() or what it returns from main(), or it may be that the child dies from a signal in which case the exit status is different but detectably so (WIFSIGNALED, etc). Note that this means that the status need not be zero.
It isn't entirely clear (to me) what you are thinking of with case 2. If the command starts but rejects the options it is called with, it is actually case 1, but the chances of the exit status being zero should be small (though it has been known for programs to exit with status 0 on error). Alternatively, the command can't be found, or is found but is not executable, in which case execvp() returns and you have case 3.
In case 3, the execvp() call fails. You know that because it returns; a successful execvp() never returns. There is no point in testing the return value of execvp(); the mere fact that it returns means it failed. You can tell why it failed from the setting of errno. POSIX uses the exit statuses of 126 and 127 — see xargs and system() for example. You can look at the error codes from execvp() to determine when you should return either of those or some other non-zero value.
In the third case, errno IS accessible from the parent as well, so you could just exit(errno).
However, that is not the best thing to do, since the value of errno could change by the time you exit.
To be more sure that you don't lose errno if you have code between your exec() and exit() calls, assign errno to an int:
execvp(<args>);
int errcode=errno;
/* other code */
exit(errcode);
As for your other question, exit status is not directly comparable to the errno, and you shouldn't be trying to retrieve errno from anything but errno (as above) anyway.
This documentation may help:
http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
Here is my code:
it works fine. Child status is returned in waitpid hence it tells either child process is executed successfully or not.
//declaration of a process id variable
pid_t pid, ret_pid;
//fork a child process is assigned
//to the process id
pid=fork();
DFG_STATUS("Forking and executing process in dfgrunufesimulator %d \n", pid);
//code to show that the fork failed
//if the process id is less than 0
if(pid<0)
{
return DFG_FAILURE;
}
else if(pid==0)
{
//this statement creates a specified child process
exec_ret = execvp(res[0],res); //child process
DFG_STATUS("Process failed ALERT exec_ret = %d\n", exec_ret);
exit(errno);
}
//code that exits only once a child
//process has been completed
else
{
ret_pid = waitpid(pid, &status, 0);
if ( ret_pid == -1)
{
perror("waitpid");
return DFG_FAILURE;
}
DFG_STATUS("ret_pid = %d, pid = %d, child status = %d\n",ret_pid,pid,status);
if (WIFEXITED(status)) {
DFG_STATUS("child exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
DFG_STATUS("child killed (signal %d)\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
DFG_STATUS("child stopped (signal %d)\n", WSTOPSIG(status));
#ifdef WIFCONTINUED /* Not all implementations support this */
} else if (WIFCONTINUED(status)) {
DFG_STATUS("child continued\n");
#endif
} else { /* Non-standard case -- may never happen */
DFG_STATUS("Unexpected status (0x%x)\n", status);
}
if(status != 0) /* Child process failed to execute */
return DFG_FAILURE;
result = DFG_SUCCESS;
}