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