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