diff options
| author | gjelinek <none@none> | 2008-07-13 10:43:22 -0700 |
|---|---|---|
| committer | gjelinek <none@none> | 2008-07-13 10:43:22 -0700 |
| commit | ff17c8bf86c3e567734be83f90267edee20f580f (patch) | |
| tree | 9d59d65b3daf859d8c1ffcc50fb84da8934c1ea8 /usr/src/lib/libzonecfg | |
| parent | 019c3c436f78111e4ecf8382da622143f7b45c6d (diff) | |
| download | illumos-joyent-ff17c8bf86c3e567734be83f90267edee20f580f.tar.gz | |
6553514 native zone svr4 pkg code should be moved into zone callbacks
6621020 zlogin tries to write unneeded zero-length message and hangs
6704382 Upgrade process with zones freezes everytime using GUI installer on ultra 45 with 1024 MB of memory
6724480 wrong reference in embedded help for zoneadm
6588602 libbrand '%*' token expansion is a mess
6705863 brand dtd says zoneroot but it should be zonepath
--HG--
rename : usr/src/cmd/zoneadm/sw_cmp.c => deleted_files/usr/src/cmd/zoneadm/sw_cmp.c
rename : usr/src/lib/brand/native/zone/postclone.sh => deleted_files/usr/src/lib/brand/native/zone/postclone.sh
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; |
