--- /dev/null	2014-01-14 16:17:11.000000000 +0000
+++ new/usr/src/lib/brand/lx/lx_support/lx_support.c	2014-01-14 16:17:11.408104705 +0000
@@ -0,0 +1,592 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * lx_support is a small cli utility used to perform some brand-specific
+ * tasks when booting, halting, or verifying a zone.  This utility is not
+ * intended to be called by users - it is intended to be invoked by the
+ * zones utilities.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stropts.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <libzonecfg.h>
+#include <sys/lx_audio.h>
+#include <sys/lx_brand.h>
+
+static void lxs_err(char *msg, ...) __NORETURN;
+static void usage(void) __NORETURN;
+
+#define	CP_CMD		"/usr/bin/cp"
+#define	MOUNT_CMD	"/sbin/mount"
+
+#define	LXA_AUDIO_DEV		"/dev/brand/lx/audio_devctl"
+#define	INTSTRLEN		32
+#define	KVSTRLEN		10
+
+static char *bname = NULL;
+static char *zonename = NULL;
+static char *zoneroot = NULL;
+
+#if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
+#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
+#endif
+
+static void
+lxs_err(char *msg, ...)
+{
+	char	buf[1024];
+	va_list	ap;
+
+	va_start(ap, msg);
+	/*LINTED*/
+	(void) vsnprintf(buf, sizeof (buf), msg, ap);
+	va_end(ap);
+
+	(void) printf("%s error: %s\n", bname, buf);
+
+	exit(1);
+	/*NOTREACHED*/
+}
+
+/*
+ * The Linux init(1M) command requires communication over the /dev/initctl
+ * FIFO.  Since any attempt to create a file in /dev will fail, we must
+ * create it here.
+ */
+static void
+lxs_make_initctl()
+{
+	char		cmdbuf[ARG_MAX];
+	char		path[MAXPATHLEN];
+	char		special[MAXPATHLEN];
+	struct stat	buf;
+	int		err;
+
+	if (snprintf(special, sizeof (special), "%s/dev/initctl", zoneroot) >=
+	    sizeof (special))
+		lxs_err("%s: %s", gettext("Failed to create /dev/initctl"),
+		    gettext("zoneroot is too long"));
+
+	if (snprintf(path, sizeof (path), "%s/root/dev/initctl", zoneroot) >=
+	    sizeof (path))
+		lxs_err("%s: %s", gettext("Failed to create /dev/initctl"),
+		    gettext("zoneroot is too long"));
+
+	/* create the actual fifo as <zoneroot>/dev/initctl */
+	if (stat(special, &buf) != 0) {
+		err = errno;
+		if (err != ENOENT)
+			lxs_err("%s: %s",
+			    gettext("Failed to create /dev/initctl"),
+			    strerror(err));
+		if (mkfifo(special, 0644) < 0) {
+			err = errno;
+			lxs_err("%s: %s",
+			    gettext("Failed to create /dev/initctl"),
+			    strerror(err));
+		}
+	} else {
+		if ((buf.st_mode & S_IFIFO) == 0)
+			lxs_err("%s: %s",
+			    gettext("Failed to create /dev/initctl"),
+			    gettext("It already exists, and is not a FIFO."));
+	}
+
+	/*
+	 * now lofs mount the <zoneroot>/dev/initctl fifo onto
+	 * <zoneroot>/root/dev/initctl
+	 */
+	if (snprintf(cmdbuf, sizeof (cmdbuf), "%s -F lofs %s %s", MOUNT_CMD,
+	    special, path) >= sizeof (cmdbuf))
+		lxs_err("%s: %s", gettext("Failed to lofs mount /dev/initctl"),
+		    gettext("zoneroot is too long"));
+
+	if (system(cmdbuf) < 0) {
+		err = errno;
+		lxs_err("%s: %s", gettext("Failed to lofs mount /dev/initctl"),
+		    strerror(err));
+	}
+}
+
+/*
+ * fsck gets really confused when run inside a zone.  Removing this file
+ * prevents it from running
+ */
+static void
+lxs_remove_autofsck()
+{
+	char	path[MAXPATHLEN];
+	int	err;
+
+	if (snprintf(path, MAXPATHLEN, "%s/root/.autofsck", zoneroot) >=
+	    MAXPATHLEN)
+		lxs_err("%s: %s", gettext("Failed to remove /.autofsck"),
+		    gettext("zoneroot is too long"));
+
+	if (unlink(path) < 0) {
+		err = errno;
+		if (err != ENOENT)
+			lxs_err("%s: %s",
+			    gettext("Failed to remove /.autofsck"),
+			    strerror(err));
+	}
+}
+
+/*
+ * Extract any lx-supported attributes from the zone configuration file.
+ */
+static void
+lxs_getattrs(zone_dochandle_t zdh, boolean_t *restart, boolean_t *audio,
+    char **idev, char **odev, char **kvers)
+{
+	struct zone_attrtab	attrtab;
+	int			err;
+
+	/* initialize the attribute iterator */
+	if (zonecfg_setattrent(zdh) != Z_OK) {
+		zonecfg_fini_handle(zdh);
+		lxs_err(gettext("error accessing zone configuration"));
+	}
+
+	*idev = (char *)malloc(INTSTRLEN);
+	*odev = (char *)malloc(INTSTRLEN);
+	*kvers = (char *)malloc(KVSTRLEN);
+	if (*idev == NULL || *odev == NULL || *kvers == NULL)
+		lxs_err(gettext("out of memory"));
+
+	*audio = B_FALSE;
+	*restart = B_FALSE;
+	bzero(*idev, INTSTRLEN);
+	bzero(*odev, INTSTRLEN);
+	bzero(*kvers, KVSTRLEN);
+	while ((err = zonecfg_getattrent(zdh, &attrtab)) == Z_OK) {
+		if ((strcmp(attrtab.zone_attr_name, "init-restart") == 0) &&
+		    (zonecfg_get_attr_boolean(&attrtab, restart) != Z_OK))
+			lxs_err(gettext("invalid type for zone attribute: %s"),
+			    attrtab.zone_attr_name);
+		if ((strcmp(attrtab.zone_attr_name, "audio") == 0) &&
+		    (zonecfg_get_attr_boolean(&attrtab, audio) != Z_OK))
+			lxs_err(gettext("invalid type for zone attribute: %s"),
+			    attrtab.zone_attr_name);
+		if ((strcmp(attrtab.zone_attr_name, "audio-inputdev") == 0) &&
+		    (zonecfg_get_attr_string(&attrtab, *idev,
+		    INTSTRLEN) != Z_OK))
+			lxs_err(gettext("invalid type for zone attribute: %s"),
+			    attrtab.zone_attr_name);
+		if ((strcmp(attrtab.zone_attr_name, "audio-outputdev") == 0) &&
+		    (zonecfg_get_attr_string(&attrtab, *odev,
+		    INTSTRLEN) != Z_OK))
+			lxs_err(gettext("invalid type for zone attribute: %s"),
+			    attrtab.zone_attr_name);
+		if ((strcmp(attrtab.zone_attr_name, "kernel-version") == 0) &&
+		    (zonecfg_get_attr_string(&attrtab, *kvers,
+		    KVSTRLEN) != Z_OK))
+			lxs_err(gettext("invalid type for zone attribute: %s"),
+			    attrtab.zone_attr_name);
+	}
+
+	if (strlen(*kvers) == 0) {
+		free(*kvers);
+		*kvers = NULL;
+	}
+
+	/* some kind of error while looking up attributes */
+	if (err != Z_NO_ENTRY)
+		lxs_err(gettext("error accessing zone configuration"));
+}
+
+static int
+lxs_iodev_ok(char *dev)
+{
+	int i, j;
+
+	if ((j = strlen(dev)) == 0)
+		return (1);
+	if (strcmp(dev, "default") == 0)
+		return (1);
+	if (strcmp(dev, "none") == 0)
+		return (1);
+	for (i = 0; i < j; i++) {
+		if (!isdigit(dev[i]))
+			return (0);
+	}
+	return (1);
+}
+
+/*
+ * The audio configuration settings are read from the zone configuration
+ * file.  Audio configuration is specified via the following attributes
+ * (settable via zonecfg):
+ * 	attr name: audio
+ * 	attr type: boolean
+ *
+ * 	attr name: audio-inputdev
+ * 	attr type: string
+ * 	attr values: "none" | [0-9]+
+ *
+ * 	attr name: audio-outputdev
+ * 	attr type: string
+ * 	attr values: "none" | [0-9]+
+ *
+ * The user can enable linux brand audio device (ie /dev/dsp and /dev/mixer)
+ * for a zone by setting the "audio" attribute to true.  (The absence of
+ * this attribute leads to an assumed value of false.)
+ *
+ * If the "audio" attribute is set to true and "audio-inputdev" and
+ * "audio-outputdev" are not set, then when a linux applications access
+ * audio devices these access will be mapped to the system default audio
+ * device, ie /dev/audio and/dev/audioctl.
+ *
+ * If "audio-inputdev" is set to none, then audio input will be disabled.
+ * If "audio-inputdev" is set to an integer, then when a Linux application
+ * attempts to access audio devices these access will be mapped to
+ * /dev/sound/<audio-inputdev attribute value>.  The same behavior will
+ * apply to the "audio-outputdev" attribute for linux audio output
+ * device accesses.
+ *
+ * If "audio-inputdev" or "audio-outputdev" exist but the audio attribute
+ * is missing (or set to false) audio will not be enabled for the zone.
+ */
+static void
+lxs_init_audio(char *idev, char *odev)
+{
+	int			err, fd;
+	lxa_zone_reg_t		lxa_zr;
+
+	/* sanity check the input and output device properties */
+	if (!lxs_iodev_ok(idev))
+		lxs_err(gettext("invalid value for zone attribute: %s"),
+		    "audio-inputdev");
+
+	if (!lxs_iodev_ok(odev))
+		lxs_err(gettext("invalid value for zone attribute: %s"),
+		    "audio-outputdev");
+
+	/* initialize the zone name in the ioctl request */
+	bzero(&lxa_zr, sizeof (lxa_zr));
+	(void) strlcpy(lxa_zr.lxa_zr_zone_name, zonename,
+	    sizeof (lxa_zr.lxa_zr_zone_name));
+
+	/* initialize the input device property in the ioctl request */
+	(void) strlcpy(lxa_zr.lxa_zr_inputdev, idev,
+	    sizeof (lxa_zr.lxa_zr_inputdev));
+	if (lxa_zr.lxa_zr_inputdev[0] == '\0') {
+		/*
+		 * if no input device was specified, set the input device
+		 * to "default"
+		 */
+		(void) strlcpy(lxa_zr.lxa_zr_inputdev, "default",
+		    sizeof (lxa_zr.lxa_zr_inputdev));
+	}
+
+	/* initialize the output device property in the ioctl request */
+	(void) strlcpy(lxa_zr.lxa_zr_outputdev, odev,
+	    sizeof (lxa_zr.lxa_zr_outputdev));
+	if (lxa_zr.lxa_zr_outputdev[0] == '\0') {
+		/*
+		 * if no output device was specified, set the output device
+		 * to "default"
+		 */
+		(void) strlcpy(lxa_zr.lxa_zr_outputdev, "default",
+		    sizeof (lxa_zr.lxa_zr_outputdev));
+	}
+
+	/* open the audio device control node */
+	if ((fd = open(LXA_AUDIO_DEV, O_RDWR)) < 0)
+		lxs_err(gettext("error accessing lx_audio device"));
+
+	/* enable audio for this zone */
+	err = ioctl(fd, LXA_IOC_ZONE_REG, &lxa_zr);
+	(void) close(fd);
+	if (err != 0)
+		lxs_err(gettext("error configuring lx_audio device"));
+}
+
+static int
+lxs_boot()
+{
+	zoneid_t	zoneid;
+	zone_dochandle_t zdh;
+	boolean_t	audio, restart;
+	char		*idev, *odev, *kvers;
+	int		kversnum;
+
+	lxs_make_initctl();
+	lxs_remove_autofsck();
+
+	if ((zdh = zonecfg_init_handle()) == NULL)
+		lxs_err(gettext("unable to initialize zone handle"));
+
+	if (zonecfg_get_handle((char *)zonename, zdh) != Z_OK) {
+		zonecfg_fini_handle(zdh);
+		lxs_err(gettext("unable to load zone configuration"));
+	}
+
+	/* Extract any relevant attributes from the config file. */
+	lxs_getattrs(zdh, &restart, &audio, &idev, &odev, &kvers);
+	zonecfg_fini_handle(zdh);
+
+	/* Configure the zone's audio support (if any). */
+	if (audio == B_TRUE)
+		lxs_init_audio(idev, odev);
+
+	/*
+	 * Let the kernel know whether or not this zone's init process
+	 * should be automatically restarted on its death.
+	 */
+	if ((zoneid = getzoneidbyname(zonename)) < 0)
+		lxs_err(gettext("unable to get zoneid"));
+	if (zone_setattr(zoneid, LX_ATTR_RESTART_INIT, &restart,
+	    sizeof (boolean_t)) == -1)
+		lxs_err(gettext("error setting zone's restart_init property"));
+
+	if ((kvers != NULL) && (strcmp(kvers, "2.6") == 0))
+		kversnum = LX_KERN_2_6;
+	else
+		kversnum = LX_KERN_2_4;
+
+	if (zone_setattr(zoneid, LX_KERN_VERSION_NUM, &kversnum,
+	    sizeof (int)) < 0)
+		lxs_err(gettext("unable to set kernel version"));
+
+	return (0);
+}
+
+static int
+lxs_halt()
+{
+	lxa_zone_reg_t	lxa_zr;
+	int		fd, rv;
+
+	/*
+	 * We don't bother to check if audio is configured for this zone
+	 * before issuing a request to unconfigure it.  There's no real
+	 * reason to do this, it would require looking up the xml zone and
+	 * brand configuration information (which could have been changed
+	 * since the zone was booted), and it would involve more library
+	 * calls there by increasing chances for failure.
+	 */
+
+	/* initialize the zone name in the ioctl request */
+	bzero(&lxa_zr, sizeof (lxa_zr));
+	(void) strlcpy(lxa_zr.lxa_zr_zone_name, zonename,
+	    sizeof (lxa_zr.lxa_zr_zone_name));
+
+	/* open the audio device control node */
+	if ((fd = open(LXA_AUDIO_DEV, O_RDWR)) < 0)
+		lxs_err(gettext("error accessing lx_audio device"));
+
+	/*
+	 * disable audio for this zone
+	 *
+	 * we ignore ENOENT errors here because it's possible that
+	 * audio is not configured for this zone.  (either it was
+	 * already unconfigured or someone could have added the
+	 * audio resource to this zone after it was booted.)
+	 */
+	rv = ioctl(fd, LXA_IOC_ZONE_UNREG, &lxa_zr);
+	(void) close(fd);
+	if ((rv == 0) || (errno == ENOENT))
+		return (0);
+	lxs_err(gettext("error unconfiguring lx_audio device: %s"),
+	    strerror(errno));
+	/*NOTREACHED*/
+}
+
+static int
+lxs_verify(char *xmlfile)
+{
+	zone_dochandle_t	handle;
+/*	struct zone_fstab	fstab; */
+	struct zone_dstab	dstab;
+	struct zone_devtab	devtab;
+	boolean_t		audio, restart;
+	char			*idev, *odev, *kvers;
+	zone_iptype_t		iptype;
+	char			hostidp[HW_HOSTID_LEN];
+
+	if ((handle = zonecfg_init_handle()) == NULL)
+		lxs_err(gettext("internal libzonecfg.so.1 error"), 0);
+
+	if (zonecfg_get_xml_handle(xmlfile, handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	/*
+	 * Check to see whether the zone has any inherit-pkg-dirs
+	 * configured.
+	 */
+/*	if (zonecfg_setipdent(handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	if (zonecfg_getipdent(handle, &fstab) == Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support inherit-pkg-dirs"));
+	}
+*/
+	/*
+	 * Check to see whether the zone has any ZFS datasets configured.
+	 */
+	if (zonecfg_setdsent(handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	if (zonecfg_getdsent(handle, &dstab) == Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support ZFS datasets"));
+	}
+
+	/*
+	 * Check to see whether the zone has any devices configured.
+	 */
+	if (zonecfg_setdevent(handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	if (zonecfg_getdevent(handle, &devtab) == Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support added devices"));
+	}
+
+	/*
+	 * Check to see whether the zone has ip-type configured as exclusive
+	 */
+	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	if (iptype == ZS_EXCLUSIVE) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support an 'exclusive' "
+		    "ip-type"));
+	}
+
+	/*
+	 * Check to see whether the zone has hostid emulation enabled.
+	 */
+	if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support hostid emulation"));
+	}
+
+	/* Extract any relevant attributes from the config file. */
+	lxs_getattrs(handle, &restart, &audio, &idev, &odev, &kvers);
+	zonecfg_fini_handle(handle);
+
+	if (audio) {
+		/* sanity check the input and output device properties */
+		if (!lxs_iodev_ok(idev))
+			lxs_err(gettext("invalid value for zone attribute: %s"),
+			    "audio-inputdev");
+
+		if (!lxs_iodev_ok(odev))
+			lxs_err(gettext("invalid value for zone attribute: %s"),
+			    "audio-outputdev");
+	}
+	if (kvers) {
+		if ((strcmp(kvers, "2.4")) != 0 && (strcmp(kvers, "2.6") != 0))
+			lxs_err(gettext("invalid value for zone attribute: %s"),
+			    "kernel-version");
+	}
+	return (0);
+}
+
+static void
+usage()
+{
+
+	(void) fprintf(stderr,
+	    gettext("usage:\t%s boot <zoneroot> <zonename>\n"), bname);
+	(void) fprintf(stderr,
+	    gettext("      \t%s halt <zoneroot> <zonename>\n"), bname);
+	(void) fprintf(stderr,
+	    gettext("      \t%s verify <xml file>\n\n"), bname);
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+
+	bname = basename(argv[0]);
+
+	if (argc < 3)
+		usage();
+
+	if (strcmp(argv[1], "boot") == 0) {
+		if (argc != 4)
+			lxs_err(gettext("usage: %s %s <zoneroot> <zonename>"),
+			    bname, argv[1]);
+		zoneroot = argv[2];
+		zonename = argv[3];
+		return (lxs_boot());
+	}
+
+	if (strcmp(argv[1], "halt") == 0) {
+		if (argc != 4)
+			lxs_err(gettext("usage: %s %s <zoneroot> <zonename>"),
+			    bname, argv[1]);
+		zoneroot = argv[2];
+		zonename = argv[3];
+		return (lxs_halt());
+	}
+
+	if (strcmp(argv[1], "verify") == 0) {
+		if (argc != 3)
+			lxs_err(gettext("usage: %s verify <xml file>"),
+			    bname);
+		return (lxs_verify(argv[2]));
+	}
+
+	usage();
+	/*NOTREACHED*/
+}
