I am trying to do something a little weird here. I need to start a process, logcat, from a deamon that will run in the background and print to the terminal without taking control of stdin. It is for logging so ideally logcat will print log messages while still allowing the user to input standard commands and initialize programs from the shell. Here is the code for the daemon I have so far. The program, logcat, starts and shows log messages but I cannot enter any commands into stdin as it appears that the program has taken control of stdin.
int main ( int argc, char** argv, char** env )
{
int fd;
if ((fd = open("/dev/console", O_RDWR)) < 0) {
fd = open("/dev/null", O_RDWR);
}
printf("THIS IS A TEST\n");
dup2(1, fd);
dup2(2, fd);
pid_t childpid = fork();
if(childpid == -1) {
perror("Failed to fork, logcat not starting");
return 1;
}
if(childpid == 0) {
//this is the child, exec logcat
setsid();
int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
} else {
//this is the parent do nothing
close(fd);
return 0;
}
close(fd);
return 0;
}
Thanks
The 'logcat' command seems to be for Android development - that might explain the odd location of the command.
The key operation that you must fix is to ensure that you close your current standard input (the terminal) and open /dev/null/
for the input device:
close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
...error - failed to open /dev/null!
This means that your daemonized child process will not read anything from the terminal.
What I think you want to do is:
/dev/null
.logcat
to write to the current standard output.At some point in the proceedings, you do your daemonization properly (borrowing the link from @bstpierre's answer), making sure that the terminal you are connected to is not your controlling terminal, so that interrupts and hangups sent to the terminal don't affect your daemon. The plumbing is simpler than what you have set up - you should deal with standard input and leave standard output and standard error unchanged (instead of changing the outputs and leaving the input unchanged).
Now, you might want the output to go to /dev/console
; if so, then it is reasonable to revise the code to open /dev/console
. However, it is not reasonable to fall back on /dev/null
if you can't open /dev/console
; your program should report an error and fail (because there is no point in having logcat writing to /dev/null
!). Make sure you open the console with the O_NOCTTY
flag so it does not become the controlling terminal for the daemon.
The final comment I'd make is:
I don't much like it when that happens.
See also: SO 958249
How to Daemonize in Linux [dead link]
How to Daemonize in Linux [wayback machine archive of the above]
gist on github -- code taken from link above
Executive summary:
One of the things I keep running across is Linux daemons that don’t properly daemonize themselves. To properly daemonize, the following steps must be followed.
- The fork() call is used to create a separate process.
- The setsid() call is used to detach the process from the parent (normally a shell).
- The file mask should be reset.
- The current directory should be changed to something benign.
- The standard files (stdin,stdout and stderr) need to be reopened.
Failure to do any of these steps will lead to a daemon process that can misbehave. The typical symptoms are as follows.
- Starting the daemon and then logging out will cause the terminal to hang. This is particularly nasty with ssh.
- The directory from which the daemon was launched remains locked.
- Spurious output appears in the shell from which the daemon was started.
There is special purposed function for this in glibc:
#include <unistd.h>
...
/* We are in the parent, yet */
daemon(0,0);
/* Now we are in the child */
...
More details here http://linux.die.net/man/3/daemon
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With