Bug in forking and running processes - c

So I've been trying to fork a process two times, first fork is to let the main process continue working and the second is to let the child capture the output of the execution of the grand child process. The code is as follow:
void execute_run(char **parameters) {
task_t* task = create_task();
tasks[task_number] = *task;
int pipe_stdout[2];
ASSERT_SYS_OK(pipe(pipe_stdout)); // creating a pipe for stdout
pid_t pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// child process
char buffer[MAXLENGTH_OUTPUT];
pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// this process will redirect stdout to buffer
const char* program_name = parameters[0];
char** program_args = &parameters[1];
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(dup2(pipe_stdout[1], STDOUT_FILENO));
// redirecting stdout to pipe
ASSERT_SYS_OK(close(pipe_stdout[1]));
ASSERT_SYS_OK(execvp(program_name, program_args));
}
else {
ASSERT_SYS_OK(close(pipe_stdout[1]));
int status;
do
{
// this loop runs forever
} while (waitpid(pid, &status, WNOHANG) == 0);
ASSERT_SYS_OK(close(pipe_stdout[0]));
// this is never printed
fprintf(stderr, "Child process finished with status %d\n", status);
}
} else {
// parent process won't use any of the pipe ends
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(close(pipe_stdout[1]));
}
}
char** parameters are ['cat', 'in.txt'] in the example i'm trying to run (and file exists).
Thanks in advance!
I've tried debugging it and running with different commands like 'ls' for which it works fine, nevertheless I can't figure out why with 'cat' it doesn't work

Related

Background process killing with Parent process in C

I have the following code in my main function
pid_t pid;
pid = fork(); //Two processes are made
if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
{
int status;
if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
{
printf("Exitstatus [");
for (int i = 0; i < noOfTokens; i++)
{
printf("%s ", commands[i]);
}
printf("\b] = %d\n", WEXITSTATUS(status));
}
}
else if (pid == 0) //Child process. Executes commands and prints error if something unexpected happened
{
if (runBGflag==1) insertElement(getpid(),ptr);
execvp(commands[0], commands);
printf ("exec: %s\n", strerror(errno));
exit(1);
}
In a nutshell, a child process is made and if the runBackGround flag is set, the parent process will not wait for the child process to exit, but rather continue running. If a background process is made, the PID of the background process is stored in a list. At a later point, this function is called
void delete_zombies(void)
{
pid_t kidpid;
int status;
char buffer[1337];
while ((kidpid = waitpid(-1, &status, WNOHANG)) > 0)
{
removeElement(kidpid,buffer,1337);
printf("Child %ld terminated\n", kidpid);
printf("its command was %s\n",buffer);
}
}
This function simply checks if any child processes have died and in that case deletes them. It will then search for the childs PID in the list, remove it and print it out.
The problem is, the delete_zombies function will find that a child has died and will then try to remove it from the list, but it only finds an empty list, as if the child process never inserted its PID into the list.
This is really strange, because delete_zombies only finds a dead child process, when there was one created with the background flag set, so we know insertElement must have been called, but strangely when the parent checks in the list nothing is there
Is the cause for that, that child process and parent process have seperate lists, or is the PID maybe wrong?

Shell prompt returns before the child process complets via putty

