My original code is too long to post so let me try to write a simple version
//this commands() function will be called multiple times
int commands()
{
pid_t pid = fork();
if(pid<0)
{
printf("Failed to open child process\n");
return -1;
}
if(pid == 0)
{
//we are in child
child_function(); // calls some function to do some work
//note that this function end up calling execvp() so it never comes back
}
else
{
int status=0;
int_returned_pid = waitpid(-1, &status,0);
if(status !=0)
return 1;
else
return 0;
}
}
so what happens is, when the program calls commands first time, it successfully creates a child, child process finishes and command returns.
But when commands function is called second time, again child is successfully created and child_function() is called. after this, the program just stops and it feels like its waiting for input or someting (it does not crash).
After spending several hours here, I have no idea what is the problem, Please help.
Edit: I am using pipes in my program and basically when commands function is called the first time, I need its children to read someting from stdin, do some stuff and then write to pipe. And then upon calling commands function second time, i need its children to read from that pipe that the 1st call children wrote to and then to write to stdout.
Do I need to close these pipes in a parent process ?
Related
I need help returning a "status code" from my child program back to the parent, where it will check the status code, print code, and exit the parent. This is for a class project, so I will put some relevant code here, but I don't to post the entire project for obvious reasons.
I have forked and created the child process through exec. The parent does some fancy math and uses a named pipe to push data to the child process. The child does some more fancy math. When I uses a keyword, the child needs to return the number of times it did the fancy math on its end back to the parent, where the parent will see this, print out the returned number, and exit the parent.
int status;
pid_t child_id;
child_id = fork();
if (child_id == 0)
{
// put child code here
exec(opens second process);
}
if (child_id < 0)
{
perror("fork failed\n");
exit(EXIT_FAILURE);
}
while(child_id != 0)
{
//parent process
//do fancy math stuff here
// pipe
//open pipe
//converted math to "string" to pass to other program
// use fprintf to send data to other program
fprintf(fp,"%s",str);
//close pipe
//**************************************************
//this block doesn't work, always returns 0
if (WIFEXITED(status)){
int returned = WEXITSTATUS(status);
printf("exited normally with status %d\n",returned);
}
//***************************************************
return 0;
second c program is just a simple reading of the pipe, does some more fancy math, and has return statements placed where I want to return a number.
As far as I understand it, there is a way to pass the return value from the child program, but I can't seem to understand how. I haved added a piece of code that I found, but I can't seem to get it to work. I have read about it, but maybe I am missing something?
please disregard any syntax or structure issues.
You're attempting to read status via the WIFEXITED function, but you never give it a value. Attempting to read an uninitialized value invokes undefined behavior.
You need to call the wait function, which tells the parent to wait for a child to finish and receive its return code:
wait(&status);
if (WIFEXITED(status)){
int returned = WEXITSTATUS(status);
printf("exited normally with status %d\n",returned);
}
I'm currently writing a shell in C, and I'm having trouble with my pipeline.
I call the entire function process() line by line, with a parsed tree of commands as the input. process() works perfectly fine on simple commands and redirections so far, so I know that's not the problem.
In the below, my cmdList is an already-parsed I've structured my pipeline such that the child pipes its stdout into the stdin of the parent function. The child represents the left tree of cmdList, while the parent represents the right side. Here's what it looks like when I try to recursively call process():
else if (cmdList->type==PIPE)
{
int pipefd[2];
pid_t fork_result;
pipe(pipefd);
fork_result=fork();
if (fork_result < 0) {
fprintf(stderr, "Fork failure2\n");
exit(EXIT_FAILURE);
}
if (fork_result==0) {
int jo3 = close(pipefd[0]);
int jo1 = dup2(pipefd[1], STDOUT_FILENO);
process(cmdList->left);
exit(EXIT_failure);
}
else
{
close(pipefd[1]);
int status;
wait(&status);
dup2(pipefd[0], STDIN_FILENO);
process(cmdList->right); //dies here
fprintf(stderr,"FAIL\n");
exit(EXIT_FAILURE);
}
}
This causes my entire program to die, including the main function that calls process(). If I replace my recurisve process() calls with
execvp(cmdList->left->argv[0],cmdList->left->argv);
execvp(cmdList->right->argv[0],cmdList->right->argv);
then my program runs forever.
Things I've already tried:
All dup2's and wait's return as expected, without error.
Using a debugger, the program always gets to the execvp's with everything doing fine.
As stated, the rest of process() works perfectly on everything not having to do with the pipeline.
I'm not really sure what's going wrong with this. Is there anything that stands out?
I have read that system function make use of execl, fork and wait functions internally. So, I tried to simulate working of system without using it. But I am not able to achieve the same working.
When we call a program using system function the code below(after) system() function call also executes. So to simulate system function i wrote this code below:
int main()
{
printf("In controller Start: %d\n\n",getpid());
system("./prog1");
printf("Forking New Process %d\n\n",fork());
printf("Process Id: %d\n\n",getpid());
execl("./infinite",0);
printf("In controller End\n\n");
return 0;
}
In the above code after running "infinite" program the last line does not get printed.
i.e. printf("In controller End\n\n");
What to do in order to print the last line and also execute the "infinite" program without using system function.
It would be great if someone can explain the step by step working of system function like which function is called by system first and so on.
Why execution is not continuing to last line like it must have did if we made a simple function call other than execl.
Foot notes:-
infinite: is a binary file created using C code.
The last line doesn't get printed because it is never executed. The execl function never returns if everything went okay, instead it replaces your program with the one in the call.
I highly recommend you read the manual pages for fork and execl.
In short, fork splits the current process into two, and returns differently depending on if it returns to the parent or the child process. In the child process you then does your exec call, while the parent process continues to do what it wants. The parent must however wait on the child process to finish, or the child process will become what is called a "zombie" process.
In your code, both the parent and the child processes calls exec.
this is basis of fork
/*previous code*/
if((cpid=fork())<0){
printf("\n\tFORK ERROR");
exit(1);
}
if(cpid==0){ /*SON*/
/*CODE FOR SON-your `execl("./infinite",0);` goes here*/
}else{ /*FATHER*/
/*CODE FOR FATHER-your `printf("In controller End\n\n");` */
}
dont forget that when making a fork memory and variables are copied to the SON pid
In your example you do the same thing in both the parent and the child process. You have to check the return value of fork, which indicates if you are in the parent or the child, and then exec in the child, while you wait in your main process.
When you call fork(), both the parent and child process continue executing the same code from that point, but the return value of fork() is different for each. Generally you would do some conditional logic based on that return value.
I would imagine that system() does something like this:
int childpid = fork();
if (childpid) {
/* This is the parent */
wait( childpid );
} else {
/* This is the child */
execl( program_name );
}
Since execl() replaces the current executable with a new one, the child will run that executable then end. The parent will wait for the child to complete then continue.
You are not performing any kind of conditional statement based on the return value of fork. If you don't make sure that one process does the exec and one does something else then both will do the same thing.
You usually want to check against 0 and then execute the program you want to run. 0 signals that everything went ok and you are in the child process.
int main()
{
int pid;
printf("In controller Start: %d\n\n",getpid());
system("./prog1");
pid = fork();
printf("Forking New Process %d\n\n",pid);
printf("Process Id: %d\n\n",getpid());
if (pid == 0) { /* Son process : execute the command */
execl("./infinite",0);
} else { /* Original process : keep working */
printf("In controller End\n\n");
return 0;
}
}
I am currently trying to run a fork function in C where in the child section of the code,
I am trying to execute a command using exacvp, but before the execution I am trying a printf function which never executes. I ran this in debug and I have noticed that the pid is never assigned 0. I did try a simple fork example on a separate project and it worked smoothly. Does anyone have an idea why the child section never executes?
int startProcesses(int background) {
int i = 0;
while(*(lineArray+i) != NULL) {
int pid;
int status;
char *processName;
pid = fork();
if (pid == 0) {
printf("I am child");
// Child Process
processName = strtok(lineArray[i], " ");
execvp(processName, lineArray[i]);
i++;
continue;
} else if (!background) {
// Parent Process
waitpid(pid, &status, 0);
i++;
if(WEXITSTATUS(status)) {
printf(CANNOT_RUN_ERROR);
return 1;
}
} else {
i++;
continue;
}
}
return 0;
}
stdio files are flushed on program's exit, but execvp directly replaces the process with another image, bypassing the flush-at-exit mechanism and leaving the I am child message in memory never to be sent to the screen. Add an explicit fflush(stdout) before execvp, or end your string with \n so that it is automatically flushed when running on a TTY.
Note that execvp never exits, and if it does, it is because it has failed to execute the new process. At that point, the only thing the child can do is to report an error and call _exit(127) (or similar exit status). If the child continues, an incorrectly configured command name will cause it to execute the rest of the parent's loop in parallel with the parent. This process will continue for other descendants, effectively creating a fork bomb that can grind your system to a halt.
The following code calls an except script which copies an file via ftp to a server.
int status;
int child_pnr;
if((child_pnr = fork())==0)
{
printf("Childnr %i\n",child_pnr);
execv("/home/..../ftptest.exp",NULL);
}
else if (child_pnr > 0)
{
printf("Parent... childnr %i generated\n",child_pnr);
sleep(7);
}
else
perror("fork() error");
As execv() will terminate after execution I spawned a childprocess for this function. Why is the ftptest.exp interupted from parent if I don't have the sleep(7)....
By "interrupted", I presume you mean that the parent does not wait for the child to complete the operation before doing whatever it does next?
The parent and the child will run in parallel after the fork. If you want the parent to "hang" until the child is done then you need to wait for it.
See man wait and search for fork examples on the internet.