From c3711902ce4e56bf8239854306692bce6e18cfb8 Mon Sep 17 00:00:00 2001 From: miker Date: Sat, 30 Jun 2007 03:14:36 +0000 Subject: [PATCH] Patch from Scott McKellar implementing cleaner daemonization; moved daemonizing code above worker forking in system boostrapping: 1. As long as I was in the neighborhood, I replaced the error messages going to stderr with messages going to the logging machinery. 2. I altered the comment just above daemonize(), because the original was inaccurate. This function does not change the process title. 3. Pedantic point: I captured the return value of fork() with a pid_t instead of an int. 4. After the fork, the parent process terminates with _exit() instead of exit(). That way it doesn't flush any buffers or close any files. It also doesn't call any functions registered with atexit(). In fact it doesn't do much of anything except get out of the way and let the child process take its place in every way. 5. The child process switches to the root directory, calls setsid() to create a new session, and freopens the three standard streams to /dev/null. I could have changed directories before the fork, or at any of several other places. I don't think it makes any difference. I could also have done the freopens before the fork, but if the fork failed, I might not have a way to report it (if the logging is going to stderr for some reason). Note that I'm not flushing any buffers, apart from the three standard streams. There's no need to. The child process inherits the file descriptors intact and can do with them whatever it likes. The parent may have died, but the estate doesn't have to go through probate. I didn't add any error checking for chdir(), setsid(), or freopen(). The first two are unlikely to fail, as is the freopen of stdin. The freopens of stderr and stdout could fail, if for example they are redirected to a full disk. I don't know how paranoid we need to be. For more details, see archives starting at http://list.georgialibraries.org/pipermail/open-ils-dev/2007-June/001378.html and also http://list.georgialibraries.org/pipermail/open-ils-dev/2007-June/001405.html git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@987 9efc2488-bf62-4759-914b-345cdb29e865 --- src/libopensrf/osrf_system.c | 42 ++++++++++++++++++------------------ src/libopensrf/utils.c | 32 ++++++++++++++++++--------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/libopensrf/osrf_system.c b/src/libopensrf/osrf_system.c index c378b7b..e5596dd 100644 --- a/src/libopensrf/osrf_system.c +++ b/src/libopensrf/osrf_system.c @@ -79,7 +79,12 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { hostname, configfile ); return -1; } - + + /** daemonize me **/ + /* background and let our children do their thing */ + /* NOTE: This has been moved from below the 'if (apps)' block below ... move it back if things go crazy */ + daemonize(); + jsonObject* apps = osrf_settings_host_value_object("/activeapps/appname"); osrfStringArray* arr = osrfNewStringArray(8); @@ -122,7 +127,7 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { } else { - fprintf(stderr, " * Running application %s\n", appname); + osrfLogError( OSRF_LOG_MARK, " * Running application %s\n", appname); if( osrfAppRegisterApplication( appname, libfile ) == 0 ) osrf_prefork_run(appname); @@ -131,27 +136,22 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { } } // language == c } + } // should we do something if there are no apps? does the wait(NULL) below do that for us? + + while(1) { + errno = 0; + pid_t pid = wait(NULL); + if(-1 == pid) { + if(errno == ECHILD) + osrfLogError(OSRF_LOG_MARK, "We have no more live services... exiting"); + else + osrfLogError(OSRF_LOG_MARK, "Exiting top-level system loop with error: %s", strerror(errno)); + break; + } else { + osrfLogError(OSRF_LOG_MARK, "We lost a top-level service process with PID %ld", pid); + } } - /** daemonize me **/ - - /* background and let our children do their thing */ - daemonize(); - while(1) { - errno = 0; - pid_t pid = wait(NULL); - if(-1 == pid) { - if(errno == ECHILD) - osrfLogError(OSRF_LOG_MARK, "We have no more live services... exiting"); - else - osrfLogError(OSRF_LOG_MARK, "Exiting top-level system loop with error: %s", strerror(errno)); - break; - } else { - osrfLogError(OSRF_LOG_MARK, "We lost a top-level service process with PID %ld", pid); - } - } - - return 0; } diff --git a/src/libopensrf/utils.c b/src/libopensrf/utils.c index 07ed9a2..908145b 100644 --- a/src/libopensrf/utils.c +++ b/src/libopensrf/utils.c @@ -13,12 +13,13 @@ GNU General Public License for more details. */ #include +#include #include inline void* safe_malloc( int size ) { void* ptr = (void*) malloc( size ); if( ptr == NULL ) { - perror("safe_malloc(): Out of Memory" ); + osrfLogError( OSRF_LOG_MARK, "Out of Memory" ); exit(99); } memset( ptr, 0, size ); @@ -189,7 +190,7 @@ int buffer_add(growing_buffer* gb, char* data) { } if( gb->size > BUFFER_MAX_SIZE ) { - fprintf(stderr, "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE ); + osrfLogError( OSRF_LOG_MARK, "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE ); buffer_free( gb ); return 0; } @@ -366,20 +367,34 @@ char* uescape( const char* string, int size, int full_escape ) { } -// A function to turn a process into a daemon and set it's process name in ps/top +// A function to turn a process into a daemon int daemonize() { - int f = fork(); + pid_t f = fork(); if (f == -1) { - perror("Failed to fork!"); + osrfLogError( OSRF_LOG_MARK, "Failed to fork!" ); return -1; } else if (f == 0) { // We're in the child now... + + // Change directories. Otherwise whatever directory + // we're in couldn't be deleted until the program + // terminated -- possibly causing some inconvenience. + chdir( "/" ); + + /* create new session */ setsid(); + + // Now that we're no longer attached to a terminal, + // we don't want any traffic on the standard streams + freopen( "/dev/null", "r", stdin ); + freopen( "/dev/null", "w", stdout ); + freopen( "/dev/null", "w", stderr ); + return 0; } else { // We're in the parent... - exit(0); + _exit(0); } } @@ -406,10 +421,7 @@ char* file_to_string(const char* filename) { FILE* file = fopen(filename, "r"); if(!file) { - int l = strlen(filename) + 64; - char b[l]; - snprintf(b,l,"Unable to open file [%s] in file_to_string()", filename); - perror(b); + osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename ); return NULL; } -- 2.43.2