views:

112

answers:

2

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

+4  A: 

How to Daemonize in Linux

bstpierre
This helped a ton. Thank you.
Mike
@Mike - there's a lot of stuff you can get wrong... I've left out bits before and that article is a good starting point for remembering all the pieces.
bstpierre
+3  A: 

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:

  1. Run your launcher program from a command line, which will have standard input, standard output and standard error connected to 'the terminal'.
  2. Inside your program, you want to replace the standard input so it comes from /dev/null.
  3. You want to leave standard output alone - you want logcat to write to the current standard output.
  4. You probably want to leave standard error alone too.

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:

  • Are you sure you want random text appearing over your terminal or console when it is in use for other things?

I don't much like it when that happens.


See also: SO 958249

Jonathan Leffler
Thank you sooooo much for your great in-depth answer. The problem was the stdin as you had mentioned. I had to redirect from logcat to stdin, along with some other stuff such as daemonizing the process. This has saved me so much stress and worry. Thanks again I really appreciate it.
Mike