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