PSARC/2006/269 Zone Boot Arguments II
authordp
Thu, 22 Jun 2006 14:42:46 -0700
changeset 2267 c5d9a656170f
parent 2266 0f434036255b
child 2268 27e71a31e355
PSARC/2006/269 Zone Boot Arguments II 4943812 init improperly respawning stuff during reboot 4994285 RFE: zones should support boot arguments 6315349 halt.c contains an uninitialized variable 6395642 missing global zone checks for menu updates in uadmin(2) 6415633 krtld calls printf(), goes boom 6421372 libc's lintlib doesn't include <sys/uadmin.h> 6433526 zoneadm should use statvfs64
usr/src/cmd/fmthard/fmthard.c
usr/src/cmd/halt/halt.c
usr/src/cmd/truss/print.c
usr/src/cmd/truss/systable.c
usr/src/cmd/zoneadm/zfs.c
usr/src/cmd/zoneadm/zoneadm.c
usr/src/cmd/zoneadmd/vplat.c
usr/src/cmd/zoneadmd/zcons.c
usr/src/cmd/zoneadmd/zoneadmd.c
usr/src/cmd/zoneadmd/zoneadmd.h
usr/src/cmd/zonecfg/zonecfg.c
usr/src/cmd/zonecfg/zonecfg.h
usr/src/cmd/zonecfg/zonecfg_grammar.y
usr/src/cmd/zonecfg/zonecfg_lex.l
usr/src/head/libzonecfg.h
usr/src/head/zone.h
usr/src/lib/libc/amd64/sys/uadmin.c
usr/src/lib/libc/i386/sys/uadmin.c
usr/src/lib/libc/port/llib-lc
usr/src/lib/libc/port/sys/zone.c
usr/src/lib/libc/spec/sys.spec
usr/src/lib/libzonecfg/common/libzonecfg.c
usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
usr/src/lib/libzonecfg/spec/libzonecfg.spec
usr/src/psm/stand/boot/i386/common/multiboot.c
usr/src/uts/common/krtld/kobj_bootflags.c
usr/src/uts/common/krtld/kobj_subr.c
usr/src/uts/common/os/exit.c
usr/src/uts/common/os/main.c
usr/src/uts/common/os/zone.c
usr/src/uts/common/sys/systm.h
usr/src/uts/common/sys/uadmin.h
usr/src/uts/common/sys/zone.h
usr/src/uts/common/syscall/corectl.c
usr/src/uts/common/syscall/uadmin.c
usr/src/uts/intel/krtld/Makefile
usr/src/uts/sparc/krtld/Makefile
--- a/usr/src/cmd/fmthard/fmthard.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/fmthard/fmthard.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -32,7 +31,7 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -360,14 +359,13 @@
 	 * This is used during installation of core floppies.
 	 */
 	if (uflag == 1)
-		uadmin(A_REBOOT, AD_BOOT, 0);
+		(void) uadmin(A_REBOOT, AD_BOOT, 0);
 	else if (uflag == 2)
-		uadmin(A_REBOOT, AD_IBOOT, 0);
+		(void) uadmin(A_REBOOT, AD_IBOOT, 0);
 
 	(void) printf("fmthard:  New volume table of contents now in place.\n");
 
 	return (0);
-	/*NOTREACHED*/
 }
 
 
--- a/usr/src/cmd/halt/halt.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/halt/halt.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,7 +43,7 @@
  * argv[0] to determine which behavior to exhibit.
  */
 
-#include <sys/stat.h>
+#include <procfs.h>
 #include <sys/types.h>
 #include <sys/uadmin.h>
 #include <alloca.h>
@@ -78,6 +77,8 @@
 extern int audit_reboot_success(void);
 extern int audit_reboot_fail(void);
 
+static char *cmdname;	/* basename(argv[0]), the name of the command */
+
 typedef struct ctidlist_struct {
 	ctid_t ctid;
 	struct ctidlist_struct *next;
@@ -91,61 +92,91 @@
 
 #define	ZONEADM_PROG "/usr/sbin/zoneadm"
 
+static pid_t
+get_initpid()
+{
+	static int init_pid = -1;
+
+	if (init_pid == -1) {
+		if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
+		    sizeof (init_pid)) != sizeof (init_pid)) {
+			assert(errno == ESRCH);
+			init_pid = -1;
+		}
+	}
+	return (init_pid);
+}
+
+/*
+ * Quiesce or resume init using /proc.  When stopping init, we can't send
+ * SIGTSTP (since init ignores it) or SIGSTOP (since the kernel won't permit
+ * it).
+ */
+static int
+direct_init(long command)
+{
+	char ctlfile[MAXPATHLEN];
+	pid_t pid;
+	int ctlfd;
+
+	assert(command == PCDSTOP || command == PCRUN);
+	if ((pid = get_initpid()) == -1) {
+		return (-1);
+	}
+
+	(void) snprintf(ctlfile, sizeof (ctlfile), "/proc/%d/ctl", pid);
+	if ((ctlfd = open(ctlfile, O_WRONLY)) == -1)
+		return (-1);
+
+	if (command == PCDSTOP) {
+		if (write(ctlfd, &command, sizeof (long)) == -1) {
+			(void) close(ctlfd);
+			return (-1);
+		}
+	} else {	/* command == PCRUN */
+		long cmds[2];
+		cmds[0] = command;
+		cmds[1] = 0;
+		if (write(ctlfd, cmds, sizeof (cmds)) == -1) {
+			(void) close(ctlfd);
+			return (-1);
+		}
+	}
+	(void) close(ctlfd);
+	return (0);
+}
+
 static void
 stop_startd()
 {
-	ctid_t ctid;
-
 	scf_handle_t *h;
 	scf_property_t *prop = NULL;
 	scf_value_t *val = NULL;
 	uint64_t uint64;
-	int ret;
 
-	h = scf_handle_create(SCF_VERSION);
-	if (h == NULL)
+	if ((h = scf_handle_create(SCF_VERSION)) == NULL)
 		return;
 
-	ret = scf_handle_bind(h);
-	if (ret) {
-		scf_handle_destroy(h);
-		return;
-	}
-
-	prop = scf_property_create(h);
-	val = scf_value_create(h);
-
-	if (!(prop && val))
-		goto out;
-
-	ret = scf_handle_decode_fmri(h, FMRI_STARTD_CONTRACT,
-	    NULL, NULL, NULL, NULL, prop, SCF_DECODE_FMRI_EXACT);
-	if (ret)
+	if ((scf_handle_bind(h) != 0) ||
+	    ((prop = scf_property_create(h)) == NULL) ||
+	    ((val = scf_value_create(h)) == NULL))
 		goto out;
 
-	ret = scf_property_is_type(prop, SCF_TYPE_COUNT);
-	if (ret)
-		goto out;
-
-	ret = scf_property_get_value(prop, val);
-	if (ret)
-		goto out;
-
-	ret = scf_value_get_count(val, &uint64);
-	if (ret)
+	if (scf_handle_decode_fmri(h, FMRI_STARTD_CONTRACT,
+	    NULL, NULL, NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
 		goto out;
 
-	ctid = (ctid_t)uint64;
-	startdct = ctid;
-	(void) sigsend(P_CTID, ctid, SIGSTOP);
+	if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
+	    scf_property_get_value(prop, val) != 0 ||
+	    scf_value_get_count(val, &uint64) != 0)
+		goto out;
+
+	startdct = (ctid_t)uint64;
+	(void) sigsend(P_CTID, startdct, SIGSTOP);
 
 out:
-	if (prop)
-		scf_property_destroy(prop);
-	if (val)
-		scf_value_destroy(val);
-
-	(void) scf_handle_unbind(h);
+	scf_property_destroy(prop);
+	scf_value_destroy(val);
 	scf_handle_destroy(h);
 }
 
@@ -198,7 +229,6 @@
 
 	uint64_t uint64;
 	ssize_t bytes;
-	int ret;
 
 	length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
 	if (length <= 0)
@@ -207,67 +237,51 @@
 	length++;
 	fmri = alloca(length * sizeof (char));
 
-	h = scf_handle_create(SCF_VERSION);
-	if (!h)
+	if ((h = scf_handle_create(SCF_VERSION)) == NULL)
 		return;
 
-	ret = scf_handle_bind(h);
-	if (ret) {
+	if (scf_handle_bind(h) != 0) {
 		scf_handle_destroy(h);
 		return;
 	}
 
-	sc = scf_scope_create(h);
-	svc = scf_service_create(h);
-	inst = scf_instance_create(h);
-	snap = scf_snapshot_create(h);
-	pg = scf_pg_create(h);
-	prop = scf_property_create(h);
-	val = scf_value_create(h);
-	siter = scf_iter_create(h);
-	iiter = scf_iter_create(h);
-
-	if (!(sc && svc && inst && snap &&
-	    pg && prop && val && siter && iiter))
+	if ((sc = scf_scope_create(h)) == NULL ||
+	    (svc = scf_service_create(h)) == NULL ||
+	    (inst = scf_instance_create(h)) == NULL ||
+	    (snap = scf_snapshot_create(h)) == NULL ||
+	    (pg = scf_pg_create(h)) == NULL ||
+	    (prop = scf_property_create(h)) == NULL ||
+	    (val = scf_value_create(h)) == NULL ||
+	    (siter = scf_iter_create(h)) == NULL ||
+	    (iiter = scf_iter_create(h)) == NULL)
 		goto out;
 
-	ret = scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc);
-	if (ret)
+	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) != 0)
 		goto out;
 
-	ret = scf_iter_scope_services(siter, sc);
-	if (ret)
+	if (scf_iter_scope_services(siter, sc) != 0)
 		goto out;
 
 	while (scf_iter_next_service(siter, svc) == 1) {
 
-		ret = scf_iter_service_instances(iiter, svc);
-		if (ret)
+		if (scf_iter_service_instances(iiter, svc) != 0)
 			continue;
 
 		while (scf_iter_next_instance(iiter, inst) == 1) {
 
-			ret = scf_instance_get_snapshot(inst, "running", snap);
-				if (ret)
-					isnap = NULL;
-				else
-					isnap = snap;
+			if ((scf_instance_get_snapshot(inst, "running",
+			    snap)) != 0)
+				isnap = NULL;
+			else
+				isnap = snap;
 
-			ret = scf_instance_get_pg_composed(inst, isnap,
-			    SCF_PG_GENERAL, pg);
-			if (ret)
+			if (scf_instance_get_pg_composed(inst, isnap,
+			    SCF_PG_GENERAL, pg) != 0)
 				continue;
 
-			ret = scf_pg_get_property(pg, "restarter", prop);
-			if (ret)
-				continue;
-
-			ret = scf_property_is_type(prop, SCF_TYPE_ASTRING);
-			if (ret)
-				continue;
-
-			ret = scf_property_get_value(prop, val);
-			if (ret)
+			if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER,
+			    prop) != 0 ||
+			    scf_property_get_value(prop, val) != 0)
 				continue;
 
 			bytes = scf_value_get_astring(val, fmri, length);
@@ -278,21 +292,13 @@
 			    length)
 				continue;
 
-			ret = scf_handle_decode_fmri(h, fmri, NULL, NULL,
-			    NULL, NULL, prop, SCF_DECODE_FMRI_EXACT);
-			if (ret)
+			if (scf_handle_decode_fmri(h, fmri, NULL, NULL,
+			    NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
 				continue;
 
-			ret = scf_property_is_type(prop, SCF_TYPE_COUNT);
-			if (ret)
-				continue;
-
-			ret = scf_property_get_value(prop, val);
-			if (ret)
-				continue;
-
-			ret = scf_value_get_count(val, &uint64);
-			if (ret)
+			if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
+			    scf_property_get_value(prop, val) != 0 ||
+			    scf_value_get_count(val, &uint64) != 0)
 				continue;
 
 			ctid = (ctid_t)uint64;
@@ -302,24 +308,15 @@
 		}
 	}
 out:
-	if (sc)
-		scf_scope_destroy(sc);
-	if (svc)
-		scf_service_destroy(svc);
-	if (inst)
-		scf_instance_destroy(inst);
-	if (snap)
-		scf_snapshot_destroy(snap);
-	if (pg)
-		scf_pg_destroy(pg);
-	if (prop)
-		scf_property_destroy(prop);
-	if (val)
-		scf_value_destroy(val);
-	if (siter)
-		scf_iter_destroy(siter);
-	if (iiter)
-		scf_iter_destroy(iiter);
+	scf_scope_destroy(sc);
+	scf_service_destroy(svc);
+	scf_instance_destroy(inst);
+	scf_snapshot_destroy(snap);
+	scf_pg_destroy(pg);
+	scf_property_destroy(prop);
+	scf_value_destroy(val);
+	scf_iter_destroy(siter);
+	scf_iter_destroy(iiter);
 
 	(void) scf_handle_unbind(h);
 	scf_handle_destroy(h);
@@ -374,11 +371,11 @@
  * halt later on.
  */
 static int
-halt_zones(const char *name)
+halt_zones()
 {
 	pid_t pid;
 	zoneid_t *zones;
-	size_t nz, old_nz;
+	size_t nz = 0, old_nz;
 	int i;
 	char zname[ZONENAME_MAX];
 
@@ -396,7 +393,7 @@
 		if (zones == NULL) {
 			(void) fprintf(stderr,
 			    gettext("%s: Could not halt zones"
-			    " (out of memory).\n"), name);
+			    " (out of memory).\n"), cmdname);
 			return (0);
 		}
 
@@ -407,13 +404,11 @@
 	}
 
 	if (nz == 2) {
-		(void) fprintf(stderr,
-		    gettext("%s: Halting 1 zone.\n"),
-		    name);
+		(void) fprintf(stderr, gettext("%s: Halting 1 zone.\n"),
+		    cmdname);
 	} else {
-		(void) fprintf(stderr,
-		    gettext("%s: Halting %i zones.\n"),
-		    name, nz - 1);
+		(void) fprintf(stderr, gettext("%s: Halting %i zones.\n"),
+		    cmdname, nz - 1);
 	}
 
 	for (i = 0; i < nz; i++) {
@@ -429,7 +424,7 @@
 				(void) fprintf(stderr,
 				    gettext("%s: Unexpected error while "
 				    "looking up zone %ul: %s.\n"),
-				    name, zones[i], strerror(errno));
+				    cmdname, zones[i], strerror(errno));
 			}
 
 			continue;
