1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <string.h> 33 #include <locale.h> 34 #include <libintl.h> 35 #include <dirent.h> 36 #include <pkgstrct.h> 37 #include <pkgdev.h> 38 #include <pkglocs.h> 39 #include <archives.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <sys/stat.h> 43 #include <sys/param.h> 44 #include <stdlib.h> 45 #include <unistd.h> 46 #include <assert.h> 47 #include <wait.h> 48 49 /* 50 * libinstzones includes 51 */ 52 53 #include <instzones_api.h> 54 55 /* 56 * consolidation pkg command library includes 57 */ 58 59 #include <pkglib.h> 60 #include <pkgweb.h> 61 62 /* 63 * local pkg command library includes 64 */ 65 66 #include <install.h> 67 #include <libinst.h> 68 #include <libadm.h> 69 #include <dryrun.h> 70 #include <messages.h> 71 72 /* 73 * pkginstall local includes 74 */ 75 76 #include "pkginstall.h" 77 78 extern int pkgverbose; 79 extern fsblkcnt_t pkgmap_blks; /* main.c */ 80 81 extern struct pkgdev pkgdev; 82 83 extern char tmpdir[]; 84 extern char pkgbin[]; 85 extern char instdir[]; 86 extern char saveSpoolInstallDir[]; 87 extern char *pkginst; 88 89 extern int dbchg; 90 extern int nosetuid; 91 extern int nocnflct; 92 extern int warnflag; 93 94 #define DMRG_DONE -1 95 96 #define ck_efile(s, p) \ 97 ((p->cinfo.modtime >= 0) && \ 98 p->ainfo.local && \ 99 cverify(0, &p->ftype, s, &p->cinfo, 1)) 100 101 static int eocflag; 102 103 /* 104 * The variable below indicates that fix_attributes() will be inadequate 105 * because a replacement was permitted. 106 */ 107 static int repl_permitted = 0; 108 109 static int domerg(struct cfextra **extlist, int part, int nparts, 110 int myclass, char **srcp, char **dstp, 111 char **r_updated, char **r_skipped, 112 char **r_anyPathLocal); 113 static void endofclass(struct cfextra **extlist, int myclass, 114 int ckflag, PKGserver server, VFP_T **a_cfTmpVfp); 115 static int fix_attributes(struct cfextra **, int); 116 static int dir_is_populated(char *dirpath); 117 static boolean_t absolutepath(char *path); 118 static boolean_t parametricpath(char *path, char **relocpath); 119 120 /* Used to keep track of the entries in extlist that are regular files. */ 121 struct reg_files { 122 struct reg_files *next; 123 int val; 124 }; 125 static struct reg_files *regfiles_head = NULL; 126 127 /* 128 * This is the function that actually installs one volume (usually that's 129 * all there is). Upon entry, the extlist is entirely correct: 130 * 131 * 1. It contains only those files which are to be installed 132 * from all volumes. 133 * 2. The mode bits in the ainfo structure for each file are set 134 * correctly in accordance with administrative defaults. 135 * 3. mstat.setuid/setgid reflect what the status *was* before 136 * pkgdbmerg() processed compliance. 137 */ 138 void 139 instvol(struct cfextra **extlist, char *srcinst, int part, 140 int nparts, PKGserver pkgserver, VFP_T **a_cfTmpVfp, 141 char **r_updated, char **r_skipped, 142 char *a_zoneName) 143 { 144 FILE *listfp; 145 char *updated = (char *)NULL; 146 char *skipped = (char *)NULL; 147 char *anyPathLocal = (char *)NULL; 148 char *relocpath = (char *)NULL; 149 char *dstp; 150 char *listfile; 151 char *srcp; 152 char *pspool_loc; 153 char scrpt_dst[PATH_MAX]; 154 int count; 155 int entryidx; /* array of current package objects */ 156 int n; 157 int nc = 0; 158 int pass; /* pass count through the for loop. */ 159 int tcount; 160 struct cfent *ept; 161 struct cfextra *ext; 162 struct mergstat *mstat; 163 struct reg_files *rfp = NULL; 164 165 /* 166 * r_updated and r_skipped are optional parameters that can be passed in 167 * by the caller if the caller wants to know if any objects are either 168 * updated or skipped. Do not initialize either r_updated or r_skipped; 169 * the call to instvol could be cumulative and any previous update or 170 * skipped indication must not be disturbed - these flags are only set, 171 * they must never be reset. These flags are "char *" pointers so that 172 * the object that was skipped or updated can be displayed in debugging 173 * output. 174 */ 175 176 if (part == 1) { 177 pkgvolume(&pkgdev, srcinst, part, nparts); 178 } 179 180 tcount = 0; 181 nc = cl_getn(); 182 183 /* 184 * For each class in this volume, install those files. 185 * 186 * NOTE : This loop index may be decremented by code below forcing a 187 * second trip through for the same class. This happens only when a 188 * class is split between an archive and the tree. Examples would be 189 * old WOS packages and the occasional class containing dynamic 190 * libraries which require special treatment. 191 */ 192 193 if (is_depend_pkginfo_DB() == B_FALSE) { 194 int classidx; /* the current class */ 195 196 for (classidx = 0; classidx < nc; classidx++) { 197 int pass_relative = 0; 198 int rel_init = 0; 199 200 eocflag = count = pass = 0; 201 listfp = (FILE *)0; 202 listfile = NULL; 203 204 /* Now what do we pass to the class action script */ 205 206 if (cl_pthrel(classidx) == REL_2_CAS) { 207 pass_relative = 1; 208 } 209 210 for (;;) { 211 if (!tcount++) { 212 /* first file to install */ 213 if (a_zoneName == (char *)NULL) { 214 echo(MSG_INS_N_N, part, nparts); 215 } else { 216 echo(MSG_INS_N_N_LZ, part, nparts, 217 a_zoneName); 218 } 219 } 220 221 /* 222 * If there's an install class action script and no 223 * list file has been created yet, create that file 224 * and provide the pointer in listfp. 225 */ 226 if (cl_iscript(classidx) && !listfp) { 227 /* create list file */ 228 putparam("TMPDIR", tmpdir); 229 listfile = tempnam(tmpdir, "list"); 230 if ((listfp = fopen(listfile, "w")) == NULL) { 231 progerr(ERR_WTMPFILE, listfile); 232 quit(99); 233 } 234 } 235 236 /* 237 * The following function goes through the package 238 * object list returning the array index of the next 239 * regular file. If it encounters a directory, 240 * symlink, named pipe or device, it just creates it. 241 */ 242 243 entryidx = domerg(extlist, (pass++ ? 0 : part), nparts, 244 classidx, &srcp, &dstp, &updated, &skipped, 245 &anyPathLocal); 246 247 /* Evaluate the return code */ 248 if (entryidx == DMRG_DONE) { 249 /* 250 * Set ept to the first entry in extlist 251 * which is guaranteed to exist so 252 * later checks against ept->ftype are 253 * not compared to NULL. 254 */ 255 ext = extlist[0]; 256 ept = &(ext->cf_ent); 257 break; /* no more entries to process */ 258 } 259 260 ext = extlist[entryidx]; 261 ept = &(ext->cf_ent); 262 mstat = &(ext->mstat); 263 264 /* 265 * If not installing from a partially spooled package 266 * (the "save/pspool" area), and the file contents can 267 * be changed (type is 'e' or 'v'), and the class is not 268 * "none": copy the file from the package (in pristine 269 * state with no actions performed) into the appropriate 270 * location in the packages destination "save/pspool" 271 * area. 272 */ 273 274 if ((!is_partial_inst()) && 275 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 276 (strcmp(ept->pkg_class, "none") != 0)) { 277 278 if (absolutepath(ext->map_path) == B_TRUE && 279 parametricpath(ext->cf_ent.ainfo.local, 280 &relocpath) == B_FALSE) { 281 pspool_loc = ROOT; 282 } else { 283 pspool_loc = RELOC; 284 } 285 286 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 287 saveSpoolInstallDir, pspool_loc, 288 relocpath ? relocpath : ext->map_path); 289 290 if (n >= PATH_MAX) { 291 progerr(ERR_CREATE_PATH_2, 292 saveSpoolInstallDir, 293 ext->map_path); 294 quit(99); 295 } 296 297 /* copy, preserve source file mode */ 298 299 if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) { 300 warnflag++; 301 } 302 } 303 304 /* 305 * If this isn't writeable anyway, it's not going 306 * into the list file. Only count it if it's going 307 * into the list file. 308 */ 309 if (is_fs_writeable(ext->cf_ent.path, 310 &(ext->fsys_value))) 311 count++; 312 313 pkgvolume(&pkgdev, srcinst, part, nparts); 314 315 /* 316 * If source verification is OK for this class, make 317 * sure the source we're passing to the class action 318 * script is useable. 319 */ 320 if (cl_svfy(classidx) != NOVERIFY) { 321 if (cl_iscript(classidx) || 322 ((ept->ftype == 'e') || 323 (ept->ftype == 'n'))) { 324 if (ck_efile(srcp, ept)) { 325 progerr(ERR_CORRUPT, 326 srcp); 327 logerr(getErrbufAddr()); 328 warnflag++; 329 continue; 330 } 331 } 332 } 333 334 /* 335 * If there's a class action script for this class, 336 * just collect names in a temporary file 337 * that will be used as the stdin when the 338 * class action script is invoked. 339 */ 340 341 if ((cl_iscript(classidx)) && 342 ((is_fs_writeable(ept->path, 343 &(ext->fsys_value))))) { 344 if (pass_relative) { 345 if (!rel_init) { 346 (void) fputs(instdir, listfp); 347 (void) putc('\n', listfp); 348 rel_init++; 349 } 350 (void) fputs(ext->map_path, listfp); 351 (void) putc('\n', listfp); 352 } else { 353 (void) fputs(srcp ? 354 srcp : "/dev/null", listfp); 355 (void) putc(' ', listfp); 356 (void) fputs(dstp, listfp); 357 (void) putc('\n', listfp); 358 } 359 /* 360 * Note which entries in extlist are regular 361 * files to be installed via the class action 362 * script. 363 */ 364 if (regfiles_head == NULL) { 365 assert(rfp == NULL); 366 regfiles_head = 367 malloc(sizeof (struct reg_files)); 368 if (regfiles_head == NULL) { 369 progerr(ERR_MEMORY, errno); 370 quit(99); 371 } 372 regfiles_head->next = NULL; 373 regfiles_head->val = entryidx; 374 rfp = regfiles_head; 375 } else { 376 assert(rfp != NULL); 377 rfp->next = 378 malloc(sizeof (struct reg_files)); 379 if (rfp->next == NULL) { 380 progerr(ERR_MEMORY, errno); 381 quit(99); 382 } 383 rfp = rfp->next; 384 rfp->next = NULL; 385 rfp->val = entryidx; 386 } 387 388 /* 389 * A warning message about unwritable targets 390 * in a class may be appropriate here. 391 */ 392 continue; 393 } 394 395 /* 396 * If not installing from a partially spooled package 397 * (the "save/pspool" area), and the file contents can 398 * be changed (type is 'e' or 'v') and the class 399 * identifier is not "none": copy the file from the 400 * package (in pristine state with no actions performed) 401 * into the appropriate location in the packages 402 * destination "save/pspool" area. 403 */ 404 405 if ((!is_partial_inst()) && 406 ((ept->ftype == 'e') || (ept->ftype == 'v') && 407 (strcmp(ept->pkg_class, "none") != 0))) { 408 409 if (absolutepath(ext->map_path) == B_TRUE && 410 parametricpath(ext->cf_ent.ainfo.local, 411 &relocpath) == B_FALSE) { 412 pspool_loc = ROOT; 413 } else { 414 pspool_loc = RELOC; 415 } 416 417 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 418 saveSpoolInstallDir, pspool_loc, 419 relocpath ? relocpath : ext->map_path); 420 421 if (n >= PATH_MAX) { 422 progerr(ERR_CREATE_PATH_2, 423 saveSpoolInstallDir, 424 ext->map_path); 425 quit(99); 426 } 427 428 /* copy, preserve source file mode */ 429 430 if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) { 431 warnflag++; 432 } 433 } 434 435 /* 436 * There are several tests here to determine 437 * how we're going to deal with objects 438 * intended for remote read-only filesystems. 439 * We don't use is_served() because this may be 440 * a server. We're actually interested in if 441 * it's *really* remote and *really* not 442 * writeable. 443 */ 444 445 n = is_remote_fs(ept->path, &(ext->fsys_value)); 446 if ((n != 0) && 447 !is_fs_writeable(ept->path, 448 &(ext->fsys_value))) { 449 450 /* 451 * Don't change the file, we can't write 452 * to it anyway. 453 */ 454 455 mstat->attrchg = 0; 456 mstat->contchg = 0; 457 458 /* 459 * If it's currently mounted, we can 460 * at least test it for existence. 461 */ 462 463 if (is_mounted(ept->path, &(ext->fsys_value))) { 464 if (!isfile(NULL, dstp)) { 465 echo(MSG_IS_PRESENT, dstp); 466 } else { 467 echo(WRN_INSTVOL_NONE, dstp); 468 } 469 } else { 470 char *server_host; 471 472 server_host = get_server_host( 473 ext->fsys_value); 474 475 /* If not, we're just stuck. */ 476 echo(WRN_INSTVOL_NOVERIFY, 477 dstp, server_host); 478 } 479 480 continue; 481 } 482 483 /* echo output destination name */ 484 485 echo("%s", dstp); 486 487 /* 488 * if no source then no need to copy/verify 489 */ 490 491 if (srcp == (char *)NULL) { 492 continue; 493 } 494 495 /* 496 * If doing a partial installation (creating a 497 * non-global zone), extra steps need to be taken: 498 * 499 * 1) if the file is not type 'e' and not type 'v' and 500 * the class is "none": then the file must already 501 * exist (as a result of the initial non-global zone 502 * installation which caused all non-e/v files to be 503 * copied from the global zone to the non-global 504 * zone). If this is the case, verify that the file 505 * exists and has the correct attributes. 506 * 507 * 2) if the file is not type 'e' and not type 'v' 508 * and the class is NOT "none", *OR* if the file is 509 * type 'e' or type 'v': then check to see if the 510 * file is located in an area inherited from the 511 * global zone. If so, then there is no ability to 512 * change the file since inherited file systems are 513 * "read only" - just verify that the file exists and 514 * verify attributes only if not 'e' or 'v'. 515 */ 516 517 if (is_partial_inst() != 0) { 518 519 /* 520 * determine if the destination package is in an 521 * area inherited from the global zone 522 */ 523 524 n = pkgMatchInherited(srcp, dstp, 525 get_inst_root(), ept->ainfo.mode, 526 ept->cinfo.modtime, ept->ftype, 527 ept->cinfo.cksum); 528 529 echoDebug(DBG_INSTVOL_PARTIAL_INST, 530 srcp ? srcp : "", dstp ? dstp: "", 531 ((get_inst_root()) && 532 (strcmp(get_inst_root(), "/") != 0)) ? 533 get_inst_root() : "", 534 ept->ainfo.mode, ept->cinfo.modtime, 535 ept->ftype, ept->cinfo.cksum, n); 536 537 /* 538 * if not type 'e|v' and class 'none', then the 539 * file must already exist. 540 */ 541 542 if ((ept->ftype != 'e') && 543 (ept->ftype != 'v') && 544 (strcmp(cl_nam(ept->pkg_class_idx), 545 "none") == 0)) { 546 547 /* 548 * if the file is in a space inherited 549 * from the global zone, and if the 550 * contents or attributes are incorrect, 551 * then generate a warning that the 552 * global zone file contents and/or file 553 * attributes have been modified and 554 * that the modifications are extended 555 * to the non-global zone (inherited 556 * from the global zone). 557 */ 558 559 if (n == 0) { 560 /* is file changed? */ 561 n = finalck(ept, 1, 1, B_TRUE); 562 563 /* no - ok - continue */ 564 if (n == 0) { 565 continue; 566 } 567 568 /* output warning message */ 569 logerr(NOTE_INSTVOL_FINALCKFAIL, 570 pkginst, ext->map_path, 571 a_zoneName, ept->path); 572 continue; 573 } else if (!finalck(ept, 1, 1, 574 B_FALSE)) { 575 /* 576 * non-e/v file of class "none" 577 * not inherited from the global 578 * zone: verify file already 579 * exists:everything checks here 580 */ 581 mstat->attrchg = 0; 582 mstat->contchg = 0; 583 } 584 continue; 585 } 586 587 /* 588 * non-e/v file with class action script, or 589 * e/v file: if the file is in an area inherited 590 * from the global zone, then no need (or the 591 * ability) to update just accept the file as is 592 */ 593 594 if (n == B_TRUE) { 595 /* 596 * the object is in an area inherited 597 * from the global zone and the objects 598 * attributes are verified 599 */ 600 601 mstat->attrchg = 0; 602 mstat->contchg = 0; 603 604 /* NOTE: package object skipped */ 605 606 if (skipped == (char *)NULL) { 607 skipped = dstp; 608 echoDebug(DBG_INSTVOL_OBJ_SKIPPED, 609 skipped); 610 } 611 continue; 612 } 613 } 614 615 /* 616 * Copy from source media to target path and fix file 617 * mode and permission now in case installation halted. 618 */ 619 620 if (z_path_is_inherited(dstp, ept->ftype, 621 get_inst_root()) == B_FALSE) { 622 623 /* 624 * If the filesystem is read-only don't attempt 625 * to copy a file. Just check that the content 626 * and attributes of the file are correct. 627 * 628 * Normally this doesn't happen, because files, 629 * which don't change, are not returned by 630 * domerg(). However when installing a patch in 631 * a sparse zone, which was already installed 632 * in global zone with -G option, NGZ's 633 * contents db still contains the old record 634 * for this file and therefore domerg() 635 * considers these files to be different even 636 * though they are the same. 637 */ 638 n = 0; 639 if (is_fs_writeable(ept->path, 640 &(ext->fsys_value))) 641 n = cppath(MODE_SET|DIR_DISPLAY, srcp, 642 dstp, ept->ainfo.mode); 643 644 if (n != 0) { 645 warnflag++; 646 } else if (!finalck(ept, 1, 1, B_FALSE)) { 647 /* 648 * everything checks here 649 */ 650 mstat->attrchg = 0; 651 mstat->contchg = 0; 652 } 653 } 654 655 /* NOTE: a package object was updated */ 656 657 if (updated == (char *)NULL) { 658 echoDebug(DBG_INSTVOL_OBJ_UPDATED, dstp); 659 updated = dstp; 660 } 661 } 662 663 /* 664 * We have now completed processing of all pathnames 665 * associated with this volume and class. 666 */ 667 if (cl_iscript(classidx)) { 668 /* 669 * Execute appropriate class action script 670 * with list of source/destination pathnames 671 * as the input to the script. 672 */ 673 674 if (chdir(pkgbin)) { 675 progerr(ERR_CHGDIR, pkgbin); 676 quit(99); 677 } 678 679 if (listfp) { 680 (void) fclose(listfp); 681 } 682 683 /* 684 * if the object associated with the class action script 685 * is in an area inherited from the global zone, then 686 * there is no need to run the class action script - 687 * assume that anything the script would do has already 688 * been done in the area shared from the global zone. 689 */ 690 691 /* nothing updated, nothing skipped */ 692 693 echoDebug(DBG_INSTVOL_CAS_INFO, is_partial_inst(), 694 updated ? updated : "", 695 skipped ? skipped : "", 696 anyPathLocal ? anyPathLocal : ""); 697 698 if ((is_partial_inst() != 0) && 699 (updated == (char *)NULL) && 700 (anyPathLocal == (char *)NULL)) { 701 702 /* 703 * installing in non-global zone, and no object 704 * has been updated (installed/verified in non- 705 * inherited area), and no path delivered by the 706 * package is in an area not inherited from the 707 * global zone (all paths delivered are in 708 * areas inherited from the global zone): do not 709 * run the class action script because the only 710 * affected areas are inherited (read only). 711 */ 712 713 echoDebug(DBG_INSTVOL_NOT_RUNNING_CAS, 714 a_zoneName ? a_zoneName : "?", 715 eocflag ? "ENDOFCLASS" : 716 cl_iscript(classidx), 717 cl_nam(classidx), 718 cl_iscript(classidx)); 719 720 if ((r_skipped != (char **)NULL) && 721 (*r_skipped == (char *)NULL) && 722 (skipped == (char *)NULL)) { 723 skipped = "postinstall"; 724 echoDebug(DBG_INSTVOL_OBJ_SKIPPED, 725 skipped); 726 } 727 } else { 728 /* run the class action script */ 729 730 echoDebug(DBG_INSTVOL_RUNNING_CAS, 731 a_zoneName ? a_zoneName : "?", 732 eocflag ? "ENDOFCLASS" : 733 cl_iscript(classidx), 734 cl_nam(classidx), 735 cl_iscript(classidx)); 736 737 /* Use ULIMIT if supplied. */ 738 set_ulimit(cl_iscript(classidx), ERR_CASFAIL); 739 740 if (eocflag) { 741 /* 742 * end of class detected. 743 * Since there are no more volumes which 744 * contain pathnames associated with 745 * this class, execute class action 746 * script with the ENDOFCLASS argument; 747 * we do this even if none of the path 748 * names associated with this class and 749 * volume needed installation to 750 * guarantee the class action script is 751 * executed at least once during package 752 * installation. 753 */ 754 if (pkgverbose) { 755 n = pkgexecl((listfp ? 756 listfile : CAS_STDIN), 757 CAS_STDOUT, 758 CAS_USER, CAS_GRP, 759 SHELL, "-x", 760 cl_iscript(classidx), 761 "ENDOFCLASS", NULL); 762 } else { 763 n = pkgexecl( 764 (listfp ? 765 listfile : CAS_STDIN), 766 CAS_STDOUT, CAS_USER, 767 CAS_GRP, SHELL, 768 cl_iscript(classidx), 769 "ENDOFCLASS", NULL); 770 } 771 ckreturn(n, ERR_CASFAIL); 772 } else if (count) { 773 /* execute class action script */ 774 if (pkgverbose) { 775 n = pkgexecl(listfile, 776 CAS_STDOUT, CAS_USER, 777 CAS_GRP, SHELL, "-x", 778 cl_iscript(classidx), 779 NULL); 780 } else { 781 n = pkgexecl(listfile, 782 CAS_STDOUT, CAS_USER, 783 CAS_GRP, SHELL, 784 cl_iscript(classidx), 785 NULL); 786 } 787 ckreturn(n, ERR_CASFAIL); 788 } 789 790 /* 791 * Ensure the mod times on disk match those 792 * in the pkgmap. In this case, call cverify 793 * with checksumming disabled, since the only 794 * action that needs to be done is to verify 795 * that the attributes are correct. 796 */ 797 798 if ((rfp = regfiles_head) != NULL) { 799 while (rfp != NULL) { 800 ept = &(extlist[rfp->val]->cf_ent); 801 cverify(1, &ept->ftype, ept->path, 802 &ept->cinfo, 0); 803 rfp = rfp->next; 804 } 805 regfiles_free(); 806 } 807 808 clr_ulimit(); 809 810 if ((r_updated != (char **)NULL) && 811 (*r_updated == (char *)NULL) && 812 (updated == (char *)NULL)) { 813 updated = "postinstall"; 814 echoDebug(DBG_INSTVOL_OBJ_UPDATED, 815 updated); 816 } 817 } 818 if (listfile) { 819 (void) remove(listfile); 820 } 821 } 822 823 if (eocflag && (!is_partial_inst() || (is_partial_inst() && 824 strcmp(cl_nam(classidx), "none") != 0))) { 825 if (cl_dvfy(classidx) == QKVERIFY && !repl_permitted) { 826 /* 827 * The quick verify just fixes everything. 828 * If it returns 0, all is well. If it 829 * returns 1, then the class installation 830 * was incomplete and we retry on the 831 * stuff that failed in the conventional 832 * way (without a CAS). this is primarily 833 * to accomodate old archives such as are 834 * found in pre-2.5 WOS; but, it is also 835 * used when a critical dynamic library 836 * is not archived with its class. 837 */ 838 if (!fix_attributes(extlist, classidx)) { 839 /* 840 * Reset the CAS pointer. If the 841 * function returns 0 then there 842 * was no script there in the first 843 * place and we'll just have to 844 * call this a miss. 845 */ 846 if (cl_deliscript(classidx)) 847 /* 848 * Decrement classidx for 849 * next pass. 850 */ 851 classidx--; 852 } 853 } else { 854 /* 855 * Finalize merge. This checks to make sure 856 * file attributes are correct and any links 857 * specified are created. 858 */ 859 (void) endofclass(extlist, classidx, 860 (cl_iscript(classidx) ? 0 : 1), 861 pkgserver, a_cfTmpVfp); 862 } 863 } 864 } 865 } 866 867 /* 868 * Instead of creating links back to the GZ files the logic is 869 * to let zdo recreate the files from the GZ then invoke pkgadd to 870 * install the editable files and skip over any 'f'type files. 871 * The commented out block is to create the links which should be 872 * removed once the current code is tested to be correct. 873 */ 874 875 /* 876 * Go through extlist creating links for 'f'type files 877 * if we're in a global zone. Note that this code lies 878 * here instead of in the main loop to support CAF packages. 879 * In a CAF package the files are installed by the i.none script 880 * and don't exist until all files are done being processed, thus 881 * the additional loop through extlist. 882 */ 883 884 /* 885 * output appropriate completion message 886 */ 887 888 if (is_depend_pkginfo_DB() == B_TRUE) { 889 /* updating database only (hollow package) */ 890 if (a_zoneName == (char *)NULL) { 891 echo(MSG_DBUPD_N_N, part, nparts); 892 } else { 893 echo(MSG_DBUPD_N_N_LZ, part, nparts, a_zoneName); 894 } 895 } else if (tcount == 0) { 896 /* updating package (non-hollow package) */ 897 if (a_zoneName == (char *)NULL) { 898 echo(MSG_INST_N_N, part, nparts); 899 } else { 900 echo(MSG_INST_N_N_LZ, part, nparts, a_zoneName); 901 } 902 } 903 904 /* 905 * if any package objects were updated (not inherited from the 906 * global zone or otherwise already in existence), set the updated 907 * flag as appropriate 908 */ 909 910 if (updated != (char *)NULL) { 911 echoDebug(DBG_INSTVOL_OBJ_UPDATED, updated); 912 if (r_updated != (char **)NULL) { 913 *r_updated = updated; 914 } 915 } 916 917 /* 918 * if any package objects were skipped (verified inherited from the 919 * global zone), set the skipped flag as appropriate 920 */ 921 922 if (skipped != (char *)NULL) { 923 echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped); 924 if (r_skipped != (char **)NULL) { 925 *r_skipped = skipped; 926 } 927 } 928 } 929 930 /* 931 * Name: domerg 932 * Description: For the specified class, review each entry and return the array 933 * index number of the next regular file to process. Hard links are 934 * skipped (they are created in endofclass() and directories, 935 * symlinks, pipes and devices are created here, as well as any 936 * file that already exists and has the correct attributes. 937 * Arguments: struct cfextra **extlist - [RO, *RW] 938 * - Pointer to list of cfextra structures representing 939 * the pkgmap of the package to be installed 940 * int part - [RO, *RO] 941 * - the part of the package currently being processed; 942 * packages begin with part "1" and proceed for the 943 * number (nparts) that comprise the package (volume). 944 * int nparts - [RO, *RO] 945 * - the number of parts the package is divided into 946 * int myclass - [RO, *RO] 947 * - index into class array of the current class 948 * char **srcp - [RW, *RW] 949 * - pointer to pointer to string representing the source 950 * path for the next package to process - if this 951 * function returns != DMRG_DONE then this pointer is 952 * set to a pointer to a string representing the source 953 * path for the next object from the package to process 954 * char **dstp - [RW, *RW] 955 * - pointer to pointer to string representing the target 956 * path for the next package to process - if this 957 * function returns != DMRG_DONE then this pointer is 958 * set to a pointer to a string representing the target 959 * path for the next object from the package to process 960 * char **r_updated - [RO, *RW] 961 * - pointer to pointer to string - set if the last path 962 * returned exists or does not need updating and the 963 * object is NOT located in an area inherited from the 964 * global zone. This is used to determine if the last 965 * path object returned DOES exist in an area that is 966 * inherited from the global zone. If no paths are 967 * inherited from the global zone, this is always set 968 * when a path to be installed exists and has the 969 * correct contents. 970 * char **r_skipped - [RO, *RW] 971 * - pointer to pointer to string - set if the last path 972 * returned exists or does not need updating and the 973 * object IS located in an area inherited from the 974 * global zone. This is used to determine if the last 975 * path object returned does NOT exist in an area that 976 * is inherited from the global zone. If no paths are 977 * inherited from the global zone, this is never set. 978 * char **r_anyPathLocal - [RO, *RW] 979 * - pointer to pointer to string - set if any object 980 * belonging to the package is NOT located in an area 981 * inherited from the global zone. This is used to 982 * determine if the package references ANY objects that 983 * are NOT located in an area inherited from the global 984 * zone - regardless of whether or not they need to be 985 * updated (installed/copied). If no paths are inherited 986 * from the global zone, this is always set when a path 987 * to be installed already exists and has the correct 988 * contents. 989 * Returns: int 990 * != DMRG_DONE - index into extlist of the next path to 991 * be processed - that needs to be installed/copied 992 * == DMRG_DONE - all entries processed 993 */ 994 995 static int 996 domerg(struct cfextra **extlist, int part, int nparts, 997 int myclass, char **srcp, char **dstp, 998 char **r_updated, char **r_skipped, 999 char **r_anyPathLocal) 1000 { 1001 boolean_t stateFlag = B_FALSE; 1002 int i; 1003 int msg_ugid; 1004 static int maxvol = 0; 1005 static int svindx = 0; 1006 static int svpart = 0; 1007 struct cfent *ept = (struct cfent *)NULL; 1008 struct mergstat *mstat = (struct mergstat *)NULL; 1009 1010 /* reset returned path pointers */ 1011 1012 *dstp = (char *)NULL; 1013 *srcp = (char *)NULL; 1014 1015 /* set to start or continue based on which part being processed */ 1016 1017 if (part != 0) { 1018 maxvol = 0; 1019 svindx = 0; 1020 svpart = part; 1021 } else { 1022 i = svindx; 1023 part = svpart; 1024 } 1025 1026 /* 1027 * This goes through the pkgmap entries one by one testing them 1028 * for inclusion in the package database as well as for validity 1029 * against existing files. 1030 */ 1031 for (i = svindx; extlist[i]; i++) { 1032 ept = &(extlist[i]->cf_ent); 1033 mstat = &(extlist[i]->mstat); 1034 1035 /* 1036 * as paths are processed, if the "anyPathLocal" flag has not 1037 * been set, if the object is not of type 'i' (package script), 1038 * check to see if the object is in an area inherited from the 1039 * global zone - if not, set "anyPathLocal" to the path found, 1040 * indicating that at least one path is in an area that is not 1041 * inherited from the global zone. 1042 */ 1043 1044 if ((r_anyPathLocal != (char **)NULL) && 1045 (*r_anyPathLocal == (char *)NULL) && 1046 (ept->ftype != 'i') && 1047 (z_path_is_inherited(ept->path, ept->ftype, 1048 get_inst_root()) == B_FALSE)) { 1049 echoDebug(DBG_INSTVOL_OBJ_LOCAL, ept->path); 1050 *r_anyPathLocal = ept->path; 1051 } 1052 1053 /* if this isn't the class of current interest, skip it */ 1054 1055 if (myclass != ept->pkg_class_idx) { 1056 continue; 1057 } 1058 1059 /* if the class is invalid, announce it & exit */ 1060 if (ept->pkg_class_idx == -1) { 1061 progerr(ERR_CLIDX, ept->pkg_class_idx, 1062 (ept->path && *ept->path) ? ept->path : "unknown"); 1063 logerr(gettext("pathname=%s"), 1064 (ept->path && *ept->path) ? ept->path : "unknown"); 1065 logerr(gettext("class=<%s>"), 1066 (ept->pkg_class && *ept->pkg_class) ? 1067 ept->pkg_class : "Unknown"); 1068 logerr(gettext("CLASSES=<%s>"), 1069 getenv("CLASSES") ? getenv("CLASSES") : "Not Set"); 1070 quit(99); 1071 } 1072 1073 /* 1074 * Next check to see if we are going to try to delete a 1075 * populated directory in some distressing way. 1076 */ 1077 if (mstat->dir2nondir) 1078 if (dir_is_populated(ept->path)) { 1079 logerr(WRN_INSTVOL_NOTDIR, ept->path); 1080 warnflag++; 1081 mstat->denied = 1; /* install denied! */ 1082 continue; 1083 } else { /* Replace is OK. */ 1084 /* 1085 * Remove this directory, so it won't 1086 * interfere with creation of the new object. 1087 */ 1088 if (rmdir(ept->path)) { 1089 /* 1090 * If it didn't work, there's nothing 1091 * we can do. To continue would 1092 * likely corrupt the filesystem 1093 * which is unacceptable. 1094 */ 1095 progerr(ERR_RMDIR, ept->path); 1096 quit(99); 1097 } 1098 1099 repl_permitted = 1; /* flag it */ 1100 } 1101 1102 /* adjust the max volume number appropriately */ 1103 1104 if (ept->volno > maxvol) { 1105 maxvol = ept->volno; 1106 } 1107 1108 /* if this part goes into another volume, skip it */ 1109 1110 if (part != ept->volno) { 1111 continue; 1112 } 1113 1114 /* 1115 * If it's a conflicting file and it's not supposed to be 1116 * installed, note it and skip. 1117 */ 1118 if (nocnflct && mstat->shared && ept->ftype != 'e') { 1119 if (mstat->contchg || mstat->attrchg) { 1120 echo(MSG_SHIGN, ept->path); 1121 } 1122 continue; 1123 } 1124 1125 /* 1126 * If we want to set uid or gid but user says no, note it. 1127 * Remember that the actual mode bits in the structure have 1128 * already been adjusted and the mstat flag is telling us 1129 * about the original mode. 1130 */ 1131 if (nosetuid && (mstat->setuid || mstat->setgid)) { 1132 msg_ugid = 1; /* don't repeat attribute message. */ 1133 if (is_fs_writeable(ept->path, 1134 &(extlist[i]->fsys_value))) { 1135 if (!(mstat->contchg) && mstat->attrchg) { 1136 echo(MSG_UGMOD, ept->path); 1137 } else { 1138 echo(MSG_UGID, ept->path); 1139 } 1140 } 1141 } else { 1142 msg_ugid = 0; 1143 } 1144 1145 switch (ept->ftype) { 1146 case 'l': /* hard link */ 1147 /* links treated as object "update/skip" */ 1148 stateFlag = B_TRUE; 1149 continue; /* defer to final proc */ 1150 1151 case 's': /* for symlink, verify without fix first */ 1152 /* links treated as object "update/skip" */ 1153 stateFlag = B_TRUE; 1154 1155 /* Do this only for default verify */ 1156 if (cl_dvfy(myclass) == DEFAULT) { 1157 if (averify(0, &ept->ftype, 1158 ept->path, &ept->ainfo)) 1159 echo(MSG_SLINK, ept->path); 1160 } 1161 1162 /*FALLTHRU*/ 1163 1164 case 'd': /* directory */ 1165 case 'x': /* exclusive directory */ 1166 case 'c': /* character special device */ 1167 case 'b': /* block special device */ 1168 case 'p': /* named pipe */ 1169 /* these NOT treated as object "update/skip" */ 1170 stateFlag = B_FALSE; 1171 1172 /* 1173 * If we can't get to it for legitimate reasons, 1174 * don't try to verify it. 1175 */ 1176 if ((z_path_is_inherited(ept->path, ept->ftype, 1177 get_inst_root())) || 1178 is_remote_fs(ept->path, 1179 &(extlist[i]->fsys_value)) && 1180 !is_fs_writeable(ept->path, 1181 &(extlist[i]->fsys_value))) { 1182 mstat->attrchg = 0; 1183 mstat->contchg = 0; 1184 break; 1185 } 1186 1187 if (averify(1, &ept->ftype, ept->path, 1188 &ept->ainfo) == 0) { 1189 mstat->contchg = mstat->attrchg = 0; 1190 } else { 1191 progerr(ERR_CREATE_PKGOBJ, ept->path); 1192 logerr(getErrbufAddr()); 1193 warnflag++; 1194 } 1195 1196 break; 1197 1198 case 'i': /* information file */ 1199 /* not treated as object "update/skip" */ 1200 stateFlag = B_FALSE; 1201 break; 1202 1203 default: 1204 /* all files treated as object "update/skip" */ 1205 stateFlag = B_TRUE; 1206 break; 1207 } 1208 1209 /* 1210 * Both contchg and shared flags have to be taken into 1211 * account. contchg is set if the file is already present 1212 * in the package database, if it does not exist or if it 1213 * exists and is modified. 1214 * The shared flag is set when 'e' or 'v' file is not 1215 * present in the package database, exists and is not 1216 * modified. It also has to be checked here. 1217 * Shared flag is also set when file is present in package 1218 * database and owned by more than one package, but for 1219 * this case contchg has already been set. 1220 */ 1221 if (mstat->contchg || (mstat->shared && 1222 ((ept->ftype == 'e') || (ept->ftype == 'v')))) { 1223 *dstp = ept->path; 1224 if ((ept->ftype == 'f') || (ept->ftype == 'e') || 1225 (ept->ftype == 'v')) { 1226 *srcp = ept->ainfo.local; 1227 if (is_partial_inst() != 0) { 1228 if (*srcp[0] == '~') { 1229 /* Done only for C style */ 1230 char *tmp_ptr; 1231 tmp_ptr = extlist[i]->map_path; 1232 if (ept->ftype != 'f') { 1233 /* 1234 * translate source 1235 * pathname 1236 */ 1237 *srcp = 1238 srcpath(instdir, 1239 tmp_ptr, 1240 part, 1241 nparts); 1242 } else { 1243 /* 1244 * instdir has the absolute path 1245 * to saveSpoolInstallDir for 1246 * the package. This is only 1247 * useful for 'e','v' types. 1248 * 1249 * For 'f', we generate the 1250 * absolute src path with the 1251 * help of install root and the 1252 * basedir. 1253 */ 1254 *srcp = trans_srcp_pi( 1255 ept->ainfo.local); 1256 } 1257 } else { 1258 *srcp = extlist[i]->map_path; 1259 } 1260 } else { 1261 if (*srcp[0] == '~') { 1262 /* translate source pathname */ 1263 *srcp = srcpath(instdir, 1264 &(ept->ainfo.local[1]), 1265 part, nparts); 1266 } 1267 } 1268 1269 echoDebug(DBG_DOMERG_NO_SUCH_FILE, 1270 ept->ftype, cl_nam(ept->pkg_class_idx), 1271 ept->path); 1272 } else { 1273 /* 1274 * At this point, we're returning a non-file 1275 * that couldn't be created in the standard 1276 * way. If it refers to a filesystem that is 1277 * not writeable by us, don't waste the 1278 * calling process's time. 1279 */ 1280 if (!is_fs_writeable(ept->path, 1281 &(extlist[i]->fsys_value))) { 1282 echoDebug(DBG_DOMERG_NOT_WRITABLE, 1283 ept->ftype, 1284 cl_nam(ept->pkg_class_idx), 1285 ept->path); 1286 continue; 1287 } 1288 1289 *srcp = NULL; 1290 echoDebug(DBG_DOMERG_NOT_THERE, 1291 ept->ftype, cl_nam(ept->pkg_class_idx), 1292 ept->path); 1293 } 1294 1295 svindx = i+1; 1296 backup(*dstp, 1); 1297 return (i); 1298 } 1299 1300 if (mstat->attrchg) { 1301 backup(ept->path, 0); 1302 if (!msg_ugid) 1303 echo(MSG_ATTRIB, ept->path); 1304 1305 /* fix the attributes now for robustness sake */ 1306 if (averify(1, &ept->ftype, 1307 ept->path, 1308 &ept->ainfo) == 0) { 1309 mstat->attrchg = 0; 1310 } 1311 } 1312 1313 /* 1314 * package object exists, or does not need updating: if the path 1315 * is in an area inherited from the global zone, then treat 1316 * the object as if it were "skipped" - if the path is not in an 1317 * area inherited from the global zone, then treat the object as 1318 * if it were "updated" 1319 */ 1320 1321 /* LINTED warning: statement has no consequent: if */ 1322 if ((stateFlag == B_FALSE) || (ept == (struct cfent *)NULL)) { 1323 /* 1324 * the object in question is a directory or special 1325 * file - the fact that this type of object already 1326 * exists or does not need updating must not trigger 1327 * the object updated/object skipped indication - 1328 * that would cause class action scripts to be run 1329 * when installing a new non-global zone - that action 1330 * must only be done when a file object that is in 1331 * an area inherited from the global zone is present. 1332 */ 1333 } else if (z_path_is_inherited(ept->path, ept->ftype, 1334 get_inst_root()) == B_TRUE) { 1335 if (r_skipped != (char **)NULL) { 1336 if (*r_skipped == (char *)NULL) { 1337 echoDebug(DBG_INSTVOL_OBJ_SKIPPED, 1338 ept->path); 1339 *r_skipped = ept->path; 1340 } 1341 } 1342 } else { 1343 if (r_updated != (char **)NULL) { 1344 if (*r_updated == (char *)NULL) { 1345 echoDebug(DBG_INSTVOL_OBJ_UPDATED, 1346 ept->path); 1347 } 1348 *r_updated = ept->path; 1349 } 1350 } 1351 } 1352 1353 if (maxvol == part) { 1354 eocflag++; /* endofclass */ 1355 } 1356 1357 return (DMRG_DONE); /* no remaining entries on this volume */ 1358 } 1359 1360 /* 1361 * Determine if the provided directory is populated. Return 0 if so and 1 if 1362 * not. This also returns 0 if the dirpath is not a directory or if it does 1363 * not exist. 1364 */ 1365 static int 1366 dir_is_populated(char *dirpath) { 1367 DIR *dirfp; 1368 struct dirent *drp; 1369 int retcode = 0; 1370 1371 if ((dirfp = opendir(dirpath)) != NULL) { 1372 while ((drp = readdir(dirfp)) != NULL) { 1373 if (strcmp(drp->d_name, ".") == 0) { 1374 continue; 1375 } 1376 if (strcmp(drp->d_name, "..") == 0) { 1377 continue; 1378 } 1379 /* 1380 * If we get here, there's a real file in the 1381 * directory 1382 */ 1383 retcode = 1; 1384 break; 1385 } 1386 (void) closedir(dirfp); 1387 } 1388 1389 return (retcode); 1390 } 1391 1392 /* 1393 * This is the function that cleans up the installation of this class. 1394 * This is where hard links get put in since the stuff they're linking 1395 * probably exists by now. 1396 */ 1397 static void 1398 endofclass(struct cfextra **extlist, int myclass, int ckflag, 1399 PKGserver pkgserver, VFP_T **a_cfTmpVfp) 1400 { 1401 char *temppath; 1402 char *pspool_loc; 1403 char *relocpath = (char *)NULL; 1404 char scrpt_dst[PATH_MAX]; 1405 int flag; 1406 int idx; 1407 int n; 1408 struct cfent *ept; /* entry from the internal list */ 1409 struct cfextra entry; /* entry from the package database */ 1410 struct mergstat *mstat; /* merge status */ 1411 struct pinfo *pinfo; 1412 1413 /* open the package database (contents) file */ 1414 1415 if (!ocfile(&pkgserver, a_cfTmpVfp, pkgmap_blks)) { 1416 quit(99); 1417 } 1418 1419 echo(MSG_VERIFYING_CLASS, cl_nam(myclass)); 1420 1421 for (idx = 0; /* void */; idx++) { 1422 /* find next package object in this class */ 1423 while (extlist[idx]) { 1424 if ((extlist[idx]->cf_ent.ftype != 'i') && 1425 extlist[idx]->cf_ent.pkg_class_idx == myclass) { 1426 break; 1427 } 1428 idx++; 1429 } 1430 1431 if (extlist[idx] == NULL) 1432 break; 1433 1434 1435 ept = &(extlist[idx]->cf_ent); 1436 mstat = &(extlist[idx]->mstat); 1437 1438 temppath = extlist[idx]->client_path; 1439 1440 /* 1441 * At this point the only difference between the entry 1442 * in the contents file and the entry in extlist[] is 1443 * that the status indicator contains CONFIRM_CONT. 1444 * This function should return one or something is wrong. 1445 */ 1446 1447 n = srchcfile(&(entry.cf_ent), temppath, pkgserver); 1448 1449 if (n < 0) { 1450 char *errstr = getErrstr(); 1451 progerr(ERR_CFBAD); 1452 logerr(gettext("pathname=%s"), 1453 entry.cf_ent.path && *entry.cf_ent.path ? 1454 entry.cf_ent.path : "Unknown"); 1455 logerr(gettext("problem=%s"), 1456 (errstr && *errstr) ? errstr : "Unknown"); 1457 quit(99); 1458 } else if (n != 1) { 1459 /* 1460 * Check if path should be in the package 1461 * database. 1462 */ 1463 if ((mstat->shared && nocnflct)) { 1464 continue; 1465 } 1466 progerr(ERR_CFMISSING, ept->path); 1467 quit(99); 1468 } 1469 1470 /* 1471 * If merge was not appropriate for this object, now is the 1472 * time to choose one or the other. 1473 */ 1474 if (mstat->denied) { 1475 /* 1476 * If installation was denied AFTER the package 1477 * database was updated, skip this. We've already 1478 * announced the discrepancy and the verifications 1479 * that follow will make faulty decisions based on 1480 * the ftype, which may not be correct. 1481 */ 1482 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1483 warnflag++; 1484 } else { 1485 if (mstat->replace) 1486 /* 1487 * This replaces the old entry with the new 1488 * one. This should never happen in the new 1489 * DB since the entries are already identical. 1490 */ 1491 repl_cfent(ept, &(entry.cf_ent)); 1492 1493 /* 1494 * Validate this entry and change the status flag in 1495 * the package database. 1496 */ 1497 if (ept->ftype == RM_RDY) { 1498 (void) eptstat(&(entry.cf_ent), pkginst, 1499 STAT_NEXT); 1500 } else { 1501 /* check the hard link now. */ 1502 if (ept->ftype == 'l') { 1503 if (averify(0, &ept->ftype, 1504 ept->path, &ept->ainfo)) { 1505 echo(MSG_HRDLINK, 1506 ept->path); 1507 mstat->attrchg++; 1508 } 1509 } 1510 1511 /* 1512 * Don't install or verify objects for 1513 * remote, read-only filesystems. We need 1514 * only flag them as shared from some server. 1515 * Otherwise, ok to do final check. 1516 */ 1517 if (is_remote_fs(ept->path, 1518 &(extlist[idx]->fsys_value)) && 1519 !is_fs_writeable(ept->path, 1520 &(extlist[idx]->fsys_value))) { 1521 flag = -1; 1522 } else { 1523 boolean_t inheritedFlag; 1524 inheritedFlag = 1525 z_path_is_inherited(ept->path, 1526 ept->ftype, get_inst_root()); 1527 flag = finalck(ept, mstat->attrchg, 1528 (ckflag ? mstat->contchg : 1529 (-1)), inheritedFlag); 1530 } 1531 1532 pinfo = entry.cf_ent.pinfo; 1533 1534 /* Find this package in the list. */ 1535 while (pinfo) { 1536 if (strcmp(pkginst, pinfo->pkg) == 0) { 1537 break; 1538 } 1539 pinfo = pinfo->next; 1540 } 1541 1542 /* 1543 * If this package owns this file, then store 1544 * it in the database with the appropriate 1545 * status. Need to check pinfo in case it 1546 * points to NULL which could happen if 1547 * pinfo->next = NULL above. 1548 */ 1549 if (pinfo) { 1550 if (flag < 0 || is_served(ept->path, 1551 &(extlist[idx]->fsys_value))) { 1552 /* 1553 * This is provided to 1554 * clients by a server. 1555 */ 1556 pinfo->status = SERVED_FILE; 1557 } else { 1558 /* 1559 * It's either there or it's 1560 * not. 1561 */ 1562 pinfo->status = (flag ? 1563 NOT_FND : ENTRY_OK); 1564 } 1565 } 1566 } 1567 } 1568 1569 /* 1570 * If not installing from a partially spooled package, the 1571 * "save/pspool" area, and the file contents can be 1572 * changed (type is 'e' or 'v'), and the class IS "none": 1573 * copy the installed volatile file into the appropriate 1574 * location in the packages destination "save/pspool" area. 1575 */ 1576 1577 if ((!is_partial_inst()) && 1578 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1579 (strcmp(ept->pkg_class, "none") == 0)) { 1580 1581 if (absolutepath(extlist[idx]->map_path) == B_TRUE && 1582 parametricpath(extlist[idx]->cf_ent.ainfo.local, 1583 &relocpath) == B_FALSE) { 1584 pspool_loc = ROOT; 1585 } else { 1586 pspool_loc = RELOC; 1587 } 1588 1589 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1590 saveSpoolInstallDir, pspool_loc, 1591 relocpath ? relocpath : extlist[idx]->map_path); 1592 1593 if (n >= PATH_MAX) { 1594 progerr(ERR_CREATE_PATH_2, 1595 saveSpoolInstallDir, 1596 extlist[idx]->map_path); 1597 quit(99); 1598 } 1599 1600 /* copy, preserve source file mode */ 1601 1602 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1603 warnflag++; 1604 } 1605 } 1606 1607 /* 1608 * Now insert this potentially changed package database 1609 * entry. 1610 */ 1611 if (entry.cf_ent.npkgs) { 1612 if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) { 1613 quit(99); 1614 } 1615 } 1616 } 1617 1618 n = swapcfile(pkgserver, a_cfTmpVfp, pkginst, dbchg); 1619 if (n == RESULT_WRN) { 1620 warnflag++; 1621 } else if (n == RESULT_ERR) { 1622 quit(99); 1623 } 1624 } 1625 1626 /* 1627 * This function goes through and fixes all the attributes. This is called 1628 * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary 1629 * use for this is to fix up files installed by a class action script 1630 * which is time-critical and reliable enough to assume likely success. 1631 * The first such format was for WOS compressed-cpio'd file sets. 1632 * The second format is the Class Archive Format. 1633 */ 1634 static int 1635 fix_attributes(struct cfextra **extlist, int idx) 1636 { 1637 struct cfextra *ext; 1638 int i, retval = 1; 1639 int nc = cl_getn(); 1640 int n; 1641 struct cfent *ept; 1642 struct mergstat *mstat; 1643 char scrpt_dst[PATH_MAX]; 1644 char *pspool_loc; 1645 char *relocpath = (char *)NULL; 1646 1647 for (i = 0; extlist[i]; i++) { 1648 ext = extlist[i]; 1649 ept = &(extlist[i]->cf_ent); 1650 mstat = &(extlist[i]->mstat); 1651 1652 /* 1653 * We don't care about 'i'nfo files because, they 1654 * aren't laid down, 'e'ditable files can change 1655 * anyway, so who cares and 's'ymlinks were already 1656 * fixed in domerg(); however, certain old WOS 1657 * package symlinks depend on a bug in the old 1658 * pkgadd which has recently been expunged. For 1659 * those packages in 2.2, we repeat the verification 1660 * of symlinks. 1661 * 1662 * By 2.6 or so, ftype == 's' should be added to this. 1663 */ 1664 if (ept->ftype == 'i' || ept->ftype == 'e' || 1665 (mstat->shared && nocnflct)) 1666 continue; 1667 1668 if (mstat->denied) { 1669 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1670 warnflag++; 1671 continue; 1672 } 1673 1674 if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) { 1675 progerr(ERR_CLIDX, ept->pkg_class_idx, 1676 (ept->path && *ept->path) ? ept->path : "unknown"); 1677 continue; 1678 } 1679 1680 /* If this is the right class, do the fast verify. */ 1681 if (ept->pkg_class_idx == idx) { 1682 if (fverify(1, &ept->ftype, ept->path, 1683 &ept->ainfo, &ept->cinfo) == 0) { 1684 mstat->attrchg = 0; 1685 mstat->contchg = 0; 1686 } else /* We'll try full verify later */ 1687 retval = 0; 1688 } 1689 /* 1690 * Need to copy the installed volitale file back to the 1691 * partial spooled area if we are installing to a local zone 1692 * or similar installation method. 1693 */ 1694 1695 if ((!is_partial_inst()) && 1696 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1697 (strcmp(ept->pkg_class, "none") == 0)) { 1698 1699 if (absolutepath(ext->map_path) == B_TRUE && 1700 parametricpath(ext->cf_ent.ainfo.local, 1701 &relocpath) == B_FALSE) { 1702 pspool_loc = ROOT; 1703 } else { 1704 pspool_loc = RELOC; 1705 } 1706 1707 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1708 saveSpoolInstallDir, pspool_loc, 1709 relocpath ? relocpath : ext->map_path); 1710 1711 if (n >= PATH_MAX) { 1712 progerr(ERR_CREATE_PATH_2, 1713 saveSpoolInstallDir, 1714 ext->map_path); 1715 quit(99); 1716 } 1717 1718 /* copy, preserve source file mode */ 1719 1720 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1721 warnflag++; 1722 } 1723 } 1724 } 1725 1726 return (retval); 1727 } 1728 1729 /* 1730 * Check to see if first charcter in path is a '/'. 1731 * 1732 * Return: 1733 * B_TRUE - if path is prepended with '/' 1734 * B_FALSE - if not 1735 */ 1736 static boolean_t 1737 absolutepath(char *path) 1738 { 1739 assert(path != NULL); 1740 assert(path[0] != '\0'); 1741 1742 return (path[0] == '/' ? B_TRUE : B_FALSE); 1743 } 1744 1745 /* 1746 * Check to see if path contains a '$' which makes it 1747 * a parametric path and therefore relocatable. 1748 * 1749 * Parameters: 1750 * path - The path to determine if it is absolute 1751 * relocpath - The value of the unconditioned path 1752 * i.e. $OPTDIR/usr/ls 1753 * Return: 1754 * B_TRUE - if path is a parametric path 1755 * B_FALSE - if not 1756 */ 1757 static boolean_t 1758 parametricpath(char *path, char **relocpath) 1759 { 1760 assert(path != NULL); 1761 assert(path[0] != '\0'); 1762 1763 /* 1764 * If this is a valid parametric path then a '$' MUST occur at the 1765 * first or second character. 1766 */ 1767 1768 if (path[0] == '$' || path[1] == '$') { 1769 /* 1770 * If a parametric path exists then when copying the 1771 * path to the pspool directoy from the installing 1772 * pkgs reloc directory we want to use the uncononditional 1773 * varaiable path. 1774 */ 1775 *relocpath = (path + 1); 1776 return (B_TRUE); 1777 } 1778 return (B_FALSE); 1779 } 1780 1781 void 1782 regfiles_free() 1783 { 1784 if (regfiles_head != NULL) { 1785 struct reg_files *rfp = regfiles_head->next; 1786 1787 while (rfp != NULL) { 1788 free(regfiles_head); 1789 regfiles_head = rfp; 1790 rfp = regfiles_head->next; 1791 } 1792 free(regfiles_head); 1793 regfiles_head = NULL; 1794 } 1795 } 1796