diff options
Diffstat (limited to 'usr/src/cmd/zoneadm/zoneadm.c')
| -rw-r--r-- | usr/src/cmd/zoneadm/zoneadm.c | 280 |
1 files changed, 232 insertions, 48 deletions
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c index 4a0b9eae44..287aa4ca95 100644 --- a/usr/src/cmd/zoneadm/zoneadm.c +++ b/usr/src/cmd/zoneadm/zoneadm.c @@ -108,9 +108,11 @@ static size_t nzents; #define CMD_VERIFY 6 #define CMD_INSTALL 7 #define CMD_UNINSTALL 8 +#define CMD_MOUNT 9 +#define CMD_UNMOUNT 10 #define CMD_MIN CMD_HELP -#define CMD_MAX CMD_UNINSTALL +#define CMD_MAX CMD_UNMOUNT struct cmd { uint_t cmd_num; /* command number */ @@ -139,6 +141,8 @@ static int list_func(int argc, char *argv[]); static int verify_func(int argc, char *argv[]); static int install_func(int argc, char *argv[]); static int uninstall_func(int argc, char *argv[]); +static int mount_func(int argc, char *argv[]); +static int unmount_func(int argc, char *argv[]); static int sanity_check(char *zone, int cmd_num, boolean_t running, boolean_t unsafe_when_running); static int cmd_match(char *cmd); @@ -154,7 +158,10 @@ static struct cmd cmdtab[] = { { CMD_VERIFY, "verify", SHELP_VERIFY, verify_func }, { CMD_INSTALL, "install", SHELP_INSTALL, install_func }, { CMD_UNINSTALL, "uninstall", SHELP_UNINSTALL, - uninstall_func } + uninstall_func }, + /* Private commands for admin/install */ + { CMD_MOUNT, "mount", NULL, mount_func }, + { CMD_UNMOUNT, "unmount", NULL, unmount_func } }; /* global variables */ @@ -226,6 +233,8 @@ long_help(int cmd_num) return (gettext("Uninstall the configuration from the " "system. The -F flag can be used\n\tto force the " "action.")); + default: + return (""); } /* NOTREACHED */ return (NULL); @@ -248,6 +257,8 @@ usage(boolean_t explicit) gettext("subcommand")); (void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands")); for (i = CMD_MIN; i <= CMD_MAX; i++) { + if (cmdtab[i].short_usage == NULL) + continue; (void) fprintf(fd, "%s\n", cmdtab[i].short_usage); if (explicit) (void) fprintf(fd, "\t%s\n\n", long_help(i)); @@ -356,7 +367,7 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) } static int -lookup_zone_info(char *zone_name, zone_entry_t *zent) +lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) { char root[MAXPATHLEN]; int err; @@ -365,8 +376,7 @@ lookup_zone_info(char *zone_name, zone_entry_t *zent) (void) strlcpy(zent->zroot, "???", sizeof (zent->zroot)); zent->zstate_str = "???"; - if ((zent->zid = getzoneidbyname(zone_name)) == -1) - zent->zid = ZONE_ID_UNDEFINED; + zent->zid = zid; if ((err = zone_get_zonepath(zent->zname, root, sizeof (root))) != Z_OK) { @@ -395,11 +405,14 @@ lookup_zone_info(char *zone_name, zone_entry_t *zent) */ static int -fetch_zents() +fetch_zents(void) { zoneid_t *zids = NULL; uint_t nzents_saved; - int i; + int i, retv; + FILE *fp; + boolean_t inaltroot; + zone_entry_t *zentp; if (nzents > 0) return (Z_OK); @@ -429,20 +442,56 @@ again: zents = safe_calloc(nzents, sizeof (zone_entry_t)); + inaltroot = zonecfg_in_alt_root(); + if (inaltroot) + fp = zonecfg_open_scratch("", B_FALSE); + else + fp = NULL; + zentp = zents; + retv = Z_OK; for (i = 0; i < nzents; i++) { char name[ZONENAME_MAX]; + char altname[ZONENAME_MAX]; - if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) + if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) { zperror(gettext("failed to get zone name"), B_FALSE); - else if (lookup_zone_info(name, &zents[i]) != Z_OK) - zerror(gettext("failed to get zone list")); + retv = Z_ERR; + continue; + } + if (zonecfg_is_scratch(name)) { + /* Ignore scratch zones by default */ + if (!inaltroot) + continue; + if (fp == NULL || + zonecfg_reverse_scratch(fp, name, altname, + sizeof (altname), NULL, 0) == -1) { + zerror(gettext("cannot resolve scratch " + "zone %s"), name); + retv = Z_ERR; + continue; + } + (void) strcpy(name, altname); + } else { + /* Ignore non-scratch when in an alternate root */ + if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0) + continue; + } + if (lookup_zone_info(name, zids[i], zentp) != Z_OK) { + zerror(gettext("failed to get zone data")); + retv = Z_ERR; + continue; + } + zentp++; } + nzents = zentp - zents; + if (fp != NULL) + zonecfg_close_scratch(fp); free(zids); - return (Z_OK); + return (retv); } -static void +static int zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) { int i; @@ -454,22 +503,17 @@ zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) * First get the list of running zones from the kernel and print them. * If that is all we need, then return. */ - if (fetch_zents() != Z_OK) { + if ((i = fetch_zents()) != Z_OK) { /* * No need for error messages; fetch_zents() has already taken * care of this. */ - return; + return (i); } - for (i = 0; i < nzents; i++) { - if (!verbose && !parsable) { - zone_print(&zents[i], verbose, parsable); - continue; - } + for (i = 0; i < nzents; i++) zone_print(&zents[i], verbose, parsable); - } if (min_state >= ZONE_STATE_RUNNING) - return; + return (Z_OK); /* * Next, get the full list of zones from the configuration, skipping * any we have already printed. @@ -484,7 +528,7 @@ zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) free(name); continue; } - if (lookup_zone_info(name, &zent) != Z_OK) { + if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) { free(name); continue; } @@ -493,6 +537,7 @@ zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) zone_print(&zent, verbose, parsable); } endzoneent(cookie); + return (Z_OK); } static zone_entry_t * @@ -635,16 +680,18 @@ crosscheck_zonepaths(char *path) continue; } } - res = resolvepath(ze->zone_path, rpath, sizeof (rpath)); + (void) snprintf(path_copy, sizeof (path_copy), "%s%s", + zonecfg_get_root(), ze->zone_path); + res = resolvepath(path_copy, rpath, sizeof (rpath)); if (res == -1) { if (errno != ENOENT) { - zperror(ze->zone_path, B_FALSE); + zperror(path_copy, B_FALSE); free(ze); return (Z_ERR); } (void) printf(gettext("WARNING: zone %s is installed, " "but its %s %s does not exist.\n"), ze->zone_name, - "zonepath", ze->zone_path); + "zonepath", path_copy); free(ze); continue; } @@ -848,12 +895,17 @@ grab_lock_file(const char *zone_name, int *lockfd) char pathbuf[PATH_MAX]; struct flock flock; - if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) { - zerror(gettext("could not mkdir %s: %s"), ZONES_TMPDIR, + if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(), + ZONES_TMPDIR) >= sizeof (pathbuf)) { + zerror(gettext("alternate root path is too long")); + return (Z_ERR); + } + if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) { + zerror(gettext("could not mkdir %s: %s"), pathbuf, strerror(errno)); return (Z_ERR); } - (void) chmod(ZONES_TMPDIR, S_IRWXU); + (void) chmod(pathbuf, S_IRWXU); /* * One of these lock files is created for each zone (when needed). @@ -861,8 +913,11 @@ grab_lock_file(const char *zone_name, int *lockfd) * but since there is only one per zone, there is no resource * starvation issue. */ - (void) snprintf(pathbuf, sizeof (pathbuf), "%s/%s.zoneadm.lock", - ZONES_TMPDIR, zone_name); + if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock", + zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) { + zerror(gettext("alternate root path is too long")); + return (Z_ERR); + } if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { zerror(gettext("could not open %s: %s"), pathbuf, strerror(errno)); @@ -884,10 +939,11 @@ grab_lock_file(const char *zone_name, int *lockfd) return (Z_OK); } -static void +static boolean_t get_doorname(const char *zone_name, char *buffer) { - (void) snprintf(buffer, PATH_MAX, ZONE_DOOR_PATH, zone_name); + return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH, + zonecfg_get_root(), zone_name) < PATH_MAX); } /* @@ -931,7 +987,8 @@ start_zoneadmd(const char *zone_name) int doorfd, lockfd; struct door_info info; - get_doorname(zone_name, doorpath); + if (!get_doorname(zone_name, doorpath)) + return (Z_ERR); if (grab_lock_file(zone_name, &lockfd) != Z_OK) return (Z_ERR); @@ -960,12 +1017,22 @@ start_zoneadmd(const char *zone_name) zperror(gettext("could not fork"), B_FALSE); goto out; } else if (child_pid == 0) { - /* child process */ + const char *argv[6], **ap; + /* child process */ prepare_audit_context(); - (void) execl("/usr/lib/zones/zoneadmd", "zoneadmd", "-z", - zone_name, NULL); + ap = argv; + *ap++ = "zoneadmd"; + *ap++ = "-z"; + *ap++ = zone_name; + if (zonecfg_in_alt_root()) { + *ap++ = "-R"; + *ap++ = zonecfg_get_root(); + } + *ap = NULL; + + (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv); zperror(gettext("could not exec zoneadmd"), B_FALSE); _exit(Z_ERR); } else { @@ -995,7 +1062,8 @@ ping_zoneadmd(const char *zone_name) int doorfd; struct door_info info; - get_doorname(zone_name, doorpath); + if (!get_doorname(zone_name, doorpath)) + return (Z_ERR); if ((doorfd = open(doorpath, O_RDONLY)) < 0) { return (Z_ERR); @@ -1036,7 +1104,11 @@ call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg) } arg->uniqid = uniqid; (void) strlcpy(arg->locale, locale, sizeof (arg->locale)); - get_doorname(zone_name, doorpath); + if (!get_doorname(zone_name, doorpath)) { + zerror(gettext("alternate root path is too long")); + free(rvalp); + return (-1); + } /* * Loop trying to start zoneadmd; if something goes seriously @@ -1104,6 +1176,11 @@ ready_func(int argc, char *argv[]) zone_cmd_arg_t zarg; int arg; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot ready zone in alternate root")); + return (Z_ERR); + } + optind = 0; if ((arg = getopt(argc, argv, "?")) != EOF) { switch (arg) { @@ -1138,6 +1215,11 @@ boot_func(int argc, char *argv[]) zone_cmd_arg_t zarg; int arg; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot boot zone in alternate root")); + return (Z_ERR); + } + zarg.bootbuf[0] = '\0'; /* @@ -1197,7 +1279,7 @@ static int list_func(int argc, char *argv[]) { zone_entry_t *zentp, zent; - int arg; + int arg, retv; boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE; zone_state_t min_state = ZONE_STATE_RUNNING; zoneid_t zone_id = getzoneid(); @@ -1233,12 +1315,13 @@ list_func(int argc, char *argv[]) return (Z_ERR); } if (zone_id == GLOBAL_ZONEID) { - zone_print_list(min_state, verbose, parsable); + retv = zone_print_list(min_state, verbose, parsable); } else { + retv = Z_OK; fake_up_local_zone(zone_id, &zent); zone_print(&zent, verbose, parsable); } - return (Z_OK); + return (retv); } /* @@ -1284,7 +1367,8 @@ list_func(int argc, char *argv[]) } else if ((zentp = lookup_running_zone(target_zone)) != NULL) { zone_print(zentp, verbose, parsable); output = B_TRUE; - } else if (lookup_zone_info(target_zone, &zent) == Z_OK) { + } else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED, + &zent) == Z_OK) { zone_print(&zent, verbose, parsable); output = B_TRUE; } @@ -1380,6 +1464,8 @@ sanity_check(char *zone, int cmd_num, boolean_t running, zone_entry_t *zent; priv_set_t *privset; zone_state_t state; + char kernzone[ZONENAME_MAX]; + FILE *fp; if (getzoneid() != GLOBAL_ZONEID) { zerror(gettext("must be in the global zone to %s a zone."), @@ -1411,10 +1497,7 @@ sanity_check(char *zone, int cmd_num, boolean_t running, return (Z_ERR); } - zent = lookup_running_zone(zone); - if (strcmp(zone, GLOBAL_ZONENAME) == 0) { - assert((zent != NULL) && (zent->zid == GLOBAL_ZONEID)); zerror(gettext("%s operation is invalid for the global zone."), cmd_to_str(cmd_num)); return (Z_ERR); @@ -1426,6 +1509,19 @@ sanity_check(char *zone, int cmd_num, boolean_t running, return (Z_ERR); } + if (!zonecfg_in_alt_root()) { + zent = lookup_running_zone(zone); + } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) { + zent = NULL; + } else { + if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(), + kernzone, sizeof (kernzone)) == 0) + zent = lookup_running_zone(kernzone); + else + zent = NULL; + zonecfg_close_scratch(fp); + } + /* * Look up from the kernel for 'running' zones. */ @@ -1481,6 +1577,7 @@ sanity_check(char *zone, int cmd_num, boolean_t running, break; case CMD_READY: case CMD_BOOT: + case CMD_MOUNT: if (state < ZONE_STATE_INSTALLED) { zerror(gettext("must be %s before %s."), zone_state_str(ZONE_STATE_INSTALLED), @@ -1496,6 +1593,14 @@ sanity_check(char *zone, int cmd_num, boolean_t running, return (Z_ERR); } break; + case CMD_UNMOUNT: + if (state != ZONE_STATE_MOUNTED) { + zerror(gettext("must be %s before %s."), + zone_state_str(ZONE_STATE_MOUNTED), + cmd_to_str(cmd_num)); + return (Z_ERR); + } + break; } } return (Z_OK); @@ -1507,6 +1612,11 @@ halt_func(int argc, char *argv[]) zone_cmd_arg_t zarg; int arg; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot halt zone in alternate root")); + return (Z_ERR); + } + optind = 0; if ((arg = getopt(argc, argv, "?")) != EOF) { switch (arg) { @@ -1540,6 +1650,11 @@ reboot_func(int argc, char *argv[]) zone_cmd_arg_t zarg; int arg; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot reboot zone in alternate root")); + return (Z_ERR); + } + optind = 0; if ((arg = getopt(argc, argv, "?")) != EOF) { switch (arg) { @@ -1792,6 +1907,7 @@ verify_details(int cmd_num) char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN]; int return_code = Z_OK; int err; + boolean_t in_alt_root; if ((handle = zonecfg_init_handle()) == NULL) { zperror(cmd_to_str(cmd_num), B_TRUE); @@ -1834,6 +1950,10 @@ verify_details(int cmd_num) return_code = Z_ERR; } + in_alt_root = zonecfg_in_alt_root(); + if (in_alt_root) + goto no_net; + if ((err = zonecfg_setnwifent(handle)) != Z_OK) { errno = err; zperror(cmd_to_str(cmd_num), B_TRUE); @@ -1881,12 +2001,13 @@ verify_details(int cmd_num) (void) close(so); } (void) zonecfg_endnwifent(handle); +no_net: if (verify_filesystems(handle) != Z_OK) return_code = Z_ERR; - if (verify_rctls(handle) != Z_OK) + if (!in_alt_root && verify_rctls(handle) != Z_OK) return_code = Z_ERR; - if (verify_pool(handle) != Z_OK) + if (!in_alt_root && verify_pool(handle) != Z_OK) return_code = Z_ERR; zonecfg_fini_handle(handle); if (return_code == Z_ERR) @@ -1933,6 +2054,11 @@ install_func(int argc, char *argv[]) char zonepath[MAXPATHLEN]; int status; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot install zone in alternate root")); + return (Z_ERR); + } + optind = 0; if ((arg = getopt(argc, argv, "?")) != EOF) { switch (arg) { @@ -2059,6 +2185,11 @@ uninstall_func(int argc, char *argv[]) int err, arg; int status; + if (zonecfg_in_alt_root()) { + zerror(gettext("cannot uninstall zone in alternate root")); + return (Z_ERR); + } + optind = 0; while ((arg = getopt(argc, argv, "?F")) != EOF) { switch (arg) { @@ -2167,6 +2298,46 @@ bad: return (err); } +/* ARGSUSED */ +static int +mount_func(int argc, char *argv[]) +{ + zone_cmd_arg_t zarg; + + if (argc > 0) + return (Z_USAGE); + if (sanity_check(target_zone, CMD_MOUNT, B_FALSE, B_FALSE) != Z_OK) + return (Z_ERR); + if (verify_details(CMD_MOUNT) != Z_OK) + return (Z_ERR); + + zarg.cmd = Z_MOUNT; + if (call_zoneadmd(target_zone, &zarg) != 0) { + zerror(gettext("call to %s failed"), "zoneadmd"); + return (Z_ERR); + } + return (Z_OK); +} + +/* ARGSUSED */ +static int +unmount_func(int argc, char *argv[]) +{ + zone_cmd_arg_t zarg; + + if (argc > 0) + return (Z_USAGE); + if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE) != Z_OK) + return (Z_ERR); + + zarg.cmd = Z_UNMOUNT; + if (call_zoneadmd(target_zone, &zarg) != 0) { + zerror(gettext("call to %s failed"), "zoneadmd"); + return (Z_ERR); + } + return (Z_OK); +} + static int help_func(int argc, char *argv[]) { @@ -2253,6 +2424,7 @@ main(int argc, char **argv) { int arg; zoneid_t zid; + struct stat st; if ((locale = setlocale(LC_ALL, "")) == NULL) locale = "C"; @@ -2266,13 +2438,25 @@ main(int argc, char **argv) exit(Z_ERR); } - while ((arg = getopt(argc, argv, "?z:")) != EOF) { + while ((arg = getopt(argc, argv, "?z:R:")) != EOF) { switch (arg) { case '?': return (usage(B_TRUE)); case 'z': target_zone = optarg; break; + case 'R': /* private option for admin/install use */ + if (*optarg != '/') { + zerror(gettext("root path must be absolute.")); + exit(Z_ERR); + } + if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { + zerror( + gettext("root path must be a directory.")); + exit(Z_ERR); + } + zonecfg_set_root(optarg); + break; default: return (usage(B_FALSE)); } |
