1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 /*
31 * System includes
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <errno.h>
40 #include <locale.h>
41 #include <libintl.h>
42 #include <pkgstrct.h>
43 #include <pkgdev.h>
44 #include <pkginfo.h>
45 #include <pkglocs.h>
46 #include <pkglib.h>
47 #include <assert.h>
48
49 /*
50 * libinstzones includes
51 */
52
53 #include <instzones_api.h>
54
55 /*
56 * consolidation pkg command library includes
57 */
58
59 #include <pkglib.h>
60
61 /*
62 * local pkg command library includes
63 */
64
65 #include "install.h"
66 #include "libinst.h"
67 #include "libadm.h"
68 #include "messages.h"
69
70 /*
71 * pkgrm local includes
72 */
73
74 #include "quit.h"
75
76 /*
77 * exported global variables
78 */
79
80 /* these globals are set by ckreturn and used by quit.c */
81
82 int admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */
83 int doreboot = 0; /* != 0 if reboot required after installation */
84 int failflag = 0; /* != 0 if fatal error has occurred (1) */
85 int intrflag = 0; /* != 0 if user selected quit (3) */
86 int ireboot = 0; /* != 0 if immediate reboot required */
87 int nullflag = 0; /* != 0 if admin interaction required (5) */
88 int warnflag = 0; /* != 0 if non-fatal error has occurred (2) */
89
90 /* imported by quit.c */
91 int npkgs = 0; /* the number of packages yet to be installed */
92
93 /* imported by presvr4.c */
94 int started = 0;
95 char *tmpdir = NULL; /* location to place temporary files */
96
97 /* imported by various (many) */
98 struct admin adm; /* holds info about installation admin */
99 struct pkgdev pkgdev; /* holds info about the installation device */
100
101 /*
102 * internal global variables
103 */
104
105 static char *admnfile = NULL; /* file to use for installation admin */
106 static char *pkginst = NULL; /* current pkg/src instance 2 process */
107 static char *vfstab_file = NULL;
108 static char *zoneTempDir = (char *)NULL;
109
110 /* set by ckreturn() */
111
112 static int interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */
113
114 static int nointeract = 0; /* non-zero - no user interaction */
115 static int pkgrmremote = 0; /* remove pkg objs stored remotely */
116 static int pkgverbose = 0; /* non-zero if verbose mode selected */
117
118 /*
119 * Assume the package complies with the standards as regards user
120 * interaction during procedure scripts.
121 */
122
123 static int old_pkg = 0;
124 static int old_symlinks = 0;
125 static int no_map_client = 0;
126
127 /* Set by -O nozones: do not process any zones */
128
129 static boolean_t noZones = B_FALSE;
130
131 /* Set by -O zonelist=<names...>: process only named zones */
132
133 static boolean_t usedZoneList = B_FALSE;
134
135 /* Set by -O debug: debug output is enabled? */
136
137 static boolean_t debugFlag = B_FALSE;
138
139 /*
140 * imported (external) functions
141 */
142
143 /* check.c */
144
145 extern int preremove_verify(char **a_pkgList, zoneList_t a_zlst,
146 char *a_zoneTempDir);
147 /* quit.c */
148
149 extern void quitSetZonelist(zoneList_t a_zlst);
150
151 /*
152 * imported (external) variables
153 */
154
155 extern char *pkgdir;
156
157 /* printable string - if string is null results in ??? */
158
159 #define PSTR(STR) (((STR) == (char *)NULL) ? "???" : (STR))
160
161 #define MAX_FDS 20
162
163 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
164 #define TEXT_DOMAIN "SYS_TEST"
165 #endif
166
167 /*
168 * forward declarations
169 */
170
171 static void ckreturn(int retcode);
172 static void create_zone_adminfile(char **r_zoneAdminFile,
173 char *a_zoneTempDir, char *a_admnfile);
174 static void create_zone_tempdir(char **r_zoneTempDir,
175 char *a_tmpdir);
176 static int doRemove(int a_nodelete, char *a_altBinDir,
177 int a_longestPkg, char *a_adminFile,
178 char *a_zoneAdminFile, zoneList_t zlst);
179 static int pkgRemove(int a_nodelete, char *a_altBinDir,
180 char *a_adminFile);
181 static int pkgZoneCheckRemove(char *a_zoneName, char *a_altBinDir,
182 char *a_adminFile, char *a_stdoutPath,
183 zone_state_t a_zoneState, boolean_t tmpzone);
184 static int pkgZoneRemove(char *a_zoneName, int a_nodelete,
185 char *a_altBinDir, char *a_adminFile,
186 zone_state_t a_zoneState, boolean_t tmpzone);
187 static void resetreturn();
188 static void usage(void);
189 static boolean_t check_applicability(char *a_packageDir,
190 char *a_pkgInst, char *a_rootPath,
191 CAF_T a_flags);
192 static boolean_t check_packages(char **a_pkgList, char *a_packageDir);
193 static boolean_t path_valid(char *path);
194 static boolean_t remove_packages(char **a_pkgList, int a_nodelete,
195 int a_longestPkg, int a_repeat,
196 char *a_altBinDir, char *a_pkgdir,
197 char *a_spoolDir, boolean_t a_noZones);
198 static boolean_t remove_packages_from_spool_directory(char **a_pkgList,
199 int a_nodelete, int a_longestPkg, int a_repeat,
200 char *a_altBinDir);
201 static boolean_t remove_packages_in_global_no_zones(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_with_zones(char **a_pkgList,
205 int a_nodelete, int a_longestPkg, int a_repeat,
206 char *a_altBinDir, char *a_pkgdir,
207 zoneList_t a_zlst);
208 static boolean_t remove_packages_in_nonglobal_zone(char **a_pkgList,
209 int a_nodelete, int a_longestPkg, int a_repeat,
210 char *a_altBinDir, char *a_pkgdir);
211 static boolean_t shall_we_continue(char *a_pkgInst, int a_npkgs);
212
213 /*
214 * *****************************************************************************
215 * global external (public) functions
216 * *****************************************************************************
217 */
218
219 /*
220 * Name: main
221 * Description: main entry point for pkgrm
222 * Returns: int
223 * 0 Successful completion
224 * 1 Fatal error.
225 * 2 Warning.
226 * 3 Interruption.
227 * 4 Administration.
228 * 5 Administration. Interaction is required. Do not use pkgrm -n.
229 * 10 Reboot after removal of all packages.
230 * 20 Reboot after removal of this package.
231 */
232
233 int
main(int argc,char ** argv)234 main(int argc, char **argv)
235 {
236 char **category = NULL;
237 char *altBinDir = (char *)NULL;
238 char *catg_arg = NULL;
239 char *p;
240 char *prog_full_name = NULL;
241 char *spoolDir = 0;
242 int c;
243 int longestPkg = 0;
244 int n;
245 int nodelete = 0; /* dont rm files/run scripts */
246 int pkgLgth = 0;
247 int repeat;
248 struct sigaction nact;
249 struct sigaction oact;
250
251 /* initialize locale environment */
252
253 (void) setlocale(LC_ALL, "");
254 (void) textdomain(TEXT_DOMAIN);
255
256 /* initialize program name */
257
258 prog_full_name = argv[0];
259 (void) set_prog_name(argv[0]);
260
261 /* tell spmi zones interface how to access package output functions */
262
263 z_set_output_functions(echo, echoDebug, progerr);
264
265 /* tell quit which ckreturn function to call */
266
267 quitSetCkreturnFunc(&ckreturn);
268
269 /* Read PKG_INSTALL_ROOT from the environment, if it's there. */
270
271 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
272 progerr(ERR_ROOT_SET);
273 exit(1);
274 }
275
276 if (z_running_in_global_zone() && !enable_local_fs()) {
277 progerr(ERR_CANNOT_ENABLE_LOCAL_FS);
278 }
279
280 pkgserversetmode(DEFAULTMODE);
281
282 /*
283 * ********************************************************************
284 * parse command line options
285 * ********************************************************************
286 */
287
288 while ((c = getopt(argc, argv, "?Aa:b:FMnO:R:s:V:vY:Z")) != EOF) {
289 switch (c) {
290 /*
291 * Public interface: Allow admin to remove objects
292 * from a service area via a reference client.
293 * Remove the package files from the client's file
294 * system, absolutely. If a file is shared with other
295 * packages, the default behavior is to not remove
296 * the file from the client's file system.
297 */
298 case 'A':
299 pkgrmremote++;
300 break;
301
302 /*
303 * Public interface: Use the installation
304 * administration file, admin, in place of the
305 * default admin file. pkgrm first looks in the
306 * current working directory for the administration
307 * file. If the specified administration file is not
308 * in the current working directory, pkgrm looks in
309 * the /var/sadm/install/admin directory for the
310 * administra- tion file.
311 */
312 case 'a':
313 admnfile = flex_device(optarg, 0);
314 break;
315
316 /*
317 * Not a public interface: location where package executables
318 * can be found - default is /usr/sadm/install/bin.
319 */
320 case 'b':
321 if (!path_valid(optarg)) {
322 progerr(ERR_PATH, optarg);
323 quit(1);
324 }
325 if (isdir(optarg) != 0) {
326 p = strerror(errno);
327 progerr(ERR_CANNOT_USE_DIR, optarg, p);
328 quit(1);
329 }
330 altBinDir = optarg;
331 break;
332
333 /*
334 * Not a public interface: pass -F option to
335 * pkgremove which suppresses the removal of any
336 * files and any class action scripts, and suppresses
337 * the running of any class action scripts. The
338 * package files remain but the package looks like it
339 * is not installed. This is mainly for use by the
340 * upgrade process.
341 */
342 case 'F':
343 nodelete++;
344 break;
345
346 /*
347 * Public interface: Instruct pkgrm not to use the
348 * $root_path/etc/vfstab file for determining the
349 * client's mount points. This option assumes the
350 * mount points are correct on the server and it
351 * behaves consistently with Solaris 2.5 and earlier
352 * releases.
353 */
354 case 'M':
355 no_map_client = 1;
356 break;
357
358 /*
359 * Public interface: package removal occurs in
360 * non-interactive mode. Suppress output of the list of
361 * removed files. The default mode is interactive.
362 */
363 case 'n':
364 nointeract++;
365 (void) echoSetFlag(B_FALSE);
366 break;
367
368 /*
369 * Not a public interface: the -O option allows the behavior
370 * of the package tools to be modified. Recognized options:
371 * -> debug
372 * ---> enable debugging output
373 * -> nozones
374 * ---> act as though in global zone with no non-global zones
375 * -> enable-hollow-package-support
376 * --> Enable hollow package support. When specified, for any
377 * --> package that has SUNW_PKG_HOLLOW=true:
378 * --> Do not calculate and verify package size against target
379 * --> Do not run any package procedure or class action scripts
380 * --> Do not create or remove any target directories
381 * --> Do not perform any script locking
382 * --> Do not install or uninstall any components of any package
383 * --> Do not output any status or database update messages
384 * -> zonelist="<names...>"
385 * ---> add package to space-separated list of zones only
386 */
387
388 case 'O':
389 for (p = strtok(optarg, ","); p != (char *)NULL;
390 p = strtok(NULL, ",")) {
391
392 if (strcmp(p, "nozones") == 0) {
393 noZones = B_TRUE;
394 continue;
395 }
396
397 if (strcmp(p,
398 "enable-hollow-package-support") == 0) {
399 set_depend_pkginfo_DB(B_TRUE);
400 continue;
401 }
402
403 if (strcmp(p, "debug") == 0) {
404 /* set debug flag/enable debug output */
405 debugFlag = B_TRUE;
406 (void) echoDebugSetFlag(debugFlag);
407
408 /* debug info on arguments to pkgadd */
409 for (n = 0; n < argc && argv[n]; n++) {
410 echoDebug(DBG_ARG, n, argv[n]);
411 }
412
413 continue;
414 }
415
416 if (strncmp(p, "zonelist=", 9) == 0) {
417 if (z_set_zone_spec(p + 9) == -1)
418 quit(1);
419 usedZoneList = B_TRUE;
420 continue;
421 }
422
423 /* -O option not recognized - issue warning */
424
425 progerr(ERR_INVALID_O_OPTION, p);
426 continue;
427 }
428 break;
429
430 /*
431 * Public interface: defines the full path name of a
432 * directory to use as the root_path. All files,
433 * including package system information files, are
434 * relocated to a directory tree starting in the
435 * specified root_path.
436 */
437 case 'R':
438 if (!set_inst_root(optarg)) {
439 progerr(ERR_ROOT_CMD);
440 exit(1);
441 }
442 break;
443
444 /*
445 * Public interface: remove the specified package(s)
446 * from the directory spool. The default directory
447 * for spooled packages is /var/sadm/pkg.
448 */
449 case 's':
450 spoolDir = flex_device(optarg, 1);
451 break;
452
453 /*
454 * Public interface: Allow admin to establish the client
455 * filesystem using a vfstab-like file of stable format.
456 */
457 case 'V':
458 vfstab_file = flex_device(optarg, 2);
459 no_map_client = 0;
460 break;
461
462 /*
463 * Public interface: trace all of the scripts that
464 * get executed by pkgrm, located in the
465 * pkginst/install directory. This option is used for
466 * debugging the procedural and non- procedural
467 * scripts.
468 */
469 case 'v':
470 pkgverbose++;
471 break;
472
473 /*
474 * Public interface: remove packages based on the
475 * CATEGORY variable from the installed/spooled
476 * pkginfo file
477 */
478 case 'Y':
479 catg_arg = strdup(optarg);
480
481 if ((category = get_categories(catg_arg)) == NULL) {
482 progerr(ERR_CAT_INV, catg_arg);
483 exit(1);
484 } else if (is_not_valid_category(category,
485 get_prog_name())) {
486 progerr(ERR_CAT_SYS);
487 exit(1);
488 } else if (is_not_valid_length(category)) {
489 progerr(ERR_CAT_LNGTH);
490 exit(1);
491 }
492
493 break;
494
495 /*
496 * unrecognized option
497 */
498 default:
499 usage();
500 /* NOTREACHED */
501 }
502 }
503
504 /*
505 * ********************************************************************
506 * validate command line options
507 * ********************************************************************
508 */
509
510 /* set "debug echo" flag according to setting of "-O debug" option */
511
512 (void) echoDebugSetFlag(debugFlag);
513
514 /* output entry debugging information */
515
516 if (z_running_in_global_zone()) {
517 echoDebug(DBG_ENTRY_IN_GZ, prog_full_name);
518 } else {
519 echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(),
520 z_get_zonename());
521 }
522
523 /* -s cannot be used with several */
524
525 if (spoolDir != (char *)NULL) {
526 if (admnfile != (char *)NULL) {
527 progerr(ERR_SPOOLDIR_AND_ADMNFILE);
528 usage();
529 /* NOTREACHED */
530 }
531
532 if (pkgrmremote != 0) {
533 progerr(ERR_SPOOLDIR_AND_PKGRMREMOTE);
534 usage();
535 /* NOTREACHED */
536 }
537
538 if (pkgverbose != 0) {
539 progerr(ERR_SPOOLDIR_AND_PKGVERBOSE);
540 usage();
541 /* NOTREACHED */
542 }
543
544 if (is_an_inst_root() != 0) {
545 progerr(ERR_SPOOLDIR_AND_INST_ROOT);
546 usage();
547 /* NOTREACHED */
548 }
549 }
550
551 /* -V cannot be used with -A */
552
553 if (no_map_client && pkgrmremote) {
554 progerr(ERR_V_USED_AND_PKGRMREMOTE);
555 usage();
556 /* NOTREACHED */
557 }
558
559 /* -n used without pkg names or category */
560
561 if (nointeract && (optind == argc) && (catg_arg == NULL)) {
562 progerr(ERR_BAD_N_PKGRM);
563 usage();
564 /* NOTREACHED */
565 }
566
567 /* Error if specified zone list isn't valid on target */
568 if (usedZoneList && z_verify_zone_spec() == -1)
569 usage();
570
571 /*
572 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler
573 */
574
575 /* hold SIGINT/SIGHUP interrupts */
576
577 (void) sighold(SIGHUP);
578 (void) sighold(SIGINT);
579
580 /* connect quit.c:trap() to SIGINT */
581
582 nact.sa_handler = quitGetTrapHandler();
583 nact.sa_flags = SA_RESTART;
584 (void) sigemptyset(&nact.sa_mask);
585
586 (void) sigaction(SIGINT, &nact, &oact);
587
588 /* connect quit.c:trap() to SIGHUP */
589
590 nact.sa_handler = quitGetTrapHandler();
591 nact.sa_flags = SA_RESTART;
592 (void) sigemptyset(&nact.sa_mask);
593
594 (void) sigaction(SIGHUP, &nact, &oact);
595
596 /* release hold on signals */
597
598 (void) sigrelse(SIGHUP);
599 (void) sigrelse(SIGINT);
600
601 /* establish temporary directory to use */
602
603 tmpdir = getenv("TMPDIR");
604 if (tmpdir == NULL) {
605 tmpdir = P_tmpdir;
606 }
607
608 echoDebug(DBG_PKGRM_TMPDIR, tmpdir);
609
610 /* initialize path parameters */
611
612 set_PKGpaths(get_inst_root());
613
614 /*
615 * initialize installation admin parameters - if removing from a spool
616 * directory then the admin file is ignore.
617 */
618
619 if (spoolDir == NULL) {
620 echoDebug(DBG_PKGRM_ADMINFILE, admnfile ? admnfile : "");
621 setadminFile(admnfile);
622 }
623
624 /*
625 * if running in the global zone, and non-global zones exist, then
626 * enable hollow package support so that any packages that are marked
627 * SUNW_PKG_HOLLOW=true will be correctly removed in non-global zones
628 * when removed directly in the global zone by the global zone admin.
629 */
630
631 if (is_depend_pkginfo_DB()) {
632 echoDebug(DBG_PKGRM_HOLLOW_ENABLED);
633 } else if ((z_running_in_global_zone() == B_TRUE) &&
634 (z_non_global_zones_exist() == B_TRUE)) {
635 echoDebug(DBG_PKGRM_ENABLING_HOLLOW);
636 set_depend_pkginfo_DB(B_TRUE);
637 }
638
639 /*
640 * See if user wants this to be handled as an old style pkg.
641 * NOTE : the ``exception_pkg()'' stuff is to be used only
642 * through on495. This function comes out for on1095. See
643 * PSARC 1993-546. -- JST
644 */
645 if (getenv("NONABI_SCRIPTS") != NULL) {
646 old_pkg = 1;
647 }
648
649 /*
650 * See if the user wants to process symlinks consistent with
651 * the old behavior.
652 */
653
654 if (getenv("PKG_NONABI_SYMLINKS") != NULL) {
655 old_symlinks = 1;
656 }
657
658 if (devtype((spoolDir ? spoolDir : get_PKGLOC()), &pkgdev) ||
659 pkgdev.dirname == NULL) {
660 progerr(ERR_BAD_DEVICE, spoolDir ? spoolDir : get_PKGLOC());
661 quit(1);
662 /* NOTREACHED */
663 }
664
665 pkgdir = pkgdev.dirname;
666 repeat = ((optind >= argc) && pkgdev.mount);
667
668 /*
669 * error if there are packages on the command line and a category
670 * was specified
671 */
672
673 if (optind < argc && catg_arg != NULL) {
674 progerr(ERR_PKGS_AND_CAT_PKGRM);
675 usage();
676 /* NOTREACHED */
677 }
678
679 /*
680 * ********************************************************************
681 * main package processing "loop"
682 * ********************************************************************
683 */
684
685 for (;;) {
686 boolean_t b;
687 char **pkglist; /* points to array of pkgs */
688
689 /*
690 * mount the spool device if required
691 */
692
693 if (pkgdev.mount) {
694 if (n = pkgmount(&pkgdev, NULL, 0, 0, 1)) {
695 quit(n);
696 /* NOTREACHED */
697 }
698 }
699
700 if (chdir(pkgdev.dirname)) {
701 progerr(ERR_CHDIR, pkgdev.dirname);
702 quit(1);
703 /* NOTREACHED */
704 }
705
706 /*
707 * spool device mounted/available - get the list of the
708 * packages to remove
709 */
710
711 n = pkgGetPackageList(&pkglist, argv, optind,
712 catg_arg, category, &pkgdev);
713
714 switch (n) {
715 case -1: /* no packages found */
716 echoDebug(DBG_PKGLIST_RM_NONFOUND,
717 PSTR(pkgdev.dirname));
718 progerr(ERR_NOPKGS, pkgdev.dirname);
719 quit(1);
720 /* NOTREACHED */
721
722 case 0: /* packages found */
723 break;
724
725 default: /* "quit" error */
726 echoDebug(DBG_PKGLIST_RM_ERROR,
727 pkgdev.dirname, n);
728 quit(n);
729 /* NOTREACHED */
730 }
731
732 /*
733 * count the number of packages to remove
734 * NOTE: npkgs is a global variable that is referenced by quit.c
735 * when error messages are generated - it is referenced directly
736 * by the other functions called below...
737 */
738
739 for (npkgs = 0; pkglist[npkgs] != (char *)NULL; /* void */) {
740 pkgLgth = strlen(pkglist[npkgs]);
741 if (pkgLgth > longestPkg) {
742 longestPkg = pkgLgth;
743 }
744 echoDebug(DBG_PKG_SELECTED, npkgs, pkglist[npkgs]);
745 npkgs++;
746 }
747
748 /* output number of packages to be removed */
749
750 echoDebug(DBG_NUM_PKGS_TO_REMOVE, npkgs, longestPkg);
751
752 /*
753 * package list generated - remove packages
754 */
755
756 b = remove_packages(pkglist, nodelete, longestPkg, repeat,
757 altBinDir, pkgdev.dirname, spoolDir, noZones);
758
759 /*
760 * unmount the spool directory if necessary
761 */
762
763 if (pkgdev.mount) {
764 (void) chdir("/");
765 if (pkgumount(&pkgdev)) {
766 progerr(ERR_PKGUNMOUNT, pkgdev.bdevice);
767 quit(99);
768 /* NOTREACHED */
769
770 }
771 }
772
773 /*
774 * continue with next sequence of packages if continue set
775 */
776
777 if (b == B_TRUE) {
778 continue;
779 }
780
781 /*
782 * not continuing - quit with 0 exit code
783 */
784
785 quit(0);
786 /* NOTREACHED */
787 #ifdef lint
788 return (0);
789 #endif /* lint */
790 }
791 }
792
793 /*
794 * *****************************************************************************
795 * static internal (private) functions
796 * *****************************************************************************
797 */
798
799 /*
800 * Name: doRemove
801 * Description: Remove a package from the global zone, and optionally from one
802 * or more non-global zones.
803 * Arguments: a_nodelete: should the files and scripts remain installed?
804 * - if != 0 pass -F flag to pkgremove - suppress
805 * the removal of any files and any class action scripts
806 * and suppress the running of any class action scripts.
807 * The package files remain but the package looks like it
808 * is not installed. This is mainly for use by upgrade.
809 * - if == 0 do not pass -F flag to pkgremove - all
810 * files and class action scripts are removed, and any
811 * appropriate class action scripts are run.
812 * a_altBinDir - pointer to string representing location of the
813 * pkgremove executable to run. If not NULL, then pass
814 * the path specified to the -b option to pkgremove.
815 * a_longestPkg - length of the longest package "name" (for
816 * output format alignment)
817 * a_adminFile - pointer to string representing the admin
818 * file to pass to pkgremove when removing a package from
819 * the global zone only. Typically the admin file used for
820 * the global zone is the admin file passed in by the user.
821 * If this is == NULL no admin file is given to pkgremove.
822 * a_zoneAdminFile - pointer to string representing the admin
823 * file to pass to pkgremove when removing the package
824 * from a non-global zone only. Typically the admin file
825 * used for non-global zones supresses all checks since
826 * the dependency checking is done for all zones first
827 * before proceeding.
828 * A zoneAdminFile MUST be specified if a_zlst != NULL.
829 * A zoneAdminFile must NOT be specified if a_zlst == NULL.
830 * a_zlst - list of zones to process; NULL if no zones to process.
831 * Returns: int (see ckreturn() function for details)
832 * 0 - success
833 * 1 - package operation failed (fatal error)
834 * 2 - non-fatal error (warning)
835 * 3 - user selected quit (operation interrupted)
836 * 4 - admin settings prevented operation
837 * 5 - interaction required and -n (non-interactive) specified
838 * "10" will be added to indicate "immediate reboot required"
839 * "20" will be added to indicate "reboot after install required"
840 */
841
842 static int
doRemove(int a_nodelete,char * a_altBinDir,int a_longestPkg,char * a_adminFile,char * a_zoneAdminFile,zoneList_t a_zlst)843 doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile,
844 char *a_zoneAdminFile, zoneList_t a_zlst)
845 {
846 boolean_t b;
847 char *zoneName;
848 char ans[MAX_INPUT];
849 int n;
850 int zoneIndex;
851 int zonesSkipped;
852 struct pkginfo *pinfo = (struct pkginfo *)NULL;
853 zone_state_t zst;
854
855 /* entry assertions */
856
857 if (a_zlst != (zoneList_t)NULL) {
858 /* zone list specified - zone admin file required */
859 assert(a_zoneAdminFile != (char *)NULL);
860 assert(*a_zoneAdminFile != '\0');
861 } else {
862 /* no zone list specified - no zone admin file needed */
863 assert(a_zoneAdminFile == (char *)NULL);
864 }
865
866 /* NOTE: required 'pkgdir' set to spool directory or NULL */
867 b = pkginfoIsPkgInstalled(&pinfo, pkginst);
868 if (b == B_FALSE) {
869 progerr(ERR_NO_SUCH_INSTANCE, pkginst);
870 pkginfoFree(&pinfo);
871 return (2);
872 }
873
874 /* entry debugging info */
875
876 echoDebug(DBG_DOREMOVE_ENTRY);
877 echoDebug(DBG_DOREMOVE_ARGS, PSTR(pinfo->pkginst), PSTR(pinfo->name),
878 PSTR(pinfo->arch), PSTR(pinfo->version), PSTR(pinfo->basedir),
879 PSTR(pinfo->catg), pinfo->status);
880
881 if (!nointeract) {
882 char fmt1[100];
883
884 /* create format based on max pkg name length */
885
886 (void) snprintf(fmt1, sizeof (fmt1), " %%-%d.%ds %%s",
887 a_longestPkg, a_longestPkg);
888
889 if (pinfo->status == PI_SPOOLED) {
890 echo(INFO_SPOOLED);
891 } else {
892 if (getuid()) {
893 progerr(ERR_NOT_ROOT, get_prog_name());
894 exit(1);
895 }
896 echo(INFO_INSTALL);
897 }
898
899 echo(fmt1, pinfo->pkginst, pinfo->name);
900
901 if (pinfo->arch || pinfo->version) {
902 char fmt2[100];
903
904 /* create format based on max pkg name length */
905
906 (void) snprintf(fmt2, sizeof (fmt2), " %%%d.%ds ",
907 a_longestPkg, a_longestPkg);
908
909 /* LINTED variable format specifier to fprintf() */
910 (void) fprintf(stderr, fmt2, "");
911
912 if (pinfo->arch) {
913 (void) fprintf(stderr, "(%s) ", pinfo->arch);
914 }
915
916 if (pinfo->version) {
917 (void) fprintf(stderr, "%s", pinfo->version);
918 }
919
920 (void) fprintf(stderr, "\n");
921 }
922
923 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONFIRM);
924 if (n != 0) {
925 quit(n);
926 /* NOTREACHED */
927 }
928
929 if (strchr("yY", *ans) == NULL) {
930 pkginfoFree(&pinfo);
931 return (0);
932 }
933 }
934
935 if (pinfo->status == PI_SPOOLED) {
936 /* removal from a directory */
937 echo(INFO_RMSPOOL, pkginst);
938 pkginfoFree(&pinfo);
939 return (rrmdir(pkginst));
940 }
941
942 /* exit if not root */
943
944 if (getuid()) {
945 progerr(ERR_NOT_ROOT, get_prog_name());
946 exit(1);
947 }
948
949 pkginfoFree(&pinfo);
950
951 zonesSkipped = 0;
952
953 if (interrupted != 0) {
954 echo(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
955 echoDebug(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
956 return (n);
957 }
958
959 echoDebug(DBG_REMOVE_FLAG_VALUES, "before pkgZoneRemove",
960 admnflag, doreboot, failflag, interrupted,
961 intrflag, ireboot, nullflag, warnflag);
962
963 for (zoneIndex = 0;
964 a_zlst != NULL &&
965 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != NULL;
966 zoneIndex++) {
967
968 /* skip the zone if it is NOT running */
969
970 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
971 if (zst != ZONE_STATE_RUNNING && zst != ZONE_STATE_MOUNTED) {
972 zonesSkipped++;
973 echoDebug(DBG_SKIPPING_ZONE, zoneName);
974 continue;
975 }
976
977 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
978 echoDebug(DBG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
979
980 /*
981 * remove package from zone; use the zone admin file which
982 * suppresses all checks.
983 */
984
985 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex),
986 a_nodelete, a_altBinDir, a_zoneAdminFile,
987 zst, B_FALSE);
988
989 /* set success/fail condition variables */
990
991 ckreturn(n);
992
993 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
994 admnflag, doreboot, failflag, interrupted, intrflag,
995 ireboot, nullflag, warnflag);
996 }
997
998 if (zonesSkipped > 0) {
999 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
1000
1001 for (zoneIndex = 0;
1002 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1003 (char *)NULL; zoneIndex++) {
1004
1005 /* skip the zone if it IS running */
1006
1007 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
1008 if (zst == ZONE_STATE_RUNNING ||
1009 zst == ZONE_STATE_MOUNTED) {
1010 zonesSkipped++;
1011 echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName);
1012 continue;
1013 }
1014
1015 /* skip the zone if it is NOT bootable */
1016
1017 if (z_zlist_is_zone_runnable(a_zlst,
1018 zoneIndex) == B_FALSE) {
1019 echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName);
1020 echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE,
1021 zoneName);
1022 continue;
1023 }
1024
1025 /* mount up the zone */
1026
1027 echo(MSG_BOOTING_ZONE, zoneName);
1028 echoDebug(DBG_BOOTING_ZONE, zoneName);
1029
1030 b = z_zlist_change_zone_state(a_zlst, zoneIndex,
1031 ZONE_STATE_MOUNTED);
1032 if (b == B_FALSE) {
1033 progerr(ERR_CANNOT_BOOT_ZONE, zoneName);
1034 /* set fatal error return condition */
1035 ckreturn(1);
1036 continue;
1037 }
1038
1039 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
1040
1041 /*
1042 * remove package from zone; use the zone admin file
1043 * which suppresses all checks.
1044 */
1045
1046 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst,
1047 zoneIndex), a_nodelete, a_altBinDir,
1048 a_zoneAdminFile, ZONE_STATE_MOUNTED, B_TRUE);
1049
1050 /* set success/fail condition variables */
1051
1052 ckreturn(n);
1053
1054 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
1055 admnflag, doreboot, failflag, interrupted,
1056 intrflag, ireboot, nullflag, warnflag);
1057
1058 /* restore original state of zone */
1059
1060 echo(MSG_RESTORE_ZONE_STATE, zoneName);
1061 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
1062
1063 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
1064 }
1065 }
1066
1067 /*
1068 * Process global zone if it was either the only possible
1069 * target (no list of zones specified) or it appears in the list
1070 */
1071 if (a_zlst == NULL || z_on_zone_spec(GLOBAL_ZONENAME)) {
1072 /* reset interrupted flag before calling pkgremove */
1073 interrupted = 0; /* last action was NOT quit */
1074
1075 /*
1076 * call pkgremove for this package for the global zone;
1077 * use the admin file passed in by the user via -a.
1078 */
1079 n = pkgRemove(a_nodelete, a_altBinDir, a_adminFile);
1080
1081 /* set success/fail condition variables */
1082 ckreturn(n);
1083 }
1084
1085 return (n);
1086 }
1087
1088 /*
1089 * function to clear out any exisiting error return conditions that may have
1090 * been set by previous calls to ckreturn()
1091 */
1092 static void
resetreturn()1093 resetreturn()
1094 {
1095 admnflag = 0; /* != 0 if any pkg op admin setting failure (4) */
1096 doreboot = 0; /* != 0 if reboot required after installation (>= 10) */
1097 failflag = 0; /* != 0 if fatal error has occurred (1) */
1098 intrflag = 0; /* != 0 if user selected quit (3) */
1099 ireboot = 0; /* != 0 if immediate reboot required (>= 20) */
1100 nullflag = 0; /* != 0 if admin interaction required (5) */
1101 warnflag = 0; /* != 0 if non-fatal error has occurred (2) */
1102 interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */
1103 }
1104
1105 /*
1106 * function which checks the indicated return value
1107 * and indicates disposition of installation
1108 */
1109 static void
ckreturn(int retcode)1110 ckreturn(int retcode)
1111 {
1112 /*
1113 * entry debugging info
1114 */
1115
1116 echoDebug(DBG_PKGRM_CKRETURN, retcode, PSTR(pkginst));
1117
1118 switch (retcode) {
1119 case 0: /* successful */
1120 case 10:
1121 case 20:
1122 break; /* empty case */
1123
1124 case 1: /* package operation failed (fatal error) */
1125 case 11:
1126 case 21:
1127 failflag++;
1128 interrupted++;
1129 break;
1130
1131 case 2: /* non-fatal error (warning) */
1132 case 12:
1133 case 22:
1134 warnflag++;
1135 interrupted++;
1136 break;
1137
1138 case 3: /* user selected quit; operation interrupted */
1139 case 13:
1140 case 23:
1141 intrflag++;
1142 interrupted++;
1143 break;
1144
1145 case 4: /* admin settings prevented operation */
1146 case 14:
1147 case 24:
1148 admnflag++;
1149 interrupted++;
1150 break;
1151
1152 case 5: /* administration: interaction req (no -n) */
1153 case 15:
1154 case 25:
1155 nullflag++;
1156 interrupted++;
1157 break;
1158
1159 default:
1160 failflag++;
1161 interrupted++;
1162 return;
1163 }
1164
1165 if (retcode >= 20) {
1166 ireboot++;
1167 } else if (retcode >= 10) {
1168 doreboot++;
1169 }
1170 }
1171
1172 static int
pkgZoneCheckRemove(char * a_zoneName,char * a_altBinDir,char * a_adminFile,char * a_stdoutPath,zone_state_t a_zoneState,boolean_t tmpzone)1173 pkgZoneCheckRemove(char *a_zoneName, char *a_altBinDir, char *a_adminFile,
1174 char *a_stdoutPath, zone_state_t a_zoneState, boolean_t tmpzone)
1175 {
1176 char *arg[MAXARGS];
1177 char *p;
1178 char adminfd_path[PATH_MAX];
1179 char path[PATH_MAX];
1180 int fds[MAX_FDS];
1181 int maxfds;
1182 int n;
1183 int nargs;
1184
1185 /* entry assertions */
1186
1187 assert(a_zoneName != (char *)NULL);
1188 assert(*a_zoneName != '\0');
1189
1190 /* entry debugging info */
1191
1192 echoDebug(DBG_PKGZONECHECKREMOVE_ENTRY);
1193 echoDebug(DBG_PKGZONECHECKREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1194 PSTR(pkgdev.dirname), PSTR(a_adminFile), PSTR(a_stdoutPath));
1195
1196 /* generate path to pkgremove */
1197
1198 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1199 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1200
1201 /* start at first file descriptor */
1202
1203 maxfds = 0;
1204
1205 /*
1206 * generate argument list for call to pkgremove
1207 */
1208
1209 /* start at argument 0 */
1210
1211 nargs = 0;
1212
1213 /* first argument is path to executable */
1214
1215 arg[nargs++] = strdup(path);
1216
1217 /* second argument is always: pass -O debug to pkgremove: debug mode */
1218
1219 if (debugFlag == B_TRUE) {
1220 arg[nargs++] = "-O";
1221 arg[nargs++] = "debug";
1222 }
1223
1224 /* pkgrm -b dir: pass -b to pkgremove */
1225
1226 if (a_altBinDir != (char *)NULL) {
1227 arg[nargs++] = "-b";
1228 arg[nargs++] = a_altBinDir;
1229 }
1230
1231 /*
1232 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1233 * pkg requiring operator interaction during a procedure script
1234 * (common before on1093)
1235 */
1236
1237 if (old_pkg) {
1238 arg[nargs++] = "-o";
1239 }
1240
1241 /*
1242 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1243 * symlinks consistent with old behavior
1244 */
1245
1246 if (old_symlinks) {
1247 arg[nargs++] = "-y";
1248 }
1249
1250 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1251
1252 arg[nargs++] = "-M";
1253
1254 /* pkgrm -A: pass -A to pkgremove */
1255
1256 if (pkgrmremote) {
1257 arg[nargs++] = "-A";
1258 }
1259
1260 /* pkgrm -v: pass -v to pkgremove: never trace scripts */
1261
1262 /* pass "-O enable-hollow-package-support" */
1263
1264 if (is_depend_pkginfo_DB()) {
1265 arg[nargs++] = "-O";
1266 arg[nargs++] = "enable-hollow-package-support";
1267 }
1268
1269 /* pass -n to pkgremove: always in noninteractive mode */
1270
1271 arg[nargs++] = "-n";
1272
1273 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1274
1275 if (a_adminFile) {
1276 int fd;
1277 fd = openLocal(a_adminFile, O_RDONLY, tmpdir);
1278 if (fd < 0) {
1279 progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile,
1280 errno, strerror(errno));
1281 return (1);
1282 }
1283 (void) snprintf(adminfd_path, sizeof (adminfd_path),
1284 "/proc/self/fd/%d", fd);
1285 fds[maxfds++] = fd;
1286 arg[nargs++] = "-a";
1287 arg[nargs++] = strdup(adminfd_path);
1288 }
1289
1290 /*
1291 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1292 */
1293 if (a_zoneState == ZONE_STATE_MOUNTED) {
1294 arg[nargs++] = "-R";
1295 arg[nargs++] = "/a";
1296 }
1297
1298 /* pkgrm -F: pass -F to pkgremove: always update DB only */
1299
1300 arg[nargs++] = "-F";
1301
1302 /* pass "-O preremovecheck" */
1303
1304 arg[nargs++] = "-O";
1305 arg[nargs++] = "preremovecheck";
1306
1307 /* add "-O addzonename" */
1308
1309 arg[nargs++] = "-O";
1310 arg[nargs++] = "addzonename";
1311
1312 /*
1313 * add parent zone info/type
1314 */
1315
1316 p = z_get_zonename();
1317 if ((p != NULL) && (*p != '\0')) {
1318 char zn[MAXPATHLEN];
1319 (void) snprintf(zn, sizeof (zn),
1320 "parent-zone-name=%s", p);
1321 arg[nargs++] = "-O";
1322 arg[nargs++] = strdup(zn);
1323 }
1324
1325 /* current zone type */
1326
1327 arg[nargs++] = "-O";
1328 if (z_running_in_global_zone() == B_TRUE) {
1329 char zn[MAXPATHLEN];
1330 (void) snprintf(zn, sizeof (zn),
1331 "parent-zone-type=%s",
1332 TAG_VALUE_GLOBAL_ZONE);
1333 arg[nargs++] = strdup(zn);
1334 } else {
1335 char zn[MAXPATHLEN];
1336 (void) snprintf(zn, sizeof (zn),
1337 "parent-zone-type=%s",
1338 TAG_VALUE_NONGLOBAL_ZONE);
1339 arg[nargs++] = strdup(zn);
1340 }
1341
1342 /* Add arguments how to start the pkgserv */
1343
1344 arg[nargs++] = "-O";
1345 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1346
1347 /* pass -N to pkgremove: program name to report */
1348
1349 arg[nargs++] = "-N";
1350 arg[nargs++] = get_prog_name();
1351
1352 /* add package instance name */
1353
1354 arg[nargs++] = pkginst;
1355
1356 /* terminate argument list */
1357
1358 arg[nargs++] = NULL;
1359
1360 /* execute pkgremove command */
1361
1362 if (debugFlag == B_TRUE) {
1363 echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]);
1364 for (n = 0; arg[n]; n++) {
1365 echoDebug(DBG_ARG, n, arg[n]);
1366 }
1367 }
1368
1369 /* terminate file descriptor list */
1370
1371 fds[maxfds] = -1;
1372
1373 /* exec command in zone */
1374
1375 n = z_zone_exec(a_zoneName, path, arg, a_stdoutPath, (char *)NULL, fds);
1376
1377 echoDebug(DBG_ZONE_EXEC_EXIT, a_zoneName, arg[0], n,
1378 PSTR(a_stdoutPath));
1379
1380 /*
1381 * close any files that were opened for use by the
1382 * /proc/self/fd interface so they could be passed to programs
1383 * via the z_zone_exec() interface
1384 */
1385
1386 for (; maxfds > 0; maxfds--) {
1387 (void) close(fds[maxfds-1]);
1388 }
1389
1390 /* return results of pkgremove in zone execution */
1391
1392 return (n);
1393 }
1394
1395 static int
pkgZoneRemove(char * a_zoneName,int a_nodelete,char * a_altBinDir,char * a_adminFile,zone_state_t a_zoneState,boolean_t tmpzone)1396 pkgZoneRemove(char *a_zoneName, int a_nodelete, char *a_altBinDir,
1397 char *a_adminFile, zone_state_t a_zoneState, boolean_t tmpzone)
1398 {
1399 char *arg[MAXARGS];
1400 char *p;
1401 char adminfd_path[PATH_MAX];
1402 char path[PATH_MAX];
1403 int fds[MAX_FDS];
1404 int maxfds;
1405 int n;
1406 int nargs;
1407
1408 /* entry assertions */
1409
1410 assert(a_zoneName != (char *)NULL);
1411 assert(*a_zoneName != '\0');
1412
1413 /* entry debugging info */
1414
1415 echoDebug(DBG_PKGZONEREMOVE_ENTRY);
1416 echoDebug(DBG_PKGZONEREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1417 PSTR(pkgdev.dirname), a_nodelete, PSTR(a_adminFile));
1418
1419 /* generate path to pkgremove */
1420
1421 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1422 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1423
1424 /* start at first file descriptor */
1425
1426 maxfds = 0;
1427
1428 /*
1429 * generate argument list for call to pkgremove
1430 */
1431
1432 /* start at argument 0 */
1433
1434 nargs = 0;
1435
1436 /* first argument is path to executable */
1437
1438 arg[nargs++] = strdup(path);
1439
1440 /* second argument is always: pass -O debug to pkgremove: debug mode */
1441
1442 if (debugFlag == B_TRUE) {
1443 arg[nargs++] = "-O";
1444 arg[nargs++] = "debug";
1445 }
1446
1447 /* pkgrm -b dir: pass -b to pkgremove */
1448
1449 if (a_altBinDir != (char *)NULL) {
1450 arg[nargs++] = "-b";
1451 arg[nargs++] = a_altBinDir;
1452 }
1453
1454 /*
1455 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1456 * pkg requiring operator interaction during a procedure script
1457 * (common before on1093)
1458 */
1459
1460 if (old_pkg) {
1461 arg[nargs++] = "-o";
1462 }
1463
1464 /*
1465 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1466 * symlinks consistent with old behavior
1467 */
1468
1469 if (old_symlinks) {
1470 arg[nargs++] = "-y";
1471 }
1472
1473 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1474
1475 arg[nargs++] = "-M";
1476
1477 /* pkgrm -A: pass -A to pkgremove */
1478
1479 if (pkgrmremote) {
1480 arg[nargs++] = "-A";
1481 }
1482
1483 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1484
1485 if (pkgverbose) {
1486 arg[nargs++] = "-v";
1487 }
1488
1489 /* pass "-O enable-hollow-package-support" */
1490
1491 if (is_depend_pkginfo_DB()) {
1492 arg[nargs++] = "-O";
1493 arg[nargs++] = "enable-hollow-package-support";
1494 }
1495
1496 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1497
1498 if (nointeract) {
1499 arg[nargs++] = "-n";
1500 }
1501
1502 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1503
1504 if (a_adminFile) {
1505 int fd;
1506 fd = openLocal(a_adminFile, O_RDONLY, tmpdir);
1507 if (fd < 0) {
1508 progerr(ERR_CANNOT_COPY_LOCAL, a_adminFile,
1509 errno, strerror(errno));
1510 return (1);
1511 }
1512 (void) snprintf(adminfd_path, sizeof (adminfd_path),
1513 "/proc/self/fd/%d", fd);
1514 fds[maxfds++] = fd;
1515 arg[nargs++] = "-a";
1516 arg[nargs++] = adminfd_path;
1517 }
1518
1519 /*
1520 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1521 */
1522 if (a_zoneState == ZONE_STATE_MOUNTED) {
1523 arg[nargs++] = "-R";
1524 arg[nargs++] = "/a";
1525 }
1526
1527 /* pkgrm -F: pass -F to pkgremove: update DB only */
1528
1529 if (a_nodelete) {
1530 arg[nargs++] = "-F";
1531 }
1532
1533 /* add "-O addzonename" */
1534
1535 arg[nargs++] = "-O";
1536 arg[nargs++] = "addzonename";
1537
1538 /*
1539 * add parent zone info/type
1540 */
1541
1542 p = z_get_zonename();
1543 if ((p != NULL) && (*p != '\0')) {
1544 char zn[MAXPATHLEN];
1545 (void) snprintf(zn, sizeof (zn),
1546 "parent-zone-name=%s", p);
1547 arg[nargs++] = "-O";
1548 arg[nargs++] = strdup(zn);
1549 }
1550
1551 /* current zone type */
1552
1553 arg[nargs++] = "-O";
1554 if (z_running_in_global_zone() == B_TRUE) {
1555 char zn[MAXPATHLEN];
1556 (void) snprintf(zn, sizeof (zn),
1557 "parent-zone-type=%s",
1558 TAG_VALUE_GLOBAL_ZONE);
1559 arg[nargs++] = strdup(zn);
1560 } else {
1561 char zn[MAXPATHLEN];
1562 (void) snprintf(zn, sizeof (zn),
1563 "parent-zone-type=%s",
1564 TAG_VALUE_NONGLOBAL_ZONE);
1565 arg[nargs++] = strdup(zn);
1566 }
1567
1568 /* Add arguments how to start the pkgserv */
1569
1570 arg[nargs++] = "-O";
1571 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1572
1573 /* pass -N to pkgremove: program name to report */
1574
1575 arg[nargs++] = "-N";
1576 arg[nargs++] = get_prog_name();
1577
1578 /* add package instance name */
1579
1580 arg[nargs++] = pkginst;
1581
1582 /* terminate argument list */
1583
1584 arg[nargs++] = NULL;
1585
1586 /* execute pkgremove command */
1587
1588 if (debugFlag == B_TRUE) {
1589 echoDebug(DBG_ZONE_EXEC_ENTER, a_zoneName, arg[0]);
1590 for (n = 0; arg[n]; n++) {
1591 echoDebug(DBG_ARG, n, arg[n]);
1592 }
1593 }
1594
1595 /* terminate file descriptor list */
1596
1597 fds[maxfds] = -1;
1598
1599 /* exec command in zone */
1600
1601 n = z_zone_exec(a_zoneName, path, arg, (char *)NULL, (char *)NULL, fds);
1602
1603 /*
1604 * close any files that were opened for use by the
1605 * /proc/self/fd interface so they could be passed to programs
1606 * via the z_zone_exec() interface
1607 */
1608
1609 for (; maxfds > 0; maxfds--) {
1610 (void) close(fds[maxfds-1]);
1611 }
1612
1613 return (n);
1614 }
1615
1616 /*
1617 * Name: pkgRemove
1618 * Description: Invoke pkgremove in the current zone to perform a remove
1619 * of a single package from the current zone or standalone system
1620 * Arguments: a_nodelete: should the files and scripts remain installed?
1621 * - if != 0 pass -F flag to pkgremove - suppress
1622 * the removal of any files and any class action scripts
1623 * and suppress the running of any class action scripts.
1624 * The package files remain but the package looks like it
1625 * is not installed. This is mainly for use by upgrade.
1626 * - if == 0 do not pass -F flag to pkgremove - all
1627 * files and class action scripts are removed, and any
1628 * appropriate class action scripts are run.
1629 * a_altBinDir - pointer to string representing location of the
1630 * pkgremove executable to run. If not NULL, then pass
1631 * the path specified to the -b option to pkgremove.
1632 * a_adminFile - pointer to string representing the admin
1633 * file to pass to pkgremove when removing the package.
1634 * If this is == NULL no admin file is given to pkgremove.
1635 * Returns: int (see ckreturn() function for details)
1636 * 0 - success
1637 * 1 - package operation failed (fatal error)
1638 * 2 - non-fatal error (warning)
1639 * 3 - user selected quit (operation interrupted)
1640 * 4 - admin settings prevented operation
1641 * 5 - interaction required and -n (non-interactive) specified
1642 * "10" will be added to indicate "immediate reboot required"
1643 * "20" will be added to indicate "reboot after install required"
1644 */
1645
1646 static int
pkgRemove(int a_nodelete,char * a_altBinDir,char * a_adminFile)1647 pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile)
1648 {
1649 char *arg[MAXARGS];
1650 char *p;
1651 char path[PATH_MAX];
1652 int n;
1653 int nargs;
1654
1655 /* entry debugging info */
1656
1657 echoDebug(DBG_PKGREMOVE_ENTRY);
1658 echoDebug(DBG_PKGREMOVE_ARGS, PSTR(pkginst), PSTR(pkgdev.dirname),
1659 a_nodelete, PSTR(a_adminFile));
1660
1661 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1662 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1663
1664 nargs = 0;
1665
1666 /* first argument is path to executable */
1667
1668 arg[nargs++] = strdup(path);
1669
1670 /* second argument is always: pass -O debug to pkgremove: debug mode */
1671
1672 if (debugFlag == B_TRUE) {
1673 arg[nargs++] = "-O";
1674 arg[nargs++] = "debug";
1675 }
1676
1677 /* Add arguments how to start the pkgserv */
1678
1679 arg[nargs++] = "-O";
1680 arg[nargs++] = pkgmodeargument(pkgservergetmode());
1681
1682 /* pkgrm -b dir: pass -b to pkgremove */
1683
1684 if (a_altBinDir != (char *)NULL) {
1685 arg[nargs++] = "-b";
1686 arg[nargs++] = a_altBinDir;
1687 }
1688
1689 /*
1690 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1691 * pkg requiring operator interaction during a procedure script
1692 * (common before on1093)
1693 */
1694
1695 if (old_pkg) {
1696 arg[nargs++] = "-o";
1697 }
1698
1699 /*
1700 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1701 * symlinks consistent with old behavior
1702 */
1703
1704 if (old_symlinks) {
1705 arg[nargs++] = "-y";
1706 }
1707
1708 /* pkgrm -M: pass -M to pkgrm: dont mount client file systems */
1709
1710 if (no_map_client) {
1711 arg[nargs++] = "-M";
1712 }
1713
1714 /* pkgrm -A: pass -A to pkgrm */
1715
1716 if (pkgrmremote) {
1717 arg[nargs++] = "-A";
1718 }
1719
1720 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1721
1722 if (pkgverbose) {
1723 arg[nargs++] = "-v";
1724 }
1725
1726 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1727
1728 if (nointeract) {
1729 arg[nargs++] = "-n";
1730 }
1731
1732 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1733
1734 if (a_adminFile) {
1735 arg[nargs++] = "-a";
1736 arg[nargs++] = strdup(a_adminFile);
1737 }
1738
1739 /* pkgrm -V vfstab: pass -V vfstab to pkgremove: alternate vfstab */
1740
1741 if (vfstab_file) {
1742 arg[nargs++] = "-V";
1743 arg[nargs++] = vfstab_file;
1744 }
1745
1746 /* pkgrm -R root: pass -R root to pkgremove: alternative root */
1747
1748 if (is_an_inst_root()) {
1749 arg[nargs++] = "-R";
1750 arg[nargs++] = get_inst_root();
1751 }
1752
1753 /* pkgrm -F: pass -F to pkgremove: update DB only */
1754
1755 if (a_nodelete) {
1756 arg[nargs++] = "-F";
1757 }
1758
1759 /*
1760 * add parent zone info/type
1761 */
1762
1763 p = z_get_zonename();
1764 if ((p != NULL) && (*p != '\0')) {
1765 char zn[MAXPATHLEN];
1766 (void) snprintf(zn, sizeof (zn),
1767 "parent-zone-name=%s", p);
1768 arg[nargs++] = "-O";
1769 arg[nargs++] = strdup(zn);
1770 }
1771
1772 /* current zone type */
1773
1774 arg[nargs++] = "-O";
1775 if (z_running_in_global_zone() == B_TRUE) {
1776 char zn[MAXPATHLEN];
1777 (void) snprintf(zn, sizeof (zn),
1778 "parent-zone-type=%s",
1779 TAG_VALUE_GLOBAL_ZONE);
1780 arg[nargs++] = strdup(zn);
1781 } else {
1782 char zn[MAXPATHLEN];
1783 (void) snprintf(zn, sizeof (zn),
1784 "parent-zone-type=%s",
1785 TAG_VALUE_NONGLOBAL_ZONE);
1786 arg[nargs++] = strdup(zn);
1787 }
1788
1789 /* pass -N to pkgremove: program name to report */
1790
1791 arg[nargs++] = "-N";
1792 arg[nargs++] = get_prog_name();
1793
1794 /* add package instance name */
1795
1796 arg[nargs++] = pkginst;
1797
1798 /* terminate argument list */
1799
1800 arg[nargs++] = NULL;
1801
1802 /*
1803 * run the appropriate pkgremove command in the specified zone
1804 */
1805
1806 if (debugFlag == B_TRUE) {
1807 echoDebug(DBG_ZONE_EXEC_ENTER, "global", arg[0]);
1808 for (n = 0; arg[n]; n++) {
1809 echoDebug(DBG_ARG, n, arg[n]);
1810 }
1811 }
1812
1813 /* execute pkgremove command */
1814
1815 n = pkgexecv(NULL, NULL, NULL, NULL, arg);
1816
1817 /* return results of pkgrm in this zone */
1818
1819 return (n);
1820 }
1821
1822 static void
usage(void)1823 usage(void)
1824 {
1825 char *prog = get_prog_name();
1826
1827 (void) fprintf(stderr, ERR_USAGE_PKGRM, prog, prog);
1828 exit(1);
1829 }
1830
1831 /*
1832 * Name: remove_packages_in_global_with_zones
1833 * Description: Remove packages from the global zone and from non-global zones
1834 * when run from the global zone and when non-global zones are
1835 * present.
1836 * Arguments: a_pkgList - pointer to array of strings, each string specifying
1837 * the name of one package to be removed.
1838 * a_nodelete: should the files and scripts remain installed?
1839 * - if != 0 pass -F flag to pkgremove - suppress
1840 * the removal of any files and any class action scripts
1841 * and suppress the running of any class action scripts.
1842 * The package files remain but the package looks like it
1843 * is not installed. This is mainly for use by upgrade.
1844 * - if == 0 do not pass -F flag to pkgremove - all
1845 * files and class action scripts are removed, and any
1846 * appropriate class action scripts are run.
1847 * a_longestPkg - length of the longest package "name" (for
1848 * output format alignment)
1849 * a_repeat - are there more packages avialable in "optind"
1850 * - B_TRUE - process packages from optind
1851 * - B_FALSE - do not process packages from optind
1852 * a_altBinDir - pointer to string representing location of the
1853 * pkgremove executable to run. If not NULL, then pass
1854 * the path specified to the -b option to pkgremove.
1855 * a_pkgdir - pointer to string representing the directory
1856 * where the packages to be removed are located.
1857 * a_zlst - list of zones to process; NULL if no zones to process.
1858 * Returns: int (see ckreturn() function for details)
1859 * 0 - success
1860 * 1 - package operation failed (fatal error)
1861 * 2 - non-fatal error (warning)
1862 * 3 - user selected quit (operation interrupted)
1863 * 4 - admin settings prevented operation
1864 * 5 - interaction required and -n (non-interactive) specified
1865 * "10" will be added to indicate "immediate reboot required"
1866 * "20" will be added to indicate "reboot after install required"
1867 */
1868
1869 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)1870 remove_packages_in_global_with_zones(char **a_pkgList, int a_nodelete,
1871 int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir,
1872 zoneList_t a_zlst)
1873 {
1874 static char *zoneAdminFile = (char *)NULL;
1875
1876 boolean_t b;
1877 char *zoneName;
1878 char *scratchName;
1879 char preremovecheckPath[PATH_MAX+1];
1880 int i;
1881 int n;
1882 int savenpkgs = npkgs;
1883 int zoneIndex;
1884 int zonesSkipped;
1885 zone_state_t zst;
1886
1887 /* entry assertions */
1888
1889 assert(a_zlst != (zoneList_t)NULL);
1890 assert(a_pkgList != (char **)NULL);
1891 assert(a_longestPkg > 0);
1892 assert(a_pkgdir != (char *)NULL);
1893 assert(*a_pkgdir != '\0');
1894
1895 /* entry debugging info */
1896
1897 echoDebug(DBG_PKGREMPKGSGZWNGZ_ENTRY);
1898 echoDebug(DBG_PKGREMPKGSGZWNGZ_ARGS, a_nodelete, a_longestPkg,
1899 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
1900
1901 /* check all packages */
1902
1903 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
1904 quit(1);
1905 }
1906
1907 /* create temporary directory for use by zone operations */
1908
1909 create_zone_tempdir(&zoneTempDir, tmpdir);
1910
1911 /* create hands off settings admin file for use in a non-global zone */
1912
1913 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
1914
1915 /*
1916 * all of the packages (as listed in the package list) are
1917 * removed one at a time from all non-global zones and then
1918 * from the global zone.
1919 */
1920
1921 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
1922 /* reset interrupted flag before calling pkgremove */
1923
1924 interrupted = 0; /* last action was NOT quit */
1925
1926 /* skip package if it is "in the global zone only" */
1927
1928 if (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE) {
1929 continue;
1930 }
1931
1932 /*
1933 * if operation failed in global zone do not propagate to
1934 * non-global zones
1935 */
1936
1937 zonesSkipped = 0;
1938
1939 if (interrupted != 0) {
1940 echo(MSG_DOREMOVE_INTERRUPTED, pkginst);
1941 echoDebug(DBG_DOREMOVE_INTERRUPTED, pkginst);
1942 break;
1943 }
1944
1945 echoDebug(DBG_REMOVE_FLAG_VALUES, "before loop",
1946 admnflag, doreboot, failflag, interrupted,
1947 intrflag, ireboot, nullflag, warnflag);
1948
1949 for (zoneIndex = 0;
1950 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1951 (char *)NULL; zoneIndex++) {
1952
1953 /* skip the zone if it is NOT running */
1954
1955 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
1956 if (zst != ZONE_STATE_RUNNING &&
1957 zst != ZONE_STATE_MOUNTED) {
1958 zonesSkipped++;
1959 echoDebug(DBG_SKIPPING_ZONE, zoneName);
1960 continue;
1961 }
1962
1963 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
1964 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
1965 zoneName);
1966
1967 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
1968
1969 (void) snprintf(preremovecheckPath,
1970 sizeof (preremovecheckPath),
1971 "%s/%s.%s.preremovecheck.txt",
1972 zoneTempDir, pkginst, scratchName);
1973
1974 /*
1975 * dependency check this package this zone; use the
1976 * user supplied admin file so that the appropriate
1977 * level of dependency checking is (or is not) done.
1978 */
1979
1980 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
1981 admnfile, preremovecheckPath,
1982 zst, B_FALSE);
1983
1984 /* set success/fail condition variables */
1985
1986 ckreturn(n);
1987
1988 echoDebug(DBG_REMOVE_FLAG_VALUES,
1989 "after pkgzonecheckremove",
1990 admnflag, doreboot, failflag, interrupted,
1991 intrflag, ireboot, nullflag, warnflag);
1992 }
1993
1994 if (zonesSkipped == 0) {
1995 continue;
1996 }
1997
1998 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
1999
2000 for (zoneIndex = 0;
2001 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
2002 (char *)NULL; zoneIndex++) {
2003
2004 /* skip the zone if it IS running */
2005
2006 zst = z_zlist_get_current_state(a_zlst, zoneIndex);
2007 if (zst == ZONE_STATE_RUNNING ||
2008 zst == ZONE_STATE_MOUNTED) {
2009 zonesSkipped++;
2010 echoDebug(DBG_SKIPPING_ZONE_BOOT, zoneName);
2011 continue;
2012 }
2013
2014 /* skip the zone if it is NOT bootable */
2015
2016 if (z_zlist_is_zone_runnable(a_zlst,
2017 zoneIndex) == B_FALSE) {
2018 echo(MSG_SKIPPING_ZONE_NOT_RUNNABLE, zoneName);
2019 echoDebug(DBG_SKIPPING_ZONE_NOT_RUNNABLE,
2020 zoneName);
2021 continue;
2022 }
2023
2024 /* mount up the zone */
2025
2026 echo(MSG_BOOTING_ZONE, zoneName);
2027 echoDebug(DBG_BOOTING_ZONE, zoneName);
2028
2029 b = z_zlist_change_zone_state(a_zlst, zoneIndex,
2030 ZONE_STATE_MOUNTED);
2031 if (b == B_FALSE) {
2032 progerr(ERR_CANNOT_BOOT_ZONE, zoneName);
2033 /* set fatal error return condition */
2034 ckreturn(1);
2035 continue;
2036 }
2037
2038 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
2039 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
2040 zoneName);
2041
2042 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
2043
2044 (void) snprintf(preremovecheckPath,
2045 sizeof (preremovecheckPath),
2046 "%s/%s.%s.preremovecheck.txt",
2047 zoneTempDir, pkginst, scratchName);
2048
2049 /*
2050 * dependency check this package this zone; use the
2051 * user supplied admin file so that the appropriate
2052 * level of dependency checking is (or is not) done.
2053 */
2054
2055 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
2056 admnfile, preremovecheckPath,
2057 ZONE_STATE_MOUNTED, B_TRUE);
2058
2059 /* set success/fail condition variables */
2060
2061 ckreturn(n);
2062
2063 echoDebug(DBG_REMOVE_FLAG_VALUES,
2064 "after pkgzonecheckremove",
2065 admnflag, doreboot, failflag, interrupted,
2066 intrflag, ireboot, nullflag, warnflag);
2067
2068 /* restore original state of zone */
2069
2070 echo(MSG_RESTORE_ZONE_STATE, zoneName);
2071 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
2072
2073 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
2074 }
2075 npkgs--;
2076 }
2077
2078 /*
2079 * look at all pre-remove check files
2080 */
2081
2082 i = preremove_verify(a_pkgList, a_zlst, zoneTempDir);
2083 if (i != 0) {
2084 quit(i);
2085 }
2086
2087 npkgs = savenpkgs;
2088
2089 /*
2090 * reset all error return condition variables that may have been
2091 * set during package removal dependency checking so that they
2092 * do not reflect on the success/failure of the actual package
2093 * removal operations
2094 */
2095
2096 resetreturn();
2097
2098 /*
2099 * all of the packages (as listed in the package list) are
2100 * removed one at a time.
2101 */
2102
2103 interrupted = 0;
2104 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2105 boolean_t in_gz_only;
2106 started = 0;
2107
2108 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2109 continue;
2110 }
2111
2112 in_gz_only = pkgIsPkgInGzOnly(get_inst_root(), pkginst);
2113
2114 /* reset interrupted flag before calling pkgremove */
2115
2116 interrupted = 0;
2117
2118 /*
2119 * pkgrm invoked from within the global zone and there are
2120 * non-global zones configured:
2121 * Remove the package from the global zone.
2122 * If not removing the package from the global zone only,
2123 * then remove the package from the list of zones specified.
2124 */
2125
2126 if (in_gz_only) {
2127 /* global zone only */
2128 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2129 admnfile, (char *)NULL, (zoneList_t)NULL);
2130 } else {
2131 /* global zone and non-global zones */
2132 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2133 zoneAdminFile, zoneAdminFile, a_zlst);
2134 }
2135
2136 /* set success/fail condition variables */
2137
2138 ckreturn(n);
2139
2140 npkgs--;
2141 }
2142
2143 /*
2144 * all packages in the package list have been removed.
2145 * Continue with removal if:
2146 * -- immediate reboot is NOT required
2147 * -- there are more packages to remove
2148 * else return do NOT continue.
2149 */
2150
2151 if ((ireboot == 0) && (a_repeat != 0)) {
2152 return (B_TRUE);
2153 }
2154
2155 /* return 'dont continue' */
2156
2157 return (B_FALSE);
2158 }
2159
2160 /*
2161 * Name: remove_packages_in_nonglobal_zone
2162 * Description: Remove packages in a non-global zone when run from a
2163 * non-global zone.
2164 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2165 * the name of one package to be removed.
2166 * a_nodelete: should the files and scripts remain installed?
2167 * - if != 0 pass -F flag to pkgremove - suppress
2168 * the removal of any files and any class action scripts
2169 * and suppress the running of any class action scripts.
2170 * The package files remain but the package looks like it
2171 * is not installed. This is mainly for use by upgrade.
2172 * - if == 0 do not pass -F flag to pkgremove - all
2173 * files and class action scripts are removed, and any
2174 * appropriate class action scripts are run.
2175 * a_longestPkg - length of the longest package "name" (for
2176 * output format alignment)
2177 * a_repeat - are there more packages avialable in "optind"
2178 * - B_TRUE - process packages from optind
2179 * - B_FALSE - do not process packages from optind
2180 * a_altBinDir - pointer to string representing location of the
2181 * pkgremove executable to run. If not NULL, then pass
2182 * the path specified to the -b option to pkgremove.
2183 * a_pkgdir - pointer to string representing the directory
2184 * where the packages to be removed are located.
2185 * Returns: int (see ckreturn() function for details)
2186 * 0 - success
2187 * 1 - package operation failed (fatal error)
2188 * 2 - non-fatal error (warning)
2189 * 3 - user selected quit (operation interrupted)
2190 * 4 - admin settings prevented operation
2191 * 5 - interaction required and -n (non-interactive) specified
2192 * "10" will be added to indicate "immediate reboot required"
2193 * "20" will be added to indicate "reboot after install required"
2194 */
2195
2196 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)2197 remove_packages_in_nonglobal_zone(char **a_pkgList, int a_nodelete,
2198 int a_longestPkg, int a_repeat, char *a_altBinDir, char *a_pkgdir)
2199 {
2200 static char *zoneAdminFile = (char *)NULL;
2201
2202 int n;
2203 int i;
2204
2205 /* entry assertions */
2206
2207 assert(a_pkgList != (char **)NULL);
2208 assert(a_longestPkg > 0);
2209 assert(a_pkgdir != (char *)NULL);
2210 assert(*a_pkgdir != '\0');
2211
2212 /* entry debugging info */
2213
2214 echoDebug(DBG_PKGREMPKGSNGZ_ENTRY);
2215 echoDebug(DBG_PKGREMPKGSNGZ_ARGS, a_nodelete, a_longestPkg,
2216 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
2217
2218 /* check all package */
2219
2220 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
2221 quit(1);
2222 }
2223
2224 /* create temporary directory for use by zone operations */
2225
2226 create_zone_tempdir(&zoneTempDir, tmpdir);
2227
2228 /* create hands off settings admin file for use in a non-global zone */
2229
2230 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
2231
2232 /*
2233 * all of the packages (as listed in the package list) are
2234 * removed one at a time.
2235 */
2236
2237 interrupted = 0;
2238 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2239 started = 0;
2240
2241 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2242 continue;
2243 }
2244
2245 interrupted = 0;
2246
2247 /*
2248 * pkgrm invoked from within a non-global zone: remove
2249 * the package from the current zone only - no non-global
2250 * zones are possible.
2251 */
2252
2253 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2254 admnfile, (char *)NULL, (zoneList_t)NULL);
2255
2256 /* set success/fail condition variables */
2257
2258 ckreturn(n);
2259
2260 npkgs--;
2261 }
2262
2263 /*
2264 * all packages in the package list have been removed.
2265 * Continue with removal if:
2266 * -- immediate reboot is NOT required
2267 * -- there are more packages to remove
2268 * else return do NOT continue.
2269 */
2270
2271 if ((ireboot == 0) && (a_repeat != 0)) {
2272 return (B_TRUE);
2273 }
2274
2275 /* return 'dont continue' */
2276
2277 return (B_FALSE);
2278 }
2279
2280 /*
2281 * Name: remove_packages_in_global_no_zones
2282 * Description: Remove packages from the global zone only when run in the
2283 * global zone and no non-global zones are installed.
2284 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2285 * the name of one package to be removed.
2286 * a_nodelete: should the files and scripts remain installed?
2287 * - if != 0 pass -F flag to pkgremove - suppress
2288 * the removal of any files and any class action scripts
2289 * and suppress the running of any class action scripts.
2290 * The package files remain but the package looks like it
2291 * is not installed. This is mainly for use by upgrade.
2292 * - if == 0 do not pass -F flag to pkgremove - all
2293 * files and class action scripts are removed, and any
2294 * appropriate class action scripts are run.
2295 * a_longestPkg - length of the longest package "name" (for
2296 * output format alignment)
2297 * a_repeat - are there more packages avialable in "optind"
2298 * - B_TRUE - process packages from optind
2299 * - B_FALSE - do not process packages from optind
2300 * a_altBinDir - pointer to string representing location of the
2301 * pkgremove executable to run. If not NULL, then pass
2302 * the path specified to the -b option to pkgremove.
2303 * Returns: int (see ckreturn() function for details)
2304 * 0 - success
2305 * 1 - package operation failed (fatal error)
2306 * 2 - non-fatal error (warning)
2307 * 3 - user selected quit (operation interrupted)
2308 * 4 - admin settings prevented operation
2309 * 5 - interaction required and -n (non-interactive) specified
2310 * "10" will be added to indicate "immediate reboot required"
2311 * "20" will be added to indicate "reboot after install required"
2312 */
2313
2314 static boolean_t
remove_packages_in_global_no_zones(char ** a_pkgList,int a_nodelete,int a_longestPkg,int a_repeat,char * a_altBinDir)2315 remove_packages_in_global_no_zones(char **a_pkgList, int a_nodelete,
2316 int a_longestPkg, int a_repeat, char *a_altBinDir)
2317 {
2318 int n;
2319 int i;
2320
2321 /* entry assertions */
2322
2323 assert(a_pkgList != (char **)NULL);
2324 assert(a_longestPkg > 0);
2325
2326 /* entry debugging info */
2327
2328 echoDebug(DBG_PKGREMPKGSGZNNGZ_ENTRY);
2329 echoDebug(DBG_PKGREMPKGSGZNNGZ_ARGS, a_nodelete, a_longestPkg,
2330 a_repeat, PSTR(a_altBinDir));
2331
2332 /*
2333 * all of the packages (as listed in the package list) are
2334 * removed one at a time.
2335 */
2336
2337 interrupted = 0;
2338 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2339 started = 0;
2340
2341 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2342 continue;
2343 }
2344
2345 interrupted = 0;
2346
2347 /*
2348 * pkgrm invoked from within the global zone and there are
2349 * NO non-global zones configured:
2350 * Remove the package from the global zone only.
2351 */
2352
2353 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2354 admnfile, (char *)NULL, (zoneList_t)NULL);
2355
2356 /* set success/fail condition variables */
2357
2358 ckreturn(n);
2359
2360 npkgs--;
2361 }
2362
2363 /*
2364 * all packages in the package list have been removed.
2365 * Continue with removal if:
2366 * -- immediate reboot is NOT required
2367 * -- there are more packages to remove
2368 * else return do NOT continue.
2369 */
2370
2371 if ((ireboot == 0) && (a_repeat != 0)) {
2372 return (B_TRUE);
2373 }
2374
2375 /* return 'dont continue' */
2376
2377 return (B_FALSE);
2378 }
2379
2380 /*
2381 * Name: remove_packages_from_spool_directory
2382 * Description: Remove packages from a spool directory only.
2383 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2384 * the name of one package to be removed.
2385 * a_nodelete: should the files and scripts remain installed?
2386 * - if != 0 pass -F flag to pkgremove - suppress
2387 * the removal of any files and any class action scripts
2388 * and suppress the running of any class action scripts.
2389 * The package files remain but the package looks like it
2390 * is not installed. This is mainly for use by upgrade.
2391 * - if == 0 do not pass -F flag to pkgremove - all
2392 * files and class action scripts are removed, and any
2393 * appropriate class action scripts are run.
2394 * a_longestPkg - length of the longest package "name" (for
2395 * output format alignment)
2396 * a_repeat - are there more packages avialable in "optind"
2397 * - B_TRUE - process packages from optind
2398 * - B_FALSE - do not process packages from optind
2399 * a_altBinDir - pointer to string representing location of the
2400 * pkgremove executable to run. If not NULL, then pass
2401 * the path specified to the -b option to pkgremove.
2402 * Returns: int (see ckreturn() function for details)
2403 * 0 - success
2404 * 1 - package operation failed (fatal error)
2405 * 2 - non-fatal error (warning)
2406 * 3 - user selected quit (operation interrupted)
2407 * 4 - admin settings prevented operation
2408 * 5 - interaction required and -n (non-interactive) specified
2409 * "10" will be added to indicate "immediate reboot required"
2410 * "20" will be added to indicate "reboot after install required"
2411 */
2412
2413 static boolean_t
remove_packages_from_spool_directory(char ** a_pkgList,int a_nodelete,int a_longestPkg,int a_repeat,char * a_altBinDir)2414 remove_packages_from_spool_directory(char **a_pkgList, int a_nodelete,
2415 int a_longestPkg, int a_repeat, char *a_altBinDir)
2416 {
2417 int n;
2418 int i;
2419
2420 /* entry assertions */
2421
2422 assert(a_pkgList != (char **)NULL);
2423 assert(a_longestPkg > 0);
2424
2425 /*
2426 * all of the packages (as listed in the package list) are
2427 * removed one at a time.
2428 */
2429
2430 interrupted = 0;
2431 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2432 started = 0;
2433
2434 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2435 continue;
2436 }
2437
2438 interrupted = 0;
2439
2440 /*
2441 * pkgrm invoked from any type of zone BUT the target
2442 * to be removed is a local spool directory: remove the
2443 * packages from the spool directory only.
2444 */
2445
2446 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2447 admnfile, (char *)NULL, (zoneList_t)NULL);
2448
2449 /* set success/fail condition variables */
2450
2451 ckreturn(n);
2452
2453 npkgs--;
2454 }
2455
2456 /*
2457 * all packages in the package list have been removed.
2458 * Continue with removal if:
2459 * -- immediate reboot is NOT required
2460 * -- there are more packages to remove
2461 * else return do NOT continue.
2462 */
2463
2464 if ((ireboot == 0) && (a_repeat != 0)) {
2465 return (B_TRUE);
2466 }
2467
2468 /* return 'dont continue' */
2469
2470 return (B_FALSE);
2471 }
2472
2473 /*
2474 * Name: remove_packages
2475 * Description: Remove packages from the global zone, and optionally from one
2476 * or more non-global zones, or from a specified spool directory.
2477 * Arguments: a_pkgList - pointer to array of strings, each string specifying
2478 * the name of one package to be removed.
2479 * a_nodelete: should the files and scripts remain installed?
2480 * - if != 0 pass -F flag to pkgremove - suppress
2481 * the removal of any files and any class action scripts
2482 * and suppress the running of any class action scripts.
2483 * The package files remain but the package looks like it
2484 * is not installed. This is mainly for use by upgrade.
2485 * - if == 0 do not pass -F flag to pkgremove - all
2486 * files and class action scripts are removed, and any
2487 * appropriate class action scripts are run.
2488 * a_longestPkg - length of the longest package "name" (for
2489 * output format alignment)
2490 * a_repeat - are there more packages avialable in "optind"
2491 * - B_TRUE - process packages from optind
2492 * - B_FALSE - do not process packages from optind
2493 * a_altBinDir - pointer to string representing location of the
2494 * pkgremove executable to run. If not NULL, then pass
2495 * the path specified to the -b option to pkgremove.
2496 * a_pkgdir - pointer to string representing the directory
2497 * where the packages to be removed are located.
2498 * a_spoolDir - pointer to string specifying spool directory
2499 * to remove packages from. If != NULL then all zones
2500 * processing is bypassed and the packages are removed
2501 * from the specified spool directory only.
2502 * a_noZones - if non-global zones are configured, should the
2503 * packages be removed from the non-global zones?
2504 * - B_TRUE - do NOT remove packages from non-global zones
2505 * - B_FALSE - remove packages from non-global zones
2506 * Returns: int (see ckreturn() function for details)
2507 * 0 - success
2508 * 1 - package operation failed (fatal error)
2509 * 2 - non-fatal error (warning)
2510 * 3 - user selected quit (operation interrupted)
2511 * 4 - admin settings prevented operation
2512 * 5 - interaction required and -n (non-interactive) specified
2513 * "10" will be added to indicate "immediate reboot required"
2514 * "20" will be added to indicate "reboot after install required"
2515 */
2516
2517 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)2518 remove_packages(char **a_pkgList, int a_nodelete, int a_longestPkg,
2519 int a_repeat, char *a_altBinDir, char *a_pkgdir, char *a_spoolDir,
2520 boolean_t a_noZones)
2521 {
2522 zoneList_t zlst;
2523 boolean_t b;
2524
2525 /* entry assertions */
2526
2527 assert(a_pkgList != (char **)NULL);
2528
2529 echoDebug(DBG_REMOVEPKGS_ENTRY);
2530 echoDebug(DBG_REMOVEPKGS_ARGS, npkgs, a_nodelete, a_longestPkg,
2531 a_repeat, PSTR(a_pkgdir), PSTR(a_spoolDir));
2532
2533 /*
2534 * if removing from spool directory, bypass all zones checks
2535 */
2536
2537 if (a_spoolDir != (char *)NULL) {
2538 /* in non-global zone */
2539
2540 echoDebug(DBG_REMOVE_PKGS_FROM_SPOOL, a_spoolDir);
2541
2542 b = remove_packages_from_spool_directory(a_pkgList, a_nodelete,
2543 a_longestPkg, a_repeat, a_altBinDir);
2544
2545 return (B_FALSE);
2546 }
2547
2548 /* exit if not root */
2549
2550 if (getuid()) {
2551 progerr(ERR_NOT_ROOT, get_prog_name());
2552 exit(1);
2553 }
2554
2555 /*
2556 * if running in the global zone AND one or more non-global
2557 * zones exist, add packages in a 'zones aware' manner, else
2558 * add packages in the standard 'non-zones aware' manner.
2559 */
2560
2561 if ((a_noZones == B_FALSE) && (z_running_in_global_zone() == B_FALSE)) {
2562 /* in non-global zone */
2563
2564 echoDebug(DBG_IN_LZ);
2565
2566 b = z_lock_this_zone(ZLOCKS_PKG_ADMIN);
2567 if (b != B_TRUE) {
2568 progerr(ERR_CANNOT_LOCK_THIS_ZONE);
2569 /* set fatal error return condition */
2570 ckreturn(1);
2571 return (B_FALSE);
2572 }
2573
2574 b = remove_packages_in_nonglobal_zone(a_pkgList, a_nodelete,
2575 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir);
2576
2577 (void) z_unlock_this_zone(ZLOCKS_ALL);
2578
2579 return (B_FALSE);
2580 }
2581
2582 /* running in the global zone */
2583
2584 b = z_non_global_zones_exist();
2585 if ((a_noZones == B_FALSE) && (b == B_TRUE)) {
2586
2587 echoDebug(DBG_IN_GZ_WITH_LZ);
2588
2589 /* get a list of all non-global zones */
2590 zlst = z_get_nonglobal_zone_list();
2591 if (zlst == (zoneList_t)NULL) {
2592 progerr(ERR_CANNOT_GET_ZONE_LIST);
2593 quit(1);
2594 }
2595
2596 /* need to lock all of the zones */
2597
2598 quitSetZonelist(zlst);
2599 b = z_lock_zones(zlst, ZLOCKS_PKG_ADMIN);
2600 if (b == B_FALSE) {
2601 z_free_zone_list(zlst);
2602 progerr(ERR_CANNOT_LOCK_ZONES);
2603 /* set fatal error return condition */
2604 ckreturn(1);
2605 return (B_FALSE);
2606 }
2607
2608 /* add packages to all zones */
2609
2610 b = remove_packages_in_global_with_zones(a_pkgList, a_nodelete,
2611 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir, zlst);
2612
2613 /* unlock all zones */
2614
2615 (void) z_unlock_zones(zlst, ZLOCKS_ALL);
2616 quitSetZonelist((zoneList_t)NULL);
2617
2618 /* free list of all non-global zones */
2619
2620 z_free_zone_list(zlst);
2621
2622 return (B_FALSE);
2623 }
2624
2625 /* in global zone no non-global zones */
2626
2627 echoDebug(DBG_IN_GZ_NO_LZ);
2628
2629 b = z_lock_this_zone(ZLOCKS_PKG_ADMIN);
2630 if (b != B_TRUE) {
2631 progerr(ERR_CANNOT_LOCK_THIS_ZONE);
2632 /* set fatal error return condition */
2633 ckreturn(1);
2634 return (B_FALSE);
2635 }
2636
2637 b = remove_packages_in_global_no_zones(a_pkgList, a_nodelete,
2638 a_longestPkg, a_repeat, a_altBinDir);
2639
2640 (void) z_unlock_this_zone(ZLOCKS_ALL);
2641
2642 return (B_FALSE);
2643 }
2644
2645 /*
2646 * Name: path_valid
2647 * Description: Checks a string for being a valid path
2648 *
2649 * Arguments: path - path to validate
2650 *
2651 * Returns : B_TRUE - success, B_FALSE otherwise.
2652 * B_FALSE means path was null, too long (>PATH_MAX),
2653 * or too short (<1)
2654 */
2655 static boolean_t
path_valid(char * path)2656 path_valid(char *path)
2657 {
2658 if (path == NULL) {
2659 return (B_FALSE);
2660 } else if (strlen(path) > PATH_MAX) {
2661 return (B_FALSE);
2662 } else if (strlen(path) >= 1) {
2663 return (B_TRUE);
2664 } else {
2665 /* path < 1 */
2666 return (B_FALSE);
2667 }
2668 }
2669
2670 /*
2671 */
2672
2673 static boolean_t
check_packages(char ** a_pkgList,char * a_packageDir)2674 check_packages(char **a_pkgList, char *a_packageDir)
2675 {
2676 int savenpkgs = npkgs;
2677 int i;
2678 CAF_T flags = 0;
2679
2680 /* set flags for applicability check */
2681
2682 if (z_running_in_global_zone() == B_TRUE) {
2683 flags |= CAF_IN_GLOBAL_ZONE;
2684 }
2685
2686 /*
2687 * for each package to remove, verify that the package is installed
2688 * and is removable.
2689 */
2690
2691 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2692 /* check package applicability */
2693 if (check_applicability(a_packageDir, pkginst, get_inst_root(),
2694 flags) == B_FALSE) {
2695 progerr(ERR_PKG_NOT_REMOVABLE, pkginst);
2696 npkgs = savenpkgs;
2697 return (B_FALSE);
2698 }
2699 npkgs--;
2700 }
2701
2702 npkgs = savenpkgs;
2703 return (B_TRUE);
2704 }
2705
2706 /*
2707 * - is this package removable from this zone?
2708 * - does the scope of remove conflict with existing installation
2709 */
2710
2711 static boolean_t
check_applicability(char * a_packageDir,char * a_pkgInst,char * a_rootPath,CAF_T a_flags)2712 check_applicability(char *a_packageDir, char *a_pkgInst,
2713 char *a_rootPath, CAF_T a_flags)
2714 {
2715 FILE *pkginfoFP;
2716 boolean_t all_zones; /* pkg is "all zones" only */
2717 char pkginfoPath[PATH_MAX];
2718 char pkgpath[PATH_MAX];
2719 int len;
2720
2721 /* entry assertions */
2722
2723 assert(a_packageDir != (char *)NULL);
2724 assert(*a_packageDir != '\0');
2725 assert(a_pkgInst != (char *)NULL);
2726 assert(*a_pkgInst != '\0');
2727
2728 /* normalize root path */
2729
2730 if (a_rootPath == (char *)NULL) {
2731 a_rootPath = "";
2732 }
2733
2734 /*
2735 * determine if this package is currently installed
2736 * if not installed return success - operation will fail
2737 * when the removal is attempted
2738 */
2739
2740 if (pkginfoIsPkgInstalled((struct pkginfo **)NULL, a_pkgInst) !=
2741 B_TRUE) {
2742 return (B_TRUE);
2743 }
2744
2745 /*
2746 * calculate paths to various objects
2747 */
2748
2749 len = snprintf(pkgpath, sizeof (pkgpath), "%s/%s", a_packageDir,
2750 a_pkgInst);
2751 if (len > sizeof (pkgpath)) {
2752 progerr(ERR_CREATE_PATH_2, a_packageDir, a_pkgInst);
2753 return (B_FALSE);
2754 }
2755
2756 /* if not installed then just return */
2757
2758 if (isdir(pkgpath) != 0) {
2759 progerr(ERR_NO_PKGDIR, pkgpath, a_pkgInst, strerror(errno));
2760 return (B_TRUE);
2761 }
2762
2763 len = snprintf(pkginfoPath, sizeof (pkginfoPath),
2764 "%s/pkginfo", pkgpath);
2765 if (len > sizeof (pkgpath)) {
2766 progerr(ERR_CREATE_PATH_2, pkgpath, "pkginfo");
2767 return (B_FALSE);
2768 }
2769
2770 /*
2771 * gather information from this packages pkginfo file
2772 */
2773
2774 pkginfoFP = fopen(pkginfoPath, "r");
2775
2776 if (pkginfoFP == (FILE *)NULL) {
2777 progerr(ERR_NO_PKG_INFOFILE, a_pkgInst, pkginfoPath,
2778 strerror(errno));
2779 return (B_FALSE);
2780 }
2781
2782 /* determine "ALLZONES" setting for this package */
2783
2784 all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
2785 "true", B_FALSE);
2786
2787 /* close pkginfo file */
2788
2789 (void) fclose(pkginfoFP);
2790
2791 /* gather information from the global zone only file */
2792
2793 /*
2794 * verify package applicability based on information gathered;
2795 * the package IS currently installed....
2796 */
2797
2798 /* pkg ALLZONES=true & not running in global zone */
2799
2800 if ((all_zones == B_TRUE) && (!(a_flags & CAF_IN_GLOBAL_ZONE))) {
2801 progerr(ERR_ALLZONES_AND_IN_LZ_PKGRM, a_pkgInst);
2802 return (B_FALSE);
2803 }
2804
2805 return (B_TRUE);
2806 }
2807
2808 /*
2809 * Name: shall_we_continue
2810 * Description: Called from within a loop that is installing packages,
2811 * this function examines various global variables and decides
2812 * whether or not to ask an appropriate question, and wait for
2813 * and appropriate reply.
2814 * Arguments: <<global variables>>
2815 * Returns: B_TRUE - continue processing with next package
2816 * B_FALSE - do not continue processing with next package
2817 */
2818
2819 static boolean_t
shall_we_continue(char * a_pkgInst,int a_npkgs)2820 shall_we_continue(char *a_pkgInst, int a_npkgs)
2821 {
2822 char ans[MAX_INPUT];
2823 int n;
2824
2825 /* return FALSE if immediate reboot required */
2826
2827 if (ireboot) {
2828 ptext(stderr, MSG_SUSPEND_RM, a_pkgInst);
2829 return (B_FALSE);
2830 }
2831
2832 /* return TRUE if not interrupted */
2833
2834 if (!interrupted) {
2835 return (B_TRUE);
2836 }
2837
2838 /* output appropriate interrupt message */
2839
2840 echo(a_npkgs == 1 ? MSG_1MORETODO : MSG_MORETODO, a_npkgs);
2841
2842 /* if running with no interaction (-n) do not ask question */
2843
2844 if (nointeract) {
2845 quit(0);
2846 /* NOTREACHED */
2847 }
2848
2849 /* interaction possible: ask question */
2850
2851 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONTINUE_RM);
2852 if (n != 0) {
2853 quit(n);
2854 /* NOTREACHED */
2855 }
2856
2857 if (strchr("yY", *ans) == NULL) {
2858 quit(0);
2859 /* NOTREACHED */
2860 }
2861 return (B_TRUE);
2862 }
2863
2864 /*
2865 * Name: create_zone_adminfile
2866 * Description: Given a zone temporary directory and optionally an existing
2867 * administration file, generate an administration file that
2868 * can be used to perform "non-interactive" operations in a
2869 * non-global zone.
2870 * Arguments: r_zoneAdminFile - pointer to handle that will contain a
2871 * string representing the path to the temporary
2872 * administration file created - this must be NULL
2873 * before the first call to this function - on
2874 * subsequent calls if the pointer is NOT null then
2875 * the existing string will NOT be overwritten.
2876 * a_zoneTempDir - pointer to string representing the path
2877 * to the zone temporary directory to create the
2878 * temporary administration file in
2879 * a_admnfile - pointer to string representing the path to
2880 * an existing "user" administration file - the
2881 * administration file created will contain the
2882 * settings contained in this file, modified as
2883 * appropriate to supress any interaction;
2884 * If this is == NULL then the administration file
2885 * created will not contain any extra settings
2886 * Returns: void
2887 * NOTE: Any string returned is placed in new storage for the
2888 * calling method. The caller must use 'free' to dispose
2889 * of the storage once the string is no longer needed.
2890 * NOTE: On any error this function will call 'quit(1)'
2891 */
2892
2893 static void
create_zone_adminfile(char ** r_zoneAdminFile,char * a_zoneTempDir,char * a_admnfile)2894 create_zone_adminfile(char **r_zoneAdminFile, char *a_zoneTempDir,
2895 char *a_admnfile)
2896 {
2897 boolean_t b;
2898
2899 /* entry assertions */
2900
2901 assert(r_zoneAdminFile != (char **)NULL);
2902 assert(a_zoneTempDir != (char *)NULL);
2903 assert(*a_zoneTempDir != '\0');
2904
2905 /* entry debugging info */
2906
2907 echoDebug(DBG_CREATE_ZONE_ADMINFILE, a_zoneTempDir, PSTR(a_admnfile));
2908
2909 /* if temporary name already exists, do not overwrite */
2910
2911 if (*r_zoneAdminFile != (char *)NULL) {
2912 return;
2913 }
2914
2915 /* create temporary name */
2916
2917 *r_zoneAdminFile = tempnam(a_zoneTempDir, "zadmn");
2918 b = z_create_zone_admin_file(*r_zoneAdminFile, a_admnfile);
2919 if (b == B_FALSE) {
2920 progerr(ERR_CREATE_TMPADMIN, *r_zoneAdminFile,
2921 strerror(errno));
2922 quit(1);
2923 /* NOTREACHED */
2924 }
2925
2926 echoDebug(DBG_CREATED_ZONE_ADMINFILE, *r_zoneAdminFile);
2927 }
2928
2929 /*
2930 * Name: create_zone_tempdir
2931 * Description: Given a system temporary directory, create a "zone" specific
2932 * temporary directory and return the path to the directory
2933 * created.
2934 * Arguments: r_zoneTempDir - pointer to handle that will contain a
2935 * string representing the path to the temporary
2936 * directory created - this must be NULL before the
2937 * first call to this function - on subsequent calls
2938 * if the pointer is NOT null then the existing string
2939 * will NOT be overwritten.
2940 * a_zoneTempDir - pointer to string representing the path
2941 * to the system temporary directory to create the
2942 * temporary zone directory in
2943 * Returns: void
2944 * NOTE: Any string returned is placed in new storage for the
2945 * calling method. The caller must use 'free' to dispose
2946 * of the storage once the string is no longer needed.
2947 * NOTE: On any error this function will call 'quit(1)'
2948 * NOTE: This function calls "quitSetZoneTmpdir" on success to
2949 * register the directory created with quit() so that the
2950 * directory will be automatically deleted on exit.
2951 */
2952
2953 static void
create_zone_tempdir(char ** r_zoneTempDir,char * a_tmpdir)2954 create_zone_tempdir(char **r_zoneTempDir, char *a_tmpdir)
2955 {
2956 boolean_t b;
2957
2958 /* entry assertions */
2959
2960 assert(r_zoneTempDir != (char **)NULL);
2961 assert(a_tmpdir != (char *)NULL);
2962 assert(*a_tmpdir != '\0');
2963
2964 /* entry debugging info */
2965
2966 echoDebug(DBG_CREATE_ZONE_TEMPDIR, a_tmpdir);
2967
2968 /* if temporary directory already exists, do not overwrite */
2969
2970 if (*r_zoneTempDir != (char *)NULL) {
2971 return;
2972 }
2973
2974 /* create temporary directory */
2975
2976 b = setup_temporary_directory(r_zoneTempDir, a_tmpdir, "ztemp");
2977 if (b == B_FALSE) {
2978 progerr(ERR_ZONETEMPDIR, a_tmpdir, strerror(errno));
2979 quit(1);
2980 /* NOTREACHED */
2981 }
2982
2983 /* register with quit() to directory is removed on exit */
2984
2985 quitSetZoneTmpdir(*r_zoneTempDir);
2986
2987 /* exit debugging info */
2988
2989 echoDebug(DBG_CREATED_ZONE_TEMPDIR, *r_zoneTempDir);
2990 }
2991