/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * System includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * libinstzones includes */ #include /* * consolidation pkg command library includes */ #include /* * local pkg command library includes */ #include "install.h" #include "libinst.h" #include "libadm.h" #include "messages.h" /* * pkgrm local includes */ #include "quit.h" /* * exported global variables */ /* these globals are set by ckreturn and used by quit.c */ int admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */ int doreboot = 0; /* != 0 if reboot required after installation */ int failflag = 0; /* != 0 if fatal error has occurred (1) */ int intrflag = 0; /* != 0 if user selected quit (3) */ int ireboot = 0; /* != 0 if immediate reboot required */ int nullflag = 0; /* != 0 if admin interaction required (5) */ int warnflag = 0; /* != 0 if non-fatal error has occurred (2) */ /* imported by quit.c */ int npkgs = 0; /* the number of packages yet to be installed */ /* imported by presvr4.c */ int started = 0; char *tmpdir = NULL; /* location to place temporary files */ /* imported by various (many) */ struct admin adm; /* holds info about installation admin */ struct pkgdev pkgdev; /* holds info about the installation device */ /* * internal global variables */ static char *admnfile = NULL; /* file to use for installation admin */ static char *pkginst = NULL; /* current pkg/src instance 2 process */ static char *vfstab_file = NULL; static char *zoneTempDir = (char *)NULL; /* set by ckreturn() */ static int interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */ static int nointeract = 0; /* non-zero - no user interaction */ static int pkgrmremote = 0; /* remove pkg objs stored remotely */ static int pkgverbose = 0; /* non-zero if verbose mode selected */ /* * Assume the package complies with the standards as regards user * interaction during procedure scripts. */ static int old_pkg = 0; static int old_symlinks = 0; static int no_map_client = 0; /* Set by -O nozones: do not process any zones */ static boolean_t noZones = B_FALSE; /* Set by -O zonelist=: process only named zones */ static boolean_t usedZoneList = B_FALSE; /* Set by -O debug: debug output is enabled? */ static boolean_t debugFlag = B_FALSE; /* * imported (external) functions */ /* presvr4.c */ extern int presvr4(char *pkg, int a_nointeract); /* check.c */ extern int preremove_verify(char **a_pkgList, zoneList_t a_zlst, char *a_zoneTempDir); /* quit.c */ extern void quitSetZonelist(zoneList_t a_zlst); /* * imported (external) variables */ extern char *pkgdir; /* printable string - if string is null results in ??? */ #define PSTR(STR) (((STR) == (char *)NULL) ? "???" : (STR)) #define MAX_FDS 20 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" #endif #define INHERITFS "inherited-filesystem=" #define INHERITFS_LEN ((sizeof (INHERITFS))-1) /* * forward declarations */ static void ckreturn(int retcode); static void create_zone_adminfile(char **r_zoneAdminFile, char *a_zoneTempDir, char *a_admnfile); static void create_zone_tempdir(char **r_zoneTempDir, char *a_tmpdir); static int doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile, char *a_zoneAdminFile, zoneList_t zlst); static int pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile, char **a_inheritedPkgDirs); static int pkgZoneCheckRemove(char *a_zoneName, char **a_inheritedPkgDirs, char *a_altBinDir, char *a_adminFile, char *a_stdoutPath, zone_state_t a_zoneState); static int pkgZoneRemove(char *a_zoneName, char **a_inheritedPkgDirs, int a_nodelete, char *a_altBinDir, char *a_adminFile, zone_state_t a_zoneState); static void resetreturn(); static void usage(void); static boolean_t check_applicability(char *a_packageDir, char *a_pkgInst, char *a_rootPath, CAF_T a_flags); static boolean_t check_packages(char **a_pkgList, char *a_packageDir); static boolean_t path_valid(char *path); static boolean_t remove_packages(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir, char *a_spoolDir, boolean_t a_noZones); static boolean_t remove_packages_from_spool_directory(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir); static boolean_t remove_packages_in_global_no_zones(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir); static boolean_t remove_packages_in_global_with_zones(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir, zoneList_t a_zlst); static boolean_t remove_packages_in_nonglobal_zone(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir); static boolean_t shall_we_continue(char *a_pkgInst, int a_npkgs); /* * ***************************************************************************** * global external (public) functions * ***************************************************************************** */ /* * Name: main * Description: main entry point for pkgrm * Returns: int * 0 Successful completion * 1 Fatal error. * 2 Warning. * 3 Interruption. * 4 Administration. * 5 Administration. Interaction is required. Do not use pkgrm -n. * 10 Reboot after removal of all packages. * 20 Reboot after removal of this package. */ int main(int argc, char **argv) { char **category = NULL; char *altBinDir = (char *)NULL; char *catg_arg = NULL; char *p; char *prog_full_name = NULL; char *spoolDir = 0; int c; int longestPkg = 0; int n; int nodelete = 0; /* dont rm files/run scripts */ int pkgLgth = 0; int repeat; struct sigaction nact; struct sigaction oact; /* initialize locale environment */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* initialize program name */ prog_full_name = argv[0]; (void) set_prog_name(argv[0]); /* tell spmi zones interface how to access package output functions */ z_set_output_functions(echo, echoDebug, progerr); /* tell quit which ckreturn function to call */ quitSetCkreturnFunc(&ckreturn); /* Read PKG_INSTALL_ROOT from the environment, if it's there. */ if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { progerr(ERR_ROOT_SET); exit(1); } if (z_running_in_global_zone() && !enable_local_fs()) { progerr(ERR_CANNOT_ENABLE_LOCAL_FS); } /* * ******************************************************************** * parse command line options * ******************************************************************** */ while ((c = getopt(argc, argv, "?Aa:b:FMnO:R:s:V:vY:Z")) != EOF) { switch (c) { /* * Public interface: Allow admin to remove objects * from a service area via a reference client. * Remove the package files from the client's file * system, absolutely. If a file is shared with other * packages, the default behavior is to not remove * the file from the client's file system. */ case 'A': pkgrmremote++; break; /* * Public interface: Use the installation * administration file, admin, in place of the * default admin file. pkgrm first looks in the * current working directory for the administration * file. If the specified administration file is not * in the current working directory, pkgrm looks in * the /var/sadm/install/admin directory for the * administra- tion file. */ case 'a': admnfile = flex_device(optarg, 0); break; /* * Not a public interface: location where package executables * can be found - default is /usr/sadm/install/bin. */ case 'b': if (!path_valid(optarg)) { progerr(ERR_PATH, optarg); quit(1); } if (isdir(optarg) != 0) { p = strerror(errno); progerr(ERR_CANNOT_USE_DIR, optarg, p); quit(1); } altBinDir = optarg; break; /* * Not a public interface: pass -F option to * pkgremove which suppresses the removal of any * files and any class action scripts, and suppresses * the running of any class action scripts. The * package files remain but the package looks like it * is not installed. This is mainly for use by the * upgrade process. */ case 'F': nodelete++; break; /* * Public interface: Instruct pkgrm not to use the * $root_path/etc/vfstab file for determining the * client's mount points. This option assumes the * mount points are correct on the server and it * behaves consistently with Solaris 2.5 and earlier * releases. */ case 'M': no_map_client = 1; break; /* * Public interface: package removal occurs in * non-interactive mode. Suppress output of the list of * removed files. The default mode is interactive. */ case 'n': nointeract++; (void) echoSetFlag(B_FALSE); break; /* * Not a public interface: the -O option allows the behavior * of the package tools to be modified. Recognized options: * -> debug * ---> enable debugging output * -> nozones * ---> act as though in global zone with no non-global zones * -> inherited-filesystems * ---> add specified file system to list of file systems * ---> that are inherited from the global zone * -> enable-hollow-package-support * --> Enable hollow package support. When specified, for any * --> package that has SUNW_PKG_HOLLOW=true: * --> Do not calculate and verify package size against target * --> Do not run any package procedure or class action scripts * --> Do not create or remove any target directories * --> Do not perform any script locking * --> Do not install or uninstall any components of any package * --> Do not output any status or database update messages * -> zonelist="" * ---> add package to space-separated list of zones only */ case 'O': for (p = strtok(optarg, ","); p != (char *)NULL; p = strtok(NULL, ",")) { if (strcmp(p, "nozones") == 0) { noZones = B_TRUE; continue; } if (strncmp(p, INHERITFS, INHERITFS_LEN) == 0) { if (z_add_inherited_file_system( p+INHERITFS_LEN) == B_FALSE) { progerr(ERR_NOSUCH_INHERITED, p+INHERITFS_LEN); quit(1); /* NOTREACHED */ } continue; } if (strcmp(p, "enable-hollow-package-support") == 0) { set_depend_pkginfo_DB(B_TRUE); continue; } if (strcmp(p, "debug") == 0) { /* set debug flag/enable debug output */ debugFlag = B_TRUE; (void) echoDebugSetFlag(debugFlag); /* debug info on arguments to pkgadd */ for (n = 0; n < argc && argv[n]; n++) { echoDebug(DBG_ARG, n, argv[n]); } continue; } if (strncmp(p, "zonelist=", 9) == 0) { if (z_set_zone_spec(p + 9) == -1) quit(1); usedZoneList = B_TRUE; continue; } /* -O option not recognized - issue warning */ progerr(ERR_INVALID_O_OPTION, p); continue; } break; /* * Public interface: defines the full path name of a * directory to use as the root_path. All files, * including package system information files, are * relocated to a directory tree starting in the * specified root_path. */ case 'R': if (!set_inst_root(optarg)) { progerr(ERR_ROOT_CMD); exit(1); } break; /* * Public interface: remove the specified package(s) * from the directory spool. The default directory * for spooled packages is /var/sadm/pkg. */ case 's': spoolDir = flex_device(optarg, 1); break; /* * Public interface: Allow admin to establish the client * filesystem using a vfstab-like file of stable format. */ case 'V': vfstab_file = flex_device(optarg, 2); no_map_client = 0; break; /* * Public interface: trace all of the scripts that * get executed by pkgrm, located in the * pkginst/install directory. This option is used for * debugging the procedural and non- procedural * scripts. */ case 'v': pkgverbose++; break; /* * Public interface: remove packages based on the * CATEGORY variable from the installed/spooled * pkginfo file */ case 'Y': catg_arg = strdup(optarg); if ((category = get_categories(catg_arg)) == NULL) { progerr(ERR_CAT_INV, catg_arg); exit(1); } else if (is_not_valid_category(category, get_prog_name())) { progerr(ERR_CAT_SYS); exit(1); } else if (is_not_valid_length(category)) { progerr(ERR_CAT_LNGTH); exit(1); } break; /* * unrecognized option */ default: usage(); /* NOTREACHED */ } } /* * ******************************************************************** * validate command line options * ******************************************************************** */ /* set "debug echo" flag according to setting of "-O debug" option */ (void) echoDebugSetFlag(debugFlag); /* output entry debugging information */ if (z_running_in_global_zone()) { echoDebug(DBG_ENTRY_IN_GZ, prog_full_name); } else { echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(), z_get_zonename()); } /* -s cannot be used with several */ if (spoolDir != (char *)NULL) { if (admnfile != (char *)NULL) { progerr(ERR_SPOOLDIR_AND_ADMNFILE); usage(); /* NOTREACHED */ } if (pkgrmremote != 0) { progerr(ERR_SPOOLDIR_AND_PKGRMREMOTE); usage(); /* NOTREACHED */ } if (pkgverbose != 0) { progerr(ERR_SPOOLDIR_AND_PKGVERBOSE); usage(); /* NOTREACHED */ } if (is_an_inst_root() != 0) { progerr(ERR_SPOOLDIR_AND_INST_ROOT); usage(); /* NOTREACHED */ } } /* -V cannot be used with -A */ if (no_map_client && pkgrmremote) { progerr(ERR_V_USED_AND_PKGRMREMOTE); usage(); /* NOTREACHED */ } /* -n used without pkg names or category */ if (nointeract && (optind == argc) && (catg_arg == NULL)) { progerr(ERR_BAD_N_PKGRM); usage(); /* NOTREACHED */ } /* Error if specified zone list isn't valid on target */ if (usedZoneList && z_verify_zone_spec() == -1) usage(); /* * hook SIGINT and SIGHUP interrupts into quit.c's trap handler */ /* hold SIGINT/SIGHUP interrupts */ (void) sighold(SIGHUP); (void) sighold(SIGINT); /* connect quit.c:trap() to SIGINT */ nact.sa_handler = quitGetTrapHandler(); nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGINT, &nact, &oact); /* connect quit.c:trap() to SIGHUP */ nact.sa_handler = quitGetTrapHandler(); nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGHUP, &nact, &oact); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); /* establish temporary directory to use */ tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) { tmpdir = P_tmpdir; } echoDebug(DBG_PKGRM_TMPDIR, tmpdir); /* initialize path parameters */ set_PKGpaths(get_inst_root()); /* * initialize installation admin parameters - if removing from a spool * directory then the admin file is ignore. */ if (spoolDir == NULL) { echoDebug(DBG_PKGRM_ADMINFILE, admnfile ? admnfile : ""); setadminFile(admnfile); } /* * if running in the global zone, and non-global zones exist, then * enable hollow package support so that any packages that are marked * SUNW_PKG_HOLLOW=true will be correctly removed in non-global zones * when removed directly in the global zone by the global zone admin. */ if (is_depend_pkginfo_DB()) { echoDebug(DBG_PKGRM_HOLLOW_ENABLED); } else if ((z_running_in_global_zone() == B_TRUE) && (z_non_global_zones_exist() == B_TRUE)) { echoDebug(DBG_PKGRM_ENABLING_HOLLOW); set_depend_pkginfo_DB(B_TRUE); } /* * See if user wants this to be handled as an old style pkg. * NOTE : the ``exception_pkg()'' stuff is to be used only * through on495. This function comes out for on1095. See * PSARC 1993-546. -- JST */ if (getenv("NONABI_SCRIPTS") != NULL) { old_pkg = 1; } /* * See if the user wants to process symlinks consistent with * the old behavior. */ if (getenv("PKG_NONABI_SYMLINKS") != NULL) { old_symlinks = 1; } if (devtype((spoolDir ? spoolDir : get_PKGLOC()), &pkgdev) || pkgdev.dirname == NULL) { progerr(ERR_BAD_DEVICE, spoolDir ? spoolDir : get_PKGLOC()); quit(1); /* NOTREACHED */ } pkgdir = pkgdev.dirname; repeat = ((optind >= argc) && pkgdev.mount); /* * error if there are packages on the command line and a category * was specified */ if (optind < argc && catg_arg != NULL) { progerr(ERR_PKGS_AND_CAT_PKGRM); usage(); /* NOTREACHED */ } /* * ******************************************************************** * main package processing "loop" * ******************************************************************** */ for (;;) { boolean_t b; char **pkglist; /* points to array of pkgs */ /* * mount the spool device if required */ if (pkgdev.mount) { if (n = pkgmount(&pkgdev, NULL, 0, 0, 1)) { quit(n); /* NOTREACHED */ } } if (chdir(pkgdev.dirname)) { progerr(ERR_CHDIR, pkgdev.dirname); quit(1); /* NOTREACHED */ } /* * spool device mounted/available - get the list of the * packages to remove */ n = pkgGetPackageList(&pkglist, argv, optind, catg_arg, category, &pkgdev); switch (n) { case -1: /* no packages found */ echoDebug(DBG_PKGLIST_RM_NONFOUND, PSTR(pkgdev.dirname)); progerr(ERR_NOPKGS, pkgdev.dirname); quit(1); /* NOTREACHED */ case 0: /* packages found */ break; default: /* "quit" error */ echoDebug(DBG_PKGLIST_RM_ERROR, pkgdev.dirname, n); quit(n); /* NOTREACHED */ } /* * count the number of packages to remove * NOTE: npkgs is a global variable that is referenced by quit.c * when error messages are generated - it is referenced directly * by the other functions called below... */ for (npkgs = 0; pkglist[npkgs] != (char *)NULL; /* void */) { pkgLgth = strlen(pkglist[npkgs]); if (pkgLgth > longestPkg) { longestPkg = pkgLgth; } echoDebug(DBG_PKG_SELECTED, npkgs, pkglist[npkgs]); npkgs++; } /* output number of packages to be removed */ echoDebug(DBG_NUM_PKGS_TO_REMOVE, npkgs, longestPkg); /* * package list generated - remove packages */ b = remove_packages(pkglist, nodelete, longestPkg, repeat, altBinDir, pkgdev.dirname, spoolDir, noZones); /* * unmount the spool directory if necessary */ if (pkgdev.mount) { (void) chdir("/"); if (pkgumount(&pkgdev)) { progerr(ERR_PKGUNMOUNT, pkgdev.bdevice); quit(99); /* NOTREACHED */ } } /* * continue with next sequence of packages if continue set */ if (b == B_TRUE) { continue; } /* * not continuing - quit with 0 exit code */ quit(0); /* NOTREACHED */ #ifdef lint return (0); #endif /* lint */ } } /* * ***************************************************************************** * static internal (private) functions * ***************************************************************************** */ /* * Name: doRemove * Description: Remove a package from the global zone, and optionally from one * or more non-global zones. * Arguments: a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_adminFile - pointer to string representing the admin * file to pass to pkgremove when removing a package from * the global zone only. Typically the admin file used for * the global zone is the admin file passed in by the user. * If this is == NULL no admin file is given to pkgremove. * a_zoneAdminFile - pointer to string representing the admin * file to pass to pkgremove when removing the package * from a non-global zone only. Typically the admin file * used for non-global zones supresses all checks since * the dependency checking is done for all zones first * before proceeding. * A zoneAdminFile MUST be specified if a_zlst != NULL. * A zoneAdminFile must NOT be specified if a_zlst == NULL. * a_zlst - list of zones to process; NULL if no zones to process. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static int doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile, char *a_zoneAdminFile, zoneList_t a_zlst) { boolean_t b; char **inheritedPkgDirs; char *zoneName; char ans[MAX_INPUT]; int n; int zoneIndex; int zonesSkipped; struct pkginfo *pinfo = (struct pkginfo *)NULL; zone_state_t zst; /* entry assertions */ if (a_zlst != (zoneList_t)NULL) { /* zone list specified - zone admin file required */ assert(a_zoneAdminFile != (char *)NULL); assert(*a_zoneAdminFile != '\0'); } else { /* no zone list specified - no zone admin file needed */ assert(a_zoneAdminFile == (char *)NULL); } /* NOTE: required 'pkgdir' set to spool directory or NULL */ b = pkginfoIsPkgInstalled(&pinfo, pkginst); if (b == B_FALSE) { progerr(ERR_NO_SUCH_INSTANCE, pkginst); pkginfoFree(&pinfo); return (2); } /* entry debugging info */ echoDebug(DBG_DOREMOVE_ENTRY); echoDebug(DBG_DOREMOVE_ARGS, PSTR(pinfo->pkginst), PSTR(pinfo->name), PSTR(pinfo->arch), PSTR(pinfo->version), PSTR(pinfo->basedir), PSTR(pinfo->catg), pinfo->status); if (!nointeract) { char fmt1[100]; /* create format based on max pkg name length */ (void) snprintf(fmt1, sizeof (fmt1), " %%-%d.%ds %%s", a_longestPkg, a_longestPkg); if (pinfo->status == PI_SPOOLED) { echo(INFO_SPOOLED); } else { if (getuid()) { progerr(ERR_NOT_ROOT, get_prog_name()); exit(1); } echo(INFO_INSTALL); } echo(fmt1, pinfo->pkginst, pinfo->name); if (pinfo->arch || pinfo->version) { char fmt2[100]; /* create format based on max pkg name length */ (void) snprintf(fmt2, sizeof (fmt2), " %%%d.%ds ", a_longestPkg, a_longestPkg); /* LINTED variable format specifier to fprintf() */ (void) fprintf(stderr, fmt2, ""); if (pinfo->arch) { (void) fprintf(stderr, "(%s) ", pinfo->arch); } if (pinfo->version) { (void) fprintf(stderr, "%s", pinfo->version); } (void) fprintf(stderr, "\n"); } n = ckyorn(ans, NULL, NULL, NULL, ASK_CONFIRM); if (n != 0) { quit(n); /* NOTREACHED */ } if (strchr("yY", *ans) == NULL) { pkginfoFree(&pinfo); return (0); } } if (pinfo->status == PI_PRESVR4) { pkginfoFree(&pinfo); return (presvr4(pkginst, nointeract)); } if (pinfo->status == PI_SPOOLED) { /* removal from a directory */ echo(INFO_RMSPOOL, pkginst); pkginfoFree(&pinfo); return (rrmdir(pkginst)); } /* exit if not root */ if (getuid()) { progerr(ERR_NOT_ROOT, get_prog_name()); exit(1); } pkginfoFree(&pinfo); zonesSkipped = 0; if (interrupted != 0) { echo(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst); echoDebug(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst); return (n); } echoDebug(DBG_REMOVE_FLAG_VALUES, "before pkgZoneRemove", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); for (zoneIndex = 0; a_zlst != NULL && (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != NULL; zoneIndex++) { /* skip the zone if it is NOT running */ zst = z_zlist_get_current_state(a_zlst, zoneIndex); if (zst != ZONE_STATE_RUNNING && zst != ZONE_STATE_MOUNTED) { zonesSkipped++; echoDebug(DBG_SKIPPING_ZONE, zoneName); continue; } echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName); echoDebug(DBG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName); /* determine list of directories inherited from global zone */ inheritedPkgDirs = z_zlist_get_inherited_pkg_dirs(a_zlst, zoneIndex); /* * remove package from zone; use the zone admin file which * suppresses all checks. */ n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex), inheritedPkgDirs, a_nodelete, a_altBinDir, a_zoneAdminFile, zst); /* set success/fail condition variables */ ckreturn(n); echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); } if (zonesSkipped > 0) { echoDebug(DBG_ZONES_SKIPPED, zonesSkipped); for (zoneIndex = 0; (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != (char *)NULL; zoneIndex++) { /* skip the zone if it IS running */ zst = z_zlist_get_current_state(a_zlst, zoneIndex); if (zst == ZONE_STATE_RUNNING || zst == ZONE_STATE_MOUNTED) { zonesSkipped++; echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName); continue; } /* skip the zone if it is NOT bootable */ if (z_zlist_is_zone_runnable(a_zlst, zoneIndex) == B_FALSE) { echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName); echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName); continue; } /* mount up the zone */ echo(MSG_BOOTING_ZONE, zoneName); echoDebug(DBG_BOOTING_ZONE, zoneName); b = z_zlist_change_zone_state(a_zlst, zoneIndex, ZONE_STATE_MOUNTED); if (b == B_FALSE) { progerr(ERR_CANNOT_BOOT_ZONE, zoneName); /* set fatal error return condition */ ckreturn(1); continue; } echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName); /* determine list of dirs inherited from global zone */ inheritedPkgDirs = z_zlist_get_inherited_pkg_dirs(a_zlst, zoneIndex); /* * remove package from zone; use the zone admin file * which suppresses all checks. */ n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex), inheritedPkgDirs, a_nodelete, a_altBinDir, a_zoneAdminFile, ZONE_STATE_MOUNTED); /* set success/fail condition variables */ ckreturn(n); echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); /* restore original state of zone */ echo(MSG_RESTORE_ZONE_STATE, zoneName); echoDebug(DBG_RESTORE_ZONE_STATE, zoneName); b = z_zlist_restore_zone_state(a_zlst, zoneIndex); } } /* * Process global zone if it was either the only possible * target (no list of zones specified) or it appears in the list */ if (a_zlst == NULL || z_on_zone_spec(GLOBAL_ZONENAME)) { /* reset interrupted flag before calling pkgremove */ interrupted = 0; /* last action was NOT quit */ /* * call pkgremove for this package for the global zone; * use the admin file passed in by the user via -a. */ n = pkgRemove(a_nodelete, a_altBinDir, a_adminFile, z_get_inherited_file_systems()); /* set success/fail condition variables */ ckreturn(n); } return (n); } /* * function to clear out any exisiting error return conditions that may have * been set by previous calls to ckreturn() */ static void resetreturn() { admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */ doreboot = 0; /* != 0 if reboot required after installation (>= 10) */ failflag = 0; /* != 0 if fatal error has occurred (1) */ intrflag = 0; /* != 0 if user selected quit (3) */ ireboot = 0; /* != 0 if immediate reboot required (>= 20) */ nullflag = 0; /* != 0 if admin interaction required (5) */ warnflag = 0; /* != 0 if non-fatal error has occurred (2) */ interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */ } /* * function which checks the indicated return value * and indicates disposition of installation */ static void ckreturn(int retcode) { /* * entry debugging info */ echoDebug(DBG_PKGRM_CKRETURN, retcode, PSTR(pkginst)); switch (retcode) { case 0: /* successful */ case 10: case 20: break; /* empty case */ case 1: /* package operation failed (fatal error) */ case 11: case 21: failflag++; interrupted++; break; case 2: /* non-fatal error (warning) */ case 12: case 22: warnflag++; interrupted++; break; case 3: /* user selected quit; operation interrupted */ case 13: case 23: intrflag++; interrupted++; break; case 4: /* admin settings prevented operation */ case 14: case 24: admnflag++; interrupted++; break; case 5: /* administration: interaction req (no -n) */ case 15: case 25: nullflag++; interrupted++; break; default: failflag++; interrupted++; return; } if (retcode >= 20) { ireboot++; } else if (retcode >= 10) { doreboot++; } } static int pkgZoneCheckRemove(char *a_zoneName, char **a_inheritedPkgDirs, char *a_altBinDir, char *a_adminFile, char *a_stdoutPath, zone_state_t a_zoneState) { char *arg[MAXARGS]; char *p; char adminfd_path[PATH_MAX]; char path[PATH_MAX]; int fds[MAX_FDS]; int maxfds; int n; int nargs; /* entry assertions */ assert(a_zoneName != (char *)NULL); assert(*a_zoneName != '\0'); /* entry debugging info */ echoDebug(DBG_PKGZONECHECKREMOVE_ENTRY); echoDebug(DBG_PKGZONECHECKREMOVE_ARGS, a_zoneName, PSTR(pkginst), PSTR(pkgdev.dirname), PSTR(a_adminFile), PSTR(a_stdoutPath)); /* generate path to pkgremove */ (void) snprintf(path, sizeof (path), "%s/pkgremove", a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir); /* start at first file descriptor */ maxfds = 0; /* * generate argument list for call to pkgremove */ /* start at argument 0 */ nargs = 0; /* first argument is path to executable */ arg[nargs++] = strdup(path); /* second argument is always: pass -O debug to pkgremove: debug mode */ if (debugFlag == B_TRUE) { arg[nargs++] = "-O"; arg[nargs++] = "debug"; } /* pkgrm -b dir: pass -b to pkgremove */ if (a_altBinDir != (char *)NULL) { arg[nargs++] = "-b"; arg[nargs++] = a_altBinDir; } /* * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a * pkg requiring operator interaction during a procedure script * (common before on1093) */ if (old_pkg) { arg[nargs++] = "-o"; } /* * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process * symlinks consistent with old behavior */ if (old_symlinks) { arg[nargs++] = "-y"; } /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */ arg[nargs++] = "-M"; /* pkgrm -A: pass -A to pkgremove */ if (pkgrmremote) { arg[nargs++] = "-A"; } /* pkgrm -v: pass -v to pkgremove: never trace scripts */ /* pass "-O enable-hollow-package-support" */ if (is_depend_pkginfo_DB()) { arg[nargs++] = "-O"; arg[nargs++] = "enable-hollow-package-support"; } /* pass -n to pkgremove: always in noninteractive mode */ arg[nargs++] = "-n"; /* pkgrm -a admin: pass -a admin to pkgremove: admin file */ if (a_adminFile) { int fd; fd = openLocal(a_adminFile, O_RDONLY, tmpdir); if (fd < 0) { progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile, errno, strerror(errno)); return (1); } (void) snprintf(adminfd_path, sizeof (adminfd_path), "/proc/self/fd/%d", fd); fds[maxfds++] = fd; arg[nargs++] = "-a"; arg[nargs++] = strdup(adminfd_path); } /* * pkgadd -R root: pass -R /a to pkgremove in mounted zone */ if (a_zoneState == ZONE_STATE_MOUNTED) { arg[nargs++] = "-R"; arg[nargs++] = "/a"; } /* pkgrm -F: pass -F to pkgremove: always update DB only */ arg[nargs++] = "-F"; /* pass "-O preremovecheck" */ arg[nargs++] = "-O"; arg[nargs++] = "preremovecheck"; /* add "-O addzonename" */ arg[nargs++] = "-O"; arg[nargs++] = "addzonename"; /* add all inherited file systems */ if (a_inheritedPkgDirs != (char **)NULL) { for (n = 0; a_inheritedPkgDirs[n] != (char *)NULL; n++) { char ifs[MAXPATHLEN+22]; (void) snprintf(ifs, sizeof (ifs), "inherited-filesystem=%s", a_inheritedPkgDirs[n]); arg[nargs++] = "-O"; arg[nargs++] = strdup(ifs); } } /* * add parent zone info/type */ p = z_get_zonename(); if ((p != NULL) && (*p != '\0')) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-name=%s", p); arg[nargs++] = "-O"; arg[nargs++] = strdup(zn); } /* current zone type */ arg[nargs++] = "-O"; if (z_running_in_global_zone() == B_TRUE) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_GLOBAL_ZONE); arg[nargs++] = strdup(zn); } else { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_NONGLOBAL_ZONE); arg[nargs++] = strdup(zn); } /* pass -N to pkgremove: program name to report */ arg[nargs++] = "-N"; arg[nargs++] = get_prog_name(); /* add package instance name */ arg[nargs++] = pkginst; /* terminate argument list */ arg[nargs++] = NULL; /* execute pkgremove command */ if (debugFlag == B_TRUE) { echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]); for (n = 0; arg[n]; n++) { echoDebug(DBG_ARG, n, arg[n]); } } /* terminate file descriptor list */ fds[maxfds] = -1; /* exec command in zone */ n = z_zone_exec(a_zoneName, path, arg, a_stdoutPath, (char *)NULL, fds); echoDebug(DBG_ZONE_EXEC_EXIT, a_zoneName, arg[0], n, PSTR(a_stdoutPath)); /* * close any files that were opened for use by the * /proc/self/fd interface so they could be passed to programs * via the z_zone_exec() interface */ for (; maxfds > 0; maxfds--) { (void) close(fds[maxfds-1]); } /* return results of pkgremove in zone execution */ return (n); } static int pkgZoneRemove(char *a_zoneName, char **a_inheritedPkgDirs, int a_nodelete, char *a_altBinDir, char *a_adminFile, zone_state_t a_zoneState) { char *arg[MAXARGS]; char *p; char adminfd_path[PATH_MAX]; char path[PATH_MAX]; int fds[MAX_FDS]; int maxfds; int n; int nargs; /* entry assertions */ assert(a_zoneName != (char *)NULL); assert(*a_zoneName != '\0'); /* entry debugging info */ echoDebug(DBG_PKGZONEREMOVE_ENTRY); echoDebug(DBG_PKGZONEREMOVE_ARGS, a_zoneName, PSTR(pkginst), PSTR(pkgdev.dirname), a_nodelete, PSTR(a_adminFile)); /* generate path to pkgremove */ (void) snprintf(path, sizeof (path), "%s/pkgremove", a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir); /* start at first file descriptor */ maxfds = 0; /* * generate argument list for call to pkgremove */ /* start at argument 0 */ nargs = 0; /* first argument is path to executable */ arg[nargs++] = strdup(path); /* second argument is always: pass -O debug to pkgremove: debug mode */ if (debugFlag == B_TRUE) { arg[nargs++] = "-O"; arg[nargs++] = "debug"; } /* pkgrm -b dir: pass -b to pkgremove */ if (a_altBinDir != (char *)NULL) { arg[nargs++] = "-b"; arg[nargs++] = a_altBinDir; } /* * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a * pkg requiring operator interaction during a procedure script * (common before on1093) */ if (old_pkg) { arg[nargs++] = "-o"; } /* * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process * symlinks consistent with old behavior */ if (old_symlinks) { arg[nargs++] = "-y"; } /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */ arg[nargs++] = "-M"; /* pkgrm -A: pass -A to pkgremove */ if (pkgrmremote) { arg[nargs++] = "-A"; } /* pkgrm -v: pass -v to pkgremove: trace scripts */ if (pkgverbose) { arg[nargs++] = "-v"; } /* pass "-O enable-hollow-package-support" */ if (is_depend_pkginfo_DB()) { arg[nargs++] = "-O"; arg[nargs++] = "enable-hollow-package-support"; } /* pkgrm -n: pass -n to pkgremove: noninteractive mode */ if (nointeract) { arg[nargs++] = "-n"; } /* pkgrm -a admin: pass -a admin to pkgremove: admin file */ if (a_adminFile) { int fd; fd = openLocal(a_adminFile, O_RDONLY, tmpdir); if (fd < 0) { progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile, errno, strerror(errno)); return (1); } (void) snprintf(adminfd_path, sizeof (adminfd_path), "/proc/self/fd/%d", fd); fds[maxfds++] = fd; arg[nargs++] = "-a"; arg[nargs++] = adminfd_path; } /* * pkgadd -R root: pass -R /a to pkgremove in mounted zone */ if (a_zoneState == ZONE_STATE_MOUNTED) { arg[nargs++] = "-R"; arg[nargs++] = "/a"; } /* pkgrm -F: pass -F to pkgremove: update DB only */ if (a_nodelete) { arg[nargs++] = "-F"; } /* add "-O addzonename" */ arg[nargs++] = "-O"; arg[nargs++] = "addzonename"; /* add all inherited file systems */ if (a_inheritedPkgDirs != (char **)NULL) { for (n = 0; a_inheritedPkgDirs[n] != (char *)NULL; n++) { char ifs[MAXPATHLEN+22]; (void) snprintf(ifs, sizeof (ifs), "inherited-filesystem=%s", a_inheritedPkgDirs[n]); arg[nargs++] = "-O"; arg[nargs++] = strdup(ifs); } } /* * add parent zone info/type */ p = z_get_zonename(); if ((p != NULL) && (*p != '\0')) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-name=%s", p); arg[nargs++] = "-O"; arg[nargs++] = strdup(zn); } /* current zone type */ arg[nargs++] = "-O"; if (z_running_in_global_zone() == B_TRUE) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_GLOBAL_ZONE); arg[nargs++] = strdup(zn); } else { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_NONGLOBAL_ZONE); arg[nargs++] = strdup(zn); } /* pass -N to pkgremove: program name to report */ arg[nargs++] = "-N"; arg[nargs++] = get_prog_name(); /* add package instance name */ arg[nargs++] = pkginst; /* terminate argument list */ arg[nargs++] = NULL; /* execute pkgremove command */ if (debugFlag == B_TRUE) { echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]); for (n = 0; arg[n]; n++) { echoDebug(DBG_ARG, n, arg[n]); } } /* terminate file descriptor list */ fds[maxfds] = -1; /* exec command in zone */ n = z_zone_exec(a_zoneName, path, arg, (char *)NULL, (char *)NULL, fds); /* * close any files that were opened for use by the * /proc/self/fd interface so they could be passed to programs * via the z_zone_exec() interface */ for (; maxfds > 0; maxfds--) { (void) close(fds[maxfds-1]); } return (n); } /* * Name: pkgRemove * Description: Invoke pkgremove in the current zone to perform a remove * of a single package from the current zone or standalone system * Arguments: a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * a_adminFile - pointer to string representing the admin * file to pass to pkgremove when removing the package. * If this is == NULL no admin file is given to pkgremove. * a_inheritedPkgDirs - pointer to array of strings, each one * representing the non-global zones full path of a * directory that is inherited from the global zone. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static int pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile, char **a_inheritedPkgDirs) { char *arg[MAXARGS]; char *p; char path[PATH_MAX]; int n; int nargs; /* entry debugging info */ echoDebug(DBG_PKGREMOVE_ENTRY); echoDebug(DBG_PKGREMOVE_ARGS, PSTR(pkginst), PSTR(pkgdev.dirname), a_nodelete, PSTR(a_adminFile)); (void) snprintf(path, sizeof (path), "%s/pkgremove", a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir); nargs = 0; /* first argument is path to executable */ arg[nargs++] = strdup(path); /* second argument is always: pass -O debug to pkgremove: debug mode */ if (debugFlag == B_TRUE) { arg[nargs++] = "-O"; arg[nargs++] = "debug"; } /* pkgrm -b dir: pass -b to pkgremove */ if (a_altBinDir != (char *)NULL) { arg[nargs++] = "-b"; arg[nargs++] = a_altBinDir; } /* * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a * pkg requiring operator interaction during a procedure script * (common before on1093) */ if (old_pkg) { arg[nargs++] = "-o"; } /* * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process * symlinks consistent with old behavior */ if (old_symlinks) { arg[nargs++] = "-y"; } /* pkgrm -M: pass -M to pkgrm: dont mount client file systems */ if (no_map_client) { arg[nargs++] = "-M"; } /* pkgrm -A: pass -A to pkgrm */ if (pkgrmremote) { arg[nargs++] = "-A"; } /* pkgrm -v: pass -v to pkgremove: trace scripts */ if (pkgverbose) { arg[nargs++] = "-v"; } /* pkgrm -n: pass -n to pkgremove: noninteractive mode */ if (nointeract) { arg[nargs++] = "-n"; } /* pkgrm -a admin: pass -a admin to pkgremove: admin file */ if (a_adminFile) { arg[nargs++] = "-a"; arg[nargs++] = strdup(a_adminFile); } /* pkgrm -V vfstab: pass -V vfstab to pkgremove: alternate vfstab */ if (vfstab_file) { arg[nargs++] = "-V"; arg[nargs++] = vfstab_file; } /* pkgrm -R root: pass -R root to pkgremove: alternative root */ if (is_an_inst_root()) { arg[nargs++] = "-R"; arg[nargs++] = get_inst_root(); } /* pkgrm -F: pass -F to pkgremove: update DB only */ if (a_nodelete) { arg[nargs++] = "-F"; } /* add all inherited file systems */ if (a_inheritedPkgDirs != (char **)NULL) { for (n = 0; a_inheritedPkgDirs[n] != (char *)NULL; n++) { char ifs[MAXPATHLEN+22]; (void) snprintf(ifs, sizeof (ifs), "inherited-filesystem=%s", a_inheritedPkgDirs[n]); arg[nargs++] = "-O"; arg[nargs++] = strdup(ifs); } } /* * add parent zone info/type */ p = z_get_zonename(); if ((p != NULL) && (*p != '\0')) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-name=%s", p); arg[nargs++] = "-O"; arg[nargs++] = strdup(zn); } /* current zone type */ arg[nargs++] = "-O"; if (z_running_in_global_zone() == B_TRUE) { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_GLOBAL_ZONE); arg[nargs++] = strdup(zn); } else { char zn[MAXPATHLEN]; (void) snprintf(zn, sizeof (zn), "parent-zone-type=%s", TAG_VALUE_NONGLOBAL_ZONE); arg[nargs++] = strdup(zn); } /* pass -N to pkgremove: program name to report */ arg[nargs++] = "-N"; arg[nargs++] = get_prog_name(); /* add package instance name */ arg[nargs++] = pkginst; /* terminate argument list */ arg[nargs++] = NULL; /* * run the appropriate pkgremove command in the specified zone */ if (debugFlag == B_TRUE) { echoDebug(DBG_ZONE_EXEC_ENTER, "global", arg[0]); for (n = 0; arg[n]; n++) { echoDebug(DBG_ARG, n, arg[n]); } } /* execute pkgremove command */ n = pkgexecv(NULL, NULL, NULL, NULL, arg); /* return results of pkgrm in this zone */ return (n); } static void usage(void) { char *prog = get_prog_name(); (void) fprintf(stderr, ERR_USAGE_PKGRM, prog, prog); exit(1); } /* * Name: remove_packages_in_global_with_zones * Description: Remove packages from the global zone and from non-global zones * when run from the global zone and when non-global zones are * present. * Arguments: a_pkgList - pointer to array of strings, each string specifying * the name of one package to be removed. * a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_repeat - are there more packages avialable in "optind" * - B_TRUE - process packages from optind * - B_FALSE - do not process packages from optind * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * a_pkgdir - pointer to string representing the directory * where the packages to be removed are located. * a_zlst - list of zones to process; NULL if no zones to process. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static boolean_t remove_packages_in_global_with_zones(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir, zoneList_t a_zlst) { static char *zoneAdminFile = (char *)NULL; boolean_t b; char **inheritedPkgDirs; char *zoneName; char *scratchName; char preremovecheckPath[PATH_MAX+1]; int i; int n; int savenpkgs = npkgs; int zoneIndex; int zonesSkipped; zone_state_t zst; /* entry assertions */ assert(a_zlst != (zoneList_t)NULL); assert(a_pkgList != (char **)NULL); assert(a_longestPkg > 0); assert(a_pkgdir != (char *)NULL); assert(*a_pkgdir != '\0'); /* entry debugging info */ echoDebug(DBG_PKGREMPKGSGZWNGZ_ENTRY); echoDebug(DBG_PKGREMPKGSGZWNGZ_ARGS, a_nodelete, a_longestPkg, a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir)); /* check all packages */ if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) { quit(1); } /* create temporary directory for use by zone operations */ create_zone_tempdir(&zoneTempDir, tmpdir); /* create hands off settings admin file for use in a non-global zone */ create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile); /* * all of the packages (as listed in the package list) are * removed one at a time from all non-global zones and then * from the global zone. */ for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { /* reset interrupted flag before calling pkgremove */ interrupted = 0; /* last action was NOT quit */ /* skip package if it is "in the global zone only" */ if (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE) { continue; } /* * if operation failed in global zone do not propagate to * non-global zones */ zonesSkipped = 0; if (interrupted != 0) { echo(MSG_DOREMOVE_INTERRUPTED, pkginst); echoDebug(DBG_DOREMOVE_INTERRUPTED, pkginst); break; } echoDebug(DBG_REMOVE_FLAG_VALUES, "before loop", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); for (zoneIndex = 0; (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != (char *)NULL; zoneIndex++) { /* skip the zone if it is NOT running */ zst = z_zlist_get_current_state(a_zlst, zoneIndex); if (zst != ZONE_STATE_RUNNING && zst != ZONE_STATE_MOUNTED) { zonesSkipped++; echoDebug(DBG_SKIPPING_ZONE, zoneName); continue; } echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName); echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName); scratchName = z_zlist_get_scratch(a_zlst, zoneIndex); (void) snprintf(preremovecheckPath, sizeof (preremovecheckPath), "%s/%s.%s.preremovecheck.txt", zoneTempDir, pkginst, scratchName); /* determine list of dirs inherited from global zone */ inheritedPkgDirs = z_zlist_get_inherited_pkg_dirs(a_zlst, zoneIndex); /* * dependency check this package this zone; use the * user supplied admin file so that the appropriate * level of dependency checking is (or is not) done. */ n = pkgZoneCheckRemove(scratchName, inheritedPkgDirs, a_altBinDir, admnfile, preremovecheckPath, zst); /* set success/fail condition variables */ ckreturn(n); echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgzonecheckremove", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); } if (zonesSkipped == 0) { continue; } echoDebug(DBG_ZONES_SKIPPED, zonesSkipped); for (zoneIndex = 0; (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != (char *)NULL; zoneIndex++) { /* skip the zone if it IS running */ zst = z_zlist_get_current_state(a_zlst, zoneIndex); if (zst == ZONE_STATE_RUNNING || zst == ZONE_STATE_MOUNTED) { zonesSkipped++; echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName); continue; } /* skip the zone if it is NOT bootable */ if (z_zlist_is_zone_runnable(a_zlst, zoneIndex) == B_FALSE) { echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName); echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName); continue; } /* mount up the zone */ echo(MSG_BOOTING_ZONE, zoneName); echoDebug(DBG_BOOTING_ZONE, zoneName); b = z_zlist_change_zone_state(a_zlst, zoneIndex, ZONE_STATE_MOUNTED); if (b == B_FALSE) { progerr(ERR_CANNOT_BOOT_ZONE, zoneName); /* set fatal error return condition */ ckreturn(1); continue; } echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName); echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName); scratchName = z_zlist_get_scratch(a_zlst, zoneIndex); (void) snprintf(preremovecheckPath, sizeof (preremovecheckPath), "%s/%s.%s.preremovecheck.txt", zoneTempDir, pkginst, scratchName); /* determine list of dirs inherited from global zone */ inheritedPkgDirs = z_zlist_get_inherited_pkg_dirs(a_zlst, zoneIndex); /* * dependency check this package this zone; use the * user supplied admin file so that the appropriate * level of dependency checking is (or is not) done. */ n = pkgZoneCheckRemove(scratchName, inheritedPkgDirs, a_altBinDir, admnfile, preremovecheckPath, ZONE_STATE_MOUNTED); /* set success/fail condition variables */ ckreturn(n); echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgzonecheckremove", admnflag, doreboot, failflag, interrupted, intrflag, ireboot, nullflag, warnflag); /* restore original state of zone */ echo(MSG_RESTORE_ZONE_STATE, zoneName); echoDebug(DBG_RESTORE_ZONE_STATE, zoneName); b = z_zlist_restore_zone_state(a_zlst, zoneIndex); } npkgs--; } /* * look at all pre-remove check files */ i = preremove_verify(a_pkgList, a_zlst, zoneTempDir); if (i != 0) { quit(i); } npkgs = savenpkgs; /* * reset all error return condition variables that may have been * set during package removal dependency checking so that they * do not reflect on the success/failure of the actual package * removal operations */ resetreturn(); /* * all of the packages (as listed in the package list) are * removed one at a time. */ interrupted = 0; for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { boolean_t in_gz_only; started = 0; if (shall_we_continue(pkginst, npkgs) == B_FALSE) { continue; } in_gz_only = pkgIsPkgInGzOnly(get_inst_root(), pkginst); /* reset interrupted flag before calling pkgremove */ interrupted = 0; /* * pkgrm invoked from within the global zone and there are * non-global zones configured: * Remove the package from the global zone. * If not removing the package from the global zone only, * then remove the package from the list of zones specified. */ if (in_gz_only) { /* global zone only */ n = doRemove(a_nodelete, a_altBinDir, a_longestPkg, admnfile, (char *)NULL, (zoneList_t)NULL); } else { /* global zone and non-global zones */ n = doRemove(a_nodelete, a_altBinDir, a_longestPkg, zoneAdminFile, zoneAdminFile, a_zlst); } /* set success/fail condition variables */ ckreturn(n); npkgs--; } /* * all packages in the package list have been removed. * Continue with removal if: * -- immediate reboot is NOT required * -- there are more packages to remove * else return do NOT continue. */ if ((ireboot == 0) && (a_repeat != 0)) { return (B_TRUE); } /* return 'dont continue' */ return (B_FALSE); } /* * Name: remove_packages_in_nonglobal_zone * Description: Remove packages in a non-global zone when run from a * non-global zone. * Arguments: a_pkgList - pointer to array of strings, each string specifying * the name of one package to be removed. * a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_repeat - are there more packages avialable in "optind" * - B_TRUE - process packages from optind * - B_FALSE - do not process packages from optind * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * a_pkgdir - pointer to string representing the directory * where the packages to be removed are located. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static boolean_t remove_packages_in_nonglobal_zone(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir) { static char *zoneAdminFile = (char *)NULL; int n; int i; /* entry assertions */ assert(a_pkgList != (char **)NULL); assert(a_longestPkg > 0); assert(a_pkgdir != (char *)NULL); assert(*a_pkgdir != '\0'); /* entry debugging info */ echoDebug(DBG_PKGREMPKGSNGZ_ENTRY); echoDebug(DBG_PKGREMPKGSNGZ_ARGS, a_nodelete, a_longestPkg, a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir)); /* check all package */ if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) { quit(1); } /* create temporary directory for use by zone operations */ create_zone_tempdir(&zoneTempDir, tmpdir); /* create hands off settings admin file for use in a non-global zone */ create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile); /* * all of the packages (as listed in the package list) are * removed one at a time. */ interrupted = 0; for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { started = 0; if (shall_we_continue(pkginst, npkgs) == B_FALSE) { continue; } interrupted = 0; /* * pkgrm invoked from within a non-global zone: remove * the package from the current zone only - no non-global * zones are possible. */ n = doRemove(a_nodelete, a_altBinDir, a_longestPkg, admnfile, (char *)NULL, (zoneList_t)NULL); /* set success/fail condition variables */ ckreturn(n); npkgs--; } /* * all packages in the package list have been removed. * Continue with removal if: * -- immediate reboot is NOT required * -- there are more packages to remove * else return do NOT continue. */ if ((ireboot == 0) && (a_repeat != 0)) { return (B_TRUE); } /* return 'dont continue' */ return (B_FALSE); } /* * Name: remove_packages_in_global_no_zones * Description: Remove packages from the global zone only when run in the * global zone and no non-global zones are installed. * Arguments: a_pkgList - pointer to array of strings, each string specifying * the name of one package to be removed. * a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_repeat - are there more packages avialable in "optind" * - B_TRUE - process packages from optind * - B_FALSE - do not process packages from optind * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static boolean_t remove_packages_in_global_no_zones(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir) { int n; int i; /* entry assertions */ assert(a_pkgList != (char **)NULL); assert(a_longestPkg > 0); /* entry debugging info */ echoDebug(DBG_PKGREMPKGSGZNNGZ_ENTRY); echoDebug(DBG_PKGREMPKGSGZNNGZ_ARGS, a_nodelete, a_longestPkg, a_repeat, PSTR(a_altBinDir)); /* * all of the packages (as listed in the package list) are * removed one at a time. */ interrupted = 0; for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { started = 0; if (shall_we_continue(pkginst, npkgs) == B_FALSE) { continue; } interrupted = 0; /* * pkgrm invoked from within the global zone and there are * NO non-global zones configured: * Remove the package from the global zone only. */ n = doRemove(a_nodelete, a_altBinDir, a_longestPkg, admnfile, (char *)NULL, (zoneList_t)NULL); /* set success/fail condition variables */ ckreturn(n); npkgs--; } /* * all packages in the package list have been removed. * Continue with removal if: * -- immediate reboot is NOT required * -- there are more packages to remove * else return do NOT continue. */ if ((ireboot == 0) && (a_repeat != 0)) { return (B_TRUE); } /* return 'dont continue' */ return (B_FALSE); } /* * Name: remove_packages_from_spool_directory * Description: Remove packages from a spool directory only. * Arguments: a_pkgList - pointer to array of strings, each string specifying * the name of one package to be removed. * a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_repeat - are there more packages avialable in "optind" * - B_TRUE - process packages from optind * - B_FALSE - do not process packages from optind * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static boolean_t remove_packages_from_spool_directory(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir) { int n; int i; /* entry assertions */ assert(a_pkgList != (char **)NULL); assert(a_longestPkg > 0); /* * all of the packages (as listed in the package list) are * removed one at a time. */ interrupted = 0; for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { started = 0; if (shall_we_continue(pkginst, npkgs) == B_FALSE) { continue; } interrupted = 0; /* * pkgrm invoked from any type of zone BUT the target * to be removed is a local spool directory: remove the * packages from the spool directory only. */ n = doRemove(a_nodelete, a_altBinDir, a_longestPkg, admnfile, (char *)NULL, (zoneList_t)NULL); /* set success/fail condition variables */ ckreturn(n); npkgs--; } /* * all packages in the package list have been removed. * Continue with removal if: * -- immediate reboot is NOT required * -- there are more packages to remove * else return do NOT continue. */ if ((ireboot == 0) && (a_repeat != 0)) { return (B_TRUE); } /* return 'dont continue' */ return (B_FALSE); } /* * Name: remove_packages * Description: Remove packages from the global zone, and optionally from one * or more non-global zones, or from a specified spool directory. * Arguments: a_pkgList - pointer to array of strings, each string specifying * the name of one package to be removed. * a_nodelete: should the files and scripts remain installed? * - if != 0 pass -F flag to pkgremove - suppress * the removal of any files and any class action scripts * and suppress the running of any class action scripts. * The package files remain but the package looks like it * is not installed. This is mainly for use by upgrade. * - if == 0 do not pass -F flag to pkgremove - all * files and class action scripts are removed, and any * appropriate class action scripts are run. * a_longestPkg - length of the longest package "name" (for * output format alignment) * a_repeat - are there more packages avialable in "optind" * - B_TRUE - process packages from optind * - B_FALSE - do not process packages from optind * a_altBinDir - pointer to string representing location of the * pkgremove executable to run. If not NULL, then pass * the path specified to the -b option to pkgremove. * a_pkgdir - pointer to string representing the directory * where the packages to be removed are located. * a_spoolDir - pointer to string specifying spool directory * to remove packages from. If != NULL then all zones * processing is bypassed and the packages are removed * from the specified spool directory only. * a_noZones - if non-global zones are configured, should the * packages be removed from the non-global zones? * - B_TRUE - do NOT remove packages from non-global zones * - B_FALSE - remove packages from non-global zones * Returns: int (see ckreturn() function for details) * 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" will be added to indicate "immediate reboot required" * "20" will be added to indicate "reboot after install required" */ static boolean_t remove_packages(char **a_pkgList, int a_nodelete, int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir, char *a_spoolDir, boolean_t a_noZones) { zoneList_t zlst; boolean_t b; /* entry assertions */ assert(a_pkgList != (char **)NULL); echoDebug(DBG_REMOVEPKGS_ENTRY); echoDebug(DBG_REMOVEPKGS_ARGS, npkgs, a_nodelete, a_longestPkg, a_repeat, PSTR(a_pkgdir), PSTR(a_spoolDir)); /* * if removing from spool directory, bypass all zones checks */ if (a_spoolDir != (char *)NULL) { /* in non-global zone */ echoDebug(DBG_REMOVE_PKGS_FROM_SPOOL, a_spoolDir); b = remove_packages_from_spool_directory(a_pkgList, a_nodelete, a_longestPkg, a_repeat, a_altBinDir); return (B_FALSE); } /* exit if not root */ if (getuid()) { progerr(ERR_NOT_ROOT, get_prog_name()); exit(1); } /* * if running in the global zone AND one or more non-global * zones exist, add packages in a 'zones aware' manner, else * add packages in the standard 'non-zones aware' manner. */ if ((a_noZones == B_FALSE) && (z_running_in_global_zone() == B_FALSE)) { /* in non-global zone */ echoDebug(DBG_IN_LZ); b = z_lock_this_zone(ZLOCKS_PKG_ADMIN); if (b != B_TRUE) { progerr(ERR_CANNOT_LOCK_THIS_ZONE); /* set fatal error return condition */ ckreturn(1); return (B_FALSE); } b = remove_packages_in_nonglobal_zone(a_pkgList, a_nodelete, a_longestPkg, a_repeat, a_altBinDir, a_pkgdir); (void) z_unlock_this_zone(ZLOCKS_ALL); return (B_FALSE); } /* running in the global zone */ b = z_non_global_zones_exist(); if ((a_noZones == B_FALSE) && (b == B_TRUE)) { echoDebug(DBG_IN_GZ_WITH_LZ); /* get a list of all non-global zones */ zlst = z_get_nonglobal_zone_list(); if (zlst == (zoneList_t)NULL) { progerr(ERR_CANNOT_GET_ZONE_LIST); quit(1); } /* need to lock all of the zones */ quitSetZonelist(zlst); b = z_lock_zones(zlst, ZLOCKS_PKG_ADMIN); if (b == B_FALSE) { z_free_zone_list(zlst); progerr(ERR_CANNOT_LOCK_ZONES); /* set fatal error return condition */ ckreturn(1); return (B_FALSE); } /* add packages to all zones */ b = remove_packages_in_global_with_zones(a_pkgList, a_nodelete, a_longestPkg, a_repeat, a_altBinDir, a_pkgdir, zlst); /* unlock all zones */ (void) z_unlock_zones(zlst, ZLOCKS_ALL); quitSetZonelist((zoneList_t)NULL); /* free list of all non-global zones */ z_free_zone_list(zlst); return (B_FALSE); } /* in global zone no non-global zones */ echoDebug(DBG_IN_GZ_NO_LZ); b = z_lock_this_zone(ZLOCKS_PKG_ADMIN); if (b != B_TRUE) { progerr(ERR_CANNOT_LOCK_THIS_ZONE); /* set fatal error return condition */ ckreturn(1); return (B_FALSE); } b = remove_packages_in_global_no_zones(a_pkgList, a_nodelete, a_longestPkg, a_repeat, a_altBinDir); (void) z_unlock_this_zone(ZLOCKS_ALL); return (B_FALSE); } /* * Name: path_valid * Description: Checks a string for being a valid path * * Arguments: path - path to validate * * Returns : B_TRUE - success, B_FALSE otherwise. * B_FALSE means path was null, too long (>PATH_MAX), * or too short (<1) */ static boolean_t path_valid(char *path) { if (path == NULL) { return (B_FALSE); } else if (strlen(path) > PATH_MAX) { return (B_FALSE); } else if (strlen(path) >= 1) { return (B_TRUE); } else { /* path < 1 */ return (B_FALSE); } } /* */ static boolean_t check_packages(char **a_pkgList, char *a_packageDir) { int savenpkgs = npkgs; int i; CAF_T flags = 0; /* set flags for applicability check */ if (z_running_in_global_zone() == B_TRUE) { flags |= CAF_IN_GLOBAL_ZONE; } /* * for each package to remove, verify that the package is installed * and is removable. */ for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) { /* check package applicability */ if (check_applicability(a_packageDir, pkginst, get_inst_root(), flags) == B_FALSE) { progerr(ERR_PKG_NOT_REMOVABLE, pkginst); npkgs = savenpkgs; return (B_FALSE); } npkgs--; } npkgs = savenpkgs; return (B_TRUE); } /* * - is this package removable from this zone? * - does the scope of remove conflict with existing installation */ static boolean_t check_applicability(char *a_packageDir, char *a_pkgInst, char *a_rootPath, CAF_T a_flags) { FILE *pkginfoFP; boolean_t all_zones; /* pkg is "all zones" only */ char pkginfoPath[PATH_MAX]; char pkgpath[PATH_MAX]; int len; /* entry assertions */ assert(a_packageDir != (char *)NULL); assert(*a_packageDir != '\0'); assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* normalize root path */ if (a_rootPath == (char *)NULL) { a_rootPath = ""; } /* * determine if this package is currently installed * if not installed return success - operation will fail * when the removal is attempted */ if (pkginfoIsPkgInstalled((struct pkginfo **)NULL, a_pkgInst) != B_TRUE) { return (B_TRUE); } /* * calculate paths to various objects */ len = snprintf(pkgpath, sizeof (pkgpath), "%s/%s", a_packageDir, a_pkgInst); if (len > sizeof (pkgpath)) { progerr(ERR_CREATE_PATH_2, a_packageDir, a_pkgInst); return (B_FALSE); } /* if not installed then just return */ if (isdir(pkgpath) != 0) { progerr(ERR_NO_PKGDIR, pkgpath, a_pkgInst, strerror(errno)); return (B_TRUE); } len = snprintf(pkginfoPath, sizeof (pkginfoPath), "%s/pkginfo", pkgpath); if (len > sizeof (pkgpath)) { progerr(ERR_CREATE_PATH_2, pkgpath, "pkginfo"); return (B_FALSE); } /* * gather information from this packages pkginfo file */ pkginfoFP = fopen(pkginfoPath, "r"); if (pkginfoFP == (FILE *)NULL) { progerr(ERR_NO_PKG_INFOFILE, a_pkgInst, pkginfoPath, strerror(errno)); return (B_FALSE); } /* determine "ALLZONES" setting for this package */ all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE, "true", B_FALSE); /* close pkginfo file */ (void) fclose(pkginfoFP); /* gather information from the global zone only file */ /* * verify package applicability based on information gathered; * the package IS currently installed.... */ /* pkg ALLZONES=true & not running in global zone */ if ((all_zones == B_TRUE) && (!(a_flags & CAF_IN_GLOBAL_ZONE))) { progerr(ERR_ALLZONES_AND_IN_LZ_PKGRM, a_pkgInst); return (B_FALSE); } return (B_TRUE); } /* * Name: shall_we_continue * Description: Called from within a loop that is installing packages, * this function examines various global variables and decides * whether or not to ask an appropriate question, and wait for * and appropriate reply. * Arguments: <> * Returns: B_TRUE - continue processing with next package * B_FALSE - do not continue processing with next package */ static boolean_t shall_we_continue(char *a_pkgInst, int a_npkgs) { char ans[MAX_INPUT]; int n; /* return FALSE if immediate reboot required */ if (ireboot) { ptext(stderr, MSG_SUSPEND_RM, a_pkgInst); return (B_FALSE); } /* return TRUE if not interrupted */ if (!interrupted) { return (B_TRUE); } /* output appropriate interrupt message */ echo(a_npkgs == 1 ? MSG_1MORETODO : MSG_MORETODO, a_npkgs); /* if running with no interaction (-n) do not ask question */ if (nointeract) { quit(0); /* NOTREACHED */ } /* interaction possible: ask question */ n = ckyorn(ans, NULL, NULL, NULL, ASK_CONTINUE_RM); if (n != 0) { quit(n); /* NOTREACHED */ } if (strchr("yY", *ans) == NULL) { quit(0); /* NOTREACHED */ } return (B_TRUE); } /* * Name: create_zone_adminfile * Description: Given a zone temporary directory and optionally an existing * administration file, generate an administration file that * can be used to perform "non-interactive" operations in a * non-global zone. * Arguments: r_zoneAdminFile - pointer to handle that will contain a * string representing the path to the temporary * administration file created - this must be NULL * before the first call to this function - on * subsequent calls if the pointer is NOT null then * the existing string will NOT be overwritten. * a_zoneTempDir - pointer to string representing the path * to the zone temporary directory to create the * temporary administration file in * a_admnfile - pointer to string representing the path to * an existing "user" administration file - the * administration file created will contain the * settings contained in this file, modified as * appropriate to supress any interaction; * If this is == NULL then the administration file * created will not contain any extra settings * Returns: void * 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. * NOTE: On any error this function will call 'quit(1)' */ static void create_zone_adminfile(char **r_zoneAdminFile, char *a_zoneTempDir, char *a_admnfile) { boolean_t b; /* entry assertions */ assert(r_zoneAdminFile != (char **)NULL); assert(a_zoneTempDir != (char *)NULL); assert(*a_zoneTempDir != '\0'); /* entry debugging info */ echoDebug(DBG_CREATE_ZONE_ADMINFILE, a_zoneTempDir, PSTR(a_admnfile)); /* if temporary name already exists, do not overwrite */ if (*r_zoneAdminFile != (char *)NULL) { return; } /* create temporary name */ *r_zoneAdminFile = tempnam(a_zoneTempDir, "zadmn"); b = z_create_zone_admin_file(*r_zoneAdminFile, a_admnfile); if (b == B_FALSE) { progerr(ERR_CREATE_TMPADMIN, *r_zoneAdminFile, strerror(errno)); quit(1); /* NOTREACHED */ } echoDebug(DBG_CREATED_ZONE_ADMINFILE, *r_zoneAdminFile); } /* * Name: create_zone_tempdir * Description: Given a system temporary directory, create a "zone" specific * temporary directory and return the path to the directory * created. * Arguments: r_zoneTempDir - pointer to handle that will contain a * string representing the path to the temporary * directory created - this must be NULL before the * first call to this function - on subsequent calls * if the pointer is NOT null then the existing string * will NOT be overwritten. * a_zoneTempDir - pointer to string representing the path * to the system temporary directory to create the * temporary zone directory in * Returns: void * 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. * NOTE: On any error this function will call 'quit(1)' * NOTE: This function calls "quitSetZoneTmpdir" on success to * register the directory created with quit() so that the * directory will be automatically deleted on exit. */ static void create_zone_tempdir(char **r_zoneTempDir, char *a_tmpdir) { boolean_t b; /* entry assertions */ assert(r_zoneTempDir != (char **)NULL); assert(a_tmpdir != (char *)NULL); assert(*a_tmpdir != '\0'); /* entry debugging info */ echoDebug(DBG_CREATE_ZONE_TEMPDIR, a_tmpdir); /* if temporary directory already exists, do not overwrite */ if (*r_zoneTempDir != (char *)NULL) { return; } /* create temporary directory */ b = setup_temporary_directory(r_zoneTempDir, a_tmpdir, "ztemp"); if (b == B_FALSE) { progerr(ERR_ZONETEMPDIR, a_tmpdir, strerror(errno)); quit(1); /* NOTREACHED */ } /* register with quit() to directory is removed on exit */ quitSetZoneTmpdir(*r_zoneTempDir); /* exit debugging info */ echoDebug(DBG_CREATED_ZONE_TEMPDIR, *r_zoneTempDir); }