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