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 32 #include <stdio.h> 33 #include <limits.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <utime.h> 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/stat.h> 40 #include <sys/statvfs.h> 41 #include <grp.h> 42 #include <pwd.h> 43 #include <errno.h> 44 #include <string.h> 45 #include <stdarg.h> 46 #include <fcntl.h> 47 #include <sys/mkdev.h> 48 #include "pkgstrct.h" 49 #include "pkglib.h" 50 #include "pkglibmsgs.h" 51 #include "pkglocale.h" 52 53 #define WDMSK 0xFFFF 54 #define DATEFMT "%D %r" 55 #define LONG_BOUNDARY ((sizeof (unsigned long))-1) 56 #define CHUNK 1024*1024 57 58 static char theErrBuf[PATH_MAX+512] = {'\0'}; 59 static char *theErrStr = NULL; 60 61 /* checksum disable switch */ 62 static int enable_checksum = 1; 63 64 /* attribute disable flag */ 65 static int disable_attributes = 0; 66 67 /* non-ABI symlinks supported */ 68 static int nonabi_symlinks; 69 70 /* 71 * forward declarations 72 */ 73 74 static int clear_target(char *path, char *ftype, int is_a_dir); 75 76 unsigned long compute_checksum(int *r_err, char *path); 77 78 /* union used to generate checksum */ 79 typedef union hilo { 80 struct part { 81 uint16_t hi; 82 uint16_t lo; 83 } hl; 84 uint32_t lg; 85 } CHECKSUM_T; 86 87 /*PRINTFLIKE1*/ 88 static void 89 reperr(char *fmt, ...) 90 { 91 char *pt; 92 ssize_t ptln; 93 va_list ap; 94 int n; 95 96 if (fmt == (char *)NULL) { 97 theErrBuf[0] = '\0'; 98 } else { 99 if (n = strlen(theErrBuf)) { 100 pt = theErrBuf + n; 101 *pt++ = '\n'; 102 *pt = '\0'; 103 ptln = sizeof (theErrBuf)-n; 104 } else { 105 pt = theErrBuf; 106 ptln = sizeof (theErrBuf); 107 } 108 va_start(ap, fmt); 109 /* LINTED variable format specifier to vsnprintf() */ 110 (void) vsnprintf(pt, ptln, fmt, ap); 111 va_end(ap); 112 } 113 } 114 115 /* 116 * Name: cverify 117 * Description: This function verifies and (if fix > 0) fixes the contents 118 * of the file at the path provided 119 * Arguments: fix - 0 - do not fix entries, 1 - fix entries 120 * ftype - single character "type" the entry is supposed to be 121 * path - path to file 122 * cinfo - content info structure representing the contents 123 * the entry is supposed to contain 124 * allow_checksum - determine if checksumming should be disabled: 125 * == 0 - do not perform checksum ever - override enable_checksum. 126 * != 0 - use the default checksum flag "enable_checksum" to 127 * determine if checksumming should be done. 128 * NOTE: modification and creation times can be repaired; the contents 129 * of the file cannot be corrected if the checksum indicates that 130 * the contents are not correct - VE_CONT will be returned in this 131 * case. 132 * Possible return values: 133 * - 0 = successful 134 * - VE_EXIST = path name does not exist 135 * - VE_FTYPE = path file type is not recognized, is not supported, 136 * or is not what was expected 137 * - VE_ATTR = path mode/group/user is not what was expected 138 * - VE_CONT = mod time/link target/major/minor/size/file system type/current 139 * directory is not what was expected 140 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ 141 * chown failed 142 */ 143 144 int 145 cverify(int fix, char *ftype, char *path, struct cinfo *cinfo, 146 int allow_checksum) 147 { 148 struct stat status; /* file status buffer */ 149 struct utimbuf times; 150 unsigned long mycksum; 151 int setval, retcode; 152 char tbuf1[512]; 153 char tbuf2[512]; 154 int cksumerr; 155 156 setval = (*ftype == '?'); 157 retcode = 0; 158 reperr(NULL); 159 160 if (stat(path, &status) < 0) { 161 reperr(pkg_gt(ERR_EXIST)); 162 return (VE_EXIST); 163 } 164 165 /* -1 requires modtimes to be the same */ 166 /* 0 reports modtime failure */ 167 /* 1 fixes modtimes */ 168 169 if (setval || (cinfo->modtime == BADCONT)) { 170 cinfo->modtime = status.st_mtime; 171 } else if (status.st_mtime != cinfo->modtime) { 172 if (fix > 0) { 173 /* reset times on the file */ 174 times.actime = cinfo->modtime; 175 times.modtime = cinfo->modtime; 176 if (utime(path, ×)) { 177 reperr(pkg_gt(ERR_MODFAIL)); 178 retcode = VE_FAIL; 179 } 180 } else if (fix < 0) { 181 /* modtimes must be the same */ 182 if (strftime(tbuf1, sizeof (tbuf1), DATEFMT, 183 localtime(&cinfo->modtime)) == 0) { 184 reperr(pkg_gt(ERR_MEM)); 185 } 186 if (strftime(tbuf2, sizeof (tbuf2), DATEFMT, 187 localtime(&status.st_mtime)) == 0) { 188 reperr(pkg_gt(ERR_MEM)); 189 } 190 reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2); 191 retcode = VE_CONT; 192 } 193 } 194 195 if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) { 196 cinfo->size = status.st_size; 197 } else if (status.st_size != cinfo->size) { 198 if (!retcode) { 199 retcode = VE_CONT; 200 } 201 reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size); 202 } 203 204 cksumerr = 0; 205 206 /* 207 * see if checksumming should be done: if checksumming is allowed, 208 * and checksumming is enabled, then checksum the file. 209 */ 210 211 /* return if no need to compute checksum */ 212 213 if ((allow_checksum == 0) || (enable_checksum == 0)) { 214 return (retcode); 215 } 216 217 /* compute checksum */ 218 219 mycksum = compute_checksum(&cksumerr, path); 220 221 /* set value if not set or if checksum cannot be computed */ 222 223 if (setval || (cinfo->cksum == BADCONT)) { 224 cinfo->cksum = mycksum; 225 return (retcode); 226 } 227 228 /* report / return error if checksums mismatch or there is an error */ 229 230 if ((mycksum != cinfo->cksum) || cksumerr) { 231 if (!retcode) { 232 retcode = VE_CONT; 233 } 234 if (!cksumerr) { 235 reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum); 236 } 237 } 238 239 return (retcode); 240 } 241 242 /* 243 * Name: compute_checksum 244 * Description: generate checksum for specified file 245 * Arguments: r_cksumerr (int *) [RO, *RW] 246 * - pointer to integer that is set on return to: 247 * == 0 - no error occurred 248 * != 0 - error occurred 249 * a_path (char *) [RO, *RO] 250 * - pointer to string representing path to file to 251 * generate checksum of 252 * Returns: unsigned long - results: 253 * - If *r_cksumerr == 0, checksum of specified file 254 * - If *r_cksumerr != 0, undefined 255 */ 256 unsigned long 257 compute_checksum(int *r_cksumerr, char *a_path) 258 { 259 CHECKSUM_T suma; /* to split four-bytes into 2 two-byte values */ 260 CHECKSUM_T tempa; 261 int fd; 262 uint32_t lg; /* running checksum value */ 263 uint32_t buf[CHUNK/4]; /* to read CHUNK bytes */ 264 uint32_t lsavhi; /* high order two-bytes of four-byte checksum */ 265 uint32_t lsavlo; /* low order two-bytes of four-byte checksum */ 266 int leap = sizeof (uint32_t); 267 int notyet = 0; 268 int nread; 269 struct stat64 sbuf; 270 271 /* reset error flag */ 272 *r_cksumerr = 0; 273 274 /* open file and obtain -> where file is mapped/read */ 275 if ((fd = open(a_path, O_RDONLY)) < 0) { 276 *r_cksumerr = 1; 277 reperr(pkg_gt(ERR_NO_CKSUM)); 278 perror(ERR_NO_CKSUM); 279 return (0); 280 } 281 282 if (fstat64(fd, &sbuf) != 0) { 283 *r_cksumerr = 1; 284 reperr(pkg_gt(ERR_NO_CKSUM)); 285 perror(ERR_NO_CKSUM); 286 return (0); 287 } 288 289 /* initialize checksum value */ 290 lg = 0; 291 292 /* 293 * Read CHUNK bytes off the file at a time; Read size of long bytes 294 * from memory at a time and process them. 295 * If last read, then read remnant bytes and process individually. 296 */ 297 errno = 0; 298 while ((nread = read(fd, (void*)buf, 299 (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) { 300 uchar_t *s; 301 uint32_t *p = buf; 302 303 notyet = nread % leap; 304 nread -= notyet; 305 306 for (; nread > 0; nread -= leap) { 307 lg += ((((*p)>>24)&0xFF) & WDMSK); 308 lg += ((((*p)>>16)&0xFF) & WDMSK); 309 lg += ((((*p)>>8)&0xFF) & WDMSK); 310 lg += (((*p)&0xFF) & WDMSK); 311 p++; 312 } 313 s = (uchar_t *)p; 314 /* leftover bytes less than four in number */ 315 while (notyet--) 316 lg += (((uint32_t)(*s++)) & WDMSK); 317 } 318 319 /* wind up */ 320 (void) close(fd); 321 322 /* compute checksum components */ 323 suma.lg = lg; 324 tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK); 325 lsavhi = (uint32_t)tempa.hl.hi; 326 lsavlo = (uint32_t)tempa.hl.lo; 327 328 /* return final checksum value */ 329 return (lsavhi+lsavlo); 330 } 331 332 static struct stat status; /* file status buffer */ 333 static struct statvfs vfsstatus; /* filesystem status buffer */ 334 335 /* 336 * Remove the thing that's currently in place so we can put down the package 337 * object. If we're replacing a directory with a directory, leave it alone. 338 * Returns 1 if all OK and 0 if failed. 339 */ 340 static int 341 clear_target(char *path, char *ftype, int is_a_dir) 342 { 343 int retcode = 1; 344 345 if (is_a_dir) { /* if there's a directory there already ... */ 346 /* ... and this isn't, ... */ 347 if ((*ftype != 'd') && (*ftype != 'x')) { 348 if (rmdir(path)) { /* try to remove it. */ 349 reperr(pkg_gt(ERR_RMDIR), path); 350 retcode = 0; 351 } 352 } 353 } else { 354 if (remove(path)) { 355 if (errno != ENOENT) { 356 retcode = 0; /* It didn't work. */ 357 } 358 } 359 } 360 361 return (retcode); 362 } 363 364 /* 365 * Name: averify 366 * Description: This function verifies and (if fix > 0) fixes the attributes 367 * of the file at the path provided. 368 * Arguments: fix - 0 - do not fix entries, 1 - fix entries 369 * ftype - single character "type" the entry is supposed to be 370 * path - path to file 371 * ainfo - attribute info structure representing the attributes 372 * the entry is supposed to be 373 * NOTE: attributes are links and permissions 374 * Possible return values: 375 * - 0 = successful 376 * - VE_EXIST = path name does not exist 377 * - VE_FTYPE = path file type is not recognized, is not supported, 378 * or is not what was expected 379 * - VE_ATTR = path mode/group/user is not what was expected 380 * - VE_CONT = mod time/link target/major/minor/size/file system type/current 381 * directory is not what was expected 382 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ 383 * chown failed 384 */ 385 int 386 averify(int fix, char *ftype, char *path, struct ainfo *ainfo) 387 { 388 struct group *grp; /* group entry buffer */ 389 struct passwd *pwd; 390 int n; 391 int setval; 392 int uid, gid; 393 int dochown; 394 int retcode; 395 int statError = 0; 396 int targ_is_dir = 0; /* replacing a directory */ 397 char myftype; 398 char buf[PATH_MAX]; 399 ino_t my_ino; 400 dev_t my_dev; 401 char cwd[MAXPATHLEN]; 402 char *cd; 403 char *c; 404 405 setval = (*ftype == '?'); 406 retcode = 0; 407 reperr(NULL); 408 409 if (get_disable_attribute_check()) { 410 return (0); 411 } 412 413 if (*ftype == 'l') { 414 if (stat(path, &status) < 0) { 415 retcode = VE_EXIST; 416 reperr(pkg_gt(ERR_EXIST)); 417 } 418 419 my_ino = status.st_ino; 420 my_dev = status.st_dev; 421 422 /* Get copy of the current working directory */ 423 if (getcwd(cwd, MAXPATHLEN) == NULL) { 424 reperr(pkg_gt(ERR_GETWD), ainfo->local); 425 return (VE_FAIL); 426 } 427 428 /* 429 * Change to the directory in which the hard 430 * link is to be created. 431 */ 432 cd = strdup(path); 433 c = strrchr(cd, '/'); 434 if (c) { 435 /* bugid 4247895 */ 436 if (strcmp(cd, c) == 0) 437 strcpy(cd, "/"); 438 else 439 *c = NULL; 440 441 if (chdir(cd) != 0) { 442 reperr(pkg_gt(ERR_CHDIR), cd); 443 return (VE_FAIL); 444 } 445 } 446 free(cd); 447 448 if (retcode || (status.st_nlink < 2) || 449 (stat(ainfo->local, &status) < 0) || 450 (my_dev != status.st_dev) || (my_ino != status.st_ino)) { 451 if (fix) { 452 /* 453 * Don't want to do a hard link to a 454 * directory. 455 */ 456 if (!isdir(ainfo->local)) { 457 chdir(cwd); 458 reperr(pkg_gt(ERR_LINKISDIR), 459 ainfo->local); 460 return (VE_FAIL); 461 } 462 /* Now do the link. */ 463 if (!clear_target(path, ftype, targ_is_dir)) 464 return (VE_FAIL); 465 466 if (link(ainfo->local, path)) { 467 chdir(cwd); 468 reperr(pkg_gt(ERR_LINKFAIL), 469 ainfo->local); 470 return (VE_FAIL); 471 } 472 retcode = 0; 473 } else { 474 /* Go back to previous working directory */ 475 if (chdir(cwd) != 0) 476 reperr(pkg_gt(ERR_CHDIR), cwd); 477 478 reperr(pkg_gt(ERR_LINK), ainfo->local); 479 return (VE_CONT); 480 } 481 } 482 483 /* Go back to previous working directory */ 484 if (chdir(cwd) != 0) { 485 reperr(pkg_gt(ERR_CHDIR), cwd); 486 return (VE_CONT); 487 } 488 489 return (retcode); 490 } 491 492 retcode = 0; 493 494 /* If we are to process symlinks the old way then we follow the link */ 495 if (nonABI_symlinks()) { 496 if ((*ftype == 's') ? lstat(path, &status) : 497 stat(path, &status)) { 498 reperr(pkg_gt(ERR_EXIST)); 499 retcode = VE_EXIST; 500 myftype = '?'; 501 statError++; 502 } 503 /* If not then we inspect the target of the link */ 504 } else { 505 if ((n = lstat(path, &status)) == -1) { 506 reperr(pkg_gt(ERR_EXIST)); 507 retcode = VE_EXIST; 508 myftype = '?'; 509 statError++; 510 } 511 } 512 if (!statError) { 513 /* determining actual type of existing object */ 514 switch (status.st_mode & S_IFMT) { 515 case S_IFLNK: 516 myftype = 's'; 517 break; 518 519 case S_IFIFO: 520 myftype = 'p'; 521 break; 522 523 case S_IFCHR: 524 myftype = 'c'; 525 break; 526 527 case S_IFDIR: 528 myftype = 'd'; 529 targ_is_dir = 1; 530 break; 531 532 case S_IFBLK: 533 myftype = 'b'; 534 break; 535 536 case S_IFREG: 537 case 0: 538 myftype = 'f'; 539 break; 540 541 case S_IFDOOR: 542 myftype = 'D'; 543 break; 544 545 default: 546 reperr(pkg_gt(ERR_UNKNOWN)); 547 return (VE_FTYPE); 548 } 549 } 550 551 if (setval) { 552 /* 553 * Check to make sure that a package or an installf that uses 554 * wild cards '?' to assume the ftype of an object on the 555 * system is not assuming a door ftype. Doors are not supported 556 * but should be ignored. 557 */ 558 if (myftype == 'D') { 559 reperr(pkg_gt(ERR_FTYPED), path); 560 retcode = VE_FTYPE; 561 return (VE_FTYPE); 562 } else { 563 *ftype = myftype; 564 } 565 } else if (!retcode && (*ftype != myftype) && 566 ((myftype != 'f') || !strchr("ilev", *ftype)) && 567 ((myftype != 'd') || (*ftype != 'x'))) { 568 reperr(pkg_gt(ERR_FTYPE), *ftype, myftype); 569 retcode = VE_FTYPE; 570 } 571 572 if (!retcode && (*ftype == 's')) { 573 /* make sure that symbolic link is correct */ 574 n = readlink(path, buf, PATH_MAX); 575 if (n < 0) { 576 reperr(pkg_gt(ERR_SLINK), ainfo->local); 577 retcode = VE_CONT; 578 } else if (ainfo->local != NULL) { 579 buf[n] = '\0'; 580 if (strcmp(buf, ainfo->local)) { 581 reperr(pkg_gt(ERR_SLINK), ainfo->local); 582 retcode = VE_CONT; 583 } 584 } else if (ainfo->local == NULL) { 585 /* 586 * Since a sym link target exists, insert it 587 * into the ainfo structure 588 */ 589 buf[n] = '\0'; 590 ainfo->local = strdup(buf); 591 } 592 } 593 594 if (retcode) { 595 /* The path doesn't exist or is different than it should be. */ 596 if (fix) { 597 /* 598 * Clear the way for the write. If it won't clear, 599 * there's nothing we can do. 600 */ 601 if (!clear_target(path, ftype, targ_is_dir)) 602 return (VE_FAIL); 603 604 if ((*ftype == 'd') || (*ftype == 'x')) { 605 char *pt, *p; 606 607 /* Try to make it the easy way */ 608 if (mkdir(path, ainfo->mode)) { 609 /* 610 * Failing that, walk through the 611 * parent directories creating 612 * whatever is needed. 613 */ 614 p = strdup(path); 615 pt = (*p == '/') ? p+1 : p; 616 do { 617 if (pt = strchr(pt, '/')) 618 *pt = '\0'; 619 if (access(p, 0) && 620 mkdir(p, ainfo->mode)) 621 break; 622 if (pt) 623 *pt++ = '/'; 624 } while (pt); 625 free(p); 626 } 627 if (stat(path, &status) < 0) { 628 reperr(pkg_gt(ERR_DIRFAIL)); 629 return (VE_FAIL); 630 } 631 } else if (*ftype == 's') { 632 if (symlink(ainfo->local, path)) { 633 reperr(pkg_gt(ERR_SLINKFAIL), 634 ainfo->local); 635 return (VE_FAIL); 636 } 637 638 } else if (*ftype == 'c') { 639 int wilddevno = 0; 640 /* 641 * The next three if's support 2.4 and older 642 * packages that use "?" as device numbers. 643 * This should be considered for removal by 644 * release 2.7 or so. 645 */ 646 if (ainfo->major == BADMAJOR) { 647 ainfo->major = 0; 648 wilddevno = 1; 649 } 650 651 if (ainfo->minor == BADMINOR) { 652 ainfo->minor = 0; 653 wilddevno = 1; 654 } 655 656 if (wilddevno) { 657 wilddevno = 0; 658 logerr(MSG_WLDDEVNO, path, 659 ainfo->major, ainfo->minor); 660 } 661 662 if (mknod(path, ainfo->mode | S_IFCHR, 663 #ifdef SUNOS41 664 makedev(ainfo->xmajor, ainfo->xminor)) || 665 #else 666 makedev(ainfo->major, ainfo->minor)) || 667 #endif 668 (stat(path, &status) < 0)) { 669 reperr(pkg_gt(ERR_CDEVFAIL)); 670 return (VE_FAIL); 671 } 672 } else if (*ftype == 'b') { 673 int wilddevno = 0; 674 /* 675 * The next three if's support 2.4 and older 676 * packages that use "?" as device numbers. 677 * This should be considered for removal by 678 * release 2.7 or so. 679 */ 680 if (ainfo->major == BADMAJOR) { 681 ainfo->major = 0; 682 wilddevno = 1; 683 } 684 685 if (ainfo->minor == BADMINOR) { 686 ainfo->minor = 0; 687 wilddevno = 1; 688 } 689 690 if (wilddevno) { 691 wilddevno = 0; 692 logerr(MSG_WLDDEVNO, path, 693 ainfo->major, ainfo->minor); 694 } 695 696 if (mknod(path, ainfo->mode | S_IFBLK, 697 #ifdef SUNOS41 698 makedev(ainfo->xmajor, ainfo->xminor)) || 699 #else 700 makedev(ainfo->major, ainfo->minor)) || 701 #endif 702 (stat(path, &status) < 0)) { 703 reperr(pkg_gt(ERR_BDEVFAIL)); 704 return (VE_FAIL); 705 } 706 } else if (*ftype == 'p') { 707 if (mknod(path, ainfo->mode | S_IFIFO, NULL) || 708 (stat(path, &status) < 0)) { 709 reperr(pkg_gt(ERR_PIPEFAIL)); 710 return (VE_FAIL); 711 } 712 } else 713 return (retcode); 714 715 } else 716 return (retcode); 717 } 718 719 if (*ftype == 's') 720 return (0); /* don't check anything else */ 721 if (*ftype == 'i') 722 return (0); /* don't check anything else */ 723 724 retcode = 0; 725 if ((myftype == 'c') || (myftype == 'b')) { 726 #ifdef SUNOS41 727 if (setval || (ainfo->xmajor < 0)) 728 ainfo->xmajor = ((status.st_rdev>>8)&0377); 729 if (setval || (ainfo->xminor < 0)) 730 ainfo->xminor = (status.st_rdev&0377); 731 /* check major & minor */ 732 if (status.st_rdev != makedev(ainfo->xmajor, ainfo->xminor)) { 733 reperr(pkg_gt(ERR_MAJMIN), ainfo->xmajor, 734 ainfo->xminor, 735 (status.st_rdev>>8)&0377, status.st_rdev&0377); 736 retcode = VE_CONT; 737 } 738 #else 739 if (setval || (ainfo->major == BADMAJOR)) 740 ainfo->major = major(status.st_rdev); 741 if (setval || (ainfo->minor == BADMINOR)) 742 ainfo->minor = minor(status.st_rdev); 743 /* check major & minor */ 744 if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) { 745 reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor, 746 major(status.st_rdev), minor(status.st_rdev)); 747 retcode = VE_CONT; 748 } 749 #endif 750 } 751 752 /* compare specified mode w/ actual mode excluding sticky bit */ 753 if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD)) 754 ainfo->mode = status.st_mode & 07777; 755 else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) { 756 if (fix) { 757 if ((ainfo->mode == BADMODE) || 758 (chmod(path, ainfo->mode) < 0)) 759 retcode = VE_FAIL; 760 } else { 761 reperr(pkg_gt(ERR_PERM), ainfo->mode, 762 status.st_mode & 07777); 763 if (!retcode) 764 retcode = VE_ATTR; 765 } 766 } 767 768 dochown = 0; 769 770 /* get group entry for specified group */ 771 if (setval || strcmp(ainfo->group, BADGROUP) == 0) { 772 grp = cgrgid(status.st_gid); 773 if (grp) 774 (void) strcpy(ainfo->group, grp->gr_name); 775 else { 776 if (!retcode) 777 retcode = VE_ATTR; 778 reperr(pkg_gt(ERR_BADGRPID), status.st_gid); 779 } 780 gid = status.st_gid; 781 } else if ((grp = cgrnam(ainfo->group)) == NULL) { 782 reperr(pkg_gt(ERR_BADGRPNM), ainfo->group); 783 if (!retcode) 784 retcode = VE_ATTR; 785 } else if ((gid = grp->gr_gid) != status.st_gid) { 786 if (fix) { 787 /* save specified GID */ 788 gid = grp->gr_gid; 789 dochown++; 790 } else { 791 if ((grp = cgrgid((int)status.st_gid)) == 792 (struct group *)NULL) { 793 reperr(pkg_gt(ERR_GROUP), ainfo->group, 794 "(null)"); 795 } else { 796 reperr(pkg_gt(ERR_GROUP), ainfo->group, 797 grp->gr_name); 798 } 799 if (!retcode) 800 retcode = VE_ATTR; 801 } 802 } 803 804 /* get password entry for specified owner */ 805 if (setval || strcmp(ainfo->owner, BADOWNER) == 0) { 806 pwd = cpwuid((int)status.st_uid); 807 if (pwd) 808 (void) strcpy(ainfo->owner, pwd->pw_name); 809 else { 810 if (!retcode) 811 retcode = VE_ATTR; 812 reperr(pkg_gt(ERR_BADUSRID), status.st_uid); 813 } 814 uid = status.st_uid; 815 } else if ((pwd = cpwnam(ainfo->owner)) == NULL) { 816 /* UID does not exist in password file */ 817 reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner); 818 if (!retcode) 819 retcode = VE_ATTR; 820 } else if ((uid = pwd->pw_uid) != status.st_uid) { 821 /* get owner name for actual UID */ 822 if (fix) { 823 uid = pwd->pw_uid; 824 dochown++; 825 } else { 826 pwd = cpwuid((int)status.st_uid); 827 if (pwd == NULL) 828 reperr(pkg_gt(ERR_BADUSRID), 829 (int)status.st_uid); 830 else 831 reperr(pkg_gt(ERR_OWNER), ainfo->owner, 832 pwd->pw_name); 833 834 if (!retcode) 835 retcode = VE_ATTR; 836 } 837 } 838 839 if (statvfs(path, &vfsstatus) < 0) { 840 reperr(pkg_gt(ERR_EXIST)); 841 retcode = VE_FAIL; 842 } else { 843 if (dochown) { 844 /* pcfs doesn't support file ownership */ 845 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 && 846 chown(path, uid, gid) < 0) { 847 retcode = VE_FAIL; /* chown failed */ 848 } 849 } 850 } 851 852 if (retcode == VE_FAIL) 853 reperr(pkg_gt(ERR_ATTRFAIL)); 854 return (retcode); 855 } 856 857 /* 858 * This is a special fast verify which basically checks the attributes 859 * and then, if all is OK, checks the size and mod time using the same 860 * stat and statvfs structures. 861 */ 862 int 863 fverify(int fix, char *ftype, char *path, struct ainfo *ainfo, 864 struct cinfo *cinfo) 865 { 866 int retval; 867 868 /* return success if attribute checks are disabled */ 869 870 if (get_disable_attribute_check()) { 871 return (0); 872 } 873 874 if ((retval = averify(fix, ftype, path, ainfo)) == 0) { 875 if (*ftype == 'f' || *ftype == 'i') { 876 if (cinfo->size != status.st_size) { 877 reperr(pkg_gt(WRN_QV_SIZE), path); 878 retval = VE_CONT; 879 } 880 /* pcfs doesn't support modification times */ 881 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0) { 882 if (cinfo->modtime != status.st_mtime) { 883 reperr(pkg_gt(WRN_QV_MTIME), path); 884 retval = VE_CONT; 885 } 886 } 887 } 888 } 889 890 return (retval); 891 } 892 893 /* 894 * This function determines whether or not non-ABI symlinks are supported. 895 */ 896 897 int 898 nonABI_symlinks(void) 899 { 900 return (nonabi_symlinks); 901 } 902 903 void 904 set_nonABI_symlinks(void) 905 { 906 nonabi_symlinks = 1; 907 } 908 909 /* 910 * Disable attribute checking. Only disable attribute checking if files 911 * are guaranteed to exist in the FS. 912 */ 913 void 914 disable_attribute_check(void) 915 { 916 disable_attributes = 1; 917 } 918 919 /* 920 * This function determines whether or not to do attribute checking. 921 * Returns: 0 - Do attribute checking 922 * !0 - Don't do attribute checking 923 */ 924 int 925 get_disable_attribute_check(void) 926 { 927 return (disable_attributes); 928 } 929 930 /* 931 * This function returns the address of the "global" error buffer that 932 * is populated by the various functions in this module. 933 */ 934 935 char * 936 getErrbufAddr(void) 937 { 938 return (theErrBuf); 939 } 940 941 /* 942 * This function returns the size of the buffer returned by getErrbufAddr() 943 */ 944 945 int 946 getErrbufSize(void) 947 { 948 return (sizeof (theErrBuf)); 949 } 950 951 /* 952 * This function returns the current global "error string" 953 */ 954 955 char * 956 getErrstr(void) 957 { 958 return (theErrStr); 959 } 960 961 /* 962 * This function sets the global "error string" 963 */ 964 965 void 966 setErrstr(char *a_errstr) 967 { 968 theErrStr = a_errstr; 969 } 970 971 /* 972 * This function enables checksumming 973 */ 974 975 void 976 checksum_on(void) 977 { 978 enable_checksum = 1; 979 } 980 981 /* 982 * This function disables checksumming 983 */ 984 985 void 986 checksum_off(void) 987 { 988 enable_checksum = 0; 989 } 990