diff options
Diffstat (limited to 'usr/src/lib/libzonecfg')
| -rw-r--r-- | usr/src/lib/libzonecfg/Makefile.com | 4 | ||||
| -rw-r--r-- | usr/src/lib/libzonecfg/common/libzonecfg.c | 1621 | ||||
| -rw-r--r-- | usr/src/lib/libzonecfg/common/mapfile-vers | 12 |
3 files changed, 418 insertions, 1219 deletions
diff --git a/usr/src/lib/libzonecfg/Makefile.com b/usr/src/lib/libzonecfg/Makefile.com index b7999ed78b..f2b2bd03b9 100644 --- a/usr/src/lib/libzonecfg/Makefile.com +++ b/usr/src/lib/libzonecfg/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -33,7 +33,7 @@ include ../../Makefile.lib LIBS = $(DYNLIB) $(LINTLIB) LDLIBS += -lc -lsocket -lnsl -luuid -lnvpair -lsysevent -lsec -lbrand \ - -lpool -lscf -lproc -luutil + -lpool -lscf -lproc -luutil -lbsm # DYNLIB libraries do not have lint libs and are not linted $(DYNLIB) := LDLIBS += -lxml2 diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c index e538cc6108..75fb6700c2 100644 --- a/usr/src/lib/libzonecfg/common/libzonecfg.c +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c @@ -52,6 +52,8 @@ #include <libproc.h> #include <sys/priocntl.h> #include <libuutil.h> +#include <wait.h> +#include <bsm/adt.h> #include <arpa/inet.h> #include <netdb.h> @@ -138,22 +140,12 @@ #define DETACHED "SUNWdetached.xml" #define ATTACH_FORCED "SUNWattached.xml" -#define PKG_PATH "/var/sadm/pkg" -#define CONTENTS_FILE "/var/sadm/install/contents" -#define SUNW_PKG_ALL_ZONES "SUNW_PKG_ALLZONES=true\n" -#define SUNW_PKG_THIS_ZONE "SUNW_PKG_THISZONE=true\n" -#define VERSION "VERSION=" -#define PATCHLIST "PATCHLIST=" -#define PATCHINFO "PATCH_INFO_" -#define PKGINFO_RD_LEN 128 #define TMP_POOL_NAME "SUNWtmp_%s" #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9) #define RCAP_SERVICE "system/rcap:default" #define POOLD_SERVICE "system/pools/dynamic:default" -enum zn_ipd_fs {ZONE_IPD, ZONE_FS}; - /* * rctl alias definitions * @@ -216,31 +208,13 @@ struct znotify { int zn_failure_count; }; -struct zone_pkginfo { - boolean_t zpi_all_zones; - boolean_t zpi_this_zone; - int zpi_patch_cnt; - char *zpi_version; - char **zpi_patchinfo; -}; - -typedef struct { - uu_avl_node_t patch_node; - char *patch_num; - char *patch_vers; - uu_list_t *obs_patches; -} patch_node_t; +/* used to track nested zone-lock operations */ +static int zone_lock_cnt = 0; -typedef struct { - uu_list_node_t link; - char *patch_num; -} obs_patch_node_t; - -typedef struct { - uu_avl_t *obs_patches_avl; - zone_dochandle_t handle; - int res; -} patch_parms_t; +/* used to communicate lock status to children */ +#define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD" +static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1"; +static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0"; char *zonecfg_root = ""; @@ -1329,12 +1303,6 @@ zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) if (zonecfg_check_handle(handle) != Z_OK) return (Z_BAD_HANDLE); - /* - * We can only detach if we have taken a sw inventory. - */ - if (!handle->zone_dh_sw_inv) - return (Z_INVAL); - if (flags & ZONE_DRY_RUN) { (void) strlcpy(migpath, "-", sizeof (migpath)); } else { @@ -2468,22 +2436,58 @@ zonecfg_modify_dev( return (Z_OK); } -/* Lock to serialize all zonecfg_devwalks */ +/* Lock to serialize all devwalks */ static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; /* - * Global variables used to pass data from zonecfg_devwalk to the nftw + * Global variables used to pass data from zonecfg_dev_manifest to the nftw * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* - * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. + * parameter and g_devwalk_cb is really the *cb parameter from + * zonecfg_dev_manifest. */ -static void *g_devwalk_data; +typedef struct __g_devwalk_data *g_devwalk_data_t; +static g_devwalk_data_t g_devwalk_data; static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, void *); static size_t g_devwalk_skip_prefix; /* - * This is the nftw call-back function used by zonecfg_devwalk. It is - * responsible for calling the actual call-back that is passed in to - * zonecfg_devwalk as the *cb argument. + * zonecfg_dev_manifest call-back function used during detach to generate the + * dev info in the manifest. + */ +static int +get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, + const char *acl, void *hdl) +{ + zone_dochandle_t handle = (zone_dochandle_t)hdl; + xmlNodePtr newnode; + xmlNodePtr cur; + int err; + char buf[128]; + + if ((err = operation_prep(handle)) != Z_OK) + return (err); + + cur = handle->zone_dh_cur; + newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); + if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) + return (err); + (void) snprintf(buf, sizeof (buf), "%lu", uid); + if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) + return (err); + (void) snprintf(buf, sizeof (buf), "%lu", gid); + if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) + return (err); + (void) snprintf(buf, sizeof (buf), "%o", mode); + if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) + return (err); + if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) + return (err); + return (Z_OK); +} + +/* + * This is the nftw call-back function used by zonecfg_dev_manifest. It is + * responsible for calling the actual call-back. */ /* ARGSUSED2 */ static int @@ -2514,19 +2518,17 @@ zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, } /* - * Walk the dev tree for the zone specified by hdl and call the call-back (cb) - * function for each entry in the tree. The call-back will be passed the - * name, uid, gid, mode, acl string and the void *data input parameter - * for each dev entry. + * Walk the dev tree for the zone specified by hdl and call the + * get_detach_dev_entry call-back function for each entry in the tree. The + * call-back will be passed the name, uid, gid, mode, acl string and the + * handle input parameter for each dev entry. * - * Data is passed to the zonecfg_devwalk_cb through the global variables + * Data is passed to get_detach_dev_entry through the global variables * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The - * zonecfg_devwalk_cb function will actually call *cb. + * zonecfg_devwalk_cb function will actually call get_detach_dev_entry. */ int -zonecfg_devwalk(zone_dochandle_t hdl, - int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), - void *data) +zonecfg_dev_manifest(zone_dochandle_t hdl) { char path[MAXPATHLEN]; int ret; @@ -2536,16 +2538,16 @@ zonecfg_devwalk(zone_dochandle_t hdl, if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) return (Z_TOO_BIG); - g_devwalk_skip_prefix = strlen(path) + 1; /* - * We have to serialize all zonecfg_devwalks in the same process + * We have to serialize all devwalks in the same process * (which should be fine), since nftw() is so badly designed. */ (void) pthread_mutex_lock(&zonecfg_devwalk_lock); - g_devwalk_data = data; - g_devwalk_cb = cb; + g_devwalk_skip_prefix = strlen(path) + 1; + g_devwalk_data = (g_devwalk_data_t)hdl; + g_devwalk_cb = get_detach_dev_entry; (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); @@ -3155,6 +3157,64 @@ zonecfg_remove_rctl_value( return (Z_NO_PROPERTY_ID); } +void +zonecfg_set_swinv(zone_dochandle_t handle) +{ + handle->zone_dh_sw_inv = B_TRUE; +} + +/* + * Add the pkg to the sw inventory on the handle. + */ +int +zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version) +{ + xmlNodePtr newnode; + xmlNodePtr cur; + int err; + + if ((err = operation_prep(handle)) != Z_OK) + return (err); + + cur = handle->zone_dh_cur; + newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); + if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) + return (err); + if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) + return (err); + return (Z_OK); +} + +int +zonecfg_add_patch(zone_dochandle_t handle, char *id, void **pnode) +{ + xmlNodePtr node = (xmlNodePtr)*pnode; + xmlNodePtr cur; + int err; + + if ((err = operation_prep(handle)) != Z_OK) + return (err); + + cur = handle->zone_dh_cur; + node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); + if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) + return (err); + *pnode = (void *)node; + return (Z_OK); +} + +int +zonecfg_add_patch_obs(char *id, void *cur) +{ + xmlNodePtr node; + int err; + + node = xmlNewTextChild((xmlNodePtr)cur, NULL, DTD_ELEM_OBSOLETES, NULL); + if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) + return (err); + return (Z_OK); +} + char * zonecfg_strerror(int errnum) { @@ -6813,1261 +6873,392 @@ zonecfg_enddevperment(zone_dochandle_t handle) return (zonecfg_endent(handle)); } -/* - * Maintain a space separated list of unique pkg names. PATH_MAX is used in - * the pkg code as the maximum size for a pkg name. - */ -static int -add_pkg_to_str(char **str, char *pkg) +/* PRINTFLIKE1 */ +static void +zerror(const char *zone_name, const char *fmt, ...) { - int len, newlen; - char tstr[PATH_MAX + 3]; - char *tmp; - - len = strlen(pkg); - if (*str == NULL) { - /* space for str + 2 spaces + NULL */ - if ((*str = (char *)malloc(len + 3)) == NULL) - return (Z_NOMEM); - (void) snprintf(*str, len + 3, " %s ", pkg); - return (Z_OK); - } + va_list alist; - (void) snprintf(tstr, sizeof (tstr), " %s ", pkg); - if (strstr(*str, tstr) != NULL) - return (Z_OK); - - /* space for str + 1 space + NULL */ - newlen = strlen(*str) + len + 2; - if ((tmp = (char *)realloc(*str, newlen)) == NULL) - return (Z_NOMEM); - *str = tmp; - (void) strlcat(*str, pkg, newlen); - (void) strlcat(*str, " ", newlen); - return (Z_OK); + va_start(alist, fmt); + (void) fprintf(stderr, "zone '%s': ", zone_name); + (void) vfprintf(stderr, fmt, alist); + (void) fprintf(stderr, "\n"); + va_end(alist); } -/* - * Process a list of pkgs from an entry in the contents file, adding each pkg - * name to the list of pkgs. - * - * It is possible for the pkg name to be preceeded by a special character - * which indicates some bookkeeping information for pkging. Check if the - * first char is not an Alpha char. If so, skip over it. - */ -static int -add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn) +static void +zperror(const char *str) { - char *p; - int pkg_cnt = *pcnt; - char **pkgs = *plist; - int res = Z_OK; - - while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { - char **tmpp; - int i; - - /* skip over any special pkg bookkeeping char */ - if (!isalpha(*p)) { - p++; - if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK) - break; - } - - /* Check if the pkg is already in the list */ - for (i = 0; i < pkg_cnt; i++) { - if (strcmp(p, pkgs[i]) == 0) - break; - } - - if (i < pkg_cnt) - continue; - - /* The pkg is not in the list; add it. */ - if ((tmpp = (char **)realloc(pkgs, - sizeof (char *) * (pkg_cnt + 1))) == NULL) { - res = Z_NOMEM; - break; - } - pkgs = tmpp; - - if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { - res = Z_NOMEM; - break; - } - pkg_cnt++; - } - - *plist = pkgs; - *pcnt = pkg_cnt; - - return (res); + (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); } /* - * Process an entry from the contents file (type "directory"). If the - * directory path is in the list of ipds and is not under a lofs mount within - * the ipd then add the associated list of pkgs to the pkg list. The input - * parameter "entry" will be broken up by the parser within this function so - * its value will be modified when this function exits. + * The following three routines implement a simple locking mechanism to + * ensure that only one instance of zoneadm at a time is able to manipulate + * a given zone. The lock is built on top of an fcntl(2) lock of + * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock. If a zoneadm instance + * can grab that lock, it is allowed to manipulate the zone. + * + * Since zoneadm may call external applications which in turn invoke + * zoneadm again, we introduce the notion of "lock inheritance". Any + * instance of zoneadm that has another instance in its ancestry is assumed + * to be acting on behalf of the original zoneadm, and is thus allowed to + * manipulate its zone. * - * The entries we are looking for will look something like: - * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... + * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment + * variable. When zoneadm is granted a lock on its zone, this environment + * variable is set to 1. When it releases the lock, the variable is set to + * 0. Since a child process inherits its parent's environment, checking + * the state of this variable indicates whether or not any ancestor owns + * the lock. */ -static int -get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt, - char **pkg_warn) -{ - char *f1; - char *f2; - char *lastp; - int i; - char *nlp; - - if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || - (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) - return (Z_OK); - - /* Check if this directory entry is in the list of ipds. */ - for (i = 0; ipds[i] != NULL; i++) { - char wildcard[MAXPATHLEN]; - - /* - * We want to match on the path and any other directory - * entries under this path. When we use FNM_PATHNAME then - * that means '/' will not be matched by a wildcard (*) so - * we omit FNM_PATHNAME on the call with the wildcard matching. - */ - (void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]); - if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 || - fnmatch(wildcard, f1, 0) == 0) { - /* It looks like we do want the pkgs for this path. */ - break; +void +zonecfg_init_lock_file(const char *zone_name, char **lock_env) +{ + *lock_env = getenv(LOCK_ENV_VAR); + if (*lock_env == NULL) { + if (putenv(zoneadm_lock_not_held) != 0) { + zerror(zone_name, gettext("could not set env: %s"), + strerror(errno)); + exit(1); } + } else { + if (atoi(*lock_env) == 1) + zone_lock_cnt = 1; } +} - /* This entry did not match any of the ipds. */ - if (ipds[i] == NULL) - return (Z_OK); - +void +zonecfg_release_lock_file(const char *zone_name, int lockfd) +{ /* - * Check if there is a fs mounted under the ipd. If so, ignore this - * entry. + * If we are cleaning up from a failed attempt to lock the zone for + * the first time, we might have a zone_lock_cnt of 0. In that + * error case, we don't want to do anything but close the lock + * file. */ - for (i = 0; fss[i] != NULL; i++) { - char wildcard[MAXPATHLEN]; - - (void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]); - if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 || - fnmatch(wildcard, f1, 0) == 0) { - /* We should ignore this path. */ - break; + assert(zone_lock_cnt >= 0); + if (zone_lock_cnt > 0) { + assert(getenv(LOCK_ENV_VAR) != NULL); + assert(atoi(getenv(LOCK_ENV_VAR)) == 1); + if (--zone_lock_cnt > 0) { + assert(lockfd == -1); + return; + } + if (putenv(zoneadm_lock_not_held) != 0) { + zerror(zone_name, gettext("could not set env: %s"), + strerror(errno)); + exit(1); } } + assert(lockfd >= 0); + (void) close(lockfd); +} - /* If not null, then we matched an fs mount point so ignore entry. */ - if (fss[i] != NULL) - return (Z_OK); +int +zonecfg_grab_lock_file(const char *zone_name, int *lockfd) +{ + char pathbuf[PATH_MAX]; + struct flock flock; /* - * We do want the pkgs for this entry. First, skip over the next 4 - * fields in the entry so that we call add_pkg_list starting with the - * pkg names. + * If we already have the lock, we can skip this expensive song + * and dance. */ - for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++) - ; - /* If there are < 4 fields this entry is corrupt, just skip it. */ - if (i < 4) + assert(zone_lock_cnt >= 0); + assert(getenv(LOCK_ENV_VAR) != NULL); + if (zone_lock_cnt > 0) { + assert(atoi(getenv(LOCK_ENV_VAR)) == 1); + zone_lock_cnt++; + *lockfd = -1; return (Z_OK); - - /* strip newline from the line */ - nlp = (lastp + strlen(lastp) - 1); - if (*nlp == '\n') - *nlp = '\0'; - - return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn)); -} - -/* - * Read an entry from a pkginfo or contents file. Some of these lines can - * either be arbitrarily long or be continued by a backslash at the end of - * the line. This function coalesces lines that are longer than the read - * buffer, and lines that are continued, into one buffer which is returned. - * The caller must free this memory. NULL is returned when we hit EOF or - * if we run out of memory (errno is set to ENOMEM). - */ -static char * -read_pkg_data(FILE *fp) -{ - char *start; - char *inp; - char *p; - int char_cnt = 0; - - errno = 0; - if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { - errno = ENOMEM; - return (NULL); } + assert(getenv(LOCK_ENV_VAR) != NULL); + assert(atoi(getenv(LOCK_ENV_VAR)) == 0); - inp = start; - while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { - int len; - - len = strlen(inp); - if (inp[len - 1] == '\n' && - (len == 1 || inp[len - 2] != '\\')) { - char_cnt = len; - break; - } - - if (inp[len - 2] == '\\') - char_cnt += len - 2; - else - char_cnt += PKGINFO_RD_LEN - 1; - - if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { - errno = ENOMEM; - break; - } - - start = p; - inp = start + char_cnt; - } - - if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { - free(start); - start = NULL; + if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(), + ZONES_TMPDIR) >= sizeof (pathbuf)) { + zerror(zone_name, gettext("alternate root path is too long")); + return (-1); } - - return (start); -} - -static void -free_ipd_pkgs(char **pkgs, int cnt) -{ - int i; - - for (i = 0; i < cnt; i++) - free(pkgs[i]); - free(pkgs); -} - -/* - * Get a list of the inherited pkg dirs or fs entries configured for the - * zone. The type parameter will be either ZONE_IPD or ZONE_FS. - */ -static int -get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list) -{ - int res; - struct zone_fstab fstab; - int cnt = 0; - char **entries = NULL; - int i; - int (*fp)(zone_dochandle_t, struct zone_fstab *); - - if (type == ZONE_IPD) { - fp = zonecfg_getipdent; - res = zonecfg_setipdent(handle); - } else { - fp = zonecfg_getfsent; - res = zonecfg_setfsent(handle); + if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) { + zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf, + strerror(errno)); + return (-1); } + (void) chmod(pathbuf, S_IRWXU); - if (res != Z_OK) - return (res); - - while (fp(handle, &fstab) == Z_OK) { - char **p; - - if ((p = (char **)realloc(entries, - sizeof (char *) * (cnt + 1))) == NULL) { - res = Z_NOMEM; - break; - } - entries = p; - - if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) { - res = Z_NOMEM; - break; - } - - cnt++; + /* + * One of these lock files is created for each zone (when needed). + * The lock files are not cleaned up (except on system reboot), + * but since there is only one per zone, there is no resource + * starvation issue. + */ + if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock", + zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) { + zerror(zone_name, gettext("alternate root path is too long")); + return (-1); } - - if (type == ZONE_IPD) - (void) zonecfg_endipdent(handle); - else - (void) zonecfg_endfsent(handle); - - /* Add a NULL terminating element. */ - if (res == Z_OK) { - char **p; - - if ((p = (char **)realloc(entries, - sizeof (char *) * (cnt + 1))) == NULL) { - res = Z_NOMEM; - } else { - entries = p; - entries[cnt] = NULL; - } + if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + zerror(zone_name, gettext("could not open %s: %s"), pathbuf, + strerror(errno)); + return (-1); } - - if (res != Z_OK) { - if (entries != NULL) { - for (i = 0; i < cnt; i++) - free(entries[i]); - free(entries); - } - return (res); + /* + * Lock the file to synchronize with other zoneadmds + */ + flock.l_type = F_WRLCK; + flock.l_whence = SEEK_SET; + flock.l_start = (off_t)0; + flock.l_len = (off_t)0; + if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) || + (putenv(zoneadm_lock_held) != 0)) { + zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf, + strerror(errno)); + zonecfg_release_lock_file(zone_name, *lockfd); + return (-1); } - - *list = entries; + zone_lock_cnt = 1; return (Z_OK); } -/* - * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the - * list of pkgs that deliver into those dirs. - */ -static int -get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) -{ - int res; - char **ipds; - char **fss; - int pkg_cnt = 0; - char **pkgs = NULL; - int i; - - if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK) - return (res); - - if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) { - for (i = 0; ipds[i] != NULL; i++) - free(ipds[i]); - free(ipds); - return (res); - } - - /* We only have to process the contents file if we have ipds. */ - if (ipds != NULL) { - FILE *fp; - - if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { - char *buf; - char *pkg_warn = NULL; - - while ((buf = read_pkg_data(fp)) != NULL) { - res = get_path_pkgs(buf, ipds, fss, &pkgs, - &pkg_cnt, &pkg_warn); - free(buf); - if (res != Z_OK) - break; - } - - (void) fclose(fp); - - if (pkg_warn != NULL) { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - "WARNING: package operation in progress " - "on the following packages:\n %s\n"), - pkg_warn); - free(pkg_warn); - } - } - } - - for (i = 0; ipds[i] != NULL; i++) - free(ipds[i]); - free(ipds); - - for (i = 0; fss[i] != NULL; i++) - free(fss[i]); - free(fss); - - if (res != Z_OK) { - free_ipd_pkgs(pkgs, pkg_cnt); - } else { - *pkg_list = pkgs; - *cnt = pkg_cnt; - } - - return (res); -} - -/* - * Return true if pkg_name is in the list of pkgs that deliver into an - * inherited pkg directory for the zone. - */ static boolean_t -dir_pkg(char *pkg_name, char **pkg_list, int cnt) +get_doorname(const char *zone_name, char *buffer) { - int i; - - for (i = 0; i < cnt; i++) { - if (strcmp(pkg_name, pkg_list[i]) == 0) - return (B_TRUE); - } - - return (B_FALSE); + return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH, + zonecfg_get_root(), zone_name) < PATH_MAX); } /* - * Keep track of obsoleted patches for this specific patch. We don't need to - * keep track of the patch version since once a patch is obsoleted, all prior - * versions are also obsolete and there won't be any new versions. + * system daemons are not audited. For the global zone, this occurs + * "naturally" since init is started with the default audit + * characteristics. Since zoneadmd is a system daemon and it starts + * init for a zone, it is necessary to clear out the audit + * characteristics inherited from whomever started zoneadmd. This is + * indicated by the audit id, which is set from the ruid parameter of + * adt_set_user(), below. */ -static int -add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool) -{ - obs_patch_node_t *obs; - - if (patch->obs_patches == NULL) { - if ((patch->obs_patches = uu_list_create(patches_pool, NULL, - 0)) == NULL) - return (Z_NOMEM); - } - - if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t))) - == NULL) - return (Z_NOMEM); - if ((obs->patch_num = strdup(num)) == NULL) { - free(obs); - return (Z_NOMEM); - } - - uu_list_node_init(obs, &obs->link, patches_pool); - (void) uu_list_insert_before(patch->obs_patches, NULL, obs); - - return (Z_OK); -} - -/* - * Keep track of obsoleted patches. We don't need to keep track of the patch - * version since once a patch is obsoleted, all prior versions are also - * obsolete and there won't be any new versions. - */ -static int -save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches) +static void +prepare_audit_context(const char *zone_name) { - patch_node_t *patch; - uu_avl_index_t where; - - if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) - return (Z_NOMEM); - - if ((patch->patch_num = strdup(num)) == NULL) { - free(patch); - return (Z_NOMEM); - } - - patch->patch_vers = NULL; - patch->obs_patches = NULL; + adt_session_data_t *ah; + char *failure = gettext("audit failure: %s"); - uu_avl_node_init(patch, &patch->patch_node, patches_pool); - - if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) { - free(patch->patch_num); - free(patch); - return (Z_OK); + if (adt_start_session(&ah, NULL, 0)) { + zerror(zone_name, failure, strerror(errno)); + return; } - - uu_avl_insert(obs_patches, patch, where); - return (Z_OK); -} - -/* - * Keep a list of patches for a pkg. If we see a newer version of a patch, - * we only keep track of the newer version. - */ -static boolean_t -save_patch(patch_node_t *patch, uu_avl_t *patches_avl) -{ - patch_node_t *existing; - uu_avl_index_t where; - - /* - * Check if this is a newer version of a patch we already have. - * If it is an older version of a patch we already have, ignore it. - */ - if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL, - &where)) != NULL) { - char *endptr; - ulong_t pvers, evers; - - pvers = strtoul(patch->patch_vers, &endptr, 10); - evers = strtoul(existing->patch_vers, &endptr, 10); - - if (pvers <= evers) - return (B_FALSE); - - /* - * Remove the lower version patch from the tree so we can - * insert the new higher version one. We also discard the - * obsolete patch list from the old version since the new - * version will have its own, likely different, list. - */ - uu_avl_remove(patches_avl, existing); - free(existing->patch_num); - free(existing->patch_vers); - if (existing->obs_patches != NULL) { - obs_patch_node_t *op; - void *cookie2 = NULL; - - while ((op = uu_list_teardown(existing->obs_patches, - &cookie2)) != NULL) { - free(op->patch_num); - free(op); - } - uu_list_destroy(existing->obs_patches); - } - free(existing); - - /* - * Now that the old one is gone, find the new location - * in the tree. - */ - (void) uu_avl_find(patches_avl, patch, NULL, &where); + if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, + ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) { + zerror(zone_name, failure, strerror(errno)); + (void) adt_end_session(ah); + return; } + if (adt_set_proc(ah)) + zerror(zone_name, failure, strerror(errno)); - uu_avl_insert(patches_avl, patch, where); - return (B_TRUE); -} - -/* - * Check if a patch is on the list of obsoleted patches. We don't need to - * check the patch version since once a patch is obsoleted, all prior versions - * are also obsolete and there won't be any new versions. - */ -static boolean_t -obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches) -{ - uu_avl_index_t where; - - if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) - return (B_TRUE); - - return (B_FALSE); + (void) adt_end_session(ah); } -/* ARGSUSED */ static int -patch_node_compare(const void *l_arg, const void *r_arg, void *private) +start_zoneadmd(const char *zone_name, boolean_t lock) { - patch_node_t *l = (patch_node_t *)l_arg; - patch_node_t *r = (patch_node_t *)r_arg; - char *endptr; - ulong_t lnum, rnum; + char doorpath[PATH_MAX]; + pid_t child_pid; + int error = -1; + int doorfd, lockfd; + struct door_info info; - lnum = strtoul(l->patch_num, &endptr, 10); - rnum = strtoul(r->patch_num, &endptr, 10); - - if (lnum > rnum) - return (1); - if (lnum < rnum) + if (!get_doorname(zone_name, doorpath)) return (-1); - return (0); -} - -/* - * Parse the patchinfo string for the patch. - * - * We are parsing entries of the form: - * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ - * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ - * 119255-06 Incompatibles: - * - * A backed out patch will have "backed out\n" as the status. We should - * skip these patches. We also ignore any entries that seem to be - * corrupted. Obsolete patches are saved in the obs_patches parameter - * AVL list. - */ -static int -parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl, - uu_avl_t *obs_patches, uu_list_pool_t *list_pool) -{ - char *p; - char *lastp; - char *ep; - char *pvers; - boolean_t add_info = B_FALSE; - patch_node_t *patch; - if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1)) - return (Z_OK); - - /* Skip over "PATCH_INFO_" to get the patch id. */ - p = patchinfo + sizeof (PATCHINFO) - 1; - if ((ep = strchr(p, '=')) == NULL) - return (Z_OK); - - *ep++ = '\0'; - - /* Ignore all but installed patches. */ - if (strncmp(ep, "Installed:", 10) != 0) - return (Z_OK); - - /* remove newline */ - lastp = (ep + strlen(ep) - 1); - if (*lastp == '\n') - *lastp = '\0'; - - if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) - return (Z_NOMEM); - - if ((pvers = strchr(p, '-')) != NULL) - *pvers++ = '\0'; - else - pvers = ""; - - if ((patch->patch_num = strdup(p)) == NULL) { - free(patch); - return (Z_NOMEM); - } - if ((patch->patch_vers = strdup(pvers)) == NULL) { - free(patch->patch_num); - free(patch); - return (Z_NOMEM); - } - patch->obs_patches = NULL; - - uu_avl_node_init(patch, &patch->patch_node, patches_pool); - if (!save_patch(patch, patches_avl)) { - free(patch->patch_num); - free(patch->patch_vers); - assert(patch->obs_patches == NULL); - free(patch); - return (Z_OK); - } + if (lock) + if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK) + return (-1); /* - * Start with the first token. This will probably be "Installed:". - * If we can't tokenize this entry, just return. + * Now that we have the lock, re-confirm that the daemon is + * *not* up and working fine. If it is still down, we have a green + * light to start it. */ - if ((p = strtok_r(ep, " ", &lastp)) == NULL) - return (Z_OK); - - do { - if (strcmp(p, "Installed:") == 0 || - strcmp(p, "Requires:") == 0 || - strcmp(p, "From:") == 0 || - strcmp(p, "Incompatibles:") == 0) { - add_info = B_FALSE; - continue; - } else if (strcmp(p, "Obsoletes:") == 0) { - add_info = B_TRUE; - continue; + if ((doorfd = open(doorpath, O_RDONLY)) < 0) { + if (errno != ENOENT) { + zperror(doorpath); + goto out; } - - if (!add_info) - continue; - - if ((pvers = strchr(p, '-')) != NULL) - *pvers = '\0'; - - /* - * We save all of the obsolete patches in one big list in the - * obs_patches AVL tree so that we know not to output those as - * part of the sw dependencies. However, we also need to save - * the obsolete patch information for this sepcific patch so - * so that we can do the cross manifest patch checking - * correctly. - */ - if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK) - return (Z_NOMEM); - if (add_obs_patch(patch, p, list_pool) != Z_OK) - return (Z_NOMEM); - } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); - - return (Z_OK); -} - -/* - * AVL walker callback used to add patch to XML manifest. - * - * PATH_MAX is used in the pkg/patch code as the maximum size for the patch - * number/version string. - */ -static int -add_patch(void *e, void *p) -{ - xmlNodePtr node; - xmlNodePtr cur; - char id[PATH_MAX]; - patch_node_t *patch; - patch_parms_t *args; - - patch = e; - args = p; - - /* skip this patch if it has been obsoleted */ - if (obsolete_patch(patch, args->obs_patches_avl)) - return (UU_WALK_NEXT); - - if (patch->patch_vers[0] == '\0') - (void) snprintf(id, sizeof (id), "%s", patch->patch_num); - else - (void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num, - patch->patch_vers); - - if ((args->res = operation_prep(args->handle)) != Z_OK) - return (UU_WALK_DONE); - - cur = args->handle->zone_dh_cur; - node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); - if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK) - return (UU_WALK_DONE); - - if (patch->obs_patches != NULL) { - obs_patch_node_t *op; - xmlNodePtr node2; - - for (op = uu_list_first(patch->obs_patches); op != NULL; - op = uu_list_next(patch->obs_patches, op)) { - (void) snprintf(id, sizeof (id), "%s", op->patch_num); - node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES, - NULL); - if ((args->res = newprop(node2, DTD_ATTR_ID, id)) - != Z_OK) - return (UU_WALK_DONE); + } else { + if (door_info(doorfd, &info) == 0 && + ((info.di_attributes & DOOR_REVOKED) == 0)) { + error = Z_OK; + (void) close(doorfd); + goto out; } + (void) close(doorfd); } - return (UU_WALK_NEXT); -} - -static void -patch_avl_delete(uu_avl_t *patches_avl) -{ - if (patches_avl != NULL) { - patch_node_t *p; - void *cookie = NULL; - - while ((p = (patch_node_t *)uu_avl_teardown(patches_avl, - &cookie)) != NULL) { - free(p->patch_num); - free(p->patch_vers); - - if (p->obs_patches != NULL) { - obs_patch_node_t *op; - void *cookie2 = NULL; - - while ((op = uu_list_teardown(p->obs_patches, - &cookie2)) != NULL) { - free(op->patch_num); - free(op); - } - uu_list_destroy(p->obs_patches); - } - - free(p); - } - - uu_avl_destroy(patches_avl); + if ((child_pid = fork()) == -1) { + zperror(gettext("could not fork")); + goto out; } -} -/* - * Add the unique, highest version patches that are associated with this pkg - * to the sw inventory on the handle. - */ -static int -add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop, - uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, - uu_list_pool_t *list_pool) -{ - int i; - int res; - uu_avl_t *patches_avl; - patch_parms_t args; + if (child_pid == 0) { + const char *argv[6], **ap; - if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) - == NULL) - return (Z_NOMEM); + /* child process */ + prepare_audit_context(zone_name); - for (i = 0; i < infop->zpi_patch_cnt; i++) { - if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool, - patches_avl, obs_patches, list_pool)) != Z_OK) { - patch_avl_delete(patches_avl); - return (res); + ap = argv; + *ap++ = "zoneadmd"; + *ap++ = "-z"; + *ap++ = zone_name; + if (zonecfg_in_alt_root()) { + *ap++ = "-R"; + *ap++ = zonecfg_get_root(); } - } - - args.obs_patches_avl = obs_patches; - args.handle = handle; - args.res = Z_OK; - - (void) uu_avl_walk(patches_avl, add_patch, &args, 0); - - patch_avl_delete(patches_avl); - return (args.res); -} - -/* - * Keep track of the pkgs we have already processed so that we can quickly - * skip those pkgs while recursively doing dependents. - */ -static boolean_t -pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool) -{ - uu_avl_index_t where; - - if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) { - zone_pkg_entry_t *pkg; + *ap = NULL; + (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv); /* - * We need to add it. If we don't have memory we just skip - * this pkg since this routine improves performance but the - * algorithm is still correct without it. + * TRANSLATION_NOTE + * zoneadmd is a literal that should not be translated. */ - if ((pkg = (zone_pkg_entry_t *) - malloc(sizeof (zone_pkg_entry_t))) == NULL) - return (B_FALSE); - - if ((pkg->zpe_name = strdup(pname)) == NULL) { - free(pkg); - return (B_FALSE); + zperror(gettext("could not exec zoneadmd")); + _exit(1); + } else { + /* parent process */ + pid_t retval; + int pstatus = 0; + + do { + retval = waitpid(child_pid, &pstatus, 0); + } while (retval != child_pid); + if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) && + WEXITSTATUS(pstatus) != 0)) { + zerror(zone_name, gettext("could not start %s"), + "zoneadmd"); + goto out; } - - pkg->zpe_vers = NULL; - pkg->zpe_patches_avl = NULL; - - /* Insert pkg into the AVL tree. */ - uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool); - uu_avl_insert(saw_pkgs, pkg, where); - return (B_FALSE); - } - - return (B_TRUE); -} - -/* - * Add the pkg to the sw inventory on the handle. - */ -static int -add_pkg(zone_dochandle_t handle, char *name, char *version) -{ - xmlNodePtr newnode; - xmlNodePtr cur; - int err; - - if ((err = operation_prep(handle)) != Z_OK) - return (err); - - cur = handle->zone_dh_cur; - newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); - if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) - return (err); - if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) - return (err); - return (Z_OK); -} - -static void -free_pkginfo(struct zone_pkginfo *infop) -{ - free(infop->zpi_version); - if (infop->zpi_patch_cnt > 0) { - int i; - - for (i = 0; i < infop->zpi_patch_cnt; i++) - free(infop->zpi_patchinfo[i]); - free(infop->zpi_patchinfo); } + error = Z_OK; +out: + if (lock) + zonecfg_release_lock_file(zone_name, lockfd); + return (error); } -/* - * Read the pkginfo file and populate the structure with the data we need - * from this pkg for a sw inventory. - */ -static int -get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) +int +zonecfg_ping_zoneadmd(const char *zone_name) { - FILE *fp; - char *buf; - int err = 0; - - infop->zpi_all_zones = B_FALSE; - infop->zpi_this_zone = B_FALSE; - infop->zpi_version = NULL; - infop->zpi_patch_cnt = 0; - infop->zpi_patchinfo = NULL; - - if ((fp = fopen(pkginfo, "r")) == NULL) - return (errno); - - while ((buf = read_pkg_data(fp)) != NULL) { - if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { - int len; - - if ((infop->zpi_version = - strdup(buf + sizeof (VERSION) - 1)) == NULL) { - err = ENOMEM; - break; - } - - /* remove trailing newline */ - len = strlen(infop->zpi_version); - *(infop->zpi_version + len - 1) = 0; + char doorpath[PATH_MAX]; + int doorfd; + struct door_info info; - } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { - infop->zpi_all_zones = B_TRUE; - - } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { - infop->zpi_this_zone = B_TRUE; - - } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) - == 0) { - char **p; - - if ((p = (char **)realloc(infop->zpi_patchinfo, - sizeof (char *) * (infop->zpi_patch_cnt + 1))) - == NULL) { - err = ENOMEM; - break; - } - infop->zpi_patchinfo = p; - - if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = - strdup(buf)) == NULL) { - err = ENOMEM; - break; - } - infop->zpi_patch_cnt++; - } - - free(buf); - } - - free(buf); + if (!get_doorname(zone_name, doorpath)) + return (-1); - if (errno == ENOMEM) { - err = ENOMEM; - /* Clean up anything we did manage to allocate. */ - free_pkginfo(infop); + if ((doorfd = open(doorpath, O_RDONLY)) < 0) { + return (-1); } - - (void) fclose(fp); - - return (err); -} - -/* - * Add any dependent pkgs to the list. The pkg depend file lists pkg - * dependencies, one per line with an entry that looks like: - * P SUNWcar Core Architecture, (Root) - * See the depend(4) man page. - */ -static int -add_dependents(zone_dochandle_t handle, char *pname, - uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, - uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool) -{ - int res = Z_OK; - FILE *fp; - char depend[MAXPATHLEN]; - char *buf; - struct stat sbuf; - - (void) snprintf(depend, sizeof (depend), "%s/%s/install/depend", - PKG_PATH, pname); - - if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) + if (door_info(doorfd, &info) == 0 && + ((info.di_attributes & DOOR_REVOKED) == 0)) { + (void) close(doorfd); return (Z_OK); - - if ((fp = fopen(depend, "r")) == NULL) - return (Z_OK); - - while ((buf = read_pkg_data(fp)) != NULL) { - char *deppkg; - char *delims = " \t"; - char pkginfo[MAXPATHLEN]; - struct zone_pkginfo info; - - if (*buf != 'P') { - free(buf); - continue; - } - - /* Skip past the leading 'P '. */ - if ((deppkg = strtok(buf + 2, delims)) == NULL) { - free(buf); - continue; - } - - /* If the pkg is already in the manifest don't add it again. */ - if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) { - free(buf); - continue; - } - - (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", - PKG_PATH, deppkg); - - if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) { - free(buf); - continue; - } - - if (get_pkginfo(pkginfo, &info) != 0) { - res = Z_NOMEM; - free(buf); - break; - } - - if ((res = add_dependents(handle, deppkg, patches_pool, - obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK && - (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) { - if (info.zpi_patch_cnt > 0) - res = add_patches(handle, &info, patches_pool, - obs_patches, list_pool); - } - - free(buf); - free_pkginfo(&info); - - if (res != Z_OK) - break; } - - (void) fclose(fp); - return (res); + (void) close(doorfd); + return (-1); } -/* ARGSUSED */ -static int -pkg_entry_compare(const void *l_arg, const void *r_arg, void *private) -{ - zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg; - char *name = (char *)r_arg; - - return (strcmp(pkg->zpe_name, name)); -} - -static void -pkg_avl_delete(uu_avl_t *pavl) +int +zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale, + boolean_t lock) { - if (pavl != NULL) { - zone_pkg_entry_t *p; - void *cookie = NULL; + char doorpath[PATH_MAX]; + int doorfd, result; + door_arg_t darg; - while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) { - free(p->zpe_name); - free(p); - } + zoneid_t zoneid; + uint64_t uniqid = 0; - uu_avl_destroy(pavl); - } -} + zone_cmd_rval_t *rvalp; + size_t rlen; + char *cp, *errbuf; -/* - * Take a software inventory of the global zone. We need to get the set of - * packages and patches that are on the global zone that the specified - * non-global zone depends on. The packages we need in the inventory are: - * - * - skip the package if SUNW_PKG_THISZONE is 'true' - * otherwise, - * - add the package if - * a) SUNW_PKG_ALLZONES is 'true', - * or - * b) any file delivered by the package is in a file system that is inherited - * from the global zone. - * If the zone does not inherit any file systems (whole root) - * then (b) will be skipped. - * - * For each of the packages that is being added to the inventory, we will also - * add its dependent packages to the inventory. - * - * For each of the packages that is being added to the inventory, we will also - * add all of the associated, unique patches to the inventory. - * - * See the comment for zonecfg_getpkgdata() for compatability restrictions on - * how we must save the XML representation of the software inventory. - */ -static int -zonecfg_sw_inventory(zone_dochandle_t handle) -{ - char pkginfo[MAXPATHLEN]; - int res; - struct dirent *dp; - DIR *dirp; - struct stat buf; - struct zone_pkginfo info; - int pkg_cnt = 0; - char **pkgs = NULL; - uu_avl_pool_t *pkgs_pool = NULL; - uu_avl_pool_t *patches_pool = NULL; - uu_list_pool_t *list_pool = NULL; - uu_avl_t *saw_pkgs = NULL; - uu_avl_t *obs_patches = NULL; - - if ((pkgs_pool = uu_avl_pool_create("pkgs_pool", - sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry), - pkg_entry_compare, UU_DEFAULT)) == NULL) { - res = Z_NOMEM; - goto done; - } - - if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) { - res = Z_NOMEM; - goto done; + rlen = getpagesize(); + if ((rvalp = malloc(rlen)) == NULL) { + zerror(zone_name, gettext("failed to allocate %lu bytes: %s"), + rlen, strerror(errno)); + return (-1); } - if ((patches_pool = uu_avl_pool_create("patches_pool", - sizeof (patch_node_t), offsetof(patch_node_t, patch_node), - patch_node_compare, UU_DEFAULT)) == NULL) { - res = Z_NOMEM; - goto done; + if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) { + (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid, + sizeof (uniqid)); } - - if ((list_pool = uu_list_pool_create("list_pool", - sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL, - UU_DEFAULT)) == NULL) { - res = Z_NOMEM; - goto done; + arg->uniqid = uniqid; + (void) strlcpy(arg->locale, locale, sizeof (arg->locale)); + if (!get_doorname(zone_name, doorpath)) { + zerror(zone_name, gettext("alternate root path is too long")); + free(rvalp); + return (-1); } /* - * The obs_patches AVL tree saves all of the obsolete patches so - * that we know not to output those as part of the sw dependencies. + * Loop trying to start zoneadmd; if something goes seriously + * wrong we break out and fail. */ - if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) - == NULL) { - res = Z_NOMEM; - goto done; - } - - if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) { - res = Z_NOMEM; - goto done; - } - - if ((dirp = opendir(PKG_PATH)) == NULL) { - res = Z_NOMEM; - goto done; - } - - while ((dp = readdir(dirp)) != (struct dirent *)0) { - if (strcmp(dp->d_name, ".") == 0 || - strcmp(dp->d_name, "..") == 0) - continue; - - (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", - PKG_PATH, dp->d_name); - - if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) - continue; + for (;;) { + if (start_zoneadmd(zone_name, lock) != Z_OK) + break; - if (get_pkginfo(pkginfo, &info) != 0) { - res = Z_NOMEM; + if ((doorfd = open(doorpath, O_RDONLY)) < 0) { + zperror(gettext("failed to open zone door")); break; } - if (!info.zpi_this_zone && - (info.zpi_all_zones || - dir_pkg(dp->d_name, pkgs, pkg_cnt)) && - !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) { + darg.data_ptr = (char *)arg; + darg.data_size = sizeof (*arg); + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = (char *)rvalp; + darg.rsize = rlen; + if (door_call(doorfd, &darg) != 0) { + (void) close(doorfd); /* - * Add dependents first so any patches will get - * associated with the right pkg in the xml file. + * We'll get EBADF if the door has been revoked. */ - if ((res = add_dependents(handle, dp->d_name, - patches_pool, obs_patches, list_pool, saw_pkgs, - pkgs_pool)) == Z_OK && - (res = add_pkg(handle, dp->d_name, - info.zpi_version)) == Z_OK) { - if (info.zpi_patch_cnt > 0) - res = add_patches(handle, &info, - patches_pool, obs_patches, - list_pool); + if (errno != EBADF) { + zperror(gettext("door_call failed")); + break; } + continue; /* take another lap */ } + (void) close(doorfd); - free_pkginfo(&info); + if (darg.data_size == 0) { + /* Door server is going away; kick it again. */ + continue; + } - if (res != Z_OK) - break; + errbuf = rvalp->errbuf; + while (*errbuf != '\0') { + /* + * Remove any newlines since zerror() + * will append one automatically. + */ + cp = strchr(errbuf, '\n'); + if (cp != NULL) + *cp = '\0'; + zerror(zone_name, "%s", errbuf); + if (cp == NULL) + break; + errbuf = cp + 1; + } + result = rvalp->rval == 0 ? 0 : -1; + free(rvalp); + return (result); } - (void) closedir(dirp); - -done: - pkg_avl_delete(saw_pkgs); - patch_avl_delete(obs_patches); - if (pkgs_pool != NULL) - uu_avl_pool_destroy(pkgs_pool); - if (patches_pool != NULL) - uu_avl_pool_destroy(patches_pool); - if (list_pool != NULL) - uu_list_pool_destroy(list_pool); - free_ipd_pkgs(pkgs, pkg_cnt); - - if (res == Z_OK) - handle->zone_dh_sw_inv = B_TRUE; - - return (res); -} - -/* - * zonecfg_devwalk call-back function used during detach to generate the - * dev info in the manifest. - */ -static int -get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, - const char *acl, void *hdl) -{ - zone_dochandle_t handle = (zone_dochandle_t)hdl; - xmlNodePtr newnode; - xmlNodePtr cur; - int err; - char buf[128]; - - if ((err = operation_prep(handle)) != Z_OK) - return (err); - - cur = handle->zone_dh_cur; - newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); - if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) - return (err); - (void) snprintf(buf, sizeof (buf), "%lu", uid); - if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) - return (err); - (void) snprintf(buf, sizeof (buf), "%lu", gid); - if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) - return (err); - (void) snprintf(buf, sizeof (buf), "%o", mode); - if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) - return (err); - if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) - return (err); - return (Z_OK); -} - -/* - * Get the information required to support detaching a zone. This is - * called on the source system when detaching (the detaching parameter should - * be set to true) and on the destination system before attaching (the - * detaching parameter should be false). - * - * For native Solaris zones, the detach/attach process involves validating - * that the software on the global zone can support the zone when we attach. - * To do this we take a software inventory of the global zone. We also - * have to keep track of the device configuration so that we can properly - * recreate it on the destination. - */ -int -zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) -{ - int res; - - if ((res = zonecfg_sw_inventory(handle)) != Z_OK) - return (res); - - if (detaching) - res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); - - return (res); + free(rvalp); + return (-1); } diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers index e36565f19d..e4572f3374 100644 --- a/usr/src/lib/libzonecfg/common/mapfile-vers +++ b/usr/src/lib/libzonecfg/common/mapfile-vers @@ -40,6 +40,9 @@ SUNWprivate_1.1 { zonecfg_add_fs_option; zonecfg_add_ipd; zonecfg_add_nwif; + zonecfg_add_patch; + zonecfg_add_patch_obs; + zonecfg_add_pkg; zonecfg_add_pset; zonecfg_add_rctl; zonecfg_add_rctl_value; @@ -49,6 +52,7 @@ SUNWprivate_1.1 { zonecfg_attach_manifest; zonecfg_bind_pool; zonecfg_bind_tmp_pool; + zonecfg_call_zoneadmd; zonecfg_check_handle; zonecfg_close_scratch; zonecfg_construct_rctlblk; @@ -71,7 +75,7 @@ SUNWprivate_1.1 { zonecfg_detached; zonecfg_detach_save; zonecfg_devperms_apply; - zonecfg_devwalk; + zonecfg_dev_manifest; zonecfg_enable_rcapd; zonecfg_endattrent; zonecfg_enddevent; @@ -96,7 +100,6 @@ SUNWprivate_1.1 { zonecfg_get_autoboot; zonecfg_get_bootargs; zonecfg_get_brand; - zonecfg_get_detach_info; zonecfg_get_dflt_sched_class; zonecfg_getdevent; zonecfg_getdevperment; @@ -123,9 +126,11 @@ SUNWprivate_1.1 { zonecfg_get_uuid; zonecfg_get_xml_handle; zonecfg_get_zonepath; + zonecfg_grab_lock_file; zonecfg_ifname_exists; zonecfg_in_alt_root; zonecfg_init_handle; + zonecfg_init_lock_file; zonecfg_is_rctl; zonecfg_is_scratch; zonecfg_lock_scratch; @@ -154,6 +159,8 @@ SUNWprivate_1.1 { zonecfg_notify_unbind; zonecfg_num_resources; zonecfg_open_scratch; + zonecfg_ping_zoneadmd; + zonecfg_release_lock_file; zonecfg_remove_fs_option; zonecfg_remove_rctl_value; zonecfg_reverse_scratch; @@ -179,6 +186,7 @@ SUNWprivate_1.1 { zonecfg_setrctlent; zonecfg_set_root; zonecfg_set_sched; + zonecfg_set_swinv; zonecfg_set_zonepath; zonecfg_strerror; zonecfg_str_to_bytes; |
