Writing daemons
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4 ry. .ibu cy. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
/* for signal, SIG_ERR, SIGHUP, and SIGTERM */#include <signal.h>/* for exit */#include <stdlib.h>/* for daemon and sleep */#include <unistd.h>void sighup(int code) { /* This is normally used for "restart the daemon" (re-read the configuration files and such) */}void sigterm(int code) { /* Terminate the daemon after we clean up the process */ exit(0);}int main(int argc, char *argv[]) { if(signal(SIGHUP, sighup) == SIG_ERR) return 1; if(signal(SIGTERM, sigterm) == SIG_ERR) return 2; if(daemon(0, 0) != 0) return 3; /* Do daemon stuff (infinite loop is merely filler) */ for( ; ; ) sleep(1); return 0;}
Not every unix provides a daemon function, so here's an example daemon function. Also, this allows you to see what it does. (Once again, I wrote this right now, so we'll hope I didn't make any mistakes.):
/* For O_RDWR */#include <fcntl.h>/* For exit */#include <stdlib.h>/* For chdir, close, fork, open, and STD* stream macros */#include <unistd.h>#ifndef STDIN #define STDIN 0#endif#ifndef STDOUT #define STDOUT 1#endif#ifndef STDERR #define STDERR 2#endifint daemon(int nochdir, int noclose) { switch(fork()) { case -1: /* parent, error */ return -1; case 0: /* child */ break; default: /* parent */ exit(0); break; } /* change the current working directory to root */ if(!nochdir) if(chdir("/") != 0) return -1; /* redirect the standard streams to /dev/null */ if(!noclose) { int devnull = open("/dev/null", O_RDWR, 0); if(devnull == -1) return -1; close(STDIN); dup(devnull); close(STDOUT); dup(devnull); close(STDERR); dup(devnull); } return 0;}
Edit: some more comments and fixing a mistake (two times now, that'll teach me not to test the code I post better ).
[edited by - Null and Void on October 4, 2003 8:50:50 PM]
And daemons typically do a double fork() to detach themselves from the tty that started them.
[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
quote:
Original post by Fruny
Use sigaction() to register your signal handlers and not the old signal(), which is flawed.
And daemons typically do a double fork() to detach themselves from the tty that started them.
A double fork()? How does that work? I would have thought you just ended up with a 3-level tree of processes, with the tty at the root...
Actually, checking the man page for fork(), I don''t understand how it works at all. It would seem that calling fork() once will create a second instance of the program - but wouldn''t that second instance then just go on to call fork() again, ad infinitum?
And I take it that sigaction() is as standard as signal(), i.e. it''ll be in my headers?
Null and Void, I can''t see your code right now (browser bug) but from what I can tell from the HTML source it looks useful. I''ll look at it tomorrow when I can get to a machine with a decent browser.
Superpig
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4
ry. .ibu cy. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
the double fork idea is unnecessary. pointless, even.
only thing that may be missing from the custom daemon is setsid().
quote:
W.R. Stevens, Advanced Unix Programming, 13.3.2 p 417
Under SVR4, some people recommend calling fork again [after setsid] and having the parent terminate. The second child continues as the daemon. This guarantees that the daemon is not a session leader, which prevents it from acquiring a controlling terminal under the SVR4 rules. Alternatively, to avoid acquiring a controlling terminal be sure to specify O_NOCTTY whenever opening a terminal device.
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int daemon_init(){ pid_t pid = fork(); if( pid < 0 ) return -1 // failed else if( pid != 0 ) exit(0); // parent terminates // child continues setsid(); // create new session pid = fork(); if( pid < 0 ) return -1 // failed else if( pid != 0 ) exit(0); // parent terminates chdir("/"); // not doing it could prevent filesystems to be // unmounted at reboot time, since the daemon // would stay on them. umask(0); // don't inherit the file creation mask. // // Close any open file descriptor. // return 0;}
[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
[edited by - Fruny on October 4, 2003 9:09:14 PM]
quote:
Original post by superpig
It would seem that calling fork() once will create a second instance of the program - but wouldn''t that second instance then just go on to call fork() again, ad infinitum?
That doesn''t happen because execution continues after the call to
fork
.BTW, it''s a good idea to make the daemonization (at least the
fork
ing part) optional - controlled by a command line option, for example. This will let another process control and supervise the daemon and may also make debugging easier.
quote:
Original post by spockquote:
Original post by superpig
It would seem that calling fork() once will create a second instance of the program - but wouldn''t that second instance then just go on to call fork() again, ad infinitum?
That doesn''t happen because execution continues after the call tofork
.
Ah! That''s what I''d missed. I thought the process was restarting.
Thanks, everyone. If I do manage to build a ''service framework,'' I''ll probably make it available for download, if anyone wants it.
Superpig
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4
ry. .ibu cy. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
quote:That''d be really handy, since I want to embark on a similar project very soon and would just end up doing the same thing myself.
Original post by superpig
Thanks, everyone. If I do manage to build a ''service framework,'' I''ll probably make it available for download, if anyone wants it.
"The sun is the same in a relative way,
but you''re older"
--Pink Floyd