UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

#1 2002-07-30 12:25 AM

HectorLasso
Administrator
From: Colombia
Registered: 2002-06-12
Posts: 353

Re: How to daemonize a server

I want to explain how to daemonize a process.

By 'daemonize' I mean to send the process to background dettaching it from the controlling tty, and making it child of the init process.

The code is fairly simple, it first fork()s a new process, changes the session ID and once again fork()s a new process:

void daemonize(void) {
   int fd;
   switch (fork()) {
       case 0:
          break;
       case -1:
          // Error
          fprintf(stderr, "Error demonizing (fork)! %d - %s\n", errno, strerror(errno));
          exit(0);
          break;
       default:
          _exit(0);
   }

   if (setsid() < 0) {
      fprintf(stderr, "Error demonizing (setsid)! %d - %s\n", errno, strerror(errno));
      exit(0);
   }
   switch (fork()) {
       case 0:
          break;
       case -1:
          // Error
          fprintf(stderr, "Error demonizing (fork2)! %d - %s\n", errno, strerror(errno));
          exit(0);
          break;
       default:
          _exit(0);
   }

   chdir("/");

   fd = open("/dev/null", O_RDONLY);
   if (fd != 0) {
      dup2(fd, 0);
      close(fd);
   }
   fd = open("/dev/null", O_WRONLY);
   if (fd != 1) {
      dup2(fd, 1);
      close(fd);
   }
   fd = open("/dev/null", O_WRONLY);
   if (fd != 2) {
      dup2(fd, 2);
      close(fd);
   }

}

Well, that is all you have to do in your process to make it daemon.

