Print this page
OS-200 need a better mechanism for storing persistent zone_did
Small comment-out because we don't include OS-200
OS-4019 zoneadm is slow with 1000s of zones
OS-3524 in order to support interaction with docker containers, need to be able to connect to stdio for init from GZ
OS-3525 in order to support 'docker logs' need to be able to get stdio from zone to log file
OS-3429 Expose zone's init exit status
OS-399 zone phys. mem. cap should be a rctl and have associated kstat

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zoneadm/zoneadm.c
          +++ new/usr/src/cmd/zoneadm/zoneadm.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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  25   25   * Copyright (c) 2015 by Delphix. All rights reserved.
       26 + * Copyright 2015, Joyent Inc. All rights reserved.
  26   27   */
  27   28  
  28   29  /*
  29   30   * zoneadm is a command interpreter for zone administration.  It is all in
  30   31   * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
  31   32   * main() calls parse_and_run() which calls cmd_match(), then invokes the
  32   33   * appropriate command's handler function.  The rest of the program is the
  33   34   * handler functions and their helper functions.
  34   35   *
  35   36   * Some of the helper functions are used largely to simplify I18N: reducing
↓ open down ↓ 58 lines elided ↑ open up ↑
  94   95  /* Reflects kernel zone entries */
  95   96  typedef struct zone_entry {
  96   97          zoneid_t        zid;
  97   98          char            zname[ZONENAME_MAX];
  98   99          char            *zstate_str;
  99  100          zone_state_t    zstate_num;
 100  101          char            zbrand[MAXNAMELEN];
 101  102          char            zroot[MAXPATHLEN];
 102  103          char            zuuid[UUID_PRINTABLE_STRING_LENGTH];
 103  104          zone_iptype_t   ziptype;
      105 +        zoneid_t        zdid;
 104  106  } zone_entry_t;
 105  107  
 106  108  #define CLUSTER_BRAND_NAME      "cluster"
 107  109  
 108  110  static zone_entry_t *zents;
 109  111  static size_t nzents;
 110  112  
 111  113  #define LOOPBACK_IF     "lo0"
 112  114  #define SOCKET_AF(af)   (((af) == AF_UNSPEC) ? AF_INET : (af))
 113  115  
↓ open down ↓ 322 lines elided ↑ open up ↑
 436  438  
 437  439          assert(!(verbose && parsable));
 438  440          if (firsttime && verbose) {
 439  441                  firsttime = B_FALSE;
 440  442                  (void) printf("%*s %-16s %-10s %-30s %-8s %-6s\n",
 441  443                      ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND",
 442  444                      "IP");
 443  445          }
 444  446          if (!verbose) {
 445  447                  char *cp, *clim;
      448 +                char zdid[80];
 446  449  
 447  450                  if (!parsable) {
 448  451                          (void) printf("%s\n", zent->zname);
 449  452                          return;
 450  453                  }
 451  454                  if (zent->zid == ZONE_ID_UNDEFINED)
 452  455                          (void) printf("-");
 453  456                  else
 454  457                          (void) printf("%lu", zent->zid);
 455  458                  (void) printf(":%s:%s:", zent->zname, zent->zstate_str);
 456  459                  cp = zent->zroot;
 457  460                  while ((clim = strchr(cp, ':')) != NULL) {
 458  461                          (void) printf("%.*s\\:", clim - cp, cp);
 459  462                          cp = clim + 1;
 460  463                  }
 461      -                (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
 462      -                    ip_type_str);
      464 +                if (zent->zdid == -1)
      465 +                        zdid[0] = '\0';
      466 +                else
      467 +                        (void) snprintf(zdid, sizeof (zdid), "%d", zent->zdid);
      468 +                (void) printf("%s:%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
      469 +                    ip_type_str, zdid);
 463  470                  return;
 464  471          }
 465  472          if (zent->zstate_str != NULL) {
 466  473                  if (zent->zid == ZONE_ID_UNDEFINED)
 467  474                          (void) printf("%*s", ZONEID_WIDTH, "-");
 468  475                  else
 469  476                          (void) printf("%*lu", ZONEID_WIDTH, zent->zid);
 470  477                  (void) printf(" %-16s %-10s %-30s %-8s %-6s\n", zent->zname,
 471  478                      zent->zstate_str, zent->zroot, zent->zbrand, ip_type_str);
 472  479          }
