63
64 #include <arpa/inet.h>
65 #include <netdb.h>
66
67 #include <libxml/xmlmemory.h>
68 #include <libxml/parser.h>
69
70 #include <libdevinfo.h>
71 #include <uuid/uuid.h>
72 #include <dirent.h>
73 #include <libbrand.h>
74
75 #include <libzonecfg.h>
76 #include "zonecfg_impl.h"
77
78 #define _PATH_TMPFILE "/zonecfg.XXXXXX"
79 #define ZONE_CB_RETRY_COUNT 10
80 #define ZONE_EVENT_PING_SUBCLASS "ping"
81 #define ZONE_EVENT_PING_PUBLISHER "solaris"
82
83 /* Hard-code the DTD element/attribute/entity names just once, here. */
84 #define DTD_ELEM_ATTR (const xmlChar *) "attr"
85 #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
86 #define DTD_ELEM_DEVICE (const xmlChar *) "device"
87 #define DTD_ELEM_FS (const xmlChar *) "filesystem"
88 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
89 #define DTD_ELEM_NET (const xmlChar *) "network"
90 #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
91 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
92 #define DTD_ELEM_ZONE (const xmlChar *) "zone"
93 #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
94 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
95 #define DTD_ELEM_PSET (const xmlChar *) "pset"
96 #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
97 #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
98 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
99 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
100 #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
101 #define DTD_ELEM_SECFLAGS (const xmlChar *) "security-flags"
102
115 #define DTD_ATTR_NAME (const xmlChar *) "name"
116 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
117 #define DTD_ATTR_POOL (const xmlChar *) "pool"
118 #define DTD_ATTR_PRIV (const xmlChar *) "priv"
119 #define DTD_ATTR_RAW (const xmlChar *) "raw"
120 #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
121 #define DTD_ATTR_TYPE (const xmlChar *) "type"
122 #define DTD_ATTR_VALUE (const xmlChar *) "value"
123 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
124 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
125 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
126 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
127 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
128 #define DTD_ATTR_VERSION (const xmlChar *) "version"
129 #define DTD_ATTR_ID (const xmlChar *) "id"
130 #define DTD_ATTR_UID (const xmlChar *) "uid"
131 #define DTD_ATTR_GID (const xmlChar *) "gid"
132 #define DTD_ATTR_MODE (const xmlChar *) "mode"
133 #define DTD_ATTR_ACL (const xmlChar *) "acl"
134 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
135 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
136 #define DTD_ATTR_USER (const xmlChar *) "user"
137 #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
138 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
139 #define DTD_ATTR_DEFAULT (const xmlChar *) "default"
140 #define DTD_ATTR_LOWER (const xmlChar *) "lower"
141 #define DTD_ATTR_UPPER (const xmlChar *) "upper"
142
143
144 #define DTD_ENTITY_BOOLEAN "boolean"
145 #define DTD_ENTITY_DEVPATH "devpath"
146 #define DTD_ENTITY_DRIVER "driver"
147 #define DTD_ENTITY_DRVMIN "drv_min"
148 #define DTD_ENTITY_FALSE "false"
149 #define DTD_ENTITY_INT "int"
150 #define DTD_ENTITY_STRING "string"
151 #define DTD_ENTITY_TRUE "true"
152 #define DTD_ENTITY_UINT "uint"
153
154 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
5668 if (err < 0)
5669 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5670
5671 return (Z_OK);
5672 }
5673
5674 if (strcmp(zone_name, "global") == 0)
5675 return (zonecfg_default_brand(brandname, rp_sz));
5676
5677 if ((handle = zonecfg_init_handle()) == NULL)
5678 return (Z_NOMEM);
5679
5680 err = zonecfg_get_handle((char *)zone_name, handle);
5681 if (err == Z_OK)
5682 err = zonecfg_get_brand(handle, brandname, rp_sz);
5683
5684 zonecfg_fini_handle(handle);
5685 return (err);
5686 }
5687
5688 /*
5689 * Return the appropriate root for the active /dev.
5690 * For normal zone, the path is $ZONEPATH/root;
5691 * for scratch zone, the dev path is $ZONEPATH/lu.
5692 */
5693 int
5694 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5695 {
5696 int err;
5697 char *suffix;
5698 zone_state_t state;
5699
5700 /* This function makes sense for non-global zones only. */
5701 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5702 return (Z_BOGUS_ZONE_NAME);
5703 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5704 return (err);
5705
5706 if (zone_get_state(zone_name, &state) == Z_OK &&
5707 state == ZONE_STATE_MOUNTED)
|
63
64 #include <arpa/inet.h>
65 #include <netdb.h>
66
67 #include <libxml/xmlmemory.h>
68 #include <libxml/parser.h>
69
70 #include <libdevinfo.h>
71 #include <uuid/uuid.h>
72 #include <dirent.h>
73 #include <libbrand.h>
74
75 #include <libzonecfg.h>
76 #include "zonecfg_impl.h"
77
78 #define _PATH_TMPFILE "/zonecfg.XXXXXX"
79 #define ZONE_CB_RETRY_COUNT 10
80 #define ZONE_EVENT_PING_SUBCLASS "ping"
81 #define ZONE_EVENT_PING_PUBLISHER "solaris"
82
83 #define DEBUGID_FILE "/etc/zones/did.txt"
84
85 /* Hard-code the DTD element/attribute/entity names just once, here. */
86 #define DTD_ELEM_ATTR (const xmlChar *) "attr"
87 #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
88 #define DTD_ELEM_DEVICE (const xmlChar *) "device"
89 #define DTD_ELEM_FS (const xmlChar *) "filesystem"
90 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
91 #define DTD_ELEM_NET (const xmlChar *) "network"
92 #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
93 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
94 #define DTD_ELEM_ZONE (const xmlChar *) "zone"
95 #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
96 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
97 #define DTD_ELEM_PSET (const xmlChar *) "pset"
98 #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
99 #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
100 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
101 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
102 #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
103 #define DTD_ELEM_SECFLAGS (const xmlChar *) "security-flags"
104
117 #define DTD_ATTR_NAME (const xmlChar *) "name"
118 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
119 #define DTD_ATTR_POOL (const xmlChar *) "pool"
120 #define DTD_ATTR_PRIV (const xmlChar *) "priv"
121 #define DTD_ATTR_RAW (const xmlChar *) "raw"
122 #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
123 #define DTD_ATTR_TYPE (const xmlChar *) "type"
124 #define DTD_ATTR_VALUE (const xmlChar *) "value"
125 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
126 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
127 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
128 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
129 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
130 #define DTD_ATTR_VERSION (const xmlChar *) "version"
131 #define DTD_ATTR_ID (const xmlChar *) "id"
132 #define DTD_ATTR_UID (const xmlChar *) "uid"
133 #define DTD_ATTR_GID (const xmlChar *) "gid"
134 #define DTD_ATTR_MODE (const xmlChar *) "mode"
135 #define DTD_ATTR_ACL (const xmlChar *) "acl"
136 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
137 #define DTD_ATTR_DID (const xmlChar *) "debugid"
138 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
139 #define DTD_ATTR_USER (const xmlChar *) "user"
140 #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
141 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
142 #define DTD_ATTR_DEFAULT (const xmlChar *) "default"
143 #define DTD_ATTR_LOWER (const xmlChar *) "lower"
144 #define DTD_ATTR_UPPER (const xmlChar *) "upper"
145
146
147 #define DTD_ENTITY_BOOLEAN "boolean"
148 #define DTD_ENTITY_DEVPATH "devpath"
149 #define DTD_ENTITY_DRIVER "driver"
150 #define DTD_ENTITY_DRVMIN "drv_min"
151 #define DTD_ENTITY_FALSE "false"
152 #define DTD_ENTITY_INT "int"
153 #define DTD_ENTITY_STRING "string"
154 #define DTD_ENTITY_TRUE "true"
155 #define DTD_ENTITY_UINT "uint"
156
157 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
5671 if (err < 0)
5672 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5673
5674 return (Z_OK);
5675 }
5676
5677 if (strcmp(zone_name, "global") == 0)
5678 return (zonecfg_default_brand(brandname, rp_sz));
5679
5680 if ((handle = zonecfg_init_handle()) == NULL)
5681 return (Z_NOMEM);
5682
5683 err = zonecfg_get_handle((char *)zone_name, handle);
5684 if (err == Z_OK)
5685 err = zonecfg_get_brand(handle, brandname, rp_sz);
5686
5687 zonecfg_fini_handle(handle);
5688 return (err);
5689 }
5690
5691 /*
5692 * Atomically get a new zone_did value. The currently allocated value
5693 * is stored in /etc/zones/did.txt. Lock the file, read the current value,
5694 * increment, save the new value and unlock the file. Return the new value
5695 * or -1 if there was an error. The ID namespace is large enough that we
5696 * don't worry about recycling an ID when a zone is deleted.
5697 */
5698 static zoneid_t
5699 new_zone_did()
5700 {
5701 int fd;
5702 int len;
5703 int val;
5704 struct flock lck;
5705 char pathbuf[PATH_MAX];
5706 char buf[80];
5707
5708 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
5709 DEBUGID_FILE) >= sizeof (pathbuf)) {
5710 printf(gettext("alternate root path is too long"));
5711 return (-1);
5712 }
5713
5714 if ((fd = open(pathbuf, O_RDWR | O_CREAT,
5715 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
5716 perror("new_zone_did open failed");
5717 return (-1);
5718 }
5719
5720 /* Initialize the lock. */
5721 lck.l_whence = SEEK_SET;
5722 lck.l_start = 0;
5723 lck.l_len = 0;
5724
5725 /* Wait until we acquire an exclusive lock on the file. */
5726 lck.l_type = F_WRLCK;
5727 if (fcntl(fd, F_SETLKW, &lck) == -1) {
5728 perror("new_zone_did lock failed");
5729 (void) close(fd);
5730 return (-1);
5731 }
5732
5733 /* Get currently allocated value */
5734 len = read(fd, buf, sizeof (buf));
5735 if (len == -1) {
5736 perror("new_zone_did read failed");
5737 val = -1;
5738 } else {
5739 if (lseek(fd, 0L, SEEK_SET) == -1) {
5740 perror("new_zone_did seek failed");
5741 val = -1;
5742 } else {
5743 if (len == 0) {
5744 /* Just created the file, initialize at 1 */
5745 val = 1;
5746 } else {
5747 val = atoi(buf);
5748 val++;
5749 }
5750
5751 (void) snprintf(buf, sizeof (buf), "%d\n", val);
5752 len = strlen(buf);
5753
5754 /* Save newly allocated value */
5755 if (write(fd, buf, len) == -1) {
5756 perror("new_zone_did write failed");
5757 val = -1;
5758 }
5759 }
5760 }
5761
5762 /* Release the file lock. */
5763 lck.l_type = F_UNLCK;
5764 if (fcntl(fd, F_SETLK, &lck) == -1) {
5765 perror("new_zone_did unlock failed");
5766 val = -1;
5767 }
5768
5769 if (close(fd) != 0)
5770 perror("new_zone_did close failed");
5771
5772 return (val);
5773 }
5774
5775 /*
5776 * Called by zoneadmd to get the zone's debug ID.
5777 * If the zone doesn't already have an ID, a new one is generated and
5778 * persistently saved onto the zone. Normally either zoneadm or zonecfg
5779 * will assign a new ID for the zone, so zoneadmd should never have to
5780 * generate one, but we also handle that here just to be paranoid.
5781 */
5782 zoneid_t
5783 zone_get_did(char *zone_name)
5784 {
5785 int res;
5786 zoneid_t new_did;
5787 zone_dochandle_t handle;
5788 char did_str[80];
5789
5790 if ((handle = zonecfg_init_handle()) == NULL)
5791 return (getpid());
5792
5793 if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
5794 return (getpid());
5795
5796 res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5797
5798 /* If the zone already has an assigned debug ID, return it. */
5799 if (res == Z_OK && did_str[0] != '\0') {
5800 zonecfg_fini_handle(handle);
5801 return (atoi(did_str));
5802 }
5803
5804 /*
5805 * The zone doesn't have an assigned debug ID yet, generate one and
5806 * save it as part of the zone definition.
5807 */
5808 if ((new_did = new_zone_did()) == -1) {
5809 /*
5810 * We should really never hit this block of code.
5811 * Generating a new ID failed for some reason. Use the current
5812 * pid as a temporary ID so that the zone can continue to boot
5813 * but we don't persistently save this temporary ID on the zone.
5814 */
5815 zonecfg_fini_handle(handle);
5816 return (getpid());
5817 }
5818
5819 /* Now persistently save this new ID onto the zone. */
5820 (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5821 (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5822 (void) zonecfg_save(handle);
5823
5824 zonecfg_fini_handle(handle);
5825 return (new_did);
5826 }
5827
5828 zoneid_t
5829 zonecfg_get_did(zone_dochandle_t handle)
5830 {
5831 char did_str[80];
5832 int err;
5833 zoneid_t did;
5834
5835 err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5836 if (err == Z_OK && did_str[0] != '\0')
5837 did = atoi(did_str);
5838 else
5839 did = -1;
5840
5841 return (did);
5842 }
5843
5844 void
5845 zonecfg_set_did(zone_dochandle_t handle)
5846 {
5847 zoneid_t new_did;
5848 char did_str[80];
5849
5850 if ((new_did = new_zone_did()) == -1)
5851 return;
5852 (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5853 (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5854 }
5855
5856 /*
5857 * Return the appropriate root for the active /dev.
5858 * For normal zone, the path is $ZONEPATH/root;
5859 * for scratch zone, the dev path is $ZONEPATH/lu.
5860 */
5861 int
5862 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5863 {
5864 int err;
5865 char *suffix;
5866 zone_state_t state;
5867
5868 /* This function makes sense for non-global zones only. */
5869 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5870 return (Z_BOGUS_ZONE_NAME);
5871 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5872 return (err);
5873
5874 if (zone_get_state(zone_name, &state) == Z_OK &&
5875 state == ZONE_STATE_MOUNTED)
|