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 two 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 * - Acting as a server for 'zlogin -C' instances. When zlogin -C is
80 * run, zlogin connects to zoneadmd via unix domain socket. zoneadmd
81 * functions as a two-way proxy for console I/O, relaying user input
82 * to the master side of the console, and relaying output from the
83 * zone to the user.
84 */
85
86 #include <sys/types.h>
87 #include <sys/socket.h>
88 #include <sys/stat.h>
89 #include <sys/termios.h>
90 #include <sys/zcons.h>
91 #include <sys/mkdev.h>
92
93 #include <assert.h>
94 #include <ctype.h>
95 #include <errno.h>
96 #include <fcntl.h>
97 #include <stdarg.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <strings.h>
101 #include <stropts.h>
102 #include <thread.h>
248 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
249 "but it could not be controlled.", devpath);
250 return (DI_WALK_CONTINUE);
251 }
252 if (devctl_device_remove(hdl) == 0) {
253 cb->killed++;
254 } else {
255 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
256 "but it could not be removed.", devpath);
257 }
258 devctl_release(hdl);
259 return (DI_WALK_CONTINUE);
260 }
261
262 static int
263 destroy_console_devs(zlog_t *zlogp)
264 {
265 char conspath[MAXPATHLEN];
266 di_node_t root;
267 struct cb_data cb;
268 int masterfd;
269 int slavefd;
270
271 /*
272 * Signal the master side to release its handle on the slave side by
273 * issuing a ZC_RELEASESLAVE ioctl.
274 */
275 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
276 zone_name, ZCONS_MASTER_NAME);
277 if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
278 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
279 zone_name, ZCONS_SLAVE_NAME);
280 if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
281 if (ioctl(masterfd, ZC_RELEASESLAVE,
282 (caddr_t)(intptr_t)slavefd) != 0)
283 zerror(zlogp, B_TRUE, "WARNING: error while "
284 "releasing slave handle of zone console for"
285 " %s", zone_name);
286 (void) close(slavefd);
287 } else {
288 zerror(zlogp, B_TRUE, "WARNING: could not open slave "
289 "side of zone console for %s to release slave "
290 "handle", zone_name);
291 }
292 (void) close(masterfd);
293 } else {
294 zerror(zlogp, B_TRUE, "WARNING: could not open master side of "
295 "zone console for %s to release slave handle", zone_name);
296 }
297
298 bzero(&cb, sizeof (cb));
299 cb.zlogp = zlogp;
300
301 if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
302 DI_NODE_NIL) {
303 zerror(zlogp, B_TRUE, "%s failed", "di_init");
304 return (-1);
305 }
306
307 (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
308 if (cb.found > 1) {
309 zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
310 "instances detected for zone '%s'; %d of %d "
311 "successfully removed.",
312 zone_name, cb.killed, cb.found);
313 }
314
315 di_fini(root);
316 return (0);
317 }
318
319 /*
320 * init_console_dev() drives the device-tree configuration of the zone
321 * console device. The general strategy is to use the libdevice (devctl)
322 * interfaces to instantiate a new zone console node. We do a lot of
323 * sanity checking, and are careful to reuse a console if one exists.
324 *
325 * Once the device is in the device tree, we kick devfsadm via di_init_devs()
326 * to ensure that the appropriate symlinks (to the master and slave console
327 * devices) are placed in /dev in the global zone.
328 */
329 static int
330 init_console_dev(zlog_t *zlogp)
331 {
332 char conspath[MAXPATHLEN];
333 devctl_hdl_t bus_hdl = NULL;
334 devctl_hdl_t dev_hdl = NULL;
335 devctl_ddef_t ddef_hdl = NULL;
336 di_devlink_handle_t dl = NULL;
337 int rv = -1;
338 int ndevs;
339 int masterfd;
340 int slavefd;
341 int i;
342
343 /*
344 * Don't re-setup console if it is working and ready already; just
345 * skip ahead to making devlinks, which we do for sanity's sake.
346 */
347 ndevs = count_console_devs(zlogp);
348 if (ndevs == 1) {
349 goto devlinks;
350 } else if (ndevs > 1 || ndevs == -1) {
351 /*
352 * For now, this seems like a reasonable but harsh punishment.
353 * If needed, we could try to get clever and delete all but
354 * the console which is pointed at by the current symlink.
355 */
356 if (destroy_console_devs(zlogp) == -1) {
357 goto error;
358 }
359 }
360
388 }
389 if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
390 zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
391 "property");
392 goto error;
393 }
394 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
395 zerror(zlogp, B_TRUE, "failed to create console node");
396 goto error;
397 }
398
399 devlinks:
400 if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
401 (void) di_devlink_fini(&dl);
402 } else {
403 zerror(zlogp, B_TRUE, "failed to create devlinks");
404 goto error;
405 }
406
407 /*
408 * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
409 * which will cause the master to retain a reference to the slave.
410 * This prevents ttymon from blowing through the slave's STREAMS anchor.
411 */
412 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
413 zone_name, ZCONS_MASTER_NAME);
414 if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
415 zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
416 "zone console for %s to acquire slave handle", zone_name);
417 goto error;
418 }
419 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
420 zone_name, ZCONS_SLAVE_NAME);
421 if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
422 zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
423 " console for %s to acquire slave handle", zone_name);
424 (void) close(masterfd);
425 goto error;
426 }
427 /*
428 * This ioctl can occasionally return ENXIO if devfs doesn't have
429 * everything plumbed up yet due to heavy zone startup load. Wait for
430 * 1 sec. and retry a few times before we fail to boot the zone.
431 */
432 for (i = 0; i < 5; i++) {
433 if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd)
434 == 0) {
435 rv = 0;
436 break;
437 } else if (errno != ENXIO) {
438 break;
439 }
440 (void) sleep(1);
441 }
442 if (rv != 0)
443 zerror(zlogp, B_TRUE, "ERROR: error while acquiring slave "
444 "handle of zone console for %s", zone_name);
445
446 (void) close(slavefd);
447 (void) close(masterfd);
448
449 error:
450 if (ddef_hdl)
451 devctl_ddef_free(ddef_hdl);
452 if (bus_hdl)
453 devctl_release(bus_hdl);
454 if (dev_hdl)
455 devctl_release(dev_hdl);
456 return (rv);
457 }
458
459 static int
460 init_console_sock(zlog_t *zlogp)
461 {
462 int servfd;
463 struct sockaddr_un servaddr;
464
465 bzero(&servaddr, sizeof (servaddr));
466 servaddr.sun_family = AF_UNIX;
467 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
683 lstr = localize_msg(clilocale, str);
684 (void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
685 (void) write(clifd, outbuf, strlen(outbuf));
686 }
687
688 /*
689 * Check to see if the client at the other end of the socket is still
690 * alive; we know it is not if it throws EPIPE at us when we try to write
691 * an otherwise harmless 0-length message to it.
692 */
693 static int
694 test_client(int clifd)
695 {
696 if ((write(clifd, "", 0) == -1) && errno == EPIPE)
697 return (-1);
698 return (0);
699 }
700
701 /*
702 * This routine drives the console I/O loop. It polls for input from the
703 * master side of the console (output to the console), and from the client
704 * (input from the console user). Additionally, it polls on the server fd,
705 * and disconnects any clients that might try to hook up with the zone while
706 * the console is in use.
707 *
708 * When the client first calls us up, it is expected to send a line giving
709 * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
710 * This is so that we can report that the console is busy along with
711 * some diagnostics about who has it busy; the locale is used so that
712 * asynchronous messages about zone state (like the NOTICE: zone halted
713 * messages) can be output in the user's locale.
714 */
715 static void
716 do_console_io(zlog_t *zlogp, int consfd, int servfd)
717 {
718 struct pollfd pollfds[4];
719 char ibuf[BUFSIZ];
720 int cc, ret;
721 int clifd = -1;
722 int pollerr = 0;
723 char clilocale[MAXPATHLEN];
887 return (-1);
888 }
889 return (0);
890 }
891
892 /*
893 * serve_console() is the master loop for driving console I/O. It is also the
894 * routine which is ultimately responsible for "pulling the plug" on zoneadmd
895 * when it realizes that the daemon should shut down.
896 *
897 * The rules for shutdown are: there must be no console client, and the zone
898 * state must be < ready. However, we need to give things a chance to actually
899 * get going when the daemon starts up-- otherwise the daemon would immediately
900 * exit on startup if the zone was in the installed state, so we first drop
901 * into the do_console_io() loop in order to give *something* a chance to
902 * happen.
903 */
904 void
905 serve_console(zlog_t *zlogp)
906 {
907 int masterfd;
908 zone_state_t zstate;
909 char conspath[MAXPATHLEN];
910
911 (void) snprintf(conspath, sizeof (conspath),
912 "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
913
914 for (;;) {
915 masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
916 if (masterfd == -1) {
917 zerror(zlogp, B_TRUE, "failed to open console master");
918 (void) mutex_lock(&lock);
919 goto death;
920 }
921
922 /*
923 * Setting RPROTDIS on the stream means that the control
924 * portion of messages received (which we don't care about)
925 * will be discarded by the stream head. If we allowed such
926 * messages, we wouldn't be able to use read(2), as it fails
927 * (EBADMSG) when a message with a control element is received.
928 */
929 if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
930 zerror(zlogp, B_TRUE, "failed to set options on "
931 "console master");
932 (void) mutex_lock(&lock);
933 goto death;
934 }
935
936 do_console_io(zlogp, masterfd, serverfd);
937
938 /*
939 * We would prefer not to do this, but hostile zone processes
940 * can cause the stream to become tainted, and reads will
941 * fail. So, in case something has gone seriously ill,
942 * we dismantle the stream and reopen the console when we
943 * take another lap.
944 */
945 (void) close(masterfd);
946
947 (void) mutex_lock(&lock);
948 /*
949 * We need to set death_throes (see below) atomically with
950 * respect to noticing that (a) we have no console client and
951 * (b) the zone is not installed. Otherwise we could get a
952 * request to boot during this time. Once we set death_throes,
953 * any incoming door stuff will be turned away.
954 */
955 if (zone_get_state(zone_name, &zstate) == Z_OK) {
956 if (zstate < ZONE_STATE_READY)
957 goto death;
958 } else {
959 zerror(zlogp, B_FALSE,
960 "unable to determine state of zone");
961 goto death;
962 }
963 /*
964 * Even if zone_get_state() fails, stay conservative, and
965 * take another lap.
|
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 * +---manager--+-subsidiary+
61 * | |
62 * | zcons driver |
63 * | zonename="myzone" |
64 * +------------------------+
65 *
66 * There are basically two 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 manager 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 * - Acting as a server for 'zlogin -C' instances. When zlogin -C is
80 * run, zlogin connects to zoneadmd via unix domain socket. zoneadmd
81 * functions as a two-way proxy for console I/O, relaying user input
82 * to the manager side of the console, and relaying output from the
83 * zone to the user.
84 */
85
86 #include <sys/types.h>
87 #include <sys/socket.h>
88 #include <sys/stat.h>
89 #include <sys/termios.h>
90 #include <sys/zcons.h>
91 #include <sys/mkdev.h>
92
93 #include <assert.h>
94 #include <ctype.h>
95 #include <errno.h>
96 #include <fcntl.h>
97 #include <stdarg.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <strings.h>
101 #include <stropts.h>
102 #include <thread.h>
248 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
249 "but it could not be controlled.", devpath);
250 return (DI_WALK_CONTINUE);
251 }
252 if (devctl_device_remove(hdl) == 0) {
253 cb->killed++;
254 } else {
255 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
256 "but it could not be removed.", devpath);
257 }
258 devctl_release(hdl);
259 return (DI_WALK_CONTINUE);
260 }
261
262 static int
263 destroy_console_devs(zlog_t *zlogp)
264 {
265 char conspath[MAXPATHLEN];
266 di_node_t root;
267 struct cb_data cb;
268 int managerfd;
269 int subfd;
270
271 /*
272 * Signal the manager side to release its handle on the subsidiary side
273 * by issuing a ZC_RELEASESUBSID ioctl.
274 */
275 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
276 zone_name, ZCONS_MANAGER_NAME);
277 if ((managerfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
278 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
279 zone_name, ZCONS_SUBSIDIARY_NAME);
280 if ((subfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
281 if (ioctl(managerfd, ZC_RELEASESUBSID,
282 (caddr_t)(intptr_t)subfd) != 0)
283 zerror(zlogp, B_TRUE, "WARNING: error while "
284 "releasing subsidiary handle of zone "
285 "console for %s", zone_name);
286 (void) close(subfd);
287 } else {
288 zerror(zlogp, B_TRUE, "WARNING: could not open "
289 "subsidiary side of zone console for %s to "
290 "release subsidiary handle", zone_name);
291 }
292 (void) close(managerfd);
293 } else {
294 zerror(zlogp, B_TRUE, "WARNING: could not open manager side of "
295 "zone console for %s to release subsidiary handle",
296 zone_name);
297 }
298
299 bzero(&cb, sizeof (cb));
300 cb.zlogp = zlogp;
301
302 if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
303 DI_NODE_NIL) {
304 zerror(zlogp, B_TRUE, "%s failed", "di_init");
305 return (-1);
306 }
307
308 (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
309 if (cb.found > 1) {
310 zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
311 "instances detected for zone '%s'; %d of %d "
312 "successfully removed.",
313 zone_name, cb.killed, cb.found);
314 }
315
316 di_fini(root);
317 return (0);
318 }
319
320 /*
321 * init_console_dev() drives the device-tree configuration of the zone
322 * console device. The general strategy is to use the libdevice (devctl)
323 * interfaces to instantiate a new zone console node. We do a lot of
324 * sanity checking, and are careful to reuse a console if one exists.
325 *
326 * Once the device is in the device tree, we kick devfsadm via di_init_devs()
327 * to ensure that the appropriate symlinks (to the manager and subsidiary
328 * console devices) are placed in /dev in the global zone.
329 */
330 static int
331 init_console_dev(zlog_t *zlogp)
332 {
333 char conspath[MAXPATHLEN];
334 devctl_hdl_t bus_hdl = NULL;
335 devctl_hdl_t dev_hdl = NULL;
336 devctl_ddef_t ddef_hdl = NULL;
337 di_devlink_handle_t dl = NULL;
338 int rv = -1;
339 int ndevs;
340 int managerfd;
341 int subfd;
342 int i;
343
344 /*
345 * Don't re-setup console if it is working and ready already; just
346 * skip ahead to making devlinks, which we do for sanity's sake.
347 */
348 ndevs = count_console_devs(zlogp);
349 if (ndevs == 1) {
350 goto devlinks;
351 } else if (ndevs > 1 || ndevs == -1) {
352 /*
353 * For now, this seems like a reasonable but harsh punishment.
354 * If needed, we could try to get clever and delete all but
355 * the console which is pointed at by the current symlink.
356 */
357 if (destroy_console_devs(zlogp) == -1) {
358 goto error;
359 }
360 }
361
389 }
390 if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
391 zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
392 "property");
393 goto error;
394 }
395 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
396 zerror(zlogp, B_TRUE, "failed to create console node");
397 goto error;
398 }
399
400 devlinks:
401 if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
402 (void) di_devlink_fini(&dl);
403 } else {
404 zerror(zlogp, B_TRUE, "failed to create devlinks");
405 goto error;
406 }
407
408 /*
409 * Open the manager side of the console and issue the ZC_HOLDSUBSID
410 * ioctl, which will cause the manager to retain a reference to the
411 * subsidiary. This prevents ttymon from blowing through the
412 * subsidiary's STREAMS anchor.
413 */
414 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
415 zone_name, ZCONS_MANAGER_NAME);
416 if ((managerfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
417 zerror(zlogp, B_TRUE, "ERROR: could not open manager side of "
418 "zone console for %s to acquire subsidiary handle",
419 zone_name);
420 goto error;
421 }
422 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
423 zone_name, ZCONS_SUBSIDIARY_NAME);
424 if ((subfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
425 zerror(zlogp, B_TRUE, "ERROR: could not open subsidiary side "
426 "of zone console for %s to acquire subsidiary handle",
427 zone_name);
428 (void) close(managerfd);
429 goto error;
430 }
431 /*
432 * This ioctl can occasionally return ENXIO if devfs doesn't have
433 * everything plumbed up yet due to heavy zone startup load. Wait for
434 * 1 sec. and retry a few times before we fail to boot the zone.
435 */
436 for (i = 0; i < 5; i++) {
437 if (ioctl(managerfd, ZC_HOLDSUBSID, (caddr_t)(intptr_t)subfd)
438 == 0) {
439 rv = 0;
440 break;
441 } else if (errno != ENXIO) {
442 break;
443 }
444 (void) sleep(1);
445 }
446 if (rv != 0)
447 zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
448 "subsidiary handle of zone console for %s", zone_name);
449
450 (void) close(subfd);
451 (void) close(managerfd);
452
453 error:
454 if (ddef_hdl)
455 devctl_ddef_free(ddef_hdl);
456 if (bus_hdl)
457 devctl_release(bus_hdl);
458 if (dev_hdl)
459 devctl_release(dev_hdl);
460 return (rv);
461 }
462
463 static int
464 init_console_sock(zlog_t *zlogp)
465 {
466 int servfd;
467 struct sockaddr_un servaddr;
468
469 bzero(&servaddr, sizeof (servaddr));
470 servaddr.sun_family = AF_UNIX;
471 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
687 lstr = localize_msg(clilocale, str);
688 (void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
689 (void) write(clifd, outbuf, strlen(outbuf));
690 }
691
692 /*
693 * Check to see if the client at the other end of the socket is still
694 * alive; we know it is not if it throws EPIPE at us when we try to write
695 * an otherwise harmless 0-length message to it.
696 */
697 static int
698 test_client(int clifd)
699 {
700 if ((write(clifd, "", 0) == -1) && errno == EPIPE)
701 return (-1);
702 return (0);
703 }
704
705 /*
706 * This routine drives the console I/O loop. It polls for input from the
707 * manager side of the console (output to the console), and from the client
708 * (input from the console user). Additionally, it polls on the server fd,
709 * and disconnects any clients that might try to hook up with the zone while
710 * the console is in use.
711 *
712 * When the client first calls us up, it is expected to send a line giving
713 * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
714 * This is so that we can report that the console is busy along with
715 * some diagnostics about who has it busy; the locale is used so that
716 * asynchronous messages about zone state (like the NOTICE: zone halted
717 * messages) can be output in the user's locale.
718 */
719 static void
720 do_console_io(zlog_t *zlogp, int consfd, int servfd)
721 {
722 struct pollfd pollfds[4];
723 char ibuf[BUFSIZ];
724 int cc, ret;
725 int clifd = -1;
726 int pollerr = 0;
727 char clilocale[MAXPATHLEN];
891 return (-1);
892 }
893 return (0);
894 }
895
896 /*
897 * serve_console() is the master loop for driving console I/O. It is also the
898 * routine which is ultimately responsible for "pulling the plug" on zoneadmd
899 * when it realizes that the daemon should shut down.
900 *
901 * The rules for shutdown are: there must be no console client, and the zone
902 * state must be < ready. However, we need to give things a chance to actually
903 * get going when the daemon starts up-- otherwise the daemon would immediately
904 * exit on startup if the zone was in the installed state, so we first drop
905 * into the do_console_io() loop in order to give *something* a chance to
906 * happen.
907 */
908 void
909 serve_console(zlog_t *zlogp)
910 {
911 int managerfd;
912 zone_state_t zstate;
913 char conspath[MAXPATHLEN];
914
915 (void) snprintf(conspath, sizeof (conspath),
916 "/dev/zcons/%s/%s", zone_name, ZCONS_MANAGER_NAME);
917
918 for (;;) {
919 managerfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
920 if (managerfd == -1) {
921 zerror(zlogp, B_TRUE, "failed to open console manager");
922 (void) mutex_lock(&lock);
923 goto death;
924 }
925
926 /*
927 * Setting RPROTDIS on the stream means that the control
928 * portion of messages received (which we don't care about)
929 * will be discarded by the stream head. If we allowed such
930 * messages, we wouldn't be able to use read(2), as it fails
931 * (EBADMSG) when a message with a control element is received.
932 */
933 if (ioctl(managerfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
934 zerror(zlogp, B_TRUE, "failed to set options on "
935 "console manager");
936 (void) mutex_lock(&lock);
937 goto death;
938 }
939
940 do_console_io(zlogp, managerfd, serverfd);
941
942 /*
943 * We would prefer not to do this, but hostile zone processes
944 * can cause the stream to become tainted, and reads will
945 * fail. So, in case something has gone seriously ill,
946 * we dismantle the stream and reopen the console when we
947 * take another lap.
948 */
949 (void) close(managerfd);
950
951 (void) mutex_lock(&lock);
952 /*
953 * We need to set death_throes (see below) atomically with
954 * respect to noticing that (a) we have no console client and
955 * (b) the zone is not installed. Otherwise we could get a
956 * request to boot during this time. Once we set death_throes,
957 * any incoming door stuff will be turned away.
958 */
959 if (zone_get_state(zone_name, &zstate) == Z_OK) {
960 if (zstate < ZONE_STATE_READY)
961 goto death;
962 } else {
963 zerror(zlogp, B_FALSE,
964 "unable to determine state of zone");
965 goto death;
966 }
967 /*
968 * Even if zone_get_state() fails, stay conservative, and
969 * take another lap.
|