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