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 /* 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 PKGserver pkgserver, 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(&pkgserver, 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 break; 1409 1410 1411 ept = &(extlist[idx]->cf_ent); 1412 mstat = &(extlist[idx]->mstat); 1413 1414 temppath = extlist[idx]->client_path; 1415 1416 /* 1417 * At this point the only difference between the entry 1418 * in the contents file and the entry in extlist[] is 1419 * that the status indicator contains CONFIRM_CONT. 1420 * This function should return one or something is wrong. 1421 */ 1422 1423 n = srchcfile(&(entry.cf_ent), temppath, pkgserver); 1424 1425 if (n < 0) { 1426 char *errstr = getErrstr(); 1427 progerr(ERR_CFBAD); 1428 logerr(gettext("pathname=%s"), 1429 entry.cf_ent.path && *entry.cf_ent.path ? 1430 entry.cf_ent.path : "Unknown"); 1431 logerr(gettext("problem=%s"), 1432 (errstr && *errstr) ? errstr : "Unknown"); 1433 quit(99); 1434 } else if (n != 1) { 1435 /* 1436 * Check if path should be in the package 1437 * database. 1438 */ 1439 if ((mstat->shared && nocnflct)) { 1440 continue; 1441 } 1442 progerr(ERR_CFMISSING, ept->path); 1443 quit(99); 1444 } 1445 1446 /* 1447 * If merge was not appropriate for this object, now is the 1448 * time to choose one or the other. 1449 */ 1450 if (mstat->denied) { 1451 /* 1452 * If installation was denied AFTER the package 1453 * database was updated, skip this. We've already 1454 * announced the discrepancy and the verifications 1455 * that follow will make faulty decisions based on 1456 * the ftype, which may not be correct. 1457 */ 1458 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1459 warnflag++; 1460 } else { 1461 if (mstat->replace) 1462 /* 1463 * This replaces the old entry with the new 1464 * one. This should never happen in the new 1465 * DB since the entries are already identical. 1466 */ 1467 repl_cfent(ept, &(entry.cf_ent)); 1468 1469 /* 1470 * Validate this entry and change the status flag in 1471 * the package database. 1472 */ 1473 if (ept->ftype == RM_RDY) { 1474 (void) eptstat(&(entry.cf_ent), pkginst, 1475 STAT_NEXT); 1476 } else { 1477 /* check the hard link now. */ 1478 if (ept->ftype == 'l') { 1479 if (averify(0, &ept->ftype, 1480 ept->path, &ept->ainfo)) { 1481 echo(MSG_HRDLINK, 1482 ept->path); 1483 mstat->attrchg++; 1484 } 1485 } 1486 1487 /* 1488 * Don't install or verify objects for 1489 * remote, read-only filesystems. We need 1490 * only flag them as shared from some server. 1491 * Otherwise, ok to do final check. 1492 */ 1493 if (is_remote_fs(ept->path, 1494 &(extlist[idx]->fsys_value)) && 1495 !is_fs_writeable(ept->path, 1496 &(extlist[idx]->fsys_value))) { 1497 flag = -1; 1498 } else { 1499 boolean_t inheritedFlag; 1500 inheritedFlag = 1501 z_path_is_inherited(ept->path, 1502 ept->ftype, get_inst_root()); 1503 flag = finalck(ept, mstat->attrchg, 1504 (ckflag ? mstat->contchg : 1505 (-1)), inheritedFlag); 1506 } 1507 1508 pinfo = entry.cf_ent.pinfo; 1509 1510 /* Find this package in the list. */ 1511 while (pinfo) { 1512 if (strcmp(pkginst, pinfo->pkg) == 0) { 1513 break; 1514 } 1515 pinfo = pinfo->next; 1516 } 1517 1518 /* 1519 * If this package owns this file, then store 1520 * it in the database with the appropriate 1521 * status. Need to check pinfo in case it 1522 * points to NULL which could happen if 1523 * pinfo->next = NULL above. 1524 */ 1525 if (pinfo) { 1526 if (flag < 0 || is_served(ept->path, 1527 &(extlist[idx]->fsys_value))) { 1528 /* 1529 * This is provided to 1530 * clients by a server. 1531 */ 1532 pinfo->status = SERVED_FILE; 1533 } else { 1534 /* 1535 * It's either there or it's 1536 * not. 1537 */ 1538 pinfo->status = (flag ? 1539 NOT_FND : ENTRY_OK); 1540 } 1541 } 1542 } 1543 } 1544 1545 /* 1546 * If not installing from a partially spooled package, the 1547 * "save/pspool" area, and the file contents can be 1548 * changed (type is 'e' or 'v'), and the class IS "none": 1549 * copy the installed volatile file into the appropriate 1550 * location in the packages destination "save/pspool" area. 1551 */ 1552 1553 if ((!is_partial_inst()) && 1554 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1555 (strcmp(ept->pkg_class, "none") == 0)) { 1556 1557 if (absolutepath(extlist[idx]->map_path) == B_TRUE && 1558 parametricpath(extlist[idx]->cf_ent.ainfo.local, 1559 &relocpath) == B_FALSE) { 1560 pspool_loc = ROOT; 1561 } else { 1562 pspool_loc = RELOC; 1563 } 1564 1565 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1566 saveSpoolInstallDir, pspool_loc, 1567 relocpath ? relocpath : extlist[idx]->map_path); 1568 1569 if (n >= PATH_MAX) { 1570 progerr(ERR_CREATE_PATH_2, 1571 saveSpoolInstallDir, 1572 extlist[idx]->map_path); 1573 quit(99); 1574 } 1575 1576 /* copy, preserve source file mode */ 1577 1578 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1579 warnflag++; 1580 } 1581 } 1582 1583 /* 1584 * Now insert this potentially changed package database 1585 * entry. 1586 */ 1587 if (entry.cf_ent.npkgs) { 1588 if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) { 1589 quit(99); 1590 } 1591 } 1592 } 1593 1594 n = swapcfile(pkgserver, a_cfTmpVfp, pkginst, dbchg); 1595 if (n == RESULT_WRN) { 1596 warnflag++; 1597 } else if (n == RESULT_ERR) { 1598 quit(99); 1599 } 1600 } 1601 1602 /* 1603 * This function goes through and fixes all the attributes. This is called 1604 * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary 1605 * use for this is to fix up files installed by a class action script 1606 * which is time-critical and reliable enough to assume likely success. 1607 * The first such format was for WOS compressed-cpio'd file sets. 1608 * The second format is the Class Archive Format. 1609 */ 1610 static int 1611 fix_attributes(struct cfextra **extlist, int idx) 1612 { 1613 struct cfextra *ext; 1614 int i, retval = 1; 1615 int nc = cl_getn(); 1616 int n; 1617 struct cfent *ept; 1618 struct mergstat *mstat; 1619 char scrpt_dst[PATH_MAX]; 1620 char *pspool_loc; 1621 char *relocpath = (char *)NULL; 1622 1623 for (i = 0; extlist[i]; i++) { 1624 ext = extlist[i]; 1625 ept = &(extlist[i]->cf_ent); 1626 mstat = &(extlist[i]->mstat); 1627 1628 /* 1629 * We don't care about 'i'nfo files because, they 1630 * aren't laid down, 'e'ditable files can change 1631 * anyway, so who cares and 's'ymlinks were already 1632 * fixed in domerg(); however, certain old WOS 1633 * package symlinks depend on a bug in the old 1634 * pkgadd which has recently been expunged. For 1635 * those packages in 2.2, we repeat the verification 1636 * of symlinks. 1637 * 1638 * By 2.6 or so, ftype == 's' should be added to this. 1639 */ 1640 if (ept->ftype == 'i' || ept->ftype == 'e' || 1641 (mstat->shared && nocnflct)) 1642 continue; 1643 1644 if (mstat->denied) { 1645 progerr(ERR_COULD_NOT_INSTALL, ept->path); 1646 warnflag++; 1647 continue; 1648 } 1649 1650 if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) { 1651 progerr(ERR_CLIDX, ept->pkg_class_idx, 1652 (ept->path && *ept->path) ? ept->path : "unknown"); 1653 continue; 1654 } 1655 1656 /* If this is the right class, do the fast verify. */ 1657 if (ept->pkg_class_idx == idx) { 1658 if (fverify(1, &ept->ftype, ept->path, 1659 &ept->ainfo, &ept->cinfo) == 0) { 1660 mstat->attrchg = 0; 1661 mstat->contchg = 0; 1662 } else /* We'll try full verify later */ 1663 retval = 0; 1664 } 1665 /* 1666 * Need to copy the installed volitale file back to the 1667 * partial spooled area if we are installing to a local zone 1668 * or similar installation method. 1669 */ 1670 1671 if ((!is_partial_inst()) && 1672 ((ept->ftype == 'e') || (ept->ftype == 'v')) && 1673 (strcmp(ept->pkg_class, "none") == 0)) { 1674 1675 if (absolutepath(ext->map_path) == B_TRUE && 1676 parametricpath(ext->cf_ent.ainfo.local, 1677 &relocpath) == B_FALSE) { 1678 pspool_loc = ROOT; 1679 } else { 1680 pspool_loc = RELOC; 1681 } 1682 1683 n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", 1684 saveSpoolInstallDir, pspool_loc, 1685 relocpath ? relocpath : ext->map_path); 1686 1687 if (n >= PATH_MAX) { 1688 progerr(ERR_CREATE_PATH_2, 1689 saveSpoolInstallDir, 1690 ext->map_path); 1691 quit(99); 1692 } 1693 1694 /* copy, preserve source file mode */ 1695 1696 if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { 1697 warnflag++; 1698 } 1699 } 1700 } 1701 1702 return (retval); 1703 } 1704 1705 /* 1706 * Check to see if first charcter in path is a '/'. 1707 * 1708 * Return: 1709 * B_TRUE - if path is prepended with '/' 1710 * B_FALSE - if not 1711 */ 1712 static boolean_t 1713 absolutepath(char *path) 1714 { 1715 assert(path != NULL); 1716 assert(path[0] != '\0'); 1717 1718 return (path[0] == '/' ? B_TRUE : B_FALSE); 1719 } 1720 1721 /* 1722 * Check to see if path contains a '$' which makes it 1723 * a parametric path and therefore relocatable. 1724 * 1725 * Parameters: 1726 * path - The path to determine if it is absolute 1727 * relocpath - The value of the unconditioned path 1728 * i.e. $OPTDIR/usr/ls 1729 * Return: 1730 * B_TRUE - if path is a parametric path 1731 * B_FALSE - if not 1732 */ 1733 static boolean_t 1734 parametricpath(char *path, char **relocpath) 1735 { 1736 assert(path != NULL); 1737 assert(path[0] != '\0'); 1738 1739 /* 1740 * If this is a valid parametric path then a '$' MUST occur at the 1741 * first or second character. 1742 */ 1743 1744 if (path[0] == '$' || path[1] == '$') { 1745 /* 1746 * If a parametric path exists then when copying the 1747 * path to the pspool directoy from the installing 1748 * pkgs reloc directory we want to use the uncononditional 1749 * varaiable path. 1750 */ 1751 *relocpath = (path + 1); 1752 return (B_TRUE); 1753 } 1754 return (B_FALSE); 1755 } 1756 1757 void 1758 regfiles_free() 1759 { 1760 if (regfiles_head != NULL) { 1761 struct reg_files *rfp = regfiles_head->next; 1762 1763 while (rfp != NULL) { 1764 free(regfiles_head); 1765 regfiles_head = rfp; 1766 rfp = regfiles_head->next; 1767 } 1768 free(regfiles_head); 1769 regfiles_head = NULL; 1770 } 1771 } 1772