Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/zoneadmd/zcons.c
          +++ new/usr/src/cmd/zoneadmd/zcons.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   * Copyright 2015 Joyent, Inc.
  26   26   * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  27   27   */
  28   28  
  29   29  /*
  30   30   * Console support for zones requires a significant infrastructure.  The
  31   31   * core pieces are contained in this file, but other portions of note
  32   32   * are in the zlogin(1M) command, the zcons(7D) driver, and in the
  33   33   * devfsadm(1M) misc_link generator.
  34   34   *
  35   35   * Care is taken to make the console behave in an "intuitive" fashion for
  36   36   * administrators.  Essentially, we try as much as possible to mimic the
  37   37   * experience of using a system via a tip line and system controller.
  38   38   *
  39   39   * The zone console architecture looks like this:
  40   40   *
  41   41   *                                      Global Zone | Non-Global Zone
  42   42   *                        .--------------.          |
  43   43   *        .-----------.   | zoneadmd -z  |          | .--------. .---------.
  44   44   *        | zlogin -C |   |     myzone   |          | | ttymon | | syslogd |
  45   45   *        `-----------'   `--------------'          | `--------' `---------'
  46   46   *                  |       |       | |             |      |       |
  47   47   *  User            |       |       | |             |      V       V
  48   48   * - - - - - - - - -|- - - -|- - - -|-|- - - - - - -|- - /dev/zconsole - - -
  49   49   *  Kernel          V       V       | |                        |
  50   50   *               [AF_UNIX Socket]   | `--------. .-------------'
  51   51   *                                  |          | |
  52   52   *                                  |          V V
  53   53   *                                  |     +-----------+
  54   54   *                                  |     |  ldterm,  |
  55   55   *                                  |     |   etc.    |
  56   56   *                                  |     +-----------+
  57   57   *                                  |     +-[Anchor]--+
  58   58   *                                  |     |   ptem    |
  59   59   *                                  V     +-----------+
  60   60   *                           +---master---+---slave---+
  61   61   *                           |                        |
  62   62   *                           |      zcons driver      |
  63   63   *                           |    zonename="myzone"   |
  64   64   *                           +------------------------+
  65   65   *
  66   66   * There are basically two major tasks which the console subsystem in
  67   67   * zoneadmd accomplishes:
  68   68   *
  69   69   * - Setup and teardown of zcons driver instances.  One zcons instance
  70   70   *   is maintained per zone; we take advantage of the libdevice APIs
  71   71   *   to online new instances of zcons as needed.  Care is taken to
  72   72   *   prune and manage these appropriately; see init_console_dev() and
  73   73   *   destroy_console_dev().  The end result is the creation of the
  74   74   *   zcons(7D) instance and an open file descriptor to the master side.
  75   75   *   zcons instances are associated with zones via their zonename device
  76   76   *   property.  This the console instance to persist across reboots,
  77   77   *   and while the zone is halted.
  78   78   *
  79   79   * - Acting as a server for 'zlogin -C' instances.  When zlogin -C is
  80   80   *   run, zlogin connects to zoneadmd via unix domain socket.  zoneadmd
  81   81   *   functions as a two-way proxy for console I/O, relaying user input
  82   82   *   to the master side of the console, and relaying output from the
  83   83   *   zone to the user.
  84   84   */
  85   85  
  86   86  #include <sys/types.h>
  87   87  #include <sys/socket.h>
  88   88  #include <sys/stat.h>
  89   89  #include <sys/termios.h>
  90   90  #include <sys/zcons.h>
  91   91  #include <sys/mkdev.h>
  92   92  
  93   93  #include <assert.h>
  94   94  #include <ctype.h>
  95   95  #include <errno.h>
  96   96  #include <fcntl.h>
  97   97  #include <stdarg.h>
  98   98  #include <stdio.h>
  99   99  #include <stdlib.h>
 100  100  #include <strings.h>
 101  101  #include <stropts.h>
 102  102  #include <thread.h>
 103  103  #include <ucred.h>
 104  104  #include <unistd.h>
 105  105  #include <zone.h>
 106  106  
 107  107  #include <libdevinfo.h>
 108  108  #include <libdevice.h>
 109  109  #include <libzonecfg.h>
 110  110  
 111  111  #include <syslog.h>
 112  112  #include <sys/modctl.h>
 113  113  
 114  114  #include "zoneadmd.h"
 115  115  
 116  116  #define ZCONSNEX_DEVTREEPATH    "/pseudo/zconsnex@1"
 117  117  #define ZCONSNEX_FILEPATH       "/devices/pseudo/zconsnex@1"
 118  118  
 119  119  #define CONSOLE_SOCKPATH        ZONES_TMPDIR "/%s.console_sock"
 120  120  
 121  121  #define ZCONS_RETRY             10
 122  122  
 123  123  static int      serverfd = -1;  /* console server unix domain socket fd */
 124  124  char boot_args[BOOTARGS_MAX];
 125  125  
 126  126  /*
 127  127   * The eventstream is a simple one-directional flow of messages from the
 128  128   * door server to the console subsystem, implemented with a pipe.
 129  129   * It is used to wake up the console poller when it needs to take action,
 130  130   * message the user, die off, etc.
 131  131   */
 132  132  static int eventstream[2];
 133  133  
 134  134  /* flag used to cope with race creating master zcons devlink */
 135  135  static boolean_t master_zcons_failed = B_FALSE;
 136  136  /* flag to track if we've seen a state change when there is no master zcons */
 137  137  static boolean_t state_changed = B_FALSE;
 138  138  
 139  139  int
 140  140  eventstream_init()
 141  141  {
 142  142          if (pipe(eventstream) == -1)
 143  143                  return (-1);
 144  144          return (0);
 145  145  }
 146  146  
 147  147  void
 148  148  eventstream_write(zone_evt_t evt)
 149  149  {
 150  150          (void) write(eventstream[0], &evt, sizeof (evt));
 151  151  }
 152  152  
 153  153  static zone_evt_t
 154  154  eventstream_read(void)
 155  155  {
 156  156          zone_evt_t evt = Z_EVT_NULL;
 157  157  
 158  158          (void) read(eventstream[1], &evt, sizeof (evt));
 159  159          return (evt);
 160  160  }
 161  161  
 162  162  /*
 163  163   * count_console_devs() and its helper count_cb() do a walk of the
 164  164   * subtree of the device tree where zone console nodes are represented.
 165  165   * The goal is to count zone console instances already setup for a zone
 166  166   * with the given name.  More than 1 is anomolous, and our caller will
 167  167   * have to deal with that if we find that's the case.
 168  168   *
 169  169   * Note: this algorithm is a linear search of nodes in the zconsnex subtree
 170  170   * of the device tree, and could be a scalability problem, but I don't see
 171  171   * how to avoid it.
 172  172   */
 173  173  
 174  174  /*
 175  175   * cb_data is shared by count_cb and destroy_cb for simplicity.
 176  176   */
 177  177  struct cb_data {
 178  178          zlog_t *zlogp;
 179  179          int found;
 180  180          int killed;
 181  181  };
 182  182  
 183  183  static int
 184  184  count_cb(di_node_t node, void *arg)
 185  185  {
 186  186          struct cb_data *cb = (struct cb_data *)arg;
 187  187          char *prop_data;
 188  188  
 189  189          if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
 190  190              &prop_data) != -1) {
 191  191                  assert(prop_data != NULL);
 192  192                  if (strcmp(prop_data, zone_name) == 0) {
 193  193                          cb->found++;
 194  194                          return (DI_WALK_CONTINUE);
 195  195                  }
 196  196          }
 197  197          return (DI_WALK_CONTINUE);
 198  198  }
 199  199  
 200  200  static int
 201  201  count_console_devs(zlog_t *zlogp)
 202  202  {
 203  203          di_node_t root;
 204  204          struct cb_data cb;
 205  205  
 206  206          bzero(&cb, sizeof (cb));
 207  207          cb.zlogp = zlogp;
 208  208  
 209  209          if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
 210  210              DI_NODE_NIL) {
 211  211                  zerror(zlogp, B_TRUE, "%s failed", "di_init");
 212  212                  return (-1);
 213  213          }
 214  214  
 215  215          (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, count_cb);
 216  216          di_fini(root);
 217  217          return (cb.found);
 218  218  }
 219  219  
 220  220  /*
 221  221   * destroy_console_devs() and its helper destroy_cb() tears down any console
 222  222   * instances associated with this zone.  If things went very wrong, we
 223  223   * might have more than one console instance hanging around.  This routine
 224  224   * hunts down and tries to remove all of them.  Of course, if the console
 225  225   * is open, the instance will not detach, which is a potential issue.
 226  226   */
 227  227  static int
 228  228  destroy_cb(di_node_t node, void *arg)
 229  229  {
 230  230          struct cb_data *cb = (struct cb_data *)arg;
 231  231          char *prop_data;
 232  232          char *tmp;
 233  233          char devpath[MAXPATHLEN];
 234  234          devctl_hdl_t hdl;
 235  235  
 236  236          if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
 237  237              &prop_data) == -1)
 238  238                  return (DI_WALK_CONTINUE);
 239  239  
 240  240          assert(prop_data != NULL);
 241  241          if (strcmp(prop_data, zone_name) != 0) {
 242  242                  /* this is the console for a different zone */
 243  243                  return (DI_WALK_CONTINUE);
 244  244          }
 245  245  
 246  246          cb->found++;
 247  247          tmp = di_devfs_path(node);
 248  248          (void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
 249  249          di_devfs_path_free(tmp);
 250  250  
 251  251          if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
 252  252                  zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
 253  253                      "but it could not be controlled.", devpath);
 254  254                  return (DI_WALK_CONTINUE);
 255  255          }
 256  256          if (devctl_device_remove(hdl) == 0) {
 257  257                  cb->killed++;
 258  258          } else {
 259  259                  zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
 260  260                      "but it could not be removed.", devpath);
 261  261          }
 262  262          devctl_release(hdl);
 263  263          return (DI_WALK_CONTINUE);
 264  264  }
 265  265  
 266  266  static int
 267  267  destroy_console_devs(zlog_t *zlogp)
 268  268  {
 269  269          char conspath[MAXPATHLEN];
 270  270          di_node_t root;
 271  271          struct cb_data cb;
 272  272          int masterfd;
 273  273          int slavefd;
 274  274  
 275  275          /*
 276  276           * Signal the master side to release its handle on the slave side by
 277  277           * issuing a ZC_RELEASESLAVE ioctl.
 278  278           */
 279  279          (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 280  280              zone_name, ZCONS_MASTER_NAME);
 281  281          if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
 282  282                  (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 283  283                      zone_name, ZCONS_SLAVE_NAME);
 284  284                  if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
 285  285                          if (ioctl(masterfd, ZC_RELEASESLAVE,
 286  286                              (caddr_t)(intptr_t)slavefd) != 0)
 287  287                                  zerror(zlogp, B_TRUE, "WARNING: error while "
 288  288                                      "releasing slave handle of zone console for"
 289  289                                      " %s", zone_name);
 290  290                          (void) close(slavefd);
 291  291                  } else {
 292  292                          zerror(zlogp, B_TRUE, "WARNING: could not open slave "
 293  293                              "side of zone console for %s to release slave "
 294  294                              "handle", zone_name);
 295  295                  }
 296  296                  (void) close(masterfd);
 297  297          } else {
 298  298                  zerror(zlogp, B_TRUE, "WARNING: could not open master side of "
 299  299                      "zone console for %s to release slave handle", zone_name);
 300  300          }
 301  301  
 302  302          bzero(&cb, sizeof (cb));
 303  303          cb.zlogp = zlogp;
 304  304  
 305  305          if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
 306  306              DI_NODE_NIL) {
 307  307                  zerror(zlogp, B_TRUE, "%s failed", "di_init");
 308  308                  return (-1);
 309  309          }
 310  310  
 311  311          (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
 312  312          if (cb.found > 1) {
 313  313                  zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
 314  314                      "instances detected for zone '%s'; %d of %d "
 315  315                      "successfully removed.",
 316  316                      zone_name, cb.killed, cb.found);
 317  317          }
 318  318  
  
    | 
      ↓ open down ↓ | 
    318 lines elided | 
    
      ↑ open up ↑ | 
  
 319  319          di_fini(root);
 320  320          return (0);
 321  321  }
 322  322  
 323  323  /*
 324  324   * init_console_dev() drives the device-tree configuration of the zone
 325  325   * console device.  The general strategy is to use the libdevice (devctl)
 326  326   * interfaces to instantiate a new zone console node.  We do a lot of
 327  327   * sanity checking, and are careful to reuse a console if one exists.
 328  328   *
 329      - * Once the device is in the device tree, we kick devfsadm via di_devlink_init()
      329 + * Once the device is in the device tree, we kick devfsadm via di_init_devs()
 330  330   * to ensure that the appropriate symlinks (to the master and slave console
 331  331   * devices) are placed in /dev in the global zone.
 332  332   */
 333  333  static int
 334  334  init_console_dev(zlog_t *zlogp)
 335  335  {
 336  336          char conspath[MAXPATHLEN];
 337  337          devctl_hdl_t bus_hdl = NULL;
 338  338          devctl_hdl_t dev_hdl = NULL;
 339  339          devctl_ddef_t ddef_hdl = NULL;
 340  340          di_devlink_handle_t dl = NULL;
 341  341          int rv = -1;
 342  342          int ndevs;
 343  343          int masterfd;
 344  344          int slavefd;
 345  345          int i;
 346  346  
 347  347          /*
 348  348           * Don't re-setup console if it is working and ready already; just
 349  349           * skip ahead to making devlinks, which we do for sanity's sake.
 350  350           */
 351  351          ndevs = count_console_devs(zlogp);
 352  352          if (ndevs == 1) {
 353  353                  goto devlinks;
 354  354          } else if (ndevs > 1 || ndevs == -1) {
 355  355                  /*
 356  356                   * For now, this seems like a reasonable but harsh punishment.
 357  357                   * If needed, we could try to get clever and delete all but
 358  358                   * the console which is pointed at by the current symlink.
 359  359                   */
 360  360                  if (destroy_console_devs(zlogp) == -1) {
 361  361                          goto error;
 362  362                  }
 363  363          }
 364  364  
 365  365          /*
 366  366           * Time to make the consoles!
 367  367           */
 368  368          if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) {
 369  369                  zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire");
 370  370                  goto error;
 371  371          }
 372  372          if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) {
 373  373                  zerror(zlogp, B_TRUE, "failed to allocate ddef handle");
 374  374                  goto error;
 375  375          }
 376  376          /*
 377  377           * Set three properties on this node; the first is the name of the
 378  378           * zone; the second is a flag which lets pseudo know that it is
 379  379           * OK to automatically allocate an instance # for this device;
 380  380           * the third tells the device framework not to auto-detach this
 381  381           * node-- we need the node to still be there when we ask devfsadmd
 382  382           * to make links, and when we need to open it.
 383  383           */
 384  384          if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) {
 385  385                  zerror(zlogp, B_TRUE, "failed to create zonename property");
 386  386                  goto error;
 387  387          }
 388  388          if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) {
 389  389                  zerror(zlogp, B_TRUE, "failed to create auto-assign-instance "
 390  390                      "property");
 391  391                  goto error;
 392  392          }
 393  393          if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
 394  394                  zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
 395  395                      "property");
 396  396                  goto error;
 397  397          }
 398  398          if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
 399  399                  zerror(zlogp, B_TRUE, "failed to create console node");
 400  400                  goto error;
 401  401          }
 402  402  
 403  403  devlinks:
 404  404          if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
 405  405                  (void) di_devlink_fini(&dl);
 406  406          } else {
 407  407                  zerror(zlogp, B_TRUE, "failed to create devlinks");
 408  408                  goto error;
 409  409          }
 410  410  
 411  411          /*
 412  412           * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
  
    | 
      ↓ open down ↓ | 
    73 lines elided | 
    
      ↑ open up ↑ | 
  
 413  413           * which will cause the master to retain a reference to the slave.
 414  414           * This prevents ttymon from blowing through the slave's STREAMS anchor.
 415  415           *
 416  416           * In very rare cases the open returns ENOENT if devfs doesn't have
 417  417           * everything setup yet due to heavy zone startup load. Wait for
 418  418           * 1 sec. and retry a few times. Even if we can't setup the zone's
 419  419           * console, we still go ahead and boot the zone.
 420  420           */
 421  421          (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 422  422              zone_name, ZCONS_MASTER_NAME);
 423      -        for (i = 0; i < ZCONS_RETRY; i++) {
 424      -                masterfd = open(conspath, O_RDWR | O_NOCTTY);
 425      -                if (masterfd >= 0 || errno != ENOENT)
 426      -                        break;
 427      -                (void) sleep(1);
 428      -        }
 429      -        if (masterfd == -1) {
      423 +        if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
 430  424                  zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
 431  425                      "zone console for %s to acquire slave handle", zone_name);
 432  426                  master_zcons_failed = B_TRUE;
 433  427          }
 434      -
 435  428          (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 436  429              zone_name, ZCONS_SLAVE_NAME);
 437  430          for (i = 0; i < ZCONS_RETRY; i++) {
 438  431                  slavefd = open(conspath, O_RDWR | O_NOCTTY);
 439  432                  if (slavefd >= 0 || errno != ENOENT)
 440  433                          break;
 441  434                  (void) sleep(1);
 442  435          }
 443  436          if (slavefd == -1)
 444  437                  zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
 445  438                      " console for %s to acquire slave handle", zone_name);
 446  439  
 447  440          /*
 448  441           * This ioctl can occasionally return ENXIO if devfs doesn't have
 449  442           * everything plumbed up yet due to heavy zone startup load. Wait for
 450  443           * 1 sec. and retry a few times before we fail to boot the zone.
 451  444           */
 452  445          if (masterfd != -1 && slavefd != -1) {
 453  446                  for (i = 0; i < ZCONS_RETRY; i++) {
 454  447                          if (ioctl(masterfd, ZC_HOLDSLAVE,
 455  448                              (caddr_t)(intptr_t)slavefd) == 0) {
 456  449                                  rv = 0;
 457  450                                  break;
 458  451                          } else if (errno != ENXIO) {
 459  452                                  break;
 460  453                          }
 461  454                          (void) sleep(1);
 462  455                  }
 463  456                  if (rv != 0)
 464  457                          zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
 465  458                              "slave handle of zone console for %s", zone_name);
 466  459          }
 467  460  
 468  461          if (slavefd != -1)
 469  462                  (void) close(slavefd);
 470  463          if (masterfd != -1)
 471  464                  (void) close(masterfd);
 472  465  
 473  466  error:
 474  467          if (ddef_hdl)
 475  468                  devctl_ddef_free(ddef_hdl);
 476  469          if (bus_hdl)
 477  470                  devctl_release(bus_hdl);
 478  471          if (dev_hdl)
 479  472                  devctl_release(dev_hdl);
 480  473          return (rv);
 481  474  }
 482  475  
 483  476  static int
 484  477  init_console_sock(zlog_t *zlogp)
 485  478  {
 486  479          int servfd;
 487  480          struct sockaddr_un servaddr;
 488  481  
 489  482          bzero(&servaddr, sizeof (servaddr));
 490  483          servaddr.sun_family = AF_UNIX;
 491  484          (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
 492  485              CONSOLE_SOCKPATH, zone_name);
 493  486  
 494  487          if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 495  488                  zerror(zlogp, B_TRUE, "console setup: could not create socket");
 496  489                  return (-1);
 497  490          }
 498  491          (void) unlink(servaddr.sun_path);
 499  492  
 500  493          if (bind(servfd, (struct sockaddr *)&servaddr,
 501  494              sizeof (servaddr)) == -1) {
 502  495                  zerror(zlogp, B_TRUE,
 503  496                      "console setup: could not bind to socket");
 504  497                  goto out;
 505  498          }
 506  499  
 507  500          if (listen(servfd, 4) == -1) {
 508  501                  zerror(zlogp, B_TRUE,
 509  502                      "console setup: could not listen on socket");
 510  503                  goto out;
 511  504          }
 512  505          return (servfd);
 513  506  
 514  507  out:
 515  508          (void) unlink(servaddr.sun_path);
 516  509          (void) close(servfd);
 517  510          return (-1);
 518  511  }
 519  512  
 520  513  static void
 521  514  destroy_console_sock(int servfd)
 522  515  {
 523  516          char path[MAXPATHLEN];
 524  517  
 525  518          (void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
 526  519          (void) unlink(path);
 527  520          (void) shutdown(servfd, SHUT_RDWR);
 528  521          (void) close(servfd);
 529  522  }
 530  523  
 531  524  /*
 532  525   * Read the "ident" string from the client's descriptor; this routine also
 533  526   * tolerates being called with pid=NULL, for times when you want to "eat"
 534  527   * the ident string from a client without saving it.
 535  528   */
 536  529  static int
 537  530  get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
 538  531      int *disconnect)
 539  532  {
 540  533          char buf[BUFSIZ], *bufp;
 541  534          size_t buflen = sizeof (buf);
 542  535          char c = '\0';
 543  536          int i = 0, r;
 544  537          ucred_t *cred = NULL;
 545  538  
 546  539          /* "eat up the ident string" case, for simplicity */
 547  540          if (pid == NULL) {
 548  541                  assert(locale == NULL && locale_len == 0);
 549  542                  while (read(clifd, &c, 1) == 1) {
 550  543                          if (c == '\n')
 551  544                                  return (0);
 552  545                  }
 553  546          }
 554  547  
 555  548          bzero(buf, sizeof (buf));
 556  549          while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
 557  550                  buflen--;
 558  551                  if (c == '\n')
 559  552                          break;
 560  553  
 561  554                  buf[i] = c;
 562  555                  i++;
 563  556          }
 564  557          if (r == -1)
 565  558                  return (-1);
 566  559  
 567  560          /*
 568  561           * We've filled the buffer, but still haven't seen \n.  Keep eating
 569  562           * until we find it; we don't expect this to happen, but this is
 570  563           * defensive.
 571  564           */
 572  565          if (c != '\n') {
 573  566                  while ((r = read(clifd, &c, sizeof (c))) > 0)
 574  567                          if (c == '\n')
 575  568                                  break;
 576  569          }
 577  570  
 578  571          if (getpeerucred(clifd, &cred) == 0) {
 579  572                  *pid = ucred_getpid((const ucred_t *)cred);
 580  573                  ucred_free(cred);
 581  574          } else {
 582  575                  return (-1);
 583  576          }
 584  577  
 585  578          /*
 586  579           * Parse buffer for message of the form:
 587  580           * IDENT <locale> <disconnect flag>
 588  581           */
 589  582          bufp = buf;
 590  583          if (strncmp(bufp, "IDENT ", 6) != 0)
 591  584                  return (-1);
 592  585          bufp += 6;
 593  586          errno = 0;
 594  587  
 595  588          while (*bufp != '\0' && isspace(*bufp))
 596  589                  bufp++;
 597  590          buflen = strlen(bufp) - 1;
 598  591          *disconnect = atoi(&bufp[buflen]);
 599  592          bufp[buflen - 1] = '\0';
 600  593          (void) strlcpy(locale, bufp, locale_len);
 601  594  
 602  595          return (0);
 603  596  }
 604  597  
 605  598  static int
 606  599  accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
 607  600      int *disconnect)
 608  601  {
 609  602          int connfd;
 610  603          struct sockaddr_un cliaddr;
 611  604          socklen_t clilen;
 612  605  
 613  606          clilen = sizeof (cliaddr);
 614  607          connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
 615  608          if (connfd == -1)
 616  609                  return (-1);
 617  610          if (get_client_ident(connfd, pid, locale, locale_len,
 618  611              disconnect) == -1) {
 619  612                  (void) shutdown(connfd, SHUT_RDWR);
 620  613                  (void) close(connfd);
 621  614                  return (-1);
 622  615          }
 623  616          (void) write(connfd, "OK\n", 3);
 624  617          return (connfd);
 625  618  }
 626  619  
 627  620  static void
 628  621  reject_client(int servfd, pid_t clientpid)
 629  622  {
 630  623          int connfd;
 631  624          struct sockaddr_un cliaddr;
 632  625          socklen_t clilen;
 633  626          char nak[MAXPATHLEN];
 634  627  
 635  628          clilen = sizeof (cliaddr);
 636  629          connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
 637  630  
 638  631          /*
 639  632           * After hear its ident string, tell client to get lost.
 640  633           */
 641  634          if (get_client_ident(connfd, NULL, NULL, 0, NULL) == 0) {
 642  635                  (void) snprintf(nak, sizeof (nak), "%lu\n",
 643  636                      clientpid);
 644  637                  (void) write(connfd, nak, strlen(nak));
 645  638          }
 646  639          (void) shutdown(connfd, SHUT_RDWR);
 647  640          (void) close(connfd);
 648  641  }
 649  642  
 650  643  static void
 651  644  event_message(int clifd, char *clilocale, zone_evt_t evt, int dflag)
 652  645  {
 653  646          char *str, *lstr = NULL;
 654  647          char lmsg[BUFSIZ];
 655  648          char outbuf[BUFSIZ];
 656  649  
 657  650          if (clifd == -1)
 658  651                  return;
 659  652  
 660  653          switch (evt) {
 661  654          case Z_EVT_ZONE_BOOTING:
 662  655                  if (*boot_args == '\0') {
 663  656                          str = "NOTICE: Zone booting up";
 664  657                          break;
 665  658                  }
 666  659                  /*LINTED*/
 667  660                  (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 668  661                      "NOTICE: Zone booting up with arguments: %s"), boot_args);
 669  662                  lstr = lmsg;
 670  663                  break;
 671  664          case Z_EVT_ZONE_READIED:
 672  665                  str = "NOTICE: Zone readied";
 673  666                  break;
 674  667          case Z_EVT_ZONE_HALTED:
 675  668                  if (dflag)
 676  669                          str = "NOTICE: Zone halted.  Disconnecting...";
 677  670                  else
 678  671                          str = "NOTICE: Zone halted";
 679  672                  break;
 680  673          case Z_EVT_ZONE_REBOOTING:
 681  674                  if (*boot_args == '\0') {
 682  675                          str = "NOTICE: Zone rebooting";
 683  676                          break;
 684  677                  }
 685  678                  /*LINTED*/
 686  679                  (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 687  680                      "NOTICE: Zone rebooting with arguments: %s"), boot_args);
 688  681                  lstr = lmsg;
 689  682                  break;
 690  683          case Z_EVT_ZONE_UNINSTALLING:
 691  684                  str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
 692  685                  break;
 693  686          case Z_EVT_ZONE_BOOTFAILED:
 694  687                  if (dflag)
 695  688                          str = "NOTICE: Zone boot failed.  Disconnecting...";
 696  689                  else
 697  690                          str = "NOTICE: Zone boot failed";
 698  691                  break;
 699  692          default:
 700  693                  return;
 701  694          }
 702  695  
 703  696          if (lstr == NULL)
 704  697                  lstr = localize_msg(clilocale, str);
 705  698          (void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
 706  699          (void) write(clifd, outbuf, strlen(outbuf));
 707  700  }
 708  701  
 709  702  /*
 710  703   * Check to see if the client at the other end of the socket is still
 711  704   * alive; we know it is not if it throws EPIPE at us when we try to write
 712  705   * an otherwise harmless 0-length message to it.
 713  706   */
 714  707  static int
 715  708  test_client(int clifd)
 716  709  {
 717  710          if ((write(clifd, "", 0) == -1) && errno == EPIPE)
 718  711                  return (-1);
 719  712          return (0);
 720  713  }
 721  714  
 722  715  /*
 723  716   * This routine drives the console I/O loop.  It polls for input from the
 724  717   * master side of the console (output to the console), and from the client
 725  718   * (input from the console user).  Additionally, it polls on the server fd,
 726  719   * and disconnects any clients that might try to hook up with the zone while
 727  720   * the console is in use.
 728  721   *
 729  722   * When the client first calls us up, it is expected to send a line giving
 730  723   * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
 731  724   * This is so that we can report that the console is busy along with
 732  725   * some diagnostics about who has it busy; the locale is used so that
 733  726   * asynchronous messages about zone state (like the NOTICE: zone halted
 734  727   * messages) can be output in the user's locale.
 735  728   */
 736  729  static void
 737  730  do_console_io(zlog_t *zlogp, int consfd, int servfd)
 738  731  {
 739  732          struct pollfd pollfds[4];
 740  733          char ibuf[BUFSIZ];
 741  734          int cc, ret;
 742  735          int clifd = -1;
 743  736          int pollerr = 0;
 744  737          char clilocale[MAXPATHLEN];
 745  738          pid_t clipid = 0;
 746  739          int disconnect = 0;
 747  740  
 748  741          /* console side, watch for read events */
 749  742          pollfds[0].fd = consfd;
 750  743          pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
 751  744              POLLPRI | POLLERR | POLLHUP | POLLNVAL;
 752  745  
 753  746          /* client side, watch for read events */
 754  747          pollfds[1].fd = clifd;
 755  748          pollfds[1].events = pollfds[0].events;
 756  749  
 757  750          /* the server socket; watch for events (new connections) */
 758  751          pollfds[2].fd = servfd;
 759  752          pollfds[2].events = pollfds[0].events;
 760  753  
 761  754          /* the eventstram; watch for events (e.g.: zone halted) */
 762  755          pollfds[3].fd = eventstream[1];
 763  756          pollfds[3].events = pollfds[0].events;
 764  757  
 765  758          for (;;) {
 766  759                  pollfds[0].revents = pollfds[1].revents = 0;
 767  760                  pollfds[2].revents = pollfds[3].revents = 0;
 768  761  
 769  762                  ret = poll(pollfds,
 770  763                      sizeof (pollfds) / sizeof (struct pollfd), -1);
 771  764                  if (ret == -1 && errno != EINTR) {
 772  765                          zerror(zlogp, B_TRUE, "poll failed");
 773  766                          /* we are hosed, close connection */
 774  767                          break;
 775  768                  }
 776  769  
 777  770                  /* event from console side */
 778  771                  if (pollfds[0].revents) {
 779  772                          if (pollfds[0].revents &
 780  773                              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
 781  774                                  errno = 0;
 782  775                                  cc = read(consfd, ibuf, BUFSIZ);
 783  776                                  if (cc <= 0 && (errno != EINTR) &&
 784  777                                      (errno != EAGAIN))
 785  778                                          break;
 786  779                                  /*
 787  780                                   * Lose I/O if no one is listening
 788  781                                   */
 789  782                                  if (clifd != -1 && cc > 0)
 790  783                                          (void) write(clifd, ibuf, cc);
 791  784                          } else {
 792  785                                  pollerr = pollfds[0].revents;
 793  786                                  zerror(zlogp, B_FALSE,
 794  787                                      "closing connection with (console) "
 795  788                                      "pollerr %d\n", pollerr);
 796  789                                  break;
 797  790                          }
 798  791                  }
 799  792  
 800  793                  /* event from client side */
 801  794                  if (pollfds[1].revents) {
 802  795                          if (pollfds[1].revents &
 803  796                              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
 804  797                                  errno = 0;
 805  798                                  cc = read(clifd, ibuf, BUFSIZ);
 806  799                                  if (cc <= 0 && (errno != EINTR) &&
 807  800                                      (errno != EAGAIN))
 808  801                                          break;
 809  802                                  (void) write(consfd, ibuf, cc);
 810  803                          } else {
 811  804                                  pollerr = pollfds[1].revents;
 812  805                                  zerror(zlogp, B_FALSE,
 813  806                                      "closing connection with (client) "
 814  807                                      "pollerr %d\n", pollerr);
 815  808                                  break;
 816  809                          }
 817  810                  }
 818  811  
 819  812                  /* event from server socket */
 820  813                  if (pollfds[2].revents &&
 821  814                      (pollfds[2].revents & (POLLIN | POLLRDNORM))) {
 822  815                          if (clifd != -1) {
 823  816                                  /*
 824  817                                   * Test the client to see if it is really
 825  818                                   * still alive.  If it has died but we
 826  819                                   * haven't yet detected that, we might
 827  820                                   * deny a legitimate connect attempt.  If it
 828  821                                   * is dead, we break out; once we tear down
 829  822                                   * the old connection, the new connection
 830  823                                   * will happen.
 831  824                                   */
 832  825                                  if (test_client(clifd) == -1) {
 833  826                                          break;
 834  827                                  }
 835  828                                  /* we're already handling a client */
 836  829                                  reject_client(servfd, clipid);
 837  830  
 838  831  
 839  832                          } else if ((clifd = accept_client(servfd, &clipid,
 840  833                              clilocale, sizeof (clilocale),
 841  834                              &disconnect)) != -1) {
 842  835                                  pollfds[1].fd = clifd;
 843  836  
 844  837                          } else {
 845  838                                  break;
 846  839                          }
 847  840                  }
 848  841  
 849  842                  /*
 850  843                   * Watch for events on the eventstream.  This is how we get
 851  844                   * notified of the zone halting, etc.  It provides us a
 852  845                   * "wakeup" from poll when important things happen, which
 853  846                   * is good.
 854  847                   */
 855  848                  if (pollfds[3].revents) {
 856  849                          int evt = eventstream_read();
 857  850                          /*
 858  851                           * After we drain out the event, if we aren't servicing
 859  852                           * a console client, we hop back out to our caller,
 860  853                           * which will check to see if it is time to shutdown
 861  854                           * the daemon, or if we should take another console
 862  855                           * service lap.
 863  856                           */
 864  857                          if (clifd == -1) {
 865  858                                  break;
 866  859                          }
 867  860                          event_message(clifd, clilocale, evt, disconnect);
 868  861                          /*
 869  862                           * Special handling for the message that the zone is
 870  863                           * uninstalling; we boot the client, then break out
 871  864                           * of this function.  When we return to the
 872  865                           * serve_console loop, we will see that the zone is
 873  866                           * in a state < READY, and so zoneadmd will shutdown.
 874  867                           */
 875  868                          if (evt == Z_EVT_ZONE_UNINSTALLING) {
 876  869                                  break;
 877  870                          }
 878  871                          /*
 879  872                           * Diconnect if -C and -d options were specified and
 880  873                           * zone was halted or failed to boot.
 881  874                           */
 882  875                          if ((evt == Z_EVT_ZONE_HALTED ||
 883  876                              evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
 884  877                                  break;
 885  878                          }
 886  879                  }
 887  880  
 888  881          }
 889  882  
 890  883          if (clifd != -1) {
 891  884                  (void) shutdown(clifd, SHUT_RDWR);
 892  885                  (void) close(clifd);
 893  886          }
 894  887  }
 895  888  
 896  889  int
 897  890  init_console(zlog_t *zlogp)
 898  891  {
 899  892          if (init_console_dev(zlogp) == -1) {
 900  893                  zerror(zlogp, B_FALSE,
 901  894                      "console setup: device initialization failed");
 902  895          }
 903  896  
 904  897          if ((serverfd = init_console_sock(zlogp)) == -1) {
 905  898                  zerror(zlogp, B_FALSE,
 906  899                      "console setup: socket initialization failed");
 907  900                  return (-1);
 908  901          }
 909  902          return (0);
 910  903  }
 911  904  
 912  905  /*
 913  906   * Maintain a simple flag that tracks if we have seen at least one state
 914  907   * change. This is currently only used to handle the special case where we are
 915  908   * running without a console device, which is what normally drives shutdown.
 916  909   */
 917  910  void
 918  911  zcons_statechanged()
 919  912  {
 920  913          state_changed = B_TRUE;
 921  914  }
 922  915  
 923  916  /*
 924  917   * serve_console() is the master loop for driving console I/O.  It is also the
 925  918   * routine which is ultimately responsible for "pulling the plug" on zoneadmd
 926  919   * when it realizes that the daemon should shut down.
 927  920   *
 928  921   * The rules for shutdown are: there must be no console client, and the zone
 929  922   * state must be < ready.  However, we need to give things a chance to actually
 930  923   * get going when the daemon starts up-- otherwise the daemon would immediately
 931  924   * exit on startup if the zone was in the installed state, so we first drop
 932  925   * into the do_console_io() loop in order to give *something* a chance to
 933  926   * happen.
 934  927   */
 935  928  void
 936  929  serve_console(zlog_t *zlogp)
 937  930  {
 938  931          int masterfd;
 939  932          zone_state_t zstate;
 940  933          char conspath[MAXPATHLEN];
 941  934          static boolean_t cons_warned = B_FALSE;
 942  935  
 943  936          (void) snprintf(conspath, sizeof (conspath),
 944  937              "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
 945  938  
 946  939          for (;;) {
 947  940                  masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
 948  941                  if (masterfd == -1) {
 949  942                          if (master_zcons_failed) {
 950  943                                  /*
 951  944                                   * If we don't have a console and the zone is
 952  945                                   * not shutting down, there may have been a
 953  946                                   * race/failure with devfs while creating the
 954  947                                   * console. In this case we want to leave the
 955  948                                   * zone up, even without a console, so
 956  949                                   * periodically recheck.
 957  950                                   */
 958  951                                  int i;
 959  952  
 960  953                                  /*
 961  954                                   * In the normal flow of this loop, we use
 962  955                                   * do_console_io to give things a chance to get
 963  956                                   * going first. However, in this case we can't
 964  957                                   * use that, so we have to wait for at least
 965  958                                   * one state change before checking the state.
 966  959                                   */
 967  960                                  for (i = 0; i < 60; i++) {
 968  961                                          if (state_changed)
 969  962                                                  break;
 970  963                                          (void) sleep(1);
 971  964                                  }
 972  965  
 973  966                                  if (i < 60 && zone_get_state(zone_name,
 974  967                                      &zstate) == Z_OK &&
 975  968                                      (zstate == ZONE_STATE_READY ||
 976  969                                      zstate == ZONE_STATE_RUNNING)) {
 977  970                                          if (!cons_warned) {
 978  971                                                  zerror(zlogp, B_FALSE,
 979  972                                                      "WARNING: missing zone "
 980  973                                                      "console for %s",
 981  974                                                      zone_name);
 982  975                                                  cons_warned = B_TRUE;
 983  976                                          }
 984  977                                          (void) sleep(ZCONS_RETRY);
 985  978                                          continue;
 986  979                                  }
 987  980                          }
 988  981  
 989  982                          zerror(zlogp, B_TRUE, "failed to open console master");
 990  983                          (void) mutex_lock(&lock);
 991  984                          goto death;
 992  985                  }
 993  986  
 994  987                  /*
 995  988                   * Setting RPROTDIS on the stream means that the control
 996  989                   * portion of messages received (which we don't care about)
 997  990                   * will be discarded by the stream head.  If we allowed such
 998  991                   * messages, we wouldn't be able to use read(2), as it fails
 999  992                   * (EBADMSG) when a message with a control element is received.
1000  993                   */
1001  994                  if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
1002  995                          zerror(zlogp, B_TRUE, "failed to set options on "
1003  996                              "console master");
1004  997                          (void) mutex_lock(&lock);
1005  998                          goto death;
1006  999                  }
1007 1000  
1008 1001                  do_console_io(zlogp, masterfd, serverfd);
1009 1002  
1010 1003                  /*
1011 1004                   * We would prefer not to do this, but hostile zone processes
1012 1005                   * can cause the stream to become tainted, and reads will
1013 1006                   * fail.  So, in case something has gone seriously ill,
1014 1007                   * we dismantle the stream and reopen the console when we
1015 1008                   * take another lap.
1016 1009                   */
1017 1010                  (void) close(masterfd);
1018 1011  
1019 1012                  (void) mutex_lock(&lock);
1020 1013                  /*
1021 1014                   * We need to set death_throes (see below) atomically with
1022 1015                   * respect to noticing that (a) we have no console client and
1023 1016                   * (b) the zone is not installed.  Otherwise we could get a
1024 1017                   * request to boot during this time.  Once we set death_throes,
1025 1018                   * any incoming door stuff will be turned away.
1026 1019                   */
1027 1020                  if (zone_get_state(zone_name, &zstate) == Z_OK) {
1028 1021                          if (zstate < ZONE_STATE_READY)
1029 1022                                  goto death;
1030 1023                  } else {
1031 1024                          zerror(zlogp, B_FALSE,
1032 1025                              "unable to determine state of zone");
1033 1026                          goto death;
1034 1027                  }
1035 1028                  /*
1036 1029                   * Even if zone_get_state() fails, stay conservative, and
1037 1030                   * take another lap.
1038 1031                   */
1039 1032                  (void) mutex_unlock(&lock);
1040 1033          }
1041 1034  
1042 1035  death:
1043 1036          assert(MUTEX_HELD(&lock));
1044 1037          in_death_throes = B_TRUE;
1045 1038          (void) mutex_unlock(&lock);
1046 1039  
1047 1040          destroy_console_sock(serverfd);
1048 1041          (void) destroy_console_devs(zlogp);
1049 1042  }
  
    | 
      ↓ open down ↓ | 
    605 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX