Exemple #1
0
int
main(int argc, char **argv)
{
	boolean_t	is_daemon  = B_TRUE;
	boolean_t	is_verbose = B_FALSE;
	int		ipc_fd;
	int		c;
	struct rlimit	rl;

	/*
	 * -l is ignored for compatibility with old agent.
	 */

	while ((c = getopt(argc, argv, "vd:l:fa")) != EOF) {

		switch (c) {

		case 'a':
			do_adopt = B_TRUE;
			grandparent = getpid();
			break;

		case 'd':
			debug_level = strtoul(optarg, NULL, 0);
			break;

		case 'f':
			is_daemon = B_FALSE;
			break;

		case 'v':
			is_verbose = B_TRUE;
			break;

		case '?':
			(void) fprintf(stderr, "usage: %s [-a] [-d n] [-f] [-v]"
			    "\n", argv[0]);
			return (EXIT_FAILURE);

		default:
			break;
		}
	}

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	if (geteuid() != 0) {
		dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
		dhcpmsg(MSG_ERROR, "must be super-user");
		dhcpmsg_fini();
		return (EXIT_FAILURE);
	}

	if (is_daemon && daemonize() == 0) {
		dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
		dhcpmsg(MSG_ERR, "cannot become daemon, exiting");
		dhcpmsg_fini();
		return (EXIT_FAILURE);
	}

	dhcpmsg_init(argv[0], is_daemon, is_verbose, debug_level);
	(void) atexit(dhcpmsg_fini);

	tq = iu_tq_create();
	eh = iu_eh_create();

	if (eh == NULL || tq == NULL) {
		errno = ENOMEM;
		dhcpmsg(MSG_ERR, "cannot create timer queue or event handler");
		return (EXIT_FAILURE);
	}

	/*
	 * ignore most signals that could be reasonably generated.
	 */

	(void) signal(SIGTERM, graceful_shutdown);
	(void) signal(SIGQUIT, graceful_shutdown);
	(void) signal(SIGPIPE, SIG_IGN);
	(void) signal(SIGUSR1, SIG_IGN);
	(void) signal(SIGUSR2, SIG_IGN);
	(void) signal(SIGINT,  SIG_IGN);
	(void) signal(SIGHUP,  SIG_IGN);
	(void) signal(SIGCHLD, SIG_IGN);

	/*
	 * upon SIGTHAW we need to refresh any non-infinite leases.
	 */

	(void) iu_eh_register_signal(eh, SIGTHAW, refresh_ifslist, NULL);

	class_id = get_class_id();
	if (class_id != NULL)
		class_id_len = strlen(class_id);
	else
		dhcpmsg(MSG_WARNING, "get_class_id failed, continuing "
		    "with no vendor class id");

	/*
	 * the inactivity timer is enabled any time there are no
	 * interfaces under DHCP control.  if DHCP_INACTIVITY_WAIT
	 * seconds transpire without an interface under DHCP control,
	 * the agent shuts down.
	 */

	inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT,
	    inactivity_shutdown, NULL);

	/*
	 * max out the number available descriptors, just in case..
	 */

	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
		dhcpmsg(MSG_ERR, "setrlimit failed");

	(void) enable_extended_FILE_stdio(-1, -1);

	/*
	 * create the ipc channel that the agent will listen for
	 * requests on, and register it with the event handler so that
	 * `accept_event' will be called back.
	 */

	switch (dhcp_ipc_init(&ipc_fd)) {

	case 0:
		break;

	case DHCP_IPC_E_BIND:
		dhcpmsg(MSG_ERROR, "dhcp_ipc_init: cannot bind to port "
		    "%i (agent already running?)", IPPORT_DHCPAGENT);
		return (EXIT_FAILURE);

	default:
		dhcpmsg(MSG_ERROR, "dhcp_ipc_init failed");
		return (EXIT_FAILURE);
	}

	if (iu_register_event(eh, ipc_fd, POLLIN, accept_event, 0) == -1) {
		dhcpmsg(MSG_ERR, "cannot register ipc fd for messages");
		return (EXIT_FAILURE);
	}

	/*
	 * Create the global routing socket.  This is used for monitoring
	 * interface transitions, so that we learn about the kernel's Duplicate
	 * Address Detection status, and for inserting and removing default
	 * routes as learned from DHCP servers.
	 */
	rtsock_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
	if (rtsock_fd == -1) {
		dhcpmsg(MSG_ERR, "cannot open routing socket");
		return (EXIT_FAILURE);
	}
	if (iu_register_event(eh, rtsock_fd, POLLIN, rtsock_event, 0) == -1) {
		dhcpmsg(MSG_ERR, "cannot register routing socket for messages");
		return (EXIT_FAILURE);
	}

	/*
	 * if the -a (adopt) option was specified, try to adopt the
	 * kernel-managed interface before we start.
	 */

	if (do_adopt && dhcp_adopt() == 0)
		return (EXIT_FAILURE);

	/*
	 * enter the main event loop; this is where all the real work
	 * takes place (through registering events and scheduling timers).
	 * this function only returns when the agent is shutting down.
	 */

	switch (iu_handle_events(eh, tq)) {

	case -1:
		dhcpmsg(MSG_WARNING, "iu_handle_events exited abnormally");
		break;

	case DHCP_REASON_INACTIVITY:
		dhcpmsg(MSG_INFO, "no interfaces to manage, shutting down...");
		break;

	case DHCP_REASON_TERMINATE:
		dhcpmsg(MSG_INFO, "received SIGTERM, shutting down...");
		break;

	case DHCP_REASON_SIGNAL:
		dhcpmsg(MSG_WARNING, "received unexpected signal, shutting "
		    "down...");
		break;
	}

	(void) iu_eh_unregister_signal(eh, SIGTHAW, NULL);

	iu_eh_destroy(eh);
	iu_tq_destroy(tq);

	return (EXIT_SUCCESS);
}
Exemple #2
0
int
main(int argc, char **argv)
{
	dsvcd_datastore_t	**ds_table;
	dsvc_datastore_t	dd;
	dsvc_synchtype_t	synchtype;
	char			**modules;
	unsigned int		i, j;
	int			debug_level = 0;
	boolean_t		is_daemon = B_TRUE;
	boolean_t		is_verbose = B_FALSE;
	int			sig, nmodules, nsynchmods, c;
	sigset_t		sigset;
	char			signame[SIG2STR_MAX];
	char			*progname;
	void			*stackbase;
	unsigned int		stacksize = 16 * 1024;
	struct rlimit		rl;

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	/*
	 * Mask all signals except SIGABRT; doing this here ensures that
	 * all threads created through door_create() have them masked too.
	 */
	(void) sigfillset(&sigset);
	(void) sigdelset(&sigset, SIGABRT);
	(void) thr_sigsetmask(SIG_BLOCK, &sigset, NULL);

	/*
	 * Figure out our program name; just keep the final piece so that
	 * our dhcpmsg() messages don't get too long.
	 */
	progname = strrchr(argv[0], '/');
	if (progname != NULL)
		progname++;
	else
		progname = argv[0];

	/*
	 * Set the door thread creation procedure so that all of our
	 * threads are created with thread stacks with backing store.
	 */
	(void) door_server_create(doorserv_create);

	while ((c = getopt(argc, argv, "d:fv")) != EOF) {
		switch (c) {

		case 'd':
			debug_level = atoi(optarg);
			break;

		case 'f':
			is_daemon = B_FALSE;
			break;

		case 'v':
			is_verbose = B_TRUE;
			break;

		case '?':
			(void) fprintf(stderr,
			    gettext("usage: %s [-dn] [-f] [-v]\n"), progname);
			return (EXIT_FAILURE);

		default:
			break;
		}
	}

	if (geteuid() != 0) {
		dhcpmsg_init(progname, B_FALSE, is_verbose, debug_level);
		dhcpmsg(MSG_ERROR, "must be super-user");
		dhcpmsg_fini();
		return (EXIT_FAILURE);
	}

	if (is_daemon && daemonize() == 0) {
		dhcpmsg_init(progname, B_FALSE, is_verbose, debug_level);
		dhcpmsg(MSG_ERROR, "cannot become daemon, exiting");
		dhcpmsg_fini();
		return (EXIT_FAILURE);
	}

	dhcpmsg_init(progname, is_daemon, is_verbose, debug_level);
	(void) atexit(dhcpmsg_fini);

	/*
	 * Max out the number available descriptors since we need to
	 * allocate two per held lock.
	 */
	rl.rlim_cur = RLIM_INFINITY;
	rl.rlim_max = RLIM_INFINITY;
	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
		dhcpmsg(MSG_ERR, "setrlimit failed");

	(void) enable_extended_FILE_stdio(-1, -1);

	if (enumerate_dd(&modules, &nmodules) != DSVC_SUCCESS) {
		dhcpmsg(MSG_ERROR, "cannot enumerate public modules, exiting");
		return (EXIT_FAILURE);
	}

	/*
	 * NOTE: this code assumes that a module that needs dsvclockd will
	 * always need it (even as the container version is ramped).  If
	 * this becomes bogus in a future release, we'll have to make this
	 * logic more sophisticated.
	 */
	nsynchmods = nmodules;
	for (i = 0; i < nmodules; i++) {
		dd.d_resource = modules[i];
		dd.d_conver = DSVC_CUR_CONVER;
		dd.d_location = "";
		if (module_synchtype(&dd, &synchtype) != DSVC_SUCCESS) {
			dhcpmsg(MSG_WARNING, "cannot determine synchronization "
			    "type for `%s', skipping", modules[i]);
			free(modules[i]);
			modules[i] = NULL;
			nsynchmods--;
			continue;
		}
		if ((synchtype & DSVC_SYNCH_STRATMASK) != DSVC_SYNCH_DSVCD) {
			free(modules[i]);
			modules[i] = NULL;
			nsynchmods--;
		}
	}

	if (nsynchmods == 0) {
		dhcpmsg(MSG_INFO, "no public modules need synchronization");
		return (EXIT_SUCCESS);
	}

	/*
	 * Allocate the datastore table; include one extra entry so that
	 * the table is NULL-terminated.
	 */
	ds_table = calloc(nsynchmods + 1, sizeof (dsvcd_datastore_t *));
	if (ds_table == NULL) {
		dhcpmsg(MSG_ERR, "cannot allocate datastore table, exiting");
		return (EXIT_FAILURE);
	}
	ds_table[nsynchmods] = NULL;

	/*
	 * Create the datastores (which implicitly creates the doors).
	 * then sit around and wait for requests to come in on the doors.
	 */
	for (i = 0, j = 0; i < nmodules; i++) {
		if (modules[i] != NULL) {
			ds_table[j] = ds_create(modules[i], svc_lock);
			if (ds_table[j] == NULL) {
				while (j-- > 0)
					ds_destroy(ds_table[j]);
				return (EXIT_FAILURE);
			}
			free(modules[i]);
			j++;
		}
	}
	free(modules);

	stackbase = stack_create(&stacksize);
	if (stackbase == NULL)
		dhcpmsg(MSG_ERR, "cannot create reaper stack; containers "
		    "will not be reaped");
	else {
		errno = thr_create(stackbase, stacksize, reaper, ds_table,
		    THR_DAEMON, NULL);
		if (errno != 0) {
			dhcpmsg(MSG_ERR, "cannot create reaper thread; "
			    "containers will not be reaped");
			stack_destroy(stackbase, stacksize);
		}
	}

	/*
	 * Synchronously wait for a QUIT, TERM, or INT, then shutdown.
	 */
	(void) sigemptyset(&sigset);
	(void) sigaddset(&sigset, SIGQUIT);
	(void) sigaddset(&sigset, SIGTERM);
	(void) sigaddset(&sigset, SIGINT);

	(void) sigwait(&sigset, &sig);
	if (sig != SIGTERM && sig != SIGQUIT && sig != SIGINT)
		dhcpmsg(MSG_WARNING, "received unexpected signal");

	if (sig2str(sig, signame) == -1)
		(void) strlcpy(signame, "???", sizeof (signame));

	dhcpmsg(MSG_INFO, "shutting down via SIG%s", signame);

	for (i = 0; i < nsynchmods; i++)
		ds_destroy(ds_table[i]);

	return (EXIT_SUCCESS);
}