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