Print this page
5700 add zlogin -d option to allow graceful disconnect when zone is halted
Reviewed by: Andrew Gabriel <illumos@cucumber.demon.co.uk>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zoneadmd/zcons.c
          +++ new/usr/src/cmd/zoneadmd/zcons.c
↓ open down ↓ 15 lines elided ↑ open up ↑
  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 2012 Joyent, Inc.  All rights reserved.
       26 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  26   27   */
  27   28  
  28   29  /*
  29   30   * Console support for zones requires a significant infrastructure.  The
  30   31   * core pieces are contained in this file, but other portions of note
  31   32   * are in the zlogin(1M) command, the zcons(7D) driver, and in the
  32   33   * devfsadm(1M) misc_link generator.
  33   34   *
  34   35   * Care is taken to make the console behave in an "intuitive" fashion for
  35   36   * administrators.  Essentially, we try as much as possible to mimic the
↓ open down ↓ 466 lines elided ↑ open up ↑
 502  503          (void) shutdown(servfd, SHUT_RDWR);
 503  504          (void) close(servfd);
 504  505  }
 505  506  
 506  507  /*
 507  508   * Read the "ident" string from the client's descriptor; this routine also
 508  509   * tolerates being called with pid=NULL, for times when you want to "eat"
 509  510   * the ident string from a client without saving it.
 510  511   */
 511  512  static int
 512      -get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len)
      513 +get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
      514 +        int *disconnect)
 513  515  {
 514  516          char buf[BUFSIZ], *bufp;
 515  517          size_t buflen = sizeof (buf);
 516  518          char c = '\0';
 517  519          int i = 0, r;
 518  520  
 519  521          /* "eat up the ident string" case, for simplicity */
 520  522          if (pid == NULL) {
 521  523                  assert(locale == NULL && locale_len == 0);
 522  524                  while (read(clifd, &c, 1) == 1) {
↓ open down ↓ 19 lines elided ↑ open up ↑
 542  544           * until we find it; we don't expect this to happen, but this is
 543  545           * defensive.
 544  546           */
 545  547          if (c != '\n') {
 546  548                  while ((r = read(clifd, &c, sizeof (c))) > 0)
 547  549                          if (c == '\n')
 548  550                                  break;
 549  551          }
 550  552  
 551  553          /*
 552      -         * Parse buffer for message of the form: IDENT <pid> <locale>
      554 +         * Parse buffer for message of the form:
      555 +         * IDENT <pid> <locale> <disconnect flag>
 553  556           */
 554  557          bufp = buf;
 555  558          if (strncmp(bufp, "IDENT ", 6) != 0)
 556  559                  return (-1);
 557  560          bufp += 6;
 558  561          errno = 0;
 559  562          *pid = strtoll(bufp, &bufp, 10);
 560  563          if (errno != 0)
 561  564                  return (-1);
 562  565  
 563  566          while (*bufp != '\0' && isspace(*bufp))
 564  567                  bufp++;
      568 +        buflen = strlen(bufp) - 1;
      569 +        *disconnect = atoi(&bufp[buflen]);
      570 +        bufp[buflen - 1] = '\0';
 565  571          (void) strlcpy(locale, bufp, locale_len);
 566  572  
 567  573          return (0);
 568  574  }
 569  575  
 570  576  static int
 571      -accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len)
      577 +accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
      578 +        int *disconnect)
 572  579  {
 573  580          int connfd;
 574  581          struct sockaddr_un cliaddr;
 575  582          socklen_t clilen;
 576  583  
 577  584          clilen = sizeof (cliaddr);
 578  585          connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
 579  586          if (connfd == -1)
 580  587                  return (-1);
 581      -        if (get_client_ident(connfd, pid, locale, locale_len) == -1) {
      588 +        if (get_client_ident(connfd, pid, locale, locale_len,
      589 +            disconnect) == -1) {
 582  590                  (void) shutdown(connfd, SHUT_RDWR);
 583  591                  (void) close(connfd);
 584  592                  return (-1);
 585  593          }
 586  594          (void) write(connfd, "OK\n", 3);
 587  595          return (connfd);
 588  596  }
 589  597  
 590  598  static void
 591  599  reject_client(int servfd, pid_t clientpid)
↓ open down ↓ 2 lines elided ↑ open up ↑
 594  602          struct sockaddr_un cliaddr;
 595  603          socklen_t clilen;
 596  604          char nak[MAXPATHLEN];
 597  605  
 598  606          clilen = sizeof (cliaddr);
 599  607          connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
 600  608  
 601  609          /*
 602  610           * After hear its ident string, tell client to get lost.
 603  611           */
 604      -        if (get_client_ident(connfd, NULL, NULL, 0) == 0) {
      612 +        if (get_client_ident(connfd, NULL, NULL, 0, NULL) == 0) {
 605  613                  (void) snprintf(nak, sizeof (nak), "%lu\n",
 606  614                      clientpid);
 607  615                  (void) write(connfd, nak, strlen(nak));
 608  616          }
 609  617          (void) shutdown(connfd, SHUT_RDWR);
 610  618          (void) close(connfd);
 611  619  }
 612  620  
 613  621  static void
 614      -event_message(int clifd, char *clilocale, zone_evt_t evt)
      622 +event_message(int clifd, char *clilocale, zone_evt_t evt, int dflag)
 615  623  {
 616  624          char *str, *lstr = NULL;
 617  625          char lmsg[BUFSIZ];
 618  626          char outbuf[BUFSIZ];
 619  627  
 620  628          if (clifd == -1)
 621  629                  return;
 622  630  
 623  631          switch (evt) {
 624  632          case Z_EVT_ZONE_BOOTING:
↓ open down ↓ 3 lines elided ↑ open up ↑
 628  636                  }
 629  637                  /*LINTED*/
 630  638                  (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 631  639                      "NOTICE: Zone booting up with arguments: %s"), boot_args);
 632  640                  lstr = lmsg;
 633  641                  break;
 634  642          case Z_EVT_ZONE_READIED:
 635  643                  str = "NOTICE: Zone readied";
 636  644                  break;
 637  645          case Z_EVT_ZONE_HALTED:
 638      -                str = "NOTICE: Zone halted";
      646 +                if (dflag)
      647 +                        str = "NOTICE: Zone halted.  Disconnecting...";
      648 +                else
      649 +                        str = "NOTICE: Zone halted";
 639  650                  break;
 640  651          case Z_EVT_ZONE_REBOOTING:
 641  652                  if (*boot_args == '\0') {
 642  653                          str = "NOTICE: Zone rebooting";
 643  654                          break;
 644  655                  }
 645  656                  /*LINTED*/
 646  657                  (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
 647  658                      "NOTICE: Zone rebooting with arguments: %s"), boot_args);
 648  659                  lstr = lmsg;
 649  660                  break;
 650  661          case Z_EVT_ZONE_UNINSTALLING:
 651  662                  str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
 652  663                  break;
 653  664          case Z_EVT_ZONE_BOOTFAILED:
 654      -                str = "NOTICE: Zone boot failed";
      665 +                if (dflag)
      666 +                        str = "NOTICE: Zone boot failed.  Disconnecting...";
      667 +                else
      668 +                        str = "NOTICE: Zone boot failed";
 655  669                  break;
 656  670          case Z_EVT_ZONE_BADARGS:
 657  671                  /*LINTED*/
 658  672                  (void) snprintf(lmsg, sizeof (lmsg),
 659  673                      localize_msg(clilocale,
 660  674                      "WARNING: Ignoring invalid boot arguments: %s"),
 661  675                      bad_boot_arg);
 662  676                  lstr = lmsg;
 663  677                  break;
 664  678          default:
