Using C to send an exec process to the background? - c

My question sounds the same as this but it isn't:
Start a process in the background in Linux with C
I know how to do fork() but not how to send a process to the background. My program should work like a simple command unix shell that supports pipes and background processes. I could do pipe and fork but I don't know how to send a process to the background with & like the last line of the program:
~>./a.out uname
SunOS
^C
my:~>./a.out uname &
How to achieve the background process?
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define TIMEOUT (20)
int main(int argc, char *argv[])
{
pid_t pid;
if(argc > 1 && strncmp(argv[1], "-help", strlen(argv[1])) == 0)
{
fprintf(stderr, "Usage: Prog [CommandLineArgs]\n\nRunSafe takes as arguments:\nthe program to be run (Prog) and its command line arguments (CommandLineArgs) (if any)\n\nRunSafe will execute Prog with its command line arguments and\nterminate it and any remaining childprocesses after %d seconds\n", TIMEOUT);
exit(0);
}
if((pid = fork()) == 0) /* Fork off child */
{
execvp(argv[1], argv+1);
fprintf(stderr,"Failed to execute: %s\n",argv[1]);
perror("Reason");
kill(getppid(),SIGKILL); /* kill waiting parent */
exit(errno); /* execvp failed, no child - exit immediately */
}
else if(pid != -1)
{
sleep(TIMEOUT);
if(kill(0,0) == 0) /* are there processes left? */
{
fprintf(stderr,"\Attempting to kill remaining (child) processes\n");
kill(0, SIGKILL); /* send SIGKILL to all child processes */
}
}
else
{
fprintf(stderr,"Failed to fork off child process\n");
perror("Reason");
}
}
The solution in plain English appears to be here:
How do I exec() a process in the background in C?
Catch SIGCHLD and in the the handler, call wait().
Am I on the right track?

Q: How do I send a process to the background?
A: In general, exactly what you're already doing: fork()/exec().
Q: What's not working as you expect?
I suspect maybe you also want a "nohup" (to completely disassociate the child from the parent).
The key to doing this is to run "setsid()" in the child process:
How to use fork() to daemonize a child process independant of it's parent?
http://www.enderunix.org/docs/eng/daemon.php

Related

Two pipe in C and ls | sort | grep r [duplicate]

