/* Copyright (C) 2008 Andreas Baumann This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "port/string.h" /* for strdup, memset */ #include "port/stdio.h" /* for fprintf */ #define DEFAULT_TEXT_DOMAIN CMDLINE_PARSER_PACKAGE #include "port/gettext.h" /* for i18n */ #include "errors.h" /* global error codes */ #include "log/log.h" /* logging facility */ #include "log/messages.h" /* for i18n */ #include "daemon/daemon.h" /* Unix daemonizing code */ #include "daemon/signals.h" /* signal suspension */ #include /* for exit, unistd, getuid, getppid */ #include /* for EXIT_FAILURE, EXIT_SUCCESS */ /* local message identifiers, we use the category of the daemon in WolfBones */ #define WOLF_MSG_DAEMON_TESTING_CONFIGURATION WOLF_MSG_DAEMON_USER_BASE+1 #define WOLF_MSG_DAEMON_STARTED_DAEMON WOLF_MSG_DAEMON_USER_BASE+2 #define WOLF_MSG_DAEMON_SUSPENDING_ON_SIGNAL_ERROR WOLF_MSG_DAEMON_USER_BASE+3 #define WOLF_MSG_DAEMON_REREADING_CONFIGURATION WOLF_MSG_DAEMON_USER_BASE+4 #define WOLF_MSG_DAEMON_GOT_TERMINATION_SIGNAL WOLF_MSG_DAEMON_USER_BASE+5 #define WOLF_MSG_DAEMON_UNEXPECED_SIGNAL WOLF_MSG_DAEMON_USER_BASE+6 #define WOLF_MSG_DAEMON_STOPPED_DAEMON WOLF_MSG_DAEMON_USER_BASE+7 #ifndef MAKE_DEPENDENCIES #include "testd_cmdline.h" /* for command line and option parsing (gengetopt) */ #endif #define DEFAULT_CONFIG_FILE "/etc/" CMDLINE_PARSER_PACKAGE ".conf" static int parse_options_and_arguments( int argc, char *argv[], struct gengetopt_args_info *args_info ) { struct cmdline_parser_params params; cmdline_parser_params_init( ¶ms ); params.override = 1; params.initialize = 0; params.check_required = 1; cmdline_parser_init( args_info ); if( cmdline_parser_ext( argc, argv, args_info, ¶ms ) != 0 ) { cmdline_parser_free( args_info ); return EXIT_FAILURE; } return EXIT_SUCCESS; } static int test_config( const char *filename ) { wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_TESTING_CONFIGURATION, _( "Testing configuraton read from '%s'" ), filename ); return EXIT_SUCCESS; } static int read_config( const char *filename, struct gengetopt_args_info *args_info ) { char *config_filename = strdup( filename ); struct cmdline_parser_params params; cmdline_parser_params_init( ¶ms ); params.override = 0; params.initialize = 0; params.check_required = 1; if( cmdline_parser_config_file( config_filename, args_info, ¶ms ) != 0 ) { /* TODO: gengetopt must support i18n for this */ fprintf( stderr, "\n%s\n", gengetopt_args_info_usage ); cmdline_parser_free( args_info ); free( config_filename ); return EXIT_FAILURE; } free( config_filename ); return EXIT_SUCCESS; } int main( int argc, char *argv[] ) { struct gengetopt_args_info args_info; wolf_error_t error; wolf_daemon_params_t daemon_params; wolf_daemon_p demon = NULL; int sig = 0; wolf_port_initialize_i18n( argv[0], "libwolf" ); wolf_port_initialize_i18n( argv[0], CMDLINE_PARSER_PACKAGE ); if( parse_options_and_arguments( argc, argv, &args_info ) == EXIT_FAILURE ) { exit( EXIT_FAILURE ); } if( read_config( args_info.config_file_given ? args_info.config_file_arg : DEFAULT_CONFIG_FILE, &args_info ) == EXIT_FAILURE ) { exit( EXIT_FAILURE ); } if( args_info.test_given ) { cmdline_parser_free( &args_info ); exit( test_config( args_info.config_file_given ? args_info.config_file_arg : DEFAULT_CONFIG_FILE ) ); } wolf_log_openlogtostderr( (wolf_log_level_t)((int)WOLF_LOG_DEBUG - 1 + (int)args_info.debug_given) ); if( args_info.logfile_given ) wolf_log_openlogtofile( args_info.logfile_arg, args_info.logfile_level_given ? wolf_log_str_to_level( args_info.logfile_level_arg ) : WOLF_LOG_NOTICE ); if( !args_info.foreground_given ) { wolf_log_openlogtosyslog( CMDLINE_PARSER_PACKAGE, args_info.syslog_facility_given ? wolf_log_str_to_syslog_facility( args_info.syslog_facility_arg ) : WOLF_LOG_DAEMON, args_info.syslog_level_given ? wolf_log_str_to_level( args_info.syslog_level_arg ) : WOLF_LOG_NOTICE, WOLF_LOG_SYSLOG_DEFAULT_OPTIONS ); memset( &daemon_params, 0, sizeof( daemon_params ) ); daemon_params.daemon_name = CMDLINE_PARSER_PACKAGE; daemon_params.pid_filename = args_info.pidfile_given ? args_info.pidfile_arg : NULL; daemon_params.group_name = args_info.group_given ? args_info.group_arg : NULL; daemon_params.user_name = args_info.user_given ? args_info.user_arg : NULL; demon = wolf_daemon_new( daemon_params, &error ); if( demon == NULL ) { cmdline_parser_free( &args_info ); exit( EXIT_FAILURE ); } if( ( error = wolf_daemon_start( demon ) ) != WOLF_OK ) { cmdline_parser_free( &args_info ); wolf_daemon_exit( demon ); } } else { if( ( error = wolf_daemon_signals_initialize( ) ) != WOLF_OK ) { cmdline_parser_free( &args_info ); exit( EXIT_FAILURE ); } if( ( error = wolf_daemon_signals_install_handlers( ) ) != WOLF_OK ) { wolf_daemon_signals_terminate( ); cmdline_parser_free( &args_info ); exit( EXIT_FAILURE ); } } wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_STARTED_DAEMON, _( "Started %s daemon" ), CMDLINE_PARSER_PACKAGE ); while( ( sig != SIGTERM ) && ( sig != SIGINT ) && ( sig != -1 ) ) { sig = wolf_daemon_signals_suspend( 60, &error ); switch( sig ) { case 0: /* timeout */ break; case -1: /* internal error */ wolf_log( WOLF_LOG_CRIT, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_SUSPENDING_ON_SIGNAL_ERROR, _( "Suspending on UNIX signal resulted in an error %d!" ), error ); break; case SIGHUP: wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_REREADING_CONFIGURATION, _( "Rereading configuration" ) ); break; case SIGTERM: case SIGINT: wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_GOT_TERMINATION_SIGNAL, _( "Got termination signal, shutting down the daemon" ) ); break; case SIGUSR1: break; case SIGUSR2: break; default: wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_UNEXPECED_SIGNAL, _( "Unexpected signal '%s' (%s)" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ) ); } } wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_STOPPED_DAEMON, _( "Stopped %s daemon" ), CMDLINE_PARSER_PACKAGE ); wolf_log_closelogtofile( ); if( !args_info.foreground_given ) { wolf_log_closelogtosyslog( ); cmdline_parser_free( &args_info ); wolf_daemon_exit( demon ); } else { cmdline_parser_free( &args_info ); wolf_daemon_signals_terminate( ); exit( EXIT_SUCCESS ); } exit( EXIT_FAILURE ); }