The double fork() thing is meant to make the process an orphan, in fact making it a child of the init process (usually PID 1).
The setsid() is used to create a new session, making the process a group leader, dettaching it from the controlling tty (a Ctrl-C won't help ; ) and making it a session leader (what this means just escapes my mind)

The chdir() call just changes the current path to "/". If you left the process in the old dir, then an "umount" could fail because the file system would be busy... (thanks Rob)
I also close stdin, stdout and sterr, opening /dev/null instead as Rob suggests. I'm not sure if this method is safe...

Enjoy

Offline

#2 2002-07-30 01:56 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,847
Website

Re: How to daemonize a server

You generally need to ignore SIGHUP as well, so that the session-leader
parent exit()'ing doesn't kill the newly fork()'d child...  Using _exit(), as
you do instead, may eliminate the need to do so; I'm not sure...

Other good things to do when daemonizing: chdir("/"), so you're not
tying up access to whatever dir you were run from (if, eg., it's on a
separately mounted partition); close stdin/stdout/stderr, and reopen
them to "/dev/null" (some leave them closed, but I think it's safer to
have them set to "/dev/null" just in case some rogue lib function
decides to start spitting junk to stdout/stderr)...

Offline

#3 2002-07-30 02:33 PM

HectorLasso
Administrator
From: Colombia
Registered: 2002-06-12
Posts: 353

Re: How to daemonize a server

Rob,

Thank you for your comments. You are completely right, and in fact, the code I have already does that, so I'll add those things later today.

Regards

Offline

#4 2002-08-30 07:55 AM

Uzume
Administrator
Registered: 2002-08-30
Posts: 186

Re: How to daemonize a server

It should be noted that a fork(2) after a sucessful call to setsid(2) will also orphan the session and thus ensure the daemon and all it descendants (unless they create a new session for themselves) can NEVER attain a controlling terminal.

Offline

#5 2002-09-01 08:15 AM

mlampkin
Administrator
From: Sol 3
Registered: 2002-06-12
Posts: 911
Website

Re: How to daemonize a server

The kid (if you read one of the previous lounge msgs) is in bed so I can write a bit...

A "session leader" is nothing more than a process who's group and id are equal...

So just cause I like typing... you do the first fork, kill the parent (who was the leader) and keep the child ~ which now has non-equal process group and id numbers...  Btw, when you call _exit for the parent (instead of exit ~ which would cause the children to be signaled under some conditions) you are assured that at that time, the child will become "owned" immediately by its original parent's parent, and quite often the core init process (if it were next in the hierarchy)...  if it hasn't dropped to init though, it could fall under another process that DOES have a controlling terminal...

Anyway... The inequality between process group and process id ensures (is required so) that the call to setsid will be sucessful (for the parent it would (nromally) fail since it has equivalent group / id numbers)...  once the setsid calls completes, the child now is the session leader (same group / proc numbers) and has  no controlling terminal since it has completely broken from whoever it's parent was after the first call to fork...

As for the second call to fork...  well,quite often it isn't necessary...  the deal is (correct me if I am wrong ~ the beer is kicking in) that some systems REQUIRE that a process must be a group lead to have a controlling terminal.. so by calling fork again, you are ~ now that you know there is no controlling terminal or process ~ assuring you are becoming a child of the init process which you KNOW has no terminal...  Also, since you did a setsid, when you fork ~ you are assured that the only place the child has to go when the parent _exit( )'s is to init...

Of course...  if someone wanted to be a butthead... I am fairly certain (never tried since there was no reason) that after doing all that,  a person COULD call setsid again to become a process / session leader and then get (at least) a psuedo-terminal attached via ioctl...

...and also... if someone really wanted to be odd (I've done it before)...  since you KNOW init is process 1...  instead of fork, setsid, fork... you can always do a while (getppid( ) != 1) { fork( ) etc. } ....  just to confuse folks...  it will eventually get you down to the init level...   you can even make the function recursive so you don't have to jump thru hoops to do your final (in the child) close on any open descriptors... ;-)

Oops, almost forgot...  personal preference...  I normally do a call of  sysconf(_SC_OPEN_MAX) and close EVERYTHING up to that limit... and if I get a ENOSYS (etc.) then I default (these days) to 1024... and just ignore any close( ) errors...  then do my stdin, stdout and sterr remaps if desired...

Yeah, I like typing...  it helps me figure out when I have had too much to drink... under about 40 words per minute and I call it quits...  lol.

Michael


"The only difference between me and a madman is that I'm not mad."

Salvador Dali (1904-1989)

Offline

#6 2002-09-08 06:56 AM

Uzume
Administrator
Registered: 2002-08-30
Posts: 186

Re: How to daemonize a server

The first fork()/_exit() pair will orphan the child making it be inherited by PID 1 (AKA init). This also guarantees it is NOT a group leader so a subsequent call to setsid() has a chance to suceed.

The second fork()/_exit() pair has has no real usefulness that I know of EXCEPT to orphan the session making it so the session cannot attain a controlling terminal.

This posted method is the new POSIX method which is different than the old BSD daemonization sheme (which I believe didn't have sessions but did have process groups and controlling terminals).

Offline

#7 2002-09-08 12:26 PM

mlampkin
Administrator
From: Sol 3
Registered: 2002-06-12
Posts: 911
Website

Re: How to daemonize a server

Agreed with the first with the add that the first fork and forces -exit (buff flush etc. associated with it) sets up for a guaranteed sucessful setsid ( ) call...

Side note though...

Think of the setsid( ) call as the "new" way to do thing (disassociate from the terminal) and the fork( ) call after it as redundancy to deal with the SVr4 (I think thats it ~ wish I had my lib here) stuff...     Under the latter, the second fork would do the disassociation (to avoid the condition  under some older  op sys, where setsid might in fact grab the old proc leader's terminal)... by doing both, you cover both situations without  harm...

....and considering setsid( )...


Second side note - someone (again) correct me if I am wrong... BUT... as far as I know there is no way to 100% disassociate a process to the point where it cannot regain a terminal of some sort...  the convolutions we go through when creating a daemon is to, to put it bluntly, nothing more than to add an extra layer of obfuscation i.e. its harder to GET a terminal in any fashion back... but it is not a guaranteed preventative measure...

As for exit (or _exit)  (I believe) the only guarantee is that iy will drop you to either the  "parent" process group or init... with no specification as to which (again, someone point me to the standards on this ~ I'm don't have access to about 90% of my stuff where I am at?) and its the setsid performs the "break" that assures the proc (or proc group)is "owned" by init...

Too early for this... lol.... must sleep and thing about it...





Michael


"The only difference between me and a madman is that I'm not mad."

Salvador Dali (1904-1989)

Offline

#8 2002-09-08 05:54 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,847
Website

Re: How to daemonize a server

I think the idea of completely disassociating from a controlling terminal
to such a degree is not really to make it impossible to regain a
controlling terminal if you really WANT to, but rather to make it so
that you can't gain one ACCIDENTALLY...  If you're a pgroup/session
leader, and you happen to open up a terminal device for whatever
reason, at least some systems will now make that your controlling
terminal, automatically...  By orphaning yourself to such an extent,
you are thwarting that auto-cterm behavior, but that's about it...  If
you really WANTED to get back a cterm, you surely could...

Offline

#9 2002-09-09 08:50 AM

Uzume
Administrator
Registered: 2002-08-30
Posts: 186

Re: How to daemonize a server

Offline

#10 2002-09-09 01:16 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,847
Website

Re: How to daemonize a server

I think what Michael was saying is that it DOESN'T really mean that
there is truly "no way", as you say...  After all, you can just call
setsid() again, to become a session leader, and then acquire a
cterm at will...  Doing this stuff doesn't prevent you from regaining
a cterm if you really WANT one; it just prevents you from accidentally
regaining one when you DON'T want one...  Which is what I said... ;-)

Offline

#11 2002-09-09 10:36 PM

mlampkin
Administrator
From: Sol 3
Registered: 2002-06-12
Posts: 911
Website

Re: How to daemonize a server

Oh my... someone quoting the standards to ME... lol ;-)

But anyway... I think I said all that already with the main caveat being that there is nothing in the spec saying a process / daemon could NOT call setsid( ) to become a group /  session leader and use ioctl to regain a controlling terminal... 


A bit of confusion may have resulted by my note / joke  about doing multiple calls to fork instead of using setsid (or setpgid) calls...  while meant as a joke since there are "modern" methods... here are a couple quick notes from the specs to "prove" I am not a complete lunatic...

"Thus, a process group may be orphaned by the termination of the last connecting parent process outside of the group or by the termination of the last direct descendant of the parent process"

...and...

"Upon the close of the last file descriptor in the system (whether or not it is in the current session) associated with the controlling terminal, it is unspecified whether all processes that had that terminal as their controlling terminal cease to have any controlling terminal."

What this means is that a fork and exit does NOT always guarantee that the child will be owned by init thought that is the typical result... which is (another) reason to call setsid... BUT...  a quirk of some (admittedly older) impls / systems was that there was an absolute limit to the number of descendents of a parent process the system would track which means doing enough forks / exits would get your to the point where the system did not recognize the child as a direct descendant of the start process and would eventually dump it to init...

Along the same lines, if the above works on a particular impl... and that impl ALSO does a complete disassociation of the controlling terminal on the close of all open descriptors associated with the terminal... then doing the multiple forks and finishing up with a close on those  descriptors DOES give you a daemon...


I do not recommend doing any of the above...  except to be odd... which is why I said " if someone wanted to be a butthead..." when describing it... and then whether it works / what happens depends on the particular OS impl...


Michael


"The only difference between me and a madman is that I'm not mad."

Salvador Dali (1904-1989)

Offline

#12 2002-09-09 11:40 PM

Uzume
Administrator
Registered: 2002-08-30
Posts: 186

Re: How to daemonize a server

Good!...smiles: The only interesting thing I might add to Loco's daemonization code (though really I would probably just stop after the setsid(), not do the double fork() and just not open any terminal devices) would be is to add a call to "setpgid(0, 0);" so that THAT process would be a group leader in an orphaned session and thus not be able to aquire a cterm via open()s even without O_NOCTTY and also could NOT sucessfully call setsid().

Of course one could always fork() away from that PID and start all over.

Offline

Board footer

Powered by FluxBB