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