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