Thread: Detaching from Console

  1. #1
    Registered User HalNineThousand's Avatar
    Join Date
    Mar 2008
    Posts
    43

    Detaching from Console

    I know I can run a program like this:

    cprog >/dev/null 2>&1 &

    and it'll basically run on its own and it is essentially detached from the console so I can go ahead and use the console for other tasks.

    Is there any way, from within a C or C++ program, on Linux, for the program to detach itself from the console and operate as a daemon and be independent of the console instance from which it was started?

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by HalNineThousand View Post
    Is there any way, from within a C or C++ program, on Linux, for the program to detach itself from the console and operate as a daemon and be independent of the console instance from which it was started?
    Of course. The basic steps:

    Code:
    #include <unistd.h>
    
    pid = fork();
    if(pid < 0)
    {
        /* Report error and exit */
    }
    if(pid == 0)
    {
        /* The child becomes the daemon. */
        /* Detach all standard I/O descriptors */
        close(0);
        close(1);
        close(2);
        /* Enter a new session */
        setsid();
        /* We are now daemonized */
        run_the_daemon();
        exit(0);
    }
    else
    {
        /* The parent need not exist anymore */
        exit(0);
    }

  3. #3
    Registered User HalNineThousand's Avatar
    Join Date
    Mar 2008
    Posts
    43
    When you use
    Code:
        run_the_daemon();
    Do you mean to call the actual daemon program through a system call, or do you mean to simply just call the function in this program itself? I'm assuming you mean the latter, but just wanted to check.

    As for the fork(), is that because when it forks, the child is "spun off" on its own and the parent just exits? What happens if you issue the close statements before forking?

    That also answers another question I've had along the way. After reading this over and examining it, I take it the close statements are closing STDERR, STDOUT, and STDIN, so that would explain why whenever I opened my first file in other programs, it would always get 3 as a file descriptor. Is that right?

    Thanks!

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You must fork because the shell is waiting for the process it started to exit.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by HalNineThousand View Post
    Do you mean to call the actual daemon program through a system call, or do you mean to simply just call the function in this program itself? I'm assuming you mean the latter, but just wanted to check.
    I mean the latter. You don't necessarily have to implement it that way, though. You could bundle this section of code into a function called "become_daemon()" and then just return from it instead of calling run_the_daemon(). Now the main program just calls this function to become daemonized.

    Quote Originally Posted by HalNineThousand View Post
    As for the fork(), is that because when it forks, the child is "spun off" on its own and the parent just exits? What happens if you issue the close statements before forking?
    You COULD call close() before forking, but if fork() fails, you will now have no way of printing an error message.

    That also answers another question I've had along the way. After reading this over and examining it, I take it the close statements are closing STDERR, STDOUT, and STDIN, so that would explain why whenever I opened my first file in other programs, it would always get 3 as a file descriptor. Is that right?
    Correct.

  6. #6
    Registered User HalNineThousand's Avatar
    Join Date
    Mar 2008
    Posts
    43
    I was hoping that you did mean run_the_daemon() as a call to any function because I was thinking just what you suggested: use it as a subroutine, so I could put it in my personal library to make it easier in the long run.

    I follow your reasoning on the closing and fork(). I'm still so new to C++ that I always want to make sure I know about any side effects that aren't obvious.

    What would make fork() fail?

    And thanks for all the help!

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by HalNineThousand View Post
    I follow your reasoning on the closing and fork(). I'm still so new to C++ that I always want to make sure I know about any side effects that aren't obvious.

    What would make fork() fail?
    fork() can fail if you have reached your user process limit, or if the system is completely out of space in the process table, or if not enough memory is available. If fork() is failing because of not enough memory, the system is in a poor, poor state already, but you at least would want to print an error message.

  8. #8
    Registered User HalNineThousand's Avatar
    Join Date
    Mar 2008
    Posts
    43
    Okay. Makes sense. And yes, I would want to print an error. I prefer programs that communicate too much as opposed to not giving enough info.

    Thank you!

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    19
    Don't forget to...

    chdir("/");

    ...or the directory that you started the deamon from will be locked until the program is stopped.

  10. #10
    Registered User HalNineThousand's Avatar
    Join Date
    Mar 2008
    Posts
    43
    You mean locked as in can't delete it, right?

    And I take it you mean the directory it was started from, not the one the executable was in, right?

  11. #11
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Right and right. You can't delete it, and you can't unmount the volume it is on either.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  12. #12
    Registered User
    Join Date
    Mar 2008
    Posts
    44
    What will happen then when something tries to write to any of the closed descriptors? As opposed to when you connect them to /dev/null like so:
    Code:
        for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
        i=open("/dev/null",O_RDWR); /* open stdin */
        dup(i); /* stdout */
        dup(i); /* stderr */
    (Taken from this example.)

    Or is it good enough to redirect everything to a log file?

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The write() system call fails if you try to write to a closed descriptor, and read() fails if you try to read from a closed descriptor.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  14. #14
    Registered User
    Join Date
    Mar 2008
    Posts
    44
    Thanks.
    So I guess "good practice" depends on what kind of daemon you're making and what it does.

  15. #15
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by heras View Post
    Thanks.
    So I guess "good practice" depends on what kind of daemon you're making and what it does.
    Obviously you are in control of your own code. A write() to stdout will return an error if the descriptor is closed. But since you are writing this program specifically as a daemon, you would have no reason to write() to stdout in the first place. And even if you did, you would be perfectly free to ignore the harmless error which would result.

    Connecting the standard descriptors to /dev/null is a practice used when you might exec() a program that doesn't expect to have those descriptors closed. In your case, it is unnecessary.

    The thing about chdir("/") is a good piece of advice I forgot about in my original post. Again, however, not strictly necessary, since the superuser can just go to single user mode if a misbehaving program is interfering with unmounting a filesystem (and programs misbehave often).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Full Screen Console
    By St0rmTroop3er in forum C++ Programming
    Replies: 1
    Last Post: 09-26-2005, 09:59 PM
  2. Problems with a simple console game
    By DZeek in forum C++ Programming
    Replies: 9
    Last Post: 03-06-2005, 02:02 PM
  3. Console Functions Help
    By Artist_of_dream in forum C++ Programming
    Replies: 9
    Last Post: 12-04-2004, 03:44 AM
  4. Detaching a program from the console
    By trainee in forum Windows Programming
    Replies: 6
    Last Post: 01-22-2004, 03:22 PM
  5. Just one Question?
    By Irish-Slasher in forum C++ Programming
    Replies: 6
    Last Post: 02-12-2002, 10:19 AM