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