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