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