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