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