@@ -439,7 +434,7 @@
 			(void) fprintf(stderr,
 			    gettext("%s: Zone \"%s\" could not be"
 			    " halted (could not fork(): %s).\n"),
-			    name, zname, strerror(errno));
+			    cmdname, zname, strerror(errno));
 			continue;
 		}
 		if (pid == 0) {
@@ -448,7 +443,7 @@
 			(void) fprintf(stderr,
 			    gettext("%s: Zone \"%s\" could not be halted"
 			    " (cannot exec(" ZONEADM_PROG "): %s).\n"),
-			    name, zname, strerror(errno));
+			    cmdname, zname, strerror(errno));
 			exit(0);
 		}
 	}
@@ -463,7 +458,7 @@
  */
 
 static void
-check_zones_haltedness(const char *name)
+check_zones_haltedness()
 {
 	int t = 0, t_prog = 0;
 	size_t nz = 0, last_nz;
@@ -487,12 +482,12 @@
 				(void) fprintf(stderr,
 				    gettext("%s: Still waiting for 1 zone to "
 				    "halt. Will wait up to 20 seconds.\n"),
-				    name);
+				    cmdname);
 			} else {
 				(void) fprintf(stderr,
 				    gettext("%s: Still waiting for %i zones "
 				    "to halt. Will wait up to 20 seconds.\n"),
-				    name, nz - 1);
+				    cmdname, nz - 1);
 			}
 		}
 
@@ -502,7 +497,6 @@
 int
 main(int argc, char *argv[])
 {
-	char *cmdname = basename(argv[0]);
 	char *ttyn = ttyname(STDERR_FILENO);
 
 	int qflag = 0, needlog = 1, nosync = 0;
@@ -510,17 +504,17 @@
 	int cmd, fcn, c, aval, r;
 	const char *usage;
 	zoneid_t zoneid = getzoneid();
-	pid_t init_pid = 1;
-	int need_check_zones;
+	int need_check_zones = 0;
 
-	char bootargs_buf[257];		/* uadmin()'s buffer is 257 bytes. */
+	char bootargs_buf[BOOTARGS_MAX];
 
 	const char * const resetting = "/etc/svc/volatile/resetting";
 
-
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
+	cmdname = basename(argv[0]);
+
 	if (strcmp(cmdname, "halt") == 0) {
 		(void) audit_halt_setup(argc, argv);
 		usage = gettext("usage: %s [ -dlnqy ]\n");
@@ -650,24 +644,18 @@
 
 	(void) signal(SIGHUP, SIG_IGN);	/* for remote connections */
 
-	if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
-	    sizeof (init_pid)) != sizeof (init_pid)) {
-		assert(errno == ESRCH);
-		init_pid = -1;
-	}
-
 	/*
 	 * We start to fork a bunch of zoneadms to halt any active zones.
 	 * This will proceed with halt in parallel until we call
 	 * check_zone_haltedness later on.
 	 */
 	if (zoneid == GLOBAL_ZONEID && cmd != A_DUMP) {
-		need_check_zones = halt_zones(cmdname);
+		need_check_zones = halt_zones();
 	}
 
 
 	/* sync boot archive in the global zone */
-	if (getzoneid() == GLOBAL_ZONEID && !nosync) {
+	if (zoneid == GLOBAL_ZONEID && !nosync) {
 		(void) system("/sbin/bootadm -a update_all");
 	}
 
@@ -676,14 +664,13 @@
 	 * smf(5)'s benefit, and idle the init process.
 	 */
 	if (cmd != A_DUMP) {
-		if (init_pid != -1 && kill(init_pid, SIGTSTP) == -1) {
+		if (direct_init(PCDSTOP) == -1) {
 			/*
 			 * TRANSLATION_NOTE
 			 * Don't translate the word "init"
 			 */
 			(void) fprintf(stderr,
 			    gettext("%s: can't idle init\n"), cmdname);
-
 			goto fail;
 		}
 
@@ -702,7 +689,7 @@
 		 * Wait a little while for zones to shutdown.
 		 */
 		if (need_check_zones) {
-			check_zones_haltedness(cmdname);
+			check_zones_haltedness();
 
 			(void) fprintf(stderr,
 			    gettext("%s: Completing system halt.\n"),
@@ -747,20 +734,35 @@
 	if (cmd == A_DUMP && nosync != 0)
 		(void) uadmin(A_DUMP, AD_NOSYNC, NULL);
 
-	(void) uadmin(cmd, fcn, mdep);
-	perror(cmdname);
-	do
+	if (uadmin(cmd, fcn, mdep) == -1)
+		(void) fprintf(stderr, "%s: uadmin failed: %s\n",
+		    cmdname, strerror(errno));
+	else
+		(void) fprintf(stderr, "%s: uadmin unexpectedly returned 0\n",
+		    cmdname);
+
+	do {
 		r = remove(resetting);
-	while (r != 0 && errno == EINTR);
+	} while (r != 0 && errno == EINTR);
+
 	if (r != 0 && errno != ENOENT)
 		(void) fprintf(stderr, gettext("%s: could not remove %s.\n"),
 		    cmdname, resetting);
 
+	if (direct_init(PCRUN) == -1) {
+		/*
+		 * TRANSLATION_NOTE
+		 * Don't translate the word "init"
+		 */
+		(void) fprintf(stderr,
+		    gettext("%s: can't resume init\n"), cmdname);
+	}
+
 	continue_restarters();
 
-	if (init_pid != -1)
+	if (get_initpid() != -1)
 		/* tell init to restate current level */
-		(void) kill(init_pid, SIGHUP);
+		(void) kill(get_initpid(), SIGHUP);
 
 fail:
 	if (fcn == AD_BOOT)
--- a/usr/src/cmd/truss/print.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/truss/print.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2312,6 +2312,8 @@
 		case ZONE_ATTR_POOLID:	s = "ZONE_ATTR_POOLID"; break;
 		case ZONE_ATTR_INITPID:	s = "ZONE_ATTR_INITPID"; break;
 		case ZONE_ATTR_SLBL:	s = "ZONE_ATTR_SLBL"; break;
+		case ZONE_ATTR_INITNAME:	s = "ZONE_ATTR_INITNAME"; break;
+		case ZONE_ATTR_BOOTARGS:	s = "ZONE_ATTR_BOOTARGS"; break;
 		}
 	}
 
--- a/usr/src/cmd/truss/systable.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/truss/systable.c	Thu Jun 22 14:42:46 2006 -0700
@@ -788,8 +788,9 @@
 {"zone_list",	3, DEC, NOV, HID, HEX, HEX},			/* 4 */
 {"zone_shutdown", 2, DEC, NOV, HID, DEC},			/* 5 */
 {"zone_lookup", 2, DEC, NOV, HID, STG},				/* 6 */
-{"zone_boot", 3, DEC, NOV, HID, DEC, STG},			/* 7 */
+{"zone_boot", 2, DEC, NOV, HID, DEC},				/* 7 */
 {"zone_version", 2, HEX, NOV, HID, DEC},			/* 8 */
+{"zone_setattr", 5, DEC, NOV, HID, DEC, ZGA, HEX, DEC},		/* 9 */
 };
 #define	NZONECODE	(sizeof (zonetable) / sizeof (struct systable))
 
@@ -1208,9 +1209,8 @@
 			break;
 		case SYS_lwp_create:	/* lwp_create() */
 			subcode =	/* 0 for parent, 1 for child */
-				(Lsp->pr_why == PR_SYSEXIT &&
-				    Lsp->pr_errno == 0 &&
-				    Lsp->pr_rval1 == 0);
+			    (Lsp->pr_why == PR_SYSEXIT && Lsp->pr_errno == 0 &&
+			    Lsp->pr_rval1 == 0);
 			break;
 		case SYS_msgsys:	/* msgsys() */
 		case SYS_semsys:	/* semsys() */
@@ -1263,37 +1263,37 @@
 maxsyscalls()
 {
 	return (PRMAXSYS + 1
-		+ NOPENCODE - 1
-		+ NOPEN64CODE - 1
-		+ NSIGCODE - 1
-		+ NMSGCODE - 1
-		+ NSEMCODE - 1
-		+ NSHMCODE - 1
-		+ NPIDCODE - 1
-		+ NSFSCODE - 1
-		+ NUTSCODE - 1
-		+ NSGPCODE - 1
-		+ NCTXCODE - 1
-		+ NHRTCODE - 1
-		+ NCORCODE - 1
-		+ NAIOCODE - 1
-		+ NDOORCODE - 1
-		+ NPSETCODE - 1
-		+ NLWPCREATECODE - 1
-		+ NTASKSYSCODE - 1
-		+ NEXACCTSYSCODE - 1
-		+ NFSATSYSCODE - 1
-		+ NLWPPARKCODE - 1
-		+ NLWPRWLOCKCODE - 1
-		+ NSENDFILESYSCODE - 1
-		+ NLGRPSYSCODE - 1
-		+ NRUSAGESYSCODE - 1
-		+ NFCNTLCODE - 1
-		+ NPRIVSYSCODE - 1
-		+ NUCREDSYSCODE - 1
-		+ NPORTCODE - 1
-		+ NZONECODE - 1
-		+ NLABELCODE - 1);
+	    + NOPENCODE - 1
+	    + NOPEN64CODE - 1
+	    + NSIGCODE - 1
+	    + NMSGCODE - 1
+	    + NSEMCODE - 1
+	    + NSHMCODE - 1
+	    + NPIDCODE - 1
+	    + NSFSCODE - 1
+	    + NUTSCODE - 1
+	    + NSGPCODE - 1
+	    + NCTXCODE - 1
+	    + NHRTCODE - 1
+	    + NCORCODE - 1
+	    + NAIOCODE - 1
+	    + NDOORCODE - 1
+	    + NPSETCODE - 1
+	    + NLWPCREATECODE - 1
+	    + NTASKSYSCODE - 1
+	    + NEXACCTSYSCODE - 1
+	    + NFSATSYSCODE - 1
+	    + NLWPPARKCODE - 1
+	    + NLWPRWLOCKCODE - 1
+	    + NSENDFILESYSCODE - 1
+	    + NLGRPSYSCODE - 1
+	    + NRUSAGESYSCODE - 1
+	    + NFCNTLCODE - 1
+	    + NPRIVSYSCODE - 1
+	    + NUCREDSYSCODE - 1
+	    + NPORTCODE - 1
+	    + NZONECODE - 1
+	    + NLABELCODE - 1);
 }
 
 /*
--- a/usr/src/cmd/zoneadm/zfs.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadm/zfs.c	Thu Jun 22 14:42:46 2006 -0700
@@ -811,9 +811,9 @@
 	int res;
 	char *path;
 	char *parent;
-	struct statvfs buf1, buf2;
+	struct statvfs64 buf1, buf2;
 
-	if (statvfs(zonepath, &buf1) != 0)
+	if (statvfs64(zonepath, &buf1) != 0)
 		return (B_FALSE);
 
 	if (strcmp(buf1.f_basetype, "zfs") != 0)
@@ -823,7 +823,7 @@
 		return (B_FALSE);
 
 	parent = dirname(path);
-	res = statvfs(parent, &buf2);
+	res = statvfs64(parent, &buf2);
 	free(path);
 
 	if (res != 0)
--- a/usr/src/cmd/zoneadm/zoneadm.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadm/zoneadm.c	Thu Jun 22 14:42:46 2006 -0700
@@ -112,10 +112,10 @@
 };
 
 #define	SHELP_HELP	"help"
-#define	SHELP_BOOT	"boot [-s]"
+#define	SHELP_BOOT	"boot [-- boot_arguments]"
 #define	SHELP_HALT	"halt"
 #define	SHELP_READY	"ready"
-#define	SHELP_REBOOT	"reboot"
+#define	SHELP_REBOOT	"reboot [-- boot_arguments]"
 #define	SHELP_LIST	"list [-cipv]"
 #define	SHELP_VERIFY	"verify"
 #define	SHELP_INSTALL	"install [-x nodataset]"
@@ -191,9 +191,8 @@
 	case CMD_HELP:
 		return (gettext("Print usage message."));
 	case CMD_BOOT:
-		return (gettext("Activates (boots) specified zone.  "
-		    "The -s flag can be used\n\tto boot the zone in "
-		    "the single-user state."));
+		return (gettext("Activates (boots) specified zone.  See "
+		    "zoneadm(1m) for valid boot\n\targuments."));
 	case CMD_HALT:
 		return (gettext("Halts specified zone, bypassing shutdown "
 		    "scripts and removing runtime\n\tresources of the zone."));
@@ -202,7 +201,8 @@
 		    "does not start any user\n\tprocesses in the zone."));
 	case CMD_REBOOT:
 		return (gettext("Restarts the zone (equivalent to a halt / "
-		    "boot sequence).\n\tFails if the zone is not active."));
+		    "boot sequence).\n\tFails if the zone is not active.  "
+		    "See zoneadm(1m) for valid boot\n\targuments."));
 	case CMD_LIST:
 		return (gettext("Lists the current zones, or a "
 		    "specific zone if indicated.  By default,\n\tall "
@@ -772,7 +772,7 @@
 	int res;			/* result of last library/system call */
 	boolean_t err = B_FALSE;	/* have we run into an error? */
 	struct stat stbuf;
-	struct statvfs vfsbuf;
+	struct statvfs64 vfsbuf;
 	char rpath[MAXPATHLEN];		/* resolved path */
 	char ppath[MAXPATHLEN];		/* parent path */
 	char rppath[MAXPATHLEN];	/* resolved parent path */
@@ -904,7 +904,7 @@
 		err = B_TRUE;
 	}
 
