Print this page
Merge cleanup from previous six commits
OS-200 need a better mechanism for storing persistent zone_did
OS-2564 zone boot failed: could not start zoneadmd
OS-1763 mount of /etc/svc/volatile failed: Device busy
OS-511 make zonecfg device resource extensible, like the net resource
OS-224 add more zonecfg net properties

@@ -143,10 +143,13 @@
 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it wasn't */
 #endif
 
 #define DEFAULT_LOCALE  "C"
 
+#define RSRC_NET        "net"
+#define RSRC_DEV        "device"
+
 static const char *
 z_cmd_name(zone_cmd_t zcmd)
 {
         /* This list needs to match the enum in sys/zone.h */
         static const char *zcmdstr[] = {

@@ -679,10 +682,12 @@
 
         } else if (child == 0) {        /* child */
                 char opt_buf[MAX_MNTOPT_STR];
                 int optlen = 0;
                 int mflag = MS_DATA;
+                int i;
+                int ret;
 
                 (void) ct_tmpl_clear(tmpl_fd);
                 /*
                  * Even though there are no procs running in the zone, we
                  * do this for paranoia's sake.

@@ -706,14 +711,31 @@
                         (void) strlcpy(opt_buf, opt, sizeof (opt_buf));
                         opt = opt_buf;
                         optlen = MAX_MNTOPT_STR;
                         mflag = MS_OPTIONSTR;
                 }
-                if (mount(spec, dir, mflag, fstype, NULL, 0, opt, optlen) != 0)
-                        _exit(errno);
-                _exit(0);
+
+                /*
+                 * There is an obscure race condition which can cause mount
+                 * to return EBUSY. This happens for example on the mount
+                 * of the zone's /etc/svc/volatile file system if there is
+                 * a GZ process running svcs -Z, which will touch the
+                 * mountpoint, just as we're trying to do the mount. To cope
+                 * with this, we retry up to 3 times to let this transient
+                 * process get out of the way.
+                 */
+                for (i = 0; i < 3; i++) {
+                        ret = 0;
+                        if (mount(spec, dir, mflag, fstype, NULL, 0, opt,
+                            optlen) != 0)
+                                ret = errno;
+                        if (ret != EBUSY)
+                                break;
+                        (void) sleep(1);
         }
+                _exit(ret);
+        }
 
         /* parent */
         if (contract_latest(&ct) == -1)
                 ct = -1;
         (void) ct_tmpl_clear(tmpl_fd);

@@ -732,10 +754,119 @@
 
         return (0);
 }
 
 /*
+ * env variable name format
+ *      _ZONECFG;{resource name};{identifying attr. name};{property name}
+ */
+static void
+set_zonecfg_env(char *rsrc, char *attr, char *name, char *val)
+{
+        char *p;
+        /* Enough for maximal name, rsrc + attr, & slop for ZONECFG & _'s */
+        char nm[2 * MAXNAMELEN + 32];
+
+        if (attr == NULL)
+                (void) snprintf(nm, sizeof (nm), "_ZONECFG_%s_%s", rsrc,
+                    name);
+        else
+                (void) snprintf(nm, sizeof (nm), "_ZONECFG_%s_%s_%s", rsrc,
+                    attr, name);
+
+        p = nm;
+        while ((p = strchr(p, '-')) != NULL)
+                *p++ = '_';
+
+        (void) setenv(nm, val, 1);
+}
+
+/*
+ * Export zonecfg network and device properties into environment for the boot
+ * and state change hooks.
+ * If debug is true, export the brand hook debug env. variable as well.
+ *
+ * We could export more of the config in the future, as necessary.
+ */
+static int
+setup_subproc_env()
+{
+        int res;
+        zone_dochandle_t handle;
+        struct zone_nwiftab ntab;
+        struct zone_devtab dtab;
+        char net_resources[MAXNAMELEN * 2];
+        char dev_resources[MAXNAMELEN * 2];
+
+        if ((handle = zonecfg_init_handle()) == NULL)
+                exit(Z_NOMEM);
+
+        if ((res = zonecfg_get_handle(zone_name, handle)) != Z_OK)
+                goto done;
+
+        if ((res = zonecfg_setnwifent(handle)) != Z_OK)
+                goto done;
+
+        while (zonecfg_getnwifent(handle, &ntab) == Z_OK) {
+                struct zone_res_attrtab *rap;
+                char *phys;
+
+                phys = ntab.zone_nwif_physical;
+
+                (void) strlcat(net_resources, phys, sizeof (net_resources));
+                (void) strlcat(net_resources, " ", sizeof (net_resources));
+
+                set_zonecfg_env(RSRC_NET, phys, "physical", phys);
+
+                set_zonecfg_env(RSRC_NET, phys, "address",
+                    ntab.zone_nwif_address);
+                set_zonecfg_env(RSRC_NET, phys, "allowed-address",
+                    ntab.zone_nwif_allowed_address);
+                set_zonecfg_env(RSRC_NET, phys, "defrouter",
+                    ntab.zone_nwif_defrouter);
+                set_zonecfg_env(RSRC_NET, phys, "global-nic",
+                    ntab.zone_nwif_gnic);
+                set_zonecfg_env(RSRC_NET, phys, "mac-addr", ntab.zone_nwif_mac);
+                set_zonecfg_env(RSRC_NET, phys, "vlan-id",
+                    ntab.zone_nwif_vlan_id);
+
+                for (rap = ntab.zone_nwif_attrp; rap != NULL;
+                    rap = rap->zone_res_attr_next)
+                        set_zonecfg_env(RSRC_NET, phys, rap->zone_res_attr_name,
+                            rap->zone_res_attr_value);
+        }
+
+        (void) zonecfg_endnwifent(handle);
+
+        if ((res = zonecfg_setdevent(handle)) != Z_OK)
+                goto done;
+
+        while (zonecfg_getdevent(handle, &dtab) == Z_OK) {
+                struct zone_res_attrtab *rap;
+                char *match;
+
+                match = dtab.zone_dev_match;
+
+                (void) strlcat(dev_resources, match, sizeof (dev_resources));
+                (void) strlcat(dev_resources, " ", sizeof (dev_resources));
+
+                for (rap = dtab.zone_dev_attrp; rap != NULL;
+                    rap = rap->zone_res_attr_next)
+                        set_zonecfg_env(RSRC_DEV, match,
+                            rap->zone_res_attr_name, rap->zone_res_attr_value);
+        }
+
+        (void) zonecfg_enddevent(handle);
+
+        res = Z_OK;
+
+done:
+        zonecfg_fini_handle(handle);
+        return (res);
+}
+
+/*
  * If retstr is not NULL, the output of the subproc is returned in the str,
  * otherwise it is output using zerror().  Any memory allocated for retstr
  * should be freed by the caller.
  */
 int

