Print this page
14249 pseudo-terminal nomenclature should reflect POSIX
Change-Id: Ib4a3cef899ff4c71b09cb0dc6878863c5e8357bc


  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.