Home | History | Annotate | Download | only in zoneadmd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Console support for zones requires a significant infrastructure.  The
     29  * core pieces are contained in this file, but other portions of note
     30  * are in the zlogin(1M) command, the zcons(7D) driver, and in the
     31  * devfsadm(1M) misc_link generator.
     32  *
     33  * Care is taken to make the console behave in an "intuitive" fashion for
     34  * administrators.  Essentially, we try as much as possible to mimic the
     35  * experience of using a system via a tip line and system controller.
     36  *
     37  * The zone console architecture looks like this:
     38  *
     39  *                                      Global Zone | Non-Global Zone
     40  *                        .--------------.          |
     41  *        .-----------.   | zoneadmd -z  |          | .--------. .---------.
     42  *        | zlogin -C |   |     myzone   |          | | ttymon | | syslogd |
     43  *        `-----------'   `--------------'          | `--------' `---------'
     44  *                  |       |       | |             |      |       |
     45  *  User            |       |       | |             |      V       V
     46  * - - - - - - - - -|- - - -|- - - -|-|- - - - - - -|- - /dev/zconsole - - -
     47  *  Kernel          V       V       | |                        |
     48  *               [AF_UNIX Socket]   | `--------. .-------------'
     49  *                                  |          | |
     50  *                                  |          V V
     51  *                                  |     +-----------+
     52  *                                  |     |  ldterm,  |
     53  *                                  |     |   etc.    |
     54  *                                  |     +-----------+
     55  *                                  |     +-[Anchor]--+
     56  *                                  |     |   ptem    |
     57  *                                  V     +-----------+
     58  *                           +---master---+---slave---+
     59  *                           |                        |
     60  *                           |      zcons driver      |
     61  *                           |    zonename="myzone"   |
     62  *                           +------------------------+
     63  *
     64  * There are basically two major tasks which the console subsystem in
     65  * zoneadmd accomplishes:
     66  *
     67  * - Setup and teardown of zcons driver instances.  One zcons instance
     68  *   is maintained per zone; we take advantage of the libdevice APIs
     69  *   to online new instances of zcons as needed.  Care is taken to
     70  *   prune and manage these appropriately; see init_console_dev() and
     71  *   destroy_console_dev().  The end result is the creation of the
     72  *   zcons(7D) instance and an open file descriptor to the master side.
     73  *   zcons instances are associated with zones via their zonename device
     74  *   property.  This the console instance to persist across reboots,
     75  *   and while the zone is halted.
     76  *
     77  * - Acting as a server for 'zlogin -C' instances.  When zlogin -C is
     78  *   run, zlogin connects to zoneadmd via unix domain socket.  zoneadmd
     79  *   functions as a two-way proxy for console I/O, relaying user input
     80  *   to the master side of the console, and relaying output from the
     81  *   zone to the user.
     82  */
     83 
     84 #include <sys/types.h>
     85 #include <sys/socket.h>
     86 #include <sys/stat.h>
     87 #include <sys/termios.h>
     88 #include <sys/zcons.h>
     89 #include <sys/mkdev.h>
     90 
     91 #include <assert.h>
     92 #include <ctype.h>
     93 #include <errno.h>
     94 #include <fcntl.h>
     95 #include <stdarg.h>
     96 #include <stdio.h>
     97 #include <stdlib.h>
     98 #include <strings.h>
     99 #include <stropts.h>
    100 #include <thread.h>
    101 #include <ucred.h>
    102 #include <unistd.h>
    103 #include <zone.h>
    104 
    105 #include <libdevinfo.h>
    106 #include <libdevice.h>
    107 #include <libzonecfg.h>
    108 
    109 #include <syslog.h>
    110 #include <sys/modctl.h>
    111 
    112 #include "zoneadmd.h"
    113 
    114 #define	ZCONSNEX_DEVTREEPATH	"/pseudo/zconsnex@1"
    115 #define	ZCONSNEX_FILEPATH	"/devices/pseudo/zconsnex@1"
    116 
    117 #define	CONSOLE_SOCKPATH	ZONES_TMPDIR "/%s.console_sock"
    118 
    119 static int	serverfd = -1;	/* console server unix domain socket fd */
    120 char boot_args[BOOTARGS_MAX];
    121 char bad_boot_arg[BOOTARGS_MAX];
    122 
    123 /*
    124  * The eventstream is a simple one-directional flow of messages from the
    125  * door server to the console subsystem, implemented with a pipe.
    126  * It is used to wake up the console poller when it needs to take action,
    127  * message the user, die off, etc.
    128  */
    129 static int eventstream[2];
    130 
    131 
    132 
    133 int
    134 eventstream_init()
    135 {
    136 	if (pipe(eventstream) == -1)
    137 		return (-1);
    138 	return (0);
    139 }
    140 
    141 void
    142 eventstream_write(zone_evt_t evt)
    143 {
    144 	(void) write(eventstream[0], &evt, sizeof (evt));
    145 }
    146 
    147 static zone_evt_t
    148 eventstream_read(void)
    149 {
    150 	zone_evt_t evt = Z_EVT_NULL;
    151 
    152 	(void) read(eventstream[1], &evt, sizeof (evt));
    153 	return (evt);
    154 }
    155 
    156 /*
    157  * count_console_devs() and its helper count_cb() do a walk of the
    158  * subtree of the device tree where zone console nodes are represented.
    159  * The goal is to count zone console instances already setup for a zone
    160  * with the given name.  More than 1 is anomolous, and our caller will
    161  * have to deal with that if we find that's the case.
    162  *
    163  * Note: this algorithm is a linear search of nodes in the zconsnex subtree
    164  * of the device tree, and could be a scalability problem, but I don't see
    165  * how to avoid it.
    166  */
    167 
    168 /*
    169  * cb_data is shared by count_cb and destroy_cb for simplicity.
    170  */
    171 struct cb_data {
    172 	zlog_t *zlogp;
    173 	int found;
    174 	int killed;
    175 };
    176 
    177 static int
    178 count_cb(di_node_t node, void *arg)
    179 {
    180 	struct cb_data *cb = (struct cb_data *)arg;
    181 	char *prop_data;
    182 
    183 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
    184 	    &prop_data) != -1) {
    185 		assert(prop_data != NULL);
    186 		if (strcmp(prop_data, zone_name) == 0) {
    187 			cb->found++;
    188 			return (DI_WALK_CONTINUE);
    189 		}
    190 	}
    191 	return (DI_WALK_CONTINUE);
    192 }
    193 
    194 static int
    195 count_console_devs(zlog_t *zlogp)
    196 {
    197 	di_node_t root;
    198 	struct cb_data cb;
    199 
    200 	bzero(&cb, sizeof (cb));
    201 	cb.zlogp = zlogp;
    202 
    203 	if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
    204 	    DI_NODE_NIL) {
    205 		zerror(zlogp, B_TRUE, "%s failed", "di_init");
    206 		return (-1);
    207 	}
    208 
    209 	(void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, count_cb);
    210 	di_fini(root);
    211 	return (cb.found);
    212 }
    213 
    214 /*
    215  * destroy_console_devs() and its helper destroy_cb() tears down any console
    216  * instances associated with this zone.  If things went very wrong, we
    217  * might have more than one console instance hanging around.  This routine
    218  * hunts down and tries to remove all of them.  Of course, if the console
    219  * is open, the instance will not detach, which is a potential issue.
    220  */
    221 static int
    222 destroy_cb(di_node_t node, void *arg)
    223 {
    224 	struct cb_data *cb = (struct cb_data *)arg;
    225 	char *prop_data;
    226 	char *tmp;
    227 	char devpath[MAXPATHLEN];
    228 	devctl_hdl_t hdl;
    229 
    230 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
    231 	    &prop_data) == -1)
    232 		return (DI_WALK_CONTINUE);
    233 
    234 	assert(prop_data != NULL);
    235 	if (strcmp(prop_data, zone_name) != 0) {
    236 		/* this is the console for a different zone */
    237 		return (DI_WALK_CONTINUE);
    238 	}
    239 
    240 	cb->found++;
    241 	tmp = di_devfs_path(node);
    242 	(void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
    243 	di_devfs_path_free(tmp);
    244 
    245 	if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
    246 		zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
    247 		    "but it could not be controlled.", devpath);
    248 		return (DI_WALK_CONTINUE);
    249 	}
    250 	if (devctl_device_remove(hdl) == 0) {
    251 		cb->killed++;
    252 	} else {
    253 		zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
    254 		    "but it could not be removed.", devpath);
    255 	}
    256 	devctl_release(hdl);
    257 	return (DI_WALK_CONTINUE);
    258 }
    259 
    260 static int
    261 destroy_console_devs(zlog_t *zlogp)
    262 {
    263 	char conspath[MAXPATHLEN];
    264 	di_node_t root;
    265 	struct cb_data cb;
    266 	int masterfd;
    267 	int slavefd;
    268 
    269 	/*
    270 	 * Signal the master side to release its handle on the slave side by
    271 	 * issuing a ZC_RELEASESLAVE ioctl.
    272 	 */
    273 	(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
    274 	    zone_name, ZCONS_MASTER_NAME);
    275 	if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
    276 		(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
    277 		    zone_name, ZCONS_SLAVE_NAME);
    278 		if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
    279 			if (ioctl(masterfd, ZC_RELEASESLAVE,
    280 			    (caddr_t)(intptr_t)slavefd) != 0)
    281 				zerror(zlogp, B_TRUE, "WARNING: error while "
    282 				    "releasing slave handle of zone console for"
    283 				    " %s", zone_name);
    284 			(void) close(slavefd);
    285 		} else {
    286 			zerror(zlogp, B_TRUE, "WARNING: could not open slave "
    287 			    "side of zone console for %s to release slave "
    288 			    "handle", zone_name);
    289 		}
    290 		(void) close(masterfd);
    291 	} else {
    292 		zerror(zlogp, B_TRUE, "WARNING: could not open master side of "
    293 		    "zone console for %s to release slave handle", zone_name);
    294 	}
    295 
    296 	bzero(&cb, sizeof (cb));
    297 	cb.zlogp = zlogp;
    298 
    299 	if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
    300 	    DI_NODE_NIL) {
    301 		zerror(zlogp, B_TRUE, "%s failed", "di_init");
    302 		return (-1);
    303 	}
    304 
    305 	(void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
    306 	if (cb.found > 1) {
    307 		zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
    308 		    "instances detected for zone '%s'; %d of %d "
    309 		    "successfully removed.",
    310 		    zone_name, cb.killed, cb.found);
    311 	}
    312 
    313 	di_fini(root);
    314 	return (0);
    315 }
    316 
    317 /*
    318  * init_console_dev() drives the device-tree configuration of the zone
    319  * console device.  The general strategy is to use the libdevice (devctl)
    320  * interfaces to instantiate a new zone console node.  We do a lot of
    321  * sanity checking, and are careful to reuse a console if one exists.
    322  *
    323  * Once the device is in the device tree, we kick devfsadm via di_init_devs()
    324  * to ensure that the appropriate symlinks (to the master and slave console
    325  * devices) are placed in /dev in the global zone.
    326  */
    327 static int
    328 init_console_dev(zlog_t *zlogp)
    329 {
    330 	char conspath[MAXPATHLEN];
    331 	devctl_hdl_t bus_hdl = NULL;
    332 	devctl_hdl_t dev_hdl = NULL;
    333 	devctl_ddef_t ddef_hdl = NULL;
    334 	di_devlink_handle_t dl = NULL;
    335 	int rv = -1;
    336 	int ndevs;
    337 	int masterfd;
    338 	int slavefd;
    339 
    340 	/*
    341 	 * Don't re-setup console if it is working and ready already; just
    342 	 * skip ahead to making devlinks, which we do for sanity's sake.
    343 	 */
    344 	ndevs = count_console_devs(zlogp);
    345 	if (ndevs == 1) {
    346 		goto devlinks;
    347 	} else if (ndevs > 1 || ndevs == -1) {
    348 		/*
    349 		 * For now, this seems like a reasonable but harsh punishment.
    350 		 * If needed, we could try to get clever and delete all but
    351 		 * the console which is pointed at by the current symlink.
    352 		 */
    353 		if (destroy_console_devs(zlogp) == -1) {
    354 			goto error;
    355 		}
    356 	}
    357 
    358 	/*
    359 	 * Time to make the consoles!
    360 	 */
    361 	if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) {
    362 		zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire");
    363 		goto error;
    364 	}
    365 	if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) {
    366 		zerror(zlogp, B_TRUE, "failed to allocate ddef handle");
    367 		goto error;
    368 	}
    369 	/*
    370 	 * Set three properties on this node; the first is the name of the
    371 	 * zone; the second is a flag which lets pseudo know that it is
    372 	 * OK to automatically allocate an instance # for this device;
    373 	 * the third tells the device framework not to auto-detach this
    374 	 * node-- we need the node to still be there when we ask devfsadmd
    375 	 * to make links, and when we need to open it.
    376 	 */
    377 	if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) {
    378 		zerror(zlogp, B_TRUE, "failed to create zonename property");
    379 		goto error;
    380 	}
    381 	if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) {
    382 		zerror(zlogp, B_TRUE, "failed to create auto-assign-instance "
    383 		    "property");
    384 		goto error;
    385 	}
    386 	if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
    387 		zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
    388 		    "property");
    389 		goto error;
    390 	}
    391 	if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
    392 		zerror(zlogp, B_TRUE, "failed to create console node");
    393 		goto error;
    394 	}
    395 
    396 devlinks:
    397 	if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
    398 		(void) di_devlink_fini(&dl);
    399 	} else {
    400 		zerror(zlogp, B_TRUE, "failed to create devlinks");
    401 		goto error;
    402 	}
    403 
    404 	/*
    405 	 * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
    406 	 * which will cause the master to retain a reference to the slave.
    407 	 * This prevents ttymon from blowing through the slave's STREAMS anchor.
    408 	 */
    409 	(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
    410 	    zone_name, ZCONS_MASTER_NAME);
    411 	if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
    412 		zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
    413 		    "zone console for %s to acquire slave handle", zone_name);
    414 		goto error;
    415 	}
    416 	(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
    417 	    zone_name, ZCONS_SLAVE_NAME);
    418 	if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
    419 		zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
    420 		    " console for %s to acquire slave handle", zone_name);
    421 		(void) close(masterfd);
    422 		goto error;
    423 	}
    424 	if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd) == 0)
    425 		rv = 0;
    426 	else
    427 		zerror(zlogp, B_TRUE, "ERROR: error while acquiring slave "
    428 		    "handle of zone console for %s", zone_name);
    429 	(void) close(slavefd);
    430 	(void) close(masterfd);
    431 
    432 error:
    433 	if (ddef_hdl)
    434 		devctl_ddef_free(ddef_hdl);
    435 	if (bus_hdl)
    436 		devctl_release(bus_hdl);
    437 	if (dev_hdl)
    438 		devctl_release(dev_hdl);
    439 	return (rv);
    440 }
    441 
    442 static int
    443 init_console_sock(zlog_t *zlogp)
    444 {
    445 	int servfd;
    446 	struct sockaddr_un servaddr;
    447 
    448 	bzero(&servaddr, sizeof (servaddr));
    449 	servaddr.sun_family = AF_UNIX;
    450 	(void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
    451 	    CONSOLE_SOCKPATH, zone_name);
    452 
    453 	if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    454 		zerror(zlogp, B_TRUE, "console setup: could not create socket");
    455 		return (-1);
    456 	}
    457 	(void) unlink(servaddr.sun_path);
    458 
    459 	if (bind(servfd, (struct sockaddr *)&servaddr,
    460 	    sizeof (servaddr)) == -1) {
    461 		zerror(zlogp, B_TRUE,
    462 		    "console setup: could not bind to socket");
    463 		goto out;
    464 	}
    465 
    466 	if (listen(servfd, 4) == -1) {
    467 		zerror(zlogp, B_TRUE,
    468 		    "console setup: could not listen on socket");
    469 		goto out;
    470 	}
    471 	return (servfd);
    472 
    473 out:
    474 	(void) unlink(servaddr.sun_path);
    475 	(void) close(servfd);
    476 	return (-1);
    477 }
    478 
    479 static void
    480 destroy_console_sock(int servfd)
    481 {
    482 	char path[MAXPATHLEN];
    483 
    484 	(void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
    485 	(void) unlink(path);
    486 	(void) shutdown(servfd, SHUT_RDWR);
    487 	(void) close(servfd);
    488 }
    489 
    490 /*
    491  * Read the "ident" string from the client's descriptor; this routine also
    492  * tolerates being called with pid=NULL, for times when you want to "eat"
    493  * the ident string from a client without saving it.
    494  */
    495 static int
    496 get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len)
    497 {
    498 	char buf[BUFSIZ], *bufp;
    499 	size_t buflen = sizeof (buf);
    500 	char c = '\0';
    501 	int i = 0, r;
    502 
    503 	/* "eat up the ident string" case, for simplicity */
    504 	if (pid == NULL) {
    505 		assert(locale == NULL && locale_len == 0);
    506 		while (read(clifd, &c, 1) == 1) {
    507 			if (c == '\n')
    508 				return (0);
    509 		}
    510 	}
    511 
    512 	bzero(buf, sizeof (buf));
    513 	while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
    514 		buflen--;
    515 		if (c == '\n')
    516 			break;
    517 
    518 		buf[i] = c;
    519 		i++;
    520 	}
    521 	if (r == -1)
    522 		return (-1);
    523 
    524 	/*
    525 	 * We've filled the buffer, but still haven't seen \n.  Keep eating
    526 	 * until we find it; we don't expect this to happen, but this is
    527 	 * defensive.
    528 	 */
    529 	if (c != '\n') {
    530 		while ((r = read(clifd, &c, sizeof (c))) > 0)
    531 			if (c == '\n')
    532 				break;
    533 	}
    534 
    535 	/*
    536 	 * Parse buffer for message of the form: IDENT <pid> <locale>
    537 	 */
    538 	bufp = buf;
    539 	if (strncmp(bufp, "IDENT ", 6) != 0)
    540 		return (-1);
    541 	bufp += 6;
    542 	errno = 0;
    543 	*pid = strtoll(bufp, &bufp, 10);
    544 	if (errno != 0)
    545 		return (-1);
    546 
    547 	while (*bufp != '\0' && isspace(*bufp))
    548 		bufp++;
    549 	(void) strlcpy(locale, bufp, locale_len);
    550 
    551 	return (0);
    552 }
    553 
    554 static int
    555 accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len)
    556 {
    557 	int connfd;
    558 	struct sockaddr_un cliaddr;
    559 	socklen_t clilen;
    560 
    561 	clilen = sizeof (cliaddr);
    562 	connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
    563 	if (connfd == -1)
    564 		return (-1);
    565 	if (get_client_ident(connfd, pid, locale, locale_len) == -1) {
    566 		(void) shutdown(connfd, SHUT_RDWR);
    567 		(void) close(connfd);
    568 		return (-1);
    569 	}
    570 	(void) write(connfd, "OK\n", 3);
    571 	return (connfd);
    572 }
    573 
    574 static void
    575 reject_client(int servfd, pid_t clientpid)
    576 {
    577 	int connfd;
    578 	struct sockaddr_un cliaddr;
    579 	socklen_t clilen;
    580 	char nak[MAXPATHLEN];
    581 
    582 	clilen = sizeof (cliaddr);
    583 	connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
    584 
    585 	/*
    586 	 * After hear its ident string, tell client to get lost.
    587 	 */
    588 	if (get_client_ident(connfd, NULL, NULL, 0) == 0) {
    589 		(void) snprintf(nak, sizeof (nak), "%lu\n",
    590 		    clientpid);
    591 		(void) write(connfd, nak, strlen(nak));
    592 	}
    593 	(void) shutdown(connfd, SHUT_RDWR);
    594 	(void) close(connfd);
    595 }
    596 
    597 static void
    598 event_message(int clifd, char *clilocale, zone_evt_t evt)
    599 {
    600 	char *str, *lstr = NULL;
    601 	char lmsg[BUFSIZ];
    602 	char outbuf[BUFSIZ];
    603 
    604 	if (clifd == -1)
    605 		return;
    606 
    607 	switch (evt) {
    608 	case Z_EVT_ZONE_BOOTING:
    609 		if (*boot_args == '\0') {
    610 			str = "NOTICE: Zone booting up";
    611 			break;
    612 		}
    613 		/*LINTED*/
    614 		(void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
    615 		    "NOTICE: Zone booting up with arguments: %s"), boot_args);
    616 		lstr = lmsg;
    617 		break;
    618 	case Z_EVT_ZONE_READIED:
    619 		str = "NOTICE: Zone readied";
    620 		break;
    621 	case Z_EVT_ZONE_HALTED:
    622 		str = "NOTICE: Zone halted";
    623 		break;
    624 	case Z_EVT_ZONE_REBOOTING:
    625 		if (*boot_args == '\0') {
    626 			str = "NOTICE: Zone rebooting";
    627 			break;
    628 		}
    629 		/*LINTED*/
    630 		(void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
    631 		    "NOTICE: Zone rebooting with arguments: %s"), boot_args);
    632 		lstr = lmsg;
    633 		break;
    634 	case Z_EVT_ZONE_UNINSTALLING:
    635 		str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
    636 		break;
    637 	case Z_EVT_ZONE_BOOTFAILED:
    638 		str = "NOTICE: Zone boot failed";
    639 		break;
    640 	case Z_EVT_ZONE_BADARGS:
    641 		/*LINTED*/
    642 		(void) snprintf(lmsg, sizeof (lmsg),
    643 		    localize_msg(clilocale,
    644 		    "WARNING: Ignoring invalid boot arguments: %s"),
    645 		    bad_boot_arg);
    646 		lstr = lmsg;
    647 		break;
    648 	default:
    649 		return;
    650 	}
    651 
    652 	if (lstr == NULL)
    653 		lstr = localize_msg(clilocale, str);
    654 	(void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
    655 	(void) write(clifd, outbuf, strlen(outbuf));
    656 }
    657 
    658 /*
    659  * Check to see if the client at the other end of the socket is still
    660  * alive; we know it is not if it throws EPIPE at us when we try to write
    661  * an otherwise harmless 0-length message to it.
    662  */
    663 static int
    664 test_client(int clifd)
    665 {
    666 	if ((write(clifd, "", 0) == -1) && errno == EPIPE)
    667 		return (-1);
    668 	return (0);
    669 }
    670 
    671 /*
    672  * This routine drives the console I/O loop.  It polls for input from the
    673  * master side of the console (output to the console), and from the client
    674  * (input from the console user).  Additionally, it polls on the server fd,
    675  * and disconnects any clients that might try to hook up with the zone while
    676  * the console is in use.
    677  *
    678  * When the client first calls us up, it is expected to send a line giving
    679  * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
    680  * This is so that we can report that the console is busy along with
    681  * some diagnostics about who has it busy; the locale is used so that
    682  * asynchronous messages about zone state (like the NOTICE: zone halted
    683  * messages) can be output in the user's locale.
    684  */
    685 static void
    686 do_console_io(zlog_t *zlogp, int consfd, int servfd)
    687 {
    688 	struct pollfd pollfds[4];
    689 	char ibuf[BUFSIZ];
    690 	int cc, ret;
    691 	int clifd = -1;
    692 	int pollerr = 0;
    693 	char clilocale[MAXPATHLEN];
    694 	pid_t clipid = 0;
    695 
    696 	/* console side, watch for read events */
    697 	pollfds[0].fd = consfd;
    698 	pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
    699 	    POLLPRI | POLLERR | POLLHUP | POLLNVAL;
    700 
    701 	/* client side, watch for read events */
    702 	pollfds[1].fd = clifd;
    703 	pollfds[1].events = pollfds[0].events;
    704 
    705 	/* the server socket; watch for events (new connections) */
    706 	pollfds[2].fd = servfd;
    707 	pollfds[2].events = pollfds[0].events;
    708 
    709 	/* the eventstram; watch for events (e.g.: zone halted) */
    710 	pollfds[3].fd = eventstream[1];
    711 	pollfds[3].events = pollfds[0].events;
    712 
    713 	for (;;) {
    714 		pollfds[0].revents = pollfds[1].revents = 0;
    715 		pollfds[2].revents = pollfds[3].revents = 0;
    716 
    717 		ret = poll(pollfds,
    718 		    sizeof (pollfds) / sizeof (struct pollfd), -1);
    719 		if (ret == -1 && errno != EINTR) {
    720 			zerror(zlogp, B_TRUE, "poll failed");
    721 			/* we are hosed, close connection */
    722 			break;
    723 		}
    724 
    725 		/* event from console side */
    726 		if (pollfds[0].revents) {
    727 			if (pollfds[0].revents &
    728 			    (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
    729 				errno = 0;
    730 				cc = read(consfd, ibuf, BUFSIZ);
    731 				if (cc <= 0 && (errno != EINTR) &&
    732 				    (errno != EAGAIN))
    733 					break;
    734 				/*
    735 				 * Lose I/O if no one is listening
    736 				 */
    737 				if (clifd != -1 && cc > 0)
    738 					(void) write(clifd, ibuf, cc);
    739 			} else {
    740 				pollerr = pollfds[0].revents;
    741 				zerror(zlogp, B_FALSE,
    742 				    "closing connection with (console) "
    743 				    "pollerr %d\n", pollerr);
    744 				break;
    745 			}
    746 		}
    747 
    748 		/* event from client side */
    749 		if (pollfds[1].revents) {
    750 			if (pollfds[1].revents &
    751 			    (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
    752 				errno = 0;
    753 				cc = read(clifd, ibuf, BUFSIZ);
    754 				if (cc <= 0 && (errno != EINTR) &&
    755 				    (errno != EAGAIN))
    756 					break;
    757 				(void) write(consfd, ibuf, cc);
    758 			} else {
    759 				pollerr = pollfds[1].revents;
    760 				zerror(zlogp, B_FALSE,
    761 				    "closing connection with (client) "
    762 				    "pollerr %d\n", pollerr);
    763 				break;
    764 			}
    765 		}
    766 
    767 		/* event from server socket */
    768 		if (pollfds[2].revents &&
    769 		    (pollfds[2].revents & (POLLIN | POLLRDNORM))) {
    770 			if (clifd != -1) {
    771 				/*
    772 				 * Test the client to see if it is really
    773 				 * still alive.  If it has died but we
    774 				 * haven't yet detected that, we might
    775 				 * deny a legitimate connect attempt.  If it
    776 				 * is dead, we break out; once we tear down
    777 				 * the old connection, the new connection
    778 				 * will happen.
    779 				 */
    780 				if (test_client(clifd) == -1) {
    781 					break;
    782 				}
    783 				/* we're already handling a client */
    784 				reject_client(servfd, clipid);
    785 
    786 
    787 			} else if ((clifd = accept_client(servfd, &clipid,
    788 			    clilocale, sizeof (clilocale))) != -1) {
    789 				pollfds[1].fd = clifd;
    790 
    791 			} else {
    792 				break;
    793 			}
    794 		}
    795 
    796 		/*
    797 		 * Watch for events on the eventstream.  This is how we get
    798 		 * notified of the zone halting, etc.  It provides us a
    799 		 * "wakeup" from poll when important things happen, which
    800 		 * is good.
    801 		 */
    802 		if (pollfds[3].revents) {
    803 			int evt = eventstream_read();
    804 			/*
    805 			 * After we drain out the event, if we aren't servicing
    806 			 * a console client, we hop back out to our caller,
    807 			 * which will check to see if it is time to shutdown
    808 			 * the daemon, or if we should take another console
    809 			 * service lap.
    810 			 */
    811 			if (clifd == -1) {
    812 				break;
    813 			}
    814 			event_message(clifd, clilocale, evt);
    815 			/*
    816 			 * Special handling for the message that the zone is
    817 			 * uninstalling; we boot the client, then break out
    818 			 * of this function.  When we return to the
    819 			 * serve_console loop, we will see that the zone is
    820 			 * in a state < READY, and so zoneadmd will shutdown.
    821 			 */
    822 			if (evt == Z_EVT_ZONE_UNINSTALLING) {
    823 				break;
    824 			}
    825 		}
    826 
    827 	}
    828 
    829 	if (clifd != -1) {
    830 		(void) shutdown(clifd, SHUT_RDWR);
    831 		(void) close(clifd);
    832 	}
    833 }
    834 
    835 int
    836 init_console(zlog_t *zlogp)
    837 {
    838 	if (init_console_dev(zlogp) == -1) {
    839 		zerror(zlogp, B_FALSE,
    840 		    "console setup: device initialization failed");
    841 		return (-1);
    842 	}
    843 
    844 	if ((serverfd = init_console_sock(zlogp)) == -1) {
    845 		zerror(zlogp, B_FALSE,
    846 		    "console setup: socket initialization failed");
    847 		return (-1);
    848 	}
    849 	return (0);
    850 }
    851 
    852 /*
    853  * serve_console() is the master loop for driving console I/O.  It is also the
    854  * routine which is ultimately responsible for "pulling the plug" on zoneadmd
    855  * when it realizes that the daemon should shut down.
    856  *
    857  * The rules for shutdown are: there must be no console client, and the zone
    858  * state must be < ready.  However, we need to give things a chance to actually
    859  * get going when the daemon starts up-- otherwise the daemon would immediately
    860  * exit on startup if the zone was in the installed state, so we first drop
    861  * into the do_console_io() loop in order to give *something* a chance to
    862  * happen.
    863  */
    864 void
    865 serve_console(zlog_t *zlogp)
    866 {
    867 	int masterfd;
    868 	zone_state_t zstate;
    869 	char conspath[MAXPATHLEN];
    870 
    871 	(void) snprintf(conspath, sizeof (conspath),
    872 	    "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
    873 
    874 	for (;;) {
    875 		masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
    876 		if (masterfd == -1) {
    877 			zerror(zlogp, B_TRUE, "failed to open console master");
    878 			(void) mutex_lock(&lock);
    879 			goto death;
    880 		}
    881 
    882 		/*
    883 		 * Setting RPROTDIS on the stream means that the control
    884 		 * portion of messages received (which we don't care about)
    885 		 * will be discarded by the stream head.  If we allowed such
    886 		 * messages, we wouldn't be able to use read(2), as it fails
    887 		 * (EBADMSG) when a message with a control element is received.
    888 		 */
    889 		if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
    890 			zerror(zlogp, B_TRUE, "failed to set options on "
    891 			    "console master");
    892 			(void) mutex_lock(&lock);
    893 			goto death;
    894 		}
    895 
    896 		do_console_io(zlogp, masterfd, serverfd);
    897 
    898 		/*
    899 		 * We would prefer not to do this, but hostile zone processes
    900 		 * can cause the stream to become tainted, and reads will
    901 		 * fail.  So, in case something has gone seriously ill,
    902 		 * we dismantle the stream and reopen the console when we
    903 		 * take another lap.
    904 		 */
    905 		(void) close(masterfd);
    906 
    907 		(void) mutex_lock(&lock);
    908 		/*
    909 		 * We need to set death_throes (see below) atomically with
    910 		 * respect to noticing that (a) we have no console client and
    911 		 * (b) the zone is not installed.  Otherwise we could get a
    912 		 * request to boot during this time.  Once we set death_throes,
    913 		 * any incoming door stuff will be turned away.
    914 		 */
    915 		if (zone_get_state(zone_name, &zstate) == Z_OK) {
    916 			if (zstate < ZONE_STATE_READY)
    917 				goto death;
    918 		} else {
    919 			zerror(zlogp, B_FALSE,
    920 			    "unable to determine state of zone");
    921 			goto death;
    922 		}
    923 		/*
    924 		 * Even if zone_get_state() fails, stay conservative, and
    925 		 * take another lap.
    926 		 */
    927 		(void) mutex_unlock(&lock);
    928 	}
    929 
    930 death:
    931 	assert(MUTEX_HELD(&lock));
    932 	in_death_throes = B_TRUE;
    933 	(void) mutex_unlock(&lock);
    934 
    935 	destroy_console_sock(serverfd);
    936 	(void) destroy_console_devs(zlogp);
    937 }
    938