@@ -756,10 +887,15 @@
                 rd_cnt = 0;
         } else {
                 inbuf = buf;
         }
 
+        if (setup_subproc_env() != Z_OK) {
+                zerror(zlogp, B_FALSE, "failed to setup environment");
+                return (-1);
+        }
+
         file = popen(cmdbuf, "r");
         if (file == NULL) {
                 zerror(zlogp, B_TRUE, "could not launch: %s", cmdbuf);
                 return (-1);
         }

@@ -1461,10 +1597,11 @@
                 switch (cmd) {
                 case Z_READY:
                         rval = zone_ready(zlogp, Z_MNT_BOOT, zstate);
                         if (rval == 0)
                                 eventstream_write(Z_EVT_ZONE_READIED);
+                        zcons_statechanged();
                         break;
                 case Z_BOOT:
                 case Z_FORCEBOOT:
                         eventstream_write(Z_EVT_ZONE_BOOTING);
                         if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))

@@ -1471,10 +1608,11 @@
                             == 0) {
                                 rval = zone_bootup(zlogp, zargp->bootbuf,
                                     zstate);
                         }
                         audit_put_record(zlogp, uc, rval, "boot");
+                        zcons_statechanged();
                         if (rval != 0) {
                                 bringup_failure_recovery = B_TRUE;
                                 (void) zone_halt(zlogp, B_FALSE, B_FALSE,
                                     zstate);
                                 eventstream_write(Z_EVT_ZONE_BOOTFAILED);

@@ -1593,10 +1731,11 @@
                         (void) strlcpy(boot_args, zargp->bootbuf,
                             sizeof (boot_args));
                         eventstream_write(Z_EVT_ZONE_BOOTING);
                         rval = zone_bootup(zlogp, zargp->bootbuf, zstate);
                         audit_put_record(zlogp, uc, rval, "boot");
+                        zcons_statechanged();
                         if (rval != 0) {
                                 bringup_failure_recovery = B_TRUE;
                                 (void) zone_halt(zlogp, B_FALSE, B_TRUE,
                                     zstate);
                                 eventstream_write(Z_EVT_ZONE_BOOTFAILED);

@@ -1607,10 +1746,11 @@
                         if (kernelcall) /* Invalid; can't happen */
                                 abort();
                         if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate))
                             != 0)
                                 break;
+                        zcons_statechanged();
                         eventstream_write(Z_EVT_ZONE_HALTED);
                         break;
                 case Z_SHUTDOWN:
                 case Z_REBOOT:
                 case Z_NOTE_UNINSTALLING:

@@ -1654,10 +1794,11 @@
                 switch (cmd) {
                 case Z_READY:
                         if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate))
                             != 0)
                                 break;
+                        zcons_statechanged();
                         if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) == 0)
                                 eventstream_write(Z_EVT_ZONE_READIED);
                         else
                                 eventstream_write(Z_EVT_ZONE_HALTED);
                         break;

@@ -1679,10 +1820,11 @@
                         }
                         if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate))
                             != 0)
                                 break;
                         eventstream_write(Z_EVT_ZONE_HALTED);
+                        zcons_statechanged();
                         break;
                 case Z_REBOOT:
                         (void) strlcpy(boot_args, zargp->bootbuf,
                             sizeof (boot_args));
                         eventstream_write(Z_EVT_ZONE_REBOOTING);

@@ -1690,12 +1832,13 @@
                             != 0) {
                                 eventstream_write(Z_EVT_ZONE_BOOTFAILED);
                                 boot_args[0] = '\0';
                                 break;
                         }
-                        if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))
-                            != 0) {
+                        zcons_statechanged();
+                        if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) !=
+                            0) {
                                 eventstream_write(Z_EVT_ZONE_BOOTFAILED);
                                 boot_args[0] = '\0';
                                 break;
                         }
                         rval = zone_bootup(zlogp, zargp->bootbuf, zstate);