summaryrefslogtreecommitdiff
path: root/usr/src/cmd/zoneadm/zoneadm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/zoneadm/zoneadm.c')
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c280
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));
}