-	if (statvfs(rpath, &vfsbuf) != 0) {
+	if (statvfs64(rpath, &vfsbuf) != 0) {
 		zperror(rpath, B_FALSE);
 		return (Z_ERR);
 	}
@@ -1315,10 +1315,18 @@
 	zarg.bootbuf[0] = '\0';
 
 	/*
-	 * At the current time, the only supported subargument to the
-	 * "boot" subcommand is "-s" which specifies a single-user boot.
-	 * In the future, other boot arguments should be supported
-	 * including "-m" for specifying alternate smf(5) milestones.
+	 * The following getopt processes arguments to zone boot; that
+	 * is to say, the [here] portion of the argument string:
+	 *
+	 *	zoneadm -z myzone boot [here] -- -v -m verbose
+	 *
+	 * Where [here] can either be nothing, -? (in which case we bail
+	 * and print usage), or -s.  Support for -s is vestigal and
+	 * obsolete, but is retained because it was a documented interface
+	 * and there are known consumers including admin/install; the
+	 * proper way to specify boot arguments like -s is:
+	 *
+	 *	zoneadm -z myzone boot -- -s -v -m verbose.
 	 */
 	optind = 0;
 	if ((arg = getopt(argc, argv, "?s")) != EOF) {
@@ -1335,10 +1343,21 @@
 			return (Z_USAGE);
 		}
 	}
-	if (argc > optind) {
-		sub_usage(SHELP_BOOT, CMD_BOOT);
-		return (Z_USAGE);
-	}
+
+	for (; optind < argc; optind++) {
+		if (strlcat(zarg.bootbuf, argv[optind],
+		    sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
+			zerror(gettext("Boot argument list too long"));
+			return (Z_ERR);
+		}
+		if (optind < argc - 1)
+			if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
+			    sizeof (zarg.bootbuf)) {
+				zerror(gettext("Boot argument list too long"));
+				return (Z_ERR);
+			}
+	}
+
 	if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE) != Z_OK)
 		return (Z_ERR);
 	if (verify_details(CMD_BOOT) != Z_OK)
@@ -1789,10 +1808,23 @@
 			return (Z_USAGE);
 		}
 	}
-	if (argc > 0) {
-		sub_usage(SHELP_REBOOT, CMD_REBOOT);
-		return (Z_USAGE);
-	}
+
+	zarg.bootbuf[0] = '\0';
+	for (; optind < argc; optind++) {
+		if (strlcat(zarg.bootbuf, argv[optind],
+		    sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
+			zerror(gettext("Boot argument list too long"));
+			return (Z_ERR);
+		}
+		if (optind < argc - 1)
+			if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
+			    sizeof (zarg.bootbuf)) {
+				zerror(gettext("Boot argument list too long"));
+				return (Z_ERR);
+			}
+	}
+
+
 	/*
 	 * zoneadmd should be the one to decide whether or not to proceed,
 	 * so even though it seems that the fourth parameter below should
--- a/usr/src/cmd/zoneadmd/vplat.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadmd/vplat.c	Thu Jun 22 14:42:46 2006 -0700
@@ -1322,7 +1322,7 @@
 	(void) zonecfg_get_uuid(zone_name, uuid);
 	altstr = strdup(zonecfg_get_root());
 	if (altstr == NULL) {
-		zerror(zlogp, B_TRUE, "out of memory");
+		zerror(zlogp, B_TRUE, "memory allocation failed");
 		return (B_FALSE);
 	}
 	zonecfg_set_root("");
@@ -2819,7 +2819,7 @@
 
 	zids = malloc(nzents * sizeof (zoneid_t));
 	if (zids == NULL) {
-		zerror(zlogp, B_TRUE, "unable to allocate memory");
+		zerror(zlogp, B_TRUE, "memory allocation failed");
 		return (-1);
 	}
 	nzents_saved = nzents;
@@ -3071,7 +3071,7 @@
 
 	zids = malloc(nzents * sizeof (zoneid_t));
 	if (zids == NULL) {
-		zerror(zlogp, B_TRUE, "unable to allocate memory");
+		zerror(zlogp, B_TRUE, "memory allocation failed");
 		return;
 	}
 	nzents_saved = nzents;
@@ -3291,7 +3291,7 @@
 		nzids += 10;
 		zids = malloc(nzids * sizeof (*zids));
 		if (zids == NULL) {
-			zerror(zlogp, B_TRUE, "unable to allocate memory");
+			zerror(zlogp, B_TRUE, "memory allocation failed");
 			return (B_TRUE);
 		}
 		if (zone_list(zids, &nzids) == 0)
--- a/usr/src/cmd/zoneadmd/zcons.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadmd/zcons.c	Thu Jun 22 14:42:46 2006 -0700
@@ -128,6 +128,8 @@
 
 static int	slavefd = -1;	/* slave side of console */
 static int	serverfd = -1;	/* console server unix domain socket fd */
+char boot_args[BOOTARGS_MAX];
+char bad_boot_arg[BOOTARGS_MAX];
 
 static struct termios base_termios = {	/* from init.c */
 	BRKINT|ICRNL|IXON|IMAXBEL,			/* iflag */
@@ -147,6 +149,8 @@
  */
 static int eventstream[2];
 
+
+
 int
 eventstream_init()
 {
@@ -697,39 +701,62 @@
 static void
 event_message(int clifd, char *clilocale, zone_evt_t evt)
 {
-	char msg[BUFSIZ];
-	char *str;
-	const char *fmt;
+	char *str, *lstr = NULL;
+	char lmsg[BUFSIZ];
+	char outbuf[BUFSIZ];
 
 	if (clifd == -1)
 		return;
 
 	switch (evt) {
 	case Z_EVT_ZONE_BOOTING:
-		str = "Zone booting up";
+		if (*boot_args == '\0') {
+			str = "NOTICE: Zone booting up";
+			break;
+		}
+		/*LINTED*/
+		(void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
+		    "NOTICE: Zone booting up with arguments: %s"), boot_args);
+		lstr = lmsg;
 		break;
 	case Z_EVT_ZONE_READIED:
-		str = "Zone readied";
+		str = "NOTICE: Zone readied";
 		break;
 	case Z_EVT_ZONE_HALTED:
-		str = "Zone halted";
+		str = "NOTICE: Zone halted";
 		break;
 	case Z_EVT_ZONE_REBOOTING:
-		str = "Zone rebooting";
+		if (*boot_args == '\0') {
+			str = "NOTICE: Zone rebooting";
+			break;
+		}
+		/*LINTED*/
+		(void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
+		    "NOTICE: Zone rebooting with arguments: %s"), boot_args);
+		lstr = lmsg;
 		break;
 	case Z_EVT_ZONE_UNINSTALLING:
-		str = "Zone is being uninstalled.  Disconnecting...";
+		str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
 		break;
 	case Z_EVT_ZONE_BOOTFAILED:
-		str = "Zone boot failed";
+		str = "NOTICE: Zone boot failed";
+		break;
+	case Z_EVT_ZONE_BADARGS:
+		/*LINTED*/
+		(void) snprintf(lmsg, sizeof (lmsg),
+		    localize_msg(clilocale,
+		    "WARNING: Ignoring invalid boot arguments: %s"),
+		    bad_boot_arg);
+		lstr = lmsg;
 		break;
 	default:
 		return;
 	}
-	str = localize_msg(clilocale, str);
-	fmt = localize_msg(clilocale, "\r\n[NOTICE: %s]\r\n");
-	(void) snprintf(msg, sizeof (msg), fmt, str);
-	(void) write(clifd, msg, strlen(msg));
+
+	if (lstr == NULL)
+		lstr = localize_msg(clilocale, str);
+	(void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
+	(void) write(clifd, outbuf, strlen(outbuf));
 }
 
 /*
--- a/usr/src/cmd/zoneadmd/zoneadmd.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c	Thu Jun 22 14:42:46 2006 -0700
@@ -240,6 +240,181 @@
 	}
 }
 
+/*
+ * Emit a warning for any boot arguments which are unrecognized.  Since
+ * Solaris boot arguments are getopt(3c) compatible (see kernel(1m)), we
+ * put the arguments into an argv style array, use getopt to process them,
+ * and put the resultant argument string back into outargs.
+ *
+ * During the filtering, we pull out any arguments which are truly "boot"
+ * arguments, leaving only those which are to be passed intact to the
+ * progenitor process.  The one we support at the moment is -i, which
+ * indicates to the kernel which program should be launched as 'init'.
+ *
+ * A return of Z_INVAL indicates specifically that the arguments are
+ * not valid; this is a non-fatal error.  Except for Z_OK, all other return
+ * values are treated as fatal.
+ */
+static int
+filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
+    char *init_file, char *badarg)
+{
+	int argc = 0, argc_save;
+	int i;
+	int err;
+	char *arg, *lasts, **argv = NULL, **argv_save;
+	char zonecfg_args[BOOTARGS_MAX];
+	char scratchargs[BOOTARGS_MAX], *sargs;
+	char c;
+
+	bzero(outargs, BOOTARGS_MAX);
+	bzero(badarg, BOOTARGS_MAX);
+
+	(void) strlcpy(init_file, PATH_TO_INIT, MAXPATHLEN);
+
+	/*
+	 * If the user didn't specify transient boot arguments, check
+	 * to see if there were any specified in the zone configuration,
+	 * and use them if applicable.
+	 */
+	if (inargs == NULL || inargs[0] == '\0')  {
+		zone_dochandle_t handle;
+		if ((handle = zonecfg_init_handle()) == NULL) {
+			zerror(zlogp, B_TRUE,
+			    "getting zone configuration handle");
+			return (Z_BAD_HANDLE);
+		}
+		err = zonecfg_get_snapshot_handle(zone_name, handle);
+		if (err != Z_OK) {
+			zerror(zlogp, B_FALSE,
+			    "invalid configuration snapshot");
+			zonecfg_fini_handle(handle);
+			return (Z_BAD_HANDLE);
+		}
+
+		bzero(zonecfg_args, sizeof (zonecfg_args));
+		(void) zonecfg_get_bootargs(handle, zonecfg_args,
+		    sizeof (zonecfg_args));
+		inargs = zonecfg_args;
+		zonecfg_fini_handle(handle);
+	}
+
+	if (strlen(inargs) >= BOOTARGS_MAX) {
+		zerror(zlogp, B_FALSE, "boot argument string too long");
+		return (Z_INVAL);
+	}
+
+	(void) strlcpy(scratchargs, inargs, sizeof (scratchargs));
+	sargs = scratchargs;
+	while ((arg = strtok_r(sargs, " \t", &lasts)) != NULL) {
+		sargs = NULL;
+		argc++;
+	}
+
+	if ((argv = calloc(argc + 1, sizeof (char *))) == NULL) {
+		zerror(zlogp, B_FALSE, "memory allocation failed");
+		return (Z_NOMEM);
+	}
+
+	argv_save = argv;
+	argc_save = argc;
+
+	(void) strlcpy(scratchargs, inargs, sizeof (scratchargs));
+	sargs = scratchargs;
+	i = 0;
+	while ((arg = strtok_r(sargs, " \t", &lasts)) != NULL) {
+		sargs = NULL;
+		if ((argv[i] = strdup(arg)) == NULL) {
+			err = Z_NOMEM;
+			zerror(zlogp, B_FALSE, "memory allocation failed");
+			goto done;
+		}
+		i++;
+	}
+
+	/*
+	 * We preserve compatibility with the Solaris system boot behavior,
+	 * which allows:
+	 *
+	 * 	# reboot kernel/unix -s -m verbose
+	 *
+	 * In this example, kernel/unix tells the booter what file to
+	 * boot.  We don't want reboot in a zone to be gratuitously different,
+	 * so we silently ignore the boot file, if necessary.
+	 */
+	if (argv[0] == NULL)
+		goto done;
+
+	assert(argv[0][0] != ' ');
+	assert(argv[0][0] != '\t');
+
+	if (argv[0][0] != '-' && argv[0][0] != '\0') {
+		argv = &argv[1];
+		argc--;
+	}
+
+	optind = 0;
+	opterr = 0;
+	err = Z_OK;
+	while ((c = getopt(argc, argv, "i:m:s")) != -1) {
+		switch (c) {
+		case 'i':
+			/*
+			 * -i is handled by the runtime and is not passed
+			 * along to userland
+			 */
+			(void) strlcpy(init_file, optarg, MAXPATHLEN);
+			break;
+		case 'm':
+		case 's':
+			/* These pass through unmolested */
+			(void) snprintf(outargs, BOOTARGS_MAX,
+			    "%s -%c %s ", outargs, c, optarg ? optarg : "");
+			break;
+		case '?':
+			/*
+			 * We warn about unknown arguments but pass them
+			 * along anyway-- if someone wants to develop their
+			 * own init replacement, they can pass it whatever
+			 * args they want.
+			 */
+			err = Z_INVAL;
+			(void) snprintf(outargs, BOOTARGS_MAX,
+			    "%s -%c", outargs, optopt);
+			(void) snprintf(badarg, BOOTARGS_MAX,
+			    "%s -%c", badarg, optopt);
+			break;
+		}
+	}
+
+	/*
+	 * For Solaris Zones we warn about and discard non-option arguments.
+	 * Hence 'boot foo bar baz gub' --> 'boot'.  However, to be similar
+	 * to the kernel, we concat up all the other remaining boot args.
+	 * and warn on them as a group.
+	 */
+	if (optind < argc) {
+		err = Z_INVAL;
+		while (optind < argc) {
+			(void) snprintf(badarg, BOOTARGS_MAX, "%s%s%s",
+			    badarg, strlen(badarg) > 0 ? " " : "",
+			    argv[optind]);
+			optind++;
+		}
+		zerror(zlogp, B_FALSE, "WARNING: Unused or invalid boot "
+		    "arguments `%s'.", badarg);
+	}
+
+done:
+	for (i = 0; i < argc_save; i++) {
+		if (argv_save[i] != NULL)
+			free(argv_save[i]);
+	}
+	free(argv_save);
+	return (err);
+}
+
+
 static int
 mkzonedir(zlog_t *zlogp)
 {
@@ -403,7 +578,9 @@
 {
 	zoneid_t zoneid;
 	struct stat st;
-	char zroot[MAXPATHLEN], initpath[MAXPATHLEN];
+	char zroot[MAXPATHLEN], initpath[MAXPATHLEN], init_file[MAXPATHLEN];
+	char nbootargs[BOOTARGS_MAX];
+	int err;
 
 	if (init_console_slave(zlogp) != 0)
 		return (-1);
@@ -417,15 +594,24 @@
 	if (zone_mount_early(zlogp, zoneid) != 0)
 		return (-1);
 
+	err = filter_bootargs(zlogp, bootargs, nbootargs, init_file,
+	    bad_boot_arg);
+	if (err == Z_INVAL)
+		eventstream_write(Z_EVT_ZONE_BADARGS);
+	else if (err != Z_OK)
+		return (-1);
+
+	assert(init_file[0] != '\0');
+
 	/*
-	 * Try to anticipate possible problems: Make sure init is executable.
+	 * Try to anticipate possible problems: Make sure whatever binary
+	 * is supposed to be init is executable.
 	 */
 	if (zone_get_rootpath(zone_name, zroot, sizeof (zroot)) != Z_OK) {
 		zerror(zlogp, B_FALSE, "unable to determine zone root");
 		return (-1);
 	}
-	(void) snprintf(initpath, sizeof (initpath), "%s%s", zroot,
-	    PATH_TO_INIT);
+	(void) snprintf(initpath, sizeof (initpath), "%s%s", zroot, init_file);
 
 	if (stat(initpath, &st) == -1) {
 		zerror(zlogp, B_TRUE, "could not stat %s", initpath);
@@ -437,7 +623,17 @@
 		return (-1);
 	}
 
-	if (zone_boot(zoneid, bootargs) == -1) {
+	if (zone_setattr(zoneid, ZONE_ATTR_INITNAME, init_file, 0) == -1) {
+		zerror(zlogp, B_TRUE, "could not set zone boot file");
+		return (-1);
+	}
+
+	if (zone_setattr(zoneid, ZONE_ATTR_BOOTARGS, nbootargs, 0) == -1) {
+		zerror(zlogp, B_TRUE, "could not set zone boot arguments");
+		return (-1);
+	}
+
+	if (zone_boot(zoneid) == -1) {
 		zerror(zlogp, B_TRUE, "unable to boot zone");
 		return (-1);
 	}
@@ -568,7 +764,9 @@
 		/*
 		 * This really shouldn't be happening.
 		 */
-		zerror(&logsys, B_FALSE, "invalid argument");
+		zerror(&logsys, B_FALSE, "argument size (%d bytes) "
+		    "unexpected (expected %d bytes)", alen,
+		    sizeof (zone_cmd_arg_t));
 		goto out;
 	}
 	cmd = zargp->cmd;
@@ -754,6 +952,8 @@
 			rval = 0;
 			break;
 		case Z_BOOT:
+			(void) strlcpy(boot_args, zargp->bootbuf,
+			    sizeof (boot_args));
 			eventstream_write(Z_EVT_ZONE_BOOTING);
 			rval = zone_bootup(zlogp, zargp->bootbuf);
 			audit_put_record(zlogp, uc, rval, "boot");
@@ -762,6 +962,7 @@
 				(void) zone_halt(zlogp, B_FALSE);
 				eventstream_write(Z_EVT_ZONE_BOOTFAILED);
 			}
+			boot_args[0] = '\0';
 			break;
 		case Z_HALT:
 			if (kernelcall)	/* Invalid; can't happen */
@@ -834,21 +1035,26 @@
 			eventstream_write(Z_EVT_ZONE_HALTED);
 			break;
 		case Z_REBOOT:
+			(void) strlcpy(boot_args, zargp->bootbuf,
+			    sizeof (boot_args));
 			eventstream_write(Z_EVT_ZONE_REBOOTING);
 			if ((rval = zone_halt(zlogp, B_FALSE)) != 0) {
 				eventstream_write(Z_EVT_ZONE_BOOTFAILED);
+				boot_args[0] = '\0';
 				break;
 			}
 			if ((rval = zone_ready(zlogp, B_FALSE)) != 0) {
 				eventstream_write(Z_EVT_ZONE_BOOTFAILED);
+				boot_args[0] = '\0';
 				break;
 			}
-			rval = zone_bootup(zlogp, "");
+			rval = zone_bootup(zlogp, zargp->bootbuf);
 			audit_put_record(zlogp, uc, rval, "reboot");
 			if (rval != 0) {
 				(void) zone_halt(zlogp, B_FALSE);
 				eventstream_write(Z_EVT_ZONE_BOOTFAILED);
 			}
+			boot_args[0] = '\0';
 			break;
 		case Z_NOTE_UNINSTALLING:
 		case Z_MOUNT:
@@ -944,7 +1150,7 @@
 
 top:
 	if ((err = zone_get_state(zone_name, &zstate)) != Z_OK) {
-		zerror(zlogp, B_FALSE, "failed to get zone state: %s\n",
+		zerror(zlogp, B_FALSE, "failed to get zone state: %s",
 		    zonecfg_strerror(err));
 		goto out;
 	}
@@ -1125,13 +1331,13 @@
 	}
 
 	if (zone_get_id(zone_name, &zid) != 0) {
-		zerror(zlogp, B_FALSE, "could not manage %s: %s\n", zone_name,
+		zerror(zlogp, B_FALSE, "could not manage %s: %s", zone_name,
 		    zonecfg_strerror(Z_NO_ZONE));
 		return (1);
 	}
 
 	if ((err = zone_get_state(zone_name, &zstate)) != Z_OK) {
-		zerror(zlogp, B_FALSE, "failed to get zone state: %s\n",
+		zerror(zlogp, B_FALSE, "failed to get zone state: %s",
 		    zonecfg_strerror(err));
 		return (1);
 	}
@@ -1159,7 +1365,7 @@
 
 	if (priv_isfullset(privset) == B_FALSE) {
 		zerror(zlogp, B_FALSE, "You lack sufficient privilege to "
-		    "run this command (all privs required)\n");
+		    "run this command (all privs required)");
 		priv_freeset(privset);
 		return (1);
 	}
--- a/usr/src/cmd/zoneadmd/zoneadmd.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zoneadmd/zoneadmd.h	Thu Jun 22 14:42:46 2006 -0700
@@ -71,6 +71,9 @@
 extern boolean_t in_death_throes;
 extern boolean_t bringup_failure_recovery;
 extern char *zone_name;
+extern char boot_args[BOOTARGS_MAX];
+extern char bad_boot_arg[BOOTARGS_MAX];
+
 
 extern void zerror(zlog_t *, boolean_t, const char *, ...);
 extern char *localize_msg(char *locale, const char *msg);
@@ -85,7 +88,8 @@
 	Z_EVT_ZONE_HALTED,
 	Z_EVT_ZONE_READIED,
 	Z_EVT_ZONE_UNINSTALLING,
-	Z_EVT_ZONE_BOOTFAILED
+	Z_EVT_ZONE_BOOTFAILED,
+	Z_EVT_ZONE_BADARGS
 } zone_evt_t;
 
 extern int eventstream_init();
--- a/usr/src/cmd/zonecfg/zonecfg.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.c	Thu Jun 22 14:42:46 2006 -0700
@@ -155,6 +155,7 @@
 	"attr",
 	"dataset",
 	"limitpriv",
+	"bootargs",
 	NULL
 };
 
