Ejemplo n.º 1
0
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;
}