Author: grothoff Date: 2006-07-29 00:56:57 -0700 (Sat, 29 Jul 2006) New Revision: 3152
Added: GNUnet/src/util/os/console.c GNUnet/src/util/os/user.c GNUnet/src/util/threads/signal.c Modified: GNUnet/src/include/core.h GNUnet/src/include/gnunet_util_getopt.h GNUnet/src/include/gnunet_util_os.h GNUnet/src/include/gnunet_util_threads.h GNUnet/src/server/core.c GNUnet/src/server/gnunetd.c GNUnet/src/server/handler.c GNUnet/src/server/handler.h GNUnet/src/server/startup.c GNUnet/src/server/startup.h GNUnet/src/server/tcpserver.c GNUnet/src/server/version.c GNUnet/src/server/version.h GNUnet/src/util/os/Makefile.am GNUnet/src/util/os/osconfig.c GNUnet/src/util/threads/Makefile.am GNUnet/src/util/threads/shutdown.c Log: moving more code into util Modified: GNUnet/src/include/core.h =================================================================== --- GNUnet/src/include/core.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/include/core.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -38,21 +38,25 @@ /** * Initialize the CORE's globals. */ -void initCore(); +int initCore(struct GE_Context * ectx, + struct GC_Configuration * cfg, + struct CronManager * cron, + struct LoadMonitor * monitor); + /** * Shutdown the CORE modules (also shuts down all * application modules). */ -void doneCore(); +void doneCore(void); void * requestService(const char * pos); int releaseService(void * service); -void unloadApplicationModules(); +void unloadApplicationModules(void); -void loadApplicationModules(); +void loadApplicationModules(void); Modified: GNUnet/src/include/gnunet_util_getopt.h =================================================================== --- GNUnet/src/include/gnunet_util_getopt.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/include/gnunet_util_getopt.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -181,7 +181,7 @@ * Marker to end the list of options. */ #define COMMAND_LINE_OPTION_END \ - { '\0', NULL, NULL, 0, NULL, NULL } + { '\0', NULL, NULL, NULL, 0, NULL, NULL } /** * Parse the command line. Modified: GNUnet/src/include/gnunet_util_os.h =================================================================== --- GNUnet/src/include/gnunet_util_os.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/include/gnunet_util_os.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -213,6 +213,14 @@ const char * group); /** + * Change current process to run as the given + * user + * @return OK on success, SYSERR on error + */ +int os_change_user(struct GE_Context * ectx, + const char * user); + +/** * Get the current CPU load. * @param ectx for error reporting * @param cfg to determine acceptable load level (LOAD::MAXCPULOAD) @@ -270,6 +278,27 @@ struct GC_Configuration * cfg, enum InstallPathKind dirkind); + + +/** + * Fork and start a new session to go into the background + * in the way a good deamon should. + * + * @param filedes pointer to an array of 2 file descriptors + * to complete the detachment protocol (handshake) + */ +int os_terminal_detach(struct GE_Context * ectx, + int * filedes); + +/** + * Complete the handshake of detaching from the terminal. + * @param success use NO for error, YES for successful start + */ +void os_terminal_detach_complete(struct GE_Context * ectx, + int * filedes, + int success); + + #if 0 /* keep Emacsens' auto-indent happy */ { #endif Modified: GNUnet/src/include/gnunet_util_threads.h =================================================================== --- GNUnet/src/include/gnunet_util_threads.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/include/gnunet_util_threads.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -187,6 +187,29 @@ */ void GNUNET_SHUTDOWN_WAITFOR(void); +struct SignalHandlerContext; + +/** + * A signal handler. Since different OSes have different signatures + * for their handlers, the API only gives the most restrictive + * signature -- no arguments, no return value. Note that this will + * work even if the OS expects a function with arguments. However, + * the implementation must guarantee that this handler is not called + * for signals other than the one that it has been registered for. + */ +typedef void (*SignalHandler)(void); + +/** + * Install a signal handler that will be run if the + * given signal is received. + */ +struct SignalHandlerContext * signal_handler_install(int signal, + SignalHandler handler); + +void signal_handler_uninstall(int signal, + SignalHandler handler, + struct SignalHandlerContext * ctx); + #if 0 /* keep Emacsens' auto-indent happy */ { #endif Modified: GNUnet/src/server/core.c =================================================================== --- GNUnet/src/server/core.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/core.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -523,8 +523,21 @@ /** * Initialize the CORE's globals. */ -void initCore() { - initTCPServer(); +int initCore(struct GE_Context * ectx, + struct GC_Configuration * cfg, + struct CronManager * cron, + struct LoadMonitor * monitor) { + identity = requestService("identity"); + if (identity == NULL) + return SYSERR; + identity->getPeerIdentity(identity->getPublicPrivateKey(), + &myIdentity); + initTCPServer(ectx, + cfg); + applicationCore.ectx = ectx; + applicationCore.cfg = cfg; + applicationCore.load_monitor = monitor; + applicationCore.cron = cron; applicationCore.version = 0; applicationCore.myIdentity = &myIdentity; /* core.c */ applicationCore.loadApplicationModule = &loadApplicationModule; /* core.c */ @@ -569,13 +582,8 @@ applicationCore.getSlotCount = &getSlotCount; /* connection.c */ applicationCore.isSlotUsed = &isSlotUsed; /* connection.c */ applicationCore.getLastActivityOf = &getLastActivityOf; /* connection.c */ - - identity = requestService("identity"); - if (identity == NULL) - errexit(_("FATAL: Identity plugin not found!\n")); - identity->getPeerIdentity(identity->getPublicPrivateKey(), - &myIdentity); - initHandler(); + initHandler(ectx); + return OK; } /** Modified: GNUnet/src/server/gnunetd.c =================================================================== --- GNUnet/src/server/gnunetd.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/gnunetd.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -30,7 +30,9 @@ #include "gnunet_util.h" #include "gnunet_util_config_impl.h" #include "gnunet_util_error_loggers.h" +#include "gnunet_util_cron.h" #include "gnunet_core.h" +#include "gnunet_directories.h" #include "core.h" #include "connection.h" #include "tcpserver.h" @@ -38,104 +40,136 @@ #include "startup.h" #include "version.h" +static struct GC_Configuration * cfg; + +static struct CronManager * cron; + /** - * The main method of gnunetd. And here is how it works: - * <ol> - * <li>detach from tty, initialize all coresystems - * <li>a) start core-services - * b) initialize application services and download hostlist - * <li>wait for semaphore to signal shutdown - * <li>shutdown all services (in roughly inverse order) - * <li>exit - * </ol> + * Cron job that triggers re-reading of the configuration. */ -void gnunet_main() { - int filedes[2]; /* pipe between client and parent */ +static void reread_config_helper(void * unused) { + char * filename; + + filename = NULL; + if (-1 == GC_get_configuration_value_string(cfg, + "GNUNET", + "CONFIGFILE", + DEFAULT_DAEMON_CONFIG_FILE, + &filename)) { + GE_BREAK(NULL, 0); /* should never happen */ + return; + } + GE_ASSERT(NULL, filename != NULL); + GC_parse_configuration(cfg, + filename); + FREE(filename); +} - /* init 0: change user */ -#ifndef MINGW - char *user = getConfigurationString("GNUNETD", "USER"); - if (user && strlen(user)) - changeUser(user); - FREENONNULL(user); -#endif +/** + * Signal handler for SIGHUP. + * Re-reads the configuration file. + */ +static void reread_config() { + cron_add_job(cron, + &reread_config_helper, + 1 * cronSECONDS, + 0, + NULL); +} - /* init 1: version management for GNUnet core, - essentially forces running gnunet-update - whenever the version OR configuration changes. */ - if (OK != checkUpToDate()) - errexit(_("Configuration or GNUnet version changed. You need to run `%s'!\n"), - "gnunet-update"); - - /* init 2: become deamon, initialize core subsystems */ - if (NO == debug_flag()) - detachFromTerminal(filedes); - +/** + * Park main thread until shutdown has been signaled. + */ +static void waitForSignalHandler(struct GE_Context * ectx) { GE_LOG(ectx, GE_INFO | GE_USER | GE_REQUEST, - _("`%s' starting\n"), - "gnunetd"); - - initCore(); - initConnection(); /* requires core, starts transports! */ - loadApplicationModules(); /* still single-threaded! */ - - /* initialize signal handler (CTRL-C / SIGTERM) */ - if (NO == debug_flag()) - detachFromTerminalComplete(filedes); - writePIDFile(); - - startCron(); - enableCoreProcessing(); - - /* init 4: wait for shutdown */ - /* wait for SIGTERM, SIGTERM will set - doShutdown to YES and send this thread - a SIGUSR1 which will wake us up from the - sleep */ - initSignalHandlers(); - GE_LOG(ectx, - GE_INFO | GE_USER | GE_REQUEST, _("`%s' startup complete.\n"), - "gnunetd"); - - waitForSignalHandler(); + "gnunetd"); + GNUNET_SHUTDOWN_WAITFOR(); GE_LOG(ectx, GE_INFO | GE_USER | GE_REQUEST, _("`%s' is shutting down.\n"), "gnunetd"); - - /* init 5: shutdown */ - disableCoreProcessing(); /* calls on applications! */ - stopCron(); /* avoid concurrency! */ - stopTCPServer(); /* calls on applications! */ - unloadApplicationModules(); /* requires connection+tcpserver+handler */ +} - doneConnection(); /* requires core, stops transports! */ +/** + * The main method of gnunetd. + */ +int gnunet_main(struct GE_Context * ectx) { + struct LoadMonitor * mon; + struct SignalHandlerContext * shc_hup; + int filedes[2]; /* pipe between client and parent */ + + if (NO == debug_flag()) { + if (OK != detachFromTerminal(ectx, + filedes)) + return SYSERR; + } + mon = os_network_monitor_create(ectx, + cfg); + cron = cron_create(ectx); + shc_hup = signal_handler_install(SIGHUP, &reread_config); + initCore(ectx, + cfg, + cron, + mon); + initConnection(); + loadApplicationModules(); + writePIDFile(ectx, cfg); + if (NO == debug_flag()) + detachFromTerminalComplete(ectx, + filedes); + cron_start(cron); + enableCoreProcessing(); + waitForSignalHandler(ectx); + disableCoreProcessing(); + cron_stop(cron); + deletePIDFile(ectx, cfg); + stopTCPServer(); + unloadApplicationModules(); + doneConnection(); doneCore(); - - /* init 6: goodbye */ - deletePIDFile(); - doneSignalHandlers(); + os_network_monitor_destroy(mon); + signal_handler_uninstall(SIGHUP, + &reread_config, + shc_hup); + cron_destroy(cron); + return OK; } -#ifdef MINGW /** - * Main method of the windows service + * All gnunetd command line options */ -void WINAPI ServiceMain(DWORD argc, LPSTR *argv) { - win_service_main(gnunet_main); -} +static struct CommandLineOption gnunetdOptions[] = { + COMMAND_LINE_OPTION_CFG_FILE, /* -c */ + { '@', "win-service", NULL, gettext_noop(""), 0, + &gnunet_getopt_configure_set_option, "GNUNETD:WINSERVICE" }, + { 'd', "debug", NULL, + gettext_noop("run in debug mode; gnunetd will " + "not daemonize and error messages will " + "be written to stderr instead of a logfile"), + 0, &gnunet_getopt_configure_set_option, "GNUNETD:DEBUG" }, + COMMAND_LINE_OPTION_HELP(_("Starts the gnunetd daemon.")), /* -h */ + COMMAND_LINE_OPTION_HOSTNAME, /* -H */ + COMMAND_LINE_OPTION_LOGGING, /* -L */ + { 'p', "padding", "PADDING", gettext_noop(""), 1, + &gnunet_getopt_configure_set_option, "GNUNETD-EXPERIMENTAL:PADDING" }, +#ifndef MINGW + { 'u', "user", "USERNAME", gettext_noop(""), 1, + &gnunet_getopt_configure_set_option, "GNUNETD:USERNAME" }, #endif + COMMAND_LINE_OPTION_VERSION(PACKAGE_VERSION), /* -v */ + COMMAND_LINE_OPTION_END, +}; /** * Initialize util (parse command line, options) and * call the main routine. */ int main(int argc, - char * argv[]) { + const char * argv[]) { + char * user; int ret; - struct GC_Configuration * cfg; struct GE_Context * ectx; if ( (4 != sizeof(MESSAGE_HEADER)) || @@ -144,7 +178,6 @@ "Sorry, your C compiler did not properly align the C structs. Aborting.\n"); return -1; } - ectx = GE_create_context_stderr(NO, GE_WARNING | GE_ERROR | GE_FATAL | GE_USER | GE_ADMIN | GE_DEVELOPER | @@ -152,31 +185,46 @@ GE_setDefaultContext(ectx); cfg = GC_create_C_impl(); GE_ASSERT(ectx, cfg != NULL); - /* init 1: get options and basic services up */ - ret = gnunet_parse_options("gnunetd", - ectx, - cfg, - &gnunetdOptions, - (unsigned int) argc, - argv); - if (ret == -1) { + if (-1 == gnunet_parse_options("gnunetd", + ectx, + cfg, + gnunetdOptions, + (unsigned int) argc, + argv)) { GC_free(cfg); GE_free_context(ectx); return -1; } - /* now: patch up default context according to config! */ - -#ifdef MINGW - if (win_service()) { - SERVICE_TABLE_ENTRY DispatchTable[] = - {{"GNUnet", ServiceMain}, {NULL, NULL}}; - GNStartServiceCtrlDispatcher(DispatchTable); - - return 0; - } else -#endif - gnunet_main(); - + user = NULL; + if (0 == GC_get_configuration_value_string(cfg, + "GNUNETD", + "USER", + NULL, + &user)) { + if (OK != os_change_user(ectx, + user)) { + GC_free(cfg); + GE_free_context(ectx); + FREE(user); + return 1; + } + FREE(user); + } + if (OK != checkUpToDate(ectx, + cfg)) { + GE_LOG(ectx, + GE_USER | GE_FATAL | GE_IMMEDIATE, + _("Configuration or GNUnet version changed. You need to run `%s'!\n"), + "gnunet-update"); + GC_free(cfg); + GE_free_context(ectx); + return 1; + } + ret = gnunet_main(ectx); + GC_free(cfg); + GE_free_context(ectx); + if (ret != OK) + return 1; return 0; } Modified: GNUnet/src/server/handler.c =================================================================== --- GNUnet/src/server/handler.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/handler.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -627,7 +627,8 @@ /** * Initialize message handling module. */ -void initHandler() { +void initHandler(struct GE_Context * e) { + ectx = e; handlerLock = MUTEX_CREATE(NO); transport = requestService("transport"); GE_ASSERT(ectx, transport != NULL); Modified: GNUnet/src/server/handler.h =================================================================== --- GNUnet/src/server/handler.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/handler.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -33,7 +33,7 @@ * Initialize message handling module (make ready to register * handlers). */ -void initHandler(); +void initHandler(struct GE_Context * e); /** * Shutdown message handling module. Modified: GNUnet/src/server/startup.c =================================================================== --- GNUnet/src/server/startup.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/startup.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -23,11 +23,7 @@ * @brief insignificant gnunetd helper methods * * Helper methods for the startup of gnunetd: - * - install signal handling - * - system checks on startup * - PID file handling - * - detaching from terminal - * - command line parsing * * @author Christian Grothoff */ @@ -40,545 +36,63 @@ #include "core.h" #include "startup.h" - -/** - * This flag is set if gnunetd is not (to be) detached from the - * console. - */ -static int debug_flag_ = NO; - -/** - * This flag is set if gnunetd was started as windows service - */ -static int win_service_ = NO; - -int debug_flag() { - return debug_flag_; +static char * getPIDFile(struct GC_Configuration * cfg) { + char * pif; + + if (0 != GC_get_configuration_value_string(cfg, + "GNUNETD", + "PIDFILE", + NULL, + &pif)) + return NULL; + return pif; } -int win_service() { - return win_service_; -} - - -#ifdef MINGW - /** - * Windows service information - */ - static SERVICE_STATUS theServiceStatus; - static SERVICE_STATUS_HANDLE hService; -#endif - /** - * This flag is set if gnunetd is shutting down. - */ -static struct SEMAPHORE * doShutdown; - -/* ************* SIGNAL HANDLING *********** */ - -/** - * Cron job that triggers re-reading of the configuration. - */ -static void reread_config_helper(void * unused) { - LOG(LOG_DEBUG, - "Re-reading configuration file.\n"); - readConfiguration(); - triggerGlobalConfigurationRefresh(); - LOG(LOG_DEBUG, - "New configuration active.\n"); -} - -/** - * Signal handler for SIGHUP. - * Re-reads the configuration file. - */ -static void reread_config(int signum) { - addCronJob(&reread_config_helper, - 1 * cronSECONDS, - 0, - NULL); -} - -#ifdef MINGW -static void shutdown_gnunetd(int signum); - -BOOL WINAPI win_shutdown_gnunetd(DWORD dwCtrlType) -{ - switch(dwCtrlType) - { - case CTRL_C_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_SHUTDOWN_EVENT: - case CTRL_LOGOFF_EVENT: - case SERVICE_CONTROL_STOP: - shutdown_gnunetd(dwCtrlType); - } - - return TRUE; -} - -/** - * This function is called from the Windows Service Control Manager - * when a service has to shutdown - */ -void WINAPI ServiceCtrlHandler(DWORD dwOpcode) { - if (dwOpcode == SERVICE_CONTROL_STOP) - win_shutdown_gnunetd(SERVICE_CONTROL_STOP); -} - -/** - * called by gnunetd.c::ServiceMain() - */ -void win_service_main(void (*gn_main)()) { - memset(&theServiceStatus, 0, sizeof(theServiceStatus)); - theServiceStatus.dwServiceType = SERVICE_WIN32; - theServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - theServiceStatus.dwCurrentState = SERVICE_RUNNING; - - hService = GNRegisterServiceCtrlHandler("GNUnet", ServiceCtrlHandler); - if (! hService) - return; - - GNSetServiceStatus(hService, &theServiceStatus); - - gn_main(); - - theServiceStatus.dwCurrentState = SERVICE_STOPPED; - GNSetServiceStatus(hService, &theServiceStatus); -} -#endif - -/** - * Try a propper shutdown of gnunetd. - */ -static void shutdown_gnunetd(int signum) { - -#ifdef MINGW -if (win_service()) -{ - /* If GNUnet runs as service, only the - Service Control Manager is allowed - to kill us. */ - if (signum != SERVICE_CONTROL_STOP) - { - SERVICE_STATUS theStat; - - /* Init proper shutdown through the SCM */ - if (GNControlService(hService, SERVICE_CONTROL_STOP, &theStat)) - { - /* Success */ - - /* The Service Control Manager will call - gnunetd.c::ServiceCtrlHandler(), which calls - this function again. We then stop the gnunetd. */ - return; - } - /* We weren't able to tell the SCM to stop the service, - but we don't care. - Just shut the gnunetd process down. */ - } - - /* Acknowledge the shutdown request */ - theServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; - GNSetServiceStatus(hService, &theServiceStatus); -} -#endif - - SEMAPHORE_UP(doShutdown); -} - -static int shutdownHandler(ClientHandle client, - const CS_MESSAGE_HEADER * msg) { - int ret; - - if (ntohs(msg->size) != sizeof(CS_MESSAGE_HEADER)) { - LOG(LOG_WARNING, - _("The `%s' request received from client is malformed.\n"), - "shutdown"); - return SYSERR; - } - LOG(LOG_INFO, - "shutdown request accepted from client\n"); - - if (SYSERR == unregisterCSHandler(CS_PROTO_SHUTDOWN_REQUEST, - &shutdownHandler)) - GNUNET_ASSERT(0); - ret = sendTCPResultToClient(client, - OK); - shutdown_gnunetd(0); - return ret; -} - -/** - * Initialize signal handlers - */ -void initSignalHandlers() { -#ifndef MINGW - struct sigaction sig; - struct sigaction oldsig; -#endif - - doShutdown = SEMAPHORE_CREATE(0); - -#ifndef MINGW - sig.sa_handler = &shutdown_gnunetd; - sigemptyset(&sig.sa_mask); -#ifdef SA_INTERRUPT - sig.sa_flags = SA_INTERRUPT; /* SunOS */ -#else - sig.sa_flags = SA_RESTART; -#endif - sigaction(SIGINT, &sig, &oldsig); - sigaction(SIGTERM, &sig, &oldsig); - sigaction(SIGQUIT, &sig, &oldsig); - - sig.sa_handler = &reread_config; - sigaction(SIGHUP, &sig, &oldsig); -#else - SetConsoleCtrlHandler(&win_shutdown_gnunetd, TRUE); -#endif - - if (SYSERR == registerCSHandler(CS_PROTO_SHUTDOWN_REQUEST, - &shutdownHandler)) - GE_ASSERT(ectx, 0); -} - -void doneSignalHandlers() { -#ifndef MINGW - struct sigaction sig; - struct sigaction oldsig; - - sig.sa_handler = SIG_DFL; - sigemptyset(&sig.sa_mask); -#ifdef SA_INTERRUPT - sig.sa_flags = SA_INTERRUPT; /* SunOS */ -#else - sig.sa_flags = SA_RESTART; -#endif - sigaction(SIGINT, &sig, &oldsig); - sigaction(SIGTERM, &sig, &oldsig); - sigaction(SIGQUIT, &sig, &oldsig); -#else - SetConsoleCtrlHandler(&win_shutdown_gnunetd, TRUE); -#endif - SEMAPHORE_DESTROY(doShutdown); - doShutdown = NULL; -} - -/** - * Cron job to timeout gnunetd. - */ -static void semaphore_up(void * sem) { - SEMAPHORE_UP((Semaphore*)sem); -} - -void waitForSignalHandler() { - int valgrind; - - /* mechanism to stop gnunetd after a certain - time without a signal -- to debug with valgrind*/ - valgrind = getConfigurationInt("GNUNETD", - "VALGRIND"); - if (valgrind > 0) - addCronJob(&semaphore_up, - valgrind * cronSECONDS, - 0, - doShutdown); -#if 0 - /* If Valgrind is used to debug memory leaks, some sort of mechanism - is needed to make gnunetd exit without using any signal -IW*/ - FILE *fp; - - while(1) { - fp=FOPEN("/tmp/quitgn", "r"); - if(fp) { - fprintf(stderr, "QUITTING...\n"); - fclose(fp); - return; - } - sleep(1); - } -#endif - SEMAPHORE_DOWN(doShutdown); - if (valgrind > 0) - delCronJob(&semaphore_up, - 0, - doShutdown); - -} - -static char * getPIDFile() { - return getFileName("GNUNETD", - "PIDFILE", - _("You must specify a name for the PID file in section" - " `%s' under `%s'.\n")); -} - -/** * Write our process ID to the pid file. */ -void writePIDFile() { +void writePIDFile(struct GE_Context * ectx, + struct GC_Configuration * cfg) { FILE * pidfd; char * pif; - pif = getPIDFile(); + pif = getPIDFile(cfg); + if (pif == NULL) + return; /* no PID file */ pidfd = FOPEN(pif, "w"); if (pidfd == NULL) { - LOG(LOG_WARNING, - _("Could not write PID to file `%s': %s.\n"), - pif, - STRERROR(errno)); - } else { - fprintf(pidfd, "%u", (unsigned int) getpid()); - fclose(pidfd); + GE_LOG_STRERROR_FILE(ectx, + GE_WARNING | GE_ADMIN | GE_BULK, + "fopen", + pif); + return; } + if (0 > FPRINTF(pidfd, + "%u", + (unsigned int) getpid())) + GE_LOG_STRERROR_FILE(ectx, + GE_WARNING | GE_ADMIN | GE_BULK, + "fprintf", + pif); + if (0 != FCLOSE(pidfd)) + GE_LOG_STRERROR_FILE(ectx, + GE_WARNING | GE_ADMIN | GE_BULK, + "fclose", + pif); FREE(pif); } -void deletePIDFile() { - char * pif = getPIDFile(); - UNLINK(pif); +void deletePIDFile(struct GE_Context * ectx, + struct GC_Configuration * cfg) { + char * pif = getPIDFile(cfg); + if (pif == NULL) + return; /* no PID file */ + if (0 != UNLINK(pif)) + GE_LOG_STRERROR_FILE(ectx, + GE_WARNING | GE_ADMIN | GE_BULK, + "unlink", + pif); FREE(pif); } -/* ************** DETACHING FROM TERMAINAL ************** */ - -/** - * Fork and start a new session to go into the background - * in the way a good deamon should. - * - * @param filedes pointer to an array of 2 file descriptors - * to complete the detachment protocol (handshake) - */ -void detachFromTerminal(int * filedes) { -#ifndef MINGW - pid_t pid; - int nullfd; -#endif - - /* Don't hold the wrong FS mounted */ - if (CHDIR("/") < 0) { - perror("chdir"); - exit(1); - } - -#ifndef MINGW - PIPE(filedes); - pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - if (pid) { /* Parent */ - int ok; - char c; - - closefile(filedes[1]); /* we only read */ - ok = SYSERR; - while (0 < READ(filedes[0], &c, sizeof(char))) { - if (c == '.') - ok = OK; - } - fflush(stdout); - if (ok == OK) - exit(0); - else - exit(1); /* child reported error */ - } - closefile(filedes[0]); /* we only write */ - nullfd = fileopen("/dev/null", - O_CREAT | O_RDWR | O_APPEND); - if (nullfd < 0) { - perror("/dev/null"); - exit(1); - } - /* child - close fds linking to invoking terminal, but - * close usual incoming fds, but redirect them somewhere - * useful so the fds don't get reallocated elsewhere. - */ - if (dup2(nullfd,0) < 0 || - dup2(nullfd,1) < 0 || - dup2(nullfd,2) < 0) { - perror("dup2"); /* Should never happen */ - exit(1); - } - pid = setsid(); /* Detach from controlling terminal */ -#else - FreeConsole(); -#endif -} - -void detachFromTerminalComplete(int * filedes) { -#ifndef MINGW - char c = '.'; - WRITE(filedes[1], &c, sizeof(char)); /* signal success */ - closefile(filedes[1]); -#endif -} - -/* ****************** COMMAND LINE PARSING ********************* */ - -static void printDot(void * unused) { - LOG(LOG_DEBUG, "."); -} - -/** - * Print a list of the options we offer. - */ -static void printhelp() { - static Help help[] = { - HELP_CONFIG, - { 'd', "debug", NULL, - gettext_noop("run in debug mode; gnunetd will " - "not daemonize and error messages will " - "be written to stderr instead of a logfile") }, - HELP_HELP, - HELP_LOGLEVEL, -#ifndef MINGW /* not supported */ - { 'u', "user", "LOGIN", - gettext_noop("run as user LOGIN") }, -#endif - HELP_VERSION, - HELP_END, - }; - formatHelp("gnunetd [OPTIONS]", - _("Starts the gnunetd daemon."), - help); -} - -#ifndef MINGW -/** - * @brief Change user ID - */ -void changeUser(const char *user) { - struct passwd * pws; - - pws = getpwnam(user); - if(pws == NULL) { - LOG(LOG_WARNING, - _("User `%s' not known, cannot change UID to it.\n"), user); - return; - } - if((0 != setgid(pws->pw_gid)) || - (0 != setegid(pws->pw_gid)) || - (0 != setuid(pws->pw_uid)) || (0 != seteuid(pws->pw_uid))) { - if((0 != setregid(pws->pw_gid, pws->pw_gid)) || - (0 != setreuid(pws->pw_uid, pws->pw_uid))) - LOG(LOG_WARNING, - _("Cannot change user/group to `%s': %s\n"), - user, STRERROR(errno)); - } -} -#endif - -/** - * Perform option parsing from the command line. - */ -int parseGnunetdCommandLine(int argc, - char * argv[]) { - int cont = OK; - int c; - - /* set the 'magic' code that indicates that - this process is 'gnunetd' (and not any of - the tools). This can be used by code - that runs in both the tools and in gnunetd - to distinguish between the two cases. */ - FREENONNULL(setConfigurationString("GNUNETD", - "_MAGIC_", - "YES")); - while (1) { - int option_index = 0; - static struct GNoption long_options[] = { - { "loglevel",1, 0, 'L' }, - { "config", 1, 0, 'c' }, - { "version", 0, 0, 'v' }, - { "help", 0, 0, 'h' }, - { "user", 1, 0, 'u' }, - { "debug", 0, 0, 'd' }, - { "livedot", 0, 0, 'l' }, - { "padding", 1, 0, 'p' }, - { "win-service", 0, 0, '@' }, - { 0,0,0,0 } - }; - - c = GNgetopt_long(argc, - argv, - "vhdc:u:L:lp:@", - long_options, - &option_index); - - if (c == -1) - break; /* No more flags to process */ - - switch(c) { - case 'p': - FREENONNULL(setConfigurationString("GNUNETD-EXPERIMENTAL", - "PADDING", - GNoptarg)); - break; - case 'l': - addCronJob(&printDot, - 1 * cronSECONDS, - 1 * cronSECONDS, - NULL); - break; - case 'c': - FREENONNULL(setConfigurationString("FILES", - "gnunet.conf", - GNoptarg)); - break; - case 'v': - printf("GNUnet v%s\n", - VERSION); - cont = SYSERR; - break; - case 'h': - printhelp(); - cont = SYSERR; - break; - case 'L': - FREENONNULL(setConfigurationString("GNUNETD", - "LOGLEVEL", - GNoptarg)); - break; - case 'd': - debug_flag_ = YES; - FREENONNULL(setConfigurationString("GNUNETD", - "LOGFILE", - NULL)); - break; -#ifndef MINGW /* not supported */ - case 'u': - changeUser(GNoptarg); - break; -#endif -#ifdef MINGW - case '@': - win_service_ = YES; - break; -#endif - default: - LOG(LOG_FAILURE, - _("Use --help to get a list of options.\n")); - cont = SYSERR; - } /* end of parsing commandline */ - } - if (GNoptind < argc) { - LOG(LOG_WARNING, - _("Invalid command-line arguments:\n")); - while (GNoptind < argc) { - LOG(LOG_WARNING, - _("Argument %d: `%s'\n"), - GNoptind+1, - argv[GNoptind]); - GNoptind++; - } - LOG(LOG_FATAL, - _("Invalid command-line arguments.\n")); - return SYSERR; - } - return cont; -} - /* end of startup.c */ Modified: GNUnet/src/server/startup.h =================================================================== --- GNUnet/src/server/startup.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/startup.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -22,13 +22,8 @@ * @file server/startup.h * @author Christian Grothoff * @brief Helper methods for the startup of gnunetd: - * - install signal handling - * - system checks on startup * - PID file handling - * - detaching from terminal - * - command line parsing - * - **/ + */ #ifndef STARTUP_H #define STARTUP_H @@ -36,60 +31,17 @@ #include "gnunet_util.h" #include "platform.h" -int debug_flag(void); - -int win_service(void); - /** - * Initialize signal handlers - **/ -void initSignalHandlers(void); - -void doneSignalHandlers(void); - -void waitForSignalHandler(void); - -/** - * Fork and start a new session to go into the background - * in the way a good deamon should. - * - * @param filedes pointer to an array of 2 file descriptors - * to complete the detachment protocol (handshake) - **/ -void detachFromTerminal(int * filedes); - -/** - * Detached process signals former parent success. - **/ -void detachFromTerminalComplete(int * filedes); - - -/** * Write our process ID to the pid file. **/ -void writePIDFile(void); +void writePIDFile(struct GE_Context * ectx, + struct GC_Configuration * cfg); /** * Delete the pid file. **/ -void deletePIDFile(void); +void deletePIDFile(struct GE_Context * ectx, + struct GC_Configuration * cfg); -/** - * Load all of the user-specified application modules. - */ -void loadApplicationModules(void); - -#ifndef MINGW -/** - * @brief Change user ID - */ -void changeUser(const char *user); #endif - -#ifdef MINGW -BOOL WINAPI win_shutdown_gnunetd(DWORD dwCtrlType); -void win_service_main(void (*gn_main)()); -#endif - -#endif /* end of startup.h */ Modified: GNUnet/src/server/tcpserver.c =================================================================== --- GNUnet/src/server/tcpserver.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/tcpserver.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -92,6 +92,26 @@ ip); } +static int shutdownHandler(ClientHandle client, + const MESSAGE_HEADER * msg) { + int ret; + + if (ntohs(msg->size) != sizeof(MESSAGE_HEADER)) { + GE_LOG(NULL, + GE_WARNING | GE_USER | GE_BULK, + _("The `%s' request received from client is malformed.\n"), + "shutdown"); + return SYSERR; + } + GE_LOG(NULL, + GE_INFO | GE_USER | GE_REQUEST, + "shutdown request accepted from client\n"); + ret = sendTCPResultToClient(client, + OK); + GNUNET_SHUTDOWN_INITIATE(); + return ret; +} + int registerClientExitHandler(ClientExitHandler callback) { MUTEX_LOCK(handlerlock); GROW(exitHandlers, Modified: GNUnet/src/server/version.c =================================================================== --- GNUnet/src/server/version.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/version.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -110,7 +110,6 @@ * @return OK if we are */ int checkUpToDate(struct GE_Context * ectx, - State_ServiceAPI * sapi, struct GC_Configuration * cfg) { char * version; int len; @@ -122,7 +121,6 @@ (void**)&version); if (len == -1) { upToDate(ectx, - sapi, cfg); /* first start */ return OK; } @@ -150,7 +148,6 @@ * Writes the version tag */ void upToDate(struct GE_Context * ectx, - State_ServiceAPI * sapi, struct GC_Configuration * cfg) { char * version; int len; Modified: GNUnet/src/server/version.h =================================================================== --- GNUnet/src/server/version.h 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/server/version.h 2006-07-29 07:56:57 UTC (rev 3152) @@ -27,7 +27,6 @@ #define GNUNETD_VERSION_H #include "gnunet_util.h" -#include "gnunet_state_service.h" /** @@ -35,14 +34,12 @@ * @return OK if we are */ int checkUpToDate(struct GE_Context * ectx, - State_ServiceAPI * sapi, struct GC_Configuration * cfg); /** * We are up-to-date. */ void upToDate(struct GE_Context * ectx, - State_ServiceAPI * sapi, struct GC_Configuration * cfg); #endif Modified: GNUnet/src/util/os/Makefile.am =================================================================== --- GNUnet/src/util/os/Makefile.am 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/os/Makefile.am 2006-07-29 07:56:57 UTC (rev 3152) @@ -14,6 +14,7 @@ semaphore.c \ statuscalls.c \ time.c \ + user.c \ installpath.c check_PROGRAMS = \ Added: GNUnet/src/util/os/console.c =================================================================== --- GNUnet/src/util/os/console.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/os/console.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -0,0 +1,131 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/os/console.c + * @brief code to detach from console + * @author Christian Grothoff + * + * Helper code for writing proper termination code when an application + * receives a SIGTERM/SIGHUP etc. + */ + +#include "gnunet_util_os.h" +#include "gnunet_util_error.h" +#include "gnunet_util_string.h" +#include "platform.h" + +/** + * Fork and start a new session to go into the background + * in the way a good deamon should. + * + * @param filedes pointer to an array of 2 file descriptors + * to complete the detachment protocol (handshake) + */ +int os_terminal_detach(struct GE_Context * ectx, + int * filedes) { + pid_t pid; + int nullfd; + + /* Don't hold the wrong FS mounted */ + if (CHDIR("/") < 0) { + GE_LOG_STRERROR(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "chdir"); + return SYSERR; + } + + PIPE(filedes); + pid = fork(); + if (pid < 0) { + GE_LOG_STRERROR(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "fork"); + return SYSERR; + } + if (pid) { /* Parent */ + int ok; + char c; + + if (0 != CLOSE(filedes[1])) + GE_LOG_STRERROR(ectx, + GE_WARNING | GE_USER | GE_BULK, + "close"); + ok = SYSERR; + while (0 < READ(filedes[0], + &c, + sizeof(char))) { + if (c == '.') + ok = OK; + } + fflush(stdout); + if (ok == OK) + exit(0); + else + exit(1); /* child reported error */ + } + if (0 != CLOSE(filedes[0])) + GE_LOG_STRERROR(ectx, + GE_WARNING | GE_USER | GE_BULK, + "close"); + nullfd = fileopen("/dev/null", + O_CREAT | O_RDWR | O_APPEND); + if (nullfd < 0) { + GE_LOG_STRERROR_FILE(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "fork", + "/dev/null"); + return SYSERR; + } + /* child - close fds linking to invoking terminal, but + * close usual incoming fds, but redirect them somewhere + * useful so the fds don't get reallocated elsewhere. + */ + if (dup2(nullfd,0) < 0 || + dup2(nullfd,1) < 0 || + dup2(nullfd,2) < 0) { + GE_LOG_STRERROR(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "dup2"); + return SYSERR; + } + pid = setsid(); /* Detach from controlling terminal */ + if (pid == -1) + GE_LOG_STRERROR(ectx, + GE_ERROR | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "setsid"); +} + +void os_terminal_detach_complete(struct GE_Context * ectx, + int * filedes, + int success) { + char c = '.'; + + if (! success) + c = '!'; + WRITE(filedes[1], + &c, + sizeof(char)); /* signal success */ + if (0 != CLOSE(filedes[1])) + GE_LOG_STRERROR(ectx, + GE_WARNING | GE_USER | GE_ADMIN | GE_IMMEDIATE, + "close"); +} + Property changes on: GNUnet/src/util/os/console.c ___________________________________________________________________ Name: svn:eol-style + native Modified: GNUnet/src/util/os/osconfig.c =================================================================== --- GNUnet/src/util/os/osconfig.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/os/osconfig.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -320,86 +320,5 @@ return SYSERR; } -int os_modify_user(struct GE_Context * ectx, - int testCapability, - int doAdd, - const char *group_name, - const char *user_name) { - int haveGroup; - if (testCapability) { - /* TODO: actually check that group/user - exists/does not yet exist */ -#ifdef WINDOWS - return IsWinNT() ? OK : SYSERR; -#endif -#ifdef LINUX - if (geteuid() != 0) - return SYSERR; - if (doAdd == YES) { - if ( ( (ACCESS("/usr/sbin/adduser", X_OK) == 0) || - (ACCESS("/usr/sbin/useradd", X_OK) == 0) ) && - ( (ACCESS("/usr/sbin/addgroup", X_OK) == 0) || - (ACCESS("/usr/sbin/groupadd", X_OK) == 0) ) ) - return OK; - return SYSERR; - } else if (doAdd == NO) { - if ( (ACCESS("/usr/sbin/deluser", X_OK) == 0) || - (ACCESS("/usr/sbin/userdel", X_OK) == 0) ) - return OK; - return SYSERR; - } else if (doAdd == SYSERR) { - if ( ( (ACCESS("/usr/sbin/dleuser", X_OK) == 0) || - (ACCESS("/usr/sbin/userdel", X_OK) == 0) ) && - ( (ACCESS("/usr/sbin/delgroup", X_OK) == 0) || - (ACCESS("/usr/sbin/groupdel", X_OK) == 0) ) ) - return OK; - return SYSERR; - } -#endif - return SYSERR; - } - if ( (user_name == NULL) || - (0 == strlen(user_name)) ) - return 0; - -#ifdef WINDOWS - if (IsWinNT()) - return CreateServiceAccount(user_name, - "GNUnet service account"); -#else - if (ACCESS("/usr/sbin/adduser", - X_OK) == 0) { - /* Debian */ - /* TODO: FreeBSD? http://www.freebsd.org/cgi/man.cgi?query=adduser&sektion=8 */ - char * cmd; - - haveGroup = group_name && strlen(group_name) > 0; - cmd = MALLOC(haveGroup ? strlen(group_name) : 0 + strlen(user_name) + 64); - - if (haveGroup) { - sprintf(cmd, - "/usr/sbin/addgroup --quiet --system %s", - group_name); - system(cmd); - } - - sprintf(cmd, - "/usr/sbin/adduser --quiet --system %s %s " - "--no-create-home %s", - haveGroup ? "--ingroup" : "", - haveGroup ? group_name : "", - user_name); - system(cmd); - FREE(cmd); - return OK; - } - /* TODO: useradd */ - else - return SYSERR; -#endif - return SYSERR; -} - - /* end of osconfig.c */ Added: GNUnet/src/util/os/user.c =================================================================== --- GNUnet/src/util/os/user.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/os/user.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -0,0 +1,144 @@ +/* + This file is part of GNUnet. + (C) 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/os/user.c + * @brief wrappers for UID functions + * @author Christian Grothoff + */ + +#include "gnunet_util_os.h" +#include "gnunet_util_string.h" +#include "platform.h" + +int os_modify_user(struct GE_Context * ectx, + int testCapability, + int doAdd, + const char *group_name, + const char *user_name) { + int haveGroup; + + if (testCapability) { + /* TODO: actually check that group/user + exists/does not yet exist */ +#ifdef WINDOWS + return IsWinNT() ? OK : SYSERR; +#endif +#ifdef LINUX + if (geteuid() != 0) + return SYSERR; + if (doAdd == YES) { + if ( ( (ACCESS("/usr/sbin/adduser", X_OK) == 0) || + (ACCESS("/usr/sbin/useradd", X_OK) == 0) ) && + ( (ACCESS("/usr/sbin/addgroup", X_OK) == 0) || + (ACCESS("/usr/sbin/groupadd", X_OK) == 0) ) ) + return OK; + return SYSERR; + } else if (doAdd == NO) { + if ( (ACCESS("/usr/sbin/deluser", X_OK) == 0) || + (ACCESS("/usr/sbin/userdel", X_OK) == 0) ) + return OK; + return SYSERR; + } else if (doAdd == SYSERR) { + if ( ( (ACCESS("/usr/sbin/dleuser", X_OK) == 0) || + (ACCESS("/usr/sbin/userdel", X_OK) == 0) ) && + ( (ACCESS("/usr/sbin/delgroup", X_OK) == 0) || + (ACCESS("/usr/sbin/groupdel", X_OK) == 0) ) ) + return OK; + return SYSERR; + } +#endif + return SYSERR; + } + if ( (user_name == NULL) || + (0 == strlen(user_name)) ) + return 0; + +#ifdef WINDOWS + if (IsWinNT()) + return CreateServiceAccount(user_name, + "GNUnet service account"); +#else + if (ACCESS("/usr/sbin/adduser", + X_OK) == 0) { + /* Debian */ + /* TODO: FreeBSD? http://www.freebsd.org/cgi/man.cgi?query=adduser&sektion=8 */ + char * cmd; + + haveGroup = group_name && strlen(group_name) > 0; + cmd = MALLOC(haveGroup ? strlen(group_name) : 0 + strlen(user_name) + 64); + + if (haveGroup) { + sprintf(cmd, + "/usr/sbin/addgroup --quiet --system %s", + group_name); + system(cmd); + } + + sprintf(cmd, + "/usr/sbin/adduser --quiet --system %s %s " + "--no-create-home %s", + haveGroup ? "--ingroup" : "", + haveGroup ? group_name : "", + user_name); + system(cmd); + FREE(cmd); + return OK; + } + /* TODO: useradd */ + else + return SYSERR; +#endif + return SYSERR; +} + + +/** + * @brief Change user ID + */ +int os_change_user(struct GE_Context * ectx, + const char * user) { + struct passwd * pws; + + pws = getpwnam(user); + if (pws == NULL) { + GE_LOG(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + _("User `%s' not known, cannot change UID to it.\n"), + user); + return SYSERR; + } + if((0 != setgid(pws->pw_gid)) || + (0 != setegid(pws->pw_gid)) || + (0 != setuid(pws->pw_uid)) || (0 != seteuid(pws->pw_uid))) { + if((0 != setregid(pws->pw_gid, pws->pw_gid)) || + (0 != setreuid(pws->pw_uid, pws->pw_uid))) { + GE_LOG(ectx, + GE_FATAL | GE_USER | GE_ADMIN | GE_IMMEDIATE, + _("Cannot change user/group to `%s': %s\n"), + user, + STRERROR(errno)); + return SYSERR; + } + } + return OK; +} + + Property changes on: GNUnet/src/util/os/user.c ___________________________________________________________________ Name: svn:eol-style + native Modified: GNUnet/src/util/threads/Makefile.am =================================================================== --- GNUnet/src/util/threads/Makefile.am 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/threads/Makefile.am 2006-07-29 07:56:57 UTC (rev 3152) @@ -10,6 +10,7 @@ pthread.c \ semaphore.c \ shutdown.c \ + signal.c \ time.c check_PROGRAMS = \ Modified: GNUnet/src/util/threads/shutdown.c =================================================================== --- GNUnet/src/util/threads/shutdown.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/threads/shutdown.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -39,6 +39,12 @@ static int shutdown_active; +static struct SignalHandlerContext * shc_int; + +static struct SignalHandlerContext * shc_term; + +static struct SignalHandlerContext * shc_quit; + void GNUNET_SHUTDOWN_INITIATE() { GE_ASSERT(NULL, shutdown_signal != NULL); shutdown_active = YES; @@ -53,71 +59,31 @@ SEMAPHORE_DOWN(shutdown_signal, YES); } -#ifdef MINGW -BOOL WINAPI run_shutdown_win(DWORD dwCtrlType) { - switch(dwCtrlType) { - case CTRL_C_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_SHUTDOWN_EVENT: - case CTRL_LOGOFF_EVENT: - GNUNET_SHUTDOWN_INITIATE(); - } - return TRUE; -} -#else -static void run_shutdown(int signum) { +static void run_shutdown() { GNUNET_SHUTDOWN_INITIATE(); } -#endif /** * Initialize the signal handlers, etc. */ void __attribute__ ((constructor)) shutdown_handlers_ltdl_init() { -#ifndef MINGW - struct sigaction sig; - struct sigaction oldsig; -#endif - GE_ASSERT(NULL, shutdown_signal == NULL); GE_ASSERT(NULL, shutdown_active == NO); shutdown_signal = SEMAPHORE_CREATE(0); -#ifndef MINGW - sig.sa_handler = &run_shutdown; - sigemptyset(&sig.sa_mask); -#ifdef SA_INTERRUPT - sig.sa_flags = SA_INTERRUPT; /* SunOS */ -#else - sig.sa_flags = SA_RESTART; -#endif - sigaction(SIGINT, &sig, &oldsig); - sigaction(SIGTERM, &sig, &oldsig); - sigaction(SIGQUIT, &sig, &oldsig); -#else - SetConsoleCtrlHandler(&run_shutdown_win, TRUE); -#endif + shc_int = signal_handler_install(SIGINT, &run_shutdown); + shc_term = signal_handler_install(SIGTERM, &run_shutdown); + shc_quit = signal_handler_install(SIGQUIT, &run_shutdown); } void __attribute__ ((destructor)) shutdown_handlers_ltdl_fini() { -#ifndef MINGW - struct sigaction sig; - struct sigaction oldsig; - - sig.sa_handler = SIG_DFL; - sigemptyset(&sig.sa_mask); -#ifdef SA_INTERRUPT - sig.sa_flags = SA_INTERRUPT; /* SunOS */ -#else - sig.sa_flags = SA_RESTART; -#endif - sigaction(SIGINT, &sig, &oldsig); - sigaction(SIGTERM, &sig, &oldsig); - sigaction(SIGQUIT, &sig, &oldsig); -#else - SetConsoleCtrlHandler(&run_shutdown_win, FALSE); -#endif + signal_handler_uninstall(SIGINT, &run_shutdown, shc_int); + signal_handler_uninstall(SIGTERM, &run_shutdown, shc_term); + signal_handler_uninstall(SIGQUIT, &run_shutdown, shc_quit); SEMAPHORE_DESTROY(shutdown_signal); shutdown_signal = NULL; + shc_int = NULL; + shc_term = NULL; + shc_quit = NULL; } /* end of shutdown.c */ Added: GNUnet/src/util/threads/signal.c =================================================================== --- GNUnet/src/util/threads/signal.c 2006-07-29 01:13:50 UTC (rev 3151) +++ GNUnet/src/util/threads/signal.c 2006-07-29 07:56:57 UTC (rev 3152) @@ -0,0 +1,77 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/threads/signal.c + * @brief code for installing and uninstalling signal handlers + * @author Christian Grothoff + */ + +#include "gnunet_util_threads.h" +#include "gnunet_util_string.h" +#include "platform.h" + +typedef struct SignalHandlerContext { + int sig; + + SignalHandler method; + +#ifndef MINGW + struct sigaction oldsig; +#endif +} SignalHandlerContext; + +struct SignalHandlerContext * signal_handler_install(int signal, + SignalHandler handler) { + struct SignalHandlerContext * ret; + struct sigaction sig; + + ret = MALLOC(sizeof(struct SignalHandlerContext)); + ret->sig = signal; + ret->method = handler; +#ifndef MINGW + sig.sa_handler = (void*) handler; + sigemptyset(&sig.sa_mask); +#ifdef SA_INTERRUPT + sig.sa_flags = SA_INTERRUPT; /* SunOS */ +#else + sig.sa_flags = SA_RESTART; +#endif + sigaction(signal, &sig, &ret->oldsig); +#else + /* FIXME: mingw! */ +#endif + return ret; +} + +void signal_handler_uninstall(int signal, + SignalHandler handler, + struct SignalHandlerContext * ctx) { +#ifndef MINGW + struct sigaction sig; + + GE_ASSERT(NULL, (ctx->sig == signal) && (ctx->method == handler)); + sigemptyset(&sig.sa_mask); + sigaction(signal, &ctx->oldsig, &sig); +#else + /* FIXME: mingw! */ +#endif +} + Property changes on: GNUnet/src/util/threads/signal.c ___________________________________________________________________ Name: svn:eol-style + native _______________________________________________ GNUnet-SVN mailing list GNUnet-SVN@gnu.org http://lists.gnu.org/mailman/listinfo/gnunet-svn