@@ -179,6 +180,7 @@
 	"action",
 	"raw",
 	"limitpriv",
+	"bootargs",
 	NULL
 };
 
@@ -243,6 +245,7 @@
 	"set autoboot=",
 	"set pool=",
 	"set limitpriv=",
+	"set bootargs=",
 	NULL
 };
 
@@ -895,6 +898,8 @@
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_AUTOBOOT));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+		    pt_to_str(PT_BOOTARGS));
+		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_POOL));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_LIMITPRIV));
@@ -1310,6 +1315,7 @@
 	struct zone_rctlvaltab *valptr;
 	int err, arg;
 	char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
+	char bootargs[BOOTARGS_MAX];
 	char *limitpriv;
 	FILE *of;
 	boolean_t autoboot;
@@ -1365,6 +1371,12 @@
 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
 		    pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
 
+	if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
+	    strlen(bootargs) > 0) {
+		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+		    pt_to_str(PT_BOOTARGS), bootargs);
+	}
+
 	if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
 	    strlen(pool) > 0)
 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
@@ -1377,6 +1389,7 @@
 		free(limitpriv);
 	}
 
+
 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
 		zone_perror(zone, err, FALSE);
 		goto done;
@@ -2676,6 +2689,8 @@
 			res_type = RT_POOL;
 		} else if (prop_type == PT_LIMITPRIV) {
 			res_type = RT_LIMITPRIV;
+		} else if (prop_type == PT_BOOTARGS) {
+			res_type = RT_BOOTARGS;
 		} else {
 			zerr(gettext("Cannot set a resource-specific property "
 			    "from the global scope."));
@@ -2784,6 +2799,12 @@
 		else
 			need_to_commit = TRUE;
 		return;
+	case RT_BOOTARGS:
+		if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
+			zone_perror(zone, err, TRUE);
+		else
+			need_to_commit = TRUE;
+		return;
 	case RT_FS:
 		switch (prop_type) {
 		case PT_DIR:
@@ -3053,6 +3074,21 @@
 }
 
 static void
+info_bootargs(zone_dochandle_t handle, FILE *fp)
+{
+	char bootargs[BOOTARGS_MAX];
+	int err;
+
+	if ((err = zonecfg_get_bootargs(handle, bootargs,
+	    sizeof (bootargs))) == Z_OK) {
+		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
+		    bootargs);
+	} else {
+		zone_perror(zone, err, TRUE);
+	}
+}
+
+static void
 output_fs(FILE *fp, struct zone_fstab *fstab)
 {
 	zone_fsopt_t *this;
@@ -3421,6 +3457,7 @@
 		info_zonename(handle, fp);
 		info_zonepath(handle, fp);
 		info_autoboot(handle, fp);
+		info_bootargs(handle, fp);
 		info_pool(handle, fp);
 		info_limitpriv(handle, fp);
 		info_ipd(handle, fp, cmd);
@@ -3446,6 +3483,9 @@
 	case RT_LIMITPRIV:
 		info_limitpriv(handle, fp);
 		break;
+	case RT_BOOTARGS:
+		info_bootargs(handle, fp);
+		break;
 	case RT_FS:
 		info_fs(handle, fp, cmd);
 		break;
--- a/usr/src/cmd/zonecfg/zonecfg.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.h	Thu Jun 22 14:42:46 2006 -0700
@@ -81,9 +81,10 @@
 #define	RT_ATTR		10
 #define	RT_DATASET	11
 #define	RT_LIMITPRIV	12	/* really a property, but for info ... */
+#define	RT_BOOTARGS	13	/* really a property, but for info ... */
 
 #define	RT_MIN		RT_UNKNOWN
-#define	RT_MAX		RT_LIMITPRIV
+#define	RT_MAX		RT_BOOTARGS
 
 /* property types: increment PT_MAX when expanding this list */
 #define	PT_UNKNOWN	0
@@ -105,9 +106,10 @@
 #define	PT_ACTION	16
 #define	PT_RAW		17
 #define	PT_LIMITPRIV	18
+#define	PT_BOOTARGS	19
 
 #define	PT_MIN		PT_UNKNOWN
-#define	PT_MAX		PT_LIMITPRIV
+#define	PT_MAX		PT_BOOTARGS
 
 #define	MAX_EQ_PROP_PAIRS	3
 
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y	Thu Jun 22 14:42:46 2006 -0700
@@ -60,14 +60,15 @@
 %token COMMIT REVERT EXIT SEMICOLON TOKEN ZONENAME ZONEPATH AUTOBOOT POOL NET
 %token FS IPD ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
 %token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
-%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV
+%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS
 
 %type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
     property_value OPEN_PAREN CLOSE_PAREN COMMA simple_prop_val
 %type <complex> complex_piece complex_prop_val
 %type <ival> resource_type NET FS IPD DEVICE RCTL ATTR
 %type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
-    MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV VALUE PRIV LIMIT ACTION
+    MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
+    ACTION
 %type <cmd> command
 %type <cmd> add_command ADD
 %type <cmd> cancel_command CANCEL
@@ -446,6 +447,15 @@
 		$$->cmd_res_type = RT_LIMITPRIV;
 		$$->cmd_prop_nv_pairs = 0;
 	}
+	|	INFO BOOTARGS
+	{
+		if (($$ = alloc_cmd()) == NULL)
+			YYERROR;
+		cmd = $$;
+		$$->cmd_handler = &info_func;
+		$$->cmd_res_type = RT_BOOTARGS;
+		$$->cmd_prop_nv_pairs = 0;
+	}
 	|	INFO resource_type property_name EQUAL property_value
 	{
 		if (($$ = alloc_cmd()) == NULL)
@@ -688,6 +698,7 @@
 	| AUTOBOOT	{ $$ = PT_AUTOBOOT; }
 	| POOL		{ $$ = PT_POOL; }
 	| LIMITPRIV	{ $$ = PT_LIMITPRIV; }
+	| BOOTARGS	{ $$ = PT_BOOTARGS; }
 	| ADDRESS	{ $$ = PT_ADDRESS; }
 	| PHYSICAL	{ $$ = PT_PHYSICAL; }
 	| NAME		{ $$ = PT_NAME; }
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l	Thu Jun 22 14:42:46 2006 -0700
@@ -40,7 +40,7 @@
 char *safe_strdup(char *s);
 %}
 
