/* $Id$ */ /*** This file is part of ivam2. ivam2 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 of the License, or (at your option) any later version. ivam2 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 ivam2; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "main.h" #include "exec.h" #include "modemman.h" #include "msntab.h" #include "cmdline.h" oop_source* event_source = NULL; struct gengetopt_args_info args; const char *appname = NULL; uid_t target_uid = 0; gid_t target_gid = 0; #define DEFAULT_MSNTABLE PKGSYSCONFDIR"/msntab" #define IVAM_USER "ivam" #define IVAM_GROUP "ivam" static void *oop_exit_cb(oop_source *source, int sig, void *user) { daemon_log(LOG_ERR, "Recieved signal %s", sig == SIGINT ? "SIGINT" : (sig == SIGTERM ? "SIGTERM" : "UNKNWON")); return OOP_HALT; } static void *oop_reload_cb(oop_source *source, int sig, void *user) { daemon_log(LOG_ERR, "Reloading MSN table."); msntab_flush(); if (msntab_load(args.msntab_arg ? args.msntab_arg : DEFAULT_MSNTABLE) < 0) { daemon_log(LOG_ERR, "Ignoring all calls."); msntab_flush(); } return OOP_CONTINUE; } static void *oop_dump_cb(oop_source *source, int sig, void *user) { msntab_dump(); return OOP_CONTINUE; } static int change_uid_gid(void) { struct passwd *pw; if (args.no_drop_root_flag) return 0; if (initgroups(IVAM_USER, target_gid) != 0) { daemon_log(LOG_ERR, "Failed to change group list: %s", strerror(errno)); return -1; } if (setgid(target_gid) != 0) { daemon_log(LOG_ERR, "Failed to change GID: %s", strerror(errno)); return -1; } if (setuid(target_uid) != 0) { daemon_log(LOG_ERR, "Failed to change UID: %s", strerror(errno)); return -1; } if ((pw = getpwuid(target_uid))) { setenv("USER", pw->pw_name, 1); setenv("LOGNAME", pw->pw_name, 1); setenv("HOME", pw->pw_dir, 1); } else { unsetenv("USER"); unsetenv("LOGNAME"); unsetenv("HOME"); } daemon_log(LOG_INFO, "Successfully dropped root privileges."); return 0; } static int get_target_uid_gid(void) { struct passwd *pw; struct group * gr; if (args.no_drop_root_flag) { target_uid = getuid(); target_gid = getgid(); return 0; } if (!(pw = getpwnam(IVAM_USER))) { daemon_log(LOG_ERR, "Failed to find user '%s'.", IVAM_USER); return -1; } if (!(gr = getgrnam(IVAM_GROUP))) { daemon_log(LOG_ERR, "Failed to find group '%s'.", IVAM_GROUP); return -1; } target_uid = pw->pw_uid; target_gid = gr->gr_gid; daemon_log(LOG_INFO, "Found user '%s' (UID %lu) and group '%s' (GID %lu).", IVAM_USER, (unsigned long) target_uid, IVAM_GROUP, (unsigned long) target_gid); return 0; } int main_loop(void) { int r = -1, retval_sent = 0; oop_source_sys *sys = NULL; daemon_log(LOG_INFO, "Starting up "PACKAGE" version "VERSION" <"PACKAGE_BUGREPORT">."); if (get_target_uid_gid() < 0) goto finish; setenv("PATH", BINDIR":/usr/sbin:/usr/bin:/sbin:/bin/:/usr/local/sbin:/usr/local/bin", 1); daemon_log(LOG_INFO, "Path set to '%s'.", getenv("PATH")); if (!(sys = oop_sys_new())) { daemon_log(LOG_ERR, "Failed to create system source."); goto finish; } event_source = oop_sys_source(sys); assert(event_source); if (modem_manager_init(args.channels_arg) < 0) goto finish; if (change_uid_gid() < 0) goto finish; if (child_process_init() < 0) goto finish; if (msntab_load(args.msntab_arg ? args.msntab_arg : DEFAULT_MSNTABLE) < 0) goto finish; event_source->on_signal(event_source, SIGINT, oop_exit_cb, NULL); event_source->on_signal(event_source, SIGTERM, oop_exit_cb, NULL); event_source->on_signal(event_source, SIGHUP, oop_reload_cb, NULL); event_source->on_signal(event_source, SIGUSR1, oop_dump_cb, NULL); signal(SIGPIPE, SIG_IGN); if (!args.no_daemon_flag) { daemon_retval_send(0); retval_sent = 1; } daemon_log(LOG_INFO, "Start up complete."); if (oop_sys_run(sys) == OOP_ERROR) { daemon_log(LOG_ERR, "oop_sys_new() returned OOP_ERROR"); goto finish; } r = 0; finish: daemon_log(LOG_INFO, "Shutting down."); if (!retval_sent && !args.no_daemon_flag) daemon_retval_send(1); event_source->cancel_signal(event_source, SIGTERM, oop_exit_cb, NULL); event_source->cancel_signal(event_source, SIGINT, oop_exit_cb, NULL); event_source->cancel_signal(event_source, SIGHUP, oop_reload_cb, NULL); event_source->cancel_signal(event_source, SIGUSR1, oop_dump_cb, NULL); msntab_flush(); modem_manager_done(); child_process_done(); if (sys) { event_source = NULL; oop_sys_delete(sys); } daemon_log(LOG_INFO, "Shut down complete."); return r; } int main(int argc, char*argv[]) { pid_t pid; int ret; appname = daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]); cmdline_parser(argc, argv, &args); if (args.no_syslog_flag) daemon_log_use = DAEMON_LOG_STDERR; if (args.kill_flag) { int ret; if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno)); return ret < 0 ? 1 : 0; } if (args.reload_flag || args.info_flag) { int ret; if ((ret = daemon_pid_file_kill(args.reload_flag ? SIGHUP : SIGUSR1)) < 0) daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno)); return ret < 0 ? 1 : 0; } if (args.check_flag) { if ((pid = daemon_pid_file_is_running()) >= 0) daemon_log(LOG_INFO, "Daemon running on PID %u.", pid); else daemon_log(LOG_INFO, "Daemon not running."); return pid >= 0 ? 0 : 1; } if ((pid = daemon_pid_file_is_running()) >= 0) { daemon_log(LOG_ERR, "Daemon already running on PID %u.", pid); return 1; } if (!args.no_daemon_flag) { daemon_retval_init(); if ((pid = daemon_fork()) < 0) { daemon_retval_done(); return 1; } else if (pid) { int ret; if ((ret = daemon_retval_wait(20)) < 0) { daemon_log(LOG_ERR, "Failed to recieve return value from daemon process."); return 255; } if (ret) daemon_log(LOG_ERR, "Daemon returned %i as return value.", ret); return ret; } } if (daemon_pid_file_create() < 0) { daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno)); if (!args.no_daemon_flag) daemon_retval_send(1); return 1; } ret = main_loop() < 0 ? 1 : 0; if (daemon_pid_file_remove() < 0) daemon_log(LOG_WARNING, "Failed to remove PID file (%s).", strerror(errno)); return ret; }