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