1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1497 dp * Common Development and Distribution License (the "License"). 6 1497 dp * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 222 comay 22 0 stevel /* 23 8662 Jordan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* 28 0 stevel * zonecfg is a lex/yacc based command interpreter used to manage zone 29 0 stevel * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which 30 0 stevel * the grammar (see zonecfg_grammar.y) builds up into commands, some of 31 0 stevel * which takes resources and/or properties as arguments. See the block 32 0 stevel * comments near the end of zonecfg_grammar.y for how the data structures 33 0 stevel * which keep track of these resources and properties are built up. 34 0 stevel * 35 0 stevel * The resource/property data structures are inserted into a command 36 0 stevel * structure (see zonecfg.h), which also keeps track of command names, 37 0 stevel * miscellaneous arguments, and function handlers. The grammar selects 38 0 stevel * the appropriate function handler, each of which takes a pointer to a 39 0 stevel * command structure as its sole argument, and invokes it. The grammar 40 0 stevel * itself is "entered" (a la the Matrix) by yyparse(), which is called 41 0 stevel * from read_input(), our main driving function. That in turn is called 42 0 stevel * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each 43 0 stevel * of which is called from main() depending on how the program was invoked. 44 0 stevel * 45 0 stevel * The rest of this module consists of the various function handlers and 46 0 stevel * their helper functions. Some of these functions, particularly the 47 0 stevel * X_to_str() functions, which maps command, resource and property numbers 48 0 stevel * to strings, are used quite liberally, as doing so results in a better 49 0 stevel * program w/rt I18N, reducing the need for translation notes. 50 0 stevel */ 51 0 stevel 52 0 stevel #include <sys/mntent.h> 53 0 stevel #include <sys/varargs.h> 54 0 stevel #include <sys/sysmacros.h> 55 0 stevel 56 0 stevel #include <errno.h> 57 2712 nn35248 #include <fcntl.h> 58 0 stevel #include <strings.h> 59 0 stevel #include <unistd.h> 60 0 stevel #include <ctype.h> 61 0 stevel #include <stdlib.h> 62 0 stevel #include <assert.h> 63 0 stevel #include <sys/stat.h> 64 0 stevel #include <zone.h> 65 0 stevel #include <arpa/inet.h> 66 0 stevel #include <netdb.h> 67 0 stevel #include <locale.h> 68 0 stevel #include <libintl.h> 69 0 stevel #include <alloca.h> 70 0 stevel #include <signal.h> 71 2712 nn35248 #include <wait.h> 72 0 stevel #include <libtecla.h> 73 789 ahrens #include <libzfs.h> 74 2712 nn35248 #include <sys/brand.h> 75 2712 nn35248 #include <libbrand.h> 76 8662 Jordan #include <sys/systeminfo.h> 77 8083 Jordan #include <libdladm.h> 78 8083 Jordan #include <libinetutil.h> 79 0 stevel 80 0 stevel #include <libzonecfg.h> 81 0 stevel #include "zonecfg.h" 82 0 stevel 83 0 stevel #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 84 0 stevel #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 85 0 stevel #endif 86 0 stevel 87 0 stevel #define PAGER "/usr/bin/more" 88 2712 nn35248 #define EXEC_PREFIX "exec " 89 2712 nn35248 #define EXEC_LEN (strlen(EXEC_PREFIX)) 90 0 stevel 91 0 stevel struct help { 92 0 stevel uint_t cmd_num; 93 0 stevel char *cmd_name; 94 0 stevel uint_t flags; 95 0 stevel char *short_usage; 96 0 stevel }; 97 0 stevel 98 0 stevel extern int yyparse(void); 99 0 stevel extern int lex_lineno; 100 0 stevel 101 0 stevel #define MAX_LINE_LEN 1024 102 0 stevel #define MAX_CMD_HIST 1024 103 2712 nn35248 #define MAX_CMD_LEN 1024 104 0 stevel 105 3247 gjelinek #define ONE_MB 1048576 106 3247 gjelinek 107 0 stevel /* 108 0 stevel * Each SHELP_ should be a simple string. 109 0 stevel */ 110 0 stevel 111 0 stevel #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \ 112 0 stevel "add <property-name> <property-value>\n\t(resource scope)" 113 0 stevel #define SHELP_CANCEL "cancel" 114 3247 gjelinek #define SHELP_CLEAR "clear <property-name>" 115 0 stevel #define SHELP_COMMIT "commit" 116 1507 gjelinek #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]" 117 0 stevel #define SHELP_DELETE "delete [-F]" 118 0 stevel #define SHELP_END "end" 119 0 stevel #define SHELP_EXIT "exit [-F]" 120 0 stevel #define SHELP_EXPORT "export [-f output-file]" 121 0 stevel #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]" 122 0 stevel #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]" 123 3247 gjelinek #define SHELP_REMOVE "remove [-F] <resource-type> " \ 124 3247 gjelinek "[ <property-name>=<property-value> ]*\n" \ 125 3247 gjelinek "\t(global scope)\n" \ 126 3247 gjelinek "remove <property-name> <property-value>\n" \ 127 3247 gjelinek "\t(resource scope)" 128 0 stevel #define SHELP_REVERT "revert [-F]" 129 0 stevel #define SHELP_SELECT "select <resource-type> { <property-name>=" \ 130 0 stevel "<property-value> }" 131 0 stevel #define SHELP_SET "set <property-name>=<property-value>" 132 0 stevel #define SHELP_VERIFY "verify" 133 0 stevel 134 0 stevel static struct help helptab[] = { 135 0 stevel { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, }, 136 0 stevel { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, }, 137 3247 gjelinek { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, }, 138 0 stevel { CMD_COMMIT, "commit", 0, SHELP_COMMIT, }, 139 0 stevel { CMD_CREATE, "create", 0, SHELP_CREATE, }, 140 0 stevel { CMD_DELETE, "delete", 0, SHELP_DELETE, }, 141 0 stevel { CMD_END, "end", 0, SHELP_END, }, 142 0 stevel { CMD_EXIT, "exit", 0, SHELP_EXIT, }, 143 0 stevel { CMD_EXPORT, "export", 0, SHELP_EXPORT, }, 144 0 stevel { CMD_HELP, "help", 0, SHELP_HELP }, 145 0 stevel { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, }, 146 0 stevel { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, }, 147 0 stevel { CMD_REVERT, "revert", 0, SHELP_REVERT, }, 148 0 stevel { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, }, 149 0 stevel { CMD_SET, "set", HELP_PROPS, SHELP_SET, }, 150 0 stevel { CMD_VERIFY, "verify", 0, SHELP_VERIFY, }, 151 0 stevel { 0 }, 152 0 stevel }; 153 0 stevel 154 0 stevel #define MAX_RT_STRLEN 16 155 0 stevel 156 0 stevel /* These *must* match the order of the RT_ define's from zonecfg.h */ 157 11024 Jordan char *res_types[] = { 158 0 stevel "unknown", 159 565 dp "zonename", 160 0 stevel "zonepath", 161 0 stevel "autoboot", 162 0 stevel "pool", 163 0 stevel "fs", 164 0 stevel "inherit-pkg-dir", 165 0 stevel "net", 166 0 stevel "device", 167 0 stevel "rctl", 168 0 stevel "attr", 169 789 ahrens "dataset", 170 1645 comay "limitpriv", 171 2267 dp "bootargs", 172 2712 nn35248 "brand", 173 3247 gjelinek "dedicated-cpu", 174 3247 gjelinek "capped-memory", 175 3247 gjelinek ALIAS_MAXLWPS, 176 3247 gjelinek ALIAS_MAXSHMMEM, 177 3247 gjelinek ALIAS_MAXSHMIDS, 178 3247 gjelinek ALIAS_MAXMSGIDS, 179 3247 gjelinek ALIAS_MAXSEMIDS, 180 3247 gjelinek ALIAS_SHARES, 181 3247 gjelinek "scheduling-class", 182 3448 dh155122 "ip-type", 183 3792 akolb "capped-cpu", 184 8662 Jordan "hostid", 185 0 stevel NULL 186 0 stevel }; 187 0 stevel 188 0 stevel /* These *must* match the order of the PT_ define's from zonecfg.h */ 189 11024 Jordan char *prop_types[] = { 190 0 stevel "unknown", 191 565 dp "zonename", 192 0 stevel "zonepath", 193 0 stevel "autoboot", 194 0 stevel "pool", 195 0 stevel "dir", 196 0 stevel "special", 197 0 stevel "type", 198 0 stevel "options", 199 0 stevel "address", 200 0 stevel "physical", 201 0 stevel "name", 202 0 stevel "value", 203 0 stevel "match", 204 0 stevel "priv", 205 0 stevel "limit", 206 0 stevel "action", 207 0 stevel "raw", 208 1645 comay "limitpriv", 209 2267 dp "bootargs", 210 2712 nn35248 "brand", 211 3247 gjelinek "ncpus", 212 3247 gjelinek "importance", 213 3247 gjelinek "swap", 214 3247 gjelinek "locked", 215 3247 gjelinek ALIAS_SHARES, 216 3247 gjelinek ALIAS_MAXLWPS, 217 3247 gjelinek ALIAS_MAXSHMMEM, 218 3247 gjelinek ALIAS_MAXSHMIDS, 219 3247 gjelinek ALIAS_MAXMSGIDS, 220 3247 gjelinek ALIAS_MAXSEMIDS, 221 3247 gjelinek ALIAS_MAXLOCKEDMEM, 222 3247 gjelinek ALIAS_MAXSWAP, 223 3247 gjelinek "scheduling-class", 224 3448 dh155122 "ip-type", 225 6076 gfaden "defrouter", 226 8662 Jordan "hostid", 227 1645 comay NULL 228 1645 comay }; 229 1645 comay 230 1645 comay /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */ 231 0 stevel static char *prop_val_types[] = { 232 0 stevel "simple", 233 0 stevel "complex", 234 0 stevel "list", 235 0 stevel }; 236 0 stevel 237 0 stevel /* 238 0 stevel * The various _cmds[] lists below are for command tab-completion. 239 0 stevel */ 240 0 stevel 241 0 stevel /* 242 0 stevel * remove has a space afterwards because it has qualifiers; the other commands 243 3247 gjelinek * that have qualifiers (add, select, etc.) don't need a space here because 244 0 stevel * they have their own _cmds[] lists below. 245 0 stevel */ 246 0 stevel static const char *global_scope_cmds[] = { 247 0 stevel "add", 248 3247 gjelinek "clear", 249 0 stevel "commit", 250 0 stevel "create", 251 0 stevel "delete", 252 0 stevel "exit", 253 0 stevel "export", 254 0 stevel "help", 255 0 stevel "info", 256 0 stevel "remove ", 257 0 stevel "revert", 258 0 stevel "select", 259 0 stevel "set", 260 0 stevel "verify", 261 0 stevel NULL 262 0 stevel }; 263 0 stevel 264 0 stevel static const char *add_cmds[] = { 265 0 stevel "add fs", 266 0 stevel "add inherit-pkg-dir", 267 0 stevel "add net", 268 0 stevel "add device", 269 0 stevel "add rctl", 270 0 stevel "add attr", 271 789 ahrens "add dataset", 272 3247 gjelinek "add dedicated-cpu", 273 3792 akolb "add capped-cpu", 274 3247 gjelinek "add capped-memory", 275 3247 gjelinek NULL 276 3247 gjelinek }; 277 3247 gjelinek 278 3247 gjelinek static const char *clear_cmds[] = { 279 3247 gjelinek "clear autoboot", 280 3247 gjelinek "clear pool", 281 3247 gjelinek "clear limitpriv", 282 3247 gjelinek "clear bootargs", 283 3247 gjelinek "clear scheduling-class", 284 3448 dh155122 "clear ip-type", 285 3247 gjelinek "clear " ALIAS_MAXLWPS, 286 3247 gjelinek "clear " ALIAS_MAXSHMMEM, 287 3247 gjelinek "clear " ALIAS_MAXSHMIDS, 288 3247 gjelinek "clear " ALIAS_MAXMSGIDS, 289 3247 gjelinek "clear " ALIAS_MAXSEMIDS, 290 3247 gjelinek "clear " ALIAS_SHARES, 291 0 stevel NULL 292 0 stevel }; 293 0 stevel 294 2607 dp static const char *remove_cmds[] = { 295 2607 dp "remove fs ", 296 2607 dp "remove inherit-pkg-dir ", 297 2607 dp "remove net ", 298 2607 dp "remove device ", 299 2607 dp "remove rctl ", 300 2607 dp "remove attr ", 301 2607 dp "remove dataset ", 302 3247 gjelinek "remove dedicated-cpu ", 303 3792 akolb "remove capped-cpu ", 304 3247 gjelinek "remove capped-memory ", 305 2607 dp NULL 306 2607 dp }; 307 2607 dp 308 0 stevel static const char *select_cmds[] = { 309 565 dp "select fs ", 310 565 dp "select inherit-pkg-dir ", 311 565 dp "select net ", 312 565 dp "select device ", 313 565 dp "select rctl ", 314 565 dp "select attr ", 315 789 ahrens "select dataset ", 316 3247 gjelinek "select dedicated-cpu", 317 3792 akolb "select capped-cpu", 318 3247 gjelinek "select capped-memory", 319 0 stevel NULL 320 0 stevel }; 321 0 stevel 322 0 stevel static const char *set_cmds[] = { 323 565 dp "set zonename=", 324 565 dp "set zonepath=", 325 2712 nn35248 "set brand=", 326 565 dp "set autoboot=", 327 565 dp "set pool=", 328 1645 comay "set limitpriv=", 329 2267 dp "set bootargs=", 330 3247 gjelinek "set scheduling-class=", 331 3448 dh155122 "set ip-type=", 332 3247 gjelinek "set " ALIAS_MAXLWPS "=", 333 3247 gjelinek "set " ALIAS_MAXSHMMEM "=", 334 3247 gjelinek "set " ALIAS_MAXSHMIDS "=", 335 3247 gjelinek "set " ALIAS_MAXMSGIDS "=", 336 3247 gjelinek "set " ALIAS_MAXSEMIDS "=", 337 3247 gjelinek "set " ALIAS_SHARES "=", 338 8662 Jordan "set hostid=", 339 0 stevel NULL 340 0 stevel }; 341 0 stevel 342 2607 dp static const char *info_cmds[] = { 343 2607 dp "info fs ", 344 2607 dp "info inherit-pkg-dir ", 345 2607 dp "info net ", 346 2607 dp "info device ", 347 2607 dp "info rctl ", 348 2607 dp "info attr ", 349 2607 dp "info dataset ", 350 3247 gjelinek "info capped-memory", 351 3247 gjelinek "info dedicated-cpu", 352 3792 akolb "info capped-cpu", 353 2607 dp "info zonename", 354 2607 dp "info zonepath", 355 2607 dp "info autoboot", 356 2607 dp "info pool", 357 2607 dp "info limitpriv", 358 2607 dp "info bootargs", 359 3247 gjelinek "info brand", 360 3247 gjelinek "info scheduling-class", 361 3448 dh155122 "info ip-type", 362 3247 gjelinek "info max-lwps", 363 3247 gjelinek "info max-shm-memory", 364 3247 gjelinek "info max-shm-ids", 365 3247 gjelinek "info max-msg-ids", 366 3247 gjelinek "info max-sem-ids", 367 3247 gjelinek "info cpu-shares", 368 8662 Jordan "info hostid", 369 2607 dp NULL 370 2607 dp }; 371 2607 dp 372 0 stevel static const char *fs_res_scope_cmds[] = { 373 0 stevel "add options ", 374 0 stevel "cancel", 375 0 stevel "end", 376 0 stevel "exit", 377 0 stevel "help", 378 0 stevel "info", 379 1645 comay "remove options ", 380 0 stevel "set dir=", 381 0 stevel "set raw=", 382 0 stevel "set special=", 383 0 stevel "set type=", 384 3247 gjelinek "clear raw", 385 0 stevel NULL 386 0 stevel }; 387 0 stevel 388 0 stevel static const char *net_res_scope_cmds[] = { 389 0 stevel "cancel", 390 0 stevel "end", 391 0 stevel "exit", 392 0 stevel "help", 393 0 stevel "info", 394 0 stevel "set address=", 395 0 stevel "set physical=", 396 0 stevel NULL 397 0 stevel }; 398 0 stevel 399 0 stevel static const char *ipd_res_scope_cmds[] = { 400 0 stevel "cancel", 401 0 stevel "end", 402 0 stevel "exit", 403 0 stevel "help", 404 0 stevel "info", 405 0 stevel "set dir=", 406 0 stevel NULL 407 0 stevel }; 408 0 stevel 409 0 stevel static const char *device_res_scope_cmds[] = { 410 0 stevel "cancel", 411 0 stevel "end", 412 0 stevel "exit", 413 0 stevel "help", 414 0 stevel "info", 415 0 stevel "set match=", 416 0 stevel NULL 417 0 stevel }; 418 0 stevel 419 0 stevel static const char *attr_res_scope_cmds[] = { 420 0 stevel "cancel", 421 0 stevel "end", 422 0 stevel "exit", 423 0 stevel "help", 424 0 stevel "info", 425 0 stevel "set name=", 426 0 stevel "set type=", 427 0 stevel "set value=", 428 0 stevel NULL 429 0 stevel }; 430 0 stevel 431 0 stevel static const char *rctl_res_scope_cmds[] = { 432 0 stevel "add value ", 433 789 ahrens "cancel", 434 789 ahrens "end", 435 789 ahrens "exit", 436 789 ahrens "help", 437 789 ahrens "info", 438 1645 comay "remove value ", 439 789 ahrens "set name=", 440 789 ahrens NULL 441 789 ahrens }; 442 789 ahrens 443 789 ahrens static const char *dataset_res_scope_cmds[] = { 444 0 stevel "cancel", 445 0 stevel "end", 446 0 stevel "exit", 447 0 stevel "help", 448 0 stevel "info", 449 0 stevel "set name=", 450 0 stevel NULL 451 0 stevel }; 452 0 stevel 453 3247 gjelinek static const char *pset_res_scope_cmds[] = { 454 3247 gjelinek "cancel", 455 3247 gjelinek "end", 456 3247 gjelinek "exit", 457 3247 gjelinek "help", 458 3247 gjelinek "info", 459 3247 gjelinek "set ncpus=", 460 3247 gjelinek "set importance=", 461 3247 gjelinek "clear importance", 462 3247 gjelinek NULL 463 3247 gjelinek }; 464 3247 gjelinek 465 3792 akolb static const char *pcap_res_scope_cmds[] = { 466 3792 akolb "cancel", 467 3792 akolb "end", 468 3792 akolb "exit", 469 3792 akolb "help", 470 3792 akolb "info", 471 3792 akolb "set ncpus=", 472 3792 akolb NULL 473 3792 akolb }; 474 3792 akolb 475 3247 gjelinek static const char *mcap_res_scope_cmds[] = { 476 3247 gjelinek "cancel", 477 3247 gjelinek "end", 478 3247 gjelinek "exit", 479 3247 gjelinek "help", 480 3247 gjelinek "info", 481 3247 gjelinek "set physical=", 482 3247 gjelinek "set swap=", 483 3247 gjelinek "set locked=", 484 3247 gjelinek "clear physical", 485 3247 gjelinek "clear swap", 486 3247 gjelinek "clear locked", 487 3247 gjelinek NULL 488 3247 gjelinek }; 489 3247 gjelinek 490 0 stevel /* Global variables */ 491 0 stevel 492 0 stevel /* set early in main(), never modified thereafter, used all over the place */ 493 0 stevel static char *execname; 494 0 stevel 495 0 stevel /* set in main(), used all over the place */ 496 0 stevel static zone_dochandle_t handle; 497 0 stevel 498 0 stevel /* used all over the place */ 499 565 dp static char zone[ZONENAME_MAX]; 500 565 dp static char revert_zone[ZONENAME_MAX]; 501 2712 nn35248 502 2712 nn35248 /* global brand operations */ 503 2727 edp static brand_handle_t brand; 504 0 stevel 505 0 stevel /* set in modifying functions, checked in read_input() */ 506 6215 gjelinek static boolean_t need_to_commit = B_FALSE; 507 6215 gjelinek boolean_t saw_error; 508 0 stevel 509 0 stevel /* set in yacc parser, checked in read_input() */ 510 6215 gjelinek boolean_t newline_terminated; 511 0 stevel 512 0 stevel /* set in main(), checked in lex error handler */ 513 6215 gjelinek boolean_t cmd_file_mode; 514 0 stevel 515 0 stevel /* set in exit_func(), checked in read_input() */ 516 6215 gjelinek static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE; 517 0 stevel 518 0 stevel /* used in short_usage() and zerr() */ 519 0 stevel static char *cmd_file_name = NULL; 520 0 stevel 521 0 stevel /* checked in read_input() and other places */ 522 6215 gjelinek static boolean_t ok_to_prompt = B_FALSE; 523 0 stevel 524 0 stevel /* set and checked in initialize() */ 525 6215 gjelinek static boolean_t got_handle = B_FALSE; 526 0 stevel 527 0 stevel /* initialized in do_interactive(), checked in initialize() */ 528 6215 gjelinek static boolean_t interactive_mode; 529 3247 gjelinek 530 3247 gjelinek /* set if configuring the global zone */ 531 6215 gjelinek static boolean_t global_zone = B_FALSE; 532 0 stevel 533 0 stevel /* set in main(), checked in multiple places */ 534 6215 gjelinek static boolean_t read_only_mode; 535 6215 gjelinek 536 6215 gjelinek /* scope is outer/global or inner/resource */ 537 6215 gjelinek static boolean_t global_scope = B_TRUE; 538 0 stevel static int resource_scope; /* should be in the RT_ list from zonecfg.h */ 539 0 stevel static int end_op = -1; /* operation on end is either add or modify */ 540 0 stevel 541 0 stevel int num_prop_vals; /* for grammar */ 542 0 stevel 543 0 stevel /* 544 0 stevel * These are for keeping track of resources as they are specified as part of 545 0 stevel * the multi-step process. They should be initialized by add_resource() or 546 0 stevel * select_func() and filled in by add_property() or set_func(). 547 0 stevel */ 548 0 stevel static struct zone_fstab old_fstab, in_progress_fstab; 549 0 stevel static struct zone_fstab old_ipdtab, in_progress_ipdtab; 550 0 stevel static struct zone_nwiftab old_nwiftab, in_progress_nwiftab; 551 0 stevel static struct zone_devtab old_devtab, in_progress_devtab; 552 0 stevel static struct zone_rctltab old_rctltab, in_progress_rctltab; 553 0 stevel static struct zone_attrtab old_attrtab, in_progress_attrtab; 554 789 ahrens static struct zone_dstab old_dstab, in_progress_dstab; 555 3247 gjelinek static struct zone_psettab old_psettab, in_progress_psettab; 556 3247 gjelinek static struct zone_mcaptab old_mcaptab, in_progress_mcaptab; 557 0 stevel 558 0 stevel static GetLine *gl; /* The gl_get_line() resource object */ 559 3247 gjelinek 560 3247 gjelinek static void bytes_to_units(char *str, char *buf, int bufsize); 561 0 stevel 562 0 stevel /* Functions begin here */ 563 0 stevel 564 6215 gjelinek static boolean_t 565 0 stevel initial_match(const char *line1, const char *line2, int word_end) 566 0 stevel { 567 0 stevel if (word_end <= 0) 568 6215 gjelinek return (B_TRUE); 569 0 stevel return (strncmp(line1, line2, word_end) == 0); 570 0 stevel } 571 0 stevel 572 0 stevel static int 573 0 stevel add_stuff(WordCompletion *cpl, const char *line1, const char **list, 574 0 stevel int word_end) 575 0 stevel { 576 0 stevel int i, err; 577 0 stevel 578 0 stevel for (i = 0; list[i] != NULL; i++) { 579 0 stevel if (initial_match(line1, list[i], word_end)) { 580 0 stevel err = cpl_add_completion(cpl, line1, 0, word_end, 581 0 stevel list[i] + word_end, "", ""); 582 0 stevel if (err != 0) 583 0 stevel return (err); 584 0 stevel } 585 0 stevel } 586 0 stevel return (0); 587 0 stevel } 588 0 stevel 589 0 stevel static 590 0 stevel /* ARGSUSED */ 591 0 stevel CPL_MATCH_FN(cmd_cpl_fn) 592 0 stevel { 593 0 stevel if (global_scope) { 594 0 stevel /* 595 0 stevel * The MAX/MIN tests below are to make sure we have at least 596 0 stevel * enough characters to distinguish from other prefixes (MAX) 597 0 stevel * but only check MIN(what we have, what we're checking). 598 0 stevel */ 599 0 stevel if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0) 600 0 stevel return (add_stuff(cpl, line, add_cmds, word_end)); 601 3247 gjelinek if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0) 602 3247 gjelinek return (add_stuff(cpl, line, clear_cmds, word_end)); 603 0 stevel if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0) 604 0 stevel return (add_stuff(cpl, line, select_cmds, word_end)); 605 0 stevel if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0) 606 0 stevel return (add_stuff(cpl, line, set_cmds, word_end)); 607 2607 dp if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0) 608 2607 dp return (add_stuff(cpl, line, remove_cmds, word_end)); 609 2607 dp if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0) 610 2607 dp return (add_stuff(cpl, line, info_cmds, word_end)); 611 0 stevel return (add_stuff(cpl, line, global_scope_cmds, word_end)); 612 0 stevel } 613 0 stevel switch (resource_scope) { 614 0 stevel case RT_FS: 615 0 stevel return (add_stuff(cpl, line, fs_res_scope_cmds, word_end)); 616 0 stevel case RT_IPD: 617 0 stevel return (add_stuff(cpl, line, ipd_res_scope_cmds, word_end)); 618 0 stevel case RT_NET: 619 0 stevel return (add_stuff(cpl, line, net_res_scope_cmds, word_end)); 620 0 stevel case RT_DEVICE: 621 0 stevel return (add_stuff(cpl, line, device_res_scope_cmds, word_end)); 622 0 stevel case RT_RCTL: 623 0 stevel return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end)); 624 0 stevel case RT_ATTR: 625 0 stevel return (add_stuff(cpl, line, attr_res_scope_cmds, word_end)); 626 789 ahrens case RT_DATASET: 627 789 ahrens return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end)); 628 3247 gjelinek case RT_DCPU: 629 3247 gjelinek return (add_stuff(cpl, line, pset_res_scope_cmds, word_end)); 630 3792 akolb case RT_PCAP: 631 3792 akolb return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end)); 632 3247 gjelinek case RT_MCAP: 633 3247 gjelinek return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end)); 634 0 stevel } 635 0 stevel return (0); 636 0 stevel } 637 0 stevel 638 0 stevel /* 639 0 stevel * For the main CMD_func() functions below, several of them call getopt() 640 0 stevel * then check optind against argc to make sure an extra parameter was not 641 0 stevel * passed in. The reason this is not caught in the grammar is that the 642 0 stevel * grammar just checks for a miscellaneous TOKEN, which is *expected* to 643 0 stevel * be "-F" (for example), but could be anything. So (for example) this 644 0 stevel * check will prevent "create bogus". 645 0 stevel */ 646 0 stevel 647 0 stevel cmd_t * 648 0 stevel alloc_cmd(void) 649 0 stevel { 650 0 stevel return (calloc(1, sizeof (cmd_t))); 651 0 stevel } 652 0 stevel 653 0 stevel void 654 0 stevel free_cmd(cmd_t *cmd) 655 0 stevel { 656 0 stevel int i; 657 0 stevel 658 0 stevel for (i = 0; i < MAX_EQ_PROP_PAIRS; i++) 659 0 stevel if (cmd->cmd_property_ptr[i] != NULL) { 660 0 stevel property_value_ptr_t pp = cmd->cmd_property_ptr[i]; 661 0 stevel 662 0 stevel switch (pp->pv_type) { 663 0 stevel case PROP_VAL_SIMPLE: 664 0 stevel free(pp->pv_simple); 665 0 stevel break; 666 0 stevel case PROP_VAL_COMPLEX: 667 0 stevel free_complex(pp->pv_complex); 668 0 stevel break; 669 0 stevel case PROP_VAL_LIST: 670 0 stevel free_list(pp->pv_list); 671 0 stevel break; 672 0 stevel } 673 0 stevel } 674 0 stevel for (i = 0; i < cmd->cmd_argc; i++) 675 0 stevel free(cmd->cmd_argv[i]); 676 0 stevel free(cmd); 677 0 stevel } 678 0 stevel 679 0 stevel complex_property_ptr_t 680 0 stevel alloc_complex(void) 681 0 stevel { 682 0 stevel return (calloc(1, sizeof (complex_property_t))); 683 0 stevel } 684 0 stevel 685 0 stevel void 686 0 stevel free_complex(complex_property_ptr_t complex) 687 0 stevel { 688 0 stevel if (complex == NULL) 689 0 stevel return; 690 0 stevel free_complex(complex->cp_next); 691 0 stevel if (complex->cp_value != NULL) 692 0 stevel free(complex->cp_value); 693 0 stevel free(complex); 694 0 stevel } 695 0 stevel 696 0 stevel list_property_ptr_t 697 0 stevel alloc_list(void) 698 0 stevel { 699 0 stevel return (calloc(1, sizeof (list_property_t))); 700 0 stevel } 701 0 stevel 702 0 stevel void 703 0 stevel free_list(list_property_ptr_t list) 704 0 stevel { 705 0 stevel if (list == NULL) 706 0 stevel return; 707 0 stevel if (list->lp_simple != NULL) 708 0 stevel free(list->lp_simple); 709 0 stevel free_complex(list->lp_complex); 710 0 stevel free_list(list->lp_next); 711 0 stevel free(list); 712 0 stevel } 713 0 stevel 714 0 stevel void 715 0 stevel free_outer_list(list_property_ptr_t list) 716 0 stevel { 717 0 stevel if (list == NULL) 718 0 stevel return; 719 0 stevel free_outer_list(list->lp_next); 720 0 stevel free(list); 721 0 stevel } 722 0 stevel 723 0 stevel static struct zone_rctlvaltab * 724 0 stevel alloc_rctlvaltab(void) 725 0 stevel { 726 0 stevel return (calloc(1, sizeof (struct zone_rctlvaltab))); 727 0 stevel } 728 0 stevel 729 0 stevel static char * 730 0 stevel rt_to_str(int res_type) 731 0 stevel { 732 0 stevel assert(res_type >= RT_MIN && res_type <= RT_MAX); 733 0 stevel return (res_types[res_type]); 734 0 stevel } 735 0 stevel 736 0 stevel static char * 737 0 stevel pt_to_str(int prop_type) 738 0 stevel { 739 0 stevel assert(prop_type >= PT_MIN && prop_type <= PT_MAX); 740 0 stevel return (prop_types[prop_type]); 741 0 stevel } 742 0 stevel 743 0 stevel static char * 744 0 stevel pvt_to_str(int pv_type) 745 0 stevel { 746 0 stevel assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX); 747 0 stevel return (prop_val_types[pv_type]); 748 0 stevel } 749 0 stevel 750 0 stevel static char * 751 0 stevel cmd_to_str(int cmd_num) 752 0 stevel { 753 0 stevel assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 754 0 stevel return (helptab[cmd_num].cmd_name); 755 0 stevel } 756 0 stevel 757 0 stevel /* 758 0 stevel * This is a separate function rather than a set of define's because of the 759 0 stevel * gettext() wrapping. 760 0 stevel */ 761 0 stevel 762 0 stevel /* 763 0 stevel * TRANSLATION_NOTE 764 0 stevel * Each string below should have \t follow \n whenever needed; the 765 0 stevel * initial \t and the terminal \n will be provided by the calling function. 766 0 stevel */ 767 0 stevel 768 0 stevel static char * 769 0 stevel long_help(int cmd_num) 770 0 stevel { 771 0 stevel static char line[1024]; /* arbitrary large amount */ 772 0 stevel 773 0 stevel assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 774 0 stevel switch (cmd_num) { 775 0 stevel case CMD_HELP: 776 0 stevel return (gettext("Prints help message.")); 777 0 stevel case CMD_CREATE: 778 0 stevel (void) snprintf(line, sizeof (line), 779 0 stevel gettext("Creates a configuration for the " 780 0 stevel "specified zone. %s should be\n\tused to " 781 0 stevel "begin configuring a new zone. If overwriting an " 782 0 stevel "existing\n\tconfiguration, the -F flag can be " 783 0 stevel "used to force the action. If\n\t-t template is " 784 0 stevel "given, creates a configuration identical to the\n" 785 0 stevel "\tspecified template, except that the zone name " 786 1634 gjelinek "is changed from\n\ttemplate to zonename. '%s -a' " 787 1634 gjelinek "creates a configuration from a\n\tdetached " 788 1634 gjelinek "zonepath. '%s -b' results in a blank " 789 1634 gjelinek "configuration.\n\t'%s' with no arguments applies " 790 1634 gjelinek "the Sun default settings."), 791 0 stevel cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE), 792 1634 gjelinek cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE)); 793 0 stevel return (line); 794 0 stevel case CMD_EXIT: 795 0 stevel return (gettext("Exits the program. The -F flag can " 796 0 stevel "be used to force the action.")); 797 0 stevel case CMD_EXPORT: 798 0 stevel return (gettext("Prints configuration to standard " 799 0 stevel "output, or to output-file if\n\tspecified, in " 800 0 stevel "a form suitable for use in a command-file.")); 801 0 stevel case CMD_ADD: 802 0 stevel return (gettext("Add specified resource to " 803 0 stevel "configuration.")); 804 0 stevel case CMD_DELETE: 805 0 stevel return (gettext("Deletes the specified zone. The -F " 806 0 stevel "flag can be used to force the\n\taction.")); 807 0 stevel case CMD_REMOVE: 808 0 stevel return (gettext("Remove specified resource from " 809 3247 gjelinek "configuration. The -F flag can be used\n\tto " 810 3247 gjelinek "force the action.")); 811 0 stevel case CMD_SELECT: 812 0 stevel (void) snprintf(line, sizeof (line), 813 0 stevel gettext("Selects a resource to modify. " 814 0 stevel "Resource modification is completed\n\twith the " 815 0 stevel "command \"%s\". The property name/value pairs " 816 0 stevel "must uniquely\n\tidentify a resource. Note that " 817 0 stevel "the curly braces ('{', '}') mean one\n\tor more " 818 0 stevel "of whatever is between them."), 819 0 stevel cmd_to_str(CMD_END)); 820 0 stevel return (line); 821 0 stevel case CMD_SET: 822 0 stevel return (gettext("Sets property values.")); 823 3247 gjelinek case CMD_CLEAR: 824 3247 gjelinek return (gettext("Clears property values.")); 825 0 stevel case CMD_INFO: 826 0 stevel return (gettext("Displays information about the " 827 0 stevel "current configuration. If resource\n\ttype is " 828 0 stevel "specified, displays only information about " 829 0 stevel "resources of\n\tthe relevant type. If resource " 830 0 stevel "id is specified, displays only\n\tinformation " 831 0 stevel "about that resource.")); 832 0 stevel case CMD_VERIFY: 833 0 stevel return (gettext("Verifies current configuration " 834 0 stevel "for correctness (some resource types\n\thave " 835 0 stevel "required properties).")); 836 0 stevel case CMD_COMMIT: 837 0 stevel (void) snprintf(line, sizeof (line), 838 0 stevel gettext("Commits current configuration. " 839 0 stevel "Configuration must be committed to\n\tbe used by " 840 0 stevel "%s. Until the configuration is committed, " 841 0 stevel "changes \n\tcan be removed with the %s " 842 0 stevel "command. This operation is\n\tattempted " 843 0 stevel "automatically upon completion of a %s " 844 0 stevel "session."), "zoneadm", cmd_to_str(CMD_REVERT), 845 0 stevel "zonecfg"); 846 0 stevel return (line); 847 0 stevel case CMD_REVERT: 848 0 stevel return (gettext("Reverts configuration back to the " 849 0 stevel "last committed state. The -F flag\n\tcan be " 850 0 stevel "used to force the action.")); 851 0 stevel case CMD_CANCEL: 852 0 stevel return (gettext("Cancels resource/property " 853 0 stevel "specification.")); 854 0 stevel case CMD_END: 855 0 stevel return (gettext("Ends resource/property " 856 0 stevel "specification.")); 857 0 stevel } 858 0 stevel /* NOTREACHED */ 859 222 comay return (NULL); 860 0 stevel } 861 0 stevel 862 0 stevel /* 863 0 stevel * Called with verbose TRUE when help is explicitly requested, FALSE for 864 0 stevel * unexpected errors. 865 0 stevel */ 866 0 stevel 867 0 stevel void 868 6215 gjelinek usage(boolean_t verbose, uint_t flags) 869 0 stevel { 870 0 stevel FILE *fp = verbose ? stdout : stderr, *newfp; 871 6215 gjelinek boolean_t need_to_close = B_FALSE; 872 0 stevel char *pager; 873 0 stevel int i; 874 0 stevel 875 0 stevel /* don't page error output */ 876 0 stevel if (verbose && interactive_mode) { 877 0 stevel if ((pager = getenv("PAGER")) == NULL) 878 0 stevel pager = PAGER; 879 0 stevel if ((newfp = popen(pager, "w")) != NULL) { 880 6215 gjelinek need_to_close = B_TRUE; 881 0 stevel fp = newfp; 882 0 stevel } 883 0 stevel } 884 0 stevel if (flags & HELP_META) { 885 0 stevel (void) fprintf(fp, gettext("More help is available for the " 886 0 stevel "following:\n")); 887 0 stevel (void) fprintf(fp, "\n\tcommands ('%s commands')\n", 888 0 stevel cmd_to_str(CMD_HELP)); 889 0 stevel (void) fprintf(fp, "\tsyntax ('%s syntax')\n", 890 0 stevel cmd_to_str(CMD_HELP)); 891 0 stevel (void) fprintf(fp, "\tusage ('%s usage')\n\n", 892 0 stevel cmd_to_str(CMD_HELP)); 893 0 stevel (void) fprintf(fp, gettext("You may also obtain help on any " 894 0 stevel "command by typing '%s <command-name>.'\n"), 895 0 stevel cmd_to_str(CMD_HELP)); 896 0 stevel } 897 0 stevel if (flags & HELP_RES_SCOPE) { 898 0 stevel switch (resource_scope) { 899 0 stevel case RT_FS: 900 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 901 0 stevel "used to configure a file-system.\n"), 902 0 stevel rt_to_str(resource_scope)); 903 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 904 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 905 0 stevel pt_to_str(PT_DIR), gettext("<path>")); 906 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 907 0 stevel pt_to_str(PT_SPECIAL), gettext("<path>")); 908 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 909 0 stevel pt_to_str(PT_RAW), gettext("<raw-device>")); 910 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 911 0 stevel pt_to_str(PT_TYPE), gettext("<file-system type>")); 912 0 stevel (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD), 913 0 stevel pt_to_str(PT_OPTIONS), 914 0 stevel gettext("<file-system options>")); 915 1645 comay (void) fprintf(fp, "\t%s %s %s\n", 916 1645 comay cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS), 917 1645 comay gettext("<file-system options>")); 918 0 stevel (void) fprintf(fp, gettext("Consult the file-system " 919 0 stevel "specific manual page, such as mount_ufs(1M), " 920 0 stevel "for\ndetails about file-system options. Note " 921 0 stevel "that any file-system options with an\nembedded " 922 0 stevel "'=' character must be enclosed in double quotes, " 923 0 stevel /*CSTYLED*/ 924 0 stevel "such as \"%s=5\".\n"), MNTOPT_RETRY); 925 0 stevel break; 926 0 stevel case RT_IPD: 927 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 928 0 stevel "used to configure a directory\ninherited from the " 929 0 stevel "global zone into a non-global zone in read-only " 930 0 stevel "mode.\n"), rt_to_str(resource_scope)); 931 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 932 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 933 0 stevel pt_to_str(PT_DIR), gettext("<path>")); 934 0 stevel break; 935 0 stevel case RT_NET: 936 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 937 0 stevel "used to configure a network interface.\n"), 938 0 stevel rt_to_str(resource_scope)); 939 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 940 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 941 0 stevel pt_to_str(PT_ADDRESS), gettext("<IP-address>")); 942 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 943 0 stevel pt_to_str(PT_PHYSICAL), gettext("<interface>")); 944 0 stevel (void) fprintf(fp, gettext("See ifconfig(1M) for " 945 0 stevel "details of the <interface> string.\n")); 946 6076 gfaden (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 947 6076 gfaden pt_to_str(PT_DEFROUTER), gettext("<IP-address>")); 948 6076 gfaden (void) fprintf(fp, gettext("%s %s and %s %s are valid " 949 6076 gfaden "if the %s property is set to %s, otherwise they " 950 6076 gfaden "must not be set.\n"), 951 3448 dh155122 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS), 952 6076 gfaden cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER), 953 3448 dh155122 pt_to_str(PT_IPTYPE), "shared"); 954 0 stevel break; 955 0 stevel case RT_DEVICE: 956 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 957 0 stevel "used to configure a device node.\n"), 958 0 stevel rt_to_str(resource_scope)); 959 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 960 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 961 0 stevel pt_to_str(PT_MATCH), gettext("<device-path>")); 962 0 stevel break; 963 0 stevel case RT_RCTL: 964 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 965 0 stevel "used to configure a resource control.\n"), 966 0 stevel rt_to_str(resource_scope)); 967 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 968 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 969 0 stevel pt_to_str(PT_NAME), gettext("<string>")); 970 0 stevel (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 971 0 stevel cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 972 1645 comay pt_to_str(PT_PRIV), gettext("<priv-value>"), 973 1645 comay pt_to_str(PT_LIMIT), gettext("<number>"), 974 1645 comay pt_to_str(PT_ACTION), gettext("<action-value>")); 975 1645 comay (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 976 1645 comay cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE), 977 0 stevel pt_to_str(PT_PRIV), gettext("<priv-value>"), 978 0 stevel pt_to_str(PT_LIMIT), gettext("<number>"), 979 0 stevel pt_to_str(PT_ACTION), gettext("<action-value>")); 980 0 stevel (void) fprintf(fp, "%s\n\t%s := privileged\n" 981 0 stevel "\t%s := none | deny\n", gettext("Where"), 982 0 stevel gettext("<priv-value>"), gettext("<action-value>")); 983 0 stevel break; 984 0 stevel case RT_ATTR: 985 0 stevel (void) fprintf(fp, gettext("The '%s' resource scope is " 986 0 stevel "used to configure a generic attribute.\n"), 987 0 stevel rt_to_str(resource_scope)); 988 0 stevel (void) fprintf(fp, gettext("Valid commands:\n")); 989 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 990 0 stevel pt_to_str(PT_NAME), gettext("<name>")); 991 0 stevel (void) fprintf(fp, "\t%s %s=boolean\n", 992 0 stevel cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 993 0 stevel (void) fprintf(fp, "\t%s %s=true | false\n", 994 0 stevel cmd_to_str(CMD_SET), pt_to_str(PT_VALUE)); 995 0 stevel (void) fprintf(fp, gettext("or\n")); 996 0 stevel (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET), 997 0 stevel pt_to_str(PT_TYPE)); 998 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 999 0 stevel pt_to_str(PT_VALUE), gettext("<integer>")); 1000 0 stevel (void) fprintf(fp, gettext("or\n")); 1001 0 stevel (void) fprintf(fp, "\t%s %s=string\n", 1002 0 stevel cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 1003 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1004 0 stevel pt_to_str(PT_VALUE), gettext("<string>")); 1005 0 stevel (void) fprintf(fp, gettext("or\n")); 1006 0 stevel (void) fprintf(fp, "\t%s %s=uint\n", 1007 0 stevel cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 1008 0 stevel (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1009 0 stevel pt_to_str(PT_VALUE), gettext("<unsigned integer>")); 1010 0 stevel break; 1011 789 ahrens case RT_DATASET: 1012 789 ahrens (void) fprintf(fp, gettext("The '%s' resource scope is " 1013 789 ahrens "used to export ZFS datasets.\n"), 1014 789 ahrens rt_to_str(resource_scope)); 1015 789 ahrens (void) fprintf(fp, gettext("Valid commands:\n")); 1016 789 ahrens (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1017 789 ahrens pt_to_str(PT_NAME), gettext("<name>")); 1018 789 ahrens break; 1019 3247 gjelinek case RT_DCPU: 1020 3247 gjelinek (void) fprintf(fp, gettext("The '%s' resource scope " 1021 3247 gjelinek "configures the 'pools' facility to dedicate\na " 1022 3247 gjelinek "subset of the system's processors to this zone " 1023 3247 gjelinek "while it is running.\n"), 1024 3247 gjelinek rt_to_str(resource_scope)); 1025 3247 gjelinek (void) fprintf(fp, gettext("Valid commands:\n")); 1026 3247 gjelinek (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1027 3247 gjelinek pt_to_str(PT_NCPUS), 1028 3247 gjelinek gettext("<unsigned integer | range>")); 1029 3247 gjelinek (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1030 3247 gjelinek pt_to_str(PT_IMPORTANCE), 1031 3247 gjelinek gettext("<unsigned integer>")); 1032 3247 gjelinek break; 1033 3792 akolb case RT_PCAP: 1034 3792 akolb (void) fprintf(fp, gettext("The '%s' resource scope is " 1035 3792 akolb "used to set an upper limit (a cap) on the\n" 1036 3792 akolb "percentage of CPU that can be used by this zone. " 1037 3792 akolb "A '%s' value of 1\ncorresponds to one cpu. The " 1038 3792 akolb "value can be set higher than 1, up to the total\n" 1039 3792 akolb "number of CPUs on the system. The value can " 1040 3792 akolb "also be less than 1,\nrepresenting a fraction of " 1041 3792 akolb "a cpu.\n"), 1042 3792 akolb rt_to_str(resource_scope), pt_to_str(PT_NCPUS)); 1043 3792 akolb (void) fprintf(fp, gettext("Valid commands:\n")); 1044 3792 akolb (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1045 3792 akolb pt_to_str(PT_NCPUS), gettext("<unsigned decimal>")); 1046 3792 akolb break; 1047 3247 gjelinek case RT_MCAP: 1048 3247 gjelinek (void) fprintf(fp, gettext("The '%s' resource scope is " 1049 3247 gjelinek "used to set an upper limit (a cap) on the\n" 1050 3247 gjelinek "amount of physical memory, swap space and locked " 1051 3247 gjelinek "memory that can be used by\nthis zone.\n"), 1052 3247 gjelinek rt_to_str(resource_scope)); 1053 3247 gjelinek (void) fprintf(fp, gettext("Valid commands:\n")); 1054 3247 gjelinek (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1055 3247 gjelinek pt_to_str(PT_PHYSICAL), 1056 3247 gjelinek gettext("<qualified unsigned decimal>")); 1057 3247 gjelinek (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1058 3247 gjelinek pt_to_str(PT_SWAP), 1059 3247 gjelinek gettext("<qualified unsigned decimal>")); 1060 3247 gjelinek (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1061 3247 gjelinek pt_to_str(PT_LOCKED), 1062 3247 gjelinek gettext("<qualified unsigned decimal>")); 1063 3247 gjelinek break; 1064 0 stevel } 1065 0 stevel (void) fprintf(fp, gettext("And from any resource scope, you " 1066 0 stevel "can:\n")); 1067 0 stevel (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END), 1068 0 stevel gettext("(to conclude this operation)")); 1069 0 stevel (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL), 1070 0 stevel gettext("(to cancel this operation)")); 1071 0 stevel (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT), 1072 0 stevel gettext("(to exit the zonecfg utility)")); 1073 0 stevel } 1074 0 stevel if (flags & HELP_USAGE) { 1075 0 stevel (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"), 1076 0 stevel execname, cmd_to_str(CMD_HELP)); 1077 0 stevel (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n", 1078 0 stevel execname, gettext("interactive")); 1079 0 stevel (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname); 1080 0 stevel (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n", 1081 0 stevel execname); 1082 0 stevel } 1083 0 stevel if (flags & HELP_SUBCMDS) { 1084 0 stevel (void) fprintf(fp, "%s:\n\n", gettext("Commands")); 1085 0 stevel for (i = 0; i <= CMD_MAX; i++) { 1086 0 stevel (void) fprintf(fp, "%s\n", helptab[i].short_usage); 1087 0 stevel if (verbose) 1088 0 stevel (void) fprintf(fp, "\t%s\n\n", long_help(i)); 1089 0 stevel } 1090 0 stevel } 1091 0 stevel if (flags & HELP_SYNTAX) { 1092 0 stevel if (!verbose) 1093 0 stevel (void) fprintf(fp, "\n"); 1094 0 stevel (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n"); 1095 0 stevel (void) fprintf(fp, gettext("\t(except the reserved words " 1096 0 stevel "'%s' and anything starting with '%s')\n"), "global", 1097 0 stevel "SUNW"); 1098 0 stevel (void) fprintf(fp, 1099 0 stevel gettext("\tName must be less than %d characters.\n"), 1100 0 stevel ZONENAME_MAX); 1101 0 stevel if (verbose) 1102 0 stevel (void) fprintf(fp, "\n"); 1103 0 stevel } 1104 0 stevel if (flags & HELP_NETADDR) { 1105 0 stevel (void) fprintf(fp, gettext("\n<net-addr> :=")); 1106 0 stevel (void) fprintf(fp, 1107 0 stevel gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n")); 1108 0 stevel (void) fprintf(fp, 1109 0 stevel gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n")); 1110 0 stevel (void) fprintf(fp, 1111 0 stevel gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n")); 1112 0 stevel (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and " 1113 0 stevel "IPv6 address syntax.\n")); 1114 0 stevel (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n")); 1115 0 stevel (void) fprintf(fp, 1116 0 stevel gettext("<IPv6-prefix-length> := [0-128]\n")); 1117 0 stevel (void) fprintf(fp, 1118 0 stevel gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n")); 1119 0 stevel } 1120 0 stevel if (flags & HELP_RESOURCES) { 1121 2607 dp (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t" 1122 3792 akolb "%s | %s | %s | %s\n\n", 1123 0 stevel gettext("resource type"), rt_to_str(RT_FS), 1124 0 stevel rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE), 1125 2607 dp rt_to_str(RT_RCTL), rt_to_str(RT_ATTR), 1126 3247 gjelinek rt_to_str(RT_DATASET), rt_to_str(RT_DCPU), 1127 3792 akolb rt_to_str(RT_PCAP), rt_to_str(RT_MCAP)); 1128 0 stevel } 1129 0 stevel if (flags & HELP_PROPS) { 1130 0 stevel (void) fprintf(fp, gettext("For resource type ... there are " 1131 0 stevel "property types ...:\n")); 1132 0 stevel (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1133 565 dp pt_to_str(PT_ZONENAME)); 1134 565 dp (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1135 0 stevel pt_to_str(PT_ZONEPATH)); 1136 0 stevel (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1137 2712 nn35248 pt_to_str(PT_BRAND)); 1138 2712 nn35248 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1139 0 stevel pt_to_str(PT_AUTOBOOT)); 1140 0 stevel (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1141 2267 dp pt_to_str(PT_BOOTARGS)); 1142 2267 dp (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1143 0 stevel pt_to_str(PT_POOL)); 1144 1645 comay (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1145 1645 comay pt_to_str(PT_LIMITPRIV)); 1146 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1147 3247 gjelinek pt_to_str(PT_SCHED)); 1148 3448 dh155122 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1149 3448 dh155122 pt_to_str(PT_IPTYPE)); 1150 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1151 8662 Jordan pt_to_str(PT_HOSTID)); 1152 8662 Jordan (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1153 3247 gjelinek pt_to_str(PT_MAXLWPS)); 1154 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1155 3247 gjelinek pt_to_str(PT_MAXSHMMEM)); 1156 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1157 3247 gjelinek pt_to_str(PT_MAXSHMIDS)); 1158 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1159 3247 gjelinek pt_to_str(PT_MAXMSGIDS)); 1160 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1161 3247 gjelinek pt_to_str(PT_MAXSEMIDS)); 1162 3247 gjelinek (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1163 3247 gjelinek pt_to_str(PT_SHARES)); 1164 0 stevel (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s\n", rt_to_str(RT_FS), 1165 0 stevel pt_to_str(PT_DIR), pt_to_str(PT_SPECIAL), 1166 0 stevel pt_to_str(PT_RAW), pt_to_str(PT_TYPE), 1167 0 stevel pt_to_str(PT_OPTIONS)); 1168 0 stevel (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_IPD), 1169 0 stevel pt_to_str(PT_DIR)); 1170 6076 gfaden (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_NET), 1171 6076 gfaden pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL), 1172 6076 gfaden pt_to_str(PT_DEFROUTER)); 1173 0 stevel (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE), 1174 0 stevel pt_to_str(PT_MATCH)); 1175 0 stevel (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL), 1176 0 stevel pt_to_str(PT_NAME), pt_to_str(PT_VALUE)); 1177 0 stevel (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR), 1178 0 stevel pt_to_str(PT_NAME), pt_to_str(PT_TYPE), 1179 0 stevel pt_to_str(PT_VALUE)); 1180 789 ahrens (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET), 1181 789 ahrens pt_to_str(PT_NAME)); 1182 3247 gjelinek (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU), 1183 3247 gjelinek pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE)); 1184 3792 akolb (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP), 1185 3792 akolb pt_to_str(PT_NCPUS)); 1186 3247 gjelinek (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP), 1187 3247 gjelinek pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP), 1188 3247 gjelinek pt_to_str(PT_LOCKED)); 1189 0 stevel } 1190 0 stevel if (need_to_close) 1191 0 stevel (void) pclose(fp); 1192 0 stevel } 1193 0 stevel 1194 0 stevel /* PRINTFLIKE1 */ 1195 0 stevel static void 1196 0 stevel zerr(const char *fmt, ...) 1197 0 stevel { 1198 0 stevel va_list alist; 1199 0 stevel static int last_lineno; 1200 0 stevel 1201 0 stevel /* lex_lineno has already been incremented in the lexer; compensate */ 1202 0 stevel if (cmd_file_mode && lex_lineno > last_lineno) { 1203 0 stevel if (strcmp(cmd_file_name, "-") == 0) 1204 0 stevel (void) fprintf(stderr, gettext("On line %d:\n"), 1205 0 stevel lex_lineno - 1); 1206 0 stevel else 1207 0 stevel (void) fprintf(stderr, gettext("On line %d of %s:\n"), 1208 0 stevel lex_lineno - 1, cmd_file_name); 1209 0 stevel last_lineno = lex_lineno; 1210 0 stevel } 1211 0 stevel va_start(alist, fmt); 1212 0 stevel (void) vfprintf(stderr, fmt, alist); 1213 0 stevel (void) fprintf(stderr, "\n"); 1214 0 stevel va_end(alist); 1215 0 stevel } 1216 0 stevel 1217 0 stevel static void 1218 6215 gjelinek zone_perror(char *prefix, int err, boolean_t set_saw) 1219 0 stevel { 1220 0 stevel zerr("%s: %s", prefix, zonecfg_strerror(err)); 1221 0 stevel if (set_saw) 1222 6215 gjelinek saw_error = B_TRUE; 1223 0 stevel } 1224 0 stevel 1225 0 stevel /* 1226 0 stevel * zone_perror() expects a single string, but for remove and select 1227 0 stevel * we have both the command and the resource type, so this wrapper 1228 0 stevel * function serves the same purpose in a slightly different way. 1229 0 stevel */ 1230 0 stevel 1231 0 stevel static void 1232 6215 gjelinek z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw) 1233 0 stevel { 1234 0 stevel zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num), 1235 0 stevel zonecfg_strerror(err)); 1236 0 stevel if (set_saw) 1237 6215 gjelinek saw_error = B_TRUE; 1238 0 stevel } 1239 0 stevel 1240 0 stevel /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */ 1241 0 stevel static int 1242 6215 gjelinek initialize(boolean_t handle_expected) 1243 0 stevel { 1244 0 stevel int err; 1245 2712 nn35248 char brandname[MAXNAMELEN]; 1246 0 stevel 1247 0 stevel if (zonecfg_check_handle(handle) != Z_OK) { 1248 0 stevel if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) { 1249 6215 gjelinek got_handle = B_TRUE; 1250 2712 nn35248 if (zonecfg_get_brand(handle, brandname, 1251 2712 nn35248 sizeof (brandname)) != Z_OK) { 1252 2712 nn35248 zerr("Zone %s is inconsistent: missing " 1253 2712 nn35248 "brand attribute", zone); 1254 2712 nn35248 exit(Z_ERR); 1255 2712 nn35248 } 1256 2712 nn35248 if ((brand = brand_open(brandname)) == NULL) { 1257 2712 nn35248 zerr("Zone %s uses non-existent brand \"%s\"." 1258 2712 nn35248 " Unable to continue", zone, brandname); 1259 2712 nn35248 exit(Z_ERR); 1260 2712 nn35248 } 1261 3247 gjelinek } else if (global_zone && err == Z_NO_ZONE && !got_handle && 1262 3247 gjelinek !read_only_mode) { 1263 3247 gjelinek /* 1264 3247 gjelinek * We implicitly create the global zone config if it 1265 3247 gjelinek * doesn't exist. 1266 3247 gjelinek */ 1267 3247 gjelinek zone_dochandle_t tmphandle; 1268 3247 gjelinek 1269 3247 gjelinek if ((tmphandle = zonecfg_init_handle()) == NULL) { 1270 6215 gjelinek zone_perror(execname, Z_NOMEM, B_TRUE); 1271 3247 gjelinek exit(Z_ERR); 1272 3247 gjelinek } 1273 3247 gjelinek 1274 3247 gjelinek err = zonecfg_get_template_handle("SUNWblank", zone, 1275 3247 gjelinek tmphandle); 1276 3247 gjelinek 1277 3247 gjelinek if (err != Z_OK) { 1278 3247 gjelinek zonecfg_fini_handle(tmphandle); 1279 6215 gjelinek zone_perror("SUNWblank", err, B_TRUE); 1280 3247 gjelinek return (err); 1281 3247 gjelinek } 1282 3247 gjelinek 1283 6215 gjelinek need_to_commit = B_TRUE; 1284 3247 gjelinek zonecfg_fini_handle(handle); 1285 3247 gjelinek handle = tmphandle; 1286 6215 gjelinek got_handle = B_TRUE; 1287 3247 gjelinek 1288 0 stevel } else { 1289 0 stevel zone_perror(zone, err, handle_expected || got_handle); 1290 0 stevel if (err == Z_NO_ZONE && !got_handle && 1291 0 stevel interactive_mode && !read_only_mode) 1292 0 stevel (void) printf(gettext("Use '%s' to begin " 1293 0 stevel "configuring a new zone.\n"), 1294 0 stevel cmd_to_str(CMD_CREATE)); 1295 0 stevel return (err); 1296 0 stevel } 1297 0 stevel } 1298 0 stevel return (Z_OK); 1299 0 stevel } 1300 0 stevel 1301 6215 gjelinek static boolean_t 1302 565 dp state_atleast(zone_state_t state) 1303 565 dp { 1304 565 dp zone_state_t state_num; 1305 565 dp int err; 1306 565 dp 1307 565 dp if ((err = zone_get_state(zone, &state_num)) != Z_OK) { 1308 565 dp /* all states are greater than "non-existent" */ 1309 565 dp if (err == Z_NO_ZONE) 1310 565 dp return (B_FALSE); 1311 565 dp zerr(gettext("Unexpectedly failed to determine state " 1312 565 dp "of zone %s: %s"), zone, zonecfg_strerror(err)); 1313 565 dp exit(Z_ERR); 1314 565 dp } 1315 565 dp return (state_num >= state); 1316 565 dp } 1317 565 dp 1318 0 stevel /* 1319 0 stevel * short_usage() is for bad syntax: getopt() issues, too many arguments, etc. 1320 0 stevel */ 1321 0 stevel 1322 0 stevel void 1323 0 stevel short_usage(int command) 1324 0 stevel { 1325 0 stevel /* lex_lineno has already been incremented in the lexer; compensate */ 1326 0 stevel if (cmd_file_mode) { 1327 0 stevel if (strcmp(cmd_file_name, "-") == 0) 1328 0 stevel (void) fprintf(stderr, 1329 0 stevel gettext("syntax error on line %d\n"), 1330 0 stevel lex_lineno - 1); 1331 0 stevel else 1332 0 stevel (void) fprintf(stderr, 1333 0 stevel gettext("syntax error on line %d of %s\n"), 1334 0 stevel lex_lineno - 1, cmd_file_name); 1335 0 stevel } 1336 0 stevel (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"), 1337 0 stevel helptab[command].short_usage); 1338 6215 gjelinek saw_error = B_TRUE; 1339 0 stevel } 1340 0 stevel 1341 0 stevel /* 1342 0 stevel * long_usage() is for bad semantics: e.g., wrong property type for a given 1343 0 stevel * resource type. It is also used by longer_usage() below. 1344 0 stevel */ 1345 0 stevel 1346 0 stevel void 1347 6215 gjelinek long_usage(uint_t cmd_num, boolean_t set_saw) 1348 0 stevel { 1349 0 stevel (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"), 1350 0 stevel helptab[cmd_num].short_usage); 1351 0 stevel (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num)); 1352 0 stevel if (set_saw) 1353 6215 gjelinek saw_error = B_TRUE; 1354 0 stevel } 1355 0 stevel 1356 0 stevel /* 1357 0 stevel * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also 1358 0 stevel * any extra usage() flags as appropriate for whatever command. 1359 0 stevel */ 1360 0 stevel 1361 0 stevel void 1362 0 stevel longer_usage(uint_t cmd_num) 1363 0 stevel { 1364 6215 gjelinek long_usage(cmd_num, B_FALSE); 1365 0 stevel if (helptab[cmd_num].flags != 0) { 1366 0 stevel (void) printf("\n"); 1367 6215 gjelinek usage(B_TRUE, helptab[cmd_num].flags); 1368 0 stevel } 1369 0 stevel } 1370 0 stevel 1371 0 stevel /* 1372 0 stevel * scope_usage() is simply used when a command is called from the wrong scope. 1373 0 stevel */ 1374 0 stevel 1375 0 stevel static void 1376 0 stevel scope_usage(uint_t cmd_num) 1377 0 stevel { 1378 0 stevel zerr(gettext("The %s command only makes sense in the %s scope."), 1379 0 stevel cmd_to_str(cmd_num), 1380 0 stevel global_scope ? gettext("resource") : gettext("global")); 1381 6215 gjelinek saw_error = B_TRUE; 1382 6215 gjelinek } 1383 6215 gjelinek 1384 6215 gjelinek /* 1385 6215 gjelinek * On input, B_TRUE => yes, B_FALSE => no. 1386 6215 gjelinek * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1. 1387 6215 gjelinek */ 1388 6215 gjelinek 1389 6215 gjelinek static int 1390 6215 gjelinek ask_yesno(boolean_t default_answer, const char *question) 1391 0 stevel { 1392 0 stevel char line[64]; /* should be enough to answer yes or no */ 1393 0 stevel 1394 0 stevel if (!ok_to_prompt) { 1395 6215 gjelinek saw_error = B_TRUE; 1396 0 stevel return (-1); 1397 0 stevel } 1398 0 stevel for (;;) { 1399 565 dp if (printf("%s (%s)? ", question, 1400 565 dp default_answer ? "[y]/n" : "y/[n]") < 0) 1401 565 dp return (-1); 1402 565 dp if (fgets(line, sizeof (line), stdin) == NULL) 1403 565 dp return (-1); 1404 565 dp 1405 565 dp if (line[0] == '\n') 1406 0 stevel return (default_answer ? 1 : 0); 1407 0 stevel if (tolower(line[0]) == 'y') 1408 0 stevel return (1); 1409 0 stevel if (tolower(line[0]) == 'n') 1410 0 stevel return (0); 1411 0 stevel } 1412 0 stevel } 1413 0 stevel 1414 0 stevel /* 1415 0 stevel * Prints warning if zone already exists. 1416 0 stevel * In interactive mode, prompts if we should continue anyway and returns Z_OK 1417 0 stevel * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR. 1418 0 stevel * 1419 0 stevel * Note that if a zone exists and its state is >= INSTALLED, an error message 1420 0 stevel * will be printed and this function will return Z_ERR regardless of mode. 1421 0 stevel */ 1422 0 stevel 1423 0 stevel static int 1424 6215 gjelinek check_if_zone_already_exists(boolean_t force) 1425 0 stevel { 1426 0 stevel char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 1427 0 stevel zone_dochandle_t tmphandle; 1428 0 stevel int res, answer; 1429 0 stevel 1430 0 stevel if ((tmphandle = zonecfg_init_handle()) == NULL) { 1431 6215 gjelinek zone_perror(execname, Z_NOMEM, B_TRUE); 1432 0 stevel exit(Z_ERR); 1433 0 stevel } 1434 0 stevel res = zonecfg_get_handle(zone, tmphandle); 1435 0 stevel zonecfg_fini_handle(tmphandle); 1436 565 dp if (res != Z_OK) 1437 565 dp return (Z_OK); 1438 565 dp 1439 565 dp if (state_atleast(ZONE_STATE_INSTALLED)) { 1440 0 stevel zerr(gettext("Zone %s already installed; %s not allowed."), 1441 0 stevel zone, cmd_to_str(CMD_CREATE)); 1442 0 stevel return (Z_ERR); 1443 0 stevel } 1444 0 stevel 1445 0 stevel if (force) { 1446 0 stevel (void) printf(gettext("Zone %s already exists; overwriting.\n"), 1447 0 stevel zone); 1448 0 stevel return (Z_OK); 1449 0 stevel } 1450 0 stevel (void) snprintf(line, sizeof (line), 1451 0 stevel gettext("Zone %s already exists; %s anyway"), zone, 1452 0 stevel cmd_to_str(CMD_CREATE)); 1453 6215 gjelinek if ((answer = ask_yesno(B_FALSE, line)) == -1) { 1454 0 stevel zerr(gettext("Zone exists, input not from terminal and -F not " 1455 0 stevel "specified:\n%s command ignored, exiting."), 1456 0 stevel cmd_to_str(CMD_CREATE)); 1457 0 stevel exit(Z_ERR); 1458 0 stevel } 1459 0 stevel return (answer == 1 ? Z_OK : Z_ERR); 1460 0 stevel } 1461 0 stevel 1462 6215 gjelinek static boolean_t 1463 0 stevel zone_is_read_only(int cmd_num) 1464 0 stevel { 1465 0 stevel if (strncmp(zone, "SUNW", 4) == 0) { 1466 0 stevel zerr(gettext("%s: zones beginning with SUNW are read-only."), 1467 0 stevel zone); 1468 6215 gjelinek saw_error = B_TRUE; 1469 6215 gjelinek return (B_TRUE); 1470 0 stevel } 1471 0 stevel if (read_only_mode) { 1472 0 stevel zerr(gettext("%s: cannot %s in read-only mode."), zone, 1473 0 stevel cmd_to_str(cmd_num)); 1474 6215 gjelinek saw_error = B_TRUE; 1475 6215 gjelinek return (B_TRUE); 1476 6215 gjelinek } 1477 6215 gjelinek return (B_FALSE); 1478 0 stevel } 1479 0 stevel 1480 0 stevel /* 1481 0 stevel * Create a new configuration. 1482 0 stevel */ 1483 0 stevel void 1484 0 stevel create_func(cmd_t *cmd) 1485 0 stevel { 1486 0 stevel int err, arg; 1487 0 stevel char zone_template[ZONENAME_MAX]; 1488 1507 gjelinek char attach_path[MAXPATHLEN]; 1489 0 stevel zone_dochandle_t tmphandle; 1490 6215 gjelinek boolean_t force = B_FALSE; 1491 6215 gjelinek boolean_t attach = B_FALSE; 1492 6215 gjelinek boolean_t arg_err = B_FALSE; 1493 0 stevel 1494 0 stevel assert(cmd != NULL); 1495 0 stevel 1496 0 stevel /* This is the default if no arguments are given. */ 1497 0 stevel (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template)); 1498 0 stevel 1499 0 stevel optind = 0; 1500 2712 nn35248 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:")) 1501 2712 nn35248 != EOF) { 1502 0 stevel switch (arg) { 1503 0 stevel case '?': 1504 0 stevel if (optopt == '?') 1505 0 stevel longer_usage(CMD_CREATE); 1506 0 stevel else 1507 0 stevel short_usage(CMD_CREATE); 1508 6215 gjelinek arg_err = B_TRUE; 1509 3691 gjelinek break; 1510 1507 gjelinek case 'a': 1511 1507 gjelinek (void) strlcpy(attach_path, optarg, 1512 1507 gjelinek sizeof (attach_path)); 1513 6215 gjelinek attach = B_TRUE; 1514 1507 gjelinek break; 1515 0 stevel case 'b': 1516 0 stevel (void) strlcpy(zone_template, "SUNWblank", 1517 0 stevel sizeof (zone_template)); 1518 0 stevel break; 1519 0 stevel case 'F': 1520 6215 gjelinek force = B_TRUE; 1521 0 stevel break; 1522 0 stevel case 't': 1523 0 stevel (void) strlcpy(zone_template, optarg, 1524 0 stevel sizeof (zone_template)); 1525 0 stevel break; 1526 0 stevel default: 1527 0 stevel short_usage(CMD_CREATE); 1528 6215 gjelinek arg_err = B_TRUE; 1529 3691 gjelinek break; 1530 3691 gjelinek } 1531 3691 gjelinek } 1532 3691 gjelinek if (arg_err) 1533 3691 gjelinek return; 1534 3691 gjelinek 1535 0 stevel if (optind != cmd->cmd_argc) { 1536 0 stevel short_usage(CMD_CREATE); 1537 0 stevel return; 1538 0 stevel } 1539 0 stevel 1540 0 stevel if (zone_is_read_only(CMD_CREATE)) 1541 0 stevel return; 1542 0 stevel 1543 0 stevel if (check_if_zone_already_exists(force) != Z_OK) 1544 0 stevel return; 1545 0 stevel 1546 0 stevel /* 1547 0 stevel * Get a temporary handle first. If that fails, the old handle 1548 0 stevel * will not be lost. Then finish whichever one we don't need, 1549 0 stevel * to avoid leaks. Then get the handle for zone_template, and 1550 0 stevel * set the name to zone: this "copy, rename" method is how 1551 0 stevel * create -[b|t] works. 1552 0 stevel */ 1553 0 stevel if ((tmphandle = zonecfg_init_handle()) == NULL) { 1554 6215 gjelinek zone_perror(execname, Z_NOMEM, B_TRUE); 1555 0 stevel exit(Z_ERR); 1556 0 stevel } 1557 1507 gjelinek 1558 1507 gjelinek if (attach) 1559 7257 gjelinek err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED, 1560 7257 gjelinek zone, B_FALSE, tmphandle); 1561 1507 gjelinek else 1562 1507 gjelinek err = zonecfg_get_template_handle(zone_template, zone, 1563 1507 gjelinek tmphandle); 1564 1507 gjelinek 1565 1507 gjelinek if (err != Z_OK) { 1566 0 stevel zonecfg_fini_handle(tmphandle); 1567 1507 gjelinek if (attach && err == Z_NO_ZONE) 1568 1507 gjelinek (void) fprintf(stderr, gettext("invalid path to " 1569 1507 gjelinek "detached zone\n")); 1570 1507 gjelinek else if (attach && err == Z_INVALID_DOCUMENT) 1571 1507 gjelinek (void) fprintf(stderr, gettext("Cannot attach to an " 1572 1507 gjelinek "earlier release of the operating system\n")); 1573 1507 gjelinek else 1574 6215 gjelinek zone_perror(zone_template, err, B_TRUE); 1575 6215 gjelinek return; 1576 6215 gjelinek } 1577 6215 gjelinek 1578 6215 gjelinek need_to_commit = B_TRUE; 1579 0 stevel zonecfg_fini_handle(handle); 1580 0 stevel handle = tmphandle; 1581 6215 gjelinek got_handle = B_TRUE; 1582 0 stevel } 1583 0 stevel 1584 0 stevel /* 1585 0 stevel * This malloc()'s memory, which must be freed by the caller. 1586 0 stevel */ 1587 0 stevel static char * 1588 0 stevel quoteit(char *instr) 1589 0 stevel { 1590 0 stevel char *outstr; 1591 0 stevel size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */ 1592 0 stevel 1593 0 stevel if ((outstr = malloc(outstrsize)) == NULL) { 1594 6215 gjelinek zone_perror(zone, Z_NOMEM, B_FALSE); 1595 0 stevel exit(Z_ERR); 1596 0 stevel } 1597 0 stevel if (strchr(instr, ' ') == NULL) { 1598 0 stevel (void) strlcpy(outstr, instr, outstrsize); 1599 0 stevel return (outstr); 1600 0 stevel } 1601 0 stevel (void) snprintf(outstr, outstrsize, "\"%s\"", instr); 1602 0 stevel return (outstr); 1603 0 stevel } 1604 0 stevel 1605 0 stevel static void 1606 0 stevel export_prop(FILE *of, int prop_num, char *prop_id) 1607 0 stevel { 1608 0 stevel char *quote_str; 1609 0 stevel 1610 0 stevel if (strlen(prop_id) == 0) 1611 0 stevel return; 1612 0 stevel quote_str = quoteit(prop_id); 1613 0 stevel (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1614 0 stevel pt_to_str(prop_num), quote_str); 1615 0 stevel free(quote_str); 1616 0 stevel } 1617 0 stevel 1618 0 stevel void 1619 0 stevel export_func(cmd_t *cmd) 1620 0 stevel { 1621 0 stevel struct zone_nwiftab nwiftab; 1622 0 stevel struct zone_fstab fstab; 1623 0 stevel struct zone_devtab devtab; 1624 0 stevel struct zone_attrtab attrtab; 1625 0 stevel struct zone_rctltab rctltab; 1626 789 ahrens struct zone_dstab dstab; 1627 3247 gjelinek struct zone_psettab psettab; 1628 3247 gjelinek struct zone_mcaptab mcaptab; 1629 0 stevel struct zone_rctlvaltab *valptr; 1630 0 stevel int err, arg; 1631 0 stevel char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN]; 1632 2267 dp char bootargs[BOOTARGS_MAX]; 1633 3247 gjelinek char sched[MAXNAMELEN]; 1634 2712 nn35248 char brand[MAXNAMELEN]; 1635 8662 Jordan char hostidp[HW_HOSTID_LEN]; 1636 1645 comay char *limitpriv; 1637 0 stevel FILE *of; 1638 0 stevel boolean_t autoboot; 1639 3448 dh155122 zone_iptype_t iptype; 1640 6215 gjelinek boolean_t need_to_close = B_FALSE; 1641 6215 gjelinek boolean_t arg_err = B_FALSE; 1642 0 stevel 1643 0 stevel assert(cmd != NULL); 1644 0 stevel 1645 0 stevel outfile[0] = '\0'; 1646 0 stevel optind = 0; 1647 0 stevel while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) { 1648 0 stevel switch (arg) { 1649 0 stevel case '?': 1650 0 stevel if (optopt == '?') 1651 0 stevel longer_usage(CMD_EXPORT); 1652 0 stevel else 1653 0 stevel short_usage(CMD_EXPORT); 1654 6215 gjelinek arg_err = B_TRUE; 1655 3691 gjelinek break; 1656 0 stevel case 'f': 1657 0 stevel (void) strlcpy(outfile, optarg, sizeof (outfile)); 1658 0 stevel break; 1659 0 stevel default: 1660 0 stevel short_usage(CMD_EXPORT); 1661 6215 gjelinek arg_err = B_TRUE; 1662 3691 gjelinek break; 1663 3691 gjelinek } 1664 3691 gjelinek } 1665 3691 gjelinek if (arg_err) 1666 3691 gjelinek return; 1667 3691 gjelinek 1668 0 stevel if (optind != cmd->cmd_argc) { 1669 0 stevel short_usage(CMD_EXPORT); 1670 0 stevel return; 1671 0 stevel } 1672 0 stevel if (strlen(outfile) == 0) { 1673 0 stevel of = stdout; 1674 0 stevel } else { 1675 0 stevel if ((of = fopen(outfile, "w")) == NULL) { 1676 0 stevel zerr(gettext("opening file %s: %s"), 1677 0 stevel outfile, strerror(errno)); 1678 0 stevel goto done; 1679 0 stevel } 1680 0 stevel setbuf(of, NULL); 1681 6215 gjelinek need_to_close = B_TRUE; 1682 6215 gjelinek } 1683 6215 gjelinek 1684 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 1685 0 stevel goto done; 1686 0 stevel 1687 0 stevel (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE)); 1688 0 stevel 1689 0 stevel if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK && 1690 0 stevel strlen(zonepath) > 0) 1691 0 stevel (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1692 0 stevel pt_to_str(PT_ZONEPATH), zonepath); 1693 2712 nn35248 1694 2712 nn35248 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) && 1695 2712 nn35248 (strcmp(brand, NATIVE_BRAND_NAME) != 0)) 1696 2712 nn35248 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1697 2712 nn35248 pt_to_str(PT_BRAND), brand); 1698 0 stevel 1699 0 stevel if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK) 1700 0 stevel (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1701 0 stevel pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false"); 1702 0 stevel 1703 2267 dp if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK && 1704 2267 dp strlen(bootargs) > 0) { 1705 2267 dp (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1706 2267 dp pt_to_str(PT_BOOTARGS), bootargs); 1707 2267 dp } 1708 2267 dp 1709 0 stevel if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 1710 0 stevel strlen(pool) > 0) 1711 0 stevel (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1712 0 stevel pt_to_str(PT_POOL), pool); 1713 1645 comay 1714 1645 comay if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK && 1715 1645 comay strlen(limitpriv) > 0) { 1716 1645 comay (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1717 1645 comay pt_to_str(PT_LIMITPRIV), limitpriv); 1718 1645 comay free(limitpriv); 1719 1645 comay } 1720 2267 dp 1721 3247 gjelinek if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK && 1722 3247 gjelinek strlen(sched) > 0) 1723 3247 gjelinek (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1724 3247 gjelinek pt_to_str(PT_SCHED), sched); 1725 3448 dh155122 1726 3448 dh155122 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) { 1727 3448 dh155122 switch (iptype) { 1728 3448 dh155122 case ZS_SHARED: 1729 3448 dh155122 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1730 3448 dh155122 pt_to_str(PT_IPTYPE), "shared"); 1731 3448 dh155122 break; 1732 3448 dh155122 case ZS_EXCLUSIVE: 1733 3448 dh155122 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1734 3448 dh155122 pt_to_str(PT_IPTYPE), "exclusive"); 1735 3448 dh155122 break; 1736 3448 dh155122 } 1737 8662 Jordan } 1738 8662 Jordan 1739 8662 Jordan if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) { 1740 8662 Jordan (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1741 8662 Jordan pt_to_str(PT_HOSTID), hostidp); 1742 3448 dh155122 } 1743 0 stevel 1744 0 stevel if ((err = zonecfg_setipdent(handle)) != Z_OK) { 1745 6215 gjelinek zone_perror(zone, err, B_FALSE); 1746 0 stevel goto done; 1747 0 stevel } 1748 0 stevel while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 1749 0 stevel (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1750 0 stevel rt_to_str(RT_IPD)); 1751 0 stevel export_prop(of, PT_DIR, fstab.zone_fs_dir); 1752 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1753 0 stevel } 1754 0 stevel (void) zonecfg_endipdent(handle); 1755 0 stevel 1756 0 stevel if ((err = zonecfg_setfsent(handle)) != Z_OK) { 1757 6215 gjelinek zone_perror(zone, err, B_FALSE); 1758 0 stevel goto done; 1759 0 stevel } 1760 0 stevel while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 1761 0 stevel zone_fsopt_t *optptr; 1762 0 stevel 1763 0 stevel (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1764 0 stevel rt_to_str(RT_FS)); 1765 0 stevel export_prop(of, PT_DIR, fstab.zone_fs_dir); 1766 0 stevel export_prop(of, PT_SPECIAL, fstab.zone_fs_special); 1767 0 stevel export_prop(of, PT_RAW, fstab.zone_fs_raw); 1768 0 stevel export_prop(of, PT_TYPE, fstab.zone_fs_type); 1769 0 stevel for (optptr = fstab.zone_fs_options; optptr != NULL; 1770 0 stevel optptr = optptr->zone_fsopt_next) { 1771 0 stevel /* 1772 0 stevel * Simple property values with embedded equal signs 1773 0 stevel * need to be quoted to prevent the lexer from 1774 0 stevel * mis-parsing them as complex name=value pairs. 1775 0 stevel */ 1776 0 stevel if (strchr(optptr->zone_fsopt_opt, '=')) 1777 0 stevel (void) fprintf(of, "%s %s \"%s\"\n", 1778 0 stevel cmd_to_str(CMD_ADD), 1779 0 stevel pt_to_str(PT_OPTIONS), 1780 0 stevel optptr->zone_fsopt_opt); 1781 0 stevel else 1782 0 stevel (void) fprintf(of, "%s %s %s\n", 1783 0 stevel cmd_to_str(CMD_ADD), 1784 0 stevel pt_to_str(PT_OPTIONS), 1785 0 stevel optptr->zone_fsopt_opt); 1786 0 stevel } 1787 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1788 0 stevel zonecfg_free_fs_option_list(fstab.zone_fs_options); 1789 0 stevel } 1790 0 stevel (void) zonecfg_endfsent(handle); 1791 0 stevel 1792 0 stevel if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 1793 6215 gjelinek zone_perror(zone, err, B_FALSE); 1794 0 stevel goto done; 1795 0 stevel } 1796 0 stevel while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 1797 0 stevel (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1798 0 stevel rt_to_str(RT_NET)); 1799 0 stevel export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address); 1800 0 stevel export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical); 1801 6076 gfaden export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter); 1802 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1803 0 stevel } 1804 0 stevel (void) zonecfg_endnwifent(handle); 1805 0 stevel 1806 0 stevel if ((err = zonecfg_setdevent(handle)) != Z_OK) { 1807 6215 gjelinek zone_perror(zone, err, B_FALSE); 1808 0 stevel goto done; 1809 0 stevel } 1810 0 stevel while (zonecfg_getdevent(handle, &devtab) == Z_OK) { 1811 0 stevel (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1812 0 stevel rt_to_str(RT_DEVICE)); 1813 0 stevel export_prop(of, PT_MATCH, devtab.zone_dev_match); 1814 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1815 0 stevel } 1816 0 stevel (void) zonecfg_enddevent(handle); 1817 0 stevel 1818 0 stevel if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 1819 6215 gjelinek zone_perror(zone, err, B_FALSE); 1820 0 stevel goto done; 1821 0 stevel } 1822 0 stevel while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 1823 0 stevel (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD)); 1824 0 stevel export_prop(of, PT_NAME, rctltab.zone_rctl_name); 1825 0 stevel for (valptr = rctltab.zone_rctl_valptr; valptr != NULL; 1826 0 stevel valptr = valptr->zone_rctlval_next) { 1827 0 stevel fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n", 1828 0 stevel cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 1829 0 stevel pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 1830 0 stevel pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 1831 0 stevel pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 1832 0 stevel } 1833 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1834 0 stevel zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 1835 0 stevel } 1836 0 stevel (void) zonecfg_endrctlent(handle); 1837 0 stevel 1838 0 stevel if ((err = zonecfg_setattrent(handle)) != Z_OK) { 1839 6215 gjelinek zone_perror(zone, err, B_FALSE); 1840 0 stevel goto done; 1841 0 stevel } 1842 0 stevel while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 1843 0 stevel (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1844 0 stevel rt_to_str(RT_ATTR)); 1845 0 stevel export_prop(of, PT_NAME, attrtab.zone_attr_name); 1846 0 stevel export_prop(of, PT_TYPE, attrtab.zone_attr_type); 1847 0 stevel export_prop(of, PT_VALUE, attrtab.zone_attr_value); 1848 0 stevel (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1849 0 stevel } 1850 0 stevel (void) zonecfg_endattrent(handle); 1851 0 stevel 1852 789 ahrens if ((err = zonecfg_setdsent(handle)) != Z_OK) { 1853 6215 gjelinek zone_perror(zone, err, B_FALSE); 1854 789 ahrens goto done; 1855 789 ahrens } 1856 789 ahrens while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 1857 789 ahrens (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1858 789 ahrens rt_to_str(RT_DATASET)); 1859 789 ahrens export_prop(of, PT_NAME, dstab.zone_dataset_name); 1860 789 ahrens (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1861 789 ahrens } 1862 789 ahrens (void) zonecfg_enddsent(handle); 1863 789 ahrens 1864 3247 gjelinek if (zonecfg_getpsetent(handle, &psettab) == Z_OK) { 1865 3247 gjelinek (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1866 3247 gjelinek rt_to_str(RT_DCPU)); 1867 3247 gjelinek if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0) 1868 3247 gjelinek (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1869 3247 gjelinek pt_to_str(PT_NCPUS), psettab.zone_ncpu_max); 1870 3247 gjelinek else 1871 3247 gjelinek (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET), 1872 3247 gjelinek pt_to_str(PT_NCPUS), psettab.zone_ncpu_min, 1873 3247 gjelinek psettab.zone_ncpu_max); 1874 3247 gjelinek if (psettab.zone_importance[0] != '\0') 1875 3247 gjelinek (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1876 3247 gjelinek pt_to_str(PT_IMPORTANCE), psettab.zone_importance); 1877 3247 gjelinek (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1878 3247 gjelinek } 1879 3247 gjelinek 1880 3247 gjelinek if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) { 1881 3247 gjelinek char buf[128]; 1882 3247 gjelinek 1883 3247 gjelinek (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1884 3247 gjelinek rt_to_str(RT_MCAP)); 1885 3247 gjelinek bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf)); 1886 3247 gjelinek (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1887 3247 gjelinek pt_to_str(PT_PHYSICAL), buf); 1888 3247 gjelinek (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1889 3247 gjelinek } 1890 3247 gjelinek 1891 3792 akolb /* 1892 3792 akolb * There is nothing to export for pcap since this resource is just 1893 3792 akolb * a container for an rctl alias. 1894 3792 akolb */ 1895 3792 akolb 1896 0 stevel done: 1897 0 stevel if (need_to_close) 1898 0 stevel (void) fclose(of); 1899 0 stevel } 1900 0 stevel 1901 0 stevel void 1902 0 stevel exit_func(cmd_t *cmd) 1903 0 stevel { 1904 0 stevel int arg, answer; 1905 6215 gjelinek boolean_t arg_err = B_FALSE; 1906 0 stevel 1907 0 stevel optind = 0; 1908 0 stevel while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 1909 0 stevel switch (arg) { 1910 0 stevel case '?': 1911 0 stevel longer_usage(CMD_EXIT); 1912 6215 gjelinek arg_err = B_TRUE; 1913 6215 gjelinek break; 1914 6215 gjelinek case 'F': 1915 6215 gjelinek force_exit = B_TRUE; 1916 0 stevel break; 1917 0 stevel default: 1918 0 stevel short_usage(CMD_EXIT); 1919 6215 gjelinek arg_err = B_TRUE; 1920 3691 gjelinek break; 1921 3691 gjelinek } 1922 3691 gjelinek } 1923 3691 gjelinek if (arg_err) 1924 3691 gjelinek return; 1925 3691 gjelinek 1926 0 stevel if (optind < cmd->cmd_argc) { 1927 0 stevel short_usage(CMD_EXIT); 1928 0 stevel return; 1929 0 stevel } 1930 0 stevel 1931 0 stevel if (global_scope || force_exit) { 1932 6215 gjelinek time_to_exit = B_TRUE; 1933 6215 gjelinek return; 1934 6215 gjelinek } 1935 6215 gjelinek 1936 6215 gjelinek answer = ask_yesno(B_FALSE, "Resource incomplete; really quit"); 1937 0 stevel if (answer == -1) { 1938 0 stevel zerr(gettext("Resource incomplete, input " 1939 0 stevel "not from terminal and -F not specified:\n%s command " 1940 0 stevel "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT)); 1941 0 stevel exit(Z_ERR); 1942 0 stevel } else if (answer == 1) { 1943 6215 gjelinek time_to_exit = B_TRUE; 1944 0 stevel } 1945 0 stevel /* (answer == 0) => just return */ 1946 0 stevel } 1947 0 stevel 1948 0 stevel static int 1949 0 stevel validate_zonepath_syntax(char *path) 1950 0 stevel { 1951 0 stevel if (path[0] != '/') { 1952 0 stevel zerr(gettext("%s is not an absolute path."), path); 1953 0 stevel return (Z_ERR); 1954 0 stevel } 1955 0 stevel if (strcmp(path, "/") == 0) { 1956 0 stevel zerr(gettext("/ is not allowed as a %s."), 1957 0 stevel pt_to_str(PT_ZONEPATH)); 1958 0 stevel return (Z_ERR); 1959 0 stevel } 1960 0 stevel return (Z_OK); 1961 0 stevel } 1962 0 stevel 1963 0 stevel static void 1964 0 stevel add_resource(cmd_t *cmd) 1965 0 stevel { 1966 0 stevel int type; 1967 3247 gjelinek struct zone_psettab tmp_psettab; 1968 3247 gjelinek struct zone_mcaptab tmp_mcaptab; 1969 3792 akolb uint64_t tmp; 1970 3247 gjelinek uint64_t tmp_mcap; 1971 3247 gjelinek char pool[MAXNAMELEN]; 1972 0 stevel 1973 0 stevel if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 1974 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 1975 0 stevel goto bad; 1976 0 stevel } 1977 0 stevel 1978 0 stevel switch (type) { 1979 0 stevel case RT_FS: 1980 0 stevel bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 1981 0 stevel return; 1982 0 stevel case RT_IPD: 1983 565 dp if (state_atleast(ZONE_STATE_INSTALLED)) { 1984 0 stevel zerr(gettext("Zone %s already installed; %s %s not " 1985 0 stevel "allowed."), zone, cmd_to_str(CMD_ADD), 1986 0 stevel rt_to_str(RT_IPD)); 1987 0 stevel goto bad; 1988 0 stevel } 1989 0 stevel bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 1990 0 stevel return; 1991 0 stevel case RT_NET: 1992 0 stevel bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 1993 0 stevel return; 1994 0 stevel case RT_DEVICE: 1995 0 stevel bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 1996 0 stevel return; 1997 0 stevel case RT_RCTL: 1998 3247 gjelinek if (global_zone) 1999 3247 gjelinek zerr(gettext("WARNING: Setting a global zone resource " 2000 3247 gjelinek "control too low could deny\nservice " 2001 3247 gjelinek "to even the root user; " 2002 3247 gjelinek "this could render the system impossible\n" 2003 3247 gjelinek "to administer. Please use caution.")); 2004 0 stevel bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 2005 0 stevel return; 2006 0 stevel case RT_ATTR: 2007 0 stevel bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 2008 789 ahrens return; 2009 789 ahrens case RT_DATASET: 2010 789 ahrens bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 2011 3247 gjelinek return; 2012 3247 gjelinek case RT_DCPU: 2013 3792 akolb /* Make sure there isn't already a cpu-set or cpu-cap entry. */ 2014 3247 gjelinek if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2015 3247 gjelinek zerr(gettext("The %s resource already exists."), 2016 3247 gjelinek rt_to_str(RT_DCPU)); 2017 3792 akolb goto bad; 2018 3792 akolb } 2019 3792 akolb if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != 2020 3792 akolb Z_NO_ENTRY) { 2021 3792 akolb zerr(gettext("The %s resource already exists."), 2022 3792 akolb rt_to_str(RT_PCAP)); 2023 3247 gjelinek goto bad; 2024 3247 gjelinek } 2025 3247 gjelinek 2026 3247 gjelinek /* Make sure the pool property isn't set. */ 2027 3247 gjelinek if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 2028 3247 gjelinek strlen(pool) > 0) { 2029 3247 gjelinek zerr(gettext("The %s property is already set. " 2030 3247 gjelinek "A persistent pool is incompatible with\nthe %s " 2031 3247 gjelinek "resource."), 2032 3247 gjelinek pt_to_str(PT_POOL), rt_to_str(RT_DCPU)); 2033 3247 gjelinek goto bad; 2034 3247 gjelinek } 2035 3247 gjelinek 2036 3247 gjelinek bzero(&in_progress_psettab, sizeof (in_progress_psettab)); 2037 3792 akolb return; 2038 3792 akolb case RT_PCAP: 2039 3792 akolb /* 2040 3792 akolb * Make sure there isn't already a cpu-set or incompatible 2041 3792 akolb * cpu-cap rctls. 2042 3792 akolb */ 2043 3792 akolb if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2044 3792 akolb zerr(gettext("The %s resource already exists."), 2045 3792 akolb rt_to_str(RT_DCPU)); 2046 3792 akolb goto bad; 2047 3792 akolb } 2048 3792 akolb 2049 3792 akolb switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) { 2050 3792 akolb case Z_ALIAS_DISALLOW: 2051 3792 akolb zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW, 2052 6215 gjelinek B_FALSE); 2053 3792 akolb goto bad; 2054 3792 akolb 2055 3792 akolb case Z_OK: 2056 3792 akolb zerr(gettext("The %s resource already exists."), 2057 3792 akolb rt_to_str(RT_PCAP)); 2058 3792 akolb goto bad; 2059 3792 akolb 2060 3792 akolb default: 2061 3792 akolb break; 2062 3792 akolb } 2063 3247 gjelinek return; 2064 3247 gjelinek case RT_MCAP: 2065 3247 gjelinek /* 2066 3247 gjelinek * Make sure there isn't already a mem-cap entry or max-swap 2067 3247 gjelinek * or max-locked rctl. 2068 3247 gjelinek */ 2069 3247 gjelinek if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK || 2070 3247 gjelinek zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap) 2071 3247 gjelinek == Z_OK || 2072 3247 gjelinek zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 2073 3247 gjelinek &tmp_mcap) == Z_OK) { 2074 3247 gjelinek zerr(gettext("The %s resource or a related resource " 2075 3247 gjelinek "control already exists."), rt_to_str(RT_MCAP)); 2076 3247 gjelinek goto bad; 2077 3247 gjelinek } 2078 3247 gjelinek if (global_zone) 2079 3247 gjelinek zerr(gettext("WARNING: Setting a global zone memory " 2080 3247 gjelinek "cap too low could deny\nservice " 2081 3247 gjelinek "to even the root user; " 2082 3247 gjelinek "this could render the system impossible\n" 2083 3247 gjelinek "to administer. Please use caution.")); 2084 3247 gjelinek bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab)); 2085 0 stevel return; 2086 0 stevel default: 2087 6215 gjelinek zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 2088 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2089 6215 gjelinek usage(B_FALSE, HELP_RESOURCES); 2090 0 stevel } 2091 0 stevel bad: 2092 6215 gjelinek global_scope = B_TRUE; 2093 0 stevel end_op = -1; 2094 0 stevel } 2095 0 stevel 2096 0 stevel static void 2097 0 stevel do_complex_rctl_val(complex_property_ptr_t cp) 2098 0 stevel { 2099 0 stevel struct zone_rctlvaltab *rctlvaltab; 2100 0 stevel complex_property_ptr_t cx; 2101 6215 gjelinek boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE, 2102 6215 gjelinek seen_action = B_FALSE; 2103 0 stevel rctlblk_t *rctlblk; 2104 0 stevel int err; 2105 0 stevel 2106 0 stevel if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 2107 6215 gjelinek zone_perror(zone, Z_NOMEM, B_TRUE); 2108 0 stevel exit(Z_ERR); 2109 0 stevel } 2110 0 stevel for (cx = cp; cx != NULL; cx = cx->cp_next) { 2111 0 stevel switch (cx->cp_type) { 2112 0 stevel case PT_PRIV: 2113 0 stevel if (seen_priv) { 2114 0 stevel zerr(gettext("%s already specified"), 2115 0 stevel pt_to_str(PT_PRIV)); 2116 0 stevel goto bad; 2117 0 stevel } 2118 0 stevel (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2119 0 stevel cx->cp_value, 2120 0 stevel sizeof (rctlvaltab->zone_rctlval_priv)); 2121 6215 gjelinek seen_priv = B_TRUE; 2122 0 stevel break; 2123 0 stevel case PT_LIMIT: 2124 0 stevel if (seen_limit) { 2125 0 stevel zerr(gettext("%s already specified"), 2126 0 stevel pt_to_str(PT_LIMIT)); 2127 0 stevel goto bad; 2128 0 stevel } 2129 0 stevel (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2130 0 stevel cx->cp_value, 2131 0 stevel sizeof (rctlvaltab->zone_rctlval_limit)); 2132 6215 gjelinek seen_limit = B_TRUE; 2133 0 stevel break; 2134 0 stevel case PT_ACTION: 2135 0 stevel if (seen_action) { 2136 0 stevel zerr(gettext("%s already specified"), 2137 0 stevel pt_to_str(PT_ACTION)); 2138 0 stevel goto bad; 2139 0 stevel } 2140 0 stevel (void) strlcpy(rctlvaltab->zone_rctlval_action, 2141 0 stevel cx->cp_value, 2142 0 stevel sizeof (rctlvaltab->zone_rctlval_action)); 2143 6215 gjelinek seen_action = B_TRUE; 2144 0 stevel break; 2145 0 stevel default: 2146 0 stevel zone_perror(pt_to_str(PT_VALUE), 2147 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2148 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2149 6215 gjelinek usage(B_FALSE, HELP_PROPS); 2150 0 stevel zonecfg_free_rctl_value_list(rctlvaltab); 2151 0 stevel return; 2152 0 stevel } 2153 0 stevel } 2154 0 stevel if (!seen_priv) 2155 0 stevel zerr(gettext("%s not specified"), pt_to_str(PT_PRIV)); 2156 0 stevel if (!seen_limit) 2157 0 stevel zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT)); 2158 0 stevel if (!seen_action) 2159 0 stevel zerr(gettext("%s not specified"), pt_to_str(PT_ACTION)); 2160 0 stevel if (!seen_priv || !seen_limit || !seen_action) 2161 0 stevel goto bad; 2162 0 stevel rctlvaltab->zone_rctlval_next = NULL; 2163 0 stevel rctlblk = alloca(rctlblk_size()); 2164 0 stevel /* 2165 0 stevel * Make sure the rctl value looks roughly correct; we won't know if 2166 0 stevel * it's truly OK until we verify the configuration on the target 2167 0 stevel * system. 2168 0 stevel */ 2169 0 stevel if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK || 2170 0 stevel !zonecfg_valid_rctlblk(rctlblk)) { 2171 0 stevel zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL), 2172 0 stevel pt_to_str(PT_VALUE)); 2173 0 stevel goto bad; 2174 0 stevel } 2175 0 stevel err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab); 2176 0 stevel if (err != Z_OK) 2177 6215 gjelinek zone_perror(pt_to_str(PT_VALUE), err, B_TRUE); 2178 0 stevel return; 2179 0 stevel 2180 0 stevel bad: 2181 0 stevel zonecfg_free_rctl_value_list(rctlvaltab); 2182 0 stevel } 2183 0 stevel 2184 0 stevel static void 2185 0 stevel add_property(cmd_t *cmd) 2186 0 stevel { 2187 0 stevel char *prop_id; 2188 0 stevel int err, res_type, prop_type; 2189 0 stevel property_value_ptr_t pp; 2190 0 stevel list_property_ptr_t l; 2191 0 stevel 2192 0 stevel res_type = resource_scope; 2193 0 stevel prop_type = cmd->cmd_prop_name[0]; 2194 0 stevel if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2195 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2196 0 stevel return; 2197 0 stevel } 2198 0 stevel 2199 0 stevel if (cmd->cmd_prop_nv_pairs != 1) { 2200 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2201 6215 gjelinek return; 2202 6215 gjelinek } 2203 6215 gjelinek 2204 6215 gjelinek if (initialize(B_TRUE) != Z_OK) 2205 0 stevel return; 2206 0 stevel 2207 0 stevel switch (res_type) { 2208 0 stevel case RT_FS: 2209 0 stevel if (prop_type != PT_OPTIONS) { 2210 0 stevel zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2211 6215 gjelinek B_TRUE); 2212 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2213 6215 gjelinek usage(B_FALSE, HELP_PROPS); 2214 0 stevel return; 2215 0 stevel } 2216 0 stevel pp = cmd->cmd_property_ptr[0]; 2217 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE && 2218 0 stevel pp->pv_type != PROP_VAL_LIST) { 2219 0 stevel zerr(gettext("A %s or %s value was expected here."), 2220 0 stevel pvt_to_str(PROP_VAL_SIMPLE), 2221 0 stevel pvt_to_str(PROP_VAL_LIST)); 2222 6215 gjelinek saw_error = B_TRUE; 2223 0 stevel return; 2224 0 stevel } 2225 0 stevel if (pp->pv_type == PROP_VAL_SIMPLE) { 2226 0 stevel if (pp->pv_simple == NULL) { 2227 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2228 0 stevel return; 2229 0 stevel } 2230 0 stevel prop_id = pp->pv_simple; 2231 0 stevel err = zonecfg_add_fs_option(&in_progress_fstab, 2232 0 stevel prop_id); 2233 0 stevel if (err != Z_OK) 2234 6215 gjelinek zone_perror(pt_to_str(prop_type), err, B_TRUE); 2235 0 stevel } else { 2236 0 stevel list_property_ptr_t list; 2237 0 stevel 2238 0 stevel for (list = pp->pv_list; list != NULL; 2239 0 stevel list = list->lp_next) { 2240 0 stevel prop_id = list->lp_simple; 2241 0 stevel if (prop_id == NULL) 2242 0 stevel break; 2243 0 stevel err = zonecfg_add_fs_option( 2244 0 stevel &in_progress_fstab, prop_id); 2245 0 stevel if (err != Z_OK) 2246 0 stevel zone_perror(pt_to_str(prop_type), err, 2247 6215 gjelinek B_TRUE); 2248 0 stevel } 2249 0 stevel } 2250 0 stevel return; 2251 0 stevel case RT_RCTL: 2252 0 stevel if (prop_type != PT_VALUE) { 2253 0 stevel zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2254 6215 gjelinek B_TRUE); 2255 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2256 6215 gjelinek usage(B_FALSE, HELP_PROPS); 2257 0 stevel return; 2258 0 stevel } 2259 0 stevel pp = cmd->cmd_property_ptr[0]; 2260 0 stevel if (pp->pv_type != PROP_VAL_COMPLEX && 2261 0 stevel pp->pv_type != PROP_VAL_LIST) { 2262 0 stevel zerr(gettext("A %s or %s value was expected here."), 2263 0 stevel pvt_to_str(PROP_VAL_COMPLEX), 2264 0 stevel pvt_to_str(PROP_VAL_LIST)); 2265 6215 gjelinek saw_error = B_TRUE; 2266 0 stevel return; 2267 0 stevel } 2268 0 stevel if (pp->pv_type == PROP_VAL_COMPLEX) { 2269 0 stevel do_complex_rctl_val(pp->pv_complex); 2270 0 stevel return; 2271 0 stevel } 2272 0 stevel for (l = pp->pv_list; l != NULL; l = l->lp_next) 2273 0 stevel do_complex_rctl_val(l->lp_complex); 2274 0 stevel return; 2275 0 stevel default: 2276 6215 gjelinek zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 2277 6215 gjelinek long_usage(CMD_ADD, B_TRUE); 2278 6215 gjelinek usage(B_FALSE, HELP_RESOURCES); 2279 0 stevel return; 2280 0 stevel } 2281 0 stevel } 2282 0 stevel 2283 3247 gjelinek static boolean_t 2284 3247 gjelinek gz_invalid_resource(int type) 2285 3247 gjelinek { 2286 3247 gjelinek return (global_zone && (type == RT_FS || type == RT_IPD || 2287 3247 gjelinek type == RT_NET || type == RT_DEVICE || type == RT_ATTR || 2288 3247 gjelinek type == RT_DATASET)); 2289 3247 gjelinek } 2290 3247 gjelinek 2291 3247 gjelinek static boolean_t 2292 3247 gjelinek gz_invalid_rt_property(int type) 2293 3247 gjelinek { 2294 3247 gjelinek return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH || 2295 3247 gjelinek type == RT_AUTOBOOT || type == RT_LIMITPRIV || 2296 3448 dh155122 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED || 2297 8662 Jordan type == RT_IPTYPE || type == RT_HOSTID)); 2298 3247 gjelinek } 2299 3247 gjelinek 2300 3247 gjelinek static boolean_t 2301 3247 gjelinek gz_invalid_property(int type) 2302 3247 gjelinek { 2303 3247 gjelinek return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH || 2304 3247 gjelinek type == PT_AUTOBOOT || type == PT_LIMITPRIV || 2305 3448 dh155122 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED || 2306 8662 Jordan type == PT_IPTYPE || type == PT_HOSTID)); 2307 3247 gjelinek } 2308 3247 gjelinek 2309 0 stevel void 2310 0 stevel add_func(cmd_t *cmd) 2311 0 stevel { 2312 0 stevel int arg; 2313 6215 gjelinek boolean_t arg_err = B_FALSE; 2314 3691 gjelinek 2315 3691 gjelinek assert(cmd != NULL); 2316 3691 gjelinek 2317 3691 gjelinek optind = 0; 2318 3691 gjelinek while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 2319 0 stevel switch (arg) { 2320 0 stevel case '?': 2321 0 stevel longer_usage(CMD_ADD); 2322 6215 gjelinek arg_err = B_TRUE; 2323 3691 gjelinek break; 2324 0 stevel default: 2325 0 stevel short_usage(CMD_ADD); 2326 6215 gjelinek arg_err = B_TRUE; 2327 3691 gjelinek break; 2328 3691 gjelinek } 2329 3691 gjelinek } 2330 3691 gjelinek if (arg_err) 2331 3691 gjelinek return; 2332 3691 gjelinek 2333 0 stevel if (optind != cmd->cmd_argc) { 2334 0 stevel short_usage(CMD_ADD); 2335 0 stevel return; 2336 0 stevel } 2337 0 stevel 2338 0 stevel if (zone_is_read_only(CMD_ADD)) 2339 0 stevel return; 2340 0 stevel 2341 6215 gjelinek if (initialize(B_TRUE) != Z_OK) 2342 0 stevel return; 2343 0 stevel if (global_scope) { 2344 3247 gjelinek if (gz_invalid_resource(cmd->cmd_res_type)) { 2345 3247 gjelinek zerr(gettext("Cannot add a %s resource to the " 2346 3247 gjelinek "global zone."), rt_to_str(cmd->cmd_res_type)); 2347 6215 gjelinek saw_error = B_TRUE; 2348 6215 gjelinek return; 2349 6215 gjelinek } 2350 6215 gjelinek 2351 6215 gjelinek global_scope = B_FALSE; 2352 0 stevel resource_scope = cmd->cmd_res_type; 2353 0 stevel end_op = CMD_ADD; 2354 0 stevel add_resource(cmd); 2355 0 stevel } else 2356 0 stevel add_property(cmd); 2357 0 stevel } 2358 0 stevel 2359 565 dp /* 2360 565 dp * This routine has an unusual implementation, because it tries very 2361 565 dp * hard to succeed in the face of a variety of failure modes. 2362 565 dp * The most common and most vexing occurs when the index file and 2363 565 dp * the /etc/zones/<zonename.xml> file are not both present. In 2364 565 dp * this case, delete must eradicate as much of the zone state as is left 2365 565 dp * so that the user can later create a new zone with the same name. 2366 565 dp */ 2367 0 stevel void 2368 0 stevel delete_func(cmd_t *cmd) 2369 0 stevel { 2370 0 stevel int err, arg, answer; 2371 0 stevel char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 2372 6215 gjelinek boolean_t force = B_FALSE; 2373 6215 gjelinek boolean_t arg_err = B_FALSE; 2374 0 stevel 2375 0 stevel optind = 0; 2376 0 stevel while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2377 0 stevel switch (arg) { 2378 0 stevel case '?': 2379 0 stevel longer_usage(CMD_DELETE); 2380 6215 gjelinek arg_err = B_TRUE; 2381 6215 gjelinek break; 2382 6215 gjelinek case 'F': 2383 6215 gjelinek force = B_TRUE; 2384 0 stevel break; 2385 0 stevel default: 2386 0 stevel short_usage(CMD_DELETE); 2387 6215 gjelinek arg_err = B_TRUE; 2388 3691 gjelinek break; 2389 3691 gjelinek } 2390 3691 gjelinek } 2391 3691 gjelinek if (arg_err) 2392 3691 gjelinek return; 2393 3691 gjelinek 2394 0 stevel if (optind != cmd->cmd_argc) { 2395 0 stevel short_usage(CMD_DELETE); 2396 0 stevel return; 2397 0 stevel } 2398 0 stevel 2399 0 stevel if (zone_is_read_only(CMD_DELETE)) 2400 0 stevel return; 2401 0 stevel 2402 0 stevel if (!force) { 2403 565 dp /* 2404 565 dp * Initialize sets up the global called "handle" and warns the 2405 565 dp * user if the zone is not configured. In force mode, we don't 2406 565 dp * trust that evaluation, and hence skip it. (We don't need the 2407 565 dp * handle to be loaded anyway, since zonecfg_destroy is done by 2408 565 dp * zonename). However, we also have to take care to emulate the 2409 565 dp * messages spit out by initialize; see below. 2410 565 dp */ 2411 6215 gjelinek if (initialize(B_TRUE) != Z_OK) 2412 565 dp return; 2413 565 dp 2414 0 stevel (void) snprintf(line, sizeof (line), 2415 0 stevel gettext("Are you sure you want to delete zone %s"), zone); 2416 6215 gjelinek if ((answer = ask_yesno(B_FALSE, line)) == -1) { 2417 565 dp zerr(gettext("Input not from terminal and -F not " 2418 565 dp "specified:\n%s command ignored, exiting."), 2419 565 dp cmd_to_str(CMD_DELETE)); 2420 0 stevel exit(Z_ERR); 2421 0 stevel } 2422 0 stevel if (answer != 1) 2423 0 stevel return; 2424 0 stevel } 2425 0 stevel 2426 565 dp if ((err = zonecfg_destroy(zone, force)) != Z_OK) { 2427 565 dp if ((err == Z_BAD_ZONE_STATE) && !force) { 2428 565 dp zerr(gettext("Zone %s not in %s state; %s not " 2429 565 dp "allowed. Use -F to force %s."), 2430 565 dp zone, zone_state_str(ZONE_STATE_CONFIGURED), 2431 565 dp cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE)); 2432 565 dp } else { 2433 6215 gjelinek zone_perror(zone, err, B_TRUE); 2434 6215 gjelinek } 2435 6215 gjelinek } 2436 6215 gjelinek need_to_commit = B_FALSE; 2437 565 dp 2438 565 dp /* 2439 565 dp * Emulate initialize's messaging; if there wasn't a valid handle to 2440 565 dp * begin with, then user had typed delete (or delete -F) multiple 2441 565 dp * times. So we emit a message. 2442 565 dp * 2443 565 dp * We only do this in the 'force' case because normally, initialize() 2444 565 dp * takes care of this for us. 2445 565 dp */ 2446 565 dp if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode) 2447 565 dp (void) printf(gettext("Use '%s' to begin " 2448 565 dp "configuring a new zone.\n"), cmd_to_str(CMD_CREATE)); 2449 0 stevel 2450 0 stevel /* 2451 0 stevel * Time for a new handle: finish the old one off first 2452 0 stevel * then get a new one properly to avoid leaks. 2453 0 stevel */ 2454 565 dp if (got_handle) { 2455 565 dp zonecfg_fini_handle(handle); 2456 565 dp if ((handle = zonecfg_init_handle()) == NULL) { 2457 6215 gjelinek zone_perror(execname, Z_NOMEM, B_TRUE); 2458 565 dp exit(Z_ERR); 2459 565 dp } 2460 565 dp if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) { 2461 565 dp /* If there was no zone before, that's OK */ 2462 565 dp if (err != Z_NO_ZONE) 2463 6215 gjelinek zone_perror(zone, err, B_TRUE); 2464 6215 gjelinek got_handle = B_FALSE; 2465 6215 gjelinek } 2466 6215 gjelinek } 2467 6215 gjelinek } 2468 6215 gjelinek 2469 6215 gjelinek static int 2470 6215 gjelinek fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only) 2471 6215 gjelinek { 2472 6215 gjelinek int err, i; 2473 6215 gjelinek property_value_ptr_t pp; 2474 6215 gjelinek 2475 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2476 0 stevel return (err); 2477 0 stevel 2478 1086 vp157776 bzero(fstab, sizeof (*fstab)); 2479 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2480 0 stevel pp = cmd->cmd_property_ptr[i]; 2481 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2482 0 stevel zerr(gettext("A simple value was expected here.")); 2483 6215 gjelinek saw_error = B_TRUE; 2484 0 stevel return (Z_INSUFFICIENT_SPEC); 2485 0 stevel } 2486 0 stevel switch (cmd->cmd_prop_name[i]) { 2487 0 stevel case PT_DIR: 2488 0 stevel (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 2489 0 stevel sizeof (fstab->zone_fs_dir)); 2490 0 stevel break; 2491 0 stevel case PT_SPECIAL: 2492 0 stevel (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 2493 0 stevel sizeof (fstab->zone_fs_special)); 2494 0 stevel break; 2495 0 stevel case PT_RAW: 2496 0 stevel (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 2497 0 stevel sizeof (fstab->zone_fs_raw)); 2498 0 stevel break; 2499 0 stevel case PT_TYPE: 2500 0 stevel (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 2501 0 stevel sizeof (fstab->zone_fs_type)); 2502 0 stevel break; 2503 0 stevel default: 2504 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2505 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2506 0 stevel return (Z_INSUFFICIENT_SPEC); 2507 0 stevel } 2508 0 stevel } 2509 0 stevel if (fill_in_only) 2510 0 stevel return (Z_OK); 2511 0 stevel return (zonecfg_lookup_filesystem(handle, fstab)); 2512 0 stevel } 2513 0 stevel 2514 0 stevel static int 2515 6215 gjelinek fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, boolean_t fill_in_only) 2516 6215 gjelinek { 2517 6215 gjelinek int err, i; 2518 6215 gjelinek property_value_ptr_t pp; 2519 6215 gjelinek 2520 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2521 0 stevel return (err); 2522 0 stevel 2523 1086 vp157776 bzero(ipdtab, sizeof (*ipdtab)); 2524 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2525 0 stevel pp = cmd->cmd_property_ptr[i]; 2526 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2527 0 stevel zerr(gettext("A simple value was expected here.")); 2528 6215 gjelinek saw_error = B_TRUE; 2529 0 stevel return (Z_INSUFFICIENT_SPEC); 2530 0 stevel } 2531 0 stevel switch (cmd->cmd_prop_name[i]) { 2532 0 stevel case PT_DIR: 2533 0 stevel (void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple, 2534 0 stevel sizeof (ipdtab->zone_fs_dir)); 2535 0 stevel break; 2536 0 stevel default: 2537 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2538 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2539 0 stevel return (Z_INSUFFICIENT_SPEC); 2540 0 stevel } 2541 0 stevel } 2542 0 stevel if (fill_in_only) 2543 0 stevel return (Z_OK); 2544 0 stevel return (zonecfg_lookup_ipd(handle, ipdtab)); 2545 0 stevel } 2546 0 stevel 2547 0 stevel static int 2548 6215 gjelinek fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, 2549 6215 gjelinek boolean_t fill_in_only) 2550 6215 gjelinek { 2551 6215 gjelinek int err, i; 2552 6215 gjelinek property_value_ptr_t pp; 2553 6215 gjelinek 2554 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2555 0 stevel return (err); 2556 0 stevel 2557 1086 vp157776 bzero(nwiftab, sizeof (*nwiftab)); 2558 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2559 0 stevel pp = cmd->cmd_property_ptr[i]; 2560 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2561 0 stevel zerr(gettext("A simple value was expected here.")); 2562 6215 gjelinek saw_error = B_TRUE; 2563 0 stevel return (Z_INSUFFICIENT_SPEC); 2564 0 stevel } 2565 0 stevel switch (cmd->cmd_prop_name[i]) { 2566 0 stevel case PT_ADDRESS: 2567 0 stevel (void) strlcpy(nwiftab->zone_nwif_address, 2568 0 stevel pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 2569 0 stevel break; 2570 0 stevel case PT_PHYSICAL: 2571 0 stevel (void) strlcpy(nwiftab->zone_nwif_physical, 2572 0 stevel pp->pv_simple, 2573 0 stevel sizeof (nwiftab->zone_nwif_physical)); 2574 0 stevel break; 2575 6076 gfaden case PT_DEFROUTER: 2576 6076 gfaden (void) strlcpy(nwiftab->zone_nwif_defrouter, 2577 6076 gfaden pp->pv_simple, 2578 6076 gfaden sizeof (nwiftab->zone_nwif_defrouter)); 2579 6076 gfaden break; 2580 0 stevel default: 2581 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2582 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2583 0 stevel return (Z_INSUFFICIENT_SPEC); 2584 0 stevel } 2585 0 stevel } 2586 0 stevel if (fill_in_only) 2587 0 stevel return (Z_OK); 2588 0 stevel err = zonecfg_lookup_nwif(handle, nwiftab); 2589 0 stevel return (err); 2590 0 stevel } 2591 0 stevel 2592 0 stevel static int 2593 6215 gjelinek fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only) 2594 6215 gjelinek { 2595 6215 gjelinek int err, i; 2596 6215 gjelinek property_value_ptr_t pp; 2597 6215 gjelinek 2598 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2599 0 stevel return (err); 2600 0 stevel 2601 1086 vp157776 bzero(devtab, sizeof (*devtab)); 2602 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2603 0 stevel pp = cmd->cmd_property_ptr[i]; 2604 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2605 0 stevel zerr(gettext("A simple value was expected here.")); 2606 6215 gjelinek saw_error = B_TRUE; 2607 0 stevel return (Z_INSUFFICIENT_SPEC); 2608 0 stevel } 2609 0 stevel switch (cmd->cmd_prop_name[i]) { 2610 0 stevel case PT_MATCH: 2611 0 stevel (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2612 0 stevel sizeof (devtab->zone_dev_match)); 2613 0 stevel break; 2614 0 stevel default: 2615 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2616 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2617 0 stevel return (Z_INSUFFICIENT_SPEC); 2618 0 stevel } 2619 0 stevel } 2620 0 stevel if (fill_in_only) 2621 0 stevel return (Z_OK); 2622 0 stevel err = zonecfg_lookup_dev(handle, devtab); 2623 0 stevel return (err); 2624 0 stevel } 2625 0 stevel 2626 0 stevel static int 2627 6215 gjelinek fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, 2628 6215 gjelinek boolean_t fill_in_only) 2629 6215 gjelinek { 2630 6215 gjelinek int err, i; 2631 6215 gjelinek property_value_ptr_t pp; 2632 6215 gjelinek 2633 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2634 0 stevel return (err); 2635 0 stevel 2636 1086 vp157776 bzero(rctltab, sizeof (*rctltab)); 2637 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2638 0 stevel pp = cmd->cmd_property_ptr[i]; 2639 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2640 0 stevel zerr(gettext("A simple value was expected here.")); 2641 6215 gjelinek saw_error = B_TRUE; 2642 0 stevel return (Z_INSUFFICIENT_SPEC); 2643 0 stevel } 2644 0 stevel switch (cmd->cmd_prop_name[i]) { 2645 0 stevel case PT_NAME: 2646 0 stevel (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2647 0 stevel sizeof (rctltab->zone_rctl_name)); 2648 0 stevel break; 2649 0 stevel default: 2650 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2651 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2652 0 stevel return (Z_INSUFFICIENT_SPEC); 2653 0 stevel } 2654 0 stevel } 2655 0 stevel if (fill_in_only) 2656 0 stevel return (Z_OK); 2657 0 stevel err = zonecfg_lookup_rctl(handle, rctltab); 2658 0 stevel return (err); 2659 0 stevel } 2660 0 stevel 2661 0 stevel static int 2662 6215 gjelinek fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, 2663 6215 gjelinek boolean_t fill_in_only) 2664 6215 gjelinek { 2665 6215 gjelinek int err, i; 2666 6215 gjelinek property_value_ptr_t pp; 2667 6215 gjelinek 2668 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2669 0 stevel return (err); 2670 0 stevel 2671 1086 vp157776 bzero(attrtab, sizeof (*attrtab)); 2672 0 stevel for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2673 0 stevel pp = cmd->cmd_property_ptr[i]; 2674 0 stevel if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2675 0 stevel zerr(gettext("A simple value was expected here.")); 2676 6215 gjelinek saw_error = B_TRUE; 2677 0 stevel return (Z_INSUFFICIENT_SPEC); 2678 0 stevel } 2679 0 stevel switch (cmd->cmd_prop_name[i]) { 2680 0 stevel case PT_NAME: 2681 0 stevel (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2682 0 stevel sizeof (attrtab->zone_attr_name)); 2683 0 stevel break; 2684 0 stevel case PT_TYPE: 2685 0 stevel (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2686 0 stevel sizeof (attrtab->zone_attr_type)); 2687 0 stevel break; 2688 0 stevel case PT_VALUE: 2689 0 stevel (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2690 0 stevel sizeof (attrtab->zone_attr_value)); 2691 0 stevel break; 2692 0 stevel default: 2693 0 stevel zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2694 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2695 0 stevel return (Z_INSUFFICIENT_SPEC); 2696 0 stevel } 2697 0 stevel } 2698 0 stevel if (fill_in_only) 2699 0 stevel return (Z_OK); 2700 0 stevel err = zonecfg_lookup_attr(handle, attrtab); 2701 0 stevel return (err); 2702 0 stevel } 2703 0 stevel 2704 789 ahrens static int 2705 6215 gjelinek fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only) 2706 6215 gjelinek { 2707 6215 gjelinek int err, i; 2708 6215 gjelinek property_value_ptr_t pp; 2709 6215 gjelinek 2710 6215 gjelinek if ((err = initialize(B_TRUE)) != Z_OK) 2711 789 ahrens return (err); 2712 789 ahrens 2713 789 ahrens dstab->zone_dataset_name[0] = '\0'; 2714 789 ahrens for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2715 789 ahrens pp = cmd->cmd_property_ptr[i]; 2716 789 ahrens if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2717 789 ahrens zerr(gettext("A simple value was expected here.")); 2718 6215 gjelinek saw_error = B_TRUE; 2719 789 ahrens return (Z_INSUFFICIENT_SPEC); 2720 789 ahrens } 2721 789 ahrens switch (cmd->cmd_prop_name[i]) { 2722 789 ahrens case PT_NAME: 2723 789 ahrens (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2724 789 ahrens sizeof (dstab->zone_dataset_name)); 2725 789 ahrens break; 2726 789 ahrens default: 2727 789 ahrens zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2728 6215 gjelinek Z_NO_PROPERTY_TYPE, B_TRUE); 2729 789 ahrens return (Z_INSUFFICIENT_SPEC); 2730 789 ahrens } 2731 789 ahrens } 2732 789 ahrens if (fill_in_only) 2733 789 ahrens return (Z_OK); 2734 789 ahrens return (zonecfg_lookup_ds(handle, dstab)); 2735 789 ahrens } 2736 789 ahrens 2737 0 stevel static void 2738 3247 gjelinek remove_aliased_rctl(int type, char *name) 2739 3247 gjelinek { 2740 3247 gjelinek int err; 2741 3247 gjelinek uint64_t tmp; 2742 3247 gjelinek 2743 3247 gjelinek if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) { 2744 3247 gjelinek zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2745 3247 gjelinek zonecfg_strerror(err)); 2746 6215 gjelinek saw_error = B_TRUE; 2747 3247 gjelinek return; 2748 3247 gjelinek } 2749 3247 gjelinek if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) { 2750 3247 gjelinek zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2751 3247 gjelinek zonecfg_strerror(err)); 2752 6215 gjelinek saw_error = B_TRUE; 2753 6215 gjelinek } else { 2754 6215 gjelinek need_to_commit = B_TRUE; 2755 3247 gjelinek } 2756 3247 gjelinek } 2757 3247 gjelinek 2758 3247 gjelinek static boolean_t 2759 3247 gjelinek prompt_remove_resource(cmd_t *cmd, char *rsrc) 2760 3247 gjelinek { 2761 3247 gjelinek int num; 2762 3247 gjelinek int answer; 2763 3247 gjelinek int arg; 2764 3247 gjelinek boolean_t force = B_FALSE; 2765 3247 gjelinek char prompt[128]; 2766 6215 gjelinek boolean_t arg_err = B_FALSE; 2767 3247 gjelinek 2768 3247 gjelinek optind = 0; 2769 3247 gjelinek while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 2770 3247 gjelinek switch (arg) { 2771 3247 gjelinek case 'F': 2772 3247 gjelinek force = B_TRUE; 2773 3247 gjelinek break; 2774 3247 gjelinek default: 2775 6215 gjelinek arg_err = B_TRUE; 2776 3691 gjelinek break; 2777 3691 gjelinek } 2778 3691 gjelinek } 2779 3691 gjelinek if (arg_err) 2780 3691 gjelinek return (B_FALSE); 2781 3691 gjelinek 2782 3247 gjelinek 2783 3247 gjelinek num = zonecfg_num_resources(handle, rsrc); 2784 3247 gjelinek 2785 3247 gjelinek if (num == 0) { 2786 3247 gjelinek z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY, 2787 6215 gjelinek B_TRUE); 2788 3247 gjelinek return (B_FALSE); 2789 3247 gjelinek } 2790 3247 gjelinek if (num > 1 && !force) { 2791 3247 gjelinek if (!interactive_mode) { 2792 3247 gjelinek zerr(gettext("There are multiple instances of this " 2793 3247 gjelinek "resource. Either qualify the resource to\n" 2794 3247 gjelinek "remove a single instance or use the -F option to " 2795 3247 gjelinek "remove all instances.")); 2796 6215 gjelinek saw_error = B_TRUE; 2797 3247 gjelinek return (B_FALSE); 2798 3247 gjelinek } 2799 3247 gjelinek (void) snprintf(prompt, sizeof (prompt), gettext( 2800 3247 gjelinek "Are you sure you want to remove ALL '%s' resources"), 2801 3247 gjelinek rsrc); 2802 6215 gjelinek answer = ask_yesno(B_FALSE, prompt); 2803 3247 gjelinek if (answer == -1) { 2804 3247 gjelinek zerr(gettext("Resource incomplete.")); 2805 3247 gjelinek return (B_FALSE); 2806 3247 gjelinek } 2807 3247 gjelinek if (answer != 1) 2808 3247 gjelinek return (B_FALSE); 2809 3247 gjelinek } 2810 3247 gjelinek return (B_TRUE); 2811 3247 gjelinek } 2812 3247 gjelinek 2813 3247 gjelinek static void 2814 3247 gjelinek remove_fs(cmd_t *cmd) 2815 3247 gjelinek { 2816 3247 gjelinek int err; 2817 3247 gjelinek 2818 3247 gjelinek /* traditional, qualified fs removal */ 2819 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2820 3247 gjelinek struct zone_fstab fstab; 2821 3247 gjelinek 2822 6215 gjelinek if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) { 2823 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2824 3247 gjelinek return; 2825 3247 gjelinek } 2826 3247 gjelinek if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 2827 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2828 6215 gjelinek else 2829 6215 gjelinek need_to_commit = B_TRUE; 2830 3247 gjelinek zonecfg_free_fs_option_list(fstab.zone_fs_options); 2831 3247 gjelinek return; 2832 3247 gjelinek } 2833 3247 gjelinek 2834 3247 gjelinek /* 2835 3247 gjelinek * unqualified fs removal. remove all fs's but prompt if more 2836 3247 gjelinek * than one. 2837 3247 gjelinek */ 2838 3247 gjelinek if (!prompt_remove_resource(cmd, "fs")) 2839 3247 gjelinek return; 2840 3247 gjelinek 2841 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK) 2842 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2843 6215 gjelinek else 2844 6215 gjelinek need_to_commit = B_TRUE; 2845 3247 gjelinek } 2846 3247 gjelinek 2847 3247 gjelinek static void 2848 3247 gjelinek remove_ipd(cmd_t *cmd) 2849 3247 gjelinek { 2850 3247 gjelinek int err; 2851 3247 gjelinek 2852 3247 gjelinek if (state_atleast(ZONE_STATE_INSTALLED)) { 2853 3247 gjelinek zerr(gettext("Zone %s already installed; %s %s not allowed."), 2854 3247 gjelinek zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD)); 2855 3247 gjelinek return; 2856 3247 gjelinek } 2857 3247 gjelinek 2858 3247 gjelinek /* traditional, qualified ipd removal */ 2859 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2860 3247 gjelinek struct zone_fstab fstab; 2861 3247 gjelinek 2862 6215 gjelinek if ((err = fill_in_ipdtab(cmd, &fstab, B_FALSE)) != Z_OK) { 2863 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 2864 3247 gjelinek return; 2865 3247 gjelinek } 2866 3247 gjelinek if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK) 2867 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 2868 6215 gjelinek else 2869 6215 gjelinek need_to_commit = B_TRUE; 2870 3247 gjelinek return; 2871 3247 gjelinek } 2872 3247 gjelinek 2873 3247 gjelinek /* 2874 3247 gjelinek * unqualified ipd removal. remove all ipds but prompt if more 2875 3247 gjelinek * than one. 2876 3247 gjelinek */ 2877 3247 gjelinek if (!prompt_remove_resource(cmd, "inherit-pkg-dir")) 2878 3247 gjelinek return; 2879 3247 gjelinek 2880 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir")) 2881 3247 gjelinek != Z_OK) 2882 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 2883 6215 gjelinek else 2884 6215 gjelinek need_to_commit = B_TRUE; 2885 3247 gjelinek } 2886 3247 gjelinek 2887 3247 gjelinek static void 2888 3247 gjelinek remove_net(cmd_t *cmd) 2889 3247 gjelinek { 2890 3247 gjelinek int err; 2891 3247 gjelinek 2892 3247 gjelinek /* traditional, qualified net removal */ 2893 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2894 3247 gjelinek struct zone_nwiftab nwiftab; 2895 3247 gjelinek 2896 6215 gjelinek if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) { 2897 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 2898 3247 gjelinek return; 2899 3247 gjelinek } 2900 3247 gjelinek if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 2901 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 2902 6215 gjelinek else 2903 6215 gjelinek need_to_commit = B_TRUE; 2904 3247 gjelinek return; 2905 3247 gjelinek } 2906 3247 gjelinek 2907 3247 gjelinek /* 2908 3247 gjelinek * unqualified net removal. remove all nets but prompt if more 2909 3247 gjelinek * than one. 2910 3247 gjelinek */ 2911 3247 gjelinek if (!prompt_remove_resource(cmd, "net")) 2912 3247 gjelinek return; 2913 3247 gjelinek 2914 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK) 2915 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 2916 6215 gjelinek else 2917 6215 gjelinek need_to_commit = B_TRUE; 2918 3247 gjelinek } 2919 3247 gjelinek 2920 3247 gjelinek static void 2921 3247 gjelinek remove_device(cmd_t *cmd) 2922 3247 gjelinek { 2923 3247 gjelinek int err; 2924 3247 gjelinek 2925 3247 gjelinek /* traditional, qualified device removal */ 2926 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2927 3247 gjelinek struct zone_devtab devtab; 2928 3247 gjelinek 2929 6215 gjelinek if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) { 2930 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 2931 3247 gjelinek return; 2932 3247 gjelinek } 2933 3247 gjelinek if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 2934 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 2935 6215 gjelinek else 2936 6215 gjelinek need_to_commit = B_TRUE; 2937 3247 gjelinek return; 2938 3247 gjelinek } 2939 3247 gjelinek 2940 3247 gjelinek /* 2941 3247 gjelinek * unqualified device removal. remove all devices but prompt if more 2942 3247 gjelinek * than one. 2943 3247 gjelinek */ 2944 3247 gjelinek if (!prompt_remove_resource(cmd, "device")) 2945 3247 gjelinek return; 2946 3247 gjelinek 2947 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK) 2948 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 2949 6215 gjelinek else 2950 6215 gjelinek need_to_commit = B_TRUE; 2951 3247 gjelinek } 2952 3247 gjelinek 2953 3247 gjelinek static void 2954 3247 gjelinek remove_attr(cmd_t *cmd) 2955 3247 gjelinek { 2956 3247 gjelinek int err; 2957 3247 gjelinek 2958 3247 gjelinek /* traditional, qualified attr removal */ 2959 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2960 3247 gjelinek struct zone_attrtab attrtab; 2961 3247 gjelinek 2962 6215 gjelinek if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) { 2963 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 2964 3247 gjelinek return; 2965 3247 gjelinek } 2966 3247 gjelinek if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 2967 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 2968 6215 gjelinek else 2969 6215 gjelinek need_to_commit = B_TRUE; 2970 3247 gjelinek return; 2971 3247 gjelinek } 2972 3247 gjelinek 2973 3247 gjelinek /* 2974 3247 gjelinek * unqualified attr removal. remove all attrs but prompt if more 2975 3247 gjelinek * than one. 2976 3247 gjelinek */ 2977 3247 gjelinek if (!prompt_remove_resource(cmd, "attr")) 2978 3247 gjelinek return; 2979 3247 gjelinek 2980 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK) 2981 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 2982 6215 gjelinek else 2983 6215 gjelinek need_to_commit = B_TRUE; 2984 3247 gjelinek } 2985 3247 gjelinek 2986 3247 gjelinek static void 2987 3247 gjelinek remove_dataset(cmd_t *cmd) 2988 3247 gjelinek { 2989 3247 gjelinek int err; 2990 3247 gjelinek 2991 3247 gjelinek /* traditional, qualified dataset removal */ 2992 3247 gjelinek if (cmd->cmd_prop_nv_pairs > 0) { 2993 3247 gjelinek struct zone_dstab dstab; 2994 3247 gjelinek 2995 6215 gjelinek if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) { 2996 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 2997 3247 gjelinek return; 2998 3247 gjelinek } 2999 3247 gjelinek if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 3000 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3001 6215 gjelinek else 3002 6215 gjelinek need_to_commit = B_TRUE; 3003 3247 gjelinek return; 3004 3247 gjelinek } 3005 3247 gjelinek 3006 3247 gjelinek /* 3007 3247 gjelinek * unqualified dataset removal. remove all datasets but prompt if more 3008 3247 gjelinek * than one. 3009 3247 gjelinek */ 3010 3247 gjelinek if (!prompt_remove_resource(cmd, "dataset")) 3011 3247 gjelinek return; 3012 3247 gjelinek 3013 3247 gjelinek if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK) 3014 6215 gjelinek z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3015 6215 gjelinek else 3016 6215 gjelinek need_to_commit = B_TRUE; 3017 3247 gjelinek } 3018 3247 gjelinek 3019 3247 gjelinek static void 3020 3247 gjelinek remove_rctl(cmd_t *cmd) 3021 3247 gjelinek { 3022