-%a 3000
+%a 4000
 
 %{
 /*
@@ -174,6 +174,9 @@
 <TSTATE>limitpriv	{ return LIMITPRIV; }
 <CSTATE>limitpriv	{ return LIMITPRIV; }
 
+<TSTATE>bootargs	{ return BOOTARGS; }
+<CSTATE>bootargs	{ return BOOTARGS; }
+
 <TSTATE>type	{ return TYPE; }
 <CSTATE>type	{ return TYPE; }
 
--- a/usr/src/head/libzonecfg.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/head/libzonecfg.h	Thu Jun 22 14:42:46 2006 -0700
@@ -216,7 +216,8 @@
 extern	boolean_t zonecfg_in_alt_root(void);
 
 /*
- * Zone name, path to zone directory, autoboot setting and pool.
+ * Zone name, path to zone directory, autoboot setting, pool and boot
+ * arguments.
  */
 extern	int	zonecfg_validate_zonename(const char *);
 extern	int	zonecfg_get_name(zone_dochandle_t, char *, size_t);
@@ -227,6 +228,8 @@
 extern	int	zonecfg_set_autoboot(zone_dochandle_t, boolean_t);
 extern	int	zonecfg_get_pool(zone_dochandle_t, char *, size_t);
 extern	int	zonecfg_set_pool(zone_dochandle_t, char *);
+extern	int	zonecfg_get_bootargs(zone_dochandle_t, char *, size_t);
+extern	int	zonecfg_set_bootargs(zone_dochandle_t, char *);
 
 /*
  * Filesystem configuration.
--- a/usr/src/head/zone.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/head/zone.h	Thu Jun 22 14:42:46 2006 -0700
@@ -59,9 +59,10 @@
 extern zoneid_t	zone_create(const char *, const char *,
     const struct priv_set *, const char *, size_t, const char *, size_t, int *,
     int, int, const bslabel_t *);
-extern int	zone_boot(zoneid_t, const char *);
+extern int	zone_boot(zoneid_t);
 extern int	zone_destroy(zoneid_t);
 extern ssize_t	zone_getattr(zoneid_t, int, void *, size_t);
+extern int	zone_setattr(zoneid_t, int, void *, size_t);
 extern int	zone_enter(zoneid_t);
 extern int	zone_list(zoneid_t *, uint_t *);
 extern int	zone_shutdown(zoneid_t);
--- a/usr/src/lib/libc/amd64/sys/uadmin.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libc/amd64/sys/uadmin.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,15 +44,14 @@
 #include <sys/uadmin.h>
 #include <unistd.h>
 #include <string.h>
-
-#define	MAX_BOOTARG	256
+#include <zone.h>
 
 static int
 legal_arg(char *bargs)
 {
 	int i;
 
-	for (i = 0; i < MAX_BOOTARG; i++, bargs++) {
+	for (i = 0; i < BOOTARGS_MAX; i++, bargs++) {
 		if (*bargs == 0 && i > 0)
 			return (i);
 		if (!isprint(*bargs))
@@ -73,7 +71,8 @@
 	char *altroot;
 
 	bargs = (char *)mdep;
-	if (geteuid() == 0 && (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
+	if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID &&
+	    (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
 		switch (fcn) {
 		case AD_IBOOT:
 		case AD_SBOOT:
--- a/usr/src/lib/libc/i386/sys/uadmin.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libc/i386/sys/uadmin.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,15 +44,14 @@
 #include <sys/uadmin.h>
 #include <unistd.h>
 #include <string.h>
-
-#define	MAX_BOOTARG	256
+#include <zone.h>
 
 static int
 legal_arg(char *bargs)
 {
 	int i;
 
-	for (i = 0; i < MAX_BOOTARG; i++, bargs++) {
+	for (i = 0; i < BOOTARGS_MAX; i++, bargs++) {
 		if (*bargs == 0 && i > 0)
 			return (i);
 		if (!isprint(*bargs))
@@ -73,7 +71,8 @@
 	char *altroot;
 
 	bargs = (char *)mdep;
-	if (geteuid() == 0 && (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
+	if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID &&
+	    (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
 		switch (fcn) {
 		case AD_IBOOT:
 		case AD_SBOOT:
--- a/usr/src/lib/libc/port/llib-lc	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libc/port/llib-lc	Thu Jun 22 14:42:46 2006 -0700
@@ -127,6 +127,7 @@
 #include <sys/timeb.h>
 #include <sys/times.h>
 #include <sys/types.h>
+#include <sys/uadmin.h>
 #include <sys/utsname.h>
 #include <sys/vfstab.h>
 #include <sys/sendfile.h>
--- a/usr/src/lib/libc/port/sys/zone.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libc/port/sys/zone.c	Thu Jun 22 14:42:46 2006 -0700
@@ -68,9 +68,9 @@
 }
 
 int
-zone_boot(zoneid_t zoneid, const char *bootargs)
+zone_boot(zoneid_t zoneid)
 {
-	return (syscall(SYS_zone, ZONE_BOOT, zoneid, bootargs));
+	return (syscall(SYS_zone, ZONE_BOOT, zoneid));
 }
 
 int
@@ -99,6 +99,12 @@
 }
 
 int
+zone_setattr(zoneid_t zoneid, int attr, void *valp, size_t size)
+{
+	return (syscall(SYS_zone, ZONE_SETATTR, zoneid, attr, valp, size));
+}
+
+int
 zone_enter(zoneid_t zoneid)
 {
 	return (syscall(SYS_zone, ZONE_ENTER, zoneid));
--- a/usr/src/lib/libc/spec/sys.spec	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libc/spec/sys.spec	Thu Jun 22 14:42:46 2006 -0700
@@ -3475,6 +3475,14 @@
 exception	$return == -1
 end
 
+function	zone_setattr
+include		<zone.h>
+declaration	int zone_setattr(zoneid_t zoneid, int attr, void *valp, \
+		    size_t sizep)
+version		SUNWprivate_1.1
+exception	$return == -1
+end
+
 function	zone_get_id
 include		<zone.h>
 declaration	int zone_get_id(const char *str, zoneid_t *zip)
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c	Thu Jun 22 14:42:46 2006 -0700
@@ -90,6 +90,7 @@
 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
+#define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
@@ -875,9 +876,21 @@
 }
 
 int
-zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitprivsize)
-{
-	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitprivsize));
+zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
+{
+	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
+}
+
+int
+zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
+{
+	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
+}
+
+int
+zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
+{
+	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
 }
 
 /*
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Thu Jun 22 14:42:46 2006 -0700
@@ -102,4 +102,5 @@
 			autoboot	(true | false) #REQUIRED
 			pool		CDATA ""
 			limitpriv	CDATA ""
+			bootargs	CDATA ""
 			version		NMTOKEN #FIXED '1'>
--- a/usr/src/lib/libzonecfg/spec/libzonecfg.spec	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/lib/libzonecfg/spec/libzonecfg.spec	Thu Jun 22 14:42:46 2006 -0700
@@ -162,6 +162,18 @@
 version		SUNWprivate_1.1
 end		
 
+function	zonecfg_get_bootargs
+include		<libzonecfg.h>
+declaration	int zonecfg_get_bootargs(zone_dochandle_t, char *, size_t)
+version		SUNWprivate_1.1
+end		
+
+function	zonecfg_set_bootargs
+include		<libzonecfg.h>
+declaration	int zonecfg_set_bootargs(zone_dochandle_t, char *)
+version		SUNWprivate_1.1
+end		
+
 function	zonecfg_add_fs_option
 include		<libzonecfg.h>
 declaration	int zonecfg_add_fs_option(struct zone_fstab *, char *)
--- a/usr/src/psm/stand/boot/i386/common/multiboot.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/psm/stand/boot/i386/common/multiboot.c	Thu Jun 22 14:42:46 2006 -0700
@@ -62,6 +62,7 @@
 static void print_mbinfo(void);
 
 int debug;
+static int started_bootfile = 0;
 
 #define	dprintf	if (debug & D_MBOOT) printf
 
@@ -137,7 +138,7 @@
 	 * May set graphics mode, for which bios support is required.
 	 */
 	console_init2(inputdevice_prop, outputdevice_prop,
-		console_prop);
+	    console_prop);
 
 #ifdef  BOOTAMD64
 	/* Test to see if this CPU is an AMD64 */
@@ -197,6 +198,14 @@
 	if (verbosemode)
 		printf("Boot about to exit to 32-bit kernel image at 0x%x.\n",
 		    entry);
+
+	/*
+	 * It's a while before the kernel actually gets around to setting
+	 * up traps; if we die during that period, multiboot's trap handler
+	 * will get control.  We want to at least know roughly where we
+	 * died.
+	 */
+	started_bootfile = 1;
 	exitto(entry);
 
 	panic("failed to boot %s\n", bootfile);
@@ -286,27 +295,27 @@
 	uint32_t *esp = (uint32_t *)regs->r_esp;
 
 	printf("trap type %d (0x%x) err code 0x%x eip=0x%x\n",
-		regs->r_trapno, regs->r_trapno, regs->r_err,
-		regs->r_eip);
+	    regs->r_trapno, regs->r_trapno, regs->r_err,
+	    regs->r_eip);
 	printf("%%eflags = 0x%08x\t%%cs:%%eip = 0x%04x:0x%08x\n",
-		regs->r_efl, regs->r_cs, regs->r_eip);
+	    regs->r_efl, regs->r_cs, regs->r_eip);
 	printf("%%eax = 0x%08x\t%%ebx = 0x%08x\t%%ecx = 0x%08x\n",
-		regs->r_eax, regs->r_ebx, regs->r_ecx);
+	    regs->r_eax, regs->r_ebx, regs->r_ecx);
 	printf("%%edx = 0x%08x\t%%esi = 0x%08x\t%%edi = 0x%08x\n",
-		regs->r_edx, regs->r_esi, regs->r_edi);
+	    regs->r_edx, regs->r_esi, regs->r_edi);
 	printf("%%esp = 0x%08x\t%%ebp = 0x%08x\n",
-		regs->r_esp, regs->r_ebp);
+	    regs->r_esp, regs->r_ebp);
 	printf("%%ss = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\t%%fs = 0x%04x\n",
-		regs->r_ss, regs->r_ds, regs->r_es, regs->r_fs);
+	    regs->r_ss, regs->r_ds, regs->r_es, regs->r_fs);
 	printf("GDT @ 0x%08x lim 0x%04x\t\tIDT @ 0x%08x lim 0x%04x\n",
-		regs->r_gdt.dtr_base, regs->r_gdt.dtr_limit,
-		regs->r_idt.dtr_base, regs->r_idt.dtr_limit);
+	    regs->r_gdt.dtr_base, regs->r_gdt.dtr_limit,
+	    regs->r_idt.dtr_base, regs->r_idt.dtr_limit);
 	printf("LDT = 0x%04x\tTASK = 0x%04x\n",
-		regs->r_ldt, regs->r_tr);
+	    regs->r_ldt, regs->r_tr);
 	printf("%%cr0 = 0x%08x\t%%cr2 = 0x%08x\t%%cr3 = 0x%08x\n",
-		regs->r_cr0, regs->r_cr2, regs->r_cr3);
+	    regs->r_cr0, regs->r_cr2, regs->r_cr3);
 	printf("%%cr4 = 0x%08x\n",
-		regs->r_cr4);
+	    regs->r_cr4);
 
 	printf("\nStack (starting at 0x%x):\n", (uint32_t)esp);
 	for (j = 0; j < stack_lines; j++) {
@@ -325,5 +334,8 @@
 	/* Show registers and stack: [24 lines max (prevents scrolling)] */
 	show_regs_and_stack(regs, STACK_LINES);
 
-	panic("unexpected trap in boot loader\n");
+	if (started_bootfile == 0)
+		panic("unexpected trap in boot loader\n");
+	else
+		panic("unexpected trap after starting %s\n", bootfile);
 }
--- a/usr/src/uts/common/krtld/kobj_bootflags.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/krtld/kobj_bootflags.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,7 +49,7 @@
 	uchar_t num_O_opt = 0;
 	char *cp;
 	int c;
-
+	char scratch[BOOTARGS_MAX];
 
 	if (BOP_GETPROP(ops, "boot-args", kern_bootargs) != 0) {
 		boothowto |= RB_ASKNAME;
@@ -74,6 +73,7 @@
 	params.gos_strp = cp;
 	getoptstr_init(&params);
 	while ((c = getoptstr(&params)) != -1) {
+
 		switch (c) {
 		case 'a':
 			boothowto |= RB_ASKNAME;
@@ -110,16 +110,20 @@
 			boothowto |= RB_KMDB;
 			break;
 		case 'm':
-			if (2 + params.gos_optarglen + 1 > sizeof (initargs))
-				printf(
-				    "unix: -m argument too long.  Ignoring.\n");
-			else {
-				(void) strcpy(initargs, "-m");
-				(void) strncat(initargs, params.gos_optargp,
-				    params.gos_optarglen);
-				initargs[sizeof ("-m") - 1 +
-				    params.gos_optarglen] = '\0';
+			if (strlen(initargs) + 3 + params.gos_optarglen + 1 >
+			    sizeof (initargs)) {
+				_kobj_printf(ops,
+				    "unix: init options too long.  "
+				    "Ignoring -m.\n");
+				break;
 			}
+			/* gos_optargp is not null terminated */
+			(void) strncpy(scratch, params.gos_optargp,
+			    params.gos_optarglen);
+			scratch[params.gos_optarglen] = '\0';
+			(void) strlcat(initargs, "-m ", sizeof (initargs));
+			(void) strlcat(initargs, scratch, sizeof (initargs));
+			(void) strlcat(initargs, " ", sizeof (initargs));
 			break;
 		case 'O': {
 			char **str = &kobj_kmdb_argv[num_O_opt];
@@ -139,13 +143,31 @@
 			break;
 		}
 		case 'r':
+			if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
+				_kobj_printf(ops, "unix: init options too "
+				    "long.  Ignoring -r.\n");
+				break;
+			}
 			boothowto |= RB_RECONFIG;
+			(void) strlcat(initargs, "-r ", sizeof (initargs));
 			break;
 		case 's':
+			if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
+				_kobj_printf(ops, "unix: init options too "
+				    "long.  Ignoring -s.\n");
+				break;
+			}
 			boothowto |= RB_SINGLE;
+			(void) strlcat(initargs, "-s ", sizeof (initargs));
 			break;
 		case 'v':
+			if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
+				_kobj_printf(ops, "unix: init options too "
+				    "long.  Ignoring -v.\n");
+				break;
+			}
 			boothowto |= RB_VERBOSE;
+			(void) strlcat(initargs, "-v ", sizeof (initargs));
 			break;
 		case 'w':
 			boothowto |= RB_WRITABLE;
--- a/usr/src/uts/common/krtld/kobj_subr.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/krtld/kobj_subr.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,9 +27,17 @@
 
 #include <sys/types.h>
 #include <sys/param.h>
+#include <sys/systm.h>
 
 /*
- * Standalone copies of some basic routines.
+ * Standalone copies of some basic routines.  Note that these routines
+ * are transformed via Makefile -D flags into krtld_* routines.  So,
+ * this version of strcmp() will become krtld_strcmp() when built.
+ *
+ * This dubious practice is so that krtld can have its own private
+ * versions of these routines suitable for use during early boot,
+ * when kernel-based routines might not work.  Make sure to use 'nm'
+ * on your krtld to make sure it is calling the appropriate routines.
  */
 
 int
@@ -107,6 +114,27 @@
 	return (os1);
 }
 
