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