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