3

Please look at this code. It runs in CentOS6 64bit.

#include<stdio.h>

int main(int argc, char **argv)
{
         fprintf(stderr, "output 1\n");
         printf("output 2\n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 3\n ");
         printf("output 4\n"); 
         fflush(stdout);

         daemon(0, 1);

         fprintf(stderr, "output 5\n");
         printf("output 6\n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 7\n");
         printf("output 8\n");
         fflush(stdout);

}

If I run it, I will see these messages:

output 1
output 2
abc
output 3
output 4
output 5
output 6
abc
output 7
output 8

If I use ssh to login and run it, I will see the same results.

However, If I use the binary name as the parameter of ssh and run it, The program will exit when writing data to stderr after calling daemon(0, 1). Suppose the binary name is myapp. I run

ssh localhost myapp

And I will only see these messages:

output 1
output 2
abc
output 3
output 4
output 5
output 6
abc

Does anyone know why? according to the debugging, the program only exits after doing three things:

  1. Call daemon(0, 1).
  2. Call system to run another application or bash command.
  3. Write something to stderr.

Thanks a lot!

MLSC
  • 5,350
  • 6
  • 41
  • 85
flypen
  • 2,323
  • 4
  • 27
  • 46
  • In the man page it is said that after `dameon` the program forks, the parent exits and only the child will see further errors. To get more debug info maybe you should try to test the return code of your functions. Also, the answer to this [question](http://stackoverflow.com/questions/17954432/creating-a-daemon-in-linux) might help get some clues (there is a part on behavior on stdout/stderr) – n0p Mar 10 '14 at 10:41
  • If you do `ssh localhost 'myapp;sleep 10'`, do you see all the output? The `ssh` server exits soon after the parent `myapp` process exits, so any output that the child, and any `system()` calls, after that might not be visible. – Mark Plotnick Mar 10 '14 at 15:52

1 Answers1

0

If you run this command from a shell, you're probably seeing a new shell prompt between output 4 and output 5 (this would be more noticeable if there were sleeps in between the output lines).

That's because the daemon() system call causes the program to split into two independent processes. This is called a "fork", and can be controlled a little more closely using the fork() system call. After the fork, both processes keep pointers to the open file descriptors: stdin, stdout and stderr. According to "man 3 daemon", the parent process calls exit() after the fork.

When you call your executable from SSH, the SSH session will run one process. It forks off a child, and the main process exits. SSH sees that the command you issued has finished, and so it closes the SSH connection. That closes stdout and stderr. Unfortunately, your child process still has some work to do, but it can't write to the shared stderr because that file descriptor has been closed. If you printed some more debug info, like the return values from the printf() and fprintf() calls, you'd see that it was not able to write to the closed file descriptors.

If, instead of printing to stderr, you printed to a log file (which most daemons do), then you'll see that the child process would continue to run in the background and write as you expected.

If you had chosen to use fork() instead of daemon(), you could have the parent wait until the child finishes. You would do this with pid_t waitpid(pid_t pid, int *stat_loc, int options);.

You might also want to take a look at signals that are sent between the parent and child. When a child process dies, it will send SIGCHILD to the parent. If you'd like the reverse notification, you can set one up (on Linux only) using prctl(PR_SET_PDEATHSIG, SIGHUP);, so that the parent sends a SIGHUP to the child.

Alan Porter
  • 1,853
  • 1
  • 14
  • 11