xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_main.c (revision 60414d47)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5fee9b58dSjrutt  * Common Development and Distribution License (the "License").
6fee9b58dSjrutt  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22f6e214c7SGavin Maltby  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/stat.h>
277c478bd9Sstevel@tonic-gate #include <sys/wait.h>
287c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
297c478bd9Sstevel@tonic-gate #include <sys/resource.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <priv_utils.h>
327c478bd9Sstevel@tonic-gate #include <signal.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <limits.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
39f6e214c7SGavin Maltby #include <zone.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <fmd_error.h>
427c478bd9Sstevel@tonic-gate #include <fmd_string.h>
437c478bd9Sstevel@tonic-gate #include <fmd_conf.h>
447c478bd9Sstevel@tonic-gate #include <fmd_dispq.h>
457c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
467c478bd9Sstevel@tonic-gate #include <fmd.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate fmd_t fmd;
49*60414d47SToomas Soome mutex_t _svcstate_lock = ERRORCHECKMUTEX;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * For DEBUG builds, we define a set of hooks for libumem that provide useful
537c478bd9Sstevel@tonic-gate  * default settings for the allocator's debugging facilities.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate #ifdef	DEBUG
567c478bd9Sstevel@tonic-gate const char *
_umem_debug_init()577c478bd9Sstevel@tonic-gate _umem_debug_init()
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	return ("default,verbose"); /* $UMEM_DEBUG setting */
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate const char *
_umem_logging_init(void)637c478bd9Sstevel@tonic-gate _umem_logging_init(void)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	return ("fail,contents"); /* $UMEM_LOGGING setting */
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * We use a two-phase algorithm for becoming a daemon because we want the
717c478bd9Sstevel@tonic-gate  * daemon process (the child) to do the work of becoming MT-hot and opening our
727c478bd9Sstevel@tonic-gate  * event transport.  Since these operations can fail and need to result in the
737c478bd9Sstevel@tonic-gate  * daemon failing to start, the parent must wait until fmd_run() completes to
747c478bd9Sstevel@tonic-gate  * know whether it can return zero or non-zero status to the invoking command.
757c478bd9Sstevel@tonic-gate  * The parent waits on a pipe inside this function to read the exit status.
767c478bd9Sstevel@tonic-gate  * The child gets the write-end of the pipe returned by daemonize_init() and
777c478bd9Sstevel@tonic-gate  * then fmd_run() uses the pipe to set the exit status and detach the parent.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate static int
daemonize_init(void)807c478bd9Sstevel@tonic-gate daemonize_init(void)
817c478bd9Sstevel@tonic-gate {
82f6e214c7SGavin Maltby 	const char *gzp1, *gzp2, *gzp3, *gzp4, *gzp5;
837c478bd9Sstevel@tonic-gate 	int status, pfds[2];
847c478bd9Sstevel@tonic-gate 	sigset_t set, oset;
857c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
867c478bd9Sstevel@tonic-gate 	char path[PATH_MAX];
877c478bd9Sstevel@tonic-gate 	pid_t pid;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	/*
907c478bd9Sstevel@tonic-gate 	 * Set our per-process core file path to leave core files in our
917c478bd9Sstevel@tonic-gate 	 * var/fm/fmd directory, named after the PID to aid in debugging,
927c478bd9Sstevel@tonic-gate 	 * and make sure that there is no restriction on core file size.
937c478bd9Sstevel@tonic-gate 	 */
947c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path),
957c478bd9Sstevel@tonic-gate 	    "%s/var/fm/fmd/core.%s.%%p", fmd.d_rootdir, fmd.d_pname);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	(void) core_set_process_path(path, strlen(path) + 1, fmd.d_pid);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = RLIM_INFINITY;
1007c478bd9Sstevel@tonic-gate 	rlim.rlim_max = RLIM_INFINITY;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	(void) setrlimit(RLIMIT_CORE, &rlim);
1037c478bd9Sstevel@tonic-gate 
1040166a357SEric Schrock 	/*
1050166a357SEric Schrock 	 * Claim all the file descriptors we can.
1060166a357SEric Schrock 	 */
1070166a357SEric Schrock 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
1080166a357SEric Schrock 		rlim.rlim_cur = rlim.rlim_max;
1090166a357SEric Schrock 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
1100166a357SEric Schrock 	}
1110166a357SEric Schrock 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * Reset all of our privilege sets to the minimum set of required
1147c478bd9Sstevel@tonic-gate 	 * privileges.  We continue to run as root so that files we create
1157c478bd9Sstevel@tonic-gate 	 * such as logs and checkpoints are secured in the /var filesystem.
116f6e214c7SGavin Maltby 	 *
117f6e214c7SGavin Maltby 	 * In a non-global zone some of the privileges we retain in a
118f6e214c7SGavin Maltby 	 * global zone are only optionally assigned to the zone, while others
119f6e214c7SGavin Maltby 	 * are prohibited:
120f6e214c7SGavin Maltby 	 *
121f6e214c7SGavin Maltby 	 * PRIV_PROC_PRIOCNTL (optional in a non-global zone):
122f6e214c7SGavin Maltby 	 *	There are no calls to priocntl(2) in fmd or plugins.
123f6e214c7SGavin Maltby 	 *
124f6e214c7SGavin Maltby 	 * PRIV_SYS_CONFIG (prohibited in a non-global zone):
125f6e214c7SGavin Maltby 	 *	Required, I think, for sysevent_post_event and/or
126f6e214c7SGavin Maltby 	 *	other legacy sysevent activity.  Legacy sysevent is not
127f6e214c7SGavin Maltby 	 *	supported in a non-global zone.
128f6e214c7SGavin Maltby 	 *
129f6e214c7SGavin Maltby 	 * PRIV_SYS_DEVICES (prohibited in a non-global zone):
130f6e214c7SGavin Maltby 	 *	Needed in the global zone for ioctls on various drivers
131f6e214c7SGavin Maltby 	 *	such as memory-controller drivers.
132f6e214c7SGavin Maltby 	 *
133f6e214c7SGavin Maltby 	 * PRIV_SYS_RES_CONFIG (prohibited in a non-global zone):
134f6e214c7SGavin Maltby 	 *	Require for p_online(2) calls to offline cpus.
135f6e214c7SGavin Maltby 	 *
136f6e214c7SGavin Maltby 	 * PRIV_SYS_NET_CONFIG (prohibited in a non-global zone):
137f6e214c7SGavin Maltby 	 *	Required for ipsec in etm (which also requires
138f6e214c7SGavin Maltby 	 *	PRIV_NET_PRIVADDR).
139f6e214c7SGavin Maltby 	 *
140f6e214c7SGavin Maltby 	 * We do without those privileges in a non-global zone.  It's
141f6e214c7SGavin Maltby 	 * possible that there are other privs we could drop since
142f6e214c7SGavin Maltby 	 * hardware-related plugins are not present.
1437c478bd9Sstevel@tonic-gate 	 */
144f6e214c7SGavin Maltby 	if (getzoneid() == GLOBAL_ZONEID) {
145f6e214c7SGavin Maltby 		gzp1 = PRIV_PROC_PRIOCNTL;
146f6e214c7SGavin Maltby 		gzp2 = PRIV_SYS_CONFIG;
147f6e214c7SGavin Maltby 		gzp3 = PRIV_SYS_DEVICES;
148f6e214c7SGavin Maltby 		gzp4 = PRIV_SYS_RES_CONFIG;
149f6e214c7SGavin Maltby 		gzp5 = PRIV_SYS_NET_CONFIG;
150f6e214c7SGavin Maltby 	} else {
151f6e214c7SGavin Maltby 		gzp1 = gzp2 = gzp3 = gzp4 = gzp5 = NULL;
152f6e214c7SGavin Maltby 	}
153f6e214c7SGavin Maltby 
1547c478bd9Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
1557c478bd9Sstevel@tonic-gate 	    0, 0, /* run as uid 0 and gid 0 */
1567c478bd9Sstevel@tonic-gate 	    PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH,
1577c478bd9Sstevel@tonic-gate 	    PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_PROC_OWNER,
158f6e214c7SGavin Maltby 	    PRIV_SYS_ADMIN, PRIV_NET_PRIVADDR,
159f6e214c7SGavin Maltby 	    gzp1, gzp2, gzp3, gzp4, gzp5, NULL) != 0)
1607c478bd9Sstevel@tonic-gate 		fmd_error(EFMD_EXIT, "additional privileges required to run\n");
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * Block all signals prior to the fork and leave them blocked in the
1647c478bd9Sstevel@tonic-gate 	 * parent so we don't get in a situation where the parent gets SIGINT
1657c478bd9Sstevel@tonic-gate 	 * and returns non-zero exit status and the child is actually running.
1667c478bd9Sstevel@tonic-gate 	 * In the child, restore the signal mask once we've done our setsid().
1677c478bd9Sstevel@tonic-gate 	 */
1687c478bd9Sstevel@tonic-gate 	(void) sigfillset(&set);
1697c478bd9Sstevel@tonic-gate 	(void) sigdelset(&set, SIGABRT);
1707c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (pipe(pfds) == -1)
1737c478bd9Sstevel@tonic-gate 		fmd_error(EFMD_EXIT, "failed to create pipe for daemonize");
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == -1)
1767c478bd9Sstevel@tonic-gate 		fmd_error(EFMD_EXIT, "failed to fork into background");
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * If we're the parent process, wait for either the child to send us
1807c478bd9Sstevel@tonic-gate 	 * the appropriate exit status over the pipe or for the read to fail
1817c478bd9Sstevel@tonic-gate 	 * (presumably with 0 for EOF if our child terminated abnormally).
1827c478bd9Sstevel@tonic-gate 	 * If the read fails, exit with either the child's exit status if it
1837c478bd9Sstevel@tonic-gate 	 * exited or with FMD_EXIT_ERROR if it died from a fatal signal.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if (pid != 0) {
1867c478bd9Sstevel@tonic-gate 		(void) close(pfds[1]);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
1897c478bd9Sstevel@tonic-gate 			_exit(status);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
1927c478bd9Sstevel@tonic-gate 			_exit(WEXITSTATUS(status));
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 		_exit(FMD_EXIT_ERROR);
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	fmd.d_pid = getpid();
1987c478bd9Sstevel@tonic-gate 	(void) setsid();
1997c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
2007c478bd9Sstevel@tonic-gate 	(void) chdir("/");
2017c478bd9Sstevel@tonic-gate 	(void) umask(022);
2027c478bd9Sstevel@tonic-gate 	(void) close(pfds[0]);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	return (pfds[1]);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static void
daemonize_fini(int fd)2087c478bd9Sstevel@tonic-gate daemonize_fini(int fd)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	(void) close(fd);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
2137c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
2147c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
2157c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
2167c478bd9Sstevel@tonic-gate 		(void) close(fd);
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate static void
handler(int sig)2217c478bd9Sstevel@tonic-gate handler(int sig)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	if (fmd.d_signal == 0)
2247c478bd9Sstevel@tonic-gate 		fmd.d_signal = sig;
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate static int
usage(const char * arg0,FILE * fp)2287c478bd9Sstevel@tonic-gate usage(const char *arg0, FILE *fp)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
2317c478bd9Sstevel@tonic-gate 	    "Usage: %s [-V] [-f file] [-o opt=val] [-R dir]\n", arg0);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	return (FMD_EXIT_USAGE);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])2377c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	const char *opt_f = NULL, *opt_R = NULL;
2407c478bd9Sstevel@tonic-gate 	const char optstr[] = "f:o:R:V";
2417c478bd9Sstevel@tonic-gate 	int c, pfd = -1, opt_V = 0;
2427c478bd9Sstevel@tonic-gate 	char *p;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	struct sigaction act;
2457c478bd9Sstevel@tonic-gate 	sigset_t set;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/*
2487c478bd9Sstevel@tonic-gate 	 * Parse the command-line once to validate all options and retrieve
2497c478bd9Sstevel@tonic-gate 	 * any overrides for our configuration file and root directory.
2507c478bd9Sstevel@tonic-gate 	 */
2517c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, optstr)) != EOF) {
2527c478bd9Sstevel@tonic-gate 		switch (c) {
2537c478bd9Sstevel@tonic-gate 		case 'f':
2547c478bd9Sstevel@tonic-gate 			opt_f = optarg;
2557c478bd9Sstevel@tonic-gate 			break;
2567c478bd9Sstevel@tonic-gate 		case 'o':
2577c478bd9Sstevel@tonic-gate 			break; /* handle -o below */
2587c478bd9Sstevel@tonic-gate 		case 'R':
2597c478bd9Sstevel@tonic-gate 			opt_R = optarg;
2607c478bd9Sstevel@tonic-gate 			break;
2617c478bd9Sstevel@tonic-gate 		case 'V':
2627c478bd9Sstevel@tonic-gate 			opt_V++;
2637c478bd9Sstevel@tonic-gate 			break;
2647c478bd9Sstevel@tonic-gate 		default:
2657c478bd9Sstevel@tonic-gate 			return (usage(argv[0], stderr));
2667c478bd9Sstevel@tonic-gate 		}
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (optind < argc)
2707c478bd9Sstevel@tonic-gate 		return (usage(argv[0], stderr));
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (opt_V) {
2737c478bd9Sstevel@tonic-gate #ifdef DEBUG
2740166a357SEric Schrock 		const char *debug = " (DEBUG)";
2757c478bd9Sstevel@tonic-gate #else
2760166a357SEric Schrock 		const char *debug = "";
2777c478bd9Sstevel@tonic-gate #endif
2780166a357SEric Schrock 		(void) printf("%s: version %s%s\n",
2790166a357SEric Schrock 		    argv[0], _fmd_version, debug);
2807c478bd9Sstevel@tonic-gate 		return (FMD_EXIT_SUCCESS);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	closefrom(STDERR_FILENO + 1);
2847c478bd9Sstevel@tonic-gate 	fmd_create(&fmd, argv[0], opt_R, opt_f);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * Now that we've initialized our global state, parse the command-line
2887c478bd9Sstevel@tonic-gate 	 * again for any configuration options specified using -o and set them.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
2917c478bd9Sstevel@tonic-gate 		if (c == 'o') {
2927c478bd9Sstevel@tonic-gate 			if ((p = strchr(optarg, '=')) == NULL) {
2937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: failed to set "
2947c478bd9Sstevel@tonic-gate 				    "option -o %s: option requires value\n",
2957c478bd9Sstevel@tonic-gate 				    fmd.d_pname, optarg);
2967c478bd9Sstevel@tonic-gate 				return (FMD_EXIT_USAGE);
2977c478bd9Sstevel@tonic-gate 			}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			*p++ = '\0'; /* strike out the delimiter */
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			if (p[0] == '"' && p[strlen(p) - 1] == '"') {
3027c478bd9Sstevel@tonic-gate 				p[strlen(p) - 1] = '\0';
3037c478bd9Sstevel@tonic-gate 				(void) fmd_stresc2chr(++p);
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 			if (fmd_conf_setprop(fmd.d_conf, optarg, p) != 0) {
3077c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3087c478bd9Sstevel@tonic-gate 				    "%s: failed to set option -o %s: %s\n",
3097c478bd9Sstevel@tonic-gate 				    fmd.d_pname, optarg, fmd_strerror(errno));
3107c478bd9Sstevel@tonic-gate 				return (FMD_EXIT_USAGE);
3117c478bd9Sstevel@tonic-gate 			}
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (fmd.d_fmd_debug & FMD_DBG_HELP) {
3167c478bd9Sstevel@tonic-gate 		fmd_help(&fmd);
3177c478bd9Sstevel@tonic-gate 		fmd_destroy(&fmd);
3187c478bd9Sstevel@tonic-gate 		return (FMD_EXIT_SUCCESS);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Update the value of fmd.d_fg based on "fg" in case it changed.  We
3237c478bd9Sstevel@tonic-gate 	 * use this property to decide whether to daemonize below.
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	(void) fmd_conf_getprop(fmd.d_conf, "fg", &fmd.d_fg);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	/*
3287c478bd9Sstevel@tonic-gate 	 * Once we're done setting our global state up, set up signal handlers
3297c478bd9Sstevel@tonic-gate 	 * for ensuring orderly termination on SIGTERM.  If we are starting in
3307c478bd9Sstevel@tonic-gate 	 * the foreground, we also use the same handler for SIGINT and SIGHUP.
3317c478bd9Sstevel@tonic-gate 	 */
3327c478bd9Sstevel@tonic-gate 	(void) sigfillset(&set);
3337c478bd9Sstevel@tonic-gate 	(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	(void) sigfillset(&act.sa_mask);
3367c478bd9Sstevel@tonic-gate 	act.sa_handler = handler;
3377c478bd9Sstevel@tonic-gate 	act.sa_flags = 0;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &act, NULL);
3407c478bd9Sstevel@tonic-gate 	(void) sigdelset(&set, SIGTERM);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (fmd.d_fg) {
3437c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGHUP, &act, NULL);
3447c478bd9Sstevel@tonic-gate 		(void) sigdelset(&set, SIGHUP);
3457c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGINT, &act, NULL);
3467c478bd9Sstevel@tonic-gate 		(void) sigdelset(&set, SIGINT);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 		(void) sigdelset(&set, SIGTSTP);
3497c478bd9Sstevel@tonic-gate 		(void) sigdelset(&set, SIGTTIN);
3507c478bd9Sstevel@tonic-gate 		(void) sigdelset(&set, SIGTTOU);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		(void) printf("%s: [ loading modules ... ", fmd.d_pname);
3537c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
3547c478bd9Sstevel@tonic-gate 	} else
3557c478bd9Sstevel@tonic-gate 		pfd = daemonize_init();
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * Prior to this point, we are single-threaded.  Once fmd_run() is
3597c478bd9Sstevel@tonic-gate 	 * called, we will be multi-threaded from this point on.  The daemon's
3607c478bd9Sstevel@tonic-gate 	 * main thread will wait at the end of this function for signals.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	fmd_run(&fmd, pfd);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (fmd.d_fg) {
3657c478bd9Sstevel@tonic-gate 		(void) printf("done ]\n");
3667c478bd9Sstevel@tonic-gate 		(void) printf("%s: [ awaiting events ]\n", fmd.d_pname);
3677c478bd9Sstevel@tonic-gate 	} else
3687c478bd9Sstevel@tonic-gate 		daemonize_fini(pfd);
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	while (!fmd.d_signal)
3717c478bd9Sstevel@tonic-gate 		(void) sigsuspend(&set);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	fmd_destroy(&fmd);
3747c478bd9Sstevel@tonic-gate 	return (FMD_EXIT_SUCCESS);
3757c478bd9Sstevel@tonic-gate }
376