↓ open down ↓ 74 lines elided ↑ open up ↑
 547  554  
 548  555          /*
 549  556           * Get ip type of the zone.
 550  557           * Note for global zone, ZS_SHARED is set always.
 551  558           */
 552  559          if (zid == GLOBAL_ZONEID) {
 553  560                  zent->ziptype = ZS_SHARED;
 554  561                  return (Z_OK);
 555  562          }
 556  563  
      564 +        if ((handle = zonecfg_init_handle()) == NULL) {
      565 +                zperror2(zent->zname, gettext("could not init handle"));
      566 +                return (Z_ERR);
      567 +        }
      568 +        if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
      569 +                zperror2(zent->zname, gettext("could not get handle"));
      570 +                zonecfg_fini_handle(handle);
      571 +                return (Z_ERR);
      572 +        }
      573 +
      574 +        if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
      575 +                zperror2(zent->zname, gettext("could not get ip-type"));
      576 +                zonecfg_fini_handle(handle);
      577 +                return (Z_ERR);
      578 +        }
      579 +
 557  580          /*
 558  581           * There is a race condition where the zone could boot while
 559  582           * we're walking the index file.  In this case the zone state
 560  583           * could be seen as running from the call above, but the zoneid
 561  584           * would be undefined.
 562  585           *
 563  586           * There is also a race condition where the zone could shutdown after
 564  587           * we got its running state above.  This is also not an error and
 565  588           * we fall back to getting the ziptype from the zone configuration.
 566  589           */
 567  590          if (zent->zstate_num == ZONE_STATE_RUNNING &&
 568  591              zid != ZONE_ID_UNDEFINED) {
 569  592                  ushort_t flags;
 570  593  
 571  594                  if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
 572  595                      sizeof (flags)) >= 0) {
 573  596                          if (flags & ZF_NET_EXCL)
 574  597                                  zent->ziptype = ZS_EXCLUSIVE;
 575  598                          else
 576  599                                  zent->ziptype = ZS_SHARED;
 577      -                        return (Z_OK);
 578  600                  }
 579  601          }
 580  602  
 581      -        if ((handle = zonecfg_init_handle()) == NULL) {
 582      -                zperror2(zent->zname, gettext("could not init handle"));
 583      -                return (Z_ERR);
 584      -        }
 585      -        if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
 586      -                zperror2(zent->zname, gettext("could not get handle"));
 587      -                zonecfg_fini_handle(handle);
 588      -                return (Z_ERR);
 589      -        }
      603 +        zent->zdid = zonecfg_get_did(handle);
 590  604  
 591      -        if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
 592      -                zperror2(zent->zname, gettext("could not get ip-type"));
 593      -                zonecfg_fini_handle(handle);
 594      -                return (Z_ERR);
 595      -        }
 596  605          zonecfg_fini_handle(handle);
 597  606  
 598  607          return (Z_OK);
 599  608  }
 600  609  
 601  610  /*
 602  611   * fetch_zents() calls zone_list(2) to find out how many zones are running
 603  612   * (which is stored in the global nzents), then calls zone_list(2) again
 604  613   * to fetch the list of running zones (stored in the global zents).  This
 605  614   * function may be called multiple times, so if zents is already set, we
↓ open down ↓ 153 lines elided ↑ open up ↑
 759  768                          zone_print(&zent, verbose, parsable);
 760  769          }
 761  770          endzoneent(cookie);
 762  771          return (Z_OK);
 763  772  }
 764  773  
 765  774  /*
 766  775   * Retrieve a zone entry by name.  Returns NULL if no such zone exists.
 767  776   */
 768  777  static zone_entry_t *
 769      -lookup_running_zone(const char *str)
      778 +lookup_running_zone(const char *name)
 770  779  {
 771      -        int i;
      780 +        zoneid_t zid;
      781 +        zone_entry_t *zent;
 772  782  
 773      -        if (fetch_zents() != Z_OK)
      783 +        if ((zid = getzoneidbyname(name)) == -1)
 774  784                  return (NULL);
 775  785  
 776      -        for (i = 0; i < nzents; i++) {
 777      -                if (strcmp(str, zents[i].zname) == 0)
 778      -                        return (&zents[i]);
      786 +        if ((zent = malloc(sizeof (zone_entry_t))) == NULL)
      787 +                return (NULL);
      788 +
      789 +        if (lookup_zone_info(name, zid, zent) != Z_OK) {
      790 +                free(zent);
      791 +                return (NULL);
 779  792          }
 780      -        return (NULL);
      793 +        return (zent);
 781  794  }
 782  795  
 783  796  /*
 784  797   * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
 785  798   * B_FALSE, it should be off.  Return B_TRUE if the mode is bad (incorrect).
 786  799   */
 787  800  static boolean_t
 788  801  bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file)
 789  802  {
 790  803          char *str;
↓ open down ↓ 1985 lines elided ↑ open up ↑
2776 2789           * privileges will be used when this zone is created in the
2777 2790           * kernel.
2778 2791           */
2779 2792          if (!in_alt_root && cmd_num != CMD_MOUNT &&
2780 2793              verify_limitpriv(handle) != Z_OK)
2781 2794                  return_code = Z_ERR;
2782 2795  
2783 2796          return (return_code);
2784 2797  }
2785 2798  
     2799 +/*
     2800 + * Called when readying or booting a zone.  We double check that the zone's
     2801 + * debug ID is set and is unique.  This covers the case of pre-existing zones
     2802 + * with no ID.  Also, its possible that a zone was migrated to this host
     2803 + * and as a result it has a duplicate ID.  In this case we preserve the ID
     2804 + * of the first zone we match on in the index file (since it was there before
     2805 + * the current zone) and we assign a new unique ID to the current zone.
     2806 + * Return true if we assigned a new ID, indicating that the zone configuration
     2807 + * needs to be saved.
     2808 + */
     2809 +static boolean_t
     2810 +verify_fix_did(zone_dochandle_t handle)
     2811 +{
     2812 +        zoneid_t mydid;
     2813 +        zone_entry_t zent;
     2814 +        FILE *cookie;
     2815 +        char *name;
     2816 +        boolean_t fix = B_FALSE;
     2817 +
     2818 +        mydid = zonecfg_get_did(handle);
     2819 +        if (mydid == -1) {
     2820 +                zonecfg_set_did(handle);
     2821 +                return (B_TRUE);
     2822 +        }
     2823 +
     2824 +        /* Get the full list of zones from the configuration. */
     2825 +        cookie = setzoneent();
     2826 +        while ((name = getzoneent(cookie)) != NULL) {
     2827 +                if (strcmp(target_zone, name) == 0) {
     2828 +                        free(name);
     2829 +                        break;  /* Once we find our entry, stop. */
     2830 +                }
     2831 +
     2832 +                if (strcmp(name, "global") == 0 ||
     2833 +                    lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
     2834 +                        free(name);
     2835 +                        continue;
     2836 +                }
     2837 +
     2838 +                free(name);
     2839 +                if (zent.zdid == mydid) {
     2840 +                        fix = B_TRUE;
     2841 +                        break;
     2842 +                }
     2843 +        }
     2844 +        endzoneent(cookie);
     2845 +
     2846 +        if (fix) {
     2847 +                zonecfg_set_did(handle);
     2848 +                return (B_TRUE);
     2849 +        }
     2850 +
     2851 +        return (B_FALSE);
     2852 +}
     2853 +
