1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2017 Peter Tribble.
24 */
25
26 /*
27 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
28 */
29
30 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
32
33
34 /*
35 * System includes
36 */
37
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>
52
53 /*
54 * libinstzones includes
55 */
56
57 #include <instzones_api.h>
58
59 /*
60 * consolidation pkg command library includes
61 */
62
63 #include <pkglib.h>
64
65 /*
66 * local pkg command library includes
67 */
68
69 #include "install.h"
70 #include "libinst.h"
71 #include "libadm.h"
72 #include "messages.h"
73
74 /*
75 * pkgrm local includes
76 */
77
78 #include "quit.h"
79
80 /*
81 * exported global variables
82 */
83
84 /* these globals are set by ckreturn and used by quit.c */
85
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) */
93
94 /* imported by quit.c */
95 int npkgs = 0; /* the number of packages yet to be installed */
96
97 /* imported by presvr4.c */
98 int started = 0;
99 char *tmpdir = NULL; /* location to place temporary files */
100
101 /* imported by various (many) */
102 struct admin adm; /* holds info about installation admin */
103 struct pkgdev pkgdev; /* holds info about the installation device */
104
105 /*
106 * internal global variables
107 */
108
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;
113
114 /* set by ckreturn() */
115
116 static int interrupted = 0; /* last pkg op was quit (1,2,3,4,5) */
117
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 */
121
122 /*
123 * Assume the package complies with the standards as regards user
124 * interaction during procedure scripts.
125 */
126
127 static int old_pkg = 0;
128 static int old_symlinks = 0;
129 static int no_map_client = 0;
130
131 /* Set by -O nozones: do not process any zones */
132
133 static boolean_t noZones = B_FALSE;
134
135 /* Set by -O zonelist=<names...>: process only named zones */
136
137 static boolean_t usedZoneList = B_FALSE;
138
139 /* Set by -O debug: debug output is enabled? */
140
141 static boolean_t debugFlag = B_FALSE;
142
143 /*
144 * imported (external) functions
145 */
146
147 /* check.c */
148
149 extern int preremove_verify(char **a_pkgList, zoneList_t a_zlst,
150 char *a_zoneTempDir);
151 /* quit.c */
152
153 extern void quitSetZonelist(zoneList_t a_zlst);
154
155 /*
156 * imported (external) variables
157 */
158
159 extern char *pkgdir;
160
161 /* printable string - if string is null results in ??? */
162
163 #define PSTR(STR) (((STR) == (char *)NULL) ? "???" : (STR))
164
165 #define MAX_FDS 20
166
167 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
168 #define TEXT_DOMAIN "SYS_TEST"
169 #endif
170
171 /*
172 * forward declarations
173 */
174
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);
215
216 /*
217 * *****************************************************************************
218 * global external (public) functions
219 * *****************************************************************************
220 */
221
222 /*
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.
234 */
235
236 int
main(int argc,char ** argv)237 main(int argc, char **argv)
238 {
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;
253
254 /* initialize locale environment */
255
256 (void) setlocale(LC_ALL, "");
257 (void) textdomain(TEXT_DOMAIN);
258
259 /* initialize program name */
260
261 prog_full_name = argv[0];
262 (void) set_prog_name(argv[0]);
263
264 /* tell spmi zones interface how to access package output functions */
265
266 z_set_output_functions(echo, echoDebug, progerr);
267
268 /* tell quit which ckreturn function to call */
269
270 quitSetCkreturnFunc(&ckreturn);
271
272 /* Read PKG_INSTALL_ROOT from the environment, if it's there. */
273
274 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
275 progerr(ERR_ROOT_SET);
276 exit(1);
277 }
278
279 if (z_running_in_global_zone() && !enable_local_fs()) {
280 progerr(ERR_CANNOT_ENABLE_LOCAL_FS);
281 }
282
283 pkgserversetmode(DEFAULTMODE);
284
285 /*
286 * ********************************************************************
287 * parse command line options
288 * ********************************************************************
289 */
290
291 while ((c = getopt(argc, argv, "?Aa:b:FMnO:R:s:V:vY:Z")) != EOF) {
292 switch (c) {
293 /*
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.
300 */
301 case 'A':
302 pkgrmremote++;
303 break;
304
305 /*
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.
314 */
315 case 'a':
316 admnfile = flex_device(optarg, 0);
317 break;
318
319 /*
320 * Not a public interface: location where package executables
321 * can be found - default is /usr/sadm/install/bin.
322 */
323 case 'b':
324 if (!path_valid(optarg)) {
325 progerr(ERR_PATH, optarg);
326 quit(1);
327 }
328 if (isdir(optarg) != 0) {
329 p = strerror(errno);
330 progerr(ERR_CANNOT_USE_DIR, optarg, p);
331 quit(1);
332 }
333 altBinDir = optarg;
334 break;
335
336 /*
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.
344 */
345 case 'F':
346 nodelete++;
347 break;
348
349 /*
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.
356 */
357 case 'M':
358 no_map_client = 1;
359 break;
360
361 /*
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.
365 */
366 case 'n':
367 nointeract++;
368 (void) echoSetFlag(B_FALSE);
369 break;
370
371 /*
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
389 */
390
391 case 'O':
392 for (p = strtok(optarg, ","); p != (char *)NULL;
393 p = strtok(NULL, ",")) {
394
395 if (strcmp(p, "nozones") == 0) {
396 noZones = B_TRUE;
397 continue;
398 }
399
400 if (strcmp(p,
401 "enable-hollow-package-support") == 0) {
402 set_depend_pkginfo_DB(B_TRUE);
403 continue;
404 }
405
406 if (strcmp(p, "debug") == 0) {
407 /* set debug flag/enable debug output */
408 debugFlag = B_TRUE;
409 (void) echoDebugSetFlag(debugFlag);
410
411 /* debug info on arguments to pkgadd */
412 for (n = 0; n < argc && argv[n]; n++) {
413 echoDebug(DBG_ARG, n, argv[n]);
414 }
415
416 continue;
417 }
418
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;
424 }
425
426 /* -O option not recognized - issue warning */
427
428 progerr(ERR_INVALID_O_OPTION, p);
429 continue;
430 }
431 break;
432
433 /*
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.
439 */
440 case 'R':
441 if (!set_inst_root(optarg)) {
442 progerr(ERR_ROOT_CMD);
443 exit(1);
444 }
445 break;
446
447 /*
448 * Public interface: remove the specified package(s)
449 * from the directory spool. The default directory
450 * for spooled packages is /var/sadm/pkg.
451 */
452 case 's':
453 spoolDir = flex_device(optarg, 1);
454 break;
455
456 /*
457 * Public interface: Allow admin to establish the client
458 * filesystem using a vfstab-like file of stable format.
459 */
460 case 'V':
461 vfstab_file = flex_device(optarg, 2);
462 no_map_client = 0;
463 break;
464
465 /*
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.
471 */
472 case 'v':
473 pkgverbose++;
474 break;
475
476 /*
477 * Public interface: remove packages based on the
478 * CATEGORY variable from the installed/spooled
479 * pkginfo file
480 */
481 case 'Y':
482 catg_arg = strdup(optarg);
483
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);
494 }
495
496 break;
497
498 /*
499 * unrecognized option
500 */
501 default:
502 usage();
503 /* NOTREACHED */
504 }
505 }
506
507 /*
508 * ********************************************************************
509 * validate command line options
510 * ********************************************************************
511 */
512
513 /* set "debug echo" flag according to setting of "-O debug" option */
514
515 (void) echoDebugSetFlag(debugFlag);
516
517 /* output entry debugging information */
518
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());
524 }
525
526 /* -s cannot be used with several */
527
528 if (spoolDir != (char *)NULL) {
529 if (admnfile != (char *)NULL) {
530 progerr(ERR_SPOOLDIR_AND_ADMNFILE);
531 usage();
532 /* NOTREACHED */
533 }
534
535 if (pkgrmremote != 0) {
536 progerr(ERR_SPOOLDIR_AND_PKGRMREMOTE);
537 usage();
538 /* NOTREACHED */
539 }
540
541 if (pkgverbose != 0) {
542 progerr(ERR_SPOOLDIR_AND_PKGVERBOSE);
543 usage();
544 /* NOTREACHED */
545 }
546
547 if (is_an_inst_root() != 0) {
548 progerr(ERR_SPOOLDIR_AND_INST_ROOT);
549 usage();
550 /* NOTREACHED */
551 }
552 }
553
554 /* -V cannot be used with -A */
555
556 if (no_map_client && pkgrmremote) {
557 progerr(ERR_V_USED_AND_PKGRMREMOTE);
558 usage();
559 /* NOTREACHED */
560 }
561
562 /* -n used without pkg names or category */
563
564 if (nointeract && (optind == argc) && (catg_arg == NULL)) {
565 progerr(ERR_BAD_N_PKGRM);
566 usage();
567 /* NOTREACHED */
568 }
569
570 /* Error if specified zone list isn't valid on target */
571 if (usedZoneList && z_verify_zone_spec() == -1)
572 usage();
573
574 /*
575 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler
576 */
577
578 /* hold SIGINT/SIGHUP interrupts */
579
580 (void) sighold(SIGHUP);
581 (void) sighold(SIGINT);
582
583 /* connect quit.c:trap() to SIGINT */
584
585 nact.sa_handler = quitGetTrapHandler();
586 nact.sa_flags = SA_RESTART;
587 (void) sigemptyset(&nact.sa_mask);
588
589 (void) sigaction(SIGINT, &nact, &oact);
590
591 /* connect quit.c:trap() to SIGHUP */
592
593 nact.sa_handler = quitGetTrapHandler();
594 nact.sa_flags = SA_RESTART;
595 (void) sigemptyset(&nact.sa_mask);
596
597 (void) sigaction(SIGHUP, &nact, &oact);
598
599 /* release hold on signals */
600
601 (void) sigrelse(SIGHUP);
602 (void) sigrelse(SIGINT);
603
604 /* establish temporary directory to use */
605
606 tmpdir = getenv("TMPDIR");
607 if (tmpdir == NULL) {
608 tmpdir = P_tmpdir;
609 }
610
611 echoDebug(DBG_PKGRM_TMPDIR, tmpdir);
612
613 /* initialize path parameters */
614
615 set_PKGpaths(get_inst_root());
616
617 /*
618 * initialize installation admin parameters - if removing from a spool
619 * directory then the admin file is ignore.
620 */
621
622 if (spoolDir == NULL) {
623 echoDebug(DBG_PKGRM_ADMINFILE, admnfile ? admnfile : "");
624 setadminFile(admnfile);
625 }
626
627 /*
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.
632 */
633
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);
640 }
641
642 /*
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
647 */
648 if (getenv("NONABI_SCRIPTS") != NULL) {
649 old_pkg = 1;
650 }
651
652 /*
653 * See if the user wants to process symlinks consistent with
654 * the old behavior.
655 */
656
657 if (getenv("PKG_NONABI_SYMLINKS") != NULL) {
658 old_symlinks = 1;
659 }
660
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 */
666 }
667
668 pkgdir = pkgdev.dirname;
669 repeat = ((optind >= argc) && pkgdev.mount);
670
671 /*
672 * error if there are packages on the command line and a category
673 * was specified
674 */
675
676 if (optind < argc && catg_arg != NULL) {
677 progerr(ERR_PKGS_AND_CAT_PKGRM);
678 usage();
679 /* NOTREACHED */
680 }
681
682 /*
683 * ********************************************************************
684 * main package processing "loop"
685 * ********************************************************************
686 */
687
688 for (;;) {
689 boolean_t b;
690 char **pkglist; /* points to array of pkgs */
691
692 /*
693 * mount the spool device if required
694 */
695
696 if (pkgdev.mount) {
697 if (n = pkgmount(&pkgdev, NULL, 0, 0, 1)) {
698 quit(n);
699 /* NOTREACHED */
700 }
701 }
702
703 if (chdir(pkgdev.dirname)) {
704 progerr(ERR_CHDIR, pkgdev.dirname);
705 quit(1);
706 /* NOTREACHED */
707 }
708
709 /*
710 * spool device mounted/available - get the list of the
711 * packages to remove
712 */
713
714 n = pkgGetPackageList(&pkglist, argv, optind,
715 catg_arg, category, &pkgdev);
716
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 */
724
725 case 0: /* packages found */
726 break;
727
728 default: /* "quit" error */
729 echoDebug(DBG_PKGLIST_RM_ERROR,
730 pkgdev.dirname, n);
731 quit(n);
732 /* NOTREACHED */
733 }
734
735 /*
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...
740 */
741
742 for (npkgs = 0; pkglist[npkgs] != (char *)NULL; /* void */) {
743 pkgLgth = strlen(pkglist[npkgs]);
744 if (pkgLgth > longestPkg) {
745 longestPkg = pkgLgth;
746 }
747 echoDebug(DBG_PKG_SELECTED, npkgs, pkglist[npkgs]);
748 npkgs++;
749 }
750
751 /* output number of packages to be removed */
752
753 echoDebug(DBG_NUM_PKGS_TO_REMOVE, npkgs, longestPkg);
754
755 /*
756 * package list generated - remove packages
757 */
758
759 b = remove_packages(pkglist, nodelete, longestPkg, repeat,
760 altBinDir, pkgdev.dirname, spoolDir, noZones);
761
762 /*
763 * unmount the spool directory if necessary
764 */
765
766 if (pkgdev.mount) {
767 (void) chdir("/");
768 if (pkgumount(&pkgdev)) {
769 progerr(ERR_PKGUNMOUNT, pkgdev.bdevice);
770 quit(99);
771 /* NOTREACHED */
772
773 }
774 }
775
776 /*
777 * continue with next sequence of packages if continue set
778 */
779
780 if (b == B_TRUE) {
781 continue;
782 }
783
784 /*
785 * not continuing - quit with 0 exit code
786 */
787
788 quit(0);
789 /* NOTREACHED */
790 #ifdef lint
791 return (0);
792 #endif /* lint */
793 }
794 }
795
796 /*
797 * *****************************************************************************
798 * static internal (private) functions
799 * *****************************************************************************
800 */
801
802 /*
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"
843 */
844
845 static int
doRemove(int a_nodelete,char * a_altBinDir,int a_longestPkg,char * a_adminFile,char * a_zoneAdminFile,zoneList_t a_zlst)846 doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile,
847 char *a_zoneAdminFile, zoneList_t a_zlst)
848 {
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;
857
858 /* entry assertions */
859
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);
867 }
868
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);
875 }
876
877 /* entry debugging info */
878
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);
883
884 if (!nointeract) {
885 char fmt1[100];
886
887 /* create format based on max pkg name length */
888
889 (void) snprintf(fmt1, sizeof (fmt1), " %%-%d.%ds %%s",
890 a_longestPkg, a_longestPkg);
891
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);
898 }
899 echo(INFO_INSTALL);
900 }
901
902 echo(fmt1, pinfo->pkginst, pinfo->name);
903
904 if (pinfo->arch || pinfo->version) {
905 char fmt2[100];
906
907 /* create format based on max pkg name length */
908
909 (void) snprintf(fmt2, sizeof (fmt2), " %%%d.%ds ",
910 a_longestPkg, a_longestPkg);
911
912 /* LINTED variable format specifier to fprintf() */
913 (void) fprintf(stderr, fmt2, "");
914
915 if (pinfo->arch) {
916 (void) fprintf(stderr, "(%s) ", pinfo->arch);
917 }
918
919 if (pinfo->version) {
920 (void) fprintf(stderr, "%s", pinfo->version);
921 }
922
923 (void) fprintf(stderr, "\n");
924 }
925
926 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONFIRM);
927 if (n != 0) {
928 quit(n);
929 /* NOTREACHED */
930 }
931
932 if (strchr("yY", *ans) == NULL) {
933 pkginfoFree(&pinfo);
934 return (0);
935 }
936 }
937
938 if (pinfo->status == PI_SPOOLED) {
939 /* removal from a directory */
940 echo(INFO_RMSPOOL, pkginst);
941 pkginfoFree(&pinfo);
942 return (rrmdir(pkginst));
943 }
944
945 /* exit if not root */
946
947 if (getuid()) {
948 progerr(ERR_NOT_ROOT, get_prog_name());
949 exit(1);
950 }
951
952 pkginfoFree(&pinfo);
953
954 zonesSkipped = 0;
955
956 if (interrupted != 0) {
957 echo(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
958 echoDebug(MSG_DOREMOVE_INTERRUPTED_B4_Z, pkginst);
959 return (n);
960 }
961
962 echoDebug(DBG_REMOVE_FLAG_VALUES, "before pkgZoneRemove",
963 admnflag, doreboot, failflag, interrupted,
964 intrflag, ireboot, nullflag, warnflag);
965
966 for (zoneIndex = 0;
967 a_zlst != NULL &&
968 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) != NULL;
969 zoneIndex++) {
970
971 /* skip the zone if it is NOT running */
972
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;
978 }
979
980 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
981 echoDebug(DBG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
982
983 /*
984 * remove package from zone; use the zone admin file which
985 * suppresses all checks.
986 */
987
988 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex),
989 a_nodelete, a_altBinDir, a_zoneAdminFile,
990 zst, B_FALSE);
991
992 /* set success/fail condition variables */
993
994 ckreturn(n);
995
996 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
997 admnflag, doreboot, failflag, interrupted, intrflag,
998 ireboot, nullflag, warnflag);
999 }
1000
1001 if (zonesSkipped > 0) {
1002 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
1003
1004 for (zoneIndex = 0;
1005 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1006 (char *)NULL; zoneIndex++) {
1007
1008 /* skip the zone if it IS running */
1009
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;
1016 }
1017
1018 /* skip the zone if it is NOT bootable */
1019
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;
1026 }
1027
1028 /* mount up the zone */
1029
1030 echo(MSG_BOOTING_ZONE, zoneName);
1031 echoDebug(DBG_BOOTING_ZONE, zoneName);
1032
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;
1040 }
1041
1042 echo(MSG_REMOVE_PKG_FROM_ZONE, pkginst, zoneName);
1043
1044 /*
1045 * remove package from zone; use the zone admin file
1046 * which suppresses all checks.
1047 */
1048
1049 n = pkgZoneRemove(z_zlist_get_scratch(a_zlst,
1050 zoneIndex), a_nodelete, a_altBinDir,
1051 a_zoneAdminFile, ZONE_STATE_MOUNTED, B_TRUE);
1052
1053 /* set success/fail condition variables */
1054
1055 ckreturn(n);
1056
1057 echoDebug(DBG_REMOVE_FLAG_VALUES, "after pkgZoneRemove",
1058 admnflag, doreboot, failflag, interrupted,
1059 intrflag, ireboot, nullflag, warnflag);
1060
1061 /* restore original state of zone */
1062
1063 echo(MSG_RESTORE_ZONE_STATE, zoneName);
1064 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
1065
1066 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
1067 }
1068 }
1069
1070 /*
1071 * Process global zone if it was either the only possible
1072 * target (no list of zones specified) or it appears in the list
1073 */
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 */
1077
1078 /*
1079 * call pkgremove for this package for the global zone;
1080 * use the admin file passed in by the user via -a.
1081 */
1082 n = pkgRemove(a_nodelete, a_altBinDir, a_adminFile);
1083
1084 /* set success/fail condition variables */
1085 ckreturn(n);
1086 }
1087
1088 return (n);
1089 }
1090
1091 /*
1092 * function to clear out any exisiting error return conditions that may have
1093 * been set by previous calls to ckreturn()
1094 */
1095 static void
resetreturn()1096 resetreturn()
1097 {
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) */
1106 }
1107
1108 /*
1109 * function which checks the indicated return value
1110 * and indicates disposition of installation
1111 */
1112 static void
ckreturn(int retcode)1113 ckreturn(int retcode)
1114 {
1115 /*
1116 * entry debugging info
1117 */
1118
1119 echoDebug(DBG_PKGRM_CKRETURN, retcode, PSTR(pkginst));
1120
1121 switch (retcode) {
1122 case 0: /* successful */
1123 case 10:
1124 case 20:
1125 break; /* empty case */
1126
1127 case 1: /* package operation failed (fatal error) */
1128 case 11:
1129 case 21:
1130 failflag++;
1131 interrupted++;
1132 break;
1133
1134 case 2: /* non-fatal error (warning) */
1135 case 12:
1136 case 22:
1137 warnflag++;
1138 interrupted++;
1139 break;
1140
1141 case 3: /* user selected quit; operation interrupted */
1142 case 13:
1143 case 23:
1144 intrflag++;
1145 interrupted++;
1146 break;
1147
1148 case 4: /* admin settings prevented operation */
1149 case 14:
1150 case 24:
1151 admnflag++;
1152 interrupted++;
1153 break;
1154
1155 case 5: /* administration: interaction req (no -n) */
1156 case 15:
1157 case 25:
1158 nullflag++;
1159 interrupted++;
1160 break;
1161
1162 default:
1163 failflag++;
1164 interrupted++;
1165 return;
1166 }
1167
1168 if (retcode >= 20) {
1169 ireboot++;
1170 } else if (retcode >= 10) {
1171 doreboot++;
1172 }
1173 }
1174
1175 static int
pkgZoneCheckRemove(char * a_zoneName,char * a_altBinDir,char * a_adminFile,char * a_stdoutPath,zone_state_t a_zoneState,boolean_t tmpzone)1176 pkgZoneCheckRemove(char *a_zoneName, char *a_altBinDir, char *a_adminFile,
1177 char *a_stdoutPath, zone_state_t a_zoneState, boolean_t tmpzone)
1178 {
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;
1187
1188 /* entry assertions */
1189
1190 assert(a_zoneName != (char *)NULL);
1191 assert(*a_zoneName != '\0');
1192
1193 /* entry debugging info */
1194
1195 echoDebug(DBG_PKGZONECHECKREMOVE_ENTRY);
1196 echoDebug(DBG_PKGZONECHECKREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1197 PSTR(pkgdev.dirname), PSTR(a_adminFile), PSTR(a_stdoutPath));
1198
1199 /* generate path to pkgremove */
1200
1201 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1202 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1203
1204 /* start at first file descriptor */
1205
1206 maxfds = 0;
1207
1208 /*
1209 * generate argument list for call to pkgremove
1210 */
1211
1212 /* start at argument 0 */
1213
1214 nargs = 0;
1215
1216 /* first argument is path to executable */
1217
1218 arg[nargs++] = strdup(path);
1219
1220 /* second argument is always: pass -O debug to pkgremove: debug mode */
1221
1222 if (debugFlag == B_TRUE) {
1223 arg[nargs++] = "-O";
1224 arg[nargs++] = "debug";
1225 }
1226
1227 /* pkgrm -b dir: pass -b to pkgremove */
1228
1229 if (a_altBinDir != (char *)NULL) {
1230 arg[nargs++] = "-b";
1231 arg[nargs++] = a_altBinDir;
1232 }
1233
1234 /*
1235 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1236 * pkg requiring operator interaction during a procedure script
1237 * (common before on1093)
1238 */
1239
1240 if (old_pkg) {
1241 arg[nargs++] = "-o";
1242 }
1243
1244 /*
1245 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1246 * symlinks consistent with old behavior
1247 */
1248
1249 if (old_symlinks) {
1250 arg[nargs++] = "-y";
1251 }
1252
1253 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1254
1255 arg[nargs++] = "-M";
1256
1257 /* pkgrm -A: pass -A to pkgremove */
1258
1259 if (pkgrmremote) {
1260 arg[nargs++] = "-A";
1261 }
1262
1263 /* pkgrm -v: pass -v to pkgremove: never trace scripts */
1264
1265 /* pass "-O enable-hollow-package-support" */
1266
1267 if (is_depend_pkginfo_DB()) {
1268 arg[nargs++] = "-O";
1269 arg[nargs++] = "enable-hollow-package-support";
1270 }
1271
1272 /* pass -n to pkgremove: always in noninteractive mode */
1273
1274 arg[nargs++] = "-n";
1275
1276 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1277
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);
1285 }
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);
1291 }
1292
1293 /*
1294 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1295 */
1296 if (a_zoneState == ZONE_STATE_MOUNTED) {
1297 arg[nargs++] = "-R";
1298 arg[nargs++] = "/a";
1299 }
1300
1301 /* pkgrm -F: pass -F to pkgremove: always update DB only */
1302
1303 arg[nargs++] = "-F";
1304
1305 /* pass "-O preremovecheck" */
1306
1307 arg[nargs++] = "-O";
1308 arg[nargs++] = "preremovecheck";
1309
1310 /* add "-O addzonename" */
1311
1312 arg[nargs++] = "-O";
1313 arg[nargs++] = "addzonename";
1314
1315 /*
1316 * add parent zone info/type
1317 */
1318
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);
1326 }
1327
1328 /* current zone type */
1329
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);
1343 }
1344
1345 /* Add arguments how to start the pkgserv */
1346
1347 arg[nargs++] = "-O";
1348 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1349
1350 /* pass -N to pkgremove: program name to report */
1351
1352 arg[nargs++] = "-N";
1353 arg[nargs++] = get_prog_name();
1354
1355 /* add package instance name */
1356
1357 arg[nargs++] = pkginst;
1358
1359 /* terminate argument list */
1360
1361 arg[nargs++] = NULL;
1362
1363 /* execute pkgremove command */
1364
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]);
1369 }
1370 }
1371
1372 /* terminate file descriptor list */
1373
1374 fds[maxfds] = -1;
1375
1376 /* exec command in zone */
1377
1378 n = z_zone_exec(a_zoneName, path, arg, a_stdoutPath, (char *)NULL, fds);
1379
1380 echoDebug(DBG_ZONE_EXEC_EXIT, a_zoneName, arg[0], n,
1381 PSTR(a_stdoutPath));
1382
1383 /*
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
1387 */
1388
1389 for (; maxfds > 0; maxfds--) {
1390 (void) close(fds[maxfds-1]);
1391 }
1392
1393 /* return results of pkgremove in zone execution */
1394
1395 return (n);
1396 }
1397
1398 static int
pkgZoneRemove(char * a_zoneName,int a_nodelete,char * a_altBinDir,char * a_adminFile,zone_state_t a_zoneState,boolean_t tmpzone)1399 pkgZoneRemove(char *a_zoneName, int a_nodelete, char *a_altBinDir,
1400 char *a_adminFile, zone_state_t a_zoneState, boolean_t tmpzone)
1401 {
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;
1410
1411 /* entry assertions */
1412
1413 assert(a_zoneName != (char *)NULL);
1414 assert(*a_zoneName != '\0');
1415
1416 /* entry debugging info */
1417
1418 echoDebug(DBG_PKGZONEREMOVE_ENTRY);
1419 echoDebug(DBG_PKGZONEREMOVE_ARGS, a_zoneName, PSTR(pkginst),
1420 PSTR(pkgdev.dirname), a_nodelete, PSTR(a_adminFile));
1421
1422 /* generate path to pkgremove */
1423
1424 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1425 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1426
1427 /* start at first file descriptor */
1428
1429 maxfds = 0;
1430
1431 /*
1432 * generate argument list for call to pkgremove
1433 */
1434
1435 /* start at argument 0 */
1436
1437 nargs = 0;
1438
1439 /* first argument is path to executable */
1440
1441 arg[nargs++] = strdup(path);
1442
1443 /* second argument is always: pass -O debug to pkgremove: debug mode */
1444
1445 if (debugFlag == B_TRUE) {
1446 arg[nargs++] = "-O";
1447 arg[nargs++] = "debug";
1448 }
1449
1450 /* pkgrm -b dir: pass -b to pkgremove */
1451
1452 if (a_altBinDir != (char *)NULL) {
1453 arg[nargs++] = "-b";
1454 arg[nargs++] = a_altBinDir;
1455 }
1456
1457 /*
1458 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1459 * pkg requiring operator interaction during a procedure script
1460 * (common before on1093)
1461 */
1462
1463 if (old_pkg) {
1464 arg[nargs++] = "-o";
1465 }
1466
1467 /*
1468 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1469 * symlinks consistent with old behavior
1470 */
1471
1472 if (old_symlinks) {
1473 arg[nargs++] = "-y";
1474 }
1475
1476 /* pkgrm -M: pass -M to pkgremove: don't mount client file systems */
1477
1478 arg[nargs++] = "-M";
1479
1480 /* pkgrm -A: pass -A to pkgremove */
1481
1482 if (pkgrmremote) {
1483 arg[nargs++] = "-A";
1484 }
1485
1486 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1487
1488 if (pkgverbose) {
1489 arg[nargs++] = "-v";
1490 }
1491
1492 /* pass "-O enable-hollow-package-support" */
1493
1494 if (is_depend_pkginfo_DB()) {
1495 arg[nargs++] = "-O";
1496 arg[nargs++] = "enable-hollow-package-support";
1497 }
1498
1499 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1500
1501 if (nointeract) {
1502 arg[nargs++] = "-n";
1503 }
1504
1505 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1506
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);
1514 }
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;
1520 }
1521
1522 /*
1523 * pkgadd -R root: pass -R /a to pkgremove in mounted zone
1524 */
1525 if (a_zoneState == ZONE_STATE_MOUNTED) {
1526 arg[nargs++] = "-R";
1527 arg[nargs++] = "/a";
1528 }
1529
1530 /* pkgrm -F: pass -F to pkgremove: update DB only */
1531
1532 if (a_nodelete) {
1533 arg[nargs++] = "-F";
1534 }
1535
1536 /* add "-O addzonename" */
1537
1538 arg[nargs++] = "-O";
1539 arg[nargs++] = "addzonename";
1540
1541 /*
1542 * add parent zone info/type
1543 */
1544
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);
1552 }
1553
1554 /* current zone type */
1555
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);
1569 }
1570
1571 /* Add arguments how to start the pkgserv */
1572
1573 arg[nargs++] = "-O";
1574 arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
1575
1576 /* pass -N to pkgremove: program name to report */
1577
1578 arg[nargs++] = "-N";
1579 arg[nargs++] = get_prog_name();
1580
1581 /* add package instance name */
1582
1583 arg[nargs++] = pkginst;
1584
1585 /* terminate argument list */
1586
1587 arg[nargs++] = NULL;
1588
1589 /* execute pkgremove command */
1590
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]);
1595 }
1596 }
1597
1598 /* terminate file descriptor list */
1599
1600 fds[maxfds] = -1;
1601
1602 /* exec command in zone */
1603
1604 n = z_zone_exec(a_zoneName, path, arg, (char *)NULL, (char *)NULL, fds);
1605
1606 /*
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
1610 */
1611
1612 for (; maxfds > 0; maxfds--) {
1613 (void) close(fds[maxfds-1]);
1614 }
1615
1616 return (n);
1617 }
1618
1619 /*
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"
1647 */
1648
1649 static int
pkgRemove(int a_nodelete,char * a_altBinDir,char * a_adminFile)1650 pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile)
1651 {
1652 char *arg[MAXARGS];
1653 char *p;
1654 char path[PATH_MAX];
1655 int n;
1656 int nargs;
1657
1658 /* entry debugging info */
1659
1660 echoDebug(DBG_PKGREMOVE_ENTRY);
1661 echoDebug(DBG_PKGREMOVE_ARGS, PSTR(pkginst), PSTR(pkgdev.dirname),
1662 a_nodelete, PSTR(a_adminFile));
1663
1664 (void) snprintf(path, sizeof (path), "%s/pkgremove",
1665 a_altBinDir == (char *)NULL ? PKGBIN : a_altBinDir);
1666
1667 nargs = 0;
1668
1669 /* first argument is path to executable */
1670
1671 arg[nargs++] = strdup(path);
1672
1673 /* second argument is always: pass -O debug to pkgremove: debug mode */
1674
1675 if (debugFlag == B_TRUE) {
1676 arg[nargs++] = "-O";
1677 arg[nargs++] = "debug";
1678 }
1679
1680 /* Add arguments how to start the pkgserv */
1681
1682 arg[nargs++] = "-O";
1683 arg[nargs++] = pkgmodeargument(pkgservergetmode());
1684
1685 /* pkgrm -b dir: pass -b to pkgremove */
1686
1687 if (a_altBinDir != (char *)NULL) {
1688 arg[nargs++] = "-b";
1689 arg[nargs++] = a_altBinDir;
1690 }
1691
1692 /*
1693 * NONABI_SCRIPTS defined: pass -o to pkgremove; refers to a
1694 * pkg requiring operator interaction during a procedure script
1695 * (common before on1093)
1696 */
1697
1698 if (old_pkg) {
1699 arg[nargs++] = "-o";
1700 }
1701
1702 /*
1703 * PKG_NONABI_SYMLINKS defined: pass -y to pkgremove; process
1704 * symlinks consistent with old behavior
1705 */
1706
1707 if (old_symlinks) {
1708 arg[nargs++] = "-y";
1709 }
1710
1711 /* pkgrm -M: pass -M to pkgrm: dont mount client file systems */
1712
1713 if (no_map_client) {
1714 arg[nargs++] = "-M";
1715 }
1716
1717 /* pkgrm -A: pass -A to pkgrm */
1718
1719 if (pkgrmremote) {
1720 arg[nargs++] = "-A";
1721 }
1722
1723 /* pkgrm -v: pass -v to pkgremove: trace scripts */
1724
1725 if (pkgverbose) {
1726 arg[nargs++] = "-v";
1727 }
1728
1729 /* pkgrm -n: pass -n to pkgremove: noninteractive mode */
1730
1731 if (nointeract) {
1732 arg[nargs++] = "-n";
1733 }
1734
1735 /* pkgrm -a admin: pass -a admin to pkgremove: admin file */
1736
1737 if (a_adminFile) {
1738 arg[nargs++] = "-a";
1739 arg[nargs++] = strdup(a_adminFile);
1740 }
1741
1742 /* pkgrm -V vfstab: pass -V vfstab to pkgremove: alternate vfstab */
1743
1744 if (vfstab_file) {
1745 arg[nargs++] = "-V";
1746 arg[nargs++] = vfstab_file;
1747 }
1748
1749 /* pkgrm -R root: pass -R root to pkgremove: alternative root */
1750
1751 if (is_an_inst_root()) {
1752 arg[nargs++] = "-R";
1753 arg[nargs++] = get_inst_root();
1754 }
1755
1756 /* pkgrm -F: pass -F to pkgremove: update DB only */
1757
1758 if (a_nodelete) {
1759 arg[nargs++] = "-F";
1760 }
1761
1762 /*
1763 * add parent zone info/type
1764 */
1765
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);
1773 }
1774
1775 /* current zone type */
1776
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);
1790 }
1791
1792 /* pass -N to pkgremove: program name to report */
1793
1794 arg[nargs++] = "-N";
1795 arg[nargs++] = get_prog_name();
1796
1797 /* add package instance name */
1798
1799 arg[nargs++] = pkginst;
1800
1801 /* terminate argument list */
1802
1803 arg[nargs++] = NULL;
1804
1805 /*
1806 * run the appropriate pkgremove command in the specified zone
1807 */
1808
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]);
1813 }
1814 }
1815
1816 /* execute pkgremove command */
1817
1818 n = pkgexecv(NULL, NULL, NULL, NULL, arg);
1819
1820 /* return results of pkgrm in this zone */
1821
1822 return (n);
1823 }
1824
1825 static void
usage(void)1826 usage(void)
1827 {
1828 char *prog = get_prog_name();
1829
1830 (void) fprintf(stderr, ERR_USAGE_PKGRM, prog, prog);
1831 exit(1);
1832 }
1833
1834 /*
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"
1870 */
1871
1872 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)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)
1876 {
1877 static char *zoneAdminFile = (char *)NULL;
1878
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;
1889
1890 /* entry assertions */
1891
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');
1897
1898 /* entry debugging info */
1899
1900 echoDebug(DBG_PKGREMPKGSGZWNGZ_ENTRY);
1901 echoDebug(DBG_PKGREMPKGSGZWNGZ_ARGS, a_nodelete, a_longestPkg,
1902 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
1903
1904 /* check all packages */
1905
1906 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
1907 quit(1);
1908 }
1909
1910 /* create temporary directory for use by zone operations */
1911
1912 create_zone_tempdir(&zoneTempDir, tmpdir);
1913
1914 /* create hands off settings admin file for use in a non-global zone */
1915
1916 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
1917
1918 /*
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.
1922 */
1923
1924 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
1925 /* reset interrupted flag before calling pkgremove */
1926
1927 interrupted = 0; /* last action was NOT quit */
1928
1929 /* skip package if it is "in the global zone only" */
1930
1931 if (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE) {
1932 continue;
1933 }
1934
1935 /*
1936 * if operation failed in global zone do not propagate to
1937 * non-global zones
1938 */
1939
1940 zonesSkipped = 0;
1941
1942 if (interrupted != 0) {
1943 echo(MSG_DOREMOVE_INTERRUPTED, pkginst);
1944 echoDebug(DBG_DOREMOVE_INTERRUPTED, pkginst);
1945 break;
1946 }
1947
1948 echoDebug(DBG_REMOVE_FLAG_VALUES, "before loop",
1949 admnflag, doreboot, failflag, interrupted,
1950 intrflag, ireboot, nullflag, warnflag);
1951
1952 for (zoneIndex = 0;
1953 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
1954 (char *)NULL; zoneIndex++) {
1955
1956 /* skip the zone if it is NOT running */
1957
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;
1964 }
1965
1966 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
1967 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
1968 zoneName);
1969
1970 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
1971
1972 (void) snprintf(preremovecheckPath,
1973 sizeof (preremovecheckPath),
1974 "%s/%s.%s.preremovecheck.txt",
1975 zoneTempDir, pkginst, scratchName);
1976
1977 /*
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.
1981 */
1982
1983 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
1984 admnfile, preremovecheckPath,
1985 zst, B_FALSE);
1986
1987 /* set success/fail condition variables */
1988
1989 ckreturn(n);
1990
1991 echoDebug(DBG_REMOVE_FLAG_VALUES,
1992 "after pkgzonecheckremove",
1993 admnflag, doreboot, failflag, interrupted,
1994 intrflag, ireboot, nullflag, warnflag);
1995 }
1996
1997 if (zonesSkipped == 0) {
1998 continue;
1999 }
2000
2001 echoDebug(DBG_ZONES_SKIPPED, zonesSkipped);
2002
2003 for (zoneIndex = 0;
2004 (zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
2005 (char *)NULL; zoneIndex++) {
2006
2007 /* skip the zone if it IS running */
2008
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;
2015 }
2016
2017 /* skip the zone if it is NOT bootable */
2018
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;
2025 }
2026
2027 /* mount up the zone */
2028
2029 echo(MSG_BOOTING_ZONE, zoneName);
2030 echoDebug(DBG_BOOTING_ZONE, zoneName);
2031
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;
2039 }
2040
2041 echo(MSG_CHECKREMOVE_PKG_IN_ZONE, pkginst, zoneName);
2042 echoDebug(DBG_CHECKREMOVE_PKG_IN_ZONE, pkginst,
2043 zoneName);
2044
2045 scratchName = z_zlist_get_scratch(a_zlst, zoneIndex);
2046
2047 (void) snprintf(preremovecheckPath,
2048 sizeof (preremovecheckPath),
2049 "%s/%s.%s.preremovecheck.txt",
2050 zoneTempDir, pkginst, scratchName);
2051
2052 /*
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.
2056 */
2057
2058 n = pkgZoneCheckRemove(scratchName, a_altBinDir,
2059 admnfile, preremovecheckPath,
2060 ZONE_STATE_MOUNTED, B_TRUE);
2061
2062 /* set success/fail condition variables */
2063
2064 ckreturn(n);
2065
2066 echoDebug(DBG_REMOVE_FLAG_VALUES,
2067 "after pkgzonecheckremove",
2068 admnflag, doreboot, failflag, interrupted,
2069 intrflag, ireboot, nullflag, warnflag);
2070
2071 /* restore original state of zone */
2072
2073 echo(MSG_RESTORE_ZONE_STATE, zoneName);
2074 echoDebug(DBG_RESTORE_ZONE_STATE, zoneName);
2075
2076 b = z_zlist_restore_zone_state(a_zlst, zoneIndex);
2077 }
2078 npkgs--;
2079 }
2080
2081 /*
2082 * look at all pre-remove check files
2083 */
2084
2085 i = preremove_verify(a_pkgList, a_zlst, zoneTempDir);
2086 if (i != 0) {
2087 quit(i);
2088 }
2089
2090 npkgs = savenpkgs;
2091
2092 /*
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
2097 */
2098
2099 resetreturn();
2100
2101 /*
2102 * all of the packages (as listed in the package list) are
2103 * removed one at a time.
2104 */
2105
2106 interrupted = 0;
2107 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2108 boolean_t in_gz_only;
2109 started = 0;
2110
2111 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2112 continue;
2113 }
2114
2115 in_gz_only = pkgIsPkgInGzOnly(get_inst_root(), pkginst);
2116
2117 /* reset interrupted flag before calling pkgremove */
2118
2119 interrupted = 0;
2120
2121 /*
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.
2127 */
2128
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);
2137 }
2138
2139 /* set success/fail condition variables */
2140
2141 ckreturn(n);
2142
2143 npkgs--;
2144 }
2145
2146 /*
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.
2152 */
2153
2154 if ((ireboot == 0) && (a_repeat != 0)) {
2155 return (B_TRUE);
2156 }
2157
2158 /* return 'dont continue' */
2159
2160 return (B_FALSE);
2161 }
2162
2163 /*
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"
2197 */
2198
2199 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)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)
2202 {
2203 static char *zoneAdminFile = (char *)NULL;
2204
2205 int n;
2206 int i;
2207
2208 /* entry assertions */
2209
2210 assert(a_pkgList != (char **)NULL);
2211 assert(a_longestPkg > 0);
2212 assert(a_pkgdir != (char *)NULL);
2213 assert(*a_pkgdir != '\0');
2214
2215 /* entry debugging info */
2216
2217 echoDebug(DBG_PKGREMPKGSNGZ_ENTRY);
2218 echoDebug(DBG_PKGREMPKGSNGZ_ARGS, a_nodelete, a_longestPkg,
2219 a_repeat, PSTR(a_altBinDir), PSTR(a_pkgdir));
2220
2221 /* check all package */
2222
2223 if (check_packages(a_pkgList, a_pkgdir) != B_TRUE) {
2224 quit(1);
2225 }
2226
2227 /* create temporary directory for use by zone operations */
2228
2229 create_zone_tempdir(&zoneTempDir, tmpdir);
2230
2231 /* create hands off settings admin file for use in a non-global zone */
2232
2233 create_zone_adminfile(&zoneAdminFile, zoneTempDir, admnfile);
2234
2235 /*
2236 * all of the packages (as listed in the package list) are
2237 * removed one at a time.
2238 */
2239
2240 interrupted = 0;
2241 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2242 started = 0;
2243
2244 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2245 continue;
2246 }
2247
2248 interrupted = 0;
2249
2250 /*
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.
2254 */
2255
2256 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2257 admnfile, (char *)NULL, (zoneList_t)NULL);
2258
2259 /* set success/fail condition variables */
2260
2261 ckreturn(n);
2262
2263 npkgs--;
2264 }
2265
2266 /*
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.
2272 */
2273
2274 if ((ireboot == 0) && (a_repeat != 0)) {
2275 return (B_TRUE);
2276 }
2277
2278 /* return 'dont continue' */
2279
2280 return (B_FALSE);
2281 }
2282
2283 /*
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"
2315 */
2316
2317 static boolean_t
remove_packages_in_global_no_zones(char ** a_pkgList,int a_nodelete,int a_longestPkg,int a_repeat,char * a_altBinDir)2318 remove_packages_in_global_no_zones(char **a_pkgList, int a_nodelete,
2319 int a_longestPkg, int a_repeat, char *a_altBinDir)
2320 {
2321 int n;
2322 int i;
2323
2324 /* entry assertions */
2325
2326 assert(a_pkgList != (char **)NULL);
2327 assert(a_longestPkg > 0);
2328
2329 /* entry debugging info */
2330
2331 echoDebug(DBG_PKGREMPKGSGZNNGZ_ENTRY);
2332 echoDebug(DBG_PKGREMPKGSGZNNGZ_ARGS, a_nodelete, a_longestPkg,
2333 a_repeat, PSTR(a_altBinDir));
2334
2335 /*
2336 * all of the packages (as listed in the package list) are
2337 * removed one at a time.
2338 */
2339
2340 interrupted = 0;
2341 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2342 started = 0;
2343
2344 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2345 continue;
2346 }
2347
2348 interrupted = 0;
2349
2350 /*
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.
2354 */
2355
2356 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2357 admnfile, (char *)NULL, (zoneList_t)NULL);
2358
2359 /* set success/fail condition variables */
2360
2361 ckreturn(n);
2362
2363 npkgs--;
2364 }
2365
2366 /*
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.
2372 */
2373
2374 if ((ireboot == 0) && (a_repeat != 0)) {
2375 return (B_TRUE);
2376 }
2377
2378 /* return 'dont continue' */
2379
2380 return (B_FALSE);
2381 }
2382
2383 /*
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"
2414 */
2415
2416 static boolean_t
remove_packages_from_spool_directory(char ** a_pkgList,int a_nodelete,int a_longestPkg,int a_repeat,char * a_altBinDir)2417 remove_packages_from_spool_directory(char **a_pkgList, int a_nodelete,
2418 int a_longestPkg, int a_repeat, char *a_altBinDir)
2419 {
2420 int n;
2421 int i;
2422
2423 /* entry assertions */
2424
2425 assert(a_pkgList != (char **)NULL);
2426 assert(a_longestPkg > 0);
2427
2428 /*
2429 * all of the packages (as listed in the package list) are
2430 * removed one at a time.
2431 */
2432
2433 interrupted = 0;
2434 for (i = 0; (pkginst = a_pkgList[i]) != NULL; i++) {
2435 started = 0;
2436
2437 if (shall_we_continue(pkginst, npkgs) == B_FALSE) {
2438 continue;
2439 }
2440
2441 interrupted = 0;
2442
2443 /*
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.
2447 */
2448
2449 n = doRemove(a_nodelete, a_altBinDir, a_longestPkg,
2450 admnfile, (char *)NULL, (zoneList_t)NULL);
2451
2452 /* set success/fail condition variables */
2453
2454 ckreturn(n);
2455
2456 npkgs--;
2457 }
2458
2459 /*
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.
2465 */
2466
2467 if ((ireboot == 0) && (a_repeat != 0)) {
2468 return (B_TRUE);
2469 }
2470
2471 /* return 'dont continue' */
2472
2473 return (B_FALSE);
2474 }
2475
2476 /*
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"
2518 */
2519
2520 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)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)
2524 {
2525 zoneList_t zlst;
2526 boolean_t b;
2527
2528 /* entry assertions */
2529
2530 assert(a_pkgList != (char **)NULL);
2531
2532 echoDebug(DBG_REMOVEPKGS_ENTRY);
2533 echoDebug(DBG_REMOVEPKGS_ARGS, npkgs, a_nodelete, a_longestPkg,
2534 a_repeat, PSTR(a_pkgdir), PSTR(a_spoolDir));
2535
2536 /*
2537 * if removing from spool directory, bypass all zones checks
2538 */
2539
2540 if (a_spoolDir != (char *)NULL) {
2541 /* in non-global zone */
2542
2543 echoDebug(DBG_REMOVE_PKGS_FROM_SPOOL, a_spoolDir);
2544
2545 b = remove_packages_from_spool_directory(a_pkgList, a_nodelete,
2546 a_longestPkg, a_repeat, a_altBinDir);
2547
2548 return (B_FALSE);
2549 }
2550
2551 /* exit if not root */
2552
2553 if (getuid()) {
2554 progerr(ERR_NOT_ROOT, get_prog_name());
2555 exit(1);
2556 }
2557
2558 /*
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.
2562 */
2563
2564 if ((a_noZones == B_FALSE) && (z_running_in_global_zone() == B_FALSE)) {
2565 /* in non-global zone */
2566
2567 echoDebug(DBG_IN_LZ);
2568
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);
2575 }
2576
2577 b = remove_packages_in_nonglobal_zone(a_pkgList, a_nodelete,
2578 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir);
2579
2580 (void) z_unlock_this_zone(ZLOCKS_ALL);
2581
2582 return (B_FALSE);
2583 }
2584
2585 /* running in the global zone */
2586
2587 b = z_non_global_zones_exist();
2588 if ((a_noZones == B_FALSE) && (b == B_TRUE)) {
2589
2590 echoDebug(DBG_IN_GZ_WITH_LZ);
2591
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);
2597 }
2598
2599 /* need to lock all of the zones */
2600
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);
2609 }
2610
2611 /* add packages to all zones */
2612
2613 b = remove_packages_in_global_with_zones(a_pkgList, a_nodelete,
2614 a_longestPkg, a_repeat, a_altBinDir, a_pkgdir, zlst);
2615
2616 /* unlock all zones */
2617
2618 (void) z_unlock_zones(zlst, ZLOCKS_ALL);
2619 quitSetZonelist((zoneList_t)NULL);
2620
2621 /* free list of all non-global zones */
2622
2623 z_free_zone_list(zlst);
2624
2625 return (B_FALSE);
2626 }
2627
2628 /* in global zone no non-global zones */
2629
2630 echoDebug(DBG_IN_GZ_NO_LZ);
2631
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);
2638 }
2639
2640 b = remove_packages_in_global_no_zones(a_pkgList, a_nodelete,
2641 a_longestPkg, a_repeat, a_altBinDir);
2642
2643 (void) z_unlock_this_zone(ZLOCKS_ALL);
2644
2645 return (B_FALSE);
2646 }
2647
2648 /*
2649 */
2650
2651 static boolean_t
check_packages(char ** a_pkgList,char * a_packageDir)2652 check_packages(char **a_pkgList, char *a_packageDir)
2653 {
2654 int savenpkgs = npkgs;
2655 int i;
2656 CAF_T flags = 0;
2657
2658 /* set flags for applicability check */
2659
2660 if (z_running_in_global_zone() == B_TRUE) {
2661 flags |= CAF_IN_GLOBAL_ZONE;
2662 }
2663
2664 /*
2665 * for each package to remove, verify that the package is installed
2666 * and is removable.
2667 */
2668
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);
2676 }
2677 npkgs--;
2678 }
2679
2680 npkgs = savenpkgs;
2681 return (B_TRUE);
2682 }
2683
2684 /*
2685 * - is this package removable from this zone?
2686 * - does the scope of remove conflict with existing installation
2687 */
2688
2689 static boolean_t
check_applicability(char * a_packageDir,char * a_pkgInst,char * a_rootPath,CAF_T a_flags)2690 check_applicability(char *a_packageDir, char *a_pkgInst,
2691 char *a_rootPath, CAF_T a_flags)
2692 {
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;
2698
2699 /* entry assertions */
2700
2701 assert(a_packageDir != (char *)NULL);
2702 assert(*a_packageDir != '\0');
2703 assert(a_pkgInst != (char *)NULL);
2704 assert(*a_pkgInst != '\0');
2705
2706 /* normalize root path */
2707
2708 if (a_rootPath == (char *)NULL) {
2709 a_rootPath = "";
2710 }
2711
2712 /*
2713 * determine if this package is currently installed
2714 * if not installed return success - operation will fail
2715 * when the removal is attempted
2716 */
2717
2718 if (pkginfoIsPkgInstalled((struct pkginfo **)NULL, a_pkgInst) !=
2719 B_TRUE) {
2720 return (B_TRUE);
2721 }
2722
2723 /*
2724 * calculate paths to various objects
2725 */
2726
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);
2732 }
2733
2734 /* if not installed then just return */
2735
2736 if (isdir(pkgpath) != 0) {
2737 progerr(ERR_NO_PKGDIR, pkgpath, a_pkgInst, strerror(errno));
2738 return (B_TRUE);
2739 }
2740
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);
2746 }
2747
2748 /*
2749 * gather information from this packages pkginfo file
2750 */
2751
2752 pkginfoFP = fopen(pkginfoPath, "r");
2753
2754 if (pkginfoFP == (FILE *)NULL) {
2755 progerr(ERR_NO_PKG_INFOFILE, a_pkgInst, pkginfoPath,
2756 strerror(errno));
2757 return (B_FALSE);
2758 }
2759
2760 /* determine "ALLZONES" setting for this package */
2761
2762 all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
2763 "true", B_FALSE);
2764
2765 /* close pkginfo file */
2766
2767 (void) fclose(pkginfoFP);
2768
2769 /* gather information from the global zone only file */
2770
2771 /*
2772 * verify package applicability based on information gathered;
2773 * the package IS currently installed....
2774 */
2775
2776 /* pkg ALLZONES=true & not running in global zone */
2777
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);
2781 }
2782
2783 return (B_TRUE);
2784 }
2785
2786 /*
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
2795 */
2796
2797 static boolean_t
shall_we_continue(char * a_pkgInst,int a_npkgs)2798 shall_we_continue(char *a_pkgInst, int a_npkgs)
2799 {
2800 char ans[MAX_INPUT];
2801 int n;
2802
2803 /* return FALSE if immediate reboot required */
2804
2805 if (ireboot) {
2806 ptext(stderr, MSG_SUSPEND_RM, a_pkgInst);
2807 return (B_FALSE);
2808 }
2809
2810 /* return TRUE if not interrupted */
2811
2812 if (!interrupted) {
2813 return (B_TRUE);
2814 }
2815
2816 /* output appropriate interrupt message */
2817
2818 echo(a_npkgs == 1 ? MSG_1MORETODO : MSG_MORETODO, a_npkgs);
2819
2820 /* if running with no interaction (-n) do not ask question */
2821
2822 if (nointeract) {
2823 quit(0);
2824 /* NOTREACHED */
2825 }
2826
2827 /* interaction possible: ask question */
2828
2829 n = ckyorn(ans, NULL, NULL, NULL, ASK_CONTINUE_RM);
2830 if (n != 0) {
2831 quit(n);
2832 /* NOTREACHED */
2833 }
2834
2835 if (strchr("yY", *ans) == NULL) {
2836 quit(0);
2837 /* NOTREACHED */
2838 }
2839 return (B_TRUE);
2840 }
2841
2842 /*
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)'
2869 */
2870
2871 static void
create_zone_adminfile(char ** r_zoneAdminFile,char * a_zoneTempDir,char * a_admnfile)2872 create_zone_adminfile(char **r_zoneAdminFile, char *a_zoneTempDir,
2873 char *a_admnfile)
2874 {
2875 boolean_t b;
2876
2877 /* entry assertions */
2878
2879 assert(r_zoneAdminFile != (char **)NULL);
2880 assert(a_zoneTempDir != (char *)NULL);
2881 assert(*a_zoneTempDir != '\0');
2882
2883 /* entry debugging info */
2884
2885 echoDebug(DBG_CREATE_ZONE_ADMINFILE, a_zoneTempDir, PSTR(a_admnfile));
2886
2887 /* if temporary name already exists, do not overwrite */
2888
2889 if (*r_zoneAdminFile != (char *)NULL) {
2890 return;
2891 }
2892
2893 /* create temporary name */
2894
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 */
2902 }
2903
2904 echoDebug(DBG_CREATED_ZONE_ADMINFILE, *r_zoneAdminFile);
2905 }
2906
2907 /*
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.
2929 */
2930
2931 static void
create_zone_tempdir(char ** r_zoneTempDir,char * a_tmpdir)2932 create_zone_tempdir(char **r_zoneTempDir, char *a_tmpdir)
2933 {
2934 boolean_t b;
2935
2936 /* entry assertions */
2937
2938 assert(r_zoneTempDir != (char **)NULL);
2939 assert(a_tmpdir != (char *)NULL);
2940 assert(*a_tmpdir != '\0');
2941
2942 /* entry debugging info */
2943
2944 echoDebug(DBG_CREATE_ZONE_TEMPDIR, a_tmpdir);
2945
2946 /* if temporary directory already exists, do not overwrite */
2947
2948 if (*r_zoneTempDir != (char *)NULL) {
2949 return;
2950 }
2951
2952 /* create temporary directory */
2953
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 */
2959 }
2960
2961 /* register with quit() to directory is removed on exit */
2962
2963 quitSetZoneTmpdir(*r_zoneTempDir);
2964
2965 /* exit debugging info */
2966
2967 echoDebug(DBG_CREATED_ZONE_TEMPDIR, *r_zoneTempDir);
2968 }
2969