Print this page
PSARC 2008/290 lofi mount
6384817 Need persistent lofi based mounts and direct mount(1m) support for lofi
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/zoneadm/zoneadm.c
+++ new/usr/src/cmd/zoneadm/zoneadm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "@(#)zoneadm.c 1.64 08/01/14 SMI"
27 +#pragma ident "@(#)zoneadm.c 1.65 08/05/07 SMI"
28 28
29 29 /*
30 30 * zoneadm is a command interpreter for zone administration. It is all in
31 31 * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
32 32 * main() calls parse_and_run() which calls cmd_match(), then invokes the
33 33 * appropriate command's handler function. The rest of the program is the
34 34 * handler functions and their helper functions.
35 35 *
36 36 * Some of the helper functions are used largely to simplify I18N: reducing
37 37 * the need for translation notes. This is particularly true of many of
38 38 * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather
39 39 * than zerror(gettext("foo failed")) with a translation note indicating
40 40 * that "foo" need not be translated.
41 41 */
42 42
43 43 #include <stdio.h>
44 44 #include <errno.h>
45 45 #include <unistd.h>
46 46 #include <signal.h>
47 47 #include <stdarg.h>
48 48 #include <ctype.h>
49 49 #include <stdlib.h>
50 50 #include <string.h>
51 51 #include <wait.h>
52 52 #include <zone.h>
53 53 #include <priv.h>
54 54 #include <locale.h>
55 55 #include <libintl.h>
56 56 #include <libzonecfg.h>
57 57 #include <bsm/adt.h>
58 58 #include <sys/brand.h>
59 59 #include <sys/param.h>
60 60 #include <sys/types.h>
61 61 #include <sys/stat.h>
62 62 #include <sys/statvfs.h>
63 63 #include <assert.h>
64 64 #include <sys/sockio.h>
65 65 #include <sys/mntent.h>
66 66 #include <limits.h>
67 67 #include <dirent.h>
68 68 #include <uuid/uuid.h>
69 69 #include <libdlpi.h>
70 70
71 71 #include <fcntl.h>
72 72 #include <door.h>
73 73 #include <macros.h>
74 74 #include <libgen.h>
75 75 #include <fnmatch.h>
76 76 #include <sys/modctl.h>
77 77 #include <libbrand.h>
78 78 #include <libscf.h>
79 79 #include <procfs.h>
80 80 #include <strings.h>
81 81
82 82 #include <pool.h>
83 83 #include <sys/pool.h>
84 84 #include <sys/priocntl.h>
85 85 #include <sys/fsspriocntl.h>
86 86
87 87 #include "zoneadm.h"
88 88
89 89 #define MAXARGS 8
90 90
91 91 /* Reflects kernel zone entries */
92 92 typedef struct zone_entry {
93 93 zoneid_t zid;
94 94 char zname[ZONENAME_MAX];
95 95 char *zstate_str;
96 96 zone_state_t zstate_num;
97 97 char zbrand[MAXNAMELEN];
98 98 char zroot[MAXPATHLEN];
99 99 char zuuid[UUID_PRINTABLE_STRING_LENGTH];
100 100 zone_iptype_t ziptype;
101 101 } zone_entry_t;
102 102
103 103 #define CLUSTER_BRAND_NAME "cluster"
104 104
105 105 static zone_entry_t *zents;
106 106 static size_t nzents;
107 107 static boolean_t is_native_zone = B_TRUE;
108 108 static boolean_t is_cluster_zone = B_FALSE;
109 109
110 110 #define LOOPBACK_IF "lo0"
111 111 #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af))
112 112
113 113 struct net_if {
114 114 char *name;
115 115 int af;
116 116 };
117 117
118 118 /* 0755 is the default directory mode. */
119 119 #define DEFAULT_DIR_MODE \
120 120 (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
121 121
122 122 struct cmd {
123 123 uint_t cmd_num; /* command number */
124 124 char *cmd_name; /* command name */
125 125 char *short_usage; /* short form help */
126 126 int (*handler)(int argc, char *argv[]); /* function to call */
127 127
128 128 };
129 129
130 130 #define SHELP_HELP "help"
131 131 #define SHELP_BOOT "boot [-- boot_arguments]"
132 132 #define SHELP_HALT "halt"
133 133 #define SHELP_READY "ready"
134 134 #define SHELP_REBOOT "reboot [-- boot_arguments]"
135 135 #define SHELP_LIST "list [-cipv]"
136 136 #define SHELP_VERIFY "verify"
137 137 #define SHELP_INSTALL "install [-x nodataset] [brand-specific args]"
138 138 #define SHELP_UNINSTALL "uninstall [-F]"
139 139 #define SHELP_CLONE "clone [-m method] [-s <ZFS snapshot>] zonename"
140 140 #define SHELP_MOVE "move zonepath"
141 141 #define SHELP_DETACH "detach [-n]"
142 142 #define SHELP_ATTACH "attach [-F] [-n <path>] [-u]"
143 143 #define SHELP_MARK "mark incomplete"
144 144
145 145 #define EXEC_PREFIX "exec "
146 146 #define EXEC_LEN (strlen(EXEC_PREFIX))
147 147 #define RMCOMMAND "/usr/bin/rm -rf"
148 148
149 149 static int cleanup_zonepath(char *, boolean_t);
150 150
151 151
152 152 static int help_func(int argc, char *argv[]);
153 153 static int ready_func(int argc, char *argv[]);
154 154 static int boot_func(int argc, char *argv[]);
155 155 static int halt_func(int argc, char *argv[]);
156 156 static int reboot_func(int argc, char *argv[]);
157 157 static int list_func(int argc, char *argv[]);
158 158 static int verify_func(int argc, char *argv[]);
159 159 static int install_func(int argc, char *argv[]);
160 160 static int uninstall_func(int argc, char *argv[]);
161 161 static int mount_func(int argc, char *argv[]);
162 162 static int unmount_func(int argc, char *argv[]);
163 163 static int clone_func(int argc, char *argv[]);
164 164 static int move_func(int argc, char *argv[]);
165 165 static int detach_func(int argc, char *argv[]);
166 166 static int attach_func(int argc, char *argv[]);
167 167 static int mark_func(int argc, char *argv[]);
168 168 static int apply_func(int argc, char *argv[]);
169 169 static int sanity_check(char *zone, int cmd_num, boolean_t running,
170 170 boolean_t unsafe_when_running, boolean_t force);
171 171 static int cmd_match(char *cmd);
172 172 static int verify_details(int, char *argv[]);
173 173 static int verify_brand(zone_dochandle_t, int, char *argv[]);
174 174 static int invoke_brand_handler(int, char *argv[]);
175 175
176 176 static struct cmd cmdtab[] = {
177 177 { CMD_HELP, "help", SHELP_HELP, help_func },
178 178 { CMD_BOOT, "boot", SHELP_BOOT, boot_func },
179 179 { CMD_HALT, "halt", SHELP_HALT, halt_func },
180 180 { CMD_READY, "ready", SHELP_READY, ready_func },
181 181 { CMD_REBOOT, "reboot", SHELP_REBOOT, reboot_func },
182 182 { CMD_LIST, "list", SHELP_LIST, list_func },
183 183 { CMD_VERIFY, "verify", SHELP_VERIFY, verify_func },
184 184 { CMD_INSTALL, "install", SHELP_INSTALL, install_func },
185 185 { CMD_UNINSTALL, "uninstall", SHELP_UNINSTALL,
186 186 uninstall_func },
187 187 /* mount and unmount are private commands for admin/install */
188 188 { CMD_MOUNT, "mount", NULL, mount_func },
189 189 { CMD_UNMOUNT, "unmount", NULL, unmount_func },
190 190 { CMD_CLONE, "clone", SHELP_CLONE, clone_func },
191 191 { CMD_MOVE, "move", SHELP_MOVE, move_func },
192 192 { CMD_DETACH, "detach", SHELP_DETACH, detach_func },
193 193 { CMD_ATTACH, "attach", SHELP_ATTACH, attach_func },
194 194 { CMD_MARK, "mark", SHELP_MARK, mark_func },
195 195 { CMD_APPLY, "apply", NULL, apply_func }
196 196 };
197 197
198 198 /* global variables */
199 199
200 200 /* set early in main(), never modified thereafter, used all over the place */
201 201 static char *execname;
202 202 static char target_brand[MAXNAMELEN];
203 203 static char *locale;
204 204 char *target_zone;
205 205 static char *target_uuid;
206 206
207 207 /* used in do_subproc() and signal handler */
208 208 static volatile boolean_t child_killed;
209 209 /* used in attach_func() and signal handler */
210 210 static volatile boolean_t attach_interupted;
211 211 static int do_subproc_cnt = 0;
212 212
213 213 /*
214 214 * Used to indicate whether this zoneadm instance has another zoneadm
215 215 * instance in its ancestry.
216 216 */
217 217 static boolean_t zoneadm_is_nested = B_FALSE;
218 218
219 219 /* used to track nested zone-lock operations */
220 220 static int zone_lock_cnt = 0;
221 221
222 222 /* used to communicate lock status to children */
223 223 #define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD"
224 224 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
225 225 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
226 226
227 227 char *
228 228 cmd_to_str(int cmd_num)
229 229 {
230 230 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
231 231 return (cmdtab[cmd_num].cmd_name);
232 232 }
233 233
234 234 /* This is a separate function because of gettext() wrapping. */
235 235 static char *
236 236 long_help(int cmd_num)
237 237 {
238 238 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
239 239 switch (cmd_num) {
240 240 case CMD_HELP:
241 241 return (gettext("Print usage message."));
242 242 case CMD_BOOT:
243 243 return (gettext("Activates (boots) specified zone. See "
244 244 "zoneadm(1m) for valid boot\n\targuments."));
245 245 case CMD_HALT:
246 246 return (gettext("Halts specified zone, bypassing shutdown "
247 247 "scripts and removing runtime\n\tresources of the zone."));
248 248 case CMD_READY:
249 249 return (gettext("Prepares a zone for running applications but "
250 250 "does not start any user\n\tprocesses in the zone."));
251 251 case CMD_REBOOT:
252 252 return (gettext("Restarts the zone (equivalent to a halt / "
253 253 "boot sequence).\n\tFails if the zone is not active. "
254 254 "See zoneadm(1m) for valid boot\n\targuments."));
255 255 case CMD_LIST:
256 256 return (gettext("Lists the current zones, or a "
257 257 "specific zone if indicated. By default,\n\tall "
258 258 "running zones are listed, though this can be "
259 259 "expanded to all\n\tinstalled zones with the -i "
260 260 "option or all configured zones with the\n\t-c "
261 261 "option. When used with the general -z <zone> and/or -u "
262 262 "<uuid-match>\n\toptions, lists only the specified "
263 263 "matching zone, but lists it\n\tregardless of its state, "
264 264 "and the -i and -c options are disallowed. The\n\t-v "
265 265 "option can be used to display verbose information: zone "
266 266 "name, id,\n\tcurrent state, root directory and options. "
267 267 "The -p option can be used\n\tto request machine-parsable "
268 268 "output. The -v and -p options are mutually\n\texclusive."
269 269 " If neither -v nor -p is used, just the zone name is "
270 270 "listed."));
271 271 case CMD_VERIFY:
272 272 return (gettext("Check to make sure the configuration "
273 273 "can safely be instantiated\n\ton the machine: "
274 274 "physical network interfaces exist, etc."));
275 275 case CMD_INSTALL:
276 276 return (gettext("Install the configuration on to the system. "
277 277 "The -x nodataset option\n\tcan be used to prevent the "
278 278 "creation of a new ZFS file system for the\n\tzone "
279 279 "(assuming the zonepath is within a ZFS file system).\n\t"
280 280 "All other arguments are passed to the brand installation "
281 281 "function;\n\tsee brand(4) for more information."));
282 282 case CMD_UNINSTALL:
283 283 return (gettext("Uninstall the configuration from the system. "
284 284 "The -F flag can be used\n\tto force the action."));
285 285 case CMD_CLONE:
286 286 return (gettext("Clone the installation of another zone. "
287 287 "The -m option can be used to\n\tspecify 'copy' which "
288 288 "forces a copy of the source zone. The -s option\n\t"
289 289 "can be used to specify the name of a ZFS snapshot "
290 290 "that was taken from\n\ta previous clone command. The "
291 291 "snapshot will be used as the source\n\tinstead of "
292 292 "creating a new ZFS snapshot."));
293 293 case CMD_MOVE:
294 294 return (gettext("Move the zone to a new zonepath."));
295 295 case CMD_DETACH:
296 296 return (gettext("Detach the zone from the system. The zone "
297 297 "state is changed to\n\t'configured' (but the files under "
298 298 "the zonepath are untouched).\n\tThe zone can subsequently "
299 299 "be attached, or can be moved to another\n\tsystem and "
300 300 "attached there. The -n option can be used to specify\n\t"
301 301 "'no-execute' mode. When -n is used, the information "
302 302 "needed to attach\n\tthe zone is sent to standard output "
303 303 "but the zone is not actually\n\tdetached."));
304 304 case CMD_ATTACH:
305 305 return (gettext("Attach the zone to the system. The zone "
306 306 "state must be 'configured'\n\tprior to attach; upon "
307 307 "successful completion, the zone state will be\n\t"
308 308 "'installed'. The system software on the current "
309 309 "system must be\n\tcompatible with the software on the "
310 310 "zone's original system or use\n\tthe -u option to update "
311 311 "the zone to the current system software.\n\tSpecify -F "
312 312 "to force the attach and skip software compatibility "
313 313 "tests.\n\tThe -n option can be used to specify "
314 314 "'no-execute' mode. When -n is\n\tused, the information "
315 315 "needed to attach the zone is read from the\n\tspecified "
316 316 "path and the configuration is only validated. The path "
317 317 "can\n\tbe '-' to specify standard input. The -F, -n and "
318 318 "-u options are\n\tmutually exclusive."));
319 319 case CMD_MARK:
320 320 return (gettext("Set the state of the zone. This can be used "
321 321 "to force the zone\n\tstate to 'incomplete' "
322 322 "administratively if some activity has rendered\n\tthe "
323 323 "zone permanently unusable. The only valid state that "
324 324 "may be\n\tspecified is 'incomplete'."));
325 325 default:
326 326 return ("");
327 327 }
328 328 /* NOTREACHED */
329 329 return (NULL);
330 330 }
331 331
332 332 /*
333 333 * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for
334 334 * unexpected errors.
335 335 */
336 336
337 337 static int
338 338 usage(boolean_t explicit)
339 339 {
340 340 int i;
341 341 FILE *fd = explicit ? stdout : stderr;
342 342
343 343 (void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname);
344 344 (void) fprintf(fd, "\t%s [-z <zone>] [-u <uuid-match>] list\n",
345 345 execname);
346 346 (void) fprintf(fd, "\t%s {-z <zone>|-u <uuid-match>} <%s>\n", execname,
347 347 gettext("subcommand"));
348 348 (void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands"));
349 349 for (i = CMD_MIN; i <= CMD_MAX; i++) {
350 350 if (cmdtab[i].short_usage == NULL)
351 351 continue;
352 352 (void) fprintf(fd, "%s\n", cmdtab[i].short_usage);
353 353 if (explicit)
354 354 (void) fprintf(fd, "\t%s\n\n", long_help(i));
355 355 }
356 356 if (!explicit)
357 357 (void) fputs("\n", fd);
358 358 return (Z_USAGE);
359 359 }
360 360
361 361 static void
362 362 sub_usage(char *short_usage, int cmd_num)
363 363 {
364 364 (void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage);
365 365 (void) fprintf(stderr, "\t%s\n", long_help(cmd_num));
366 366 }
367 367
368 368 /*
369 369 * zperror() is like perror(3c) except that this also prints the executable
370 370 * name at the start of the message, and takes a boolean indicating whether
371 371 * to call libc'c strerror() or that from libzonecfg.
372 372 */
373 373
374 374 void
375 375 zperror(const char *str, boolean_t zonecfg_error)
376 376 {
377 377 (void) fprintf(stderr, "%s: %s: %s\n", execname, str,
378 378 zonecfg_error ? zonecfg_strerror(errno) : strerror(errno));
379 379 }
380 380
381 381 /*
382 382 * zperror2() is very similar to zperror() above, except it also prints a
383 383 * supplied zone name after the executable.
384 384 *
385 385 * All current consumers of this function want libzonecfg's strerror() rather
386 386 * than libc's; if this ever changes, this function can be made more generic
387 387 * like zperror() above.
388 388 */
389 389
390 390 void
391 391 zperror2(const char *zone, const char *str)
392 392 {
393 393 (void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str,
394 394 zonecfg_strerror(errno));
395 395 }
396 396
397 397 /* PRINTFLIKE1 */
398 398 void
399 399 zerror(const char *fmt, ...)
400 400 {
401 401 va_list alist;
402 402
403 403 va_start(alist, fmt);
404 404 (void) fprintf(stderr, "%s: ", execname);
405 405 if (target_zone != NULL)
406 406 (void) fprintf(stderr, "zone '%s': ", target_zone);
407 407 (void) vfprintf(stderr, fmt, alist);
408 408 (void) fprintf(stderr, "\n");
409 409 va_end(alist);
410 410 }
411 411
412 412 static void *
413 413 safe_calloc(size_t nelem, size_t elsize)
414 414 {
415 415 void *r = calloc(nelem, elsize);
416 416
417 417 if (r == NULL) {
418 418 zerror(gettext("failed to allocate %lu bytes: %s"),
419 419 (ulong_t)nelem * elsize, strerror(errno));
420 420 exit(Z_ERR);
421 421 }
422 422 return (r);
423 423 }
424 424
425 425 static void
426 426 zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
427 427 {
428 428 static boolean_t firsttime = B_TRUE;
429 429 char *ip_type_str;
430 430
431 431 if (zent->ziptype == ZS_EXCLUSIVE)
432 432 ip_type_str = "excl";
433 433 else
434 434 ip_type_str = "shared";
435 435
436 436 assert(!(verbose && parsable));
437 437 if (firsttime && verbose) {
438 438 firsttime = B_FALSE;
439 439 (void) printf("%*s %-16s %-10s %-30s %-8s %-6s\n",
440 440 ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND",
441 441 "IP");
442 442 }
443 443 if (!verbose) {
444 444 char *cp, *clim;
445 445
446 446 if (!parsable) {
447 447 (void) printf("%s\n", zent->zname);
448 448 return;
449 449 }
450 450 if (zent->zid == ZONE_ID_UNDEFINED)
451 451 (void) printf("-");
452 452 else
453 453 (void) printf("%lu", zent->zid);
454 454 (void) printf(":%s:%s:", zent->zname, zent->zstate_str);
455 455 cp = zent->zroot;
456 456 while ((clim = strchr(cp, ':')) != NULL) {
457 457 (void) printf("%.*s\\:", clim - cp, cp);
458 458 cp = clim + 1;
459 459 }
460 460 (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
461 461 ip_type_str);
462 462 return;
463 463 }
464 464 if (zent->zstate_str != NULL) {
465 465 if (zent->zid == ZONE_ID_UNDEFINED)
466 466 (void) printf("%*s", ZONEID_WIDTH, "-");
467 467 else
468 468 (void) printf("%*lu", ZONEID_WIDTH, zent->zid);
469 469 (void) printf(" %-16s %-10s %-30s %-8s %-6s\n", zent->zname,
470 470 zent->zstate_str, zent->zroot, zent->zbrand, ip_type_str);
471 471 }
472 472 }
473 473
474 474 static int
475 475 lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
476 476 {
477 477 char root[MAXPATHLEN], *cp;
478 478 int err;
479 479 uuid_t uuid;
480 480
481 481 (void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
482 482 (void) strlcpy(zent->zroot, "???", sizeof (zent->zroot));
483 483 (void) strlcpy(zent->zbrand, "???", sizeof (zent->zbrand));
484 484 zent->zstate_str = "???";
485 485
486 486 zent->zid = zid;
487 487
488 488 if (zonecfg_get_uuid(zone_name, uuid) == Z_OK &&
489 489 !uuid_is_null(uuid))
490 490 uuid_unparse(uuid, zent->zuuid);
491 491 else
492 492 zent->zuuid[0] = '\0';
493 493
494 494 /*
495 495 * For labeled zones which query the zone path of lower-level
496 496 * zones, the path needs to be adjusted to drop the final
497 497 * "/root" component. This adjusted path is then useful
498 498 * for reading down any exported directories from the
499 499 * lower-level zone.
500 500 */
501 501 if (is_system_labeled() && zent->zid != ZONE_ID_UNDEFINED) {
502 502 if (zone_getattr(zent->zid, ZONE_ATTR_ROOT, zent->zroot,
503 503 sizeof (zent->zroot)) == -1) {
504 504 zperror2(zent->zname,
505 505 gettext("could not get zone path."));
506 506 return (Z_ERR);
507 507 }
508 508 cp = zent->zroot + strlen(zent->zroot) - 5;
509 509 if (cp > zent->zroot && strcmp(cp, "/root") == 0)
510 510 *cp = 0;
511 511 } else {
512 512 if ((err = zone_get_zonepath(zent->zname, root,
513 513 sizeof (root))) != Z_OK) {
514 514 errno = err;
515 515 zperror2(zent->zname,
516 516 gettext("could not get zone path."));
517 517 return (Z_ERR);
518 518 }
519 519 (void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
520 520 }
521 521
522 522 if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) {
523 523 errno = err;
524 524 zperror2(zent->zname, gettext("could not get state"));
525 525 return (Z_ERR);
526 526 }
527 527 zent->zstate_str = zone_state_str(zent->zstate_num);
528 528
529 529 /*
530 530 * A zone's brand is only available in the .xml file describing it,
531 531 * which is only visible to the global zone. This causes
532 532 * zone_get_brand() to fail when called from within a non-global
533 533 * zone. Fortunately we only do this on labeled systems, where we
534 534 * know all zones are native.
535 535 */
536 536 if (getzoneid() != GLOBAL_ZONEID) {
537 537 assert(is_system_labeled() != 0);
538 538 (void) strlcpy(zent->zbrand, NATIVE_BRAND_NAME,
539 539 sizeof (zent->zbrand));
540 540 } else if (zone_get_brand(zent->zname, zent->zbrand,
541 541 sizeof (zent->zbrand)) != Z_OK) {
542 542 zperror2(zent->zname, gettext("could not get brand name"));
543 543 return (Z_ERR);
544 544 }
545 545
546 546 /*
547 547 * Get ip type of the zone.
548 548 * Note for global zone, ZS_SHARED is set always.
549 549 */
550 550 if (zid == GLOBAL_ZONEID) {
551 551 zent->ziptype = ZS_SHARED;
552 552 } else {
553 553
554 554 if (zent->zstate_num == ZONE_STATE_RUNNING) {
555 555 ushort_t flags;
556 556
557 557 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
558 558 sizeof (flags)) < 0) {
559 559 zperror2(zent->zname,
560 560 gettext("could not get zone flags"));
561 561 return (Z_ERR);
562 562 }
563 563 if (flags & ZF_NET_EXCL)
564 564 zent->ziptype = ZS_EXCLUSIVE;
565 565 else
566 566 zent->ziptype = ZS_SHARED;
567 567 } else {
568 568 zone_dochandle_t handle;
569 569
570 570 if ((handle = zonecfg_init_handle()) == NULL) {
571 571 zperror2(zent->zname,
572 572 gettext("could not init handle"));
573 573 return (Z_ERR);
574 574 }
575 575 if ((err = zonecfg_get_handle(zent->zname, handle))
576 576 != Z_OK) {
577 577 zperror2(zent->zname,
578 578 gettext("could not get handle"));
579 579 zonecfg_fini_handle(handle);
580 580 return (Z_ERR);
581 581 }
582 582
583 583 if ((err = zonecfg_get_iptype(handle, &zent->ziptype))
584 584 != Z_OK) {
585 585 zperror2(zent->zname,
586 586 gettext("could not get ip-type"));
587 587 zonecfg_fini_handle(handle);
588 588 return (Z_ERR);
589 589 }
590 590 zonecfg_fini_handle(handle);
591 591 }
592 592 }
593 593
594 594 return (Z_OK);
595 595 }
596 596
597 597 /*
598 598 * fetch_zents() calls zone_list(2) to find out how many zones are running
599 599 * (which is stored in the global nzents), then calls zone_list(2) again
600 600 * to fetch the list of running zones (stored in the global zents). This
601 601 * function may be called multiple times, so if zents is already set, we
602 602 * return immediately to save work.
603 603 */
604 604
605 605 static int
606 606 fetch_zents(void)
607 607 {
608 608 zoneid_t *zids = NULL;
609 609 uint_t nzents_saved;
610 610 int i, retv;
611 611 FILE *fp;
612 612 boolean_t inaltroot;
613 613 zone_entry_t *zentp;
614 614
615 615 if (nzents > 0)
616 616 return (Z_OK);
617 617
618 618 if (zone_list(NULL, &nzents) != 0) {
619 619 zperror(gettext("failed to get zoneid list"), B_FALSE);
620 620 return (Z_ERR);
621 621 }
622 622
623 623 again:
624 624 if (nzents == 0)
625 625 return (Z_OK);
626 626
627 627 zids = safe_calloc(nzents, sizeof (zoneid_t));
628 628 nzents_saved = nzents;
629 629
630 630 if (zone_list(zids, &nzents) != 0) {
631 631 zperror(gettext("failed to get zone list"), B_FALSE);
632 632 free(zids);
633 633 return (Z_ERR);
634 634 }
635 635 if (nzents != nzents_saved) {
636 636 /* list changed, try again */
637 637 free(zids);
638 638 goto again;
639 639 }
640 640
641 641 zents = safe_calloc(nzents, sizeof (zone_entry_t));
642 642
643 643 inaltroot = zonecfg_in_alt_root();
644 644 if (inaltroot)
645 645 fp = zonecfg_open_scratch("", B_FALSE);
646 646 else
647 647 fp = NULL;
648 648 zentp = zents;
649 649 retv = Z_OK;
650 650 for (i = 0; i < nzents; i++) {
651 651 char name[ZONENAME_MAX];
652 652 char altname[ZONENAME_MAX];
653 653
654 654 if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
655 655 zperror(gettext("failed to get zone name"), B_FALSE);
656 656 retv = Z_ERR;
657 657 continue;
658 658 }
659 659 if (zonecfg_is_scratch(name)) {
660 660 /* Ignore scratch zones by default */
661 661 if (!inaltroot)
662 662 continue;
663 663 if (fp == NULL ||
664 664 zonecfg_reverse_scratch(fp, name, altname,
665 665 sizeof (altname), NULL, 0) == -1) {
666 666 zerror(gettext("could not resolve scratch "
667 667 "zone %s"), name);
668 668 retv = Z_ERR;
669 669 continue;
670 670 }
671 671 (void) strcpy(name, altname);
672 672 } else {
673 673 /* Ignore non-scratch when in an alternate root */
674 674 if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0)
675 675 continue;
676 676 }
677 677 if (lookup_zone_info(name, zids[i], zentp) != Z_OK) {
678 678 zerror(gettext("failed to get zone data"));
679 679 retv = Z_ERR;
680 680 continue;
681 681 }
682 682 zentp++;
683 683 }
684 684 nzents = zentp - zents;
685 685 if (fp != NULL)
686 686 zonecfg_close_scratch(fp);
687 687
688 688 free(zids);
689 689 return (retv);
690 690 }
691 691
692 692 static int
693 693 zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
694 694 {
695 695 int i;
696 696 zone_entry_t zent;
697 697 FILE *cookie;
698 698 char *name;
699 699
700 700 /*
701 701 * First get the list of running zones from the kernel and print them.
702 702 * If that is all we need, then return.
703 703 */
704 704 if ((i = fetch_zents()) != Z_OK) {
705 705 /*
706 706 * No need for error messages; fetch_zents() has already taken
707 707 * care of this.
708 708 */
709 709 return (i);
710 710 }
711 711 for (i = 0; i < nzents; i++)
712 712 zone_print(&zents[i], verbose, parsable);
713 713 if (min_state >= ZONE_STATE_RUNNING)
714 714 return (Z_OK);
715 715 /*
716 716 * Next, get the full list of zones from the configuration, skipping
717 717 * any we have already printed.
718 718 */
719 719 cookie = setzoneent();
720 720 while ((name = getzoneent(cookie)) != NULL) {
721 721 for (i = 0; i < nzents; i++) {
722 722 if (strcmp(zents[i].zname, name) == 0)
723 723 break;
724 724 }
725 725 if (i < nzents) {
726 726 free(name);
727 727 continue;
728 728 }
729 729 if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
730 730 free(name);
731 731 continue;
732 732 }
733 733 free(name);
734 734 if (zent.zstate_num >= min_state)
735 735 zone_print(&zent, verbose, parsable);
736 736 }
737 737 endzoneent(cookie);
738 738 return (Z_OK);
739 739 }
740 740
741 741 static zone_entry_t *
742 742 lookup_running_zone(char *str)
743 743 {
744 744 zoneid_t zoneid;
745 745 char *cp;
746 746 int i;
747 747
748 748 if (fetch_zents() != Z_OK)
749 749 return (NULL);
750 750
751 751 for (i = 0; i < nzents; i++) {
752 752 if (strcmp(str, zents[i].zname) == 0)
753 753 return (&zents[i]);
754 754 }
755 755 errno = 0;
756 756 zoneid = strtol(str, &cp, 0);
757 757 if (zoneid < MIN_ZONEID || zoneid > MAX_ZONEID ||
758 758 errno != 0 || *cp != '\0')
759 759 return (NULL);
760 760 for (i = 0; i < nzents; i++) {
761 761 if (zoneid == zents[i].zid)
762 762 return (&zents[i]);
763 763 }
764 764 return (NULL);
765 765 }
766 766
767 767 /*
768 768 * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
769 769 * B_FALSE, it should be off. Return B_TRUE if the mode is bad (incorrect).
770 770 */
771 771 static boolean_t
772 772 bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file)
773 773 {
774 774 char *str;
775 775
776 776 assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR ||
777 777 bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP ||
778 778 bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH);
779 779 /*
780 780 * TRANSLATION_NOTE
781 781 * The strings below will be used as part of a larger message,
782 782 * either:
783 783 * (file name) must be (owner|group|world) (read|writ|execut)able
784 784 * or
785 785 * (file name) must not be (owner|group|world) (read|writ|execut)able
786 786 */
787 787 switch (bit) {
788 788 case S_IRUSR:
789 789 str = gettext("owner readable");
790 790 break;
791 791 case S_IWUSR:
792 792 str = gettext("owner writable");
793 793 break;
794 794 case S_IXUSR:
795 795 str = gettext("owner executable");
796 796 break;
797 797 case S_IRGRP:
798 798 str = gettext("group readable");
799 799 break;
800 800 case S_IWGRP:
801 801 str = gettext("group writable");
802 802 break;
803 803 case S_IXGRP:
804 804 str = gettext("group executable");
805 805 break;
806 806 case S_IROTH:
807 807 str = gettext("world readable");
808 808 break;
809 809 case S_IWOTH:
810 810 str = gettext("world writable");
811 811 break;
812 812 case S_IXOTH:
813 813 str = gettext("world executable");
814 814 break;
815 815 }
816 816 if ((mode & bit) == (on ? 0 : bit)) {
817 817 /*
818 818 * TRANSLATION_NOTE
819 819 * The first parameter below is a file name; the second
820 820 * is one of the "(owner|group|world) (read|writ|execut)able"
821 821 * strings from above.
822 822 */
823 823 /*
824 824 * The code below could be simplified but not in a way
825 825 * that would easily translate to non-English locales.
826 826 */
827 827 if (on) {
828 828 (void) fprintf(stderr, gettext("%s must be %s.\n"),
829 829 file, str);
830 830 } else {
831 831 (void) fprintf(stderr, gettext("%s must not be %s.\n"),
832 832 file, str);
833 833 }
834 834 return (B_TRUE);
835 835 }
836 836 return (B_FALSE);
837 837 }
838 838
839 839 /*
840 840 * We want to make sure that no zone has its zone path as a child node
841 841 * (in the directory sense) of any other. We do that by comparing this
842 842 * zone's path to the path of all other (non-global) zones. The comparison
843 843 * in each case is simple: add '/' to the end of the path, then do a
844 844 * strncmp() of the two paths, using the length of the shorter one.
845 845 */
846 846
847 847 static int
848 848 crosscheck_zonepaths(char *path)
849 849 {
850 850 char rpath[MAXPATHLEN]; /* resolved path */
851 851 char path_copy[MAXPATHLEN]; /* copy of original path */
852 852 char rpath_copy[MAXPATHLEN]; /* copy of original rpath */
853 853 struct zoneent *ze;
854 854 int res, err;
855 855 FILE *cookie;
856 856
857 857 cookie = setzoneent();
858 858 while ((ze = getzoneent_private(cookie)) != NULL) {
859 859 /* Skip zones which are not installed. */
860 860 if (ze->zone_state < ZONE_STATE_INSTALLED) {
861 861 free(ze);
862 862 continue;
863 863 }
864 864 /* Skip the global zone and the current target zone. */
865 865 if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 ||
866 866 strcmp(ze->zone_name, target_zone) == 0) {
867 867 free(ze);
868 868 continue;
869 869 }
870 870 if (strlen(ze->zone_path) == 0) {
871 871 /* old index file without path, fall back */
872 872 if ((err = zone_get_zonepath(ze->zone_name,
873 873 ze->zone_path, sizeof (ze->zone_path))) != Z_OK) {
874 874 errno = err;
875 875 zperror2(ze->zone_name,
876 876 gettext("could not get zone path"));
877 877 free(ze);
878 878 continue;
879 879 }
880 880 }
881 881 (void) snprintf(path_copy, sizeof (path_copy), "%s%s",
882 882 zonecfg_get_root(), ze->zone_path);
883 883 res = resolvepath(path_copy, rpath, sizeof (rpath));
884 884 if (res == -1) {
885 885 if (errno != ENOENT) {
886 886 zperror(path_copy, B_FALSE);
887 887 free(ze);
888 888 return (Z_ERR);
889 889 }
890 890 (void) printf(gettext("WARNING: zone %s is installed, "
891 891 "but its %s %s does not exist.\n"), ze->zone_name,
892 892 "zonepath", path_copy);
893 893 free(ze);
894 894 continue;
895 895 }
896 896 rpath[res] = '\0';
897 897 (void) snprintf(path_copy, sizeof (path_copy), "%s/", path);
898 898 (void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath);
899 899 if (strncmp(path_copy, rpath_copy,
900 900 min(strlen(path_copy), strlen(rpath_copy))) == 0) {
901 901 /*
902 902 * TRANSLATION_NOTE
903 903 * zonepath is a literal that should not be translated.
904 904 */
905 905 (void) fprintf(stderr, gettext("%s zonepath (%s) and "
906 906 "%s zonepath (%s) overlap.\n"),
907 907 target_zone, path, ze->zone_name, rpath);
908 908 free(ze);
909 909 return (Z_ERR);
910 910 }
911 911 free(ze);
912 912 }
913 913 endzoneent(cookie);
914 914 return (Z_OK);
915 915 }
916 916
917 917 static int
918 918 validate_zonepath(char *path, int cmd_num)
919 919 {
920 920 int res; /* result of last library/system call */
921 921 boolean_t err = B_FALSE; /* have we run into an error? */
922 922 struct stat stbuf;
923 923 struct statvfs64 vfsbuf;
924 924 char rpath[MAXPATHLEN]; /* resolved path */
925 925 char ppath[MAXPATHLEN]; /* parent path */
926 926 char rppath[MAXPATHLEN]; /* resolved parent path */
927 927 char rootpath[MAXPATHLEN]; /* root path */
928 928 zone_state_t state;
929 929
930 930 if (path[0] != '/') {
931 931 (void) fprintf(stderr,
932 932 gettext("%s is not an absolute path.\n"), path);
933 933 return (Z_ERR);
934 934 }
935 935 if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) {
936 936 if ((errno != ENOENT) ||
937 937 (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL &&
938 938 cmd_num != CMD_CLONE && cmd_num != CMD_MOVE)) {
939 939 zperror(path, B_FALSE);
940 940 return (Z_ERR);
941 941 }
942 942 if (cmd_num == CMD_VERIFY) {
943 943 /*
944 944 * TRANSLATION_NOTE
945 945 * zoneadm is a literal that should not be translated.
946 946 */
947 947 (void) fprintf(stderr, gettext("WARNING: %s does not "
948 948 "exist, so it could not be verified.\nWhen "
949 949 "'zoneadm %s' is run, '%s' will try to create\n%s, "
950 950 "and '%s' will be tried again,\nbut the '%s' may "
951 951 "fail if:\nthe parent directory of %s is group- or "
952 952 "other-writable\nor\n%s overlaps with any other "
953 953 "installed zones.\n"), path,
954 954 cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL),
955 955 path, cmd_to_str(CMD_VERIFY),
956 956 cmd_to_str(CMD_VERIFY), path, path);
957 957 return (Z_OK);
958 958 }
959 959 /*
960 960 * The zonepath is supposed to be mode 700 but its
961 961 * parent(s) 755. So use 755 on the mkdirp() then
962 962 * chmod() the zonepath itself to 700.
963 963 */
964 964 if (mkdirp(path, DEFAULT_DIR_MODE) < 0) {
965 965 zperror(path, B_FALSE);
966 966 return (Z_ERR);
967 967 }
968 968 /*
969 969 * If the chmod() fails, report the error, but might
970 970 * as well continue the verify procedure.
971 971 */
972 972 if (chmod(path, S_IRWXU) != 0)
973 973 zperror(path, B_FALSE);
974 974 /*
975 975 * Since the mkdir() succeeded, we should not have to
976 976 * worry about a subsequent ENOENT, thus this should
977 977 * only recurse once.
978 978 */
979 979 return (validate_zonepath(path, cmd_num));
980 980 }
981 981 rpath[res] = '\0';
982 982 if (strcmp(path, rpath) != 0) {
983 983 errno = Z_RESOLVED_PATH;
984 984 zperror(path, B_TRUE);
985 985 return (Z_ERR);
986 986 }
987 987 if ((res = stat(rpath, &stbuf)) != 0) {
988 988 zperror(rpath, B_FALSE);
989 989 return (Z_ERR);
990 990 }
991 991 if (!S_ISDIR(stbuf.st_mode)) {
992 992 (void) fprintf(stderr, gettext("%s is not a directory.\n"),
993 993 rpath);
994 994 return (Z_ERR);
995 995 }
996 996 if (strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) {
997 997 (void) printf(gettext("WARNING: %s is on a temporary "
998 998 "file system.\n"), rpath);
999 999 }
1000 1000 if (crosscheck_zonepaths(rpath) != Z_OK)
1001 1001 return (Z_ERR);
1002 1002 /*
1003 1003 * Try to collect and report as many minor errors as possible
1004 1004 * before returning, so the user can learn everything that needs
1005 1005 * to be fixed up front.
1006 1006 */
1007 1007 if (stbuf.st_uid != 0) {
1008 1008 (void) fprintf(stderr, gettext("%s is not owned by root.\n"),
1009 1009 rpath);
1010 1010 err = B_TRUE;
1011 1011 }
1012 1012 err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath);
1013 1013 err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath);
1014 1014 err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath);
1015 1015 err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath);
1016 1016 err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath);
1017 1017 err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath);
1018 1018 err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath);
1019 1019 err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath);
1020 1020 err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath);
1021 1021
1022 1022 (void) snprintf(ppath, sizeof (ppath), "%s/..", path);
1023 1023 if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) {
1024 1024 zperror(ppath, B_FALSE);
1025 1025 return (Z_ERR);
1026 1026 }
1027 1027 rppath[res] = '\0';
1028 1028 if ((res = stat(rppath, &stbuf)) != 0) {
1029 1029 zperror(rppath, B_FALSE);
1030 1030 return (Z_ERR);
1031 1031 }
1032 1032 /* theoretically impossible */
1033 1033 if (!S_ISDIR(stbuf.st_mode)) {
1034 1034 (void) fprintf(stderr, gettext("%s is not a directory.\n"),
1035 1035 rppath);
1036 1036 return (Z_ERR);
1037 1037 }
1038 1038 if (stbuf.st_uid != 0) {
1039 1039 (void) fprintf(stderr, gettext("%s is not owned by root.\n"),
1040 1040 rppath);
1041 1041 err = B_TRUE;
1042 1042 }
1043 1043 err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath);
1044 1044 err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath);
1045 1045 err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath);
1046 1046 err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath);
1047 1047 err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath);
1048 1048 if (strcmp(rpath, rppath) == 0) {
1049 1049 (void) fprintf(stderr, gettext("%s is its own parent.\n"),
1050 1050 rppath);
1051 1051 err = B_TRUE;
1052 1052 }
1053 1053
1054 1054 if (statvfs64(rpath, &vfsbuf) != 0) {
1055 1055 zperror(rpath, B_FALSE);
1056 1056 return (Z_ERR);
1057 1057 }
1058 1058 if (strcmp(vfsbuf.f_basetype, MNTTYPE_NFS) == 0) {
1059 1059 /*
1060 1060 * TRANSLATION_NOTE
1061 1061 * Zonepath and NFS are literals that should not be translated.
1062 1062 */
1063 1063 (void) fprintf(stderr, gettext("Zonepath %s is on an NFS "
1064 1064 "mounted file system.\n"
1065 1065 "\tA local file system must be used.\n"), rpath);
1066 1066 return (Z_ERR);
1067 1067 }
1068 1068 if (vfsbuf.f_flag & ST_NOSUID) {
1069 1069 /*
1070 1070 * TRANSLATION_NOTE
1071 1071 * Zonepath and nosuid are literals that should not be
1072 1072 * translated.
1073 1073 */
1074 1074 (void) fprintf(stderr, gettext("Zonepath %s is on a nosuid "
1075 1075 "file system.\n"), rpath);
1076 1076 return (Z_ERR);
1077 1077 }
1078 1078
1079 1079 if ((res = zone_get_state(target_zone, &state)) != Z_OK) {
1080 1080 errno = res;
1081 1081 zperror2(target_zone, gettext("could not get state"));
1082 1082 return (Z_ERR);
1083 1083 }
1084 1084 /*
1085 1085 * The existence of the root path is only bad in the configured state,
1086 1086 * as it is *supposed* to be there at the installed and later states.
1087 1087 * However, the root path is expected to be there if the zone is
1088 1088 * detached.
1089 1089 * State/command mismatches are caught earlier in verify_details().
1090 1090 */
1091 1091 if (state == ZONE_STATE_CONFIGURED && cmd_num != CMD_ATTACH) {
1092 1092 if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >=
1093 1093 sizeof (rootpath)) {
1094 1094 /*
1095 1095 * TRANSLATION_NOTE
1096 1096 * Zonepath is a literal that should not be translated.
1097 1097 */
1098 1098 (void) fprintf(stderr,
1099 1099 gettext("Zonepath %s is too long.\n"), rpath);
1100 1100 return (Z_ERR);
1101 1101 }
1102 1102 if ((res = stat(rootpath, &stbuf)) == 0) {
1103 1103 if (zonecfg_detached(rpath))
1104 1104 (void) fprintf(stderr,
1105 1105 gettext("Cannot %s detached "
1106 1106 "zone.\nUse attach or remove %s "
1107 1107 "directory.\n"), cmd_to_str(cmd_num),
1108 1108 rpath);
1109 1109 else
1110 1110 (void) fprintf(stderr,
1111 1111 gettext("Rootpath %s exists; "
1112 1112 "remove or move aside prior to %s.\n"),
1113 1113 rootpath, cmd_to_str(cmd_num));
1114 1114 return (Z_ERR);
1115 1115 }
1116 1116 }
1117 1117
1118 1118 return (err ? Z_ERR : Z_OK);
1119 1119 }
1120 1120
1121 1121 /*
1122 1122 * The following two routines implement a simple locking mechanism to
1123 1123 * ensure that only one instance of zoneadm at a time is able to manipulate
1124 1124 * a given zone. The lock is built on top of an fcntl(2) lock of
1125 1125 * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock. If a zoneadm instance
1126 1126 * can grab that lock, it is allowed to manipulate the zone.
1127 1127 *
1128 1128 * Since zoneadm may call external applications which in turn invoke
1129 1129 * zoneadm again, we introduce the notion of "lock inheritance". Any
1130 1130 * instance of zoneadm that has another instance in its ancestry is assumed
1131 1131 * to be acting on behalf of the original zoneadm, and is thus allowed to
1132 1132 * manipulate its zone.
1133 1133 *
1134 1134 * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment
1135 1135 * variable. When zoneadm is granted a lock on its zone, this environment
1136 1136 * variable is set to 1. When it releases the lock, the variable is set to
1137 1137 * 0. Since a child process inherits its parent's environment, checking
1138 1138 * the state of this variable indicates whether or not any ancestor owns
1139 1139 * the lock.
1140 1140 */
1141 1141 static void
1142 1142 release_lock_file(int lockfd)
1143 1143 {
1144 1144 /*
1145 1145 * If we are cleaning up from a failed attempt to lock the zone for
1146 1146 * the first time, we might have a zone_lock_cnt of 0. In that
1147 1147 * error case, we don't want to do anything but close the lock
1148 1148 * file.
1149 1149 */
1150 1150 assert(zone_lock_cnt >= 0);
1151 1151 if (zone_lock_cnt > 0) {
1152 1152 assert(getenv(LOCK_ENV_VAR) != NULL);
1153 1153 assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
1154 1154 if (--zone_lock_cnt > 0) {
1155 1155 assert(lockfd == -1);
1156 1156 return;
1157 1157 }
1158 1158 if (putenv(zoneadm_lock_not_held) != 0) {
1159 1159 zperror(target_zone, B_TRUE);
1160 1160 exit(Z_ERR);
1161 1161 }
1162 1162 }
1163 1163 assert(lockfd >= 0);
1164 1164 (void) close(lockfd);
1165 1165 }
1166 1166
1167 1167 static int
1168 1168 grab_lock_file(const char *zone_name, int *lockfd)
1169 1169 {
1170 1170 char pathbuf[PATH_MAX];
1171 1171 struct flock flock;
1172 1172
1173 1173 /*
1174 1174 * If we already have the lock, we can skip this expensive song
1175 1175 * and dance.
1176 1176 */
1177 1177 if (zone_lock_cnt > 0) {
1178 1178 zone_lock_cnt++;
1179 1179 *lockfd = -1;
1180 1180 return (Z_OK);
1181 1181 }
1182 1182 assert(getenv(LOCK_ENV_VAR) != NULL);
1183 1183 assert(atoi(getenv(LOCK_ENV_VAR)) == 0);
1184 1184
1185 1185 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
1186 1186 ZONES_TMPDIR) >= sizeof (pathbuf)) {
1187 1187 zerror(gettext("alternate root path is too long"));
1188 1188 return (Z_ERR);
1189 1189 }
1190 1190 if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
1191 1191 zerror(gettext("could not mkdir %s: %s"), pathbuf,
1192 1192 strerror(errno));
1193 1193 return (Z_ERR);
1194 1194 }
1195 1195 (void) chmod(pathbuf, S_IRWXU);
1196 1196
1197 1197 /*
1198 1198 * One of these lock files is created for each zone (when needed).
1199 1199 * The lock files are not cleaned up (except on system reboot),
1200 1200 * but since there is only one per zone, there is no resource
1201 1201 * starvation issue.
1202 1202 */
1203 1203 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
1204 1204 zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
1205 1205 zerror(gettext("alternate root path is too long"));
1206 1206 return (Z_ERR);
1207 1207 }
1208 1208 if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
1209 1209 zerror(gettext("could not open %s: %s"), pathbuf,
1210 1210 strerror(errno));
1211 1211 return (Z_ERR);
1212 1212 }
1213 1213 /*
1214 1214 * Lock the file to synchronize with other zoneadmds
1215 1215 */
1216 1216 flock.l_type = F_WRLCK;
1217 1217 flock.l_whence = SEEK_SET;
1218 1218 flock.l_start = (off_t)0;
1219 1219 flock.l_len = (off_t)0;
1220 1220 if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) ||
1221 1221 (putenv(zoneadm_lock_held) != 0)) {
1222 1222 zerror(gettext("unable to lock %s: %s"), pathbuf,
1223 1223 strerror(errno));
1224 1224 release_lock_file(*lockfd);
1225 1225 return (Z_ERR);
1226 1226 }
1227 1227 zone_lock_cnt = 1;
1228 1228 return (Z_OK);
1229 1229 }
1230 1230
1231 1231 static boolean_t
1232 1232 get_doorname(const char *zone_name, char *buffer)
1233 1233 {
1234 1234 return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
1235 1235 zonecfg_get_root(), zone_name) < PATH_MAX);
1236 1236 }
1237 1237
1238 1238 /*
1239 1239 * system daemons are not audited. For the global zone, this occurs
1240 1240 * "naturally" since init is started with the default audit
1241 1241 * characteristics. Since zoneadmd is a system daemon and it starts
1242 1242 * init for a zone, it is necessary to clear out the audit
1243 1243 * characteristics inherited from whomever started zoneadmd. This is
1244 1244 * indicated by the audit id, which is set from the ruid parameter of
1245 1245 * adt_set_user(), below.
1246 1246 */
1247 1247
1248 1248 static void
1249 1249 prepare_audit_context()
1250 1250 {
1251 1251 adt_session_data_t *ah;
1252 1252 char *failure = gettext("audit failure: %s");
1253 1253
1254 1254 if (adt_start_session(&ah, NULL, 0)) {
1255 1255 zerror(failure, strerror(errno));
1256 1256 return;
1257 1257 }
1258 1258 if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
1259 1259 ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
1260 1260 zerror(failure, strerror(errno));
1261 1261 (void) adt_end_session(ah);
1262 1262 return;
1263 1263 }
1264 1264 if (adt_set_proc(ah))
1265 1265 zerror(failure, strerror(errno));
1266 1266
1267 1267 (void) adt_end_session(ah);
1268 1268 }
1269 1269
1270 1270 static int
1271 1271 start_zoneadmd(const char *zone_name)
1272 1272 {
1273 1273 char doorpath[PATH_MAX];
1274 1274 pid_t child_pid;
1275 1275 int error = Z_ERR;
1276 1276 int doorfd, lockfd;
1277 1277 struct door_info info;
1278 1278
1279 1279 if (!get_doorname(zone_name, doorpath))
1280 1280 return (Z_ERR);
1281 1281
1282 1282 if (grab_lock_file(zone_name, &lockfd) != Z_OK)
1283 1283 return (Z_ERR);
1284 1284
1285 1285 /*
1286 1286 * Now that we have the lock, re-confirm that the daemon is
1287 1287 * *not* up and working fine. If it is still down, we have a green
1288 1288 * light to start it.
1289 1289 */
1290 1290 if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1291 1291 if (errno != ENOENT) {
1292 1292 zperror(doorpath, B_FALSE);
1293 1293 goto out;
1294 1294 }
1295 1295 } else {
1296 1296 if (door_info(doorfd, &info) == 0 &&
1297 1297 ((info.di_attributes & DOOR_REVOKED) == 0)) {
1298 1298 error = Z_OK;
1299 1299 (void) close(doorfd);
1300 1300 goto out;
1301 1301 }
1302 1302 (void) close(doorfd);
1303 1303 }
1304 1304
1305 1305 if ((child_pid = fork()) == -1) {
1306 1306 zperror(gettext("could not fork"), B_FALSE);
1307 1307 goto out;
1308 1308 } else if (child_pid == 0) {
1309 1309 const char *argv[6], **ap;
1310 1310
1311 1311 /* child process */
1312 1312 prepare_audit_context();
1313 1313
1314 1314 ap = argv;
1315 1315 *ap++ = "zoneadmd";
1316 1316 *ap++ = "-z";
1317 1317 *ap++ = zone_name;
1318 1318 if (zonecfg_in_alt_root()) {
1319 1319 *ap++ = "-R";
1320 1320 *ap++ = zonecfg_get_root();
1321 1321 }
1322 1322 *ap = NULL;
1323 1323
1324 1324 (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv);
1325 1325 /*
1326 1326 * TRANSLATION_NOTE
1327 1327 * zoneadmd is a literal that should not be translated.
1328 1328 */
1329 1329 zperror(gettext("could not exec zoneadmd"), B_FALSE);
1330 1330 _exit(Z_ERR);
1331 1331 } else {
1332 1332 /* parent process */
1333 1333 pid_t retval;
1334 1334 int pstatus = 0;
1335 1335
1336 1336 do {
1337 1337 retval = waitpid(child_pid, &pstatus, 0);
1338 1338 } while (retval != child_pid);
1339 1339 if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
1340 1340 WEXITSTATUS(pstatus) != 0)) {
1341 1341 zerror(gettext("could not start %s"), "zoneadmd");
1342 1342 goto out;
1343 1343 }
1344 1344 }
1345 1345 error = Z_OK;
1346 1346 out:
1347 1347 release_lock_file(lockfd);
1348 1348 return (error);
1349 1349 }
1350 1350
1351 1351 static int
1352 1352 ping_zoneadmd(const char *zone_name)
1353 1353 {
1354 1354 char doorpath[PATH_MAX];
1355 1355 int doorfd;
1356 1356 struct door_info info;
1357 1357
1358 1358 if (!get_doorname(zone_name, doorpath))
1359 1359 return (Z_ERR);
1360 1360
1361 1361 if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1362 1362 return (Z_ERR);
1363 1363 }
1364 1364 if (door_info(doorfd, &info) == 0 &&
1365 1365 ((info.di_attributes & DOOR_REVOKED) == 0)) {
1366 1366 (void) close(doorfd);
1367 1367 return (Z_OK);
1368 1368 }
1369 1369 (void) close(doorfd);
1370 1370 return (Z_ERR);
1371 1371 }
1372 1372
1373 1373 static int
1374 1374 call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg)
1375 1375 {
1376 1376 char doorpath[PATH_MAX];
1377 1377 int doorfd, result;
1378 1378 door_arg_t darg;
1379 1379
1380 1380 zoneid_t zoneid;
1381 1381 uint64_t uniqid = 0;
1382 1382
1383 1383 zone_cmd_rval_t *rvalp;
1384 1384 size_t rlen;
1385 1385 char *cp, *errbuf;
1386 1386
1387 1387 rlen = getpagesize();
1388 1388 if ((rvalp = malloc(rlen)) == NULL) {
1389 1389 zerror(gettext("failed to allocate %lu bytes: %s"), rlen,
1390 1390 strerror(errno));
1391 1391 return (-1);
1392 1392 }
1393 1393
1394 1394 if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
1395 1395 (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
1396 1396 sizeof (uniqid));
1397 1397 }
1398 1398 arg->uniqid = uniqid;
1399 1399 (void) strlcpy(arg->locale, locale, sizeof (arg->locale));
1400 1400 if (!get_doorname(zone_name, doorpath)) {
1401 1401 zerror(gettext("alternate root path is too long"));
1402 1402 free(rvalp);
1403 1403 return (-1);
1404 1404 }
1405 1405
1406 1406 /*
1407 1407 * Loop trying to start zoneadmd; if something goes seriously
1408 1408 * wrong we break out and fail.
1409 1409 */
1410 1410 for (;;) {
1411 1411 if (start_zoneadmd(zone_name) != Z_OK)
1412 1412 break;
1413 1413
1414 1414 if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1415 1415 zperror(gettext("failed to open zone door"), B_FALSE);
1416 1416 break;
1417 1417 }
1418 1418
1419 1419 darg.data_ptr = (char *)arg;
1420 1420 darg.data_size = sizeof (*arg);
1421 1421 darg.desc_ptr = NULL;
1422 1422 darg.desc_num = 0;
1423 1423 darg.rbuf = (char *)rvalp;
1424 1424 darg.rsize = rlen;
1425 1425 if (door_call(doorfd, &darg) != 0) {
1426 1426 (void) close(doorfd);
1427 1427 /*
1428 1428 * We'll get EBADF if the door has been revoked.
1429 1429 */
1430 1430 if (errno != EBADF) {
1431 1431 zperror(gettext("door_call failed"), B_FALSE);
1432 1432 break;
1433 1433 }
1434 1434 continue; /* take another lap */
1435 1435 }
1436 1436 (void) close(doorfd);
1437 1437
1438 1438 if (darg.data_size == 0) {
1439 1439 /* Door server is going away; kick it again. */
1440 1440 continue;
1441 1441 }
1442 1442
1443 1443 errbuf = rvalp->errbuf;
1444 1444 while (*errbuf != '\0') {
1445 1445 /*
1446 1446 * Remove any newlines since zerror()
1447 1447 * will append one automatically.
1448 1448 */
1449 1449 cp = strchr(errbuf, '\n');
1450 1450 if (cp != NULL)
1451 1451 *cp = '\0';
1452 1452 zerror("%s", errbuf);
1453 1453 if (cp == NULL)
1454 1454 break;
1455 1455 errbuf = cp + 1;
1456 1456 }
1457 1457 result = rvalp->rval == 0 ? 0 : -1;
1458 1458 free(rvalp);
1459 1459 return (result);
1460 1460 }
1461 1461
1462 1462 free(rvalp);
1463 1463 return (-1);
1464 1464 }
1465 1465
1466 1466 static int
1467 1467 invoke_brand_handler(int cmd_num, char *argv[])
1468 1468 {
1469 1469 zone_dochandle_t handle;
1470 1470 int err;
1471 1471
1472 1472 if ((handle = zonecfg_init_handle()) == NULL) {
1473 1473 zperror(cmd_to_str(cmd_num), B_TRUE);
1474 1474 return (Z_ERR);
1475 1475 }
1476 1476 if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
1477 1477 errno = err;
1478 1478 zperror(cmd_to_str(cmd_num), B_TRUE);
1479 1479 zonecfg_fini_handle(handle);
1480 1480 return (Z_ERR);
1481 1481 }
1482 1482 if (verify_brand(handle, cmd_num, argv) != Z_OK) {
1483 1483 zonecfg_fini_handle(handle);
1484 1484 return (Z_ERR);
1485 1485 }
1486 1486 zonecfg_fini_handle(handle);
1487 1487 return (Z_OK);
1488 1488 }
1489 1489
1490 1490 static int
1491 1491 ready_func(int argc, char *argv[])
1492 1492 {
1493 1493 zone_cmd_arg_t zarg;
1494 1494 int arg;
1495 1495
1496 1496 if (zonecfg_in_alt_root()) {
1497 1497 zerror(gettext("cannot ready zone in alternate root"));
1498 1498 return (Z_ERR);
1499 1499 }
1500 1500
1501 1501 optind = 0;
1502 1502 if ((arg = getopt(argc, argv, "?")) != EOF) {
1503 1503 switch (arg) {
1504 1504 case '?':
1505 1505 sub_usage(SHELP_READY, CMD_READY);
1506 1506 return (optopt == '?' ? Z_OK : Z_USAGE);
1507 1507 default:
1508 1508 sub_usage(SHELP_READY, CMD_READY);
1509 1509 return (Z_USAGE);
1510 1510 }
1511 1511 }
1512 1512 if (argc > optind) {
1513 1513 sub_usage(SHELP_READY, CMD_READY);
1514 1514 return (Z_USAGE);
1515 1515 }
1516 1516 if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE, B_FALSE)
1517 1517 != Z_OK)
1518 1518 return (Z_ERR);
1519 1519 if (verify_details(CMD_READY, argv) != Z_OK)
1520 1520 return (Z_ERR);
1521 1521
1522 1522 zarg.cmd = Z_READY;
1523 1523 if (call_zoneadmd(target_zone, &zarg) != 0) {
1524 1524 zerror(gettext("call to %s failed"), "zoneadmd");
1525 1525 return (Z_ERR);
1526 1526 }
1527 1527 return (Z_OK);
1528 1528 }
1529 1529
1530 1530 static int
1531 1531 boot_func(int argc, char *argv[])
1532 1532 {
1533 1533 zone_cmd_arg_t zarg;
1534 1534 boolean_t force = B_FALSE;
1535 1535 int arg;
1536 1536
1537 1537 if (zonecfg_in_alt_root()) {
1538 1538 zerror(gettext("cannot boot zone in alternate root"));
1539 1539 return (Z_ERR);
1540 1540 }
1541 1541
1542 1542 zarg.bootbuf[0] = '\0';
1543 1543
1544 1544 /*
1545 1545 * The following getopt processes arguments to zone boot; that
1546 1546 * is to say, the [here] portion of the argument string:
1547 1547 *
1548 1548 * zoneadm -z myzone boot [here] -- -v -m verbose
1549 1549 *
1550 1550 * Where [here] can either be nothing, -? (in which case we bail
1551 1551 * and print usage), -f (a private option to indicate that the
1552 1552 * boot operation should be 'forced'), or -s. Support for -s is
1553 1553 * vestigal and obsolete, but is retained because it was a
1554 1554 * documented interface and there are known consumers including
1555 1555 * admin/install; the proper way to specify boot arguments like -s
1556 1556 * is:
1557 1557 *
1558 1558 * zoneadm -z myzone boot -- -s -v -m verbose.
1559 1559 */
1560 1560 optind = 0;
1561 1561 while ((arg = getopt(argc, argv, "?fs")) != EOF) {
1562 1562 switch (arg) {
1563 1563 case '?':
1564 1564 sub_usage(SHELP_BOOT, CMD_BOOT);
1565 1565 return (optopt == '?' ? Z_OK : Z_USAGE);
1566 1566 case 's':
1567 1567 (void) strlcpy(zarg.bootbuf, "-s",
1568 1568 sizeof (zarg.bootbuf));
1569 1569 break;
1570 1570 case 'f':
1571 1571 force = B_TRUE;
1572 1572 break;
1573 1573 default:
1574 1574 sub_usage(SHELP_BOOT, CMD_BOOT);
1575 1575 return (Z_USAGE);
1576 1576 }
1577 1577 }
1578 1578
1579 1579 for (; optind < argc; optind++) {
1580 1580 if (strlcat(zarg.bootbuf, argv[optind],
1581 1581 sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
1582 1582 zerror(gettext("Boot argument list too long"));
1583 1583 return (Z_ERR);
1584 1584 }
1585 1585 if (optind < argc - 1)
1586 1586 if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
1587 1587 sizeof (zarg.bootbuf)) {
1588 1588 zerror(gettext("Boot argument list too long"));
1589 1589 return (Z_ERR);
1590 1590 }
1591 1591 }
1592 1592 if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE, force)
1593 1593 != Z_OK)
1594 1594 return (Z_ERR);
1595 1595 if (verify_details(CMD_BOOT, argv) != Z_OK)
1596 1596 return (Z_ERR);
1597 1597 zarg.cmd = force ? Z_FORCEBOOT : Z_BOOT;
1598 1598 if (call_zoneadmd(target_zone, &zarg) != 0) {
1599 1599 zerror(gettext("call to %s failed"), "zoneadmd");
1600 1600 return (Z_ERR);
1601 1601 }
1602 1602
1603 1603 return (Z_OK);
1604 1604 }
1605 1605
1606 1606 static void
1607 1607 fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr)
1608 1608 {
1609 1609 ssize_t result;
1610 1610 uuid_t uuid;
1611 1611 FILE *fp;
1612 1612 ushort_t flags;
1613 1613
1614 1614 (void) memset(zeptr, 0, sizeof (*zeptr));
1615 1615
1616 1616 zeptr->zid = zid;
1617 1617
1618 1618 /*
1619 1619 * Since we're looking up our own (non-global) zone name,
1620 1620 * we can be assured that it will succeed.
1621 1621 */
1622 1622 result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname));
1623 1623 assert(result >= 0);
1624 1624 if (zonecfg_is_scratch(zeptr->zname) &&
1625 1625 (fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
1626 1626 (void) zonecfg_reverse_scratch(fp, zeptr->zname, zeptr->zname,
1627 1627 sizeof (zeptr->zname), NULL, 0);
1628 1628 zonecfg_close_scratch(fp);
1629 1629 }
1630 1630
1631 1631 if (is_system_labeled()) {
1632 1632 (void) zone_getattr(zid, ZONE_ATTR_ROOT, zeptr->zroot,
1633 1633 sizeof (zeptr->zroot));
1634 1634 (void) strlcpy(zeptr->zbrand, NATIVE_BRAND_NAME,
1635 1635 sizeof (zeptr->zbrand));
1636 1636 } else {
1637 1637 (void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
1638 1638 (void) zone_getattr(zid, ZONE_ATTR_BRAND, zeptr->zbrand,
1639 1639 sizeof (zeptr->zbrand));
1640 1640 }
1641 1641
1642 1642 zeptr->zstate_str = "running";
1643 1643 if (zonecfg_get_uuid(zeptr->zname, uuid) == Z_OK &&
1644 1644 !uuid_is_null(uuid))
1645 1645 uuid_unparse(uuid, zeptr->zuuid);
1646 1646
1647 1647 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) {
1648 1648 zperror2(zeptr->zname, gettext("could not get zone flags"));
1649 1649 exit(Z_ERR);
1650 1650 }
1651 1651 if (flags & ZF_NET_EXCL)
1652 1652 zeptr->ziptype = ZS_EXCLUSIVE;
1653 1653 else
1654 1654 zeptr->ziptype = ZS_SHARED;
1655 1655 }
1656 1656
1657 1657 static int
1658 1658 list_func(int argc, char *argv[])
1659 1659 {
1660 1660 zone_entry_t *zentp, zent;
1661 1661 int arg, retv;
1662 1662 boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE;
1663 1663 zone_state_t min_state = ZONE_STATE_RUNNING;
1664 1664 zoneid_t zone_id = getzoneid();
1665 1665
1666 1666 if (target_zone == NULL) {
1667 1667 /* all zones: default view to running but allow override */
1668 1668 optind = 0;
1669 1669 while ((arg = getopt(argc, argv, "?cipv")) != EOF) {
1670 1670 switch (arg) {
1671 1671 case '?':
1672 1672 sub_usage(SHELP_LIST, CMD_LIST);
1673 1673 return (optopt == '?' ? Z_OK : Z_USAGE);
1674 1674 /*
1675 1675 * The 'i' and 'c' options are not mutually
1676 1676 * exclusive so if 'c' is given, then min_state
1677 1677 * is set to 0 (ZONE_STATE_CONFIGURED) which is
1678 1678 * the lowest possible state. If 'i' is given,
1679 1679 * then min_state is set to be the lowest state
1680 1680 * so far.
1681 1681 */
1682 1682 case 'c':
1683 1683 min_state = ZONE_STATE_CONFIGURED;
1684 1684 break;
1685 1685 case 'i':
1686 1686 min_state = min(ZONE_STATE_INSTALLED,
1687 1687 min_state);
1688 1688
1689 1689 break;
1690 1690 case 'p':
1691 1691 parsable = B_TRUE;
1692 1692 break;
1693 1693 case 'v':
1694 1694 verbose = B_TRUE;
1695 1695 break;
1696 1696 default:
1697 1697 sub_usage(SHELP_LIST, CMD_LIST);
1698 1698 return (Z_USAGE);
1699 1699 }
1700 1700 }
1701 1701 if (parsable && verbose) {
1702 1702 zerror(gettext("%s -p and -v are mutually exclusive."),
1703 1703 cmd_to_str(CMD_LIST));
1704 1704 return (Z_ERR);
1705 1705 }
1706 1706 if (zone_id == GLOBAL_ZONEID || is_system_labeled()) {
1707 1707 retv = zone_print_list(min_state, verbose, parsable);
1708 1708 } else {
1709 1709 fake_up_local_zone(zone_id, &zent);
1710 1710 retv = Z_OK;
1711 1711 zone_print(&zent, verbose, parsable);
1712 1712 }
1713 1713 return (retv);
1714 1714 }
1715 1715
1716 1716 /*
1717 1717 * Specific target zone: disallow -i/-c suboptions.
1718 1718 */
1719 1719 optind = 0;
1720 1720 while ((arg = getopt(argc, argv, "?pv")) != EOF) {
1721 1721 switch (arg) {
1722 1722 case '?':
1723 1723 sub_usage(SHELP_LIST, CMD_LIST);
1724 1724 return (optopt == '?' ? Z_OK : Z_USAGE);
1725 1725 case 'p':
1726 1726 parsable = B_TRUE;
1727 1727 break;
1728 1728 case 'v':
1729 1729 verbose = B_TRUE;
1730 1730 break;
1731 1731 default:
1732 1732 sub_usage(SHELP_LIST, CMD_LIST);
1733 1733 return (Z_USAGE);
1734 1734 }
1735 1735 }
1736 1736 if (parsable && verbose) {
1737 1737 zerror(gettext("%s -p and -v are mutually exclusive."),
1738 1738 cmd_to_str(CMD_LIST));
1739 1739 return (Z_ERR);
1740 1740 }
1741 1741 if (argc > optind) {
1742 1742 sub_usage(SHELP_LIST, CMD_LIST);
1743 1743 return (Z_USAGE);
1744 1744 }
1745 1745 if (zone_id != GLOBAL_ZONEID && !is_system_labeled()) {
1746 1746 fake_up_local_zone(zone_id, &zent);
1747 1747 /*
1748 1748 * main() will issue a Z_NO_ZONE error if it cannot get an
1749 1749 * id for target_zone, which in a non-global zone should
1750 1750 * happen for any zone name except `zonename`. Thus we
1751 1751 * assert() that here but don't otherwise check.
1752 1752 */
1753 1753 assert(strcmp(zent.zname, target_zone) == 0);
1754 1754 zone_print(&zent, verbose, parsable);
1755 1755 output = B_TRUE;
1756 1756 } else if ((zentp = lookup_running_zone(target_zone)) != NULL) {
1757 1757 zone_print(zentp, verbose, parsable);
1758 1758 output = B_TRUE;
1759 1759 } else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED,
1760 1760 &zent) == Z_OK) {
1761 1761 zone_print(&zent, verbose, parsable);
1762 1762 output = B_TRUE;
1763 1763 }
1764 1764
1765 1765 /*
1766 1766 * Invoke brand-specific handler. Note that we do this
1767 1767 * only if we're in the global zone, and target_zone is specified
1768 1768 * and it is not the global zone.
1769 1769 */
1770 1770 if (zone_id == GLOBAL_ZONEID && target_zone != NULL &&
1771 1771 strcmp(target_zone, GLOBAL_ZONENAME) != 0)
1772 1772 if (invoke_brand_handler(CMD_LIST, argv) != Z_OK)
1773 1773 return (Z_ERR);
1774 1774
1775 1775 return (output ? Z_OK : Z_ERR);
1776 1776 }
1777 1777
1778 1778 static void
1779 1779 sigterm(int sig)
1780 1780 {
1781 1781 /*
1782 1782 * Ignore SIG{INT,TERM}, so we don't end up in an infinite loop,
1783 1783 * then propagate the signal to our process group.
1784 1784 */
1785 1785 assert(sig == SIGINT || sig == SIGTERM);
1786 1786 (void) sigset(SIGINT, SIG_IGN);
1787 1787 (void) sigset(SIGTERM, SIG_IGN);
1788 1788 (void) kill(0, sig);
1789 1789 child_killed = B_TRUE;
1790 1790 }
1791 1791
1792 1792 static int
1793 1793 do_subproc(char *cmdbuf)
1794 1794 {
1795 1795 char inbuf[1024]; /* arbitrary large amount */
1796 1796 FILE *file;
1797 1797
1798 1798 do_subproc_cnt++;
1799 1799 child_killed = B_FALSE;
1800 1800 /*
1801 1801 * We use popen(3c) to launch child processes for [un]install;
1802 1802 * this library call does not return a PID, so we have to kill
1803 1803 * the whole process group. To avoid killing our parent, we
1804 1804 * become a process group leader here. But doing so can wreak
1805 1805 * havoc with reading from stdin when launched by a non-job-control
1806 1806 * shell, so we close stdin and reopen it as /dev/null first.
1807 1807 */
1808 1808 (void) close(STDIN_FILENO);
1809 1809 (void) openat(STDIN_FILENO, "/dev/null", O_RDONLY);
1810 1810 if (!zoneadm_is_nested)
1811 1811 (void) setpgid(0, 0);
1812 1812 (void) sigset(SIGINT, sigterm);
1813 1813 (void) sigset(SIGTERM, sigterm);
1814 1814 file = popen(cmdbuf, "r");
1815 1815 for (;;) {
1816 1816 if (child_killed || fgets(inbuf, sizeof (inbuf), file) == NULL)
1817 1817 break;
1818 1818 (void) fputs(inbuf, stdout);
1819 1819 }
1820 1820 (void) sigset(SIGINT, SIG_DFL);
1821 1821 (void) sigset(SIGTERM, SIG_DFL);
1822 1822 return (pclose(file));
1823 1823 }
1824 1824
1825 1825 static int
1826 1826 do_subproc_interactive(char *cmdbuf)
1827 1827 {
1828 1828 void (*saveint)(int);
1829 1829 void (*saveterm)(int);
1830 1830 void (*savequit)(int);
1831 1831 void (*savehup)(int);
1832 1832 int pid, child, status;
1833 1833
1834 1834 /*
1835 1835 * do_subproc() links stdin to /dev/null, which would break any
1836 1836 * interactive subprocess we try to launch here. Similarly, we
1837 1837 * can't have been launched as a subprocess ourselves.
1838 1838 */
1839 1839 assert(do_subproc_cnt == 0 && !zoneadm_is_nested);
1840 1840
1841 1841 if ((child = vfork()) == 0) {
1842 1842 (void) execl("/bin/sh", "sh", "-c", cmdbuf, (char *)NULL);
1843 1843 }
1844 1844
1845 1845 if (child == -1)
1846 1846 return (-1);
1847 1847
1848 1848 saveint = sigset(SIGINT, SIG_IGN);
1849 1849 saveterm = sigset(SIGTERM, SIG_IGN);
1850 1850 savequit = sigset(SIGQUIT, SIG_IGN);
1851 1851 savehup = sigset(SIGHUP, SIG_IGN);
1852 1852
1853 1853 while ((pid = waitpid(child, &status, 0)) != child && pid != -1)
1854 1854 ;
1855 1855
1856 1856 (void) sigset(SIGINT, saveint);
1857 1857 (void) sigset(SIGTERM, saveterm);
1858 1858 (void) sigset(SIGQUIT, savequit);
1859 1859 (void) sigset(SIGHUP, savehup);
1860 1860
1861 1861 return (pid == -1 ? -1 : status);
1862 1862 }
1863 1863
1864 1864 static int
1865 1865 subproc_status(const char *cmd, int status, boolean_t verbose_failure)
1866 1866 {
1867 1867 if (WIFEXITED(status)) {
1868 1868 int exit_code = WEXITSTATUS(status);
1869 1869
1870 1870 if ((verbose_failure) && (exit_code != ZONE_SUBPROC_OK))
1871 1871 zerror(gettext("'%s' failed with exit code %d."), cmd,
1872 1872 exit_code);
1873 1873
1874 1874 return (exit_code);
1875 1875 } else if (WIFSIGNALED(status)) {
1876 1876 int signal = WTERMSIG(status);
1877 1877 char sigstr[SIG2STR_MAX];
1878 1878
1879 1879 if (sig2str(signal, sigstr) == 0) {
1880 1880 zerror(gettext("'%s' terminated by signal SIG%s."), cmd,
1881 1881 sigstr);
1882 1882 } else {
1883 1883 zerror(gettext("'%s' terminated by an unknown signal."),
1884 1884 cmd);
1885 1885 }
1886 1886 } else {
1887 1887 zerror(gettext("'%s' failed for unknown reasons."), cmd);
1888 1888 }
1889 1889
1890 1890 /*
1891 1891 * Assume a subprocess that died due to a signal or an unknown error
1892 1892 * should be considered an exit code of ZONE_SUBPROC_FATAL, as the
1893 1893 * user will likely need to do some manual cleanup.
1894 1894 */
1895 1895 return (ZONE_SUBPROC_FATAL);
1896 1896 }
1897 1897
1898 1898 /*
1899 1899 * Various sanity checks; make sure:
1900 1900 * 1. We're in the global zone.
1901 1901 * 2. The calling user has sufficient privilege.
1902 1902 * 3. The target zone is neither the global zone nor anything starting with
1903 1903 * "SUNW".
1904 1904 * 4a. If we're looking for a 'not running' (i.e., configured or installed)
1905 1905 * zone, the name service knows about it.
1906 1906 * 4b. For some operations which expect a zone not to be running, that it is
1907 1907 * not already running (or ready).
1908 1908 */
1909 1909 static int
1910 1910 sanity_check(char *zone, int cmd_num, boolean_t running,
1911 1911 boolean_t unsafe_when_running, boolean_t force)
1912 1912 {
1913 1913 zone_entry_t *zent;
1914 1914 priv_set_t *privset;
1915 1915 zone_state_t state, min_state;
1916 1916 char kernzone[ZONENAME_MAX];
1917 1917 FILE *fp;
1918 1918
1919 1919 if (getzoneid() != GLOBAL_ZONEID) {
1920 1920 switch (cmd_num) {
1921 1921 case CMD_HALT:
1922 1922 zerror(gettext("use %s to %s this zone."), "halt(1M)",
1923 1923 cmd_to_str(cmd_num));
1924 1924 break;
1925 1925 case CMD_REBOOT:
1926 1926 zerror(gettext("use %s to %s this zone."),
1927 1927 "reboot(1M)", cmd_to_str(cmd_num));
1928 1928 break;
1929 1929 default:
1930 1930 zerror(gettext("must be in the global zone to %s a "
1931 1931 "zone."), cmd_to_str(cmd_num));
1932 1932 break;
1933 1933 }
1934 1934 return (Z_ERR);
1935 1935 }
1936 1936
1937 1937 if ((privset = priv_allocset()) == NULL) {
1938 1938 zerror(gettext("%s failed"), "priv_allocset");
1939 1939 return (Z_ERR);
1940 1940 }
1941 1941
1942 1942 if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1943 1943 zerror(gettext("%s failed"), "getppriv");
1944 1944 priv_freeset(privset);
1945 1945 return (Z_ERR);
1946 1946 }
1947 1947
1948 1948 if (priv_isfullset(privset) == B_FALSE) {
1949 1949 zerror(gettext("only a privileged user may %s a zone."),
1950 1950 cmd_to_str(cmd_num));
1951 1951 priv_freeset(privset);
1952 1952 return (Z_ERR);
1953 1953 }
1954 1954 priv_freeset(privset);
1955 1955
1956 1956 if (zone == NULL) {
1957 1957 zerror(gettext("no zone specified"));
1958 1958 return (Z_ERR);
1959 1959 }
1960 1960
1961 1961 if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
1962 1962 zerror(gettext("%s operation is invalid for the global zone."),
1963 1963 cmd_to_str(cmd_num));
1964 1964 return (Z_ERR);
1965 1965 }
1966 1966
1967 1967 if (strncmp(zone, "SUNW", 4) == 0) {
1968 1968 zerror(gettext("%s operation is invalid for zones starting "
1969 1969 "with SUNW."), cmd_to_str(cmd_num));
1970 1970 return (Z_ERR);
1971 1971 }
1972 1972
1973 1973 if (!is_native_zone && !is_cluster_zone && cmd_num == CMD_MOUNT) {
1974 1974 zerror(gettext("%s operation is invalid for branded zones."),
1975 1975 cmd_to_str(cmd_num));
1976 1976 return (Z_ERR);
1977 1977 }
1978 1978
1979 1979 if (!zonecfg_in_alt_root()) {
1980 1980 zent = lookup_running_zone(zone);
1981 1981 } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) {
1982 1982 zent = NULL;
1983 1983 } else {
1984 1984 if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(),
1985 1985 kernzone, sizeof (kernzone)) == 0)
1986 1986 zent = lookup_running_zone(kernzone);
1987 1987 else
1988 1988 zent = NULL;
1989 1989 zonecfg_close_scratch(fp);
1990 1990 }
1991 1991
1992 1992 /*
1993 1993 * Look up from the kernel for 'running' zones.
1994 1994 */
1995 1995 if (running && !force) {
1996 1996 if (zent == NULL) {
1997 1997 zerror(gettext("not running"));
1998 1998 return (Z_ERR);
1999 1999 }
2000 2000 } else {
2001 2001 int err;
2002 2002
2003 2003 if (unsafe_when_running && zent != NULL) {
2004 2004 /* check whether the zone is ready or running */
2005 2005 if ((err = zone_get_state(zent->zname,
2006 2006 &zent->zstate_num)) != Z_OK) {
2007 2007 errno = err;
2008 2008 zperror2(zent->zname,
2009 2009 gettext("could not get state"));
2010 2010 /* can't tell, so hedge */
2011 2011 zent->zstate_str = "ready/running";
2012 2012 } else {
2013 2013 zent->zstate_str =
2014 2014 zone_state_str(zent->zstate_num);
2015 2015 }
2016 2016 zerror(gettext("%s operation is invalid for %s zones."),
2017 2017 cmd_to_str(cmd_num), zent->zstate_str);
2018 2018 return (Z_ERR);
2019 2019 }
2020 2020 if ((err = zone_get_state(zone, &state)) != Z_OK) {
2021 2021 errno = err;
2022 2022 zperror2(zone, gettext("could not get state"));
2023 2023 return (Z_ERR);
2024 2024 }
2025 2025 switch (cmd_num) {
2026 2026 case CMD_UNINSTALL:
2027 2027 if (state == ZONE_STATE_CONFIGURED) {
2028 2028 zerror(gettext("is already in state '%s'."),
2029 2029 zone_state_str(ZONE_STATE_CONFIGURED));
2030 2030 return (Z_ERR);
2031 2031 }
2032 2032 break;
2033 2033 case CMD_ATTACH:
2034 2034 case CMD_CLONE:
2035 2035 case CMD_INSTALL:
2036 2036 if (state == ZONE_STATE_INSTALLED) {
2037 2037 zerror(gettext("is already %s."),
2038 2038 zone_state_str(ZONE_STATE_INSTALLED));
2039 2039 return (Z_ERR);
2040 2040 } else if (state == ZONE_STATE_INCOMPLETE) {
2041 2041 zerror(gettext("zone is %s; %s required."),
2042 2042 zone_state_str(ZONE_STATE_INCOMPLETE),
2043 2043 cmd_to_str(CMD_UNINSTALL));
2044 2044 return (Z_ERR);
2045 2045 }
2046 2046 break;
2047 2047 case CMD_DETACH:
2048 2048 case CMD_MOVE:
2049 2049 case CMD_READY:
2050 2050 case CMD_BOOT:
2051 2051 case CMD_MOUNT:
2052 2052 case CMD_MARK:
2053 2053 if ((cmd_num == CMD_BOOT || cmd_num == CMD_MOUNT) &&
2054 2054 force)
2055 2055 min_state = ZONE_STATE_INCOMPLETE;
2056 2056 else
2057 2057 min_state = ZONE_STATE_INSTALLED;
2058 2058
2059 2059 if (force && cmd_num == CMD_BOOT && is_native_zone) {
2060 2060 zerror(gettext("Only branded zones may be "
2061 2061 "force-booted."));
2062 2062 return (Z_ERR);
2063 2063 }
2064 2064
2065 2065 if (state < min_state) {
2066 2066 zerror(gettext("must be %s before %s."),
2067 2067 zone_state_str(min_state),
2068 2068 cmd_to_str(cmd_num));
2069 2069 return (Z_ERR);
2070 2070 }
2071 2071 break;
2072 2072 case CMD_VERIFY:
2073 2073 if (state == ZONE_STATE_INCOMPLETE) {
2074 2074 zerror(gettext("zone is %s; %s required."),
2075 2075 zone_state_str(ZONE_STATE_INCOMPLETE),
2076 2076 cmd_to_str(CMD_UNINSTALL));
2077 2077 return (Z_ERR);
2078 2078 }
2079 2079 break;
2080 2080 case CMD_UNMOUNT:
2081 2081 if (state != ZONE_STATE_MOUNTED) {
2082 2082 zerror(gettext("must be %s before %s."),
2083 2083 zone_state_str(ZONE_STATE_MOUNTED),
2084 2084 cmd_to_str(cmd_num));
2085 2085 return (Z_ERR);
2086 2086 }
2087 2087 break;
2088 2088 }
2089 2089 }
2090 2090 return (Z_OK);
2091 2091 }
2092 2092
2093 2093 static int
2094 2094 halt_func(int argc, char *argv[])
2095 2095 {
2096 2096 zone_cmd_arg_t zarg;
2097 2097 int arg;
2098 2098
2099 2099 if (zonecfg_in_alt_root()) {
2100 2100 zerror(gettext("cannot halt zone in alternate root"));
2101 2101 return (Z_ERR);
2102 2102 }
2103 2103
2104 2104 optind = 0;
2105 2105 if ((arg = getopt(argc, argv, "?")) != EOF) {
2106 2106 switch (arg) {
2107 2107 case '?':
2108 2108 sub_usage(SHELP_HALT, CMD_HALT);
2109 2109 return (optopt == '?' ? Z_OK : Z_USAGE);
2110 2110 default:
2111 2111 sub_usage(SHELP_HALT, CMD_HALT);
2112 2112 return (Z_USAGE);
2113 2113 }
2114 2114 }
2115 2115 if (argc > optind) {
2116 2116 sub_usage(SHELP_HALT, CMD_HALT);
2117 2117 return (Z_USAGE);
2118 2118 }
2119 2119 /*
2120 2120 * zoneadmd should be the one to decide whether or not to proceed,
2121 2121 * so even though it seems that the fourth parameter below should
2122 2122 * perhaps be B_TRUE, it really shouldn't be.
2123 2123 */
2124 2124 if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE, B_FALSE)
2125 2125 != Z_OK)
2126 2126 return (Z_ERR);
2127 2127
2128 2128 /*
2129 2129 * Invoke brand-specific handler.
2130 2130 */
2131 2131 if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
2132 2132 return (Z_ERR);
2133 2133
2134 2134 zarg.cmd = Z_HALT;
2135 2135 return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
2136 2136 }
2137 2137
2138 2138 static int
2139 2139 reboot_func(int argc, char *argv[])
2140 2140 {
2141 2141 zone_cmd_arg_t zarg;
2142 2142 int arg;
2143 2143
2144 2144 if (zonecfg_in_alt_root()) {
2145 2145 zerror(gettext("cannot reboot zone in alternate root"));
2146 2146 return (Z_ERR);
2147 2147 }
2148 2148
2149 2149 optind = 0;
2150 2150 if ((arg = getopt(argc, argv, "?")) != EOF) {
2151 2151 switch (arg) {
2152 2152 case '?':
2153 2153 sub_usage(SHELP_REBOOT, CMD_REBOOT);
2154 2154 return (optopt == '?' ? Z_OK : Z_USAGE);
2155 2155 default:
2156 2156 sub_usage(SHELP_REBOOT, CMD_REBOOT);
2157 2157 return (Z_USAGE);
2158 2158 }
2159 2159 }
2160 2160
2161 2161 zarg.bootbuf[0] = '\0';
2162 2162 for (; optind < argc; optind++) {
2163 2163 if (strlcat(zarg.bootbuf, argv[optind],
2164 2164 sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
2165 2165 zerror(gettext("Boot argument list too long"));
2166 2166 return (Z_ERR);
2167 2167 }
2168 2168 if (optind < argc - 1)
2169 2169 if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
2170 2170 sizeof (zarg.bootbuf)) {
2171 2171 zerror(gettext("Boot argument list too long"));
2172 2172 return (Z_ERR);
2173 2173 }
2174 2174 }
2175 2175
2176 2176
2177 2177 /*
2178 2178 * zoneadmd should be the one to decide whether or not to proceed,
2179 2179 * so even though it seems that the fourth parameter below should
2180 2180 * perhaps be B_TRUE, it really shouldn't be.
2181 2181 */
2182 2182 if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE, B_FALSE)
2183 2183 != Z_OK)
2184 2184 return (Z_ERR);
2185 2185 if (verify_details(CMD_REBOOT, argv) != Z_OK)
2186 2186 return (Z_ERR);
2187 2187
2188 2188 zarg.cmd = Z_REBOOT;
2189 2189 return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
2190 2190 }
2191 2191
2192 2192 static int
2193 2193 verify_brand(zone_dochandle_t handle, int cmd_num, char *argv[])
2194 2194 {
2195 2195 char cmdbuf[MAXPATHLEN];
2196 2196 int err;
2197 2197 char zonepath[MAXPATHLEN];
2198 2198 brand_handle_t bh = NULL;
2199 2199 int status, i;
2200 2200
2201 2201 /*
2202 2202 * Fetch the verify command from the brand configuration.
2203 2203 * "exec" the command so that the returned status is that of
2204 2204 * the command and not the shell.
2205 2205 */
2206 2206 if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) !=
2207 2207 Z_OK) {
2208 2208 errno = err;
2209 2209 zperror(cmd_to_str(cmd_num), B_TRUE);
2210 2210 return (Z_ERR);
2211 2211 }
2212 2212 if ((bh = brand_open(target_brand)) == NULL) {
2213 2213 zerror(gettext("missing or invalid brand"));
2214 2214 return (Z_ERR);
2215 2215 }
2216 2216
2217 2217 /*
2218 2218 * If the brand has its own verification routine, execute it now.
2219 2219 * The verification routine validates the intended zoneadm
2220 2220 * operation for the specific brand. The zoneadm subcommand and
2221 2221 * all its arguments are passed to the routine.
2222 2222 */
2223 2223 (void) strcpy(cmdbuf, EXEC_PREFIX);
2224 2224 err = brand_get_verify_adm(bh, target_zone, zonepath,
2225 2225 cmdbuf + EXEC_LEN, sizeof (cmdbuf) - EXEC_LEN, 0, NULL);
2226 2226 brand_close(bh);
2227 2227 if (err != 0)
2228 2228 return (Z_BRAND_ERROR);
2229 2229 if (strlen(cmdbuf) <= EXEC_LEN)
2230 2230 return (Z_OK);
2231 2231
2232 2232 if (strlcat(cmdbuf, cmd_to_str(cmd_num),
2233 2233 sizeof (cmdbuf)) >= sizeof (cmdbuf))
2234 2234 return (Z_ERR);
2235 2235
2236 2236 /* Build the argv string */
2237 2237 i = 0;
2238 2238 while (argv[i] != NULL) {
2239 2239 if ((strlcat(cmdbuf, " ",
2240 2240 sizeof (cmdbuf)) >= sizeof (cmdbuf)) ||
2241 2241 (strlcat(cmdbuf, argv[i++],
2242 2242 sizeof (cmdbuf)) >= sizeof (cmdbuf)))
2243 2243 return (Z_ERR);
2244 2244 }
2245 2245
2246 2246 if (zoneadm_is_nested)
2247 2247 status = do_subproc(cmdbuf);
2248 2248 else
2249 2249 status = do_subproc_interactive(cmdbuf);
2250 2250 err = subproc_status(gettext("brand-specific verification"),
2251 2251 status, B_FALSE);
2252 2252
2253 2253 return ((err == ZONE_SUBPROC_OK) ? Z_OK : Z_BRAND_ERROR);
2254 2254 }
2255 2255
2256 2256 static int
2257 2257 verify_rctls(zone_dochandle_t handle)
2258 2258 {
2259 2259 struct zone_rctltab rctltab;
2260 2260 size_t rbs = rctlblk_size();
2261 2261 rctlblk_t *rctlblk;
2262 2262 int error = Z_INVAL;
2263 2263
2264 2264 if ((rctlblk = malloc(rbs)) == NULL) {
2265 2265 zerror(gettext("failed to allocate %lu bytes: %s"), rbs,
2266 2266 strerror(errno));
2267 2267 return (Z_NOMEM);
2268 2268 }
2269 2269
2270 2270 if (zonecfg_setrctlent(handle) != Z_OK) {
2271 2271 zerror(gettext("zonecfg_setrctlent failed"));
2272 2272 free(rctlblk);
2273 2273 return (error);
2274 2274 }
2275 2275
2276 2276 rctltab.zone_rctl_valptr = NULL;
2277 2277 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
2278 2278 struct zone_rctlvaltab *rctlval;
2279 2279 const char *name = rctltab.zone_rctl_name;
2280 2280
2281 2281 if (!zonecfg_is_rctl(name)) {
2282 2282 zerror(gettext("WARNING: Ignoring unrecognized rctl "
2283 2283 "'%s'."), name);
2284 2284 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2285 2285 rctltab.zone_rctl_valptr = NULL;
2286 2286 continue;
2287 2287 }
2288 2288
2289 2289 for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL;
2290 2290 rctlval = rctlval->zone_rctlval_next) {
2291 2291 if (zonecfg_construct_rctlblk(rctlval, rctlblk)
2292 2292 != Z_OK) {
2293 2293 zerror(gettext("invalid rctl value: "
2294 2294 "(priv=%s,limit=%s,action%s)"),
2295 2295 rctlval->zone_rctlval_priv,
2296 2296 rctlval->zone_rctlval_limit,
2297 2297 rctlval->zone_rctlval_action);
2298 2298 goto out;
2299 2299 }
2300 2300 if (!zonecfg_valid_rctl(name, rctlblk)) {
2301 2301 zerror(gettext("(priv=%s,limit=%s,action=%s) "
2302 2302 "is not a valid value for rctl '%s'"),
2303 2303 rctlval->zone_rctlval_priv,
2304 2304 rctlval->zone_rctlval_limit,
2305 2305 rctlval->zone_rctlval_action,
2306 2306 name);
2307 2307 goto out;
2308 2308 }
2309 2309 }
2310 2310 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2311 2311 }
2312 2312 rctltab.zone_rctl_valptr = NULL;
2313 2313 error = Z_OK;
2314 2314 out:
2315 2315 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2316 2316 (void) zonecfg_endrctlent(handle);
2317 2317 free(rctlblk);
2318 2318 return (error);
2319 2319 }
2320 2320
2321 2321 static int
2322 2322 verify_pool(zone_dochandle_t handle)
2323 2323 {
2324 2324 char poolname[MAXPATHLEN];
2325 2325 pool_conf_t *poolconf;
2326 2326 pool_t *pool;
2327 2327 int status;
2328 2328 int error;
2329 2329
2330 2330 /*
2331 2331 * This ends up being very similar to the check done in zoneadmd.
2332 2332 */
2333 2333 error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
2334 2334 if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
2335 2335 /*
2336 2336 * No pool specified.
2337 2337 */
2338 2338 return (0);
2339 2339 }
2340 2340 if (error != Z_OK) {
2341 2341 zperror(gettext("Unable to retrieve pool name from "
2342 2342 "configuration"), B_TRUE);
2343 2343 return (error);
2344 2344 }
2345 2345 /*
2346 2346 * Don't do anything if pools aren't enabled.
2347 2347 */
2348 2348 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
2349 2349 zerror(gettext("WARNING: pools facility not active; "
2350 2350 "zone will not be bound to pool '%s'."), poolname);
2351 2351 return (Z_OK);
2352 2352 }
2353 2353 /*
2354 2354 * Try to provide a sane error message if the requested pool doesn't
2355 2355 * exist. It isn't clear that pools-related failures should
2356 2356 * necessarily translate to a failure to verify the zone configuration,
2357 2357 * hence they are not considered errors.
2358 2358 */
2359 2359 if ((poolconf = pool_conf_alloc()) == NULL) {
2360 2360 zerror(gettext("WARNING: pool_conf_alloc failed; "
2361 2361 "using default pool"));
2362 2362 return (Z_OK);
2363 2363 }
2364 2364 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
2365 2365 PO_SUCCESS) {
2366 2366 zerror(gettext("WARNING: pool_conf_open failed; "
2367 2367 "using default pool"));
2368 2368 pool_conf_free(poolconf);
2369 2369 return (Z_OK);
2370 2370 }
2371 2371 pool = pool_get_pool(poolconf, poolname);
2372 2372 (void) pool_conf_close(poolconf);
2373 2373 pool_conf_free(poolconf);
2374 2374 if (pool == NULL) {
2375 2375 zerror(gettext("WARNING: pool '%s' not found. "
2376 2376 "using default pool"), poolname);
2377 2377 }
2378 2378
2379 2379 return (Z_OK);
2380 2380 }
2381 2381
2382 2382 static int
2383 2383 verify_ipd(zone_dochandle_t handle)
2384 2384 {
2385 2385 int return_code = Z_OK;
2386 2386 struct zone_fstab fstab;
2387 2387 struct stat st;
2388 2388 char specdir[MAXPATHLEN];
2389 2389
2390 2390 if (zonecfg_setipdent(handle) != Z_OK) {
2391 2391 /*
2392 2392 * TRANSLATION_NOTE
2393 2393 * inherit-pkg-dirs is a literal that should not be translated.
2394 2394 */
2395 2395 (void) fprintf(stderr, gettext("could not verify "
2396 2396 "inherit-pkg-dirs: unable to enumerate mounts\n"));
2397 2397 return (Z_ERR);
2398 2398 }
2399 2399 while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
2400 2400 /*
2401 2401 * Verify fs_dir exists.
2402 2402 */
2403 2403 (void) snprintf(specdir, sizeof (specdir), "%s%s",
2404 2404 zonecfg_get_root(), fstab.zone_fs_dir);
2405 2405 if (stat(specdir, &st) != 0) {
2406 2406 /*
2407 2407 * TRANSLATION_NOTE
2408 2408 * inherit-pkg-dir is a literal that should not be
2409 2409 * translated.
2410 2410 */
2411 2411 (void) fprintf(stderr, gettext("could not verify "
2412 2412 "inherit-pkg-dir %s: %s\n"),
2413 2413 fstab.zone_fs_dir, strerror(errno));
2414 2414 return_code = Z_ERR;
2415 2415 }
2416 2416 if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
2417 2417 /*
2418 2418 * TRANSLATION_NOTE
2419 2419 * inherit-pkg-dir and NFS are literals that should
2420 2420 * not be translated.
2421 2421 */
2422 2422 (void) fprintf(stderr, gettext("cannot verify "
2423 2423 "inherit-pkg-dir %s: NFS mounted file system.\n"
2424 2424 "\tA local file system must be used.\n"),
2425 2425 fstab.zone_fs_dir);
2426 2426 return_code = Z_ERR;
2427 2427 }
2428 2428 }
2429 2429 (void) zonecfg_endipdent(handle);
|
↓ open down ↓ |
2392 lines elided |
↑ open up ↑ |
2430 2430
2431 2431 return (return_code);
2432 2432 }
2433 2433
2434 2434 /*
2435 2435 * Verify that the special device/file system exists and is valid.
2436 2436 */
2437 2437 static int
2438 2438 verify_fs_special(struct zone_fstab *fstab)
2439 2439 {
2440 - struct stat st;
2440 + struct stat64 st;
2441 2441
2442 2442 /*
2443 2443 * This validation is really intended for standard zone administration.
2444 2444 * If we are in a mini-root or some other upgrade situation where
2445 2445 * we are using the scratch zone, just by-pass this.
2446 2446 */
2447 2447 if (zonecfg_in_alt_root())
2448 2448 return (Z_OK);
2449 2449
2450 2450 if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
2451 2451 return (verify_fs_zfs(fstab));
2452 2452
2453 - if (stat(fstab->zone_fs_special, &st) != 0) {
2453 + if (stat64(fstab->zone_fs_special, &st) != 0) {
2454 2454 (void) fprintf(stderr, gettext("could not verify fs "
2455 2455 "%s: could not access %s: %s\n"), fstab->zone_fs_dir,
2456 2456 fstab->zone_fs_special, strerror(errno));
2457 2457 return (Z_ERR);
2458 2458 }
2459 2459
2460 2460 if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
2461 2461 /*
2462 2462 * TRANSLATION_NOTE
2463 2463 * fs and NFS are literals that should
2464 2464 * not be translated.
2465 2465 */
2466 2466 (void) fprintf(stderr, gettext("cannot verify "
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
2467 2467 "fs %s: NFS mounted file system.\n"
2468 2468 "\tA local file system must be used.\n"),
2469 2469 fstab->zone_fs_special);
2470 2470 return (Z_ERR);
2471 2471 }
2472 2472
2473 2473 return (Z_OK);
2474 2474 }
2475 2475
2476 2476 static int
2477 +isregfile(const char *path)
2478 +{
2479 + struct stat64 st;
2480 +
2481 + if (stat64(path, &st) == -1)
2482 + return (-1);
2483 +
2484 + return (S_ISREG(st.st_mode));
2485 +}
2486 +
2487 +static int
2477 2488 verify_filesystems(zone_dochandle_t handle)
2478 2489 {
2479 2490 int return_code = Z_OK;
2480 2491 struct zone_fstab fstab;
2481 2492 char cmdbuf[MAXPATHLEN];
2482 2493 struct stat st;
2483 2494
2484 2495 /*
2485 2496 * No need to verify inherit-pkg-dir fs types, as their type is
2486 2497 * implicitly lofs, which is known. Therefore, the types are only
2487 2498 * verified for regular file systems below.
2488 2499 *
2489 2500 * Since the actual mount point is not known until the dependent mounts
2490 2501 * are performed, we don't attempt any path validation here: that will
2491 2502 * happen later when zoneadmd actually does the mounts.
2492 2503 */
2493 2504 if (zonecfg_setfsent(handle) != Z_OK) {
2494 2505 (void) fprintf(stderr, gettext("could not verify file systems: "
2495 2506 "unable to enumerate mounts\n"));
2496 2507 return (Z_ERR);
2497 2508 }
2498 2509 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
2499 2510 if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) {
2500 2511 (void) fprintf(stderr, gettext("cannot verify fs %s: "
2501 2512 "type %s is not allowed.\n"), fstab.zone_fs_dir,
2502 2513 fstab.zone_fs_type);
2503 2514 return_code = Z_ERR;
2504 2515 goto next_fs;
2505 2516 }
2506 2517 /*
2507 2518 * Verify /usr/lib/fs/<fstype>/mount exists.
2508 2519 */
2509 2520 if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount",
2510 2521 fstab.zone_fs_type) &g