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