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, VFP_T **a_cfVfp, 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, VFP_T **a_cfVfp, 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 a_cfVfp, 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\n"), 1064 (ept->path && *ept->path) ? ept->path : "unknown"); 1065 logerr(gettext("class=<%s>\n"), 1066 (ept->pkg_class && *ept->pkg_class) ? 1067 ept->pkg_class : "Unknown"); 1068 logerr(gettext("CLASSES=<%s>\n"), 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 /* translate source pathname */ 1230 *srcp = srcpath(instdir, 1231 extlist[i]->map_path, 1232 part, nparts); 1233 } else { 1234 *srcp = extlist[i]->map_path; 1235 } 1236 } else { 1237 if (*srcp[0] == '~') { 1238 /* translate source pathname */ 1239 *srcp = srcpath(instdir, 1240 &(ept->ainfo.local[1]), 1241 part, nparts); 1242 } 1243 } 1244 1245 echoDebug(DBG_DOMERG_NO_SUCH_FILE, 1246 ept->ftype, cl_nam(ept->pkg_class_idx), 1247 ept->path); 1248 } else { 1249 /* 1250 * At this point, we're returning a non-file 1251 * that couldn't be created in the standard 1252 * way. If it refers to a filesystem that is 1253 * not writeable by us, don't waste the 1254 * calling process's time. 1255 */ 1256 if (!is_fs_writeable(ept->path, 1257 &(extlist[i]->fsys_value))) { 1258 echoDebug(DBG_DOMERG_NOT_WRITABLE, 1259 ept->ftype, 1260 cl_nam(ept->pkg_class_idx), 1261 ept->path); 1262 continue; 1263 } 1264 1265 *srcp = NULL; 1266 echoDebug(DBG_DOMERG_NOT_THERE, 1267 ept->ftype, cl_nam(ept->pkg_class_idx), 1268 ept->path); 1269 } 1270 1271 svindx = i+1; 1272 backup(*dstp, 1); 1273 return (i); 1274 } 1275 1276 if (mstat->attrchg) { 1277 backup(ept->path, 0); 1278 if (!msg_ugid) 1279 echo(MSG_ATTRIB, ept->path); 1280 1281 /* fix the attributes now for robustness sake */ 1282 if (averify(1, &ept->ftype, 1283 ept->path, 1284 &ept->ainfo) == 0) { 1285 mstat->attrchg = 0; 1286 } 1287 } 1288 1289 /* 1290 * package object exists, or does not need updating: if the path 1291 * is in an area inherited from the global zone, then treat 1292 * the object as if it were "skipped" - if the path is not in an 1293 * area inherited from the global zone, then treat the object as 1294 * if it were "updated" 1295 */ 1296 1297 /* LINTED warning: statement has no consequent: if */ 1298 if ((stateFlag == B_FALSE) || (ept == (struct cfent *)NULL)) { 1299 /* 1300 * the object in question is a directory or special 1301 * file - the fact that this type of object already 1302 * exists or does not need updating must not trigger 1303 * the object updated/object skipped indication - 1304 * that would cause class action scripts to be run 1305 * when installing a new non-global zone - that action 1306 * must only be done when a file object that is in 1307 * an area inherited from the global zone is present. 1308 */ 1309 } else if (z_path_is_inherited(ept->path, ept->ftype, 1310 get_inst_root()) == B_TRUE) { 1311 if (r_skipped != (char **)NULL) { 1312 if (*r_skipped == (char *)NULL) { 1313 echoDebug(DBG_INSTVOL_OBJ_SKIPPED, 1314 ept->path); 1315 *r_skipped = ept->path; 1316 } 1317 } 1318 } else { 1319 if (r_updated != (char **)NULL) { 1320 if (*r_updated == (char *)NULL) { 1321 echoDebug(DBG_INSTVOL_OBJ_UPDATED, 1322 ept->path); 1323 } 1324 *r_updated = ept->path; 1325 } 1326 } 1327 } 1328 1329 if (maxvol == part) { 1330 eocflag++; /* endofclass */ 1331 } 1332 1333 return (DMRG_DONE); /* no remaining entries on this volume */ 1334 } 1335 1336 /* 1337 * Determine if the provided directory is populated. Return 0 if so and 1 if 1338 * not. This also returns 0 if the dirpath is not a directory or if it does 1339 * not exist. 1340 */ 1341 static int 1342 dir_is_populated(char *dirpath) { 1343 DIR *dirfp; 1344 struct dirent *drp; 1345 int retcode = 0; 1346 1347 if ((dirfp = opendir(dirpath)) != NULL) { 1348 while ((drp = readdir(dirfp)) != NULL) { 1349 if (strcmp(drp->d_name, ".") == 0) { 1350 continue; 1351 } 1352 if (strcmp(drp->d_name, "..") == 0) { 1353 continue; 1354 } 1355 /* 1356 * If we get here, there's a real file in the 1357 * directory 1358 */ 1359 retcode = 1; 1360 break; 1361 } 1362 (void) closedir(dirfp); 1363 } 1364 1365 return (retcode); 1366 } 1367 1368 /* 1369 * This is the function that cleans up the installation of this class. 1370 * This is where hard links get put in since the stuff they're linking 1371 * probably exists by now. 1372 */ 1373 static void 1374 endofclass(struct cfextra **extlist, int myclass, int ckflag, 1375 VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp) 1376 { 1377 char *temppath; 1378 char *pspool_loc; 1379 char *relocpath = (char *)NULL; 1380 char scrpt_dst[PATH_MAX]; 1381 int flag; 1382 int idx; 1383 int n; 1384 struct cfent *ept; /* entry from the internal list */ 1385 struct cfextra entry; /* entry from the package database */ 1386 struct mergstat *mstat; /* merge status */ 1387 struct pinfo *pinfo; 1388 1389 /* open the package database (contents) file */ 1390 1391 if (!ocfile(a_cfVfp, a_cfTmpVfp, pkgmap_blks)) { 1392 quit(99); 1393 } 1394 1395 echo(MSG_VERIFYING_CLASS, cl_nam(myclass)); 1396 1397 for (idx = 0; /* void */; idx++) { 1398 /* find next package object in this class */ 1399 while (extlist[idx]) { 1400 if ((extlist[idx]->cf_ent.ftype != 'i') && 1401 extlist[idx]->cf_ent.pkg_class_idx == myclass) { 1402 break; 1403 } 1404 idx++; 1405 } 1406 1407 if (extlist[idx] == NULL) { 1408 /* finish copying contents file and exit loop */ 1409 (void) srchcfile(&(entry.cf_ent), NULL, 1410 *a_cfVfp, *a_cfTmpVfp); 1411 break; 1412 } 1413 1414 ept = &(extlist[idx]->cf_ent); 1415 mstat = &(extlist[idx]->mstat); 1416 1417 temppath = 1418 extlist[idx] ? extlist[idx]->client_path : 1419 NULL; 1420 1421 /* 1422 * At this point the only difference between the entry 1423 * in the contents file and the entry in extlist[] is 1424 * that the status indicator contains CONFIRM_CONT. 1425 * So for the new DB we use this knowledge and just 1426 * verify everything in accordance with extlist without 1427 * trying to retrieve the entry from the DB. 1428 */ 1429 1430 n = srchcfile(&(entry.cf_ent), 1431 (ept ? temppath : NULL), *a_cfVfp, *a_cfTmpVfp); 1432 1433 if (n == 0) { 1434 break; 1435 } else if (n < 0) { 1436 char *errstr = getErrstr(); 1437 progerr(ERR_CFBAD); 1438 logerr(gettext("pathname=%s\n"), 1439 entry.cf_ent.path && *entry.cf_ent.path ? 1440 entry.cf_ent.path : "Unknown"); 1441 logerr(gettext("problem=%s\n"), 1442 (errstr && *errstr) ? errstr : "Unknown"); 1443 quit(99); 1444 } else if (n != 1) { 1445 /* 1446 * Check if path should be in the package 1447 * database. 1448 */ 1449 if ((mstat->shared && nocnflct)) { 1450 continue; 1451 } 1452 progerr(ERR_CFMISSING, ept->path); 1453 quit(99); 1454 } 1455 1456 /* 1457 * If merge was not appropriate for this object, now is the 1458 * time to choose one or the other. 1459 */ 1460 if (mstat->denied) { 1461 /* 1462 * If installation was denied AFTER the package 1463 * database was updated, skip this. We've already 1464 * announced the discrepancy and the verifications 1465 * that follow will make faulty decisions based on 1466 * the ftype, which may not be correct. 1467 */ 1468 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1469 warnflag++; 1470 } else { 1471 if (mstat->replace) 1472 /* 1473 * This replaces the old entry with the new 1474 * one. This should never happen in the new 1475 * DB since the entries are already identical. 1476 */ 1477 repl_cfent(ept, &(entry.cf_ent)); 1478 1479 /* 1480 * Validate this entry and change the status flag in 1481 * the package database. 1482 */ 1483 if (ept->ftype == RM_RDY) { 1484 (void) eptstat(&(entry.cf_ent), pkginst, 1485 STAT_NEXT); 1486 } else { 1487 /* check the hard link now. */ 1488 if (ept->ftype == 'l') { 1489 if (averify(0, &ept->ftype, 1490 ept->path, &ept->ainfo)) { 1491 echo(MSG_HRDLINK, 1492 ept->path); 1493 mstat->attrchg++; 1494 } 1495 } 1496 1497 /* 1498 * Don't install or verify objects for 1499 * remote, read-only filesystems. We need 1500 * only flag them as shared from some server. 1501 * Otherwise, ok to do final check. 1502 */ 1503 if (is_remote_fs(ept->path, 1504 &(extlist[idx]->fsys_value)) && 1505 !is_fs_writeable(ept->path, 1506 &(extlist[idx]->fsys_value))) { 1507 flag = -1; 1508 } else { 1509 boolean_t inheritedFlag; 1510 inheritedFlag = 1511 z_path_is_inherited(ept->path, 1512 ept->ftype, get_inst_root()); 1513 flag = finalck(ept, mstat->attrchg, 1514 (ckflag ? mstat->contchg : 1515 (-1)), inheritedFlag); 1516 } 1517 1518 pinfo = entry.cf_ent.pinfo; 1519 1520 /* Find this package in the list. */ 1521 while (pinfo) { 1522 if (strcmp(pkginst, pinfo->pkg) == 0) { 1523 break; 1524 } 1525 pinfo = pinfo->next; 1526 } 1527 1528 /* 1529 * If this package owns this file, then store 1530 * it in the database with the appropriate 1531 * status. Need to check pinfo in case it 1532 * points to NULL which could happen if 1533 * pinfo->next = NULL above. 1534 */ 1535 if (pinfo) { 1536 if (flag < 0 || is_served(ept->path, 1537 &(extlist[idx]->fsys_value))) { 1538 /* 1539 * This is provided to 1540 * clients by a server. 1541 */ 1542 pinfo->status = SERVED_FILE; 1543 } else { 1544 /* 1545 * It's either there or it's 1546 * not. 1547 */ 1548 pinfo->status = (flag ? 1549 NOT_FND : ENTRY_OK); 1550 } 1551 } 1552 } 1553 } 1554 1555 /* 1556 * If not installing from a partially spooled package, the 1557 * "save/pspool" area, and the file contents can be 1558 * changed (type is 'e' or 'v'), and the class IS "none": 1559 * copy the installed volatile file into the appropriate 1560 * location in the packages destination "save/pspool" area. 1561 */ 1562 1563 if ((!is_partial_inst()) && 1564 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1565 (strcmp(ept->pkg_class, "none") == 0)) { 1566 1567 if (absolutepath(extlist[idx]->map_path) == B_TRUE && 1568 parametricpath(extlist[idx]->cf_ent.ainfo.local, 1569 &relocpath) == B_FALSE) { 1570 pspool_loc = ROOT; 1571 } else { 1572 pspool_loc = RELOC; 1573 } 1574 1575 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1576 saveSpoolInstallDir, pspool_loc, 1577 relocpath ? relocpath : extlist[idx]->map_path); 1578 1579 if (n >= PATH_MAX) { 1580 progerr(ERR_CREATE_PATH_2, 1581 saveSpoolInstallDir, 1582 extlist[idx]->map_path); 1583 quit(99); 1584 } 1585 1586 /* copy, preserve source file mode */ 1587 1588 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1589 warnflag++; 1590 } 1591 } 1592 1593 /* 1594 * Now insert this potentially changed package database 1595 * entry. 1596 */ 1597 if (entry.cf_ent.npkgs) { 1598 if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) { 1599 quit(99); 1600 } 1601 } 1602 } 1603 1604 n = swapcfile(a_cfVfp, a_cfTmpVfp, pkginst, dbchg); 1605 if (n == RESULT_WRN) { 1606 warnflag++; 1607 } else if (n == RESULT_ERR) { 1608 quit(99); 1609 } 1610 } 1611 1612 /* 1613 * This function goes through and fixes all the attributes. This is called 1614 * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary 1615 * use for this is to fix up files installed by a class action script 1616 * which is time-critical and reliable enough to assume likely success. 1617 * The first such format was for WOS compressed-cpio'd file sets. 1618 * The second format is the Class Archive Format. 1619 */ 1620 static int 1621 fix_attributes(struct cfextra **extlist, int idx) 1622 { 1623 struct cfextra *ext; 1624 int i, retval = 1; 1625 int nc = cl_getn(); 1626 int n; 1627 struct cfent *ept; 1628 struct mergstat *mstat; 1629 char scrpt_dst[PATH_MAX]; 1630 char *pspool_loc; 1631 char *relocpath = (char *)NULL; 1632 1633 for (i = 0; extlist[i]; i++) { 1634 ext = extlist[i]; 1635 ept = &(extlist[i]->cf_ent); 1636 mstat = &(extlist[i]->mstat); 1637 1638 /* 1639 * We don't care about 'i'nfo files because, they 1640 * aren't laid down, 'e'ditable files can change 1641 * anyway, so who cares and 's'ymlinks were already 1642 * fixed in domerg(); however, certain old WOS 1643 * package symlinks depend on a bug in the old 1644 * pkgadd which has recently been expunged. For 1645 * those packages in 2.2, we repeat the verification 1646 * of symlinks. 1647 * 1648 * By 2.6 or so, ftype == 's' should be added to this. 1649 */ 1650 if (ept->ftype == 'i' || ept->ftype == 'e' || 1651 (mstat->shared && nocnflct)) 1652 continue; 1653 1654 if (mstat->denied) { 1655 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1656 warnflag++; 1657 continue; 1658 } 1659 1660 if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) { 1661 progerr(ERR_CLIDX, ept->pkg_class_idx, 1662 (ept->path && *ept->path) ? ept->path : "unknown"); 1663 continue; 1664 } 1665 1666 /* If this is the right class, do the fast verify. */ 1667 if (ept->pkg_class_idx == idx) { 1668 if (fverify(1, &ept->ftype, ept->path, 1669 &ept->ainfo, &ept->cinfo) == 0) { 1670 mstat->attrchg = 0; 1671 mstat->contchg = 0; 1672 } else /* We'll try full verify later */ 1673 retval = 0; 1674 } 1675 /* 1676 * Need to copy the installed volitale file back to the 1677 * partial spooled area if we are installing to a local zone 1678 * or similar installation method. 1679 */ 1680 1681 if ((!is_partial_inst()) && 1682 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1683 (strcmp(ept->pkg_class, "none") == 0)) { 1684 1685 if (absolutepath(ext->map_path) == B_TRUE && 1686 parametricpath(ext->cf_ent.ainfo.local, 1687 &relocpath) == B_FALSE) { 1688 pspool_loc = ROOT; 1689 } else { 1690 pspool_loc = RELOC; 1691 } 1692 1693 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1694 saveSpoolInstallDir, pspool_loc, 1695 relocpath ? relocpath : ext->map_path); 1696 1697 if (n >= PATH_MAX) { 1698 progerr(ERR_CREATE_PATH_2, 1699 saveSpoolInstallDir, 1700 ext->map_path); 1701 quit(99); 1702 } 1703 1704 /* copy, preserve source file mode */ 1705 1706 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1707 warnflag++; 1708 } 1709 } 1710 } 1711 1712 return (retval); 1713 } 1714 1715 /* 1716 * Check to see if first charcter in path is a '/'. 1717 * 1718 * Return: 1719 * B_TRUE - if path is prepended with '/' 1720 * B_FALSE - if not 1721 */ 1722 static boolean_t 1723 absolutepath(char *path) 1724 { 1725 assert(path != NULL); 1726 assert(path[0] != '\0'); 1727 1728 return (path[0] == '/' ? B_TRUE : B_FALSE); 1729 } 1730 1731 /* 1732 * Check to see if path contains a '$' which makes it 1733 * a parametric path and therefore relocatable. 1734 * 1735 * Parameters: 1736 * path - The path to determine if it is absolute 1737 * relocpath - The value of the unconditioned path 1738 * i.e. $OPTDIR/usr/ls 1739 * Return: 1740 * B_TRUE - if path is a parametric path 1741 * B_FALSE - if not 1742 */ 1743 static boolean_t 1744 parametricpath(char *path, char **relocpath) 1745 { 1746 assert(path != NULL); 1747 assert(path[0] != '\0'); 1748 1749 /* 1750 * If this is a valid parametric path then a '$' MUST occur at the 1751 * first or second character. 1752 */ 1753 1754 if (path[0] == '$' || path[1] == '$') { 1755 /* 1756 * If a parametric path exists then when copying the 1757 * path to the pspool directoy from the installing 1758 * pkgs reloc directory we want to use the uncononditional 1759 * varaiable path. 1760 */ 1761 *relocpath = (path + 1); 1762 return (B_TRUE); 1763 } 1764 return (B_FALSE); 1765 } 1766 1767 void 1768 regfiles_free() 1769 { 1770 if (regfiles_head != NULL) { 1771 struct reg_files *rfp = regfiles_head->next; 1772 1773 while (rfp != NULL) { 1774 free(regfiles_head); 1775 regfiles_head = rfp; 1776 rfp = regfiles_head->next; 1777 } 1778 free(regfiles_head); 1779 regfiles_head = NULL; 1780 } 1781 } 1782