1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Program: pkgcond 30 * 31 * Function: Implements the package command suite public utility pkgcond(1M) 32 * 33 * Usage: pkgcond [-nv] [-O debug] condition [ argument ] 34 * 35 * command options: 36 * -n - negate results of condition test 37 * -v - verbose output of condition testing 38 * 39 * <condition> may be any one of: 40 * can_add_driver [path] 41 * can_remove_driver [path] 42 * can_update_driver [path] 43 * is_alternative_root [path] 44 * is_boot_environment [path] 45 * is_diskless_client [path] 46 * is_global_zone [path] 47 * is_mounted_miniroot [path] 48 * is_netinstall_image [path] 49 * is_nonglobal_zone [path] 50 * is_path_writable path 51 * is_running_system [path] 52 * is_sparse_root_nonglobal_zone [path] 53 * is_what [path] 54 * is_whole_root_nonglobal_zone [path] 55 * 56 * <option(s)> are specific to the condition used 57 * 58 * Input: depends on command 59 * 60 * Output: depends on command 61 * 62 * Exit status: If the -n option is not specified: 63 * == 0 - the specified condition is true (or exists). 64 * == 1 - the specified condition is false (or does not exist). 65 * == 2 - command line usage errors (including bad keywords) 66 * == 3 - command failed to perform the test due to a fatal error 67 * 68 * If the -n option is specified: 69 * == 0 - the specified condition is false (or does not exist). 70 * == 1 - the specified condition is true (or exists). 71 * == 2 - command line usage errors (including bad keywords) 72 * == 3 - command failed to perform the test due to a fatal error 73 */ 74 75 #include <stdio.h> 76 #include <sys/mnttab.h> 77 #include <sys/mntent.h> 78 #include <stdarg.h> 79 #include <stdlib.h> 80 #include <string.h> 81 #include <strings.h> 82 #include <fcntl.h> 83 #include <ctype.h> 84 #include <sys/types.h> 85 #include <sys/stat.h> 86 #include <unistd.h> 87 #include <locale.h> 88 #include <errno.h> 89 #include <sys/param.h> 90 #include <assert.h> 91 92 #include <instzones_api.h> 93 #include <pkglib.h> 94 #include <install.h> 95 #include <libinst.h> 96 #include <libadm.h> 97 #include <messages.h> 98 #include "pkgcond.h" 99 #include "pkgcond_msgs.h" 100 101 /* Should be defined by cc -D */ 102 103 #if !defined(TEXT_DOMAIN) 104 #define TEXT_DOMAIN "SYS_TEST" 105 #endif 106 107 /* commands to execute */ 108 109 #define LS_CMD "/usr/bin/ls" 110 111 /* 112 * type definition and "types" for testPath() 113 */ 114 115 typedef enum { 116 TEST_EXISTS = 0x01, 117 TEST_NOT_EXISTS = 0x02, 118 TEST_IS_DIRECTORY = 0x04, 119 TEST_IS_FILE = 0x08, 120 TEST_NOT_DIRECTORY = 0x10, 121 TEST_NOT_FILE = 0x20, 122 TEST_IS_SYMBOLIC_LINK = 0x40, 123 TEST_NOT_SYMBOLIC_LINK = 0x80, 124 TEST_GLOBAL_TOKEN_IN_FILE = 0x100 125 } TEST_TYPES; 126 127 /* holds file system info */ 128 129 struct fsi_t { 130 char *fsi_mntOptions; 131 char *fsi_fsType; 132 char *fsi_mntPoint; 133 }; 134 typedef struct fsi_t FSI_T; 135 136 /* holds parsed global data */ 137 138 struct globalData_t { 139 /* sparse root (are any file systems mounted read-only)? */ 140 boolean_t gd_srFsMountedRO; 141 /* initial install: PKG_INIT_INSTALL=true */ 142 boolean_t gd_initialInstall; 143 /* global zone install: SUNW_PKG_INSTALL_ZONENAME=global */ 144 boolean_t gd_globalZoneInstall; 145 /* non-global zone install: SUNW_PKG_INSTALL_ZONENAME!=global */ 146 boolean_t gd_nonglobalZoneInstall; 147 /* non-global zone is in a mounted state */ 148 boolean_t inMountedState; 149 /* sorted list of all mounted file systems */ 150 FSI_T *gd_fileSystemConfig; 151 /* number of mounted file systems in list */ 152 long gd_fileSystemConfigLen; 153 /* current zone name */ 154 char *gd_zoneName; 155 /* version of target: PATCH_CLIENT_VERSION */ 156 char *gd_patchClientVersion; 157 /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneName */ 158 char *gd_parentZoneName; 159 /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneType */ 160 char *gd_parentZoneType; 161 /* root path to target: PKG_INSTALL_ROOT */ 162 char *gd_installRoot; 163 /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneName */ 164 char *gd_currentZoneName; 165 /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneType */ 166 char *gd_currentZoneType; 167 /* list of inherited file systems */ 168 char **gd_inheritedFileSystems; 169 /* path provided on command line */ 170 char *gd_cmdline_path; 171 }; 172 typedef struct globalData_t GLOBALDATA_T; 173 174 /* holds subcommands and their definitions */ 175 176 struct cmd_t { 177 char *c_name; 178 char *c_args; 179 int (*c_func)(int argc, char **argv, GLOBALDATA_T *a_gdt); 180 }; 181 typedef struct cmd_t CMD_T; 182 183 /* Command function prototypes */ 184 185 static int cmd_can_add_driver(int argc, char **argv, 186 GLOBALDATA_T *a_gdt); 187 static int cmd_can_remove_driver(int argc, char **argv, 188 GLOBALDATA_T *a_gdt); 189 static int cmd_can_update_driver(int argc, char **argv, 190 GLOBALDATA_T *a_gdt); 191 static int cmd_is_alternative_root(int argc, char **argv, 192 GLOBALDATA_T *a_gdt); 193 static int cmd_is_boot_environment(int argc, char **argv, 194 GLOBALDATA_T *a_gdt); 195 static int cmd_is_diskless_client(int argc, char **argv, 196 GLOBALDATA_T *a_gdt); 197 static int cmd_is_global_zone(int argc, char **argv, 198 GLOBALDATA_T *a_gdt); 199 static int cmd_is_mounted_miniroot(int argc, char **argv, 200 GLOBALDATA_T *a_gdt); 201 static int cmd_is_netinstall_image(int argc, char **argv, 202 GLOBALDATA_T *a_gdt); 203 static int cmd_is_nonglobal_zone(int argc, char **argv, 204 GLOBALDATA_T *a_gdt); 205 static int cmd_is_path_writable(int argc, char **argv, 206 GLOBALDATA_T *a_gdt); 207 static int cmd_is_running_system(int argc, char **argv, 208 GLOBALDATA_T *a_gdt); 209 static int cmd_is_sparse_root_ng_zone(int argc, char **argv, 210 GLOBALDATA_T *a_gdt); 211 static int cmd_is_what(int argc, char **argv, 212 GLOBALDATA_T *a_gdt); 213 static int cmd_is_whole_root_ng_zone(int argc, char **argv, 214 GLOBALDATA_T *a_gdt); 215 216 /* Utility function Prototypes */ 217 218 static boolean_t getNegateResults(void); 219 static boolean_t recursionCheck(int *r_recursion, char *a_function); 220 static boolean_t checkForReadOnlyMount(GLOBALDATA_T *a_gdt, 221 char *a_mntPoint, char *a_fsType, char *a_mntOptions); 222 static int adjustResults(int a_result); 223 static int calculateFileSystemConfig(GLOBALDATA_T *a_gdt); 224 static int getRootPath(char **r_rootPath); 225 static int getZoneName(char **r_zoneName); 226 static int mountOptionPresent(char *a_mntOptions, char *a_opt); 227 static int parseGlobalData(char *a_envVar, GLOBALDATA_T **a_gdt); 228 static int resolvePath(char **r_path); 229 static int setRootPath(char *a_path, char *a_envVar, 230 boolean_t a_mustExist); 231 static int testPath(TEST_TYPES a_tt, char *format, ...); 232 static int usage(char *a_format, ...); 233 static int findToken(char *path, char *token); 234 static char *getMountOption(char **p); 235 static void dumpGlobalData(GLOBALDATA_T *a_gdt); 236 static void removeLeadingWhitespace(char **a_str); 237 static void setNegateResults(boolean_t setting); 238 static void setVerbose(boolean_t); 239 static void sortedInsert(FSI_T **r_list, long *a_listSize, 240 char *a_mntPoint, char *a_fsType, char *a_mntOptions); 241 static void setCmdLinePath(char **a_path, char **args, 242 int num_args); 243 244 /* local static data */ 245 246 static boolean_t _negateResults = B_FALSE; 247 static char *_rootPath = "/"; 248 249 /* define subcommand data structure */ 250 251 static CMD_T cmds[] = { 252 { "can_add_driver", " [path]", 253 cmd_can_add_driver }, 254 { "can_remove_driver", " [path]", 255 cmd_can_remove_driver }, 256 { "can_update_driver", " [path]", 257 cmd_can_update_driver }, 258 { "is_alternative_root", " [path]", 259 cmd_is_alternative_root }, 260 { "is_boot_environment", " [path]", 261 cmd_is_boot_environment }, 262 { "is_diskless_client", " [path]", 263 cmd_is_diskless_client }, 264 { "is_global_zone", " [path]", 265 cmd_is_global_zone }, 266 { "is_mounted_miniroot", " [path]", 267 cmd_is_mounted_miniroot }, 268 { "is_netinstall_image", " [path]", 269 cmd_is_netinstall_image }, 270 { "is_nonglobal_zone", " [path]", 271 cmd_is_nonglobal_zone }, 272 { "is_path_writable", " path", 273 cmd_is_path_writable }, 274 { "is_running_system", " [path]", 275 cmd_is_running_system }, 276 { "is_sparse_root_nonglobal_zone", " [path]", 277 cmd_is_sparse_root_ng_zone }, 278 { "is_what", " [path]", 279 cmd_is_what }, 280 { "is_whole_root_nonglobal_zone", " [path]", 281 cmd_is_whole_root_ng_zone }, 282 /* last one must be all NULLs */ 283 { NULL, NULL } 284 }; 285 286 /* 287 * ***************************************************************************** 288 * main 289 * ***************************************************************************** 290 */ 291 292 /* 293 * Name: main 294 * Description: main processing loop for pkgcond * 295 * Return: 0 - condition is satisfied (true) 296 * 1 - condition is not satisfied (false) 297 * 2 - command line usage errors 298 * 3 - failure to determine condition 299 */ 300 301 int 302 main(int argc, char **argv) 303 { 304 GLOBALDATA_T *gdt = NULL; 305 char **newargv; 306 char *p; 307 int cur_cmd; 308 int i; 309 int newargc; 310 311 /* make standard output non-buffered */ 312 313 setbuf(stdout, NULL); 314 315 /* set the default text domain for messaging */ 316 317 (void) setlocale(LC_ALL, ""); 318 (void) textdomain(TEXT_DOMAIN); 319 320 /* remember command name */ 321 322 set_prog_name(argv[0]); 323 324 /* tell spmi zones interface how to access package output functions */ 325 326 z_set_output_functions(echo, echoDebug, progerr); 327 328 /* set verbose mode if appropriate environment variable is set */ 329 330 if (getenv(ENV_VAR_VERBOSE)) { 331 /* same as -v */ 332 setVerbose(B_TRUE); 333 } 334 335 /* set debug mode if appropriate environment variable is set */ 336 337 if (getenv(ENV_VAR_DEBUG)) { 338 /* same as -O debug */ 339 340 /* set sml tracing (sml.c) */ 341 smlSetVerbose(B_TRUE); 342 343 /* set log and echo (interactive) message tracing */ 344 setVerbose(B_TRUE); 345 346 /* enable echoDebug debugging messages */ 347 echoDebugSetFlag(B_TRUE); 348 } 349 350 /* generate usage if no options or arguments specified */ 351 352 if (argc <= 1) { 353 (void) usage(MSG_NO_ARGUMENTS_SPECIFIED); 354 return (R_USAGE); 355 } 356 357 /* 358 * process any arguments that can appear before the subcommand 359 */ 360 361 while ((i = getopt(argc, argv, ":O:vn?")) != EOF) { 362 switch (i) { 363 /* 364 * Not a public interface: the -O option allows the behavior 365 * of the package tools to be modified. Recognized options: 366 * -> debug 367 * ---> enable debugging output 368 */ 369 370 case 'O': 371 for (p = strtok(optarg, ","); p != NULL; 372 p = strtok(NULL, ",")) { 373 374 /* debug - enable all tracing */ 375 376 if (strcmp(p, "debug") == 0) { 377 /* set sml tracing */ 378 smlSetVerbose(B_TRUE); 379 /* set log/echo tracing */ 380 setVerbose(B_TRUE); 381 /* enable debugging messages */ 382 echoDebugSetFlag(B_TRUE); 383 continue; 384 } 385 386 progerr(ERR_INVALID_O_OPTION, p); 387 return (adjustResults(R_USAGE)); 388 } 389 break; 390 391 /* 392 * Public interface: enable verbose (debug) output. 393 */ 394 395 case 'v': /* verbose mode enabled */ 396 /* set command tracing only */ 397 setVerbose(B_TRUE); 398 break; 399 400 /* 401 * Public interface: negate output results. 402 */ 403 404 case 'n': 405 setNegateResults(B_TRUE); 406 break; 407 408 /* 409 * unrecognized option 410 */ 411 412 case '?': 413 default: 414 (void) usage(MSG_INVALID_OPTION_SPECIFIED, optopt); 415 return (R_USAGE); 416 } 417 } 418 419 /* 420 * done processing options that can preceed subcommand 421 */ 422 423 /* error if no subcommand specified */ 424 425 if ((argc-optind) <= 0) { 426 (void) usage(MSG_NO_ARGUMENTS_SPECIFIED); 427 return (R_USAGE); 428 } 429 430 /* parse global data if environment variable set */ 431 432 if (parseGlobalData(PKGCOND_GLOBAL_VARIABLE, &gdt) != R_SUCCESS) { 433 log_msg(LOG_MSG_ERR, ERR_CANNOT_USE_GLOBAL_DATA, 434 PKGCOND_GLOBAL_VARIABLE); 435 return (R_ERROR); 436 } 437 438 if (setRootPath(gdt->gd_installRoot, 439 (strcmp(gdt->gd_installRoot, "/") == 0) ? NULL : 440 ENV_VAR_SET, B_TRUE) != R_SUCCESS) { 441 log_msg(LOG_MSG_ERR, ERR_CANNOT_SET_ROOT_PATH, 442 ENV_VAR_PKGROOT); 443 return (R_ERROR); 444 } 445 446 /* set path provided on the command line */ 447 448 setCmdLinePath(&(gdt->gd_cmdline_path), argv, argc); 449 echoDebug(DBG_CMDLINE_PATH, 450 gdt->gd_cmdline_path == NULL ? "" : gdt->gd_cmdline_path); 451 452 /* determine how file systems are layered in this zone */ 453 454 if (calculateFileSystemConfig(gdt) != R_SUCCESS) { 455 log_msg(LOG_MSG_ERR, ERR_CANNOT_CALC_FS_CONFIG); 456 return (R_ERROR); 457 } 458 459 /* dump global data read in (only if debugging) */ 460 461 dumpGlobalData(gdt); 462 463 /* search for specified subcommand and execute if found */ 464 465 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { 466 if (ci_streq(argv[optind], cmds[cur_cmd].c_name)) { 467 int result; 468 469 /* make subcommand the first option */ 470 471 newargc = argc - optind; 472 newargv = argv + optind; 473 opterr = optind = 1; optopt = 0; 474 475 476 /* call subcommand with its own argc/argv */ 477 478 result = cmds[cur_cmd].c_func(newargc, newargv, gdt); 479 480 /* process result code and exit */ 481 482 result = adjustResults(result); 483 log_msg(LOG_MSG_DEBUG, DBG_RESULTS, result); 484 return (result); 485 } 486 } 487 488 /* subcommand not found - output error message and exit with error */ 489 490 log_msg(LOG_MSG_ERR, ERR_BAD_SUB, argv[optind]); 491 (void) usage(MSG_UNRECOGNIZED_CONDITION_SPECIFIED); 492 return (R_USAGE); 493 } 494 495 /* 496 * ***************************************************************************** 497 * command implementation functions 498 * ***************************************************************************** 499 */ 500 501 /* 502 * Name: cmd_is_diskless_client 503 * Description: determine if target is a diskless client 504 * Scope: public 505 * Arguments: argc,argv: 506 * - optional path to target to test 507 * Returns: int 508 * == 0 - success 509 * != 0 - failure 510 * IMPLEMENTATION: 511 * - must not be initial installation to the install root 512 * - must not be installation of a zone 513 * - must not be a whole root non-global zone 514 * - must not be a non-global zone 515 * - must not be a mounted mini-root 516 * - must not be a netinstall image 517 * - must not be a boot environment 518 * - The package "SUNWdclnt" must be installed at "/" 519 * - The root path must not be "/" 520 * - The path "/export/exec/Solaris_\*\/usr" must exist at "/" 521 * - The directory "$ROOTDIR/../templates" must exist 522 */ 523 524 static int 525 cmd_is_diskless_client(int argc, char **argv, GLOBALDATA_T *a_gdt) 526 { 527 char *rootPath = NULL; 528 char cmd[MAXPATHLEN+1]; 529 int c; 530 int r; 531 int rc; 532 static char *cmdName = "is_diskless_client"; 533 static int recursion = 0; 534 535 /* process any command line options */ 536 537 while ((c = getopt(argc, argv, ":")) != EOF) { 538 switch (c) { 539 case '\0': /* prevent end-of-loop not reached warning */ 540 break; 541 case '?': 542 default: 543 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 544 return (R_USAGE); 545 } 546 } 547 548 /* prevent recursion */ 549 550 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 551 552 /* 553 * a diskless client cannot be any of the following 554 */ 555 556 /* cannot be whole root non-global zone */ 557 558 r = cmd_is_whole_root_ng_zone(argc, argv, a_gdt); 559 560 /* cannot be nonglobal zone */ 561 562 if (r != R_SUCCESS) { 563 r = cmd_is_nonglobal_zone(argc, argv, a_gdt); 564 } 565 566 /* cannot be mounted miniroot */ 567 568 if (r != R_SUCCESS) { 569 r = cmd_is_mounted_miniroot(argc, argv, a_gdt); 570 } 571 572 /* cannot be a netinstall image */ 573 574 if (r != R_SUCCESS) { 575 r = cmd_is_netinstall_image(argc, argv, a_gdt); 576 } 577 578 /* cannot be a boot environment */ 579 580 if (r != R_SUCCESS) { 581 r = cmd_is_boot_environment(argc, argv, a_gdt); 582 } 583 584 /* no need to guard against recursion any more */ 585 586 recursion--; 587 588 /* return failure if any of the preceeding are true */ 589 590 switch (r) { 591 case R_SUCCESS: 592 return (R_FAILURE); 593 case R_FAILURE: 594 break; 595 case R_USAGE: 596 case R_ERROR: 597 default: 598 return (r); 599 } 600 } 601 602 /* normalize argc/argv */ 603 604 argc -= optind; 605 argv += optind; 606 607 /* error if more than one argument */ 608 609 if (argc > 1) { 610 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 611 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 612 return (R_USAGE); 613 } 614 615 /* process root path if first argument present */ 616 617 if (argc == 1) { 618 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 619 return (R_ERROR); 620 } 621 } 622 623 /* get current root path */ 624 625 r = getRootPath(&rootPath); 626 if (r != R_SUCCESS) { 627 return (r); 628 } 629 630 /* start of command debugging information */ 631 632 echoDebug(DBG_ROOTPATH_IS, rootPath); 633 634 /* SUNWdclnt must be installed */ 635 636 if (pkgTestInstalled("SUNWdclnt", "/") != B_TRUE) { 637 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PKG_NOT_INSTALLED, 638 rootPath, "SUNWdclnt", "/"); 639 return (R_FAILURE); 640 } 641 642 /* - $ROOTDIR must not be "/" */ 643 644 if (strcmp(rootPath, "/") == 0) { 645 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ROOTPATH_BAD, rootPath, "/"); 646 return (R_FAILURE); 647 } 648 649 /* - zone name must be global */ 650 651 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { 652 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_BAD, rootPath, 653 GLOBAL_ZONENAME); 654 return (R_FAILURE); 655 } 656 657 /* 658 * /export/exec/Solaris_"*"/usr must exist; 659 * create ls command to test: 660 * /usr/bin/ls /export/exec/Solaris_"*"/usr 661 */ 662 663 (void) snprintf(cmd, sizeof (cmd), "%s %s >/dev/null 2>&1", 664 LS_CMD, "/export/exec/Solaris_*/usr"); 665 666 /* execute command */ 667 668 rc = system(cmd); 669 670 /* return error if ls returns something other than "0" */ 671 672 if (rc != 0) { 673 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_MISSING, 674 rootPath, "/export/exec/Solaris_*/usr"); 675 return (R_FAILURE); 676 } 677 678 /* 679 * /usr must be empty on a diskless client: 680 * create ls command to test: 681 * /usr/bin/ls -d1 $ROOTDIR/usr/\* 682 */ 683 (void) snprintf(cmd, sizeof (cmd), "%s %s %s/%s >/dev/null 2>&1", 684 LS_CMD, "-1d", rootPath, "usr/*"); 685 686 /* execute command */ 687 688 rc = system(cmd); 689 690 /* return error if ls returns "0" */ 691 692 if (rc == 0) { 693 log_msg(LOG_MSG_DEBUG, DBG_IDLC_USR_IS_NOT_EMPTY, 694 rootPath); 695 return (R_FAILURE); 696 } 697 698 /* there must be a templates directory at ${ROOTPATH}/../templates */ 699 700 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 701 "%s/%s", rootPath, "../templates"); 702 if (r != R_SUCCESS) { 703 log_msg(LOG_MSG_DEBUG, DBG_IDLC_NO_TEMPLATES_PATH, 704 rootPath, rootPath, "../templates"); 705 return (R_FAILURE); 706 } 707 708 /* must not be initial installation to the install root */ 709 710 if ((a_gdt->gd_initialInstall == B_TRUE) && 711 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 712 /* initial install: install root cannot be diskless client */ 713 log_msg(LOG_MSG_DEBUG, DBG_IDLC_INITIAL_INSTALL, rootPath); 714 return (R_FAILURE); 715 } 716 717 /* must not be installation of a zone */ 718 719 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 720 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 721 /* initial zone install: no path can be diskless client */ 722 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_INSTALL, rootPath); 723 return (R_FAILURE); 724 } 725 726 /* the path is a diskless client */ 727 728 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_IS_DISKLESS_CLIENT, rootPath); 729 730 return (R_SUCCESS); 731 } 732 733 /* 734 * Name: cmd_is_global_zone 735 * Description: determine if target is a global zone 736 * Scope: public 737 * Arguments: argc,argv: 738 * - optional path to target to test 739 * Returns: int 740 * == 0 - success 741 * != 0 - failure 742 * IMPLEMENTATION: 743 * - must not be initial installation to the install root 744 * - must not be installation of a non-global zone 745 * - must not be a non-global zone 746 * - must not be a mounted mini-root 747 * - must not be a netinstall image 748 * - must not be a diskless client 749 * - if $ROOTDIR is "/": 750 * -- if zone name is "GLOBAL", then is a global zone; 751 * -- else not a global zone. 752 * - $ROOTDIR/etc/zones must exist and be a directory 753 * - $ROOTDIR/.tmp_proto must not exist 754 * - $ROOTDIR/var must exist and must not be a symbolic link 755 */ 756 757 static int 758 cmd_is_global_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) 759 { 760 char *rootPath = NULL; 761 int c; 762 int r; 763 static char *cmdName = "is_global_zone"; 764 static int recursion = 0; 765 766 /* process any command line options */ 767 768 while ((c = getopt(argc, argv, ":")) != EOF) { 769 switch (c) { 770 case '\0': /* prevent end-of-loop not reached warning */ 771 break; 772 case '?': 773 default: 774 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 775 return (R_USAGE); 776 } 777 } 778 779 /* prevent recursion */ 780 781 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 782 783 /* 784 * a global zone cannot be any of the following 785 */ 786 787 /* cannot be a non-global zone */ 788 789 r = cmd_is_nonglobal_zone(argc, argv, a_gdt); 790 791 /* cannot be a mounted miniroot */ 792 793 if (r != R_SUCCESS) { 794 r = cmd_is_mounted_miniroot(argc, argv, a_gdt); 795 } 796 797 /* cannot be a netinstall image */ 798 799 if (r != R_SUCCESS) { 800 r = cmd_is_netinstall_image(argc, argv, a_gdt); 801 } 802 803 /* cannot be a diskless client */ 804 805 if (r != R_SUCCESS) { 806 r = cmd_is_diskless_client(argc, argv, a_gdt); 807 } 808 809 /* no need to guard against recursion any more */ 810 811 recursion--; 812 813 /* return failure if any of the preceeding are true */ 814 815 switch (r) { 816 case R_SUCCESS: 817 return (R_FAILURE); 818 case R_FAILURE: 819 break; 820 case R_USAGE: 821 case R_ERROR: 822 default: 823 return (r); 824 } 825 } 826 827 /* normalize argc/argv */ 828 829 argc -= optind; 830 argv += optind; 831 832 /* error if more than one argument */ 833 834 if (argc > 1) { 835 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 836 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 837 return (R_USAGE); 838 } 839 840 /* process root path if first argument present */ 841 842 if (argc == 1) { 843 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 844 return (R_ERROR); 845 } 846 } 847 848 /* get current root path */ 849 850 r = getRootPath(&rootPath); 851 if (r != R_SUCCESS) { 852 return (r); 853 } 854 855 /* start of command debugging information */ 856 857 echoDebug(DBG_ROOTPATH_IS, rootPath); 858 859 /* must not be initial installation to the install root */ 860 861 if ((a_gdt->gd_initialInstall == B_TRUE) && 862 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 863 /* initial install: install root cannot be global zone */ 864 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_INITIAL_INSTALL, rootPath); 865 return (R_FAILURE); 866 } 867 868 /* must not be installation of a non-global zone */ 869 870 if (a_gdt->gd_nonglobalZoneInstall == B_TRUE) { 871 /* initial nonglobal zone install: no path can be global zone */ 872 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_NGZ_ZONE_INSTALL, rootPath); 873 return (R_FAILURE); 874 } 875 876 /* handle if global zone installation to the install root */ 877 878 if ((a_gdt->gd_globalZoneInstall == B_TRUE) && 879 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 880 /* the path is a global zone */ 881 882 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, 883 rootPath); 884 885 return (R_SUCCESS); 886 } 887 888 /* true if current root is "/" and zone name is GLOBAL_ZONENAME */ 889 890 if (strcmp(rootPath, "/") == 0) { 891 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { 892 /* the path is a global zone */ 893 894 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, 895 rootPath); 896 897 return (R_SUCCESS); 898 } 899 900 /* inside a non-global zone */ 901 902 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_ZONENAME_ISNT_GLOBAL, 903 rootPath, a_gdt->gd_zoneName); 904 905 return (R_FAILURE); 906 } 907 908 /* 909 * current root is not "/" - see if target looks like a global zone 910 * 911 * - rootpath is not "/" 912 * - and $ROOTDIR/etc/zones exists 913 * - and $ROOTDIR/.tmp_proto does not exist 914 * - and $ROOTDIR/var is not a symbolic link 915 */ 916 917 /* not global zone if /etc/zones does not exist */ 918 919 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 920 "%s/%s", rootPath, "/etc/zones"); 921 if (r != R_SUCCESS) { 922 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_ISNT_DIRECTORY, 923 rootPath, "/etc/zones"); 924 return (R_FAILURE); 925 } 926 927 /* .tmp_proto must not exist */ 928 929 r = testPath(TEST_NOT_EXISTS, 930 "%s/%s", rootPath, ".tmp_proto"); 931 if (r != R_SUCCESS) { 932 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_EXISTS, 933 rootPath, "/.tmp_proto"); 934 return (R_FAILURE); 935 } 936 937 /* /var must not be a symbolic link */ 938 939 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 940 "%s/%s", rootPath, "/var"); 941 if (r != R_SUCCESS) { 942 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_SYMLINK, 943 rootPath, "/var"); 944 return (R_FAILURE); 945 } 946 947 /* the path is a global zone */ 948 949 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, rootPath); 950 951 return (R_SUCCESS); 952 } 953 954 /* 955 * Name: cmd_is_netinstall_image 956 * Description: determine if target is a net install image 957 * Scope: public 958 * Arguments: argc,argv: 959 * - optional path to target to test 960 * Returns: int 961 * == 0 - success 962 * != 0 - failure 963 * IMPLEMENTATION: 964 * - must not be initial installation to the install root 965 * - must not be installation of a zone 966 * - must not be a global zone 967 * - must not be a mounted mini-root 968 * - zone name must be "global" 969 * - $ROOTDIR/.tmp_proto must exist and must be a directory 970 * - $ROOTDIR/var must exist and must be a symbolic link 971 * - $ROOTDIR/tmp/kernel must exist and must be a directory 972 * - $ROOTDIR/.tmp_proto/kernel must exist and must be a symbolic link 973 */ 974 975 static int 976 cmd_is_netinstall_image(int argc, char **argv, GLOBALDATA_T *a_gdt) 977 { 978 char *rootPath = NULL; 979 int c; 980 int r; 981 static char *cmdName = "is_netinstall_image"; 982 static int recursion = 0; 983 984 /* process any command line options */ 985 986 while ((c = getopt(argc, argv, ":")) != EOF) { 987 switch (c) { 988 case '\0': /* prevent end-of-loop not reached warning */ 989 break; 990 case '?': 991 default: 992 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 993 return (R_USAGE); 994 } 995 } 996 997 /* prevent recursion */ 998 999 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1000 1001 /* a netinstall image cannot be a global zone */ 1002 1003 r = cmd_is_global_zone(argc, argv, a_gdt); 1004 1005 /* no need to guard against recursion any more */ 1006 1007 recursion--; 1008 1009 switch (r) { 1010 case R_SUCCESS: 1011 return (R_FAILURE); 1012 case R_FAILURE: 1013 break; 1014 case R_USAGE: 1015 case R_ERROR: 1016 default: 1017 return (r); 1018 } 1019 } 1020 1021 /* normalize argc/argv */ 1022 1023 argc -= optind; 1024 argv += optind; 1025 1026 /* error if more than one argument */ 1027 1028 if (argc > 1) { 1029 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1030 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1031 return (R_USAGE); 1032 } 1033 1034 /* process root path if first argument present */ 1035 1036 if (argc == 1) { 1037 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1038 return (R_ERROR); 1039 } 1040 } 1041 1042 /* get current root path */ 1043 1044 r = getRootPath(&rootPath); 1045 if (r != R_SUCCESS) { 1046 return (r); 1047 } 1048 1049 /* start of command debugging information */ 1050 1051 echoDebug(DBG_ROOTPATH_IS, rootPath); 1052 1053 /* current zone name must be "global" */ 1054 1055 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { 1056 log_msg(LOG_MSG_DEBUG, DBG_INIM_BAD_CURRENT_ZONE, 1057 rootPath, GLOBAL_ZONENAME); 1058 return (R_FAILURE); 1059 } 1060 1061 /* cannot be a mounted_miniroot */ 1062 1063 if (cmd_is_mounted_miniroot(argc, argv, a_gdt) == R_SUCCESS) { 1064 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT, 1065 rootPath); 1066 return (R_FAILURE); 1067 } 1068 1069 /* $ROOTDIR/.tmp_proto exists */ 1070 1071 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 1072 "%s/%s", rootPath, ".tmp_proto"); 1073 if (r != R_SUCCESS) { 1074 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY, 1075 rootPath, "/.tmp_proto"); 1076 return (R_FAILURE); 1077 } 1078 1079 /* $ROOTDIR/var is a symbolic link */ 1080 1081 r = testPath(TEST_IS_SYMBOLIC_LINK, 1082 "%s/%s", rootPath, "/var"); 1083 if (r != R_SUCCESS) { 1084 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK, 1085 rootPath, "/var"); 1086 return (R_FAILURE); 1087 } 1088 1089 /* $ROOTDIR/tmp/kernel does exist */ 1090 1091 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 1092 "%s/%s", rootPath, "/tmp/kernel"); 1093 if (r != R_SUCCESS) { 1094 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY, 1095 rootPath, "/tmp/kernel"); 1096 return (R_FAILURE); 1097 } 1098 1099 /* $ROOTDIR/.tmp_proto/kernel is a symbolic link */ 1100 1101 r = testPath(TEST_IS_SYMBOLIC_LINK, 1102 "%s/%s", rootPath, "/.tmp_proto/kernel"); 1103 if (r != R_SUCCESS) { 1104 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK, 1105 rootPath, "/.tmp_proto/kernel"); 1106 return (R_FAILURE); 1107 } 1108 1109 /* must not be initial installation to the install root */ 1110 1111 if ((a_gdt->gd_initialInstall == B_TRUE) && 1112 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 1113 /* initial install: install root cannot be netinstall image */ 1114 log_msg(LOG_MSG_DEBUG, DBG_INIM_INITIAL_INSTALL, rootPath); 1115 return (R_FAILURE); 1116 } 1117 1118 /* must not be installation of a zone */ 1119 1120 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 1121 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 1122 /* initial zone install: no path can be netinstall image */ 1123 log_msg(LOG_MSG_DEBUG, DBG_INIM_ZONE_INSTALL, rootPath); 1124 return (R_FAILURE); 1125 } 1126 1127 /* target is a netinstall image */ 1128 1129 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_IS_NETINSTALL_IMAGE, rootPath); 1130 1131 return (R_SUCCESS); 1132 } 1133 1134 /* 1135 * Name: cmd_is_mounted_miniroot 1136 * Description: determine if target is a mounted miniroot image 1137 * Scope: public 1138 * Arguments: argc,argv: 1139 * - optional path to target to test 1140 * Returns: int 1141 * == 0 - success 1142 * != 0 - failure 1143 * IMPLEMENTATION: 1144 * - must not be initial installation to the install root 1145 * - must not be installation of a zone 1146 * - zone name must be "global" 1147 * - $ROOTDIR/tmp/kernel must exist and must be a symbolic link 1148 * - $ROOTDIR/tmp/root/kernel must exist and must be a directory 1149 */ 1150 1151 static int 1152 cmd_is_mounted_miniroot(int argc, char **argv, GLOBALDATA_T *a_gdt) 1153 { 1154 char *rootPath = NULL; 1155 int c; 1156 int r; 1157 static char *cmdName = "is_mounted_miniroot"; 1158 static int recursion = 0; 1159 1160 /* process any command line options */ 1161 1162 while ((c = getopt(argc, argv, ":")) != EOF) { 1163 switch (c) { 1164 case '\0': /* prevent end-of-loop not reached warning */ 1165 break; 1166 case '?': 1167 default: 1168 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1169 return (R_USAGE); 1170 } 1171 } 1172 1173 /* prevent recursion */ 1174 1175 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1176 recursion--; 1177 } 1178 1179 /* normalize argc/argv */ 1180 1181 argc -= optind; 1182 argv += optind; 1183 1184 /* error if more than one argument */ 1185 1186 if (argc > 1) { 1187 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1188 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1189 return (R_USAGE); 1190 } 1191 1192 /* process root path if first argument present */ 1193 1194 if (argc == 1) { 1195 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1196 return (R_ERROR); 1197 } 1198 } 1199 1200 /* get current root path */ 1201 1202 r = getRootPath(&rootPath); 1203 if (r != R_SUCCESS) { 1204 return (r); 1205 } 1206 1207 /* start of command debugging information */ 1208 1209 echoDebug(DBG_ROOTPATH_IS, rootPath); 1210 1211 /* current zone name must be "global" */ 1212 1213 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { 1214 log_msg(LOG_MSG_DEBUG, DBG_IMRT_BAD_CURRENT_ZONE, 1215 rootPath, GLOBAL_ZONENAME); 1216 return (R_FAILURE); 1217 } 1218 1219 /* $ROOTDIR/tmp/kernel is a symbolic link */ 1220 1221 r = testPath(TEST_IS_SYMBOLIC_LINK, 1222 "%s/%s", rootPath, "/tmp/kernel"); 1223 if (r != R_SUCCESS) { 1224 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_SYMLINK, 1225 rootPath, "/tmp/kernel"); 1226 return (R_FAILURE); 1227 } 1228 1229 /* $ROOTDIR/tmp/root/kernel is a directory */ 1230 1231 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 1232 "%s/%s", rootPath, "/tmp/root/kernel"); 1233 if (r != R_SUCCESS) { 1234 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_DIRECTORY, 1235 rootPath, "/tmp/root/kernel"); 1236 return (R_FAILURE); 1237 } 1238 1239 /* must not be initial installation to the install root */ 1240 1241 if ((a_gdt->gd_initialInstall == B_TRUE) && 1242 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 1243 /* initial install: install root cannot be mounted miniroot */ 1244 log_msg(LOG_MSG_DEBUG, DBG_IMRT_INITIAL_INSTALL, rootPath); 1245 return (R_FAILURE); 1246 } 1247 1248 /* must not be installation of a zone */ 1249 1250 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 1251 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 1252 /* initial zone install: no path can be mounted miniroot */ 1253 log_msg(LOG_MSG_DEBUG, DBG_IMRT_ZONE_INSTALL, rootPath); 1254 return (R_FAILURE); 1255 } 1256 1257 /* target is a mounted miniroot */ 1258 1259 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT, rootPath); 1260 1261 return (R_SUCCESS); 1262 } 1263 1264 /* 1265 * Name: cmd_is_nonglobal_zone 1266 * Description: determine if target is a global zone 1267 * Scope: public 1268 * Arguments: argc,argv: 1269 * - optional path to target to test 1270 * Returns: int 1271 * == 0 - success 1272 * != 0 - failure 1273 * - must not be initial installation to the install root 1274 * - must not be installation of a global zone 1275 * - success if installation of a non-global zone 1276 */ 1277 1278 static int 1279 cmd_is_nonglobal_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) 1280 { 1281 char *rootPath = NULL; 1282 int c; 1283 int r; 1284 static char *cmdName = "is_nonglobal_zone"; 1285 static int recursion = 0; 1286 1287 /* process any command line options */ 1288 1289 while ((c = getopt(argc, argv, ":")) != EOF) { 1290 switch (c) { 1291 case '\0': /* prevent end-of-loop not reached warning */ 1292 break; 1293 case '?': 1294 default: 1295 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1296 return (R_USAGE); 1297 } 1298 } 1299 1300 /* prevent recursion */ 1301 1302 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1303 recursion--; 1304 } 1305 1306 /* normalize argc/argv */ 1307 1308 argc -= optind; 1309 argv += optind; 1310 1311 /* error if more than one argument */ 1312 1313 if (argc > 1) { 1314 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1315 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1316 return (R_USAGE); 1317 } 1318 1319 /* process root path if first argument present */ 1320 1321 if (argc == 1) { 1322 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1323 return (R_ERROR); 1324 } 1325 } 1326 1327 /* get current root path */ 1328 1329 r = getRootPath(&rootPath); 1330 if (r != R_SUCCESS) { 1331 return (r); 1332 } 1333 1334 /* start of command debugging information */ 1335 1336 echoDebug(DBG_ROOTPATH_IS, rootPath); 1337 1338 /* handle if non-global zone installation to the install root */ 1339 1340 if ((a_gdt->gd_nonglobalZoneInstall == B_TRUE) && 1341 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 1342 log_msg(LOG_MSG_DEBUG, DBG_NGZN_INSTALL_ZONENAME_IS_NGZ, 1343 rootPath, a_gdt->gd_zoneName); 1344 return (R_SUCCESS); 1345 } 1346 1347 /* must not be initial installation to the install root */ 1348 1349 if ((a_gdt->gd_initialInstall == B_TRUE) && 1350 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 1351 /* initial install: install root cannot be non-global zone */ 1352 log_msg(LOG_MSG_DEBUG, DBG_NGZN_INITIAL_INSTALL, rootPath); 1353 return (R_FAILURE); 1354 } 1355 1356 /* must not be installation of a global zone */ 1357 1358 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 1359 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 1360 /* initial global zone install: no path can be nonglobal zone */ 1361 log_msg(LOG_MSG_DEBUG, DBG_NGZN_GLOBAL_ZONE_INSTALL, rootPath); 1362 return (R_FAILURE); 1363 } 1364 1365 /* 1366 * ********************************************************************* 1367 * if root directory is "/" then the only thing that needs to be done is 1368 * to test the zone name directly - if the zone name is "global" then 1369 * the target is not a non-global zone; otherwise if the zone name is 1370 * not "global" then the target IS a non-global zone. 1371 * ********************************************************************* 1372 */ 1373 1374 if (strcmp(rootPath, "/") == 0) { 1375 /* target is current running root */ 1376 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { 1377 /* in the global zone */ 1378 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ, 1379 rootPath, a_gdt->gd_zoneName); 1380 return (R_FAILURE); 1381 } 1382 /* in a non-global zone */ 1383 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_IS_NGZ, 1384 rootPath, a_gdt->gd_zoneName); 1385 return (R_SUCCESS); 1386 } 1387 1388 /* 1389 * $ROOTDIR/etc/zones/index must exist in a global zone. It also 1390 * exists in a non-global zone after s10u4 but we can't check that 1391 * since it is undeterministic for all releases so we only check 1392 * for the global zone here. 1393 */ 1394 1395 r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/zones/index"); 1396 if (r == R_SUCCESS) { 1397 1398 /* See if "global" exists in .../etc/zones/index */ 1399 1400 if (testPath(TEST_GLOBAL_TOKEN_IN_FILE, "%s/%s", rootPath, 1401 "/etc/zones/index") != R_SUCCESS) { 1402 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ, 1403 rootPath, GLOBAL_ZONENAME); 1404 return (R_FAILURE); 1405 } 1406 } 1407 1408 /* 1409 * ********************************************************************* 1410 * If the root directory is "/" then you can use only the zone 1411 * name to determine if the zone is non-global or not since the 1412 * package is being installed or removed to the current "zone". 1413 * 1414 * Since the root directory being tested is not "/" then you have to 1415 * look into the target to try and infer zone type using means other 1416 * than the zone name only. 1417 * ********************************************************************* 1418 */ 1419 1420 /* reject if any items found that cannot be in a non-global zone */ 1421 1422 /* .tmp_proto must not exist */ 1423 1424 r = testPath(TEST_NOT_EXISTS, "%s/%s", rootPath, ".tmp_proto"); 1425 if (r != R_SUCCESS) { 1426 /* $R/.tmp_proto cannot exist in a non-global zone */ 1427 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS, 1428 rootPath, "/.tmp_proto"); 1429 return (R_FAILURE); 1430 } 1431 1432 /* /var must not be a symbolic link */ 1433 1434 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1435 "%s/%s", rootPath, "/var"); 1436 if (r != R_SUCCESS) { 1437 /* $R/var cannot be a symbolic link in a non-global zone */ 1438 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_DOES_NOT_EXIST, 1439 rootPath, "/var"); 1440 return (R_FAILURE); 1441 } 1442 1443 /* $ROOTDIR/tmp/root/kernel must not exist */ 1444 1445 r = testPath(TEST_NOT_EXISTS, 1446 "%s/%s", rootPath, "/tmp/root/kernel"); 1447 if (r != R_SUCCESS) { 1448 /* $R/tmp/root/kernel cannot exist in a non-global zone */ 1449 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS, 1450 rootPath, "/tmp/root/kernel"); 1451 return (R_FAILURE); 1452 } 1453 1454 /* 1455 * ********************************************************************* 1456 * no items exist in $ROOTDIR that identify something other than 1457 * a non-global zone. 1458 * 1459 * if in global zone no more tests possible: is a non-global zone 1460 * ********************************************************************* 1461 */ 1462 1463 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { 1464 /* in the global zone */ 1465 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IN_GZ_IS_NONGLOBAL_ZONE, 1466 rootPath); 1467 return (R_SUCCESS); 1468 } 1469 1470 /* 1471 * ********************************************************************* 1472 * In non-global zone: interrogate zone name and type. 1473 * 1474 * The parent zone is the zone that the "pkgadd" or "pkgrm" command was 1475 * run in. The child zone is the zone that the "pkginstall" or 1476 * "pkgremove" command was run in. 1477 * ********************************************************************* 1478 */ 1479 1480 /* 1481 * If parent zone name and current zone name defined, and 1482 * both zone names are the same, since pkgcond is running 1483 * inside of a non-global zone, this is how the scratch 1484 * zone is implemented, so target is a non-global zone 1485 */ 1486 1487 if ((a_gdt->gd_parentZoneName != NULL) && 1488 (a_gdt->gd_currentZoneName != NULL) && 1489 (strcmp(a_gdt->gd_parentZoneName, 1490 a_gdt->gd_currentZoneName) == 0)) { 1491 /* parent and current zone name identical: non-gz */ 1492 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PARENT_CHILD_SAMEZONE, 1493 rootPath, a_gdt->gd_parentZoneName); 1494 return (R_SUCCESS); 1495 } 1496 1497 /* 1498 * In non-global zone if inherited FS's exits 1499 * or zone specific read only FS's exist 1500 * or it is in a mounted state. 1501 */ 1502 1503 if (a_gdt->gd_inheritedFileSystems != NULL || 1504 a_gdt->gd_srFsMountedRO || a_gdt->inMountedState) { 1505 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath); 1506 return (R_SUCCESS); 1507 } 1508 1509 /* 1510 * the parent and current zone name are not the same; 1511 * interrogate the zone types: the parent must be global 1512 * and the current must be non-global, which would be set 1513 * when a package command is run in the global zone that in 1514 * turn runs a package command within the non-global zone. 1515 */ 1516 1517 /* if defined, parent zone type must be "global" */ 1518 1519 if ((a_gdt->gd_parentZoneType != NULL) && 1520 (strcmp(a_gdt->gd_parentZoneType, "nonglobal") == 0)) { 1521 log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_PARENT_ZONETYPE, 1522 rootPath, "nonglobal"); 1523 return (R_FAILURE); 1524 } 1525 1526 /* if defined, current zone type must be "nonglobal" */ 1527 1528 if ((a_gdt->gd_currentZoneType != NULL) && 1529 (strcmp(a_gdt->gd_currentZoneType, GLOBAL_ZONENAME) == 0)) { 1530 log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_CURRENT_ZONETYPE, 1531 rootPath, GLOBAL_ZONENAME); 1532 return (R_FAILURE); 1533 } 1534 1535 /* 1536 * ********************************************************************* 1537 * no other tests possible: target is a non-global zone 1538 * ********************************************************************* 1539 */ 1540 1541 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath); 1542 1543 return (R_SUCCESS); 1544 } 1545 1546 /* 1547 * Name: cmd_is_running_system 1548 * Description: determine if target is a global zone 1549 * Scope: public 1550 * Arguments: argc,argv: 1551 * - optional path to target to test 1552 * Returns: int 1553 * == 0 - success 1554 * != 0 - failure 1555 * IMPLEMENTATION: 1556 * - must not be initial installation to the install root 1557 * - must not be installation of a zone 1558 * - must not be a diskless client 1559 * - $ROOTDIR must be "/" 1560 * - zone name must be "global" 1561 */ 1562 1563 static int 1564 cmd_is_running_system(int argc, char **argv, GLOBALDATA_T *a_gdt) 1565 { 1566 char *rootPath = NULL; 1567 int c; 1568 int r; 1569 static char *cmdName = "is_running_system"; 1570 static int recursion = 0; 1571 1572 /* process any command line options */ 1573 1574 while ((c = getopt(argc, argv, ":")) != EOF) { 1575 switch (c) { 1576 case '\0': /* prevent end-of-loop not reached warning */ 1577 break; 1578 case '?': 1579 default: 1580 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1581 return (R_USAGE); 1582 } 1583 } 1584 1585 /* prevent recursion */ 1586 1587 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1588 1589 /* a running system cannot be a diskless client */ 1590 1591 r = cmd_is_diskless_client(argc, argv, a_gdt); 1592 1593 /* no need to guard against recursion any more */ 1594 1595 recursion--; 1596 1597 switch (r) { 1598 case R_SUCCESS: 1599 return (R_FAILURE); 1600 case R_FAILURE: 1601 break; 1602 case R_USAGE: 1603 case R_ERROR: 1604 default: 1605 return (r); 1606 } 1607 } 1608 1609 /* normalize argc/argv */ 1610 1611 argc -= optind; 1612 argv += optind; 1613 1614 /* error if more than one argument */ 1615 1616 if (argc > 1) { 1617 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1618 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1619 return (R_USAGE); 1620 } 1621 1622 /* process root path if first argument present */ 1623 1624 if (argc == 1) { 1625 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1626 return (R_ERROR); 1627 } 1628 } 1629 1630 /* get current root path */ 1631 1632 r = getRootPath(&rootPath); 1633 if (r != R_SUCCESS) { 1634 return (r); 1635 } 1636 1637 /* start of command debugging information */ 1638 1639 echoDebug(DBG_ROOTPATH_IS, rootPath); 1640 1641 /* if root path is "/" then check zone name */ 1642 1643 if (strcmp(rootPath, "/") != 0) { 1644 log_msg(LOG_MSG_DEBUG, DBG_IRST_ROOTPATH_BAD, rootPath, "/"); 1645 return (R_FAILURE); 1646 } 1647 1648 /* zone name must be global */ 1649 1650 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { 1651 log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_BAD, rootPath, 1652 GLOBAL_ZONENAME); 1653 return (R_FAILURE); 1654 } 1655 1656 /* must not be initial installation to the install root */ 1657 1658 if ((a_gdt->gd_initialInstall == B_TRUE) && 1659 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 1660 /* initial install: install root cannot be the running system */ 1661 log_msg(LOG_MSG_DEBUG, DBG_IRST_INITIAL_INSTALL, rootPath); 1662 return (R_FAILURE); 1663 } 1664 1665 /* must not be installation of a zone */ 1666 1667 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 1668 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 1669 /* initial zone install: no path can be running system */ 1670 log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_INSTALL, rootPath); 1671 return (R_FAILURE); 1672 } 1673 1674 /* target is a running system */ 1675 1676 log_msg(LOG_MSG_DEBUG, DBG_IRST_PATH_IS_RUNNING_SYSTEM, rootPath); 1677 1678 return (R_SUCCESS); 1679 } 1680 1681 /* 1682 * Name: cmd_can_add_driver 1683 * Description: determine if target is a global zone 1684 * Scope: public 1685 * Arguments: argc,argv: 1686 * - optional path to target to test 1687 * Returns: int 1688 * == 0 - success 1689 * != 0 - failure 1690 * Implementation: 1691 * A driver can be added to the system if the components of a Solaris 1692 * instance capable of loading drivers is present and it is not the 1693 * currently running system. 1694 */ 1695 1696 static int 1697 cmd_can_add_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) 1698 { 1699 char *rootPath = NULL; 1700 int c; 1701 int r; 1702 static char *cmdName = "can_add_driver"; 1703 static int recursion = 0; 1704 1705 /* process any command line options */ 1706 1707 while ((c = getopt(argc, argv, ":")) != EOF) { 1708 switch (c) { 1709 case '\0': /* prevent end-of-loop not reached warning */ 1710 break; 1711 case '?': 1712 default: 1713 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1714 return (R_USAGE); 1715 } 1716 } 1717 1718 /* prevent recursion */ 1719 1720 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1721 1722 /* see if this is the current running system */ 1723 1724 r = cmd_is_running_system(argc, argv, a_gdt); 1725 1726 /* cannot be a diskless client */ 1727 1728 if (r != R_SUCCESS) { 1729 r = cmd_is_diskless_client(argc, argv, a_gdt); 1730 } 1731 1732 /* no need to guard against recursion any more */ 1733 1734 recursion--; 1735 1736 switch (r) { 1737 case R_SUCCESS: 1738 /* is a running system */ 1739 return (R_FAILURE); 1740 case R_FAILURE: 1741 /* not a running syste */ 1742 break; 1743 case R_USAGE: 1744 case R_ERROR: 1745 default: 1746 /* cannot determine if is a running system */ 1747 return (r); 1748 } 1749 } 1750 1751 /* normalize argc/argv */ 1752 1753 argc -= optind; 1754 argv += optind; 1755 1756 /* error if more than one argument */ 1757 1758 if (argc > 1) { 1759 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1760 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1761 return (R_USAGE); 1762 } 1763 1764 /* process root path if first argument present */ 1765 1766 if (argc == 1) { 1767 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1768 return (R_ERROR); 1769 } 1770 } 1771 1772 /* get current root path */ 1773 1774 r = getRootPath(&rootPath); 1775 if (r != R_SUCCESS) { 1776 return (r); 1777 } 1778 1779 /* start of command debugging information */ 1780 1781 echoDebug(DBG_ROOTPATH_IS, rootPath); 1782 1783 /* /etc must exist and must not be a symbolic link */ 1784 1785 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1786 "%s/%s", rootPath, "/etc"); 1787 if (r != R_SUCCESS) { 1788 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, 1789 rootPath, "/etc"); 1790 return (R_FAILURE); 1791 } 1792 1793 /* /platform must exist and must not be a symbolic link */ 1794 1795 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1796 "%s/%s", rootPath, "/platform"); 1797 if (r != R_SUCCESS) { 1798 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, 1799 rootPath, "/platform"); 1800 return (R_FAILURE); 1801 } 1802 1803 /* /kernel must exist and must not be a symbolic link */ 1804 1805 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1806 "%s/%s", rootPath, "/kernel"); 1807 if (r != R_SUCCESS) { 1808 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, 1809 rootPath, "/kernel"); 1810 return (R_FAILURE); 1811 } 1812 1813 /* can add a driver */ 1814 1815 log_msg(LOG_MSG_DEBUG, DBG_ADDV_YES, rootPath); 1816 1817 return (R_SUCCESS); 1818 } 1819 1820 /* 1821 * Name: cmd_can_update_driver 1822 * Description: determine if target is a global zone 1823 * Scope: public 1824 * Arguments: argc,argv: 1825 * - optional path to target to test 1826 * Returns: int 1827 * == 0 - success 1828 * != 0 - failure 1829 * Implementation: 1830 * A driver can be added to the system if the components of a Solaris 1831 * instance capable of loading drivers is present and it is not the 1832 * currently running system. 1833 */ 1834 1835 static int 1836 cmd_can_update_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) 1837 { 1838 char *rootPath = NULL; 1839 int c; 1840 int r; 1841 static char *cmdName = "can_update_driver"; 1842 static int recursion = 0; 1843 1844 /* process any command line options */ 1845 1846 while ((c = getopt(argc, argv, ":")) != EOF) { 1847 switch (c) { 1848 case '\0': /* prevent end-of-loop not reached warning */ 1849 break; 1850 case '?': 1851 default: 1852 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1853 return (R_USAGE); 1854 } 1855 } 1856 1857 /* prevent recursion */ 1858 1859 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1860 1861 /* see if this is the current running system */ 1862 1863 r = cmd_is_running_system(argc, argv, a_gdt); 1864 1865 /* cannot be a diskless client */ 1866 1867 if (r != R_SUCCESS) { 1868 r = cmd_is_diskless_client(argc, argv, a_gdt); 1869 } 1870 1871 /* no need to guard against recursion any more */ 1872 1873 recursion--; 1874 1875 switch (r) { 1876 case R_SUCCESS: 1877 /* is a running system */ 1878 return (R_FAILURE); 1879 case R_FAILURE: 1880 /* not a running syste */ 1881 break; 1882 case R_USAGE: 1883 case R_ERROR: 1884 default: 1885 /* cannot determine if is a running system */ 1886 return (r); 1887 } 1888 } 1889 1890 /* normalize argc/argv */ 1891 1892 argc -= optind; 1893 argv += optind; 1894 1895 /* error if more than one argument */ 1896 1897 if (argc > 1) { 1898 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 1899 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 1900 return (R_USAGE); 1901 } 1902 1903 /* process root path if first argument present */ 1904 1905 if (argc == 1) { 1906 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 1907 return (R_ERROR); 1908 } 1909 } 1910 1911 /* get current root path */ 1912 1913 r = getRootPath(&rootPath); 1914 if (r != R_SUCCESS) { 1915 return (r); 1916 } 1917 1918 /* start of command debugging information */ 1919 1920 echoDebug(DBG_ROOTPATH_IS, rootPath); 1921 1922 /* /etc must exist and must not be a symbolic link */ 1923 1924 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1925 "%s/%s", rootPath, "/etc"); 1926 if (r != R_SUCCESS) { 1927 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, 1928 rootPath, "/etc"); 1929 return (R_FAILURE); 1930 } 1931 1932 /* /platform must exist and must not be a symbolic link */ 1933 1934 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1935 "%s/%s", rootPath, "/platform"); 1936 if (r != R_SUCCESS) { 1937 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, 1938 rootPath, "/platform"); 1939 return (R_FAILURE); 1940 } 1941 1942 /* /kernel must exist and must not be a symbolic link */ 1943 1944 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 1945 "%s/%s", rootPath, "/kernel"); 1946 if (r != R_SUCCESS) { 1947 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, 1948 rootPath, "/kernel"); 1949 return (R_FAILURE); 1950 } 1951 1952 /* can update driver */ 1953 1954 log_msg(LOG_MSG_DEBUG, DBG_UPDV_YES, rootPath); 1955 1956 return (R_SUCCESS); 1957 } 1958 1959 /* 1960 * Name: cmd_can_remove_driver 1961 * Description: determine if target is a global zone 1962 * Scope: public 1963 * Arguments: argc,argv: 1964 * - optional path to target to test 1965 * Returns: int 1966 * == 0 - success 1967 * != 0 - failure 1968 * Implementation: 1969 * A driver can be added to the system if the components of a Solaris 1970 * instance capable of loading drivers is present and it is not the 1971 * currently running system. 1972 */ 1973 1974 static int 1975 cmd_can_remove_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) 1976 { 1977 char *rootPath = NULL; 1978 int c; 1979 int r; 1980 static char *cmdName = "can_remove_driver"; 1981 static int recursion = 0; 1982 1983 /* process any command line options */ 1984 1985 while ((c = getopt(argc, argv, ":")) != EOF) { 1986 switch (c) { 1987 case '\0': /* prevent end-of-loop not reached warning */ 1988 break; 1989 case '?': 1990 default: 1991 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 1992 return (R_USAGE); 1993 } 1994 } 1995 1996 /* prevent recursion */ 1997 1998 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 1999 2000 /* see if this is the current running system */ 2001 2002 r = cmd_is_running_system(argc, argv, a_gdt); 2003 2004 /* cannot be a diskless client */ 2005 2006 if (r != R_SUCCESS) { 2007 r = cmd_is_diskless_client(argc, argv, a_gdt); 2008 } 2009 2010 /* no need to guard against recursion any more */ 2011 2012 recursion--; 2013 2014 switch (r) { 2015 case R_SUCCESS: 2016 /* is a running system */ 2017 return (R_FAILURE); 2018 case R_FAILURE: 2019 /* not a running syste */ 2020 break; 2021 case R_USAGE: 2022 case R_ERROR: 2023 default: 2024 /* cannot determine if is a running system */ 2025 return (r); 2026 } 2027 } 2028 2029 /* normalize argc/argv */ 2030 2031 argc -= optind; 2032 argv += optind; 2033 2034 /* error if more than one argument */ 2035 2036 if (argc > 1) { 2037 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2038 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2039 return (R_USAGE); 2040 } 2041 2042 /* process root path if first argument present */ 2043 2044 if (argc == 1) { 2045 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2046 return (R_ERROR); 2047 } 2048 } 2049 2050 /* get current root path */ 2051 2052 r = getRootPath(&rootPath); 2053 if (r != R_SUCCESS) { 2054 return (r); 2055 } 2056 2057 /* start of command debugging information */ 2058 2059 echoDebug(DBG_ROOTPATH_IS, rootPath); 2060 2061 /* /etc must exist and must not be a symbolic link */ 2062 2063 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 2064 "%s/%s", rootPath, "/etc"); 2065 if (r != R_SUCCESS) { 2066 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, 2067 rootPath, "/etc"); 2068 return (R_FAILURE); 2069 } 2070 2071 /* /platform must exist and must not be a symbolic link */ 2072 2073 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 2074 "%s/%s", rootPath, "/platform"); 2075 if (r != R_SUCCESS) { 2076 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, 2077 rootPath, "/platform"); 2078 return (R_FAILURE); 2079 } 2080 2081 /* /kernel must exist and must not be a symbolic link */ 2082 2083 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, 2084 "%s/%s", rootPath, "/kernel"); 2085 if (r != R_SUCCESS) { 2086 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, 2087 rootPath, "/kernel"); 2088 return (R_FAILURE); 2089 } 2090 2091 /* can remove driver */ 2092 2093 log_msg(LOG_MSG_DEBUG, DBG_RMDV_YES, rootPath); 2094 2095 return (R_SUCCESS); 2096 } 2097 2098 /* 2099 * Name: cmd_is_path_writable 2100 * Description: determine if target path is writable (not inherited) 2101 * Scope: public 2102 * Arguments: argc,argv: 2103 * - optional path to target to test 2104 * Returns: int 2105 * == 0 - success 2106 * != 0 - failure 2107 * IMPLEMENTATION: 2108 * - path must be found in the file systems configured 2109 * - file system type must not be "inherited" 2110 * - mount options must not include "read only" 2111 */ 2112 2113 static int 2114 cmd_is_path_writable(int argc, char **argv, GLOBALDATA_T *a_gdt) 2115 { 2116 FSI_T *list; 2117 char *rootPath = NULL; 2118 int c; 2119 int n; 2120 int nn; 2121 int r; 2122 long listSize; 2123 long rootPathLen; 2124 static char *cmdName = "is_path_writable"; 2125 static int recursion = 0; 2126 2127 /* process any command line options */ 2128 2129 while ((c = getopt(argc, argv, ":")) != EOF) { 2130 switch (c) { 2131 case '\0': /* prevent end-of-loop not reached warning */ 2132 break; 2133 case '?': 2134 default: 2135 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2136 return (R_USAGE); 2137 } 2138 } 2139 2140 /* prevent recursion */ 2141 2142 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 2143 recursion--; 2144 } 2145 2146 /* normalize argc/argv */ 2147 2148 argc -= optind; 2149 argv += optind; 2150 2151 /* error if more than one argument */ 2152 2153 if (argc > 1) { 2154 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2155 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2156 return (R_USAGE); 2157 } 2158 2159 /* process root path if first argument present */ 2160 2161 if (argc != 1) { 2162 (void) usage(ERR_REQUIRED_ROOTPATH_MISSING, cmdName); 2163 return (R_USAGE); 2164 } 2165 2166 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2167 return (R_ERROR); 2168 } 2169 2170 /* get current root path */ 2171 2172 r = getRootPath(&rootPath); 2173 if (r != R_SUCCESS) { 2174 return (r); 2175 } 2176 2177 /* start of command debugging information */ 2178 2179 echoDebug(DBG_ROOTPATH_IS, rootPath); 2180 2181 /* search file system conf for this path */ 2182 2183 rootPathLen = strlen(rootPath); 2184 list = a_gdt->gd_fileSystemConfig; 2185 listSize = a_gdt->gd_fileSystemConfigLen; 2186 for (nn = 0, n = 0; n < listSize; n++) { 2187 long mplen = strlen(list[n].fsi_mntPoint); 2188 if (rootPathLen < mplen) { 2189 /* root path is longer than target, ignore */ 2190 continue; 2191 } 2192 if (strncmp(rootPath, list[n].fsi_mntPoint, mplen) == 0) { 2193 /* remember last partial match */ 2194 nn = n; 2195 } 2196 } 2197 2198 log_msg(LOG_MSG_DEBUG, DBG_PWRT_INFO, 2199 rootPath, list[nn].fsi_mntPoint, list[nn].fsi_fsType, 2200 list[nn].fsi_mntOptions); 2201 2202 /* 2203 * need to determine if the mount point is writeable: 2204 * If parent mount point is "inherited" then it is not writeable 2205 */ 2206 2207 if (strcmp(list[nn].fsi_fsType, FSTYPE_INHERITED) == 0) { 2208 log_msg(LOG_MSG_DEBUG, DBG_PWRT_INHERITED, rootPath, 2209 list[nn].fsi_mntOptions); 2210 return (R_FAILURE); 2211 } 2212 2213 /* see if the file system is mounted with the "read only" option */ 2214 2215 r = mountOptionPresent(list[nn].fsi_mntOptions, MNTOPT_RO); 2216 if (r == R_SUCCESS) { 2217 log_msg(LOG_MSG_DEBUG, DBG_PWRT_READONLY, 2218 rootPath, list[nn].fsi_mntOptions); 2219 return (R_FAILURE); 2220 } 2221 2222 /* target path is writable */ 2223 2224 log_msg(LOG_MSG_DEBUG, DBG_PWRT_IS, rootPath); 2225 2226 return (R_SUCCESS); 2227 } 2228 2229 /* 2230 * Name: cmd_is_alternative_root 2231 * Description: determine if target is an alternative root 2232 * Scope: public 2233 * Arguments: argc,argv: 2234 * - optional path to target to test 2235 * Returns: int 2236 * == 0 - success 2237 * != 0 - failure 2238 * Implementation: 2239 * - success if an initial installation to the install root 2240 * (an initial install to $PKG_INSTALL_ROOT means that $PKG_INSTALL_ROOT 2241 * points to an alternative root that is under construction) 2242 * - must not be installation of a zone 2243 * - must not be a boot environment 2244 * - must not be a diskless client 2245 * - must not be a mounted miniroot 2246 * - must not be a netinstall image 2247 * - must not be a nonglobal zone 2248 * - must not be a running system 2249 * - $ROOTDIR must not be "/" 2250 * - $ROOTDIR/var must exist 2251 */ 2252 2253 static int 2254 cmd_is_alternative_root(int argc, char **argv, GLOBALDATA_T *a_gdt) 2255 { 2256 char *rootPath = NULL; 2257 int c; 2258 int r; 2259 static char *cmdName = "is_alternative_root"; 2260 static int recursion = 0; 2261 2262 /* process any command line options */ 2263 2264 while ((c = getopt(argc, argv, ":")) != EOF) { 2265 switch (c) { 2266 case '\0': /* prevent end-of-loop not reached warning */ 2267 break; 2268 case '?': 2269 default: 2270 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2271 return (R_USAGE); 2272 } 2273 } 2274 2275 /* prevent recursion */ 2276 2277 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 2278 2279 /* 2280 * an alternative root cannot be any of the following 2281 */ 2282 2283 /* cannot be a boot_environment */ 2284 2285 r = cmd_is_boot_environment(argc, argv, a_gdt); 2286 2287 /* cannot be a diskless_client */ 2288 2289 if (r != R_SUCCESS) { 2290 r = cmd_is_diskless_client(argc, argv, a_gdt); 2291 } 2292 2293 /* cannot be a mounted_miniroot */ 2294 2295 if (r != R_SUCCESS) { 2296 r = cmd_is_mounted_miniroot(argc, argv, a_gdt); 2297 } 2298 2299 /* cannot be a netinstall_image */ 2300 2301 if (r != R_SUCCESS) { 2302 r = cmd_is_netinstall_image(argc, argv, a_gdt); 2303 } 2304 2305 /* cannot be a nonglobal_zone */ 2306 2307 if (r != R_SUCCESS) { 2308 r = cmd_is_nonglobal_zone(argc, argv, a_gdt); 2309 } 2310 2311 /* cannot be a running_system */ 2312 2313 if (r != R_SUCCESS) { 2314 r = cmd_is_running_system(argc, argv, a_gdt); 2315 } 2316 2317 /* no need to guard against recursion any more */ 2318 2319 recursion--; 2320 2321 /* return failure if any of the preceeding are true */ 2322 2323 switch (r) { 2324 case R_SUCCESS: 2325 return (R_FAILURE); 2326 case R_FAILURE: 2327 break; 2328 case R_USAGE: 2329 case R_ERROR: 2330 default: 2331 return (r); 2332 } 2333 } 2334 2335 /* normalize argc/argv */ 2336 2337 argc -= optind; 2338 argv += optind; 2339 2340 /* error if more than one argument */ 2341 2342 if (argc > 1) { 2343 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2344 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2345 return (R_USAGE); 2346 } 2347 2348 /* process root path if first argument present */ 2349 2350 if (argc == 1) { 2351 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2352 return (R_ERROR); 2353 } 2354 } 2355 2356 /* get current root path */ 2357 2358 r = getRootPath(&rootPath); 2359 if (r != R_SUCCESS) { 2360 return (r); 2361 } 2362 2363 /* start of command debugging information */ 2364 2365 echoDebug(DBG_ROOTPATH_IS, rootPath); 2366 2367 /* return success if initial installation */ 2368 2369 if ((a_gdt->gd_initialInstall == B_TRUE) && 2370 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 2371 log_msg(LOG_MSG_DEBUG, DBG_IALR_INITIAL_INSTALL, rootPath); 2372 return (R_SUCCESS); 2373 } 2374 2375 /* root path must not be "/" */ 2376 2377 if (strcmp(rootPath, "/") == 0) { 2378 log_msg(LOG_MSG_DEBUG, DBG_IALR_BAD_ROOTPATH, rootPath, "/"); 2379 return (R_FAILURE); 2380 } 2381 2382 /* /var must exist */ 2383 2384 r = testPath(TEST_EXISTS, 2385 "%s/%s", rootPath, "/var"); 2386 if (r != R_SUCCESS) { 2387 log_msg(LOG_MSG_DEBUG, DBG_IALR_PATH_DOES_NOT_EXIST, 2388 rootPath, "/var"); 2389 return (R_FAILURE); 2390 } 2391 2392 /* must not be installation of a zone */ 2393 2394 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 2395 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 2396 /* initial zone install: no path can be alternative root */ 2397 log_msg(LOG_MSG_DEBUG, DBG_IALR_ZONE_INSTALL, rootPath); 2398 return (R_FAILURE); 2399 } 2400 2401 /* target is an alternative root */ 2402 2403 log_msg(LOG_MSG_DEBUG, DBG_IALR_IS, rootPath); 2404 2405 return (R_SUCCESS); 2406 } 2407 2408 /* 2409 * Name: cmd_is_boot_environment 2410 * Description: determine if target is an alternative, inactive boot environment 2411 * Scope: public 2412 * Arguments: argc,argv: 2413 * - optional path to target to test 2414 * Returns: int 2415 * == 0 - success 2416 * != 0 - failure 2417 * IMPLEMENTATION: 2418 * - must not be initial installation to the install root 2419 * - must not be installation of a zone 2420 * - must not be a diskless client 2421 * - must not be a netinstall image 2422 * - must not be a mounted miniroot 2423 * - $ROOTDIR must not be "/" 2424 * - $ROOTDIR/etc/lutab must exist 2425 * - $ROOTDIR/etc/lu must exist and must be a directory 2426 */ 2427 2428 static int 2429 cmd_is_boot_environment(int argc, char **argv, GLOBALDATA_T *a_gdt) 2430 { 2431 char *rootPath = NULL; 2432 int c; 2433 int r; 2434 static char *cmdName = "is_boot_environment"; 2435 static int recursion = 0; 2436 2437 /* process any command line options */ 2438 2439 while ((c = getopt(argc, argv, ":")) != EOF) { 2440 switch (c) { 2441 case '\0': /* prevent end-of-loop not reached warning */ 2442 break; 2443 case '?': 2444 default: 2445 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2446 return (R_USAGE); 2447 } 2448 } 2449 2450 /* prevent recursion */ 2451 2452 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 2453 /* 2454 * a boot environment cannot be any of the following 2455 */ 2456 2457 /* cannot be a diskless client */ 2458 2459 r = cmd_is_diskless_client(argc, argv, a_gdt); 2460 2461 /* cannot be a netinstall_image */ 2462 2463 if (r != R_SUCCESS) { 2464 r = cmd_is_netinstall_image(argc, argv, a_gdt); 2465 } 2466 2467 /* cannot be a mounted_miniroot */ 2468 2469 if (r != R_SUCCESS) { 2470 r = cmd_is_mounted_miniroot(argc, argv, a_gdt); 2471 } 2472 2473 /* no need to guard against recursion any more */ 2474 2475 recursion--; 2476 2477 /* return failure if any of the preceeding are true */ 2478 2479 switch (r) { 2480 case R_SUCCESS: 2481 return (R_FAILURE); 2482 case R_FAILURE: 2483 break; 2484 case R_USAGE: 2485 case R_ERROR: 2486 default: 2487 return (r); 2488 } 2489 } 2490 2491 /* normalize argc/argv */ 2492 2493 argc -= optind; 2494 argv += optind; 2495 2496 /* error if more than one argument */ 2497 2498 if (argc > 1) { 2499 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2500 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2501 return (R_USAGE); 2502 } 2503 2504 /* process root path if first argument present */ 2505 2506 if (argc == 1) { 2507 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2508 return (R_ERROR); 2509 } 2510 } 2511 2512 /* get current root path */ 2513 2514 r = getRootPath(&rootPath); 2515 if (r != R_SUCCESS) { 2516 return (r); 2517 } 2518 2519 /* start of command debugging information */ 2520 2521 echoDebug(DBG_ROOTPATH_IS, rootPath); 2522 2523 /* root path must not be "/" */ 2524 2525 if (strcmp(rootPath, "/") == 0) { 2526 log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ROOTPATH, rootPath, "/"); 2527 return (R_FAILURE); 2528 } 2529 2530 /* zone name must be global */ 2531 2532 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { 2533 log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ZONE, rootPath, 2534 GLOBAL_ZONENAME); 2535 return (R_FAILURE); 2536 } 2537 2538 /* $ROOTDIR/etc/lutab must exist */ 2539 2540 r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/lutab"); 2541 if (r != R_SUCCESS) { 2542 log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLUTAB, rootPath, 2543 "/etc/lutab"); 2544 return (R_FAILURE); 2545 } 2546 2547 /* $ROOTDIR/etc/lu must exist */ 2548 2549 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, 2550 "%s/%s", rootPath, "/etc/lu"); 2551 if (r != R_SUCCESS) { 2552 log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLU, rootPath, "/etc/lu"); 2553 return (R_FAILURE); 2554 } 2555 2556 /* must not be initial installation */ 2557 2558 if ((a_gdt->gd_initialInstall == B_TRUE) && 2559 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { 2560 log_msg(LOG_MSG_DEBUG, DBG_BENV_INITIAL_INSTALL, rootPath); 2561 return (R_FAILURE); 2562 } 2563 2564 /* must not be installation of a zone */ 2565 2566 if ((a_gdt->gd_globalZoneInstall == B_TRUE) || 2567 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { 2568 /* initial zone install: no path can be boot environment */ 2569 log_msg(LOG_MSG_DEBUG, DBG_BENV_ZONE_INSTALL, rootPath); 2570 return (R_FAILURE); 2571 } 2572 2573 /* target is a boot environment */ 2574 2575 log_msg(LOG_MSG_DEBUG, DBG_BENV_IS, rootPath); 2576 2577 return (R_SUCCESS); 2578 } 2579 2580 /* 2581 * Name: cmd_is_sparse_root_ng_zone 2582 * Description: determine if target is a sparse non-global zone 2583 * Scope: public 2584 * Arguments: argc,argv: 2585 * - optional path to target to test 2586 * Returns: int 2587 * == 0 - success 2588 * != 0 - failure 2589 * IMPLEMENATION: 2590 * - must be a non-global zone 2591 * - inherited file systems must be present, and/or 2592 * - read-only lofs file systems must be present 2593 */ 2594 2595 static int 2596 cmd_is_sparse_root_ng_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) 2597 { 2598 char *rootPath = NULL; 2599 int c; 2600 int r; 2601 static char *cmdName = "is_sparse_root_nonglobal_zone"; 2602 static int recursion = 0; 2603 2604 /* process any command line options */ 2605 2606 while ((c = getopt(argc, argv, ":")) != EOF) { 2607 switch (c) { 2608 case '\0': /* prevent end-of-loop not reached warning */ 2609 break; 2610 case '?': 2611 default: 2612 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2613 return (R_USAGE); 2614 } 2615 } 2616 2617 /* prevent recursion */ 2618 2619 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 2620 2621 /* see if this is a non-global zone */ 2622 2623 r = cmd_is_nonglobal_zone(argc, argv, a_gdt); 2624 2625 /* no need to guard against recursion any more */ 2626 2627 recursion--; 2628 2629 switch (r) { 2630 case R_SUCCESS: 2631 /* is a non-global zone */ 2632 break; 2633 case R_FAILURE: 2634 /* not a non-global zone */ 2635 return (R_FAILURE); 2636 case R_USAGE: 2637 case R_ERROR: 2638 default: 2639 /* cannot determine if non-global zone */ 2640 return (r); 2641 } 2642 } 2643 2644 /* normalize argc/argv */ 2645 2646 argc -= optind; 2647 argv += optind; 2648 2649 /* error if more than one argument */ 2650 2651 if (argc > 1) { 2652 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2653 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2654 return (R_USAGE); 2655 } 2656 2657 /* process root path if first argument present */ 2658 2659 if (argc == 1) { 2660 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2661 return (R_ERROR); 2662 } 2663 } 2664 2665 /* get current root path */ 2666 2667 r = getRootPath(&rootPath); 2668 if (r != R_SUCCESS) { 2669 return (r); 2670 } 2671 2672 /* start of command debugging information */ 2673 2674 echoDebug(DBG_ROOTPATH_IS, rootPath); 2675 2676 /* 2677 * in a non-global zone: 2678 * if any file systems are inherited, or if /usr is read only, 2679 * then the target is a sparse root non-global zone. 2680 */ 2681 2682 if ((a_gdt->gd_inheritedFileSystems != (char **)NULL) || 2683 (a_gdt->gd_srFsMountedRO == B_TRUE)) { 2684 /* no inherited file systems */ 2685 log_msg(LOG_MSG_DEBUG, DBG_SRNG_IS, rootPath); 2686 return (R_SUCCESS); 2687 } 2688 2689 /* target is not a sparse root non-global zone */ 2690 2691 log_msg(LOG_MSG_DEBUG, DBG_SRNG_IS_NOT, rootPath); 2692 2693 return (R_FAILURE); 2694 2695 } 2696 2697 /* 2698 * Name: cmd_is_what 2699 * Description: determine what the target is 2700 * Scope: public 2701 * Arguments: argc,argv: 2702 * - optional path to target to test 2703 * Returns: int 2704 * == 0 - success 2705 * != 0 - failure 2706 */ 2707 2708 static int 2709 cmd_is_what(int argc, char **argv, GLOBALDATA_T *a_gdt) 2710 { 2711 char *rootPath = NULL; 2712 int c; 2713 int cur_cmd; 2714 int r; 2715 static char *cmdName = "is_what"; 2716 2717 /* process any command line options */ 2718 2719 while ((c = getopt(argc, argv, ":")) != EOF) { 2720 switch (c) { 2721 case '\0': /* prevent end-of-loop not reached warning */ 2722 break; 2723 case '?': 2724 default: 2725 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2726 return (R_USAGE); 2727 } 2728 } 2729 2730 /* normalize argc/argv */ 2731 2732 argc -= optind; 2733 argv += optind; 2734 2735 /* error if more than one argument */ 2736 2737 if (argc > 1) { 2738 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2739 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2740 return (R_USAGE); 2741 } 2742 2743 /* process root path if first argument present */ 2744 2745 if (argc == 1) { 2746 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2747 return (R_ERROR); 2748 } 2749 } 2750 2751 /* get current root path */ 2752 2753 r = getRootPath(&rootPath); 2754 if (r != R_SUCCESS) { 2755 return (r); 2756 } 2757 2758 /* 2759 * construct the command line for all of the packages 2760 */ 2761 2762 argc = 0; 2763 argv[argc++] = strdup(get_prog_name()); 2764 argv[argc++] = strdup(rootPath); 2765 2766 /* start of command debugging information */ 2767 2768 echoDebug(DBG_ROOTPATH_IS, rootPath); 2769 2770 /* search for specified subcommand and execute if found */ 2771 2772 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { 2773 int result; 2774 2775 /* do not recursively call this function */ 2776 2777 if (cmds[cur_cmd].c_func == cmd_is_what) { 2778 continue; 2779 } 2780 2781 /* call subcommand with its own argc/argv */ 2782 2783 result = cmds[cur_cmd].c_func(argc, argv, a_gdt); 2784 2785 /* process result code and exit */ 2786 2787 result = adjustResults(result); 2788 log_msg(LOG_MSG_INFO, MSG_IS_WHAT_RESULT, 2789 cmds[cur_cmd].c_name, result); 2790 } 2791 return (R_SUCCESS); 2792 } 2793 2794 /* 2795 * Name: cmd_is_whole_root_ng_zone 2796 * Description: determine if target is a global zone 2797 * Scope: public 2798 * Arguments: argc,argv: 2799 * - optional path to target to test 2800 * Returns: int 2801 * == 0 - success 2802 * != 0 - failure 2803 * IMPLEMENTATION: 2804 * - must be a non-global zone 2805 * - no inherited file systems may be present 2806 * - no read-only lofs file systems may be present 2807 */ 2808 2809 static int 2810 cmd_is_whole_root_ng_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) 2811 { 2812 char *rootPath = NULL; 2813 int c; 2814 int r; 2815 static char *cmdName = "is_whole_root_nonglobal_zone"; 2816 static int recursion = 0; 2817 2818 /* process any command line options */ 2819 2820 while ((c = getopt(argc, argv, ":")) != EOF) { 2821 switch (c) { 2822 case '\0': /* prevent end-of-loop not reached warning */ 2823 break; 2824 case '?': 2825 default: 2826 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); 2827 return (R_USAGE); 2828 } 2829 } 2830 2831 /* prevent recursion */ 2832 2833 if (recursionCheck(&recursion, cmdName) == B_FALSE) { 2834 2835 /* see if this is a non-global zone */ 2836 2837 r = cmd_is_nonglobal_zone(argc, argv, a_gdt); 2838 2839 /* no need to guard against recursion any more */ 2840 2841 recursion--; 2842 2843 switch (r) { 2844 case R_SUCCESS: 2845 /* is a non-global zone */ 2846 break; 2847 case R_FAILURE: 2848 /* not a non-global zone */ 2849 return (R_FAILURE); 2850 case R_USAGE: 2851 case R_ERROR: 2852 default: 2853 /* cannot determine if non-global zone */ 2854 return (r); 2855 } 2856 } 2857 2858 /* normalize argc/argv */ 2859 2860 argc -= optind; 2861 argv += optind; 2862 2863 /* error if more than one argument */ 2864 2865 if (argc > 1) { 2866 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); 2867 (void) usage(MSG_IS_INVALID_OPTION, argv[1]); 2868 return (R_USAGE); 2869 } 2870 2871 /* process root path if first argument present */ 2872 2873 if (argc == 1) { 2874 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { 2875 return (R_ERROR); 2876 } 2877 } 2878 2879 /* get current root path */ 2880 2881 r = getRootPath(&rootPath); 2882 if (r != R_SUCCESS) { 2883 return (r); 2884 } 2885 2886 /* start of command debugging information */ 2887 2888 echoDebug(DBG_ROOTPATH_IS, rootPath); 2889 2890 /* 2891 * in a non-global zone: 2892 * if no file systems are inherited, and if /usr is not 2893 * read only, then the target is a whole root non-global zone. 2894 */ 2895 2896 if ((a_gdt->gd_inheritedFileSystems == (char **)NULL) && 2897 (a_gdt->gd_srFsMountedRO == B_FALSE)) { 2898 /* no inherited file systems */ 2899 log_msg(LOG_MSG_DEBUG, DBG_WRNG_IS, rootPath); 2900 return (R_SUCCESS); 2901 } 2902 2903 /* target is not a whole-root non-global zone */ 2904 2905 log_msg(LOG_MSG_DEBUG, DBG_WRNG_IS_NOT, rootPath); 2906 2907 return (R_FAILURE); 2908 } 2909 2910 /* 2911 * ***************************************************************************** 2912 * utility support functions 2913 * ***************************************************************************** 2914 */ 2915 2916 /* 2917 * Name: getMountOption 2918 * Description: return next mount option in a string 2919 * Arguments: p - pointer to string containing mount options 2920 * Output: none 2921 * Returns: char * - pointer to next option in string "p" 2922 * Side Effects: advances input "p" and inserts \0 in place of the 2923 * option separator found. 2924 */ 2925 2926 static char * 2927 getMountOption(char **p) 2928 { 2929 char *cp = *p; 2930 char *retstr; 2931 2932 /* advance past all white space */ 2933 2934 while (*cp && isspace(*cp)) 2935 cp++; 2936 2937 /* remember start of next option */ 2938 2939 retstr = cp; 2940 2941 /* advance to end of string or option separator */ 2942 2943 while (*cp && *cp != ',') 2944 cp++; 2945 2946 /* replace separator with '\0' if not at end of string */ 2947 if (*cp) { 2948 *cp = '\0'; 2949 cp++; 2950 } 2951 2952 /* reset caller's pointer and return pointer to option */ 2953 2954 *p = cp; 2955 return (retstr); 2956 } 2957 2958 /* 2959 * Name: mountOptionPresent 2960 * Description: determine if specified mount option is present in list 2961 * of mount point options 2962 * Arguments: a_mntOptions - pointer to string containing list of mount 2963 * point options to search 2964 * a_opt - pointer to string containing option to search for 2965 * Output: none 2966 * Returns: R_SUCCESS - option is present in list of mount point options 2967 * R_FAILURE - options is not present 2968 * R_ERROR - unable to determine if option is present or not 2969 */ 2970 2971 static int 2972 mountOptionPresent(char *a_mntOptions, char *a_opt) 2973 { 2974 char tmpopts[MNT_LINE_MAX]; 2975 char *f, *opts = tmpopts; 2976 2977 /* return false if no mount options present */ 2978 2979 if ((a_opt == NULL) || (*a_opt == '\0')) { 2980 return (R_FAILURE); 2981 } 2982 2983 /* return not present if no list of options to search */ 2984 2985 if (a_mntOptions == NULL) { 2986 return (R_FAILURE); 2987 } 2988 2989 /* return not present if list of options to search is empty */ 2990 2991 if (*a_mntOptions == '\0') { 2992 return (R_FAILURE); 2993 } 2994 2995 /* make local copy of option list to search */ 2996 2997 (void) strcpy(opts, a_mntOptions); 2998 2999 /* scan each option looking for the specified option */ 3000 3001 f = getMountOption(&opts); 3002 for (; *f; f = getMountOption(&opts)) { 3003 /* return success if option matches target */ 3004 if (strncmp(a_opt, f, strlen(a_opt)) == 0) { 3005 return (R_SUCCESS); 3006 } 3007 } 3008 3009 /* option not found */ 3010 3011 return (R_FAILURE); 3012 } 3013 3014 /* 3015 * Name: sortedInsert 3016 * Description: perform an alphabetical sorted insert into a list 3017 * Arguments: r_list - pointer to list to insert next entry into 3018 * a_listSize - pointer to current list size 3019 * a_mntPoint - mount point to insert (is sort key) 3020 * a_fsType - file system type for mount point 3021 * a_mntOptions - file syste mount options for mount point 3022 * Output: None 3023 * Returns: None 3024 */ 3025 3026 static void 3027 sortedInsert(FSI_T **r_list, long *a_listSize, char *a_mntPoint, 3028 char *a_fsType, char *a_mntOptions) 3029 { 3030 int listSize; 3031 FSI_T *list; 3032 int n; 3033 3034 /* entry assertions */ 3035 3036 assert(a_listSize != (long *)NULL); 3037 assert(a_mntPoint != NULL); 3038 assert(a_fsType != NULL); 3039 assert(a_mntOptions != NULL); 3040 3041 /* entry debugging info */ 3042 3043 echoDebug(DBG_SINS_ENTRY, a_mntPoint, a_fsType, a_mntOptions); 3044 3045 /* localize references to the list and list size */ 3046 3047 listSize = *a_listSize; 3048 list = *r_list; 3049 3050 /* 3051 * if list empty insert this entry as the first one in the list 3052 */ 3053 3054 if (listSize == 0) { 3055 /* allocate new entry for list */ 3056 listSize++; 3057 list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1)); 3058 3059 /* first entry is data passed to this function */ 3060 list[0].fsi_mntPoint = strdup(a_mntPoint); 3061 list[0].fsi_fsType = strdup(a_fsType); 3062 list[0].fsi_mntOptions = strdup(a_mntOptions); 3063 3064 /* second entry is all NULL - end of entry marker */ 3065 list[1].fsi_mntPoint = NULL; 3066 list[1].fsi_fsType = NULL; 3067 list[1].fsi_mntOptions = NULL; 3068 3069 /* restore list and list size references to caller */ 3070 *a_listSize = listSize; 3071 *r_list = list; 3072 3073 return; 3074 } 3075 3076 /* 3077 * list not empty - scan looking for largest match 3078 */ 3079 3080 for (n = 0; n < listSize; n++) { 3081 int c; 3082 3083 /* compare target with current list entry */ 3084 3085 c = strcmp(list[n].fsi_mntPoint, a_mntPoint); 3086 3087 if (c == 0) { 3088 char *me; 3089 long len; 3090 3091 /* entry already in list -- merge entries */ 3092 3093 len = strlen(list[n].fsi_mntOptions) + 3094 strlen(a_mntOptions) + 2; 3095 me = (char *)calloc(1, len); 3096 3097 /* merge two mount options lists into one */ 3098 3099 (void) strlcat(me, list[n].fsi_mntOptions, len); 3100 (void) strlcat(me, ",", len); 3101 (void) strlcat(me, a_mntOptions, len); 3102 3103 /* free old list, replace with merged one */ 3104 3105 free(list[n].fsi_mntOptions); 3106 list[n].fsi_mntOptions = me; 3107 3108 echoDebug(DBG_SORTEDINS_SKIPPED, 3109 n, list[n].fsi_mntPoint, a_fsType, 3110 list[n].fsi_fsType, a_mntOptions, 3111 list[n].fsi_mntOptions); 3112 3113 continue; 3114 } else if (c < 0) { 3115 /* entry before this one - skip */ 3116 continue; 3117 } 3118 3119 /* 3120 * entry after this one - insert new entry 3121 */ 3122 3123 /* allocate one more entry and make space for new entry */ 3124 listSize++; 3125 list = (FSI_T *)realloc(list, 3126 sizeof (FSI_T)*(listSize+1)); 3127 (void) memmove(&(list[n+1]), &(list[n]), 3128 sizeof (FSI_T)*(listSize-n)); 3129 3130 /* insert this entry into list */ 3131 list[n].fsi_mntPoint = strdup(a_mntPoint); 3132 list[n].fsi_fsType = strdup(a_fsType); 3133 list[n].fsi_mntOptions = strdup(a_mntOptions); 3134 3135 /* restore list and list size references to caller */ 3136 *a_listSize = listSize; 3137 *r_list = list; 3138 3139 return; 3140 } 3141 3142 /* 3143 * all entries are before this one - append to end of list 3144 */ 3145 3146 /* allocate new entry at end of list */ 3147 listSize++; 3148 list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1)); 3149 3150 /* append this entry to the end of the list */ 3151 list[listSize-1].fsi_mntPoint = strdup(a_mntPoint); 3152 list[listSize-1].fsi_fsType = strdup(a_fsType); 3153 list[listSize-1].fsi_mntOptions = strdup(a_mntOptions); 3154 3155 /* restore list and list size references to caller */ 3156 *a_listSize = listSize; 3157 *r_list = list; 3158 } 3159 3160 /* 3161 * Name: calculateFileSystemConfig 3162 * Description: generate sorted list of all mounted file systems 3163 * Arguments: a_gdt - global data structure to place sorted entries into 3164 * Output: None 3165 * Returns: R_SUCCESS - successfully generated mounted file systems list 3166 * R_FAILURE - options is not present 3167 * R_ERROR - unable to determine if option is present or not 3168 */ 3169 3170 static int 3171 calculateFileSystemConfig(GLOBALDATA_T *a_gdt) 3172 { 3173 FILE *fp; 3174 struct mnttab mntbuf; 3175 FSI_T *list; 3176 long listSize; 3177 boolean_t readOnlyMountFound = B_FALSE; 3178 3179 /* entry assetions */ 3180 3181 assert(a_gdt != (GLOBALDATA_T *)NULL); 3182 3183 /* entry debugging info */ 3184 3185 echoDebug(DBG_CALCSCFG_ENTRY); 3186 3187 /* allocate a list that has one termination entry */ 3188 3189 list = (FSI_T *)calloc(1, sizeof (FSI_T)); 3190 list[0].fsi_mntPoint = NULL; 3191 list[0].fsi_fsType = NULL; 3192 list[0].fsi_mntOptions = NULL; 3193 listSize = 0; 3194 3195 /* insert entries for all inherited file systems */ 3196 3197 if (a_gdt->gd_inheritedFileSystems) { 3198 int n; 3199 char **ifs = a_gdt->gd_inheritedFileSystems; 3200 3201 /* debugging info */ 3202 3203 echoDebug(DBG_CALCSCFG_INHERITED); 3204 3205 /* insert all inherited file systems */ 3206 3207 for (n = 0; ifs[n]; n++) { 3208 sortedInsert(&list, &listSize, ifs[n], 3209 FSTYPE_INHERITED, MNTOPT_RO); 3210 } 3211 } 3212 3213 /* open the mount table for reading */ 3214 3215 fp = fopen(MNTTAB, "r"); 3216 if (fp == (FILE *)NULL) { 3217 return (R_ERROR); 3218 } 3219 3220 /* debugging info */ 3221 3222 echoDebug(DBG_CALCSCFG_MOUNTED); 3223 3224 /* go through all the specials looking for the device */ 3225 3226 while (getmntent(fp, &mntbuf) == 0) { 3227 if (mntbuf.mnt_mountp[0] == '/') { 3228 sortedInsert(&list, &listSize, 3229 strdup(mntbuf.mnt_mountp), 3230 strdup(mntbuf.mnt_fstype), 3231 strdup(mntbuf.mnt_mntopts ? mntbuf.mnt_mntopts : "")); 3232 } 3233 3234 /* 3235 * Set flag if we are in a non-global zone and it is in 3236 * the mounted state. 3237 */ 3238 3239 if (strcmp(mntbuf.mnt_mountp, "/a") == 0 && 3240 strcmp(mntbuf.mnt_special, "/a") == 0 && 3241 strcmp(mntbuf.mnt_fstype, "lofs") == 0) { 3242 a_gdt->inMountedState = B_TRUE; 3243 } 3244 3245 if (!readOnlyMountFound) { 3246 readOnlyMountFound = checkForReadOnlyMount(a_gdt, 3247 mntbuf.mnt_mountp, mntbuf.mnt_fstype, 3248 mntbuf.mnt_mntopts); 3249 } 3250 } 3251 3252 /* close mount table file */ 3253 3254 (void) fclose(fp); 3255 3256 /* store list pointers in global data structure */ 3257 3258 a_gdt->gd_fileSystemConfig = list; 3259 a_gdt->gd_fileSystemConfigLen = listSize; 3260 3261 return (R_SUCCESS); 3262 } 3263 3264 /* 3265 * Name: checkForReadOnlyMount 3266 * Description: given a mount point, type and options, determine if the 3267 * mounted file system is part of a "sparse root" configuration 3268 * by checking if the known Zone directories a ro LOFS mounted. 3269 * Arguments: a_gdt - global data structure to place sorted entries into 3270 * a_mntPoint - pointer to string representing mount point 3271 * a_fsType - pointer to string representing file system type 3272 * a_mntOptions - pointer to string representing the options 3273 * used to mount the file system 3274 * Returns: B_TRUE - if sparse root mount is found 3275 * B_FLASE - if no sparse root mount's are found 3276 * Side Effects: set: 3277 * a_gdt->gd_srFsMountedRO = B_TRUE 3278 * if the mounted file system is part of a 'sparse root' config 3279 */ 3280 3281 static boolean_t 3282 checkForReadOnlyMount(GLOBALDATA_T *a_gdt, char *a_mntPoint, 3283 char *a_fsType, char *a_mntOptions) 3284 { 3285 /* entry assertions */ 3286 int i; 3287 char mntPoint[MAXPATHLEN]; 3288 char *zDirs[] = { "/usr", "/lib", "/platform", "/sbin", NULL }; 3289 char *aZDirs[] = { "/a/usr", "/a/lib", "/a/platform", "/a/sbin", NULL }; 3290 3291 assert(a_gdt != (GLOBALDATA_T *)NULL); 3292 assert(a_mntPoint != NULL); 3293 assert(a_fsType != NULL); 3294 3295 /* return if no read-only mount option */ 3296 3297 if (mountOptionPresent(a_mntOptions, MNTOPT_RO) != R_SUCCESS) { 3298 return (B_FALSE); 3299 } 3300 3301 /* return if file system is not read-only mounted */ 3302 3303 if (strcmp(a_fsType, MNTTYPE_LOFS) != 0) { 3304 return (B_FALSE); 3305 } 3306 3307 /* file system is a read-only lofs mounted. */ 3308 3309 /* Check read-only lofs mount's appended to the command line path */ 3310 3311 if (a_gdt->gd_cmdline_path != NULL) { 3312 if (strncmp(a_mntPoint, a_gdt->gd_cmdline_path, 3313 strlen(a_gdt->gd_cmdline_path)) == 0) { 3314 for (i = 0; zDirs[i] != NULL; i++) { 3315 (void) snprintf(mntPoint, sizeof (mntPoint), 3316 "%s%s", a_gdt->gd_cmdline_path, 3317 zDirs[i]); 3318 if (strcmp(a_mntPoint, mntPoint) == 0) { 3319 echoDebug(DBG_CKSR_FSREADONLY, 3320 a_mntPoint, a_fsType); 3321 a_gdt->gd_srFsMountedRO = B_TRUE; 3322 return (B_TRUE); 3323 } 3324 } 3325 } 3326 3327 /* Check read-only lofs mount's in the mounted state */ 3328 3329 } else if (a_gdt->inMountedState) { 3330 for (i = 0; aZDirs[i] != NULL; i++) { 3331 if (strncmp(a_mntPoint, aZDirs[i], 3332 sizeof (aZDirs[i])) == 0) { 3333 echoDebug(DBG_CKSR_FSREADONLY, a_mntPoint, 3334 a_fsType); 3335 a_gdt->gd_srFsMountedRO = B_TRUE; 3336 return (B_TRUE); 3337 } 3338 } 3339 3340 /* Check read-only lofs mount's for live system */ 3341 3342 } else { 3343 for (i = 0; zDirs[i] != NULL; i++) { 3344 if (strncmp(a_mntPoint, zDirs[i], 3345 sizeof (zDirs[i])) == 0) { 3346 echoDebug(DBG_CKSR_FSREADONLY, a_mntPoint, 3347 a_fsType); 3348 a_gdt->gd_srFsMountedRO = B_TRUE; 3349 return (B_TRUE); 3350 } 3351 } 3352 } 3353 3354 return (B_FALSE); 3355 } 3356 3357 /* 3358 * Name: adjustResults 3359 * Description: adjust output result code before existing 3360 * Arguments: a_result - result code to adjust 3361 * Returns: int - adjusted result code 3362 */ 3363 3364 static int 3365 adjustResults(int a_result) 3366 { 3367 boolean_t negate = getNegateResults(); 3368 int realResult; 3369 3370 /* adjust code as appropriate */ 3371 3372 switch (a_result) { 3373 case R_SUCCESS: /* condition satisfied */ 3374 realResult = ((negate == B_TRUE) ? 1 : 0); 3375 break; 3376 case R_FAILURE: /* condition not satisfied */ 3377 realResult = ((negate == B_TRUE) ? 0 : 1); 3378 break; 3379 case R_USAGE: /* usage errors */ 3380 realResult = 2; 3381 break; 3382 case R_ERROR: /* condition could not be determined */ 3383 default: 3384 realResult = 3; 3385 break; 3386 } 3387 3388 /* debugging output */ 3389 3390 log_msg(LOG_MSG_DEBUG, DBG_ADJUST_RESULTS, a_result, negate, 3391 realResult); 3392 3393 /* return results */ 3394 3395 return (realResult); 3396 } 3397 3398 /* 3399 * Name: setCmdLinePath 3400 * Description: set global command line path 3401 * Arguments: path - path to set from the command line 3402 * args - command line args 3403 * num_args - number of command line args 3404 * Returns: R_SUCCESS - root path successfully set 3405 * R_FAILURE - root path could not be set 3406 * R_ERROR - fatal error attempting to set root path 3407 */ 3408 3409 static void 3410 setCmdLinePath(char **path, char **args, int num_args) 3411 { 3412 char rp[PATH_MAX] = { '\0' }; 3413 struct stat statbuf; 3414 3415 if (*path != NULL) { 3416 return; 3417 } 3418 3419 /* 3420 * If a path "pkgcond is_global_zone [path]" is provided on the 3421 * command line it must be the last argument. 3422 */ 3423 3424 if (realpath(args[num_args - 1], rp) != NULL) { 3425 if (stat(rp, &statbuf) == 0) { 3426 /* make sure the target is a directory */ 3427 if ((statbuf.st_mode & S_IFDIR)) { 3428 *path = strdup(rp); 3429 } else { 3430 *path = NULL; 3431 } 3432 } 3433 } 3434 } 3435 3436 /* 3437 * Name: setRootPath 3438 * Description: set global root path returned by getRootPath 3439 * Arguments: a_path - root path to set 3440 * a_mustExist - B_TRUE if path must exist (else error) 3441 * - B_FALSE if path may not exist 3442 * Returns: R_SUCCESS - root path successfully set 3443 * R_FAILURE - root path could not be set 3444 * R_ERROR - fatal error attempting to set root path 3445 */ 3446 3447 static int 3448 setRootPath(char *a_path, char *a_envVar, boolean_t a_mustExist) 3449 { 3450 char rp[PATH_MAX] = { '\0' }; 3451 struct stat statbuf; 3452 3453 /* if no data then issue warning and return success */ 3454 3455 if ((a_path == NULL) || (*a_path == '\0')) { 3456 echoDebug(DBG_NO_DEFAULT_ROOT_PATH_SET); 3457 return (R_SUCCESS); 3458 } 3459 3460 /* path present - resolve to absolute path */ 3461 3462 if (realpath(a_path, rp) == NULL) { 3463 if (a_mustExist == B_TRUE) { 3464 /* must exist ... error */ 3465 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID, 3466 a_path, strerror(errno)); 3467 return (R_ERROR); 3468 } else { 3469 /* may not exist - use path as specified */ 3470 (void) strcpy(rp, a_path); 3471 } 3472 } 3473 3474 /* debugging output */ 3475 3476 echoDebug(DBG_DEFAULT_ROOT_PATH_SET, rp, a_envVar ? a_envVar : ""); 3477 3478 /* validate path existence if it must exist */ 3479 3480 if (a_mustExist == B_TRUE) { 3481 3482 /* get node status */ 3483 3484 if (stat(rp, &statbuf) != 0) { 3485 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID, 3486 rp, strerror(errno)); 3487 return (R_ERROR); 3488 } 3489 3490 /* make sure the target is a directory */ 3491 3492 if (!(statbuf.st_mode & S_IFDIR)) { 3493 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_NOT_DIR, rp); 3494 return (R_ERROR); 3495 } 3496 } 3497 3498 /* target exists and is a directory - set */ 3499 3500 echoDebug(DBG_SET_ROOT_PATH_TO, rp); 3501 3502 /* store copy of resolved root path */ 3503 3504 _rootPath = strdup(rp); 3505 3506 /* success! */ 3507 3508 return (R_SUCCESS); 3509 } 3510 3511 /* 3512 * Name: testPath 3513 * Description: determine if a path meets the specified conditions 3514 * Arguments: a_tt - conditions to test path against 3515 * a_format - format to use to generate path 3516 * arguments following a_format - as needed for a_format 3517 * Returns: R_SUCCESS - the path meets all of the specified conditions 3518 * R_FAILURE - the path does not meet all of the conditions 3519 * R_ERROR - error attempting to test path 3520 */ 3521 3522 /*PRINTFLIKE2*/ 3523 static int 3524 testPath(TEST_TYPES a_tt, char *a_format, ...) 3525 { 3526 char *mbPath; /* copy for the path to be returned */ 3527 char bfr[1]; 3528 int r; 3529 size_t vres = 0; 3530 struct stat statbuf; 3531 va_list ap; 3532 int fd; 3533 3534 /* entry assertions */ 3535 3536 assert(a_format != NULL); 3537 assert(*a_format != '\0'); 3538 3539 /* determine size of the message in bytes */ 3540 3541 va_start(ap, a_format); 3542 vres = vsnprintf(bfr, 1, a_format, ap); 3543 va_end(ap); 3544 3545 assert(vres > 0); 3546 3547 /* allocate storage to hold the message */ 3548 3549 mbPath = (char *)calloc(1, vres+2); 3550 assert(mbPath != NULL); 3551 3552 /* generate the results of the printf conversion */ 3553 3554 va_start(ap, a_format); 3555 vres = vsnprintf(mbPath, vres+1, a_format, ap); 3556 va_end(ap); 3557 3558 assert(vres > 0); 3559 3560 echoDebug(DBG_TEST_PATH, mbPath, (unsigned long)a_tt); 3561 3562 /* 3563 * When a path given to open(2) contains symbolic links, the 3564 * open system call first resolves all symbolic links and then 3565 * opens that final "resolved" path. As a result, it is not 3566 * possible to check the result of an fstat(2) against the 3567 * file descriptor returned by open(2) for S_IFLNK (a symbolic 3568 * link) since all symbolic links are resolved before the 3569 * target is opened. 3570 * 3571 * When testing the target as being (or not being) a symbolic 3572 * link, first use lstat(2) against the target to determine 3573 * whether or not the specified target itself is (or is not) a 3574 * symbolic link. 3575 */ 3576 3577 if (a_tt & (TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)) { 3578 /* 3579 * testing target is/is not a symbolic link; use lstat 3580 * to determine the status of the target itself rather 3581 * than what the target might finally address. 3582 */ 3583 3584 if (lstat(mbPath, &statbuf) != 0) { 3585 echoDebug(DBG_CANNOT_LSTAT_PATH, mbPath, 3586 strerror(errno)); 3587 free(mbPath); 3588 return (R_FAILURE); 3589 } 3590 3591 /* Is the target required to be a symbolic link? */ 3592 3593 if (a_tt & TEST_IS_SYMBOLIC_LINK) { 3594 /* target must be a symbolic link */ 3595 if (!(statbuf.st_mode & S_IFLNK)) { 3596 /* failure: target is not a symbolic link */ 3597 echoDebug(DBG_IS_NOT_A_SYMLINK, mbPath); 3598 free(mbPath); 3599 return (R_FAILURE); 3600 } 3601 /* success: target is a symbolic link */ 3602 echoDebug(DBG_SYMLINK_IS, mbPath); 3603 } 3604 3605 /* Is the target required to not be a symbolic link? */ 3606 3607 if (a_tt & TEST_NOT_SYMBOLIC_LINK) { 3608 /* target must not be a symbolic link */ 3609 if (statbuf.st_mode & S_IFLNK) { 3610 /* failure: target is a symbolic link */ 3611 echoDebug(DBG_IS_A_SYMLINK, mbPath); 3612 free(mbPath); 3613 return (R_FAILURE); 3614 } 3615 /* success: target is not a symbolic link */ 3616 echoDebug(DBG_SYMLINK_NOT, mbPath); 3617 } 3618 3619 /* 3620 * if only testing is/is not a symbolic link, then 3621 * no need to open the target: return success. 3622 */ 3623 3624 if (!(a_tt & 3625 (~(TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)))) { 3626 free(mbPath); 3627 return (R_SUCCESS); 3628 } 3629 } 3630 3631 /* resolve path and remove any whitespace */ 3632 3633 r = resolvePath(&mbPath); 3634 if (r != R_SUCCESS) { 3635 echoDebug(DBG_TEST_PATH_NO_RESOLVE, mbPath); 3636 free(mbPath); 3637 if (a_tt & TEST_NOT_EXISTS) { 3638 return (R_SUCCESS); 3639 } 3640 return (r); 3641 } 3642 3643 echoDebug(DBG_TEST_PATH_RESOLVE, mbPath); 3644 3645 /* open the file - this is the basic existence test */ 3646 3647 fd = open(mbPath, O_RDONLY|O_LARGEFILE, 0); 3648 3649 /* existence test failed if file cannot be opened */ 3650 3651 if (fd < 0) { 3652 /* 3653 * target could not be opened - if testing for non-existence, 3654 * return success, otherwise return failure 3655 */ 3656 if (a_tt & TEST_NOT_EXISTS) { 3657 echoDebug(DBG_CANNOT_ACCESS_PATH_OK, mbPath); 3658 free(mbPath); 3659 return (R_SUCCESS); 3660 } 3661 3662 echoDebug(DBG_CANNOT_ACCESS_PATH_BUT_SHOULD, 3663 mbPath, strerror(errno)); 3664 free(mbPath); 3665 3666 return (R_FAILURE); 3667 } 3668 3669 /* 3670 * target successfully opened - if testing for non-existence, 3671 * return failure, otherwise continue with specified tests 3672 */ 3673 3674 if (a_tt & TEST_NOT_EXISTS) { 3675 /* testing for non-existence: return failure */ 3676 echoDebug(DBG_TEST_EXISTS_SHOULD_NOT, mbPath); 3677 free(mbPath); 3678 (void) close(fd); 3679 return (R_FAILURE); 3680 } 3681 3682 /* get the file status */ 3683 3684 r = fstat(fd, &statbuf); 3685 if (r != 0) { 3686 echoDebug(DBG_PATH_DOES_NOT_EXIST, mbPath, strerror(errno)); 3687 (void) close(fd); 3688 free(mbPath); 3689 return (R_FAILURE); 3690 } 3691 3692 /* required to be a directory? */ 3693 3694 if (a_tt & TEST_IS_DIRECTORY) { 3695 if (!(statbuf.st_mode & S_IFDIR)) { 3696 /* is not a directory */ 3697 echoDebug(DBG_IS_NOT_A_DIRECTORY, mbPath); 3698 free(mbPath); 3699 return (R_FAILURE); 3700 } 3701 /* a directory */ 3702 echoDebug(DBG_DIRECTORY_IS, mbPath); 3703 } 3704 3705 /* required to not be a directory? */ 3706 3707 if (a_tt & TEST_NOT_DIRECTORY) { 3708 if (statbuf.st_mode & S_IFDIR) { 3709 /* is a directory */ 3710 echoDebug(DBG_IS_A_DIRECTORY, mbPath); 3711 free(mbPath); 3712 return (R_FAILURE); 3713 } 3714 /* not a directory */ 3715 echoDebug(DBG_DIRECTORY_NOT, mbPath); 3716 } 3717 3718 /* required to be a file? */ 3719 3720 if (a_tt & TEST_IS_FILE) { 3721 if (!(statbuf.st_mode & S_IFREG)) { 3722 /* is not a regular file */ 3723 echoDebug(DBG_IS_NOT_A_FILE, mbPath); 3724 free(mbPath); 3725 return (R_FAILURE); 3726 } 3727 /* a regular file */ 3728 echoDebug(DBG_FILE_IS, mbPath); 3729 } 3730 3731 /* required to not be a file? */ 3732 3733 if (a_tt & TEST_NOT_FILE) { 3734 if (statbuf.st_mode & S_IFREG) { 3735 /* is a regular file */ 3736 echoDebug(DBG_IS_A_FILE, mbPath); 3737 free(mbPath); 3738 return (R_FAILURE); 3739 } 3740 /* not a regular file */ 3741 echoDebug(DBG_FILE_NOT, mbPath); 3742 } 3743 3744 /* 3745 * Find token (global) in file pointed to by mbPath. 3746 * token is only compared to first word in mbPath. 3747 */ 3748 3749 if (a_tt & TEST_GLOBAL_TOKEN_IN_FILE) { 3750 if (!(statbuf.st_mode & S_IFREG)) { 3751 /* is not a regular file */ 3752 echoDebug(DBG_IS_NOT_A_FILE, mbPath); 3753 free(mbPath); 3754 return (R_FAILURE); 3755 } 3756 /* If global exists then we're not in a non-global zone */ 3757 if (findToken(mbPath, GLOBAL_ZONENAME) == R_SUCCESS) { 3758 echoDebug(DBG_TOKEN__EXISTS, GLOBAL_ZONENAME, mbPath); 3759 free(mbPath); 3760 return (R_FAILURE); 3761 } 3762 } 3763 3764 (void) close(fd); 3765 3766 /* success! */ 3767 3768 echoDebug(DBG_TESTPATH_OK, mbPath); 3769 3770 /* free up temp storage used to hold path to test */ 3771 3772 free(mbPath); 3773 3774 return (R_SUCCESS); 3775 } 3776 3777 /* 3778 * Name: findToken 3779 * Description: Find first token in file. 3780 * Arguments: 3781 * path - file to search for token 3782 * token - string to search for 3783 * Returns: 3784 * R_SUCCESS - the token exists 3785 * R_FAILURE - the token does not exist 3786 * R_ERROR - fatal error attempting to find token 3787 */ 3788 3789 static int 3790 findToken(char *path, char *token) 3791 { 3792 FILE *fp; 3793 char *cp; 3794 char line[MAXPATHLEN]; 3795 3796 if (path == NULL || token == NULL) { 3797 return (R_ERROR); 3798 } 3799 if ((fp = fopen(path, "r")) == NULL) { 3800 return (R_ERROR); 3801 } 3802 3803 while (fgets(line, sizeof (line), fp) != NULL) { 3804 for (cp = line; *cp && isspace(*cp); cp++); 3805 /* skip comments */ 3806 if (*cp == '#') { 3807 continue; 3808 } 3809 if (pkgstrContainsToken(cp, token, ":")) { 3810 (void) fclose(fp); 3811 return (R_SUCCESS); 3812 } 3813 } 3814 (void) fclose(fp); 3815 return (R_FAILURE); 3816 } 3817 3818 3819 /* 3820 * Name: resolvePath 3821 * Description: fully resolve a path to an absolute real path 3822 * Arguments: r_path - pointer to pointer to malloc()ed storage containing 3823 * the path to resolve - this path may be reallocated 3824 * as necessary to hold the fully resolved path 3825 * Output: r_path - is realloc()ed as necessary 3826 * Returns: R_SUCCESS - the path is fully resolved 3827 * R_FAILURE - the path could not be resolved 3828 * R_ERROR - fatal error attempting to resolve path 3829 */ 3830 3831 static int 3832 resolvePath(char **r_path) 3833 { 3834 int i; 3835 char resolvedPath[MAXPATHLEN+1] = {'\0'}; 3836 size_t mbPathlen; /* length of multi-byte path */ 3837 size_t wcPathlen; /* length of wide-character path */ 3838 wchar_t *wcPath; /* wide-character version of the path */ 3839 wchar_t *wptr; /* scratch pointer */ 3840 3841 /* entry assertions */ 3842 3843 assert(r_path != (char **)NULL); 3844 3845 /* return error if the path is completely empty */ 3846 3847 if (*r_path == '\0') { 3848 return (R_FAILURE); 3849 } 3850 3851 /* remove all leading whitespace */ 3852 3853 removeLeadingWhitespace(r_path); 3854 3855 /* 3856 * convert to real path: an absolute pathname that names the same file, 3857 * whose resolution does not involve ".", "..", or symbolic links. 3858 */ 3859 3860 if (realpath(*r_path, resolvedPath) != NULL) { 3861 free(*r_path); 3862 *r_path = strdup(resolvedPath); 3863 } 3864 3865 /* 3866 * convert the multi-byte version of the path to a 3867 * wide-character rendering, for doing our figuring. 3868 */ 3869 3870 mbPathlen = strlen(*r_path); 3871 3872 if ((wcPath = (wchar_t *) 3873 calloc(1, sizeof (wchar_t)*(mbPathlen+1))) == NULL) { 3874 return (R_FAILURE); 3875 } 3876 3877 /*LINTED*/ 3878 if ((wcPathlen = mbstowcs(wcPath, *r_path, mbPathlen)) == -1) { 3879 free(wcPath); 3880 return (R_FAILURE); 3881 } 3882 3883 /* 3884 * remove duplicate slashes first ("//../" -> "/") 3885 */ 3886 3887 for (wptr = wcPath, i = 0; i < wcPathlen; i++) { 3888 *wptr++ = wcPath[i]; 3889 3890 if (wcPath[i] == '/') { 3891 i++; 3892 3893 while (wcPath[i] == '/') { 3894 i++; 3895 } 3896 3897 i--; 3898 } 3899 } 3900 3901 *wptr = '\0'; 3902 3903 /* 3904 * now convert back to the multi-byte format. 3905 */ 3906 3907 /*LINTED*/ 3908 if (wcstombs(*r_path, wcPath, mbPathlen) == -1) { 3909 free(wcPath); 3910 return (R_FAILURE); 3911 } 3912 3913 /* at this point have a path */ 3914 3915 /* free up temporary storage */ 3916 3917 free(wcPath); 3918 3919 return (R_SUCCESS); 3920 } 3921 3922 /* 3923 * Name: removeLeadingWhitespace 3924 * Synopsis: Remove leading whitespace from string 3925 * Description: Remove all leading whitespace characters from a string 3926 * Arguments: a_str - [RO, *RW] - (char **) 3927 * Pointer to handle to string (in allocated storage) to 3928 * remove all leading whitespace from 3929 * Returns: void 3930 * The input string is modified as follows: 3931 * == NULL: 3932 * - input string was NULL 3933 * - input string is all whitespace 3934 * != NULL: 3935 * - copy of input string with leading 3936 * whitespace removed 3937 * CAUTION: The input string must be allocated space (via malloc() or 3938 * strdup()) - it must not be a static or inline character string 3939 * NOTE: The input string a_str will be freed with 'free' 3940 * if it is all whitespace, or if it contains any leading 3941 * whitespace characters 3942 * NOTE: Any string returned is placed in new storage for the 3943 * calling method. The caller must use 'free' to dispose 3944 * of the storage once the string is no longer needed. 3945 * Errors: If the string cannot be created, the process exits 3946 */ 3947 3948 static void 3949 removeLeadingWhitespace(char **a_str) 3950 { 3951 char *o_str; 3952 3953 /* entry assertions */ 3954 3955 assert(a_str != (char **)NULL); 3956 3957 /* if string is null, just return */ 3958 3959 if (*a_str == NULL) { 3960 return; 3961 } 3962 o_str = *a_str; 3963 3964 /* if string is empty, deallocate and return NULL */ 3965 3966 if (*o_str == '\0') { 3967 /* free string */ 3968 free(*a_str); 3969 *a_str = NULL; 3970 return; 3971 } 3972 3973 /* if first character is not a space, just return */ 3974 3975 if (!isspace(*o_str)) { 3976 return; 3977 } 3978 3979 /* advance past all space characters */ 3980 3981 while ((*o_str != '\0') && (isspace(*o_str))) { 3982 o_str++; 3983 } 3984 3985 /* if string was all space characters, deallocate and return NULL */ 3986 3987 if (*o_str == '\0') { 3988 /* free string */ 3989 free(*a_str); 3990 *a_str = NULL; 3991 return; 3992 } 3993 3994 /* have non-space/null byte, return dup, deallocate original */ 3995 3996 o_str = strdup(o_str); 3997 free(*a_str); 3998 *a_str = o_str; 3999 } 4000 4001 /* 4002 * Name: getZoneName 4003 * Description: get the name of the zone this process is running in 4004 * Arguments: r_zoneName - pointer to pointer to receive zone name 4005 * Output: r_zoneName - a pointer to malloc()ed storage containing 4006 * the zone name this process is running in is stored 4007 * in the location pointed to by r_zoneName 4008 * Returns: R_SUCCESS - the zone name is successfully returned 4009 * R_FAILURE - the zone name is not successfully returned 4010 * R_ERROR - error attempting to get the zone name 4011 */ 4012 4013 static int 4014 getZoneName(char **r_zoneName) 4015 { 4016 static char zoneName[ZONENAME_MAX] = { '\0' }; 4017 4018 /* if zone name not already present, retrieve and cache name */ 4019 4020 if (zoneName[0] == '\0') { 4021 if (getzonenamebyid(getzoneid(), zoneName, 4022 sizeof (zoneName)) < 0) { 4023 log_msg(LOG_MSG_ERR, ERR_CANNOT_GET_ZONENAME); 4024 return (R_ERROR); 4025 } 4026 } 4027 4028 /* return cached zone name */ 4029 4030 *r_zoneName = zoneName; 4031 return (R_SUCCESS); 4032 } 4033 4034 /* 4035 * Name: getRootPath 4036 * Description: get the root path being tested by this process 4037 * Arguments: r_rootPath - pointer to pointer to receive root path 4038 * Output: r_rootPath - a pointer to malloc()ed storage containing 4039 * the root path name this process is testing 4040 * Returns: R_SUCCESS - the root path is successfully returned 4041 * R_FAILURE - the root path is not successfully returned 4042 * R_ERROR - error attempting to get the root path 4043 */ 4044 4045 static int 4046 getRootPath(char **r_rootPath) 4047 { 4048 *r_rootPath = _rootPath; 4049 return (R_SUCCESS); 4050 } 4051 4052 /* 4053 * Name: setVerbose 4054 * Description: Turns on verbose output 4055 * Scope: public 4056 * Arguments: verbose = B_TRUE indicates verbose mode 4057 * Returns: none 4058 */ 4059 4060 static void 4061 setVerbose(boolean_t setting) 4062 { 4063 /* set log verbose messages */ 4064 4065 log_set_verbose(setting); 4066 4067 /* set interactive messages */ 4068 4069 echoSetFlag(setting); 4070 } 4071 4072 /* 4073 * Name: negate_results 4074 * Description: control negation of results 4075 * Scope: public 4076 * Arguments: setting 4077 * == B_TRUE indicates negated results mode 4078 * == B_FALSE indicates non-negated results mode 4079 * Returns: none 4080 */ 4081 4082 static void 4083 setNegateResults(boolean_t setting) 4084 { 4085 log_msg(LOG_MSG_DEBUG, DBG_SET_NEGATE_RESULTS, 4086 _negateResults, setting); 4087 4088 _negateResults = setting; 4089 } 4090 4091 /* 4092 * Name: getNegateResults 4093 * Description: Returns whether or not to results are negated 4094 * Scope: public 4095 * Arguments: none 4096 * Returns: B_TRUE - results are negated 4097 * B_FALSE - results are not negated 4098 */ 4099 4100 static boolean_t 4101 getNegateResults(void) 4102 { 4103 return (_negateResults); 4104 } 4105 4106 /* 4107 * Name: usage 4108 * Description: output usage string 4109 * Arguments: a_format - format to use to generate message 4110 * arguments following a_format - as needed for a_format 4111 * Output: Outputs the usage string to stderr. 4112 * Returns: R_ERROR 4113 */ 4114 4115 static int 4116 usage(char *a_format, ...) 4117 { 4118 int cur_cmd; 4119 char cmdlst[LINE_MAX+1] = { '\0' }; 4120 char *message; 4121 char bfr[1]; 4122 char *p = get_prog_name(); 4123 size_t vres = 0; 4124 va_list ap; 4125 4126 /* entry assertions */ 4127 4128 assert(a_format != NULL); 4129 assert(*a_format != '\0'); 4130 4131 /* determine size of the message in bytes */ 4132 4133 va_start(ap, a_format); 4134 /* LINTED warning: variable format specifier to vsnprintf(); */ 4135 vres = vsnprintf(bfr, 1, a_format, ap); 4136 va_end(ap); 4137 4138 assert(vres > 0); 4139 4140 /* allocate storage to hold the message */ 4141 4142 message = (char *)calloc(1, vres+2); 4143 assert(message != NULL); 4144 4145 /* generate the results of the printf conversion */ 4146 4147 va_start(ap, a_format); 4148 /* LINTED warning: variable format specifier to vsnprintf(); */ 4149 vres = vsnprintf(message, vres+1, a_format, ap); 4150 va_end(ap); 4151 4152 assert(vres > 0); 4153 4154 /* generate list of all defined conditions */ 4155 4156 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { 4157 (void) strlcat(cmdlst, "\t", sizeof (cmdlst)); 4158 (void) strlcat(cmdlst, cmds[cur_cmd].c_name, sizeof (cmdlst)); 4159 if (cmds[cur_cmd].c_args != NULL) { 4160 (void) strlcat(cmdlst, cmds[cur_cmd].c_args, 4161 sizeof (cmdlst)); 4162 } 4163 (void) strlcat(cmdlst, "\n", sizeof (cmdlst)); 4164 } 4165 4166 /* output usage with conditions */ 4167 4168 log_msg(LOG_MSG_INFO, MSG_USAGE, message, p ? p : "pkgcond", cmdlst); 4169 4170 return (R_ERROR); 4171 } 4172 4173 /* 4174 * Name: parseGlobalData 4175 * Description: parse environment global data and store in global data structure 4176 * Arguments: a_envVar - pointer to string representing the name of the 4177 * environment variable to get and parse 4178 * r_gdt - pointer to pointer to global data structure to fill in 4179 * using the parsed data from a_envVar 4180 * Output: none 4181 * Returns: R_SUCCESS - the global data is successfully parsed 4182 * R_FAILURE - problem parsing global data 4183 * R_ERROR - fatal error attempting to parse global data 4184 */ 4185 4186 static int 4187 parseGlobalData(char *a_envVar, GLOBALDATA_T **r_gdt) 4188 { 4189 int r; 4190 int n; 4191 char *a; 4192 SML_TAG *tag; 4193 SML_TAG *ntag; 4194 4195 assert(r_gdt != (GLOBALDATA_T **)NULL); 4196 4197 /* 4198 * allocate space for global data structure if needed 4199 */ 4200 4201 if (*r_gdt == (GLOBALDATA_T *)NULL) { 4202 *r_gdt = (GLOBALDATA_T *)calloc(1, sizeof (GLOBALDATA_T)); 4203 } 4204 4205 /* 4206 * get initial installation indication: 4207 * If the initial install variable is set to "true", then an initial 4208 * installation of Solaris is underway. When this condition is true: 4209 * - if the path being checked is the package install root, then 4210 * the path is considered to be an 'alternative root' which is 4211 * currently being installed. 4212 * - if the path being checked is not the package install root, then 4213 * the path needs to be further analyzed to determine what it may 4214 * be referring to. 4215 */ 4216 4217 a = getenv(ENV_VAR_INITIAL_INSTALL); 4218 if ((a != NULL) && (strcasecmp(a, "true") == 0)) { 4219 (*r_gdt)->gd_initialInstall = B_TRUE; 4220 } 4221 4222 /* get current zone name */ 4223 4224 r = getZoneName(&(*r_gdt)->gd_zoneName); 4225 if (r != R_SUCCESS) { 4226 (*r_gdt)->gd_zoneName = ""; 4227 } 4228 4229 /* 4230 * get zone installation status: 4231 * - If the package install zone name is not set, then an installation 4232 * of a global zone, or of a non-global zone, is not underway. 4233 * - If the package install zone name is set to "global", then an 4234 * installation of a global zone is underway. In this case, no path 4235 * can be a netinstall image, diskless client, mounted miniroot, 4236 * non-global zone, the current running system, alternative root, 4237 * or alternative boot environment. 4238 * - If the package install zone name is set to a value other than 4239 * "global", then an installation of a non-global zone with that name 4240 * is underway. In this case, no path can be a netinstall image, 4241 * diskless client, mounted miniroot, global zone, the current 4242 * running system, alternative root, or alternative boot environment. 4243 */ 4244 4245 a = getenv(ENV_VAR_PKGZONENAME); 4246 if ((a == NULL) || (*a == '\0')) { 4247 /* not installing a zone */ 4248 (*r_gdt)->gd_globalZoneInstall = B_FALSE; 4249 (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE; 4250 } else if (strcmp(a, GLOBAL_ZONENAME) == 0) { 4251 /* installing a global zone */ 4252 (*r_gdt)->gd_globalZoneInstall = B_TRUE; 4253 (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE; 4254 (*r_gdt)->gd_zoneName = a; 4255 } else { 4256 /* installing a non-global zone by that name */ 4257 (*r_gdt)->gd_globalZoneInstall = B_FALSE; 4258 (*r_gdt)->gd_nonglobalZoneInstall = B_TRUE; 4259 (*r_gdt)->gd_zoneName = a; 4260 } 4261 4262 /* 4263 * get package install root. If it doesn't exist check for 4264 * patch install root (ROOTDIR) 4265 */ 4266 4267 a = getenv(ENV_VAR_PKGROOT); 4268 if ((a != NULL) && (*a != '\0')) { 4269 (*r_gdt)->gd_installRoot = a; 4270 } else { 4271 a = getenv(ENV_VAR_PATCHROOT); 4272 if ((a != NULL) && (*a != '\0')) { 4273 (*r_gdt)->gd_installRoot = a; 4274 } else { 4275 (*r_gdt)->gd_installRoot = "/"; 4276 } 4277 } 4278 4279 /* 4280 * get patch client version: always set if $ROOTDIR != / and 4281 * the $ROOTDIR/var/sadm/softinfo/INST_RELEASE file exists. 4282 */ 4283 4284 a = getenv(ENV_VAR_PATCH_CLIENTVER); 4285 (*r_gdt)->gd_patchClientVersion = (a ? a : ""); 4286 4287 /* get the global data environment variable */ 4288 4289 a = getenv(a_envVar); 4290 4291 /* if no data then issue warning and return success */ 4292 4293 if ((a == NULL) || (*a_envVar == '\0')) { 4294 log_msg(LOG_MSG_DEBUG, DBG_NO_GLOBAL_DATA_AVAILABLE, a_envVar); 4295 return (R_SUCCESS); 4296 } 4297 4298 /* data present - parse into SML structure */ 4299 4300 log_msg(LOG_MSG_DEBUG, DBG_PARSE_GLOBAL, a); 4301 4302 r = smlConvertStringToTag(&tag, a); 4303 if (r != R_SUCCESS) { 4304 log_msg(LOG_MSG_ERR, ERR_CANNOT_PARSE_GLOBAL_DATA, a); 4305 return (R_FAILURE); 4306 } 4307 4308 smlDbgPrintTag(tag, DBG_PARSED_ENVIRONMENT, a_envVar); 4309 4310 /* fill in global data structure */ 4311 4312 /* find the environment condition information structure */ 4313 4314 ntag = smlGetTagByName(tag, 0, TAG_COND_TOPLEVEL); 4315 if (ntag == SML_TAG__NULL) { 4316 log_msg(LOG_MSG_WRN, WRN_PARSED_DATA_MISSING, 4317 TAG_COND_TOPLEVEL); 4318 return (R_FAILURE); 4319 } 4320 4321 /* 4322 * data found - extract what we know about 4323 */ 4324 4325 /* parent zone name */ 4326 4327 a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_NAME); 4328 (*r_gdt)->gd_parentZoneName = a; 4329 4330 /* parent zone type */ 4331 4332 a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_TYPE); 4333 (*r_gdt)->gd_parentZoneType = a; 4334 4335 /* current zone name */ 4336 4337 a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE, 4338 TAG_COND_ZONE_NAME); 4339 (*r_gdt)->gd_currentZoneName = a; 4340 4341 /* current zone type */ 4342 4343 a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE, 4344 TAG_COND_ZONE_TYPE); 4345 (*r_gdt)->gd_currentZoneType = a; 4346 4347 /* extract any inherited file systems */ 4348 4349 for (n = 0; ; n++) { 4350 char **ifs; 4351 4352 a = smlGetParamByTag(ntag, n, TAG_COND_INHERITED_FS, 4353 TAG_COND_FS_NAME); 4354 4355 if (a == NULL) { 4356 if (n > 0) { 4357 /* LINTED warning: variable may be used */ 4358 (*r_gdt)->gd_inheritedFileSystems = ifs; 4359 } 4360 break; 4361 } 4362 4363 if (n == 0) { 4364 ifs = (char **)calloc(1, sizeof (char **)*(n+2)); 4365 ifs[n] = a; 4366 ifs[n+1] = NULL; 4367 } else { 4368 ifs = (char **)realloc(ifs, sizeof (char **)*(n+2)); 4369 ifs[n] = a; 4370 ifs[n+1] = NULL; 4371 } 4372 } 4373 4374 return (R_SUCCESS); 4375 } 4376 4377 /* 4378 * Name: dumpGlobalData 4379 * Description: dump global data structure using echoDebug 4380 * Arguments: a_gdt - pointer to global data structure to dump 4381 * Outputs: echoDebug is called to output global data strucutre information 4382 * Returns: void 4383 */ 4384 4385 static void 4386 dumpGlobalData(GLOBALDATA_T *a_gdt) 4387 { 4388 /* entry assertions */ 4389 4390 assert(a_gdt != (GLOBALDATA_T *)NULL); 4391 4392 /* debugging enabled, dump the global data structure */ 4393 4394 echoDebug(DBG_DUMP_GLOBAL_ENTRY); 4395 echoDebug(DBG_DUMP_GLOBAL_PARENT_ZONE, 4396 a_gdt->gd_parentZoneName ? a_gdt->gd_parentZoneName : "", 4397 a_gdt->gd_parentZoneType ? a_gdt->gd_parentZoneType : ""); 4398 echoDebug(DBG_DUMP_GLOBAL_CURRENT_ZONE, 4399 a_gdt->gd_currentZoneName ? a_gdt->gd_currentZoneName : "", 4400 a_gdt->gd_currentZoneType ? a_gdt->gd_currentZoneType : ""); 4401 4402 if (a_gdt->gd_inheritedFileSystems) { 4403 int n; 4404 char **ifs = a_gdt->gd_inheritedFileSystems; 4405 for (n = 0; ifs[n]; n++) { 4406 echoDebug(DBG_DUMP_GLOBAL_LINE, n, ifs[n]); 4407 } 4408 } 4409 } 4410 4411 /* 4412 * Name: recursionCheck 4413 * Description: prevent recursive calling of functions 4414 * Arguments: r_recursion - pointer to int recursion counter 4415 * a_function - pointer to name of function 4416 * Returns: B_TRUE - function is recursively called 4417 * B_FALSE - function not recursively called 4418 */ 4419 4420 static boolean_t 4421 recursionCheck(int *r_recursion, char *a_function) 4422 { 4423 /* prevent recursion */ 4424 4425 (*r_recursion)++; 4426 if (*r_recursion > 1) { 4427 echoDebug(DBG_RECURSION, a_function, *r_recursion); 4428 (*r_recursion)--; 4429 return (B_TRUE); 4430 } 4431 4432 echoDebug(DBG_NO_RECURSION, a_function); 4433 return (B_FALSE); 4434 } 4435 4436 /* 4437 * Name: quit 4438 * Description: cleanup and exit 4439 * Arguments: a_retcode - the code to use to determine final exit status; 4440 * if this is NOT "99" and if a "ckreturnFunc" is 4441 * set, then that function is called with a_retcode 4442 * to set the final exit status. 4443 * Valid values are: 4444 * 0 - success 4445 * 1 - package operation failed (fatal error) 4446 * 2 - non-fatal error (warning) 4447 * 3 - user selected quit (operation interrupted) 4448 * 4 - admin settings prevented operation 4449 * 5 - interaction required and -n (non-interactive) specified 4450 * "10" is added to indicate "immediate reboot required" 4451 * "20" is be added to indicate "reboot after install required" 4452 * 99 - do not interpret the code - just exit "99" 4453 * Returns: <<this function does not return - calls exit()>> 4454 * NOTE: This is needed because libinst functions can call "quit(99)" 4455 * to force an error exit. 4456 */ 4457 4458 void 4459 quit(int a_retcode) 4460 { 4461 /* process return code if not quit(99) */ 4462 4463 if (a_retcode == 99) { 4464 exit(0x7f); /* processing error (127) */ 4465 } 4466 4467 exit(R_FAILURE); 4468 } 4469