Print this page
11894 zonecfg export should quote strings
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/zonecfg/zonecfg.c
+++ new/usr/src/cmd/zonecfg/zonecfg.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
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2014 Gary Mills
26 + * Copyright 2019 Joyent, Inc.
26 27 */
27 28
28 29 /*
29 30 * zonecfg is a lex/yacc based command interpreter used to manage zone
30 31 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
31 32 * the grammar (see zonecfg_grammar.y) builds up into commands, some of
32 33 * which takes resources and/or properties as arguments. See the block
33 34 * comments near the end of zonecfg_grammar.y for how the data structures
34 35 * which keep track of these resources and properties are built up.
35 36 *
36 37 * The resource/property data structures are inserted into a command
37 38 * structure (see zonecfg.h), which also keeps track of command names,
38 39 * miscellaneous arguments, and function handlers. The grammar selects
39 40 * the appropriate function handler, each of which takes a pointer to a
40 41 * command structure as its sole argument, and invokes it. The grammar
41 42 * itself is "entered" (a la the Matrix) by yyparse(), which is called
42 43 * from read_input(), our main driving function. That in turn is called
43 44 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
44 45 * of which is called from main() depending on how the program was invoked.
45 46 *
46 47 * The rest of this module consists of the various function handlers and
47 48 * their helper functions. Some of these functions, particularly the
48 49 * X_to_str() functions, which maps command, resource and property numbers
49 50 * to strings, are used quite liberally, as doing so results in a better
50 51 * program w/rt I18N, reducing the need for translation notes.
51 52 */
52 53
53 54 #include <sys/mntent.h>
54 55 #include <sys/varargs.h>
55 56 #include <sys/sysmacros.h>
56 57 #include <sys/secflags.h>
57 58
58 59 #include <errno.h>
59 60 #include <fcntl.h>
60 61 #include <strings.h>
61 62 #include <unistd.h>
62 63 #include <ctype.h>
63 64 #include <stdlib.h>
64 65 #include <assert.h>
65 66 #include <sys/stat.h>
66 67 #include <zone.h>
67 68 #include <arpa/inet.h>
68 69 #include <netdb.h>
69 70 #include <locale.h>
70 71 #include <libintl.h>
71 72 #include <alloca.h>
72 73 #include <signal.h>
73 74 #include <wait.h>
74 75 #include <libtecla.h>
75 76 #include <libzfs.h>
76 77 #include <sys/brand.h>
77 78 #include <libbrand.h>
78 79 #include <sys/systeminfo.h>
79 80 #include <libdladm.h>
80 81 #include <libinetutil.h>
81 82 #include <pwd.h>
82 83 #include <inet/ip.h>
83 84
84 85 #include <libzonecfg.h>
85 86 #include "zonecfg.h"
86 87
87 88 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
88 89 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
89 90 #endif
90 91
91 92 #define PAGER "/usr/bin/more"
92 93 #define EXEC_PREFIX "exec "
93 94 #define EXEC_LEN (strlen(EXEC_PREFIX))
94 95
95 96 struct help {
96 97 uint_t cmd_num;
97 98 char *cmd_name;
98 99 uint_t flags;
99 100 char *short_usage;
100 101 };
101 102
102 103 extern int yyparse(void);
103 104 extern int lex_lineno;
104 105
105 106 #define MAX_LINE_LEN 1024
106 107 #define MAX_CMD_HIST 1024
107 108 #define MAX_CMD_LEN 1024
108 109
109 110 #define ONE_MB 1048576
110 111
111 112 /*
112 113 * Each SHELP_ should be a simple string.
113 114 */
114 115
115 116 #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \
116 117 "add <property-name> <property-value>\n\t(resource scope)"
117 118 #define SHELP_CANCEL "cancel"
118 119 #define SHELP_CLEAR "clear <property-name>"
119 120 #define SHELP_COMMIT "commit"
120 121 #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]"
121 122 #define SHELP_DELETE "delete [-F]"
122 123 #define SHELP_END "end"
123 124 #define SHELP_EXIT "exit [-F]"
124 125 #define SHELP_EXPORT "export [-f output-file]"
125 126 #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]"
126 127 #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]"
127 128 #define SHELP_REMOVE "remove [-F] <resource-type> " \
128 129 "[ <property-name>=<property-value> ]*\n" \
129 130 "\t(global scope)\n" \
130 131 "remove <property-name> <property-value>\n" \
131 132 "\t(resource scope)"
132 133 #define SHELP_REVERT "revert [-F]"
133 134 #define SHELP_SELECT "select <resource-type> { <property-name>=" \
134 135 "<property-value> }"
135 136 #define SHELP_SET "set <property-name>=<property-value>"
136 137 #define SHELP_VERIFY "verify"
137 138
138 139 static struct help helptab[] = {
139 140 { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, },
140 141 { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, },
141 142 { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, },
142 143 { CMD_COMMIT, "commit", 0, SHELP_COMMIT, },
143 144 { CMD_CREATE, "create", 0, SHELP_CREATE, },
144 145 { CMD_DELETE, "delete", 0, SHELP_DELETE, },
145 146 { CMD_END, "end", 0, SHELP_END, },
146 147 { CMD_EXIT, "exit", 0, SHELP_EXIT, },
147 148 { CMD_EXPORT, "export", 0, SHELP_EXPORT, },
148 149 { CMD_HELP, "help", 0, SHELP_HELP },
149 150 { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, },
150 151 { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, },
151 152 { CMD_REVERT, "revert", 0, SHELP_REVERT, },
152 153 { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, },
153 154 { CMD_SET, "set", HELP_PROPS, SHELP_SET, },
154 155 { CMD_VERIFY, "verify", 0, SHELP_VERIFY, },
155 156 { 0 },
156 157 };
157 158
158 159 #define MAX_RT_STRLEN 16
159 160
160 161 /* These *must* match the order of the RT_ define's from zonecfg.h */
161 162 char *res_types[] = {
162 163 "unknown",
163 164 "zonename",
164 165 "zonepath",
165 166 "autoboot",
166 167 "pool",
167 168 "fs",
168 169 "net",
169 170 "device",
170 171 "rctl",
171 172 "attr",
172 173 "dataset",
173 174 "limitpriv",
174 175 "bootargs",
175 176 "brand",
176 177 "dedicated-cpu",
177 178 "capped-memory",
178 179 ALIAS_MAXLWPS,
179 180 ALIAS_MAXSHMMEM,
180 181 ALIAS_MAXSHMIDS,
181 182 ALIAS_MAXMSGIDS,
182 183 ALIAS_MAXSEMIDS,
183 184 ALIAS_SHARES,
184 185 "scheduling-class",
185 186 "ip-type",
186 187 "capped-cpu",
187 188 "hostid",
188 189 "admin",
189 190 "fs-allowed",
190 191 ALIAS_MAXPROCS,
191 192 "security-flags",
192 193 NULL
193 194 };
194 195
195 196 /* These *must* match the order of the PT_ define's from zonecfg.h */
196 197 char *prop_types[] = {
197 198 "unknown",
198 199 "zonename",
199 200 "zonepath",
200 201 "autoboot",
201 202 "pool",
202 203 "dir",
203 204 "special",
204 205 "type",
205 206 "options",
206 207 "address",
207 208 "physical",
208 209 "name",
209 210 "value",
210 211 "match",
211 212 "priv",
212 213 "limit",
213 214 "action",
214 215 "raw",
215 216 "limitpriv",
216 217 "bootargs",
217 218 "brand",
218 219 "ncpus",
219 220 "importance",
220 221 "swap",
221 222 "locked",
222 223 ALIAS_SHARES,
223 224 ALIAS_MAXLWPS,
224 225 ALIAS_MAXSHMMEM,
225 226 ALIAS_MAXSHMIDS,
226 227 ALIAS_MAXMSGIDS,
227 228 ALIAS_MAXSEMIDS,
228 229 ALIAS_MAXLOCKEDMEM,
229 230 ALIAS_MAXSWAP,
230 231 "scheduling-class",
231 232 "ip-type",
232 233 "defrouter",
233 234 "hostid",
234 235 "user",
235 236 "auths",
236 237 "fs-allowed",
237 238 ALIAS_MAXPROCS,
238 239 "allowed-address",
239 240 "default",
240 241 "lower",
241 242 "upper",
242 243 NULL
243 244 };
244 245
245 246 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
246 247 static char *prop_val_types[] = {
247 248 "simple",
248 249 "complex",
249 250 "list",
250 251 };
251 252
252 253 /*
253 254 * The various _cmds[] lists below are for command tab-completion.
254 255 */
255 256
256 257 /*
257 258 * remove has a space afterwards because it has qualifiers; the other commands
258 259 * that have qualifiers (add, select, etc.) don't need a space here because
259 260 * they have their own _cmds[] lists below.
260 261 */
261 262 static const char *global_scope_cmds[] = {
262 263 "add",
263 264 "clear",
264 265 "commit",
265 266 "create",
266 267 "delete",
267 268 "exit",
268 269 "export",
269 270 "help",
270 271 "info",
271 272 "remove ",
272 273 "revert",
273 274 "select",
274 275 "set",
275 276 "verify",
276 277 NULL
277 278 };
278 279
279 280 static const char *add_cmds[] = {
280 281 "add fs",
281 282 "add net",
282 283 "add device",
283 284 "add rctl",
284 285 "add attr",
285 286 "add dataset",
286 287 "add dedicated-cpu",
287 288 "add capped-cpu",
288 289 "add capped-memory",
289 290 "add admin",
290 291 "add security-flags",
291 292 NULL
292 293 };
293 294
294 295 static const char *clear_cmds[] = {
295 296 "clear autoboot",
296 297 "clear pool",
297 298 "clear limitpriv",
298 299 "clear bootargs",
299 300 "clear scheduling-class",
300 301 "clear ip-type",
301 302 "clear " ALIAS_MAXLWPS,
302 303 "clear " ALIAS_MAXSHMMEM,
303 304 "clear " ALIAS_MAXSHMIDS,
304 305 "clear " ALIAS_MAXMSGIDS,
305 306 "clear " ALIAS_MAXSEMIDS,
306 307 "clear " ALIAS_SHARES,
307 308 "clear " ALIAS_MAXPROCS,
308 309 NULL
309 310 };
310 311
311 312 static const char *remove_cmds[] = {
312 313 "remove fs ",
313 314 "remove net ",
314 315 "remove device ",
315 316 "remove rctl ",
316 317 "remove attr ",
317 318 "remove dataset ",
318 319 "remove dedicated-cpu ",
319 320 "remove capped-cpu ",
320 321 "remove capped-memory ",
321 322 "remove admin ",
322 323 "remove security-flags",
323 324 NULL
324 325 };
325 326
326 327 static const char *select_cmds[] = {
327 328 "select fs ",
328 329 "select net ",
329 330 "select device ",
330 331 "select rctl ",
331 332 "select attr ",
332 333 "select dataset ",
333 334 "select dedicated-cpu",
334 335 "select capped-cpu",
335 336 "select capped-memory",
336 337 "select admin",
337 338 "select security-flags",
338 339 NULL
339 340 };
340 341
341 342 static const char *set_cmds[] = {
342 343 "set zonename=",
343 344 "set zonepath=",
344 345 "set brand=",
345 346 "set autoboot=",
346 347 "set pool=",
347 348 "set limitpriv=",
348 349 "set bootargs=",
349 350 "set scheduling-class=",
350 351 "set ip-type=",
351 352 "set " ALIAS_MAXLWPS "=",
352 353 "set " ALIAS_MAXSHMMEM "=",
353 354 "set " ALIAS_MAXSHMIDS "=",
354 355 "set " ALIAS_MAXMSGIDS "=",
355 356 "set " ALIAS_MAXSEMIDS "=",
356 357 "set " ALIAS_SHARES "=",
357 358 "set hostid=",
358 359 "set fs-allowed=",
359 360 "set " ALIAS_MAXPROCS "=",
360 361 NULL
361 362 };
362 363
363 364 static const char *info_cmds[] = {
364 365 "info fs ",
365 366 "info net ",
366 367 "info device ",
367 368 "info rctl ",
368 369 "info attr ",
369 370 "info dataset ",
370 371 "info capped-memory",
371 372 "info dedicated-cpu",
372 373 "info capped-cpu",
373 374 "info security-flags",
374 375 "info zonename",
375 376 "info zonepath",
376 377 "info autoboot",
377 378 "info pool",
378 379 "info limitpriv",
379 380 "info bootargs",
380 381 "info brand",
381 382 "info scheduling-class",
382 383 "info ip-type",
383 384 "info max-lwps",
384 385 "info max-shm-memory",
385 386 "info max-shm-ids",
386 387 "info max-msg-ids",
387 388 "info max-sem-ids",
388 389 "info cpu-shares",
389 390 "info hostid",
390 391 "info admin",
391 392 "info fs-allowed",
392 393 "info max-processes",
393 394 NULL
394 395 };
395 396
396 397 static const char *fs_res_scope_cmds[] = {
397 398 "add options ",
398 399 "cancel",
399 400 "end",
400 401 "exit",
401 402 "help",
402 403 "info",
403 404 "remove options ",
404 405 "set dir=",
405 406 "set raw=",
406 407 "set special=",
407 408 "set type=",
408 409 "clear raw",
409 410 NULL
410 411 };
411 412
412 413 static const char *net_res_scope_cmds[] = {
413 414 "cancel",
414 415 "end",
415 416 "exit",
416 417 "help",
417 418 "info",
418 419 "set address=",
419 420 "set allowed-address=",
420 421 "set physical=",
421 422 "set defrouter=",
422 423 NULL
423 424 };
424 425
425 426 static const char *device_res_scope_cmds[] = {
426 427 "cancel",
427 428 "end",
428 429 "exit",
429 430 "help",
430 431 "info",
431 432 "set match=",
432 433 NULL
433 434 };
434 435
435 436 static const char *attr_res_scope_cmds[] = {
436 437 "cancel",
437 438 "end",
438 439 "exit",
439 440 "help",
440 441 "info",
441 442 "set name=",
442 443 "set type=",
443 444 "set value=",
444 445 NULL
445 446 };
446 447
447 448 static const char *rctl_res_scope_cmds[] = {
448 449 "add value ",
449 450 "cancel",
450 451 "end",
451 452 "exit",
452 453 "help",
453 454 "info",
454 455 "remove value ",
455 456 "set name=",
456 457 NULL
457 458 };
458 459
459 460 static const char *dataset_res_scope_cmds[] = {
460 461 "cancel",
461 462 "end",
462 463 "exit",
463 464 "help",
464 465 "info",
465 466 "set name=",
466 467 NULL
467 468 };
468 469
469 470 static const char *pset_res_scope_cmds[] = {
470 471 "cancel",
471 472 "end",
472 473 "exit",
473 474 "help",
474 475 "info",
475 476 "set ncpus=",
476 477 "set importance=",
477 478 "clear importance",
478 479 NULL
479 480 };
480 481
481 482 static const char *pcap_res_scope_cmds[] = {
482 483 "cancel",
483 484 "end",
484 485 "exit",
485 486 "help",
486 487 "info",
487 488 "set ncpus=",
488 489 NULL
489 490 };
490 491
491 492 static const char *mcap_res_scope_cmds[] = {
492 493 "cancel",
493 494 "end",
494 495 "exit",
495 496 "help",
496 497 "info",
497 498 "set physical=",
498 499 "set swap=",
499 500 "set locked=",
500 501 "clear physical",
501 502 "clear swap",
502 503 "clear locked",
503 504 NULL
504 505 };
505 506
506 507 static const char *admin_res_scope_cmds[] = {
507 508 "cancel",
508 509 "end",
509 510 "exit",
510 511 "help",
511 512 "info",
512 513 "set user=",
513 514 "set auths=",
514 515 NULL
515 516 };
516 517
517 518 static const char *secflags_res_scope_cmds[] = {
518 519 "cancel",
519 520 "end",
520 521 "exit",
521 522 "set default=",
522 523 "set lower=",
523 524 "set upper=",
524 525 NULL
525 526 };
526 527
527 528 struct xif {
528 529 struct xif *xif_next;
529 530 char xif_name[LIFNAMSIZ];
530 531 boolean_t xif_has_address;
531 532 boolean_t xif_has_defrouter;
532 533 };
533 534
534 535 /* Global variables */
535 536
536 537 /* list of network interfaces specified for exclusive IP zone */
537 538 struct xif *xif;
538 539
539 540 /* set early in main(), never modified thereafter, used all over the place */
540 541 static char *execname;
541 542
542 543 /* set in main(), used all over the place */
543 544 static zone_dochandle_t handle;
544 545
545 546 /* used all over the place */
546 547 static char zone[ZONENAME_MAX];
547 548 static char revert_zone[ZONENAME_MAX];
548 549
549 550 /* global brand operations */
550 551 static brand_handle_t brand;
551 552
552 553 /* set in modifying functions, checked in read_input() */
553 554 static boolean_t need_to_commit = B_FALSE;
554 555 boolean_t saw_error;
555 556
556 557 /* set in yacc parser, checked in read_input() */
557 558 boolean_t newline_terminated;
558 559
559 560 /* set in main(), checked in lex error handler */
560 561 boolean_t cmd_file_mode;
561 562
562 563 /* set in exit_func(), checked in read_input() */
563 564 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
564 565
565 566 /* used in short_usage() and zerr() */
566 567 static char *cmd_file_name = NULL;
567 568
568 569 /* checked in read_input() and other places */
569 570 static boolean_t ok_to_prompt = B_FALSE;
570 571
571 572 /* set and checked in initialize() */
572 573 static boolean_t got_handle = B_FALSE;
573 574
574 575 /* initialized in do_interactive(), checked in initialize() */
575 576 static boolean_t interactive_mode;
576 577
577 578 /* set if configuring the global zone */
578 579 static boolean_t global_zone = B_FALSE;
579 580
580 581 /* set in main(), checked in multiple places */
581 582 static boolean_t read_only_mode;
582 583
583 584 /* scope is outer/global or inner/resource */
584 585 static boolean_t global_scope = B_TRUE;
585 586 static int resource_scope; /* should be in the RT_ list from zonecfg.h */
586 587 static int end_op = -1; /* operation on end is either add or modify */
587 588
588 589 int num_prop_vals; /* for grammar */
589 590
590 591 /*
591 592 * These are for keeping track of resources as they are specified as part of
592 593 * the multi-step process. They should be initialized by add_resource() or
593 594 * select_func() and filled in by add_property() or set_func().
594 595 */
595 596 static struct zone_fstab old_fstab, in_progress_fstab;
596 597 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab;
597 598 static struct zone_devtab old_devtab, in_progress_devtab;
598 599 static struct zone_rctltab old_rctltab, in_progress_rctltab;
599 600 static struct zone_attrtab old_attrtab, in_progress_attrtab;
600 601 static struct zone_dstab old_dstab, in_progress_dstab;
601 602 static struct zone_psettab old_psettab, in_progress_psettab;
602 603 static struct zone_mcaptab old_mcaptab, in_progress_mcaptab;
603 604 static struct zone_admintab old_admintab, in_progress_admintab;
604 605 static struct zone_secflagstab old_secflagstab, in_progress_secflagstab;
605 606
606 607 static GetLine *gl; /* The gl_get_line() resource object */
607 608
608 609 static void bytes_to_units(char *str, char *buf, int bufsize);
609 610
610 611 /* Functions begin here */
611 612
612 613 static boolean_t
613 614 initial_match(const char *line1, const char *line2, int word_end)
614 615 {
615 616 if (word_end <= 0)
616 617 return (B_TRUE);
617 618 return (strncmp(line1, line2, word_end) == 0);
618 619 }
619 620
620 621 static int
621 622 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
622 623 int word_end)
623 624 {
624 625 int i, err;
625 626
626 627 for (i = 0; list[i] != NULL; i++) {
627 628 if (initial_match(line1, list[i], word_end)) {
628 629 err = cpl_add_completion(cpl, line1, 0, word_end,
629 630 list[i] + word_end, "", "");
630 631 if (err != 0)
631 632 return (err);
632 633 }
633 634 }
634 635 return (0);
635 636 }
636 637
637 638 static
638 639 /* ARGSUSED */
639 640 CPL_MATCH_FN(cmd_cpl_fn)
640 641 {
641 642 if (global_scope) {
642 643 /*
643 644 * The MAX/MIN tests below are to make sure we have at least
644 645 * enough characters to distinguish from other prefixes (MAX)
645 646 * but only check MIN(what we have, what we're checking).
646 647 */
647 648 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
648 649 return (add_stuff(cpl, line, add_cmds, word_end));
649 650 if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
650 651 return (add_stuff(cpl, line, clear_cmds, word_end));
651 652 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
652 653 return (add_stuff(cpl, line, select_cmds, word_end));
653 654 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
654 655 return (add_stuff(cpl, line, set_cmds, word_end));
655 656 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
656 657 return (add_stuff(cpl, line, remove_cmds, word_end));
657 658 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
658 659 return (add_stuff(cpl, line, info_cmds, word_end));
659 660 return (add_stuff(cpl, line, global_scope_cmds, word_end));
660 661 }
661 662 switch (resource_scope) {
662 663 case RT_FS:
663 664 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
664 665 case RT_NET:
665 666 return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
666 667 case RT_DEVICE:
667 668 return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
668 669 case RT_RCTL:
669 670 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
670 671 case RT_ATTR:
671 672 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
672 673 case RT_DATASET:
673 674 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
674 675 case RT_DCPU:
675 676 return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
676 677 case RT_PCAP:
677 678 return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
678 679 case RT_MCAP:
679 680 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
680 681 case RT_ADMIN:
681 682 return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
682 683 case RT_SECFLAGS:
683 684 return (add_stuff(cpl, line, secflags_res_scope_cmds,
684 685 word_end));
685 686
686 687 }
687 688 return (0);
688 689 }
689 690
690 691 /*
691 692 * For the main CMD_func() functions below, several of them call getopt()
692 693 * then check optind against argc to make sure an extra parameter was not
693 694 * passed in. The reason this is not caught in the grammar is that the
694 695 * grammar just checks for a miscellaneous TOKEN, which is *expected* to
695 696 * be "-F" (for example), but could be anything. So (for example) this
696 697 * check will prevent "create bogus".
697 698 */
698 699
699 700 cmd_t *
700 701 alloc_cmd(void)
701 702 {
702 703 return (calloc(1, sizeof (cmd_t)));
703 704 }
704 705
705 706 void
706 707 free_cmd(cmd_t *cmd)
707 708 {
708 709 int i;
709 710
710 711 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
711 712 if (cmd->cmd_property_ptr[i] != NULL) {
712 713 property_value_ptr_t pp = cmd->cmd_property_ptr[i];
713 714
714 715 switch (pp->pv_type) {
715 716 case PROP_VAL_SIMPLE:
716 717 free(pp->pv_simple);
717 718 break;
718 719 case PROP_VAL_COMPLEX:
719 720 free_complex(pp->pv_complex);
720 721 break;
721 722 case PROP_VAL_LIST:
722 723 free_list(pp->pv_list);
723 724 break;
724 725 }
725 726 }
726 727 for (i = 0; i < cmd->cmd_argc; i++)
727 728 free(cmd->cmd_argv[i]);
728 729 free(cmd);
729 730 }
730 731
731 732 complex_property_ptr_t
732 733 alloc_complex(void)
733 734 {
734 735 return (calloc(1, sizeof (complex_property_t)));
735 736 }
736 737
737 738 void
738 739 free_complex(complex_property_ptr_t complex)
739 740 {
740 741 if (complex == NULL)
741 742 return;
742 743 free_complex(complex->cp_next);
743 744 if (complex->cp_value != NULL)
744 745 free(complex->cp_value);
745 746 free(complex);
746 747 }
747 748
748 749 list_property_ptr_t
749 750 alloc_list(void)
750 751 {
751 752 return (calloc(1, sizeof (list_property_t)));
752 753 }
753 754
754 755 void
755 756 free_list(list_property_ptr_t list)
756 757 {
757 758 if (list == NULL)
758 759 return;
759 760 if (list->lp_simple != NULL)
760 761 free(list->lp_simple);
761 762 free_complex(list->lp_complex);
762 763 free_list(list->lp_next);
763 764 free(list);
764 765 }
765 766
766 767 void
767 768 free_outer_list(list_property_ptr_t list)
768 769 {
769 770 if (list == NULL)
770 771 return;
771 772 free_outer_list(list->lp_next);
772 773 free(list);
773 774 }
774 775
775 776 static struct zone_rctlvaltab *
776 777 alloc_rctlvaltab(void)
777 778 {
778 779 return (calloc(1, sizeof (struct zone_rctlvaltab)));
779 780 }
780 781
781 782 static char *
782 783 rt_to_str(int res_type)
783 784 {
784 785 assert(res_type >= RT_MIN && res_type <= RT_MAX);
785 786 return (res_types[res_type]);
786 787 }
787 788
788 789 static char *
789 790 pt_to_str(int prop_type)
790 791 {
791 792 assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
792 793 return (prop_types[prop_type]);
793 794 }
794 795
795 796 static char *
796 797 pvt_to_str(int pv_type)
797 798 {
798 799 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
799 800 return (prop_val_types[pv_type]);
800 801 }
801 802
802 803 static char *
803 804 cmd_to_str(int cmd_num)
804 805 {
805 806 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
806 807 return (helptab[cmd_num].cmd_name);
807 808 }
808 809
809 810 /* PRINTFLIKE1 */
810 811 static void
811 812 zerr(const char *fmt, ...)
812 813 {
813 814 va_list alist;
814 815 static int last_lineno;
815 816
816 817 /* lex_lineno has already been incremented in the lexer; compensate */
817 818 if (cmd_file_mode && lex_lineno > last_lineno) {
818 819 if (strcmp(cmd_file_name, "-") == 0)
819 820 (void) fprintf(stderr, gettext("On line %d:\n"),
820 821 lex_lineno - 1);
821 822 else
822 823 (void) fprintf(stderr, gettext("On line %d of %s:\n"),
823 824 lex_lineno - 1, cmd_file_name);
824 825 last_lineno = lex_lineno;
825 826 }
826 827 va_start(alist, fmt);
827 828 (void) vfprintf(stderr, fmt, alist);
828 829 (void) fprintf(stderr, "\n");
829 830 va_end(alist);
830 831 }
831 832
832 833 /*
833 834 * This is a separate function rather than a set of define's because of the
834 835 * gettext() wrapping.
835 836 */
836 837
837 838 /*
838 839 * TRANSLATION_NOTE
839 840 * Each string below should have \t follow \n whenever needed; the
840 841 * initial \t and the terminal \n will be provided by the calling function.
841 842 */
842 843
843 844 static char *
844 845 long_help(int cmd_num)
845 846 {
846 847 static char line[1024]; /* arbitrary large amount */
847 848
848 849 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
849 850 switch (cmd_num) {
850 851 case CMD_HELP:
851 852 return (gettext("Prints help message."));
852 853 case CMD_CREATE:
853 854 (void) snprintf(line, sizeof (line),
854 855 gettext("Creates a configuration for the "
855 856 "specified zone. %s should be\n\tused to "
856 857 "begin configuring a new zone. If overwriting an "
857 858 "existing\n\tconfiguration, the -F flag can be "
858 859 "used to force the action. If\n\t-t template is "
859 860 "given, creates a configuration identical to the\n"
860 861 "\tspecified template, except that the zone name "
861 862 "is changed from\n\ttemplate to zonename. '%s -a' "
862 863 "creates a configuration from a\n\tdetached "
863 864 "zonepath. '%s -b' results in a blank "
864 865 "configuration.\n\t'%s' with no arguments applies "
865 866 "the Sun default settings."),
866 867 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
867 868 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
868 869 return (line);
869 870 case CMD_EXIT:
870 871 return (gettext("Exits the program. The -F flag can "
871 872 "be used to force the action."));
872 873 case CMD_EXPORT:
873 874 return (gettext("Prints configuration to standard "
874 875 "output, or to output-file if\n\tspecified, in "
875 876 "a form suitable for use in a command-file."));
876 877 case CMD_ADD:
877 878 return (gettext("Add specified resource to "
878 879 "configuration."));
879 880 case CMD_DELETE:
880 881 return (gettext("Deletes the specified zone. The -F "
881 882 "flag can be used to force the\n\taction."));
882 883 case CMD_REMOVE:
883 884 return (gettext("Remove specified resource from "
884 885 "configuration. The -F flag can be used\n\tto "
885 886 "force the action."));
886 887 case CMD_SELECT:
887 888 (void) snprintf(line, sizeof (line),
888 889 gettext("Selects a resource to modify. "
889 890 "Resource modification is completed\n\twith the "
890 891 "command \"%s\". The property name/value pairs "
891 892 "must uniquely\n\tidentify a resource. Note that "
892 893 "the curly braces ('{', '}') mean one\n\tor more "
893 894 "of whatever is between them."),
894 895 cmd_to_str(CMD_END));
895 896 return (line);
896 897 case CMD_SET:
897 898 return (gettext("Sets property values."));
898 899 case CMD_CLEAR:
899 900 return (gettext("Clears property values."));
900 901 case CMD_INFO:
901 902 return (gettext("Displays information about the "
902 903 "current configuration. If resource\n\ttype is "
903 904 "specified, displays only information about "
904 905 "resources of\n\tthe relevant type. If resource "
905 906 "id is specified, displays only\n\tinformation "
906 907 "about that resource."));
907 908 case CMD_VERIFY:
908 909 return (gettext("Verifies current configuration "
909 910 "for correctness (some resource types\n\thave "
910 911 "required properties)."));
911 912 case CMD_COMMIT:
912 913 (void) snprintf(line, sizeof (line),
913 914 gettext("Commits current configuration. "
914 915 "Configuration must be committed to\n\tbe used by "
915 916 "%s. Until the configuration is committed, "
916 917 "changes \n\tcan be removed with the %s "
917 918 "command. This operation is\n\tattempted "
918 919 "automatically upon completion of a %s "
919 920 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
920 921 "zonecfg");
921 922 return (line);
922 923 case CMD_REVERT:
923 924 return (gettext("Reverts configuration back to the "
924 925 "last committed state. The -F flag\n\tcan be "
925 926 "used to force the action."));
926 927 case CMD_CANCEL:
927 928 return (gettext("Cancels resource/property "
928 929 "specification."));
929 930 case CMD_END:
930 931 return (gettext("Ends resource/property "
931 932 "specification."));
932 933 }
933 934 /* NOTREACHED */
934 935 return (NULL);
935 936 }
936 937
937 938 /*
938 939 * Return the input filename appended to each component of the path
939 940 * or the filename itself if it is absolute.
940 941 * Parameters: path string, file name, output string.
941 942 */
942 943 /* Copied almost verbatim from libtnfctl/prb_findexec.c */
943 944 static const char *
944 945 exec_cat(const char *s1, const char *s2, char *si)
945 946 {
946 947 char *s;
947 948 /* Number of remaining characters in s */
948 949 int cnt = PATH_MAX + 1;
949 950
950 951 s = si;
951 952 while (*s1 && *s1 != ':') { /* Copy first component of path to si */
952 953 if (cnt > 0) {
953 954 *s++ = *s1++;
954 955 cnt--;
955 956 } else {
956 957 s1++;
957 958 }
958 959 }
959 960 if (si != s && cnt > 0) { /* Add slash if s2 is not absolute */
960 961 *s++ = '/';
961 962 cnt--;
962 963 }
963 964 while (*s2 && cnt > 0) { /* Copy s2 to si */
964 965 *s++ = *s2++;
965 966 cnt--;
966 967 }
967 968 *s = '\0'; /* Terminate the output string */
968 969 return (*s1 ? ++s1 : NULL); /* Return next path component or NULL */
969 970 }
970 971
971 972 /* Determine that a name exists in PATH */
972 973 /* Copied with changes from libtnfctl/prb_findexec.c */
973 974 static int
974 975 path_find(const char *name)
975 976 {
976 977 const char *pathstr;
977 978 char fname[PATH_MAX + 2];
978 979 const char *cp;
979 980 struct stat stat_buf;
980 981
981 982 if ((pathstr = getenv("PATH")) == NULL) {
982 983 if (geteuid() == 0 || getuid() == 0)
983 984 pathstr = "/usr/sbin:/usr/bin";
984 985 else
985 986 pathstr = "/usr/bin:";
986 987 }
987 988 cp = strchr(name, '/') ? (const char *) "" : pathstr;
988 989
989 990 do {
990 991 cp = exec_cat(cp, name, fname);
991 992 if (stat(fname, &stat_buf) != -1) {
992 993 /* successful find of the file */
993 994 return (0);
994 995 }
995 996 } while (cp != NULL);
996 997
997 998 return (-1);
998 999 }
999 1000
1000 1001 static FILE *
1001 1002 pager_open(void)
1002 1003 {
1003 1004 FILE *newfp;
1004 1005 char *pager, *space;
1005 1006
1006 1007 pager = getenv("PAGER");
1007 1008 if (pager == NULL || *pager == '\0')
1008 1009 pager = PAGER;
1009 1010
1010 1011 space = strchr(pager, ' ');
1011 1012 if (space)
1012 1013 *space = '\0';
1013 1014 if (path_find(pager) == 0) {
1014 1015 if (space)
1015 1016 *space = ' ';
1016 1017 if ((newfp = popen(pager, "w")) == NULL)
1017 1018 zerr(gettext("PAGER open failed (%s)."),
1018 1019 strerror(errno));
1019 1020 return (newfp);
1020 1021 } else {
1021 1022 zerr(gettext("PAGER %s does not exist (%s)."),
1022 1023 pager, strerror(errno));
1023 1024 }
1024 1025 return (NULL);
1025 1026 }
1026 1027
1027 1028 static void
1028 1029 pager_close(FILE *fp)
1029 1030 {
1030 1031 int status;
1031 1032
1032 1033 status = pclose(fp);
1033 1034 if (status == -1)
1034 1035 zerr(gettext("PAGER close failed (%s)."),
1035 1036 strerror(errno));
1036 1037 }
1037 1038
1038 1039 /*
1039 1040 * Called with verbose TRUE when help is explicitly requested, FALSE for
1040 1041 * unexpected errors.
1041 1042 */
1042 1043
1043 1044 void
1044 1045 usage(boolean_t verbose, uint_t flags)
1045 1046 {
1046 1047 FILE *fp = verbose ? stdout : stderr;
1047 1048 FILE *newfp;
1048 1049 boolean_t need_to_close = B_FALSE;
1049 1050 int i;
1050 1051
1051 1052 /* don't page error output */
1052 1053 if (verbose && interactive_mode) {
1053 1054 if ((newfp = pager_open()) != NULL) {
1054 1055 need_to_close = B_TRUE;
1055 1056 fp = newfp;
1056 1057 }
1057 1058 }
1058 1059
1059 1060 if (flags & HELP_META) {
1060 1061 (void) fprintf(fp, gettext("More help is available for the "
1061 1062 "following:\n"));
1062 1063 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1063 1064 cmd_to_str(CMD_HELP));
1064 1065 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1065 1066 cmd_to_str(CMD_HELP));
1066 1067 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1067 1068 cmd_to_str(CMD_HELP));
1068 1069 (void) fprintf(fp, gettext("You may also obtain help on any "
1069 1070 "command by typing '%s <command-name>.'\n"),
1070 1071 cmd_to_str(CMD_HELP));
1071 1072 }
1072 1073 if (flags & HELP_RES_SCOPE) {
1073 1074 switch (resource_scope) {
1074 1075 case RT_FS:
1075 1076 (void) fprintf(fp, gettext("The '%s' resource scope is "
1076 1077 "used to configure a file-system.\n"),
1077 1078 rt_to_str(resource_scope));
1078 1079 (void) fprintf(fp, gettext("Valid commands:\n"));
1079 1080 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1080 1081 pt_to_str(PT_DIR), gettext("<path>"));
1081 1082 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1082 1083 pt_to_str(PT_SPECIAL), gettext("<path>"));
1083 1084 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1084 1085 pt_to_str(PT_RAW), gettext("<raw-device>"));
1085 1086 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1086 1087 pt_to_str(PT_TYPE), gettext("<file-system type>"));
1087 1088 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
1088 1089 pt_to_str(PT_OPTIONS),
1089 1090 gettext("<file-system options>"));
1090 1091 (void) fprintf(fp, "\t%s %s %s\n",
1091 1092 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
1092 1093 gettext("<file-system options>"));
1093 1094 (void) fprintf(fp, gettext("Consult the file-system "
1094 1095 "specific manual page, such as mount_ufs(1M), "
1095 1096 "for\ndetails about file-system options. Note "
1096 1097 "that any file-system options with an\nembedded "
1097 1098 "'=' character must be enclosed in double quotes, "
1098 1099 /*CSTYLED*/
1099 1100 "such as \"%s=5\".\n"), MNTOPT_RETRY);
1100 1101 break;
1101 1102 case RT_NET:
1102 1103 (void) fprintf(fp, gettext("The '%s' resource scope is "
1103 1104 "used to configure a network interface.\n"),
1104 1105 rt_to_str(resource_scope));
1105 1106 (void) fprintf(fp, gettext("Valid commands:\n"));
1106 1107 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1107 1108 pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
1108 1109 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1109 1110 pt_to_str(PT_ALLOWED_ADDRESS),
1110 1111 gettext("<IP-address>"));
1111 1112 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1112 1113 pt_to_str(PT_PHYSICAL), gettext("<interface>"));
1113 1114 (void) fprintf(fp, gettext("See ifconfig(1M) for "
1114 1115 "details of the <interface> string.\n"));
1115 1116 (void) fprintf(fp, gettext("%s %s is valid "
1116 1117 "if the %s property is set to %s, otherwise it "
1117 1118 "must not be set.\n"),
1118 1119 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
1119 1120 pt_to_str(PT_IPTYPE), gettext("shared"));
1120 1121 (void) fprintf(fp, gettext("%s %s is valid "
1121 1122 "if the %s property is set to %s, otherwise it "
1122 1123 "must not be set.\n"),
1123 1124 cmd_to_str(CMD_SET), pt_to_str(PT_ALLOWED_ADDRESS),
1124 1125 pt_to_str(PT_IPTYPE), gettext("exclusive"));
1125 1126 (void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
1126 1127 "is valid if the %s or %s property is set, "
1127 1128 "otherwise it must not be set\n"),
1128 1129 cmd_to_str(CMD_SET),
1129 1130 pt_to_str(PT_DEFROUTER), gettext("<IP-address>"),
1130 1131 cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
1131 1132 gettext(pt_to_str(PT_ADDRESS)),
1132 1133 gettext(pt_to_str(PT_ALLOWED_ADDRESS)));
1133 1134 break;
1134 1135 case RT_DEVICE:
1135 1136 (void) fprintf(fp, gettext("The '%s' resource scope is "
1136 1137 "used to configure a device node.\n"),
1137 1138 rt_to_str(resource_scope));
1138 1139 (void) fprintf(fp, gettext("Valid commands:\n"));
1139 1140 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1140 1141 pt_to_str(PT_MATCH), gettext("<device-path>"));
1141 1142 break;
1142 1143 case RT_RCTL:
1143 1144 (void) fprintf(fp, gettext("The '%s' resource scope is "
1144 1145 "used to configure a resource control.\n"),
1145 1146 rt_to_str(resource_scope));
1146 1147 (void) fprintf(fp, gettext("Valid commands:\n"));
1147 1148 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1148 1149 pt_to_str(PT_NAME), gettext("<string>"));
1149 1150 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1150 1151 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1151 1152 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1152 1153 pt_to_str(PT_LIMIT), gettext("<number>"),
1153 1154 pt_to_str(PT_ACTION), gettext("<action-value>"));
1154 1155 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1155 1156 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
1156 1157 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1157 1158 pt_to_str(PT_LIMIT), gettext("<number>"),
1158 1159 pt_to_str(PT_ACTION), gettext("<action-value>"));
1159 1160 (void) fprintf(fp, "%s\n\t%s := privileged\n"
1160 1161 "\t%s := none | deny\n", gettext("Where"),
1161 1162 gettext("<priv-value>"), gettext("<action-value>"));
1162 1163 break;
1163 1164 case RT_ATTR:
1164 1165 (void) fprintf(fp, gettext("The '%s' resource scope is "
1165 1166 "used to configure a generic attribute.\n"),
1166 1167 rt_to_str(resource_scope));
1167 1168 (void) fprintf(fp, gettext("Valid commands:\n"));
1168 1169 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1169 1170 pt_to_str(PT_NAME), gettext("<name>"));
1170 1171 (void) fprintf(fp, "\t%s %s=boolean\n",
1171 1172 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1172 1173 (void) fprintf(fp, "\t%s %s=true | false\n",
1173 1174 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
1174 1175 (void) fprintf(fp, gettext("or\n"));
1175 1176 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
1176 1177 pt_to_str(PT_TYPE));
1177 1178 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1178 1179 pt_to_str(PT_VALUE), gettext("<integer>"));
1179 1180 (void) fprintf(fp, gettext("or\n"));
1180 1181 (void) fprintf(fp, "\t%s %s=string\n",
1181 1182 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1182 1183 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1183 1184 pt_to_str(PT_VALUE), gettext("<string>"));
1184 1185 (void) fprintf(fp, gettext("or\n"));
1185 1186 (void) fprintf(fp, "\t%s %s=uint\n",
1186 1187 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1187 1188 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1188 1189 pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
1189 1190 break;
1190 1191 case RT_DATASET:
1191 1192 (void) fprintf(fp, gettext("The '%s' resource scope is "
1192 1193 "used to export ZFS datasets.\n"),
1193 1194 rt_to_str(resource_scope));
1194 1195 (void) fprintf(fp, gettext("Valid commands:\n"));
1195 1196 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1196 1197 pt_to_str(PT_NAME), gettext("<name>"));
1197 1198 break;
1198 1199 case RT_DCPU:
1199 1200 (void) fprintf(fp, gettext("The '%s' resource scope "
1200 1201 "configures the 'pools' facility to dedicate\na "
1201 1202 "subset of the system's processors to this zone "
1202 1203 "while it is running.\n"),
1203 1204 rt_to_str(resource_scope));
1204 1205 (void) fprintf(fp, gettext("Valid commands:\n"));
1205 1206 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1206 1207 pt_to_str(PT_NCPUS),
1207 1208 gettext("<unsigned integer | range>"));
1208 1209 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1209 1210 pt_to_str(PT_IMPORTANCE),
1210 1211 gettext("<unsigned integer>"));
1211 1212 break;
1212 1213 case RT_PCAP:
1213 1214 (void) fprintf(fp, gettext("The '%s' resource scope is "
1214 1215 "used to set an upper limit (a cap) on the\n"
1215 1216 "percentage of CPU that can be used by this zone. "
1216 1217 "A '%s' value of 1\ncorresponds to one cpu. The "
1217 1218 "value can be set higher than 1, up to the total\n"
1218 1219 "number of CPUs on the system. The value can "
1219 1220 "also be less than 1,\nrepresenting a fraction of "
1220 1221 "a cpu.\n"),
1221 1222 rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
1222 1223 (void) fprintf(fp, gettext("Valid commands:\n"));
1223 1224 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1224 1225 pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
1225 1226 break;
1226 1227 case RT_MCAP:
1227 1228 (void) fprintf(fp, gettext("The '%s' resource scope is "
1228 1229 "used to set an upper limit (a cap) on the\n"
1229 1230 "amount of physical memory, swap space and locked "
1230 1231 "memory that can be used by\nthis zone.\n"),
1231 1232 rt_to_str(resource_scope));
1232 1233 (void) fprintf(fp, gettext("Valid commands:\n"));
1233 1234 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1234 1235 pt_to_str(PT_PHYSICAL),
1235 1236 gettext("<qualified unsigned decimal>"));
1236 1237 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1237 1238 pt_to_str(PT_SWAP),
1238 1239 gettext("<qualified unsigned decimal>"));
1239 1240 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1240 1241 pt_to_str(PT_LOCKED),
1241 1242 gettext("<qualified unsigned decimal>"));
1242 1243 break;
1243 1244 case RT_ADMIN:
1244 1245 (void) fprintf(fp, gettext("The '%s' resource scope is "
1245 1246 "used to delegate specific zone management\n"
1246 1247 "rights to users and roles. These rights are "
1247 1248 "only applicable to this zone.\n"),
1248 1249 rt_to_str(resource_scope));
1249 1250 (void) fprintf(fp, gettext("Valid commands:\n"));
1250 1251 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1251 1252 pt_to_str(PT_USER),
1252 1253 gettext("<single user or role name>"));
1253 1254 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1254 1255 pt_to_str(PT_AUTHS),
1255 1256 gettext("<comma separated list>"));
1256 1257 break;
1257 1258 case RT_SECFLAGS:
1258 1259 (void) fprintf(fp, gettext("The '%s' resource scope is "
1259 1260 "used to specify the default security-flags\n"
1260 1261 "of this zone, and their upper and lower bound.\n"),
1261 1262 rt_to_str(resource_scope));
1262 1263 (void) fprintf(fp, "\t%s %s=%s\n",
1263 1264 cmd_to_str(CMD_SET), pt_to_str(PT_DEFAULT),
1264 1265 gettext("<security flags>"));
1265 1266 (void) fprintf(fp, "\t%s %s=%s\n",
1266 1267 cmd_to_str(CMD_SET), pt_to_str(PT_LOWER),
1267 1268 gettext("<security flags>"));
1268 1269 (void) fprintf(fp, "\t%s %s=%s\n",
1269 1270 cmd_to_str(CMD_SET), pt_to_str(PT_UPPER),
1270 1271 gettext("<security flags>"));
1271 1272 break;
1272 1273 }
1273 1274 (void) fprintf(fp, gettext("And from any resource scope, you "
1274 1275 "can:\n"));
1275 1276 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
1276 1277 gettext("(to conclude this operation)"));
1277 1278 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
1278 1279 gettext("(to cancel this operation)"));
1279 1280 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
1280 1281 gettext("(to exit the zonecfg utility)"));
1281 1282 }
1282 1283 if (flags & HELP_USAGE) {
1283 1284 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
1284 1285 execname, cmd_to_str(CMD_HELP));
1285 1286 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
1286 1287 execname, gettext("interactive"));
1287 1288 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
1288 1289 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
1289 1290 execname);
1290 1291 }
1291 1292 if (flags & HELP_SUBCMDS) {
1292 1293 (void) fprintf(fp, "%s:\n\n", gettext("Commands"));
1293 1294 for (i = 0; i <= CMD_MAX; i++) {
1294 1295 (void) fprintf(fp, "%s\n", helptab[i].short_usage);
1295 1296 if (verbose)
1296 1297 (void) fprintf(fp, "\t%s\n\n", long_help(i));
1297 1298 }
1298 1299 }
1299 1300 if (flags & HELP_SYNTAX) {
1300 1301 if (!verbose)
1301 1302 (void) fprintf(fp, "\n");
1302 1303 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
1303 1304 (void) fprintf(fp, gettext("\t(except the reserved words "
1304 1305 "'%s' and anything starting with '%s')\n"), "global",
1305 1306 "SUNW");
1306 1307 (void) fprintf(fp,
1307 1308 gettext("\tName must be less than %d characters.\n"),
1308 1309 ZONENAME_MAX);
1309 1310 if (verbose)
1310 1311 (void) fprintf(fp, "\n");
1311 1312 }
1312 1313 if (flags & HELP_NETADDR) {
1313 1314 (void) fprintf(fp, gettext("\n<net-addr> :="));
1314 1315 (void) fprintf(fp,
1315 1316 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
1316 1317 (void) fprintf(fp,
1317 1318 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
1318 1319 (void) fprintf(fp,
1319 1320 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
1320 1321 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
1321 1322 "IPv6 address syntax.\n"));
1322 1323 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
1323 1324 (void) fprintf(fp,
1324 1325 gettext("<IPv6-prefix-length> := [0-128]\n"));
1325 1326 (void) fprintf(fp,
1326 1327 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
1327 1328 }
1328 1329 if (flags & HELP_RESOURCES) {
1329 1330 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s |\n\t"
1330 1331 "%s | %s | %s | %s | %s\n\n",
1331 1332 gettext("resource type"), rt_to_str(RT_FS),
1332 1333 rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
1333 1334 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
1334 1335 rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
1335 1336 rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
1336 1337 rt_to_str(RT_ADMIN), rt_to_str(RT_SECFLAGS));
1337 1338 }
1338 1339 if (flags & HELP_PROPS) {
1339 1340 (void) fprintf(fp, gettext("For resource type ... there are "
1340 1341 "property types ...:\n"));
1341 1342 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1342 1343 pt_to_str(PT_ZONENAME));
1343 1344 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1344 1345 pt_to_str(PT_ZONEPATH));
1345 1346 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1346 1347 pt_to_str(PT_BRAND));
1347 1348 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1348 1349 pt_to_str(PT_AUTOBOOT));
1349 1350 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1350 1351 pt_to_str(PT_BOOTARGS));
1351 1352 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1352 1353 pt_to_str(PT_POOL));
1353 1354 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1354 1355 pt_to_str(PT_LIMITPRIV));
1355 1356 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1356 1357 pt_to_str(PT_SCHED));
1357 1358 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1358 1359 pt_to_str(PT_IPTYPE));
1359 1360 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1360 1361 pt_to_str(PT_HOSTID));
1361 1362 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1362 1363 pt_to_str(PT_FS_ALLOWED));
1363 1364 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1364 1365 pt_to_str(PT_MAXLWPS));
1365 1366 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1366 1367 pt_to_str(PT_MAXPROCS));
1367 1368 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1368 1369 pt_to_str(PT_MAXSHMMEM));
1369 1370 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1370 1371 pt_to_str(PT_MAXSHMIDS));
1371 1372 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1372 1373 pt_to_str(PT_MAXMSGIDS));
1373 1374 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1374 1375 pt_to_str(PT_MAXSEMIDS));
1375 1376 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1376 1377 pt_to_str(PT_SHARES));
1377 1378 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
1378 1379 rt_to_str(RT_FS), pt_to_str(PT_DIR),
1379 1380 pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
1380 1381 pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
1381 1382 (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
1382 1383 pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
1383 1384 pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
1384 1385 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1385 1386 pt_to_str(PT_MATCH));
1386 1387 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1387 1388 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1388 1389 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1389 1390 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1390 1391 pt_to_str(PT_VALUE));
1391 1392 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1392 1393 pt_to_str(PT_NAME));
1393 1394 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1394 1395 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1395 1396 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1396 1397 pt_to_str(PT_NCPUS));
1397 1398 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1398 1399 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1399 1400 pt_to_str(PT_LOCKED));
1400 1401 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1401 1402 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1402 1403 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n",
1403 1404 rt_to_str(RT_SECFLAGS), pt_to_str(PT_DEFAULT),
1404 1405 pt_to_str(PT_LOWER), pt_to_str(PT_UPPER));
1405 1406 }
1406 1407 if (need_to_close)
1407 1408 (void) pager_close(fp);
1408 1409 }
1409 1410
1410 1411 static void
1411 1412 zone_perror(char *prefix, int err, boolean_t set_saw)
1412 1413 {
1413 1414 zerr("%s: %s", prefix, zonecfg_strerror(err));
1414 1415 if (set_saw)
1415 1416 saw_error = B_TRUE;
1416 1417 }
1417 1418
1418 1419 /*
1419 1420 * zone_perror() expects a single string, but for remove and select
1420 1421 * we have both the command and the resource type, so this wrapper
1421 1422 * function serves the same purpose in a slightly different way.
1422 1423 */
1423 1424
1424 1425 static void
1425 1426 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1426 1427 {
1427 1428 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
1428 1429 zonecfg_strerror(err));
1429 1430 if (set_saw)
1430 1431 saw_error = B_TRUE;
1431 1432 }
1432 1433
1433 1434 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
1434 1435 static int
1435 1436 initialize(boolean_t handle_expected)
1436 1437 {
1437 1438 int err;
1438 1439 char brandname[MAXNAMELEN];
1439 1440
1440 1441 if (zonecfg_check_handle(handle) != Z_OK) {
1441 1442 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
1442 1443 got_handle = B_TRUE;
1443 1444 if (zonecfg_get_brand(handle, brandname,
1444 1445 sizeof (brandname)) != Z_OK) {
1445 1446 zerr("Zone %s is inconsistent: missing "
1446 1447 "brand attribute", zone);
1447 1448 exit(Z_ERR);
1448 1449 }
1449 1450 if ((brand = brand_open(brandname)) == NULL) {
1450 1451 zerr("Zone %s uses non-existent brand \"%s\"."
1451 1452 " Unable to continue", zone, brandname);
1452 1453 exit(Z_ERR);
1453 1454 }
1454 1455 /*
1455 1456 * If the user_attr file is newer than
1456 1457 * the zone config file, the admins
1457 1458 * may need to be updated since the
1458 1459 * RBAC files are authoritative for
1459 1460 * authorization checks.
1460 1461 */
1461 1462 err = zonecfg_update_userauths(handle, zone);
1462 1463 if (err == Z_OK) {
1463 1464 zerr(gettext("The administrative rights "
1464 1465 "were updated to match "
1465 1466 "the current RBAC configuration.\n"
1466 1467 "Use \"info admin\" and \"revert\" to "
1467 1468 "compare with the previous settings."));
1468 1469 need_to_commit = B_TRUE;
1469 1470 } else if (err != Z_NO_ENTRY) {
1470 1471 zerr(gettext("failed to update "
1471 1472 "admin rights."));
1472 1473 exit(Z_ERR);
1473 1474 } else if (need_to_commit) {
1474 1475 zerr(gettext("admin rights were updated "
1475 1476 "to match RBAC configuration."));
1476 1477 }
1477 1478
1478 1479 } else if (global_zone && err == Z_NO_ZONE && !got_handle &&
1479 1480 !read_only_mode) {
1480 1481 /*
1481 1482 * We implicitly create the global zone config if it
1482 1483 * doesn't exist.
1483 1484 */
1484 1485 zone_dochandle_t tmphandle;
1485 1486
1486 1487 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1487 1488 zone_perror(execname, Z_NOMEM, B_TRUE);
1488 1489 exit(Z_ERR);
1489 1490 }
1490 1491
1491 1492 err = zonecfg_get_template_handle("SUNWblank", zone,
1492 1493 tmphandle);
1493 1494
1494 1495 if (err != Z_OK) {
1495 1496 zonecfg_fini_handle(tmphandle);
1496 1497 zone_perror("SUNWblank", err, B_TRUE);
1497 1498 return (err);
1498 1499 }
1499 1500
1500 1501 need_to_commit = B_TRUE;
1501 1502 zonecfg_fini_handle(handle);
1502 1503 handle = tmphandle;
1503 1504 got_handle = B_TRUE;
1504 1505
1505 1506 } else {
1506 1507 zone_perror(zone, err, handle_expected || got_handle);
1507 1508 if (err == Z_NO_ZONE && !got_handle &&
1508 1509 interactive_mode && !read_only_mode)
1509 1510 (void) printf(gettext("Use '%s' to begin "
1510 1511 "configuring a new zone.\n"),
1511 1512 cmd_to_str(CMD_CREATE));
1512 1513 return (err);
1513 1514 }
1514 1515 }
1515 1516 return (Z_OK);
1516 1517 }
1517 1518
1518 1519 static boolean_t
1519 1520 state_atleast(zone_state_t state)
1520 1521 {
1521 1522 zone_state_t state_num;
1522 1523 int err;
1523 1524
1524 1525 if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
1525 1526 /* all states are greater than "non-existent" */
1526 1527 if (err == Z_NO_ZONE)
1527 1528 return (B_FALSE);
1528 1529 zerr(gettext("Unexpectedly failed to determine state "
1529 1530 "of zone %s: %s"), zone, zonecfg_strerror(err));
1530 1531 exit(Z_ERR);
1531 1532 }
1532 1533 return (state_num >= state);
1533 1534 }
1534 1535
1535 1536 /*
1536 1537 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
1537 1538 */
1538 1539
1539 1540 void
1540 1541 short_usage(int command)
1541 1542 {
1542 1543 /* lex_lineno has already been incremented in the lexer; compensate */
1543 1544 if (cmd_file_mode) {
1544 1545 if (strcmp(cmd_file_name, "-") == 0)
1545 1546 (void) fprintf(stderr,
1546 1547 gettext("syntax error on line %d\n"),
1547 1548 lex_lineno - 1);
1548 1549 else
1549 1550 (void) fprintf(stderr,
1550 1551 gettext("syntax error on line %d of %s\n"),
1551 1552 lex_lineno - 1, cmd_file_name);
1552 1553 }
1553 1554 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
1554 1555 helptab[command].short_usage);
1555 1556 saw_error = B_TRUE;
1556 1557 }
1557 1558
1558 1559 /*
1559 1560 * long_usage() is for bad semantics: e.g., wrong property type for a given
1560 1561 * resource type. It is also used by longer_usage() below.
1561 1562 */
1562 1563
1563 1564 void
1564 1565 long_usage(uint_t cmd_num, boolean_t set_saw)
1565 1566 {
1566 1567 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
1567 1568 helptab[cmd_num].short_usage);
1568 1569 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
1569 1570 if (set_saw)
1570 1571 saw_error = B_TRUE;
1571 1572 }
1572 1573
1573 1574 /*
1574 1575 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
1575 1576 * any extra usage() flags as appropriate for whatever command.
1576 1577 */
1577 1578
1578 1579 void
1579 1580 longer_usage(uint_t cmd_num)
1580 1581 {
1581 1582 long_usage(cmd_num, B_FALSE);
1582 1583 if (helptab[cmd_num].flags != 0) {
1583 1584 (void) printf("\n");
1584 1585 usage(B_TRUE, helptab[cmd_num].flags);
1585 1586 }
1586 1587 }
1587 1588
1588 1589 /*
1589 1590 * scope_usage() is simply used when a command is called from the wrong scope.
1590 1591 */
1591 1592
1592 1593 static void
1593 1594 scope_usage(uint_t cmd_num)
1594 1595 {
1595 1596 zerr(gettext("The %s command only makes sense in the %s scope."),
1596 1597 cmd_to_str(cmd_num),
1597 1598 global_scope ? gettext("resource") : gettext("global"));
1598 1599 saw_error = B_TRUE;
1599 1600 }
1600 1601
1601 1602 /*
1602 1603 * On input, B_TRUE => yes, B_FALSE => no.
1603 1604 * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
1604 1605 */
1605 1606
1606 1607 static int
1607 1608 ask_yesno(boolean_t default_answer, const char *question)
1608 1609 {
1609 1610 char line[64]; /* should be enough to answer yes or no */
1610 1611
1611 1612 if (!ok_to_prompt) {
1612 1613 saw_error = B_TRUE;
1613 1614 return (-1);
1614 1615 }
1615 1616 for (;;) {
1616 1617 if (printf("%s (%s)? ", question,
1617 1618 default_answer ? "[y]/n" : "y/[n]") < 0)
1618 1619 return (-1);
1619 1620 if (fgets(line, sizeof (line), stdin) == NULL)
1620 1621 return (-1);
1621 1622
1622 1623 if (line[0] == '\n')
1623 1624 return (default_answer ? 1 : 0);
1624 1625 if (tolower(line[0]) == 'y')
1625 1626 return (1);
1626 1627 if (tolower(line[0]) == 'n')
1627 1628 return (0);
1628 1629 }
1629 1630 }
1630 1631
1631 1632 /*
1632 1633 * Prints warning if zone already exists.
1633 1634 * In interactive mode, prompts if we should continue anyway and returns Z_OK
1634 1635 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR.
1635 1636 *
1636 1637 * Note that if a zone exists and its state is >= INSTALLED, an error message
1637 1638 * will be printed and this function will return Z_ERR regardless of mode.
1638 1639 */
1639 1640
1640 1641 static int
1641 1642 check_if_zone_already_exists(boolean_t force)
1642 1643 {
1643 1644 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
1644 1645 zone_dochandle_t tmphandle;
1645 1646 int res, answer;
1646 1647
1647 1648 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1648 1649 zone_perror(execname, Z_NOMEM, B_TRUE);
1649 1650 exit(Z_ERR);
1650 1651 }
1651 1652 res = zonecfg_get_handle(zone, tmphandle);
1652 1653 zonecfg_fini_handle(tmphandle);
1653 1654 if (res != Z_OK)
1654 1655 return (Z_OK);
1655 1656
1656 1657 if (state_atleast(ZONE_STATE_INSTALLED)) {
1657 1658 zerr(gettext("Zone %s already installed; %s not allowed."),
1658 1659 zone, cmd_to_str(CMD_CREATE));
1659 1660 return (Z_ERR);
1660 1661 }
1661 1662
1662 1663 if (force) {
1663 1664 (void) printf(gettext("Zone %s already exists; overwriting.\n"),
1664 1665 zone);
1665 1666 return (Z_OK);
1666 1667 }
1667 1668 (void) snprintf(line, sizeof (line),
1668 1669 gettext("Zone %s already exists; %s anyway"), zone,
1669 1670 cmd_to_str(CMD_CREATE));
1670 1671 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
1671 1672 zerr(gettext("Zone exists, input not from terminal and -F not "
1672 1673 "specified:\n%s command ignored, exiting."),
1673 1674 cmd_to_str(CMD_CREATE));
1674 1675 exit(Z_ERR);
1675 1676 }
1676 1677 return (answer == 1 ? Z_OK : Z_ERR);
1677 1678 }
1678 1679
1679 1680 static boolean_t
1680 1681 zone_is_read_only(int cmd_num)
1681 1682 {
1682 1683 if (strncmp(zone, "SUNW", 4) == 0) {
1683 1684 zerr(gettext("%s: zones beginning with SUNW are read-only."),
1684 1685 zone);
1685 1686 saw_error = B_TRUE;
1686 1687 return (B_TRUE);
1687 1688 }
1688 1689 if (read_only_mode) {
1689 1690 zerr(gettext("%s: cannot %s in read-only mode."), zone,
1690 1691 cmd_to_str(cmd_num));
1691 1692 saw_error = B_TRUE;
1692 1693 return (B_TRUE);
1693 1694 }
1694 1695 return (B_FALSE);
1695 1696 }
1696 1697
1697 1698 /*
1698 1699 * Create a new configuration.
1699 1700 */
1700 1701 void
1701 1702 create_func(cmd_t *cmd)
1702 1703 {
1703 1704 int err, arg;
1704 1705 char zone_template[ZONENAME_MAX];
1705 1706 char attach_path[MAXPATHLEN];
1706 1707 zone_dochandle_t tmphandle;
1707 1708 boolean_t force = B_FALSE;
1708 1709 boolean_t attach = B_FALSE;
1709 1710 boolean_t arg_err = B_FALSE;
1710 1711
1711 1712 assert(cmd != NULL);
1712 1713
1713 1714 /* This is the default if no arguments are given. */
1714 1715 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
1715 1716
1716 1717 optind = 0;
1717 1718 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
1718 1719 != EOF) {
1719 1720 switch (arg) {
1720 1721 case '?':
1721 1722 if (optopt == '?')
1722 1723 longer_usage(CMD_CREATE);
1723 1724 else
1724 1725 short_usage(CMD_CREATE);
1725 1726 arg_err = B_TRUE;
1726 1727 break;
1727 1728 case 'a':
1728 1729 (void) strlcpy(attach_path, optarg,
1729 1730 sizeof (attach_path));
1730 1731 attach = B_TRUE;
1731 1732 break;
1732 1733 case 'b':
1733 1734 (void) strlcpy(zone_template, "SUNWblank",
1734 1735 sizeof (zone_template));
1735 1736 break;
1736 1737 case 'F':
1737 1738 force = B_TRUE;
1738 1739 break;
1739 1740 case 't':
1740 1741 (void) strlcpy(zone_template, optarg,
1741 1742 sizeof (zone_template));
1742 1743 break;
1743 1744 default:
1744 1745 short_usage(CMD_CREATE);
1745 1746 arg_err = B_TRUE;
1746 1747 break;
1747 1748 }
1748 1749 }
1749 1750 if (arg_err)
1750 1751 return;
1751 1752
1752 1753 if (optind != cmd->cmd_argc) {
1753 1754 short_usage(CMD_CREATE);
1754 1755 return;
1755 1756 }
1756 1757
1757 1758 if (zone_is_read_only(CMD_CREATE))
1758 1759 return;
1759 1760
1760 1761 if (check_if_zone_already_exists(force) != Z_OK)
1761 1762 return;
1762 1763
1763 1764 /*
1764 1765 * Get a temporary handle first. If that fails, the old handle
1765 1766 * will not be lost. Then finish whichever one we don't need,
1766 1767 * to avoid leaks. Then get the handle for zone_template, and
1767 1768 * set the name to zone: this "copy, rename" method is how
1768 1769 * create -[b|t] works.
1769 1770 */
1770 1771 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1771 1772 zone_perror(execname, Z_NOMEM, B_TRUE);
1772 1773 exit(Z_ERR);
1773 1774 }
1774 1775
1775 1776 if (attach)
1776 1777 err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
1777 1778 zone, B_FALSE, tmphandle);
1778 1779 else
1779 1780 err = zonecfg_get_template_handle(zone_template, zone,
1780 1781 tmphandle);
1781 1782
1782 1783 if (err != Z_OK) {
1783 1784 zonecfg_fini_handle(tmphandle);
1784 1785 if (attach && err == Z_NO_ZONE)
1785 1786 (void) fprintf(stderr, gettext("invalid path to "
1786 1787 "detached zone\n"));
1787 1788 else if (attach && err == Z_INVALID_DOCUMENT)
1788 1789 (void) fprintf(stderr, gettext("Cannot attach to an "
1789 1790 "earlier release of the operating system\n"));
1790 1791 else
1791 1792 zone_perror(zone_template, err, B_TRUE);
1792 1793 return;
1793 1794 }
1794 1795
1795 1796 need_to_commit = B_TRUE;
1796 1797 zonecfg_fini_handle(handle);
1797 1798 handle = tmphandle;
1798 1799 got_handle = B_TRUE;
1799 1800 }
1800 1801
1801 1802 /*
1802 1803 * This malloc()'s memory, which must be freed by the caller.
1803 1804 */
1804 1805 static char *
1805 1806 quoteit(char *instr)
1806 1807 {
1807 1808 char *outstr;
1808 1809 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */
1809 1810
1810 1811 if ((outstr = malloc(outstrsize)) == NULL) {
1811 1812 zone_perror(zone, Z_NOMEM, B_FALSE);
1812 1813 exit(Z_ERR);
1813 1814 }
1814 1815 if (strchr(instr, ' ') == NULL) {
1815 1816 (void) strlcpy(outstr, instr, outstrsize);
1816 1817 return (outstr);
1817 1818 }
1818 1819 (void) snprintf(outstr, outstrsize, "\"%s\"", instr);
1819 1820 return (outstr);
↓ open down ↓ |
1784 lines elided |
↑ open up ↑ |
1820 1821 }
1821 1822
1822 1823 static void
1823 1824 export_prop(FILE *of, int prop_num, char *prop_id)
1824 1825 {
1825 1826 char *quote_str;
1826 1827
1827 1828 if (strlen(prop_id) == 0)
1828 1829 return;
1829 1830 quote_str = quoteit(prop_id);
1830 - (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1831 + (void) fprintf(of, "%s %s=\"%s\"\n", cmd_to_str(CMD_SET),
1831 1832 pt_to_str(prop_num), quote_str);
1832 1833 free(quote_str);
1833 1834 }
1834 1835
1835 1836 void
1836 1837 export_func(cmd_t *cmd)
1837 1838 {
1838 1839 struct zone_nwiftab nwiftab;
1839 1840 struct zone_fstab fstab;
1840 1841 struct zone_devtab devtab;
1841 1842 struct zone_attrtab attrtab;
1842 1843 struct zone_rctltab rctltab;
1843 1844 struct zone_dstab dstab;
1844 1845 struct zone_psettab psettab;
1845 1846 struct zone_mcaptab mcaptab;
1846 1847 struct zone_rctlvaltab *valptr;
1847 1848 struct zone_admintab admintab;
1848 1849 struct zone_secflagstab secflagstab;
1849 1850 int err, arg;
1850 1851 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
1851 1852 char bootargs[BOOTARGS_MAX];
1852 1853 char sched[MAXNAMELEN];
1853 1854 char brand[MAXNAMELEN];
1854 1855 char hostidp[HW_HOSTID_LEN];
1855 1856 char fsallowedp[ZONE_FS_ALLOWED_MAX];
1856 1857 char *limitpriv;
1857 1858 FILE *of;
1858 1859 boolean_t autoboot;
1859 1860 zone_iptype_t iptype;
1860 1861 boolean_t need_to_close = B_FALSE;
1861 1862 boolean_t arg_err = B_FALSE;
1862 1863
1863 1864 assert(cmd != NULL);
1864 1865
1865 1866 outfile[0] = '\0';
1866 1867 optind = 0;
1867 1868 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
1868 1869 switch (arg) {
1869 1870 case '?':
1870 1871 if (optopt == '?')
1871 1872 longer_usage(CMD_EXPORT);
1872 1873 else
1873 1874 short_usage(CMD_EXPORT);
1874 1875 arg_err = B_TRUE;
1875 1876 break;
1876 1877 case 'f':
1877 1878 (void) strlcpy(outfile, optarg, sizeof (outfile));
1878 1879 break;
1879 1880 default:
1880 1881 short_usage(CMD_EXPORT);
1881 1882 arg_err = B_TRUE;
1882 1883 break;
1883 1884 }
1884 1885 }
1885 1886 if (arg_err)
1886 1887 return;
1887 1888
1888 1889 if (optind != cmd->cmd_argc) {
1889 1890 short_usage(CMD_EXPORT);
1890 1891 return;
1891 1892 }
1892 1893 if (strlen(outfile) == 0) {
1893 1894 of = stdout;
1894 1895 } else {
1895 1896 if ((of = fopen(outfile, "w")) == NULL) {
1896 1897 zerr(gettext("opening file %s: %s"),
1897 1898 outfile, strerror(errno));
1898 1899 goto done;
1899 1900 }
1900 1901 setbuf(of, NULL);
1901 1902 need_to_close = B_TRUE;
1902 1903 }
1903 1904
1904 1905 if ((err = initialize(B_TRUE)) != Z_OK)
1905 1906 goto done;
1906 1907
1907 1908 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
1908 1909
1909 1910 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
1910 1911 strlen(zonepath) > 0)
1911 1912 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1912 1913 pt_to_str(PT_ZONEPATH), zonepath);
1913 1914
1914 1915 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
1915 1916 (strcmp(brand, NATIVE_BRAND_NAME) != 0))
1916 1917 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1917 1918 pt_to_str(PT_BRAND), brand);
1918 1919
1919 1920 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
1920 1921 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1921 1922 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
1922 1923
1923 1924 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
1924 1925 strlen(bootargs) > 0) {
1925 1926 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1926 1927 pt_to_str(PT_BOOTARGS), bootargs);
1927 1928 }
1928 1929
1929 1930 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
1930 1931 strlen(pool) > 0)
1931 1932 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1932 1933 pt_to_str(PT_POOL), pool);
1933 1934
1934 1935 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
1935 1936 strlen(limitpriv) > 0) {
1936 1937 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1937 1938 pt_to_str(PT_LIMITPRIV), limitpriv);
1938 1939 free(limitpriv);
1939 1940 }
1940 1941
1941 1942 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
1942 1943 strlen(sched) > 0)
1943 1944 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1944 1945 pt_to_str(PT_SCHED), sched);
1945 1946
1946 1947 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
1947 1948 switch (iptype) {
1948 1949 case ZS_SHARED:
1949 1950 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1950 1951 pt_to_str(PT_IPTYPE), "shared");
1951 1952 break;
1952 1953 case ZS_EXCLUSIVE:
1953 1954 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1954 1955 pt_to_str(PT_IPTYPE), "exclusive");
1955 1956 break;
1956 1957 }
1957 1958 }
1958 1959
1959 1960 if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
1960 1961 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1961 1962 pt_to_str(PT_HOSTID), hostidp);
1962 1963 }
1963 1964
1964 1965 if (zonecfg_get_fs_allowed(handle, fsallowedp,
1965 1966 sizeof (fsallowedp)) == Z_OK) {
1966 1967 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1967 1968 pt_to_str(PT_FS_ALLOWED), fsallowedp);
1968 1969 }
1969 1970
1970 1971 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
1971 1972 zone_perror(zone, err, B_FALSE);
1972 1973 goto done;
1973 1974 }
1974 1975 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1975 1976 zone_fsopt_t *optptr;
1976 1977
1977 1978 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1978 1979 rt_to_str(RT_FS));
1979 1980 export_prop(of, PT_DIR, fstab.zone_fs_dir);
1980 1981 export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
1981 1982 export_prop(of, PT_RAW, fstab.zone_fs_raw);
1982 1983 export_prop(of, PT_TYPE, fstab.zone_fs_type);
1983 1984 for (optptr = fstab.zone_fs_options; optptr != NULL;
1984 1985 optptr = optptr->zone_fsopt_next) {
1985 1986 /*
1986 1987 * Simple property values with embedded equal signs
1987 1988 * need to be quoted to prevent the lexer from
1988 1989 * mis-parsing them as complex name=value pairs.
1989 1990 */
1990 1991 if (strchr(optptr->zone_fsopt_opt, '='))
1991 1992 (void) fprintf(of, "%s %s \"%s\"\n",
1992 1993 cmd_to_str(CMD_ADD),
1993 1994 pt_to_str(PT_OPTIONS),
1994 1995 optptr->zone_fsopt_opt);
1995 1996 else
1996 1997 (void) fprintf(of, "%s %s %s\n",
1997 1998 cmd_to_str(CMD_ADD),
1998 1999 pt_to_str(PT_OPTIONS),
1999 2000 optptr->zone_fsopt_opt);
2000 2001 }
2001 2002 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2002 2003 zonecfg_free_fs_option_list(fstab.zone_fs_options);
2003 2004 }
2004 2005 (void) zonecfg_endfsent(handle);
2005 2006
2006 2007 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2007 2008 zone_perror(zone, err, B_FALSE);
2008 2009 goto done;
2009 2010 }
2010 2011 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2011 2012 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2012 2013 rt_to_str(RT_NET));
2013 2014 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
2014 2015 export_prop(of, PT_ALLOWED_ADDRESS,
2015 2016 nwiftab.zone_nwif_allowed_address);
2016 2017 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
2017 2018 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
2018 2019 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2019 2020 }
2020 2021 (void) zonecfg_endnwifent(handle);
2021 2022
2022 2023 if ((err = zonecfg_setdevent(handle)) != Z_OK) {
2023 2024 zone_perror(zone, err, B_FALSE);
2024 2025 goto done;
2025 2026 }
2026 2027 while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
2027 2028 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2028 2029 rt_to_str(RT_DEVICE));
2029 2030 export_prop(of, PT_MATCH, devtab.zone_dev_match);
2030 2031 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2031 2032 }
2032 2033 (void) zonecfg_enddevent(handle);
2033 2034
2034 2035 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
2035 2036 char buf[128];
2036 2037
2037 2038 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2038 2039 rt_to_str(RT_MCAP));
2039 2040 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
2040 2041 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2041 2042 pt_to_str(PT_PHYSICAL), buf);
2042 2043 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2043 2044 }
2044 2045
2045 2046 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
2046 2047 zone_perror(zone, err, B_FALSE);
2047 2048 goto done;
2048 2049 }
2049 2050 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
2050 2051 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
2051 2052 export_prop(of, PT_NAME, rctltab.zone_rctl_name);
2052 2053 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
2053 2054 valptr = valptr->zone_rctlval_next) {
2054 2055 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
2055 2056 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
2056 2057 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
2057 2058 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
2058 2059 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
2059 2060 }
2060 2061 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2061 2062 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2062 2063 }
2063 2064 (void) zonecfg_endrctlent(handle);
2064 2065
2065 2066 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
2066 2067 zone_perror(zone, err, B_FALSE);
2067 2068 goto done;
2068 2069 }
2069 2070 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
2070 2071 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2071 2072 rt_to_str(RT_ATTR));
2072 2073 export_prop(of, PT_NAME, attrtab.zone_attr_name);
2073 2074 export_prop(of, PT_TYPE, attrtab.zone_attr_type);
2074 2075 export_prop(of, PT_VALUE, attrtab.zone_attr_value);
2075 2076 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2076 2077 }
2077 2078 (void) zonecfg_endattrent(handle);
2078 2079
2079 2080 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
2080 2081 zone_perror(zone, err, B_FALSE);
2081 2082 goto done;
2082 2083 }
2083 2084 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
2084 2085 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2085 2086 rt_to_str(RT_DATASET));
2086 2087 export_prop(of, PT_NAME, dstab.zone_dataset_name);
2087 2088 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2088 2089 }
2089 2090 (void) zonecfg_enddsent(handle);
2090 2091
2091 2092 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
2092 2093 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2093 2094 rt_to_str(RT_DCPU));
2094 2095 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
2095 2096 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2096 2097 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
2097 2098 else
2098 2099 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
2099 2100 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
2100 2101 psettab.zone_ncpu_max);
2101 2102 if (psettab.zone_importance[0] != '\0')
2102 2103 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2103 2104 pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
2104 2105 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2105 2106 }
2106 2107
2107 2108 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
2108 2109 zone_perror(zone, err, B_FALSE);
2109 2110 goto done;
2110 2111 }
2111 2112 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
2112 2113 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2113 2114 rt_to_str(RT_ADMIN));
2114 2115 export_prop(of, PT_USER, admintab.zone_admin_user);
2115 2116 export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
2116 2117 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2117 2118 }
2118 2119
2119 2120 (void) zonecfg_endadminent(handle);
2120 2121
2121 2122 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
2122 2123 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2123 2124 rt_to_str(RT_SECFLAGS));
2124 2125 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
2125 2126 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
2126 2127 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
2127 2128 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2128 2129 }
2129 2130
2130 2131 /*
2131 2132 * There is nothing to export for pcap since this resource is just
2132 2133 * a container for an rctl alias.
2133 2134 */
2134 2135
2135 2136 done:
2136 2137 if (need_to_close)
2137 2138 (void) fclose(of);
2138 2139 }
2139 2140
2140 2141 void
2141 2142 exit_func(cmd_t *cmd)
2142 2143 {
2143 2144 int arg, answer;
2144 2145 boolean_t arg_err = B_FALSE;
2145 2146
2146 2147 optind = 0;
2147 2148 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2148 2149 switch (arg) {
2149 2150 case '?':
2150 2151 longer_usage(CMD_EXIT);
2151 2152 arg_err = B_TRUE;
2152 2153 break;
2153 2154 case 'F':
2154 2155 force_exit = B_TRUE;
2155 2156 break;
2156 2157 default:
2157 2158 short_usage(CMD_EXIT);
2158 2159 arg_err = B_TRUE;
2159 2160 break;
2160 2161 }
2161 2162 }
2162 2163 if (arg_err)
2163 2164 return;
2164 2165
2165 2166 if (optind < cmd->cmd_argc) {
2166 2167 short_usage(CMD_EXIT);
2167 2168 return;
2168 2169 }
2169 2170
2170 2171 if (global_scope || force_exit) {
2171 2172 time_to_exit = B_TRUE;
2172 2173 return;
2173 2174 }
2174 2175
2175 2176 answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2176 2177 if (answer == -1) {
2177 2178 zerr(gettext("Resource incomplete, input "
2178 2179 "not from terminal and -F not specified:\n%s command "
2179 2180 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2180 2181 exit(Z_ERR);
2181 2182 } else if (answer == 1) {
2182 2183 time_to_exit = B_TRUE;
2183 2184 }
2184 2185 /* (answer == 0) => just return */
2185 2186 }
2186 2187
2187 2188 static int
2188 2189 validate_zonepath_syntax(char *path)
2189 2190 {
2190 2191 if (path[0] != '/') {
2191 2192 zerr(gettext("%s is not an absolute path."), path);
2192 2193 return (Z_ERR);
2193 2194 }
2194 2195 /* If path is all slashes, then fail */
2195 2196 if (strspn(path, "/") == strlen(path)) {
2196 2197 zerr(gettext("/ is not allowed as a %s."),
2197 2198 pt_to_str(PT_ZONEPATH));
2198 2199 return (Z_ERR);
2199 2200 }
2200 2201 return (Z_OK);
2201 2202 }
2202 2203
2203 2204 static void
2204 2205 add_resource(cmd_t *cmd)
2205 2206 {
2206 2207 int type;
2207 2208 struct zone_psettab tmp_psettab;
2208 2209 struct zone_mcaptab tmp_mcaptab;
2209 2210 struct zone_secflagstab tmp_secflagstab;
2210 2211 uint64_t tmp;
2211 2212 uint64_t tmp_mcap;
2212 2213 char pool[MAXNAMELEN];
2213 2214
2214 2215 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2215 2216 long_usage(CMD_ADD, B_TRUE);
2216 2217 goto bad;
2217 2218 }
2218 2219
2219 2220 switch (type) {
2220 2221 case RT_FS:
2221 2222 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2222 2223 return;
2223 2224 case RT_NET:
2224 2225 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2225 2226 return;
2226 2227 case RT_DEVICE:
2227 2228 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2228 2229 return;
2229 2230 case RT_RCTL:
2230 2231 if (global_zone)
2231 2232 zerr(gettext("WARNING: Setting a global zone resource "
2232 2233 "control too low could deny\nservice "
2233 2234 "to even the root user; "
2234 2235 "this could render the system impossible\n"
2235 2236 "to administer. Please use caution."));
2236 2237 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2237 2238 return;
2238 2239 case RT_ATTR:
2239 2240 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2240 2241 return;
2241 2242 case RT_DATASET:
2242 2243 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2243 2244 return;
2244 2245 case RT_DCPU:
2245 2246 /* Make sure there isn't already a cpu-set or cpu-cap entry. */
2246 2247 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2247 2248 zerr(gettext("The %s resource already exists."),
2248 2249 rt_to_str(RT_DCPU));
2249 2250 goto bad;
2250 2251 }
2251 2252 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2252 2253 Z_NO_ENTRY) {
2253 2254 zerr(gettext("The %s resource already exists."),
2254 2255 rt_to_str(RT_PCAP));
2255 2256 goto bad;
2256 2257 }
2257 2258
2258 2259 /* Make sure the pool property isn't set. */
2259 2260 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2260 2261 strlen(pool) > 0) {
2261 2262 zerr(gettext("The %s property is already set. "
2262 2263 "A persistent pool is incompatible with\nthe %s "
2263 2264 "resource."),
2264 2265 pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2265 2266 goto bad;
2266 2267 }
2267 2268
2268 2269 bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2269 2270 return;
2270 2271 case RT_PCAP:
2271 2272 /*
2272 2273 * Make sure there isn't already a cpu-set or incompatible
2273 2274 * cpu-cap rctls.
2274 2275 */
2275 2276 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2276 2277 zerr(gettext("The %s resource already exists."),
2277 2278 rt_to_str(RT_DCPU));
2278 2279 goto bad;
2279 2280 }
2280 2281
2281 2282 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2282 2283 case Z_ALIAS_DISALLOW:
2283 2284 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2284 2285 B_FALSE);
2285 2286 goto bad;
2286 2287
2287 2288 case Z_OK:
2288 2289 zerr(gettext("The %s resource already exists."),
2289 2290 rt_to_str(RT_PCAP));
2290 2291 goto bad;
2291 2292
2292 2293 default:
2293 2294 break;
2294 2295 }
2295 2296 return;
2296 2297 case RT_MCAP:
2297 2298 /*
2298 2299 * Make sure there isn't already a mem-cap entry or max-swap
2299 2300 * or max-locked rctl.
2300 2301 */
2301 2302 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2302 2303 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2303 2304 == Z_OK ||
2304 2305 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2305 2306 &tmp_mcap) == Z_OK) {
2306 2307 zerr(gettext("The %s resource or a related resource "
2307 2308 "control already exists."), rt_to_str(RT_MCAP));
2308 2309 goto bad;
2309 2310 }
2310 2311 if (global_zone)
2311 2312 zerr(gettext("WARNING: Setting a global zone memory "
2312 2313 "cap too low could deny\nservice "
2313 2314 "to even the root user; "
2314 2315 "this could render the system impossible\n"
2315 2316 "to administer. Please use caution."));
2316 2317 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2317 2318 return;
2318 2319 case RT_ADMIN:
2319 2320 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2320 2321 return;
2321 2322 case RT_SECFLAGS:
2322 2323 /* Make sure we haven't already set this */
2323 2324 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
2324 2325 zerr(gettext("The %s resource already exists."),
2325 2326 rt_to_str(RT_SECFLAGS));
2326 2327 bzero(&in_progress_secflagstab,
2327 2328 sizeof (in_progress_secflagstab));
2328 2329 return;
2329 2330 default:
2330 2331 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2331 2332 long_usage(CMD_ADD, B_TRUE);
2332 2333 usage(B_FALSE, HELP_RESOURCES);
2333 2334 }
2334 2335 bad:
2335 2336 global_scope = B_TRUE;
2336 2337 end_op = -1;
2337 2338 }
2338 2339
2339 2340 static void
2340 2341 do_complex_rctl_val(complex_property_ptr_t cp)
2341 2342 {
2342 2343 struct zone_rctlvaltab *rctlvaltab;
2343 2344 complex_property_ptr_t cx;
2344 2345 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2345 2346 seen_action = B_FALSE;
2346 2347 rctlblk_t *rctlblk;
2347 2348 int err;
2348 2349
2349 2350 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2350 2351 zone_perror(zone, Z_NOMEM, B_TRUE);
2351 2352 exit(Z_ERR);
2352 2353 }
2353 2354 for (cx = cp; cx != NULL; cx = cx->cp_next) {
2354 2355 switch (cx->cp_type) {
2355 2356 case PT_PRIV:
2356 2357 if (seen_priv) {
2357 2358 zerr(gettext("%s already specified"),
2358 2359 pt_to_str(PT_PRIV));
2359 2360 goto bad;
2360 2361 }
2361 2362 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
2362 2363 cx->cp_value,
2363 2364 sizeof (rctlvaltab->zone_rctlval_priv));
2364 2365 seen_priv = B_TRUE;
2365 2366 break;
2366 2367 case PT_LIMIT:
2367 2368 if (seen_limit) {
2368 2369 zerr(gettext("%s already specified"),
2369 2370 pt_to_str(PT_LIMIT));
2370 2371 goto bad;
2371 2372 }
2372 2373 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
2373 2374 cx->cp_value,
2374 2375 sizeof (rctlvaltab->zone_rctlval_limit));
2375 2376 seen_limit = B_TRUE;
2376 2377 break;
2377 2378 case PT_ACTION:
2378 2379 if (seen_action) {
2379 2380 zerr(gettext("%s already specified"),
2380 2381 pt_to_str(PT_ACTION));
2381 2382 goto bad;
2382 2383 }
2383 2384 (void) strlcpy(rctlvaltab->zone_rctlval_action,
2384 2385 cx->cp_value,
2385 2386 sizeof (rctlvaltab->zone_rctlval_action));
2386 2387 seen_action = B_TRUE;
2387 2388 break;
2388 2389 default:
2389 2390 zone_perror(pt_to_str(PT_VALUE),
2390 2391 Z_NO_PROPERTY_TYPE, B_TRUE);
2391 2392 long_usage(CMD_ADD, B_TRUE);
2392 2393 usage(B_FALSE, HELP_PROPS);
2393 2394 zonecfg_free_rctl_value_list(rctlvaltab);
2394 2395 return;
2395 2396 }
2396 2397 }
2397 2398 if (!seen_priv)
2398 2399 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2399 2400 if (!seen_limit)
2400 2401 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2401 2402 if (!seen_action)
2402 2403 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2403 2404 if (!seen_priv || !seen_limit || !seen_action)
2404 2405 goto bad;
2405 2406 rctlvaltab->zone_rctlval_next = NULL;
2406 2407 rctlblk = alloca(rctlblk_size());
2407 2408 /*
2408 2409 * Make sure the rctl value looks roughly correct; we won't know if
2409 2410 * it's truly OK until we verify the configuration on the target
2410 2411 * system.
2411 2412 */
2412 2413 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2413 2414 !zonecfg_valid_rctlblk(rctlblk)) {
2414 2415 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2415 2416 pt_to_str(PT_VALUE));
2416 2417 goto bad;
2417 2418 }
2418 2419 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2419 2420 if (err != Z_OK)
2420 2421 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2421 2422 return;
2422 2423
2423 2424 bad:
2424 2425 zonecfg_free_rctl_value_list(rctlvaltab);
2425 2426 }
2426 2427
2427 2428 static void
2428 2429 add_property(cmd_t *cmd)
2429 2430 {
2430 2431 char *prop_id;
2431 2432 int err, res_type, prop_type;
2432 2433 property_value_ptr_t pp;
2433 2434 list_property_ptr_t l;
2434 2435
2435 2436 res_type = resource_scope;
2436 2437 prop_type = cmd->cmd_prop_name[0];
2437 2438 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2438 2439 long_usage(CMD_ADD, B_TRUE);
2439 2440 return;
2440 2441 }
2441 2442
2442 2443 if (cmd->cmd_prop_nv_pairs != 1) {
2443 2444 long_usage(CMD_ADD, B_TRUE);
2444 2445 return;
2445 2446 }
2446 2447
2447 2448 if (initialize(B_TRUE) != Z_OK)
2448 2449 return;
2449 2450
2450 2451 switch (res_type) {
2451 2452 case RT_FS:
2452 2453 if (prop_type != PT_OPTIONS) {
2453 2454 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2454 2455 B_TRUE);
2455 2456 long_usage(CMD_ADD, B_TRUE);
2456 2457 usage(B_FALSE, HELP_PROPS);
2457 2458 return;
2458 2459 }
2459 2460 pp = cmd->cmd_property_ptr[0];
2460 2461 if (pp->pv_type != PROP_VAL_SIMPLE &&
2461 2462 pp->pv_type != PROP_VAL_LIST) {
2462 2463 zerr(gettext("A %s or %s value was expected here."),
2463 2464 pvt_to_str(PROP_VAL_SIMPLE),
2464 2465 pvt_to_str(PROP_VAL_LIST));
2465 2466 saw_error = B_TRUE;
2466 2467 return;
2467 2468 }
2468 2469 if (pp->pv_type == PROP_VAL_SIMPLE) {
2469 2470 if (pp->pv_simple == NULL) {
2470 2471 long_usage(CMD_ADD, B_TRUE);
2471 2472 return;
2472 2473 }
2473 2474 prop_id = pp->pv_simple;
2474 2475 err = zonecfg_add_fs_option(&in_progress_fstab,
2475 2476 prop_id);
2476 2477 if (err != Z_OK)
2477 2478 zone_perror(pt_to_str(prop_type), err, B_TRUE);
2478 2479 } else {
2479 2480 list_property_ptr_t list;
2480 2481
2481 2482 for (list = pp->pv_list; list != NULL;
2482 2483 list = list->lp_next) {
2483 2484 prop_id = list->lp_simple;
2484 2485 if (prop_id == NULL)
2485 2486 break;
2486 2487 err = zonecfg_add_fs_option(
2487 2488 &in_progress_fstab, prop_id);
2488 2489 if (err != Z_OK)
2489 2490 zone_perror(pt_to_str(prop_type), err,
2490 2491 B_TRUE);
2491 2492 }
2492 2493 }
2493 2494 return;
2494 2495 case RT_RCTL:
2495 2496 if (prop_type != PT_VALUE) {
2496 2497 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2497 2498 B_TRUE);
2498 2499 long_usage(CMD_ADD, B_TRUE);
2499 2500 usage(B_FALSE, HELP_PROPS);
2500 2501 return;
2501 2502 }
2502 2503 pp = cmd->cmd_property_ptr[0];
2503 2504 if (pp->pv_type != PROP_VAL_COMPLEX &&
2504 2505 pp->pv_type != PROP_VAL_LIST) {
2505 2506 zerr(gettext("A %s or %s value was expected here."),
2506 2507 pvt_to_str(PROP_VAL_COMPLEX),
2507 2508 pvt_to_str(PROP_VAL_LIST));
2508 2509 saw_error = B_TRUE;
2509 2510 return;
2510 2511 }
2511 2512 if (pp->pv_type == PROP_VAL_COMPLEX) {
2512 2513 do_complex_rctl_val(pp->pv_complex);
2513 2514 return;
2514 2515 }
2515 2516 for (l = pp->pv_list; l != NULL; l = l->lp_next)
2516 2517 do_complex_rctl_val(l->lp_complex);
2517 2518 return;
2518 2519 default:
2519 2520 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2520 2521 long_usage(CMD_ADD, B_TRUE);
2521 2522 usage(B_FALSE, HELP_RESOURCES);
2522 2523 return;
2523 2524 }
2524 2525 }
2525 2526
2526 2527 static boolean_t
2527 2528 gz_invalid_resource(int type)
2528 2529 {
2529 2530 return (global_zone && (type == RT_FS ||
2530 2531 type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2531 2532 type == RT_DATASET));
2532 2533 }
2533 2534
2534 2535 static boolean_t
2535 2536 gz_invalid_rt_property(int type)
2536 2537 {
2537 2538 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2538 2539 type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2539 2540 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2540 2541 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2541 2542 }
2542 2543
2543 2544 static boolean_t
2544 2545 gz_invalid_property(int type)
2545 2546 {
2546 2547 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2547 2548 type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2548 2549 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2549 2550 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2550 2551 }
2551 2552
2552 2553 void
2553 2554 add_func(cmd_t *cmd)
2554 2555 {
2555 2556 int arg;
2556 2557 boolean_t arg_err = B_FALSE;
2557 2558
2558 2559 assert(cmd != NULL);
2559 2560
2560 2561 optind = 0;
2561 2562 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2562 2563 switch (arg) {
2563 2564 case '?':
2564 2565 longer_usage(CMD_ADD);
2565 2566 arg_err = B_TRUE;
2566 2567 break;
2567 2568 default:
2568 2569 short_usage(CMD_ADD);
2569 2570 arg_err = B_TRUE;
2570 2571 break;
2571 2572 }
2572 2573 }
2573 2574 if (arg_err)
2574 2575 return;
2575 2576
2576 2577 if (optind != cmd->cmd_argc) {
2577 2578 short_usage(CMD_ADD);
2578 2579 return;
2579 2580 }
2580 2581
2581 2582 if (zone_is_read_only(CMD_ADD))
2582 2583 return;
2583 2584
2584 2585 if (initialize(B_TRUE) != Z_OK)
2585 2586 return;
2586 2587 if (global_scope) {
2587 2588 if (gz_invalid_resource(cmd->cmd_res_type)) {
2588 2589 zerr(gettext("Cannot add a %s resource to the "
2589 2590 "global zone."), rt_to_str(cmd->cmd_res_type));
2590 2591 saw_error = B_TRUE;
2591 2592 return;
2592 2593 }
2593 2594
2594 2595 global_scope = B_FALSE;
2595 2596 resource_scope = cmd->cmd_res_type;
2596 2597 end_op = CMD_ADD;
2597 2598 add_resource(cmd);
2598 2599 } else
2599 2600 add_property(cmd);
2600 2601 }
2601 2602
2602 2603 /*
2603 2604 * This routine has an unusual implementation, because it tries very
2604 2605 * hard to succeed in the face of a variety of failure modes.
2605 2606 * The most common and most vexing occurs when the index file and
2606 2607 * the /etc/zones/<zonename.xml> file are not both present. In
2607 2608 * this case, delete must eradicate as much of the zone state as is left
2608 2609 * so that the user can later create a new zone with the same name.
2609 2610 */
2610 2611 void
2611 2612 delete_func(cmd_t *cmd)
2612 2613 {
2613 2614 int err, arg, answer;
2614 2615 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
2615 2616 boolean_t force = B_FALSE;
2616 2617 boolean_t arg_err = B_FALSE;
2617 2618
2618 2619 optind = 0;
2619 2620 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2620 2621 switch (arg) {
2621 2622 case '?':
2622 2623 longer_usage(CMD_DELETE);
2623 2624 arg_err = B_TRUE;
2624 2625 break;
2625 2626 case 'F':
2626 2627 force = B_TRUE;
2627 2628 break;
2628 2629 default:
2629 2630 short_usage(CMD_DELETE);
2630 2631 arg_err = B_TRUE;
2631 2632 break;
2632 2633 }
2633 2634 }
2634 2635 if (arg_err)
2635 2636 return;
2636 2637
2637 2638 if (optind != cmd->cmd_argc) {
2638 2639 short_usage(CMD_DELETE);
2639 2640 return;
2640 2641 }
2641 2642
2642 2643 if (zone_is_read_only(CMD_DELETE))
2643 2644 return;
2644 2645
2645 2646 if (!force) {
2646 2647 /*
2647 2648 * Initialize sets up the global called "handle" and warns the
2648 2649 * user if the zone is not configured. In force mode, we don't
2649 2650 * trust that evaluation, and hence skip it. (We don't need the
2650 2651 * handle to be loaded anyway, since zonecfg_destroy is done by
2651 2652 * zonename). However, we also have to take care to emulate the
2652 2653 * messages spit out by initialize; see below.
2653 2654 */
2654 2655 if (initialize(B_TRUE) != Z_OK)
2655 2656 return;
2656 2657
2657 2658 (void) snprintf(line, sizeof (line),
2658 2659 gettext("Are you sure you want to delete zone %s"), zone);
2659 2660 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2660 2661 zerr(gettext("Input not from terminal and -F not "
2661 2662 "specified:\n%s command ignored, exiting."),
2662 2663 cmd_to_str(CMD_DELETE));
2663 2664 exit(Z_ERR);
2664 2665 }
2665 2666 if (answer != 1)
2666 2667 return;
2667 2668 }
2668 2669
2669 2670 /*
2670 2671 * This function removes the authorizations from user_attr
2671 2672 * that correspond to those specified in the configuration
2672 2673 */
2673 2674 if (initialize(B_TRUE) == Z_OK) {
2674 2675 (void) zonecfg_deauthorize_users(handle, zone);
2675 2676 }
2676 2677 if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2677 2678 if ((err == Z_BAD_ZONE_STATE) && !force) {
2678 2679 zerr(gettext("Zone %s not in %s state; %s not "
2679 2680 "allowed. Use -F to force %s."),
2680 2681 zone, zone_state_str(ZONE_STATE_CONFIGURED),
2681 2682 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2682 2683 } else {
2683 2684 zone_perror(zone, err, B_TRUE);
2684 2685 }
2685 2686 }
2686 2687 need_to_commit = B_FALSE;
2687 2688
2688 2689 /*
2689 2690 * Emulate initialize's messaging; if there wasn't a valid handle to
2690 2691 * begin with, then user had typed delete (or delete -F) multiple
2691 2692 * times. So we emit a message.
2692 2693 *
2693 2694 * We only do this in the 'force' case because normally, initialize()
2694 2695 * takes care of this for us.
2695 2696 */
2696 2697 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2697 2698 (void) printf(gettext("Use '%s' to begin "
2698 2699 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2699 2700
2700 2701 /*
2701 2702 * Time for a new handle: finish the old one off first
2702 2703 * then get a new one properly to avoid leaks.
2703 2704 */
2704 2705 if (got_handle) {
2705 2706 zonecfg_fini_handle(handle);
2706 2707 if ((handle = zonecfg_init_handle()) == NULL) {
2707 2708 zone_perror(execname, Z_NOMEM, B_TRUE);
2708 2709 exit(Z_ERR);
2709 2710 }
2710 2711 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2711 2712 /* If there was no zone before, that's OK */
2712 2713 if (err != Z_NO_ZONE)
2713 2714 zone_perror(zone, err, B_TRUE);
2714 2715 got_handle = B_FALSE;
2715 2716 }
2716 2717 }
2717 2718 }
2718 2719
2719 2720 static int
2720 2721 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2721 2722 {
2722 2723 int err, i;
2723 2724 property_value_ptr_t pp;
2724 2725
2725 2726 if ((err = initialize(B_TRUE)) != Z_OK)
2726 2727 return (err);
2727 2728
2728 2729 bzero(fstab, sizeof (*fstab));
2729 2730 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2730 2731 pp = cmd->cmd_property_ptr[i];
2731 2732 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2732 2733 zerr(gettext("A simple value was expected here."));
2733 2734 saw_error = B_TRUE;
2734 2735 return (Z_INSUFFICIENT_SPEC);
2735 2736 }
2736 2737 switch (cmd->cmd_prop_name[i]) {
2737 2738 case PT_DIR:
2738 2739 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2739 2740 sizeof (fstab->zone_fs_dir));
2740 2741 break;
2741 2742 case PT_SPECIAL:
2742 2743 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2743 2744 sizeof (fstab->zone_fs_special));
2744 2745 break;
2745 2746 case PT_RAW:
2746 2747 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2747 2748 sizeof (fstab->zone_fs_raw));
2748 2749 break;
2749 2750 case PT_TYPE:
2750 2751 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2751 2752 sizeof (fstab->zone_fs_type));
2752 2753 break;
2753 2754 default:
2754 2755 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2755 2756 Z_NO_PROPERTY_TYPE, B_TRUE);
2756 2757 return (Z_INSUFFICIENT_SPEC);
2757 2758 }
2758 2759 }
2759 2760 if (fill_in_only)
2760 2761 return (Z_OK);
2761 2762 return (zonecfg_lookup_filesystem(handle, fstab));
2762 2763 }
2763 2764
2764 2765 static int
2765 2766 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2766 2767 boolean_t fill_in_only)
2767 2768 {
2768 2769 int err, i;
2769 2770 property_value_ptr_t pp;
2770 2771
2771 2772 if ((err = initialize(B_TRUE)) != Z_OK)
2772 2773 return (err);
2773 2774
2774 2775 bzero(nwiftab, sizeof (*nwiftab));
2775 2776 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2776 2777 pp = cmd->cmd_property_ptr[i];
2777 2778 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2778 2779 zerr(gettext("A simple value was expected here."));
2779 2780 saw_error = B_TRUE;
2780 2781 return (Z_INSUFFICIENT_SPEC);
2781 2782 }
2782 2783 switch (cmd->cmd_prop_name[i]) {
2783 2784 case PT_ADDRESS:
2784 2785 (void) strlcpy(nwiftab->zone_nwif_address,
2785 2786 pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2786 2787 break;
2787 2788 case PT_ALLOWED_ADDRESS:
2788 2789 (void) strlcpy(nwiftab->zone_nwif_allowed_address,
2789 2790 pp->pv_simple,
2790 2791 sizeof (nwiftab->zone_nwif_allowed_address));
2791 2792 break;
2792 2793 case PT_PHYSICAL:
2793 2794 (void) strlcpy(nwiftab->zone_nwif_physical,
2794 2795 pp->pv_simple,
2795 2796 sizeof (nwiftab->zone_nwif_physical));
2796 2797 break;
2797 2798 case PT_DEFROUTER:
2798 2799 (void) strlcpy(nwiftab->zone_nwif_defrouter,
2799 2800 pp->pv_simple,
2800 2801 sizeof (nwiftab->zone_nwif_defrouter));
2801 2802 break;
2802 2803 default:
2803 2804 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2804 2805 Z_NO_PROPERTY_TYPE, B_TRUE);
2805 2806 return (Z_INSUFFICIENT_SPEC);
2806 2807 }
2807 2808 }
2808 2809 if (fill_in_only)
2809 2810 return (Z_OK);
2810 2811 err = zonecfg_lookup_nwif(handle, nwiftab);
2811 2812 return (err);
2812 2813 }
2813 2814
2814 2815 static int
2815 2816 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2816 2817 {
2817 2818 int err, i;
2818 2819 property_value_ptr_t pp;
2819 2820
2820 2821 if ((err = initialize(B_TRUE)) != Z_OK)
2821 2822 return (err);
2822 2823
2823 2824 bzero(devtab, sizeof (*devtab));
2824 2825 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2825 2826 pp = cmd->cmd_property_ptr[i];
2826 2827 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2827 2828 zerr(gettext("A simple value was expected here."));
2828 2829 saw_error = B_TRUE;
2829 2830 return (Z_INSUFFICIENT_SPEC);
2830 2831 }
2831 2832 switch (cmd->cmd_prop_name[i]) {
2832 2833 case PT_MATCH:
2833 2834 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2834 2835 sizeof (devtab->zone_dev_match));
2835 2836 break;
2836 2837 default:
2837 2838 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2838 2839 Z_NO_PROPERTY_TYPE, B_TRUE);
2839 2840 return (Z_INSUFFICIENT_SPEC);
2840 2841 }
2841 2842 }
2842 2843 if (fill_in_only)
2843 2844 return (Z_OK);
2844 2845 err = zonecfg_lookup_dev(handle, devtab);
2845 2846 return (err);
2846 2847 }
2847 2848
2848 2849 static int
2849 2850 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2850 2851 boolean_t fill_in_only)
2851 2852 {
2852 2853 int err, i;
2853 2854 property_value_ptr_t pp;
2854 2855
2855 2856 if ((err = initialize(B_TRUE)) != Z_OK)
2856 2857 return (err);
2857 2858
2858 2859 bzero(rctltab, sizeof (*rctltab));
2859 2860 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2860 2861 pp = cmd->cmd_property_ptr[i];
2861 2862 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2862 2863 zerr(gettext("A simple value was expected here."));
2863 2864 saw_error = B_TRUE;
2864 2865 return (Z_INSUFFICIENT_SPEC);
2865 2866 }
2866 2867 switch (cmd->cmd_prop_name[i]) {
2867 2868 case PT_NAME:
2868 2869 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2869 2870 sizeof (rctltab->zone_rctl_name));
2870 2871 break;
2871 2872 default:
2872 2873 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2873 2874 Z_NO_PROPERTY_TYPE, B_TRUE);
2874 2875 return (Z_INSUFFICIENT_SPEC);
2875 2876 }
2876 2877 }
2877 2878 if (fill_in_only)
2878 2879 return (Z_OK);
2879 2880 err = zonecfg_lookup_rctl(handle, rctltab);
2880 2881 return (err);
2881 2882 }
2882 2883
2883 2884 static int
2884 2885 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2885 2886 boolean_t fill_in_only)
2886 2887 {
2887 2888 int err, i;
2888 2889 property_value_ptr_t pp;
2889 2890
2890 2891 if ((err = initialize(B_TRUE)) != Z_OK)
2891 2892 return (err);
2892 2893
2893 2894 bzero(attrtab, sizeof (*attrtab));
2894 2895 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2895 2896 pp = cmd->cmd_property_ptr[i];
2896 2897 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2897 2898 zerr(gettext("A simple value was expected here."));
2898 2899 saw_error = B_TRUE;
2899 2900 return (Z_INSUFFICIENT_SPEC);
2900 2901 }
2901 2902 switch (cmd->cmd_prop_name[i]) {
2902 2903 case PT_NAME:
2903 2904 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2904 2905 sizeof (attrtab->zone_attr_name));
2905 2906 break;
2906 2907 case PT_TYPE:
2907 2908 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2908 2909 sizeof (attrtab->zone_attr_type));
2909 2910 break;
2910 2911 case PT_VALUE:
2911 2912 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2912 2913 sizeof (attrtab->zone_attr_value));
2913 2914 break;
2914 2915 default:
2915 2916 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2916 2917 Z_NO_PROPERTY_TYPE, B_TRUE);
2917 2918 return (Z_INSUFFICIENT_SPEC);
2918 2919 }
2919 2920 }
2920 2921 if (fill_in_only)
2921 2922 return (Z_OK);
2922 2923 err = zonecfg_lookup_attr(handle, attrtab);
2923 2924 return (err);
2924 2925 }
2925 2926
2926 2927 static int
2927 2928 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2928 2929 {
2929 2930 int err, i;
2930 2931 property_value_ptr_t pp;
2931 2932
2932 2933 if ((err = initialize(B_TRUE)) != Z_OK)
2933 2934 return (err);
2934 2935
2935 2936 dstab->zone_dataset_name[0] = '\0';
2936 2937 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2937 2938 pp = cmd->cmd_property_ptr[i];
2938 2939 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2939 2940 zerr(gettext("A simple value was expected here."));
2940 2941 saw_error = B_TRUE;
2941 2942 return (Z_INSUFFICIENT_SPEC);
2942 2943 }
2943 2944 switch (cmd->cmd_prop_name[i]) {
2944 2945 case PT_NAME:
2945 2946 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2946 2947 sizeof (dstab->zone_dataset_name));
2947 2948 break;
2948 2949 default:
2949 2950 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2950 2951 Z_NO_PROPERTY_TYPE, B_TRUE);
2951 2952 return (Z_INSUFFICIENT_SPEC);
2952 2953 }
2953 2954 }
2954 2955 if (fill_in_only)
2955 2956 return (Z_OK);
2956 2957 return (zonecfg_lookup_ds(handle, dstab));
2957 2958 }
2958 2959
2959 2960 static int
2960 2961 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2961 2962 boolean_t fill_in_only)
2962 2963 {
2963 2964 int err, i;
2964 2965 property_value_ptr_t pp;
2965 2966
2966 2967 if ((err = initialize(B_TRUE)) != Z_OK)
2967 2968 return (err);
2968 2969
2969 2970 bzero(admintab, sizeof (*admintab));
2970 2971 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2971 2972 pp = cmd->cmd_property_ptr[i];
2972 2973 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2973 2974 zerr(gettext("A simple value was expected here."));
2974 2975 saw_error = B_TRUE;
2975 2976 return (Z_INSUFFICIENT_SPEC);
2976 2977 }
2977 2978 switch (cmd->cmd_prop_name[i]) {
2978 2979 case PT_USER:
2979 2980 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2980 2981 sizeof (admintab->zone_admin_user));
2981 2982 break;
2982 2983 case PT_AUTHS:
2983 2984 (void) strlcpy(admintab->zone_admin_auths,
2984 2985 pp->pv_simple, sizeof (admintab->zone_admin_auths));
2985 2986 break;
2986 2987 default:
2987 2988 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2988 2989 Z_NO_PROPERTY_TYPE, B_TRUE);
2989 2990 return (Z_INSUFFICIENT_SPEC);
2990 2991 }
2991 2992 }
2992 2993 if (fill_in_only)
2993 2994 return (Z_OK);
2994 2995 err = zonecfg_lookup_admin(handle, admintab);
2995 2996 return (err);
2996 2997 }
2997 2998
2998 2999 static int
2999 3000 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
3000 3001 boolean_t fill_in_only)
3001 3002 {
3002 3003 int err, i;
3003 3004 property_value_ptr_t pp;
3004 3005
3005 3006 if ((err = initialize(B_TRUE)) != Z_OK)
3006 3007 return (err);
3007 3008
3008 3009 bzero(secflagstab, sizeof (*secflagstab));
3009 3010 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
3010 3011 pp = cmd->cmd_property_ptr[i];
3011 3012 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
3012 3013 zerr(gettext("A simple value was expected here."));
3013 3014 saw_error = B_TRUE;
3014 3015 return (Z_INSUFFICIENT_SPEC);
3015 3016 }
3016 3017 switch (cmd->cmd_prop_name[i]) {
3017 3018 case PT_DEFAULT:
3018 3019 (void) strlcpy(secflagstab->zone_secflags_default,
3019 3020 pp->pv_simple,
3020 3021 sizeof (secflagstab->zone_secflags_default));
3021 3022 break;
3022 3023 case PT_LOWER:
3023 3024 (void) strlcpy(secflagstab->zone_secflags_lower,
3024 3025 pp->pv_simple,
3025 3026 sizeof (secflagstab->zone_secflags_lower));
3026 3027 break;
3027 3028 case PT_UPPER:
3028 3029 (void) strlcpy(secflagstab->zone_secflags_upper,
3029 3030 pp->pv_simple,
3030 3031 sizeof (secflagstab->zone_secflags_upper));
3031 3032 break;
3032 3033 default:
3033 3034 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
3034 3035 Z_NO_PROPERTY_TYPE, B_TRUE);
3035 3036 return (Z_INSUFFICIENT_SPEC);
3036 3037 }
3037 3038 }
3038 3039 if (fill_in_only)
3039 3040 return (Z_OK);
3040 3041
3041 3042 err = zonecfg_lookup_secflags(handle, secflagstab);
3042 3043
3043 3044 return (err);
3044 3045 }
3045 3046
3046 3047 static void
3047 3048 remove_aliased_rctl(int type, char *name)
3048 3049 {
3049 3050 int err;
3050 3051 uint64_t tmp;
3051 3052
3052 3053 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
3053 3054 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3054 3055 zonecfg_strerror(err));
3055 3056 saw_error = B_TRUE;
3056 3057 return;
3057 3058 }
3058 3059 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
3059 3060 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3060 3061 zonecfg_strerror(err));
3061 3062 saw_error = B_TRUE;
3062 3063 } else {
3063 3064 need_to_commit = B_TRUE;
3064 3065 }
3065 3066 }
3066 3067
3067 3068 static boolean_t
3068 3069 prompt_remove_resource(cmd_t *cmd, char *rsrc)
3069 3070 {
3070 3071 int num;
3071 3072 int answer;
3072 3073 int arg;
3073 3074 boolean_t force = B_FALSE;
3074 3075 char prompt[128];
3075 3076 boolean_t arg_err = B_FALSE;
3076 3077
3077 3078 optind = 0;
3078 3079 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3079 3080 switch (arg) {
3080 3081 case 'F':
3081 3082 force = B_TRUE;
3082 3083 break;
3083 3084 default:
3084 3085 arg_err = B_TRUE;
3085 3086 break;
3086 3087 }
3087 3088 }
3088 3089 if (arg_err)
3089 3090 return (B_FALSE);
3090 3091
3091 3092
3092 3093 num = zonecfg_num_resources(handle, rsrc);
3093 3094
3094 3095 if (num == 0) {
3095 3096 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
3096 3097 B_TRUE);
3097 3098 return (B_FALSE);
3098 3099 }
3099 3100 if (num > 1 && !force) {
3100 3101 if (!interactive_mode) {
3101 3102 zerr(gettext("There are multiple instances of this "
3102 3103 "resource. Either qualify the resource to\n"
3103 3104 "remove a single instance or use the -F option to "
3104 3105 "remove all instances."));
3105 3106 saw_error = B_TRUE;
3106 3107 return (B_FALSE);
3107 3108 }
3108 3109 (void) snprintf(prompt, sizeof (prompt), gettext(
3109 3110 "Are you sure you want to remove ALL '%s' resources"),
3110 3111 rsrc);
3111 3112 answer = ask_yesno(B_FALSE, prompt);
3112 3113 if (answer == -1) {
3113 3114 zerr(gettext("Resource incomplete."));
3114 3115 return (B_FALSE);
3115 3116 }
3116 3117 if (answer != 1)
3117 3118 return (B_FALSE);
3118 3119 }
3119 3120 return (B_TRUE);
3120 3121 }
3121 3122
3122 3123 static void
3123 3124 remove_fs(cmd_t *cmd)
3124 3125 {
3125 3126 int err;
3126 3127
3127 3128 /* traditional, qualified fs removal */
3128 3129 if (cmd->cmd_prop_nv_pairs > 0) {
3129 3130 struct zone_fstab fstab;
3130 3131
3131 3132 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
3132 3133 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3133 3134 return;
3134 3135 }
3135 3136 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
3136 3137 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3137 3138 else
3138 3139 need_to_commit = B_TRUE;
3139 3140 zonecfg_free_fs_option_list(fstab.zone_fs_options);
3140 3141 return;
3141 3142 }
3142 3143
3143 3144 /*
3144 3145 * unqualified fs removal. remove all fs's but prompt if more
3145 3146 * than one.
3146 3147 */
3147 3148 if (!prompt_remove_resource(cmd, "fs"))
3148 3149 return;
3149 3150
3150 3151 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
3151 3152 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3152 3153 else
3153 3154 need_to_commit = B_TRUE;
3154 3155 }
3155 3156
3156 3157 static void
3157 3158 remove_net(cmd_t *cmd)
3158 3159 {
3159 3160 int err;
3160 3161
3161 3162 /* traditional, qualified net removal */
3162 3163 if (cmd->cmd_prop_nv_pairs > 0) {
3163 3164 struct zone_nwiftab nwiftab;
3164 3165
3165 3166 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3166 3167 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3167 3168 return;
3168 3169 }
3169 3170 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3170 3171 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3171 3172 else
3172 3173 need_to_commit = B_TRUE;
3173 3174 return;
3174 3175 }
3175 3176
3176 3177 /*
3177 3178 * unqualified net removal. remove all nets but prompt if more
3178 3179 * than one.
3179 3180 */
3180 3181 if (!prompt_remove_resource(cmd, "net"))
3181 3182 return;
3182 3183
3183 3184 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3184 3185 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3185 3186 else
3186 3187 need_to_commit = B_TRUE;
3187 3188 }
3188 3189
3189 3190 static void
3190 3191 remove_device(cmd_t *cmd)
3191 3192 {
3192 3193 int err;
3193 3194
3194 3195 /* traditional, qualified device removal */
3195 3196 if (cmd->cmd_prop_nv_pairs > 0) {
3196 3197 struct zone_devtab devtab;
3197 3198
3198 3199 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3199 3200 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3200 3201 return;
3201 3202 }
3202 3203 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3203 3204 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3204 3205 else
3205 3206 need_to_commit = B_TRUE;
3206 3207 return;
3207 3208 }
3208 3209
3209 3210 /*
3210 3211 * unqualified device removal. remove all devices but prompt if more
3211 3212 * than one.
3212 3213 */
3213 3214 if (!prompt_remove_resource(cmd, "device"))
3214 3215 return;
3215 3216
3216 3217 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3217 3218 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3218 3219 else
3219 3220 need_to_commit = B_TRUE;
3220 3221 }
3221 3222
3222 3223 static void
3223 3224 remove_attr(cmd_t *cmd)
3224 3225 {
3225 3226 int err;
3226 3227
3227 3228 /* traditional, qualified attr removal */
3228 3229 if (cmd->cmd_prop_nv_pairs > 0) {
3229 3230 struct zone_attrtab attrtab;
3230 3231
3231 3232 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3232 3233 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3233 3234 return;
3234 3235 }
3235 3236 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3236 3237 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3237 3238 else
3238 3239 need_to_commit = B_TRUE;
3239 3240 return;
3240 3241 }
3241 3242
3242 3243 /*
3243 3244 * unqualified attr removal. remove all attrs but prompt if more
3244 3245 * than one.
3245 3246 */
3246 3247 if (!prompt_remove_resource(cmd, "attr"))
3247 3248 return;
3248 3249
3249 3250 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3250 3251 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3251 3252 else
3252 3253 need_to_commit = B_TRUE;
3253 3254 }
3254 3255
3255 3256 static void
3256 3257 remove_dataset(cmd_t *cmd)
3257 3258 {
3258 3259 int err;
3259 3260
3260 3261 /* traditional, qualified dataset removal */
3261 3262 if (cmd->cmd_prop_nv_pairs > 0) {
3262 3263 struct zone_dstab dstab;
3263 3264
3264 3265 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3265 3266 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3266 3267 return;
3267 3268 }
3268 3269 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3269 3270 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3270 3271 else
3271 3272 need_to_commit = B_TRUE;
3272 3273 return;
3273 3274 }
3274 3275
3275 3276 /*
3276 3277 * unqualified dataset removal. remove all datasets but prompt if more
3277 3278 * than one.
3278 3279 */
3279 3280 if (!prompt_remove_resource(cmd, "dataset"))
3280 3281 return;
3281 3282
3282 3283 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3283 3284 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3284 3285 else
3285 3286 need_to_commit = B_TRUE;
3286 3287 }
3287 3288
3288 3289 static void
3289 3290 remove_rctl(cmd_t *cmd)
3290 3291 {
3291 3292 int err;
3292 3293
3293 3294 /* traditional, qualified rctl removal */
3294 3295 if (cmd->cmd_prop_nv_pairs > 0) {
3295 3296 struct zone_rctltab rctltab;
3296 3297
3297 3298 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3298 3299 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3299 3300 return;
3300 3301 }
3301 3302 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3302 3303 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3303 3304 else
3304 3305 need_to_commit = B_TRUE;
3305 3306 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3306 3307 return;
3307 3308 }
3308 3309
3309 3310 /*
3310 3311 * unqualified rctl removal. remove all rctls but prompt if more
3311 3312 * than one.
3312 3313 */
3313 3314 if (!prompt_remove_resource(cmd, "rctl"))
3314 3315 return;
3315 3316
3316 3317 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3317 3318 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3318 3319 else
3319 3320 need_to_commit = B_TRUE;
3320 3321 }
3321 3322
3322 3323 static void
3323 3324 remove_pset()
3324 3325 {
3325 3326 int err;
3326 3327 struct zone_psettab psettab;
3327 3328
3328 3329 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3329 3330 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3330 3331 return;
3331 3332 }
3332 3333 if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3333 3334 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3334 3335 else
3335 3336 need_to_commit = B_TRUE;
3336 3337 }
3337 3338
3338 3339 static void
3339 3340 remove_pcap()
3340 3341 {
3341 3342 int err;
3342 3343 uint64_t tmp;
3343 3344
3344 3345 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3345 3346 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3346 3347 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3347 3348 saw_error = B_TRUE;
3348 3349 return;
3349 3350 }
3350 3351
3351 3352 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3352 3353 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3353 3354 else
3354 3355 need_to_commit = B_TRUE;
3355 3356 }
3356 3357
3357 3358 static void
3358 3359 remove_mcap()
3359 3360 {
3360 3361 int err, res1, res2, res3;
3361 3362 uint64_t tmp;
3362 3363 struct zone_mcaptab mcaptab;
3363 3364 boolean_t revert = B_FALSE;
3364 3365
3365 3366 res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3366 3367 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3367 3368 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3368 3369
3369 3370 /* if none of these exist, there is no resource to remove */
3370 3371 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3371 3372 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3372 3373 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3373 3374 saw_error = B_TRUE;
3374 3375 return;
3375 3376 }
3376 3377 if (res1 == Z_OK) {
3377 3378 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3378 3379 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3379 3380 revert = B_TRUE;
3380 3381 } else {
3381 3382 need_to_commit = B_TRUE;
3382 3383 }
3383 3384 }
3384 3385 if (res2 == Z_OK) {
3385 3386 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3386 3387 != Z_OK) {
3387 3388 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3388 3389 revert = B_TRUE;
3389 3390 } else {
3390 3391 need_to_commit = B_TRUE;
3391 3392 }
3392 3393 }
3393 3394 if (res3 == Z_OK) {
3394 3395 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3395 3396 != Z_OK) {
3396 3397 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3397 3398 revert = B_TRUE;
3398 3399 } else {
3399 3400 need_to_commit = B_TRUE;
3400 3401 }
3401 3402 }
3402 3403
3403 3404 if (revert)
3404 3405 need_to_commit = B_FALSE;
3405 3406 }
3406 3407
3407 3408 static void
3408 3409 remove_admin(cmd_t *cmd)
3409 3410 {
3410 3411 int err;
3411 3412
3412 3413 /* traditional, qualified attr removal */
3413 3414 if (cmd->cmd_prop_nv_pairs > 0) {
3414 3415 struct zone_admintab admintab;
3415 3416
3416 3417 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3417 3418 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3418 3419 err, B_TRUE);
3419 3420 return;
3420 3421 }
3421 3422 if ((err = zonecfg_delete_admin(handle, &admintab,
3422 3423 zone))
3423 3424 != Z_OK)
3424 3425 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3425 3426 err, B_TRUE);
3426 3427 else
3427 3428 need_to_commit = B_TRUE;
3428 3429 return;
3429 3430 } else {
3430 3431 /*
3431 3432 * unqualified admin removal.
3432 3433 * remove all admins but prompt if more
3433 3434 * than one.
3434 3435 */
3435 3436 if (!prompt_remove_resource(cmd, "admin"))
3436 3437 return;
3437 3438
3438 3439 if ((err = zonecfg_delete_admins(handle, zone))
3439 3440 != Z_OK)
3440 3441 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3441 3442 err, B_TRUE);
3442 3443 else
3443 3444 need_to_commit = B_TRUE;
3444 3445 }
3445 3446 }
3446 3447
3447 3448 static void
3448 3449 remove_secflags()
3449 3450 {
3450 3451 int err;
3451 3452 struct zone_secflagstab sectab = { 0 };
3452 3453
3453 3454 if (zonecfg_lookup_secflags(handle, §ab) != Z_OK) {
3454 3455 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
3455 3456 rt_to_str(RT_SECFLAGS),
3456 3457 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3457 3458 return;
3458 3459 }
3459 3460
3460 3461 if ((err = zonecfg_delete_secflags(handle, §ab)) != Z_OK) {
3461 3462 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
3462 3463 return;
3463 3464 }
3464 3465
3465 3466 need_to_commit = B_TRUE;
3466 3467 }
3467 3468
3468 3469 static void
3469 3470 remove_resource(cmd_t *cmd)
3470 3471 {
3471 3472 int type;
3472 3473 int arg;
3473 3474 boolean_t arg_err = B_FALSE;
3474 3475
3475 3476 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3476 3477 long_usage(CMD_REMOVE, B_TRUE);
3477 3478 return;
3478 3479 }
3479 3480
3480 3481 optind = 0;
3481 3482 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3482 3483 switch (arg) {
3483 3484 case '?':
3484 3485 longer_usage(CMD_REMOVE);
3485 3486 arg_err = B_TRUE;
3486 3487 break;
3487 3488 case 'F':
3488 3489 break;
3489 3490 default:
3490 3491 short_usage(CMD_REMOVE);
3491 3492 arg_err = B_TRUE;
3492 3493 break;
3493 3494 }
3494 3495 }
3495 3496 if (arg_err)
3496 3497 return;
3497 3498
3498 3499 if (initialize(B_TRUE) != Z_OK)
3499 3500 return;
3500 3501
3501 3502 switch (type) {
3502 3503 case RT_FS:
3503 3504 remove_fs(cmd);
3504 3505 return;
3505 3506 case RT_NET:
3506 3507 remove_net(cmd);
3507 3508 return;
3508 3509 case RT_DEVICE:
3509 3510 remove_device(cmd);
3510 3511 return;
3511 3512 case RT_RCTL:
3512 3513 remove_rctl(cmd);
3513 3514 return;
3514 3515 case RT_ATTR:
3515 3516 remove_attr(cmd);
3516 3517 return;
3517 3518 case RT_DATASET:
3518 3519 remove_dataset(cmd);
3519 3520 return;
3520 3521 case RT_DCPU:
3521 3522 remove_pset();
3522 3523 return;
3523 3524 case RT_PCAP:
3524 3525 remove_pcap();
3525 3526 return;
3526 3527 case RT_MCAP:
3527 3528 remove_mcap();
3528 3529 return;
3529 3530 case RT_ADMIN:
3530 3531 remove_admin(cmd);
3531 3532 return;
3532 3533 case RT_SECFLAGS:
3533 3534 remove_secflags();
3534 3535 return;
3535 3536 default:
3536 3537 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3537 3538 long_usage(CMD_REMOVE, B_TRUE);
3538 3539 usage(B_FALSE, HELP_RESOURCES);
3539 3540 return;
3540 3541 }
3541 3542 }
3542 3543
3543 3544 static void
3544 3545 remove_property(cmd_t *cmd)
3545 3546 {
3546 3547 char *prop_id;
3547 3548 int err, res_type, prop_type;
3548 3549 property_value_ptr_t pp;
3549 3550 struct zone_rctlvaltab *rctlvaltab;
3550 3551 complex_property_ptr_t cx;
3551 3552
3552 3553 res_type = resource_scope;
3553 3554 prop_type = cmd->cmd_prop_name[0];
3554 3555 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3555 3556 long_usage(CMD_REMOVE, B_TRUE);
3556 3557 return;
3557 3558 }
3558 3559
3559 3560 if (cmd->cmd_prop_nv_pairs != 1) {
3560 3561 long_usage(CMD_ADD, B_TRUE);
3561 3562 return;
3562 3563 }
3563 3564
3564 3565 if (initialize(B_TRUE) != Z_OK)
3565 3566 return;
3566 3567
3567 3568 switch (res_type) {
3568 3569 case RT_FS:
3569 3570 if (prop_type != PT_OPTIONS) {
3570 3571 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3571 3572 B_TRUE);
3572 3573 long_usage(CMD_REMOVE, B_TRUE);
3573 3574 usage(B_FALSE, HELP_PROPS);
3574 3575 return;
3575 3576 }
3576 3577 pp = cmd->cmd_property_ptr[0];
3577 3578 if (pp->pv_type == PROP_VAL_COMPLEX) {
3578 3579 zerr(gettext("A %s or %s value was expected here."),
3579 3580 pvt_to_str(PROP_VAL_SIMPLE),
3580 3581 pvt_to_str(PROP_VAL_LIST));
3581 3582 saw_error = B_TRUE;
3582 3583 return;
3583 3584 }
3584 3585 if (pp->pv_type == PROP_VAL_SIMPLE) {
3585 3586 if (pp->pv_simple == NULL) {
3586 3587 long_usage(CMD_ADD, B_TRUE);
3587 3588 return;
3588 3589 }
3589 3590 prop_id = pp->pv_simple;
3590 3591 err = zonecfg_remove_fs_option(&in_progress_fstab,
3591 3592 prop_id);
3592 3593 if (err != Z_OK)
3593 3594 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3594 3595 } else {
3595 3596 list_property_ptr_t list;
3596 3597
3597 3598 for (list = pp->pv_list; list != NULL;
3598 3599 list = list->lp_next) {
3599 3600 prop_id = list->lp_simple;
3600 3601 if (prop_id == NULL)
3601 3602 break;
3602 3603 err = zonecfg_remove_fs_option(
3603 3604 &in_progress_fstab, prop_id);
3604 3605 if (err != Z_OK)
3605 3606 zone_perror(pt_to_str(prop_type), err,
3606 3607 B_TRUE);
3607 3608 }
3608 3609 }
3609 3610 return;
3610 3611 case RT_RCTL:
3611 3612 if (prop_type != PT_VALUE) {
3612 3613 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3613 3614 B_TRUE);
3614 3615 long_usage(CMD_REMOVE, B_TRUE);
3615 3616 usage(B_FALSE, HELP_PROPS);
3616 3617 return;
3617 3618 }
3618 3619 pp = cmd->cmd_property_ptr[0];
3619 3620 if (pp->pv_type != PROP_VAL_COMPLEX) {
3620 3621 zerr(gettext("A %s value was expected here."),
3621 3622 pvt_to_str(PROP_VAL_COMPLEX));
3622 3623 saw_error = B_TRUE;
3623 3624 return;
3624 3625 }
3625 3626 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3626 3627 zone_perror(zone, Z_NOMEM, B_TRUE);
3627 3628 exit(Z_ERR);
3628 3629 }
3629 3630 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3630 3631 switch (cx->cp_type) {
3631 3632 case PT_PRIV:
3632 3633 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
3633 3634 cx->cp_value,
3634 3635 sizeof (rctlvaltab->zone_rctlval_priv));
3635 3636 break;
3636 3637 case PT_LIMIT:
3637 3638 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
3638 3639 cx->cp_value,
3639 3640 sizeof (rctlvaltab->zone_rctlval_limit));
3640 3641 break;
3641 3642 case PT_ACTION:
3642 3643 (void) strlcpy(rctlvaltab->zone_rctlval_action,
3643 3644 cx->cp_value,
3644 3645 sizeof (rctlvaltab->zone_rctlval_action));
3645 3646 break;
3646 3647 default:
3647 3648 zone_perror(pt_to_str(prop_type),
3648 3649 Z_NO_PROPERTY_TYPE, B_TRUE);
3649 3650 long_usage(CMD_ADD, B_TRUE);
3650 3651 usage(B_FALSE, HELP_PROPS);
3651 3652 zonecfg_free_rctl_value_list(rctlvaltab);
3652 3653 return;
3653 3654 }
3654 3655 }
3655 3656 rctlvaltab->zone_rctlval_next = NULL;
3656 3657 err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3657 3658 rctlvaltab);
3658 3659 if (err != Z_OK)
3659 3660 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3660 3661 zonecfg_free_rctl_value_list(rctlvaltab);
3661 3662 return;
3662 3663 case RT_NET:
3663 3664 if (prop_type != PT_DEFROUTER) {
3664 3665 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3665 3666 B_TRUE);
3666 3667 long_usage(CMD_REMOVE, B_TRUE);
3667 3668 usage(B_FALSE, HELP_PROPS);
3668 3669 return;
3669 3670 } else {
3670 3671 bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3671 3672 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3672 3673 return;
3673 3674 }
3674 3675 default:
3675 3676 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3676 3677 long_usage(CMD_REMOVE, B_TRUE);
3677 3678 usage(B_FALSE, HELP_RESOURCES);
3678 3679 return;
3679 3680 }
3680 3681 }
3681 3682
3682 3683 void
3683 3684 remove_func(cmd_t *cmd)
3684 3685 {
3685 3686 if (zone_is_read_only(CMD_REMOVE))
3686 3687 return;
3687 3688
3688 3689 assert(cmd != NULL);
3689 3690
3690 3691 if (global_scope) {
3691 3692 if (gz_invalid_resource(cmd->cmd_res_type)) {
3692 3693 zerr(gettext("%s is not a valid resource for the "
3693 3694 "global zone."), rt_to_str(cmd->cmd_res_type));
3694 3695 saw_error = B_TRUE;
3695 3696 return;
3696 3697 }
3697 3698 remove_resource(cmd);
3698 3699 } else {
3699 3700 remove_property(cmd);
3700 3701 }
3701 3702 }
3702 3703
3703 3704 static void
3704 3705 clear_property(cmd_t *cmd)
3705 3706 {
3706 3707 int res_type, prop_type;
3707 3708
3708 3709 res_type = resource_scope;
3709 3710 prop_type = cmd->cmd_res_type;
3710 3711 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3711 3712 long_usage(CMD_CLEAR, B_TRUE);
3712 3713 return;
3713 3714 }
3714 3715
3715 3716 if (initialize(B_TRUE) != Z_OK)
3716 3717 return;
3717 3718
3718 3719 switch (res_type) {
3719 3720 case RT_FS:
3720 3721 if (prop_type == PT_RAW) {
3721 3722 in_progress_fstab.zone_fs_raw[0] = '\0';
3722 3723 need_to_commit = B_TRUE;
3723 3724 return;
3724 3725 }
3725 3726 break;
3726 3727 case RT_DCPU:
3727 3728 if (prop_type == PT_IMPORTANCE) {
3728 3729 in_progress_psettab.zone_importance[0] = '\0';
3729 3730 need_to_commit = B_TRUE;
3730 3731 return;
3731 3732 }
3732 3733 break;
3733 3734 case RT_MCAP:
3734 3735 switch (prop_type) {
3735 3736 case PT_PHYSICAL:
3736 3737 in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3737 3738 need_to_commit = B_TRUE;
3738 3739 return;
3739 3740 case PT_SWAP:
3740 3741 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3741 3742 return;
3742 3743 case PT_LOCKED:
3743 3744 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3744 3745 return;
3745 3746 }
3746 3747 break;
3747 3748 case RT_SECFLAGS:
3748 3749 switch (prop_type) {
3749 3750 case PT_LOWER:
3750 3751 in_progress_secflagstab.zone_secflags_lower[0] = '\0';
3751 3752 need_to_commit = B_TRUE;
3752 3753 return;
3753 3754 case PT_DEFAULT:
3754 3755 in_progress_secflagstab.zone_secflags_default[0] = '\0';
3755 3756 need_to_commit = B_TRUE;
3756 3757 return;
3757 3758 case PT_UPPER:
3758 3759 in_progress_secflagstab.zone_secflags_upper[0] = '\0';
3759 3760 need_to_commit = B_TRUE;
3760 3761 return;
3761 3762 }
3762 3763 break;
3763 3764 default:
3764 3765 break;
3765 3766 }
3766 3767
3767 3768 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3768 3769 }
3769 3770
3770 3771 static void
3771 3772 clear_global(cmd_t *cmd)
3772 3773 {
3773 3774 int err, type;
3774 3775
3775 3776 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3776 3777 long_usage(CMD_CLEAR, B_TRUE);
3777 3778 return;
3778 3779 }
3779 3780
3780 3781 if (initialize(B_TRUE) != Z_OK)
3781 3782 return;
3782 3783
3783 3784 switch (type) {
3784 3785 case PT_ZONENAME:
3785 3786 /* FALLTHRU */
3786 3787 case PT_ZONEPATH:
3787 3788 /* FALLTHRU */
3788 3789 case PT_BRAND:
3789 3790 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3790 3791 return;
3791 3792 case PT_AUTOBOOT:
3792 3793 /* false is default; we'll treat as equivalent to clearing */
3793 3794 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3794 3795 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3795 3796 else
3796 3797 need_to_commit = B_TRUE;
3797 3798 return;
3798 3799 case PT_POOL:
3799 3800 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3800 3801 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3801 3802 else
3802 3803 need_to_commit = B_TRUE;
3803 3804 return;
3804 3805 case PT_LIMITPRIV:
3805 3806 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3806 3807 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3807 3808 else
3808 3809 need_to_commit = B_TRUE;
3809 3810 return;
3810 3811 case PT_BOOTARGS:
3811 3812 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3812 3813 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3813 3814 else
3814 3815 need_to_commit = B_TRUE;
3815 3816 return;
3816 3817 case PT_SCHED:
3817 3818 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3818 3819 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3819 3820 else
3820 3821 need_to_commit = B_TRUE;
3821 3822 return;
3822 3823 case PT_IPTYPE:
3823 3824 /* shared is default; we'll treat as equivalent to clearing */
3824 3825 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3825 3826 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3826 3827 else
3827 3828 need_to_commit = B_TRUE;
3828 3829 return;
3829 3830 case PT_MAXLWPS:
3830 3831 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3831 3832 return;
3832 3833 case PT_MAXPROCS:
3833 3834 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS);
3834 3835 return;
3835 3836 case PT_MAXSHMMEM:
3836 3837 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3837 3838 return;
3838 3839 case PT_MAXSHMIDS:
3839 3840 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3840 3841 return;
3841 3842 case PT_MAXMSGIDS:
3842 3843 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3843 3844 return;
3844 3845 case PT_MAXSEMIDS:
3845 3846 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3846 3847 return;
3847 3848 case PT_SHARES:
3848 3849 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3849 3850 return;
3850 3851 case PT_HOSTID:
3851 3852 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3852 3853 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3853 3854 else
3854 3855 need_to_commit = B_TRUE;
3855 3856 return;
3856 3857 case PT_FS_ALLOWED:
3857 3858 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3858 3859 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3859 3860 else
3860 3861 need_to_commit = B_TRUE;
3861 3862 return;
3862 3863 default:
3863 3864 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3864 3865 long_usage(CMD_CLEAR, B_TRUE);
3865 3866 usage(B_FALSE, HELP_PROPS);
3866 3867 return;
3867 3868 }
3868 3869 }
3869 3870
3870 3871 void
3871 3872 clear_func(cmd_t *cmd)
3872 3873 {
3873 3874 if (zone_is_read_only(CMD_CLEAR))
3874 3875 return;
3875 3876
3876 3877 assert(cmd != NULL);
3877 3878
3878 3879 if (global_scope) {
3879 3880 if (gz_invalid_property(cmd->cmd_res_type)) {
3880 3881 zerr(gettext("%s is not a valid property for the "
3881 3882 "global zone."), pt_to_str(cmd->cmd_res_type));
3882 3883 saw_error = B_TRUE;
3883 3884 return;
3884 3885 }
3885 3886
3886 3887 clear_global(cmd);
3887 3888 } else {
3888 3889 clear_property(cmd);
3889 3890 }
3890 3891 }
3891 3892
3892 3893 void
3893 3894 select_func(cmd_t *cmd)
3894 3895 {
3895 3896 int type, err, res;
3896 3897 uint64_t limit;
3897 3898 uint64_t tmp;
3898 3899
3899 3900 if (zone_is_read_only(CMD_SELECT))
3900 3901 return;
3901 3902
3902 3903 assert(cmd != NULL);
3903 3904
3904 3905 if (global_scope) {
3905 3906 global_scope = B_FALSE;
3906 3907 resource_scope = cmd->cmd_res_type;
3907 3908 end_op = CMD_SELECT;
3908 3909 } else {
3909 3910 scope_usage(CMD_SELECT);
3910 3911 return;
3911 3912 }
3912 3913
3913 3914 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3914 3915 long_usage(CMD_SELECT, B_TRUE);
3915 3916 return;
3916 3917 }
3917 3918
3918 3919 if (initialize(B_TRUE) != Z_OK)
3919 3920 return;
3920 3921
3921 3922 switch (type) {
3922 3923 case RT_FS:
3923 3924 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3924 3925 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3925 3926 global_scope = B_TRUE;
3926 3927 }
3927 3928 bcopy(&old_fstab, &in_progress_fstab,
3928 3929 sizeof (struct zone_fstab));
3929 3930 return;
3930 3931 case RT_NET:
3931 3932 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3932 3933 != Z_OK) {
3933 3934 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3934 3935 global_scope = B_TRUE;
3935 3936 }
3936 3937 bcopy(&old_nwiftab, &in_progress_nwiftab,
3937 3938 sizeof (struct zone_nwiftab));
3938 3939 return;
3939 3940 case RT_DEVICE:
3940 3941 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3941 3942 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3942 3943 global_scope = B_TRUE;
3943 3944 }
3944 3945 bcopy(&old_devtab, &in_progress_devtab,
3945 3946 sizeof (struct zone_devtab));
3946 3947 return;
3947 3948 case RT_RCTL:
3948 3949 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3949 3950 != Z_OK) {
3950 3951 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3951 3952 global_scope = B_TRUE;
3952 3953 }
3953 3954 bcopy(&old_rctltab, &in_progress_rctltab,
3954 3955 sizeof (struct zone_rctltab));
3955 3956 return;
3956 3957 case RT_ATTR:
3957 3958 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3958 3959 != Z_OK) {
3959 3960 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3960 3961 global_scope = B_TRUE;
3961 3962 }
3962 3963 bcopy(&old_attrtab, &in_progress_attrtab,
3963 3964 sizeof (struct zone_attrtab));
3964 3965 return;
3965 3966 case RT_DATASET:
3966 3967 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3967 3968 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3968 3969 global_scope = B_TRUE;
3969 3970 }
3970 3971 bcopy(&old_dstab, &in_progress_dstab,
3971 3972 sizeof (struct zone_dstab));
3972 3973 return;
3973 3974 case RT_DCPU:
3974 3975 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3975 3976 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3976 3977 global_scope = B_TRUE;
3977 3978 }
3978 3979 bcopy(&old_psettab, &in_progress_psettab,
3979 3980 sizeof (struct zone_psettab));
3980 3981 return;
3981 3982 case RT_PCAP:
3982 3983 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3983 3984 != Z_OK) {
3984 3985 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3985 3986 global_scope = B_TRUE;
3986 3987 }
3987 3988 return;
3988 3989 case RT_MCAP:
3989 3990 /* if none of these exist, there is no resource to select */
3990 3991 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3991 3992 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3992 3993 != Z_OK &&
3993 3994 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3994 3995 != Z_OK) {
3995 3996 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3996 3997 B_TRUE);
3997 3998 global_scope = B_TRUE;
3998 3999 }
3999 4000 if (res == Z_OK)
4000 4001 bcopy(&old_mcaptab, &in_progress_mcaptab,
4001 4002 sizeof (struct zone_mcaptab));
4002 4003 else
4003 4004 bzero(&in_progress_mcaptab,
4004 4005 sizeof (in_progress_mcaptab));
4005 4006 return;
4006 4007 case RT_ADMIN:
4007 4008 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
4008 4009 != Z_OK) {
4009 4010 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
4010 4011 B_TRUE);
4011 4012 global_scope = B_TRUE;
4012 4013 }
4013 4014 bcopy(&old_admintab, &in_progress_admintab,
4014 4015 sizeof (struct zone_admintab));
4015 4016 return;
4016 4017 case RT_SECFLAGS:
4017 4018 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
4018 4019 != Z_OK) {
4019 4020 z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
4020 4021 B_TRUE);
4021 4022 global_scope = B_TRUE;
4022 4023 }
4023 4024 bcopy(&old_secflagstab, &in_progress_secflagstab,
4024 4025 sizeof (struct zone_secflagstab));
4025 4026 return;
4026 4027 default:
4027 4028 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
4028 4029 long_usage(CMD_SELECT, B_TRUE);
4029 4030 usage(B_FALSE, HELP_RESOURCES);
4030 4031 return;
4031 4032 }
4032 4033 }
4033 4034
4034 4035 /*
4035 4036 * Network "addresses" can be one of the following forms:
4036 4037 * <IPv4 address>
4037 4038 * <IPv4 address>/<prefix length>
4038 4039 * <IPv6 address>/<prefix length>
4039 4040 * <host name>
4040 4041 * <host name>/<prefix length>
4041 4042 * In other words, the "/" followed by a prefix length is allowed but not
4042 4043 * required for IPv4 addresses and host names, and required for IPv6 addresses.
4043 4044 * If a prefix length is given, it must be in the allowable range: 0 to 32 for
4044 4045 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
4045 4046 * Host names must start with an alpha-numeric character, and all subsequent
4046 4047 * characters must be either alpha-numeric or "-".
4047 4048 *
4048 4049 * In some cases, e.g., the nexthop for the defrouter, the context indicates
4049 4050 * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
4050 4051 * require the /<prefix length> (and should ignore it if provided).
4051 4052 */
4052 4053
4053 4054 static int
4054 4055 validate_net_address_syntax(char *address, boolean_t ishost)
4055 4056 {
4056 4057 char *slashp, part1[MAXHOSTNAMELEN];
4057 4058 struct in6_addr in6;
4058 4059 struct in_addr in4;
4059 4060 int prefixlen, i;
4060 4061
4061 4062 /*
4062 4063 * Copy the part before any '/' into part1 or copy the whole
4063 4064 * thing if there is no '/'.
4064 4065 */
4065 4066 if ((slashp = strchr(address, '/')) != NULL) {
4066 4067 *slashp = '\0';
4067 4068 (void) strlcpy(part1, address, sizeof (part1));
4068 4069 *slashp = '/';
4069 4070 prefixlen = atoi(++slashp);
4070 4071 } else {
4071 4072 (void) strlcpy(part1, address, sizeof (part1));
4072 4073 }
4073 4074
4074 4075 if (ishost && slashp != NULL) {
4075 4076 zerr(gettext("Warning: prefix length in %s is not required and "
4076 4077 "will be ignored. The default host-prefix length "
4077 4078 "will be used"), address);
4078 4079 }
4079 4080
4080 4081
4081 4082 if (inet_pton(AF_INET6, part1, &in6) == 1) {
4082 4083 if (ishost) {
4083 4084 prefixlen = IPV6_ABITS;
4084 4085 } else if (slashp == NULL) {
4085 4086 zerr(gettext("%s: IPv6 addresses "
4086 4087 "require /prefix-length suffix."), address);
4087 4088 return (Z_ERR);
4088 4089 }
4089 4090 if (prefixlen < 0 || prefixlen > 128) {
4090 4091 zerr(gettext("%s: IPv6 address "
4091 4092 "prefix lengths must be 0 - 128."), address);
4092 4093 return (Z_ERR);
4093 4094 }
4094 4095 return (Z_OK);
4095 4096 }
4096 4097
4097 4098 /* At this point, any /prefix must be for IPv4. */
4098 4099 if (ishost)
4099 4100 prefixlen = IPV4_ABITS;
4100 4101 else if (slashp != NULL) {
4101 4102 if (prefixlen < 0 || prefixlen > 32) {
4102 4103 zerr(gettext("%s: IPv4 address "
4103 4104 "prefix lengths must be 0 - 32."), address);
4104 4105 return (Z_ERR);
4105 4106 }
4106 4107 }
4107 4108
4108 4109 if (inet_pton(AF_INET, part1, &in4) == 1)
4109 4110 return (Z_OK);
4110 4111
4111 4112 /* address may also be a host name */
4112 4113 if (!isalnum(part1[0])) {
4113 4114 zerr(gettext("%s: bogus host name or network address syntax"),
4114 4115 part1);
4115 4116 saw_error = B_TRUE;
4116 4117 usage(B_FALSE, HELP_NETADDR);
4117 4118 return (Z_ERR);
4118 4119 }
4119 4120 for (i = 1; part1[i]; i++)
4120 4121 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
4121 4122 zerr(gettext("%s: bogus host name or "
4122 4123 "network address syntax"), part1);
4123 4124 saw_error = B_TRUE;
4124 4125 usage(B_FALSE, HELP_NETADDR);
4125 4126 return (Z_ERR);
4126 4127 }
4127 4128 return (Z_OK);
4128 4129 }
4129 4130
4130 4131 static int
4131 4132 validate_net_physical_syntax(const char *ifname)
4132 4133 {
4133 4134 ifspec_t ifnameprop;
4134 4135 zone_iptype_t iptype;
4135 4136
4136 4137 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
4137 4138 zerr(gettext("zone configuration has an invalid or nonexistent "
4138 4139 "ip-type property"));
4139 4140 return (Z_ERR);
4140 4141 }
4141 4142 switch (iptype) {
4142 4143 case ZS_SHARED:
4143 4144 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
4144 4145 zerr(gettext("%s: invalid physical interface name"),
4145 4146 ifname);
4146 4147 return (Z_ERR);
4147 4148 }
4148 4149 if (ifnameprop.ifsp_lunvalid) {
4149 4150 zerr(gettext("%s: LUNs not allowed in physical "
4150 4151 "interface names"), ifname);
4151 4152 return (Z_ERR);
4152 4153 }
4153 4154 break;
4154 4155 case ZS_EXCLUSIVE:
4155 4156 if (dladm_valid_linkname(ifname) == B_FALSE) {
4156 4157 if (strchr(ifname, ':') != NULL)
4157 4158 zerr(gettext("%s: physical interface name "
4158 4159 "required; logical interface name not "
4159 4160 "allowed"), ifname);
4160 4161 else
4161 4162 zerr(gettext("%s: invalid physical interface "
4162 4163 "name"), ifname);
4163 4164 return (Z_ERR);
4164 4165 }
4165 4166 break;
4166 4167 }
4167 4168 return (Z_OK);
4168 4169 }
4169 4170
4170 4171 static boolean_t
4171 4172 valid_fs_type(const char *type)
4172 4173 {
4173 4174 /*
4174 4175 * Is this a valid path component?
4175 4176 */
4176 4177 if (strlen(type) + 1 > MAXNAMELEN)
4177 4178 return (B_FALSE);
4178 4179 /*
4179 4180 * Make sure a bad value for "type" doesn't make
4180 4181 * /usr/lib/fs/<type>/mount turn into something else.
4181 4182 */
4182 4183 if (strchr(type, '/') != NULL || type[0] == '\0' ||
4183 4184 strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4184 4185 return (B_FALSE);
4185 4186 /*
4186 4187 * More detailed verification happens later by zoneadm(1m).
4187 4188 */
4188 4189 return (B_TRUE);
4189 4190 }
4190 4191
4191 4192 static boolean_t
4192 4193 allow_exclusive()
4193 4194 {
4194 4195 brand_handle_t bh;
4195 4196 char brand[MAXNAMELEN];
4196 4197 boolean_t ret;
4197 4198
4198 4199 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4199 4200 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4200 4201 return (B_FALSE);
4201 4202 }
4202 4203 if ((bh = brand_open(brand)) == NULL) {
4203 4204 zerr("%s: %s\n", zone, gettext("unknown brand."));
4204 4205 return (B_FALSE);
4205 4206 }
4206 4207 ret = brand_allow_exclusive_ip(bh);
4207 4208 brand_close(bh);
4208 4209 if (!ret)
4209 4210 zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4210 4211 pt_to_str(PT_IPTYPE), "exclusive",
4211 4212 pt_to_str(PT_BRAND), brand);
4212 4213 return (ret);
4213 4214 }
4214 4215
4215 4216 static void
4216 4217 set_aliased_rctl(char *alias, int prop_type, char *s)
4217 4218 {
4218 4219 uint64_t limit;
4219 4220 int err;
4220 4221 char tmp[128];
4221 4222
4222 4223 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4223 4224 zerr(gettext("WARNING: Setting a global zone resource "
4224 4225 "control too low could deny\nservice "
4225 4226 "to even the root user; "
4226 4227 "this could render the system impossible\n"
4227 4228 "to administer. Please use caution."));
4228 4229
4229 4230 /* convert memory based properties */
4230 4231 if (prop_type == PT_MAXSHMMEM) {
4231 4232 if (!zonecfg_valid_memlimit(s, &limit)) {
4232 4233 zerr(gettext("A non-negative number with a required "
4233 4234 "scale suffix (K, M, G or T) was expected\nhere."));
4234 4235 saw_error = B_TRUE;
4235 4236 return;
4236 4237 }
4237 4238
4238 4239 (void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4239 4240 s = tmp;
4240 4241 }
4241 4242
4242 4243 if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4243 4244 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4244 4245 saw_error = B_TRUE;
4245 4246 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4246 4247 zerr(gettext("%s property is out of range."),
4247 4248 pt_to_str(prop_type));
4248 4249 saw_error = B_TRUE;
4249 4250 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4250 4251 != Z_OK) {
4251 4252 zone_perror(zone, err, B_TRUE);
4252 4253 saw_error = B_TRUE;
4253 4254 } else {
4254 4255 need_to_commit = B_TRUE;
4255 4256 }
4256 4257 }
4257 4258
4258 4259 static void
4259 4260 set_in_progress_nwiftab_address(char *prop_id, int prop_type)
4260 4261 {
4261 4262 if (prop_type == PT_ADDRESS) {
4262 4263 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
4263 4264 sizeof (in_progress_nwiftab.zone_nwif_address));
4264 4265 } else {
4265 4266 assert(prop_type == PT_ALLOWED_ADDRESS);
4266 4267 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
4267 4268 prop_id,
4268 4269 sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
4269 4270 }
4270 4271 }
4271 4272
4272 4273 void
4273 4274 set_func(cmd_t *cmd)
4274 4275 {
4275 4276 char *prop_id;
4276 4277 int arg, err, res_type, prop_type;
4277 4278 property_value_ptr_t pp;
4278 4279 boolean_t autoboot;
4279 4280 zone_iptype_t iptype;
4280 4281 boolean_t force_set = B_FALSE;
4281 4282 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4282 4283 uint64_t mem_cap, mem_limit;
4283 4284 float cap;
4284 4285 char *unitp;
4285 4286 struct zone_psettab tmp_psettab;
4286 4287 boolean_t arg_err = B_FALSE;
4287 4288
4288 4289 if (zone_is_read_only(CMD_SET))
4289 4290 return;
4290 4291
4291 4292 assert(cmd != NULL);
4292 4293
4293 4294 optind = opterr = 0;
4294 4295 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4295 4296 switch (arg) {
4296 4297 case 'F':
4297 4298 force_set = B_TRUE;
4298 4299 break;
4299 4300 default:
4300 4301 if (optopt == '?')
4301 4302 longer_usage(CMD_SET);
4302 4303 else
4303 4304 short_usage(CMD_SET);
4304 4305 arg_err = B_TRUE;
4305 4306 break;
4306 4307 }
4307 4308 }
4308 4309 if (arg_err)
4309 4310 return;
4310 4311
4311 4312 prop_type = cmd->cmd_prop_name[0];
4312 4313 if (global_scope) {
4313 4314 if (gz_invalid_property(prop_type)) {
4314 4315 zerr(gettext("%s is not a valid property for the "
4315 4316 "global zone."), pt_to_str(prop_type));
4316 4317 saw_error = B_TRUE;
4317 4318 return;
4318 4319 }
4319 4320
4320 4321 if (prop_type == PT_ZONENAME) {
4321 4322 res_type = RT_ZONENAME;
4322 4323 } else if (prop_type == PT_ZONEPATH) {
4323 4324 res_type = RT_ZONEPATH;
4324 4325 } else if (prop_type == PT_AUTOBOOT) {
4325 4326 res_type = RT_AUTOBOOT;
4326 4327 } else if (prop_type == PT_BRAND) {
4327 4328 res_type = RT_BRAND;
4328 4329 } else if (prop_type == PT_POOL) {
4329 4330 res_type = RT_POOL;
4330 4331 } else if (prop_type == PT_LIMITPRIV) {
4331 4332 res_type = RT_LIMITPRIV;
4332 4333 } else if (prop_type == PT_BOOTARGS) {
4333 4334 res_type = RT_BOOTARGS;
4334 4335 } else if (prop_type == PT_SCHED) {
4335 4336 res_type = RT_SCHED;
4336 4337 } else if (prop_type == PT_IPTYPE) {
4337 4338 res_type = RT_IPTYPE;
4338 4339 } else if (prop_type == PT_MAXLWPS) {
4339 4340 res_type = RT_MAXLWPS;
4340 4341 } else if (prop_type == PT_MAXPROCS) {
4341 4342 res_type = RT_MAXPROCS;
4342 4343 } else if (prop_type == PT_MAXSHMMEM) {
4343 4344 res_type = RT_MAXSHMMEM;
4344 4345 } else if (prop_type == PT_MAXSHMIDS) {
4345 4346 res_type = RT_MAXSHMIDS;
4346 4347 } else if (prop_type == PT_MAXMSGIDS) {
4347 4348 res_type = RT_MAXMSGIDS;
4348 4349 } else if (prop_type == PT_MAXSEMIDS) {
4349 4350 res_type = RT_MAXSEMIDS;
4350 4351 } else if (prop_type == PT_SHARES) {
4351 4352 res_type = RT_SHARES;
4352 4353 } else if (prop_type == PT_HOSTID) {
4353 4354 res_type = RT_HOSTID;
4354 4355 } else if (prop_type == PT_FS_ALLOWED) {
4355 4356 res_type = RT_FS_ALLOWED;
4356 4357 } else {
4357 4358 zerr(gettext("Cannot set a resource-specific property "
4358 4359 "from the global scope."));
4359 4360 saw_error = B_TRUE;
4360 4361 return;
4361 4362 }
4362 4363 } else {
4363 4364 res_type = resource_scope;
4364 4365 }
4365 4366
4366 4367 if (force_set) {
4367 4368 if (res_type != RT_ZONEPATH) {
4368 4369 zerr(gettext("Only zonepath setting can be forced."));
4369 4370 saw_error = B_TRUE;
4370 4371 return;
4371 4372 }
4372 4373 if (!zonecfg_in_alt_root()) {
4373 4374 zerr(gettext("Zonepath is changeable only in an "
4374 4375 "alternate root."));
4375 4376 saw_error = B_TRUE;
4376 4377 return;
4377 4378 }
4378 4379 }
4379 4380
4380 4381 pp = cmd->cmd_property_ptr[0];
4381 4382 /*
4382 4383 * A nasty expression but not that complicated:
4383 4384 * 1. fs options are simple or list (tested below)
4384 4385 * 2. rctl value's are complex or list (tested below)
4385 4386 * Anything else should be simple.
4386 4387 */
4387 4388 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4388 4389 !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4389 4390 (pp->pv_type != PROP_VAL_SIMPLE ||
4390 4391 (prop_id = pp->pv_simple) == NULL)) {
4391 4392 zerr(gettext("A %s value was expected here."),
4392 4393 pvt_to_str(PROP_VAL_SIMPLE));
4393 4394 saw_error = B_TRUE;
4394 4395 return;
4395 4396 }
4396 4397 if (prop_type == PT_UNKNOWN) {
4397 4398 long_usage(CMD_SET, B_TRUE);
4398 4399 return;
4399 4400 }
4400 4401
4401 4402 /*
4402 4403 * Special case: the user can change the zone name prior to 'create';
4403 4404 * if the zone already exists, we fall through letting initialize()
4404 4405 * and the rest of the logic run.
4405 4406 */
4406 4407 if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4407 4408 !state_atleast(ZONE_STATE_CONFIGURED)) {
4408 4409 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4409 4410 zone_perror(prop_id, err, B_TRUE);
4410 4411 usage(B_FALSE, HELP_SYNTAX);
4411 4412 return;
4412 4413 }
4413 4414 (void) strlcpy(zone, prop_id, sizeof (zone));
4414 4415 return;
4415 4416 }
4416 4417
4417 4418 if (initialize(B_TRUE) != Z_OK)
4418 4419 return;
4419 4420
4420 4421 switch (res_type) {
4421 4422 case RT_ZONENAME:
4422 4423 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4423 4424 /*
4424 4425 * Use prop_id instead of 'zone' here, since we're
4425 4426 * reporting a problem about the *new* zonename.
4426 4427 */
4427 4428 zone_perror(prop_id, err, B_TRUE);
4428 4429 usage(B_FALSE, HELP_SYNTAX);
4429 4430 } else {
4430 4431 need_to_commit = B_TRUE;
4431 4432 (void) strlcpy(zone, prop_id, sizeof (zone));
4432 4433 }
4433 4434 return;
4434 4435 case RT_ZONEPATH:
4435 4436 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4436 4437 zerr(gettext("Zone %s already installed; %s %s not "
4437 4438 "allowed."), zone, cmd_to_str(CMD_SET),
4438 4439 rt_to_str(RT_ZONEPATH));
4439 4440 return;
4440 4441 }
4441 4442 if (validate_zonepath_syntax(prop_id) != Z_OK) {
4442 4443 saw_error = B_TRUE;
4443 4444 return;
4444 4445 }
4445 4446 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4446 4447 zone_perror(zone, err, B_TRUE);
4447 4448 else
4448 4449 need_to_commit = B_TRUE;
4449 4450 return;
4450 4451 case RT_BRAND:
4451 4452 if (state_atleast(ZONE_STATE_INSTALLED)) {
4452 4453 zerr(gettext("Zone %s already installed; %s %s not "
4453 4454 "allowed."), zone, cmd_to_str(CMD_SET),
4454 4455 rt_to_str(RT_BRAND));
4455 4456 return;
4456 4457 }
4457 4458 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4458 4459 zone_perror(zone, err, B_TRUE);
4459 4460 else
4460 4461 need_to_commit = B_TRUE;
4461 4462 return;
4462 4463 case RT_AUTOBOOT:
4463 4464 if (strcmp(prop_id, "true") == 0) {
4464 4465 autoboot = B_TRUE;
4465 4466 } else if (strcmp(prop_id, "false") == 0) {
4466 4467 autoboot = B_FALSE;
4467 4468 } else {
4468 4469 zerr(gettext("%s value must be '%s' or '%s'."),
4469 4470 pt_to_str(PT_AUTOBOOT), "true", "false");
4470 4471 saw_error = B_TRUE;
4471 4472 return;
4472 4473 }
4473 4474 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4474 4475 zone_perror(zone, err, B_TRUE);
4475 4476 else
4476 4477 need_to_commit = B_TRUE;
4477 4478 return;
4478 4479 case RT_POOL:
4479 4480 /* don't allow use of the reserved temporary pool names */
4480 4481 if (strncmp("SUNW", prop_id, 4) == 0) {
4481 4482 zerr(gettext("pool names starting with SUNW are "
4482 4483 "reserved."));
4483 4484 saw_error = B_TRUE;
4484 4485 return;
4485 4486 }
4486 4487
4487 4488 /* can't set pool if dedicated-cpu exists */
4488 4489 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4489 4490 zerr(gettext("The %s resource already exists. "
4490 4491 "A persistent pool is incompatible\nwith the %s "
4491 4492 "resource."), rt_to_str(RT_DCPU),
4492 4493 rt_to_str(RT_DCPU));
4493 4494 saw_error = B_TRUE;
4494 4495 return;
4495 4496 }
4496 4497
4497 4498 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4498 4499 zone_perror(zone, err, B_TRUE);
4499 4500 else
4500 4501 need_to_commit = B_TRUE;
4501 4502 return;
4502 4503 case RT_LIMITPRIV:
4503 4504 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4504 4505 zone_perror(zone, err, B_TRUE);
4505 4506 else
4506 4507 need_to_commit = B_TRUE;
4507 4508 return;
4508 4509 case RT_BOOTARGS:
4509 4510 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4510 4511 zone_perror(zone, err, B_TRUE);
4511 4512 else
4512 4513 need_to_commit = B_TRUE;
4513 4514 return;
4514 4515 case RT_SCHED:
4515 4516 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4516 4517 zone_perror(zone, err, B_TRUE);
4517 4518 else
4518 4519 need_to_commit = B_TRUE;
4519 4520 return;
4520 4521 case RT_IPTYPE:
4521 4522 if (strcmp(prop_id, "shared") == 0) {
4522 4523 iptype = ZS_SHARED;
4523 4524 } else if (strcmp(prop_id, "exclusive") == 0) {
4524 4525 iptype = ZS_EXCLUSIVE;
4525 4526 } else {
4526 4527 zerr(gettext("%s value must be '%s' or '%s'."),
4527 4528 pt_to_str(PT_IPTYPE), "shared", "exclusive");
4528 4529 saw_error = B_TRUE;
4529 4530 return;
4530 4531 }
4531 4532 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4532 4533 saw_error = B_TRUE;
4533 4534 return;
4534 4535 }
4535 4536 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4536 4537 zone_perror(zone, err, B_TRUE);
4537 4538 else
4538 4539 need_to_commit = B_TRUE;
4539 4540 return;
4540 4541 case RT_MAXLWPS:
4541 4542 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4542 4543 return;
4543 4544 case RT_MAXPROCS:
4544 4545 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id);
4545 4546 return;
4546 4547 case RT_MAXSHMMEM:
4547 4548 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4548 4549 return;
4549 4550 case RT_MAXSHMIDS:
4550 4551 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4551 4552 return;
4552 4553 case RT_MAXMSGIDS:
4553 4554 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4554 4555 return;
4555 4556 case RT_MAXSEMIDS:
4556 4557 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4557 4558 return;
4558 4559 case RT_SHARES:
4559 4560 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4560 4561 return;
4561 4562 case RT_HOSTID:
4562 4563 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4563 4564 if (err == Z_TOO_BIG) {
4564 4565 zerr(gettext("hostid string is too large: %s"),
4565 4566 prop_id);
4566 4567 saw_error = B_TRUE;
4567 4568 } else {
4568 4569 zone_perror(pt_to_str(prop_type), err, B_TRUE);
4569 4570 }
4570 4571 return;
4571 4572 }
4572 4573 need_to_commit = B_TRUE;
4573 4574 return;
4574 4575 case RT_FS_ALLOWED:
4575 4576 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4576 4577 zone_perror(zone, err, B_TRUE);
4577 4578 else
4578 4579 need_to_commit = B_TRUE;
4579 4580 return;
4580 4581 case RT_FS:
4581 4582 switch (prop_type) {
4582 4583 case PT_DIR:
4583 4584 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4584 4585 sizeof (in_progress_fstab.zone_fs_dir));
4585 4586 return;
4586 4587 case PT_SPECIAL:
4587 4588 (void) strlcpy(in_progress_fstab.zone_fs_special,
4588 4589 prop_id,
4589 4590 sizeof (in_progress_fstab.zone_fs_special));
4590 4591 return;
4591 4592 case PT_RAW:
4592 4593 (void) strlcpy(in_progress_fstab.zone_fs_raw,
4593 4594 prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4594 4595 return;
4595 4596 case PT_TYPE:
4596 4597 if (!valid_fs_type(prop_id)) {
4597 4598 zerr(gettext("\"%s\" is not a valid %s."),
4598 4599 prop_id, pt_to_str(PT_TYPE));
4599 4600 saw_error = B_TRUE;
4600 4601 return;
4601 4602 }
4602 4603 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4603 4604 sizeof (in_progress_fstab.zone_fs_type));
4604 4605 return;
4605 4606 case PT_OPTIONS:
4606 4607 if (pp->pv_type != PROP_VAL_SIMPLE &&
4607 4608 pp->pv_type != PROP_VAL_LIST) {
4608 4609 zerr(gettext("A %s or %s value was expected "
4609 4610 "here."), pvt_to_str(PROP_VAL_SIMPLE),
4610 4611 pvt_to_str(PROP_VAL_LIST));
4611 4612 saw_error = B_TRUE;
4612 4613 return;
4613 4614 }
4614 4615 zonecfg_free_fs_option_list(
4615 4616 in_progress_fstab.zone_fs_options);
4616 4617 in_progress_fstab.zone_fs_options = NULL;
4617 4618 if (!(pp->pv_type == PROP_VAL_LIST &&
4618 4619 pp->pv_list == NULL))
4619 4620 add_property(cmd);
4620 4621 return;
4621 4622 default:
4622 4623 break;
4623 4624 }
4624 4625 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4625 4626 long_usage(CMD_SET, B_TRUE);
4626 4627 usage(B_FALSE, HELP_PROPS);
4627 4628 return;
4628 4629 case RT_NET:
4629 4630 switch (prop_type) {
4630 4631 case PT_ADDRESS:
4631 4632 case PT_ALLOWED_ADDRESS:
4632 4633 if (validate_net_address_syntax(prop_id, B_FALSE)
4633 4634 != Z_OK) {
4634 4635 saw_error = B_TRUE;
4635 4636 return;
4636 4637 }
4637 4638 set_in_progress_nwiftab_address(prop_id, prop_type);
4638 4639 break;
4639 4640 case PT_PHYSICAL:
4640 4641 if (validate_net_physical_syntax(prop_id) != Z_OK) {
4641 4642 saw_error = B_TRUE;
4642 4643 return;
4643 4644 }
4644 4645 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4645 4646 prop_id,
4646 4647 sizeof (in_progress_nwiftab.zone_nwif_physical));
4647 4648 break;
4648 4649 case PT_DEFROUTER:
4649 4650 if (validate_net_address_syntax(prop_id, B_TRUE)
4650 4651 != Z_OK) {
4651 4652 saw_error = B_TRUE;
4652 4653 return;
4653 4654 }
4654 4655 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4655 4656 prop_id,
4656 4657 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4657 4658 break;
4658 4659 default:
4659 4660 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4660 4661 B_TRUE);
4661 4662 long_usage(CMD_SET, B_TRUE);
4662 4663 usage(B_FALSE, HELP_PROPS);
4663 4664 return;
4664 4665 }
4665 4666 return;
4666 4667 case RT_DEVICE:
4667 4668 switch (prop_type) {
4668 4669 case PT_MATCH:
4669 4670 (void) strlcpy(in_progress_devtab.zone_dev_match,
4670 4671 prop_id,
4671 4672 sizeof (in_progress_devtab.zone_dev_match));
4672 4673 break;
4673 4674 default:
4674 4675 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4675 4676 B_TRUE);
4676 4677 long_usage(CMD_SET, B_TRUE);
4677 4678 usage(B_FALSE, HELP_PROPS);
4678 4679 return;
4679 4680 }
4680 4681 return;
4681 4682 case RT_RCTL:
4682 4683 switch (prop_type) {
4683 4684 case PT_NAME:
4684 4685 if (!zonecfg_valid_rctlname(prop_id)) {
4685 4686 zerr(gettext("'%s' is not a valid zone %s "
4686 4687 "name."), prop_id, rt_to_str(RT_RCTL));
4687 4688 return;
4688 4689 }
4689 4690 (void) strlcpy(in_progress_rctltab.zone_rctl_name,
4690 4691 prop_id,
4691 4692 sizeof (in_progress_rctltab.zone_rctl_name));
4692 4693 break;
4693 4694 case PT_VALUE:
4694 4695 if (pp->pv_type != PROP_VAL_COMPLEX &&
4695 4696 pp->pv_type != PROP_VAL_LIST) {
4696 4697 zerr(gettext("A %s or %s value was expected "
4697 4698 "here."), pvt_to_str(PROP_VAL_COMPLEX),
4698 4699 pvt_to_str(PROP_VAL_LIST));
4699 4700 saw_error = B_TRUE;
4700 4701 return;
4701 4702 }
4702 4703 zonecfg_free_rctl_value_list(
4703 4704 in_progress_rctltab.zone_rctl_valptr);
4704 4705 in_progress_rctltab.zone_rctl_valptr = NULL;
4705 4706 if (!(pp->pv_type == PROP_VAL_LIST &&
4706 4707 pp->pv_list == NULL))
4707 4708 add_property(cmd);
4708 4709 break;
4709 4710 default:
4710 4711 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4711 4712 B_TRUE);
4712 4713 long_usage(CMD_SET, B_TRUE);
4713 4714 usage(B_FALSE, HELP_PROPS);
4714 4715 return;
4715 4716 }
4716 4717 return;
4717 4718 case RT_ATTR:
4718 4719 switch (prop_type) {
4719 4720 case PT_NAME:
4720 4721 (void) strlcpy(in_progress_attrtab.zone_attr_name,
4721 4722 prop_id,
4722 4723 sizeof (in_progress_attrtab.zone_attr_name));
4723 4724 break;
4724 4725 case PT_TYPE:
4725 4726 (void) strlcpy(in_progress_attrtab.zone_attr_type,
4726 4727 prop_id,
4727 4728 sizeof (in_progress_attrtab.zone_attr_type));
4728 4729 break;
4729 4730 case PT_VALUE:
4730 4731 (void) strlcpy(in_progress_attrtab.zone_attr_value,
4731 4732 prop_id,
4732 4733 sizeof (in_progress_attrtab.zone_attr_value));
4733 4734 break;
4734 4735 default:
4735 4736 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4736 4737 B_TRUE);
4737 4738 long_usage(CMD_SET, B_TRUE);
4738 4739 usage(B_FALSE, HELP_PROPS);
4739 4740 return;
4740 4741 }
4741 4742 return;
4742 4743 case RT_DATASET:
4743 4744 switch (prop_type) {
4744 4745 case PT_NAME:
4745 4746 (void) strlcpy(in_progress_dstab.zone_dataset_name,
4746 4747 prop_id,
4747 4748 sizeof (in_progress_dstab.zone_dataset_name));
4748 4749 return;
4749 4750 default:
4750 4751 break;
4751 4752 }
4752 4753 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4753 4754 long_usage(CMD_SET, B_TRUE);
4754 4755 usage(B_FALSE, HELP_PROPS);
4755 4756 return;
4756 4757 case RT_DCPU:
4757 4758 switch (prop_type) {
4758 4759 char *lowp, *highp;
4759 4760
4760 4761 case PT_NCPUS:
4761 4762 lowp = prop_id;
4762 4763 if ((highp = strchr(prop_id, '-')) != NULL)
4763 4764 *highp++ = '\0';
4764 4765 else
4765 4766 highp = lowp;
4766 4767
4767 4768 /* Make sure the input makes sense. */
4768 4769 if (!zonecfg_valid_ncpus(lowp, highp)) {
4769 4770 zerr(gettext("%s property is out of range."),
4770 4771 pt_to_str(PT_NCPUS));
4771 4772 saw_error = B_TRUE;
4772 4773 return;
4773 4774 }
4774 4775
4775 4776 (void) strlcpy(
4776 4777 in_progress_psettab.zone_ncpu_min, lowp,
4777 4778 sizeof (in_progress_psettab.zone_ncpu_min));
4778 4779 (void) strlcpy(
4779 4780 in_progress_psettab.zone_ncpu_max, highp,
4780 4781 sizeof (in_progress_psettab.zone_ncpu_max));
4781 4782 return;
4782 4783 case PT_IMPORTANCE:
4783 4784 /* Make sure the value makes sense. */
4784 4785 if (!zonecfg_valid_importance(prop_id)) {
4785 4786 zerr(gettext("%s property is out of range."),
4786 4787 pt_to_str(PT_IMPORTANCE));
4787 4788 saw_error = B_TRUE;
4788 4789 return;
4789 4790 }
4790 4791
4791 4792 (void) strlcpy(in_progress_psettab.zone_importance,
4792 4793 prop_id,
4793 4794 sizeof (in_progress_psettab.zone_importance));
4794 4795 return;
4795 4796 default:
4796 4797 break;
4797 4798 }
4798 4799 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4799 4800 long_usage(CMD_SET, B_TRUE);
4800 4801 usage(B_FALSE, HELP_PROPS);
4801 4802 return;
4802 4803 case RT_PCAP:
4803 4804 if (prop_type != PT_NCPUS) {
4804 4805 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4805 4806 B_TRUE);
4806 4807 long_usage(CMD_SET, B_TRUE);
4807 4808 usage(B_FALSE, HELP_PROPS);
4808 4809 return;
4809 4810 }
4810 4811
4811 4812 /*
4812 4813 * We already checked that an rctl alias is allowed in
4813 4814 * the add_resource() function.
4814 4815 */
4815 4816
4816 4817 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4817 4818 (int)(cap * 100) < 1) {
4818 4819 zerr(gettext("%s property is out of range."),
4819 4820 pt_to_str(PT_NCPUS));
4820 4821 saw_error = B_TRUE;
4821 4822 return;
4822 4823 }
4823 4824
4824 4825 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4825 4826 (int)(cap * 100))) != Z_OK)
4826 4827 zone_perror(zone, err, B_TRUE);
4827 4828 else
4828 4829 need_to_commit = B_TRUE;
4829 4830 return;
4830 4831 case RT_MCAP:
4831 4832 switch (prop_type) {
4832 4833 case PT_PHYSICAL:
4833 4834 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4834 4835 zerr(gettext("A positive number with a "
4835 4836 "required scale suffix (K, M, G or T) was "
4836 4837 "expected here."));
4837 4838 saw_error = B_TRUE;
4838 4839 } else if (mem_cap < ONE_MB) {
4839 4840 zerr(gettext("%s value is too small. It must "
4840 4841 "be at least 1M."), pt_to_str(PT_PHYSICAL));
4841 4842 saw_error = B_TRUE;
4842 4843 } else {
4843 4844 snprintf(in_progress_mcaptab.zone_physmem_cap,
4844 4845 physmem_size, "%llu", mem_cap);
4845 4846 }
4846 4847 break;
4847 4848 case PT_SWAP:
4848 4849 /*
4849 4850 * We have to check if an rctl is allowed here since
4850 4851 * there might already be a rctl defined that blocks
4851 4852 * the alias.
4852 4853 */
4853 4854 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4854 4855 zone_perror(pt_to_str(PT_MAXSWAP),
4855 4856 Z_ALIAS_DISALLOW, B_FALSE);
4856 4857 saw_error = B_TRUE;
4857 4858 return;
4858 4859 }
4859 4860
4860 4861 if (global_zone)
4861 4862 mem_limit = ONE_MB * 100;
4862 4863 else
4863 4864 mem_limit = ONE_MB * 50;
4864 4865
4865 4866 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4866 4867 zerr(gettext("A positive number with a "
4867 4868 "required scale suffix (K, M, G or T) was "
4868 4869 "expected here."));
4869 4870 saw_error = B_TRUE;
4870 4871 } else if (mem_cap < mem_limit) {
4871 4872 char buf[128];
4872 4873
4873 4874 (void) snprintf(buf, sizeof (buf), "%llu",
4874 4875 mem_limit);
4875 4876 bytes_to_units(buf, buf, sizeof (buf));
4876 4877 zerr(gettext("%s value is too small. It must "
4877 4878 "be at least %s."), pt_to_str(PT_SWAP),
4878 4879 buf);
4879 4880 saw_error = B_TRUE;
4880 4881 } else {
4881 4882 if ((err = zonecfg_set_aliased_rctl(handle,
4882 4883 ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4883 4884 zone_perror(zone, err, B_TRUE);
4884 4885 else
4885 4886 need_to_commit = B_TRUE;
4886 4887 }
4887 4888 break;
4888 4889 case PT_LOCKED:
4889 4890 /*
4890 4891 * We have to check if an rctl is allowed here since
4891 4892 * there might already be a rctl defined that blocks
4892 4893 * the alias.
4893 4894 */
4894 4895 if (!zonecfg_aliased_rctl_ok(handle,
4895 4896 ALIAS_MAXLOCKEDMEM)) {
4896 4897 zone_perror(pt_to_str(PT_LOCKED),
4897 4898 Z_ALIAS_DISALLOW, B_FALSE);
4898 4899 saw_error = B_TRUE;
4899 4900 return;
4900 4901 }
4901 4902
4902 4903 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4903 4904 zerr(gettext("A non-negative number with a "
4904 4905 "required scale suffix (K, M, G or T) was "
4905 4906 "expected\nhere."));
4906 4907 saw_error = B_TRUE;
4907 4908 } else {
4908 4909 if ((err = zonecfg_set_aliased_rctl(handle,
4909 4910 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4910 4911 zone_perror(zone, err, B_TRUE);
4911 4912 else
4912 4913 need_to_commit = B_TRUE;
4913 4914 }
4914 4915 break;
4915 4916 default:
4916 4917 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4917 4918 B_TRUE);
4918 4919 long_usage(CMD_SET, B_TRUE);
4919 4920 usage(B_FALSE, HELP_PROPS);
4920 4921 return;
4921 4922 }
4922 4923 return;
4923 4924 case RT_ADMIN:
4924 4925 switch (prop_type) {
4925 4926 case PT_USER:
4926 4927 (void) strlcpy(in_progress_admintab.zone_admin_user,
4927 4928 prop_id,
4928 4929 sizeof (in_progress_admintab.zone_admin_user));
4929 4930 return;
4930 4931 case PT_AUTHS:
4931 4932 (void) strlcpy(in_progress_admintab.zone_admin_auths,
4932 4933 prop_id,
4933 4934 sizeof (in_progress_admintab.zone_admin_auths));
4934 4935 return;
4935 4936 default:
4936 4937 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4937 4938 B_TRUE);
4938 4939 long_usage(CMD_SET, B_TRUE);
4939 4940 usage(B_FALSE, HELP_PROPS);
4940 4941 return;
4941 4942 }
4942 4943 case RT_SECFLAGS: {
4943 4944 char *propstr;
4944 4945
4945 4946 switch (prop_type) {
4946 4947 case PT_DEFAULT:
4947 4948 propstr = in_progress_secflagstab.zone_secflags_default;
4948 4949 break;
4949 4950 case PT_UPPER:
4950 4951 propstr = in_progress_secflagstab.zone_secflags_upper;
4951 4952 break;
4952 4953 case PT_LOWER:
4953 4954 propstr = in_progress_secflagstab.zone_secflags_lower;
4954 4955 break;
4955 4956 default:
4956 4957 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4957 4958 B_TRUE);
4958 4959 long_usage(CMD_SET, B_TRUE);
4959 4960 usage(B_FALSE, HELP_PROPS);
4960 4961 return;
4961 4962 }
4962 4963 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
4963 4964 return;
4964 4965 }
4965 4966 default:
4966 4967 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4967 4968 long_usage(CMD_SET, B_TRUE);
4968 4969 usage(B_FALSE, HELP_RESOURCES);
4969 4970 return;
4970 4971 }
4971 4972 }
4972 4973
4973 4974 static void
4974 4975 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4975 4976 {
4976 4977 char *qstr;
4977 4978
4978 4979 if (*pval != '\0') {
4979 4980 qstr = quoteit(pval);
4980 4981 if (pnum == PT_SWAP || pnum == PT_LOCKED)
4981 4982 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4982 4983 qstr);
4983 4984 else
4984 4985 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4985 4986 free(qstr);
4986 4987 } else if (print_notspec)
4987 4988 (void) fprintf(fp, gettext("\t%s not specified\n"),
4988 4989 pt_to_str(pnum));
4989 4990 }
4990 4991
4991 4992 static void
4992 4993 info_zonename(zone_dochandle_t handle, FILE *fp)
4993 4994 {
4994 4995 char zonename[ZONENAME_MAX];
4995 4996
4996 4997 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4997 4998 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4998 4999 zonename);
4999 5000 else
5000 5001 (void) fprintf(fp, gettext("%s not specified\n"),
5001 5002 pt_to_str(PT_ZONENAME));
5002 5003 }
5003 5004
5004 5005 static void
5005 5006 info_zonepath(zone_dochandle_t handle, FILE *fp)
5006 5007 {
5007 5008 char zonepath[MAXPATHLEN];
5008 5009
5009 5010 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
5010 5011 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
5011 5012 zonepath);
5012 5013 else {
5013 5014 (void) fprintf(fp, gettext("%s not specified\n"),
5014 5015 pt_to_str(PT_ZONEPATH));
5015 5016 }
5016 5017 }
5017 5018
5018 5019 static void
5019 5020 info_brand(zone_dochandle_t handle, FILE *fp)
5020 5021 {
5021 5022 char brand[MAXNAMELEN];
5022 5023
5023 5024 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
5024 5025 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
5025 5026 brand);
5026 5027 else
5027 5028 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
5028 5029 gettext("not specified"));
5029 5030 }
5030 5031
5031 5032 static void
5032 5033 info_autoboot(zone_dochandle_t handle, FILE *fp)
5033 5034 {
5034 5035 boolean_t autoboot;
5035 5036 int err;
5036 5037
5037 5038 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
5038 5039 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
5039 5040 autoboot ? "true" : "false");
5040 5041 else
5041 5042 zone_perror(zone, err, B_TRUE);
5042 5043 }
5043 5044
5044 5045 static void
5045 5046 info_pool(zone_dochandle_t handle, FILE *fp)
5046 5047 {
5047 5048 char pool[MAXNAMELEN];
5048 5049 int err;
5049 5050
5050 5051 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
5051 5052 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
5052 5053 else
5053 5054 zone_perror(zone, err, B_TRUE);
5054 5055 }
5055 5056
5056 5057 static void
5057 5058 info_limitpriv(zone_dochandle_t handle, FILE *fp)
5058 5059 {
5059 5060 char *limitpriv;
5060 5061 int err;
5061 5062
5062 5063 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
5063 5064 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
5064 5065 limitpriv);
5065 5066 free(limitpriv);
5066 5067 } else {
5067 5068 zone_perror(zone, err, B_TRUE);
5068 5069 }
5069 5070 }
5070 5071
5071 5072 static void
5072 5073 info_bootargs(zone_dochandle_t handle, FILE *fp)
5073 5074 {
5074 5075 char bootargs[BOOTARGS_MAX];
5075 5076 int err;
5076 5077
5077 5078 if ((err = zonecfg_get_bootargs(handle, bootargs,
5078 5079 sizeof (bootargs))) == Z_OK) {
5079 5080 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
5080 5081 bootargs);
5081 5082 } else {
5082 5083 zone_perror(zone, err, B_TRUE);
5083 5084 }
5084 5085 }
5085 5086
5086 5087 static void
5087 5088 info_sched(zone_dochandle_t handle, FILE *fp)
5088 5089 {
5089 5090 char sched[MAXNAMELEN];
5090 5091 int err;
5091 5092
5092 5093 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
5093 5094 == Z_OK) {
5094 5095 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
5095 5096 } else {
5096 5097 zone_perror(zone, err, B_TRUE);
5097 5098 }
5098 5099 }
5099 5100
5100 5101 static void
5101 5102 info_iptype(zone_dochandle_t handle, FILE *fp)
5102 5103 {
5103 5104 zone_iptype_t iptype;
5104 5105 int err;
5105 5106
5106 5107 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
5107 5108 switch (iptype) {
5108 5109 case ZS_SHARED:
5109 5110 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5110 5111 "shared");
5111 5112 break;
5112 5113 case ZS_EXCLUSIVE:
5113 5114 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5114 5115 "exclusive");
5115 5116 break;
5116 5117 }
5117 5118 } else {
5118 5119 zone_perror(zone, err, B_TRUE);
5119 5120 }
5120 5121 }
5121 5122
5122 5123 static void
5123 5124 info_hostid(zone_dochandle_t handle, FILE *fp)
5124 5125 {
5125 5126 char hostidp[HW_HOSTID_LEN];
5126 5127 int err;
5127 5128
5128 5129 if ((err = zonecfg_get_hostid(handle, hostidp,
5129 5130 sizeof (hostidp))) == Z_OK) {
5130 5131 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
5131 5132 } else if (err == Z_BAD_PROPERTY) {
5132 5133 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
5133 5134 } else {
5134 5135 zone_perror(zone, err, B_TRUE);
5135 5136 }
5136 5137 }
5137 5138
5138 5139 static void
5139 5140 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
5140 5141 {
5141 5142 char fsallowedp[ZONE_FS_ALLOWED_MAX];
5142 5143 int err;
5143 5144
5144 5145 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
5145 5146 sizeof (fsallowedp))) == Z_OK) {
5146 5147 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
5147 5148 fsallowedp);
5148 5149 } else if (err == Z_BAD_PROPERTY) {
5149 5150 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
5150 5151 } else {
5151 5152 zone_perror(zone, err, B_TRUE);
5152 5153 }
5153 5154 }
5154 5155
5155 5156 static void
5156 5157 output_fs(FILE *fp, struct zone_fstab *fstab)
5157 5158 {
5158 5159 zone_fsopt_t *this;
5159 5160
5160 5161 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
5161 5162 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
5162 5163 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
5163 5164 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
5164 5165 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
5165 5166 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
5166 5167 for (this = fstab->zone_fs_options; this != NULL;
5167 5168 this = this->zone_fsopt_next) {
5168 5169 if (strchr(this->zone_fsopt_opt, '='))
5169 5170 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
5170 5171 else
5171 5172 (void) fprintf(fp, "%s", this->zone_fsopt_opt);
5172 5173 if (this->zone_fsopt_next != NULL)
5173 5174 (void) fprintf(fp, ",");
5174 5175 }
5175 5176 (void) fprintf(fp, "]\n");
5176 5177 }
5177 5178
5178 5179 static void
5179 5180 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5180 5181 {
5181 5182 struct zone_fstab lookup, user;
5182 5183 boolean_t output = B_FALSE;
5183 5184
5184 5185 if (zonecfg_setfsent(handle) != Z_OK)
5185 5186 return;
5186 5187 while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
5187 5188 if (cmd->cmd_prop_nv_pairs == 0) {
5188 5189 output_fs(fp, &lookup);
5189 5190 goto loopend;
5190 5191 }
5191 5192 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
5192 5193 goto loopend;
5193 5194 if (strlen(user.zone_fs_dir) > 0 &&
5194 5195 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5195 5196 goto loopend; /* no match */
5196 5197 if (strlen(user.zone_fs_special) > 0 &&
5197 5198 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5198 5199 goto loopend; /* no match */
5199 5200 if (strlen(user.zone_fs_type) > 0 &&
5200 5201 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5201 5202 goto loopend; /* no match */
5202 5203 output_fs(fp, &lookup);
5203 5204 output = B_TRUE;
5204 5205 loopend:
5205 5206 zonecfg_free_fs_option_list(lookup.zone_fs_options);
5206 5207 }
5207 5208 (void) zonecfg_endfsent(handle);
5208 5209 /*
5209 5210 * If a property n/v pair was specified, warn the user if there was
5210 5211 * nothing to output.
5211 5212 */
5212 5213 if (!output && cmd->cmd_prop_nv_pairs > 0)
5213 5214 (void) printf(gettext("No such %s resource.\n"),
5214 5215 rt_to_str(RT_FS));
5215 5216 }
5216 5217
5217 5218 static void
5218 5219 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5219 5220 {
5220 5221 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5221 5222 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5222 5223 output_prop(fp, PT_ALLOWED_ADDRESS,
5223 5224 nwiftab->zone_nwif_allowed_address, B_TRUE);
5224 5225 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5225 5226 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5226 5227 }
5227 5228
5228 5229 static void
5229 5230 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5230 5231 {
5231 5232 struct zone_nwiftab lookup, user;
5232 5233 boolean_t output = B_FALSE;
5233 5234
5234 5235 if (zonecfg_setnwifent(handle) != Z_OK)
5235 5236 return;
5236 5237 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5237 5238 if (cmd->cmd_prop_nv_pairs == 0) {
5238 5239 output_net(fp, &lookup);
5239 5240 continue;
5240 5241 }
5241 5242 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5242 5243 continue;
5243 5244 if (strlen(user.zone_nwif_physical) > 0 &&
5244 5245 strcmp(user.zone_nwif_physical,
5245 5246 lookup.zone_nwif_physical) != 0)
5246 5247 continue; /* no match */
5247 5248 /* If present make sure it matches */
5248 5249 if (strlen(user.zone_nwif_address) > 0 &&
5249 5250 !zonecfg_same_net_address(user.zone_nwif_address,
5250 5251 lookup.zone_nwif_address))
5251 5252 continue; /* no match */
5252 5253 output_net(fp, &lookup);
5253 5254 output = B_TRUE;
5254 5255 }
5255 5256 (void) zonecfg_endnwifent(handle);
5256 5257 /*
5257 5258 * If a property n/v pair was specified, warn the user if there was
5258 5259 * nothing to output.
5259 5260 */
5260 5261 if (!output && cmd->cmd_prop_nv_pairs > 0)
5261 5262 (void) printf(gettext("No such %s resource.\n"),
5262 5263 rt_to_str(RT_NET));
5263 5264 }
5264 5265
5265 5266 static void
5266 5267 output_dev(FILE *fp, struct zone_devtab *devtab)
5267 5268 {
5268 5269 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5269 5270 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5270 5271 }
5271 5272
5272 5273 static void
5273 5274 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5274 5275 {
5275 5276 struct zone_devtab lookup, user;
5276 5277 boolean_t output = B_FALSE;
5277 5278
5278 5279 if (zonecfg_setdevent(handle) != Z_OK)
5279 5280 return;
5280 5281 while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5281 5282 if (cmd->cmd_prop_nv_pairs == 0) {
5282 5283 output_dev(fp, &lookup);
5283 5284 continue;
5284 5285 }
5285 5286 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5286 5287 continue;
5287 5288 if (strlen(user.zone_dev_match) > 0 &&
5288 5289 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5289 5290 continue; /* no match */
5290 5291 output_dev(fp, &lookup);
5291 5292 output = B_TRUE;
5292 5293 }
5293 5294 (void) zonecfg_enddevent(handle);
5294 5295 /*
5295 5296 * If a property n/v pair was specified, warn the user if there was
5296 5297 * nothing to output.
5297 5298 */
5298 5299 if (!output && cmd->cmd_prop_nv_pairs > 0)
5299 5300 (void) printf(gettext("No such %s resource.\n"),
5300 5301 rt_to_str(RT_DEVICE));
5301 5302 }
5302 5303
5303 5304 static void
5304 5305 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5305 5306 {
5306 5307 struct zone_rctlvaltab *valptr;
5307 5308
5308 5309 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5309 5310 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5310 5311 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5311 5312 valptr = valptr->zone_rctlval_next) {
5312 5313 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5313 5314 pt_to_str(PT_VALUE),
5314 5315 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5315 5316 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5316 5317 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5317 5318 }
5318 5319 }
5319 5320
5320 5321 static void
5321 5322 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5322 5323 {
5323 5324 struct zone_rctltab lookup, user;
5324 5325 boolean_t output = B_FALSE;
5325 5326
5326 5327 if (zonecfg_setrctlent(handle) != Z_OK)
5327 5328 return;
5328 5329 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5329 5330 if (cmd->cmd_prop_nv_pairs == 0) {
5330 5331 output_rctl(fp, &lookup);
5331 5332 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5332 5333 (strlen(user.zone_rctl_name) == 0 ||
5333 5334 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5334 5335 output_rctl(fp, &lookup);
5335 5336 output = B_TRUE;
5336 5337 }
5337 5338 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5338 5339 }
5339 5340 (void) zonecfg_endrctlent(handle);
5340 5341 /*
5341 5342 * If a property n/v pair was specified, warn the user if there was
5342 5343 * nothing to output.
5343 5344 */
5344 5345 if (!output && cmd->cmd_prop_nv_pairs > 0)
5345 5346 (void) printf(gettext("No such %s resource.\n"),
5346 5347 rt_to_str(RT_RCTL));
5347 5348 }
5348 5349
5349 5350 static void
5350 5351 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5351 5352 {
5352 5353 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5353 5354 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5354 5355 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5355 5356 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5356 5357 }
5357 5358
5358 5359 static void
5359 5360 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5360 5361 {
5361 5362 struct zone_attrtab lookup, user;
5362 5363 boolean_t output = B_FALSE;
5363 5364
5364 5365 if (zonecfg_setattrent(handle) != Z_OK)
5365 5366 return;
5366 5367 while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5367 5368 if (cmd->cmd_prop_nv_pairs == 0) {
5368 5369 output_attr(fp, &lookup);
5369 5370 continue;
5370 5371 }
5371 5372 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5372 5373 continue;
5373 5374 if (strlen(user.zone_attr_name) > 0 &&
5374 5375 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5375 5376 continue; /* no match */
5376 5377 if (strlen(user.zone_attr_type) > 0 &&
5377 5378 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5378 5379 continue; /* no match */
5379 5380 if (strlen(user.zone_attr_value) > 0 &&
5380 5381 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5381 5382 continue; /* no match */
5382 5383 output_attr(fp, &lookup);
5383 5384 output = B_TRUE;
5384 5385 }
5385 5386 (void) zonecfg_endattrent(handle);
5386 5387 /*
5387 5388 * If a property n/v pair was specified, warn the user if there was
5388 5389 * nothing to output.
5389 5390 */
5390 5391 if (!output && cmd->cmd_prop_nv_pairs > 0)
5391 5392 (void) printf(gettext("No such %s resource.\n"),
5392 5393 rt_to_str(RT_ATTR));
5393 5394 }
5394 5395
5395 5396 static void
5396 5397 output_ds(FILE *fp, struct zone_dstab *dstab)
5397 5398 {
5398 5399 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5399 5400 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5400 5401 }
5401 5402
5402 5403 static void
5403 5404 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5404 5405 {
5405 5406 struct zone_dstab lookup, user;
5406 5407 boolean_t output = B_FALSE;
5407 5408
5408 5409 if (zonecfg_setdsent(handle) != Z_OK)
5409 5410 return;
5410 5411 while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5411 5412 if (cmd->cmd_prop_nv_pairs == 0) {
5412 5413 output_ds(fp, &lookup);
5413 5414 continue;
5414 5415 }
5415 5416 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5416 5417 continue;
5417 5418 if (strlen(user.zone_dataset_name) > 0 &&
5418 5419 strcmp(user.zone_dataset_name,
5419 5420 lookup.zone_dataset_name) != 0)
5420 5421 continue; /* no match */
5421 5422 output_ds(fp, &lookup);
5422 5423 output = B_TRUE;
5423 5424 }
5424 5425 (void) zonecfg_enddsent(handle);
5425 5426 /*
5426 5427 * If a property n/v pair was specified, warn the user if there was
5427 5428 * nothing to output.
5428 5429 */
5429 5430 if (!output && cmd->cmd_prop_nv_pairs > 0)
5430 5431 (void) printf(gettext("No such %s resource.\n"),
5431 5432 rt_to_str(RT_DATASET));
5432 5433 }
5433 5434
5434 5435 static void
5435 5436 output_pset(FILE *fp, struct zone_psettab *psettab)
5436 5437 {
5437 5438 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5438 5439 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5439 5440 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5440 5441 psettab->zone_ncpu_max);
5441 5442 else
5442 5443 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5443 5444 psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5444 5445 if (psettab->zone_importance[0] != '\0')
5445 5446 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5446 5447 psettab->zone_importance);
5447 5448 }
5448 5449
5449 5450 static void
5450 5451 info_pset(zone_dochandle_t handle, FILE *fp)
5451 5452 {
5452 5453 struct zone_psettab lookup;
5453 5454
5454 5455 if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5455 5456 output_pset(fp, &lookup);
5456 5457 }
5457 5458
5458 5459 static void
5459 5460 output_pcap(FILE *fp)
5460 5461 {
5461 5462 uint64_t cap;
5462 5463
5463 5464 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5464 5465 float scaled = (float)cap / 100;
5465 5466 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5466 5467 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5467 5468 scaled);
5468 5469 }
5469 5470 }
5470 5471
5471 5472 static void
5472 5473 info_pcap(FILE *fp)
5473 5474 {
5474 5475 output_pcap(fp);
5475 5476 }
5476 5477
5477 5478
5478 5479 static void
5479 5480 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5480 5481 {
5481 5482 uint64_t limit;
5482 5483
5483 5484 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5484 5485 /* convert memory based properties */
5485 5486 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5486 5487 char buf[128];
5487 5488
5488 5489 (void) snprintf(buf, sizeof (buf), "%llu", limit);
5489 5490 bytes_to_units(buf, buf, sizeof (buf));
5490 5491 (void) fprintf(fp, "[%s: %s]\n", alias, buf);
5491 5492 return;
5492 5493 }
5493 5494
5494 5495 (void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5495 5496 }
5496 5497 }
5497 5498
5498 5499 static void
5499 5500 bytes_to_units(char *str, char *buf, int bufsize)
5500 5501 {
5501 5502 unsigned long long num;
5502 5503 unsigned long long save = 0;
5503 5504 char *units = "BKMGT";
5504 5505 char *up = units;
5505 5506
5506 5507 num = strtoll(str, NULL, 10);
5507 5508
5508 5509 if (num < 1024) {
5509 5510 (void) snprintf(buf, bufsize, "%llu", num);
5510 5511 return;
5511 5512 }
5512 5513
5513 5514 while ((num >= 1024) && (*up != 'T')) {
5514 5515 up++; /* next unit of measurement */
5515 5516 save = num;
5516 5517 num = (num + 512) >> 10;
5517 5518 }
5518 5519
5519 5520 /* check if we should output a fraction. snprintf will round for us */
5520 5521 if (save % 1024 != 0 && ((save >> 10) < 10))
5521 5522 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5522 5523 *up);
5523 5524 else
5524 5525 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
5525 5526 }
5526 5527
5527 5528 static void
5528 5529 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5529 5530 uint64_t maxswap, int showlocked, uint64_t maxlocked)
5530 5531 {
5531 5532 char buf[128];
5532 5533
5533 5534 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5534 5535 if (mcaptab->zone_physmem_cap[0] != '\0') {
5535 5536 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5536 5537 output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5537 5538 }
5538 5539
5539 5540 if (showswap == Z_OK) {
5540 5541 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5541 5542 bytes_to_units(buf, buf, sizeof (buf));
5542 5543 output_prop(fp, PT_SWAP, buf, B_TRUE);
5543 5544 }
5544 5545
5545 5546 if (showlocked == Z_OK) {
5546 5547 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5547 5548 bytes_to_units(buf, buf, sizeof (buf));
5548 5549 output_prop(fp, PT_LOCKED, buf, B_TRUE);
5549 5550 }
5550 5551 }
5551 5552
5552 5553 static void
5553 5554 info_mcap(zone_dochandle_t handle, FILE *fp)
5554 5555 {
5555 5556 int res1, res2, res3;
5556 5557 uint64_t swap_limit;
5557 5558 uint64_t locked_limit;
5558 5559 struct zone_mcaptab lookup;
5559 5560
5560 5561 bzero(&lookup, sizeof (lookup));
5561 5562 res1 = zonecfg_getmcapent(handle, &lookup);
5562 5563 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5563 5564 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5564 5565 &locked_limit);
5565 5566
5566 5567 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5567 5568 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5568 5569 }
5569 5570
5570 5571 static void
5571 5572 output_auth(FILE *fp, struct zone_admintab *admintab)
5572 5573 {
5573 5574 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5574 5575 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5575 5576 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5576 5577 }
5577 5578
5578 5579 static void
5579 5580 output_secflags(FILE *fp, struct zone_secflagstab *sftab)
5580 5581 {
5581 5582 (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
5582 5583 output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
5583 5584 output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
5584 5585 output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
5585 5586 }
5586 5587
5587 5588 static void
5588 5589 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5589 5590 {
5590 5591 struct zone_admintab lookup, user;
5591 5592 boolean_t output = B_FALSE;
5592 5593 int err;
5593 5594
5594 5595 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5595 5596 zone_perror(zone, err, B_TRUE);
5596 5597 return;
5597 5598 }
5598 5599 while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5599 5600 if (cmd->cmd_prop_nv_pairs == 0) {
5600 5601 output_auth(fp, &lookup);
5601 5602 continue;
5602 5603 }
5603 5604 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5604 5605 continue;
5605 5606 if (strlen(user.zone_admin_user) > 0 &&
5606 5607 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5607 5608 continue; /* no match */
5608 5609 output_auth(fp, &lookup);
5609 5610 output = B_TRUE;
5610 5611 }
5611 5612 (void) zonecfg_endadminent(handle);
5612 5613 /*
5613 5614 * If a property n/v pair was specified, warn the user if there was
5614 5615 * nothing to output.
5615 5616 */
5616 5617 if (!output && cmd->cmd_prop_nv_pairs > 0)
5617 5618 (void) printf(gettext("No such %s resource.\n"),
5618 5619 rt_to_str(RT_ADMIN));
5619 5620 }
5620 5621
5621 5622 static void
5622 5623 info_secflags(zone_dochandle_t handle, FILE *fp)
5623 5624 {
5624 5625 struct zone_secflagstab sftab;
5625 5626
5626 5627 if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) {
5627 5628 output_secflags(fp, &sftab);
5628 5629 }
5629 5630 }
5630 5631
5631 5632 void
5632 5633 info_func(cmd_t *cmd)
5633 5634 {
5634 5635 FILE *fp = stdout;
5635 5636 boolean_t need_to_close = B_FALSE;
5636 5637 int type;
5637 5638 int res1, res2;
5638 5639 uint64_t swap_limit;
5639 5640 uint64_t locked_limit;
5640 5641
5641 5642 assert(cmd != NULL);
5642 5643
5643 5644 if (initialize(B_TRUE) != Z_OK)
5644 5645 return;
5645 5646
5646 5647 /* don't page error output */
5647 5648 if (interactive_mode) {
5648 5649 if ((fp = pager_open()) != NULL)
5649 5650 need_to_close = B_TRUE;
5650 5651 else
5651 5652 fp = stdout;
5652 5653
5653 5654 setbuf(fp, NULL);
5654 5655 }
5655 5656
5656 5657 if (!global_scope) {
5657 5658 switch (resource_scope) {
5658 5659 case RT_FS:
5659 5660 output_fs(fp, &in_progress_fstab);
5660 5661 break;
5661 5662 case RT_NET:
5662 5663 output_net(fp, &in_progress_nwiftab);
5663 5664 break;
5664 5665 case RT_DEVICE:
5665 5666 output_dev(fp, &in_progress_devtab);
5666 5667 break;
5667 5668 case RT_RCTL:
5668 5669 output_rctl(fp, &in_progress_rctltab);
5669 5670 break;
5670 5671 case RT_ATTR:
5671 5672 output_attr(fp, &in_progress_attrtab);
5672 5673 break;
5673 5674 case RT_DATASET:
5674 5675 output_ds(fp, &in_progress_dstab);
5675 5676 break;
5676 5677 case RT_DCPU:
5677 5678 output_pset(fp, &in_progress_psettab);
5678 5679 break;
5679 5680 case RT_PCAP:
5680 5681 output_pcap(fp);
5681 5682 break;
5682 5683 case RT_MCAP:
5683 5684 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5684 5685 &swap_limit);
5685 5686 res2 = zonecfg_get_aliased_rctl(handle,
5686 5687 ALIAS_MAXLOCKEDMEM, &locked_limit);
5687 5688 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5688 5689 res2, locked_limit);
5689 5690 break;
5690 5691 case RT_ADMIN:
5691 5692 output_auth(fp, &in_progress_admintab);
5692 5693 break;
5693 5694 case RT_SECFLAGS:
5694 5695 output_secflags(fp, &in_progress_secflagstab);
5695 5696 break;
5696 5697 }
5697 5698 goto cleanup;
5698 5699 }
5699 5700
5700 5701 type = cmd->cmd_res_type;
5701 5702
5702 5703 if (gz_invalid_rt_property(type)) {
5703 5704 zerr(gettext("%s is not a valid property for the global zone."),
5704 5705 rt_to_str(type));
5705 5706 goto cleanup;
5706 5707 }
5707 5708
5708 5709 if (gz_invalid_resource(type)) {
5709 5710 zerr(gettext("%s is not a valid resource for the global zone."),
5710 5711 rt_to_str(type));
5711 5712 goto cleanup;
5712 5713 }
5713 5714
5714 5715 switch (cmd->cmd_res_type) {
5715 5716 case RT_UNKNOWN:
5716 5717 info_zonename(handle, fp);
5717 5718 if (!global_zone) {
5718 5719 info_zonepath(handle, fp);
5719 5720 info_brand(handle, fp);
5720 5721 info_autoboot(handle, fp);
5721 5722 info_bootargs(handle, fp);
5722 5723 }
5723 5724 info_pool(handle, fp);
5724 5725 if (!global_zone) {
5725 5726 info_limitpriv(handle, fp);
5726 5727 info_sched(handle, fp);
5727 5728 info_iptype(handle, fp);
5728 5729 info_hostid(handle, fp);
5729 5730 info_fs_allowed(handle, fp);
5730 5731 }
5731 5732 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5732 5733 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5733 5734 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5734 5735 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5735 5736 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5736 5737 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5737 5738 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5738 5739 if (!global_zone) {
5739 5740 info_fs(handle, fp, cmd);
5740 5741 info_net(handle, fp, cmd);
5741 5742 info_dev(handle, fp, cmd);
5742 5743 }
5743 5744 info_pset(handle, fp);
5744 5745 info_pcap(fp);
5745 5746 info_mcap(handle, fp);
5746 5747 if (!global_zone) {
5747 5748 info_attr(handle, fp, cmd);
5748 5749 info_ds(handle, fp, cmd);
5749 5750 info_auth(handle, fp, cmd);
5750 5751 }
5751 5752 info_rctl(handle, fp, cmd);
5752 5753 info_secflags(handle, fp);
5753 5754 break;
5754 5755 case RT_ZONENAME:
5755 5756 info_zonename(handle, fp);
5756 5757 break;
5757 5758 case RT_ZONEPATH:
5758 5759 info_zonepath(handle, fp);
5759 5760 break;
5760 5761 case RT_BRAND:
5761 5762 info_brand(handle, fp);
5762 5763 break;
5763 5764 case RT_AUTOBOOT:
5764 5765 info_autoboot(handle, fp);
5765 5766 break;
5766 5767 case RT_POOL:
5767 5768 info_pool(handle, fp);
5768 5769 break;
5769 5770 case RT_LIMITPRIV:
5770 5771 info_limitpriv(handle, fp);
5771 5772 break;
5772 5773 case RT_BOOTARGS:
5773 5774 info_bootargs(handle, fp);
5774 5775 break;
5775 5776 case RT_SCHED:
5776 5777 info_sched(handle, fp);
5777 5778 break;
5778 5779 case RT_IPTYPE:
5779 5780 info_iptype(handle, fp);
5780 5781 break;
5781 5782 case RT_MAXLWPS:
5782 5783 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5783 5784 break;
5784 5785 case RT_MAXPROCS:
5785 5786 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5786 5787 break;
5787 5788 case RT_MAXSHMMEM:
5788 5789 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5789 5790 break;
5790 5791 case RT_MAXSHMIDS:
5791 5792 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5792 5793 break;
5793 5794 case RT_MAXMSGIDS:
5794 5795 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5795 5796 break;
5796 5797 case RT_MAXSEMIDS:
5797 5798 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5798 5799 break;
5799 5800 case RT_SHARES:
5800 5801 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5801 5802 break;
5802 5803 case RT_FS:
5803 5804 info_fs(handle, fp, cmd);
5804 5805 break;
5805 5806 case RT_NET:
5806 5807 info_net(handle, fp, cmd);
5807 5808 break;
5808 5809 case RT_DEVICE:
5809 5810 info_dev(handle, fp, cmd);
5810 5811 break;
5811 5812 case RT_RCTL:
5812 5813 info_rctl(handle, fp, cmd);
5813 5814 break;
5814 5815 case RT_ATTR:
5815 5816 info_attr(handle, fp, cmd);
5816 5817 break;
5817 5818 case RT_DATASET:
5818 5819 info_ds(handle, fp, cmd);
5819 5820 break;
5820 5821 case RT_DCPU:
5821 5822 info_pset(handle, fp);
5822 5823 break;
5823 5824 case RT_PCAP:
5824 5825 info_pcap(fp);
5825 5826 break;
5826 5827 case RT_MCAP:
5827 5828 info_mcap(handle, fp);
5828 5829 break;
5829 5830 case RT_HOSTID:
5830 5831 info_hostid(handle, fp);
5831 5832 break;
5832 5833 case RT_ADMIN:
5833 5834 info_auth(handle, fp, cmd);
5834 5835 break;
5835 5836 case RT_FS_ALLOWED:
5836 5837 info_fs_allowed(handle, fp);
5837 5838 break;
5838 5839 case RT_SECFLAGS:
5839 5840 info_secflags(handle, fp);
5840 5841 break;
5841 5842 default:
5842 5843 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5843 5844 B_TRUE);
5844 5845 }
5845 5846
5846 5847 cleanup:
5847 5848 if (need_to_close)
5848 5849 (void) pager_close(fp);
5849 5850 }
5850 5851
5851 5852 /*
5852 5853 * Helper function for verify-- checks that a required string property
5853 5854 * exists.
5854 5855 */
5855 5856 static void
5856 5857 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5857 5858 {
5858 5859 if (strlen(attr) == 0) {
5859 5860 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5860 5861 pt_to_str(pt));
5861 5862 saw_error = B_TRUE;
5862 5863 if (*ret_val == Z_OK)
5863 5864 *ret_val = Z_REQD_PROPERTY_MISSING;
5864 5865 }
5865 5866 }
5866 5867
5867 5868 static int
5868 5869 do_subproc(char *cmdbuf)
5869 5870 {
5870 5871 char inbuf[MAX_CMD_LEN];
5871 5872 FILE *file;
5872 5873 int status;
5873 5874
5874 5875 file = popen(cmdbuf, "r");
5875 5876 if (file == NULL) {
5876 5877 zerr(gettext("Could not launch: %s"), cmdbuf);
5877 5878 return (-1);
5878 5879 }
5879 5880
5880 5881 while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5881 5882 fprintf(stderr, "%s", inbuf);
5882 5883 status = pclose(file);
5883 5884
5884 5885 if (WIFSIGNALED(status)) {
5885 5886 zerr(gettext("%s unexpectedly terminated due to signal %d"),
5886 5887 cmdbuf, WTERMSIG(status));
5887 5888 return (-1);
5888 5889 }
5889 5890 assert(WIFEXITED(status));
5890 5891 return (WEXITSTATUS(status));
5891 5892 }
5892 5893
5893 5894 static int
5894 5895 brand_verify(zone_dochandle_t handle)
5895 5896 {
5896 5897 char xml_file[32];
5897 5898 char cmdbuf[MAX_CMD_LEN];
5898 5899 brand_handle_t bh;
5899 5900 char brand[MAXNAMELEN];
5900 5901 int err;
5901 5902
5902 5903 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5903 5904 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5904 5905 return (Z_INVALID_DOCUMENT);
5905 5906 }
5906 5907 if ((bh = brand_open(brand)) == NULL) {
5907 5908 zerr("%s: %s\n", zone, gettext("unknown brand."));
5908 5909 return (Z_INVALID_DOCUMENT);
5909 5910 }
5910 5911
5911 5912 /*
5912 5913 * Fetch the verify command, if any, from the brand configuration
5913 5914 * and build the command line to execute it.
5914 5915 */
5915 5916 strcpy(cmdbuf, EXEC_PREFIX);
5916 5917 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5917 5918 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5918 5919 brand_close(bh);
5919 5920 if (err != Z_OK) {
5920 5921 zerr("%s: %s\n", zone,
5921 5922 gettext("could not get brand verification command"));
5922 5923 return (Z_INVALID_DOCUMENT);
5923 5924 }
5924 5925
5925 5926 /*
5926 5927 * If the brand doesn't provide a verification routine, we just
5927 5928 * return success.
5928 5929 */
5929 5930 if (strlen(cmdbuf) == EXEC_LEN)
5930 5931 return (Z_OK);
5931 5932
5932 5933 /*
5933 5934 * Dump the current config information for this zone to a file.
5934 5935 */
5935 5936 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5936 5937 if (mkstemp(xml_file) == -1)
5937 5938 return (Z_TEMP_FILE);
5938 5939 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5939 5940 (void) unlink(xml_file);
5940 5941 return (err);
5941 5942 }
5942 5943
5943 5944 /*
5944 5945 * Execute the verification command.
5945 5946 */
5946 5947 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5947 5948 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5948 5949 err = Z_BRAND_ERROR;
5949 5950 } else {
5950 5951 err = do_subproc(cmdbuf);
5951 5952 }
5952 5953
5953 5954 (void) unlink(xml_file);
5954 5955 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5955 5956 }
5956 5957
5957 5958 /*
5958 5959 * Track the network interfaces listed in zonecfg(1m) in a linked list
5959 5960 * so that we can later check that defrouter is specified for an exclusive IP
5960 5961 * zone if and only if at least one allowed-address has been specified.
5961 5962 */
5962 5963 static boolean_t
5963 5964 add_nwif(struct zone_nwiftab *nwif)
5964 5965 {
5965 5966 struct xif *tmp;
5966 5967
5967 5968 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5968 5969 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
5969 5970 if (strlen(nwif->zone_nwif_allowed_address) > 0)
5970 5971 tmp->xif_has_address = B_TRUE;
5971 5972 if (strlen(nwif->zone_nwif_defrouter) > 0)
5972 5973 tmp->xif_has_defrouter = B_TRUE;
5973 5974 return (B_TRUE);
5974 5975 }
5975 5976 }
5976 5977
5977 5978 tmp = malloc(sizeof (*tmp));
5978 5979 if (tmp == NULL) {
5979 5980 zerr(gettext("memory allocation failed for %s"),
5980 5981 nwif->zone_nwif_physical);
5981 5982 return (B_FALSE);
5982 5983 }
5983 5984 strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
5984 5985 sizeof (tmp->xif_name));
5985 5986 tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
5986 5987 tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
5987 5988 tmp->xif_next = xif;
5988 5989 xif = tmp;
5989 5990 return (B_TRUE);
5990 5991 }
5991 5992
5992 5993 boolean_t
5993 5994 verify_secflags(struct zone_secflagstab *tab)
5994 5995 {
5995 5996 secflagdelta_t def = {0};
5996 5997 secflagdelta_t upper = {0};
5997 5998 secflagdelta_t lower = {0};
5998 5999 boolean_t def_set = B_FALSE;
5999 6000 boolean_t upper_set = B_FALSE;
6000 6001 boolean_t lower_set = B_FALSE;
6001 6002 boolean_t ret = B_TRUE;
6002 6003
6003 6004 if (strlen(tab->zone_secflags_default) > 0) {
6004 6005 def_set = B_TRUE;
6005 6006 if (secflags_parse(NULL, tab->zone_secflags_default,
6006 6007 &def) == -1) {
6007 6008 zerr(gettext("default security flags '%s' are invalid"),
6008 6009 tab->zone_secflags_default);
6009 6010 ret = B_FALSE;
6010 6011 }
6011 6012 } else {
6012 6013 secflags_zero(&def.psd_assign);
6013 6014 def.psd_ass_active = B_TRUE;
6014 6015 }
6015 6016
6016 6017 if (strlen(tab->zone_secflags_upper) > 0) {
6017 6018 upper_set = B_TRUE;
6018 6019 if (secflags_parse(NULL, tab->zone_secflags_upper,
6019 6020 &upper) == -1) {
6020 6021 zerr(gettext("upper security flags '%s' are invalid"),
6021 6022 tab->zone_secflags_upper);
6022 6023 ret = B_FALSE;
6023 6024 }
6024 6025 } else {
6025 6026 secflags_fullset(&upper.psd_assign);
6026 6027 upper.psd_ass_active = B_TRUE;
6027 6028 }
6028 6029
6029 6030 if (strlen(tab->zone_secflags_lower) > 0) {
6030 6031 lower_set = B_TRUE;
6031 6032 if (secflags_parse(NULL, tab->zone_secflags_lower,
6032 6033 &lower) == -1) {
6033 6034 zerr(gettext("lower security flags '%s' are invalid"),
6034 6035 tab->zone_secflags_lower);
6035 6036 ret = B_FALSE;
6036 6037 }
6037 6038 } else {
6038 6039 secflags_zero(&lower.psd_assign);
6039 6040 lower.psd_ass_active = B_TRUE;
6040 6041 }
6041 6042
6042 6043 if (def_set && !def.psd_ass_active) {
6043 6044 zerr(gettext("only assignment of security flags is "
6044 6045 "allowed (default: %s)"), tab->zone_secflags_default);
6045 6046 }
6046 6047
6047 6048 if (lower_set && !lower.psd_ass_active) {
6048 6049 zerr(gettext("only assignment of security flags is "
6049 6050 "allowed (lower: %s)"), tab->zone_secflags_lower);
6050 6051 }
6051 6052
6052 6053 if (upper_set && !upper.psd_ass_active) {
6053 6054 zerr(gettext("only assignment of security flags is "
6054 6055 "allowed (upper: %s)"), tab->zone_secflags_upper);
6055 6056 }
6056 6057
6057 6058 if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */
6058 6059 zerr(gettext("default secflags must be within the "
6059 6060 "upper limit"));
6060 6061 ret = B_FALSE;
6061 6062 }
6062 6063 if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
6063 6064 zerr(gettext("default secflags must be above the lower limit"));
6064 6065 ret = B_FALSE;
6065 6066 }
6066 6067 if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
6067 6068 zerr(gettext("lower secflags must be within the upper limit"));
6068 6069 ret = B_FALSE;
6069 6070 }
6070 6071
6071 6072 return (ret);
6072 6073 }
6073 6074
6074 6075 /*
6075 6076 * See the DTD for which attributes are required for which resources.
6076 6077 *
6077 6078 * This function can be called by commit_func(), which needs to save things,
6078 6079 * in addition to the general call from parse_and_run(), which doesn't need
6079 6080 * things saved. Since the parameters are standardized, we distinguish by
6080 6081 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
6081 6082 * that a save is needed.
6082 6083 */
6083 6084 void
6084 6085 verify_func(cmd_t *cmd)
6085 6086 {
6086 6087 struct zone_nwiftab nwiftab;
6087 6088 struct zone_fstab fstab;
6088 6089 struct zone_attrtab attrtab;
6089 6090 struct zone_rctltab rctltab;
6090 6091 struct zone_dstab dstab;
6091 6092 struct zone_psettab psettab;
6092 6093 struct zone_admintab admintab;
6093 6094 struct zone_secflagstab secflagstab;
6094 6095 char zonepath[MAXPATHLEN];
6095 6096 char sched[MAXNAMELEN];
6096 6097 char brand[MAXNAMELEN];
6097 6098 char hostidp[HW_HOSTID_LEN];
6098 6099 char fsallowedp[ZONE_FS_ALLOWED_MAX];
6099 6100 priv_set_t *privs;
6100 6101 char *privname = NULL;
6101 6102 int err, ret_val = Z_OK, arg;
6102 6103 int pset_res;
6103 6104 boolean_t save = B_FALSE;
6104 6105 boolean_t arg_err = B_FALSE;
6105 6106 zone_iptype_t iptype;
6106 6107 boolean_t has_cpu_shares = B_FALSE;
6107 6108 boolean_t has_cpu_cap = B_FALSE;
6108 6109 struct xif *tmp;
6109 6110
6110 6111 optind = 0;
6111 6112 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6112 6113 switch (arg) {
6113 6114 case '?':
6114 6115 longer_usage(CMD_VERIFY);
6115 6116 arg_err = B_TRUE;
6116 6117 break;
6117 6118 default:
6118 6119 short_usage(CMD_VERIFY);
6119 6120 arg_err = B_TRUE;
6120 6121 break;
6121 6122 }
6122 6123 }
6123 6124 if (arg_err)
6124 6125 return;
6125 6126
6126 6127 if (optind > cmd->cmd_argc) {
6127 6128 short_usage(CMD_VERIFY);
6128 6129 return;
6129 6130 }
6130 6131
6131 6132 if (zone_is_read_only(CMD_VERIFY))
6132 6133 return;
6133 6134
6134 6135 assert(cmd != NULL);
6135 6136
6136 6137 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
6137 6138 save = B_TRUE;
6138 6139 if (initialize(B_TRUE) != Z_OK)
6139 6140 return;
6140 6141
6141 6142 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
6142 6143 !global_zone) {
6143 6144 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
6144 6145 ret_val = Z_REQD_RESOURCE_MISSING;
6145 6146 saw_error = B_TRUE;
6146 6147 }
6147 6148 if (strlen(zonepath) == 0 && !global_zone) {
6148 6149 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
6149 6150 ret_val = Z_REQD_RESOURCE_MISSING;
6150 6151 saw_error = B_TRUE;
6151 6152 }
6152 6153
6153 6154 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
6154 6155 zone_perror(zone, err, B_TRUE);
6155 6156 return;
6156 6157 }
6157 6158 if ((err = brand_verify(handle)) != Z_OK) {
6158 6159 zone_perror(zone, err, B_TRUE);
6159 6160 return;
6160 6161 }
6161 6162
6162 6163 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
6163 6164 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
6164 6165 ret_val = Z_REQD_RESOURCE_MISSING;
6165 6166 saw_error = B_TRUE;
6166 6167 }
6167 6168
6168 6169 if ((privs = priv_allocset()) == NULL) {
6169 6170 zerr(gettext("%s: priv_allocset failed"), zone);
6170 6171 return;
6171 6172 }
6172 6173 if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) {
6173 6174 zerr(gettext("%s: invalid privilege: %s"), zone, privname);
6174 6175 priv_freeset(privs);
6175 6176 free(privname);
6176 6177 return;
6177 6178 }
6178 6179 priv_freeset(privs);
6179 6180
6180 6181 if (zonecfg_get_hostid(handle, hostidp,
6181 6182 sizeof (hostidp)) == Z_INVALID_PROPERTY) {
6182 6183 zerr(gettext("%s: invalid hostid: %s"),
6183 6184 zone, hostidp);
6184 6185 return;
6185 6186 }
6186 6187
6187 6188 if (zonecfg_get_fs_allowed(handle, fsallowedp,
6188 6189 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
6189 6190 zerr(gettext("%s: invalid fs-allowed: %s"),
6190 6191 zone, fsallowedp);
6191 6192 return;
6192 6193 }
6193 6194
6194 6195 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
6195 6196 zone_perror(zone, err, B_TRUE);
6196 6197 return;
6197 6198 }
6198 6199 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
6199 6200 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
6200 6201 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
6201 6202 &ret_val);
6202 6203 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
6203 6204
6204 6205 zonecfg_free_fs_option_list(fstab.zone_fs_options);
6205 6206 }
6206 6207 (void) zonecfg_endfsent(handle);
6207 6208
6208 6209 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
6209 6210 zone_perror(zone, err, B_TRUE);
6210 6211 return;
6211 6212 }
6212 6213 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
6213 6214 /*
6214 6215 * physical is required in all cases.
6215 6216 * A shared IP requires an address,
6216 6217 * and may include a default router, while
6217 6218 * an exclusive IP must have neither an address
6218 6219 * nor a default router.
6219 6220 * The physical interface name must be valid in all cases.
6220 6221 */
6221 6222 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
6222 6223 PT_PHYSICAL, &ret_val);
6223 6224 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
6224 6225 Z_OK) {
6225 6226 saw_error = B_TRUE;
6226 6227 if (ret_val == Z_OK)
6227 6228 ret_val = Z_INVAL;
6228 6229 }
6229 6230
6230 6231 switch (iptype) {
6231 6232 case ZS_SHARED:
6232 6233 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
6233 6234 PT_ADDRESS, &ret_val);
6234 6235 if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
6235 6236 zerr(gettext("%s: %s cannot be specified "
6236 6237 "for a shared IP type"),
6237 6238 rt_to_str(RT_NET),
6238 6239 pt_to_str(PT_ALLOWED_ADDRESS));
6239 6240 saw_error = B_TRUE;
6240 6241 if (ret_val == Z_OK)
6241 6242 ret_val = Z_INVAL;
6242 6243 }
6243 6244 break;
6244 6245 case ZS_EXCLUSIVE:
6245 6246 if (strlen(nwiftab.zone_nwif_address) > 0) {
6246 6247 zerr(gettext("%s: %s cannot be specified "
6247 6248 "for an exclusive IP type"),
6248 6249 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
6249 6250 saw_error = B_TRUE;
6250 6251 if (ret_val == Z_OK)
6251 6252 ret_val = Z_INVAL;
6252 6253 } else {
6253 6254 if (!add_nwif(&nwiftab)) {
6254 6255 saw_error = B_TRUE;
6255 6256 if (ret_val == Z_OK)
6256 6257 ret_val = Z_INVAL;
6257 6258 }
6258 6259 }
6259 6260 break;
6260 6261 }
6261 6262 }
6262 6263 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
6263 6264 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
6264 6265 zerr(gettext("%s: %s for %s cannot be specified "
6265 6266 "without %s for an exclusive IP type"),
6266 6267 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
6267 6268 tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
6268 6269 saw_error = B_TRUE;
6269 6270 ret_val = Z_INVAL;
6270 6271 }
6271 6272 }
6272 6273 free(xif);
6273 6274 xif = NULL;
6274 6275 (void) zonecfg_endnwifent(handle);
6275 6276
6276 6277 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
6277 6278 zone_perror(zone, err, B_TRUE);
6278 6279 return;
6279 6280 }
6280 6281 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
6281 6282 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
6282 6283 &ret_val);
6283 6284
6284 6285 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
6285 6286 has_cpu_shares = B_TRUE;
6286 6287
6287 6288 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
6288 6289 has_cpu_cap = B_TRUE;
6289 6290
6290 6291 if (rctltab.zone_rctl_valptr == NULL) {
6291 6292 zerr(gettext("%s: no %s specified"),
6292 6293 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
6293 6294 saw_error = B_TRUE;
6294 6295 if (ret_val == Z_OK)
6295 6296 ret_val = Z_REQD_PROPERTY_MISSING;
6296 6297 } else {
6297 6298 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
6298 6299 }
6299 6300 }
6300 6301 (void) zonecfg_endrctlent(handle);
6301 6302
6302 6303 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
6303 6304 has_cpu_shares) {
6304 6305 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
6305 6306 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6306 6307 saw_error = B_TRUE;
6307 6308 if (ret_val == Z_OK)
6308 6309 ret_val = Z_INCOMPATIBLE;
6309 6310 }
6310 6311
6311 6312 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
6312 6313 sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
6313 6314 strcmp(sched, "FSS") != 0) {
6314 6315 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
6315 6316 "incompatible"),
6316 6317 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
6317 6318 saw_error = B_TRUE;
6318 6319 if (ret_val == Z_OK)
6319 6320 ret_val = Z_INCOMPATIBLE;
6320 6321 }
6321 6322
6322 6323 if (pset_res == Z_OK && has_cpu_cap) {
6323 6324 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6324 6325 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6325 6326 saw_error = B_TRUE;
6326 6327 if (ret_val == Z_OK)
6327 6328 ret_val = Z_INCOMPATIBLE;
6328 6329 }
6329 6330
6330 6331 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6331 6332 zone_perror(zone, err, B_TRUE);
6332 6333 return;
6333 6334 }
6334 6335 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6335 6336 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6336 6337 &ret_val);
6337 6338 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6338 6339 &ret_val);
6339 6340 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6340 6341 &ret_val);
6341 6342 }
6342 6343 (void) zonecfg_endattrent(handle);
6343 6344
6344 6345 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6345 6346 zone_perror(zone, err, B_TRUE);
6346 6347 return;
6347 6348 }
6348 6349 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6349 6350 if (strlen(dstab.zone_dataset_name) == 0) {
6350 6351 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6351 6352 pt_to_str(PT_NAME), gettext("not specified"));
6352 6353 saw_error = B_TRUE;
6353 6354 if (ret_val == Z_OK)
6354 6355 ret_val = Z_REQD_PROPERTY_MISSING;
6355 6356 } else if (!zfs_name_valid(dstab.zone_dataset_name,
6356 6357 ZFS_TYPE_FILESYSTEM)) {
6357 6358 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6358 6359 pt_to_str(PT_NAME), gettext("invalid"));
6359 6360 saw_error = B_TRUE;
6360 6361 if (ret_val == Z_OK)
6361 6362 ret_val = Z_BAD_PROPERTY;
6362 6363 }
6363 6364
6364 6365 }
6365 6366 (void) zonecfg_enddsent(handle);
6366 6367
6367 6368 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6368 6369 zone_perror(zone, err, B_TRUE);
6369 6370 return;
6370 6371 }
6371 6372 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6372 6373 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6373 6374 PT_USER, &ret_val);
6374 6375 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6375 6376 PT_AUTHS, &ret_val);
6376 6377 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6377 6378 == NULL)) {
6378 6379 zerr(gettext("%s %s is not a valid username"),
6379 6380 pt_to_str(PT_USER),
6380 6381 admintab.zone_admin_user);
6381 6382 ret_val = Z_BAD_PROPERTY;
6382 6383 }
6383 6384 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6384 6385 admintab.zone_admin_auths, zone))) {
6385 6386 ret_val = Z_BAD_PROPERTY;
6386 6387 }
6387 6388 }
6388 6389 (void) zonecfg_endadminent(handle);
6389 6390
6390 6391 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
6391 6392 /*
6392 6393 * No properties are required, but any specified should be
6393 6394 * valid
6394 6395 */
6395 6396 if (verify_secflags(&secflagstab) != B_TRUE) {
6396 6397 /* Error is reported from verify_secflags */
6397 6398 ret_val = Z_BAD_PROPERTY;
6398 6399 }
6399 6400 }
6400 6401
6401 6402 if (!global_scope) {
6402 6403 zerr(gettext("resource specification incomplete"));
6403 6404 saw_error = B_TRUE;
6404 6405 if (ret_val == Z_OK)
6405 6406 ret_val = Z_INSUFFICIENT_SPEC;
6406 6407 }
6407 6408
6408 6409 if (save) {
6409 6410 if (ret_val == Z_OK) {
6410 6411 if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6411 6412 need_to_commit = B_FALSE;
6412 6413 (void) strlcpy(revert_zone, zone,
6413 6414 sizeof (revert_zone));
6414 6415 }
6415 6416 } else {
6416 6417 zerr(gettext("Zone %s failed to verify"), zone);
6417 6418 }
6418 6419 }
6419 6420 if (ret_val != Z_OK)
6420 6421 zone_perror(zone, ret_val, B_TRUE);
6421 6422 }
6422 6423
6423 6424 void
6424 6425 cancel_func(cmd_t *cmd)
6425 6426 {
6426 6427 int arg;
6427 6428 boolean_t arg_err = B_FALSE;
6428 6429
6429 6430 assert(cmd != NULL);
6430 6431
6431 6432 optind = 0;
6432 6433 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6433 6434 switch (arg) {
6434 6435 case '?':
6435 6436 longer_usage(CMD_CANCEL);
6436 6437 arg_err = B_TRUE;
6437 6438 break;
6438 6439 default:
6439 6440 short_usage(CMD_CANCEL);
6440 6441 arg_err = B_TRUE;
6441 6442 break;
6442 6443 }
6443 6444 }
6444 6445 if (arg_err)
6445 6446 return;
6446 6447
6447 6448 if (optind != cmd->cmd_argc) {
6448 6449 short_usage(CMD_CANCEL);
6449 6450 return;
6450 6451 }
6451 6452
6452 6453 if (global_scope)
6453 6454 scope_usage(CMD_CANCEL);
6454 6455 global_scope = B_TRUE;
6455 6456 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6456 6457 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6457 6458 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6458 6459 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6459 6460 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6460 6461 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6461 6462 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6462 6463 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6463 6464 }
6464 6465
6465 6466 static int
6466 6467 validate_attr_name(char *name)
6467 6468 {
6468 6469 int i;
6469 6470
6470 6471 if (!isalnum(name[0])) {
6471 6472 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6472 6473 "numeric character."), rt_to_str(RT_ATTR),
6473 6474 pt_to_str(PT_NAME), name);
6474 6475 return (Z_INVAL);
6475 6476 }
6476 6477 for (i = 1; name[i]; i++)
6477 6478 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6478 6479 zerr(gettext("Invalid %s %s %s: can only contain "
6479 6480 "alpha-numeric characters, plus '-' and '.'."),
6480 6481 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6481 6482 return (Z_INVAL);
6482 6483 }
6483 6484 return (Z_OK);
6484 6485 }
6485 6486
6486 6487 static int
6487 6488 validate_attr_type_val(struct zone_attrtab *attrtab)
6488 6489 {
6489 6490 boolean_t boolval;
6490 6491 int64_t intval;
6491 6492 char strval[MAXNAMELEN];
6492 6493 uint64_t uintval;
6493 6494
6494 6495 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6495 6496 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6496 6497 return (Z_OK);
6497 6498 zerr(gettext("invalid %s value for %s=%s"),
6498 6499 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6499 6500 return (Z_ERR);
6500 6501 }
6501 6502
6502 6503 if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6503 6504 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6504 6505 return (Z_OK);
6505 6506 zerr(gettext("invalid %s value for %s=%s"),
6506 6507 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6507 6508 return (Z_ERR);
6508 6509 }
6509 6510
6510 6511 if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6511 6512 if (zonecfg_get_attr_string(attrtab, strval,
6512 6513 sizeof (strval)) == Z_OK)
6513 6514 return (Z_OK);
6514 6515 zerr(gettext("invalid %s value for %s=%s"),
6515 6516 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6516 6517 return (Z_ERR);
6517 6518 }
6518 6519
6519 6520 if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6520 6521 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6521 6522 return (Z_OK);
6522 6523 zerr(gettext("invalid %s value for %s=%s"),
6523 6524 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6524 6525 return (Z_ERR);
6525 6526 }
6526 6527
6527 6528 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6528 6529 pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6529 6530 return (Z_ERR);
6530 6531 }
6531 6532
6532 6533 /*
6533 6534 * Helper function for end_func-- checks the existence of a given property
6534 6535 * and emits a message if not specified.
6535 6536 */
6536 6537 static int
6537 6538 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6538 6539 {
6539 6540 if (strlen(attr) == 0) {
6540 6541 *validation_failed = B_TRUE;
6541 6542 zerr(gettext("%s not specified"), pt_to_str(pt));
6542 6543 return (Z_ERR);
6543 6544 }
6544 6545 return (Z_OK);
6545 6546 }
6546 6547
6547 6548 static void
6548 6549 net_exists_error(struct zone_nwiftab nwif)
6549 6550 {
6550 6551 if (strlen(nwif.zone_nwif_address) > 0) {
6551 6552 zerr(gettext("A %s resource with the %s '%s', "
6552 6553 "and %s '%s' already exists."),
6553 6554 rt_to_str(RT_NET),
6554 6555 pt_to_str(PT_PHYSICAL),
6555 6556 nwif.zone_nwif_physical,
6556 6557 pt_to_str(PT_ADDRESS),
6557 6558 in_progress_nwiftab.zone_nwif_address);
6558 6559 } else {
6559 6560 zerr(gettext("A %s resource with the %s '%s', "
6560 6561 "and %s '%s' already exists."),
6561 6562 rt_to_str(RT_NET),
6562 6563 pt_to_str(PT_PHYSICAL),
6563 6564 nwif.zone_nwif_physical,
6564 6565 pt_to_str(PT_ALLOWED_ADDRESS),
6565 6566 nwif.zone_nwif_allowed_address);
6566 6567 }
6567 6568 }
6568 6569
6569 6570 void
6570 6571 end_func(cmd_t *cmd)
6571 6572 {
6572 6573 boolean_t validation_failed = B_FALSE;
6573 6574 boolean_t arg_err = B_FALSE;
6574 6575 struct zone_fstab tmp_fstab;
6575 6576 struct zone_nwiftab tmp_nwiftab;
6576 6577 struct zone_devtab tmp_devtab;
6577 6578 struct zone_rctltab tmp_rctltab;
6578 6579 struct zone_attrtab tmp_attrtab;
6579 6580 struct zone_dstab tmp_dstab;
6580 6581 struct zone_admintab tmp_admintab;
6581 6582 int err, arg, res1, res2, res3;
6582 6583 uint64_t swap_limit;
6583 6584 uint64_t locked_limit;
6584 6585 uint64_t proc_cap;
6585 6586
6586 6587 assert(cmd != NULL);
6587 6588
6588 6589 optind = 0;
6589 6590 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6590 6591 switch (arg) {
6591 6592 case '?':
6592 6593 longer_usage(CMD_END);
6593 6594 arg_err = B_TRUE;
6594 6595 break;
6595 6596 default:
6596 6597 short_usage(CMD_END);
6597 6598 arg_err = B_TRUE;
6598 6599 break;
6599 6600 }
6600 6601 }
6601 6602 if (arg_err)
6602 6603 return;
6603 6604
6604 6605 if (optind != cmd->cmd_argc) {
6605 6606 short_usage(CMD_END);
6606 6607 return;
6607 6608 }
6608 6609
6609 6610 if (global_scope) {
6610 6611 scope_usage(CMD_END);
6611 6612 return;
6612 6613 }
6613 6614
6614 6615 assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6615 6616
6616 6617 switch (resource_scope) {
6617 6618 case RT_FS:
6618 6619 /* First make sure everything was filled in. */
6619 6620 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6620 6621 PT_DIR, &validation_failed) == Z_OK) {
6621 6622 if (in_progress_fstab.zone_fs_dir[0] != '/') {
6622 6623 zerr(gettext("%s %s is not an absolute path."),
6623 6624 pt_to_str(PT_DIR),
6624 6625 in_progress_fstab.zone_fs_dir);
6625 6626 validation_failed = B_TRUE;
6626 6627 }
6627 6628 }
6628 6629
6629 6630 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6630 6631 PT_SPECIAL, &validation_failed);
6631 6632
6632 6633 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6633 6634 in_progress_fstab.zone_fs_raw[0] != '/') {
6634 6635 zerr(gettext("%s %s is not an absolute path."),
6635 6636 pt_to_str(PT_RAW),
6636 6637 in_progress_fstab.zone_fs_raw);
6637 6638 validation_failed = B_TRUE;
6638 6639 }
6639 6640
6640 6641 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6641 6642 &validation_failed);
6642 6643
6643 6644 if (validation_failed) {
6644 6645 saw_error = B_TRUE;
6645 6646 return;
6646 6647 }
6647 6648
6648 6649 if (end_op == CMD_ADD) {
6649 6650 /* Make sure there isn't already one like this. */
6650 6651 bzero(&tmp_fstab, sizeof (tmp_fstab));
6651 6652 (void) strlcpy(tmp_fstab.zone_fs_dir,
6652 6653 in_progress_fstab.zone_fs_dir,
6653 6654 sizeof (tmp_fstab.zone_fs_dir));
6654 6655 err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6655 6656 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6656 6657 if (err == Z_OK) {
6657 6658 zerr(gettext("A %s resource "
6658 6659 "with the %s '%s' already exists."),
6659 6660 rt_to_str(RT_FS), pt_to_str(PT_DIR),
6660 6661 in_progress_fstab.zone_fs_dir);
6661 6662 saw_error = B_TRUE;
6662 6663 return;
6663 6664 }
6664 6665 err = zonecfg_add_filesystem(handle,
6665 6666 &in_progress_fstab);
6666 6667 } else {
6667 6668 err = zonecfg_modify_filesystem(handle, &old_fstab,
6668 6669 &in_progress_fstab);
6669 6670 }
6670 6671 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6671 6672 in_progress_fstab.zone_fs_options = NULL;
6672 6673 break;
6673 6674
6674 6675 case RT_NET:
6675 6676 /*
6676 6677 * First make sure everything was filled in.
6677 6678 * Since we don't know whether IP will be shared
6678 6679 * or exclusive here, some checks are deferred until
6679 6680 * the verify command.
6680 6681 */
6681 6682 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6682 6683 PT_PHYSICAL, &validation_failed);
6683 6684
6684 6685 if (validation_failed) {
6685 6686 saw_error = B_TRUE;
6686 6687 return;
6687 6688 }
6688 6689 if (end_op == CMD_ADD) {
6689 6690 /* Make sure there isn't already one like this. */
6690 6691 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6691 6692 (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6692 6693 in_progress_nwiftab.zone_nwif_physical,
6693 6694 sizeof (tmp_nwiftab.zone_nwif_physical));
6694 6695 (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6695 6696 in_progress_nwiftab.zone_nwif_address,
6696 6697 sizeof (tmp_nwiftab.zone_nwif_address));
6697 6698 (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6698 6699 in_progress_nwiftab.zone_nwif_allowed_address,
6699 6700 sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6700 6701 (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6701 6702 in_progress_nwiftab.zone_nwif_defrouter,
6702 6703 sizeof (tmp_nwiftab.zone_nwif_defrouter));
6703 6704 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6704 6705 net_exists_error(in_progress_nwiftab);
6705 6706 saw_error = B_TRUE;
6706 6707 return;
6707 6708 }
6708 6709 err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6709 6710 } else {
6710 6711 err = zonecfg_modify_nwif(handle, &old_nwiftab,
6711 6712 &in_progress_nwiftab);
6712 6713 }
6713 6714 break;
6714 6715
6715 6716 case RT_DEVICE:
6716 6717 /* First make sure everything was filled in. */
6717 6718 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6718 6719 PT_MATCH, &validation_failed);
6719 6720
6720 6721 if (validation_failed) {
6721 6722 saw_error = B_TRUE;
6722 6723 return;
6723 6724 }
6724 6725
6725 6726 if (end_op == CMD_ADD) {
6726 6727 /* Make sure there isn't already one like this. */
6727 6728 (void) strlcpy(tmp_devtab.zone_dev_match,
6728 6729 in_progress_devtab.zone_dev_match,
6729 6730 sizeof (tmp_devtab.zone_dev_match));
6730 6731 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6731 6732 zerr(gettext("A %s resource with the %s '%s' "
6732 6733 "already exists."), rt_to_str(RT_DEVICE),
6733 6734 pt_to_str(PT_MATCH),
6734 6735 in_progress_devtab.zone_dev_match);
6735 6736 saw_error = B_TRUE;
6736 6737 return;
6737 6738 }
6738 6739 err = zonecfg_add_dev(handle, &in_progress_devtab);
6739 6740 } else {
6740 6741 err = zonecfg_modify_dev(handle, &old_devtab,
6741 6742 &in_progress_devtab);
6742 6743 }
6743 6744 break;
6744 6745
6745 6746 case RT_RCTL:
6746 6747 /* First make sure everything was filled in. */
6747 6748 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6748 6749 PT_NAME, &validation_failed);
6749 6750
6750 6751 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6751 6752 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6752 6753 validation_failed = B_TRUE;
6753 6754 }
6754 6755
6755 6756 if (validation_failed) {
6756 6757 saw_error = B_TRUE;
6757 6758 return;
6758 6759 }
6759 6760
6760 6761 if (end_op == CMD_ADD) {
6761 6762 /* Make sure there isn't already one like this. */
6762 6763 (void) strlcpy(tmp_rctltab.zone_rctl_name,
6763 6764 in_progress_rctltab.zone_rctl_name,
6764 6765 sizeof (tmp_rctltab.zone_rctl_name));
6765 6766 tmp_rctltab.zone_rctl_valptr = NULL;
6766 6767 err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6767 6768 zonecfg_free_rctl_value_list(
6768 6769 tmp_rctltab.zone_rctl_valptr);
6769 6770 if (err == Z_OK) {
6770 6771 zerr(gettext("A %s resource "
6771 6772 "with the %s '%s' already exists."),
6772 6773 rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6773 6774 in_progress_rctltab.zone_rctl_name);
6774 6775 saw_error = B_TRUE;
6775 6776 return;
6776 6777 }
6777 6778 err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6778 6779 } else {
6779 6780 err = zonecfg_modify_rctl(handle, &old_rctltab,
6780 6781 &in_progress_rctltab);
6781 6782 }
6782 6783 if (err == Z_OK) {
6783 6784 zonecfg_free_rctl_value_list(
6784 6785 in_progress_rctltab.zone_rctl_valptr);
6785 6786 in_progress_rctltab.zone_rctl_valptr = NULL;
6786 6787 }
6787 6788 break;
6788 6789
6789 6790 case RT_ATTR:
6790 6791 /* First make sure everything was filled in. */
6791 6792 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6792 6793 PT_NAME, &validation_failed);
6793 6794 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6794 6795 PT_TYPE, &validation_failed);
6795 6796 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6796 6797 PT_VALUE, &validation_failed);
6797 6798
6798 6799 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6799 6800 Z_OK)
6800 6801 validation_failed = B_TRUE;
6801 6802
6802 6803 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6803 6804 validation_failed = B_TRUE;
6804 6805
6805 6806 if (validation_failed) {
6806 6807 saw_error = B_TRUE;
6807 6808 return;
6808 6809 }
6809 6810 if (end_op == CMD_ADD) {
6810 6811 /* Make sure there isn't already one like this. */
6811 6812 bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6812 6813 (void) strlcpy(tmp_attrtab.zone_attr_name,
6813 6814 in_progress_attrtab.zone_attr_name,
6814 6815 sizeof (tmp_attrtab.zone_attr_name));
6815 6816 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6816 6817 zerr(gettext("An %s resource "
6817 6818 "with the %s '%s' already exists."),
6818 6819 rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6819 6820 in_progress_attrtab.zone_attr_name);
6820 6821 saw_error = B_TRUE;
6821 6822 return;
6822 6823 }
6823 6824 err = zonecfg_add_attr(handle, &in_progress_attrtab);
6824 6825 } else {
6825 6826 err = zonecfg_modify_attr(handle, &old_attrtab,
6826 6827 &in_progress_attrtab);
6827 6828 }
6828 6829 break;
6829 6830 case RT_DATASET:
6830 6831 /* First make sure everything was filled in. */
6831 6832 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6832 6833 zerr("%s %s", pt_to_str(PT_NAME),
6833 6834 gettext("not specified"));
6834 6835 saw_error = B_TRUE;
6835 6836 validation_failed = B_TRUE;
6836 6837 }
6837 6838 if (validation_failed)
6838 6839 return;
6839 6840 if (end_op == CMD_ADD) {
6840 6841 /* Make sure there isn't already one like this. */
6841 6842 bzero(&tmp_dstab, sizeof (tmp_dstab));
6842 6843 (void) strlcpy(tmp_dstab.zone_dataset_name,
6843 6844 in_progress_dstab.zone_dataset_name,
6844 6845 sizeof (tmp_dstab.zone_dataset_name));
6845 6846 err = zonecfg_lookup_ds(handle, &tmp_dstab);
6846 6847 if (err == Z_OK) {
6847 6848 zerr(gettext("A %s resource "
6848 6849 "with the %s '%s' already exists."),
6849 6850 rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6850 6851 in_progress_dstab.zone_dataset_name);
6851 6852 saw_error = B_TRUE;
6852 6853 return;
6853 6854 }
6854 6855 err = zonecfg_add_ds(handle, &in_progress_dstab);
6855 6856 } else {
6856 6857 err = zonecfg_modify_ds(handle, &old_dstab,
6857 6858 &in_progress_dstab);
6858 6859 }
6859 6860 break;
6860 6861 case RT_DCPU:
6861 6862 /* Make sure everything was filled in. */
6862 6863 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6863 6864 PT_NCPUS, &validation_failed) != Z_OK) {
6864 6865 saw_error = B_TRUE;
6865 6866 return;
6866 6867 }
6867 6868
6868 6869 if (end_op == CMD_ADD) {
6869 6870 err = zonecfg_add_pset(handle, &in_progress_psettab);
6870 6871 } else {
6871 6872 err = zonecfg_modify_pset(handle, &in_progress_psettab);
6872 6873 }
6873 6874 break;
6874 6875 case RT_PCAP:
6875 6876 /* Make sure everything was filled in. */
6876 6877 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6877 6878 != Z_OK) {
6878 6879 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6879 6880 saw_error = B_TRUE;
6880 6881 validation_failed = B_TRUE;
6881 6882 return;
6882 6883 }
6883 6884 err = Z_OK;
6884 6885 break;
6885 6886 case RT_MCAP:
6886 6887 /* Make sure everything was filled in. */
6887 6888 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6888 6889 Z_ERR : Z_OK;
6889 6890 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6890 6891 &swap_limit);
6891 6892 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6892 6893 &locked_limit);
6893 6894
6894 6895 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6895 6896 zerr(gettext("No property was specified. One of %s, "
6896 6897 "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6897 6898 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6898 6899 saw_error = B_TRUE;
6899 6900 return;
6900 6901 }
6901 6902
6902 6903 /* if phys & locked are both set, verify locked <= phys */
6903 6904 if (res1 == Z_OK && res3 == Z_OK) {
6904 6905 uint64_t phys_limit;
6905 6906 char *endp;
6906 6907
6907 6908 phys_limit = strtoull(
6908 6909 in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6909 6910 if (phys_limit < locked_limit) {
6910 6911 zerr(gettext("The %s cap must be less than or "
6911 6912 "equal to the %s cap."),
6912 6913 pt_to_str(PT_LOCKED),
6913 6914 pt_to_str(PT_PHYSICAL));
6914 6915 saw_error = B_TRUE;
6915 6916 return;
6916 6917 }
6917 6918 }
6918 6919
6919 6920 err = Z_OK;
6920 6921 if (res1 == Z_OK) {
6921 6922 /*
6922 6923 * We could be ending from either an add operation
6923 6924 * or a select operation. Since all of the properties
6924 6925 * within this resource are optional, we always use
6925 6926 * modify on the mcap entry. zonecfg_modify_mcap()
6926 6927 * will handle both adding and modifying a memory cap.
6927 6928 */
6928 6929 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6929 6930 } else if (end_op == CMD_SELECT) {
6930 6931 /*
6931 6932 * If we're ending from a select and the physical
6932 6933 * memory cap is empty then the user could have cleared
6933 6934 * the physical cap value, so try to delete the entry.
6934 6935 */
6935 6936 (void) zonecfg_delete_mcap(handle);
6936 6937 }
6937 6938 break;
6938 6939 case RT_ADMIN:
6939 6940 /* First make sure everything was filled in. */
6940 6941 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6941 6942 PT_USER, &validation_failed) == Z_OK) {
6942 6943 if (getpwnam(in_progress_admintab.zone_admin_user)
6943 6944 == NULL) {
6944 6945 zerr(gettext("%s %s is not a valid username"),
6945 6946 pt_to_str(PT_USER),
6946 6947 in_progress_admintab.zone_admin_user);
6947 6948 validation_failed = B_TRUE;
6948 6949 }
6949 6950 }
6950 6951
6951 6952 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6952 6953 PT_AUTHS, &validation_failed) == Z_OK) {
6953 6954 if (!zonecfg_valid_auths(
6954 6955 in_progress_admintab.zone_admin_auths,
6955 6956 zone)) {
6956 6957 validation_failed = B_TRUE;
6957 6958 }
6958 6959 }
6959 6960
6960 6961 if (validation_failed) {
6961 6962 saw_error = B_TRUE;
6962 6963 return;
6963 6964 }
6964 6965
6965 6966 if (end_op == CMD_ADD) {
6966 6967 /* Make sure there isn't already one like this. */
6967 6968 bzero(&tmp_admintab, sizeof (tmp_admintab));
6968 6969 (void) strlcpy(tmp_admintab.zone_admin_user,
6969 6970 in_progress_admintab.zone_admin_user,
6970 6971 sizeof (tmp_admintab.zone_admin_user));
6971 6972 err = zonecfg_lookup_admin(
6972 6973 handle, &tmp_admintab);
6973 6974 if (err == Z_OK) {
6974 6975 zerr(gettext("A %s resource "
6975 6976 "with the %s '%s' already exists."),
6976 6977 rt_to_str(RT_ADMIN),
6977 6978 pt_to_str(PT_USER),
6978 6979 in_progress_admintab.zone_admin_user);
6979 6980 saw_error = B_TRUE;
6980 6981 return;
6981 6982 }
6982 6983 err = zonecfg_add_admin(handle,
6983 6984 &in_progress_admintab, zone);
6984 6985 } else {
6985 6986 err = zonecfg_modify_admin(handle,
6986 6987 &old_admintab, &in_progress_admintab,
6987 6988 zone);
6988 6989 }
6989 6990 break;
6990 6991 case RT_SECFLAGS:
6991 6992 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
6992 6993 saw_error = B_TRUE;
6993 6994 return;
6994 6995 }
6995 6996
6996 6997 if (end_op == CMD_ADD) {
6997 6998 err = zonecfg_add_secflags(handle,
6998 6999 &in_progress_secflagstab);
6999 7000 } else {
7000 7001 err = zonecfg_modify_secflags(handle,
7001 7002 &old_secflagstab, &in_progress_secflagstab);
7002 7003 }
7003 7004 break;
7004 7005 default:
7005 7006 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
7006 7007 B_TRUE);
7007 7008 saw_error = B_TRUE;
7008 7009 return;
7009 7010 }
7010 7011
7011 7012 if (err != Z_OK) {
7012 7013 zone_perror(zone, err, B_TRUE);
7013 7014 } else {
7014 7015 need_to_commit = B_TRUE;
7015 7016 global_scope = B_TRUE;
7016 7017 end_op = -1;
7017 7018 }
7018 7019 }
7019 7020
7020 7021 void
7021 7022 commit_func(cmd_t *cmd)
7022 7023 {
7023 7024 int arg;
7024 7025 boolean_t arg_err = B_FALSE;
7025 7026
7026 7027 optind = 0;
7027 7028 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
7028 7029 switch (arg) {
7029 7030 case '?':
7030 7031 longer_usage(CMD_COMMIT);
7031 7032 arg_err = B_TRUE;
7032 7033 break;
7033 7034 default:
7034 7035 short_usage(CMD_COMMIT);
7035 7036 arg_err = B_TRUE;
7036 7037 break;
7037 7038 }
7038 7039 }
7039 7040 if (arg_err)
7040 7041 return;
7041 7042
7042 7043 if (optind != cmd->cmd_argc) {
7043 7044 short_usage(CMD_COMMIT);
7044 7045 return;
7045 7046 }
7046 7047
7047 7048 if (zone_is_read_only(CMD_COMMIT))
7048 7049 return;
7049 7050
7050 7051 assert(cmd != NULL);
7051 7052
7052 7053 cmd->cmd_argc = 1;
7053 7054 /*
7054 7055 * cmd_arg normally comes from a strdup() in the lexer, and the
7055 7056 * whole cmd structure and its (char *) attributes are freed at
7056 7057 * the completion of each command, so the strdup() below is needed
7057 7058 * to match this and prevent a core dump from trying to free()
7058 7059 * something that can't be.
7059 7060 */
7060 7061 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
7061 7062 zone_perror(zone, Z_NOMEM, B_TRUE);
7062 7063 exit(Z_ERR);
7063 7064 }
7064 7065 cmd->cmd_argv[1] = NULL;
7065 7066 verify_func(cmd);
7066 7067 }
7067 7068
7068 7069 void
7069 7070 revert_func(cmd_t *cmd)
7070 7071 {
7071 7072 char line[128]; /* enough to ask a question */
7072 7073 boolean_t force = B_FALSE;
7073 7074 boolean_t arg_err = B_FALSE;
7074 7075 int err, arg, answer;
7075 7076
7076 7077 optind = 0;
7077 7078 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
7078 7079 switch (arg) {
7079 7080 case '?':
7080 7081 longer_usage(CMD_REVERT);
7081 7082 arg_err = B_TRUE;
7082 7083 break;
7083 7084 case 'F':
7084 7085 force = B_TRUE;
7085 7086 break;
7086 7087 default:
7087 7088 short_usage(CMD_REVERT);
7088 7089 arg_err = B_TRUE;
7089 7090 break;
7090 7091 }
7091 7092 }
7092 7093 if (arg_err)
7093 7094 return;
7094 7095
7095 7096 if (optind != cmd->cmd_argc) {
7096 7097 short_usage(CMD_REVERT);
7097 7098 return;
7098 7099 }
7099 7100
7100 7101 if (zone_is_read_only(CMD_REVERT))
7101 7102 return;
7102 7103
7103 7104 if (!global_scope) {
7104 7105 zerr(gettext("You can only use %s in the global scope.\nUse"
7105 7106 " '%s' to cancel changes to a resource specification."),
7106 7107 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
7107 7108 saw_error = B_TRUE;
7108 7109 return;
7109 7110 }
7110 7111
7111 7112 if (zonecfg_check_handle(handle) != Z_OK) {
7112 7113 zerr(gettext("No changes to revert."));
7113 7114 saw_error = B_TRUE;
7114 7115 return;
7115 7116 }
7116 7117
7117 7118 if (!force) {
7118 7119 (void) snprintf(line, sizeof (line),
7119 7120 gettext("Are you sure you want to revert"));
7120 7121 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
7121 7122 zerr(gettext("Input not from terminal and -F not "
7122 7123 "specified:\n%s command ignored, exiting."),
7123 7124 cmd_to_str(CMD_REVERT));
7124 7125 exit(Z_ERR);
7125 7126 }
7126 7127 if (answer != 1)
7127 7128 return;
7128 7129 }
7129 7130
7130 7131 /*
7131 7132 * Reset any pending admins that were
7132 7133 * removed from the previous zone
7133 7134 */
7134 7135 zonecfg_remove_userauths(handle, "", zone, B_FALSE);
7135 7136
7136 7137 /*
7137 7138 * Time for a new handle: finish the old one off first
7138 7139 * then get a new one properly to avoid leaks.
7139 7140 */
7140 7141 zonecfg_fini_handle(handle);
7141 7142 if ((handle = zonecfg_init_handle()) == NULL) {
7142 7143 zone_perror(execname, Z_NOMEM, B_TRUE);
7143 7144 exit(Z_ERR);
7144 7145 }
7145 7146
7146 7147 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
7147 7148 saw_error = B_TRUE;
7148 7149 got_handle = B_FALSE;
7149 7150 if (err == Z_NO_ZONE)
7150 7151 zerr(gettext("%s: no such saved zone to revert to."),
7151 7152 revert_zone);
7152 7153 else
7153 7154 zone_perror(zone, err, B_TRUE);
7154 7155 }
7155 7156 (void) strlcpy(zone, revert_zone, sizeof (zone));
7156 7157 }
7157 7158
7158 7159 void
7159 7160 help_func(cmd_t *cmd)
7160 7161 {
7161 7162 int i;
7162 7163
7163 7164 assert(cmd != NULL);
7164 7165
7165 7166 if (cmd->cmd_argc == 0) {
7166 7167 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
7167 7168 return;
7168 7169 }
7169 7170 if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
7170 7171 usage(B_TRUE, HELP_USAGE);
7171 7172 return;
7172 7173 }
7173 7174 if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
7174 7175 usage(B_TRUE, HELP_SUBCMDS);
7175 7176 return;
7176 7177 }
7177 7178 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
7178 7179 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
7179 7180 return;
7180 7181 }
7181 7182 if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
7182 7183 longer_usage(CMD_HELP);
7183 7184 return;
7184 7185 }
7185 7186
7186 7187 for (i = 0; i <= CMD_MAX; i++) {
7187 7188 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
7188 7189 longer_usage(i);
7189 7190 return;
7190 7191 }
7191 7192 }
7192 7193 /* We do not use zerr() here because we do not want its extra \n. */
7193 7194 (void) fprintf(stderr, gettext("Unknown help subject %s. "),
7194 7195 cmd->cmd_argv[0]);
7195 7196 usage(B_FALSE, HELP_META);
7196 7197 }
7197 7198
7198 7199 static int
7199 7200 string_to_yyin(char *string)
7200 7201 {
7201 7202 if ((yyin = tmpfile()) == NULL) {
7202 7203 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7203 7204 return (Z_ERR);
7204 7205 }
7205 7206 if (fwrite(string, strlen(string), 1, yyin) != 1) {
7206 7207 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7207 7208 return (Z_ERR);
7208 7209 }
7209 7210 if (fseek(yyin, 0, SEEK_SET) != 0) {
7210 7211 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7211 7212 return (Z_ERR);
7212 7213 }
7213 7214 return (Z_OK);
7214 7215 }
7215 7216
7216 7217 /* This is the back-end helper function for read_input() below. */
7217 7218
7218 7219 static int
7219 7220 cleanup()
7220 7221 {
7221 7222 int answer;
7222 7223 cmd_t *cmd;
7223 7224
7224 7225 if (!interactive_mode && !cmd_file_mode) {
7225 7226 /*
7226 7227 * If we're not in interactive mode, and we're not in command
7227 7228 * file mode, then we must be in commands-from-the-command-line
7228 7229 * mode. As such, we can't loop back and ask for more input.
7229 7230 * It was OK to prompt for such things as whether or not to
7230 7231 * really delete a zone in the command handler called from
7231 7232 * yyparse() above, but "really quit?" makes no sense in this
7232 7233 * context. So disable prompting.
7233 7234 */
7234 7235 ok_to_prompt = B_FALSE;
7235 7236 }
7236 7237 if (!global_scope) {
7237 7238 if (!time_to_exit) {
7238 7239 /*
7239 7240 * Just print a simple error message in the -1 case,
7240 7241 * since exit_func() already handles that case, and
7241 7242 * EOF means we are finished anyway.
7242 7243 */
7243 7244 answer = ask_yesno(B_FALSE,
7244 7245 gettext("Resource incomplete; really quit"));
7245 7246 if (answer == -1) {
7246 7247 zerr(gettext("Resource incomplete."));
7247 7248 return (Z_ERR);
7248 7249 }
7249 7250 if (answer != 1) {
7250 7251 yyin = stdin;
7251 7252 return (Z_REPEAT);
7252 7253 }
7253 7254 } else {
7254 7255 saw_error = B_TRUE;
7255 7256 }
7256 7257 }
7257 7258 /*
7258 7259 * Make sure we tried something and that the handle checks
7259 7260 * out, or we would get a false error trying to commit.
7260 7261 */
7261 7262 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
7262 7263 if ((cmd = alloc_cmd()) == NULL) {
7263 7264 zone_perror(zone, Z_NOMEM, B_TRUE);
7264 7265 return (Z_ERR);
7265 7266 }
7266 7267 cmd->cmd_argc = 0;
7267 7268 cmd->cmd_argv[0] = NULL;
7268 7269 commit_func(cmd);
7269 7270 free_cmd(cmd);
7270 7271 /*
7271 7272 * need_to_commit will get set back to FALSE if the
7272 7273 * configuration is saved successfully.
7273 7274 */
7274 7275 if (need_to_commit) {
7275 7276 if (force_exit) {
7276 7277 zerr(gettext("Configuration not saved."));
7277 7278 return (Z_ERR);
7278 7279 }
7279 7280 answer = ask_yesno(B_FALSE,
7280 7281 gettext("Configuration not saved; really quit"));
7281 7282 if (answer == -1) {
7282 7283 zerr(gettext("Configuration not saved."));
7283 7284 return (Z_ERR);
7284 7285 }
7285 7286 if (answer != 1) {
7286 7287 time_to_exit = B_FALSE;
7287 7288 yyin = stdin;
7288 7289 return (Z_REPEAT);
7289 7290 }
7290 7291 }
7291 7292 }
7292 7293 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
7293 7294 }
7294 7295
7295 7296 /*
7296 7297 * read_input() is the driver of this program. It is a wrapper around
7297 7298 * yyparse(), printing appropriate prompts when needed, checking for
7298 7299 * exit conditions and reacting appropriately [the latter in its cleanup()
7299 7300 * helper function].
7300 7301 *
7301 7302 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
7302 7303 * so do_interactive() knows that we are not really done (i.e, we asked
7303 7304 * the user if we should really quit and the user said no).
7304 7305 */
7305 7306 static int
7306 7307 read_input()
7307 7308 {
7308 7309 boolean_t yyin_is_a_tty = isatty(fileno(yyin));
7309 7310 /*
7310 7311 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
7311 7312 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
7312 7313 */
7313 7314 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
7314 7315
7315 7316 /* yyin should have been set to the appropriate (FILE *) if not stdin */
7316 7317 newline_terminated = B_TRUE;
7317 7318 for (;;) {
7318 7319 if (yyin_is_a_tty) {
7319 7320 if (newline_terminated) {
7320 7321 if (global_scope)
7321 7322 (void) snprintf(prompt, sizeof (prompt),
7322 7323 "%s:%s> ", execname, zone);
7323 7324 else
7324 7325 (void) snprintf(prompt, sizeof (prompt),
7325 7326 "%s:%s:%s> ", execname, zone,
7326 7327 rt_to_str(resource_scope));
7327 7328 }
7328 7329 /*
7329 7330 * If the user hits ^C then we want to catch it and
7330 7331 * start over. If the user hits EOF then we want to
7331 7332 * bail out.
7332 7333 */
7333 7334 line = gl_get_line(gl, prompt, NULL, -1);
7334 7335 if (gl_return_status(gl) == GLR_SIGNAL) {
7335 7336 gl_abandon_line(gl);
7336 7337 continue;
7337 7338 }
7338 7339 if (line == NULL)
7339 7340 break;
7340 7341 (void) string_to_yyin(line);
7341 7342 while (!feof(yyin))
7342 7343 yyparse();
7343 7344 } else {
7344 7345 yyparse();
7345 7346 }
7346 7347 /* Bail out on an error in command file mode. */
7347 7348 if (saw_error && cmd_file_mode && !interactive_mode)
7348 7349 time_to_exit = B_TRUE;
7349 7350 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7350 7351 break;
7351 7352 }
7352 7353 return (cleanup());
7353 7354 }
7354 7355
7355 7356 /*
7356 7357 * This function is used in the zonecfg-interactive-mode scenario: it just
7357 7358 * calls read_input() until we are done.
7358 7359 */
7359 7360
7360 7361 static int
7361 7362 do_interactive(void)
7362 7363 {
7363 7364 int err;
7364 7365
7365 7366 interactive_mode = B_TRUE;
7366 7367 if (!read_only_mode) {
7367 7368 /*
7368 7369 * Try to set things up proactively in interactive mode, so
7369 7370 * that if the zone in question does not exist yet, we can
7370 7371 * provide the user with a clue.
7371 7372 */
7372 7373 (void) initialize(B_FALSE);
7373 7374 }
7374 7375 do {
7375 7376 err = read_input();
7376 7377 } while (err == Z_REPEAT);
7377 7378 return (err);
7378 7379 }
7379 7380
7380 7381 /*
7381 7382 * cmd_file is slightly more complicated, as it has to open the command file
7382 7383 * and set yyin appropriately. Once that is done, though, it just calls
7383 7384 * read_input(), and only once, since prompting is not possible.
7384 7385 */
7385 7386
7386 7387 static int
7387 7388 cmd_file(char *file)
7388 7389 {
7389 7390 FILE *infile;
7390 7391 int err;
7391 7392 struct stat statbuf;
7392 7393 boolean_t using_real_file = (strcmp(file, "-") != 0);
7393 7394
7394 7395 if (using_real_file) {
7395 7396 /*
7396 7397 * zerr() prints a line number in cmd_file_mode, which we do
7397 7398 * not want here, so temporarily unset it.
7398 7399 */
7399 7400 cmd_file_mode = B_FALSE;
7400 7401 if ((infile = fopen(file, "r")) == NULL) {
7401 7402 zerr(gettext("could not open file %s: %s"),
7402 7403 file, strerror(errno));
7403 7404 return (Z_ERR);
7404 7405 }
7405 7406 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7406 7407 zerr(gettext("could not stat file %s: %s"),
7407 7408 file, strerror(errno));
7408 7409 err = Z_ERR;
7409 7410 goto done;
7410 7411 }
7411 7412 if (!S_ISREG(statbuf.st_mode)) {
7412 7413 zerr(gettext("%s is not a regular file."), file);
7413 7414 err = Z_ERR;
7414 7415 goto done;
7415 7416 }
7416 7417 yyin = infile;
7417 7418 cmd_file_mode = B_TRUE;
7418 7419 ok_to_prompt = B_FALSE;
7419 7420 } else {
7420 7421 /*
7421 7422 * "-f -" is essentially the same as interactive mode,
7422 7423 * so treat it that way.
7423 7424 */
7424 7425 interactive_mode = B_TRUE;
7425 7426 }
7426 7427 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7427 7428 if ((err = read_input()) == Z_REPEAT)
7428 7429 err = Z_ERR;
7429 7430 done:
7430 7431 if (using_real_file)
7431 7432 (void) fclose(infile);
7432 7433 return (err);
7433 7434 }
7434 7435
7435 7436 /*
7436 7437 * Since yacc is based on reading from a (FILE *) whereas what we get from
7437 7438 * the command line is in argv format, we need to convert when the user
7438 7439 * gives us commands directly from the command line. That is done here by
7439 7440 * concatenating the argv list into a space-separated string, writing it
7440 7441 * to a temp file, and rewinding the file so yyin can be set to it. Then
7441 7442 * we call read_input(), and only once, since prompting about whether to
7442 7443 * continue or quit would make no sense in this context.
7443 7444 */
7444 7445
7445 7446 static int
7446 7447 one_command_at_a_time(int argc, char *argv[])
7447 7448 {
7448 7449 char *command;
7449 7450 size_t len = 2; /* terminal \n\0 */
7450 7451 int i, err;
7451 7452
7452 7453 for (i = 0; i < argc; i++)
7453 7454 len += strlen(argv[i]) + 1;
7454 7455 if ((command = malloc(len)) == NULL) {
7455 7456 zone_perror(execname, Z_NOMEM, B_TRUE);
7456 7457 return (Z_ERR);
7457 7458 }
7458 7459 (void) strlcpy(command, argv[0], len);
7459 7460 for (i = 1; i < argc; i++) {
7460 7461 (void) strlcat(command, " ", len);
7461 7462 (void) strlcat(command, argv[i], len);
7462 7463 }
7463 7464 (void) strlcat(command, "\n", len);
7464 7465 err = string_to_yyin(command);
7465 7466 free(command);
7466 7467 if (err != Z_OK)
7467 7468 return (err);
7468 7469 while (!feof(yyin))
7469 7470 yyparse();
7470 7471 return (cleanup());
7471 7472 }
7472 7473
7473 7474 static char *
7474 7475 get_execbasename(char *execfullname)
7475 7476 {
7476 7477 char *last_slash, *execbasename;
7477 7478
7478 7479 /* guard against '/' at end of command invocation */
7479 7480 for (;;) {
7480 7481 last_slash = strrchr(execfullname, '/');
7481 7482 if (last_slash == NULL) {
7482 7483 execbasename = execfullname;
7483 7484 break;
7484 7485 } else {
7485 7486 execbasename = last_slash + 1;
7486 7487 if (*execbasename == '\0') {
7487 7488 *last_slash = '\0';
7488 7489 continue;
7489 7490 }
7490 7491 break;
7491 7492 }
7492 7493 }
7493 7494 return (execbasename);
7494 7495 }
7495 7496
7496 7497 int
7497 7498 main(int argc, char *argv[])
7498 7499 {
7499 7500 int err, arg;
7500 7501 struct stat st;
7501 7502
7502 7503 /* This must be before anything goes to stdout. */
7503 7504 setbuf(stdout, NULL);
7504 7505
7505 7506 saw_error = B_FALSE;
7506 7507 cmd_file_mode = B_FALSE;
7507 7508 execname = get_execbasename(argv[0]);
7508 7509
7509 7510 (void) setlocale(LC_ALL, "");
7510 7511 (void) textdomain(TEXT_DOMAIN);
7511 7512
7512 7513 if (getzoneid() != GLOBAL_ZONEID) {
7513 7514 zerr(gettext("%s can only be run from the global zone."),
7514 7515 execname);
7515 7516 exit(Z_ERR);
7516 7517 }
7517 7518
7518 7519 if (argc < 2) {
7519 7520 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7520 7521 exit(Z_USAGE);
7521 7522 }
7522 7523 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7523 7524 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7524 7525 exit(Z_OK);
7525 7526 }
7526 7527
7527 7528 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7528 7529 switch (arg) {
7529 7530 case '?':
7530 7531 if (optopt == '?')
7531 7532 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7532 7533 else
7533 7534 usage(B_FALSE, HELP_USAGE);
7534 7535 exit(Z_USAGE);
7535 7536 /* NOTREACHED */
7536 7537 case 'f':
7537 7538 cmd_file_name = optarg;
7538 7539 cmd_file_mode = B_TRUE;
7539 7540 break;
7540 7541 case 'R':
7541 7542 if (*optarg != '/') {
7542 7543 zerr(gettext("root path must be absolute: %s"),
7543 7544 optarg);
7544 7545 exit(Z_USAGE);
7545 7546 }
7546 7547 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7547 7548 zerr(gettext(
7548 7549 "root path must be a directory: %s"),
7549 7550 optarg);
7550 7551 exit(Z_USAGE);
7551 7552 }
7552 7553 zonecfg_set_root(optarg);
7553 7554 break;
7554 7555 case 'z':
7555 7556 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7556 7557 global_zone = B_TRUE;
7557 7558 } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7558 7559 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7559 7560 usage(B_FALSE, HELP_SYNTAX);
7560 7561 exit(Z_USAGE);
7561 7562 }
7562 7563 (void) strlcpy(zone, optarg, sizeof (zone));
7563 7564 (void) strlcpy(revert_zone, optarg, sizeof (zone));
7564 7565 break;
7565 7566 default:
7566 7567 usage(B_FALSE, HELP_USAGE);
7567 7568 exit(Z_USAGE);
7568 7569 }
7569 7570 }
7570 7571
7571 7572 if (optind > argc || strcmp(zone, "") == 0) {
7572 7573 usage(B_FALSE, HELP_USAGE);
7573 7574 exit(Z_USAGE);
7574 7575 }
7575 7576
7576 7577 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7577 7578 read_only_mode = B_FALSE;
7578 7579 } else if (err == Z_ACCES) {
7579 7580 read_only_mode = B_TRUE;
7580 7581 /* skip this message in one-off from command line mode */
7581 7582 if (optind == argc)
7582 7583 (void) fprintf(stderr, gettext("WARNING: you do not "
7583 7584 "have write access to this zone's configuration "
7584 7585 "file;\ngoing into read-only mode.\n"));
7585 7586 } else {
7586 7587 fprintf(stderr, "%s: Could not access zone configuration "
7587 7588 "store: %s\n", execname, zonecfg_strerror(err));
7588 7589 exit(Z_ERR);
7589 7590 }
7590 7591
7591 7592 if ((handle = zonecfg_init_handle()) == NULL) {
7592 7593 zone_perror(execname, Z_NOMEM, B_TRUE);
7593 7594 exit(Z_ERR);
7594 7595 }
7595 7596
7596 7597 /*
7597 7598 * This may get set back to FALSE again in cmd_file() if cmd_file_name
7598 7599 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7599 7600 */
7600 7601 if (isatty(STDIN_FILENO))
7601 7602 ok_to_prompt = B_TRUE;
7602 7603 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7603 7604 exit(Z_ERR);
7604 7605 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7605 7606 exit(Z_ERR);
7606 7607 (void) sigset(SIGINT, SIG_IGN);
7607 7608 if (optind == argc) {
7608 7609 if (!cmd_file_mode)
7609 7610 err = do_interactive();
7610 7611 else
7611 7612 err = cmd_file(cmd_file_name);
7612 7613 } else {
7613 7614 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7614 7615 }
7615 7616 zonecfg_fini_handle(handle);
7616 7617 if (brand != NULL)
7617 7618 brand_close(brand);
7618 7619 (void) del_GetLine(gl);
7619 7620 return (err);
7620 7621 }
↓ open down ↓ |
5780 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX