I'm trying to start another process (daemon) from my own:
pid_t pid=fork();
if (pid==0) { /* child */
static char *argv[]={NULL};
execv("/sbin/daemon", argv);
exit(127); /* only if execv fails */
}
/* parent */
sleep(5); /* ugly way to wait for /sbin/daemon */
/* THIS_POINT */
How can I get rid of this sleep? I have to be sure that after THIS_POINT the /sbin/daemon is already started.
What kind of approach would you suggest?
If you have control over the daemon (so you can modify it if necessary), consider creating a pipe, and have the daemon write "OK" on its standard output (the write end of the pipe) when it is running (and then close it). Your parent process reads from the pipe and knows the daemon is running if it gets "OK". It would be sensible to include a newline after the OK; it is important to remember that the data read won't be null terminated.
int fd[2];
if (pipe(fd) != 0) { …report error… }
pid_t pid=fork();
if (pid < 0) { …report error… }
if (pid == 0)
{
static char *argv[] = { "/sbin/daemon", NULL };
dup2(fd[1], FILENO_STDOUT);
close(fd[0]);
close(fd[1]);
execv(argv[0], argv);
exit(127);
}
close(fd[1]);
char buffer[16];
if (read(fd[0], buffer, sizeof(buffer)) >= 2 && memcmp(buffer, "OK", 2) == 0)
…daemon started successfully…
else
…daemon failed…
close(fd[0]);
If you don't have control over the daemon, you can still create the pipe, but you have to rely on the daemon daemonizing itself properly by closing its standard output. In that case, the parent process will simply get zero bytes to read (EOF) from the pipe, and you then check with waitpid(pid, &status, WNOHANG) whether the child died (which would also give you EOF).
Related
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.
I have been making simple shell which performs pipe.
Here is some code for operating pipe syntax.
int fd[2];
int stdin_copy;
int stdout_copy;
int status;
char * msg;
if (pipe(fd) == -1) {
perror("pipe");
exit(1);
}
// fd[0] : process read from fd[0]
// fd[1] : process write to fd[1]
if (execok(pr_words) == 0) { /* is it executable? */
status = fork(); /* yes; create a new process */
if (status == -1) { /* verify fork succeeded */
perror("fork");
exit(1);
} else if (status == 0) { /* in the child process... */
stdout_copy = dup(1);
close(1); // close standard output
dup(fd[1]);
close(fd[0]);
close(fd[1]); // close and fd[1] will be stdout
pr_words[l_nwds] = NULL; /* mark end of argument array */
status = execve(path, pr_words, environ); /* try to execute it */
perror("execve"); /* we only get here if */
exit(0); /* execve failed... */
}
/*------------------------------------------------*/
/* The parent process (the shell) continues here. */
/*------------------------------------------------*/
else if (status > 0) { // in the parent process....
wait( & status); /* wait for process to end */
if (execok(af_words) == 0) {
if (pipe(fd2) == -1) {
perror("pipe");
exit(1);
}
status = fork();
if (status == -1) {
perror("fork");
exit(1);
} else if (status == 0) { // in the child process...
stdin_copy = dup(0);
close(0);
dup(fd[0]);
close(fd[1]);
close(fd[0]);
read(fd[0], readbuffer, sizeof(readbuffer));
af_words[r_nwds] = NULL; /* mark end of argument array */
status = execve(path, af_words, environ); /* try to execute it */
} else if (status > 0) {
wait( & status);
msg = "over";
write(2, msg, strlen(msg));
close(fd[0]);
close(fd[1]);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);
printf("%s", "hi");
}
} else {
/*----------------------------------------------------------*/
/* Command cannot be executed. Display appropriate message. */
/*----------------------------------------------------------*/
msg = "*** ERROR: '";
write(2, msg, strlen(msg));
write(2, af_words[0], strlen(af_words[0]));
msg = "' cannot be executed.\n";
write(2, msg, strlen(msg));
}
}
} else {
/*----------------------------------------------------------*/
/* Command cannot be executed. Display appropriate message. */
/*----------------------------------------------------------*/
msg = "*** ERROR: '";
write(2, msg, strlen(msg));
write(2, pr_words[0], strlen(pr_words[0]));
msg = "' cannot be executed.\n";
write(2, msg, strlen(msg));
}
pr_words and af_words is two-dimensional pointer containing command, right-side and left-side of pipe. (ex. ls | cat -> pr_words = "ls\0" , af_words = "cat\0")
And, first I make child process using fork() and register fd[1] for standard output. (and also save stdin file descriptor before closing stdin) And after execute left side of command, make other child process for handling right side of command.
Similarly, I saved stdout file descriptor before close stdout and made fd[0] standard input. By using input from first outcome of execve function, I thought every outcome would be saved in fd[1]. (Because this was currently registered as std output).
And, finally, restore pipe input and output to standard output. (I don't want to use dup2 but I have no choice because of my lack of knowledge )
However, in execution of this code, after I enter the 'ls | cat', there is no output. Furthermore, I set every entry of terminal will print '#'. (which means that '# ls' or '# cat' ...) But, after enter above pipe command, that program even does not print '#'.
I guess input and output stream of this program are completely twisted after dealing with pipe command.
How can I fix it? I mean, I want save outcome of first execve into fd[1] and after using this fd[1] for performing second execve, make final outcome will be printed through stdout file description.
I see a few issues with your code at least:
First off, you shouldn't wait() on the first process before starting the second one. A pipe only has a few KB of buffer in it, after which your shell will hang if the first child process tries to continue to write there. You need to start both children before wait()ing for each of them. Just move the first wait(&status) call down next to the other one. You'll probably want to use waitpid or something later so you know which one finished first and which status goes to which, but you can address that once you get the basics working.
Secondly, all variables and file descriptor mappings in your program are copied when you fork(). Therefore, you don't need to save stdin or stdout in either child process, because none of the changes you make in the child processes will affect the parent. Furthermore, because you only initialize stdin_copy and stdout_copy in the child processes, the versions of those variables you use in the parent process after the second fork() are uninitialized. This is what's causing the parent shell's I/O to be messed up after executing this code. You don't actually need to do anything in the parent after forking the second time to maintain the original stdin and stdout there -- you never change them in that process before that point. You probably want to remove all of this from the post-fork parent code:
close(fd[0]);
close(fd[1]);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);
Thirdly, why are you reading from the pipe before calling execve() in the second child? That's just going to strip data out of the pipe that your exec'd child will never see. That's probably what's causing the pipe itself to appear not to work. You probably want to remove this:
read(fd[0], readbuffer, sizeof(readbuffer));
Lastly, this line probably needs to go before the execok() call (and similarly for the other similar one):
pr_words[l_nwds] = NULL; /* mark end of argument array */
The skeleton of the code should look about like this, leaving off error handling and execok checks, and demonstrating the use of waitpid() if you want to know which status code is for which child:
int child_pid[2];
child_pid[0] = fork();
if (child_pid[0] == 0) {
// first child, close stdout and replace with pipe, then exec
} else {
child_pid[1] = fork();
if (child_pid[1] == 0) {
// second child, close stdin and replace with pipe, then exec
} else {
// parent, and now we have the pids of the children
waitpid(child_pid[0], &status, 0); // wait for first child
waitpid(child_pid[1], &status, 0); // wait for second child
// *do not* mess with stdin/stdout, they are okay here
}
}
// This code is pasted from
// http://linux.die.net/man/2/pipe
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */ <----- Point A
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */ <----- Point B
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
As what I understood,
if (...)
............; ---+
else |---> " Only ONE of them can be reached! "
............; ---+
So, how can the child process read from the pipe AND the parent process write to the pipe in this code?
The result of fork() is that one process becomes two (by asexual reproduction). So while it is still the case that exactly one branch of the if/else block will be taken in a process, there are two processes, and one path will be taken by each.
More specifically, look at what fork() returns: a PID to the parent, and 0 to the new child. Apart from that the two processes are almost identical. So the if (cpid == 0) check is a common pattern after fork() so that you can proceed with distinct logic in each process. In your case, that's reading in one process and writing in the other.
The system call fork() returns twice. Both in the parent process and the child process. The moment you call fork(), two exact copies of your program are running. The SINGLE difference is the return value of fork().
So your "if else only one" rule is still valid when you consider each process in isolation.
Check this resource for a description of the fork call return value:
On success, the PID of the child process is returned in
the parent, and 0 is returned in the child. On failure, -1 is returned
in the parent, no child process is created, and errno is set
appropriately.
So the line that contains cpid = fork(); is executed by both process after the fork, where the parent receives the new process' PID and the child receives 0 as PID. Hence the distinction between parent and child.
I'm creating a small program which contains three processes; a source process, a filter process and a sink process. The stdout of the source process is redirected to the stdin of the filter process, and the filter process' stdout is redirected to the sink process' stdin.
My problem is that no output is printed to stdout from the sink process. Can any of you see the problem in the following tiny snippet of code?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
// Pipes
// pipe1 is from source to filter, pipe2 is from filter to sink
int pipe1[2], pipe2[2];
// Create pipes
if (pipe(pipe1) < 0 || pipe(pipe2) < 0)
{
perror("Creating pipes failed!");
}
if (fork() == 0)
{
close(1);
dup(pipe1[1]);
close(pipe1[0]);
close(pipe2[0]);
close(pipe2[1]);
execlp("ls", "ls", NULL);
exit(0);
}
else
{
if (fork() == 0)
{
close(0);
dup(pipe1[0]);
close(pipe1[1]);
close(1);
dup(pipe2[1]);
close(pipe2[0]);
execlp("sort", "sort", NULL);
exit(0);
}
else
{
if (fork() == 0)
{
close(0);
dup(pipe2[0]);
execlp("more", "more", NULL);
exit(0);
}
}
}
wait(NULL);
printf("Done.\n");
return 0;
}
BR
Jacob
I think problem may be, wait will only wait for one process. And when the parent exits after first child returns, I suspect more command also decides to terminate, because it may get SIGHUP (speculation, not sure).
But, check for errors from on all system calls! Also for wait calls which succeeded, print why the child exited (was it signal or normal exit, and if it was normal exit, what was exit code).
Also note, perror does not exit, it only prints.
It is kind of pointless trying to see why some code fails, if it does not have error handling in it...
Some easy way to do pipes for your scenario:
char cmd[MAX_LEN];
sprintf(cmd, "%s | %s | %s", app1, app2, app3); //app123 holds app name + args
system(cmd);
if you want to capture the output of the last app, use popen:
FILE pPipe = popen(cmd, "rt"); /* same access flag as fopen()*/
while (NULL != fget(buf, buf_len, pPipe)) {
// do something with the read line in 'buf'
}
Currently am doing two forks to pipeline two process, but I think am doing my wait(&status) wrong because after the command my shell just hangs and does not return to my prompt. I know my pipe is working because I can see the result if I remove the wait.
Any tips?
pipe(mypipe);
pid1=fork();
if(pid1==0)
{
pid2=fork();
if(pid2==0)
{
close(0);
dup(mypipe[0]);
close(mypipe[1]);
execv(foundnode2->path_dir,arv2);
exit(0);
}
close(1);
dup(mypipe[1]);
close(mypipe[0]);
pid2 = wait(&status2);
execv(foundnode1->path_dir,arv1);
exit(0);
}
pid1 = wait(&status2);
Rule of Thumb: if you use dup() or dup2() to map one end of a pipe to standard input or standard output, you should close() both ends of the pipe itself. You're not doing that; your waits are waiting for the programs to finish but the programs will not finish because there is still a proess with the pipe open that could write to the pipe. Also, the process which created the pipe needs to close both ends of the pipe since it is not, itself, using the pipe (the child processes are using it). See also C MiniShell — Adding Pipelines.
Also, you should not be waiting for the first child to finish before launching the second (so the pid2 = wait(&status2); line is a bad idea). Pipes have a fairly small capacity; if the total data to be transferred is too large, the writing child may block waiting for the reading child to read, but the reading child hasn't started yet because it is waiting for the writing child to exit (and it takes a long time for this deadlock to resolve itself). You're seeing the output appear without the wait() calls because the second part of the pipeline executes and processes the data from the first part of the pipeline, but it is still waiting for more data to come from the shell.
Taking those tips into account, you might end up with:
pipe(mypipe);
pid1 = fork();
if (pid1 == 0)
{
pid2 = fork();
if (pid2 == 0)
{
close(0);
dup(mypipe[0]);
close(mypipe[1]);
close(mypipe[0]);
execv(foundnode2->path_dir, arv2);
fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
exit(1);
}
close(1);
dup(mypipe[1]);
close(mypipe[0]);
close(mypipe[1]);
execv(foundnode1->path_dir, arv1);
fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
exit(1);
}
close(mypipe[0]);
close(mypipe[1]);
pid1 = wait(&status1);
Notice the error reporting to standard error when the commands fail to execv(). Also, the exit status of 0 should be reserved for success; 1 is a convenient error exit status, or you can use EXIT_FAILURE from <stdlib.h>.
There is a lot of error checking omitted still; the fork() operations could fail; the pipe() might fail. One consequence is that if the second fork() fails, you still launch the second child (identified by foundnode1->path_dir).
And I note that you could save yourself a little work by moving the pipe creation into the first child process (the parent then does not need to — indeed, cannot — close the pipe):
int pid1 = fork();
if (pid1 == 0)
{
int mypipe[2];
pipe(mypipe);
int pid2 = fork();
if (pid2 == 0)
{
close(0);
dup(mypipe[0]);
close(mypipe[1]);
close(mypipe[0]);
execv(foundnode2->path_dir, arv2);
fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
exit(1);
}
close(1);
dup(mypipe[1]);
close(mypipe[0]);
close(mypipe[1]);
execv(foundnode1->path_dir, arv1);
fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
exit(1);
}
pid1 = wait(&status1);
If it's just a pipe with two processes, I wouldn't wait at all. Just fork and do an exec in parent and child.
int fd[2];
pipe(fd);
int pid = fork();
if (pid == -1) {
/* error handling */
} else if (pid == 0) {
dup2(fd[0], 0);
close(fd[1]);
execv(foundnode2->path_dir,arv2);
/* error handling for failed exec */
exit(1);
} else {
dup2(fd[1], 1);
close(fd[0]);
execv(foundnode1->path_dir,arv1);
/* error handling for failed exec */
exit(1);
}