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