/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2017 Peter Tribble. */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Program: pkgcond * * Function: Implements the package command suite public utility pkgcond(1M) * * Usage: pkgcond [-nv] [-O debug] condition [ argument ] * * command options: * -n - negate results of condition test * -v - verbose output of condition testing * * may be any one of: * can_add_driver [path] * can_remove_driver [path] * can_update_driver [path] * is_alternative_root [path] * is_boot_environment [path] * is_diskless_client [path] * is_global_zone [path] * is_mounted_miniroot [path] * is_netinstall_image [path] * is_nonglobal_zone [path] * is_path_writable path * is_running_system [path] * is_what [path] * is_whole_root_nonglobal_zone [path] * * are specific to the condition used * * Input: depends on command * * Output: depends on command * * Exit status: If the -n option is not specified: * == 0 - the specified condition is true (or exists). * == 1 - the specified condition is false (or does not exist). * == 2 - command line usage errors (including bad keywords) * == 3 - command failed to perform the test due to a fatal error * * If the -n option is specified: * == 0 - the specified condition is false (or does not exist). * == 1 - the specified condition is true (or exists). * == 2 - command line usage errors (including bad keywords) * == 3 - command failed to perform the test due to a fatal error */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pkgcond.h" #include "pkgcond_msgs.h" /* Should be defined by cc -D */ #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* commands to execute */ #define LS_CMD "/usr/bin/ls" /* * type definition and "types" for testPath() */ typedef enum { TEST_EXISTS = 0x01, TEST_NOT_EXISTS = 0x02, TEST_IS_DIRECTORY = 0x04, TEST_IS_FILE = 0x08, TEST_NOT_DIRECTORY = 0x10, TEST_NOT_FILE = 0x20, TEST_IS_SYMBOLIC_LINK = 0x40, TEST_NOT_SYMBOLIC_LINK = 0x80, TEST_GLOBAL_TOKEN_IN_FILE = 0x100 } TEST_TYPES; /* holds file system info */ struct fsi_t { char *fsi_mntOptions; char *fsi_fsType; char *fsi_mntPoint; }; typedef struct fsi_t FSI_T; /* holds parsed global data */ struct globalData_t { /* initial install: PKG_INIT_INSTALL=true */ boolean_t gd_initialInstall; /* global zone install: SUNW_PKG_INSTALL_ZONENAME=global */ boolean_t gd_globalZoneInstall; /* non-global zone install: SUNW_PKG_INSTALL_ZONENAME!=global */ boolean_t gd_nonglobalZoneInstall; /* non-global zone is in a mounted state */ boolean_t inMountedState; /* sorted list of all mounted file systems */ FSI_T *gd_fileSystemConfig; /* number of mounted file systems in list */ long gd_fileSystemConfigLen; /* current zone name */ char *gd_zoneName; /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneName */ char *gd_parentZoneName; /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneType */ char *gd_parentZoneType; /* root path to target: PKG_INSTALL_ROOT */ char *gd_installRoot; /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneName */ char *gd_currentZoneName; /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneType */ char *gd_currentZoneType; /* path provided on command line */ char *gd_cmdline_path; }; typedef struct globalData_t GLOBALDATA_T; /* holds subcommands and their definitions */ struct cmd_t { char *c_name; char *c_args; int (*c_func)(int argc, char **argv, GLOBALDATA_T *a_gdt); }; typedef struct cmd_t CMD_T; /* Command function prototypes */ static int cmd_can_add_driver(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_can_remove_driver(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_can_update_driver(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_alternative_root(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_boot_environment(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_diskless_client(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_global_zone(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_mounted_miniroot(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_netinstall_image(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_nonglobal_zone(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_path_writable(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_running_system(int argc, char **argv, GLOBALDATA_T *a_gdt); static int cmd_is_what(int argc, char **argv, GLOBALDATA_T *a_gdt); /* Utility function Prototypes */ static boolean_t getNegateResults(void); static boolean_t recursionCheck(int *r_recursion, char *a_function); static int adjustResults(int a_result); static int calculateFileSystemConfig(GLOBALDATA_T *a_gdt); static int getRootPath(char **r_rootPath); static int getZoneName(char **r_zoneName); static int mountOptionPresent(char *a_mntOptions, char *a_opt); static int parseGlobalData(char *a_envVar, GLOBALDATA_T **a_gdt); static int resolvePath(char **r_path); static int setRootPath(char *a_path, char *a_envVar, boolean_t a_mustExist); static int testPath(TEST_TYPES a_tt, char *format, ...); static int usage(char *a_format, ...); static int findToken(char *path, char *token); static char *getMountOption(char **p); static void dumpGlobalData(GLOBALDATA_T *a_gdt); static void removeLeadingWhitespace(char **a_str); static void setNegateResults(boolean_t setting); static void setVerbose(boolean_t); static void sortedInsert(FSI_T **r_list, long *a_listSize, char *a_mntPoint, char *a_fsType, char *a_mntOptions); static void setCmdLinePath(char **a_path, char **args, int num_args); /* local static data */ static boolean_t _negateResults = B_FALSE; static char *_rootPath = "/"; /* define subcommand data structure */ static CMD_T cmds[] = { { "can_add_driver", " [path]", cmd_can_add_driver }, { "can_remove_driver", " [path]", cmd_can_remove_driver }, { "can_update_driver", " [path]", cmd_can_update_driver }, { "is_alternative_root", " [path]", cmd_is_alternative_root }, { "is_boot_environment", " [path]", cmd_is_boot_environment }, { "is_diskless_client", " [path]", cmd_is_diskless_client }, { "is_global_zone", " [path]", cmd_is_global_zone }, { "is_mounted_miniroot", " [path]", cmd_is_mounted_miniroot }, { "is_netinstall_image", " [path]", cmd_is_netinstall_image }, { "is_nonglobal_zone", " [path]", cmd_is_nonglobal_zone }, { "is_path_writable", " path", cmd_is_path_writable }, { "is_running_system", " [path]", cmd_is_running_system }, { "is_what", " [path]", cmd_is_what }, /* last one must be all NULLs */ { NULL, NULL, NULL } }; /* * ***************************************************************************** * main * ***************************************************************************** */ /* * Name: main * Description: main processing loop for pkgcond * * Return: 0 - condition is satisfied (true) * 1 - condition is not satisfied (false) * 2 - command line usage errors * 3 - failure to determine condition */ int main(int argc, char **argv) { GLOBALDATA_T *gdt = NULL; char **newargv; char *p; int cur_cmd; int i; int newargc; /* make standard output non-buffered */ setbuf(stdout, NULL); /* set the default text domain for messaging */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* remember command name */ set_prog_name(argv[0]); /* tell spmi zones interface how to access package output functions */ z_set_output_functions(echo, echoDebug, progerr); /* set verbose mode if appropriate environment variable is set */ if (getenv(ENV_VAR_VERBOSE)) { /* same as -v */ setVerbose(B_TRUE); } /* set debug mode if appropriate environment variable is set */ if (getenv(ENV_VAR_DEBUG)) { /* same as -O debug */ /* set sml tracing (sml.c) */ smlSetVerbose(B_TRUE); /* set log and echo (interactive) message tracing */ setVerbose(B_TRUE); /* enable echoDebug debugging messages */ echoDebugSetFlag(B_TRUE); } /* generate usage if no options or arguments specified */ if (argc <= 1) { (void) usage(MSG_NO_ARGUMENTS_SPECIFIED); return (R_USAGE); } /* * process any arguments that can appear before the subcommand */ while ((i = getopt(argc, argv, ":O:vn?")) != EOF) { switch (i) { /* * Not a public interface: the -O option allows the behavior * of the package tools to be modified. Recognized options: * -> debug * ---> enable debugging output */ case 'O': for (p = strtok(optarg, ","); p != NULL; p = strtok(NULL, ",")) { /* debug - enable all tracing */ if (strcmp(p, "debug") == 0) { /* set sml tracing */ smlSetVerbose(B_TRUE); /* set log/echo tracing */ setVerbose(B_TRUE); /* enable debugging messages */ echoDebugSetFlag(B_TRUE); continue; } progerr(ERR_INVALID_O_OPTION, p); return (adjustResults(R_USAGE)); } break; /* * Public interface: enable verbose (debug) output. */ case 'v': /* verbose mode enabled */ /* set command tracing only */ setVerbose(B_TRUE); break; /* * Public interface: negate output results. */ case 'n': setNegateResults(B_TRUE); break; /* * unrecognized option */ case '?': default: (void) usage(MSG_INVALID_OPTION_SPECIFIED, optopt); return (R_USAGE); } } /* * done processing options that can preceed subcommand */ /* error if no subcommand specified */ if ((argc-optind) <= 0) { (void) usage(MSG_NO_ARGUMENTS_SPECIFIED); return (R_USAGE); } /* parse global data if environment variable set */ if (parseGlobalData(PKGCOND_GLOBAL_VARIABLE, &gdt) != R_SUCCESS) { log_msg(LOG_MSG_ERR, ERR_CANNOT_USE_GLOBAL_DATA, PKGCOND_GLOBAL_VARIABLE); return (R_ERROR); } if (setRootPath(gdt->gd_installRoot, (strcmp(gdt->gd_installRoot, "/") == 0) ? NULL : ENV_VAR_SET, B_TRUE) != R_SUCCESS) { log_msg(LOG_MSG_ERR, ERR_CANNOT_SET_ROOT_PATH, ENV_VAR_PKGROOT); return (R_ERROR); } /* set path provided on the command line */ setCmdLinePath(&(gdt->gd_cmdline_path), argv, argc); echoDebug(DBG_CMDLINE_PATH, gdt->gd_cmdline_path == NULL ? "" : gdt->gd_cmdline_path); /* determine how file systems are layered in this zone */ if (calculateFileSystemConfig(gdt) != R_SUCCESS) { log_msg(LOG_MSG_ERR, ERR_CANNOT_CALC_FS_CONFIG); return (R_ERROR); } /* dump global data read in (only if debugging) */ dumpGlobalData(gdt); /* search for specified subcommand and execute if found */ for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { if (ci_streq(argv[optind], cmds[cur_cmd].c_name)) { int result; /* make subcommand the first option */ newargc = argc - optind; newargv = argv + optind; opterr = optind = 1; optopt = 0; /* call subcommand with its own argc/argv */ result = cmds[cur_cmd].c_func(newargc, newargv, gdt); /* process result code and exit */ result = adjustResults(result); log_msg(LOG_MSG_DEBUG, DBG_RESULTS, result); return (result); } } /* subcommand not found - output error message and exit with error */ log_msg(LOG_MSG_ERR, ERR_BAD_SUB, argv[optind]); (void) usage(MSG_UNRECOGNIZED_CONDITION_SPECIFIED); return (R_USAGE); } /* * ***************************************************************************** * command implementation functions * ***************************************************************************** */ /* * Name: cmd_is_diskless_client * Description: determine if target is a diskless client * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a zone * - must not be a whole root non-global zone * - must not be a non-global zone * - must not be a mounted mini-root * - must not be a netinstall image * - must not be a boot environment * - The package "SUNWdclnt" must be installed at "/" * - The root path must not be "/" * - The path "/export/exec/Solaris_\*\/usr" must exist at "/" * - The directory "$ROOTDIR/../templates" must exist */ static int cmd_is_diskless_client(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; char cmd[MAXPATHLEN+1]; int c; int r; int rc; static char *cmdName = "is_diskless_client"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* * a diskless client cannot be any of the following */ /* cannot be non-global zone */ r = cmd_is_nonglobal_zone(argc, argv, a_gdt); /* cannot be mounted miniroot */ if (r != R_SUCCESS) { r = cmd_is_mounted_miniroot(argc, argv, a_gdt); } /* cannot be a netinstall image */ if (r != R_SUCCESS) { r = cmd_is_netinstall_image(argc, argv, a_gdt); } /* cannot be a boot environment */ if (r != R_SUCCESS) { r = cmd_is_boot_environment(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; /* return failure if any of the preceeding are true */ switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* SUNWdclnt must be installed */ if (pkgTestInstalled("SUNWdclnt", "/") != B_TRUE) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_PKG_NOT_INSTALLED, rootPath, "SUNWdclnt", "/"); return (R_FAILURE); } /* - $ROOTDIR must not be "/" */ if (strcmp(rootPath, "/") == 0) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_ROOTPATH_BAD, rootPath, "/"); return (R_FAILURE); } /* - zone name must be global */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_BAD, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* * /export/exec/Solaris_"*"/usr must exist; * create ls command to test: * /usr/bin/ls /export/exec/Solaris_"*"/usr */ (void) snprintf(cmd, sizeof (cmd), "%s %s >/dev/null 2>&1", LS_CMD, "/export/exec/Solaris_*/usr"); /* execute command */ rc = system(cmd); /* return error if ls returns something other than "0" */ if (rc != 0) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_MISSING, rootPath, "/export/exec/Solaris_*/usr"); return (R_FAILURE); } /* * /usr must be empty on a diskless client: * create ls command to test: * /usr/bin/ls -d1 $ROOTDIR/usr/\* */ (void) snprintf(cmd, sizeof (cmd), "%s %s %s/%s >/dev/null 2>&1", LS_CMD, "-1d", rootPath, "usr/*"); /* execute command */ rc = system(cmd); /* return error if ls returns "0" */ if (rc == 0) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_USR_IS_NOT_EMPTY, rootPath); return (R_FAILURE); } /* there must be a templates directory at ${ROOTPATH}/../templates */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, "../templates"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_IDLC_NO_TEMPLATES_PATH, rootPath, rootPath, "../templates"); return (R_FAILURE); } /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be diskless client */ log_msg(LOG_MSG_DEBUG, DBG_IDLC_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be diskless client */ log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* the path is a diskless client */ log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_IS_DISKLESS_CLIENT, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_global_zone * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a non-global zone * - must not be a non-global zone * - must not be a mounted mini-root * - must not be a netinstall image * - must not be a diskless client * - if $ROOTDIR is "/": * -- if zone name is "GLOBAL", then is a global zone; * -- else not a global zone. * - $ROOTDIR/etc/zones must exist and be a directory * - $ROOTDIR/.tmp_proto must not exist * - $ROOTDIR/var must exist and must not be a symbolic link */ static int cmd_is_global_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_global_zone"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* * a global zone cannot be any of the following */ /* cannot be a non-global zone */ r = cmd_is_nonglobal_zone(argc, argv, a_gdt); /* cannot be a mounted miniroot */ if (r != R_SUCCESS) { r = cmd_is_mounted_miniroot(argc, argv, a_gdt); } /* cannot be a netinstall image */ if (r != R_SUCCESS) { r = cmd_is_netinstall_image(argc, argv, a_gdt); } /* cannot be a diskless client */ if (r != R_SUCCESS) { r = cmd_is_diskless_client(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; /* return failure if any of the preceeding are true */ switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a non-global zone */ if (a_gdt->gd_nonglobalZoneInstall == B_TRUE) { /* initial nonglobal zone install: no path can be global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_NGZ_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* handle if global zone installation to the install root */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* the path is a global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* true if current root is "/" and zone name is GLOBAL_ZONENAME */ if (strcmp(rootPath, "/") == 0) { if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { /* the path is a global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* inside a non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_ZONENAME_ISNT_GLOBAL, rootPath, a_gdt->gd_zoneName); return (R_FAILURE); } /* * current root is not "/" - see if target looks like a global zone * * - rootpath is not "/" * - and $ROOTDIR/etc/zones exists * - and $ROOTDIR/.tmp_proto does not exist * - and $ROOTDIR/var is not a symbolic link */ /* not global zone if /etc/zones does not exist */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, "/etc/zones"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_ISNT_DIRECTORY, rootPath, "/etc/zones"); return (R_FAILURE); } /* .tmp_proto must not exist */ r = testPath(TEST_NOT_EXISTS, "%s/%s", rootPath, ".tmp_proto"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_EXISTS, rootPath, "/.tmp_proto"); return (R_FAILURE); } /* /var must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/var"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_SYMLINK, rootPath, "/var"); return (R_FAILURE); } /* the path is a global zone */ log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_netinstall_image * Description: determine if target is a net install image * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a zone * - must not be a global zone * - must not be a mounted mini-root * - zone name must be "global" * - $ROOTDIR/.tmp_proto must exist and must be a directory * - $ROOTDIR/var must exist and must be a symbolic link * - $ROOTDIR/tmp/kernel must exist and must be a directory * - $ROOTDIR/.tmp_proto/kernel must exist and must be a symbolic link */ static int cmd_is_netinstall_image(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_netinstall_image"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* a netinstall image cannot be a global zone */ r = cmd_is_global_zone(argc, argv, a_gdt); /* no need to guard against recursion any more */ recursion--; switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* current zone name must be "global" */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { log_msg(LOG_MSG_DEBUG, DBG_INIM_BAD_CURRENT_ZONE, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* cannot be a mounted_miniroot */ if (cmd_is_mounted_miniroot(argc, argv, a_gdt) == R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT, rootPath); return (R_FAILURE); } /* $ROOTDIR/.tmp_proto exists */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, ".tmp_proto"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY, rootPath, "/.tmp_proto"); return (R_FAILURE); } /* $ROOTDIR/var is a symbolic link */ r = testPath(TEST_IS_SYMBOLIC_LINK, "%s/%s", rootPath, "/var"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK, rootPath, "/var"); return (R_FAILURE); } /* $ROOTDIR/tmp/kernel does exist */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, "/tmp/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY, rootPath, "/tmp/kernel"); return (R_FAILURE); } /* $ROOTDIR/.tmp_proto/kernel is a symbolic link */ r = testPath(TEST_IS_SYMBOLIC_LINK, "%s/%s", rootPath, "/.tmp_proto/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK, rootPath, "/.tmp_proto/kernel"); return (R_FAILURE); } /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be netinstall image */ log_msg(LOG_MSG_DEBUG, DBG_INIM_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be netinstall image */ log_msg(LOG_MSG_DEBUG, DBG_INIM_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* target is a netinstall image */ log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_IS_NETINSTALL_IMAGE, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_mounted_miniroot * Description: determine if target is a mounted miniroot image * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a zone * - zone name must be "global" * - $ROOTDIR/tmp/kernel must exist and must be a symbolic link * - $ROOTDIR/tmp/root/kernel must exist and must be a directory */ static int cmd_is_mounted_miniroot(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_mounted_miniroot"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { recursion--; } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* current zone name must be "global" */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { log_msg(LOG_MSG_DEBUG, DBG_IMRT_BAD_CURRENT_ZONE, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* $ROOTDIR/tmp/kernel is a symbolic link */ r = testPath(TEST_IS_SYMBOLIC_LINK, "%s/%s", rootPath, "/tmp/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_SYMLINK, rootPath, "/tmp/kernel"); return (R_FAILURE); } /* $ROOTDIR/tmp/root/kernel is a directory */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, "/tmp/root/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_DIRECTORY, rootPath, "/tmp/root/kernel"); return (R_FAILURE); } /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be mounted miniroot */ log_msg(LOG_MSG_DEBUG, DBG_IMRT_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be mounted miniroot */ log_msg(LOG_MSG_DEBUG, DBG_IMRT_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* target is a mounted miniroot */ log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_nonglobal_zone * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * - must not be initial installation to the install root * - must not be installation of a global zone * - success if installation of a non-global zone */ static int cmd_is_nonglobal_zone(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_nonglobal_zone"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { recursion--; } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* handle if non-global zone installation to the install root */ if ((a_gdt->gd_nonglobalZoneInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { log_msg(LOG_MSG_DEBUG, DBG_NGZN_INSTALL_ZONENAME_IS_NGZ, rootPath, a_gdt->gd_zoneName); return (R_SUCCESS); } /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a global zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial global zone install: no path can be nonglobal zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_GLOBAL_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* * ********************************************************************* * if root directory is "/" then the only thing that needs to be done is * to test the zone name directly - if the zone name is "global" then * the target is not a non-global zone; otherwise if the zone name is * not "global" then the target IS a non-global zone. * ********************************************************************* */ if (strcmp(rootPath, "/") == 0) { /* target is current running root */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { /* in the global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ, rootPath, a_gdt->gd_zoneName); return (R_FAILURE); } /* in a non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_IS_NGZ, rootPath, a_gdt->gd_zoneName); return (R_SUCCESS); } /* * $ROOTDIR/etc/zones/index must exist in a global zone. It also * exists in a non-global zone after s10u4 but we can't check that * since it is undeterministic for all releases so we only check * for the global zone here. */ r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/zones/index"); if (r == R_SUCCESS) { /* See if "global" exists in .../etc/zones/index */ if (testPath(TEST_GLOBAL_TOKEN_IN_FILE, "%s/%s", rootPath, "/etc/zones/index") != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } } /* * ********************************************************************* * If the root directory is "/" then you can use only the zone * name to determine if the zone is non-global or not since the * package is being installed or removed to the current "zone". * * Since the root directory being tested is not "/" then you have to * look into the target to try and infer zone type using means other * than the zone name only. * ********************************************************************* */ /* reject if any items found that cannot be in a non-global zone */ /* .tmp_proto must not exist */ r = testPath(TEST_NOT_EXISTS, "%s/%s", rootPath, ".tmp_proto"); if (r != R_SUCCESS) { /* $R/.tmp_proto cannot exist in a non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS, rootPath, "/.tmp_proto"); return (R_FAILURE); } /* /var must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/var"); if (r != R_SUCCESS) { /* $R/var cannot be a symbolic link in a non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_DOES_NOT_EXIST, rootPath, "/var"); return (R_FAILURE); } /* $ROOTDIR/tmp/root/kernel must not exist */ r = testPath(TEST_NOT_EXISTS, "%s/%s", rootPath, "/tmp/root/kernel"); if (r != R_SUCCESS) { /* $R/tmp/root/kernel cannot exist in a non-global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS, rootPath, "/tmp/root/kernel"); return (R_FAILURE); } /* * ********************************************************************* * no items exist in $ROOTDIR that identify something other than * a non-global zone. * * if in global zone no more tests possible: is a non-global zone * ********************************************************************* */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) { /* in the global zone */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_IN_GZ_IS_NONGLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* * ********************************************************************* * In non-global zone: interrogate zone name and type. * * The parent zone is the zone that the "pkgadd" or "pkgrm" command was * run in. The child zone is the zone that the "pkginstall" or * "pkgremove" command was run in. * ********************************************************************* */ /* * If parent zone name and current zone name defined, and * both zone names are the same, since pkgcond is running * inside of a non-global zone, this is how the scratch * zone is implemented, so target is a non-global zone */ if ((a_gdt->gd_parentZoneName != NULL) && (a_gdt->gd_currentZoneName != NULL) && (strcmp(a_gdt->gd_parentZoneName, a_gdt->gd_currentZoneName) == 0)) { /* parent and current zone name identical: non-gz */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_PARENT_CHILD_SAMEZONE, rootPath, a_gdt->gd_parentZoneName); return (R_SUCCESS); } /* * In non-global zone if zone specific read only FS's exist * or it is in a mounted state. */ if (a_gdt->inMountedState) { log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* * the parent and current zone name are not the same; * interrogate the zone types: the parent must be global * and the current must be non-global, which would be set * when a package command is run in the global zone that in * turn runs a package command within the non-global zone. */ /* if defined, parent zone type must be "global" */ if ((a_gdt->gd_parentZoneType != NULL) && (strcmp(a_gdt->gd_parentZoneType, "nonglobal") == 0)) { log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_PARENT_ZONETYPE, rootPath, "nonglobal"); return (R_FAILURE); } /* if defined, current zone type must be "nonglobal" */ if ((a_gdt->gd_currentZoneType != NULL) && (strcmp(a_gdt->gd_currentZoneType, GLOBAL_ZONENAME) == 0)) { log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_CURRENT_ZONETYPE, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* * ********************************************************************* * no other tests possible: target is a non-global zone * ********************************************************************* */ log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_running_system * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a zone * - must not be a diskless client * - $ROOTDIR must be "/" * - zone name must be "global" */ static int cmd_is_running_system(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_running_system"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* a running system cannot be a diskless client */ r = cmd_is_diskless_client(argc, argv, a_gdt); /* no need to guard against recursion any more */ recursion--; switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* if root path is "/" then check zone name */ if (strcmp(rootPath, "/") != 0) { log_msg(LOG_MSG_DEBUG, DBG_IRST_ROOTPATH_BAD, rootPath, "/"); return (R_FAILURE); } /* zone name must be global */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_BAD, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* must not be initial installation to the install root */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { /* initial install: install root cannot be the running system */ log_msg(LOG_MSG_DEBUG, DBG_IRST_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be running system */ log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* target is a running system */ log_msg(LOG_MSG_DEBUG, DBG_IRST_PATH_IS_RUNNING_SYSTEM, rootPath); return (R_SUCCESS); } /* * Name: cmd_can_add_driver * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * Implementation: * A driver can be added to the system if the components of a Solaris * instance capable of loading drivers is present and it is not the * currently running system. */ static int cmd_can_add_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "can_add_driver"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* see if this is the current running system */ r = cmd_is_running_system(argc, argv, a_gdt); /* cannot be a diskless client */ if (r != R_SUCCESS) { r = cmd_is_diskless_client(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; switch (r) { case R_SUCCESS: /* is a running system */ return (R_FAILURE); case R_FAILURE: /* not a running syste */ break; case R_USAGE: case R_ERROR: default: /* cannot determine if is a running system */ return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* /etc must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/etc"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, rootPath, "/etc"); return (R_FAILURE); } /* /platform must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/platform"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, rootPath, "/platform"); return (R_FAILURE); } /* /kernel must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK, rootPath, "/kernel"); return (R_FAILURE); } /* can add a driver */ log_msg(LOG_MSG_DEBUG, DBG_ADDV_YES, rootPath); return (R_SUCCESS); } /* * Name: cmd_can_update_driver * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * Implementation: * A driver can be added to the system if the components of a Solaris * instance capable of loading drivers is present and it is not the * currently running system. */ static int cmd_can_update_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "can_update_driver"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* see if this is the current running system */ r = cmd_is_running_system(argc, argv, a_gdt); /* cannot be a diskless client */ if (r != R_SUCCESS) { r = cmd_is_diskless_client(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; switch (r) { case R_SUCCESS: /* is a running system */ return (R_FAILURE); case R_FAILURE: /* not a running syste */ break; case R_USAGE: case R_ERROR: default: /* cannot determine if is a running system */ return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* /etc must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/etc"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, rootPath, "/etc"); return (R_FAILURE); } /* /platform must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/platform"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, rootPath, "/platform"); return (R_FAILURE); } /* /kernel must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK, rootPath, "/kernel"); return (R_FAILURE); } /* can update driver */ log_msg(LOG_MSG_DEBUG, DBG_UPDV_YES, rootPath); return (R_SUCCESS); } /* * Name: cmd_can_remove_driver * Description: determine if target is a global zone * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * Implementation: * A driver can be added to the system if the components of a Solaris * instance capable of loading drivers is present and it is not the * currently running system. */ static int cmd_can_remove_driver(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "can_remove_driver"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* see if this is the current running system */ r = cmd_is_running_system(argc, argv, a_gdt); /* cannot be a diskless client */ if (r != R_SUCCESS) { r = cmd_is_diskless_client(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; switch (r) { case R_SUCCESS: /* is a running system */ return (R_FAILURE); case R_FAILURE: /* not a running syste */ break; case R_USAGE: case R_ERROR: default: /* cannot determine if is a running system */ return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* /etc must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/etc"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, rootPath, "/etc"); return (R_FAILURE); } /* /platform must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/platform"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, rootPath, "/platform"); return (R_FAILURE); } /* /kernel must exist and must not be a symbolic link */ r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK, "%s/%s", rootPath, "/kernel"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK, rootPath, "/kernel"); return (R_FAILURE); } /* can remove driver */ log_msg(LOG_MSG_DEBUG, DBG_RMDV_YES, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_path_writable * Description: determine if target path is writable * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - path must be found in the file systems configured * - mount options must not include "read only" */ static int cmd_is_path_writable(int argc, char **argv, GLOBALDATA_T *a_gdt) { FSI_T *list; char *rootPath = NULL; int c; int n; int nn; int r; long listSize; long rootPathLen; static char *cmdName = "is_path_writable"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { recursion--; } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc != 1) { (void) usage(ERR_REQUIRED_ROOTPATH_MISSING, cmdName); return (R_USAGE); } if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* search file system conf for this path */ rootPathLen = strlen(rootPath); list = a_gdt->gd_fileSystemConfig; listSize = a_gdt->gd_fileSystemConfigLen; for (nn = 0, n = 0; n < listSize; n++) { long mplen = strlen(list[n].fsi_mntPoint); if (rootPathLen < mplen) { /* root path is longer than target, ignore */ continue; } if (strncmp(rootPath, list[n].fsi_mntPoint, mplen) == 0) { /* remember last partial match */ nn = n; } } log_msg(LOG_MSG_DEBUG, DBG_PWRT_INFO, rootPath, list[nn].fsi_mntPoint, list[nn].fsi_fsType, list[nn].fsi_mntOptions); /* * need to determine if the mount point is writeable: */ /* see if the file system is mounted with the "read only" option */ r = mountOptionPresent(list[nn].fsi_mntOptions, MNTOPT_RO); if (r == R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_PWRT_READONLY, rootPath, list[nn].fsi_mntOptions); return (R_FAILURE); } /* target path is writable */ log_msg(LOG_MSG_DEBUG, DBG_PWRT_IS, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_alternative_root * Description: determine if target is an alternative root * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * Implementation: * - success if an initial installation to the install root * (an initial install to $PKG_INSTALL_ROOT means that $PKG_INSTALL_ROOT * points to an alternative root that is under construction) * - must not be installation of a zone * - must not be a boot environment * - must not be a diskless client * - must not be a mounted miniroot * - must not be a netinstall image * - must not be a nonglobal zone * - must not be a running system * - $ROOTDIR must not be "/" * - $ROOTDIR/var must exist */ static int cmd_is_alternative_root(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_alternative_root"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* * an alternative root cannot be any of the following */ /* cannot be a boot_environment */ r = cmd_is_boot_environment(argc, argv, a_gdt); /* cannot be a diskless_client */ if (r != R_SUCCESS) { r = cmd_is_diskless_client(argc, argv, a_gdt); } /* cannot be a mounted_miniroot */ if (r != R_SUCCESS) { r = cmd_is_mounted_miniroot(argc, argv, a_gdt); } /* cannot be a netinstall_image */ if (r != R_SUCCESS) { r = cmd_is_netinstall_image(argc, argv, a_gdt); } /* cannot be a nonglobal_zone */ if (r != R_SUCCESS) { r = cmd_is_nonglobal_zone(argc, argv, a_gdt); } /* cannot be a running_system */ if (r != R_SUCCESS) { r = cmd_is_running_system(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; /* return failure if any of the preceeding are true */ switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* return success if initial installation */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { log_msg(LOG_MSG_DEBUG, DBG_IALR_INITIAL_INSTALL, rootPath); return (R_SUCCESS); } /* root path must not be "/" */ if (strcmp(rootPath, "/") == 0) { log_msg(LOG_MSG_DEBUG, DBG_IALR_BAD_ROOTPATH, rootPath, "/"); return (R_FAILURE); } /* /var must exist */ r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/var"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_IALR_PATH_DOES_NOT_EXIST, rootPath, "/var"); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be alternative root */ log_msg(LOG_MSG_DEBUG, DBG_IALR_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* target is an alternative root */ log_msg(LOG_MSG_DEBUG, DBG_IALR_IS, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_boot_environment * Description: determine if target is an alternative, inactive boot environment * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure * IMPLEMENTATION: * - must not be initial installation to the install root * - must not be installation of a zone * - must not be a diskless client * - must not be a netinstall image * - must not be a mounted miniroot * - $ROOTDIR must not be "/" * - $ROOTDIR/etc/lutab must exist * - $ROOTDIR/etc/lu must exist and must be a directory */ static int cmd_is_boot_environment(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int r; static char *cmdName = "is_boot_environment"; static int recursion = 0; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* prevent recursion */ if (recursionCheck(&recursion, cmdName) == B_FALSE) { /* * a boot environment cannot be any of the following */ /* cannot be a diskless client */ r = cmd_is_diskless_client(argc, argv, a_gdt); /* cannot be a netinstall_image */ if (r != R_SUCCESS) { r = cmd_is_netinstall_image(argc, argv, a_gdt); } /* cannot be a mounted_miniroot */ if (r != R_SUCCESS) { r = cmd_is_mounted_miniroot(argc, argv, a_gdt); } /* no need to guard against recursion any more */ recursion--; /* return failure if any of the preceeding are true */ switch (r) { case R_SUCCESS: return (R_FAILURE); case R_FAILURE: break; case R_USAGE: case R_ERROR: default: return (r); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* root path must not be "/" */ if (strcmp(rootPath, "/") == 0) { log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ROOTPATH, rootPath, "/"); return (R_FAILURE); } /* zone name must be global */ if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) { log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ZONE, rootPath, GLOBAL_ZONENAME); return (R_FAILURE); } /* $ROOTDIR/etc/lutab must exist */ r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/lutab"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLUTAB, rootPath, "/etc/lutab"); return (R_FAILURE); } /* $ROOTDIR/etc/lu must exist */ r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY, "%s/%s", rootPath, "/etc/lu"); if (r != R_SUCCESS) { log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLU, rootPath, "/etc/lu"); return (R_FAILURE); } /* must not be initial installation */ if ((a_gdt->gd_initialInstall == B_TRUE) && (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) { log_msg(LOG_MSG_DEBUG, DBG_BENV_INITIAL_INSTALL, rootPath); return (R_FAILURE); } /* must not be installation of a zone */ if ((a_gdt->gd_globalZoneInstall == B_TRUE) || (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) { /* initial zone install: no path can be boot environment */ log_msg(LOG_MSG_DEBUG, DBG_BENV_ZONE_INSTALL, rootPath); return (R_FAILURE); } /* target is a boot environment */ log_msg(LOG_MSG_DEBUG, DBG_BENV_IS, rootPath); return (R_SUCCESS); } /* * Name: cmd_is_what * Description: determine what the target is * Scope: public * Arguments: argc,argv: * - optional path to target to test * Returns: int * == 0 - success * != 0 - failure */ static int cmd_is_what(int argc, char **argv, GLOBALDATA_T *a_gdt) { char *rootPath = NULL; int c; int cur_cmd; int r; static char *cmdName = "is_what"; /* process any command line options */ while ((c = getopt(argc, argv, ":")) != EOF) { switch (c) { case '\0': /* prevent end-of-loop not reached warning */ break; case '?': default: (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName); return (R_USAGE); } } /* normalize argc/argv */ argc -= optind; argv += optind; /* error if more than one argument */ if (argc > 1) { log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]); (void) usage(MSG_IS_INVALID_OPTION, argv[1]); return (R_USAGE); } /* process root path if first argument present */ if (argc == 1) { if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) { return (R_ERROR); } } /* get current root path */ r = getRootPath(&rootPath); if (r != R_SUCCESS) { return (r); } /* * construct the command line for all of the packages */ argc = 0; argv[argc++] = strdup(get_prog_name()); argv[argc++] = strdup(rootPath); /* start of command debugging information */ echoDebug(DBG_ROOTPATH_IS, rootPath); /* search for specified subcommand and execute if found */ for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { int result; /* do not recursively call this function */ if (cmds[cur_cmd].c_func == cmd_is_what) { continue; } /* call subcommand with its own argc/argv */ result = cmds[cur_cmd].c_func(argc, argv, a_gdt); /* process result code and exit */ result = adjustResults(result); log_msg(LOG_MSG_INFO, MSG_IS_WHAT_RESULT, cmds[cur_cmd].c_name, result); } return (R_SUCCESS); } /* * ***************************************************************************** * utility support functions * ***************************************************************************** */ /* * Name: getMountOption * Description: return next mount option in a string * Arguments: p - pointer to string containing mount options * Output: none * Returns: char * - pointer to next option in string "p" * Side Effects: advances input "p" and inserts \0 in place of the * option separator found. */ static char * getMountOption(char **p) { char *cp = *p; char *retstr; /* advance past all white space */ while (*cp && isspace(*cp)) cp++; /* remember start of next option */ retstr = cp; /* advance to end of string or option separator */ while (*cp && *cp != ',') cp++; /* replace separator with '\0' if not at end of string */ if (*cp) { *cp = '\0'; cp++; } /* reset caller's pointer and return pointer to option */ *p = cp; return (retstr); } /* * Name: mountOptionPresent * Description: determine if specified mount option is present in list * of mount point options * Arguments: a_mntOptions - pointer to string containing list of mount * point options to search * a_opt - pointer to string containing option to search for * Output: none * Returns: R_SUCCESS - option is present in list of mount point options * R_FAILURE - options is not present * R_ERROR - unable to determine if option is present or not */ static int mountOptionPresent(char *a_mntOptions, char *a_opt) { char tmpopts[MNT_LINE_MAX]; char *f, *opts = tmpopts; /* return false if no mount options present */ if ((a_opt == NULL) || (*a_opt == '\0')) { return (R_FAILURE); } /* return not present if no list of options to search */ if (a_mntOptions == NULL) { return (R_FAILURE); } /* return not present if list of options to search is empty */ if (*a_mntOptions == '\0') { return (R_FAILURE); } /* make local copy of option list to search */ (void) strcpy(opts, a_mntOptions); /* scan each option looking for the specified option */ f = getMountOption(&opts); for (; *f; f = getMountOption(&opts)) { /* return success if option matches target */ if (strncmp(a_opt, f, strlen(a_opt)) == 0) { return (R_SUCCESS); } } /* option not found */ return (R_FAILURE); } /* * Name: sortedInsert * Description: perform an alphabetical sorted insert into a list * Arguments: r_list - pointer to list to insert next entry into * a_listSize - pointer to current list size * a_mntPoint - mount point to insert (is sort key) * a_fsType - file system type for mount point * a_mntOptions - file syste mount options for mount point * Output: None * Returns: None */ static void sortedInsert(FSI_T **r_list, long *a_listSize, char *a_mntPoint, char *a_fsType, char *a_mntOptions) { int listSize; FSI_T *list; int n; /* entry assertions */ assert(a_listSize != (long *)NULL); assert(a_mntPoint != NULL); assert(a_fsType != NULL); assert(a_mntOptions != NULL); /* entry debugging info */ echoDebug(DBG_SINS_ENTRY, a_mntPoint, a_fsType, a_mntOptions); /* localize references to the list and list size */ listSize = *a_listSize; list = *r_list; /* * if list empty insert this entry as the first one in the list */ if (listSize == 0) { /* allocate new entry for list */ listSize++; list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1)); /* first entry is data passed to this function */ list[0].fsi_mntPoint = strdup(a_mntPoint); list[0].fsi_fsType = strdup(a_fsType); list[0].fsi_mntOptions = strdup(a_mntOptions); /* second entry is all NULL - end of entry marker */ list[1].fsi_mntPoint = NULL; list[1].fsi_fsType = NULL; list[1].fsi_mntOptions = NULL; /* restore list and list size references to caller */ *a_listSize = listSize; *r_list = list; return; } /* * list not empty - scan looking for largest match */ for (n = 0; n < listSize; n++) { int c; /* compare target with current list entry */ c = strcmp(list[n].fsi_mntPoint, a_mntPoint); if (c == 0) { char *me; long len; /* entry already in list -- merge entries */ len = strlen(list[n].fsi_mntOptions) + strlen(a_mntOptions) + 2; me = (char *)calloc(1, len); /* merge two mount options lists into one */ (void) strlcat(me, list[n].fsi_mntOptions, len); (void) strlcat(me, ",", len); (void) strlcat(me, a_mntOptions, len); /* free old list, replace with merged one */ free(list[n].fsi_mntOptions); list[n].fsi_mntOptions = me; echoDebug(DBG_SORTEDINS_SKIPPED, n, list[n].fsi_mntPoint, a_fsType, list[n].fsi_fsType, a_mntOptions, list[n].fsi_mntOptions); continue; } else if (c < 0) { /* entry before this one - skip */ continue; } /* * entry after this one - insert new entry */ /* allocate one more entry and make space for new entry */ listSize++; list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1)); (void) memmove(&(list[n+1]), &(list[n]), sizeof (FSI_T)*(listSize-n)); /* insert this entry into list */ list[n].fsi_mntPoint = strdup(a_mntPoint); list[n].fsi_fsType = strdup(a_fsType); list[n].fsi_mntOptions = strdup(a_mntOptions); /* restore list and list size references to caller */ *a_listSize = listSize; *r_list = list; return; } /* * all entries are before this one - append to end of list */ /* allocate new entry at end of list */ listSize++; list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1)); /* append this entry to the end of the list */ list[listSize-1].fsi_mntPoint = strdup(a_mntPoint); list[listSize-1].fsi_fsType = strdup(a_fsType); list[listSize-1].fsi_mntOptions = strdup(a_mntOptions); /* restore list and list size references to caller */ *a_listSize = listSize; *r_list = list; } /* * Name: calculateFileSystemConfig * Description: generate sorted list of all mounted file systems * Arguments: a_gdt - global data structure to place sorted entries into * Output: None * Returns: R_SUCCESS - successfully generated mounted file systems list * R_FAILURE - options is not present * R_ERROR - unable to determine if option is present or not */ static int calculateFileSystemConfig(GLOBALDATA_T *a_gdt) { FILE *fp; struct mnttab mntbuf; FSI_T *list; long listSize; /* entry assetions */ assert(a_gdt != (GLOBALDATA_T *)NULL); /* allocate a list that has one termination entry */ list = (FSI_T *)calloc(1, sizeof (FSI_T)); list[0].fsi_mntPoint = NULL; list[0].fsi_fsType = NULL; list[0].fsi_mntOptions = NULL; listSize = 0; /* open the mount table for reading */ fp = fopen(MNTTAB, "r"); if (fp == (FILE *)NULL) { return (R_ERROR); } /* debugging info */ echoDebug(DBG_CALCSCFG_MOUNTED); /* go through all the specials looking for the device */ while (getmntent(fp, &mntbuf) == 0) { if (mntbuf.mnt_mountp[0] == '/') { sortedInsert(&list, &listSize, strdup(mntbuf.mnt_mountp), strdup(mntbuf.mnt_fstype), strdup(mntbuf.mnt_mntopts ? mntbuf.mnt_mntopts : "")); } /* * Set flag if we are in a non-global zone and it is in * the mounted state. */ if (strcmp(mntbuf.mnt_mountp, "/a") == 0 && strcmp(mntbuf.mnt_special, "/a") == 0 && strcmp(mntbuf.mnt_fstype, "lofs") == 0) { a_gdt->inMountedState = B_TRUE; } } /* close mount table file */ (void) fclose(fp); /* store list pointers in global data structure */ a_gdt->gd_fileSystemConfig = list; a_gdt->gd_fileSystemConfigLen = listSize; return (R_SUCCESS); } /* * Name: adjustResults * Description: adjust output result code before existing * Arguments: a_result - result code to adjust * Returns: int - adjusted result code */ static int adjustResults(int a_result) { boolean_t negate = getNegateResults(); int realResult; /* adjust code as appropriate */ switch (a_result) { case R_SUCCESS: /* condition satisfied */ realResult = ((negate == B_TRUE) ? 1 : 0); break; case R_FAILURE: /* condition not satisfied */ realResult = ((negate == B_TRUE) ? 0 : 1); break; case R_USAGE: /* usage errors */ realResult = 2; break; case R_ERROR: /* condition could not be determined */ default: realResult = 3; break; } /* debugging output */ log_msg(LOG_MSG_DEBUG, DBG_ADJUST_RESULTS, a_result, negate, realResult); /* return results */ return (realResult); } /* * Name: setCmdLinePath * Description: set global command line path * Arguments: path - path to set from the command line * args - command line args * num_args - number of command line args * Returns: R_SUCCESS - root path successfully set * R_FAILURE - root path could not be set * R_ERROR - fatal error attempting to set root path */ static void setCmdLinePath(char **path, char **args, int num_args) { char rp[PATH_MAX] = { '\0' }; struct stat statbuf; if (*path != NULL) { return; } /* * If a path "pkgcond is_global_zone [path]" is provided on the * command line it must be the last argument. */ if (realpath(args[num_args - 1], rp) != NULL) { if (stat(rp, &statbuf) == 0) { /* make sure the target is a directory */ if ((statbuf.st_mode & S_IFDIR)) { *path = strdup(rp); } else { *path = NULL; } } } } /* * Name: setRootPath * Description: set global root path returned by getRootPath * Arguments: a_path - root path to set * a_mustExist - B_TRUE if path must exist (else error) * - B_FALSE if path may not exist * Returns: R_SUCCESS - root path successfully set * R_FAILURE - root path could not be set * R_ERROR - fatal error attempting to set root path */ static int setRootPath(char *a_path, char *a_envVar, boolean_t a_mustExist) { char rp[PATH_MAX] = { '\0' }; struct stat statbuf; /* if no data then issue warning and return success */ if ((a_path == NULL) || (*a_path == '\0')) { echoDebug(DBG_NO_DEFAULT_ROOT_PATH_SET); return (R_SUCCESS); } /* path present - resolve to absolute path */ if (realpath(a_path, rp) == NULL) { if (a_mustExist == B_TRUE) { /* must exist ... error */ log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID, a_path, strerror(errno)); return (R_ERROR); } else { /* may not exist - use path as specified */ (void) strcpy(rp, a_path); } } /* debugging output */ echoDebug(DBG_DEFAULT_ROOT_PATH_SET, rp, a_envVar ? a_envVar : ""); /* validate path existence if it must exist */ if (a_mustExist == B_TRUE) { /* get node status */ if (stat(rp, &statbuf) != 0) { log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID, rp, strerror(errno)); return (R_ERROR); } /* make sure the target is a directory */ if (!(statbuf.st_mode & S_IFDIR)) { log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_NOT_DIR, rp); return (R_ERROR); } } /* target exists and is a directory - set */ echoDebug(DBG_SET_ROOT_PATH_TO, rp); /* store copy of resolved root path */ _rootPath = strdup(rp); /* success! */ return (R_SUCCESS); } /* * Name: testPath * Description: determine if a path meets the specified conditions * Arguments: a_tt - conditions to test path against * a_format - format to use to generate path * arguments following a_format - as needed for a_format * Returns: R_SUCCESS - the path meets all of the specified conditions * R_FAILURE - the path does not meet all of the conditions * R_ERROR - error attempting to test path */ /*PRINTFLIKE2*/ static int testPath(TEST_TYPES a_tt, char *a_format, ...) { char *mbPath; /* copy for the path to be returned */ char bfr[1]; int r; size_t vres = 0; struct stat statbuf; va_list ap; int fd; /* entry assertions */ assert(a_format != NULL); assert(*a_format != '\0'); /* determine size of the message in bytes */ va_start(ap, a_format); vres = vsnprintf(bfr, 1, a_format, ap); va_end(ap); assert(vres > 0); /* allocate storage to hold the message */ mbPath = (char *)calloc(1, vres+2); assert(mbPath != NULL); /* generate the results of the printf conversion */ va_start(ap, a_format); vres = vsnprintf(mbPath, vres+1, a_format, ap); va_end(ap); assert(vres > 0); echoDebug(DBG_TEST_PATH, mbPath, (unsigned long)a_tt); /* * When a path given to open(2) contains symbolic links, the * open system call first resolves all symbolic links and then * opens that final "resolved" path. As a result, it is not * possible to check the result of an fstat(2) against the * file descriptor returned by open(2) for S_IFLNK (a symbolic * link) since all symbolic links are resolved before the * target is opened. * * When testing the target as being (or not being) a symbolic * link, first use lstat(2) against the target to determine * whether or not the specified target itself is (or is not) a * symbolic link. */ if (a_tt & (TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)) { /* * testing target is/is not a symbolic link; use lstat * to determine the status of the target itself rather * than what the target might finally address. */ if (lstat(mbPath, &statbuf) != 0) { echoDebug(DBG_CANNOT_LSTAT_PATH, mbPath, strerror(errno)); free(mbPath); return (R_FAILURE); } /* Is the target required to be a symbolic link? */ if (a_tt & TEST_IS_SYMBOLIC_LINK) { /* target must be a symbolic link */ if (!(statbuf.st_mode & S_IFLNK)) { /* failure: target is not a symbolic link */ echoDebug(DBG_IS_NOT_A_SYMLINK, mbPath); free(mbPath); return (R_FAILURE); } /* success: target is a symbolic link */ echoDebug(DBG_SYMLINK_IS, mbPath); } /* Is the target required to not be a symbolic link? */ if (a_tt & TEST_NOT_SYMBOLIC_LINK) { /* target must not be a symbolic link */ if (statbuf.st_mode & S_IFLNK) { /* failure: target is a symbolic link */ echoDebug(DBG_IS_A_SYMLINK, mbPath); free(mbPath); return (R_FAILURE); } /* success: target is not a symbolic link */ echoDebug(DBG_SYMLINK_NOT, mbPath); } /* * if only testing is/is not a symbolic link, then * no need to open the target: return success. */ if (!(a_tt & (~(TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)))) { free(mbPath); return (R_SUCCESS); } } /* resolve path and remove any whitespace */ r = resolvePath(&mbPath); if (r != R_SUCCESS) { echoDebug(DBG_TEST_PATH_NO_RESOLVE, mbPath); free(mbPath); if (a_tt & TEST_NOT_EXISTS) { return (R_SUCCESS); } return (r); } echoDebug(DBG_TEST_PATH_RESOLVE, mbPath); /* open the file - this is the basic existence test */ fd = open(mbPath, O_RDONLY|O_LARGEFILE, 0); /* existence test failed if file cannot be opened */ if (fd < 0) { /* * target could not be opened - if testing for non-existence, * return success, otherwise return failure */ if (a_tt & TEST_NOT_EXISTS) { echoDebug(DBG_CANNOT_ACCESS_PATH_OK, mbPath); free(mbPath); return (R_SUCCESS); } echoDebug(DBG_CANNOT_ACCESS_PATH_BUT_SHOULD, mbPath, strerror(errno)); free(mbPath); return (R_FAILURE); } /* * target successfully opened - if testing for non-existence, * return failure, otherwise continue with specified tests */ if (a_tt & TEST_NOT_EXISTS) { /* testing for non-existence: return failure */ echoDebug(DBG_TEST_EXISTS_SHOULD_NOT, mbPath); free(mbPath); (void) close(fd); return (R_FAILURE); } /* get the file status */ r = fstat(fd, &statbuf); if (r != 0) { echoDebug(DBG_PATH_DOES_NOT_EXIST, mbPath, strerror(errno)); (void) close(fd); free(mbPath); return (R_FAILURE); } /* required to be a directory? */ if (a_tt & TEST_IS_DIRECTORY) { if (!(statbuf.st_mode & S_IFDIR)) { /* is not a directory */ echoDebug(DBG_IS_NOT_A_DIRECTORY, mbPath); free(mbPath); return (R_FAILURE); } /* a directory */ echoDebug(DBG_DIRECTORY_IS, mbPath); } /* required to not be a directory? */ if (a_tt & TEST_NOT_DIRECTORY) { if (statbuf.st_mode & S_IFDIR) { /* is a directory */ echoDebug(DBG_IS_A_DIRECTORY, mbPath); free(mbPath); return (R_FAILURE); } /* not a directory */ echoDebug(DBG_DIRECTORY_NOT, mbPath); } /* required to be a file? */ if (a_tt & TEST_IS_FILE) { if (!(statbuf.st_mode & S_IFREG)) { /* is not a regular file */ echoDebug(DBG_IS_NOT_A_FILE, mbPath); free(mbPath); return (R_FAILURE); } /* a regular file */ echoDebug(DBG_FILE_IS, mbPath); } /* required to not be a file? */ if (a_tt & TEST_NOT_FILE) { if (statbuf.st_mode & S_IFREG) { /* is a regular file */ echoDebug(DBG_IS_A_FILE, mbPath); free(mbPath); return (R_FAILURE); } /* not a regular file */ echoDebug(DBG_FILE_NOT, mbPath); } /* * Find token (global) in file pointed to by mbPath. * token is only compared to first word in mbPath. */ if (a_tt & TEST_GLOBAL_TOKEN_IN_FILE) { if (!(statbuf.st_mode & S_IFREG)) { /* is not a regular file */ echoDebug(DBG_IS_NOT_A_FILE, mbPath); free(mbPath); return (R_FAILURE); } /* If global exists then we're not in a non-global zone */ if (findToken(mbPath, GLOBAL_ZONENAME) == R_SUCCESS) { echoDebug(DBG_TOKEN__EXISTS, GLOBAL_ZONENAME, mbPath); free(mbPath); return (R_FAILURE); } } (void) close(fd); /* success! */ echoDebug(DBG_TESTPATH_OK, mbPath); /* free up temp storage used to hold path to test */ free(mbPath); return (R_SUCCESS); } /* * Name: findToken * Description: Find first token in file. * Arguments: * path - file to search for token * token - string to search for * Returns: * R_SUCCESS - the token exists * R_FAILURE - the token does not exist * R_ERROR - fatal error attempting to find token */ static int findToken(char *path, char *token) { FILE *fp; char *cp; char line[MAXPATHLEN]; if (path == NULL || token == NULL) { return (R_ERROR); } if ((fp = fopen(path, "r")) == NULL) { return (R_ERROR); } while (fgets(line, sizeof (line), fp) != NULL) { for (cp = line; *cp && isspace(*cp); cp++) ; /* skip comments */ if (*cp == '#') { continue; } if (pkgstrContainsToken(cp, token, ":")) { (void) fclose(fp); return (R_SUCCESS); } } (void) fclose(fp); return (R_FAILURE); } /* * Name: resolvePath * Description: fully resolve a path to an absolute real path * Arguments: r_path - pointer to pointer to malloc()ed storage containing * the path to resolve - this path may be reallocated * as necessary to hold the fully resolved path * Output: r_path - is realloc()ed as necessary * Returns: R_SUCCESS - the path is fully resolved * R_FAILURE - the path could not be resolved * R_ERROR - fatal error attempting to resolve path */ static int resolvePath(char **r_path) { int i; char resolvedPath[MAXPATHLEN+1] = {'\0'}; size_t mbPathlen; /* length of multi-byte path */ size_t wcPathlen; /* length of wide-character path */ wchar_t *wcPath; /* wide-character version of the path */ wchar_t *wptr; /* scratch pointer */ /* entry assertions */ assert(r_path != NULL); /* return error if the path is completely empty */ if (**r_path == '\0') { return (R_FAILURE); } /* remove all leading whitespace */ removeLeadingWhitespace(r_path); /* * convert to real path: an absolute pathname that names the same file, * whose resolution does not involve ".", "..", or symbolic links. */ if (realpath(*r_path, resolvedPath) != NULL) { free(*r_path); *r_path = strdup(resolvedPath); } /* * convert the multi-byte version of the path to a * wide-character rendering, for doing our figuring. */ mbPathlen = strlen(*r_path); if ((wcPath = (wchar_t *) calloc(1, sizeof (wchar_t)*(mbPathlen+1))) == NULL) { return (R_FAILURE); } /*LINTED*/ if ((wcPathlen = mbstowcs(wcPath, *r_path, mbPathlen)) == -1) { free(wcPath); return (R_FAILURE); } /* * remove duplicate slashes first ("//../" -> "/") */ for (wptr = wcPath, i = 0; i < wcPathlen; i++) { *wptr++ = wcPath[i]; if (wcPath[i] == '/') { i++; while (wcPath[i] == '/') { i++; } i--; } } *wptr = '\0'; /* * now convert back to the multi-byte format. */ /*LINTED*/ if (wcstombs(*r_path, wcPath, mbPathlen) == -1) { free(wcPath); return (R_FAILURE); } /* at this point have a path */ /* free up temporary storage */ free(wcPath); return (R_SUCCESS); } /* * Name: removeLeadingWhitespace * Synopsis: Remove leading whitespace from string * Description: Remove all leading whitespace characters from a string * Arguments: a_str - [RO, *RW] - (char **) * Pointer to handle to string (in allocated storage) to * remove all leading whitespace from * Returns: void * The input string is modified as follows: * == NULL: * - input string was NULL * - input string is all whitespace * != NULL: * - copy of input string with leading * whitespace removed * CAUTION: The input string must be allocated space (via malloc() or * strdup()) - it must not be a static or inline character string * NOTE: The input string a_str will be freed with 'free' * if it is all whitespace, or if it contains any leading * whitespace characters * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ static void removeLeadingWhitespace(char **a_str) { char *o_str; /* entry assertions */ assert(a_str != (char **)NULL); /* if string is null, just return */ if (*a_str == NULL) { return; } o_str = *a_str; /* if string is empty, deallocate and return NULL */ if (*o_str == '\0') { /* free string */ free(*a_str); *a_str = NULL; return; } /* if first character is not a space, just return */ if (!isspace(*o_str)) { return; } /* advance past all space characters */ while ((*o_str != '\0') && (isspace(*o_str))) { o_str++; } /* if string was all space characters, deallocate and return NULL */ if (*o_str == '\0') { /* free string */ free(*a_str); *a_str = NULL; return; } /* have non-space/null byte, return dup, deallocate original */ o_str = strdup(o_str); free(*a_str); *a_str = o_str; } /* * Name: getZoneName * Description: get the name of the zone this process is running in * Arguments: r_zoneName - pointer to pointer to receive zone name * Output: r_zoneName - a pointer to malloc()ed storage containing * the zone name this process is running in is stored * in the location pointed to by r_zoneName * Returns: R_SUCCESS - the zone name is successfully returned * R_FAILURE - the zone name is not successfully returned * R_ERROR - error attempting to get the zone name */ static int getZoneName(char **r_zoneName) { static char zoneName[ZONENAME_MAX] = { '\0' }; /* if zone name not already present, retrieve and cache name */ if (zoneName[0] == '\0') { if (getzonenamebyid(getzoneid(), zoneName, sizeof (zoneName)) < 0) { log_msg(LOG_MSG_ERR, ERR_CANNOT_GET_ZONENAME); return (R_ERROR); } } /* return cached zone name */ *r_zoneName = zoneName; return (R_SUCCESS); } /* * Name: getRootPath * Description: get the root path being tested by this process * Arguments: r_rootPath - pointer to pointer to receive root path * Output: r_rootPath - a pointer to malloc()ed storage containing * the root path name this process is testing * Returns: R_SUCCESS - the root path is successfully returned * R_FAILURE - the root path is not successfully returned * R_ERROR - error attempting to get the root path */ static int getRootPath(char **r_rootPath) { *r_rootPath = _rootPath; return (R_SUCCESS); } /* * Name: setVerbose * Description: Turns on verbose output * Scope: public * Arguments: verbose = B_TRUE indicates verbose mode * Returns: none */ static void setVerbose(boolean_t setting) { /* set log verbose messages */ log_set_verbose(setting); /* set interactive messages */ echoSetFlag(setting); } /* * Name: negate_results * Description: control negation of results * Scope: public * Arguments: setting * == B_TRUE indicates negated results mode * == B_FALSE indicates non-negated results mode * Returns: none */ static void setNegateResults(boolean_t setting) { log_msg(LOG_MSG_DEBUG, DBG_SET_NEGATE_RESULTS, _negateResults, setting); _negateResults = setting; } /* * Name: getNegateResults * Description: Returns whether or not to results are negated * Scope: public * Arguments: none * Returns: B_TRUE - results are negated * B_FALSE - results are not negated */ static boolean_t getNegateResults(void) { return (_negateResults); } /* * Name: usage * Description: output usage string * Arguments: a_format - format to use to generate message * arguments following a_format - as needed for a_format * Output: Outputs the usage string to stderr. * Returns: R_ERROR */ static int usage(char *a_format, ...) { int cur_cmd; char cmdlst[LINE_MAX+1] = { '\0' }; char *message; char bfr[1]; char *p = get_prog_name(); size_t vres = 0; va_list ap; /* entry assertions */ assert(a_format != NULL); assert(*a_format != '\0'); /* determine size of the message in bytes */ va_start(ap, a_format); /* LINTED warning: variable format specifier to vsnprintf(); */ vres = vsnprintf(bfr, 1, a_format, ap); va_end(ap); assert(vres > 0); /* allocate storage to hold the message */ message = (char *)calloc(1, vres+2); assert(message != NULL); /* generate the results of the printf conversion */ va_start(ap, a_format); /* LINTED warning: variable format specifier to vsnprintf(); */ vres = vsnprintf(message, vres+1, a_format, ap); va_end(ap); assert(vres > 0); /* generate list of all defined conditions */ for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) { (void) strlcat(cmdlst, "\t", sizeof (cmdlst)); (void) strlcat(cmdlst, cmds[cur_cmd].c_name, sizeof (cmdlst)); if (cmds[cur_cmd].c_args != NULL) { (void) strlcat(cmdlst, cmds[cur_cmd].c_args, sizeof (cmdlst)); } (void) strlcat(cmdlst, "\n", sizeof (cmdlst)); } /* output usage with conditions */ log_msg(LOG_MSG_INFO, MSG_USAGE, message, p ? p : "pkgcond", cmdlst); return (R_ERROR); } /* * Name: parseGlobalData * Description: parse environment global data and store in global data structure * Arguments: a_envVar - pointer to string representing the name of the * environment variable to get and parse * r_gdt - pointer to pointer to global data structure to fill in * using the parsed data from a_envVar * Output: none * Returns: R_SUCCESS - the global data is successfully parsed * R_FAILURE - problem parsing global data * R_ERROR - fatal error attempting to parse global data */ static int parseGlobalData(char *a_envVar, GLOBALDATA_T **r_gdt) { int r; char *a; SML_TAG *tag; SML_TAG *ntag; assert(r_gdt != (GLOBALDATA_T **)NULL); /* * allocate space for global data structure if needed */ if (*r_gdt == (GLOBALDATA_T *)NULL) { *r_gdt = (GLOBALDATA_T *)calloc(1, sizeof (GLOBALDATA_T)); } /* * get initial installation indication: * If the initial install variable is set to "true", then an initial * installation of Solaris is underway. When this condition is true: * - if the path being checked is the package install root, then * the path is considered to be an 'alternative root' which is * currently being installed. * - if the path being checked is not the package install root, then * the path needs to be further analyzed to determine what it may * be referring to. */ a = getenv(ENV_VAR_INITIAL_INSTALL); if ((a != NULL) && (strcasecmp(a, "true") == 0)) { (*r_gdt)->gd_initialInstall = B_TRUE; } /* get current zone name */ r = getZoneName(&(*r_gdt)->gd_zoneName); if (r != R_SUCCESS) { (*r_gdt)->gd_zoneName = ""; } /* * get zone installation status: * - If the package install zone name is not set, then an installation * of a global zone, or of a non-global zone, is not underway. * - If the package install zone name is set to "global", then an * installation of a global zone is underway. In this case, no path * can be a netinstall image, diskless client, mounted miniroot, * non-global zone, the current running system, alternative root, * or alternative boot environment. * - If the package install zone name is set to a value other than * "global", then an installation of a non-global zone with that name * is underway. In this case, no path can be a netinstall image, * diskless client, mounted miniroot, global zone, the current * running system, alternative root, or alternative boot environment. */ a = getenv(ENV_VAR_PKGZONENAME); if ((a == NULL) || (*a == '\0')) { /* not installing a zone */ (*r_gdt)->gd_globalZoneInstall = B_FALSE; (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE; } else if (strcmp(a, GLOBAL_ZONENAME) == 0) { /* installing a global zone */ (*r_gdt)->gd_globalZoneInstall = B_TRUE; (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE; (*r_gdt)->gd_zoneName = a; } else { /* installing a non-global zone by that name */ (*r_gdt)->gd_globalZoneInstall = B_FALSE; (*r_gdt)->gd_nonglobalZoneInstall = B_TRUE; (*r_gdt)->gd_zoneName = a; } /* * get package install root. */ a = getenv(ENV_VAR_PKGROOT); if ((a != NULL) && (*a != '\0')) { (*r_gdt)->gd_installRoot = a; } else { (*r_gdt)->gd_installRoot = "/"; } /* get the global data environment variable */ a = getenv(a_envVar); /* if no data then issue warning and return success */ if ((a == NULL) || (*a_envVar == '\0')) { log_msg(LOG_MSG_DEBUG, DBG_NO_GLOBAL_DATA_AVAILABLE, a_envVar); return (R_SUCCESS); } /* data present - parse into SML structure */ log_msg(LOG_MSG_DEBUG, DBG_PARSE_GLOBAL, a); r = smlConvertStringToTag(&tag, a); if (r != R_SUCCESS) { log_msg(LOG_MSG_ERR, ERR_CANNOT_PARSE_GLOBAL_DATA, a); return (R_FAILURE); } smlDbgPrintTag(tag, DBG_PARSED_ENVIRONMENT, a_envVar); /* fill in global data structure */ /* find the environment condition information structure */ ntag = smlGetTagByName(tag, 0, TAG_COND_TOPLEVEL); if (ntag == SML_TAG__NULL) { log_msg(LOG_MSG_WRN, WRN_PARSED_DATA_MISSING, TAG_COND_TOPLEVEL); return (R_FAILURE); } /* * data found - extract what we know about */ /* parent zone name */ a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_NAME); (*r_gdt)->gd_parentZoneName = a; /* parent zone type */ a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_TYPE); (*r_gdt)->gd_parentZoneType = a; /* current zone name */ a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE, TAG_COND_ZONE_NAME); (*r_gdt)->gd_currentZoneName = a; /* current zone type */ a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE, TAG_COND_ZONE_TYPE); (*r_gdt)->gd_currentZoneType = a; return (R_SUCCESS); } /* * Name: dumpGlobalData * Description: dump global data structure using echoDebug * Arguments: a_gdt - pointer to global data structure to dump * Outputs: echoDebug is called to output global data strucutre information * Returns: void */ static void dumpGlobalData(GLOBALDATA_T *a_gdt) { /* entry assertions */ assert(a_gdt != (GLOBALDATA_T *)NULL); /* debugging enabled, dump the global data structure */ echoDebug(DBG_DUMP_GLOBAL_ENTRY); echoDebug(DBG_DUMP_GLOBAL_PARENT_ZONE, a_gdt->gd_parentZoneName ? a_gdt->gd_parentZoneName : "", a_gdt->gd_parentZoneType ? a_gdt->gd_parentZoneType : ""); echoDebug(DBG_DUMP_GLOBAL_CURRENT_ZONE, a_gdt->gd_currentZoneName ? a_gdt->gd_currentZoneName : "", a_gdt->gd_currentZoneType ? a_gdt->gd_currentZoneType : ""); } /* * Name: recursionCheck * Description: prevent recursive calling of functions * Arguments: r_recursion - pointer to int recursion counter * a_function - pointer to name of function * Returns: B_TRUE - function is recursively called * B_FALSE - function not recursively called */ static boolean_t recursionCheck(int *r_recursion, char *a_function) { /* prevent recursion */ (*r_recursion)++; if (*r_recursion > 1) { echoDebug(DBG_RECURSION, a_function, *r_recursion); (*r_recursion)--; return (B_TRUE); } echoDebug(DBG_NO_RECURSION, a_function); return (B_FALSE); } /* * Name: quit * Description: cleanup and exit * Arguments: a_retcode - the code to use to determine final exit status; * if this is NOT "99" and if a "ckreturnFunc" is * set, then that function is called with a_retcode * to set the final exit status. * Valid values are: * 0 - success * 1 - package operation failed (fatal error) * 2 - non-fatal error (warning) * 3 - user selected quit (operation interrupted) * 4 - admin settings prevented operation * 5 - interaction required and -n (non-interactive) specified * "10" is added to indicate "immediate reboot required" * "20" is be added to indicate "reboot after install required" * 99 - do not interpret the code - just exit "99" * Returns: <> * NOTE: This is needed because libinst functions can call "quit(99)" * to force an error exit. */ void quit(int a_retcode) { /* process return code if not quit(99) */ if (a_retcode == 99) { exit(0x7f); /* processing error (127) */ } exit(R_FAILURE); }