xref: /illumos-gate/usr/src/cmd/svc/startd/fork.c (revision c3e9074d863038c38dc15c3af85b017f42133816)
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  */
25 
26 /*
27  * fork.c - safe forking for svc.startd
28  *
29  * fork_configd() and fork_sulogin() are related, special cases that handle the
30  * spawning of specific client processes for svc.startd.
31  */
32 
33 #include <sys/contract/process.h>
34 #include <sys/corectl.h>
35 #include <sys/ctfs.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <sys/wait.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <libcontract.h>
44 #include <libcontract_priv.h>
45 #include <libscf_priv.h>
46 #include <limits.h>
47 #include <poll.h>
48 #include <port.h>
49 #include <signal.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <utmpx.h>
56 #include <spawn.h>
57 
58 #include "manifest_hash.h"
59 #include "configd_exit.h"
60 #include "protocol.h"
61 #include "startd.h"
62 
63 static	struct	utmpx	*utmpp;	/* pointer for getutxent() */
64 
65 pid_t
66 startd_fork1(int *forkerr)
67 {
68 	pid_t p;
69 
70 	/*
71 	 * prefork stack
72 	 */
73 	wait_prefork();
74 
75 	p = fork1();
76 
77 	if (p == -1 && forkerr != NULL)
78 		*forkerr = errno;
79 
80 	/*
81 	 * postfork stack
82 	 */
83 	wait_postfork(p);
84 
85 	return (p);
86 }
87 
88 /*
89  * void fork_mount(char *, char *)
90  *   Run mount(1M) with the given options and mount point.  (mount(1M) has much
91  *   hidden knowledge; it's much less correct to reimplement that logic here to
92  *   save a fork(2)/exec(2) invocation.)
93  */
94 int
95 fork_mount(char *path, char *opts)
96 {
97 	pid_t pid;
98 	uint_t tries = 0;
99 	int status;
100 
101 	for (pid = fork1(); pid == -1; pid = fork1()) {
102 		if (++tries > MAX_MOUNT_RETRIES)
103 			return (-1);
104 
105 		(void) sleep(tries);
106 	}
107 
108 	if (pid != 0) {
109 		(void) waitpid(pid, &status, 0);
110 
111 		/*
112 		 * If our mount(1M) invocation exited by peculiar means, or with
113 		 * a non-zero status, our mount likelihood is low.
114 		 */
115 		if (!WIFEXITED(status) ||
116 		    WEXITSTATUS(status) != 0)
117 			return (-1);
118 
119 		return (0);
120 	}
121 
122 	(void) execl("/sbin/mount", "mount", "-o", opts, path, NULL);
123 
124 	return (-1);
125 }
126 
127 /*
128  * pid_t fork_common(...)
129  *   Common routine used by fork_sulogin, fork_emi, and fork_configd to
130  *   fork a process in a contract with the provided terms.  Invokes
131  *   fork_sulogin (with its no-fork argument set) on errors.
132  */
133 static pid_t
134 fork_common(const char *name, const char *svc_fmri, int retries, ctid_t *ctidp,
135     uint_t inf, uint_t crit, uint_t fatal, uint_t param, uint64_t cookie)
136 {
137 	uint_t tries = 0;
138 	int ctfd, err;
139 	pid_t pid;
140 
141 	/*
142 	 * Establish process contract terms.
143 	 */
144 	if ((ctfd = open64(CTFS_ROOT "/process/template", O_RDWR)) == -1) {
145 		fork_sulogin(B_TRUE, "Could not open process contract template "
146 		    "for %s: %s\n", name, strerror(errno));
147 		/* NOTREACHED */
148 	}
149 
150 	err = ct_tmpl_set_critical(ctfd, crit);
151 	err |= ct_pr_tmpl_set_fatal(ctfd, fatal);
152 	err |= ct_tmpl_set_informative(ctfd, inf);
153 	err |= ct_pr_tmpl_set_param(ctfd, param);
154 	err |= ct_tmpl_set_cookie(ctfd, cookie);
155 	err |= ct_pr_tmpl_set_svc_fmri(ctfd, svc_fmri);
156 	err |= ct_pr_tmpl_set_svc_aux(ctfd, name);
157 	if (err) {
158 		(void) close(ctfd);
159 		fork_sulogin(B_TRUE, "Could not set %s process contract "
160 		    "terms\n", name);
161 		/* NOTREACHED */
162 	}
163 
164 	if (err = ct_tmpl_activate(ctfd)) {
165 		(void) close(ctfd);
166 		fork_sulogin(B_TRUE, "Could not activate %s process contract "
167 		    "template: %s\n", name, strerror(err));
168 		/* NOTREACHED */
169 	}
170 
171 	/*
172 	 * Attempt to fork "retries" times.
173 	 */
174 	for (pid = fork1(); pid == -1; pid = fork1()) {
175 		if (++tries > retries) {
176 			/*
177 			 * When we exit the sulogin session, init(1M)
178 			 * will restart svc.startd(1M).
179 			 */
180 			err = errno;
181 			(void) ct_tmpl_clear(ctfd);
182 			(void) close(ctfd);
183 			fork_sulogin(B_TRUE, "Could not fork to start %s: %s\n",
184 			    name, strerror(err));
185 			/* NOTREACHED */
186 		}
187 		(void) sleep(tries);
188 	}
189 
190 	/*
191 	 * Clean up, return pid and ctid.
192 	 */
193 	if (pid != 0 && (errno = contract_latest(ctidp)) != 0)
194 		uu_die("Could not get new contract id for %s\n", name);
195 	(void) ct_tmpl_clear(ctfd);
196 	(void) close(ctfd);
197 
198 	return (pid);
199 }
200 
201 /*
202  * void fork_sulogin(boolean_t, const char *, ...)
203  *   When we are invoked with the -s flag from boot (or run into an unfixable
204  *   situation), we run a private copy of sulogin.  When the sulogin session
205  *   is ended, we continue.  This is the last fallback action for system
206  *   maintenance.
207  *
208  *   If immediate is true, fork_sulogin() executes sulogin(1M) directly, without
209  *   forking.
210  *
211  *   Because fork_sulogin() is needed potentially before we daemonize, we leave
212  *   it outside the wait_register() framework.
213  */
214 /*PRINTFLIKE2*/
215 void
216 fork_sulogin(boolean_t immediate, const char *format, ...)
217 {
218 	va_list args;
219 	int fd_console;
220 
221 	(void) printf("Requesting System Maintenance Mode\n");
222 
223 	if (!booting_to_single_user)
224 		(void) printf("(See /lib/svc/share/README for more "
225 		    "information.)\n");
226 
227 	va_start(args, format);
228 	(void) vprintf(format, args);
229 	va_end(args);
230 
231 	if (!immediate) {
232 		ctid_t	ctid;
233 		pid_t	pid;
234 
235 		pid = fork_common("sulogin", SVC_SULOGIN_FMRI,
236 		    MAX_SULOGIN_RETRIES, &ctid, CT_PR_EV_HWERR, 0,
237 		    CT_PR_EV_HWERR, CT_PR_PGRPONLY, SULOGIN_COOKIE);
238 
239 		if (pid != 0) {
240 			(void) waitpid(pid, NULL, 0);
241 			contract_abandon(ctid);
242 			return;
243 		}
244 		/* close all inherited fds */
245 		closefrom(0);
246 	} else {
247 		(void) printf("Directly executing sulogin.\n");
248 		/*
249 		 * Can't call closefrom() in this MT section
250 		 * so safely close a minimum set of fds.
251 		 */
252 		(void) close(STDIN_FILENO);
253 		(void) close(STDOUT_FILENO);
254 		(void) close(STDERR_FILENO);
255 	}
256 
257 	(void) setpgrp();
258 
259 	/* open the console for sulogin */
260 	if ((fd_console = open("/dev/console", O_RDWR)) >= 0) {
261 		if (fd_console != STDIN_FILENO)
262 			while (dup2(fd_console, STDIN_FILENO) < 0 &&
263 			    errno == EINTR)
264 				;
265 		if (fd_console != STDOUT_FILENO)
266 			while (dup2(fd_console, STDOUT_FILENO) < 0 &&
267 			    errno == EINTR)
268 				;
269 		if (fd_console != STDERR_FILENO)
270 			while (dup2(fd_console, STDERR_FILENO) < 0 &&
271 			    errno == EINTR)
272 				;
273 		if (fd_console > STDERR_FILENO)
274 			(void) close(fd_console);
275 	}
276 
277 	setutxent();
278 	while ((utmpp = getutxent()) != NULL) {
279 		if (strcmp(utmpp->ut_user, "LOGIN") != 0) {
280 			if (strcmp(utmpp->ut_line, "console") == 0) {
281 				(void) kill(utmpp->ut_pid, 9);
282 				break;
283 			}
284 		}
285 	}
286 
287 	(void) execl("/sbin/sulogin", "sulogin", NULL);
288 
289 	uu_warn("Could not exec() sulogin");
290 
291 	exit(1);
292 }
293 
294 #define	CONFIGD_PATH	"/lib/svc/bin/svc.configd"
295 
296 /*
297  * void fork_configd(int status)
298  *   We are interested in exit events (since the parent's exiting means configd
299  *   is ready to run and since the child's exiting indicates an error case) and
300  *   in empty events.  This means we have a unique template for initiating
301  *   configd.
302  */
303 void
304 fork_configd(int exitstatus)
305 {
306 	pid_t pid;
307 	ctid_t ctid = -1;
308 	int err;
309 	char path[PATH_MAX];
310 
311 	/*
312 	 * Checking the existatus for the potential failure of the
313 	 * daemonized svc.configd.  If this is not the first time
314 	 * through, but a call from the svc.configd monitoring thread
315 	 * after a failure this is the status that is expected.  Other
316 	 * failures are exposed during initialization or are fixed
317 	 * by a restart (e.g door closings).
318 	 *
319 	 * If this is on-disk database corruption it will also be
320 	 * caught by a restart but could be cleared before the restart.
321 	 *
322 	 * Or this could be internal database corruption due to a
323 	 * rogue service that needs to be cleared before restart.
324 	 */
325 	if (WEXITSTATUS(exitstatus) == CONFIGD_EXIT_DATABASE_BAD) {
326 		fork_sulogin(B_FALSE, "svc.configd exited with database "
327 		    "corrupt error after initialization of the repository\n");
328 	}
329 
330 retry:
331 	log_framework(LOG_DEBUG, "fork_configd trying to start svc.configd\n");
332 
333 	/*
334 	 * If we're retrying, we will have an old contract lying around
335 	 * from the failure.  Since we're going to be creating a new
336 	 * contract shortly, we abandon the old one now.
337 	 */
338 	if (ctid != -1)
339 		contract_abandon(ctid);
340 	ctid = -1;
341 
342 	pid = fork_common("svc.configd", SCF_SERVICE_CONFIGD,
343 	    MAX_CONFIGD_RETRIES, &ctid, 0, CT_PR_EV_EXIT, 0,
344 	    CT_PR_INHERIT | CT_PR_REGENT, CONFIGD_COOKIE);
345 
346 	if (pid != 0) {
347 		int exitstatus;
348 
349 		st->st_configd_pid = pid;
350 
351 		if (waitpid(pid, &exitstatus, 0) == -1) {
352 			fork_sulogin(B_FALSE, "waitpid on svc.configd "
353 			    "failed: %s\n", strerror(errno));
354 		} else if (WIFEXITED(exitstatus)) {
355 			char *errstr;
356 
357 			/*
358 			 * Examine exitstatus.  This will eventually get more
359 			 * complicated, as we will want to teach startd how to
360 			 * invoke configd with alternate repositories, etc.
361 			 *
362 			 * Note that exec(2) failure results in an exit status
363 			 * of 1, resulting in the default clause below.
364 			 */
365 
366 			/*
367 			 * Assign readable strings to cases we don't handle, or
368 			 * have error outcomes that cannot be eliminated.
369 			 */
370 			switch (WEXITSTATUS(exitstatus)) {
371 			case CONFIGD_EXIT_BAD_ARGS:
372 				errstr = "bad arguments";
373 				break;
374 
375 			case CONFIGD_EXIT_DATABASE_BAD:
376 				errstr = "database corrupt";
377 				break;
378 
379 			case CONFIGD_EXIT_DATABASE_LOCKED:
380 				errstr = "database locked";
381 				break;
382 			case CONFIGD_EXIT_INIT_FAILED:
383 				errstr = "initialization failure";
384 				break;
385 			case CONFIGD_EXIT_DOOR_INIT_FAILED:
386 				errstr = "door initialization failure";
387 				break;
388 			case CONFIGD_EXIT_DATABASE_INIT_FAILED:
389 				errstr = "database initialization failure";
390 				break;
391 			case CONFIGD_EXIT_NO_THREADS:
392 				errstr = "no threads available";
393 				break;
394 			case CONFIGD_EXIT_LOST_MAIN_DOOR:
395 				errstr = "lost door server attachment";
396 				break;
397 			case 1:
398 				errstr = "execution failure";
399 				break;
400 			default:
401 				errstr = "unknown error";
402 				break;
403 			}
404 
405 			/*
406 			 * Remedial actions for various configd failures.
407 			 */
408 			switch (WEXITSTATUS(exitstatus)) {
409 			case CONFIGD_EXIT_OKAY:
410 				break;
411 
412 			case CONFIGD_EXIT_DATABASE_LOCKED:
413 				/* attempt remount of / read-write */
414 				if (fs_is_read_only("/", NULL) == 1) {
415 					if (fs_remount("/") == -1)
416 						fork_sulogin(B_FALSE,
417 						    "remount of root "
418 						    "filesystem failed\n");
419 
420 					goto retry;
421 				}
422 				break;
423 
424 			default:
425 				fork_sulogin(B_FALSE, "svc.configd exited "
426 				    "with status %d (%s)\n",
427 				    WEXITSTATUS(exitstatus), errstr);
428 				goto retry;
429 			}
430 		} else if (WIFSIGNALED(exitstatus)) {
431 			char signame[SIG2STR_MAX];
432 
433 			if (sig2str(WTERMSIG(exitstatus), signame))
434 				(void) snprintf(signame, SIG2STR_MAX,
435 				    "signum %d", WTERMSIG(exitstatus));
436 
437 			fork_sulogin(B_FALSE, "svc.configd signalled:"
438 			    " %s\n", signame);
439 
440 			goto retry;
441 		} else {
442 			fork_sulogin(B_FALSE, "svc.configd non-exit "
443 			    "condition: 0x%x\n", exitstatus);
444 
445 			goto retry;
446 		}
447 
448 		/*
449 		 * Announce that we have a valid svc.configd status.
450 		 */
451 		MUTEX_LOCK(&st->st_configd_live_lock);
452 		st->st_configd_lives = 1;
453 		err = pthread_cond_broadcast(&st->st_configd_live_cv);
454 		assert(err == 0);
455 		MUTEX_UNLOCK(&st->st_configd_live_lock);
456 
457 		log_framework(LOG_DEBUG, "fork_configd broadcasts configd is "
458 		    "live\n");
459 		return;
460 	}
461 
462 	/*
463 	 * Set our per-process core file path to leave core files in
464 	 * /etc/svc/volatile directory, named after the PID to aid in debugging.
465 	 */
466 	(void) snprintf(path, sizeof (path),
467 	    "/etc/svc/volatile/core.configd.%%p");
468 
469 	(void) core_set_process_path(path, strlen(path) + 1, getpid());
470 
471 	log_framework(LOG_DEBUG, "executing svc.configd\n");
472 
473 	(void) execl(CONFIGD_PATH, CONFIGD_PATH, NULL);
474 
475 	/*
476 	 * Status code is used above to identify configd exec failure.
477 	 */
478 	exit(1);
479 }
480 
481 void *
482 fork_configd_thread(void *vctid)
483 {
484 	int fd, err;
485 	ctid_t configd_ctid = (ctid_t)vctid;
486 
487 	if (configd_ctid == -1) {
488 		log_framework(LOG_DEBUG,
489 		    "fork_configd_thread starting svc.configd\n");
490 		fork_configd(0);
491 	} else {
492 		/*
493 		 * configd_ctid is known:  we broadcast and continue.
494 		 * test contract for appropriate state by verifying that
495 		 * there is one or more processes within it?
496 		 */
497 		log_framework(LOG_DEBUG,
498 		    "fork_configd_thread accepting svc.configd with CTID %ld\n",
499 		    configd_ctid);
500 		MUTEX_LOCK(&st->st_configd_live_lock);
501 		st->st_configd_lives = 1;
502 		(void) pthread_cond_broadcast(&st->st_configd_live_cv);
503 		MUTEX_UNLOCK(&st->st_configd_live_lock);
504 	}
505 
506 	fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY);
507 	if (fd == -1)
508 		uu_die("process bundle open failed");
509 
510 	/*
511 	 * Make sure we get all events (including those generated by configd
512 	 * before this thread was started).
513 	 */
514 	err = ct_event_reset(fd);
515 	assert(err == 0);
516 
517 	for (;;) {
518 		int efd, sfd;
519 		ct_evthdl_t ev;
520 		uint32_t type;
521 		ctevid_t evid;
522 		ct_stathdl_t status;
523 		ctid_t ctid;
524 		uint64_t cookie;
525 		pid_t pid;
526 
527 		if (err = ct_event_read_critical(fd, &ev)) {
528 			assert(err != EINVAL && err != EAGAIN);
529 			log_error(LOG_WARNING,
530 			    "Error reading next contract event: %s",
531 			    strerror(err));
532 			continue;
533 		}
534 
535 		evid = ct_event_get_evid(ev);
536 		ctid = ct_event_get_ctid(ev);
537 		type = ct_event_get_type(ev);
538 
539 		/* Fetch cookie. */
540 		sfd = contract_open(ctid, "process", "status", O_RDONLY);
541 		if (sfd < 0) {
542 			ct_event_free(ev);
543 			continue;
544 		}
545 
546 		if (err = ct_status_read(sfd, CTD_COMMON, &status)) {
547 			log_framework(LOG_WARNING, "Could not get status for "
548 			    "contract %ld: %s\n", ctid, strerror(err));
549 
550 			ct_event_free(ev);
551 			startd_close(sfd);
552 			continue;
553 		}
554 
555 		cookie = ct_status_get_cookie(status);
556 
557 		ct_status_free(status);
558 
559 		startd_close(sfd);
560 
561 		/*
562 		 * Don't process events from contracts we aren't interested in.
563 		 */
564 		if (cookie != CONFIGD_COOKIE) {
565 			ct_event_free(ev);
566 			continue;
567 		}
568 
569 		if (type == CT_PR_EV_EXIT) {
570 			int exitstatus;
571 
572 			(void) ct_pr_event_get_pid(ev, &pid);
573 			(void) ct_pr_event_get_exitstatus(ev,
574 			    &exitstatus);
575 
576 			if (st->st_configd_pid != pid) {
577 				/*
578 				 * This is the child exiting, so we
579 				 * abandon the contract and restart
580 				 * configd.
581 				 */
582 				contract_abandon(ctid);
583 				fork_configd(exitstatus);
584 			}
585 		}
586 
587 		efd = contract_open(ctid, "process", "ctl", O_WRONLY);
588 		if (efd != -1) {
589 			(void) ct_ctl_ack(efd, evid);
590 			startd_close(efd);
591 		}
592 
593 		ct_event_free(ev);
594 
595 	}
596 
597 	/*NOTREACHED*/
598 	return (NULL);
599 }
600 
601 void
602 fork_rc_script(char rl, const char *arg, boolean_t wait)
603 {
604 	pid_t pid;
605 	int tmpl, err, stat;
606 	char path[20] = "/sbin/rc.", log[20] = "rc..log", timebuf[20];
607 	time_t now;
608 	struct tm ltime;
609 	size_t sz;
610 	char *pathenv;
611 	char **nenv;
612 
613 	path[8] = rl;
614 
615 	tmpl = open64(CTFS_ROOT "/process/template", O_RDWR);
616 	if (tmpl >= 0) {
617 		err = ct_tmpl_set_critical(tmpl, 0);
618 		assert(err == 0);
619 
620 		err = ct_tmpl_set_informative(tmpl, 0);
621 		assert(err == 0);
622 
623 		err = ct_pr_tmpl_set_fatal(tmpl, 0);
624 		assert(err == 0);
625 
626 		err = ct_tmpl_activate(tmpl);
627 		assert(err == 0);
628 
629 		err = close(tmpl);
630 		assert(err == 0);
631 	} else {
632 		uu_warn("Could not create contract template for %s.\n", path);
633 	}
634 
635 	pid = startd_fork1(NULL);
636 	if (pid < 0) {
637 		return;
638 	} else if (pid != 0) {
639 		/* parent */
640 		if (wait) {
641 			do
642 				err = waitpid(pid, &stat, 0);
643 			while (err != 0 && errno == EINTR)
644 				;
645 
646 			if (!WIFEXITED(stat)) {
647 				log_framework(LOG_INFO,
648 				    "%s terminated with waitpid() status %d.\n",
649 				    path, stat);
650 			} else if (WEXITSTATUS(stat) != 0) {
651 				log_framework(LOG_INFO,
652 				    "%s failed with status %d.\n", path,
653 				    WEXITSTATUS(stat));
654 			}
655 		}
656 
657 		return;
658 	}
659 
660 	/* child */
661 
662 	log[2] = rl;
663 
664 	setlog(log);
665 
666 	now = time(NULL);
667 	sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
668 	    localtime_r(&now, &ltime));
669 	assert(sz != 0);
670 
671 	(void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
672 
673 	if (rl == 'S')
674 		pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
675 	else
676 		pathenv = "PATH=/usr/sbin:/usr/bin";
677 
678 	nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
679 
680 	(void) execle(path, path, arg, 0, nenv);
681 
682 	perror("exec");
683 	exit(0);
684 }
685 
686 #define	SVCCFG_PATH	"/usr/sbin/svccfg"
687 #define	EMI_MFST	"/lib/svc/manifest/system/early-manifest-import.xml"
688 #define	EMI_PATH	"/lib/svc/method/manifest-import"
689 
690 /*
691  * Set Early Manifest Import service's state and log file.
692  */
693 static int
694 emi_set_state(restarter_instance_state_t state, boolean_t setlog)
695 {
696 	int r, ret = 1;
697 	instance_data_t idata;
698 	scf_handle_t *hndl = NULL;
699 	scf_instance_t *inst = NULL;
700 
701 retry:
702 	if (hndl == NULL)
703 		hndl = libscf_handle_create_bound(SCF_VERSION);
704 
705 	if (hndl == NULL) {
706 		/*
707 		 * In the case that we can't bind to the repository
708 		 * (which should have been started), we need to allow
709 		 * the user into maintenance mode to determine what's
710 		 * failed.
711 		 */
712 		fork_sulogin(B_FALSE, "Unable to bind a new repository"
713 		    " handle: %s\n", scf_strerror(scf_error()));
714 		goto retry;
715 	}
716 
717 	if (inst == NULL)
718 		inst = safe_scf_instance_create(hndl);
719 
720 	if (scf_handle_decode_fmri(hndl, SCF_INSTANCE_EMI, NULL, NULL,
721 	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
722 		switch (scf_error()) {
723 		case SCF_ERROR_NOT_FOUND:
724 			goto out;
725 
726 		case SCF_ERROR_CONNECTION_BROKEN:
727 		case SCF_ERROR_NOT_BOUND:
728 			libscf_handle_rebind(hndl);
729 			goto retry;
730 
731 		default:
732 			fork_sulogin(B_FALSE, "Couldn't fetch %s service: "
733 			    "%s\n", SCF_INSTANCE_EMI,
734 			    scf_strerror(scf_error()));
735 			goto retry;
736 		}
737 	}
738 
739 	if (setlog) {
740 		(void) libscf_note_method_log(inst, st->st_log_prefix, EMI_LOG);
741 		log_framework(LOG_DEBUG,
742 		    "Set logfile property for %s\n", SCF_INSTANCE_EMI);
743 	}
744 
745 	idata.i_fmri = SCF_INSTANCE_EMI;
746 	idata.i_state =  RESTARTER_STATE_NONE;
747 	idata.i_next_state = RESTARTER_STATE_NONE;
748 	switch (r = _restarter_commit_states(hndl, &idata, state,
749 	    RESTARTER_STATE_NONE, NULL)) {
750 	case 0:
751 		break;
752 
753 	case ECONNABORTED:
754 		libscf_handle_rebind(hndl);
755 		goto retry;
756 
757 	case ENOMEM:
758 	case ENOENT:
759 	case EPERM:
760 	case EACCES:
761 	case EROFS:
762 		fork_sulogin(B_FALSE, "Could not set state of "
763 		    "%s: %s\n", SCF_INSTANCE_EMI, strerror(r));
764 		goto retry;
765 		break;
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