2786 2854  static int
2787 2855  verify_details(int cmd_num, char *argv[])
2788 2856  {
2789 2857          zone_dochandle_t handle;
2790 2858          char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN];
2791 2859          int return_code = Z_OK;
2792 2860          int err;
2793 2861  
2794 2862          if ((handle = zonecfg_init_handle()) == NULL) {
2795 2863                  zperror(cmd_to_str(cmd_num), B_TRUE);
↓ open down ↓ 39 lines elided ↑ open up ↑
2835 2903          if (cmd_num != CMD_ATTACH &&
2836 2904              validate_zonepath(zonepath, cmd_num) != Z_OK) {
2837 2905                  (void) fprintf(stderr, gettext("could not verify zonepath %s "
2838 2906                      "because of the above errors.\n"), zonepath);
2839 2907                  return_code = Z_ERR;
2840 2908          }
2841 2909  
2842 2910          if (verify_handle(cmd_num, handle, argv) != Z_OK)
2843 2911                  return_code = Z_ERR;
2844 2912  
     2913 +        if (cmd_num == CMD_READY || cmd_num == CMD_BOOT) {
     2914 +                int vcommit = 0, obscommit = 0;
     2915 +
     2916 +                vcommit = verify_fix_did(handle);
     2917 +                obscommit = zonecfg_fix_obsolete(handle);
     2918 +
     2919 +                if (vcommit || obscommit)
     2920 +                        if (zonecfg_save(handle) != Z_OK)
     2921 +                                (void) fprintf(stderr, gettext("Could not save "
     2922 +                                    "updated configuration.\n"));
     2923 +        }
     2924 +
2845 2925          zonecfg_fini_handle(handle);
2846 2926          if (return_code == Z_ERR)
2847 2927                  (void) fprintf(stderr,
2848 2928                      gettext("%s: zone %s failed to verify\n"),
2849 2929                      execname, target_zone);
2850 2930          return (return_code);
2851 2931  }
2852 2932  
2853 2933  static int
2854 2934  verify_func(int argc, char *argv[])
↓ open down ↓ 1003 lines elided ↑ open up ↑
3858 3938          int             status;
3859 3939          int             i;
3860 3940          boolean_t       non_std = B_FALSE;
3861 3941          struct dirent   *dp;
3862 3942          DIR             *dirp;
3863 3943                          /*
3864 3944                           * The SUNWattached.xml file is expected since it might
3865 3945                           * exist if the zone was force-attached after a
3866 3946                           * migration.
3867 3947                           */
3868      -        char            *std_entries[] = {"dev", "lu", "root",
3869      -                            "SUNWattached.xml", NULL};
3870      -                        /* (MAXPATHLEN * 3) is for the 3 std_entries dirs */
3871      -        char            cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 3) + 64];
     3948 +        char            *std_entries[] = {"dev", "lastexited", "logs", "lu",
     3949 +                            "root", "SUNWattached.xml", NULL};
     3950 +                        /* (MAXPATHLEN * 5) is for the 5 std_entries dirs */
     3951 +        char            cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 5) + 64];
