xref: /titanic_51/usr/src/cmd/svc/startd/fork.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2012 Milan Jurik. All rights reserved.
25  */
26 
27 /*
28  * fork.c - safe forking for svc.startd
29  *
30  * fork_configd() and fork_sulogin() are related, special cases that handle the
31  * spawning of specific client processes for svc.startd.
32  */
33 
34 #include <sys/contract/process.h>
35 #include <sys/corectl.h>
36 #include <sys/ctfs.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/uio.h>
40 #include <sys/wait.h>
41 #include <assert.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <libcontract.h>
45 #include <libcontract_priv.h>
46 #include <libscf_priv.h>
47 #include <limits.h>
48 #include <poll.h>
49 #include <port.h>
50 #include <signal.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <utmpx.h>
57 #include <spawn.h>
58 
59 #include "manifest_hash.h"
60 #include "configd_exit.h"
61 #include "protocol.h"
62 #include "startd.h"
63 
64 static	struct	utmpx	*utmpp;	/* pointer for getutxent() */
65 
66 pid_t
67 startd_fork1(int *forkerr)
68 {
69 	pid_t p;
70 
71 	/*
72 	 * prefork stack
73 	 */
74 	wait_prefork();
75 
76 	p = fork1();
77 
78 	if (p == -1 && forkerr != NULL)
79 		*forkerr = errno;
80 
81 	/*
82 	 * postfork stack
83 	 */
84 	wait_postfork(p);
85 
86 	return (p);
87 }
88 
89 /*
90  * void fork_mount(char *, char *)
91  *   Run mount(1M) with the given options and mount point.  (mount(1M) has much
92  *   hidden knowledge; it's much less correct to reimplement that logic here to
93  *   save a fork(2)/exec(2) invocation.)
94  */
95 int
96 fork_mount(char *path, char *opts)
97 {
98 	pid_t pid;
99 	uint_t tries = 0;
100 	int status;
101 
102 	for (pid = fork1(); pid == -1; pid = fork1()) {
103 		if (++tries > MAX_MOUNT_RETRIES)
104 			return (-1);
105 
106 		(void) sleep(tries);
107 	}
108 
109 	if (pid != 0) {
110 		(void) waitpid(pid, &status, 0);
111 
112 		/*
113 		 * If our mount(1M) invocation exited by peculiar means, or with
114 		 * a non-zero status, our mount likelihood is low.
115 		 */
116 		if (!WIFEXITED(status) ||
117 		    WEXITSTATUS(status) != 0)
118 			return (-1);
119 
120 		return (0);
121 	}
122 
123 	(void) execl("/sbin/mount", "mount", "-o", opts, path, NULL);
124 
125 	return (-1);
126 }
127 
128 /*
129  * pid_t fork_common(...)
130  *   Common routine used by fork_sulogin, fork_emi, and fork_configd to
131  *   fork a process in a contract with the provided terms.  Invokes
132  *   fork_sulogin (with its no-fork argument set) on errors.
133  */
134 static pid_t
135 fork_common(const char *name, const char *svc_fmri, int retries, ctid_t *ctidp,
136     uint_t inf, uint_t crit, uint_t fatal, uint_t param, uint64_t cookie)
137 {
138 	uint_t tries = 0;
139 	int ctfd, err;
140 	pid_t pid;
141 
142 	/*
143 	 * Establish process contract terms.
144 	 */
145 	if ((ctfd = open64(CTFS_ROOT "/process/template", O_RDWR)) == -1) {
146 		fork_sulogin(B_TRUE, "Could not open process contract template "
147 		    "for %s: %s\n", name, strerror(errno));
148 		/* NOTREACHED */
149 	}
150 
151 	err = ct_tmpl_set_critical(ctfd, crit);
152 	err |= ct_pr_tmpl_set_fatal(ctfd, fatal);
153 	err |= ct_tmpl_set_informative(ctfd, inf);
154 	err |= ct_pr_tmpl_set_param(ctfd, param);
155 	err |= ct_tmpl_set_cookie(ctfd, cookie);
156 	err |= ct_pr_tmpl_set_svc_fmri(ctfd, svc_fmri);
157 	err |= ct_pr_tmpl_set_svc_aux(ctfd, name);
158 	if (err) {
159 		(void) close(ctfd);
160 		fork_sulogin(B_TRUE, "Could not set %s process contract "
161 		    "terms\n", name);
162 		/* NOTREACHED */
163 	}
164 
165 	if (err = ct_tmpl_activate(ctfd)) {
166 		(void) close(ctfd);
167 		fork_sulogin(B_TRUE, "Could not activate %s process contract "
168 		    "template: %s\n", name, strerror(err));
169 		/* NOTREACHED */
170 	}
171 
172 	/*
173 	 * Attempt to fork "retries" times.
174 	 */
175 	for (pid = fork1(); pid == -1; pid = fork1()) {
176 		if (++tries > retries) {
177 			/*
178 			 * When we exit the sulogin session, init(1M)
179 			 * will restart svc.startd(1M).
180 			 */
181 			err = errno;
182 			(void) ct_tmpl_clear(ctfd);
183 			(void) close(ctfd);
184 			fork_sulogin(B_TRUE, "Could not fork to start %s: %s\n",
185 			    name, strerror(err));
186 			/* NOTREACHED */
187 		}
188 		(void) sleep(tries);
189 	}
190 
191 	/*
192 	 * Clean up, return pid and ctid.
193 	 */
194 	if (pid != 0 && (errno = contract_latest(ctidp)) != 0)
195 		uu_die("Could not get new contract id for %s\n", name);
196 	(void) ct_tmpl_clear(ctfd);
197 	(void) close(ctfd);
198 
199 	return (pid);
200 }
201 
202 /*
203  * void fork_sulogin(boolean_t, const char *, ...)
204  *   When we are invoked with the -s flag from boot (or run into an unfixable
205  *   situation), we run a private copy of sulogin.  When the sulogin session
206  *   is ended, we continue.  This is the last fallback action for system
207  *   maintenance.
208  *
209  *   If immediate is true, fork_sulogin() executes sulogin(1M) directly, without
210  *   forking.
211  *
212  *   Because fork_sulogin() is needed potentially before we daemonize, we leave
213  *   it outside the wait_register() framework.
214  */
215 /*PRINTFLIKE2*/
216 void
217 fork_sulogin(boolean_t immediate, const char *format, ...)
218 {
219 	va_list args;
220 	int fd_console;
221 
222 	(void) printf("Requesting System Maintenance Mode\n");
223 
224 	if (!booting_to_single_user)
225 		(void) printf("(See /lib/svc/share/README for more "
226 		    "information.)\n");
227 
228 	va_start(args, format);
229 	(void) vprintf(format, args);
230 	va_end(args);
231 
232 	if (!immediate) {
233 		ctid_t	ctid;
234 		pid_t	pid;
235 
236 		pid = fork_common("sulogin", SVC_SULOGIN_FMRI,
237 		    MAX_SULOGIN_RETRIES, &ctid, CT_PR_EV_HWERR, 0,
238 		    CT_PR_EV_HWERR, CT_PR_PGRPONLY, SULOGIN_COOKIE);
239 
240 		if (pid != 0) {
241 			(void) waitpid(pid, NULL, 0);
242 			contract_abandon(ctid);
243 			return;
244 		}
245 		/* close all inherited fds */
246 		closefrom(0);
247 	} else {
248 		(void) printf("Directly executing sulogin.\n");
249 		/*
250 		 * Can't call closefrom() in this MT section
251 		 * so safely close a minimum set of fds.
252 		 */
253 		(void) close(STDIN_FILENO);
254 		(void) close(STDOUT_FILENO);
255 		(void) close(STDERR_FILENO);
256 	}
257 
258 	(void) setpgrp();
259 
260 	/* open the console for sulogin */
261 	if ((fd_console = open("/dev/console", O_RDWR)) >= 0) {
262 		if (fd_console != STDIN_FILENO)
263 			while (dup2(fd_console, STDIN_FILENO) < 0 &&
264 			    errno == EINTR)
265 				;
266 		if (fd_console != STDOUT_FILENO)
267 			while (dup2(fd_console, STDOUT_FILENO) < 0 &&
268 			    errno == EINTR)
269 				;
270 		if (fd_console != STDERR_FILENO)
271 			while (dup2(fd_console, STDERR_FILENO) < 0 &&
272 			    errno == EINTR)
273 				;
274 		if (fd_console > STDERR_FILENO)
275 			(void) close(fd_console);
276 	}
277 
278 	setutxent();
279 	while ((utmpp = getutxent()) != NULL) {
280 		if (strcmp(utmpp->ut_user, "LOGIN") != 0) {
281 			if (strcmp(utmpp->ut_line, "console") == 0) {
282 				(void) kill(utmpp->ut_pid, 9);
283 				break;
284 			}
285 		}
286 	}
287 
288 	(void) execl("/sbin/sulogin", "sulogin", NULL);
289 
290 	uu_warn("Could not exec() sulogin");
291 
292 	exit(1);
293 }
294 
295 #define	CONFIGD_PATH	"/lib/svc/bin/svc.configd"
296 
297 /*
298  * void fork_configd(int status)
299  *   We are interested in exit events (since the parent's exiting means configd
300  *   is ready to run and since the child's exiting indicates an error case) and
301  *   in empty events.  This means we have a unique template for initiating
302  *   configd.
303  */
304 void
305 fork_configd(int exitstatus)
306 {
307 	pid_t pid;
308 	ctid_t ctid = -1;
309 	int err;
310 	char path[PATH_MAX];
311 
312 	/*
313 	 * Checking the existatus for the potential failure of the
314 	 * daemonized svc.configd.  If this is not the first time
315 	 * through, but a call from the svc.configd monitoring thread
316 	 * after a failure this is the status that is expected.  Other
317 	 * failures are exposed during initialization or are fixed
318 	 * by a restart (e.g door closings).
319 	 *
320 	 * If this is on-disk database corruption it will also be
321 	 * caught by a restart but could be cleared before the restart.
322 	 *
323 	 * Or this could be internal database corruption due to a
324 	 * rogue service that needs to be cleared before restart.
325 	 */
326 	if (WEXITSTATUS(exitstatus) == CONFIGD_EXIT_DATABASE_BAD) {
327 		fork_sulogin(B_FALSE, "svc.configd exited with database "
328 		    "corrupt error after initialization of the repository\n");
329 	}
330 
331 retry:
332 	log_framework(LOG_DEBUG, "fork_configd trying to start svc.configd\n");
333 
334 	/*
335 	 * If we're retrying, we will have an old contract lying around
336 	 * from the failure.  Since we're going to be creating a new
337 	 * contract shortly, we abandon the old one now.
338 	 */
339 	if (ctid != -1)
340 		contract_abandon(ctid);
341 	ctid = -1;
342 
343 	pid = fork_common("svc.configd", SCF_SERVICE_CONFIGD,
344 	    MAX_CONFIGD_RETRIES, &ctid, 0, CT_PR_EV_EXIT, 0,
345 	    CT_PR_INHERIT | CT_PR_REGENT, CONFIGD_COOKIE);
346 
347 	if (pid != 0) {
348 		int exitstatus;
349 
350 		st->st_configd_pid = pid;
351 
352 		if (waitpid(pid, &exitstatus, 0) == -1) {
353 			fork_sulogin(B_FALSE, "waitpid on svc.configd "
354 			    "failed: %s\n", strerror(errno));
355 		} else if (WIFEXITED(exitstatus)) {
356 			char *errstr;
357 
358 			/*
359 			 * Examine exitstatus.  This will eventually get more
360 			 * complicated, as we will want to teach startd how to
361 			 * invoke configd with alternate repositories, etc.
362 			 *
363 			 * Note that exec(2) failure results in an exit status
364 			 * of 1, resulting in the default clause below.
365 			 */
366 
367 			/*
368 			 * Assign readable strings to cases we don't handle, or
369 			 * have error outcomes that cannot be eliminated.
370 			 */
371 			switch (WEXITSTATUS(exitstatus)) {
372 			case CONFIGD_EXIT_BAD_ARGS:
373 				errstr = "bad arguments";
374 				break;
375 
376 			case CONFIGD_EXIT_DATABASE_BAD:
377 				errstr = "database corrupt";
378 				break;
379 
380 			case CONFIGD_EXIT_DATABASE_LOCKED:
381 				errstr = "database locked";
382 				break;
383 			case CONFIGD_EXIT_INIT_FAILED:
384 				errstr = "initialization failure";
385 				break;
386 			case CONFIGD_EXIT_DOOR_INIT_FAILED:
387 				errstr = "door initialization failure";
388 				break;
389 			case CONFIGD_EXIT_DATABASE_INIT_FAILED:
390 				errstr = "database initialization failure";
391 				break;
392 			case CONFIGD_EXIT_NO_THREADS:
393 				errstr = "no threads available";
394 				break;
395 			case CONFIGD_EXIT_LOST_MAIN_DOOR:
396 				errstr = "lost door server attachment";
397 				break;
398 			case 1:
399 				errstr = "execution failure";
400 				break;
401 			default:
402 				errstr = "unknown error";
403 				break;
404 			}
405 
406 			/*
407 			 * Remedial actions for various configd failures.
408 			 */
409 			switch (WEXITSTATUS(exitstatus)) {
410 			case CONFIGD_EXIT_OKAY:
411 				break;
412 
413 			case CONFIGD_EXIT_DATABASE_LOCKED:
414 				/* attempt remount of / read-write */
415 				if (fs_is_read_only("/", NULL) == 1) {
416 					if (fs_remount("/") == -1)
417 						fork_sulogin(B_FALSE,
418 						    "remount of root "
419 						    "filesystem failed\n");
420 
421 					goto retry;
422 				}
423 				break;
424 
425 			default:
426 				fork_sulogin(B_FALSE, "svc.configd exited "
427 				    "with status %d (%s)\n",
428 				    WEXITSTATUS(exitstatus), errstr);
429 				goto retry;
430 			}
431 		} else if (WIFSIGNALED(exitstatus)) {
432 			char signame[SIG2STR_MAX];
433 
434 			if (sig2str(WTERMSIG(exitstatus), signame))
435 				(void) snprintf(signame, SIG2STR_MAX,
436 				    "signum %d", WTERMSIG(exitstatus));
437 
438 			fork_sulogin(B_FALSE, "svc.configd signalled:"
439 			    " %s\n", signame);
440 
441 			goto retry;
442 		} else {
443 			fork_sulogin(B_FALSE, "svc.configd non-exit "
444 			    "condition: 0x%x\n", exitstatus);
445 
446 			goto retry;
447 		}
448 
449 		/*
450 		 * Announce that we have a valid svc.configd status.
451 		 */
452 		MUTEX_LOCK(&st->st_configd_live_lock);
453 		st->st_configd_lives = 1;
454 		err = pthread_cond_broadcast(&st->st_configd_live_cv);
455 		assert(err == 0);
456 		MUTEX_UNLOCK(&st->st_configd_live_lock);
457 
458 		log_framework(LOG_DEBUG, "fork_configd broadcasts configd is "
459 		    "live\n");
460 		return;
461 	}
462 
463 	/*
464 	 * Set our per-process core file path to leave core files in
465 	 * /etc/svc/volatile directory, named after the PID to aid in debugging.
466 	 */
467 	(void) snprintf(path, sizeof (path),
468 	    "/etc/svc/volatile/core.configd.%%p");
469 
470 	(void) core_set_process_path(path, strlen(path) + 1, getpid());
471 
472 	log_framework(LOG_DEBUG, "executing svc.configd\n");
473 
474 	(void) execl(CONFIGD_PATH, CONFIGD_PATH, NULL);
475 
476 	/*
477 	 * Status code is used above to identify configd exec failure.
478 	 */
479 	exit(1);
480 }
481 
482 void *
483 fork_configd_thread(void *vctid)
484 {
485 	int fd, err;
486 	ctid_t configd_ctid = (ctid_t)vctid;
487 
488 	if (configd_ctid == -1) {
489 		log_framework(LOG_DEBUG,
490 		    "fork_configd_thread starting svc.configd\n");
491 		fork_configd(0);
492 	} else {
493 		/*
494 		 * configd_ctid is known:  we broadcast and continue.
495 		 * test contract for appropriate state by verifying that
496 		 * there is one or more processes within it?
497 		 */
498 		log_framework(LOG_DEBUG,
499 		    "fork_configd_thread accepting svc.configd with CTID %ld\n",
500 		    configd_ctid);
501 		MUTEX_LOCK(&st->st_configd_live_lock);
502 		st->st_configd_lives = 1;
503 		(void) pthread_cond_broadcast(&st->st_configd_live_cv);
504 		MUTEX_UNLOCK(&st->st_configd_live_lock);
505 	}
506 
507 	fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY);
508 	if (fd == -1)
509 		uu_die("process bundle open failed");
510 
511 	/*
512 	 * Make sure we get all events (including those generated by configd
513 	 * before this thread was started).
514 	 */
515 	err = ct_event_reset(fd);
516 	assert(err == 0);
517 
518 	for (;;) {
519 		int efd, sfd;
520 		ct_evthdl_t ev;
521 		uint32_t type;
522 		ctevid_t evid;
523 		ct_stathdl_t status;
524 		ctid_t ctid;
525 		uint64_t cookie;
526 		pid_t pid;
527 
528 		if (err = ct_event_read_critical(fd, &ev)) {
529 			assert(err != EINVAL && err != EAGAIN);
530 			log_error(LOG_WARNING,
531 			    "Error reading next contract event: %s",
532 			    strerror(err));
533 			continue;
534 		}
535 
536 		evid = ct_event_get_evid(ev);
537 		ctid = ct_event_get_ctid(ev);
538 		type = ct_event_get_type(ev);
539 
540 		/* Fetch cookie. */
541 		sfd = contract_open(ctid, "process", "status", O_RDONLY);
542 		if (sfd < 0) {
543 			ct_event_free(ev);
544 			continue;
545 		}
546 
547 		if (err = ct_status_read(sfd, CTD_COMMON, &status)) {
548 			log_framework(LOG_WARNING, "Could not get status for "
549 			    "contract %ld: %s\n", ctid, strerror(err));
550 
551 			ct_event_free(ev);
552 			startd_close(sfd);
553 			continue;
554 		}
555 
556 		cookie = ct_status_get_cookie(status);
557 
558 		ct_status_free(status);
559 
560 		startd_close(sfd);
561 
562 		/*
563 		 * Don't process events from contracts we aren't interested in.
564 		 */
565 		if (cookie != CONFIGD_COOKIE) {
566 			ct_event_free(ev);
567 			continue;
568 		}
569 
570 		if (type == CT_PR_EV_EXIT) {
571 			int exitstatus;
572 
573 			(void) ct_pr_event_get_pid(ev, &pid);
574 			(void) ct_pr_event_get_exitstatus(ev,
575 			    &exitstatus);
576 
577 			if (st->st_configd_pid != pid) {
578 				/*
579 				 * This is the child exiting, so we
580 				 * abandon the contract and restart
581 				 * configd.
582 				 */
583 				contract_abandon(ctid);
584 				fork_configd(exitstatus);
585 			}
586 		}
587 
588 		efd = contract_open(ctid, "process", "ctl", O_WRONLY);
589 		if (efd != -1) {
590 			(void) ct_ctl_ack(efd, evid);
591 			startd_close(efd);
592 		}
593 
594 		ct_event_free(ev);
595 
596 	}
597 
598 	/*NOTREACHED*/
599 	return (NULL);
600 }
601 
602 void
603 fork_rc_script(char rl, const char *arg, boolean_t wait)
604 {
605 	pid_t pid;
606 	int tmpl, err, stat;
607 	char path[20] = "/sbin/rc.", log[20] = "rc..log", timebuf[20];
608 	time_t now;
609 	struct tm ltime;
610 	size_t sz;
611 	char *pathenv;
612 	char **nenv;
613 
614 	path[8] = rl;
615 
616 	tmpl = open64(CTFS_ROOT "/process/template", O_RDWR);
617 	if (tmpl >= 0) {
618 		err = ct_tmpl_set_critical(tmpl, 0);
619 		assert(err == 0);
620 
621 		err = ct_tmpl_set_informative(tmpl, 0);
622 		assert(err == 0);
623 
624 		err = ct_pr_tmpl_set_fatal(tmpl, 0);
625 		assert(err == 0);
626 
627 		err = ct_tmpl_activate(tmpl);
628 		assert(err == 0);
629 
630 		err = close(tmpl);
631 		assert(err == 0);
632 	} else {
633 		uu_warn("Could not create contract template for %s.\n", path);
634 	}
635 
636 	pid = startd_fork1(NULL);
637 	if (pid < 0) {
638 		return;
639 	} else if (pid != 0) {
640 		/* parent */
641 		if (wait) {
642 			do
643 				err = waitpid(pid, &stat, 0);
644 			while (err != 0 && errno == EINTR)
645 				;
646 
647 			if (!WIFEXITED(stat)) {
648 				log_framework(LOG_INFO,
649 				    "%s terminated with waitpid() status %d.\n",
650 				    path, stat);
651 			} else if (WEXITSTATUS(stat) != 0) {
652 				log_framework(LOG_INFO,
653 				    "%s failed with status %d.\n", path,
654 				    WEXITSTATUS(stat));
655 			}
656 		}
657 
658 		return;
659 	}
660 
661 	/* child */
662 
663 	log[2] = rl;
664 
665 	setlog(log);
666 
667 	now = time(NULL);
668 	sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
669 	    localtime_r(&now, &ltime));
670 	assert(sz != 0);
671 
672 	(void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
673 
674 	if (rl == 'S')
675 		pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
676 	else
677 		pathenv = "PATH=/usr/sbin:/usr/bin";
678 
679 	nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
680 
681 	(void) execle(path, path, arg, 0, nenv);
682 
683 	perror("exec");
684 	exit(0);
685 }
686 
687 #define	SVCCFG_PATH	"/usr/sbin/svccfg"
688 #define	EMI_MFST	"/lib/svc/manifest/system/early-manifest-import.xml"
689 #define	EMI_PATH	"/lib/svc/method/manifest-import"
690 
691 /*
692  * Set Early Manifest Import service's state and log file.
693  */
694 static int
695 emi_set_state(restarter_instance_state_t state, boolean_t setlog)
696 {
697 	int r, ret = 1;
698 	instance_data_t idata;
699 	scf_handle_t *hndl = NULL;
700 	scf_instance_t *inst = NULL;
701 
702 retry:
703 	if (hndl == NULL)
704 		hndl = libscf_handle_create_bound(SCF_VERSION);
705 
706 	if (hndl == NULL) {
707 		/*
708 		 * In the case that we can't bind to the repository
709 		 * (which should have been started), we need to allow
710 		 * the user into maintenance mode to determine what's
711 		 * failed.
712 		 */
713 		fork_sulogin(B_FALSE, "Unable to bind a new repository"
714 		    " handle: %s\n", scf_strerror(scf_error()));
715 		goto retry;
716 	}
717 
718 	if (inst == NULL)
719 		inst = safe_scf_instance_create(hndl);
720 
721 	if (scf_handle_decode_fmri(hndl, SCF_INSTANCE_EMI, NULL, NULL,
722 	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
723 		switch (scf_error()) {
724 		case SCF_ERROR_NOT_FOUND:
725 			goto out;
726 
727 		case SCF_ERROR_CONNECTION_BROKEN:
728 		case SCF_ERROR_NOT_BOUND:
729 			libscf_handle_rebind(hndl);
730 			goto retry;
731 
732 		default:
733 			fork_sulogin(B_FALSE, "Couldn't fetch %s service: "
734 			    "%s\n", SCF_INSTANCE_EMI,
735 			    scf_strerror(scf_error()));
736 			goto retry;
737 		}
738 	}
739 
740 	if (setlog) {
741 		(void) libscf_note_method_log(inst, st->st_log_prefix, EMI_LOG);
742 		log_framework(LOG_DEBUG,
743 		    "Set logfile property for %s\n", SCF_INSTANCE_EMI);
744 	}
745 
746 	idata.i_fmri = SCF_INSTANCE_EMI;
747 	idata.i_state =  RESTARTER_STATE_NONE;
748 	idata.i_next_state = RESTARTER_STATE_NONE;
749 	switch (r = _restarter_commit_states(hndl, &idata, state,
750 	    RESTARTER_STATE_NONE, NULL)) {
751 	case 0:
752 		break;
753 
754 	case ECONNABORTED:
755 		libscf_handle_rebind(hndl);
756 		goto retry;
757 
758 	case ENOMEM:
759 	case ENOENT:
760 	case EPERM:
761 	case EACCES:
762 	case EROFS:
763 		fork_sulogin(B_FALSE, "Could not set state of "
764 		    "%s: %s\n", SCF_INSTANCE_EMI, strerror(r));
765 		goto retry;
766 
767 	case EINVAL:
768 	default:
769 		bad_error("_restarter_commit_states", r);
770 	}
771 	ret = 0;
772 
773 out:
774 	scf_instance_destroy(inst);
775 	scf_handle_destroy(hndl);
776 	return (ret);
777 }
778 
779 /*
780  * It is possible that the early-manifest-import service is disabled.  This
781  * would not be the normal case for Solaris, but it may happen on dedicated
782  * systems.  So this function checks the state of the general/enabled
783  * property for Early Manifest Import.
784  *
785  * It is also possible that the early-manifest-import service does not yet
786  * have a repository representation when this function runs.  This happens
787  * if non-Early Manifest Import system is upgraded to an Early Manifest
788  * Import based system.  Thus, the non-existence of general/enabled is not
789  * an error.
790  *
791  * Returns 1 if Early Manifest Import is disabled and 0 otherwise.
792  */
793 static int
794 emi_is_disabled()
795 {
796 	int disabled = 0;
797 	int disconnected = 1;
798 	int enabled;
799 	scf_handle_t *hndl = NULL;
800 	scf_instance_t *inst = NULL;
801 	uchar_t stored_hash[MHASH_SIZE];
802 	char *pname;
803 	int hashash, r;
804 
805 	while (hndl == NULL) {
806 		hndl = libscf_handle_create_bound(SCF_VERSION);
807 
808 		if (hndl == NULL) {
809 			/*
810 			 * In the case that we can't bind to the repository
811 			 * (which should have been started), we need to
812 			 * allow the user into maintenance mode to
813 			 * determine what's failed.
814 			 */
815 			fork_sulogin(B_FALSE, "Unable to bind a new repository "
816 			    "handle: %s\n", scf_strerror(scf_error()));
817 		}
818 	}
819 
820 	while (disconnected) {
821 		r = libscf_fmri_get_instance(hndl, SCF_INSTANCE_EMI, &inst);
822 		if (r != 0) {
823 			switch (r) {
824 			case ECONNABORTED:
825 				libscf_handle_rebind(hndl);
826 				continue;
827 
828 			case ENOENT:
829 				/*
830 				 * Early Manifest Import service is not in
831 				 * the repository. Check the manifest file
832 				 * and service's hash in smf/manifest to
833 				 * figure out whether Early Manifest Import
834 				 * service was deleted. If Early Manifest Import
835 				 * service was deleted, treat that as a disable
836 				 * and don't run early import.
837 				 */
838 
839 				if (access(EMI_MFST, F_OK)) {
840 					/*
841 					 * Manifest isn't found, so service is
842 					 * properly removed.
843 					 */
844 					disabled = 1;
845 				} else {
846 					/*
847 					 * If manifest exists and we have the
848 					 * hash, the service was improperly
849 					 * deleted, generate a warning and treat
850 					 * this as a disable.
851 					 */
852 
853 					if ((pname = mhash_filename_to_propname(
854 					    EMI_MFST, B_TRUE)) == NULL) {
855 						/*
856 						 * Treat failure to get propname
857 						 * as a disable.
858 						 */
859 						disabled = 1;
860 						uu_warn("Failed to get propname"
861 						    " for %s.\n",
862 						    SCF_INSTANCE_EMI);
863 					} else {
864 						hashash = mhash_retrieve_entry(
865 						    hndl, pname,
866 						    stored_hash,
867 						    NULL) == 0;
868 						uu_free(pname);
869 
870 						if (hashash) {
871 							disabled = 1;
872 							uu_warn("%s service is "
873 							    "deleted \n",
874 							    SCF_INSTANCE_EMI);
875 						}
876 					}
877 
878 				}
879 
880 				disconnected = 0;
881 				continue;
882 
883 			default:
884 				bad_error("libscf_fmri_get_instance",
885 				    scf_error());
886 			}
887 		}
888 		r = libscf_get_basic_instance_data(hndl, inst, SCF_INSTANCE_EMI,
889 		    &enabled, NULL, NULL);
890 		if (r == 0) {
891 			/*
892 			 * enabled can be returned as -1, which indicates
893 			 * that the enabled property was not found.  To us
894 			 * that means that the service was not disabled.
895 			 */
896 			if (enabled == 0)
897 				disabled = 1;
898 		} else {
899 			switch (r) {
900 			case ECONNABORTED:
901 				libscf_handle_rebind(hndl);
902 				continue;
903 
904 			case ECANCELED:
905 			case ENOENT:
906 				break;
907 			default:
908 				bad_error("libscf_get_basic_instance_data", r);
909 			}
910 		}
911 		disconnected = 0;
912 	}
913 
914 out:
915 	if (inst != NULL)
916 		scf_instance_destroy(inst);
917 	scf_handle_destroy(hndl);
918 	return (disabled);
919 }
920 
921 void
922 fork_emi()
923 {
924 	pid_t pid;
925 	ctid_t ctid = -1;
926 	char **envp, **np;
927 	char *emipath;
928 	char corepath[PATH_MAX];
929 	char *svc_state;
930 	int setemilog;
931 	int sz;
932 
933 	if (emi_is_disabled()) {
934 		log_framework(LOG_NOTICE, "%s is  disabled and will "
935 		    "not be run.\n", SCF_INSTANCE_EMI);
936 		return;
937 	}
938 
939 	/*
940 	 * Early Manifest Import should run only once, at boot. If svc.startd
941 	 * is some how restarted, Early Manifest Import  should not run again.
942 	 * Use the Early Manifest Import service's state to figure out whether
943 	 * Early Manifest Import has successfully completed earlier and bail
944 	 * out if it did.
945 	 */
946 	if (svc_state = smf_get_state(SCF_INSTANCE_EMI)) {
947 		if (strcmp(svc_state, SCF_STATE_STRING_ONLINE) == 0) {
948 			free(svc_state);
949 			return;
950 		}
951 		free(svc_state);
952 	}
953 
954 	/*
955 	 * Attempt to set Early Manifest Import service's state and log file.
956 	 * If emi_set_state fails, set log file again in the next call to
957 	 * emi_set_state.
958 	 */
959 	setemilog = emi_set_state(RESTARTER_STATE_OFFLINE, B_TRUE);
960 
961 	/* Don't go further if /usr isn't available */
962 	if (access(SVCCFG_PATH, F_OK)) {
963 		log_framework(LOG_NOTICE, "Early Manifest Import is not "
964 		    "supported on systems with a separate /usr filesystem.\n");
965 		return;
966 	}
967 
968 fork_retry:
969 	log_framework(LOG_DEBUG, "Starting Early Manifest Import\n");
970 
971 	/*
972 	 * If we're retrying, we will have an old contract lying around
973 	 * from the failure.  Since we're going to be creating a new
974 	 * contract shortly, we abandon the old one now.
975 	 */
976 	if (ctid != -1)
977 		contract_abandon(ctid);
978 	ctid = -1;
979 
980 	pid = fork_common(SCF_INSTANCE_EMI, SCF_INSTANCE_EMI,
981 	    MAX_EMI_RETRIES, &ctid, 0, 0, 0, 0, EMI_COOKIE);
982 
983 	if (pid != 0) {
984 		int exitstatus;
985 
986 		if (waitpid(pid, &exitstatus, 0) == -1) {
987 			fork_sulogin(B_FALSE, "waitpid on %s failed: "
988 			    "%s\n", SCF_INSTANCE_EMI, strerror(errno));
989 		} else if (WIFEXITED(exitstatus)) {
990 			if (WEXITSTATUS(exitstatus)) {
991 				fork_sulogin(B_FALSE, "%s exited with status "
992 				    "%d \n", SCF_INSTANCE_EMI,
993 				    WEXITSTATUS(exitstatus));
994 				goto fork_retry;
995 			}
996 		} else if (WIFSIGNALED(exitstatus)) {
997 			char signame[SIG2STR_MAX];
998 
999 			if (sig2str(WTERMSIG(exitstatus), signame))
1000 				(void) snprintf(signame, SIG2STR_MAX,
1001 				    "signum %d", WTERMSIG(exitstatus));
1002 
1003 			fork_sulogin(B_FALSE, "%s signalled: %s\n",
1004 			    SCF_INSTANCE_EMI, signame);
1005 			goto fork_retry;
1006 		} else {
1007 			fork_sulogin(B_FALSE, "%s non-exit condition: 0x%x\n",
1008 			    SCF_INSTANCE_EMI, exitstatus);
1009 			goto fork_retry;
1010 		}
1011 
1012 		log_framework(LOG_DEBUG, "%s completed successfully\n",
1013 		    SCF_INSTANCE_EMI);
1014 
1015 		/*
1016 		 * Once Early Manifest Import completed, the Early Manifest
1017 		 * Import service must have been imported so set log file and
1018 		 * state properties. Since this information is required for
1019 		 * late manifest import and common admin operations, failing to
1020 		 * set these properties should result in su login so admin can
1021 		 * correct the problem.
1022 		 */
1023 		(void) emi_set_state(RESTARTER_STATE_ONLINE,
1024 		    setemilog ? B_TRUE : B_FALSE);
1025 
1026 		return;
1027 	}
1028 
1029 	/* child */
1030 
1031 	/*
1032 	 * Set our per-process core file path to leave core files in
1033 	 * /etc/svc/volatile directory, named after the PID to aid in debugging.
1034 	 */
1035 	(void) snprintf(corepath, sizeof (corepath),
1036 	    "/etc/svc/volatile/core.emi.%%p");
1037 	(void) core_set_process_path(corepath, strlen(corepath) + 1, getpid());
1038 
1039 	/*
1040 	 * Similar to running legacy services, we need to manually set
1041 	 * log files here and environment variables.
1042 	 */
1043 	setlog(EMI_LOG);
1044 
1045 	envp = startd_zalloc(sizeof (char *) * 3);
1046 	np = envp;
1047 
1048 	sz = sizeof ("SMF_FMRI=") + strlen(SCF_INSTANCE_EMI);
1049 	*np = startd_zalloc(sz);
1050 	(void) strlcpy(*np, "SMF_FMRI=", sz);
1051 	(void) strncat(*np, SCF_INSTANCE_EMI, sz);
1052 	np++;
1053 
1054 	emipath = getenv("PATH");
1055 	if (emipath == NULL)
1056 		emipath = strdup("/usr/sbin:/usr/bin");
1057 
1058 	sz = sizeof ("PATH=") + strlen(emipath);
1059 	*np = startd_zalloc(sz);
1060 	(void) strlcpy(*np, "PATH=", sz);
1061 	(void) strncat(*np, emipath, sz);
1062 
1063 	log_framework(LOG_DEBUG, "executing Early Manifest Import\n");
1064 	(void) execle(EMI_PATH, EMI_PATH, NULL, envp);
1065 
1066 	/*
1067 	 * Status code is used above to identify Early Manifest Import
1068 	 * exec failure.
1069 	 */
1070 	exit(1);
1071 }
1072 
1073 extern char **environ;
1074 
1075 /*
1076  * A local variation on system(3c) which accepts a timeout argument.  This
1077  * allows us to better ensure that the system will actually shut down.
1078  *
1079  * gracetime specifies an amount of time in seconds which the routine must wait
1080  * after the command exits, to allow for asynchronous effects (like sent
1081  * signals) to take effect.  This can be zero.
1082  */
1083 void
1084 fork_with_timeout(const char *cmd, uint_t gracetime, uint_t timeout)
1085 {
1086 	int err = 0;
1087 	pid_t pid;
1088 	char *argv[4];
1089 	posix_spawnattr_t attr;
1090 	posix_spawn_file_actions_t factions;
1091 
1092 	sigset_t mask, savemask;
1093 	uint_t msec_timeout;
1094 	uint_t msec_spent = 0;
1095 	uint_t msec_gracetime;
1096 	int status;
1097 
1098 	msec_timeout = timeout * 1000;
1099 	msec_gracetime = gracetime * 1000;
1100 
1101 	/*
1102 	 * See also system(3c) in libc.  This is very similar, except
1103 	 * that we avoid some unneeded complexity.
1104 	 */
1105 	err = posix_spawnattr_init(&attr);
1106 	if (err == 0)
1107 		err = posix_spawnattr_setflags(&attr,
1108 		    POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
1109 		    POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP |
1110 		    POSIX_SPAWN_NOEXECERR_NP);
1111 
1112 	/*
1113 	 * We choose to close fd's above 2, a deviation from system.
1114 	 */
1115 	if (err == 0)
1116 		err = posix_spawn_file_actions_init(&factions);
1117 	if (err == 0)
1118 		err = posix_spawn_file_actions_addclosefrom_np(&factions,
1119 		    STDERR_FILENO + 1);
1120 
1121 	(void) sigemptyset(&mask);
1122 	(void) sigaddset(&mask, SIGCHLD);
1123 	(void) thr_sigsetmask(SIG_BLOCK, &mask, &savemask);
1124 
1125 	argv[0] = "/bin/sh";
1126 	argv[1] = "-c";
1127 	argv[2] = (char *)cmd;
1128 	argv[3] = NULL;
1129 
1130 	if (err == 0)
1131 		err = posix_spawn(&pid, "/bin/sh", &factions, &attr,
1132 		    (char *const *)argv, (char *const *)environ);
1133 
1134 	(void) posix_spawnattr_destroy(&attr);
1135 	(void) posix_spawn_file_actions_destroy(&factions);
1136 
1137 	if (err) {
1138 		uu_warn("Failed to spawn %s: %s\n", cmd, strerror(err));
1139 	} else {
1140 		for (;;) {
1141 			int w;
1142 			w = waitpid(pid, &status, WNOHANG);
1143 			if (w == -1 && errno != EINTR)
1144 				break;
1145 			if (w > 0) {
1146 				/*
1147 				 * Command succeeded, so give it gracetime
1148 				 * seconds for it to have an effect.
1149 				 */
1150 				if (status == 0 && msec_gracetime != 0)
1151 					(void) poll(NULL, 0, msec_gracetime);
1152 				break;
1153 			}
1154 
1155 			(void) poll(NULL, 0, 100);
1156 			msec_spent += 100;
1157 			/*
1158 			 * If we timed out, kill off the process, then try to
1159 			 * wait for it-- it's possible that we could accumulate
1160 			 * a zombie here since we don't allow waitpid to hang,
1161 			 * but it's better to let that happen and continue to
1162 			 * make progress.
1163 			 */
1164 			if (msec_spent >= msec_timeout) {
1165 				uu_warn("'%s' timed out after %d "
1166 				    "seconds.  Killing.\n", cmd,
1167 				    timeout);
1168 				(void) kill(pid, SIGTERM);
1169 				(void) poll(NULL, 0, 100);
1170 				(void) kill(pid, SIGKILL);
1171 				(void) poll(NULL, 0, 100);
1172 				(void) waitpid(pid, &status, WNOHANG);
1173 				break;
1174 			}
1175 		}
1176 	}
1177 	(void) thr_sigsetmask(SIG_BLOCK, &savemask, NULL);
1178 }
1179