+size_t
+strlcat(char *dst, const char *src, size_t dstsize)
+{
+	char *df = dst;
+	size_t left = dstsize;
+	size_t l1;
+	size_t l2 = strlen(src);
+	size_t copied;
+
+	while (left-- != 0 && *df != '\0')
+		df++;
+	l1 = df - dst;
+	if (dstsize == l1)
+		return (l1 + l2);
+
+	copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
+	bcopy(src, dst + l1, copied);
+	dst[l1+copied] = '\0';
+	return (l1 + l2);
+}
+
 char *
 strchr(const char *sp, int c)
 {
--- a/usr/src/uts/common/os/exit.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/os/exit.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -162,7 +161,6 @@
 	sess_t *sp;
 	int i, err;
 	char reason_buf[64];
-	const char *ipath;
 
 	/*
 	 * Let zone admin (and global zone admin if this is for a non-global
@@ -276,8 +274,7 @@
 	 * succeed, the caller will treat this like a successful system call.
 	 * If we fail, we issue messages and the caller will proceed with exit.
 	 */
-	ipath = INGLOBALZONE(p) ? initname : zone_initname;
-	err = exec_init(ipath, 0, NULL);
+	err = exec_init(p->p_zone->zone_initname, NULL);
 
 	if (err == 0)
 		return (0);
@@ -370,7 +367,7 @@
 	DTRACE_PROC1(exit, int, why);
 
 	/*
-	 * Don't let init exit unless zone_icode() failed its exec, or
+	 * Don't let init exit unless zone_start_init() failed its exec, or
 	 * we are shutting down the zone or the machine.
 	 *
 	 * Since we are single threaded, we don't need to lock the
@@ -883,7 +880,7 @@
 	 */
 	if (idtype == P_ALL &&
 	    (options & (WOPTMASK & ~WNOWAIT)) == (WNOHANG | WEXITED) &&
-		pp->p_child_ns == NULL) {
+	    pp->p_child_ns == NULL) {
 
 		if (pp->p_child) {
 			mutex_exit(&pidlock);
--- a/usr/src/uts/common/os/main.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/os/main.c	Thu Jun 22 14:42:46 2006 -0700
@@ -122,121 +122,134 @@
 	panic("cluster()  returned");
 }
 
-char initname[INITNAME_SZ] = "/sbin/init";
-char initargs[INITARGS_SZ] = "";
+char initname[INITNAME_SZ] = "/sbin/init";	/* also referenced by zone0 */
+char initargs[BOOTARGS_MAX] = "";		/* also referenced by zone0 */
 
 /*
- * Start the initial user process.
- * The program [initname] may be invoked with one argument
- * containing the boot flags.
- *
- * It must be a 32-bit program.
+ * Construct a stack for init containing the arguments to it, then
+ * pass control to exec_common.
  */
-void
-icode(void)
+int
+exec_init(const char *initpath, const char *args)
 {
-	proc_t *p = ttoproc(curthread);
-
-	ASSERT_STACK_ALIGNED();
-
-	/*
-	 * Allocate user address space and stack segment
-	 */
-	proc_init = p;
-	zone0.zone_proc_initpid = proc_init->p_pid;
-
-	p->p_cstime = p->p_stime = p->p_cutime = p->p_utime = 0;
-	p->p_usrstack = (caddr_t)USRSTACK32;
-	p->p_model = DATAMODEL_ILP32;
-	p->p_stkprot = PROT_ZFOD & ~PROT_EXEC;
-	p->p_datprot = PROT_ZFOD & ~PROT_EXEC;
-	p->p_stk_ctl = INT32_MAX;
-
-	p->p_as = as_alloc();
-	p->p_as->a_userlimit = (caddr_t)USERLIMIT32;
-	(void) hat_setup(p->p_as->a_hat, HAT_INIT);
-	init_core();
-
-	init_mstate(curthread, LMS_SYSTEM);
-
-	if (exec_init(initname, 1, initargs[0] == '\0' ? NULL : initargs) != 0)
-		halt("Could not start init");
-
-	lwp_rtt();
-}
-
-int
-exec_init(const char *initpath, int useboothowto, const char *args)
-{
-	char *ucp;
+	caddr32_t ucp;
 	caddr32_t *uap;
-	char *argv[4];				/* backwards */
+	caddr32_t *argv;
+	caddr32_t exec_fnamep;
+	char *scratchargs;
+	int i, sarg;
+	size_t argvlen, alen;
+	boolean_t in_arg;
 	int argc = 0;
-	int error = 0, len, count = 0, i;
+	int error = 0, count = 0;
 	proc_t *p = ttoproc(curthread);
 	klwp_t *lwp = ttolwp(curthread);
 
-	/*
-	 * Construct the exec arguments in userland.  That is, make an array
-	 * of pointers to the argument strings, just like for execv().  This
-	 * is done backwards.
-	 */
-	ucp = p->p_usrstack;
+	if (args == NULL)
+		args = "";
 
-	argv[0] = NULL;				/* argv terminator */
-
-	if (args != NULL) {
-		len = strlen(args) + 1;
-		ucp -= len;
-		error |= copyoutstr(args, ucp, len, NULL);
-		argv[++argc] = ucp;
-	}
+	alen = strlen(initpath) + 1 + strlen(args) + 1;
+	scratchargs = kmem_alloc(alen, KM_SLEEP);
+	(void) snprintf(scratchargs, alen, "%s %s", initpath, args);
 
-	if (useboothowto &&
-	    boothowto & (RB_SINGLE|RB_RECONFIG|RB_VERBOSE)) {
-		error |= subyte(--ucp, '\0');		/* trailing null byte */
-
-		if (boothowto & RB_SINGLE)
-			error |= subyte(--ucp, 's');
-		if (boothowto & RB_RECONFIG)
-			error |= subyte(--ucp, 'r');
-		if (boothowto & RB_VERBOSE)
-			error |= subyte(--ucp, 'v');
-		error |= subyte(--ucp, '-');	/* leading hyphen */
-
-		argv[++argc] = ucp;
+	/*
+	 * We do a quick two state parse of the string to sort out how big
+	 * argc should be.
+	 */
+	in_arg = B_FALSE;
+	for (i = 0; i < strlen(scratchargs); i++) {
+		if (scratchargs[i] == ' ' || scratchargs[i] == '\0') {
+			if (in_arg) {
+				in_arg = B_FALSE;
+				argc++;
+			}
+		} else {
+			in_arg = B_TRUE;
+		}
 	}
-
-	len = strlen(initpath) + 1;
-	ucp -= len;
-	error |= copyoutstr(initpath, ucp, len, NULL);
-	argv[++argc] = ucp;
+	argvlen = sizeof (caddr32_t) * (argc + 1);
+	argv = kmem_zalloc(argvlen, KM_SLEEP);
 
 	/*
-	 * Move out the arg pointers.
+	 * We pull off a bit of a hack here.  We work our way through the
+	 * args string, putting nulls at the ends of space delimited tokens
+	 * (boot args don't support quoting at this time).  Then we just
+	 * copy the whole mess to userland in one go.  In other words, we
+	 * transform this: "init -s -r\0" into this on the stack:
+	 *
+	 *	-0x00 \0
+	 *	-0x01 r
+	 *	-0x02 -  <--------.
+	 *	-0x03 \0	  |
+	 *	-0x04 s		  |
+	 *	-0x05 -  <------. |
+	 *	-0x06 \0	| |
+	 *	-0x07 t		| |
+	 *	-0x08 i 	| |
+	 *	-0x09 n		| |
+	 *	-0x0a i  <---.  | |
+	 *	-0x10 NULL   |  | |	(argv[3])
+	 *	-0x14   -----|--|-'	(argv[2])
+	 *	-0x18  ------|--'	(argv[1])
+	 *	-0x1c -------'		(argv[0])
+	 *
+	 * Since we know the value of ucp at the beginning of this process,
+	 * we can trivially compute the argv[] array which we also need to
+	 * place in userland: argv[i] = ucp - sarg(i), where ucp is the
+	 * stack ptr, and sarg is the string index of the start of the
+	 * argument.
 	 */
+	ucp = (caddr32_t)(uintptr_t)p->p_usrstack;
+
+	argc = 0;
+	in_arg = B_FALSE;
+	sarg = 0;
+
+	for (i = 0; i < alen; i++) {
+		if (scratchargs[i] == ' ' || scratchargs[i] == '\0') {
+			if (in_arg == B_TRUE) {
+				in_arg = B_FALSE;
+				scratchargs[i] = '\0';
+				argv[argc++] = ucp - (alen - sarg);
+			}
+		} else if (in_arg == B_FALSE) {
+			in_arg = B_TRUE;
+			sarg = i;
+		}
+	}
+	ucp -= alen;
+	error |= copyout(scratchargs, (caddr_t)(uintptr_t)ucp, alen);
+
 	uap = (caddr32_t *)P2ALIGN((uintptr_t)ucp, sizeof (caddr32_t));
-	for (i = 0; i < argc + 1; ++i)
-		error |= suword32(--uap, (uint32_t)(uintptr_t)argv[i]);
+	uap--;	/* advance to be below the word we're in */
+	uap -= (argc + 1);	/* advance argc words down, plus one for NULL */
+	error |= copyout(argv, uap, argvlen);
 
 	if (error != 0) {
 		zcmn_err(p->p_zone->zone_id, CE_WARN,
 		    "Could not construct stack for init.\n");
+		kmem_free(argv, argvlen);
+		kmem_free(scratchargs, alen);
 		return (EFAULT);
 	}
 
+	exec_fnamep = argv[0];
+	kmem_free(argv, argvlen);
+	kmem_free(scratchargs, alen);
+
 	/*
 	 * Point at the arguments.
 	 */
 	lwp->lwp_ap = lwp->lwp_arg;
-	lwp->lwp_arg[0] = (uintptr_t)argv[argc];
+	lwp->lwp_arg[0] = (uintptr_t)exec_fnamep;
 	lwp->lwp_arg[1] = (uintptr_t)uap;
 	lwp->lwp_arg[2] = NULL;
 	curthread->t_post_sys = 1;
 	curthread->t_sysnum = SYS_execve;
 
 again:
-	error = exec_common((const char *)argv[argc], (const char **)uap, NULL);
+	error = exec_common((const char *)(uintptr_t)exec_fnamep,
+	    (const char **)(uintptr_t)uap, NULL);
 
 	/*
 	 * Normally we would just set lwp_argsaved and t_post_sys and
@@ -272,6 +285,54 @@
 	return (error);
 }
 
+/*
+ * This routine does all of the common setup for invoking init; global
+ * and non-global zones employ this routine for the functionality which is
+ * in common.
+ *
+ * This program (init, presumably) must be a 32-bit process.
+ */
+int
+start_init_common()
+{
+	proc_t *p = curproc;
+	ASSERT_STACK_ALIGNED();
+	p->p_zone->zone_proc_initpid = p->p_pid;
+
+	p->p_cstime = p->p_stime = p->p_cutime = p->p_utime = 0;
+	p->p_usrstack = (caddr_t)USRSTACK32;
+	p->p_model = DATAMODEL_ILP32;
+	p->p_stkprot = PROT_ZFOD & ~PROT_EXEC;
+	p->p_datprot = PROT_ZFOD & ~PROT_EXEC;
+	p->p_stk_ctl = INT32_MAX;
+
+	p->p_as = as_alloc();
+	p->p_as->a_userlimit = (caddr_t)USERLIMIT32;
+	(void) hat_setup(p->p_as->a_hat, HAT_INIT);
+
+	init_core();
+
+	init_mstate(curthread, LMS_SYSTEM);
+	return (exec_init(p->p_zone->zone_initname, p->p_zone->zone_bootargs));
+}
+
+/*
+ * Start the initial user process for the global zone; once running, if
+ * init should subsequently fail, it will be automatically be caught in the
+ * exit(2) path, and restarted by restart_init().
+ */
+static void
+start_init(void)
+{
+	proc_init = curproc;
+
+	ASSERT(curproc->p_zone->zone_initname != NULL);
+
+	if (start_init_common() != 0)
+		halt("unix: Could not start init");
+	lwp_rtt();
+}
+
 void
 main(void)
 {
@@ -469,7 +530,7 @@
 	 */
 
 	/* create init process */
-	if (newproc(icode, NULL, defaultcid, 59, NULL))
+	if (newproc(start_init, NULL, defaultcid, 59, NULL))
 		panic("main: unable to fork init.");
 
 	/* create pageout daemon */
--- a/usr/src/uts/common/os/zone.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/os/zone.c	Thu Jun 22 14:42:46 2006 -0700
@@ -175,6 +175,8 @@
  *     root path, privileges, resource controls, ZFS datasets)
  *   - zone_enter: allows the current process to enter a zone
  *   - zone_getattr: reports attributes of a zone
+ *   - zone_setattr: set attributes of a zone
+ *   - zone_boot: set 'init' running for the zone
  *   - zone_list: lists all zones active in the system
  *   - zone_lookup: looks up zone id based on name
  *   - zone_shutdown: initiates shutdown process (see states above)
@@ -221,6 +223,7 @@
 #include <sys/session.h>
 #include <sys/cmn_err.h>
 #include <sys/modhash.h>
+#include <sys/sunddi.h>
 #include <sys/nvpair.h>
 #include <sys/rctl.h>
 #include <sys/fss.h>
@@ -320,7 +323,7 @@
 static kcondvar_t mount_cv;
 static kmutex_t mount_lock;
 
-const char * const zone_initname = "/sbin/init";
+const char * const zone_default_initname = "/sbin/init";
 static char * const zone_prefix = "/zone/";
 
 static int zone_shutdown(zoneid_t zoneid);
@@ -338,8 +341,10 @@
  *     import of ZFS datasets to zones.
  * Version 4 alters the zone_create system call in order to support
  *     Trusted Extensions.
+ * Version 5 alters the zone_boot system call, and converts its old
+ *     bootargs parameter to be set by the zone_setattr API instead.
  */
-static const int ZONE_SYSCALL_API_VERSION = 4;
+static const int ZONE_SYSCALL_API_VERSION = 5;
 
 /*
  * Certain filesystems (such as NFS and autofs) need to know which zone
@@ -974,6 +979,7 @@
 	zone0.zone_ncpus = 0;
 	zone0.zone_ncpus_online = 0;
 	zone0.zone_proc_initpid = 1;
+	zone0.zone_initname = initname;
 	list_create(&zone0.zone_zsd, sizeof (struct zsd_entry),
 	    offsetof(struct zsd_entry, zsd_linkage));
 	list_insert_head(&zone_active, &zone0);
@@ -985,7 +991,7 @@
 	 */
 	zone0.zone_rootvp = NULL;
 	zone0.zone_vfslist = NULL;
-	zone0.zone_bootargs = NULL;
+	zone0.zone_bootargs = initargs;
 	zone0.zone_privset = kmem_alloc(sizeof (priv_set_t), KM_SLEEP);
 	/*
 	 * The global zone has all privileges
@@ -1207,7 +1213,9 @@
 	if (zone->zone_rctls != NULL)
 		rctl_set_free(zone->zone_rctls);
 	if (zone->zone_bootargs != NULL)
-		kmem_free(zone->zone_bootargs, ZONEBOOTARGS_MAX);
+		kmem_free(zone->zone_bootargs, strlen(zone->zone_bootargs) + 1);
+	if (zone->zone_initname != NULL)
+		kmem_free(zone->zone_initname, strlen(zone->zone_initname) + 1);
 	id_free(zoneid_space, zone->zone_id);
 	mutex_destroy(&zone->zone_lock);
 	cv_destroy(&zone->zone_cv);
@@ -1234,14 +1242,13 @@
 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) ||
 	    nvlist_add_string(nvl, ZONE_CB_NAME, zone->zone_name) ||
 	    nvlist_add_string(nvl, ZONE_CB_NEWSTATE,
-		zone_status_table[status]) ||
+	    zone_status_table[status]) ||
 	    nvlist_add_string(nvl, ZONE_CB_OLDSTATE,
-		zone_status_table[zone->zone_status]) ||
+	    zone_status_table[zone->zone_status]) ||
 	    nvlist_add_int32(nvl, ZONE_CB_ZONEID, zone->zone_id) ||
 	    nvlist_add_uint64(nvl, ZONE_CB_TIMESTAMP, (uint64_t)gethrtime()) ||
 	    sysevent_evc_publish(zone_event_chan, ZONE_EVENT_STATUS_CLASS,
-		ZONE_EVENT_STATUS_SUBCLASS,
-		"sun.com", "kernel", nvl, EVCH_SLEEP)) {
+	    ZONE_EVENT_STATUS_SUBCLASS, "sun.com", "kernel", nvl, EVCH_SLEEP)) {
 #ifdef DEBUG
 		(void) printf(
 		    "Failed to allocate and send zone state change event.\n");
@@ -1267,19 +1274,40 @@
 static int
 zone_set_bootargs(zone_t *zone, const char *zone_bootargs)
 {
-	char *bootargs = kmem_zalloc(ZONEBOOTARGS_MAX, KM_SLEEP);
+	char *bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
+	int err = 0;
+
+	ASSERT(zone != global_zone);
+	if ((err = copyinstr(zone_bootargs, bootargs, BOOTARGS_MAX, NULL)) != 0)
+		goto done;	/* EFAULT or ENAMETOOLONG */
+
+	if (zone->zone_bootargs != NULL)
+		kmem_free(zone->zone_bootargs, strlen(zone->zone_bootargs) + 1);
+
+	zone->zone_bootargs = kmem_alloc(strlen(bootargs) + 1, KM_SLEEP);
+	(void) strcpy(zone->zone_bootargs, bootargs);
+
+done:
+	kmem_free(bootargs, BOOTARGS_MAX);
+	return (err);
+}
+
+static int
+zone_set_initname(zone_t *zone, const char *zone_initname)
+{
+	char initname[INITNAME_SZ];
 	size_t len;
-	int err;
-
-	err = copyinstr(zone_bootargs, bootargs, ZONEBOOTARGS_MAX - 1, &len);
-	if (err != 0) {
-		kmem_free(bootargs, ZONEBOOTARGS_MAX);
+	int err = 0;
+
+	ASSERT(zone != global_zone);
+	if ((err = copyinstr(zone_initname, initname, INITNAME_SZ, &len)) != 0)
 		return (err);	/* EFAULT or ENAMETOOLONG */
-	}
-	bootargs[len] = '\0';
-
-	ASSERT(zone->zone_bootargs == NULL);
-	zone->zone_bootargs = bootargs;
+
+	if (zone->zone_initname != NULL)
+		kmem_free(zone->zone_initname, strlen(zone->zone_initname) + 1);
+
+	zone->zone_initname = kmem_alloc(strlen(initname) + 1, KM_SLEEP);
+	(void) strcpy(zone->zone_initname, initname);
 	return (0);
 }
 
@@ -2182,44 +2210,21 @@
 	return (0);
 }
 
+/*
+ * Non-global zone version of start_init.
+ */
 void
-zone_icode(void)
+zone_start_init(void)
 {
 	proc_t *p = ttoproc(curthread);
-	struct core_globals	*cg;
-
-	/*
-	 * For all purposes (ZONE_ATTR_INITPID and restart_init),
-	 * storing just the pid of init is sufficient.
-	 */
-	p->p_zone->zone_proc_initpid = p->p_pid;
+
+	ASSERT(!INGLOBALZONE(curproc));
 
 	/*
-	 * Allocate user address space and stack segment
+	 * We maintain zone_boot_err so that we can return the cause of the
+	 * failure back to the caller of the zone_boot syscall.
 	 */
-
-	p->p_cstime = p->p_stime = p->p_cutime = p->p_utime = 0;
-	p->p_usrstack = (caddr_t)USRSTACK32;
-	p->p_model = DATAMODEL_ILP32;
-	p->p_stkprot = PROT_ZFOD & ~PROT_EXEC;
-	p->p_datprot = PROT_ZFOD & ~PROT_EXEC;
-	p->p_stk_ctl = INT32_MAX;
-
-	p->p_as = as_alloc();
-	p->p_as->a_userlimit = (caddr_t)USERLIMIT32;
-	(void) hat_setup(p->p_as->a_hat, HAT_INIT);
-
-	cg = zone_getspecific(core_zone_key, p->p_zone);
-	ASSERT(cg != NULL);
-	corectl_path_hold(cg->core_default_path);
-	corectl_content_hold(cg->core_default_content);
-	p->p_corefile = cg->core_default_path;
-	p->p_content = cg->core_default_content;
-
-	init_mstate(curthread, LMS_SYSTEM);
-
-	p->p_zone->zone_boot_err = exec_init(zone_initname, 0,
-	    p->p_zone->zone_bootargs);
+	p->p_zone->zone_boot_err = start_init_common();
 
 	mutex_enter(&zone_status_lock);
 	if (p->p_zone->zone_boot_err != 0) {
@@ -2505,7 +2510,7 @@
 		 * state of the zone will be set to SHUTTING_DOWN-- userland
 		 * will have to tear down the zone, and fail, or try again.
 		 */
-		if ((zone->zone_boot_err = newproc(zone_icode, NULL, cid,
+		if ((zone->zone_boot_err = newproc(zone_start_init, NULL, cid,
 		    minclsyspri - 1, &ct)) != 0) {
 			mutex_enter(&zone_status_lock);
 			zone_status_set(zone, ZONE_IS_SHUTTING_DOWN);
@@ -2853,6 +2858,9 @@
 	zone->zone_domain[0] = '\0';
 	zone->zone_shares = 1;
 	zone->zone_bootargs = NULL;
+	zone->zone_initname =
+	    kmem_alloc(strlen(zone_default_initname) + 1, KM_SLEEP);
+	(void) strcpy(zone->zone_initname, zone_default_initname);
 
 	/*
 	 * Zsched initializes the rctls.
@@ -3076,10 +3084,12 @@
 
 /*
  * Cause the zone to boot.  This is pretty simple, since we let zoneadmd do
- * the heavy lifting.
+ * the heavy lifting.  initname is the path to the program to launch
+ * at the "top" of the zone; if this is NULL, we use the system default,
+ * which is stored at zone_default_initname.
  */
 static int
-zone_boot(zoneid_t zoneid, const char *bootargs)
+zone_boot(zoneid_t zoneid)
 {
 	int err;
 	zone_t *zone;
@@ -3099,11 +3109,6 @@
 		return (set_errno(EINVAL));
 	}
 
-	if ((err = zone_set_bootargs(zone, bootargs)) != 0) {
-		mutex_exit(&zonehash_lock);
-		return (set_errno(err));
-	}
-
 	mutex_enter(&zone_status_lock);
 	if (zone_status_get(zone) != ZONE_IS_READY) {
 		mutex_exit(&zone_status_lock);
@@ -3487,6 +3492,7 @@
 	int error = 0, err;
 	zone_t *zone;
 	char *zonepath;
+	char *outstr;
 	zone_status_t zone_status;
 	pid_t initpid;
 	boolean_t global = (curproc->p_zone == global_zone);
@@ -3550,7 +3556,7 @@
 				zonepath = kmem_alloc(size, KM_SLEEP);
 				bcopy(zone_prefix, zonepath, prefix_len);
 				bcopy(zone->zone_name, zonepath +
-					prefix_len, zname_len);
+				    prefix_len, zname_len);
 				zonepath[size - 1] = '\0';
 			}
 		}
@@ -3648,6 +3654,31 @@
 		    copyout(&initpid, buf, bufsize) != 0)
 			error = EFAULT;
 		break;
+	case ZONE_ATTR_INITNAME:
+		size = strlen(zone->zone_initname) + 1;
+		if (bufsize > size)
+			bufsize = size;
+		if (buf != NULL) {
+			err = copyoutstr(zone->zone_initname, buf, bufsize,
+			    NULL);
+			if (err != 0 && err != ENAMETOOLONG)
+				error = EFAULT;
+		}
+		break;
+	case ZONE_ATTR_BOOTARGS:
+		if (zone->zone_bootargs == NULL)
+			outstr = "";
+		else
+			outstr = zone->zone_bootargs;
+		size = strlen(outstr) + 1;
+		if (bufsize > size)
+			bufsize = size;
+		if (buf != NULL) {
+			err = copyoutstr(outstr, buf, bufsize, NULL);
+			if (err != 0 && err != ENAMETOOLONG)
+				error = EFAULT;
+		}
+		break;
 	default:
 		error = EINVAL;
 	}
@@ -3659,6 +3690,56 @@
 }
 
 /*
+ * Systemcall entry point for zone_setattr(2).
+ */
+/*ARGSUSED*/
+static int
+zone_setattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize)
+{
+	zone_t *zone;
+	zone_status_t zone_status;
+	int err;
+
+	if (secpolicy_zone_config(CRED()) != 0)
+		return (set_errno(EPERM));
+
+	/*
+	 * At present, attributes can only be set on non-running,
+	 * non-global zones.
+	 */
+	if (zoneid == GLOBAL_ZONEID) {
+		return (set_errno(EINVAL));
+	}
+
+	mutex_enter(&zonehash_lock);
+	if ((zone = zone_find_all_by_id(zoneid)) == NULL) {
+		mutex_exit(&zonehash_lock);
+		return (set_errno(EINVAL));
+	}
+	zone_hold(zone);
+	mutex_exit(&zonehash_lock);
+
+	zone_status = zone_status_get(zone);
+	if (zone_status > ZONE_IS_READY)
+		goto done;
+
+	switch (attr) {
+	case ZONE_ATTR_INITNAME:
+		err = zone_set_initname(zone, (const char *)buf);
+		break;
+	case ZONE_ATTR_BOOTARGS:
+		err = zone_set_bootargs(zone, (const char *)buf);
+		break;
+	default:
+		err = EINVAL;
+	}
+
+done:
+	zone_rele(zone);
+	return (err != 0 ? set_errno(err) : 0);
+}
+
+/*
  * Return zero if the process has at least one vnode mapped in to its
  * address space which shouldn't be allowed to change zones.
  */
@@ -4221,13 +4302,15 @@
 		    zs.extended_error, zs.match, zs.doi,
 		    zs.label));
 	case ZONE_BOOT:
