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