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  * Copyright 2012 Joyent, Inc.  All rights reserved.
  26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  27  */
  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  *        `-----------'   `--------------'          | `--------' `---------'
 
 
 101 #include <stropts.h>
 102 #include <thread.h>
 103 #include <ucred.h>
 104 #include <unistd.h>
 105 #include <zone.h>
 106 
 107 #include <libdevinfo.h>
 108 #include <libdevice.h>
 109 #include <libzonecfg.h>
 110 
 111 #include <syslog.h>
 112 #include <sys/modctl.h>
 113 
 114 #include "zoneadmd.h"
 115 
 116 #define ZCONSNEX_DEVTREEPATH    "/pseudo/zconsnex@1"
 117 #define ZCONSNEX_FILEPATH       "/devices/pseudo/zconsnex@1"
 118 
 119 #define CONSOLE_SOCKPATH        ZONES_TMPDIR "/%s.console_sock"
 120 
 121 static int      serverfd = -1;  /* console server unix domain socket fd */
 122 char boot_args[BOOTARGS_MAX];
 123 char bad_boot_arg[BOOTARGS_MAX];
 124 
 125 /*
 126  * The eventstream is a simple one-directional flow of messages from the
 127  * door server to the console subsystem, implemented with a pipe.
 128  * It is used to wake up the console poller when it needs to take action,
 129  * message the user, die off, etc.
 130  */
 131 static int eventstream[2];
 132 
 133 
 134 
 135 int
 136 eventstream_init()
 137 {
 138         if (pipe(eventstream) == -1)
 139                 return (-1);
 140         return (0);
 141 }
 142 
 143 void
 144 eventstream_write(zone_evt_t evt)
 145 {
 146         (void) write(eventstream[0], &evt, sizeof (evt));
 147 }
 148 
 149 static zone_evt_t
 150 eventstream_read(void)
 151 {
 152         zone_evt_t evt = Z_EVT_NULL;
 153 
 154         (void) read(eventstream[1], &evt, sizeof (evt));
 
 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;
 
 500 
 501         (void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
 502         (void) unlink(path);
 503         (void) shutdown(servfd, SHUT_RDWR);
 504         (void) close(servfd);
 505 }
 506 
 507 /*
 508  * Read the "ident" string from the client's descriptor; this routine also
 509  * tolerates being called with pid=NULL, for times when you want to "eat"
 510  * the ident string from a client without saving it.
 511  */
 512 static int
 513 get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
 514     int *disconnect)
 515 {
 516         char buf[BUFSIZ], *bufp;
 517         size_t buflen = sizeof (buf);
 518         char c = '\0';
 519         int i = 0, r;
 520 
 521         /* "eat up the ident string" case, for simplicity */
 522         if (pid == NULL) {
 523                 assert(locale == NULL && locale_len == 0);
 524                 while (read(clifd, &c, 1) == 1) {
 525                         if (c == '\n')
 526                                 return (0);
 527                 }
 528         }
 529 
 530         bzero(buf, sizeof (buf));
 531         while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
 532                 buflen--;
 533                 if (c == '\n')
 534                         break;
 535 
 536                 buf[i] = c;
 537                 i++;
 538         }
 539         if (r == -1)
 540                 return (-1);
 541 
 542         /*
 543          * We've filled the buffer, but still haven't seen \n.  Keep eating
 544          * until we find it; we don't expect this to happen, but this is
 545          * defensive.
 546          */
 547         if (c != '\n') {
 548                 while ((r = read(clifd, &c, sizeof (c))) > 0)
 549                         if (c == '\n')
 550                                 break;
 551         }
 552 
 553         /*
 554          * Parse buffer for message of the form:
 555          * IDENT <pid> <locale> <disconnect flag>
 556          */
 557         bufp = buf;
 558         if (strncmp(bufp, "IDENT ", 6) != 0)
 559                 return (-1);
 560         bufp += 6;
 561         errno = 0;
 562         *pid = strtoll(bufp, &bufp, 10);
 563         if (errno != 0)
 564                 return (-1);
 565 
 566         while (*bufp != '\0' && isspace(*bufp))
 567                 bufp++;
 568         buflen = strlen(bufp) - 1;
 569         *disconnect = atoi(&bufp[buflen]);
 570         bufp[buflen - 1] = '\0';
 571         (void) strlcpy(locale, bufp, locale_len);
 572 
 573         return (0);
 574 }
 575 
 576 static int
 577 accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
 578     int *disconnect)
 579 {
 580         int connfd;
 581         struct sockaddr_un cliaddr;
 582         socklen_t clilen;
 583 
 584         clilen = sizeof (cliaddr);
 
 650                 break;
 651         case Z_EVT_ZONE_REBOOTING:
 652                 if (*boot_args == '\0') {
 653                         str = "NOTICE: Zone rebooting";
 654                         break;
 655                 }
 656                 /*LINTED*/
 657                 (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 658                     "NOTICE: Zone rebooting with arguments: %s"), boot_args);
 659                 lstr = lmsg;
 660                 break;
 661         case Z_EVT_ZONE_UNINSTALLING:
 662                 str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
 663                 break;
 664         case Z_EVT_ZONE_BOOTFAILED:
 665                 if (dflag)
 666                         str = "NOTICE: Zone boot failed.  Disconnecting...";
 667                 else
 668                         str = "NOTICE: Zone boot failed";
 669                 break;
 670         case Z_EVT_ZONE_BADARGS:
 671                 /*LINTED*/
 672                 (void) snprintf(lmsg, sizeof (lmsg),
 673                     localize_msg(clilocale,
 674                     "WARNING: Ignoring invalid boot arguments: %s"),
 675                     bad_boot_arg);
 676                 lstr = lmsg;
 677                 break;
 678         default:
 679                 return;
 680         }
 681 
 682         if (lstr == NULL)
 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);
 
 861                         if ((evt == Z_EVT_ZONE_HALTED ||
 862                             evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
 863                                 break;
 864                         }
 865                 }
 866 
 867         }
 868 
 869         if (clifd != -1) {
 870                 (void) shutdown(clifd, SHUT_RDWR);
 871                 (void) close(clifd);
 872         }
 873 }
 874 
 875 int
 876 init_console(zlog_t *zlogp)
 877 {
 878         if (init_console_dev(zlogp) == -1) {
 879                 zerror(zlogp, B_FALSE,
 880                     "console setup: device initialization failed");
 881                 return (-1);
 882         }
 883 
 884         if ((serverfd = init_console_sock(zlogp)) == -1) {
 885                 zerror(zlogp, B_FALSE,
 886                     "console setup: socket initialization failed");
 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);
 
 | 
 
 
   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  * Copyright 2015 Joyent, Inc.
  26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  27  */
  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  *        `-----------'   `--------------'          | `--------' `---------'
 
 
 101 #include <stropts.h>
 102 #include <thread.h>
 103 #include <ucred.h>
 104 #include <unistd.h>
 105 #include <zone.h>
 106 
 107 #include <libdevinfo.h>
 108 #include <libdevice.h>
 109 #include <libzonecfg.h>
 110 
 111 #include <syslog.h>
 112 #include <sys/modctl.h>
 113 
 114 #include "zoneadmd.h"
 115 
 116 #define ZCONSNEX_DEVTREEPATH    "/pseudo/zconsnex@1"
 117 #define ZCONSNEX_FILEPATH       "/devices/pseudo/zconsnex@1"
 118 
 119 #define CONSOLE_SOCKPATH        ZONES_TMPDIR "/%s.console_sock"
 120 
 121 #define ZCONS_RETRY             10
 122 
 123 static int      serverfd = -1;  /* console server unix domain socket fd */
 124 char boot_args[BOOTARGS_MAX];
 125 
 126 /*
 127  * The eventstream is a simple one-directional flow of messages from the
 128  * door server to the console subsystem, implemented with a pipe.
 129  * It is used to wake up the console poller when it needs to take action,
 130  * message the user, die off, etc.
 131  */
 132 static int eventstream[2];
 133 
 134 /* flag used to cope with race creating master zcons devlink */
 135 static boolean_t master_zcons_failed = B_FALSE;
 136 /* flag to track if we've seen a state change when there is no master zcons */
 137 static boolean_t state_changed = B_FALSE;
 138 
 139 int
 140 eventstream_init()
 141 {
 142         if (pipe(eventstream) == -1)
 143                 return (-1);
 144         return (0);
 145 }
 146 
 147 void
 148 eventstream_write(zone_evt_t evt)
 149 {
 150         (void) write(eventstream[0], &evt, sizeof (evt));
 151 }
 152 
 153 static zone_evt_t
 154 eventstream_read(void)
 155 {
 156         zone_evt_t evt = Z_EVT_NULL;
 157 
 158         (void) read(eventstream[1], &evt, sizeof (evt));
 
 395                     "property");
 396                 goto error;
 397         }
 398         if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
 399                 zerror(zlogp, B_TRUE, "failed to create console node");
 400                 goto error;
 401         }
 402 
 403 devlinks:
 404         if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
 405                 (void) di_devlink_fini(&dl);
 406         } else {
 407                 zerror(zlogp, B_TRUE, "failed to create devlinks");
 408                 goto error;
 409         }
 410 
 411         /*
 412          * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
 413          * which will cause the master to retain a reference to the slave.
 414          * This prevents ttymon from blowing through the slave's STREAMS anchor.
 415          *
 416          * In very rare cases the open returns ENOENT if devfs doesn't have
 417          * everything setup yet due to heavy zone startup load. Wait for
 418          * 1 sec. and retry a few times. Even if we can't setup the zone's
 419          * console, we still go ahead and boot the zone.
 420          */
 421         (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 422             zone_name, ZCONS_MASTER_NAME);
 423         if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
 424                 zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
 425                     "zone console for %s to acquire slave handle", zone_name);
 426                 master_zcons_failed = B_TRUE;
 427         }
 428         (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 429             zone_name, ZCONS_SLAVE_NAME);
 430         for (i = 0; i < ZCONS_RETRY; i++) {
 431                 slavefd = open(conspath, O_RDWR | O_NOCTTY);
 432                 if (slavefd >= 0 || errno != ENOENT)
 433                         break;
 434                 (void) sleep(1);
 435         }
 436         if (slavefd == -1)
 437                 zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
 438                     " console for %s to acquire slave handle", zone_name);
 439 
 440         /*
 441          * This ioctl can occasionally return ENXIO if devfs doesn't have
 442          * everything plumbed up yet due to heavy zone startup load. Wait for
 443          * 1 sec. and retry a few times before we fail to boot the zone.
 444          */
 445         if (masterfd != -1 && slavefd != -1) {
 446                 for (i = 0; i < ZCONS_RETRY; i++) {
 447                         if (ioctl(masterfd, ZC_HOLDSLAVE,
 448                             (caddr_t)(intptr_t)slavefd) == 0) {
 449                                 rv = 0;
 450                                 break;
 451                         } else if (errno != ENXIO) {
 452                                 break;
 453                         }
 454                         (void) sleep(1);
 455                 }
 456                 if (rv != 0)
 457                         zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
 458                             "slave handle of zone console for %s", zone_name);
 459         }
 460 
 461         if (slavefd != -1)
 462                 (void) close(slavefd);
 463         if (masterfd != -1)
 464                 (void) close(masterfd);
 465 
 466 error:
 467         if (ddef_hdl)
 468                 devctl_ddef_free(ddef_hdl);
 469         if (bus_hdl)
 470                 devctl_release(bus_hdl);
 471         if (dev_hdl)
 472                 devctl_release(dev_hdl);
 473         return (rv);
 474 }
 475 
 476 static int
 477 init_console_sock(zlog_t *zlogp)
 478 {
 479         int servfd;
 480         struct sockaddr_un servaddr;
 481 
 482         bzero(&servaddr, sizeof (servaddr));
 483         servaddr.sun_family = AF_UNIX;
 
 517 
 518         (void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
 519         (void) unlink(path);
 520         (void) shutdown(servfd, SHUT_RDWR);
 521         (void) close(servfd);
 522 }
 523 
 524 /*
 525  * Read the "ident" string from the client's descriptor; this routine also
 526  * tolerates being called with pid=NULL, for times when you want to "eat"
 527  * the ident string from a client without saving it.
 528  */
 529 static int
 530 get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
 531     int *disconnect)
 532 {
 533         char buf[BUFSIZ], *bufp;
 534         size_t buflen = sizeof (buf);
 535         char c = '\0';
 536         int i = 0, r;
 537         ucred_t *cred = NULL;
 538 
 539         /* "eat up the ident string" case, for simplicity */
 540         if (pid == NULL) {
 541                 assert(locale == NULL && locale_len == 0);
 542                 while (read(clifd, &c, 1) == 1) {
 543                         if (c == '\n')
 544                                 return (0);
 545                 }
 546         }
 547 
 548         bzero(buf, sizeof (buf));
 549         while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
 550                 buflen--;
 551                 if (c == '\n')
 552                         break;
 553 
 554                 buf[i] = c;
 555                 i++;
 556         }
 557         if (r == -1)
 558                 return (-1);
 559 
 560         /*
 561          * We've filled the buffer, but still haven't seen \n.  Keep eating
 562          * until we find it; we don't expect this to happen, but this is
 563          * defensive.
 564          */
 565         if (c != '\n') {
 566                 while ((r = read(clifd, &c, sizeof (c))) > 0)
 567                         if (c == '\n')
 568                                 break;
 569         }
 570 
 571         if (getpeerucred(clifd, &cred) == 0) {
 572                 *pid = ucred_getpid((const ucred_t *)cred);
 573                 ucred_free(cred);
 574         } else {
 575                 return (-1);
 576         }
 577 
 578         /*
 579          * Parse buffer for message of the form:
 580          * IDENT <locale> <disconnect flag>
 581          */
 582         bufp = buf;
 583         if (strncmp(bufp, "IDENT ", 6) != 0)
 584                 return (-1);
 585         bufp += 6;
 586         errno = 0;
 587 
 588         while (*bufp != '\0' && isspace(*bufp))
 589                 bufp++;
 590         buflen = strlen(bufp) - 1;
 591         *disconnect = atoi(&bufp[buflen]);
 592         bufp[buflen - 1] = '\0';
 593         (void) strlcpy(locale, bufp, locale_len);
 594 
 595         return (0);
 596 }
 597 
 598 static int
 599 accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
 600     int *disconnect)
 601 {
 602         int connfd;
 603         struct sockaddr_un cliaddr;
 604         socklen_t clilen;
 605 
 606         clilen = sizeof (cliaddr);
 
 672                 break;
 673         case Z_EVT_ZONE_REBOOTING:
 674                 if (*boot_args == '\0') {
 675                         str = "NOTICE: Zone rebooting";
 676                         break;
 677                 }
 678                 /*LINTED*/
 679                 (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 680                     "NOTICE: Zone rebooting with arguments: %s"), boot_args);
 681                 lstr = lmsg;
 682                 break;
 683         case Z_EVT_ZONE_UNINSTALLING:
 684                 str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
 685                 break;
 686         case Z_EVT_ZONE_BOOTFAILED:
 687                 if (dflag)
 688                         str = "NOTICE: Zone boot failed.  Disconnecting...";
 689                 else
 690                         str = "NOTICE: Zone boot failed";
 691                 break;
 692         default:
 693                 return;
 694         }
 695 
 696         if (lstr == NULL)
 697                 lstr = localize_msg(clilocale, str);
 698         (void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
 699         (void) write(clifd, outbuf, strlen(outbuf));
 700 }
 701 
 702 /*
 703  * Check to see if the client at the other end of the socket is still
 704  * alive; we know it is not if it throws EPIPE at us when we try to write
 705  * an otherwise harmless 0-length message to it.
 706  */
 707 static int
 708 test_client(int clifd)
 709 {
 710         if ((write(clifd, "", 0) == -1) && errno == EPIPE)
 711                 return (-1);
 
 875                         if ((evt == Z_EVT_ZONE_HALTED ||
 876                             evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
 877                                 break;
 878                         }
 879                 }
 880 
 881         }
 882 
 883         if (clifd != -1) {
 884                 (void) shutdown(clifd, SHUT_RDWR);
 885                 (void) close(clifd);
 886         }
 887 }
 888 
 889 int
 890 init_console(zlog_t *zlogp)
 891 {
 892         if (init_console_dev(zlogp) == -1) {
 893                 zerror(zlogp, B_FALSE,
 894                     "console setup: device initialization failed");
 895         }
 896 
 897         if ((serverfd = init_console_sock(zlogp)) == -1) {
 898                 zerror(zlogp, B_FALSE,
 899                     "console setup: socket initialization failed");
 900                 return (-1);
 901         }
 902         return (0);
 903 }
 904 
 905 /*
 906  * Maintain a simple flag that tracks if we have seen at least one state
 907  * change. This is currently only used to handle the special case where we are
 908  * running without a console device, which is what normally drives shutdown.
 909  */
 910 void
 911 zcons_statechanged()
 912 {
 913         state_changed = B_TRUE;
 914 }
 915 
 916 /*
 917  * serve_console() is the master loop for driving console I/O.  It is also the
 918  * routine which is ultimately responsible for "pulling the plug" on zoneadmd
 919  * when it realizes that the daemon should shut down.
 920  *
 921  * The rules for shutdown are: there must be no console client, and the zone
 922  * state must be < ready.  However, we need to give things a chance to actually
 923  * get going when the daemon starts up-- otherwise the daemon would immediately
 924  * exit on startup if the zone was in the installed state, so we first drop
 925  * into the do_console_io() loop in order to give *something* a chance to
 926  * happen.
 927  */
 928 void
 929 serve_console(zlog_t *zlogp)
 930 {
 931         int masterfd;
 932         zone_state_t zstate;
 933         char conspath[MAXPATHLEN];
 934         static boolean_t cons_warned = B_FALSE;
 935 
 936         (void) snprintf(conspath, sizeof (conspath),
 937             "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
 938 
 939         for (;;) {
 940                 masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
 941                 if (masterfd == -1) {
 942                         if (master_zcons_failed) {
 943                                 /*
 944                                  * If we don't have a console and the zone is
 945                                  * not shutting down, there may have been a
 946                                  * race/failure with devfs while creating the
 947                                  * console. In this case we want to leave the
 948                                  * zone up, even without a console, so
 949                                  * periodically recheck.
 950                                  */
 951                                 int i;
 952 
 953                                 /*
 954                                  * In the normal flow of this loop, we use
 955                                  * do_console_io to give things a chance to get
 956                                  * going first. However, in this case we can't
 957                                  * use that, so we have to wait for at least
 958                                  * one state change before checking the state.
 959                                  */
 960                                 for (i = 0; i < 60; i++) {
 961                                         if (state_changed)
 962                                                 break;
 963                                         (void) sleep(1);
 964                                 }
 965 
 966                                 if (i < 60 && zone_get_state(zone_name,
 967                                     &zstate) == Z_OK &&
 968                                     (zstate == ZONE_STATE_READY ||
 969                                     zstate == ZONE_STATE_RUNNING)) {
 970                                         if (!cons_warned) {
 971                                                 zerror(zlogp, B_FALSE,
 972                                                     "WARNING: missing zone "
 973                                                     "console for %s",
 974                                                     zone_name);
 975                                                 cons_warned = B_TRUE;
 976                                         }
 977                                         (void) sleep(ZCONS_RETRY);
 978                                         continue;
 979                                 }
 980                         }
 981 
 982                         zerror(zlogp, B_TRUE, "failed to open console master");
 983                         (void) mutex_lock(&lock);
 984                         goto death;
 985                 }
 986 
 987                 /*
 988                  * Setting RPROTDIS on the stream means that the control
 989                  * portion of messages received (which we don't care about)
 990                  * will be discarded by the stream head.  If we allowed such
 991                  * messages, we wouldn't be able to use read(2), as it fails
 992                  * (EBADMSG) when a message with a control element is received.
 993                  */
 994                 if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
 995                         zerror(zlogp, B_TRUE, "failed to set options on "
 996                             "console master");
 997                         (void) mutex_lock(&lock);
 998                         goto death;
 999                 }
1000 
1001                 do_console_io(zlogp, masterfd, serverfd);
 
 |