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