This question already has answers here:
Pipe two or more shell commands in C using a loop
(1 answer)
Implementation of multiple pipes in C
(6 answers)
Combining two commands with a pipe
(1 answer)
Connecting n commands with pipes in a shell?
(2 answers)
Closed 18 days ago.
I need to create a program that execute in the shell this command with two pipes and three process: ls | sort | grep r. The code I have done is this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2],fd2[2];
pid_t pid1,pid2;
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
if( pid1 == 0 )
pid2 = fork();
if(pid1>0)
{
close(fd2[READ]);
close(fd2[WRITE]);
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
close(fd1[WRITE]);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
close(fd1[READ]);
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
close(fd2[WRITE]);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
close(fd2[READ]);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Probably I have wrong with the communication with this two pipe because I'm learning how they works only today. So sorry If I wrong some important thing about pipe. I hope if somebody that can help me with this and explain what I wrong. Thanks.
You created the pipes after the 1st fork (but before the 2nd).
Which means that you called pipe 4 times, 2 times in each process that exist after the 1st fork.
So fd1 and fd2 have one set of values for main process (the one for which pid1>0, aka the one that executes ls), and another for the child and grandchild processes (the 2nd fork is done after the creation of the pipes, so no problem here: the two processes that executes sort and grep do share the same file descriptors).
So for the sort | grep part, no problem. The output of sort is fd2[1], while the input of grep is fd2[0], as you want, fd2 being the result of the same pipe call, that was executed before the 2nd fork, and therefore shared between those 2 processes.
But for the ls | sort part, what you are doing is exactly as if you did something like
if(fork()){
int fd[2];
pipe(fd);
close(fd[0]);
dup2(fd[1], 1);
printf("Hello\n");
exit(0);
}else{
int fd[2];
pipe(fd);
close(fd[1]);
dup2(fd[0], 0);
char s[100];
scanf("%s", s);
printf("Should be hello=%s\n", s);
exit(0);
}
Wouldn't work as expected. There is no relationship whatsoever between the fd of the two processes.
So you need to create the pipes before the fork.
At least, the pipes that you intend to share among the processes that will be created by this fork.
I think I know why you did this strange thing. Because of another caveat with 3 process pipe chain: we often see people creating all their pipe before forking twice, having problem making their code work. For another reason: they usually forget that their pipe exist in 3 process, and they need to close all those they don't use. Even in processes that have nothing to do with fd1, both end of fd1 must be closed.
Edit:
Another strange thing you did, is closing even fd1[WRITE] even in the process where you want to use it (just after dup2). You can't do that. It is not like after dup2 you can close the original pipe because you would have a copy, or something like that. It is a copy of a descriptor to the same file. If you close the file, it is closed for the copy too.
A rewrite of your code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2], fd2[2];
pid_t pid1,pid2;
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pid1 == 0 ){
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
pid2 = fork();
}
if(pid1>0)
{
// I need to close fd1[READ] that I don't use (and that "sort" will use)
// I must keep fd1[WRITE] that I use
// I leave fd2[READ/WRITE] alone, since that variable is unitialized here (I've called "pipe(fd2)" only in the case
// pid1==0 which it is not here)
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
// I need to read fd1, but not write it (it is ls that need to write it).
// So before doing anything, I close fd1[WRITE]. Must I must keep the other end, fd1[READ] open
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
// Likewise, I need to write on fd2[WRITE], and have "grep" read on the other end.
// So I close fd2[READ] this side, and keep fd2[WRITE] open
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
// Last process. It needs to read fd2[READ], that I keep open, and don't need to write on fd2[WRITE] (that is "sort" job)
// so I close fd2[WRITE]
// I don't really case for fd1
// Situation is not exactly symetrical that for 1st process and fd2 tho. Because for 1st process, fd2 what not even initialized.
// While here, even if we don't need it, fd1 has been created by our grandfather. We shared it from our father, that shared it from its father
// So, since we use none of fd1, we need to close both.
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Note that this is not the only solution. I could have created pipe(fd2) unconditionally before even the 1st fork, and then close both fd2[0] and fd2[1] in the "ls" process. That would have been ok too.
The points are:
If you want to write on a fd[1] in a process, and read what have been written, from another process, on fd[0], then those process must share the same fd values, issued by the same pipe call; so pragmatically, that means that pipe(fd) must have been called before the fork that separated those two processes
Don't close the fd?[?] that you use. Even if you use them only through another fd on which you dup2 the fd?[?].
Close any fd?[?] that exist in a process, that is that have been created by a pipe call (you must mentally keep tracks of which process have which fd) and you don't need.

Finding the PID of a process launched by exec() or system() in C program

I need to retrieve the PID of a process started by exec() or system(). I read on the subject and did my research, but I don't understand the suggestion of using fork() to do so.
Let's say I have the following code:
int pid = fork();
if (pid < 0 ) {
exit(1);
} else if (pid == 0 ) {
execlp("ls", "-a", NULL);
} else {
wait(0)
}
How to get the pid of the process started by execlp (or by system() if system was used instead)? I don't need to kill the process, I just need the PID to retrieve stats about it.
The exec* family of functions do not create new processes, instead they replace the execution context of the process they are called from, with the execution context of their target executable. The PID is maintained when this occurs.
#include <unistd.h>
#include <stdio.h>
int main(void) {
/* Normal execution */
puts("Hello");
/* Our programs contents get "replaced" by ls */
execlp("ls", "ls", "-l", NULL);
/* We never get here */
puts("World!");
}
fork, on the other hand, creates a new child process, which of course has its own PID. This child process carries on executing a copy of the same execution context it was spawned from; you can consider the execution to be "split" as soon as fork is called. fork returns 0 in the child process, and the PID of the child process in the parent (our original process).
The idea is to fork, and then use exec* to replace the execution context of the child process.
#include <unistd.h>
#include <stdio.h>
int main(void) {
pid_t pid;
/* Normal execution */
puts("Hello");
/* execution "splits" */
pid = fork();
if (pid == 0) {
/* Our child's execution context get "replaced" by ls */
execlp("ls", "ls", "-l", NULL);
} else {
/* still in the parent */
printf("Child PID is: %d\n", (int) pid);
}
/* We only get here in the parent */
puts("World!");
}
system is a wrapper around fork, exec* and and waitpid that blocks the calling process until the child process finishes its execution. The child's PID is not reported, because by the time parent can "act" again, the PID of the child is meaningless.
Error handling omitted for clarity of examples, but you should handle errors for fork, exec*, and wait* functions.

Using Signal Handlers to Pause/Resume a Child Process

I'm currently trying to experiment with signals in C by using them to control a child process created with the fork() method. Essentially, I have a child process running the "yes" command from the linux terminal (this command just prints "y" and a newline until it is terminated). I want to be able to pause/resume this process with CTRL-Z. This is what i've got right now:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
pid_t CHILD_PROCESS;
pid_t PARENT_PROCESS;
int isPaused;
void pause_handler(int signo){
if(!isPaused){
printf("Ctrl-Z pressed. Pausing child.\n");
isPaused = 1;
kill(CHILD_PROCESS,SIGSTOP);
}
else if(isPaused){
printf("\nCtrl-Z pressed. Resuming child.\n");
kill(CHILD_PROCESS,SIGCONT);
isPaused = 0;
}
}
int main(int argc, char** argv){
pid_t pid;
PARENT_PROCESS = getpid();
pid = fork();
if(pid == 0){
system("yes");
}
isPaused = 0;
if(pid > 0){
signal(SIGTSTP, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
CHILD_PROCESS = pid;
while(1){
if(signal(SIGTSTP,pause_handler) == SIG_ERR){
printf("Signal Failure");
}
}
}
}
When I run this, I can get "Ctrl-Z pressed. Pausing child." to print to console by pressing CTRL-Z, and I can get "Ctrl-Z pressed. Resuming child." to print to the console by pressing CTRL-Z again. However, it doesn't actually resume printing "y" over and over again. Any ideas as to why the child process isn't resuming?
As it turns out, system has an implicit fork call within it, so the PID that gets stored in CHILD_PROCESS ends up not actually being the child process, and instead an intermediate one.
From man 3 system:
The system() library function uses fork(2) to create a child process
that executes the shell command specified in command using execl(3) as
follows:
execl("/bin/sh", "sh", "-c", command, (char *) 0);
system() returns after the command has been completed.
So, if we replace the system("yes") call with execl("/bin/sh", "sh", "-c", "yes", NULL), then we avoid this extra fork and the program functions as desired.
The only other issue is that, by I comment I found on this post, using printf within a signal handler is undefined behavior. Not an issue to worry about here, but something to keep in mind for future code!

Unix pipe - reading data from stdin in the child descriptor

I'm trying to implement unix piping in c (i.e. execute ls | wc). I have found a related solution to my problem (C Unix Pipes Example) however, I am not sure why a specific portion of the solved code snippet works.
Here's the code:
/* Run WC. */
int filedes[2];
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
/* Set stdout to the input side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
} else {
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
}
/* Run WC. */
pid = fork();
if (pid == 0) {
dup2(filedes[0], 0);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
}
In the child process that executes the wc command, though it attaches stndin to a file descriptor, it seems that we are not explicitly reading the output produced by ls in the first child process. Thus, to me it seems that ls is run independently and wc is running independently as we not explicitly using the output of ls when executing wc. How then does this code work (i.e. it executes ls | wc)?
The code shown just about works (it cuts a number of corners, but it works) because the forked children ensure that the the file descriptor that the executed process will write to (in the case of ls) and read from (in the case of wc) is the appropriate end of the pipe. You don't have to do any more; standard input is file descriptor 0, so wc with no (filename) arguments reads from standard input. ls always writes to standard output, file descriptor 1, unless it is writing an error message.
There are three processes in the code snippet; the parent process and two children, one from each fork().
The parent process should be closing both its ends of the pipe too; it only closes one.
In general, after you do a dup() or dup2() call on a pipe file descriptor, you should close both ends of the pipe. You get away with it here because ls generates data and terminates; you wouldn't in all circumstances.
The comment:
/* Set stdout to the input side of the pipe, and run 'ls'. */
is inaccurate; you're setting stdout to the output side of the pipe, not the input side.
You should have an error exit after the execv() calls; if they fail, they return, and the process can wreak havoc (for example, if the ls fails, you end up with two copies of wc running.
An SSCCE
Note the careful closing of both ends of the pipe in each of the processes. The parent process has no use for the pipe once it has launched both children. I left the code which closes filedes[1] early in place (but removed it from an explicit else block since the following code was also only executed if the else was executed). I might well have kept pairs of closes() in each of the three code paths where files need to be closed.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int filedes[2];
int corpse;
int status;
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0)
{
/* Set stdout to the output side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
close(filedes[1]);
close(filedes[0]);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
fprintf(stderr, "Failed to execute /bin/ls\n");
exit(1);
}
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
/* Run WC. */
pid = fork();
if (pid == 0)
{
/* Set stdin to the input side of the pipe, and run 'wc'. */
dup2(filedes[0], 0);
close(filedes[0]);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
fprintf(stderr, "Failed to execute /usr/bin/wc\n");
exit(1);
}
close(filedes[0]);
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("PID %d died 0x%.4X\n", corpse, status);
return(0);
}
Example output:
$ ./pipes-14312939
32 32 389
PID 75954 died 0x0000
PID 75955 died 0x0000
$

How do I get tcsetpgrp() to work in C?

I'm trying to give a child process (via fork()) foreground access to the terminal.
After I fork(), I run the following code in the child process:
setpgid(0, 0);
And:
setpgid(child, child);
In the parent process.
This gives the child its own process group. The call to setpgid() works correctly.
Now I want to give the child access to the terminal.
I added the following to the child after the setpgid() call:
if (!tcsetpgrp(STDIN_FILENO, getpid())) {
perror("tcsetpgrp failed");
}
After that, there is an execv() command to spawn /usr/bin/nano.
However, instead of having nano come up, nothing happens, and the terminal looks as if it's expecting user input.
Further, no code seems to execute after the tcsetpgrp() call.
I read somewhere that I need to send a SIGCONT signal to the child process to get it to work. If the process is stopped, how can I do that? Does the parent have to send the signal?
How do I go about sending the SIGCONT signal if that is the solution?
raise(SIGCONT);
Also, I'm not sure if this helps, but the code works fine and spawns nano if I run my program with:
exec ./program
Instead of:
./program
Any ideas? Thanks so much!
Figured it out. I have to ignore any SIGTTOU signals.
I did that by adding:
signal(SIGTTOU, SIG_IGN);
Before the tcsetpgrp() call.
man 3 tcsetpgrp states:
If tcsetpgrp() is called by a member of a background process group in its session, and the calling process is not blocking or ignoring SIGTTOU, a SIGTTOU signal is sent to all members of this background process group.
You need to call tcsetpgrp() in your parent process not in child. However if your parent process started and moved into background it will receive SIGTTOU and will be stopped.
It's the parent rather than child who should invoke tcsetpgrp(). After setpgid() call, the child becomes a background process. A valid case is the foreground group gives up its permission, let another background group become foreground and itself background. A process in background group can't grab controlling terminal. Example code maybe look like:
/* perror_act.h */
#ifndef PERROR_ACT_H
#define PERROR_ACT_H
#define PERROR_ACT(rtn, act) do { \
perror(rtn);\
act; \
} while (0)
#define PERROR_EXIT1(rtn) PERROR_ACT(rtn, exit(1))
#define PERROR_RETN1(rtn) PERROR_ACT(rtn, return -1)
#endif
/* invnano.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "perror_act.h"
void sig_chld(int chld)
{
exit(0);
}
int main(void)
{
pid_t child;
int p2c[2];
struct sigaction sa = {.sa_handler = sig_chld};
if (sigaction(SIGCHLD, &sa, NULL))
PERROR_EXIT1("sigaction");
if (pipe(p2c))
PERROR_EXIT1("pipe");
if ((child = fork()) < 0)
PERROR_EXIT1("fork");
if (child == 0) {
char buff;
size_t nread;
if (close(p2c[1])) /* We must make sure this fd is closed. The reason is explained in following comments. */
PERROR_EXIT1("close");
if ((nread = read(p2c[0], &buff, 1)) < 0) /* Just to receive a message from parent indicating its work is done. Content is not important. */
PERROR_EXIT1("read");
if (nread == 0) /* When all the write ends of a pipe are closed, a read() to the read end of this pipe will get a return value of 0. We've closed the child's write end so if 0 as returned, we can sure the parent have exited because of error. */
exit(1);
close(p2c[0]);
execlp("nano", "nano", (char *) 0);
PERROR_EXIT1("execlp");
} else {
if (close(p2c[0]))
PERROR_EXIT1("close");
if (setpgid(child, child))
PERROR_EXIT1("setpgid");
if (tcsetpgrp(STDIN_FILENO, child))
PERROR_EXIT1("tcsetpgrp");
if (write(p2c[1], &child, 1) != 1) /* If all the read ends of a pipe are close, a write() to the write end of this pipe will let the calling process receive a SIGPIPE whose default deposition is to terminate. */
PERROR_EXIT1("write");
while (1) /* If parent exit here, login shell will see the news and grab the controlling terminal */
pause();
}
return 0;
}

Resources