8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / svr4pkg / pkgrm / main.c
blob39a0846704932baef2b1f616f8d456312024800c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2017 Peter Tribble.
27 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
30 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
35 * System includes
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <signal.h>
43 #include <errno.h>
44 #include <locale.h>
45 #include <libintl.h>
46 #include <pkgstrct.h>
47 #include <pkgdev.h>
48 #include <pkginfo.h>
49 #include <pkglocs.h>
50 #include <pkglib.h>
51 #include <assert.h>
54 * libinstzones includes
57 #include <instzones_api.h>
60 * consolidation pkg command library includes
63 #include <pkglib.h>
66 * local pkg command library includes
69 #include "install.h"
70 #include "libinst.h"
71 #include "libadm.h"
72 #include "messages.h"
75 * pkgrm local includes
78 #include "quit.h"
81 * exported global variables
84 /* these globals are set by ckreturn and used by quit.c */
86 int admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */
87 int doreboot = 0; /* != 0 if reboot required after installation */
88 int failflag = 0; /* != 0 if fatal error has occurred (1) */
89 int intrflag = 0; /* != 0 if user selected quit (3) */
90 int ireboot = 0; /* != 0 if immediate reboot required */
91 int nullflag = 0; /* != 0 if admin interaction required (5) */
92 int warnflag = 0; /* != 0 if non-fatal error has occurred (2) */
94 /* imported by quit.c */
95 int npkgs = 0; /* the number of packages yet to be installed */
97 /* imported by presvr4.c */
98 int started = 0;
99 char *tmpdir = NULL; /* location to place temporary files */
101 /* imported by various (many) */
102 struct admin adm; /* holds info about installation admin */
103 struct pkgdev pkgdev; /* holds info about the installation device */
106 * internal global variables
109 static char *admnfile = NULL; /* file to use for installation admin */
110 static char *pkginst = NULL; /* current pkg/src instance 2 process */
111 static char *vfstab_file = NULL;
112 static char *zoneTempDir = (char *)NULL;
114 /* set by ckreturn() */
116 static int interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */
118 static int nointeract = 0; /* non-zero - no user interaction */
119 static int pkgrmremote = 0; /* remove pkg objs stored remotely */
120 static int pkgverbose = 0; /* non-zero if verbose mode selected */
123 * Assume the package complies with the standards as regards user
124 * interaction during procedure scripts.
127 static int old_pkg = 0;
128 static int old_symlinks = 0;
129 static int no_map_client = 0;
131 /* Set by -O nozones: do not process any zones */
133 static boolean_t noZones = B_FALSE;
135 /* Set by -O zonelist=<names...>: process only named zones */
137 static boolean_t usedZoneList = B_FALSE;
139 /* Set by -O debug: debug output is enabled? */
141 static boolean_t debugFlag = B_FALSE;
144 * imported (external) functions
147 /* check.c */
149 extern int preremove_verify(char **a_pkgList, zoneList_t a_zlst,
150 char *a_zoneTempDir);
151 /* quit.c */
153 extern void quitSetZonelist(zoneList_t a_zlst);
156 * imported (external) variables
159 extern char *pkgdir;
161 /* printable string - if string is null results in ??? */
163 #define PSTR(STR) (((STR) == (char *)NULL) ? "???" : (STR))
165 #define MAX_FDS 20
167 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
168 #define TEXT_DOMAIN "SYS_TEST"
169 #endif
172 * forward declarations
175 static void ckreturn(int retcode);
176 static void create_zone_adminfile(char **r_zoneAdminFile,
177 char *a_zoneTempDir, char *a_admnfile);
178 static void create_zone_tempdir(char **r_zoneTempDir,
179 char *a_tmpdir);
180 static int doRemove(int a_nodelete, char *a_altBinDir,
181 int a_longestPkg, char *a_adminFile,
182 char *a_zoneAdminFile, zoneList_t zlst);
183 static int pkgRemove(int a_nodelete, char *a_altBinDir,
184 char *a_adminFile);
185 static int pkgZoneCheckRemove(char *a_zoneName, char *a_altBinDir,
186 char *a_adminFile, char *a_stdoutPath,
187 zone_state_t a_zoneState, boolean_t tmpzone);
188 static int pkgZoneRemove(char *a_zoneName, int a_nodelete,
189 char *a_altBinDir, char *a_adminFile,
190 zone_state_t a_zoneState, boolean_t tmpzone);
191 static void resetreturn();
192 static void usage(void);
193 static boolean_t check_applicability(char *a_packageDir,
194 char *a_pkgInst, char *a_rootPath,
195 CAF_T a_flags);
196 static boolean_t check_packages(char **a_pkgList, char *a_packageDir);
197 static boolean_t remove_packages(char **a_pkgList, int a_nodelete,
198 int a_longestPkg, int a_repeat,
199 char *a_altBinDir, char *a_pkgdir,
200 char *a_spoolDir, boolean_t a_noZones);
201 static boolean_t remove_packages_from_spool_directory(char **a_pkgList,
202 int a_nodelete, int a_longestPkg, int a_repeat,
203 char *a_altBinDir);
204 static boolean_t remove_packages_in_global_no_zones(char **a_pkgList,
205 int a_nodelete, int a_longestPkg, int a_repeat,
206 char *a_altBinDir);
207 static boolean_t remove_packages_in_global_with_zones(char **a_pkgList,
208 int a_nodelete, int a_longestPkg, int a_repeat,
209 char *a_altBinDir, char *a_pkgdir,
210 zoneList_t a_zlst);
211 static boolean_t remove_packages_in_nonglobal_zone(char **a_pkgList,
212 int a_nodelete, int a_longestPkg, int a_repeat,
213 char *a_altBinDir, char *a_pkgdir);
214 static boolean_t shall_we_continue(char *a_pkgInst, int a_npkgs);
217 * *****************************************************************************
218 * global external (public) functions
219 * *****************************************************************************
223 * Name: main
224 * Description: main entry point for pkgrm
225 * Returns: int
226 * 0 Successful completion
227 * 1 Fatal error.
228 * 2 Warning.
229 * 3 Interruption.
230 * 4 Administration.
231 * 5 Administration. Interaction is required. Do not use pkgrm -n.
232 * 10 Reboot after removal of all packages.
233 * 20 Reboot after removal of this package.
237 main(int argc, char **argv)
239 char **category = NULL;
240 char *altBinDir = (char *)NULL;
241 char *catg_arg = NULL;
242 char *p;
243 char *prog_full_name = NULL;
244 char *spoolDir = 0;
245 int c;
246 int longestPkg = 0;
247 int n;
248 int nodelete = 0; /* dont rm files/run scripts */
249 int pkgLgth = 0;
250 int repeat;
251 struct sigaction nact;
252 struct sigaction oact;
254 /* initialize locale environment */
256 (void) setlocale(LC_ALL, "");
257 (void) textdomain(TEXT_DOMAIN);
259 /* initialize program name */
261 prog_full_name = argv[0];
262 (void) set_prog_name(argv[0]);
264 /* tell spmi zones interface how to access package output functions */
266 z_set_output_functions(echo, echoDebug, progerr);
268 /* tell quit which ckreturn function to call */
270 quitSetCkreturnFunc(&ckreturn);
272 /* Read PKG_INSTALL_ROOT from the environment, if it's there. */
274 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
275 progerr(ERR_ROOT_SET);
276 exit(1);
279 if (z_running_in_global_zone() && !enable_local_fs()) {
280 progerr(ERR_CANNOT_ENABLE_LOCAL_FS);
283 pkgserversetmode(DEFAULTMODE);
286 * ********************************************************************
287 * parse command line options
288 * ********************************************************************
291 while ((c = getopt(argc, argv, "?Aa:b:FMnO:R:s:V:vY:Z")) != EOF) {
292 switch (c) {
294 * Public interface: Allow admin to remove objects
295 * from a service area via a reference client.
296 * Remove the package files from the client's file
297 * system, absolutely. If a file is shared with other
298 * packages, the default behavior is to not remove
299 * the file from the client's file system.
301 case 'A':
302 pkgrmremote++;
303 break;
306 * Public interface: Use the installation
307 * administration file, admin, in place of the
308 * default admin file. pkgrm first looks in the
309 * current working directory for the administration
310 * file. If the specified administration file is not
311 * in the current working directory, pkgrm looks in
312 * the /var/sadm/install/admin directory for the
313 * administra- tion file.
315 case 'a':
316 admnfile = flex_device(optarg, 0);
317 break;
320 * Not a public interface: location where package executables
321 * can be found - default is /usr/sadm/install/bin.
323 case 'b':
324 if (!path_valid(optarg)) {
325 progerr(ERR_PATH, optarg);
326 quit(1);
328 if (isdir(optarg) != 0) {
329 p = strerror(errno);
330 progerr(ERR_CANNOT_USE_DIR, optarg, p);
331 quit(1);
333 altBinDir = optarg;
334 break;
337 * Not a public interface: pass -F option to
338 * pkgremove which suppresses the removal of any
339 * files and any class action scripts, and suppresses
340 * the running of any class action scripts. The
341 * package files remain but the package looks like it
342 * is not installed. This is mainly for use by the
343 * upgrade process.
345 case 'F':
346 nodelete++;
347 break;
350 * Public interface: Instruct pkgrm not to use the
351 * $root_path/etc/vfstab file for determining the
352 * client's mount points. This option assumes the
353 * mount points are correct on the server and it
354 * behaves consistently with Solaris 2.5 and earlier
355 * releases.
357 case 'M':
358 no_map_client = 1;
359 break;
362 * Public interface: package removal occurs in
363 * non-interactive mode. Suppress output of the list of
364 * removed files. The default mode is interactive.
366 case 'n':
367 nointeract++;
368 (void) echoSetFlag(B_FALSE);
369 break;
372 * Not a public interface: the -O option allows the behavior
373 * of the package tools to be modified. Recognized options:
374 * -> debug
375 * ---> enable debugging output
376 * -> nozones
377 * ---> act as though in global zone with no non-global zones
378 * -> enable-hollow-package-support
379 * --> Enable hollow package support. When specified, for any
380 * --> package that has SUNW_PKG_HOLLOW=true:
381 * --> Do not calculate and verify package size against target
382 * --> Do not run any package procedure or class action scripts
383 * --> Do not create or remove any target directories
384 * --> Do not perform any script locking
385 * --> Do not install or uninstall any components of any package
386 * --> Do not output any status or database update messages
387 * -> zonelist="<names...>"
388 * ---> add package to space-separated list of zones only
391 case 'O':
392 for (p = strtok(optarg, ","); p != (char *)NULL;
393 p = strtok(NULL, ",")) {
395 if (strcmp(p, "nozones") == 0) {
396 noZones = B_TRUE;
397 continue;
400 if (strcmp(p,
401 "enable-hollow-package-support") == 0) {
402 set_depend_pkginfo_DB(B_TRUE);
403 continue;
406 if (strcmp(p, "debug") == 0) {
407 /* set debug flag/enable debug output */
408 debugFlag = B_TRUE;
409 (void) echoDebugSetFlag(debugFlag);
411 /* debug info on arguments to pkgadd */
412 for (n = 0; n < argc && argv[n]; n++) {
413 echoDebug(DBG_ARG, n, argv[n]);
416 continue;
419 if (strncmp(p, "zonelist=", 9) == 0) {
420 if (z_set_zone_spec(p + 9) == -1)
421 quit(1);
422 usedZoneList = B_TRUE;
423 continue;
426 /* -O option not recognized - issue warning */
428 progerr(ERR_INVALID_O_OPTION, p);
429 continue;
431 break;
434 * Public interface: defines the full path name of a
435 * directory to use as the root_path. All files,
436 * including package system information files, are
437 * relocated to a directory tree starting in the
438 * specified root_path.
440 case 'R':
441 if (!set_inst_root(optarg)) {
442 progerr(ERR_ROOT_CMD);
443 exit(1);
445 break;
448 * Public interface: remove the specified package(s)
449 * from the directory spool. The default directory
450 * for spooled packages is /var/sadm/pkg.
452 case 's':
453 spoolDir = flex_device(optarg, 1);
454 break;
457 * Public interface: Allow admin to establish the client
458 * filesystem using a vfstab-like file of stable format.
460 case 'V':
461 vfstab_file = flex_device(optarg, 2);
462 no_map_client = 0;
463 break;
466 * Public interface: trace all of the scripts that
467 * get executed by pkgrm, located in the
468 * pkginst/install directory. This option is used for
469 * debugging the procedural and non- procedural
470 * scripts.
472 case 'v':
473 pkgverbose++;
474 break;
477 * Public interface: remove packages based on the
478 * CATEGORY variable from the installed/spooled
479 * pkginfo file
481 case 'Y':
482 catg_arg = strdup(optarg);
484 if ((category = get_categories(catg_arg)) == NULL) {
485 progerr(ERR_CAT_INV, catg_arg);
486 exit(1);
487 } else if (is_not_valid_category(category,
488 get_prog_name())) {
489 progerr(ERR_CAT_SYS);
490 exit(1);
491 } else if (is_not_valid_length(category)) {
492 progerr(ERR_CAT_LNGTH);
493 exit(1);
496 break;
499 * unrecognized option
501 default:
502 usage();
503 /* NOTREACHED */
508 * ********************************************************************
509 * validate command line options
510 * ********************************************************************
513 /* set "debug echo" flag according to setting of "-O debug" option */
515 (void) echoDebugSetFlag(debugFlag);
517 /* output entry debugging information */
519 if (z_running_in_global_zone()) {
520 echoDebug(DBG_ENTRY_IN_GZ, prog_full_name);
521 } else {
522 echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(),
523 z_get_zonename());
526 /* -s cannot be used with several */
528 if (spoolDir != (char *)NULL) {
529 if (admnfile != (char *)NULL) {
530 progerr(ERR_SPOOLDIR_AND_ADMNFILE);
531 usage();
532 /* NOTREACHED */
535 if (pkgrmremote != 0) {
536 progerr(ERR_SPOOLDIR_AND_PKGRMREMOTE);
537 usage();
538 /* NOTREACHED */
541 if (pkgverbose != 0) {
542 progerr(ERR_SPOOLDIR_AND_PKGVERBOSE);
543 usage();
544 /* NOTREACHED */
547 if (is_an_inst_root() != 0) {
548 progerr(ERR_SPOOLDIR_AND_INST_ROOT);
549 usage();
550 /* NOTREACHED */
554 /* -V cannot be used with -A */
556 if (no_map_client && pkgrmremote) {
557 progerr(ERR_V_USED_AND_PKGRMREMOTE);
558 usage();
559 /* NOTREACHED */
562 /* -n used without pkg names or category */
564 if (nointeract && (optind == argc) && (catg_arg == NULL)) {
565 progerr(ERR_BAD_N_PKGRM);
566 usage();
567 /* NOTREACHED */
570 /* Error if specified zone list isn't valid on target */
571 if (usedZoneList && z_verify_zone_spec() == -1)
572 usage();
575 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler
578 /* hold SIGINT/SIGHUP interrupts */
580 (void) sighold(SIGHUP);
581 (void) sighold(SIGINT);
583 /* connect quit.c:trap() to SIGINT */
585 nact.sa_handler = quitGetTrapHandler();
586 nact.sa_flags = SA_RESTART;
587 (void) sigemptyset(&nact.sa_mask);
589 (void) sigaction(SIGINT, &nact, &oact);
591 /* connect quit.c:trap() to SIGHUP */
593 nact.sa_handler = quitGetTrapHandler();
594 nact.sa_flags = SA_RESTART;
595 (void) sigemptyset(&nact.sa_mask);
597 (void) sigaction(SIGHUP, &nact, &oact);
599 /* release hold on signals */
601 (void) sigrelse(SIGHUP);
602 (void) sigrelse(SIGINT);
604 /* establish temporary directory to use */
606 tmpdir = getenv("TMPDIR");
607 if (tmpdir == NULL) {
608 tmpdir = P_tmpdir;
611 echoDebug(DBG_PKGRM_TMPDIR, tmpdir);
613 /* initialize path parameters */
615 set_PKGpaths(get_inst_root());
618 * initialize installation admin parameters - if removing from a spool
619 * directory then the admin file is ignore.
622 if (spoolDir == NULL) {
623 echoDebug(DBG_PKGRM_ADMINFILE, admnfile ? admnfile : "");
624 setadminFile(admnfile);
628 * if running in the global zone, and non-global zones exist, then
629 * enable hollow package support so that any packages that are marked
630 * SUNW_PKG_HOLLOW=true will be correctly removed in non-global zones
631 * when removed directly in the global zone by the global zone admin.
634 if (is_depend_pkginfo_DB()) {
635 echoDebug(DBG_PKGRM_HOLLOW_ENABLED);
636 } else if ((z_running_in_global_zone() == B_TRUE) &&
637 (z_non_global_zones_exist() == B_TRUE)) {
638 echoDebug(DBG_PKGRM_ENABLING_HOLLOW);
639 set_depend_pkginfo_DB(B_TRUE);
643 * See if user wants this to be handled as an old style pkg.
644 * NOTE : the ``exception_pkg()'' stuff is to be used only
645 * through on495. This function comes out for on1095. See
646 * PSARC 1993-546. -- JST
648 if (getenv("NONABI_SCRIPTS") != NULL) {
649 old_pkg = 1;
653 * See if the user wants to process symlinks consistent with
654 * the old behavior.
657 if (getenv("PKG_NONABI_SYMLINKS") != NULL) {
658 old_symlinks = 1;
661 if (devtype((spoolDir ? spoolDir : get_PKGLOC()), &pkgdev) ||
662 pkgdev.dirname == NULL) {
663 progerr(ERR_BAD_DEVICE, spoolDir ? spoolDir : get_PKGLOC());
664 quit(1);
665 /* NOTREACHED */
668 pkgdir = pkgdev.dirname;
669 repeat = ((optind >= argc) && pkgdev.mount);
672 * error if there are packages on the command line and a category
673 * was specified
676 if (optind < argc && catg_arg != NULL) {
677 progerr(ERR_PKGS_AND_CAT_PKGRM);
678 usage();
679 /* NOTREACHED */
683 * ********************************************************************
684 * main package processing "loop"
685 * ********************************************************************
688 for (;;) {
689 boolean_t b;
690 char **pkglist; /* points to array of pkgs */
693 * mount the spool device if required
696 if (pkgdev.mount) {
697 if (n = pkgmount(&pkgdev, NULL, 0, 0, 1)) {
698 quit(n);
699 /* NOTREACHED */
703 if (chdir(pkgdev.dirname)) {
704 progerr(ERR_CHDIR, pkgdev.dirname);
705 quit(1);
706 /* NOTREACHED */
710 * spool device mounted/available - get the list of the
711 * packages to remove
714 n = pkgGetPackageList(&pkglist, argv, optind,
715 catg_arg, category, &pkgdev);
717 switch (n) {
718 case -1: /* no packages found */
719 echoDebug(DBG_PKGLIST_RM_NONFOUND,
720 PSTR(pkgdev.dirname));
721 progerr(ERR_NOPKGS, pkgdev.dirname);
722 quit(1);
723 /* NOTREACHED */
725 case 0: /* packages found */
726 break;
728 default: /* "quit" error */
729 echoDebug(DBG_PKGLIST_RM_ERROR,
730 pkgdev.dirname, n);
731 quit(n);
732 /* NOTREACHED */
736 * count the number of packages to remove
737 * NOTE: npkgs is a global variable that is referenced by quit.c
738 * when error messages are generated - it is referenced directly
739 * by the other functions called below...
742 for (npkgs = 0; pkglist[npkgs] != (char *)NULL; /* void */) {
743 pkgLgth = strlen(pkglist[npkgs]);
744 if (pkgLgth > longestPkg) {
745 longestPkg = pkgLgth;
747 echoDebug(DBG_PKG_SELECTED, npkgs, pkglist[npkgs]);
748 npkgs++;
751 /* output number of packages to be removed */
753 echoDebug(DBG_NUM_PKGS_TO_REMOVE, npkgs, longestPkg);
756 * package list generated - remove packages
759 b = remove_packages(pkglist, nodelete, longestPkg, repeat,
760 altBinDir, pkgdev.dirname, spoolDir, noZones);
763 * unmount the spool directory if necessary
766 if (pkgdev.mount) {
767 (void) chdir("/");
768 if (pkgumount(&pkgdev)) {
769 progerr(ERR_PKGUNMOUNT, pkgdev.bdevice);
770 quit(99);
771 /* NOTREACHED */
777 * continue with next sequence of packages if continue set
780 if (b == B_TRUE) {
781 continue;
785 * not continuing - quit with 0 exit code
788 quit(0);
789 /* NOTREACHED */
790 #ifdef lint
791 return (0);
792 #endif /* lint */
797 * *****************************************************************************
798 * static internal (private) functions
799 * *****************************************************************************
803 * Name: doRemove
804 * Description: Remove a package from the global zone, and optionally from one
805 * or more non-global zones.
806 * Arguments: a_nodelete: should the files and scripts remain installed?
807 * - if != 0 pass -F flag to pkgremove - suppress
808 * the removal of any files and any class action scripts
809 * and suppress the running of any class action scripts.
810 * The package files remain but the package looks like it
811 * is not installed. This is mainly for use by upgrade.
812 * - if == 0 do not pass -F flag to pkgremove - all
813 * files and class action scripts are removed, and any
814 * appropriate class action scripts are run.
815 * a_altBinDir - pointer to string representing location of the
816 * pkgremove executable to run. If not NULL, then pass
817 * the path specified to the -b option to pkgremove.
818 * a_longestPkg - length of the longest package "name" (for
819 * output format alignment)
820 * a_adminFile - pointer to string representing the admin
821 * file to pass to pkgremove when removing a package from
822 * the global zone only. Typically the admin file used for
823 * the global zone is the admin file passed in by the user.
824 * If this is == NULL no admin file is given to pkgremove.
825 * a_zoneAdminFile - pointer to string representing the admin
826 * file to pass to pkgremove when removing the package
827 * from a non-global zone only. Typically the admin file
828 * used for non-global zones supresses all checks since
829 * the dependency checking is done for all zones first
830 * before proceeding.
831 * A zoneAdminFile MUST be specified if a_zlst != NULL.
832 * A zoneAdminFile must NOT be specified if a_zlst == NULL.
833 * a_zlst - list of zones to process; NULL if no zones to process.
834 * Returns: int (see ckreturn() function for details)
835 * 0 - success
836 * 1 - package operation failed (fatal error)
837 * 2 - non-fatal error (warning)
838 * 3 - user selected quit (operation interrupted)
839 * 4 - admin settings prevented operation
840 * 5 - interaction required and -n (non-interactive) specified
841 * "10" will be added to indicate "immediate reboot required"
842 * "20" will be added to indicate "reboot after install required"
845 static int
846 doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile,
847 char *a_zoneAdminFile, zoneList_t a_zlst)
849 boolean_t b;
850 char *zoneName;
851 char ans[MAX_INPUT];
852 int n;
853 int zoneIndex;
854 int zonesSkipped;
855 struct pkginfo *pinfo = (struct pkginfo *)NULL;
856 zone_state_t zst;
858 /* entry assertions */
860 if (a_zlst != (zoneList_t)NULL) {
861 /* zone list specified - zone admin file required */
862 assert(a_zoneAdminFile != (char *)NULL);
863 assert(*a_zoneAdminFile != '\0');
864 } else {
865 /* no zone list specified - no zone admin file needed */
866 assert(a_zoneAdminFile == (char *)NULL);
869 /* NOTE: required 'pkgdir' set to spool directory or NULL */
870 b = pkginfoIsPkgInstalled(&pinfo, pkginst);
871 if (b == B_FALSE) {
872 progerr(ERR_NO_SUCH_INSTANCE, pkginst);
873 pkginfoFree(&pinfo);
874 return (2);
877 /* entry debugging info */
879 echoDebug(DBG_DOREMOVE_ENTRY);
880 echoDebug(DBG_DOREMOVE_ARGS, PSTR(pinfo->pkginst), PSTR(pinfo->name),
881 PSTR(pinfo->arch), PSTR(pinfo->version), PSTR(pinfo->basedir),
882 PSTR(pinfo->catg), pinfo->status);
884 if (!nointeract) {
885 char fmt1[100];
887 /* create format based on max pkg name length */
889 (void) snprintf(fmt1, sizeof (fmt1), " %%-%d.%ds %%s",
890 a_longestPkg, a_longestPkg);
892 if (pinfo->status == PI_SPOOLED) {
893 echo(INFO_SPOOLED);
894 } else {
895 if (getuid()) {
896 progerr(ERR_NOT_ROOT, get_prog_name());
897 exit(1);
899 echo(INFO_INSTALL);
902 echo(fmt1, pinfo->pkginst, pinfo->name);
904 if (pinfo->arch || pinfo->version) {
905 char fmt2[100];
907 /* create format based on max pkg name length */
909 (void) snprintf(fmt2, sizeof (fmt2), " %%%d.%ds ",
910 a_longestPkg, a_longestPkg);
912 /* LINTED variable format specifier to fprintf() */
913 (void) fprintf(stderr, fmt2, "");
915 if (pinfo->arch) {
916 (void) fprintf(stderr, "(%s) ", pinfo->arch);
919 if (pinfo->version) {
920 (void) fprintf(stderr, "%s", pinfo->version);
923 (void) fprintf(stderr, "\n");
926 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONFIRM);
927 if (n != 0) {
928 quit(n);
929 /* NOTREACHED */
932 if (strchr("yY", *ans) == NULL) {
933 pkginfoFree(&pinfo);
934 return (0);
938 if (pinfo->status == PI_SPOOLED) {
939 /* removal from a directory */
940 echo(INFO_RMSPOOL, pkginst);
941 pkginfoFree(&pinfo);
942 return (rrmdir(pkginst));
945 /* exit if not root */
947 if (getuid()) {
948 progerr(ERR_NOT_ROOT, get_prog_name());
949 exit(1);
952 pkginfoFree(&pinfo);
954 zonesSkipped = 0;
956 if (interrupted != 0) {
957 echo(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
958 echoDebug(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
959 return (n);
962 echoDebug(DBG_REMOVE_FLAG_VALUES, "before pkgZoneRemove",
963 admnflag, doreboot, failflag, interrupted,
964 intrflag, ireboot, nullflag, warnflag);
966 for (zoneIndex = 0;
967 a_zlst != NULL &&
968 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != NULL;
969 zoneIndex++) {
971 /* skip the zone if it is NOT running */
973 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
974 if (zst != ZONE_STATE_RUNNING && zst != ZONE_STATE_MOUNTED) {
975 zonesSkipped++;
976 echoDebug(DBG_SKIPPING_ZONE, zoneName);
977 continue;
980 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
981 echoDebug(DBG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
984 * remove package from zone; use the zone admin file which
985 * suppresses all checks.
988 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex),
989 a_nodelete, a_altBinDir, a_zoneAdminFile,
990 zst, B_FALSE);
992 /* set success/fail condition variables */
994 ckreturn(n);
996 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
997 admnflag, doreboot, failflag, interrupted, intrflag,
998 ireboot, nullflag, warnflag);
1001 if (zonesSkipped > 0) {
1002 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
1004 for (zoneIndex = 0;
1005 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1006 (char *)NULL; zoneIndex++) {
1008 /* skip the zone if it IS running */
1010 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
1011 if (zst == ZONE_STATE_RUNNING ||
1012 zst == ZONE_STATE_MOUNTED) {
1013 zonesSkipped++;
1014 echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName);
1015 continue;
1018 /* skip the zone if it is NOT bootable */
1020 if (z_zlist_is_zone_runnable(a_zlst,
1021 zoneIndex) == B_FALSE) {
1022 echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName);
1023 echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE,
1024 zoneName);
1025 continue;
1028 /* mount up the zone */
1030 echo(MSG_BOOTING_ZONE, zoneName);
1031 echoDebug(DBG_BOOTING_ZONE, zoneName);
1033 b = z_zlist_change_zone_state(a_zlst, zoneIndex,
1034 ZONE_STATE_MOUNTED);
1035 if (b == B_FALSE) {
1036 progerr(ERR_CANNOT_BOOT_ZONE, zoneName);
1037 /* set fatal error return condition */
1038 ckreturn(1);
1039 continue;
1042 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
1045 * remove package from zone; use the zone admin file
1046 * which suppresses all checks.
1049 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst,
1050 zoneIndex), a_nodelete, a_altBinDir,
1051 a_zoneAdminFile, ZONE_STATE_MOUNTED, B_TRUE);
1053 /* set success/fail condition variables */
1055 ckreturn(n);
1057 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
1058 admnflag, doreboot, failflag, interrupted,
1059 intrflag, ireboot, nullflag, warnflag);
1061 /* restore original state of zone */
1063 echo(MSG_RESTORE_ZONE_STATE, zoneName);
1064 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
1066 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
1071 * Process global zone if it was either the only possible
1072 * target (no list of zones specified) or it appears in the list
1074 if (a_zlst == NULL || z_on_zone_spec(GLOBAL_ZONENAME)) {
1075 /* reset interrupted flag before calling pkgremove */
1076 interrupted = 0; /* last action was NOT quit */
1079 * call pkgremove for this package for the global zone;
1080 * use the admin file passed in by the user via -a.
1082 n = pkgRemove(a_nodelete, a_altBinDir, a_adminFile);
1084 /* set success/fail condition variables */
1085 ckreturn(n);
1088 return (n);
1092 * function to clear out any exisiting error return conditions that may have
1093 * been set by previous calls to ckreturn()
1095 static void
1096 resetreturn()
1098 admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */
1099 doreboot = 0; /* != 0 if reboot required after installation (>= 10) */
1100 failflag = 0; /* != 0 if fatal error has occurred (1) */
1101 intrflag = 0; /* != 0 if user selected quit (3) */
1102 ireboot = 0; /* != 0 if immediate reboot required (>= 20) */
1103 nullflag = 0; /* != 0 if admin interaction required (5) */
1104 warnflag = 0; /* != 0 if non-fatal error has occurred (2) */
1105 interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */
1109 * function which checks the indicated return value
1110 * and indicates disposition of installation
1112 static void
1113 ckreturn(int retcode)
1116 * entry debugging info
1119 echoDebug(DBG_PKGRM_CKRETURN, retcode, PSTR(pkginst));
1121 switch (retcode) {
1122 case 0: /* successful */
1123 case 10:
1124 case 20:
1125 break; /* empty case */
1127 case 1: /* package operation failed (fatal error) */
1128 case 11:
1129 case 21:
1130 failflag++;
1131 interrupted++;
1132 break;
1134 case 2: /* non-fatal error (warning) */
1135 case 12:
1136 case 22:
1137 warnflag++;
1138 interrupted++;
1139 break;
1141 case 3: /* user selected quit; operation interrupted */
1142 case 13:
1143 case 23:
1144 intrflag++;
1145 interrupted++;
1146 break;
1148 case 4: /* admin settings prevented operation */
1149 case 14:
1150 case 24:
1151 admnflag++;
1152 interrupted++;
1153 break;
1155 case 5: /* administration: interaction req (no -n) */
1156 case 15:
1157 case 25:
1158 nullflag++;
1159 interrupted++;
1160 break;
1162 default:
1163 failflag++;
1164 interrupted++;
1165 return;
1168 if (retcode >= 20) {
1169 ireboot++;
1170 } else if (retcode >= 10) {
1171 doreboot++;
1175 static int
1176 pkgZoneCheckRemove(char *a_zoneName, char *a_altBinDir, char *a_adminFile,
1177 char *a_stdoutPath, zone_state_t a_zoneState, boolean_t tmpzone)
1179 char *arg[MAXARGS];
1180 char *p;
1181 char adminfd_path[PATH_MAX];
1182 char path[PATH_MAX];
1183 int fds[MAX_FDS];
1184 int maxfds;
1185 int n;
1186 int nargs;
1188 /* entry assertions */
1190 assert(a_zoneName != (char *)NULL);
1191 assert(*a_zoneName != '\0');
1193 /* entry debugging info */
1195 echoDebug(DBG_PKGZONECHECKREMOVE_ENTRY);
1196 echoDebug(DBG_PKGZONECHECKREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1197 PSTR(pkgdev.dirname), PSTR(a_adminFile), PSTR(a_stdoutPath));
1199 /* generate path to pkgremove */
1201 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1202 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1204 /* start at first file descriptor */
1206 maxfds = 0;
1209 * generate argument list for call to pkgremove
1212 /* start at argument 0 */
1214 nargs = 0;
1216 /* first argument is path to executable */
1218 arg[nargs++] = strdup(path);
1220 /* second argument is always: pass -O debug to pkgremove: debug mode */
1222 if (debugFlag == B_TRUE) {
1223 arg[nargs++] = "-O";
1224 arg[nargs++] = "debug";
1227 /* pkgrm -b dir: pass -b to pkgremove */
1229 if (a_altBinDir != (char *)NULL) {
1230 arg[nargs++] = "-b";
1231 arg[nargs++] = a_altBinDir;
1235 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1236 * pkg requiring operator interaction during a procedure script
1237 * (common before on1093)
1240 if (old_pkg) {
1241 arg[nargs++] = "-o";
1245 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1246 * symlinks consistent with old behavior
1249 if (old_symlinks) {
1250 arg[nargs++] = "-y";
1253 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1255 arg[nargs++] = "-M";
1257 /* pkgrm -A: pass -A to pkgremove */
1259 if (pkgrmremote) {
1260 arg[nargs++] = "-A";
1263 /* pkgrm -v: pass -v to pkgremove: never trace scripts */
1265 /* pass "-O enable-hollow-package-support" */
1267 if (is_depend_pkginfo_DB()) {
1268 arg[nargs++] = "-O";
1269 arg[nargs++] = "enable-hollow-package-support";
1272 /* pass -n to pkgremove: always in noninteractive mode */
1274 arg[nargs++] = "-n";
1276 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1278 if (a_adminFile) {
1279 int fd;
1280 fd = openLocal(a_adminFile, O_RDONLY, tmpdir);
1281 if (fd < 0) {
1282 progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile,
1283 errno, strerror(errno));
1284 return (1);
1286 (void) snprintf(adminfd_path, sizeof (adminfd_path),
1287 "/proc/self/fd/%d", fd);
1288 fds[maxfds++] = fd;
1289 arg[nargs++] = "-a";
1290 arg[nargs++] = strdup(adminfd_path);
1294 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1296 if (a_zoneState == ZONE_STATE_MOUNTED) {
1297 arg[nargs++] = "-R";
1298 arg[nargs++] = "/a";
1301 /* pkgrm -F: pass -F to pkgremove: always update DB only */
1303 arg[nargs++] = "-F";
1305 /* pass "-O preremovecheck" */
1307 arg[nargs++] = "-O";
1308 arg[nargs++] = "preremovecheck";
1310 /* add "-O addzonename" */
1312 arg[nargs++] = "-O";
1313 arg[nargs++] = "addzonename";
1316 * add parent zone info/type
1319 p = z_get_zonename();
1320 if ((p != NULL) && (*p != '\0')) {
1321 char zn[MAXPATHLEN];
1322 (void) snprintf(zn, sizeof (zn),
1323 "parent-zone-name=%s", p);
1324 arg[nargs++] = "-O";
1325 arg[nargs++] = strdup(zn);
1328 /* current zone type */
1330 arg[nargs++] = "-O";
1331 if (z_running_in_global_zone() == B_TRUE) {
1332 char zn[MAXPATHLEN];
1333 (void) snprintf(zn, sizeof (zn),
1334 "parent-zone-type=%s",
1335 TAG_VALUE_GLOBAL_ZONE);
1336 arg[nargs++] = strdup(zn);
1337 } else {
1338 char zn[MAXPATHLEN];
1339 (void) snprintf(zn, sizeof (zn),
1340 "parent-zone-type=%s",
1341 TAG_VALUE_NONGLOBAL_ZONE);
1342 arg[nargs++] = strdup(zn);
1345 /* Add arguments how to start the pkgserv */
1347 arg[nargs++] = "-O";
1348 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1350 /* pass -N to pkgremove: program name to report */
1352 arg[nargs++] = "-N";
1353 arg[nargs++] = get_prog_name();
1355 /* add package instance name */
1357 arg[nargs++] = pkginst;
1359 /* terminate argument list */
1361 arg[nargs++] = NULL;
1363 /* execute pkgremove command */
1365 if (debugFlag == B_TRUE) {
1366 echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]);
1367 for (n = 0; arg[n]; n++) {
1368 echoDebug(DBG_ARG, n, arg[n]);
1372 /* terminate file descriptor list */
1374 fds[maxfds] = -1;
1376 /* exec command in zone */
1378 n = z_zone_exec(a_zoneName, path, arg, a_stdoutPath, (char *)NULL, fds);
1380 echoDebug(DBG_ZONE_EXEC_EXIT, a_zoneName, arg[0], n,
1381 PSTR(a_stdoutPath));
1384 * close any files that were opened for use by the
1385 * /proc/self/fd interface so they could be passed to programs
1386 * via the z_zone_exec() interface
1389 for (; maxfds > 0; maxfds--) {
1390 (void) close(fds[maxfds-1]);
1393 /* return results of pkgremove in zone execution */
1395 return (n);
1398 static int
1399 pkgZoneRemove(char *a_zoneName, int a_nodelete, char *a_altBinDir,
1400 char *a_adminFile, zone_state_t a_zoneState, boolean_t tmpzone)
1402 char *arg[MAXARGS];
1403 char *p;
1404 char adminfd_path[PATH_MAX];
1405 char path[PATH_MAX];
1406 int fds[MAX_FDS];
1407 int maxfds;
1408 int n;
1409 int nargs;
1411 /* entry assertions */
1413 assert(a_zoneName != (char *)NULL);
1414 assert(*a_zoneName != '\0');
1416 /* entry debugging info */
1418 echoDebug(DBG_PKGZONEREMOVE_ENTRY);
1419 echoDebug(DBG_PKGZONEREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1420 PSTR(pkgdev.dirname), a_nodelete, PSTR(a_adminFile));
1422 /* generate path to pkgremove */
1424 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1425 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1427 /* start at first file descriptor */
1429 maxfds = 0;
1432 * generate argument list for call to pkgremove
1435 /* start at argument 0 */
1437 nargs = 0;
1439 /* first argument is path to executable */
1441 arg[nargs++] = strdup(path);
1443 /* second argument is always: pass -O debug to pkgremove: debug mode */
1445 if (debugFlag == B_TRUE) {
1446 arg[nargs++] = "-O";
1447 arg[nargs++] = "debug";
1450 /* pkgrm -b dir: pass -b to pkgremove */
1452 if (a_altBinDir != (char *)NULL) {
1453 arg[nargs++] = "-b";
1454 arg[nargs++] = a_altBinDir;
1458 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1459 * pkg requiring operator interaction during a procedure script
1460 * (common before on1093)
1463 if (old_pkg) {
1464 arg[nargs++] = "-o";
1468 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1469 * symlinks consistent with old behavior
1472 if (old_symlinks) {
1473 arg[nargs++] = "-y";
1476 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1478 arg[nargs++] = "-M";
1480 /* pkgrm -A: pass -A to pkgremove */
1482 if (pkgrmremote) {
1483 arg[nargs++] = "-A";
1486 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1488 if (pkgverbose) {
1489 arg[nargs++] = "-v";
1492 /* pass "-O enable-hollow-package-support" */
1494 if (is_depend_pkginfo_DB()) {
1495 arg[nargs++] = "-O";
1496 arg[nargs++] = "enable-hollow-package-support";
1499 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1501 if (nointeract) {
1502 arg[nargs++] = "-n";
1505 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1507 if (a_adminFile) {
1508 int fd;
1509 fd = openLocal(a_adminFile, O_RDONLY, tmpdir);
1510 if (fd < 0) {
1511 progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile,
1512 errno, strerror(errno));
1513 return (1);
1515 (void) snprintf(adminfd_path, sizeof (adminfd_path),
1516 "/proc/self/fd/%d", fd);
1517 fds[maxfds++] = fd;
1518 arg[nargs++] = "-a";
1519 arg[nargs++] = adminfd_path;
1523 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1525 if (a_zoneState == ZONE_STATE_MOUNTED) {
1526 arg[nargs++] = "-R";
1527 arg[nargs++] = "/a";
1530 /* pkgrm -F: pass -F to pkgremove: update DB only */
1532 if (a_nodelete) {
1533 arg[nargs++] = "-F";
1536 /* add "-O addzonename" */
1538 arg[nargs++] = "-O";
1539 arg[nargs++] = "addzonename";
1542 * add parent zone info/type
1545 p = z_get_zonename();
1546 if ((p != NULL) && (*p != '\0')) {
1547 char zn[MAXPATHLEN];
1548 (void) snprintf(zn, sizeof (zn),
1549 "parent-zone-name=%s", p);
1550 arg[nargs++] = "-O";
1551 arg[nargs++] = strdup(zn);
1554 /* current zone type */
1556 arg[nargs++] = "-O";
1557 if (z_running_in_global_zone() == B_TRUE) {
1558 char zn[MAXPATHLEN];
1559 (void) snprintf(zn, sizeof (zn),
1560 "parent-zone-type=%s",
1561 TAG_VALUE_GLOBAL_ZONE);
1562 arg[nargs++] = strdup(zn);
1563 } else {
1564 char zn[MAXPATHLEN];
1565 (void) snprintf(zn, sizeof (zn),
1566 "parent-zone-type=%s",
1567 TAG_VALUE_NONGLOBAL_ZONE);
1568 arg[nargs++] = strdup(zn);
1571 /* Add arguments how to start the pkgserv */
1573 arg[nargs++] = "-O";
1574 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1576 /* pass -N to pkgremove: program name to report */
1578 arg[nargs++] = "-N";
1579 arg[nargs++] = get_prog_name();
1581 /* add package instance name */
1583 arg[nargs++] = pkginst;
1585 /* terminate argument list */
1587 arg[nargs++] = NULL;
1589 /* execute pkgremove command */
1591 if (debugFlag == B_TRUE) {
1592 echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]);
1593 for (n = 0; arg[n]; n++) {
1594 echoDebug(DBG_ARG, n, arg[n]);
1598 /* terminate file descriptor list */
1600 fds[maxfds] = -1;
1602 /* exec command in zone */
1604 n = z_zone_exec(a_zoneName, path, arg, (char *)NULL, (char *)NULL, fds);
1607 * close any files that were opened for use by the
1608 * /proc/self/fd interface so they could be passed to programs
1609 * via the z_zone_exec() interface
1612 for (; maxfds > 0; maxfds--) {
1613 (void) close(fds[maxfds-1]);
1616 return (n);
1620 * Name: pkgRemove
1621 * Description: Invoke pkgremove in the current zone to perform a remove
1622 * of a single package from the current zone or standalone system
1623 * Arguments: a_nodelete: should the files and scripts remain installed?
1624 * - if != 0 pass -F flag to pkgremove - suppress
1625 * the removal of any files and any class action scripts
1626 * and suppress the running of any class action scripts.
1627 * The package files remain but the package looks like it
1628 * is not installed. This is mainly for use by upgrade.
1629 * - if == 0 do not pass -F flag to pkgremove - all
1630 * files and class action scripts are removed, and any
1631 * appropriate class action scripts are run.
1632 * a_altBinDir - pointer to string representing location of the
1633 * pkgremove executable to run. If not NULL, then pass
1634 * the path specified to the -b option to pkgremove.
1635 * a_adminFile - pointer to string representing the admin
1636 * file to pass to pkgremove when removing the package.
1637 * If this is == NULL no admin file is given to pkgremove.
1638 * Returns: int (see ckreturn() function for details)
1639 * 0 - success
1640 * 1 - package operation failed (fatal error)
1641 * 2 - non-fatal error (warning)
1642 * 3 - user selected quit (operation interrupted)
1643 * 4 - admin settings prevented operation
1644 * 5 - interaction required and -n (non-interactive) specified
1645 * "10" will be added to indicate "immediate reboot required"
1646 * "20" will be added to indicate "reboot after install required"
1649 static int
1650 pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile)
1652 char *arg[MAXARGS];
1653 char *p;
1654 char path[PATH_MAX];
1655 int n;
1656 int nargs;
1658 /* entry debugging info */
1660 echoDebug(DBG_PKGREMOVE_ENTRY);
1661 echoDebug(DBG_PKGREMOVE_ARGS, PSTR(pkginst), PSTR(pkgdev.dirname),
1662 a_nodelete, PSTR(a_adminFile));
1664 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1665 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1667 nargs = 0;
1669 /* first argument is path to executable */
1671 arg[nargs++] = strdup(path);
1673 /* second argument is always: pass -O debug to pkgremove: debug mode */
1675 if (debugFlag == B_TRUE) {
1676 arg[nargs++] = "-O";
1677 arg[nargs++] = "debug";
1680 /* Add arguments how to start the pkgserv */
1682 arg[nargs++] = "-O";
1683 arg[nargs++] = pkgmodeargument(pkgservergetmode());
1685 /* pkgrm -b dir: pass -b to pkgremove */
1687 if (a_altBinDir != (char *)NULL) {
1688 arg[nargs++] = "-b";
1689 arg[nargs++] = a_altBinDir;
1693 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1694 * pkg requiring operator interaction during a procedure script
1695 * (common before on1093)
1698 if (old_pkg) {
1699 arg[nargs++] = "-o";
1703 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1704 * symlinks consistent with old behavior
1707 if (old_symlinks) {
1708 arg[nargs++] = "-y";
1711 /* pkgrm -M: pass -M to pkgrm: dont mount client file systems */
1713 if (no_map_client) {
1714 arg[nargs++] = "-M";
1717 /* pkgrm -A: pass -A to pkgrm */
1719 if (pkgrmremote) {
1720 arg[nargs++] = "-A";
1723 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1725 if (pkgverbose) {
1726 arg[nargs++] = "-v";
1729 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1731 if (nointeract) {
1732 arg[nargs++] = "-n";
1735 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1737 if (a_adminFile) {
1738 arg[nargs++] = "-a";
1739 arg[nargs++] = strdup(a_adminFile);
1742 /* pkgrm -V vfstab: pass -V vfstab to pkgremove: alternate vfstab */
1744 if (vfstab_file) {
1745 arg[nargs++] = "-V";
1746 arg[nargs++] = vfstab_file;
1749 /* pkgrm -R root: pass -R root to pkgremove: alternative root */
1751 if (is_an_inst_root()) {
1752 arg[nargs++] = "-R";
1753 arg[nargs++] = get_inst_root();
1756 /* pkgrm -F: pass -F to pkgremove: update DB only */
1758 if (a_nodelete) {
1759 arg[nargs++] = "-F";
1763 * add parent zone info/type
1766 p = z_get_zonename();
1767 if ((p != NULL) && (*p != '\0')) {
1768 char zn[MAXPATHLEN];
1769 (void) snprintf(zn, sizeof (zn),
1770 "parent-zone-name=%s", p);
1771 arg[nargs++] = "-O";
1772 arg[nargs++] = strdup(zn);
1775 /* current zone type */
1777 arg[nargs++] = "-O";
1778 if (z_running_in_global_zone() == B_TRUE) {
1779 char zn[MAXPATHLEN];
1780 (void) snprintf(zn, sizeof (zn),
1781 "parent-zone-type=%s",
1782 TAG_VALUE_GLOBAL_ZONE);
1783 arg[nargs++] = strdup(zn);
1784 } else {
1785 char zn[MAXPATHLEN];
1786 (void) snprintf(zn, sizeof (zn),
1787 "parent-zone-type=%s",
1788 TAG_VALUE_NONGLOBAL_ZONE);
1789 arg[nargs++] = strdup(zn);
1792 /* pass -N to pkgremove: program name to report */
1794 arg[nargs++] = "-N";
1795 arg[nargs++] = get_prog_name();
1797 /* add package instance name */
1799 arg[nargs++] = pkginst;
1801 /* terminate argument list */
1803 arg[nargs++] = NULL;
1806 * run the appropriate pkgremove command in the specified zone
1809 if (debugFlag == B_TRUE) {
1810 echoDebug(DBG_ZONE_EXEC_ENTER, "global", arg[0]);
1811 for (n = 0; arg[n]; n++) {
1812 echoDebug(DBG_ARG, n, arg[n]);
1816 /* execute pkgremove command */
1818 n = pkgexecv(NULL, NULL, NULL, NULL, arg);
1820 /* return results of pkgrm in this zone */
1822 return (n);
1825 static void
1826 usage(void)
1828 char *prog = get_prog_name();
1830 (void) fprintf(stderr, ERR_USAGE_PKGRM, prog, prog);
1831 exit(1);
1835 * Name: remove_packages_in_global_with_zones
1836 * Description: Remove packages from the global zone and from non-global zones
1837 * when run from the global zone and when non-global zones are
1838 * present.
1839 * Arguments: a_pkgList - pointer to array of strings, each string specifying
1840 * the name of one package to be removed.
1841 * a_nodelete: should the files and scripts remain installed?
1842 * - if != 0 pass -F flag to pkgremove - suppress
1843 * the removal of any files and any class action scripts
1844 * and suppress the running of any class action scripts.
1845 * The package files remain but the package looks like it
1846 * is not installed. This is mainly for use by upgrade.
1847 * - if == 0 do not pass -F flag to pkgremove - all
1848 * files and class action scripts are removed, and any
1849 * appropriate class action scripts are run.
1850 * a_longestPkg - length of the longest package "name" (for
1851 * output format alignment)
1852 * a_repeat - are there more packages avialable in "optind"
1853 * - B_TRUE - process packages from optind
1854 * - B_FALSE - do not process packages from optind
1855 * a_altBinDir - pointer to string representing location of the
1856 * pkgremove executable to run. If not NULL, then pass
1857 * the path specified to the -b option to pkgremove.
1858 * a_pkgdir - pointer to string representing the directory
1859 * where the packages to be removed are located.
1860 * a_zlst - list of zones to process; NULL if no zones to process.
1861 * Returns: int (see ckreturn() function for details)
1862 * 0 - success
1863 * 1 - package operation failed (fatal error)
1864 * 2 - non-fatal error (warning)
1865 * 3 - user selected quit (operation interrupted)
1866 * 4 - admin settings prevented operation
1867 * 5 - interaction required and -n (non-interactive) specified
1868 * "10" will be added to indicate "immediate reboot required"
1869 * "20" will be added to indicate "reboot after install required"
1872 static boolean_t
1873 remove_packages_in_global_with_zones(char **a_pkgList, int a_nodelete,
1874 int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir,
1875 zoneList_t a_zlst)
1877 static char *zoneAdminFile = (char *)NULL;
1879 boolean_t b;
1880 char *zoneName;
1881 char *scratchName;
1882 char preremovecheckPath[PATH_MAX+1];
1883 int i;
1884 int n;
1885 int savenpkgs = npkgs;
1886 int zoneIndex;
1887 int zonesSkipped;
1888 zone_state_t zst;
1890 /* entry assertions */
1892 assert(a_zlst != (zoneList_t)NULL);
1893 assert(a_pkgList != (char **)NULL);
1894 assert(a_longestPkg > 0);
1895 assert(a_pkgdir != (char *)NULL);
1896 assert(*a_pkgdir != '\0');
1898 /* entry debugging info */
1900 echoDebug(DBG_PKGREMPKGSGZWNGZ_ENTRY);
1901 echoDebug(DBG_PKGREMPKGSGZWNGZ_ARGS, a_nodelete, a_longestPkg,
1902 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
1904 /* check all packages */
1906 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
1907 quit(1);
1910 /* create temporary directory for use by zone operations */
1912 create_zone_tempdir(&zoneTempDir, tmpdir);
1914 /* create hands off settings admin file for use in a non-global zone */
1916 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
1919 * all of the packages (as listed in the package list) are
1920 * removed one at a time from all non-global zones and then
1921 * from the global zone.
1924 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
1925 /* reset interrupted flag before calling pkgremove */
1927 interrupted = 0; /* last action was NOT quit */
1929 /* skip package if it is "in the global zone only" */
1931 if (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE) {
1932 continue;
1936 * if operation failed in global zone do not propagate to
1937 * non-global zones
1940 zonesSkipped = 0;
1942 if (interrupted != 0) {
1943 echo(MSG_DOREMOVE_INTERRUPTED, pkginst);
1944 echoDebug(DBG_DOREMOVE_INTERRUPTED, pkginst);
1945 break;
1948 echoDebug(DBG_REMOVE_FLAG_VALUES, "before loop",
1949 admnflag, doreboot, failflag, interrupted,
1950 intrflag, ireboot, nullflag, warnflag);
1952 for (zoneIndex = 0;
1953 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1954 (char *)NULL; zoneIndex++) {
1956 /* skip the zone if it is NOT running */
1958 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
1959 if (zst != ZONE_STATE_RUNNING &&
1960 zst != ZONE_STATE_MOUNTED) {
1961 zonesSkipped++;
1962 echoDebug(DBG_SKIPPING_ZONE, zoneName);
1963 continue;
1966 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
1967 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
1968 zoneName);
1970 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
1972 (void) snprintf(preremovecheckPath,
1973 sizeof (preremovecheckPath),
1974 "%s/%s.%s.preremovecheck.txt",
1975 zoneTempDir, pkginst, scratchName);
1978 * dependency check this package this zone; use the
1979 * user supplied admin file so that the appropriate
1980 * level of dependency checking is (or is not) done.
1983 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
1984 admnfile, preremovecheckPath,
1985 zst, B_FALSE);
1987 /* set success/fail condition variables */
1989 ckreturn(n);
1991 echoDebug(DBG_REMOVE_FLAG_VALUES,
1992 "after pkgzonecheckremove",
1993 admnflag, doreboot, failflag, interrupted,
1994 intrflag, ireboot, nullflag, warnflag);
1997 if (zonesSkipped == 0) {
1998 continue;
2001 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
2003 for (zoneIndex = 0;
2004 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
2005 (char *)NULL; zoneIndex++) {
2007 /* skip the zone if it IS running */
2009 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
2010 if (zst == ZONE_STATE_RUNNING ||
2011 zst == ZONE_STATE_MOUNTED) {
2012 zonesSkipped++;
2013 echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName);
2014 continue;
2017 /* skip the zone if it is NOT bootable */
2019 if (z_zlist_is_zone_runnable(a_zlst,
2020 zoneIndex) == B_FALSE) {
2021 echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName);
2022 echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE,
2023 zoneName);
2024 continue;
2027 /* mount up the zone */
2029 echo(MSG_BOOTING_ZONE, zoneName);
2030 echoDebug(DBG_BOOTING_ZONE, zoneName);
2032 b = z_zlist_change_zone_state(a_zlst, zoneIndex,
2033 ZONE_STATE_MOUNTED);
2034 if (b == B_FALSE) {
2035 progerr(ERR_CANNOT_BOOT_ZONE, zoneName);
2036 /* set fatal error return condition */
2037 ckreturn(1);
2038 continue;
2041 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
2042 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
2043 zoneName);
2045 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
2047 (void) snprintf(preremovecheckPath,
2048 sizeof (preremovecheckPath),
2049 "%s/%s.%s.preremovecheck.txt",
2050 zoneTempDir, pkginst, scratchName);
2053 * dependency check this package this zone; use the
2054 * user supplied admin file so that the appropriate
2055 * level of dependency checking is (or is not) done.
2058 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
2059 admnfile, preremovecheckPath,
2060 ZONE_STATE_MOUNTED, B_TRUE);
2062 /* set success/fail condition variables */
2064 ckreturn(n);
2066 echoDebug(DBG_REMOVE_FLAG_VALUES,
2067 "after pkgzonecheckremove",
2068 admnflag, doreboot, failflag, interrupted,
2069 intrflag, ireboot, nullflag, warnflag);
2071 /* restore original state of zone */
2073 echo(MSG_RESTORE_ZONE_STATE, zoneName);
2074 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
2076 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
2078 npkgs--;
2082 * look at all pre-remove check files
2085 i = preremove_verify(a_pkgList, a_zlst, zoneTempDir);
2086 if (i != 0) {
2087 quit(i);
2090 npkgs = savenpkgs;
2093 * reset all error return condition variables that may have been
2094 * set during package removal dependency checking so that they
2095 * do not reflect on the success/failure of the actual package
2096 * removal operations
2099 resetreturn();
2102 * all of the packages (as listed in the package list) are
2103 * removed one at a time.
2106 interrupted = 0;
2107 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2108 boolean_t in_gz_only;
2109 started = 0;
2111 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2112 continue;
2115 in_gz_only = pkgIsPkgInGzOnly(get_inst_root(), pkginst);
2117 /* reset interrupted flag before calling pkgremove */
2119 interrupted = 0;
2122 * pkgrm invoked from within the global zone and there are
2123 * non-global zones configured:
2124 * Remove the package from the global zone.
2125 * If not removing the package from the global zone only,
2126 * then remove the package from the list of zones specified.
2129 if (in_gz_only) {
2130 /* global zone only */
2131 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2132 admnfile, (char *)NULL, (zoneList_t)NULL);
2133 } else {
2134 /* global zone and non-global zones */
2135 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2136 zoneAdminFile, zoneAdminFile, a_zlst);
2139 /* set success/fail condition variables */
2141 ckreturn(n);
2143 npkgs--;
2147 * all packages in the package list have been removed.
2148 * Continue with removal if:
2149 * -- immediate reboot is NOT required
2150 * -- there are more packages to remove
2151 * else return do NOT continue.
2154 if ((ireboot == 0) && (a_repeat != 0)) {
2155 return (B_TRUE);
2158 /* return 'dont continue' */
2160 return (B_FALSE);
2164 * Name: remove_packages_in_nonglobal_zone
2165 * Description: Remove packages in a non-global zone when run from a
2166 * non-global zone.
2167 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2168 * the name of one package to be removed.
2169 * a_nodelete: should the files and scripts remain installed?
2170 * - if != 0 pass -F flag to pkgremove - suppress
2171 * the removal of any files and any class action scripts
2172 * and suppress the running of any class action scripts.
2173 * The package files remain but the package looks like it
2174 * is not installed. This is mainly for use by upgrade.
2175 * - if == 0 do not pass -F flag to pkgremove - all
2176 * files and class action scripts are removed, and any
2177 * appropriate class action scripts are run.
2178 * a_longestPkg - length of the longest package "name" (for
2179 * output format alignment)
2180 * a_repeat - are there more packages avialable in "optind"
2181 * - B_TRUE - process packages from optind
2182 * - B_FALSE - do not process packages from optind
2183 * a_altBinDir - pointer to string representing location of the
2184 * pkgremove executable to run. If not NULL, then pass
2185 * the path specified to the -b option to pkgremove.
2186 * a_pkgdir - pointer to string representing the directory
2187 * where the packages to be removed are located.
2188 * Returns: int (see ckreturn() function for details)
2189 * 0 - success
2190 * 1 - package operation failed (fatal error)
2191 * 2 - non-fatal error (warning)
2192 * 3 - user selected quit (operation interrupted)
2193 * 4 - admin settings prevented operation
2194 * 5 - interaction required and -n (non-interactive) specified
2195 * "10" will be added to indicate "immediate reboot required"
2196 * "20" will be added to indicate "reboot after install required"
2199 static boolean_t
2200 remove_packages_in_nonglobal_zone(char **a_pkgList, int a_nodelete,
2201 int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir)
2203 static char *zoneAdminFile = (char *)NULL;
2205 int n;
2206 int i;
2208 /* entry assertions */
2210 assert(a_pkgList != (char **)NULL);
2211 assert(a_longestPkg > 0);
2212 assert(a_pkgdir != (char *)NULL);
2213 assert(*a_pkgdir != '\0');
2215 /* entry debugging info */
2217 echoDebug(DBG_PKGREMPKGSNGZ_ENTRY);
2218 echoDebug(DBG_PKGREMPKGSNGZ_ARGS, a_nodelete, a_longestPkg,
2219 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
2221 /* check all package */
2223 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
2224 quit(1);
2227 /* create temporary directory for use by zone operations */
2229 create_zone_tempdir(&zoneTempDir, tmpdir);
2231 /* create hands off settings admin file for use in a non-global zone */
2233 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
2236 * all of the packages (as listed in the package list) are
2237 * removed one at a time.
2240 interrupted = 0;
2241 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2242 started = 0;
2244 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2245 continue;
2248 interrupted = 0;
2251 * pkgrm invoked from within a non-global zone: remove
2252 * the package from the current zone only - no non-global
2253 * zones are possible.
2256 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2257 admnfile, (char *)NULL, (zoneList_t)NULL);
2259 /* set success/fail condition variables */
2261 ckreturn(n);
2263 npkgs--;
2267 * all packages in the package list have been removed.
2268 * Continue with removal if:
2269 * -- immediate reboot is NOT required
2270 * -- there are more packages to remove
2271 * else return do NOT continue.
2274 if ((ireboot == 0) && (a_repeat != 0)) {
2275 return (B_TRUE);
2278 /* return 'dont continue' */
2280 return (B_FALSE);
2284 * Name: remove_packages_in_global_no_zones
2285 * Description: Remove packages from the global zone only when run in the
2286 * global zone and no non-global zones are installed.
2287 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2288 * the name of one package to be removed.
2289 * a_nodelete: should the files and scripts remain installed?
2290 * - if != 0 pass -F flag to pkgremove - suppress
2291 * the removal of any files and any class action scripts
2292 * and suppress the running of any class action scripts.
2293 * The package files remain but the package looks like it
2294 * is not installed. This is mainly for use by upgrade.
2295 * - if == 0 do not pass -F flag to pkgremove - all
2296 * files and class action scripts are removed, and any
2297 * appropriate class action scripts are run.
2298 * a_longestPkg - length of the longest package "name" (for
2299 * output format alignment)
2300 * a_repeat - are there more packages avialable in "optind"
2301 * - B_TRUE - process packages from optind
2302 * - B_FALSE - do not process packages from optind
2303 * a_altBinDir - pointer to string representing location of the
2304 * pkgremove executable to run. If not NULL, then pass
2305 * the path specified to the -b option to pkgremove.
2306 * Returns: int (see ckreturn() function for details)
2307 * 0 - success
2308 * 1 - package operation failed (fatal error)
2309 * 2 - non-fatal error (warning)
2310 * 3 - user selected quit (operation interrupted)
2311 * 4 - admin settings prevented operation
2312 * 5 - interaction required and -n (non-interactive) specified
2313 * "10" will be added to indicate "immediate reboot required"
2314 * "20" will be added to indicate "reboot after install required"
2317 static boolean_t
2318 remove_packages_in_global_no_zones(char **a_pkgList, int a_nodelete,
2319 int a_longestPkg, int a_repeat, char *a_altBinDir)
2321 int n;
2322 int i;
2324 /* entry assertions */
2326 assert(a_pkgList != (char **)NULL);
2327 assert(a_longestPkg > 0);
2329 /* entry debugging info */
2331 echoDebug(DBG_PKGREMPKGSGZNNGZ_ENTRY);
2332 echoDebug(DBG_PKGREMPKGSGZNNGZ_ARGS, a_nodelete, a_longestPkg,
2333 a_repeat, PSTR(a_altBinDir));
2336 * all of the packages (as listed in the package list) are
2337 * removed one at a time.
2340 interrupted = 0;
2341 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2342 started = 0;
2344 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2345 continue;
2348 interrupted = 0;
2351 * pkgrm invoked from within the global zone and there are
2352 * NO non-global zones configured:
2353 * Remove the package from the global zone only.
2356 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2357 admnfile, (char *)NULL, (zoneList_t)NULL);
2359 /* set success/fail condition variables */
2361 ckreturn(n);
2363 npkgs--;
2367 * all packages in the package list have been removed.
2368 * Continue with removal if:
2369 * -- immediate reboot is NOT required
2370 * -- there are more packages to remove
2371 * else return do NOT continue.
2374 if ((ireboot == 0) && (a_repeat != 0)) {
2375 return (B_TRUE);
2378 /* return 'dont continue' */
2380 return (B_FALSE);
2384 * Name: remove_packages_from_spool_directory
2385 * Description: Remove packages from a spool directory only.
2386 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2387 * the name of one package to be removed.
2388 * a_nodelete: should the files and scripts remain installed?
2389 * - if != 0 pass -F flag to pkgremove - suppress
2390 * the removal of any files and any class action scripts
2391 * and suppress the running of any class action scripts.
2392 * The package files remain but the package looks like it
2393 * is not installed. This is mainly for use by upgrade.
2394 * - if == 0 do not pass -F flag to pkgremove - all
2395 * files and class action scripts are removed, and any
2396 * appropriate class action scripts are run.
2397 * a_longestPkg - length of the longest package "name" (for
2398 * output format alignment)
2399 * a_repeat - are there more packages avialable in "optind"
2400 * - B_TRUE - process packages from optind
2401 * - B_FALSE - do not process packages from optind
2402 * a_altBinDir - pointer to string representing location of the
2403 * pkgremove executable to run. If not NULL, then pass
2404 * the path specified to the -b option to pkgremove.
2405 * Returns: int (see ckreturn() function for details)
2406 * 0 - success
2407 * 1 - package operation failed (fatal error)
2408 * 2 - non-fatal error (warning)
2409 * 3 - user selected quit (operation interrupted)
2410 * 4 - admin settings prevented operation
2411 * 5 - interaction required and -n (non-interactive) specified
2412 * "10" will be added to indicate "immediate reboot required"
2413 * "20" will be added to indicate "reboot after install required"
2416 static boolean_t
2417 remove_packages_from_spool_directory(char **a_pkgList, int a_nodelete,
2418 int a_longestPkg, int a_repeat, char *a_altBinDir)
2420 int n;
2421 int i;
2423 /* entry assertions */
2425 assert(a_pkgList != (char **)NULL);
2426 assert(a_longestPkg > 0);
2429 * all of the packages (as listed in the package list) are
2430 * removed one at a time.
2433 interrupted = 0;
2434 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2435 started = 0;
2437 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2438 continue;
2441 interrupted = 0;
2444 * pkgrm invoked from any type of zone BUT the target
2445 * to be removed is a local spool directory: remove the
2446 * packages from the spool directory only.
2449 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2450 admnfile, (char *)NULL, (zoneList_t)NULL);
2452 /* set success/fail condition variables */
2454 ckreturn(n);
2456 npkgs--;
2460 * all packages in the package list have been removed.
2461 * Continue with removal if:
2462 * -- immediate reboot is NOT required
2463 * -- there are more packages to remove
2464 * else return do NOT continue.
2467 if ((ireboot == 0) && (a_repeat != 0)) {
2468 return (B_TRUE);
2471 /* return 'dont continue' */
2473 return (B_FALSE);
2477 * Name: remove_packages
2478 * Description: Remove packages from the global zone, and optionally from one
2479 * or more non-global zones, or from a specified spool directory.
2480 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2481 * the name of one package to be removed.
2482 * a_nodelete: should the files and scripts remain installed?
2483 * - if != 0 pass -F flag to pkgremove - suppress
2484 * the removal of any files and any class action scripts
2485 * and suppress the running of any class action scripts.
2486 * The package files remain but the package looks like it
2487 * is not installed. This is mainly for use by upgrade.
2488 * - if == 0 do not pass -F flag to pkgremove - all
2489 * files and class action scripts are removed, and any
2490 * appropriate class action scripts are run.
2491 * a_longestPkg - length of the longest package "name" (for
2492 * output format alignment)
2493 * a_repeat - are there more packages avialable in "optind"
2494 * - B_TRUE - process packages from optind
2495 * - B_FALSE - do not process packages from optind
2496 * a_altBinDir - pointer to string representing location of the
2497 * pkgremove executable to run. If not NULL, then pass
2498 * the path specified to the -b option to pkgremove.
2499 * a_pkgdir - pointer to string representing the directory
2500 * where the packages to be removed are located.
2501 * a_spoolDir - pointer to string specifying spool directory
2502 * to remove packages from. If != NULL then all zones
2503 * processing is bypassed and the packages are removed
2504 * from the specified spool directory only.
2505 * a_noZones - if non-global zones are configured, should the
2506 * packages be removed from the non-global zones?
2507 * - B_TRUE - do NOT remove packages from non-global zones
2508 * - B_FALSE - remove packages from non-global zones
2509 * Returns: int (see ckreturn() function for details)
2510 * 0 - success
2511 * 1 - package operation failed (fatal error)
2512 * 2 - non-fatal error (warning)
2513 * 3 - user selected quit (operation interrupted)
2514 * 4 - admin settings prevented operation
2515 * 5 - interaction required and -n (non-interactive) specified
2516 * "10" will be added to indicate "immediate reboot required"
2517 * "20" will be added to indicate "reboot after install required"
2520 static boolean_t
2521 remove_packages(char **a_pkgList, int a_nodelete, int a_longestPkg,
2522 int a_repeat, char *a_altBinDir, char *a_pkgdir, char *a_spoolDir,
2523 boolean_t a_noZones)
2525 zoneList_t zlst;
2526 boolean_t b;
2528 /* entry assertions */
2530 assert(a_pkgList != (char **)NULL);
2532 echoDebug(DBG_REMOVEPKGS_ENTRY);
2533 echoDebug(DBG_REMOVEPKGS_ARGS, npkgs, a_nodelete, a_longestPkg,
2534 a_repeat, PSTR(a_pkgdir), PSTR(a_spoolDir));
2537 * if removing from spool directory, bypass all zones checks
2540 if (a_spoolDir != (char *)NULL) {
2541 /* in non-global zone */
2543 echoDebug(DBG_REMOVE_PKGS_FROM_SPOOL, a_spoolDir);
2545 b = remove_packages_from_spool_directory(a_pkgList, a_nodelete,
2546 a_longestPkg, a_repeat, a_altBinDir);
2548 return (B_FALSE);
2551 /* exit if not root */
2553 if (getuid()) {
2554 progerr(ERR_NOT_ROOT, get_prog_name());
2555 exit(1);
2559 * if running in the global zone AND one or more non-global
2560 * zones exist, add packages in a 'zones aware' manner, else
2561 * add packages in the standard 'non-zones aware' manner.
2564 if ((a_noZones == B_FALSE) && (z_running_in_global_zone() == B_FALSE)) {
2565 /* in non-global zone */
2567 echoDebug(DBG_IN_LZ);
2569 b = z_lock_this_zone(ZLOCKS_PKG_ADMIN);
2570 if (b != B_TRUE) {
2571 progerr(ERR_CANNOT_LOCK_THIS_ZONE);
2572 /* set fatal error return condition */
2573 ckreturn(1);
2574 return (B_FALSE);
2577 b = remove_packages_in_nonglobal_zone(a_pkgList, a_nodelete,
2578 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir);
2580 (void) z_unlock_this_zone(ZLOCKS_ALL);
2582 return (B_FALSE);
2585 /* running in the global zone */
2587 b = z_non_global_zones_exist();
2588 if ((a_noZones == B_FALSE) && (b == B_TRUE)) {
2590 echoDebug(DBG_IN_GZ_WITH_LZ);
2592 /* get a list of all non-global zones */
2593 zlst = z_get_nonglobal_zone_list();
2594 if (zlst == (zoneList_t)NULL) {
2595 progerr(ERR_CANNOT_GET_ZONE_LIST);
2596 quit(1);
2599 /* need to lock all of the zones */
2601 quitSetZonelist(zlst);
2602 b = z_lock_zones(zlst, ZLOCKS_PKG_ADMIN);
2603 if (b == B_FALSE) {
2604 z_free_zone_list(zlst);
2605 progerr(ERR_CANNOT_LOCK_ZONES);
2606 /* set fatal error return condition */
2607 ckreturn(1);
2608 return (B_FALSE);
2611 /* add packages to all zones */
2613 b = remove_packages_in_global_with_zones(a_pkgList, a_nodelete,
2614 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir, zlst);
2616 /* unlock all zones */
2618 (void) z_unlock_zones(zlst, ZLOCKS_ALL);
2619 quitSetZonelist((zoneList_t)NULL);
2621 /* free list of all non-global zones */
2623 z_free_zone_list(zlst);
2625 return (B_FALSE);
2628 /* in global zone no non-global zones */
2630 echoDebug(DBG_IN_GZ_NO_LZ);
2632 b = z_lock_this_zone(ZLOCKS_PKG_ADMIN);
2633 if (b != B_TRUE) {
2634 progerr(ERR_CANNOT_LOCK_THIS_ZONE);
2635 /* set fatal error return condition */
2636 ckreturn(1);
2637 return (B_FALSE);
2640 b = remove_packages_in_global_no_zones(a_pkgList, a_nodelete,
2641 a_longestPkg, a_repeat, a_altBinDir);
2643 (void) z_unlock_this_zone(ZLOCKS_ALL);
2645 return (B_FALSE);
2651 static boolean_t
2652 check_packages(char **a_pkgList, char *a_packageDir)
2654 int savenpkgs = npkgs;
2655 int i;
2656 CAF_T flags = 0;
2658 /* set flags for applicability check */
2660 if (z_running_in_global_zone() == B_TRUE) {
2661 flags |= CAF_IN_GLOBAL_ZONE;
2665 * for each package to remove, verify that the package is installed
2666 * and is removable.
2669 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2670 /* check package applicability */
2671 if (check_applicability(a_packageDir, pkginst, get_inst_root(),
2672 flags) == B_FALSE) {
2673 progerr(ERR_PKG_NOT_REMOVABLE, pkginst);
2674 npkgs = savenpkgs;
2675 return (B_FALSE);
2677 npkgs--;
2680 npkgs = savenpkgs;
2681 return (B_TRUE);
2685 * - is this package removable from this zone?
2686 * - does the scope of remove conflict with existing installation
2689 static boolean_t
2690 check_applicability(char *a_packageDir, char *a_pkgInst,
2691 char *a_rootPath, CAF_T a_flags)
2693 FILE *pkginfoFP;
2694 boolean_t all_zones; /* pkg is "all zones" only */
2695 char pkginfoPath[PATH_MAX];
2696 char pkgpath[PATH_MAX];
2697 int len;
2699 /* entry assertions */
2701 assert(a_packageDir != (char *)NULL);
2702 assert(*a_packageDir != '\0');
2703 assert(a_pkgInst != (char *)NULL);
2704 assert(*a_pkgInst != '\0');
2706 /* normalize root path */
2708 if (a_rootPath == (char *)NULL) {
2709 a_rootPath = "";
2713 * determine if this package is currently installed
2714 * if not installed return success - operation will fail
2715 * when the removal is attempted
2718 if (pkginfoIsPkgInstalled((struct pkginfo **)NULL, a_pkgInst) !=
2719 B_TRUE) {
2720 return (B_TRUE);
2724 * calculate paths to various objects
2727 len = snprintf(pkgpath, sizeof (pkgpath), "%s/%s", a_packageDir,
2728 a_pkgInst);
2729 if (len > sizeof (pkgpath)) {
2730 progerr(ERR_CREATE_PATH_2, a_packageDir, a_pkgInst);
2731 return (B_FALSE);
2734 /* if not installed then just return */
2736 if (isdir(pkgpath) != 0) {
2737 progerr(ERR_NO_PKGDIR, pkgpath, a_pkgInst, strerror(errno));
2738 return (B_TRUE);
2741 len = snprintf(pkginfoPath, sizeof (pkginfoPath),
2742 "%s/pkginfo", pkgpath);
2743 if (len > sizeof (pkgpath)) {
2744 progerr(ERR_CREATE_PATH_2, pkgpath, "pkginfo");
2745 return (B_FALSE);
2749 * gather information from this packages pkginfo file
2752 pkginfoFP = fopen(pkginfoPath, "r");
2754 if (pkginfoFP == (FILE *)NULL) {
2755 progerr(ERR_NO_PKG_INFOFILE, a_pkgInst, pkginfoPath,
2756 strerror(errno));
2757 return (B_FALSE);
2760 /* determine "ALLZONES" setting for this package */
2762 all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
2763 "true", B_FALSE);
2765 /* close pkginfo file */
2767 (void) fclose(pkginfoFP);
2769 /* gather information from the global zone only file */
2772 * verify package applicability based on information gathered;
2773 * the package IS currently installed....
2776 /* pkg ALLZONES=true & not running in global zone */
2778 if ((all_zones == B_TRUE) && (!(a_flags & CAF_IN_GLOBAL_ZONE))) {
2779 progerr(ERR_ALLZONES_AND_IN_LZ_PKGRM, a_pkgInst);
2780 return (B_FALSE);
2783 return (B_TRUE);
2787 * Name: shall_we_continue
2788 * Description: Called from within a loop that is installing packages,
2789 * this function examines various global variables and decides
2790 * whether or not to ask an appropriate question, and wait for
2791 * and appropriate reply.
2792 * Arguments: <<global variables>>
2793 * Returns: B_TRUE - continue processing with next package
2794 * B_FALSE - do not continue processing with next package
2797 static boolean_t
2798 shall_we_continue(char *a_pkgInst, int a_npkgs)
2800 char ans[MAX_INPUT];
2801 int n;
2803 /* return FALSE if immediate reboot required */
2805 if (ireboot) {
2806 ptext(stderr, MSG_SUSPEND_RM, a_pkgInst);
2807 return (B_FALSE);
2810 /* return TRUE if not interrupted */
2812 if (!interrupted) {
2813 return (B_TRUE);
2816 /* output appropriate interrupt message */
2818 echo(a_npkgs == 1 ? MSG_1MORETODO : MSG_MORETODO, a_npkgs);
2820 /* if running with no interaction (-n) do not ask question */
2822 if (nointeract) {
2823 quit(0);
2824 /* NOTREACHED */
2827 /* interaction possible: ask question */
2829 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONTINUE_RM);
2830 if (n != 0) {
2831 quit(n);
2832 /* NOTREACHED */
2835 if (strchr("yY", *ans) == NULL) {
2836 quit(0);
2837 /* NOTREACHED */
2839 return (B_TRUE);
2843 * Name: create_zone_adminfile
2844 * Description: Given a zone temporary directory and optionally an existing
2845 * administration file, generate an administration file that
2846 * can be used to perform "non-interactive" operations in a
2847 * non-global zone.
2848 * Arguments: r_zoneAdminFile - pointer to handle that will contain a
2849 * string representing the path to the temporary
2850 * administration file created - this must be NULL
2851 * before the first call to this function - on
2852 * subsequent calls if the pointer is NOT null then
2853 * the existing string will NOT be overwritten.
2854 * a_zoneTempDir - pointer to string representing the path
2855 * to the zone temporary directory to create the
2856 * temporary administration file in
2857 * a_admnfile - pointer to string representing the path to
2858 * an existing "user" administration file - the
2859 * administration file created will contain the
2860 * settings contained in this file, modified as
2861 * appropriate to supress any interaction;
2862 * If this is == NULL then the administration file
2863 * created will not contain any extra settings
2864 * Returns: void
2865 * NOTE: Any string returned is placed in new storage for the
2866 * calling method. The caller must use 'free' to dispose
2867 * of the storage once the string is no longer needed.
2868 * NOTE: On any error this function will call 'quit(1)'
2871 static void
2872 create_zone_adminfile(char **r_zoneAdminFile, char *a_zoneTempDir,
2873 char *a_admnfile)
2875 boolean_t b;
2877 /* entry assertions */
2879 assert(r_zoneAdminFile != (char **)NULL);
2880 assert(a_zoneTempDir != (char *)NULL);
2881 assert(*a_zoneTempDir != '\0');
2883 /* entry debugging info */
2885 echoDebug(DBG_CREATE_ZONE_ADMINFILE, a_zoneTempDir, PSTR(a_admnfile));
2887 /* if temporary name already exists, do not overwrite */
2889 if (*r_zoneAdminFile != (char *)NULL) {
2890 return;
2893 /* create temporary name */
2895 *r_zoneAdminFile = tempnam(a_zoneTempDir, "zadmn");
2896 b = z_create_zone_admin_file(*r_zoneAdminFile, a_admnfile);
2897 if (b == B_FALSE) {
2898 progerr(ERR_CREATE_TMPADMIN, *r_zoneAdminFile,
2899 strerror(errno));
2900 quit(1);
2901 /* NOTREACHED */
2904 echoDebug(DBG_CREATED_ZONE_ADMINFILE, *r_zoneAdminFile);
2908 * Name: create_zone_tempdir
2909 * Description: Given a system temporary directory, create a "zone" specific
2910 * temporary directory and return the path to the directory
2911 * created.
2912 * Arguments: r_zoneTempDir - pointer to handle that will contain a
2913 * string representing the path to the temporary
2914 * directory created - this must be NULL before the
2915 * first call to this function - on subsequent calls
2916 * if the pointer is NOT null then the existing string
2917 * will NOT be overwritten.
2918 * a_zoneTempDir - pointer to string representing the path
2919 * to the system temporary directory to create the
2920 * temporary zone directory in
2921 * Returns: void
2922 * NOTE: Any string returned is placed in new storage for the
2923 * calling method. The caller must use 'free' to dispose
2924 * of the storage once the string is no longer needed.
2925 * NOTE: On any error this function will call 'quit(1)'
2926 * NOTE: This function calls "quitSetZoneTmpdir" on success to
2927 * register the directory created with quit() so that the
2928 * directory will be automatically deleted on exit.
2931 static void
2932 create_zone_tempdir(char **r_zoneTempDir, char *a_tmpdir)
2934 boolean_t b;
2936 /* entry assertions */
2938 assert(r_zoneTempDir != (char **)NULL);
2939 assert(a_tmpdir != (char *)NULL);
2940 assert(*a_tmpdir != '\0');
2942 /* entry debugging info */
2944 echoDebug(DBG_CREATE_ZONE_TEMPDIR, a_tmpdir);
2946 /* if temporary directory already exists, do not overwrite */
2948 if (*r_zoneTempDir != (char *)NULL) {
2949 return;
2952 /* create temporary directory */
2954 b = setup_temporary_directory(r_zoneTempDir, a_tmpdir, "ztemp");
2955 if (b == B_FALSE) {
2956 progerr(ERR_ZONETEMPDIR, a_tmpdir, strerror(errno));
2957 quit(1);
2958 /* NOTREACHED */
2961 /* register with quit() to directory is removed on exit */
2963 quitSetZoneTmpdir(*r_zoneTempDir);
2965 /* exit debugging info */
2967 echoDebug(DBG_CREATED_ZONE_TEMPDIR, *r_zoneTempDir);