↓ open down ↓ 36 lines elided ↑ open up ↑
 701  715  static void
 702  716  do_console_io(zlog_t *zlogp, int consfd, int servfd)
 703  717  {
 704  718          struct pollfd pollfds[4];
 705  719          char ibuf[BUFSIZ];
 706  720          int cc, ret;
 707  721          int clifd = -1;
 708  722          int pollerr = 0;
 709  723          char clilocale[MAXPATHLEN];
 710  724          pid_t clipid = 0;
      725 +        int disconnect = 0;
 711  726  
 712  727          /* console side, watch for read events */
 713  728          pollfds[0].fd = consfd;
 714  729          pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
 715  730              POLLPRI | POLLERR | POLLHUP | POLLNVAL;
 716  731  
 717  732          /* client side, watch for read events */
 718  733          pollfds[1].fd = clifd;
 719  734          pollfds[1].events = pollfds[0].events;
 720  735  
↓ open down ↓ 73 lines elided ↑ open up ↑
 794  809                                   * will happen.
 795  810                                   */
 796  811                                  if (test_client(clifd) == -1) {
 797  812                                          break;
 798  813                                  }
 799  814                                  /* we're already handling a client */
 800  815                                  reject_client(servfd, clipid);
 801  816  
 802  817  
 803  818                          } else if ((clifd = accept_client(servfd, &clipid,
 804      -                            clilocale, sizeof (clilocale))) != -1) {
      819 +                            clilocale, sizeof (clilocale),
      820 +                            &disconnect)) != -1) {
 805  821                                  pollfds[1].fd = clifd;
 806  822  
 807  823                          } else {
 808  824                                  break;
 809  825                          }
 810  826                  }
 811  827  
 812  828                  /*
 813  829                   * Watch for events on the eventstream.  This is how we get
 814  830                   * notified of the zone halting, etc.  It provides us a
↓ open down ↓ 5 lines elided ↑ open up ↑
 820  836                          /*
 821  837                           * After we drain out the event, if we aren't servicing
 822  838                           * a console client, we hop back out to our caller,
 823  839                           * which will check to see if it is time to shutdown
 824  840                           * the daemon, or if we should take another console
 825  841                           * service lap.
 826  842                           */
 827  843                          if (clifd == -1) {
 828  844                                  break;
 829  845                          }
 830      -                        event_message(clifd, clilocale, evt);
      846 +                        event_message(clifd, clilocale, evt, disconnect);
 831  847                          /*
 832  848                           * Special handling for the message that the zone is
 833  849                           * uninstalling; we boot the client, then break out
 834  850                           * of this function.  When we return to the
 835  851                           * serve_console loop, we will see that the zone is
 836  852                           * in a state < READY, and so zoneadmd will shutdown.
 837  853                           */
 838  854                          if (evt == Z_EVT_ZONE_UNINSTALLING) {
 839  855                                  break;
 840  856                          }
      857 +                        /*
      858 +                         * Diconnect if -C and -d options were specified and
      859 +                         * zone was halted or failed to boot.
      860 +                         */
      861 +                        if ((evt == Z_EVT_ZONE_HALTED ||
      862 +                            evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
      863 +                                break;
      864 +                        }
 841  865                  }
 842  866  
 843  867          }
 844  868  
 845  869          if (clifd != -1) {
 846  870                  (void) shutdown(clifd, SHUT_RDWR);
 847  871                  (void) close(clifd);
 848  872          }
 849  873  }
 850  874  
↓ open down ↓ 103 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX