17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53f2f09cdp * Common Development and Distribution License (the "License").
63f2f09cdp * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22e557d41Christopher Kiick * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
25bc2cf0fJoshua M. Clulow/*
26bc2cf0fJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved.
279adfa60Matthew Ahrens * Copyright (c) 2015 by Delphix. All rights reserved.
2875383e3Andy Fiddaman * Copyright 2016 Toomas Soome <tsoome@me.com>
2975383e3Andy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
30bc2cf0fJoshua M. Clulow */
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
33753a6d4Sherry Moore/*	  All Rights Reserved	*/
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate/*
367c478bdstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
377c478bdstevel@tonic-gate * The Regents of the University of California
387c478bdstevel@tonic-gate * All Rights Reserved
397c478bdstevel@tonic-gate *
407c478bdstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
417c478bdstevel@tonic-gate * software developed by the University of California, Berkeley, and its
427c478bdstevel@tonic-gate * contributors.
438e07a41Konstantin Ananyev * Portions contributed by Juergen Keil, <jk@tools.de>.
447c478bdstevel@tonic-gate */
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate
477c478bdstevel@tonic-gate/*
487c478bdstevel@tonic-gate * Common code for halt(1M), poweroff(1M), and reboot(1M).  We use
497c478bdstevel@tonic-gate * argv[0] to determine which behavior to exhibit.
507c478bdstevel@tonic-gate */
517c478bdstevel@tonic-gate
521939740Sherry Moore#include <stdio.h>
533f2f09cdp#include <procfs.h>
547c478bdstevel@tonic-gate#include <sys/types.h>
551939740Sherry Moore#include <sys/elf.h>
561939740Sherry Moore#include <sys/systeminfo.h>
571939740Sherry Moore#include <sys/stat.h>
587c478bdstevel@tonic-gate#include <sys/uadmin.h>
591939740Sherry Moore#include <sys/mntent.h>
601939740Sherry Moore#include <sys/mnttab.h>
611939740Sherry Moore#include <sys/mount.h>
628e07a41Konstantin Ananyev#include <sys/fs/ufs_mount.h>
637c478bdstevel@tonic-gate#include <alloca.h>
647c478bdstevel@tonic-gate#include <assert.h>
657c478bdstevel@tonic-gate#include <errno.h>
667c478bdstevel@tonic-gate#include <fcntl.h>
677c478bdstevel@tonic-gate#include <libgen.h>
687c478bdstevel@tonic-gate#include <libscf.h>
69753a6d4Sherry Moore#include <libscf_priv.h>
701939740Sherry Moore#include <limits.h>
717c478bdstevel@tonic-gate#include <locale.h>
727c478bdstevel@tonic-gate#include <libintl.h>
737c478bdstevel@tonic-gate#include <syslog.h>
747c478bdstevel@tonic-gate#include <signal.h>
757c478bdstevel@tonic-gate#include <strings.h>
767c478bdstevel@tonic-gate#include <unistd.h>
777c478bdstevel@tonic-gate#include <stdlib.h>
787c478bdstevel@tonic-gate#include <stdio.h>
797c478bdstevel@tonic-gate#include <strings.h>
807c478bdstevel@tonic-gate#include <time.h>
814e1f1c1Konstantin Ananyev#include <wait.h>
824e1f1c1Konstantin Ananyev#include <ctype.h>
837c478bdstevel@tonic-gate#include <utmpx.h>
847c478bdstevel@tonic-gate#include <pwd.h>
857c478bdstevel@tonic-gate#include <zone.h>
863a0fa63Enrico Perla - Sun Microsystems#include <spawn.h>
871939740Sherry Moore
881939740Sherry Moore#include <libzfs.h>
899abc7a5Toomas Soome#if defined(__x86)
909abc7a5Toomas Soome#include <libbe.h>
91753a6d4Sherry Moore#endif
921939740Sherry Moore
937c478bdstevel@tonic-gate#if !defined(TEXT_DOMAIN)
947c478bdstevel@tonic-gate#define	TEXT_DOMAIN	"SYS_TEST"
957c478bdstevel@tonic-gate#endif
967c478bdstevel@tonic-gate
971939740Sherry Moore#if defined(__sparc)
981939740Sherry Moore#define	CUR_ELFDATA	ELFDATA2MSB
999abc7a5Toomas Soome#elif defined(__x86)
1001939740Sherry Moore#define	CUR_ELFDATA	ELFDATA2LSB
1011939740Sherry Moore#endif
1021939740Sherry Moore
1031939740Sherry Moorestatic libzfs_handle_t *g_zfs;
1041939740Sherry Moore
1057c478bdstevel@tonic-gateextern int audit_halt_setup(int, char **);
1067c478bdstevel@tonic-gateextern int audit_halt_success(void);
1077c478bdstevel@tonic-gateextern int audit_halt_fail(void);
1087c478bdstevel@tonic-gate
1097c478bdstevel@tonic-gateextern int audit_reboot_setup(void);
1107c478bdstevel@tonic-gateextern int audit_reboot_success(void);
1117c478bdstevel@tonic-gateextern int audit_reboot_fail(void);
1127c478bdstevel@tonic-gate
1133f2f09cdpstatic char *cmdname;	/* basename(argv[0]), the name of the command */
1143f2f09cdp
1157c478bdstevel@tonic-gatetypedef struct ctidlist_struct {
1167c478bdstevel@tonic-gate	ctid_t ctid;
1177c478bdstevel@tonic-gate	struct ctidlist_struct *next;
1187c478bdstevel@tonic-gate} ctidlist_t;
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gatestatic ctidlist_t *ctidlist = NULL;
1217c478bdstevel@tonic-gatestatic ctid_t startdct = -1;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate#define	FMRI_STARTD_CONTRACT \
1247c478bdstevel@tonic-gate	"svc:/system/svc/restarter:default/:properties/restarter/contract"
1257c478bdstevel@tonic-gate
12680cb75fWilliam Kucharski#define	BEADM_PROG	"/usr/sbin/beadm"
127753a6d4Sherry Moore#define	BOOTADM_PROG	"/sbin/bootadm"
12880cb75fWilliam Kucharski#define	ZONEADM_PROG	"/usr/sbin/zoneadm"
12980cb75fWilliam Kucharski
1301939740Sherry Moore/*
1311939740Sherry Moore * The length of FASTBOOT_MOUNTPOINT must be less than MAXPATHLEN.
1321939740Sherry Moore */
1331939740Sherry Moore#define	FASTBOOT_MOUNTPOINT	"/tmp/.fastboot.root"
1341939740Sherry Moore
135753a6d4Sherry Moore/*
136753a6d4Sherry Moore * Fast Reboot related variables
137753a6d4Sherry Moore */
1381939740Sherry Moorestatic char	fastboot_mounted[MAXPATHLEN];
139e557d41Christopher Kiick
1409abc7a5Toomas Soome#if defined(__x86)
1419abc7a5Toomas Soomestatic char *fbarg;
1429abc7a5Toomas Soomestatic char *fbarg_used;
1439abc7a5Toomas Soomestatic int fbarg_entnum = BE_ENTRY_DEFAULT;
1449abc7a5Toomas Soome#endif	/* __x86 */
1451939740Sherry Moore
1461939740Sherry Moorestatic int validate_ufs_disk(char *, char *);
1471939740Sherry Moorestatic int validate_zfs_pool(char *, char *);
1481939740Sherry Moore
1493f2f09cdpstatic pid_t
1503f2f09cdpget_initpid()
1513f2f09cdp{
1523f2f09cdp	static int init_pid = -1;
1533f2f09cdp
1543f2f09cdp	if (init_pid == -1) {
1553f2f09cdp		if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
1563f2f09cdp		    sizeof (init_pid)) != sizeof (init_pid)) {
1573f2f09cdp			assert(errno == ESRCH);
1583f2f09cdp			init_pid = -1;
1593f2f09cdp		}
1603f2f09cdp	}
1613f2f09cdp	return (init_pid);
1623f2f09cdp}
1633f2f09cdp
1643f2f09cdp/*
1653f2f09cdp * Quiesce or resume init using /proc.  When stopping init, we can't send
1663f2f09cdp * SIGTSTP (since init ignores it) or SIGSTOP (since the kernel won't permit
1673f2f09cdp * it).
1683f2f09cdp */
1693f2f09cdpstatic int
1703f2f09cdpdirect_init(long command)
1713f2f09cdp{
1723f2f09cdp	char ctlfile[MAXPATHLEN];
1733f2f09cdp	pid_t pid;
1743f2f09cdp	int ctlfd;
1753f2f09cdp
1763f2f09cdp	assert(command == PCDSTOP || command == PCRUN);
1773f2f09cdp	if ((pid = get_initpid()) == -1) {
1783f2f09cdp		return (-1);
1793f2f09cdp	}
1803f2f09cdp
1813f2f09cdp	(void) snprintf(ctlfile, sizeof (ctlfile), "/proc/%d/ctl", pid);
1823f2f09cdp	if ((ctlfd = open(ctlfile, O_WRONLY)) == -1)
1833f2f09cdp		return (-1);
1843f2f09cdp
1853f2f09cdp	if (command == PCDSTOP) {
1863f2f09cdp		if (write(ctlfd, &command, sizeof (long)) == -1) {
1873f2f09cdp			(void) close(ctlfd);
1883f2f09cdp			return (-1);
1893f2f09cdp		}
1903f2f09cdp	} else {	/* command == PCRUN */
1913f2f09cdp		long cmds[2];
1923f2f09cdp		cmds[0] = command;
1933f2f09cdp		cmds[1] = 0;
1943f2f09cdp		if (write(ctlfd, cmds, sizeof (cmds)) == -1) {
1953f2f09cdp			(void) close(ctlfd);
1963f2f09cdp			return (-1);
1973f2f09cdp		}
1983f2f09cdp	}
1993f2f09cdp	(void) close(ctlfd);
2003f2f09cdp	return (0);
2013f2f09cdp}
2023f2f09cdp
2037c478bdstevel@tonic-gatestatic void
2047c478bdstevel@tonic-gatestop_startd()
2057c478bdstevel@tonic-gate{
2067c478bdstevel@tonic-gate	scf_handle_t *h;
2077c478bdstevel@tonic-gate	scf_property_t *prop = NULL;
2087c478bdstevel@tonic-gate	scf_value_t *val = NULL;
2097c478bdstevel@tonic-gate	uint64_t uint64;
2107c478bdstevel@tonic-gate
2113f2f09cdp	if ((h = scf_handle_create(SCF_VERSION)) == NULL)
2127c478bdstevel@tonic-gate		return;
2137c478bdstevel@tonic-gate
2143f2f09cdp	if ((scf_handle_bind(h) != 0) ||
2153f2f09cdp	    ((prop = scf_property_create(h)) == NULL) ||
2163f2f09cdp	    ((val = scf_value_create(h)) == NULL))
2177c478bdstevel@tonic-gate		goto out;
2187c478bdstevel@tonic-gate
2193f2f09cdp	if (scf_handle_decode_fmri(h, FMRI_STARTD_CONTRACT,
2203f2f09cdp	    NULL, NULL, NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
2217c478bdstevel@tonic-gate		goto out;
2227c478bdstevel@tonic-gate
2233f2f09cdp	if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
2243f2f09cdp	    scf_property_get_value(prop, val) != 0 ||
2253f2f09cdp	    scf_value_get_count(val, &uint64) != 0)
2267c478bdstevel@tonic-gate		goto out;
2277c478bdstevel@tonic-gate
2283f2f09cdp	startdct = (ctid_t)uint64;
2293f2f09cdp	(void) sigsend(P_CTID, startdct, SIGSTOP);
2307c478bdstevel@tonic-gate
2317c478bdstevel@tonic-gateout:
2323f2f09cdp	scf_property_destroy(prop);
2333f2f09cdp	scf_value_destroy(val);
2347c478bdstevel@tonic-gate	scf_handle_destroy(h);
2357c478bdstevel@tonic-gate}
2367c478bdstevel@tonic-gate
2377c478bdstevel@tonic-gatestatic void
2387c478bdstevel@tonic-gatecontinue_startd()
2397c478bdstevel@tonic-gate{
2407c478bdstevel@tonic-gate	if (startdct != -1)
2417c478bdstevel@tonic-gate		(void) sigsend(P_CTID, startdct, SIGCONT);
2427c478bdstevel@tonic-gate}
2437c478bdstevel@tonic-gate
2447c478bdstevel@tonic-gate#define	FMRI_RESTARTER_PROP "/:properties/general/restarter"
2457c478bdstevel@tonic-gate#define	FMRI_CONTRACT_PROP "/:properties/restarter/contract"
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gatestatic int
2487c478bdstevel@tonic-gatesave_ctid(ctid_t ctid)
2497c478bdstevel@tonic-gate{
2507c478bdstevel@tonic-gate	ctidlist_t *next;
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gate	for (next = ctidlist; next != NULL; next = next->next)
2537c478bdstevel@tonic-gate		if (next->ctid == ctid)
2547c478bdstevel@tonic-gate			return (-1);
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gate	next = (ctidlist_t *)malloc(sizeof (ctidlist_t));
2577c478bdstevel@tonic-gate	if (next == NULL)
2587c478bdstevel@tonic-gate		return (-1);
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate	next->ctid = ctid;
2617c478bdstevel@tonic-gate	next->next = ctidlist;
2627c478bdstevel@tonic-gate	ctidlist = next;
2637c478bdstevel@tonic-gate	return (0);
2647c478bdstevel@tonic-gate}
2657c478bdstevel@tonic-gate
2667c478bdstevel@tonic-gatestatic void
2677c478bdstevel@tonic-gatestop_delegates()
2687c478bdstevel@tonic-gate{
2697c478bdstevel@tonic-gate	ctid_t ctid;
2707c478bdstevel@tonic-gate	scf_handle_t *h;
2717c478bdstevel@tonic-gate	scf_scope_t *sc = NULL;
2727c478bdstevel@tonic-gate	scf_service_t *svc = NULL;
2737c478bdstevel@tonic-gate	scf_instance_t *inst = NULL;
2747c478bdstevel@tonic-gate	scf_snapshot_t *snap = NULL;
2757c478bdstevel@tonic-gate	scf_snapshot_t *isnap = NULL;
2767c478bdstevel@tonic-gate	scf_propertygroup_t *pg = NULL;
2777c478bdstevel@tonic-gate	scf_property_t *prop = NULL;
2787c478bdstevel@tonic-gate	scf_value_t *val = NULL;
2797c478bdstevel@tonic-gate	scf_iter_t *siter = NULL;
2807c478bdstevel@tonic-gate	scf_iter_t *iiter = NULL;
2817c478bdstevel@tonic-gate	char *fmri;
2827c478bdstevel@tonic-gate	ssize_t length;
2837c478bdstevel@tonic-gate
2847c478bdstevel@tonic-gate	uint64_t uint64;
2857c478bdstevel@tonic-gate	ssize_t bytes;
2867c478bdstevel@tonic-gate
2877c478bdstevel@tonic-gate	length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2887c478bdstevel@tonic-gate	if (length <= 0)
2897c478bdstevel@tonic-gate		return;
2907c478bdstevel@tonic-gate
2917c478bdstevel@tonic-gate	length++;
2927c478bdstevel@tonic-gate	fmri = alloca(length * sizeof (char));
2937c478bdstevel@tonic-gate
2943f2f09cdp	if ((h = scf_handle_create(SCF_VERSION)) == NULL)
2957c478bdstevel@tonic-gate		return;
2967c478bdstevel@tonic-gate
2973f2f09cdp	if (scf_handle_bind(h) != 0) {
2987c478bdstevel@tonic-gate		scf_handle_destroy(h);
2997c478bdstevel@tonic-gate		return;
3007c478bdstevel@tonic-gate	}
3017c478bdstevel@tonic-gate
3023f2f09cdp	if ((sc = scf_scope_create(h)) == NULL ||
3033f2f09cdp	    (svc = scf_service_create(h)) == NULL ||
3043f2f09cdp	    (inst = scf_instance_create(h)) == NULL ||
3053f2f09cdp	    (snap = scf_snapshot_create(h)) == NULL ||
3063f2f09cdp	    (pg = scf_pg_create(h)) == NULL ||
3073f2f09cdp	    (prop = scf_property_create(h)) == NULL ||
3083f2f09cdp	    (val = scf_value_create(h)) == NULL ||
3093f2f09cdp	    (siter = scf_iter_create(h)) == NULL ||
3103f2f09cdp	    (iiter = scf_iter_create(h)) == NULL)
3117c478bdstevel@tonic-gate		goto out;
3127c478bdstevel@tonic-gate
3133f2f09cdp	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) != 0)
3147c478bdstevel@tonic-gate		goto out;
3157c478bdstevel@tonic-gate
3163f2f09cdp	if (scf_iter_scope_services(siter, sc) != 0)
3177c478bdstevel@tonic-gate		goto out;
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gate	while (scf_iter_next_service(siter, svc) == 1) {
3207c478bdstevel@tonic-gate
3213f2f09cdp		if (scf_iter_service_instances(iiter, svc) != 0)
3227c478bdstevel@tonic-gate			continue;
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate		while (scf_iter_next_instance(iiter, inst) == 1) {
3257c478bdstevel@tonic-gate
3263f2f09cdp			if ((scf_instance_get_snapshot(inst, "running",
3273f2f09cdp			    snap)) != 0)
3283f2f09cdp				isnap = NULL;
3293f2f09cdp			else
3303f2f09cdp				isnap = snap;
3317c478bdstevel@tonic-gate
3323f2f09cdp			if (scf_instance_get_pg_composed(inst, isnap,
3333f2f09cdp			    SCF_PG_GENERAL, pg) != 0)
3347c478bdstevel@tonic-gate				continue;
3357c478bdstevel@tonic-gate
3363f2f09cdp			if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER,
3373f2f09cdp			    prop) != 0 ||
3383f2f09cdp			    scf_property_get_value(prop, val) != 0)
3397c478bdstevel@tonic-gate				continue;
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gate			bytes = scf_value_get_astring(val, fmri, length);
3427c478bdstevel@tonic-gate			if (bytes <= 0 || bytes >= length)
3437c478bdstevel@tonic-gate				continue;
3447c478bdstevel@tonic-gate
3457c478bdstevel@tonic-gate			if (strlcat(fmri, FMRI_CONTRACT_PROP, length) >=
3467c478bdstevel@tonic-gate			    length)
3477c478bdstevel@tonic-gate				continue;
3487c478bdstevel@tonic-gate
3493f2f09cdp			if (scf_handle_decode_fmri(h, fmri, NULL, NULL,
3503f2f09cdp			    NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
3517c478bdstevel@tonic-gate				continue;
3527c478bdstevel@tonic-gate
3533f2f09cdp			if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
3543f2f09cdp			    scf_property_get_value(prop, val) != 0 ||
3553f2f09cdp			    scf_value_get_count(val, &uint64) != 0)
3567c478bdstevel@tonic-gate				continue;
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gate			ctid = (ctid_t)uint64;
3597c478bdstevel@tonic-gate			if (save_ctid(ctid) == 0) {
3607c478bdstevel@tonic-gate				(void) sigsend(P_CTID, ctid, SIGSTOP);
3617c478bdstevel@tonic-gate			}
3627c478bdstevel@tonic-gate		}
3637c478bdstevel@tonic-gate	}
3647c478bdstevel@tonic-gateout:
3653f2f09cdp	scf_scope_destroy(sc);
3663f2f09cdp	scf_service_destroy(svc);
3673f2f09cdp	scf_instance_destroy(inst);
3683f2f09cdp	scf_snapshot_destroy(snap);
3693f2f09cdp	scf_pg_destroy(pg);
3703f2f09cdp	scf_property_destroy(prop);
3713f2f09cdp	scf_value_destroy(val);
3723f2f09cdp	scf_iter_destroy(siter);
3733f2f09cdp	scf_iter_destroy(iiter);
3747c478bdstevel@tonic-gate
3757c478bdstevel@tonic-gate	(void) scf_handle_unbind(h);
3767c478bdstevel@tonic-gate	scf_handle_destroy(h);
3777c478bdstevel@tonic-gate}
3787c478bdstevel@tonic-gate
3797c478bdstevel@tonic-gatestatic void
3807c478bdstevel@tonic-gatecontinue_delegates()
3817c478bdstevel@tonic-gate{
3827c478bdstevel@tonic-gate	ctidlist_t *next;
3837c478bdstevel@tonic-gate	for (next = ctidlist; next != NULL; next = next->next)
3847c478bdstevel@tonic-gate		(void) sigsend(P_CTID, next->ctid, SIGCONT);
3857c478bdstevel@tonic-gate}
3867c478bdstevel@tonic-gate
3879db7147Sherry Moore#define	FMRI_GDM "svc:/application/graphical-login/gdm:default"
3883b860eeSherry Moore#define	GDM_STOP_TIMEOUT	10	/* Give gdm 10 seconds to shut down */
3899db7147Sherry Moore
3909db7147Sherry Moore/*
3919db7147Sherry Moore * If gdm is running, try to stop gdm.
3929db7147Sherry Moore * Returns  0 on success, -1 on failure.
3939db7147Sherry Moore */
3949db7147Sherry Moorestatic int
3959db7147Sherry Moorestop_gdm()
3969db7147Sherry Moore{
3979db7147Sherry Moore	char *gdm_state = NULL;
3989db7147Sherry Moore	int retry = 0;
3999db7147Sherry Moore
4009db7147Sherry Moore	/*
4019db7147Sherry Moore	 * If gdm is running, try to stop gdm.
4029db7147Sherry Moore	 */
4039db7147Sherry Moore	while ((gdm_state = smf_get_state(FMRI_GDM)) != NULL &&
4043b860eeSherry Moore	    strcmp(gdm_state, SCF_STATE_STRING_ONLINE) == 0 &&
4053b860eeSherry Moore	    retry++ < GDM_STOP_TIMEOUT) {
4063b860eeSherry Moore
4073b860eeSherry Moore		free(gdm_state);
4083b860eeSherry Moore
4093b860eeSherry Moore		/*
4103b860eeSherry Moore		 * Only need to disable once.
4113b860eeSherry Moore		 */
4123b860eeSherry Moore		if (retry == 1 &&
4133b860eeSherry Moore		    smf_disable_instance(FMRI_GDM, SMF_TEMPORARY) != 0) {
4149db7147Sherry Moore			(void) fprintf(stderr,
4159db7147Sherry Moore			    gettext("%s: Failed to stop %s: %s.\n"),
4169db7147Sherry Moore			    cmdname, FMRI_GDM, scf_strerror(scf_error()));
4179db7147Sherry Moore			return (-1);
4189db7147Sherry Moore		}
4199db7147Sherry Moore		(void) sleep(1);
4209db7147Sherry Moore	}
4219db7147Sherry Moore
4223b860eeSherry Moore	if (retry >= GDM_STOP_TIMEOUT) {
4239db7147Sherry Moore		(void) fprintf(stderr, gettext("%s: Failed to stop %s.\n"),
4249db7147Sherry Moore		    cmdname, FMRI_GDM);
4259db7147Sherry Moore		return (-1);
4269db7147Sherry Moore	}
4279db7147Sherry Moore
4289db7147Sherry Moore	return (0);
4299db7147Sherry Moore}
4309db7147Sherry Moore
4319db7147Sherry Moore
4327c478bdstevel@tonic-gatestatic void
4337c478bdstevel@tonic-gatestop_restarters()
4347c478bdstevel@tonic-gate{
4357c478bdstevel@tonic-gate	stop_startd();
4367c478bdstevel@tonic-gate	stop_delegates();
4377c478bdstevel@tonic-gate}
4387c478bdstevel@tonic-gate
4397c478bdstevel@tonic-gatestatic void
4407c478bdstevel@tonic-gatecontinue_restarters()
4417c478bdstevel@tonic-gate{
4427c478bdstevel@tonic-gate	continue_startd();
4437c478bdstevel@tonic-gate	continue_delegates();
4447c478bdstevel@tonic-gate}
4457c478bdstevel@tonic-gate
4467c478bdstevel@tonic-gate/*
4477c478bdstevel@tonic-gate * Copy an array of strings into buf, separated by spaces.  Returns 0 on
4487c478bdstevel@tonic-gate * success.
4497c478bdstevel@tonic-gate */
4507c478bdstevel@tonic-gatestatic int
4517c478bdstevel@tonic-gategather_args(char **args, char *buf, size_t buf_sz)
4527c478bdstevel@tonic-gate{
4537c478bdstevel@tonic-gate	if (strlcpy(buf, *args, buf_sz) >= buf_sz)
4547c478bdstevel@tonic-gate		return (-1);
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gate	for (++args; *args != NULL; ++args) {
4577c478bdstevel@tonic-gate		if (strlcat(buf, " ", buf_sz) >= buf_sz)
4587c478bdstevel@tonic-gate			return (-1);
4597c478bdstevel@tonic-gate		if (strlcat(buf, *args, buf_sz) >= buf_sz)
4607c478bdstevel@tonic-gate			return (-1);
4617c478bdstevel@tonic-gate	}
4627c478bdstevel@tonic-gate
4637c478bdstevel@tonic-gate	return (0);
4647c478bdstevel@tonic-gate}
4657c478bdstevel@tonic-gate
46626f665edstaff/*
46726f665edstaff * Halt every zone on the system.  We are committed to doing a shutdown
46826f665edstaff * even if something goes wrong here. If something goes wrong, we just
46926f665edstaff * continue with the shutdown.  Return non-zero if we need to wait for zones to
47026f665edstaff * halt later on.
47126f665edstaff */
47226f665edstaffstatic int
4733f2f09cdphalt_zones()
47426f665edstaff{
47526f665edstaff	pid_t pid;
47626f665edstaff	zoneid_t *zones;
4773f2f09cdp	size_t nz = 0, old_nz;
47826f665edstaff	int i;
47926f665edstaff	char zname[ZONENAME_MAX];
48026f665edstaff
48126f665edstaff	/*
48226f665edstaff	 * Get a list of zones. If the number of zones changes in between the
48326f665edstaff	 * two zone_list calls, try again.
48426f665edstaff	 */
48526f665edstaff
48626f665edstaff	for (;;) {
48726f665edstaff		(void) zone_list(NULL, &nz);
48826f665edstaff		if (nz == 1)
48926f665edstaff			return (0);
49026f665edstaff		old_nz = nz;
49126f665edstaff		zones = calloc(sizeof (zoneid_t), nz);
49226f665edstaff		if (zones == NULL) {
49326f665edstaff			(void) fprintf(stderr,
49426f665edstaff			    gettext("%s: Could not halt zones"
4953f2f09cdp			    " (out of memory).\n"), cmdname);
49626f665edstaff			return (0);
49726f665edstaff		}
49826f665edstaff
49926f665edstaff		(void) zone_list(zones, &nz);
50026f665edstaff		if (old_nz == nz)
50126f665edstaff			break;
50226f665edstaff		free(zones);
50326f665edstaff	}
50426f665edstaff
50526f665edstaff	if (nz == 2) {
5063f2f09cdp		(void) fprintf(stderr, gettext("%s: Halting 1 zone.\n"),
5073f2f09cdp		    cmdname);
50826f665edstaff	} else {
5093f2f09cdp		(void) fprintf(stderr, gettext("%s: Halting %i zones.\n"),
5103f2f09cdp		    cmdname, nz - 1);
51126f665edstaff	}
51226f665edstaff
51326f665edstaff	for (i = 0; i < nz; i++) {
51426f665edstaff		if (zones[i] == GLOBAL_ZONEID)
51526f665edstaff			continue;
51626f665edstaff		if (getzonenamebyid(zones[i], zname, sizeof (zname)) < 0) {
51726f665edstaff			/*
51826f665edstaff			 * getzonenamebyid should only fail if we raced with
51926f665edstaff			 * another process trying to shut down the zone.
52026f665edstaff			 * We assume this happened and ignore the error.
52126f665edstaff			 */
52226f665edstaff			if (errno != EINVAL) {
52326f665edstaff				(void) fprintf(stderr,
52426f665edstaff				    gettext("%s: Unexpected error while "
52526f665edstaff				    "looking up zone %ul: %s.\n"),
5263f2f09cdp				    cmdname, zones[i], strerror(errno));
52726f665edstaff			}
52826f665edstaff
52926f665edstaff			continue;
53026f665edstaff		}
53126f665edstaff		pid = fork();
53226f665edstaff		if (pid < 0) {
53326f665edstaff			(void) fprintf(stderr,
53426f665edstaff			    gettext("%s: Zone \"%s\" could not be"
53526f665edstaff			    " halted (could not fork(): %s).\n"),
5363f2f09cdp			    cmdname, zname, strerror(errno));
53726f665edstaff			continue;
53826f665edstaff		}
53926f665edstaff		if (pid == 0) {
54026f665edstaff			(void) execl(ZONEADM_PROG, ZONEADM_PROG,
54126f665edstaff			    "-z", zname, "halt", NULL);
54226f665edstaff			(void) fprintf(stderr,
54326f665edstaff			    gettext("%s: Zone \"%s\" could not be halted"
54426f665edstaff			    " (cannot exec(" ZONEADM_PROG "): %s).\n"),
5453f2f09cdp			    cmdname, zname, strerror(errno));
54626f665edstaff			exit(0);
54726f665edstaff		}
54826f665edstaff	}
54926f665edstaff
55026f665edstaff	return (1);
55126f665edstaff}
55226f665edstaff
55326f665edstaff/*
55426f665edstaff * This function tries to wait for all non-global zones to go away.
55526f665edstaff * It will timeout if no progress is made for 5 seconds, or a total of
55626f665edstaff * 30 seconds elapses.
55726f665edstaff */
55826f665edstaff
55926f665edstaffstatic void
5603f2f09cdpcheck_zones_haltedness()
56126f665edstaff{
56226f665edstaff	int t = 0, t_prog = 0;
56326f665edstaff	size_t nz = 0, last_nz;
56426f665edstaff
56526f665edstaff	do {
56626f665edstaff		last_nz = nz;
56726f665edstaff		(void) zone_list(NULL, &nz);
56826f665edstaff		if (nz == 1)
56926f665edstaff			return;
57026f665edstaff
57126f665edstaff		(void) sleep(1);
57226f665edstaff
57326f665edstaff		if (last_nz > nz)
57426f665edstaff			t_prog = 0;
57526f665edstaff
57626f665edstaff		t++;
57726f665edstaff		t_prog++;
57826f665edstaff
57926f665edstaff		if (t == 10) {
58026f665edstaff			if (nz == 2) {
58126f665edstaff				(void) fprintf(stderr,
58226f665edstaff				    gettext("%s: Still waiting for 1 zone to "
58326f665edstaff				    "halt. Will wait up to 20 seconds.\n"),
5843f2f09cdp				    cmdname);
58526f665edstaff			} else {
58626f665edstaff				(void) fprintf(stderr,
58726f665edstaff				    gettext("%s: Still waiting for %i zones "
58826f665edstaff				    "to halt. Will wait up to 20 seconds.\n"),
5893f2f09cdp				    cmdname, nz - 1);
59026f665edstaff			}
59126f665edstaff		}
59226f665edstaff
59326f665edstaff	} while ((t < 30) && (t_prog < 5));
59426f665edstaff}
59526f665edstaff
5961939740Sherry Moore
5971939740Sherry Moore/*
5981939740Sherry Moore * Validate that this is a root disk or dataset
5991939740Sherry Moore * Returns 0 if it is a root disk or dataset;
6001939740Sherry Moore * returns 1 if it is a disk argument or dataset, but not valid or not root;
6011939740Sherry Moore * returns -1 if it is not a valid argument or a disk argument.
6021939740Sherry Moore */
6031939740Sherry Moorestatic int
6041939740Sherry Moorevalidate_disk(char *arg, char *mountpoint)
6051939740Sherry Moore{
6061939740Sherry Moore	static char root_dev_path[] = "/dev/dsk";
6071939740Sherry Moore	char kernpath[MAXPATHLEN];
6081939740Sherry Moore	struct stat64 statbuf;
6091939740Sherry Moore	int rc = 0;
6101939740Sherry Moore
6111939740Sherry Moore	if (strlen(arg) > MAXPATHLEN) {
6121939740Sherry Moore		(void) fprintf(stderr,
613753a6d4Sherry Moore		    gettext("%s: Argument is too long\n"), cmdname);
6141939740Sherry Moore		return (-1);
6151939740Sherry Moore	}
6161939740Sherry Moore
6171939740Sherry Moore	bcopy(FASTBOOT_MOUNTPOINT, mountpoint, sizeof (FASTBOOT_MOUNTPOINT));
6181939740Sherry Moore
619753a6d4Sherry Moore	if (strstr(arg, mountpoint) == NULL) {
620753a6d4Sherry Moore		/*
621753a6d4Sherry Moore		 * Do a force umount just in case some other filesystem has
622753a6d4Sherry Moore		 * been mounted there.
623753a6d4Sherry Moore		 */
624753a6d4Sherry Moore		(void) umount2(mountpoint, MS_FORCE);
625753a6d4Sherry Moore	}
6261939740Sherry Moore
6271939740Sherry Moore	/* Create the directory if it doesn't already exist */
628753a6d4Sherry Moore	if (lstat64(mountpoint, &statbuf) != 0) {
6291939740Sherry Moore		if (mkdirp(mountpoint, 0755) != 0) {
6301939740Sherry Moore			(void) fprintf(stderr,
631753a6d4Sherry Moore			    gettext("Failed to create mountpoint %s\n"),
6321939740Sherry Moore			    mountpoint);
6331939740Sherry Moore			return (-1);
6341939740Sherry Moore		}
6351939740Sherry Moore	}
6361939740Sherry Moore
6371939740Sherry Moore	if (strncmp(arg, root_dev_path, strlen(root_dev_path)) == 0) {
6381939740Sherry Moore		/* ufs root disk argument */
6391939740Sherry Moore		rc = validate_ufs_disk(arg, mountpoint);
6401939740Sherry Moore	} else {
6411939740Sherry Moore		/* zfs root pool argument */
6421939740Sherry Moore		rc = validate_zfs_pool(arg, mountpoint);
6431939740Sherry Moore	}
6441939740Sherry Moore
6451939740Sherry Moore	if (rc != 0)
6461939740Sherry Moore		return (rc);
6471939740Sherry Moore
6484e995f2Marcel Telka	/*
6494e995f2Marcel Telka	 * Check for the usual case: 64-bit kernel
6504e995f2Marcel Telka	 */
6514e995f2Marcel Telka	(void) snprintf(kernpath, MAXPATHLEN,
6524e995f2Marcel Telka	    "%s/platform/i86pc/kernel/amd64/unix", mountpoint);
6534e995f2Marcel Telka	if (stat64(kernpath, &statbuf) == 0)
6544e995f2Marcel Telka		return (0);
6554e995f2Marcel Telka
6564e995f2Marcel Telka	/*
6574e995f2Marcel Telka	 * We no longer build 32-bit kernel but in a case we are trying to boot
6584e995f2Marcel Telka	 * some ancient filesystem with 32-bit only kernel we should be able to
6594e995f2Marcel Telka	 * proceed too
6604e995f2Marcel Telka	 */
6611939740Sherry Moore	(void) snprintf(kernpath, MAXPATHLEN, "%s/platform/i86pc/kernel/unix",
6621939740Sherry Moore	    mountpoint);
6631939740Sherry Moore
6641939740Sherry Moore	if (stat64(kernpath, &statbuf) != 0) {
6651939740Sherry Moore		(void) fprintf(stderr,
6661939740Sherry Moore		    gettext("%s: %s is not a root disk or dataset\n"),
6671939740Sherry Moore		    cmdname, arg);
6681939740Sherry Moore		return (1);
6691939740Sherry Moore	}
6701939740Sherry Moore
6711939740Sherry Moore	return (0);
6721939740Sherry Moore}
6731939740Sherry Moore
6741939740Sherry Moore
6751939740Sherry Moorestatic int
6761939740Sherry Moorevalidate_ufs_disk(char *arg, char *mountpoint)
6771939740Sherry Moore{
6788e07a41Konstantin Ananyev	struct ufs_args	ufs_args = { 0 };
6798e07a41Konstantin Ananyev	char mntopts[MNT_LINE_MAX] = MNTOPT_LARGEFILES;
6801939740Sherry Moore
6811939740Sherry Moore	/* perform the mount */
6828e07a41Konstantin Ananyev	ufs_args.flags = UFSMNT_LARGEFILES;
6831939740Sherry Moore	if (mount(arg, mountpoint, MS_DATA|MS_OPTIONSTR,
6848e07a41Konstantin Ananyev	    MNTTYPE_UFS, &ufs_args, sizeof (ufs_args),
6858e07a41Konstantin Ananyev	    mntopts, sizeof (mntopts)) != 0) {
6861939740Sherry Moore		perror(cmdname);
6871939740Sherry Moore		(void) fprintf(stderr,
688753a6d4Sherry Moore		    gettext("%s: Failed to mount %s\n"), cmdname, arg);
6891939740Sherry Moore		return (-1);
6901939740Sherry Moore	}
6911939740Sherry Moore
6921939740Sherry Moore	return (0);
6931939740Sherry Moore}
6941939740Sherry Moore
6951939740Sherry Moorestatic int
6961939740Sherry Moorevalidate_zfs_pool(char *arg, char *mountpoint)
6971939740Sherry Moore{
6981939740Sherry Moore	zfs_handle_t *zhp = NULL;
6991939740Sherry Moore	char mntopts[MNT_LINE_MAX] = { '\0' };
7001939740Sherry Moore	int rc = 0;
7011939740Sherry Moore
7021939740Sherry Moore	if ((g_zfs = libzfs_init()) == NULL) {
703753a6d4Sherry Moore		(void) fprintf(stderr, gettext("Internal error: failed to "
7041939740Sherry Moore		    "initialize ZFS library\n"));
7051939740Sherry Moore		return (-1);
7061939740Sherry Moore	}
7071939740Sherry Moore
7081939740Sherry Moore	/* Try to open the dataset */
7091939740Sherry Moore	if ((zhp = zfs_open(g_zfs, arg,
7101939740Sherry Moore	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_DATASET)) == NULL)
7111939740Sherry Moore		return (-1);
7121939740Sherry Moore
7131939740Sherry Moore	/* perform the mount */
714753a6d4Sherry Moore	if (mount(zfs_get_name(zhp), mountpoint, MS_DATA|MS_OPTIONSTR|MS_RDONLY,
7151939740Sherry Moore	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
7161939740Sherry Moore		perror(cmdname);
7171939740Sherry Moore		(void) fprintf(stderr,
718753a6d4Sherry Moore		    gettext("%s: Failed to mount %s\n"), cmdname, arg);
7191939740Sherry Moore		rc = -1;
7201939740Sherry Moore	}
7211939740Sherry Moore
7221939740Sherry Moorevalidate_zfs_err_out:
7231939740Sherry Moore	if (zhp != NULL)
7241939740Sherry Moore		zfs_close(zhp);
7251939740Sherry Moore
7261939740Sherry Moore	libzfs_fini(g_zfs);
7271939740Sherry Moore	return (rc);
7281939740Sherry Moore}
7291939740Sherry Moore
7301939740Sherry Moore/*
7311939740Sherry Moore * Return 0 if not zfs, or is zfs and have successfully constructed the
7321939740Sherry Moore * boot argument; returns non-zero otherwise.
7331939740Sherry Moore * At successful completion fpth contains pointer where mount point ends.
7341939740Sherry Moore * NOTE: arg is supposed to be the resolved path
7351939740Sherry Moore */
7361939740Sherry Moorestatic int
7371939740Sherry Mooreget_zfs_bootfs_arg(const char *arg, const char ** fpth, int *is_zfs,
7389adfa60Matthew Ahrens    char *bootfs_arg)
7391939740Sherry Moore{
7401939740Sherry Moore	zfs_handle_t *zhp = NULL;
7411939740Sherry Moore	zpool_handle_t *zpoolp = NULL;
7421939740Sherry Moore	FILE *mtabp = NULL;
7431939740Sherry Moore	struct mnttab mnt;
7441939740Sherry Moore	char *poolname = NULL;
745753a6d4Sherry Moore	char physpath[MAXPATHLEN];
7469adfa60Matthew Ahrens	char mntsp[ZFS_MAX_DATASET_NAME_LEN];
7479adfa60Matthew Ahrens	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
7481939740Sherry Moore	int rc = 0;
7491939740Sherry Moore	size_t mntlen = 0;
7501939740Sherry Moore	size_t msz;
751753a6d4Sherry Moore	static char fmt[] = "-B zfs-bootfs=%s,bootpath=\"%s\"";
7521939740Sherry Moore
7531939740Sherry Moore	*fpth = arg;
7541939740Sherry Moore	*is_zfs = 0;
7551939740Sherry Moore
7561939740Sherry Moore	bzero(physpath, sizeof (physpath));
7571939740Sherry Moore	bzero(bootfs, sizeof (bootfs));
7581939740Sherry Moore
7591939740Sherry Moore	if ((mtabp = fopen(MNTTAB, "r")) == NULL) {
7601939740Sherry Moore		return (-1);
7611939740Sherry Moore	}
7621939740Sherry Moore
7631939740Sherry Moore	while (getmntent(mtabp, &mnt) == 0) {
7641939740Sherry Moore		if (strstr(arg, mnt.mnt_mountp) == arg &&
7651939740Sherry Moore		    (msz = strlen(mnt.mnt_mountp)) > mntlen) {
7661939740Sherry Moore			mntlen = msz;
7671939740Sherry Moore			*is_zfs = strcmp(MNTTYPE_ZFS, mnt.mnt_fstype) == 0;
7681939740Sherry Moore			(void) strlcpy(mntsp, mnt.mnt_special, sizeof (mntsp));
7691939740Sherry Moore		}
7701939740Sherry Moore	}
7711939740Sherry Moore
7721939740Sherry Moore	(void) fclose(mtabp);
7731939740Sherry Moore
7741939740Sherry Moore	if (mntlen > 1)
7751939740Sherry Moore		*fpth += mntlen;
7761939740Sherry Moore
7771939740Sherry Moore	if (!*is_zfs)
7781939740Sherry Moore		return (0);
7791939740Sherry Moore
7801939740Sherry Moore	if ((g_zfs = libzfs_init()) == NULL)
7811939740Sherry Moore		return (-1);
7821939740Sherry Moore
7831939740Sherry Moore	/* Try to open the dataset */
7841939740Sherry Moore	if ((zhp = zfs_open(g_zfs, mntsp,
7851939740Sherry Moore	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_DATASET)) == NULL) {
786753a6d4Sherry Moore		(void) fprintf(stderr, gettext("Cannot open %s\n"), mntsp);
7871939740Sherry Moore		rc = -1;
7881939740Sherry Moore		goto validate_zfs_err_out;
7891939740Sherry Moore	}
7901939740Sherry Moore
7911939740Sherry Moore	(void) strlcpy(bootfs, mntsp, sizeof (bootfs));
7921939740Sherry Moore
7931939740Sherry Moore	if ((poolname = strtok(mntsp, "/")) == NULL) {
7941939740Sherry Moore		rc = -1;
7951939740Sherry Moore		goto validate_zfs_err_out;
7961939740Sherry Moore	}
7971939740Sherry Moore
7981939740Sherry Moore	if ((zpoolp = zpool_open(g_zfs, poolname)) == NULL) {
799753a6d4Sherry Moore		(void) fprintf(stderr, gettext("Cannot open %s\n"), poolname);
8001939740Sherry Moore		rc = -1;
8011939740Sherry Moore		goto validate_zfs_err_out;
8021939740Sherry Moore	}
8031939740Sherry Moore
804753a6d4Sherry Moore	if (zpool_get_physpath(zpoolp, physpath, sizeof (physpath)) != 0) {
805753a6d4Sherry Moore		(void) fprintf(stderr, gettext("Cannot find phys_path\n"));
8061939740Sherry Moore		rc = -1;
8071939740Sherry Moore		goto validate_zfs_err_out;
8081939740Sherry Moore	}
8091939740Sherry Moore
810753a6d4Sherry Moore	/*
811753a6d4Sherry Moore	 * For the mirror physpath would contain the list of all
812753a6d4Sherry Moore	 * bootable devices, pick up the first one.
813753a6d4Sherry Moore	 */
814753a6d4Sherry Moore	(void) strtok(physpath, " ");
815753a6d4Sherry Moore	if (snprintf(bootfs_arg, BOOTARGS_MAX, fmt, bootfs, physpath) >=
816753a6d4Sherry Moore	    BOOTARGS_MAX) {
817753a6d4Sherry Moore		rc = E2BIG;
818753a6d4Sherry Moore		(void) fprintf(stderr,
819753a6d4Sherry Moore		    gettext("Boot arguments are too long\n"));
8201939740Sherry Moore	}
8211939740Sherry Moore
8221939740Sherry Moorevalidate_zfs_err_out:
8231939740Sherry Moore	if (zhp != NULL)
8241939740Sherry Moore		zfs_close(zhp);
8251939740Sherry Moore
8261939740Sherry Moore	if (zpoolp != NULL)
8271939740Sherry Moore		zpool_close(zpoolp);
8281939740Sherry Moore
8291939740Sherry Moore	libzfs_fini(g_zfs);
8301939740Sherry Moore	return (rc);
8311939740Sherry Moore}
8321939740Sherry Moore
8331939740Sherry Moore/*
8341939740Sherry Moore * Validate that the file exists, and is an ELF file.
8351939740Sherry Moore * Returns 0 on success, -1 on failure.
8361939740Sherry Moore */
8371939740Sherry Moorestatic int
8385b89e3fSherry Moorevalidate_unix(char *arg, int *mplen, int *is_zfs, char *bootfs_arg)
8391939740Sherry Moore{
8401939740Sherry Moore	const char *location;
8411939740Sherry Moore	int class, format;
8421939740Sherry Moore	unsigned char ident[EI_NIDENT];
8431939740Sherry Moore	char physpath[MAXPATHLEN];
8441939740Sherry Moore	int elffd = -1;
8451939740Sherry Moore	size_t	sz;
8461939740Sherry Moore
8471939740Sherry Moore	if ((sz = resolvepath(arg, physpath, sizeof (physpath) - 1)) ==
8481939740Sherry Moore	    (size_t)-1) {
8491939740Sherry Moore		(void) fprintf(stderr,
850753a6d4Sherry Moore		    gettext("Cannot resolve path for %s: %s\n"),
8511939740Sherry Moore		    arg, strerror(errno));
8521939740Sherry Moore		return (-1);
8531939740Sherry Moore	}
8541939740Sherry Moore	(void) strlcpy(arg, physpath, sz + 1);
8551939740Sherry Moore
8561939740Sherry Moore	if (strlen(arg) > MAXPATHLEN) {
8571939740Sherry Moore		(void) fprintf(stderr,
858753a6d4Sherry Moore		    gettext("%s: New kernel name is too long\n"), cmdname);
8591939740Sherry Moore		return (-1);
8601939740Sherry Moore	}
8611939740Sherry Moore
8621939740Sherry Moore	if (strncmp(basename(arg), "unix", 4) != 0) {
8631939740Sherry Moore		(void) fprintf(stderr,
864753a6d4Sherry Moore		    gettext("%s: %s: Kernel name must be unix\n"),
8651939740Sherry Moore		    cmdname, arg);
8661939740Sherry Moore		return (-1);
8671939740Sherry Moore	}
8681939740Sherry Moore
8691939740Sherry Moore	if (get_zfs_bootfs_arg(arg, &location, is_zfs, bootfs_arg) != 0)
8701939740Sherry Moore		goto err_out;
8711939740Sherry Moore
8721939740Sherry Moore	*mplen = location - arg;
8731939740Sherry Moore
8745b89e3fSherry Moore	if (strstr(location, "/boot/platform") == location) {
8755b89e3fSherry Moore		/*
8765b89e3fSherry Moore		 * Rebooting to failsafe.
8775b89e3fSherry Moore		 * Clear bootfs_arg and is_zfs flag.
8785b89e3fSherry Moore		 */
8795b89e3fSherry Moore		bootfs_arg[0] = 0;
8805b89e3fSherry Moore		*is_zfs = 0;
8815b89e3fSherry Moore	} else if (strstr(location, "/platform") != location) {
8821939740Sherry Moore		(void) fprintf(stderr,
8835b89e3fSherry Moore		    gettext("%s: %s: No /platform in file name\n"),
8845b89e3fSherry Moore		    cmdname, arg);
8855b89e3fSherry Moore		goto err_out;
8861939740Sherry Moore	}
8871939740Sherry Moore
8881939740Sherry Moore	if ((elffd = open64(arg, O_RDONLY)) < 0 ||
8891939740Sherry Moore	    (pread64(elffd, ident, EI_NIDENT, 0) != EI_NIDENT)) {
8901939740Sherry Moore		(void) fprintf(stderr, "%s: %s: %s\n",
8911939740Sherry Moore		    cmdname, arg, strerror(errno));
8921939740Sherry Moore		goto err_out;
8931939740Sherry Moore	}
8941939740Sherry Moore
8951939740Sherry Moore	class = ident[EI_CLASS];
8961939740Sherry Moore
8971939740Sherry Moore	if ((class != ELFCLASS32 && class != ELFCLASS64) ||
898753a6d4Sherry Moore	    memcmp(&ident[EI_MAG0], ELFMAG, 4) != 0) {
8991939740Sherry Moore		(void) fprintf(stderr,
900753a6d4Sherry Moore		    gettext("%s: %s: Not a valid ELF file\n"), cmdname, arg);
9011939740Sherry Moore		goto err_out;
9021939740Sherry Moore	}
9031939740Sherry Moore
9041939740Sherry Moore	format = ident[EI_DATA];
9051939740Sherry Moore
9061939740Sherry Moore	if (format != CUR_ELFDATA) {
907753a6d4Sherry Moore		(void) fprintf(stderr, gettext("%s: %s: Invalid data format\n"),
9081939740Sherry Moore		    cmdname, arg);
9091939740Sherry Moore		goto err_out;
9101939740Sherry Moore	}
9111939740Sherry Moore
9121939740Sherry Moore	return (0);
9131939740Sherry Moore
9141939740Sherry Mooreerr_out:
9151939740Sherry Moore	if (elffd >= 0) {
9161939740Sherry Moore		(void) close(elffd);
9171939740Sherry Moore		elffd = -1;
9181939740Sherry Moore	}
9191939740Sherry Moore	return (-1);
9201939740Sherry Moore}
9211939740Sherry Moore
9221939740Sherry Moorestatic int
9234e1f1c1Konstantin Ananyevhalt_exec(const char *path, ...)
9244e1f1c1Konstantin Ananyev{
9254e1f1c1Konstantin Ananyev	pid_t		pid;
9264e1f1c1Konstantin Ananyev	int		i;
9274e1f1c1Konstantin Ananyev	int		st;
9284e1f1c1Konstantin Ananyev	const char	*arg;
9294e1f1c1Konstantin Ananyev	va_list	vp;
9304e1f1c1Konstantin Ananyev	const char	*argv[256];
9314e1f1c1Konstantin Ananyev
9324e1f1c1Konstantin Ananyev	if ((pid = fork()) == -1) {
9334e1f1c1Konstantin Ananyev		return (errno);
9344e1f1c1Konstantin Ananyev	} else if (pid == 0) {
9354e1f1c1Konstantin Ananyev		(void) fclose(stdout);
9364e1f1c1Konstantin Ananyev		(void) fclose(stderr);
9374e1f1c1Konstantin Ananyev
9384e1f1c1Konstantin Ananyev		argv[0] = path;
9394e1f1c1Konstantin Ananyev		i = 1;
9404e1f1c1Konstantin Ananyev
9414e1f1c1Konstantin Ananyev		va_start(vp, path);
9424e1f1c1Konstantin Ananyev
9434e1f1c1Konstantin Ananyev		do {
9444e1f1c1Konstantin Ananyev			arg = va_arg(vp, const char *);
9454e1f1c1Konstantin Ananyev			argv[i] = arg;
9464e1f1c1Konstantin Ananyev		} while (arg != NULL &&
9474e1f1c1Konstantin Ananyev		    ++i != sizeof (argv) / sizeof (argv[0]));
9484e1f1c1Konstantin Ananyev
9494e1f1c1Konstantin Ananyev		va_end(vp);
9504e1f1c1Konstantin Ananyev
9514e1f1c1Konstantin Ananyev		(void) execve(path, (char * const *)argv, NULL);
952753a6d4Sherry Moore		(void) fprintf(stderr, gettext("Cannot execute %s: %s\n"),
9534e1f1c1Konstantin Ananyev		    path, strerror(errno));
9544e1f1c1Konstantin Ananyev		exit(-1);
9554e1f1c1Konstantin Ananyev	} else {
9564e1f1c1Konstantin Ananyev		if (waitpid(pid, &st, 0) == pid &&
9574e1f1c1Konstantin Ananyev		    !WIFSIGNALED(st) && WIFEXITED(st))
9584e1f1c1Konstantin Ananyev			st = WEXITSTATUS(st);
9594e1f1c1Konstantin Ananyev		else
9604e1f1c1Konstantin Ananyev			st = -1;
9614e1f1c1Konstantin Ananyev	}
9624e1f1c1Konstantin Ananyev	return (st);
9634e1f1c1Konstantin Ananyev}
9644e1f1c1Konstantin Ananyev
9654e1f1c1Konstantin Ananyev/*
96680cb75fWilliam Kucharski * Mount the specified BE.
96780cb75fWilliam Kucharski *
96880cb75fWilliam Kucharski * Upon success returns zero and copies bename string to mountpoint[]
9694e1f1c1Konstantin Ananyev */
9704e1f1c1Konstantin Ananyevstatic int
9711939740Sherry Moorefastboot_bename(const char *bename, char *mountpoint, size_t mpsz)
9721939740Sherry Moore{
9731939740Sherry Moore	int rc;
9741939740Sherry Moore
97580cb75fWilliam Kucharski	/*
97680cb75fWilliam Kucharski	 * Attempt to unmount the BE first in case it's already mounted
97780cb75fWilliam Kucharski	 * elsewhere.
97880cb75fWilliam Kucharski	 */
97980cb75fWilliam Kucharski	(void) halt_exec(BEADM_PROG, "umount", bename, NULL);
9801939740Sherry Moore
98180cb75fWilliam Kucharski	if ((rc = halt_exec(BEADM_PROG, "mount", bename, FASTBOOT_MOUNTPOINT,
9824e1f1c1Konstantin Ananyev	    NULL)) != 0)
98380cb75fWilliam Kucharski		(void) fprintf(stderr,
98480cb75fWilliam Kucharski		    gettext("%s: Unable to mount BE \"%s\" at %s\n"),
98580cb75fWilliam Kucharski		    cmdname, bename, FASTBOOT_MOUNTPOINT);
9861939740Sherry Moore	else
9871939740Sherry Moore		(void) strlcpy(mountpoint, FASTBOOT_MOUNTPOINT, mpsz);
9881939740Sherry Moore
9891939740Sherry Moore	return (rc);
9901939740Sherry Moore}
9911939740Sherry Moore
9921939740Sherry Moore/*
9931939740Sherry Moore * Returns 0 on successful parsing of the arguments;
994753a6d4Sherry Moore * returns EINVAL on parsing failures that should abort the reboot attempt;
995753a6d4Sherry Moore * returns other error code to fall back to regular reboot.
9961939740Sherry Moore */
9971939740Sherry Moorestatic int
998753a6d4Sherry Mooreparse_fastboot_args(char *bootargs_buf, size_t buf_size,
9995b89e3fSherry Moore    int *is_dryrun, const char *bename)
10001939740Sherry Moore{
10011939740Sherry Moore	char mountpoint[MAXPATHLEN];
10021939740Sherry Moore	char bootargs_saved[BOOTARGS_MAX];
10031939740Sherry Moore	char bootargs_scratch[BOOTARGS_MAX];
10041939740Sherry Moore	char bootfs_arg[BOOTARGS_MAX];
10051939740Sherry Moore	char unixfile[BOOTARGS_MAX];
10061939740Sherry Moore	char *head, *newarg;
10071939740Sherry Moore	int buflen;		/* length of the bootargs_buf */
10081939740Sherry Moore	int mplen;		/* length of the mount point */
10091939740Sherry Moore	int rootlen = 0;	/* length of the root argument */
10101939740Sherry Moore	int unixlen = 0;	/* length of the unix argument */
10111939740Sherry Moore	int off = 0;		/* offset into the new boot argument */
10121939740Sherry Moore	int is_zfs = 0;
10131939740Sherry Moore	int rc = 0;
10141939740Sherry Moore
10151939740Sherry Moore	bzero(mountpoint, sizeof (mountpoint));
10161939740Sherry Moore
10171939740Sherry Moore	/*
10181939740Sherry Moore	 * If argc is not 0, buflen is length of the argument being passed in;
10191939740Sherry Moore	 * else it is 0 as bootargs_buf has been initialized to all 0's.
10201939740Sherry Moore	 */
10211939740Sherry Moore	buflen = strlen(bootargs_buf);
10221939740Sherry Moore
10231939740Sherry Moore	/* Save a copy of the original argument */
10241939740Sherry Moore	bcopy(bootargs_buf, bootargs_saved, buflen);
10251939740Sherry Moore	bzero(&bootargs_saved[buflen], sizeof (bootargs_saved) - buflen);
10261939740Sherry Moore
10271939740Sherry Moore	/* Save another copy to be used by strtok */
10281939740Sherry Moore	bcopy(bootargs_buf, bootargs_scratch, buflen);
10291939740Sherry Moore	bzero(&bootargs_scratch[buflen], sizeof (bootargs_scratch) - buflen);
10301939740Sherry Moore	head = &bootargs_scratch[0];
10311939740Sherry Moore
10321939740Sherry Moore	/* Get the first argument */
10331939740Sherry Moore	newarg = strtok(bootargs_scratch, " ");
10341939740Sherry Moore
10351939740Sherry Moore	/*
10361939740Sherry Moore	 * If this is a dry run request, verify that the drivers can handle
10371939740Sherry Moore	 * fast reboot.
10381939740Sherry Moore	 */
10391939740Sherry Moore	if (newarg && strncasecmp(newarg, "dryrun", strlen("dryrun")) == 0) {
10401939740Sherry Moore		*is_dryrun = 1;
10411939740Sherry Moore		(void) system("/usr/sbin/devfsadm");
10421939740Sherry Moore	}
10431939740Sherry Moore
10441939740Sherry Moore	/*
10451939740Sherry Moore	 * Always perform a dry run to identify all the drivers that
10461939740Sherry Moore	 * need to implement devo_reset().
10471939740Sherry Moore	 */
10481939740Sherry Moore	if (uadmin(A_SHUTDOWN, AD_FASTREBOOT_DRYRUN,
10491939740Sherry Moore	    (uintptr_t)bootargs_saved) != 0) {
1050753a6d4Sherry Moore		(void) fprintf(stderr, gettext("%s: Not all drivers "
1051753a6d4Sherry Moore		    "have implemented quiesce(9E)\n"
1052753a6d4Sherry Moore		    "\tPlease see /var/adm/messages for drivers that haven't\n"
1053753a6d4Sherry Moore		    "\timplemented quiesce(9E).\n"), cmdname);
10541939740Sherry Moore	} else if (*is_dryrun) {
1055753a6d4Sherry Moore		(void) fprintf(stderr, gettext("%s: All drivers have "
10561939740Sherry Moore		    "implemented quiesce(9E)\n"), cmdname);
10571939740Sherry Moore	}
10581939740Sherry Moore
1059753a6d4Sherry Moore	/* Return if it is a true dry run. */
10601939740Sherry Moore	if (*is_dryrun)
10611939740Sherry Moore		return (rc);
10621939740Sherry Moore
10639abc7a5Toomas Soome#if defined(__x86)
10649abc7a5Toomas Soome	/* Read boot args from Boot Environment */
1065753a6d4Sherry Moore	if ((bootargs_buf[0] == 0 || isdigit(bootargs_buf[0])) &&
1066753a6d4Sherry Moore	    bename == NULL) {
1067753a6d4Sherry Moore		/*
10689abc7a5Toomas Soome		 * If no boot arguments are given, or a BE entry
10699abc7a5Toomas Soome		 * number is provided, process the boot arguments from BE.
1070753a6d4Sherry Moore		 */
1071753a6d4Sherry Moore		int entnum;
1072753a6d4Sherry Moore		if (bootargs_buf[0] == 0)
10739abc7a5Toomas Soome			entnum = BE_ENTRY_DEFAULT;
1074753a6d4Sherry Moore		else {
1075753a6d4Sherry Moore			errno = 0;
1076753a6d4Sherry Moore			entnum = strtoul(bootargs_buf, NULL, 10);
1077753a6d4Sherry Moore			rc = errno;
1078753a6d4Sherry Moore		}
1079753a6d4Sherry Moore
10809abc7a5Toomas Soome		if (rc == 0 && (rc = be_get_boot_args(&fbarg, entnum)) == 0) {
10819abc7a5Toomas Soome			if (strlcpy(bootargs_buf, fbarg,
1082753a6d4Sherry Moore			    buf_size) >= buf_size) {
10839abc7a5Toomas Soome				free(fbarg);
1084753a6d4Sherry Moore				bcopy(bootargs_saved, bootargs_buf, buf_size);
1085753a6d4Sherry Moore				rc = E2BIG;
1086753a6d4Sherry Moore			}
1087753a6d4Sherry Moore		}
10889abc7a5Toomas Soome		/* Failed to read FB args, fall back to normal reboot */
1089753a6d4Sherry Moore		if (rc != 0) {
1090753a6d4Sherry Moore			(void) fprintf(stderr,
10919abc7a5Toomas Soome			    gettext("%s: Failed to process boot "
10929abc7a5Toomas Soome			    "arguments from Boot Environment.\n"), cmdname);
1093753a6d4Sherry Moore			(void) fprintf(stderr,
1094753a6d4Sherry Moore			    gettext("%s: Falling back to regular reboot.\n"),
1095753a6d4Sherry Moore			    cmdname);
1096753a6d4Sherry Moore			return (-1);
1097753a6d4Sherry Moore		}
1098753a6d4Sherry Moore		/* No need to process further */
10999abc7a5Toomas Soome		fbarg_used = fbarg;
1100753a6d4Sherry Moore		fbarg_entnum = entnum;
1101753a6d4Sherry Moore		return (0);
1102753a6d4Sherry Moore	}
11039abc7a5Toomas Soome#endif	/* __x86 */
1104753a6d4Sherry Moore
1105753a6d4Sherry Moore	/* Zero out the boot argument buffer as we will reconstruct it */
1106753a6d4Sherry Moore	bzero(bootargs_buf, buf_size);
1107753a6d4Sherry Moore	bzero(bootfs_arg, sizeof (bootfs_arg));
1108753a6d4Sherry Moore	bzero(unixfile, sizeof (unixfile));
1109753a6d4Sherry Moore
11101939740Sherry Moore	if (bename && (rc = fastboot_bename(bename, mountpoint,
11111939740Sherry Moore	    sizeof (mountpoint))) != 0)
1112753a6d4Sherry Moore		return (EINVAL);
1113753a6d4Sherry Moore
11141939740Sherry Moore
11151939740Sherry Moore	/*
11161939740Sherry Moore	 * If BE is not specified, look for disk argument to construct
11171939740Sherry Moore	 * mountpoint; if BE has been specified, mountpoint has already been
11181939740Sherry Moore	 * constructed.
11191939740Sherry Moore	 */
11201939740Sherry Moore	if (newarg && newarg[0] != '-' && !bename) {
11211939740Sherry Moore		int tmprc;
11221939740Sherry Moore
11231939740Sherry Moore		if ((tmprc = validate_disk(newarg, mountpoint)) == 0) {
11241939740Sherry Moore			/*
11251939740Sherry Moore			 * The first argument is a valid root argument.
11261939740Sherry Moore			 * Get the next argument.
11271939740Sherry Moore			 */
11281939740Sherry Moore			newarg = strtok(NULL, " ");
11291939740Sherry Moore			rootlen = (newarg) ? (newarg - head) : buflen;
11301939740Sherry Moore			(void) strlcpy(fastboot_mounted, mountpoint,
11311939740Sherry Moore			    sizeof (fastboot_mounted));
11321939740Sherry Moore
11331939740Sherry Moore		} else if (tmprc == -1) {
11341939740Sherry Moore			/*
11351939740Sherry Moore			 * Not a disk argument.  Use / as default root.
11361939740Sherry Moore			 */
11371939740Sherry Moore			bcopy("/", mountpoint, 1);
11381939740Sherry Moore			bzero(&mountpoint[1], sizeof (mountpoint) - 1);
11391939740Sherry Moore		} else {
11401939740Sherry Moore			/*
11411939740Sherry Moore			 * Disk argument, but not valid or not root.
11421939740Sherry Moore			 * Return failure.
11431939740Sherry Moore			 */
11441939740Sherry Moore			return (EINVAL);
11451939740Sherry Moore		}
11461939740Sherry Moore	}
11471939740Sherry Moore
11481939740Sherry Moore	/*
11491939740Sherry Moore	 * Make mountpoint the first part of unixfile.
11501939740Sherry Moore	 * If there is not disk argument, and BE has not been specified,
11511939740Sherry Moore	 * mountpoint could be empty.
11521939740Sherry Moore	 */
11531939740Sherry Moore	mplen = strlen(mountpoint);
11541939740Sherry Moore	bcopy(mountpoint, unixfile, mplen);
11551939740Sherry Moore
11561939740Sherry Moore	/*
11571939740Sherry Moore	 * Look for unix argument
11581939740Sherry Moore	 */
11591939740Sherry Moore	if (newarg && newarg[0] != '-') {
11601939740Sherry Moore		bcopy(newarg, &unixfile[mplen], strlen(newarg));
11611939740Sherry Moore		newarg = strtok(NULL, " ");
11621939740Sherry Moore		rootlen = (newarg) ? (newarg - head) : buflen;
11631939740Sherry Moore	} else if (mplen != 0) {
11641939740Sherry Moore		/*
11651939740Sherry Moore		 * No unix argument, but mountpoint is not empty, use
11664e995f2Marcel Telka		 * /platform/i86pc/kernel/$ISADIR/unix as default.
11671939740Sherry Moore		 */
11681939740Sherry Moore		char isa[20];
11691939740Sherry Moore
11701939740Sherry Moore		if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) != -1)
11711939740Sherry Moore			(void) snprintf(&unixfile[mplen],
11721939740Sherry Moore			    sizeof (unixfile) - mplen,
11731939740Sherry Moore			    "/platform/i86pc/kernel/%s/unix", isa);
11741939740Sherry Moore		else if (sysinfo(SI_ARCHITECTURE_32, isa, sizeof (isa)) != -1) {
11751939740Sherry Moore			(void) snprintf(&unixfile[mplen],
11761939740Sherry Moore			    sizeof (unixfile) - mplen,
11771939740Sherry Moore			    "/platform/i86pc/kernel/unix");
11781939740Sherry Moore		} else {
11791939740Sherry Moore			(void) fprintf(stderr,
1180753a6d4Sherry Moore			    gettext("%s: Unknown architecture"), cmdname);
11811939740Sherry Moore			return (EINVAL);
11821939740Sherry Moore		}
11831939740Sherry Moore	}
11841939740Sherry Moore
11851939740Sherry Moore	/*
11861939740Sherry Moore	 * We now have the complete unix argument.  Verify that it exists and
11871939740Sherry Moore	 * is an ELF file.  Split the argument up into mountpoint and unix
11881939740Sherry Moore	 * portions again.  This is necessary to handle cases where mountpoint
11891939740Sherry Moore	 * is specified on the command line as part of the unix argument,
11901939740Sherry Moore	 * such as this:
11911939740Sherry Moore	 *	# reboot -f /.alt/platform/i86pc/kernel/amd64/unix
11921939740Sherry Moore	 */
11931939740Sherry Moore	unixlen = strlen(unixfile);
11941939740Sherry Moore	if (unixlen > 0) {
11951939740Sherry Moore		if (validate_unix(unixfile, &mplen, &is_zfs,
11965b89e3fSherry Moore		    bootfs_arg) != 0) {
11971939740Sherry Moore			/* Not a valid unix file */
11981939740Sherry Moore			return (EINVAL);
11991939740Sherry Moore		} else {
12006bc8bc6Sherry Moore			int space = 0;
12011939740Sherry Moore			/*
12021939740Sherry Moore			 * Construct boot argument.
12031939740Sherry Moore			 */
12041939740Sherry Moore			unixlen = strlen(unixfile);
12056bc8bc6Sherry Moore
12066bc8bc6Sherry Moore			/*
12076bc8bc6Sherry Moore			 * mdep cannot start with space because bootadm
12086bc8bc6Sherry Moore			 * creates bogus menu entries if it does.
12096bc8bc6Sherry Moore			 */
12106bc8bc6Sherry Moore			if (mplen > 0) {
12116bc8bc6Sherry Moore				bcopy(unixfile, bootargs_buf, mplen);
12126bc8bc6Sherry Moore				(void) strcat(bootargs_buf, " ");
12136bc8bc6Sherry Moore				space = 1;
12146bc8bc6Sherry Moore			}
12156bc8bc6Sherry Moore			bcopy(&unixfile[mplen], &bootargs_buf[mplen + space],
12161939740Sherry Moore			    unixlen - mplen);
12171939740Sherry Moore			(void) strcat(bootargs_buf, " ");
12186bc8bc6Sherry Moore			off += unixlen + space + 1;
12191939740Sherry Moore		}
12201939740Sherry Moore	} else {
12211939740Sherry Moore		/* Check to see if root is zfs */
12221939740Sherry Moore		const char	*dp;
12231939740Sherry Moore		(void) get_zfs_bootfs_arg("/", &dp, &is_zfs, bootfs_arg);
12241939740Sherry Moore	}
12251939740Sherry Moore
12261939740Sherry Moore	if (is_zfs && (buflen != 0 || bename != NULL))	{
12279e573dcToomas Soome		/* do not copy existing zfs boot args */
12289e573dcToomas Soome		if (strstr(&bootargs_saved[rootlen], "-B") == NULL ||
12299e573dcToomas Soome		    strstr(&bootargs_saved[rootlen], "zfs-bootfs=") == NULL ||
12309e573dcToomas Soome		    (strstr(&bootargs_saved[rootlen], "bootpath=") == NULL &&
12319e573dcToomas Soome		    strstr(&bootargs_saved[rootlen], "diskdevid=") == NULL))
12329e573dcToomas Soome			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
12339e573dcToomas Soome			off += sprintf(bootargs_buf + off, "%s ", bootfs_arg);
12341939740Sherry Moore	}
12351939740Sherry Moore
12361939740Sherry Moore	/*
12371939740Sherry Moore	 * Copy the rest of the arguments
12381939740Sherry Moore	 */
12391939740Sherry Moore	bcopy(&bootargs_saved[rootlen], &bootargs_buf[off], buflen - rootlen);
12401939740Sherry Moore
12411939740Sherry Moore	return (rc);
12421939740Sherry Moore}
12431939740Sherry Moore
1244de0cf91Enrico Perla - Sun Microsystems#define	MAXARGS		5
1245de0cf91Enrico Perla - Sun Microsystems
1246de0cf91Enrico Perla - Sun Microsystemsstatic void
1247de0cf91Enrico Perla - Sun Microsystemsdo_archives_update(int do_fast_reboot)
1248de0cf91Enrico Perla - Sun Microsystems{
1249de0cf91Enrico Perla - Sun Microsystems	int	r, i = 0;
1250de0cf91Enrico Perla - Sun Microsystems	pid_t	pid;
1251de0cf91Enrico Perla - Sun Microsystems	char	*cmd_argv[MAXARGS];
1252de0cf91Enrico Perla - Sun Microsystems
1253de0cf91Enrico Perla - Sun Microsystems
1254de0cf91Enrico Perla - Sun Microsystems	cmd_argv[i++] = "/sbin/bootadm";
1255de0cf91Enrico Perla - Sun Microsystems	cmd_argv[i++] = "-ea";
1256de0cf91Enrico Perla - Sun Microsystems	cmd_argv[i++] = "update_all";
1257de0cf91Enrico Perla - Sun Microsystems	if (do_fast_reboot)
1258de0cf91Enrico Perla - Sun Microsystems		cmd_argv[i++] = "fastboot";
1259de0cf91Enrico Perla - Sun Microsystems	cmd_argv[i] = NULL;
1260de0cf91Enrico Perla - Sun Microsystems
1261de0cf91Enrico Perla - Sun Microsystems	r = posix_spawn(&pid, cmd_argv[0], NULL, NULL, cmd_argv, NULL);
1262de0cf91Enrico Perla - Sun Microsystems
1263de0cf91Enrico Perla - Sun Microsystems	/* if posix_spawn fails we emit a warning and continue */
1264de0cf91Enrico Perla - Sun Microsystems
1265de0cf91Enrico Perla - Sun Microsystems	if (r != 0)
1266de0cf91Enrico Perla - Sun Microsystems		(void) fprintf(stderr, gettext("%s: WARNING, unable to start "
1267de0cf91Enrico Perla - Sun Microsystems		    "boot archive update\n"), cmdname);
1268de0cf91Enrico Perla - Sun Microsystems	else
1269de0cf91Enrico Perla - Sun Microsystems		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
1270de0cf91Enrico Perla - Sun Microsystems			;
1271de0cf91Enrico Perla - Sun Microsystems}
1272de0cf91Enrico Perla - Sun Microsystems
12737c478bdstevel@tonic-gateint
12747c478bdstevel@tonic-gatemain(int argc, char *argv[])
12757c478bdstevel@tonic-gate{
12767c478bdstevel@tonic-gate	int qflag = 0, needlog = 1, nosync = 0;
12771939740Sherry Moore	int fast_reboot = 0;
1278753a6d4Sherry Moore	int prom_reboot = 0;
12791940b2aToomas Soome	uintptr_t mdep = 0;
12807c478bdstevel@tonic-gate	int cmd, fcn, c, aval, r;
12817c478bdstevel@tonic-gate	const char *usage;
12828e07a41Konstantin Ananyev	const char *optstring;
12837c478bdstevel@tonic-gate	zoneid_t zoneid = getzoneid();
12843f2f09cdp	int need_check_zones = 0;
12853f2f09cdp	char bootargs_buf[BOOTARGS_MAX];
12863b860eeSherry Moore	char *bootargs_orig = NULL;
12871939740Sherry Moore	char *bename = NULL;
12887c478bdstevel@tonic-gate
12897c478bdstevel@tonic-gate	const char * const resetting = "/etc/svc/volatile/resetting";
12907c478bdstevel@tonic-gate
12917c478bdstevel@tonic-gate	(void) setlocale(LC_ALL, "");
12927c478bdstevel@tonic-gate	(void) textdomain(TEXT_DOMAIN);
12937c478bdstevel@tonic-gate
12943f2f09cdp	cmdname = basename(argv[0]);
12953f2f09cdp
12967c478bdstevel@tonic-gate	if (strcmp(cmdname, "halt") == 0) {
12977c478bdstevel@tonic-gate		(void) audit_halt_setup(argc, argv);
12988e07a41Konstantin Ananyev		optstring = "dlnqy";
12997c478bdstevel@tonic-gate		usage = gettext("usage: %s [ -dlnqy ]\n");
13007c478bdstevel@tonic-gate		cmd = A_SHUTDOWN;
13017c478bdstevel@tonic-gate		fcn = AD_HALT;
13027c478bdstevel@tonic-gate	} else if (strcmp(cmdname, "poweroff") == 0) {
13037c478bdstevel@tonic-gate		(void) audit_halt_setup(argc, argv);
13048e07a41Konstantin Ananyev		optstring = "dlnqy";
13057c478bdstevel@tonic