3872 3952  
3873 3953          /*
3874 3954           * We shouldn't need these checks but lets be paranoid since we
3875 3955           * could blow away the whole system here if we got the wrong zonepath.
3876 3956           */
3877 3957          if (*zonepath == NULL || strcmp(zonepath, "/") == 0) {
3878 3958                  (void) fprintf(stderr, "invalid zonepath '%s'\n", zonepath);
3879 3959                  return (Z_INVAL);
3880 3960          }
3881 3961  
↓ open down ↓ 1486 lines elided ↑ open up ↑
5368 5448   */
5369 5449  /* ARGSUSED */
5370 5450  static int
5371 5451  apply_func(int argc, char *argv[])
5372 5452  {
5373 5453          int err;
5374 5454          int res = Z_OK;
5375 5455          priv_set_t *privset;
5376 5456          zoneid_t zoneid;
5377 5457          zone_dochandle_t handle;
5378      -        struct zone_mcaptab mcap;
     5458 +        uint64_t mcap;
5379 5459          char pool_err[128];
5380 5460  
5381 5461          zoneid = getzoneid();
5382 5462  
5383 5463          if (zonecfg_in_alt_root() || zoneid != GLOBAL_ZONEID ||
5384 5464              target_zone == NULL || strcmp(target_zone, GLOBAL_ZONENAME) != 0)
5385 5465                  return (usage(B_FALSE));
5386 5466  
5387 5467          if ((privset = priv_allocset()) == NULL) {
5388 5468                  zerror(gettext("%s failed"), "priv_allocset");
↓ open down ↓ 70 lines elided ↑ open up ↑
5459 5539                                  if (err == Z_POOL || err == Z_POOL_BIND)
5460 5540                                          zerror("%s: %s", zonecfg_strerror(err),
5461 5541                                              pool_err);
5462 5542                                  else
5463 5543                                          zerror("%s", zonecfg_strerror(err));
5464 5544                          }
5465 5545                  }
5466 5546          }
5467 5547  
5468 5548          /*
5469      -         * If a memory cap is configured, set the cap in the kernel using
5470      -         * zone_setattr() and make sure the rcapd SMF service is enabled.
     5549 +         * If a memory cap is configured, make sure the rcapd SMF service is
     5550 +         * enabled.
5471 5551           */
5472      -        if (zonecfg_getmcapent(handle, &mcap) == Z_OK) {
5473      -                uint64_t num;
     5552 +        if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &mcap) == Z_OK) {
5474 5553                  char smf_err[128];
5475 5554  
5476      -                num = (uint64_t)strtoll(mcap.zone_physmem_cap, NULL, 10);
5477      -                if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
5478      -                        zerror(gettext("could not set zone memory cap"));
5479      -                        res = Z_ERR;
5480      -                }
5481      -
5482 5555                  if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) {
5483 5556                          zerror(gettext("enabling system/rcap service failed: "
5484 5557                              "%s"), smf_err);
5485 5558                          res = Z_ERR;
5486 5559                  }
5487 5560          }
5488 5561  
5489 5562          zonecfg_fini_handle(handle);
5490 5563  
5491 5564          return (res);
↓ open down ↓ 305 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX