int Globals::run(int argc, char * * argv) { Daemon daemon; char * cp; char * sockarg; name(FilePath(argv[0]).filename()); // Parse arguments. config = FilePath("/etc") + name(); for (;;) { cp = *++argv; if (!--argc || *cp != '-' || !cp[1]) break; while (*++cp) switch (*cp) { case 'c': // Configuration file. if (!--argc) usage(); config = *++argv; break; case 'd': // Increase debug level. debuglvl++; break; case 'e': // Log to stderr only. stderrOnly = true; break; case 'g': // Group. if (!--argc) usage(); group = *++argv; break; case 'j': // Jail. if (!--argc) usage(); jail = *++argv; break; case 'l': // Log to stderr too. logstd = true; break; case 'n': // Do not detach. nodaemon = true; break; case 'u': // User. if (!--argc) usage(); user = *++argv; break; default: usage(); } } if (!cp) usage(); else if (--argc) usage(); sockarg = cp; // Daemonize. // Do not change user and/or group now, since we need full // permissions for sockets. try { daemon.program(name()); daemon.lock_file(FilePath(LOCKDIR) + daemon.program()); daemon.pid_file(FilePath(RUNDIR) + (daemon.program() + ".pid")); daemon.user(user); daemon.group(group); daemon.log_to_stderr(logstd); daemon.jail(jail); daemon.block_signals(); daemon.ignore_signals(); if (!nodaemon) daemon.detach(); daemon.close_all(!stderrOnly); daemon.open_log(LOG_PID | LOG_NDELAY, LOG_MAIL); ::signal(SIGABRT, SIG_DFL); ::signal(SIGTERM, SIG_DFL); ::signal(SIGINT, SIG_DFL); ::signal(SIGILL, SIG_DFL); ::signal(SIGIOT, SIG_DFL); ::signal(SIGBUS, SIG_DFL); ::signal(SIGFPE, SIG_DFL); ::signal(SIGSEGV, SIG_DFL); ::signal(SIGSTKFLT, SIG_DFL); daemon.unblock_signals(); if (!nodaemon) { if (!daemon.lock()) { log(name() + " already running: exit"); closelog(); return 1; } daemon.write_pid(); } } catch (std::exception& e) { die = true; log(e.what(), LOG_CRIT); closelog(); return 1; } try { daemon.go_home(); // Harden our umask so that the new socket gets created // securely. umask(0077); // Register to the milter interface. socket(sockarg); debug(debuglvl); if (initialize<Undervest>() != MI_SUCCESS) { log("Cannot initialize milter interface", LOG_CRIT); closelog(); return 1; } // If we need to set the uid/gid/jail, do it now. daemon.incarcerate(); daemon.change_identity(); // Start the scheduler. schedThread = std::thread(&Scheduler::run, std::ref(sched)); // Read configuration file and domain data. reload(); if (&(*conf) == NULL) { sched.stop(); return 1; } // Start a thread to monitor and process our signals. // Note: Signals SIGTERM, SIGHUP and SIGABRT are processed // by the milter library. sigThread = std::thread(&Globals::reloader, std::ref(*this)); // Enter the milter service loop. if (start(static_cast<void *>(this)) == MI_FAILURE) throw std::runtime_error("Cannot run the milter"); } catch (std::exception& e) { die = true; sched.stop(); log(e.what(), LOG_CRIT); if (!nodaemon) { daemon.delete_pid(); daemon.delete_lock(); } closelog(); return 1; } die = true; sched.stop(); if (!nodaemon) { daemon.delete_pid(); daemon.delete_lock(); } closelog(); return 0; }