-		return (zone_boot((zoneid_t)(uintptr_t)arg1,
-		    (const char *)arg2));
+		return (zone_boot((zoneid_t)(uintptr_t)arg1));
 	case ZONE_DESTROY:
 		return (zone_destroy((zoneid_t)(uintptr_t)arg1));
 	case ZONE_GETATTR:
 		return (zone_getattr((zoneid_t)(uintptr_t)arg1,
 		    (int)(uintptr_t)arg2, arg3, (size_t)arg4));
+	case ZONE_SETATTR:
+		return (zone_setattr((zoneid_t)(uintptr_t)arg1,
+		    (int)(uintptr_t)arg2, arg3, (size_t)arg4));
 	case ZONE_ENTER:
 		return (zone_enter((zoneid_t)(uintptr_t)arg1));
 	case ZONE_LIST:
@@ -4390,8 +4473,8 @@
 }
 
 /*
- * Entry point for uadmin() to tell the zone to go away or reboot.  The caller
- * is a process in the zone to be modified.
+ * Entry point for uadmin() to tell the zone to go away or reboot.  Analog to
+ * kadmin().  The caller is a process in the zone.
  *
  * In order to shutdown the zone, we will hand off control to zoneadmd
  * (running in the global zone) via a door.  We do a half-hearted job at
@@ -4401,7 +4484,7 @@
  * zone_destroy()) know exactly which zone they're re talking about.
  */
 int
