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 <signal.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <assert.h> 38 #include <pkgstrct.h> 39 #include <sys/stat.h> 40 #include <locale.h> 41 #include <libintl.h> 42 #include <pkginfo.h> 43 #include <instzones_api.h> 44 #include <pkglib.h> 45 #include <libinst.h> 46 #include <messages.h> 47 48 /* merg() return codes */ 49 #define MRG_SAME 0 50 #define MRG_DIFFERENT 1 51 #define MRG_REPLACE 2 52 53 /* typechg() return codes */ 54 #define TYPE_OK 0 55 #define TYPE_WARNING 1 56 #define TYPE_IGNORED 2 57 #define TYPE_REPLACE 3 58 #define TYPE_FATAL 4 59 60 /* message pool */ 61 #define ERR_OUTPUT "unable to update package database" 62 #define ERR_PINFO "missing pinfo structure for <%s>" 63 #define INFO_PROCESS " %2ld%% of information processed; continuing ..." 64 65 #define WRN_NOTFILE "WARNING: %s <no longer a regular file>" 66 #define WRN_NOTSYMLN "WARNING: %s <no longer a symbolic link>" 67 #define WRN_NOTLINK "WARNING: %s <no longer a linked file>" 68 #define WRN_NOTDIR "WARNING: %s <no longer a directory>" 69 #define WRN_NOTCHAR "WARNING: %s <no longer a character special device>" 70 #define WRN_NOTBLOCK "WARNING: %s <no longer a block special device>" 71 #define WRN_NOTPIPE "WARNING: %s <no longer a named pipe>" 72 #define WRN_TOEXCL "WARNING: cannot convert %s to an exclusive directory." 73 #define WRN_ODDVERIFY "WARNING: quick verify disabled for class %s." 74 75 #define MSG_TYPIGN "Object type change ignored." 76 #define MSG_TYPE_ERR "Package attempts fatal object type change." 77 78 extern char *pkginst; 79 extern int nosetuid, nocnflct, otherstoo; 80 81 /* pkgobjmap.c */ 82 extern int cp_cfent(struct cfent *cf_ent, struct cfextra *el_ent); 83 84 /* setlist.c */ 85 extern void cl_def_dverify(int idx); 86 87 char dbst = '\0'; /* usually set by installf() or removef() */ 88 89 int files_installed(void); /* return number of files installed. */ 90 91 static int errflg = 0; 92 static int eptnum; 93 static VFP_T *fpvfp = {(VFP_T *)NULL}; 94 static long sizetot; 95 static int seconds; 96 static int installed; /* # of files, already properly installed. */ 97 static struct pinfo *pkgpinfo = (struct pinfo *)0; 98 99 static int is_setuid(struct cfent *ent); 100 static int is_setgid(struct cfent *ent); 101 static int merg(struct cfextra *el_ent, struct cfent *cf_ent); 102 static int do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, 103 struct cfent *cf_ent, int ctrl); 104 static int do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl); 105 static int typechg(struct cfent *el_ent, struct cfent *cf_ent, 106 struct mergstat *mstat); 107 108 static void set_change(struct cfextra *el_ent); 109 static void chgclass(struct cfent *cf_ent, struct pinfo *pinfo); 110 static void output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo); 111 112 /* ARGSUNUSED */ 113 void 114 notice(int n) 115 { 116 #ifdef lint 117 int i = n; 118 n = i; 119 #endif /* lint */ 120 (void) signal(SIGALRM, SIG_IGN); 121 if (sizetot != 0) { 122 echo(gettext(INFO_PROCESS), 123 vfpGetBytesRemaining(fpvfp) * 100L / sizetot); 124 } 125 (void) signal(SIGALRM, notice); 126 (void) alarm(seconds); 127 } 128 129 /* ARGSUSED */ 130 131 /* 132 * This scans the extlist (pkgmap) and the package database to the end, 133 * copying out the merged contents to the file at tmpfp. It updates the mergstat 134 * structures and deals with administrative defaults regarding setuid and 135 * conflict. 136 * 137 * Since both the extlist and the package database entries are in numerical 138 * order, they both scan unidirectionally. If the entry in the extlist is 139 * found in the package database (by pathname) then do_like_ent() is called. 140 * If the extlist entry is not found in the package database then 141 * do_new_ent() is called. srchcfile() is responsible for copying out 142 * non-matching package database entries. At package database EOF, the 143 * eocontents flag is set and the rest of the extlist are assumed to be new 144 * entries. At the end of the extlist, the eoextlist flag is set and the 145 * remaining package database ends up copied out by srchcfile(). 146 */ 147 148 int 149 pkgdbmerg(VFP_T *mapvfp, VFP_T *tmpvfp, struct cfextra **extlist, int notify) 150 { 151 static struct cfent cf_ent; /* scratch area */ 152 struct cfextra *el_ent; /* extlist entry under review */ 153 int eocontents = 0; 154 int eoextlist = 0; 155 int n; 156 int changed; 157 int assume_ok = 0; 158 159 cf_ent.pinfo = (NULL); 160 errflg = 0; 161 eptnum = 0; 162 installed = changed = 0; 163 164 fpvfp = mapvfp; /* for notice function ...arg! */ 165 166 if (notify) { 167 seconds = notify; 168 (void) signal(SIGALRM, notice); 169 (void) alarm(seconds); 170 } 171 172 (void) sighold(SIGALRM); 173 174 sizetot = (((ptrdiff_t)(mapvfp->_vfpEnd)) - 175 ((ptrdiff_t)(mapvfp->_vfpStart))); 176 vfpRewind(mapvfp); 177 vfpRewind(tmpvfp); 178 179 (void) sigrelse(SIGALRM); 180 181 do { 182 (void) sighold(SIGALRM); 183 184 /* 185 * If there's an entry in the extlist at this position, 186 * process that entry. 187 */ 188 if (!eoextlist && (el_ent = extlist[eptnum])) { 189 190 /* Metafiles don't get merged. */ 191 if ((el_ent->cf_ent.ftype == 'i') || 192 (el_ent->cf_ent.ftype == 'n')) { 193 continue; 194 } 195 196 /* 197 * Copy cfextra structure for duplicated paths. 198 * This is not just an optimization, it is 199 * necessary for correct operation of algorithm. 200 */ 201 if ((eptnum > 0) && (strncmp(el_ent->cf_ent.path, 202 extlist[eptnum-1]->cf_ent.path, PATH_MAX) == 0)) { 203 memcpy(extlist[eptnum], extlist[eptnum-1], 204 sizeof (struct cfextra)); 205 continue; 206 } 207 208 /* 209 * Normally dbst comes to us from installf() or 210 * removef() in order to specify their special 211 * database status codes. They cannot implement a 212 * quick verify (it just doesn't make sense). For 213 * that reason, we can test to see if we already have 214 * a special database status. If we don't (it's from 215 * pkgadd) then we can test to see if this is calling 216 * for a quick verify wherein we assume the install 217 * will work and fix it if it doesn't. In that case 218 * we set our own dbst to be ENTRY_OK. 219 */ 220 if (dbst == '\0') { 221 if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) == 222 QKVERIFY) { 223 assume_ok = 1; 224 } 225 } else { 226 /* 227 * If we DO end up with an installf/quick 228 * verify combination, we fix that by simply 229 * denying the quick verify for this class. 230 * This forces everything to come out alright 231 * by forcing the standard assumptions as 232 * regards package database for the rest of 233 * the load. 234 */ 235 if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) == 236 QKVERIFY) { 237 logerr(gettext(WRN_ODDVERIFY), 238 cl_nam( 239 el_ent->cf_ent.pkg_class_idx)); 240 /* 241 * Set destination verification to 242 * default. 243 */ 244 cl_def_dverify( 245 el_ent->cf_ent.pkg_class_idx); 246 } 247 } 248 249 /* 250 * Comply with administrative requirements regarding 251 * setuid/setgid processes. 252 */ 253 if (is_setuid(&(el_ent->cf_ent))) { 254 el_ent->mstat.setuid = 1; 255 } 256 if (is_setgid(&(el_ent->cf_ent))) { 257 el_ent->mstat.setgid = 1; 258 } 259 260 /* 261 * If setuid/setgid processes are not allowed, reset 262 * those bits. 263 */ 264 if (nosetuid && (el_ent->mstat.setgid || 265 el_ent->mstat.setuid)) { 266 el_ent->cf_ent.ainfo.mode &= 267 ~(S_ISUID | S_ISGID); 268 } 269 } else { 270 eoextlist = 1; /* end of extlist[] */ 271 } 272 273 /* 274 * If we're not at the end of the package database, get the 275 * next entry for comparison. 276 */ 277 if (!eocontents) { 278 279 /* Search package database for this entry. */ 280 n = srchcfile(&cf_ent, el_ent ? 281 el_ent->cf_ent.path : NULL, 282 mapvfp, tmpvfp); 283 284 /* 285 * If there was an error, note it and return an error 286 * flag. 287 */ 288 if (n < 0) { 289 char *errstr = getErrstr(); 290 logerr(gettext( 291 "bad entry read from contents file")); 292 logerr(gettext("- pathname: %s"), 293 (cf_ent.path && *cf_ent.path) ? 294 cf_ent.path : "Unknown"); 295 logerr(gettext("- problem: %s"), 296 (errstr && *errstr) ? errstr : "Unknown"); 297 return (-1); 298 /* 299 * If there was a match, then merge them into a 300 * single entry. 301 */ 302 } else if (n == 1) { 303 /* 304 * If this package is overwriting a setuid or 305 * setgid process, set the status bits so we 306 * can inform the administrator. 307 */ 308 if (is_setuid(&cf_ent)) { 309 el_ent->mstat.osetuid = 1; 310 } 311 312 if (is_setgid(&cf_ent)) { 313 el_ent->mstat.osetgid = 1; 314 } 315 /* 316 * Detect if a symlink has changed to directory 317 * If so mark all the files/dir supposed to be 318 * iniside this dir, so that they are not miss 319 * understood by do_new_ent later as already 320 * installed. 321 */ 322 if ((!eoextlist) && (cf_ent.ftype == 's') && 323 (el_ent->cf_ent.ftype == 'd')) { 324 int i; 325 int plen = strlen(el_ent->cf_ent.path); 326 for (i = eptnum + 1; extlist[i]; i++) { 327 if (strncmp(el_ent->cf_ent.path, 328 extlist[i]->cf_ent.path, 329 plen) != 0) 330 break; 331 extlist[i]->mstat.parentsyml2dir 332 = 1; 333 } 334 } 335 336 if (do_like_ent(tmpvfp, el_ent, &cf_ent, 337 assume_ok)) { 338 changed++; 339 } 340 341 /* 342 * If the alphabetical position in the package 343 * database is unfilled, then this will be a new 344 * entry. If n == 0, then we're also at the end of 345 * the contents file. 346 */ 347 } else { 348 if (n == 0) { 349 eocontents++; 350 } 351 352 /* 353 * If there is an extlist entry in the 354 * hopper, insert it at the end of the 355 * package database. 356 */ 357 if (!eoextlist) { 358 if (do_new_ent(tmpvfp, el_ent, 359 assume_ok)) { 360 changed++; 361 } 362 } 363 } 364 /* 365 * We have passed the last entry in the package database, 366 * tagging these extlist entries onto the end. 367 */ 368 } else if (!eoextlist) { 369 if (do_new_ent(tmpvfp, el_ent, assume_ok)) { 370 changed++; 371 } 372 } 373 /* Else, we'll drop out of the loop. */ 374 375 (void) sigrelse(SIGALRM); 376 } while (eptnum++, (!eocontents || !eoextlist)); 377 378 if (notify) { 379 (void) alarm(0); 380 (void) signal(SIGALRM, SIG_IGN); 381 } 382 383 return (errflg ? -1 : changed); 384 } 385 386 /* 387 * Merge a new entry with an installed package object of the same name and 388 * insert that object into the package database. Obey administrative defaults 389 * as regards conflicting files. 390 */ 391 392 static int 393 do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, struct cfent *cf_ent, int ctrl) 394 { 395 int stflag, ignore, changed, mrg_result; 396 397 ignore = changed = 0; 398 399 /* 400 * Construct the record defining the current package. If there are 401 * other packages involved, this will be appended to the existing 402 * list. If this is an update of the same package, it will get merged 403 * with the existing record. If this is a preloaded record (like from 404 * a dryrun file), it will keep it's current pinfo pointer and will 405 * pass it on to the record from the contents file - because on the 406 * final continuation, the contents file will be wrong. 407 */ 408 if (el_ent->mstat.preloaded) { 409 struct pinfo *pkginfo; 410 411 /* Contents file is not to be trusted for this list. */ 412 pkginfo = cf_ent->pinfo; 413 414 /* Free the potentially bogus list. */ 415 while (pkginfo) { 416 struct pinfo *next; 417 next = pkginfo->next; 418 free(pkginfo); 419 pkginfo = next; 420 } 421 422 cf_ent->pinfo = el_ent->cf_ent.pinfo; 423 } 424 425 pkgpinfo = eptstat(cf_ent, pkginst, DUP_ENTRY); 426 427 stflag = pkgpinfo->status; 428 429 if (otherstoo) 430 el_ent->mstat.shared = 1; 431 432 /* If it's marked for erasure, make it official */ 433 if (el_ent->cf_ent.ftype == RM_RDY) { 434 if (!errflg) { 435 pkgpinfo = eptstat(cf_ent, pkginst, RM_RDY); 436 437 /* 438 * Get copy of status character in case the object is 439 * "shared" by a server, in which case we need to 440 * maintain the shared status after the entry is 441 * written to the package database with RM_RDY 442 * status. This is needed to support the `removef' 443 * command. 444 */ 445 stflag = pkgpinfo->status; 446 pkgpinfo->status = RM_RDY; 447 448 if (putcvfpfile(cf_ent, vfpo)) { 449 progerr(gettext(ERR_OUTPUT)); 450 quit(99); 451 } 452 453 /* 454 * If object is provided by a server, allocate an 455 * info block and set the status to indicate this. 456 * This is needed to support the `removef' command. 457 */ 458 if (stflag == SERVED_FILE) { 459 el_ent->cf_ent.pinfo = 460 (struct pinfo *)calloc(1, 461 sizeof (struct pinfo)); 462 el_ent->cf_ent.pinfo->next = NULL; 463 el_ent->cf_ent.pinfo->status = SERVED_FILE; 464 } 465 } 466 return (1); 467 } 468 469 /* 470 * If there is no package associated with it, there's something 471 * very wrong. 472 */ 473 if (!pkgpinfo) { 474 progerr(gettext(ERR_PINFO), cf_ent->path); 475 quit(99); 476 } 477 478 /* 479 * Do not allow installation if nocnflct is set and other packages 480 * reference this pathname. The cp_cfent() function below writes the 481 * information from the installed file over the new entry, so the 482 * package database will be unchanged. 483 * 484 * By the way, ftype "e" is often shared and that's OK, so ftype 485 * "e" doesn't count here. 486 */ 487 if ((nocnflct && el_ent->mstat.shared && el_ent->cf_ent.ftype != 'e')) { 488 /* 489 * First set the attrchg and contchg entries for proper 490 * messaging in the install phase. 491 */ 492 set_change(el_ent); 493 494 /* 495 * Now overwrite the new entry with the entry for the 496 * currently installed object. 497 */ 498 if (cp_cfent(cf_ent, el_ent) == 0) 499 quit(99); 500 501 ignore++; 502 } else { 503 mrg_result = merg(el_ent, cf_ent); 504 505 switch (mrg_result) { 506 case MRG_SAME: 507 break; 508 509 case MRG_DIFFERENT: 510 changed++; 511 break; 512 513 case MRG_REPLACE: 514 /* 515 * We'll pick one or the other later. For now, cf_ent 516 * will have the fault value and el_ent will retain 517 * the other value. This is the only state that allows 518 * the database and the pkgmap to differ. 519 */ 520 521 el_ent->mstat.contchg = 1; /* subject to change */ 522 ignore++; 523 break; 524 525 default: 526 break; 527 } 528 } 529 530 /* el_ent structure now contains updated entry */ 531 if (!el_ent->mstat.contchg && !ignore) { 532 /* 533 * We know the DB entry matches the pkgmap, so now we need to 534 * see if the actual object matches the pkgmap. 535 */ 536 set_change(el_ent); 537 } 538 539 if (!errflg) { 540 if (ctrl == 1) { /* quick verify assumes OK */ 541 /* 542 * The pkgpinfo entry is already correctly 543 * constructed. Look into dropping this soon. 544 */ 545 pkgpinfo = eptstat(&(el_ent->cf_ent), pkginst, 546 ENTRY_OK); 547 548 if (stflag != DUP_ENTRY) { 549 changed++; 550 } 551 552 /* 553 * We could trust the prior pkginfo entry, but things 554 * could have changed and we need to update the 555 * fs_tab[] anyway. We check for a server object 556 * here. 557 */ 558 if (is_served(el_ent->server_path, 559 &(el_ent->fsys_value))) 560 pkgpinfo->status = SERVED_FILE; 561 } else { 562 if (!ignore && el_ent->mstat.contchg) { 563 pkgpinfo = 564 eptstat(&(el_ent->cf_ent), pkginst, 565 (dbst ? dbst : CONFIRM_CONT)); 566 } else if (!ignore && el_ent->mstat.attrchg) { 567 pkgpinfo = 568 eptstat(&(el_ent->cf_ent), pkginst, 569 (dbst ? dbst : CONFIRM_ATTR)); 570 } else if (!ignore && el_ent->mstat.shared) { 571 pkgpinfo = 572 eptstat(&(el_ent->cf_ent), pkginst, 573 dbst); 574 changed++; 575 } else if (stflag != DUP_ENTRY) { 576 pkgpinfo = eptstat(&(el_ent->cf_ent), 577 pkginst, '\0'); 578 if (stflag != ENTRY_OK) { 579 changed++; 580 } 581 } 582 } 583 584 if (mrg_result == MRG_REPLACE) { 585 /* 586 * Put the original package database entry back into 587 * the package database for now. 588 */ 589 output(vfpo, cf_ent, pkgpinfo); 590 } else { 591 /* Put the merged entry into the package database. */ 592 output(vfpo, &(el_ent->cf_ent), pkgpinfo); 593 } 594 } 595 596 if (pkgpinfo->aclass[0] != '\0') { 597 (void) strcpy(el_ent->cf_ent.pkg_class, pkgpinfo->aclass); 598 } 599 600 /* 601 * If a sym link entry exists in the contents file and 602 * and the destination of the link does not exist on the the system 603 * then the contents file needs to be updated appropriately so a 604 * subsequent invocation of "installf -f" will create the destination. 605 */ 606 if (el_ent->mstat.contchg && pkgpinfo->status == INST_RDY) { 607 changed++; 608 } 609 610 if (!(el_ent->mstat.preloaded)) 611 el_ent->cf_ent.pinfo = NULL; 612 613 /* 614 * If no change during the merg and we don't have a case where types 615 * were different in odd ways, count this as installed. 616 */ 617 if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg && 618 !el_ent->mstat.replace) 619 installed++; 620 return (changed); 621 } 622 623 /* Insert an entirely new entry into the package database. */ 624 static int 625 do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl) 626 { 627 struct pinfo *pinfo; 628 char *tp; 629 int changed = 0; 630 631 if (el_ent->cf_ent.ftype == RM_RDY) { 632 return (0); 633 } 634 635 tp = el_ent->server_path; 636 /* 637 * Check the file/dir existence only if any of the parent directory 638 * of the file/dir has not changed from symbolic link to directory. 639 * At this time we are only doing a dry run, the symlink is not yet 640 * replaced, so if this is done directly then access will result in 641 * incorrect information in case a file with the same attr and cont 642 * exists in the link target. 643 */ 644 if ((!el_ent->mstat.parentsyml2dir) && (access(tp, F_OK) == 0)) { 645 /* 646 * Path exists, and although its not referenced by any 647 * package we make it look like it is so it appears as a 648 * conflicting file in case the user doesn't want it 649 * installed. We set the rogue flag to distinguish this from 650 * package object conflicts if the administrator is queried 651 * about this later. Note that noconflict means NO conflict 652 * at the file level. Even rogue files count. 653 */ 654 el_ent->mstat.shared = 1; 655 el_ent->mstat.rogue = 1; 656 set_change(el_ent); 657 } else { 658 /* since path doesn't exist, we're changing everything */ 659 el_ent->mstat.rogue = 0; 660 el_ent->mstat.contchg = 1; 661 el_ent->mstat.attrchg = 1; 662 } 663 664 if (el_ent->cf_ent.ainfo.mode == WILDCARD) { 665 if (el_ent->cf_ent.ftype == 'd') { 666 el_ent->cf_ent.ainfo.mode = DEFAULT_MODE; 667 } else { 668 el_ent->cf_ent.ainfo.mode = DEFAULT_MODE_FILE; 669 } 670 logerr(WRN_SET_DEF_MODE, el_ent->cf_ent.path, 671 (int)el_ent->cf_ent.ainfo.mode); 672 } 673 674 if (strcmp(el_ent->cf_ent.ainfo.owner, DB_UNDEFINED_ENTRY) == 0) 675 (void) strcpy(el_ent->cf_ent.ainfo.owner, 676 DEFAULT_OWNER); 677 if (strcmp(el_ent->cf_ent.ainfo.group, DB_UNDEFINED_ENTRY) == 0) 678 (void) strcpy(el_ent->cf_ent.ainfo.group, 679 DEFAULT_GROUP); 680 681 /* 682 * Do not allow installation if nocnflct is set and this pathname is 683 * already in place. Since this entry is new (not associated with a 684 * package), we don't issue anything to the database we're building. 685 */ 686 if (nocnflct && el_ent->mstat.shared) { 687 return (0); 688 } 689 690 if (!errflg) { 691 if (el_ent->mstat.preloaded) { 692 /* Add this package to the already established list. */ 693 pinfo = eptstat(&(el_ent->cf_ent), pkginst, DUP_ENTRY); 694 } else { 695 el_ent->cf_ent.npkgs = 1; 696 pinfo = (struct pinfo *)calloc(1, 697 sizeof (struct pinfo)); 698 if (!pinfo) { 699 progerr(gettext(ERR_MEMORY), errno); 700 quit(99); 701 } 702 el_ent->cf_ent.pinfo = pinfo; 703 (void) strcpy(pinfo->pkg, pkginst); 704 } 705 706 if (ctrl == 1) { /* quick verify assumes OK */ 707 pinfo->status = dbst ? dbst : ENTRY_OK; 708 /* 709 * The entry won't be verified, but the entry in the 710 * database isn't necessarily ENTRY_OK. If this is 711 * coming from a server, we need to note that 712 * instead. 713 */ 714 if (is_served(el_ent->server_path, 715 &(el_ent->fsys_value))) 716 pinfo->status = SERVED_FILE; 717 } else { 718 pinfo->status = dbst ? dbst : CONFIRM_CONT; 719 } 720 721 output(vfpo, &(el_ent->cf_ent), pinfo); 722 changed++; 723 724 free(pinfo); 725 el_ent->cf_ent.pinfo = NULL; 726 } 727 if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg) { 728 installed++; 729 } 730 731 return (changed); 732 } 733 734 int 735 files_installed(void) 736 { 737 return (installed); 738 } 739 740 /* 741 * This function determines if there is a difference between the file on 742 * the disk and the file to be laid down. It set's mstat flags attrchg 743 * and contchg accordingly. 744 */ 745 static void 746 set_change(struct cfextra *el_ent) 747 { 748 int n; 749 char *tp; 750 751 tp = el_ent->server_path; 752 if ((el_ent->cf_ent.ftype == 'f') || (el_ent->cf_ent.ftype == 'e') || 753 (el_ent->cf_ent.ftype == 'v')) { 754 if (cverify(0, &(el_ent->cf_ent.ftype), tp, 755 &(el_ent->cf_ent.cinfo), 1)) { 756 el_ent->mstat.contchg = 1; 757 } else if (!el_ent->mstat.contchg && !el_ent->mstat.attrchg) { 758 if (averify(0, &(el_ent->cf_ent.ftype), tp, 759 &(el_ent->cf_ent.ainfo))) 760 el_ent->mstat.attrchg = 1; 761 } 762 } else if (!el_ent->mstat.attrchg && 763 ((el_ent->cf_ent.ftype == 'd') || 764 (el_ent->cf_ent.ftype == 'x') || 765 (el_ent->cf_ent.ftype == 'c') || 766 (el_ent->cf_ent.ftype == 'b') || 767 (el_ent->cf_ent.ftype == 'p'))) { 768 n = averify(0, &(el_ent->cf_ent.ftype), tp, 769 &(el_ent->cf_ent.ainfo)); 770 if (n == VE_ATTR) 771 el_ent->mstat.attrchg = 1; 772 else if (n && (n != VE_EXIST)) { 773 el_ent->mstat.contchg = 1; 774 } 775 } else if (!el_ent->mstat.attrchg && 776 ((el_ent->cf_ent.ftype == 's') || 777 (el_ent->cf_ent.ftype == 'l'))) { 778 n = averify(0, &(el_ent->cf_ent.ftype), tp, 779 &(el_ent->cf_ent.ainfo)); 780 if (n == VE_ATTR) 781 el_ent->mstat.attrchg = 1; 782 else if (n && (n == VE_EXIST)) { 783 el_ent->mstat.contchg = 1; 784 } 785 } 786 } 787 788 static int 789 is_setuid(struct cfent *ent) 790 { 791 return (((ent->ftype == 'f') || (ent->ftype == 'v') || 792 (ent->ftype == 'e')) && 793 (ent->ainfo.mode != BADMODE) && 794 (ent->ainfo.mode != WILDCARD) && 795 (ent->ainfo.mode & S_ISUID)); 796 } 797 798 static int 799 is_setgid(struct cfent *ent) 800 { 801 return (((ent->ftype == 'f') || (ent->ftype == 'v') || 802 (ent->ftype == 'e')) && (ent->ainfo.mode != BADMODE) && 803 (ent->ainfo.mode != WILDCARD) && 804 (ent->ainfo.mode & S_ISGID) && 805 (ent->ainfo.mode & (S_IEXEC|S_IXUSR|S_IXOTH))); 806 } 807 808 char *types[] = { 809 "fev", /* type 1, regular files */ 810 "s", /* type 2, symbolic links */ 811 "l", /* type 3, linked files */ 812 "dx", /* type 4, directories */ 813 "c", /* type 5, character special devices */ 814 "b", /* type 6, block special devices */ 815 "p", /* type 7, named pipes */ 816 NULL 817 }; 818 819 /* 820 * This determines if the ftype of the file on the disk and the file to be 821 * laid down are close enough. If they aren't, this either returns an error 822 * or displays a warning. This returns : 823 * TYPE_OK they're identical or close enough 824 * TYPE_WARNING they're pretty close (probably no problem) 825 * TYPE_IGNORED the type change was not allowed 826 * TYPE_REPLACE to be reviewed later - in endofclass() maybe 827 * TYPE_FATAL something awful happened 828 */ 829 static int 830 typechg(struct cfent *el_ent, struct cfent *cf_ent, struct mergstat *mstat) 831 { 832 int i, etype, itype, retcode; 833 834 /* If they are identical, return OK */ 835 if (cf_ent->ftype == el_ent->ftype) 836 return (TYPE_OK); 837 838 /* 839 * If package database entry is ambiguous, set it to the new entity's 840 * ftype 841 */ 842 if (cf_ent->ftype == BADFTYPE) { 843 cf_ent->ftype = el_ent->ftype; 844 return (TYPE_OK); /* do nothing; not really different */ 845 } 846 847 /* If the new entity is ambiguous, wait for the verify */ 848 if (el_ent->ftype == BADFTYPE) 849 return (TYPE_OK); 850 851 /* 852 * If we're trying to convert an existing regular directory to an 853 * exclusive directory, this is very dangerous. We will continue, but 854 * we will deny the conversion. 855 */ 856 if (el_ent->ftype == 'x' && cf_ent->ftype == 'd') { 857 logerr(gettext(WRN_TOEXCL), el_ent->path); 858 return (TYPE_IGNORED); 859 } 860 861 etype = itype = 0; 862 863 /* Set etype to that of the new entity */ 864 for (i = 0; types[i]; ++i) { 865 if (strchr(types[i], el_ent->ftype)) { 866 etype = i+1; 867 break; 868 } 869 } 870 871 /* Set itype to that in the package database. */ 872 for (i = 0; types[i]; ++i) { 873 if (strchr(types[i], cf_ent->ftype)) { 874 itype = i+1; 875 break; 876 } 877 } 878 879 if (itype == etype) { 880 /* same basic object type */ 881 return (TYPE_OK); 882 } 883 884 retcode = TYPE_WARNING; 885 886 /* 887 * If a simple object (like a file) is overwriting a directory, mark 888 * it for full inspection during installation. 889 */ 890 if (etype != 4 && itype == 4) { 891 mstat->dir2nondir = 1; 892 retcode = TYPE_REPLACE; 893 } 894 895 /* allow change, but warn user of possible problems */ 896 switch (itype) { 897 case 1: 898 logerr(gettext(WRN_NOTFILE), el_ent->path); 899 break; 900 901 case 2: 902 logerr(gettext(WRN_NOTSYMLN), el_ent->path); 903 break; 904 905 case 3: 906 logerr(gettext(WRN_NOTLINK), el_ent->path); 907 break; 908 909 case 4: 910 logerr(gettext(WRN_NOTDIR), el_ent->path); 911 break; 912 913 case 5: 914 logerr(gettext(WRN_NOTCHAR), el_ent->path); 915 break; 916 917 case 6: 918 logerr(gettext(WRN_NOTBLOCK), el_ent->path); 919 break; 920 921 case 7: 922 logerr(gettext(WRN_NOTPIPE), el_ent->path); 923 break; 924 925 default: 926 break; 927 } 928 return (retcode); 929 } 930 931 /* 932 * This function takes el_ent (the entry from the pkgmap) and cf_ent (the 933 * entry from the package database) and merge them into el_ent. The rules 934 * are still being figured out, but the comments should make the approach 935 * pretty clear. 936 * 937 * RETURN CODES: 938 * MRG_DIFFERENT The two entries are different and el_ent now contains 939 * the intended new entry to be installed. 940 * MRG_SAME The two entries were identical and the old database 941 * entry will be replaced unchanged. 942 * MRG_REPLACE One or the other entry will be used but the decision 943 * has to be made at install time. 944 */ 945 static int 946 merg(struct cfextra *el_ent, struct cfent *cf_ent) 947 { 948 int n, changed = 0; 949 950 /* 951 * We need to change the original entry to make it look like the new 952 * entry (the eptstat() routine has already added appropriate package 953 * information, but not about 'aclass' which may represent a change 954 * in class from the previous installation. 955 * 956 * NOTE: elent->cf_ent.pinfo (the list of associated packages) is NULL 957 * upon entry to this function. 958 */ 959 960 el_ent->cf_ent.pinfo = cf_ent->pinfo; 961 962 if (dbst == INST_RDY && el_ent->cf_ent.ftype == '?') { 963 el_ent->cf_ent.ftype = cf_ent->ftype; 964 } 965 966 /* 967 * Evaluate the ftype change. Usually the ftype won't change. If it 968 * does it may be easy (s -> f), not allowed (d -> x), so complex we 969 * can't figure it 'til later (d -> s) or fatal (a hook for later). 970 */ 971 if (cf_ent->ftype != el_ent->cf_ent.ftype) { 972 n = typechg(&(el_ent->cf_ent), cf_ent, &(el_ent->mstat)); 973 974 switch (n) { 975 case TYPE_OK: 976 break; 977 978 /* This is an allowable change. */ 979 case TYPE_WARNING: 980 el_ent->mstat.contchg = 1; 981 break; 982 983 /* Not allowed, but leaving it as is is OK. */ 984 case TYPE_IGNORED: 985 logerr(gettext(MSG_TYPIGN)); 986 if (cp_cfent(cf_ent, el_ent) == 0) 987 quit(99); 988 return (MRG_SAME); 989 990 /* Future analysis will reveal if this is OK. */ 991 case TYPE_REPLACE: 992 el_ent->mstat.replace = 1; 993 return (MRG_REPLACE); 994 995 /* Kill it before it does any damage. */ 996 case TYPE_FATAL: 997 logerr(gettext(MSG_TYPE_ERR)); 998 quit(99); 999 1000 default: 1001 break; 1002 } 1003 1004 changed++; 1005 } 1006 1007 /* Evaluate and merge the class. */ 1008 if (strcmp(cf_ent->pkg_class, el_ent->cf_ent.pkg_class)) { 1009 /* 1010 * we always allow a class change as long as we have 1011 * consistent ftypes, which at this point we must 1012 */ 1013 changed++; 1014 if (strcmp(cf_ent->pkg_class, "?")) { 1015 (void) strcpy(pkgpinfo->aclass, 1016 el_ent->cf_ent.pkg_class); 1017 (void) strcpy(el_ent->cf_ent.pkg_class, 1018 cf_ent->pkg_class); 1019 chgclass(&(el_ent->cf_ent), pkgpinfo); 1020 } 1021 } 1022 1023 /* 1024 * Evaluate and merge based upon the ftype of the intended package 1025 * database entry. 1026 */ 1027 if (((el_ent->cf_ent.ftype == 's') || (el_ent->cf_ent.ftype == 'l'))) { 1028 1029 /* If both have link sources, then they need to be merged. */ 1030 if (cf_ent->ainfo.local && el_ent->cf_ent.ainfo.local) { 1031 /* 1032 * If both sources are identical, the merge is 1033 * already done. 1034 */ 1035 if (strcmp(cf_ent->ainfo.local, 1036 el_ent->cf_ent.ainfo.local) != NULL) { 1037 changed++; 1038 1039 /* 1040 * Otherwise, if the pkgmap entry is 1041 * ambiguous, it will inherit the database 1042 * entry. 1043 */ 1044 if (strcmp(el_ent->cf_ent.ainfo.local, 1045 "?") == NULL) { 1046 (void) strlcpy( 1047 el_ent->cf_ent.ainfo.local, 1048 cf_ent->ainfo.local, 1049 PATH_MAX); 1050 } else { 1051 el_ent->mstat.contchg = 1; 1052 } 1053 } 1054 } 1055 return (changed ? MRG_DIFFERENT : MRG_SAME); 1056 1057 } else if (el_ent->cf_ent.ftype == 'e') { 1058 1059 /* 1060 * The contents of edittable files are assumed to be changing 1061 * since some class action script will be doing the work and 1062 * we have no way of evaluating what it will actually do. 1063 */ 1064 el_ent->mstat.contchg = 1; 1065 changed++; 1066 } else if (((el_ent->cf_ent.ftype == 'f') || 1067 (el_ent->cf_ent.ftype == 'v'))) { 1068 /* 1069 * For regular files, Look at content information; a BADCONT 1070 * in any el_ent field indicates the contents are unknown -- 1071 * since cf_ent is guaranteed to have a valid entry here (bad 1072 * assumption?) this function will recognize this as a 1073 * change. The ambiguous el_ent values will be evaluated and 1074 * set later. 1075 */ 1076 1077 /* 1078 * for type f/v files, if the file is in an area that is 1079 * inherited from the global zone, that area is read only 1080 * and the object cannot be changed - ignore any settings 1081 * in the current package database that may be present for 1082 * any existing object because they are irrelevant - since 1083 * the object is in a read-only area shared from the global 1084 * zone, accept that file's actual attributes as being correct. 1085 */ 1086 1087 if (z_path_is_inherited(el_ent->cf_ent.path, 1088 el_ent->cf_ent.ftype, get_inst_root()) == B_TRUE) { 1089 echoDebug(DBG_PKGDBMRG_INHERITED, el_ent->cf_ent.path); 1090 } else if (cf_ent->cinfo.size != el_ent->cf_ent.cinfo.size) { 1091 changed++; 1092 el_ent->mstat.contchg = 1; 1093 } else if (cf_ent->cinfo.modtime != 1094 el_ent->cf_ent.cinfo.modtime) { 1095 changed++; 1096 el_ent->mstat.contchg = 1; 1097 } else if (cf_ent->cinfo.cksum != el_ent->cf_ent.cinfo.cksum) { 1098 changed++; 1099 el_ent->mstat.contchg = 1; 1100 } 1101 } else if (((el_ent->cf_ent.ftype == 'c') || 1102 (el_ent->cf_ent.ftype == 'b'))) { 1103 /* 1104 * For devices, if major or minor numbers are identical the 1105 * merge is trivial. If the el_ent value is ambiguous (BAD), 1106 * the cf_ent value is inherited. Otherwise, the el_ent value 1107 * is preserved. 1108 */ 1109 if (cf_ent->ainfo.major != el_ent->cf_ent.ainfo.major) { 1110 changed++; 1111 if (el_ent->cf_ent.ainfo.major == BADMAJOR) { 1112 el_ent->cf_ent.ainfo.major = 1113 cf_ent->ainfo.major; 1114 } else { 1115 el_ent->mstat.contchg = 1; 1116 } 1117 } 1118 if (cf_ent->ainfo.minor != el_ent->cf_ent.ainfo.minor) { 1119 changed++; 1120 if (el_ent->cf_ent.ainfo.minor == BADMINOR) 1121 el_ent->cf_ent.ainfo.minor = 1122 cf_ent->ainfo.minor; 1123 else 1124 el_ent->mstat.contchg = 1; 1125 } 1126 } 1127 1128 /* 1129 * For mode, owner and group follow the same rules as above - if 1130 * ambiguous, inherit, otherwise keep the new one. 1131 */ 1132 if (cf_ent->ainfo.mode != el_ent->cf_ent.ainfo.mode) { 1133 changed++; /* attribute info is changing */ 1134 if (el_ent->cf_ent.ainfo.mode == BADMODE) { 1135 el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode; 1136 } else if (el_ent->cf_ent.ainfo.mode == WILDCARD) { 1137 /* 1138 * If pkgmap has a '?' set for mode, use the mode from 1139 * the pkg DB (contents file). 1140 */ 1141 el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode; 1142 el_ent->mstat.attrchg = 0; 1143 } else { 1144 el_ent->mstat.attrchg = 1; 1145 } 1146 } 1147 if (strcmp(cf_ent->ainfo.owner, el_ent->cf_ent.ainfo.owner) != 0) { 1148 changed++; /* attribute info is changing */ 1149 if (strcmp(el_ent->cf_ent.ainfo.owner, BADOWNER) == 0) 1150 (void) strcpy(el_ent->cf_ent.ainfo.owner, 1151 cf_ent->ainfo.owner); 1152 else 1153 el_ent->mstat.attrchg = 1; 1154 } 1155 if (strcmp(cf_ent->ainfo.group, el_ent->cf_ent.ainfo.group) != 0) { 1156 changed++; /* attribute info is changing */ 1157 if (strcmp(el_ent->cf_ent.ainfo.group, BADGROUP) == 0) 1158 (void) strcpy(el_ent->cf_ent.ainfo.group, 1159 cf_ent->ainfo.group); 1160 else 1161 el_ent->mstat.attrchg = 1; 1162 } 1163 return (changed ? MRG_DIFFERENT : MRG_SAME); 1164 } 1165 1166 /* 1167 * This puts the current entry into the package database in the appropriate 1168 * intermediate format for this stage of the installation. This also assures 1169 * the correct format for the various package object ftypes, stripping the 1170 * link name before storing a regular file and stuff like that. 1171 */ 1172 1173 static void 1174 output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo) 1175 { 1176 short svvolno; 1177 char *svpt; 1178 1179 /* output without volume information */ 1180 svvolno = ent->volno; 1181 ent->volno = 0; 1182 1183 pinfo->editflag = 0; 1184 if (((ent->ftype == 's') || (ent->ftype == 'l'))) { 1185 if (putcvfpfile(ent, vfpo)) { 1186 progerr(gettext(ERR_OUTPUT)); 1187 quit(99); 1188 } 1189 } else { 1190 1191 /* output without local pathname */ 1192 svpt = ent->ainfo.local; 1193 ent->ainfo.local = NULL; 1194 if (putcvfpfile(ent, vfpo)) { 1195 progerr(gettext(ERR_OUTPUT)); 1196 quit(99); 1197 } 1198 1199 ent->ainfo.local = svpt; 1200 /* 1201 * If this entry represents a file which is being edited, we 1202 * need to store in memory the fact that it is an edittable 1203 * file so that when we audit it after installation we do not 1204 * worry about its contents; we do this by resetting the ftype 1205 * to 'e' in the memory array which is later used to control 1206 * the audit 1207 */ 1208 if (pinfo->editflag) 1209 ent->ftype = 'e'; 1210 } 1211 /* restore volume information */ 1212 ent->volno = svvolno; 1213 } 1214 1215 static void 1216 chgclass(struct cfent *cf_ent, struct pinfo *pinfo) 1217 { 1218 struct pinfo *pp; 1219 char *oldclass, newclass[CLSSIZ+1]; 1220 int newcnt, oldcnt; 1221 1222 /* 1223 * we use this routine to minimize the use of the aclass element by 1224 * optimizing the use of the cf_ent->pkg_class element 1225 */ 1226 1227 (void) strlcpy(newclass, pinfo->aclass, sizeof (newclass)); 1228 newcnt = 1; 1229 1230 oldclass = cf_ent->pkg_class; 1231 oldcnt = 0; 1232 1233 /* 1234 * count the number of times the newclass will be used and see if it 1235 * exceeds the number of times the oldclass is referenced 1236 */ 1237 pp = cf_ent->pinfo; 1238 while (pp) { 1239 if (pp->aclass[0] != '\0') { 1240 if (strcmp(pp->aclass, newclass) == 0) 1241 newcnt++; 1242 else if (strcmp(pp->aclass, oldclass) == 0) 1243 oldcnt++; 1244 } 1245 pp = pp->next; 1246 } 1247 if (newcnt > oldcnt) { 1248 pp = cf_ent->pinfo; 1249 while (pp) { 1250 if (pp->aclass[0] == '\0') { 1251 (void) strcpy(pp->aclass, oldclass); 1252 } else if (strcmp(pp->aclass, newclass) == 0) { 1253 pp->aclass[0] = '\0'; 1254 } 1255 pp = pp->next; 1256 } 1257 (void) strcpy(cf_ent->pkg_class, newclass); 1258 } 1259 } 1260