xref: /titanic_50/usr/src/cmd/zoneadmd/zcons.c (revision 7a286c471efbab8562f7655a82931904703fffe0)
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