-zone_uadmin(int cmd, int fcn, cred_t *credp)
+zone_kadmin(int cmd, int fcn, const char *mdep, cred_t *credp)
 {
 	struct zarg *zargp;
 	zone_cmd_t zcmd;
@@ -4445,6 +4528,7 @@
 	if (secpolicy_zone_admin(credp, B_FALSE))
 		return (EPERM);
 	mutex_enter(&zone_status_lock);
+
 	/*
 	 * zone_status can't be ZONE_IS_EMPTY or higher since curproc
 	 * is in the zone.
@@ -4474,11 +4558,16 @@
 	 * work.  This thread can't be created in our zone otherwise
 	 * zone_destroy() would deadlock.
 	 */
-	zargp = kmem_alloc(sizeof (*zargp), KM_SLEEP);
+	zargp = kmem_zalloc(sizeof (*zargp), KM_SLEEP);
 	zargp->arg.cmd = zcmd;
 	zargp->arg.uniqid = zone->zone_uniqid;
+	zargp->zone = zone;
 	(void) strcpy(zargp->arg.locale, "C");
-	zone_hold(zargp->zone = zone);
+	/* mdep was already copied in for us by uadmin */
+	if (mdep != NULL)
+		(void) strlcpy(zargp->arg.bootbuf, mdep,
+		    sizeof (zargp->arg.bootbuf));
+	zone_hold(zone);
 
 	(void) thread_create(NULL, 0, zone_ki_call_zoneadmd, zargp, 0, &p0,
 	    TS_RUN, minclsyspri);
--- a/usr/src/uts/common/sys/systm.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/sys/systm.h	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -24,7 +23,7 @@
 
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -59,6 +58,7 @@
 
 #ifdef _KERNEL
 #include <sys/varargs.h>
+#include <sys/uadmin.h>
 
 extern int hz;			/* system clock rate */
 extern struct vnode *rootdir;	/* pointer to vnode of root directory */
@@ -446,16 +446,21 @@
 
 
 /*
- * initname holds the path to init.  It is defined by main.c, may be set by
- * bootflags.c, and is used by main.c:exec_init().
+ * initname holds the path to init and is used as a point of rendezvous
+ * between krtld (which processes the boot arguments) and the kernel.
  */
 #define	INITNAME_SZ	32
-#define	INITARGS_SZ	80
+extern char initname[INITNAME_SZ];
 
-extern char initname[INITNAME_SZ];
-extern char initargs[INITARGS_SZ];
+/*
+ * initargs holds the arguments to init (such as -v, -s, -r, -m verbose) and
+ * is a point of rendezvous between krtld (which processes the boot arguments)
+ * and the kernel.
+ */
+extern char initargs[BOOTARGS_MAX];
 
-extern int exec_init(const char *, int, const char *);
+extern int exec_init(const char *, const char *);
+extern int start_init_common(void);
 
 #endif	/* _KERNEL */
 
--- a/usr/src/uts/common/sys/uadmin.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/sys/uadmin.h	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -76,6 +75,13 @@
 #define	AD_FTRACE_START	1
 #define	AD_FTRACE_STOP	2
 
+/*
+ * When 'mdep' (the second argument to uadmin(2)) is initialized for A_REBOOT,
+ * A_SHUTDOWN or A_DUMP, it represents the boot arguments string of at most
+ * 256 characters.
+ */
+#define	BOOTARGS_MAX	256
+
 #if !defined(_ASM)
 
 #if defined(_KERNEL)
--- a/usr/src/uts/common/sys/zone.h	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/sys/zone.h	Thu Jun 22 14:42:46 2006 -0700
@@ -34,6 +34,7 @@
 #include <sys/rctl.h>
 #include <sys/pset.h>
 #include <sys/tsol/label.h>
+#include <sys/uadmin.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -72,6 +73,7 @@
 #define	ZONE_LOOKUP	6
 #define	ZONE_BOOT	7
 #define	ZONE_VERSION	8
+#define	ZONE_SETATTR	9
 
 /* zone attributes */
 #define	ZONE_ATTR_ROOT		1
@@ -82,6 +84,8 @@
 #define	ZONE_ATTR_POOLID	6
 #define	ZONE_ATTR_INITPID	7
 #define	ZONE_ATTR_SLBL		8
+#define	ZONE_ATTR_INITNAME	9
+#define	ZONE_ATTR_BOOTARGS	10
 
 #define	ZONE_EVENT_CHANNEL	"com.sun:zones:status"
 #define	ZONE_EVENT_STATUS_CLASS	"status"
@@ -158,16 +162,15 @@
 	Z_MOUNT, Z_UNMOUNT
 } zone_cmd_t;
 
-#define	ZONEBOOTARGS_MAX	257	/* uadmin()'s buffer is 257 bytes. */
-
 /*
  * The structure of a request to zoneadmd.
  */
 typedef struct zone_cmd_arg {
 	uint64_t	uniqid;		/* unique "generation number" */
 	zone_cmd_t	cmd;		/* requested action */
+	uint32_t	_pad;		/* need consistent 32/64 bit alignmt */
 	char locale[MAXPATHLEN];	/* locale in which to render messages */
-	char bootbuf[ZONEBOOTARGS_MAX];	/* arguments passed to zone_boot() */
+	char bootbuf[BOOTARGS_MAX];	/* arguments passed to zone_boot() */
 } zone_cmd_arg_t;
 
 /*
@@ -276,6 +279,7 @@
 	kcondvar_t	zone_cv;	/* used to signal state changes */
 	struct proc	*zone_zsched;	/* Dummy kernel "zsched" process */
 	pid_t		zone_proc_initpid; /* pid of "init" for this zone */
+	char		*zone_initname;	/* fs path to 'init' */
 	int		zone_boot_err;  /* for zone_boot() if boot fails */
 	char		*zone_bootargs;	/* arguments passed via zone_boot() */
 	/*
@@ -310,6 +314,7 @@
 	ts_label_t	*zone_slabel;	/* zone sensitivity label */
 	int		zone_match;	/* require label match for packets */
 	tsol_mlp_list_t zone_mlps;	/* MLPs on zone-private addresses */
+
 } zone_t;
 
 /*
@@ -478,9 +483,9 @@
 extern int zone_dataset_visible(const char *, int *);
 
 /*
- * zone version of uadmin()
+ * zone version of kadmin()
  */
-extern int zone_uadmin(int, int, struct cred *);
+extern int zone_kadmin(int, int, const char *, cred_t *);
 extern void zone_shutdown_global(void);
 
 extern void mount_in_progress(void);
--- a/usr/src/uts/common/syscall/corectl.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/syscall/corectl.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,16 +50,16 @@
  * structure (the core dumping sub-system for example) to safely use the
  * string without holding any locks on it in light of updates.
  *
- * At system boot, init_core() sets init(1M)'s core file path and content to
- * the same value as the fields core_default_path and core_default_content
- * respectively (for the global zone). All subsequent children of init(1M)
- * reference those same settings. During boot coreadm(1M) is invoked with
- * the -u option to update the system settings from /etc/coreadm.conf. This
- * has the effect of also changing the values in core_default_path and
- * core_default_content which updates the core file settings for all
- * processes in the zone.  Each zone has different default settings; when
- * processes enter a non-global zone, their core file path and content are
- * set to the zone's default path and content.
+ * At system and zone boot, init_core() sets init(1M)'s core file path and
+ * content to the same value as the fields core_default_path and
+ * core_default_content respectively (for the global zone). All subsequent
+ * children of init(1M) reference those same settings. During boot coreadm(1M)
+ * is invoked with the -u option to update the system settings from
+ * /etc/coreadm.conf. This has the effect of also changing the values in
+ * core_default_path and core_default_content which updates the core file
+ * settings for all processes in the zone.  Each zone has different default
+ * settings; when processes enter a non-global zone, their core file path and
+ * content are set to the zone's default path and content.
  *
  * Processes that have their core file settings explicitly overridden using
  * coreadm(1M) no longer reference core_default_path or core_default_content
@@ -207,22 +206,28 @@
 }
 
 /*
- * Called once, from icode(), to set init's core file path and content.
+ * Called from start_init_common(), to set init's core file path and content.
  */
 void
 init_core(void)
 {
 	struct core_globals *cg;
 
-	zone_key_create(&core_zone_key, core_init_zone, NULL, core_free_zone);
+	/*
+	 * The first time we hit this, in the global zone, we have to
+	 * initialize the zsd key.
+	 */
+	if (INGLOBALZONE(curproc)) {
+		zone_key_create(&core_zone_key, core_init_zone, NULL,
+		    core_free_zone);
+	}
 
 	/*
 	 * zone_key_create will have called core_init_zone for the
 	 * global zone, which sets up the default path and content
 	 * variables.
 	 */
-	cg = zone_getspecific(core_zone_key, global_zone);
-	ASSERT(cg != NULL);
+	VERIFY((cg = zone_getspecific(core_zone_key, curproc->p_zone)) != NULL);
 
 	corectl_path_hold(cg->core_default_path);
 	corectl_content_hold(cg->core_default_content);
@@ -293,7 +298,7 @@
 				error = EFAULT;
 		} else {
 			error = copyoutstr(refstr_value(rp), (char *)arg1,
-					(size_t)arg2, NULL);
+			    (size_t)arg2, NULL);
 			refstr_rele(rp);
 		}
 		break;
--- a/usr/src/uts/common/syscall/uadmin.c	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/common/syscall/uadmin.c	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -108,8 +107,8 @@
 			} else {
 				sigtoproc(p, NULL, SIGKILL);
 				mutex_exit(&p->p_lock);
-				(void) cv_timedwait(&p->p_srwchan_cv,
-					    &pidlock, lbolt + hz);
+				(void) cv_timedwait(&p->p_srwchan_cv, &pidlock,
+				    lbolt + hz);
 				p = practive;
 			}
 		} else {
@@ -308,7 +307,7 @@
 
 		if ((mdep != NULL) && (*(char *)mdep == '/')) {
 			panic_bootstr = i_convert_boot_device_name(mdep,
-					    NULL, &buflen);
+			    NULL, &buflen);
 		} else
 			panic_bootstr = mdep;
 
@@ -331,8 +330,8 @@
 {
 	int error = 0, rv = 0;
 	size_t nbytes = 0;
-	char buf[257];
 	cred_t *credp = CRED();
+	char *bootargs = NULL;
 
 	/*
 	 * The swapctl system call doesn't have its own entry point: it uses
@@ -349,28 +348,28 @@
 	}
 
 	/*
-	 * Handle zones.
+	 * Certain subcommands intepret a non-NULL mdep value as a pointer to
+	 * a boot string.  We pull that in as bootargs, if applicable.
 	 */
-	if (getzoneid() != GLOBAL_ZONEID) {
-		error = zone_uadmin(cmd, fcn, credp);
-		return (error ? set_errno(error) : 0);
+	if (mdep != NULL &&
+	    (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP)) {
+		bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
+		if ((error = copyinstr((const char *)mdep, bootargs,
+		    BOOTARGS_MAX, &nbytes)) != 0) {
+			kmem_free(bootargs, BOOTARGS_MAX);
+			return (set_errno(error));
+		}
 	}
 
 	/*
-	 * Certain subcommands intepret a non-NULL mdep value as a pointer to
-	 * a boot string.  Attempt to copy it in now, or reset mdep to NULL.
+	 * Invoke the appropriate kadmin() routine.
 	 */
-	if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP) {
-		if (mdep != NULL && copyinstr((const char *)mdep, buf,
-		    sizeof (buf) - 1, &nbytes) == 0) {
-			buf[nbytes] = '\0';
-			mdep = (uintptr_t)buf;
-		} else
-			mdep = NULL;
-	}
+	if (getzoneid() != GLOBAL_ZONEID)
+		error = zone_kadmin(cmd, fcn, bootargs, credp);
+	else
+		error = kadmin(cmd, fcn, bootargs, credp);
 
-	if ((error = kadmin(cmd, fcn, (void *)mdep, credp)) != 0)
-		return (set_errno(error));
-
-	return (0);
+	if (bootargs != NULL)
+		kmem_free(bootargs, BOOTARGS_MAX);
+	return (error ? set_errno(error) : 0);
 }
--- a/usr/src/uts/intel/krtld/Makefile	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/intel/krtld/Makefile	Thu Jun 22 14:42:46 2006 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -97,6 +96,7 @@
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrcpy=$(MODULE)_strcpy
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrncpy=$(MODULE)_strncpy
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrcat=$(MODULE)_strcat
+$(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrlcat=$(MODULE)_strlcat
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrchr=$(MODULE)_strchr
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dbzero=$(MODULE)_bzero
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dbcopy=$(MODULE)_bcopy
--- a/usr/src/uts/sparc/krtld/Makefile	Thu Jun 22 14:42:22 2006 -0700
+++ b/usr/src/uts/sparc/krtld/Makefile	Thu Jun 22 14:42:46 2006 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -94,6 +94,7 @@
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrcpy=$(MODULE)_strcpy
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrncpy=$(MODULE)_strncpy
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrcat=$(MODULE)_strcat
+$(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrlcat=$(MODULE)_strlcat
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dstrchr=$(MODULE)_strchr
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dbzero=$(MODULE)_bzero
 $(OBJECTS) $(LINTS)	:= CPPFLAGS += -Dbcopy=$(MODULE)_bcopy