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