/** * Main SMSD program */ /* Copyright (c) 2009 - 2017 Michal Cihar */ /* Licensend under GNU GPL 2 */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_GETOPT_LONG #include #endif #ifdef HAVE_WINDOWS_SERVICE #include "winservice.h" #endif #ifdef HAVE_KILL #include "pidfile.h" #define HAVE_PIDFILE #endif #include #include #include "common.h" #if defined(HAVE_GETPWNAM) && defined(HAVE_GETGRNAM) && defined(HAVE_SETUID) && defined(HAVE_SETGID) && defined(HAVE_INITGROUPS) #define HAVE_UID #include "uid.h" #endif #ifdef HAVE_WINDOWS_EVENT_LOG #include "log-event.h" #endif #if !defined(WIN32) #define HAVE_DEFAULT_CONFIG const char default_config[] = "/etc/gammu-smsdrc"; #endif GSM_SMSDConfig *config; volatile gboolean reconfigure = FALSE; volatile gboolean standby = FALSE; void smsd_interrupt(int signum) { SMSD_Shutdown(config); signal(signum, SIG_IGN); } void smsd_reconfigure(int signum) { reconfigure = TRUE; SMSD_Shutdown(config); } void smsd_standby(int signum) { standby = TRUE; reconfigure = TRUE; SMSD_Shutdown(config); } void smsd_resume(int signum) { standby = FALSE; } #ifdef WIN32 VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) { SMSD_Shutdown(config); } #endif NORETURN void version(void) { printf("Gammu-smsd version %s\n", GAMMU_VERSION); printf("Compiled in features:\n"); printf("OS support:\n"); #ifdef HAVE_SHM printf(" - %s\n", "SHM"); #endif #ifdef HAVE_DAEMON printf(" - %s\n", "DAEMON"); #endif #ifdef HAVE_PIDFILE printf(" - %s\n", "PID"); #endif #if defined(HAVE_ALARM) || defined(WIN32) printf(" - %s\n", "ALARM"); #endif #ifdef HAVE_UID #endif #ifdef HAVE_WINDOWS_SERVICE printf(" - %s\n", "WINDOWS_SERVICE"); #endif #ifdef HAVE_GETOPT printf(" - %s\n", "GETOPT"); #endif #ifdef HAVE_GETOPT_LONG printf(" - %s\n", "GETOPT_LONG"); #endif #ifdef HAVE_WINDOWS_EVENT_LOG printf(" - %s\n", "EVENT_LOG"); #endif #ifdef HAVE_SYSLOG printf(" - %s\n", "SYSLOG"); #endif printf("Backend services:\n"); printf(" - %s\n", "NULL"); printf(" - %s\n", "FILES"); #ifdef HAVE_MYSQL_MYSQL_H printf(" - %s\n", "MYSQL"); #endif #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H printf(" - %s\n", "POSTGRESQL"); #endif #ifdef LIBDBI_FOUND printf(" - %s\n", "DBI"); #endif #ifdef ODBC_FOUND printf(" - %s\n", "ODBC"); #endif printf("\n"); printf("Copyright (C) 2003 - 2017 Michal Cihar and other authors.\n"); printf("\n"); printf("License GPLv2: GNU GPL version 2 .\n"); printf("This is free software: you are free to change and redistribute it.\n"); printf("There is NO WARRANTY, to the extent permitted by law.\n"); printf("\n"); printf("Check for updates.\n"); printf("\n"); exit(0); } #ifdef HAVE_GETOPT_LONG #define print_option(name, longname, help) \ printf("-%s / --%s - %s\n", name, longname, help); #define print_option_param(name, longname, paramname, help) \ printf("-%s / --%s %s - %s\n", name, longname, paramname, help); #else #define print_option(name, longname, help) \ printf("-%s - %s\n", name, help); #define print_option_param(name, longname, paramname, help) \ printf("-%s %s - %s\n", name, paramname, help); #endif void help(void) { printf("usage: gammu-smsd [OPTION]...\n"); printf("options:\n"); print_option("h", "help", "shows this help"); print_option("v", "version", "shows version information"); print_option_param("c", "config", "CONFIG_FILE", "defines path to config file"); #ifdef HAVE_DAEMON print_option("d", "daemon", "daemonizes program after startup"); #endif #ifdef HAVE_PIDFILE print_option_param("p", "pid", "PID_FILE", "defines path to pid file"); #endif #ifdef HAVE_UID print_option_param("U", "user", "USER", "run daemon as a user"); print_option_param("G", "group", "GROUP", "run daemon as a group"); #endif print_option_param("f", "max-failures", "NUM", "number of failures before terminating"); #if defined(HAVE_ALARM) || defined(WIN32) print_option_param("X", "suicide", "SECONDS", "kills itself after number of seconds"); #endif #ifdef HAVE_WINDOWS_SERVICE print_option("i", "install-service", "installs SMSD as a Windows service"); print_option("u", "uninstall-service", "uninstalls SMSD as a Windows service"); print_option("s", "start-service", "starts SMSD Windows service"); print_option("k", "stop-service", "stops SMSD Windows service"); print_option("S", "run-as-service", "runs as a SMSD Windows service"); print_option_param("n", "service-name", "NAME", "name of a Windows service (default: GammuSMSD)"); #endif print_option("l", "use-log", "use logging configuration from config file (default)"); print_option("L", "no-use-log", "do not use logging configuration from config file"); #ifdef HAVE_WINDOWS_EVENT_LOG print_option("e", "install-event-log", "installs Windows EventLog description to registry"); print_option("E", "uninstall-event-log", "uninstalls Windows EventLog description to registry"); #endif } NORETURN void wrong_params(void) { fprintf(stderr, "Invalid parameter, use -h for help.\n"); exit(1); } void process_commandline(int argc, char **argv, SMSD_Parameters * params) { int opt; #ifdef WIN32 HANDLE hTimer = NULL; #endif #ifdef HAVE_GETOPT_LONG struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"config", 1, 0, 'c'}, {"daemon", 0, 0, 'd'}, {"pid", 1, 0, 'p'}, {"install-service", 0, 0, 'i'}, {"uninstall-service", 0, 0, 'u'}, {"start-service", 0, 0, 's'}, {"stop-service", 0, 0, 'k'}, {"run-as-service", 0, 0, 'S'}, {"user", 1, 0, 'U'}, {"group", 1, 0, 'G'}, {"service-name", 1, 0, 'n'}, {"suicide", 1, 0, 'X'}, {"max-failures", 1, 0, 'f'}, {"use-log", 0, 0, 'l'}, {"no-use-log", 0, 0, 'L'}, {"install-event-log", 0, 0, 'e'}, {"uninstall-event-log", 0, 0, 'E'}, {0, 0, 0, 0} }; int option_index; while ((opt = getopt_long(argc, argv, "hvdc:p:iusSkU:G:n:X:f:lLeE", long_options, &option_index)) != -1) { #elif defined(HAVE_GETOPT) while ((opt = getopt(argc, argv, "hvdc:p:iusSkU:G:n:X:f:lLeE")) != -1) { #else /* Poor mans getopt replacement */ int i; #define optarg argv[++i] for (i = 1; i < argc; i++) { if (strlen(argv[i]) != 2 || argv[i][0] != '-') { wrong_params(); } opt = argv[i][1]; #endif switch (opt) { case 'c': params->config_file = optarg; break; #ifdef HAVE_PIDFILE case 'p': params->pid_file = optarg; break; #endif #ifdef HAVE_UID case 'U': if (!fill_uid(params, optarg)) { fprintf(stderr, "Wrong user name/ID!\n"); exit(1); } break; case 'G': if (!fill_gid(params, optarg)) { fprintf(stderr, "Wrong group name/ID!\n"); exit(1); } break; #endif case 'f': params->max_failures = atoi(optarg); break; #if defined(HAVE_ALARM) || defined(WIN32) case 'X': #ifdef HAVE_ALARM alarm(atoi(optarg)); #elif defined(WIN32) CreateTimerQueueTimer(&hTimer, NULL, (WAITORTIMERCALLBACK)TimerRoutine, NULL , atoi(optarg) * 1000, 0, 0); #endif break; #endif #ifdef HAVE_DAEMON case 'd': params->daemonize = TRUE; break; #endif #ifdef HAVE_WINDOWS_EVENT_LOG case 'e': params->install_evlog = TRUE; break; case 'E': params->uninstall_evlog = TRUE; break; #endif #ifdef HAVE_WINDOWS_SERVICE case 'i': params->install_service = TRUE; break; case 'u': params->uninstall_service = TRUE; break; case 's': params->start_service = TRUE; break; case 'k': params->stop_service = TRUE; break; case 'S': params->run_service = TRUE; break; case 'n': strncpy(smsd_service_name, optarg, SERVICE_NAME_LENGTH); smsd_service_name[SERVICE_NAME_LENGTH - 1] = 0; break; #endif case 'v': version(); break; case 'l': params->use_log = TRUE; break; case 'L': params->use_log = FALSE; break; case '?': wrong_params(); case 'h': help(); exit(0); default: fprintf(stderr, "Parameter -%c not known!\n", opt); wrong_params(); break; } } #if defined(HAVE_GETOPT) || defined(HAVE_GETOPT_LONG) if (optind < argc) { wrong_params(); } #endif } void configure_daemon(SMSD_Parameters * params) { signal(SIGINT, smsd_interrupt); signal(SIGTERM, smsd_interrupt); #ifdef HAVE_SIGHUP signal(SIGHUP, smsd_reconfigure); #endif #ifdef HAVE_ALARM signal(SIGALRM, smsd_interrupt); #endif #if defined(HAVE_SIGUSR1) && defined(HAVE_SIGUSR2) signal(SIGUSR1, smsd_standby); signal(SIGUSR2, smsd_resume); #endif #ifdef HAVE_DAEMON /* Daemonize has to be before writing PID as it changes it */ if (params->daemonize) { if (daemon(1, 0) != 0) { fprintf(stderr, "daemonizing failed! (%s)\n", strerror(errno)); exit(1); } } #endif #ifdef HAVE_PIDFILE /* Writing PID file has to happen before dropping privileges */ if (params->pid_file != NULL && strlen(params->pid_file) > 0) { check_pid(params->pid_file); write_pid(params->pid_file); } #endif #ifdef HAVE_UID if (params->gid >= 0 || params->uid >= 0) { if (!set_uid_gid(params)) { fprintf(stderr, "changing uid/gid failed! (%s)\n", strerror(errno)); exit(1); } } #endif #ifdef HAVE_WINDOWS_SERVICE if (params->run_service) { if (!start_smsd_service_dispatcher()) { printf("Error starting %s service\n", smsd_service_name); service_print_error("Error running service"); exit(1); } SMSD_FreeConfig(config); exit(0); } #endif } int main(int argc, char **argv) { GSM_Error error; const char program_name[] = "gammu-smsd"; SMSD_Parameters params = { NULL, NULL, -1, -1, NULL, NULL, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, 0 }; /* * We don't need gettext, but need to set locales so that * charset conversion works. */ GSM_InitLocales(NULL); process_commandline(argc, argv, ¶ms); #ifdef HAVE_WINDOWS_SERVICE if (params.stop_service) { if (stop_smsd_service()) { printf("Service %s stopped sucessfully\n", smsd_service_name); exit(0); } else { printf("Error stopping %s service\n", smsd_service_name); service_print_error("Error stopping service"); exit(1); } } if (params.uninstall_service) { if (uninstall_smsd_service()) { printf("Service %s uninstalled sucessfully\n", smsd_service_name); exit(0); } else { printf("Error uninstalling %s service\n", smsd_service_name); service_print_error("Error uninstalling service"); exit(1); } } #endif #ifdef HAVE_WINDOWS_EVENT_LOG if (params.install_evlog) { if (eventlog_register()) { printf("Installed event log description\n"); exit(0); } else { printf("Failed to install event log description!\n"); exit(1); } } if (params.uninstall_evlog) { if (eventlog_deregister()) { printf("Uninstalled event log description\n"); exit(0); } else { printf("Failed to uninstall event log description!\n"); exit(1); } } #endif if (params.config_file == NULL) { #ifdef HAVE_DEFAULT_CONFIG params.config_file = default_config; #else fprintf(stderr, "No config file specified!\n"); help(); exit(1); #endif } #ifdef HAVE_WINDOWS_SERVICE if (params.install_service) { if (install_smsd_service(¶ms)) { printf("Service %s installed sucessfully\n", smsd_service_name); exit(0); } else { printf("Error installing %s service\n", smsd_service_name); service_print_error("Error installing service"); exit(1); } } if (params.start_service) { if (start_smsd_service()) { printf("Service %s started sucessfully\n", smsd_service_name); exit(0); } else { printf("Error starting %s service\n", smsd_service_name); service_print_error("Error starting service"); exit(1); } } #endif read_config: config = SMSD_NewConfig(program_name); assert(config != NULL); error = SMSD_ReadConfig(params.config_file, config, params.use_log); if (error != ERR_NONE) { printf("Failed to read config: %s\n", GSM_ErrorString(error)); SMSD_FreeConfig(config); return 2; } SMSD_EnableGlobalDebug(config); if (!reconfigure) configure_daemon(¶ms); reconfigure = FALSE; standby = FALSE; error = SMSD_MainLoop(config, FALSE, params.max_failures); if (error != ERR_NONE) { printf("Failed to run SMSD: %s\n", GSM_ErrorString(error)); SMSD_FreeConfig(config); return 2; } SMSD_FreeConfig(config); /* * Wait while we should be suspended. * Later we fall back to reconfigure below. */ while (standby) { sleep(1); } if (reconfigure) { goto read_config; } return 0; } /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */