1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <limits.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <signal.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 #include <pkgstrct.h> 42 #include <pkginfo.h> 43 #include <pkglocs.h> 44 #include <locale.h> 45 #include <libintl.h> 46 #include <assert.h> 47 #include <cfext.h> 48 #include <instzones_api.h> 49 #include <pkglib.h> 50 #include <install.h> 51 #include <libinst.h> 52 #include <libadm.h> 53 #include <messages.h> 54 55 struct cfent **eptlist; 56 extern int eptnum; 57 58 extern char *pkgdir; 59 extern char **environ; 60 61 /* quit.c */ 62 extern sighdlrFunc_t *quitGetTrapHandler(void); 63 extern void quitSetSilentExit(boolean_t a_silentExit); 64 extern void quitSetZoneName(char *a_zoneName); 65 66 67 68 /* check.c */ 69 extern void rcksetPreremoveCheck(boolean_t); 70 extern void rcksetZoneName(char *); 71 extern int rckpriv(void); 72 extern int rckdepend(void); 73 extern int rckrunlevel(void); 74 75 /* predepend.c */ 76 extern void predepend(char *oldpkg); 77 78 /* delmap.c */ 79 extern int delmap(int flag, char *pkginst); 80 81 #define DEFPATH "/sbin:/usr/sbin:/usr/bin" 82 83 #ifdef ALLOW_EXCEPTION_PKG_LIST 84 #define SCRIPT 0 /* Tells exception_pkg() which pkg list to use */ 85 #define LINK 1 86 #endif 87 88 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 89 #define TEXT_DOMAIN "SYS_TEST" 90 #endif 91 92 /* This is the text for the "-O inherited-filesystem=" option */ 93 94 #define INHERITFS "inherited-filesystem=" 95 #define INHERITFS_LEN ((sizeof (INHERITFS))-1) 96 97 /* This is the text for the "-O parent-zone-name=" option */ 98 99 #define PARENTZONENAME "parent-zone-name=" 100 #define PARENTZONENAME_LEN ((sizeof (PARENTZONENAME))-1) 101 102 /* This is the text for the "-O parent-zone-type=" option */ 103 104 #define PARENTZONETYPE "parent-zone-type=" 105 #define PARENTZONETYPE_LEN ((sizeof (PARENTZONETYPE))-1) 106 107 struct admin adm; /* holds info about installation admin */ 108 int dreboot; /* non-zero if reboot required after installation */ 109 int ireboot; /* non-zero if immediate reboot required */ 110 int failflag; /* non-zero if fatal error has occurred */ 111 int warnflag; /* non-zero if non-fatal error has occurred */ 112 int pkgverbose; /* non-zero if verbose mode is selected */ 113 int started; 114 int nocnflct = 0; /* pkgdbmerg needs this defined */ 115 int nosetuid = 0; /* pkgdbmerg needs this defined */ 116 117 char *pkginst; /* current package (source) instance to process */ 118 119 int dbchg; 120 char *msgtext; 121 char pkgloc[PATH_MAX]; 122 123 /* 124 * The following variable is the name of the device to which stdin 125 * is connected during execution of a procedure script. /dev/null is 126 * correct for all ABI compliant packages. For non-ABI-compliant 127 * packages, the '-o' command line switch changes this to /dev/tty 128 * to allow user interaction during these scripts. -- JST 129 */ 130 static char *script_in = PROC_STDIN; /* assume ABI compliance */ 131 132 static char *client_mntdir; /* mount point for client's basedir */ 133 static char pkgbin[PATH_MAX], 134 rlockfile[PATH_MAX], 135 *admnfile, /* file to use for installation admin */ 136 *tmpdir; /* location to place temporary files */ 137 138 static boolean_t path_valid(char *path); 139 static void ckreturn(int retcode, char *msg); 140 static void rmclass(char *aclass, int rm_remote, char *a_zoneName); 141 static void usage(void); 142 143 /* 144 * Set by -O debug: debug output is enabled? 145 */ 146 static boolean_t debugFlag = B_FALSE; 147 148 /* 149 * Set by -O preremovecheck: do remove dependency checking only 150 */ 151 static boolean_t preremoveCheck = B_FALSE; 152 153 /* Set by -O parent-zone-name= */ 154 155 static char *parentZoneName = (char *)NULL; 156 157 /* Set by -O parent-zone-type= */ 158 159 static char *parentZoneType = (char *)NULL; 160 161 static int nointeract; /* != 0 no interaction with user should occur */ 162 163 164 165 int 166 main(int argc, char *argv[]) 167 { 168 FILE *fp; 169 char *abi_comp_ptr; 170 char *abi_sym_ptr; 171 char *p; 172 char *prog_full_name = NULL; 173 char *pt; 174 char *value; 175 char *vfstab_file = NULL; 176 char *zoneName = (char *)NULL; 177 char cmdbin[PATH_MAX]; 178 char param[MAX_PKG_PARAM_LENGTH]; 179 char path[PATH_MAX]; 180 char script[PATH_MAX]; 181 int c; 182 int err; 183 int fd; 184 int i; 185 int map_client = 1; 186 int n; 187 int nodelete = 0; /* do not delete file or run scripts */ 188 int pkgrmremote = 0; /* dont remove remote objects */ 189 struct sigaction nact; 190 struct sigaction oact; 191 192 /* reset contents of all default paths */ 193 194 (void) memset(cmdbin, '\0', sizeof (cmdbin)); 195 196 /* initialize locale environment */ 197 198 (void) setlocale(LC_ALL, ""); 199 (void) textdomain(TEXT_DOMAIN); 200 201 /* initialize program name */ 202 203 prog_full_name = argv[0]; 204 (void) set_prog_name(argv[0]); 205 206 /* tell spmi zones interface how to access package output functions */ 207 208 z_set_output_functions(echo, echoDebug, progerr); 209 210 /* exit if not root */ 211 212 if (getuid()) { 213 progerr(ERR_NOT_ROOT, get_prog_name()); 214 exit(1); 215 /* NOTREACHED */ 216 } 217 218 /* Read PKG_INSTALL_ROOT from the environment, if it's there. */ 219 220 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { 221 progerr(ERR_ROOT_SET); 222 exit(1); 223 } 224 225 /* parse command line options */ 226 227 while ((c = getopt(argc, argv, "?Aa:b:FMN:nO:oR:V:vy")) != EOF) { 228 switch (c) { 229 /* 230 * Same as pkgrm: Allow admin to remove package objects from 231 * a shared area from a reference client. 232 */ 233 case 'A': 234 pkgrmremote++; 235 break; 236 237 /* 238 * Same as pkgrm: Use the installation 239 * administration file, admin, in place of the 240 * default admin file. pkgrm first looks in the 241 * current working directory for the administration 242 * file. If the specified administration file is not 243 * in the current working directory, pkgrm looks in 244 * the /var/sadm/install/admin directory for the 245 * administration file. 246 */ 247 case 'a': 248 admnfile = flex_device(optarg, 0); 249 break; 250 251 /* 252 * Same as pkgrm: location where package executables 253 * can be found - default is /usr/sadm/install/bin. 254 */ 255 case 'b': 256 if (!path_valid(optarg)) { 257 progerr(ERR_PATH, optarg); 258 exit(1); 259 } 260 if (isdir(optarg) != 0) { 261 char *p = strerror(errno); 262 progerr(ERR_CANNOT_USE_DIR, optarg, p); 263 exit(1); 264 } 265 (void) strlcpy(cmdbin, optarg, sizeof (cmdbin)); 266 break; 267 268 /* 269 * Same as pkgrm: suppresses the removal of any 270 * files and any class action scripts, and suppresses 271 * the running of any class action scripts. The 272 * package files remain but the package looks like it 273 * is not installed. This is mainly for use by the 274 * upgrade process. 275 */ 276 case 'F': 277 nodelete++; 278 break; 279 280 /* 281 * Same as pkgrm: Instruct pkgrm not to use the 282 * $root_path/etc/vfstab file for determining the 283 * client's mount points. This option assumes the 284 * mount points are correct on the server and it 285 * behaves consistently with Solaris 2.5 and earlier 286 * releases. 287 */ 288 case 'M': 289 map_client = 0; 290 break; 291 292 /* 293 * Different from pkgrm: specify program name to use 294 * for messages. 295 */ 296 case 'N': 297 (void) set_prog_name(optarg); 298 break; 299 300 /* 301 * Same as pkgrm: package removal occurs in 302 * non-interactive mode. Suppress output of the list of 303 * removed files. The default mode is interactive. 304 */ 305 case 'n': 306 nointeract++; 307 (void) echoSetFlag(B_FALSE); 308 break; 309 310 /* 311 * Almost same as pkgrm: the -O option allows the behavior 312 * of the package tools to be modified. Recognized options: 313 * -> debug 314 * ---> enable debugging output 315 * -> preremovecheck 316 * ---> perform a "pre removal" check of the specified 317 * ---> package - suppress all regular output and cause a 318 * ---> series of one or more "name=value" pair format lines 319 * ---> to be output that describes the "removability" of 320 * ---> the specified package 321 * -> enable-hollow-package-support 322 * --> Enable hollow package support. When specified, for any 323 * --> package that has SUNW_PKG_HOLLOW=true: 324 * --> Do not calculate and verify package size against target 325 * --> Do not run any package procedure or class action scripts 326 * --> Do not create or remove any target directories 327 * --> Do not perform any script locking 328 * --> Do not install or uninstall any components of any package 329 * --> Do not output any status or database update messages 330 */ 331 case 'O': 332 for (p = strtok(optarg, ","); p != (char *)NULL; 333 p = strtok(NULL, ",")) { 334 335 /* process debug option */ 336 337 if (strcmp(p, "debug") == 0) { 338 /* set debug flag/enable debug output */ 339 debugFlag = B_TRUE; 340 (void) echoDebugSetFlag(debugFlag); 341 342 /* debug info on arguments to pkgadd */ 343 for (n = 0; n < argc && argv[n]; n++) { 344 echoDebug(DBG_ARG, n, argv[n]); 345 } 346 347 continue; 348 } 349 350 /* process enable-hollow-package-support opt */ 351 352 if (strcmp(p, 353 "enable-hollow-package-support") == 0) { 354 set_depend_pkginfo_DB(B_TRUE); 355 continue; 356 } 357 358 /* process inherited-filesystem= option */ 359 360 if (strncmp(p, INHERITFS, INHERITFS_LEN) == 0) { 361 if (z_add_inherited_file_system( 362 p+INHERITFS_LEN) == B_FALSE) { 363 progerr(ERR_NOSUCH_INHERITED, 364 p+INHERITFS_LEN); 365 quit(1); 366 /* NOTREACHED */ 367 } 368 continue; 369 } 370 371 /* process preremovecheck option */ 372 373 if (strcmp(p, "preremovecheck") == 0) { 374 preremoveCheck = B_TRUE; 375 nointeract++; /* -n */ 376 nodelete++; /* -F */ 377 quitSetSilentExit(B_TRUE); 378 continue; 379 } 380 381 /* process addzonename option */ 382 383 if (strcmp(p, "addzonename") == 0) { 384 zoneName = z_get_zonename(); 385 quitSetZoneName(zoneName); 386 continue; 387 } 388 389 /* process parent-zone-name option */ 390 391 if (strncmp(p, PARENTZONENAME, 392 PARENTZONENAME_LEN) == 0) { 393 parentZoneName = p+PARENTZONENAME_LEN; 394 continue; 395 } 396 397 /* process parent-zone-type option */ 398 399 if (strncmp(p, PARENTZONETYPE, 400 PARENTZONETYPE_LEN) == 0) { 401 parentZoneType = p+PARENTZONETYPE_LEN; 402 continue; 403 } 404 405 /* option not recognized - issue warning */ 406 407 progerr(ERR_INVALID_O_OPTION, p); 408 continue; 409 } 410 break; 411 412 /* 413 * Different from pkgrm: This is an old non-ABI package 414 */ 415 416 case 'o': 417 script_in = PROC_XSTDIN; 418 break; 419 420 /* 421 * Same as pkgrm: defines the full path name of a 422 * directory to use as the root_path. All files, 423 * including package system information files, are 424 * relocated to a directory tree starting in the 425 * specified root_path. 426 */ 427 case 'R': 428 if (!set_inst_root(optarg)) { 429 progerr(ERR_ROOT_CMD); 430 exit(1); 431 } 432 break; 433 434 /* 435 * Same as pkgrm: allow admin to establish the client 436 * filesystem using a vfstab-like file of stable format. 437 */ 438 case 'V': 439 vfstab_file = flex_device(optarg, 2); 440 map_client = 1; 441 break; 442 443 /* 444 * Same as pkgrm: trace all of the scripts that 445 * get executed by pkgrm, located in the 446 * pkginst/install directory. This option is used for 447 * debugging the procedural and non-procedural 448 * scripts. 449 */ 450 case 'v': 451 pkgverbose++; 452 break; 453 454 /* 455 * Different from pkgrm: process this package using 456 * old non-ABI symlinks 457 */ 458 case 'y': 459 set_nonABI_symlinks(); 460 break; 461 462 default: 463 usage(); 464 /*NOTREACHED*/ 465 /* 466 * Although usage() calls a noreturn function, 467 * needed to add return (1); so that main() would 468 * pass compilation checks. The statement below 469 * should never be executed. 470 */ 471 return (1); 472 } 473 } 474 475 /* 476 * ******************************************************************** 477 * validate command line options 478 * ******************************************************************** 479 */ 480 481 (void) echoDebugSetFlag(debugFlag); 482 (void) log_set_verbose(debugFlag); 483 484 if (z_running_in_global_zone()) { 485 echoDebug(DBG_ENTRY_IN_GZ, prog_full_name); 486 } else { 487 echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(), 488 z_get_zonename()); 489 } 490 491 /* establish cmdbin path */ 492 493 if (cmdbin[0] == '\0') { 494 (void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin)); 495 } 496 497 /* Read the mount table */ 498 499 if (get_mntinfo(map_client, vfstab_file)) { 500 quit(99); 501 } 502 503 /* 504 * This function defines the standard /var/... directories used later 505 * to construct the paths to the various databases. 506 */ 507 508 set_PKGpaths(get_inst_root()); 509 510 /* 511 * If this is being removed from a client whose /var filesystem is 512 * mounted in some odd way, remap the administrative paths to the 513 * real filesystem. This could be avoided by simply mounting up the 514 * client now; but we aren't yet to the point in the process where 515 * modification of the filesystem is permitted. 516 */ 517 if (is_an_inst_root()) { 518 int fsys_value; 519 520 fsys_value = fsys(get_PKGLOC()); 521 if (use_srvr_map_n(fsys_value)) 522 set_PKGLOC(server_map(get_PKGLOC(), fsys_value)); 523 524 fsys_value = fsys(get_PKGADM()); 525 if (use_srvr_map_n(fsys_value)) 526 set_PKGADM(server_map(get_PKGADM(), fsys_value)); 527 } else { 528 pkgrmremote = 0; /* Makes no sense on local host. */ 529 } 530 531 /* 532 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler 533 */ 534 535 /* hold SIGINT/SIGHUP interrupts */ 536 537 (void) sighold(SIGHUP); 538 (void) sighold(SIGINT); 539 540 /* connect quit.c:trap() to SIGINT */ 541 542 nact.sa_handler = quitGetTrapHandler(); 543 nact.sa_flags = SA_RESTART; 544 (void) sigemptyset(&nact.sa_mask); 545 546 (void) sigaction(SIGINT, &nact, &oact); 547 548 /* connect quit.c:trap() to SIGHUP */ 549 550 nact.sa_handler = quitGetTrapHandler(); 551 nact.sa_flags = SA_RESTART; 552 (void) sigemptyset(&nact.sa_mask); 553 554 (void) sigaction(SIGHUP, &nact, &oact); 555 556 /* release hold on signals */ 557 558 (void) sigrelse(SIGHUP); 559 (void) sigrelse(SIGINT); 560 561 pkginst = argv[optind++]; 562 if (optind != argc) { 563 usage(); 564 } 565 566 /* validate package software database (contents) file */ 567 568 if (vcfile() == 0) { 569 quit(99); 570 } 571 572 /* 573 * Acquire the package lock - currently at "remove initialization" 574 */ 575 576 if (!lockinst(get_prog_name(), pkginst, "remove-initial")) { 577 quit(99); 578 } 579 580 /* establish temporary directory to use */ 581 582 tmpdir = getenv("TMPDIR"); 583 if (tmpdir == NULL) { 584 tmpdir = P_tmpdir; 585 } 586 587 echoDebug(DBG_PKGREMOVE_TMPDIR, tmpdir); 588 589 /* 590 * Initialize installation admin parameters by reading 591 * the adminfile. 592 */ 593 594 echoDebug(DBG_PKGREMOVE_ADMINFILE, admnfile ? admnfile : ""); 595 setadminFile(admnfile); 596 597 /* 598 * about to perform first operation that could be modified by the 599 * preremove check option - if preremove check is selected (that is, 600 * only gathering dependencies), then output a debug message to 601 * indicate that the check is beginning. Also turn echo() output 602 * off and set various other flags. 603 */ 604 605 if (preremoveCheck == B_TRUE) { 606 (void) echoSetFlag(B_FALSE); 607 echoDebug(DBG_PKGREMOVE_PRERMCHK, pkginst ? pkginst : "", 608 zoneName ? zoneName : "global"); 609 rcksetPreremoveCheck(B_TRUE); 610 rcksetZoneName(zoneName); 611 } 612 613 (void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s", get_PKGLOC(), 614 pkginst); 615 (void) snprintf(pkgbin, sizeof (pkgbin), "%s/install", pkgloc); 616 (void) snprintf(rlockfile, sizeof (rlockfile), "%s/!R-Lock!", pkgloc); 617 618 if (chdir(pkgbin)) { 619 progerr(ERR_CHDIR, pkgbin); 620 quit(99); 621 } 622 623 echo(MSG_PREREMOVE_REMINST, pkginst); 624 625 /* 626 * if a lock file is present, then a previous attempt to remove this 627 * package may have been unsuccessful. 628 */ 629 630 if (access(rlockfile, F_OK) == 0) { 631 echo(ERR_UNSUCC); 632 echoDebug(DBG_PKGINSTALL_HAS_LOCKFILE, pkginst, rlockfile, 633 zoneName ? zoneName : "global"); 634 } 635 636 /* 637 * Process all parameters from the pkginfo file 638 * and place them in the execution environment 639 */ 640 641 /* Add DB retreival of the pkginfo parameters here */ 642 (void) snprintf(path, sizeof (path), "%s/pkginfo", pkgloc); 643 if ((fp = fopen(path, "r")) == NULL) { 644 progerr(ERR_PKGINFO, path); 645 quit(99); 646 } 647 648 /* Mount up the client if necessary. */ 649 if (map_client && !mount_client()) { 650 logerr(MSG_MANMOUNT); 651 } 652 653 /* Get mount point of client */ 654 client_mntdir = getenv("CLIENT_MNTDIR"); 655 656 getuserlocale(); 657 658 /* 659 * current environment has been read; clear environment out 660 * so putparam() can be used to populate the new environment 661 * to be passed to any executables/scripts. 662 */ 663 664 environ = NULL; 665 666 if (nonABI_symlinks()) { 667 putparam("PKG_NONABI_SYMLINKS", "TRUE"); 668 } 669 670 /* 671 * read the pkginfo file and fix any PKGSAV path - the correct 672 * install_root will be prepended to the existing path. 673 */ 674 675 param[0] = '\0'; 676 while (value = fpkgparam(fp, param)) { 677 int validx = 0; 678 char *newvalue; 679 680 /* strip out any setting of PATH */ 681 682 if (strcmp(param, "PATH") == 0) { 683 free(value); 684 param[0] = '\0'; 685 continue; 686 } 687 688 /* if not PKGSAV then write out unchanged */ 689 690 if (strcmp(param, "PKGSAV") != 0) { 691 putparam(param, value); 692 free(value); 693 param[0] = '\0'; 694 continue; 695 } 696 697 /* 698 * PKGSAV parameter found - interpret the directory: 699 * If in host:path format or marked with the leading "//", 700 * then there is no client-relative translation - take it 701 * literally later rather than use fixpath(). 702 */ 703 704 if (strstr(value, ":/")) { 705 /* no modification needed */ 706 validx = 0; 707 } else if (strstr(value, "//") == value) { 708 validx = 1; 709 } else if (is_an_inst_root()) { 710 /* This PKGSAV needs to be made client-relative. */ 711 newvalue = fixpath(value); 712 free(value); 713 value = newvalue; 714 } 715 putparam(param, value+validx); 716 free(value); 717 param[0] = '\0'; 718 } 719 720 (void) fclose(fp); 721 722 /* write parent condition information to environment */ 723 724 putConditionInfo(parentZoneName, parentZoneType); 725 726 putuserlocale(); 727 728 /* 729 * Now do all the various setups based on ABI compliance 730 */ 731 732 /* Read the environment provided by the pkginfo file */ 733 abi_comp_ptr = getenv("NONABI_SCRIPTS"); 734 735 /* if not ABI compliant set global flag */ 736 abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS"); 737 if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) { 738 set_nonABI_symlinks(); 739 } 740 741 /* 742 * If pkginfo says it's not compliant then set non_abi_scripts. 743 * Oh, for two releases, set it from exception package names as 744 * well. 745 */ 746 /* 747 * ********************************************************************* 748 * this feature is removed starting with Solaris 10 - there is no built 749 * in list of packages that should be run "the old way" 750 * ********************************************************************* 751 */ 752 753 #ifdef ALLOW_EXCEPTION_PKG_LIST 754 if (exception_pkg(pkginst, SCRIPT) || 755 (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0)) 756 script_in = PROC_XSTDIN; 757 #else 758 if (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0) { 759 script_in = PROC_XSTDIN; 760 } 761 #endif 762 /* 763 * ********************************************************************* 764 * this feature is removed starting with Solaris 10 - there is no built 765 * in list of packages that should be run "the old way" 766 * ********************************************************************* 767 */ 768 769 #ifdef ALLOW_EXCEPTION_PKG_LIST 770 /* Until 2.9, set it from the execption list */ 771 if (exception_pkg(pkginst, LINK)) { 772 set_nonABI_symlinks(); 773 } 774 #endif 775 776 /* 777 * Since this is a removal, we can tell whether it's absolute or 778 * not from the resident pkginfo file read above. 779 */ 780 if ((err = set_basedirs((getenv("BASEDIR") != NULL), adm.basedir, 781 pkginst, nointeract)) != 0) { 782 quit(err); 783 } 784 785 /* 786 * See if were are removing a package that only wants to update 787 * the database or only remove files associated with CAS's. We 788 * only check the PKG_HOLLOW_VARIABLE variable if told to do so by 789 * the caller. 790 */ 791 792 if (is_depend_pkginfo_DB()) { 793 pt = getenv(PKG_HOLLOW_VARIABLE); 794 795 if ((pt != NULL) && (strncasecmp(pt, "true", 4) == 0)) { 796 echoDebug(DBG_PKGREMOVE_HOLLOW_ENABLED); 797 798 /* 799 * this is a hollow package and hollow package support 800 * is enabled -- override admin settings to suppress 801 * checks that do not make sense since no scripts will 802 * be executed and no files will be removed. 803 */ 804 805 setadminSetting("conflict", "nocheck"); 806 setadminSetting("setuid", "nocheck"); 807 setadminSetting("action", "nocheck"); 808 setadminSetting("partial", "nocheck"); 809 setadminSetting("space", "nocheck"); 810 setadminSetting("authentication", "nocheck"); 811 } else { 812 echoDebug(DBG_PKGREMOVE_HOLLOW_DISABLED); 813 set_depend_pkginfo_DB(B_FALSE); 814 } 815 } 816 817 put_path_params(); 818 819 /* If client mount point, add it to pkgremove environment */ 820 821 if (client_mntdir != NULL) { 822 putparam("CLIENT_MNTDIR", client_mntdir); 823 } 824 825 /* Establish the class list and the class attributes. */ 826 827 if ((value = getenv("CLASSES")) != NULL) { 828 cl_sets(qstrdup(value)); 829 } else { 830 progerr(ERR_CLASSES, path); 831 quit(99); 832 } 833 834 /* establish path and tmpdir */ 835 836 if (cmdbin[0] == '\0') { 837 (void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin)); 838 } 839 840 (void) snprintf(path, sizeof (path), "%s:%s", DEFPATH, cmdbin); 841 putparam("PATH", path); 842 843 putparam("TMPDIR", tmpdir); 844 845 /* 846 * Check ulimit requirement (provided in pkginfo). The purpose of 847 * this limit is to terminate pathological file growth resulting from 848 * file edits in scripts. It does not apply to files in the pkgmap 849 * and it does not apply to any database files manipulated by the 850 * installation service. 851 */ 852 if (value = getenv("ULIMIT")) { 853 if (assign_ulimit(value) == -1) { 854 progerr(ERR_BADULIMIT, value); 855 warnflag++; 856 } 857 putparam("PKG_ULIMIT", "TRUE"); 858 } 859 860 /* 861 * If only gathering dependencies, check and output status of all 862 * remaining dependencies and exit. 863 */ 864 865 if (preremoveCheck == B_TRUE) { 866 /* 867 * make sure current runlevel is appropriate 868 */ 869 870 (void) fprintf(stdout, "rckrunlevel=%d\n", rckrunlevel()); 871 872 /* 873 * determine if any packaging scripts provided with 874 * this package will execute as a priviledged user 875 */ 876 877 (void) fprintf(stdout, "rckpriv=%d\n", rckpriv()); 878 879 /* 880 * verify package dependencies 881 */ 882 883 (void) fprintf(stdout, "rckdepend=%d\n", rckdepend()); 884 885 /* 886 * ****** preremove check done - exit ****** 887 */ 888 889 echoDebug(DBG_PKGREMOVE_PRERMCHK_OK); 890 quit(0); 891 /*NOTREACHED*/ 892 } 893 894 /* 895 * Not gathering dependencies only, proceed to check dependencies 896 * and continue with the package removal operation. 897 */ 898 899 /* 900 * make sure current runlevel is appropriate 901 */ 902 903 n = rckrunlevel(); 904 905 if (n != 0) { 906 quit(n); 907 /* NOTREACHED */ 908 } 909 910 /* 911 * determine if any packaging scripts provided with 912 * this package will execute as a priviledged user 913 */ 914 915 n = rckpriv(); 916 917 if (n != 0) { 918 quit(n); 919 /* NOTREACHED */ 920 } 921 922 /* 923 * verify package dependencies 924 */ 925 n = rckdepend(); 926 927 if (n != 0) { 928 quit(n); 929 /* NOTREACHED */ 930 } 931 932 /* 933 * ********************************************************************* 934 * the actual removal of the package begins here 935 * ********************************************************************* 936 */ 937 938 /* 939 * create lockfile to indicate start of removal 940 */ 941 started++; 942 if ((fd = open(rlockfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 943 progerr(ERR_LOCKFILE, rlockfile); 944 quit(99); 945 } else { 946 (void) close(fd); 947 } 948 949 if (zoneName == (char *)NULL) { 950 echo(MSG_PKGREMOVE_PROCPKG_GZ); 951 echoDebug(DBG_PKGREMOVE_PROCPKG_GZ, pkginst, rlockfile); 952 } else { 953 echo(MSG_PKGREMOVE_PROCPKG_LZ, zoneName); 954 echoDebug(DBG_PKGREMOVE_PROCPKG_LZ, pkginst, rlockfile, 955 zoneName); 956 } 957 if (delmap(0, pkginst) != 0) { 958 progerr(ERR_DB_QUERY, pkginst); 959 quit(99); 960 } 961 962 /* 963 * Run a preremove script if one is provided by the package. 964 * Don't execute preremove script if only updating the DB. 965 * Don't execute preremove script if files are not being deleted. 966 * Don't execute preremove script if one or more files reside in 967 * an inherited FS. 968 */ 969 970 /* update the lock - at the preremove script */ 971 lockupd("preremove"); 972 973 /* execute preremove script if one is provided */ 974 (void) snprintf(script, sizeof (script), "%s/preremove", pkgbin); 975 if (access(script, F_OK) != 0) { 976 /* no script present */ 977 echoDebug(DBG_PKGREMOVE_POC_NONE, pkginst, 978 zoneName ? zoneName : "global"); 979 } else if (nodelete) { 980 /* not deleting files: skip preremove script */ 981 echoDebug(DBG_PKGREMOVE_POC_NODEL, pkginst, script, 982 zoneName ? zoneName : "global"); 983 } else if (is_depend_pkginfo_DB()) { 984 /* updating db only: skip preremove script */ 985 echoDebug(DBG_PKGREMOVE_POC_DBUPD, pkginst, script, 986 zoneName ? zoneName : "global"); 987 } else { 988 /* script present and ok to run: run the script */ 989 set_ulimit("preremove", ERR_PREREMOVE); 990 if (zoneName == (char *)NULL) { 991 echo(MSG_PKGREMOVE_EXEPOC_GZ); 992 echoDebug(DBG_PKGREMOVE_EXEPOC_GZ, pkginst, script); 993 } else { 994 echo(MSG_PKGREMOVE_EXEPOC_LZ, zoneName); 995 echoDebug(DBG_PKGREMOVE_EXEPOC_LZ, pkginst, script, 996 zoneName); 997 } 998 putparam("PKG_PROC_SCRIPT", "preremove"); 999 if (pkgverbose) { 1000 ckreturn(pkgexecl(script_in, PROC_STDOUT, 1001 PROC_USER, PROC_GRP, SHELL, "-x", 1002 script, NULL), ERR_PREREMOVE); 1003 } else { 1004 ckreturn(pkgexecl(script_in, PROC_STDOUT, 1005 PROC_USER, PROC_GRP, SHELL, script, 1006 NULL), ERR_PREREMOVE); 1007 } 1008 clr_ulimit(); 1009 } 1010 1011 /* update the lock - doing removal */ 1012 1013 lockupd("remove"); 1014 1015 /* 1016 * Ensure that the contents file is updated even if the db has 1017 * been upgraded, in the case that there are relevant entries 1018 * in a special_contents file. The return value is ignored 1019 * since we do not want special_contents operation to prevent 1020 * pkgremove from succeeding. We do report errors to stderr. 1021 */ 1022 1023 /* 1024 * Remove all components belonging to this package. 1025 * Don't remove components if only updating the DB. 1026 * Don't remove components if files are not being deleted. 1027 */ 1028 1029 if (nodelete) { 1030 echoDebug(DBG_PKGREMOVE_REM_NODEL, pkginst, 1031 zoneName ? zoneName : "global"); 1032 } else if (is_depend_pkginfo_DB()) { 1033 echoDebug(DBG_PKGREMOVE_REM_DBUPD, pkginst, 1034 zoneName ? zoneName : "global"); 1035 } else { 1036 echoDebug(DBG_PKGREMOVE_REM, pkginst, 1037 zoneName ? zoneName : "global"); 1038 /* 1039 * remove package one class at a time 1040 */ 1041 1042 /* reverse order of classes */ 1043 for (i = cl_getn() - 1; i >= 0; i--) { 1044 rmclass(cl_nam(i), pkgrmremote, zoneName); 1045 } 1046 1047 rmclass(NULL, pkgrmremote, zoneName); 1048 } 1049 1050 z_destroyMountTable(); 1051 1052 /* 1053 * Execute postremove script, if any 1054 * Don't execute postremove script if only updating the DB. 1055 * Don't execute postremove script if files are not being deleted. 1056 */ 1057 1058 /* update the lock - at the postremove script */ 1059 lockupd("postremove"); 1060 1061 /* execute postremove script if one is provided */ 1062 (void) snprintf(script, sizeof (script), "%s/postremove", pkgbin); 1063 if (access(script, F_OK) != 0) { 1064 /* no script present */ 1065 echoDebug(DBG_PKGREMOVE_PIC_NONE, pkginst, 1066 zoneName ? zoneName : "global"); 1067 } else if (nodelete) { 1068 /* not deleting files: skip postremove script */ 1069 echoDebug(DBG_PKGREMOVE_PIC_NODEL, pkginst, script, 1070 zoneName ? zoneName : "global"); 1071 } else if (is_depend_pkginfo_DB()) { 1072 /* updating db only: skip postremove script */ 1073 echoDebug(DBG_PKGREMOVE_PIC_DBUPD, pkginst, script, 1074 zoneName ? zoneName : "global"); 1075 } else { 1076 /* script present and ok to run: run the script */ 1077 set_ulimit("postremove", ERR_POSTREMOVE); 1078 if (zoneName == (char *)NULL) { 1079 echo(MSG_PKGREMOVE_EXEPIC_GZ); 1080 echoDebug(DBG_PKGREMOVE_EXEPIC_GZ, pkginst, script); 1081 } else { 1082 echo(MSG_PKGREMOVE_EXEPIC_LZ, zoneName); 1083 echoDebug(DBG_PKGREMOVE_EXEPIC_LZ, pkginst, script, 1084 zoneName); 1085 } 1086 putparam("PKG_PROC_SCRIPT", "postremove"); 1087 putparam("TMPDIR", tmpdir); 1088 if (pkgverbose) { 1089 ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, 1090 PROC_GRP, SHELL, "-x", script, NULL), 1091 ERR_POSTREMOVE); 1092 } else { 1093 ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, 1094 PROC_GRP, SHELL, script, NULL), 1095 ERR_POSTREMOVE); 1096 } 1097 clr_ulimit(); 1098 } 1099 1100 if (zoneName == (char *)NULL) { 1101 echo(MSG_PKGREMOVE_UPDINF_GZ); 1102 } else { 1103 echo(MSG_PKGREMOVE_UPDINF_LZ, zoneName); 1104 } 1105 1106 if (delmap(1, pkginst) != 0) { 1107 progerr(ERR_DB_QUERY, pkginst); 1108 quit(99); 1109 } 1110 1111 if (!warnflag && !failflag) { 1112 if (pt = getenv("PREDEPEND")) 1113 predepend(pt); 1114 (void) chdir("/"); 1115 if (rrmdir(pkgloc)) 1116 warnflag++; 1117 } 1118 1119 if ((z_running_in_global_zone() == B_TRUE) && 1120 (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE)) { 1121 boolean_t b; 1122 1123 b = pkgRemovePackageFromGzonlyList(get_inst_root(), pkginst); 1124 if (b == B_FALSE) { 1125 progerr(ERR_PKGREMOVE_GZONLY_REMOVE, pkginst); 1126 ckreturn(1, NULL); 1127 } 1128 } 1129 1130 /* release the generic package lock */ 1131 1132 (void) unlockinst(); 1133 1134 quit(0); 1135 /* LINTED: no return */ 1136 } 1137 1138 int 1139 issymlink(char *path) 1140 { 1141 struct stat statbuf; 1142 1143 /* 1144 * Obtain status of path; if symbolic link get link's status 1145 */ 1146 1147 if (lstat(path, &statbuf) != 0) { 1148 return (1); /* not symlink */ 1149 } 1150 1151 /* 1152 * Status obtained - if symbolic link, return 0 1153 */ 1154 1155 if ((statbuf.st_mode & S_IFMT) == S_IFLNK) { 1156 return (0); /* is a symlink */ 1157 } 1158 1159 /* 1160 * Not a symbolic link - return 1 1161 */ 1162 1163 return (1); /* not symlink */ 1164 } 1165 1166 static void 1167 rmclass(char *aclass, int rm_remote, char *a_zoneName) 1168 { 1169 struct cfent *ept; 1170 FILE *fp; 1171 char tmpfile[PATH_MAX]; 1172 char script[PATH_MAX]; 1173 int i; 1174 char *tmp_path; 1175 char *save_path = NULL; 1176 struct stat st; 1177 1178 if (aclass == NULL) { 1179 for (i = 0; i < eptnum; i++) { 1180 if (eptlist[i] != NULL) { 1181 rmclass(eptlist[i]->pkg_class, 1182 rm_remote, a_zoneName); 1183 } 1184 } 1185 return; 1186 } 1187 1188 /* locate class action script to execute */ 1189 (void) snprintf(script, sizeof (script), "%s/r.%s", pkgbin, aclass); 1190 if (access(script, F_OK) != 0) { 1191 (void) snprintf(script, sizeof (script), "%s/r.%s", 1192 PKGSCR, aclass); 1193 if (access(script, F_OK) != 0) 1194 script[0] = '\0'; 1195 } 1196 if (script[0] != '\0') { 1197 int td; 1198 1199 (void) snprintf(tmpfile, sizeof (tmpfile), "%s/RMLISTXXXXXX", 1200 tmpdir); 1201 td = mkstemp(tmpfile); 1202 if (td == -1) { 1203 progerr(ERR_TMPFILE); 1204 quit(99); 1205 } 1206 if ((fp = fdopen(td, "w")) == NULL) { 1207 progerr(ERR_WTMPFILE, tmpfile); 1208 quit(99); 1209 } 1210 } 1211 1212 if (a_zoneName == (char *)NULL) { 1213 echo(MSG_PKGREMOVE_REMPATHCLASS_GZ, aclass); 1214 } else { 1215 echo(MSG_PKGREMOVE_REMPATHCLASS_LZ, aclass, a_zoneName); 1216 } 1217 1218 /* process paths in reverse order */ 1219 i = eptnum; 1220 while (--i >= 0) { 1221 ept = eptlist[i]; 1222 1223 if ((ept == NULL) || strcmp(aclass, ept->pkg_class)) { 1224 continue; 1225 } 1226 1227 /* save the path, and prepend the ir */ 1228 if (is_an_inst_root()) { 1229 save_path = ept->path; 1230 tmp_path = fixpath(ept->path); 1231 ept->path = tmp_path; 1232 } 1233 1234 if (!ept->ftype || (ept->ftype == '^' && !script[0])) { 1235 /* 1236 * A path owned by more than one package is marked with 1237 * a NULL ftype (seems odd, but that's how it's 1238 * done). Such files are sacro sanct. Shared editable 1239 * files are a special case, and are marked with an 1240 * ftype of '^'. These files should only be ignored if 1241 * no class action script is present. It is the CAS's 1242 * responsibility to not remove the editable object. 1243 */ 1244 echo(MSG_SHARED, ept->path); 1245 } else if (ept->pinfo->status == SERVED_FILE && !rm_remote) { 1246 /* 1247 * If the path is provided to the client from a 1248 * server, don't remove anything unless explicitly 1249 * requested through the "-f" option. 1250 */ 1251 echo(MSG_SERVER, ept->path); 1252 } else if (z_path_is_inherited(ept->path, ept->ftype, 1253 get_inst_root())) { 1254 /* 1255 * object is in an area inherited from the global zone, 1256 * and the object cannot be removed - output a message 1257 * indicating the object cannot be removed and continue. 1258 */ 1259 echo(MSG_NOTREMOVED_INHERITED, ept->path); 1260 } else if (script[0]) { 1261 /* 1262 * If there's a class action script, just put the 1263 * path name into the list. 1264 */ 1265 (void) fprintf(fp, "%s\n", ept->path); 1266 } else if (strchr("dx", ept->ftype) != NULL || 1267 (lstat(ept->path, &st) == 0 && S_ISDIR(st.st_mode))) { 1268 /* Directories are rmdir()'d. */ 1269 1270 if (rmdir(ept->path)) { 1271 if (errno == EBUSY) { 1272 echo(MSG_DIRBUSY, ept->path); 1273 } else if (errno == EEXIST) { 1274 echo(MSG_NOTEMPTY, ept->path); 1275 } else if (errno != ENOENT) { 1276 progerr(ERR_RMDIR, ept->path); 1277 warnflag++; 1278 } 1279 } else { 1280 if (ept->pinfo->status == SERVED_FILE) { 1281 echo(MSG_RMSRVR, ept->path); 1282 } else { 1283 echo("%s", ept->path); 1284 } 1285 } 1286 1287 } else { 1288 /* 1289 * Before removing this object one more 1290 * check should be done to assure that a 1291 * shared object is not removed. 1292 * This can happen if the original object 1293 * was incorrectly updated with the 1294 * incorrect class identifier. 1295 * This handles pathologcal cases that 1296 * weren't handled above. 1297 */ 1298 if (ept->npkgs > 1) { 1299 echo(MSG_SHARED, ept->path); 1300 continue; 1301 } 1302 1303 /* Regular files are unlink()'d. */ 1304 1305 if (unlink(ept->path)) { 1306 if (errno != ENOENT) { 1307 progerr(ERR_RMPATH, ept->path); 1308 warnflag++; 1309 } 1310 } else { 1311 if (ept->pinfo->status == SERVED_FILE) { 1312 echo(MSG_RMSRVR, ept->path); 1313 } else { 1314 echo("%s", ept->path); 1315 } 1316 } 1317 } 1318 1319 /* restore the original path */ 1320 1321 if (is_an_inst_root()) { 1322 ept->path = save_path; 1323 } 1324 1325 /* 1326 * free memory allocated for this entry memory used for 1327 * pathnames will be freed later by a call to pathdup() 1328 */ 1329 1330 if (eptlist[i]) { 1331 free(eptlist[i]); 1332 } 1333 eptlist[i] = NULL; 1334 } 1335 if (script[0]) { 1336 (void) fclose(fp); 1337 set_ulimit(script, ERR_CASFAIL); 1338 if (pkgverbose) 1339 ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER, 1340 CAS_GRP, SHELL, "-x", script, NULL), 1341 ERR_CASFAIL); 1342 else 1343 ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER, 1344 CAS_GRP, SHELL, script, NULL), 1345 ERR_CASFAIL); 1346 clr_ulimit(); 1347 if (isfile(NULL, tmpfile) == 0) { 1348 if (unlink(tmpfile) == -1) 1349 progerr(ERR_RMPATH, tmpfile); 1350 } 1351 } 1352 } 1353 1354 static void 1355 ckreturn(int retcode, char *msg) 1356 { 1357 switch (retcode) { 1358 case 2: 1359 case 12: 1360 case 22: 1361 warnflag++; 1362 /*FALLTHRU*/ 1363 if (msg) 1364 progerr(msg); 1365 case 10: 1366 case 20: 1367 if (retcode >= 10) 1368 dreboot++; 1369 if (retcode >= 20) 1370 ireboot++; 1371 /*FALLTHRU*/ 1372 case 0: 1373 break; /* okay */ 1374 1375 case -1: 1376 retcode = 99; 1377 /*FALLTHRU*/ 1378 case 99: 1379 case 1: 1380 case 11: 1381 case 21: 1382 case 4: 1383 case 14: 1384 case 24: 1385 case 5: 1386 case 15: 1387 case 25: 1388 if (msg) 1389 progerr(msg); 1390 /*FALLTHRU*/ 1391 case 3: 1392 case 13: 1393 case 23: 1394 quit(retcode); 1395 /* NOT REACHED */ 1396 default: 1397 if (msg) 1398 progerr(msg); 1399 quit(1); 1400 } 1401 } 1402 1403 static void 1404 usage(void) 1405 { 1406 (void) fprintf(stderr, ERR_USAGE_PKGREMOVE); 1407 1408 exit(1); 1409 } 1410 1411 /* 1412 * Name: path_valid 1413 * Description: Checks a string for being a valid path 1414 * 1415 * Arguments: path - path to validate 1416 * 1417 * Returns : B_TRUE - success, B_FALSE otherwise. 1418 * B_FALSE means path was null, too long (>PATH_MAX), 1419 * or too short (<1) 1420 */ 1421 static boolean_t 1422 path_valid(char *path) 1423 { 1424 if (path == NULL) { 1425 return (B_FALSE); 1426 } else if (strlen(path) > PATH_MAX) { 1427 return (B_FALSE); 1428 } else if (strlen(path) >= 1) { 1429 return (B_TRUE); 1430 } else { 1431 /* path < 1 */ 1432 return (B_FALSE); 1433 } 1434 } 1435