Please review the following code example:
int main() {
pid_t childpid;
char buf[100] = {0};
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0) {
sprintf(buf,"child process id: %d\n",getpid());
write(1,buf,strlen(buf));
}
else {
sprintf(buf,"parent process id: %d\n",getpid());
write(1,buf,strlen(buf));
// fix here
wait(&childpid);
}
return 0;
}
When run directly on terminal on Linux machine, the output as expected:
[user#192 ~]$ ./test
parent process id: 28788
child process id: 28789
On another hand running the same via Putty brings:
parent process id: 28978
[user#192 ~]$ child process id: 28979
Thanks everybody for the suggestions. Adding a wait call brings prompt after child finishes.
I hope that it is a good idea to consider in a same question another case where the output differs as well, but independently of the wait() call.
This is dup() call implementation:
int main() {
pid_t childpid;
char string[] = "c\nb\na";
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0) {
close(0); // close STDIN
close(fd[1]); // close write end of a pipe
dup(*fd); // duplicate read end of the pipe to STDIN
execlp("sort","sort",NULL); // run sort(1) command
}
else {
close(*fd); // close read end of a pipe
write(fd[1],string,strlen(string));
}
return 0;
}
And again to different outputs, running program directly from the terminal,
gives:
[user#192 pipe]$ ./dup
a
b
c
[user#192 pipe]$
and via putty connection:
root#debian-512mb-ams2-01:~/C/inner/pipe# a
b
c
In the second example prompt never come back :(
What it can be?)
You need to wait() for the child process:
if(childpid == 0) {
sprintf(buf,"child process id: %d\n",getpid());
write(1,buf,sizeof(buf));
}
else {
sprintf(buf,"parent process id: %d\n",getpid());
write(1,buf,sizeof(buf));
wait(childpid); // <---
}
return 0;
All the child processes created inside a main process dies prematurely when the main process exit or dies. Hence before exit from the main process we need to have tell the operating system that please complete all the child processes before exit from the main process. For that you have to add wait() system call with a int value or NULL . For testing purpose you can use a sleep() statement as well.
write(1,buf,sizeof(buf));
wait(NULL); // just for testing sleep(5); sleep for 5 second to complete the child process
I think it may be related to latency in finishing processes (they are running independently).
Putty just show you prompt after core process is finished but it is not deterministic in your case.

Interrupt a process calling the function popen

I need to implement a child process that will execute a file and send the execution result, the 2 process will communicate with a shared memory segment.
My problem is that i want to kill the child process calling popen after 10 seconds but the function popen ignores signals.
Here is my code (shared memory segment not included) :
void kill_child(int sig)
{
kill(child_pid,SIGKILL);
printf("processus killed \n");
}
/*code....*/
signal(SIGALRM,(void (*)(int))kill_child);
if(fork()==0){
res.buffer=true;
FILE * fd;
char cmd[BUFFER_SIZE],output[BUFFER_SIZE];
strcpy(cmd,"./");
strcat(cmd,res.filepath);
system(cmd);
if((fd=popen(cmd,"r"))== NULL)
exit(1);
else
res.status=200;
strcpy(output,"");
while(fgets(buf,sizeof(buf)-1,fd))
strcat(output,buf);
if(pclose(fd))
exit(1);
strcat(res.customHTML,output);
res.buffer=true;
int err = sendResponse(res,args->client_fd);
if (err < 0) on_error("failed!\r\n");
exit(0);
}
else{
int status;
alarm(10);
waitpid(-1,&status,0);
printf("status %d _n);
}
How can make the child process interruptible?
thanks
First off, you need to actually store the child PID into child_pid. It's returned from fork for the parent process so changing your fork call to
child_pid = fork();
if(child_pid == 0)
{
...
otherwise your call to kill is being passed a random value. Luckily it seems to be defaulting to 0, which kill takes to mean kill all processes in the same process group so your child process is being killed.
Secondly, rather than calling popen() call the executable yourself with (for example) execvp() and have the parent read the output using a pipe you create yourself...
int fds[2];
pipe(fds);
child_pid = fork();
if(child_pid == 0)
{
char *cmd[]={"mycmd",NULL};
/* Replace stdout with the output of the pipe and close the original */
dup2(fds[1],1);
close(fds[0]);
close(fds[1]);
execvp(cmd[0],cmd);
}
else
{
close(fds[1]);
alarm(10);
while(...)
{
read(fds[0],....);
if(waitpid(child_pid,&status,WNOHANG))
{
....
}
}
}
This way you've only got the one child process which is running your executable and you've got visibility on when and how it exits.

how to correctly use fork, exec, wait

The shell i'm writing needs to execute a program given to it by the user. Here's the very shortened simplified version of my program
int main()
{
pid_t pid = getpid(); // this is the parents pid
char *user_input = NULL;
size_t line_sz = 0;
ssize_t line_ct = 0;
line_ct = getline(&user_input, &line_sz, stdin); //so get user input, store in user_input
for (;;)
{
pid_t child_pid = fork(); //fork a duplicate process
pid_t child_ppid = getppid(); //get the child's parent pid
if (child_ppid == pid) //if the current process is a child of the main process
{
exec(); //here I need to execute whatever program was given to user_input
exit(1); //making sure to avoid fork bomb
}
wait(); //so if it's the parent process we need to wait for the child process to finish, right?
}
}
Have I forked the new process & checked to see if it's a child process correctly
What exec could I use here for what I'm trying to do? What is the most simple way
What are my arguments to wait? the documentation I'm looking at isn't helping much
Assume the user might input something like ls, ps, pwd
Thanks.
Edit:
const char* hold = strdup(input_line);
char* argv[2];
argv[0] = input_line;
argv[1] = NULL;
char* envp[1];
envp[0] = NULL;
execve(hold, argv, envp);
Here's a simple, readable solution:
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
// we are the child
execve(...);
_exit(EXIT_FAILURE); // exec never returns
}
The child can use the stored value parent if it needs to know the parent's PID (though I don't in this example). The parent simply waits for the child to finish. Effectively, the child runs "synchronously" inside the parent, and there is no parallelism. The parent can query status to see in what manner the child exited (successfully, unsuccessfully, or with a signal).

How to use Fork() to create only 2 child processes?

I'm starting to learn some C and while studying the fork, wait functions I got to a unexpected output. At least for me.
Is there any way to create only 2 child processes from the parent?
Here my code:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main ()
{
/* Create the pipe */
int fd [2];
pipe(fd);
pid_t pid;
pid_t pidb;
pid = fork ();
pidb = fork ();
if (pid < 0)
{
printf ("Fork Failed\n");
return -1;
}
else if (pid == 0)
{
//printf("I'm the child\n");
}
else
{
//printf("I'm the parent\n");
}
printf("I'm pid %d\n",getpid());
return 0;
}
And Here is my output:
I'm pid 6763
I'm pid 6765
I'm pid 6764
I'm pid 6766
Please, ignore the pipe part, I haven't gotten that far yet. I'm just trying to create only 2 child processes so I expect 3 "I'm pid ..." outputs only 1 for the parent which I will make wait and 2 child processes that will communicate through a pipe.
Let me know if you see where my error is.
pid = fork (); #1
pidb = fork (); #2
Let us assume the parent process id is 100, the first fork creates another process 101. Now both 100 & 101 continue execution after #1, so they execute second fork. pid 100 reaches #2 creating another process 102. pid 101 reaches #2 creating another process 103. So we end up with 4 processes.
What you should do is something like this.
if(fork()) # parent
if(fork()) #parent
else # child2
else #child1
After you create process , you should check the return value. if you don't , the seconde fork() will be executed by both the parent process and the child process, so you have four processes.
if you want to create 2 child processes , just :
if (pid = fork()) {
if (pid = fork()) {
;
}
}
You can create n child processes like this:
for (i = 0; i < n; ++i) {
pid = fork();
if (pid > 0) { /* I am the parent, create more children */
continue;
} else if (pid == 0) { /* I am a child, get to work */
break;
} else {
printf("fork error\n");
exit(1);
}
}
When a fork statement is executed by the parent, a child process is created as you'd expect. You could say that the child process also executes the fork statement but returns a 0, the parent, however, returns the pid.
All code after the fork statement is executed by both, the parent and the child.
In your case what was happening was that the first fork statement created a child process. So presently there's one parent, P1, and one child, C1.
Now both P1 and C1 encounter the second fork statement. The parent creates another child (c2) as you'd expect, but even the child, c1 creates a child process (c3). So in effect you have P1, C1, C2 and C3, which is why you got 4 print statement outputs.
A good way to think about this is using trees, with each node representing a process, and the root node is the topmost parent.
you can check the value as
if ( pid < 0 )
process creation unsuccessful
this tells if the child process creation was unsuccessful..
fork returns the process id of the child process if getpid() is used from parent process..
You can create a child process within a child process. This way you can have 2 copies of the original parent process.
int main (void) {
pid_t pid, pid2;
int status;
pid = fork();
if (pid == 0) { //child process
pid2 = fork();
int status2;
if (pid2 == 0) { //child of child process
printf("friends!\n");
}
else {
printf("my ");
fflush(stdout);
wait(&status2);
}
}
else { //parent process
printf("Hello ");
fflush(stdout);
wait(&status);
}
return 0;
}
This prints the following:
Hello my friends!

Resources