diff options
author | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
---|---|---|
committer | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
commit | 5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch) | |
tree | 0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/lib/libpkg/common/verify.c | |
parent | 2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff) | |
download | illumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz |
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/lib/libpkg/common/verify.c')
-rw-r--r-- | usr/src/lib/libpkg/common/verify.c | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/usr/src/lib/libpkg/common/verify.c b/usr/src/lib/libpkg/common/verify.c new file mode 100644 index 0000000000..c48c5b8c77 --- /dev/null +++ b/usr/src/lib/libpkg/common/verify.c @@ -0,0 +1,989 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + + +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <utime.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <grp.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> +#include <stdarg.h> +#include <fcntl.h> +#include <sys/mkdev.h> +#include "pkgstrct.h" +#include "pkglib.h" +#include "pkglibmsgs.h" +#include "pkglocale.h" + +#define WDMSK 0xFFFF +#define DATEFMT "%D %r" +#define LONG_BOUNDARY ((sizeof (unsigned long))-1) +#define CHUNK 1024*1024 + +static char theErrBuf[PATH_MAX+512] = {'\0'}; +static char *theErrStr = NULL; + +/* checksum disable switch */ +static int enable_checksum = 1; + +/* attribute disable flag */ +static int disable_attributes = 0; + +/* non-ABI symlinks supported */ +static int nonabi_symlinks; + +/* + * forward declarations + */ + +static int clear_target(char *path, char *ftype, int is_a_dir); + +unsigned long compute_checksum(int *r_err, char *path); + +/* union used to generate checksum */ +typedef union hilo { + struct part { + uint16_t hi; + uint16_t lo; + } hl; + uint32_t lg; +} CHECKSUM_T; + +/*PRINTFLIKE1*/ +static void +reperr(char *fmt, ...) +{ + char *pt; + ssize_t ptln; + va_list ap; + int n; + + if (fmt == (char *)NULL) { + theErrBuf[0] = '\0'; + } else { + if (n = strlen(theErrBuf)) { + pt = theErrBuf + n; + *pt++ = '\n'; + *pt = '\0'; + ptln = sizeof (theErrBuf)-n; + } else { + pt = theErrBuf; + ptln = sizeof (theErrBuf); + } + va_start(ap, fmt); + /* LINTED variable format specifier to vsnprintf() */ + (void) vsnprintf(pt, ptln, fmt, ap); + va_end(ap); + } +} + +/* + * Name: cverify + * Description: This function verifies and (if fix > 0) fixes the contents + * of the file at the path provided + * Arguments: fix - 0 - do not fix entries, 1 - fix entries + * ftype - single character "type" the entry is supposed to be + * path - path to file + * cinfo - content info structure representing the contents + * the entry is supposed to contain + * allow_checksum - determine if checksumming should be disabled: + * == 0 - do not perform checksum ever - override enable_checksum. + * != 0 - use the default checksum flag "enable_checksum" to + * determine if checksumming should be done. + * NOTE: modification and creation times can be repaired; the contents + * of the file cannot be corrected if the checksum indicates that + * the contents are not correct - VE_CONT will be returned in this + * case. + * Possible return values: + * - 0 = successful + * - VE_EXIST = path name does not exist + * - VE_FTYPE = path file type is not recognized, is not supported, + * or is not what was expected + * - VE_ATTR = path mode/group/user is not what was expected + * - VE_CONT = mod time/link target/major/minor/size/file system type/current + * directory is not what was expected + * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ + * chown failed + */ + +int +cverify(int fix, char *ftype, char *path, struct cinfo *cinfo, + int allow_checksum) +{ + struct stat status; /* file status buffer */ + struct utimbuf times; + unsigned long mycksum; + int setval, retcode; + char tbuf1[512]; + char tbuf2[512]; + int cksumerr; + + setval = (*ftype == '?'); + retcode = 0; + reperr(NULL); + + if (stat(path, &status) < 0) { + reperr(pkg_gt(ERR_EXIST)); + return (VE_EXIST); + } + + /* -1 requires modtimes to be the same */ + /* 0 reports modtime failure */ + /* 1 fixes modtimes */ + + if (setval || (cinfo->modtime == BADCONT)) { + cinfo->modtime = status.st_mtime; + } else if (status.st_mtime != cinfo->modtime) { + if (fix > 0) { + /* reset times on the file */ + times.actime = cinfo->modtime; + times.modtime = cinfo->modtime; + if (utime(path, ×)) { + reperr(pkg_gt(ERR_MODFAIL)); + retcode = VE_FAIL; + } + } else if (fix < 0) { + /* modtimes must be the same */ + if (strftime(tbuf1, sizeof (tbuf1), DATEFMT, + localtime(&cinfo->modtime)) == 0) { + reperr(pkg_gt(ERR_MEM)); + } + if (strftime(tbuf2, sizeof (tbuf2), DATEFMT, + localtime(&status.st_mtime)) == 0) { + reperr(pkg_gt(ERR_MEM)); + } + reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2); + retcode = VE_CONT; + } + } + + if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) { + cinfo->size = status.st_size; + } else if (status.st_size != cinfo->size) { + if (!retcode) { + retcode = VE_CONT; + } + reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size); + } + + cksumerr = 0; + + /* + * see if checksumming should be done: if checksumming is allowed, + * and checksumming is enabled, then checksum the file. + */ + + /* return if no need to compute checksum */ + + if ((allow_checksum == 0) || (enable_checksum == 0)) { + return (retcode); + } + + /* compute checksum */ + + mycksum = compute_checksum(&cksumerr, path); + + /* set value if not set or if checksum cannot be computed */ + + if (setval || (cinfo->cksum == BADCONT)) { + cinfo->cksum = mycksum; + return (retcode); + } + + /* report / return error if checksums mismatch or there is an error */ + + if ((mycksum != cinfo->cksum) || cksumerr) { + if (!retcode) { + retcode = VE_CONT; + } + if (!cksumerr) { + reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum); + } + } + + return (retcode); +} + +/* + * Name: compute_checksum + * Description: generate checksum for specified file + * Arguments: r_cksumerr (int *) [RO, *RW] + * - pointer to integer that is set on return to: + * == 0 - no error occurred + * != 0 - error occurred + * a_path (char *) [RO, *RO] + * - pointer to string representing path to file to + * generate checksum of + * Returns: unsigned long - results: + * - If *r_cksumerr == 0, checksum of specified file + * - If *r_cksumerr != 0, undefined + */ +unsigned long +compute_checksum(int *r_cksumerr, char *a_path) +{ + CHECKSUM_T suma; /* to split four-bytes into 2 two-byte values */ + CHECKSUM_T tempa; + int fd; + uint32_t lg; /* running checksum value */ + uint32_t buf[CHUNK/4]; /* to read CHUNK bytes */ + uint32_t lsavhi; /* high order two-bytes of four-byte checksum */ + uint32_t lsavlo; /* low order two-bytes of four-byte checksum */ + int leap = sizeof (uint32_t); + int notyet = 0; + int nread; + struct stat64 sbuf; + + /* reset error flag */ + *r_cksumerr = 0; + + /* open file and obtain -> where file is mapped/read */ + if ((fd = open(a_path, O_RDONLY)) < 0) { + *r_cksumerr = 1; + reperr(pkg_gt(ERR_NO_CKSUM)); + perror(ERR_NO_CKSUM); + return (0); + } + + if (fstat64(fd, &sbuf) != 0) { + *r_cksumerr = 1; + reperr(pkg_gt(ERR_NO_CKSUM)); + perror(ERR_NO_CKSUM); + return (0); + } + + /* initialize checksum value */ + lg = 0; + + /* + * Read CHUNK bytes off the file at a time; Read size of long bytes + * from memory at a time and process them. + * If last read, then read remnant bytes and process individually. + */ + errno = 0; + while ((nread = read(fd, (void*)buf, + (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) { + uchar_t *s; + uint32_t *p = buf; + + notyet = nread % leap; + nread -= notyet; + + for (; nread > 0; nread -= leap) { + lg += ((((*p)>>24)&0xFF) & WDMSK); + lg += ((((*p)>>16)&0xFF) & WDMSK); + lg += ((((*p)>>8)&0xFF) & WDMSK); + lg += (((*p)&0xFF) & WDMSK); + p++; + } + s = (uchar_t *)p; + /* leftover bytes less than four in number */ + while (notyet--) + lg += (((uint32_t)(*s++)) & WDMSK); + } + + /* wind up */ + (void) close(fd); + + /* compute checksum components */ + suma.lg = lg; + tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK); + lsavhi = (uint32_t)tempa.hl.hi; + lsavlo = (uint32_t)tempa.hl.lo; + + /* return final checksum value */ + return (lsavhi+lsavlo); +} + +static struct stat status; /* file status buffer */ +static struct statvfs vfsstatus; /* filesystem status buffer */ + +/* + * Remove the thing that's currently in place so we can put down the package + * object. If we're replacing a directory with a directory, leave it alone. + * Returns 1 if all OK and 0 if failed. + */ +static int +clear_target(char *path, char *ftype, int is_a_dir) +{ + int retcode = 1; + + if (is_a_dir) { /* if there's a directory there already ... */ + /* ... and this isn't, ... */ + if ((*ftype != 'd') && (*ftype != 'x')) { + if (rmdir(path)) { /* try to remove it. */ + reperr(pkg_gt(ERR_RMDIR), path); + retcode = 0; + } + } + } else { + if (remove(path)) { + if (errno != ENOENT) { + retcode = 0; /* It didn't work. */ + } + } + } + + return (retcode); +} + +/* + * Name: averify + * Description: This function verifies and (if fix > 0) fixes the attributes + * of the file at the path provided. + * Arguments: fix - 0 - do not fix entries, 1 - fix entries + * ftype - single character "type" the entry is supposed to be + * path - path to file + * ainfo - attribute info structure representing the attributes + * the entry is supposed to be + * NOTE: attributes are links and permissions + * Possible return values: + * - 0 = successful + * - VE_EXIST = path name does not exist + * - VE_FTYPE = path file type is not recognized, is not supported, + * or is not what was expected + * - VE_ATTR = path mode/group/user is not what was expected + * - VE_CONT = mod time/link target/major/minor/size/file system type/current + * directory is not what was expected + * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ + * chown failed + */ +int +averify(int fix, char *ftype, char *path, struct ainfo *ainfo) +{ + struct group *grp; /* group entry buffer */ + struct passwd *pwd; + int n; + int setval; + int uid, gid; + int dochown; + int retcode; + int statError = 0; + int targ_is_dir = 0; /* replacing a directory */ + char myftype; + char buf[PATH_MAX]; + ino_t my_ino; + dev_t my_dev; + char cwd[MAXPATHLEN]; + char *cd; + char *c; + + setval = (*ftype == '?'); + retcode = 0; + reperr(NULL); + + if (get_disable_attribute_check()) { + return (0); + } + + if (*ftype == 'l') { + if (stat(path, &status) < 0) { + retcode = VE_EXIST; + reperr(pkg_gt(ERR_EXIST)); + } + + my_ino = status.st_ino; + my_dev = status.st_dev; + + /* Get copy of the current working directory */ + if (getcwd(cwd, MAXPATHLEN) == NULL) { + reperr(pkg_gt(ERR_GETWD), ainfo->local); + return (VE_FAIL); + } + + /* + * Change to the directory in which the hard + * link is to be created. + */ + cd = strdup(path); + c = strrchr(cd, '/'); + if (c) { + /* bugid 4247895 */ + if (strcmp(cd, c) == 0) + strcpy(cd, "/"); + else + *c = NULL; + + if (chdir(cd) != 0) { + reperr(pkg_gt(ERR_CHDIR), cd); + return (VE_FAIL); + } + } + free(cd); + + if (retcode || (status.st_nlink < 2) || + (stat(ainfo->local, &status) < 0) || + (my_dev != status.st_dev) || (my_ino != status.st_ino)) { + if (fix) { + /* + * Don't want to do a hard link to a + * directory. + */ + if (!isdir(ainfo->local)) { + chdir(cwd); + reperr(pkg_gt(ERR_LINKISDIR), + ainfo->local); + return (VE_FAIL); + } + /* Now do the link. */ + if (!clear_target(path, ftype, targ_is_dir)) + return (VE_FAIL); + + if (link(ainfo->local, path)) { + chdir(cwd); + reperr(pkg_gt(ERR_LINKFAIL), + ainfo->local); + return (VE_FAIL); + } + retcode = 0; + } else { + /* Go back to previous working directory */ + if (chdir(cwd) != 0) + reperr(pkg_gt(ERR_CHDIR), cwd); + + reperr(pkg_gt(ERR_LINK), ainfo->local); + return (VE_CONT); + } + } + + /* Go back to previous working directory */ + if (chdir(cwd) != 0) { + reperr(pkg_gt(ERR_CHDIR), cwd); + return (VE_CONT); + } + + return (retcode); + } + + retcode = 0; + + /* If we are to process symlinks the old way then we follow the link */ + if (nonABI_symlinks()) { + if ((*ftype == 's') ? lstat(path, &status) : + stat(path, &status)) { + reperr(pkg_gt(ERR_EXIST)); + retcode = VE_EXIST; + myftype = '?'; + statError++; + } + /* If not then we inspect the target of the link */ + } else { + if ((n = lstat(path, &status)) == -1) { + reperr(pkg_gt(ERR_EXIST)); + retcode = VE_EXIST; + myftype = '?'; + statError++; + } + } + if (!statError) { + /* determining actual type of existing object */ + switch (status.st_mode & S_IFMT) { + case S_IFLNK: + myftype = 's'; + break; + + case S_IFIFO: + myftype = 'p'; + break; + + case S_IFCHR: + myftype = 'c'; + break; + + case S_IFDIR: + myftype = 'd'; + targ_is_dir = 1; + break; + + case S_IFBLK: + myftype = 'b'; + break; + + case S_IFREG: + case 0: + myftype = 'f'; + break; + + case S_IFDOOR: + myftype = 'D'; + break; + + default: + reperr(pkg_gt(ERR_UNKNOWN)); + return (VE_FTYPE); + } + } + + if (setval) { + /* + * Check to make sure that a package or an installf that uses + * wild cards '?' to assume the ftype of an object on the + * system is not assuming a door ftype. Doors are not supported + * but should be ignored. + */ + if (myftype == 'D') { + reperr(pkg_gt(ERR_FTYPED), path); + retcode = VE_FTYPE; + return (VE_FTYPE); + } else { + *ftype = myftype; + } + } else if (!retcode && (*ftype != myftype) && + ((myftype != 'f') || !strchr("ilev", *ftype)) && + ((myftype != 'd') || (*ftype != 'x'))) { + reperr(pkg_gt(ERR_FTYPE), *ftype, myftype); + retcode = VE_FTYPE; + } + + if (!retcode && (*ftype == 's')) { + /* make sure that symbolic link is correct */ + n = readlink(path, buf, PATH_MAX); + if (n < 0) { + reperr(pkg_gt(ERR_SLINK), ainfo->local); + retcode = VE_CONT; + } else if (ainfo->local != NULL) { + buf[n] = '\0'; + if (strcmp(buf, ainfo->local)) { + reperr(pkg_gt(ERR_SLINK), ainfo->local); + retcode = VE_CONT; + } + } else if (ainfo->local == NULL) { + /* + * Since a sym link target exists, insert it + * into the ainfo structure + */ + buf[n] = '\0'; + ainfo->local = strdup(buf); + } + } + + if (retcode) { + /* The path doesn't exist or is different than it should be. */ + if (fix) { + /* + * Clear the way for the write. If it won't clear, + * there's nothing we can do. + */ + if (!clear_target(path, ftype, targ_is_dir)) + return (VE_FAIL); + + if ((*ftype == 'd') || (*ftype == 'x')) { + char *pt, *p; + + /* Try to make it the easy way */ + if (mkdir(path, ainfo->mode)) { + /* + * Failing that, walk through the + * parent directories creating + * whatever is needed. + */ + p = strdup(path); + pt = (*p == '/') ? p+1 : p; + do { + if (pt = strchr(pt, '/')) + *pt = '\0'; + if (access(p, 0) && + mkdir(p, ainfo->mode)) + break; + if (pt) + *pt++ = '/'; + } while (pt); + free(p); + } + if (stat(path, &status) < 0) { + reperr(pkg_gt(ERR_DIRFAIL)); + return (VE_FAIL); + } + } else if (*ftype == 's') { + if (symlink(ainfo->local, path)) { + reperr(pkg_gt(ERR_SLINKFAIL), + ainfo->local); + return (VE_FAIL); + } + + } else if (*ftype == 'c') { + int wilddevno = 0; + /* + * The next three if's support 2.4 and older + * packages that use "?" as device numbers. + * This should be considered for removal by + * release 2.7 or so. + */ + if (ainfo->major == BADMAJOR) { + ainfo->major = 0; + wilddevno = 1; + } + + if (ainfo->minor == BADMINOR) { + ainfo->minor = 0; + wilddevno = 1; + } + + if (wilddevno) { + wilddevno = 0; + logerr(MSG_WLDDEVNO, path, + ainfo->major, ainfo->minor); + } + + if (mknod(path, ainfo->mode | S_IFCHR, +#ifdef SUNOS41 + makedev(ainfo->xmajor, ainfo->xminor)) || +#else + makedev(ainfo->major, ainfo->minor)) || +#endif + (stat(path, &status) < 0)) { + reperr(pkg_gt(ERR_CDEVFAIL)); + return (VE_FAIL); + } + } else if (*ftype == 'b') { + int wilddevno = 0; + /* + * The next three if's support 2.4 and older + * packages that use "?" as device numbers. + * This should be considered for removal by + * release 2.7 or so. + */ + if (ainfo->major == BADMAJOR) { + ainfo->major = 0; + wilddevno = 1; + } + + if (ainfo->minor == BADMINOR) { + ainfo->minor = 0; + wilddevno = 1; + } + + if (wilddevno) { + wilddevno = 0; + logerr(MSG_WLDDEVNO, path, + ainfo->major, ainfo->minor); + } + + if (mknod(path, ainfo->mode | S_IFBLK, +#ifdef SUNOS41 + makedev(ainfo->xmajor, ainfo->xminor)) || +#else + makedev(ainfo->major, ainfo->minor)) || +#endif + (stat(path, &status) < 0)) { + reperr(pkg_gt(ERR_BDEVFAIL)); + return (VE_FAIL); + } + } else if (*ftype == 'p') { + if (mknod(path, ainfo->mode | S_IFIFO, NULL) || + (stat(path, &status) < 0)) { + reperr(pkg_gt(ERR_PIPEFAIL)); + return (VE_FAIL); + } + } else + return (retcode); + + } else + return (retcode); + } + + if (*ftype == 's') + return (0); /* don't check anything else */ + if (*ftype == 'i') + return (0); /* don't check anything else */ + + retcode = 0; + if ((myftype == 'c') || (myftype == 'b')) { +#ifdef SUNOS41 + if (setval || (ainfo->xmajor < 0)) + ainfo->xmajor = ((status.st_rdev>>8)&0377); + if (setval || (ainfo->xminor < 0)) + ainfo->xminor = (status.st_rdev&0377); + /* check major & minor */ + if (status.st_rdev != makedev(ainfo->xmajor, ainfo->xminor)) { + reperr(pkg_gt(ERR_MAJMIN), ainfo->xmajor, + ainfo->xminor, + (status.st_rdev>>8)&0377, status.st_rdev&0377); + retcode = VE_CONT; + } +#else + if (setval || (ainfo->major == BADMAJOR)) + ainfo->major = major(status.st_rdev); + if (setval || (ainfo->minor == BADMINOR)) + ainfo->minor = minor(status.st_rdev); + /* check major & minor */ + if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) { + reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor, + major(status.st_rdev), minor(status.st_rdev)); + retcode = VE_CONT; + } +#endif + } + + /* compare specified mode w/ actual mode excluding sticky bit */ + if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD)) + ainfo->mode = status.st_mode & 07777; + else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) { + if (fix) { + if ((ainfo->mode == BADMODE) || + (chmod(path, ainfo->mode) < 0)) + retcode = VE_FAIL; + } else { + reperr(pkg_gt(ERR_PERM), ainfo->mode, + status.st_mode & 07777); + if (!retcode) + retcode = VE_ATTR; + } + } + + dochown = 0; + + /* get group entry for specified group */ + if (setval || strcmp(ainfo->group, BADGROUP) == 0) { + grp = cgrgid(status.st_gid); + if (grp) + (void) strcpy(ainfo->group, grp->gr_name); + else { + if (!retcode) + retcode = VE_ATTR; + reperr(pkg_gt(ERR_BADGRPID), status.st_gid); + } + gid = status.st_gid; + } else if ((grp = cgrnam(ainfo->group)) == NULL) { + reperr(pkg_gt(ERR_BADGRPNM), ainfo->group); + if (!retcode) + retcode = VE_ATTR; + } else if ((gid = grp->gr_gid) != status.st_gid) { + if (fix) { + /* save specified GID */ + gid = grp->gr_gid; + dochown++; + } else { + if ((grp = cgrgid((int)status.st_gid)) == + (struct group *)NULL) { + reperr(pkg_gt(ERR_GROUP), ainfo->group, + "(null)"); + } else { + reperr(pkg_gt(ERR_GROUP), ainfo->group, + grp->gr_name); + } + if (!retcode) + retcode = VE_ATTR; + } + } + + /* get password entry for specified owner */ + if (setval || strcmp(ainfo->owner, BADOWNER) == 0) { + pwd = cpwuid((int)status.st_uid); + if (pwd) + (void) strcpy(ainfo->owner, pwd->pw_name); + else { + if (!retcode) + retcode = VE_ATTR; + reperr(pkg_gt(ERR_BADUSRID), status.st_uid); + } + uid = status.st_uid; + } else if ((pwd = cpwnam(ainfo->owner)) == NULL) { + /* UID does not exist in password file */ + reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner); + if (!retcode) + retcode = VE_ATTR; + } else if ((uid = pwd->pw_uid) != status.st_uid) { + /* get owner name for actual UID */ + if (fix) { + uid = pwd->pw_uid; + dochown++; + } else { + pwd = cpwuid((int)status.st_uid); + if (pwd == NULL) + reperr(pkg_gt(ERR_BADUSRID), + (int)status.st_uid); + else + reperr(pkg_gt(ERR_OWNER), ainfo->owner, + pwd->pw_name); + + if (!retcode) + retcode = VE_ATTR; + } + } + + if (statvfs(path, &vfsstatus) < 0) { + reperr(pkg_gt(ERR_EXIST)); + retcode = VE_FAIL; + } else { + if (dochown) { + /* pcfs doesn't support file ownership */ + if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 && + chown(path, uid, gid) < 0) { + retcode = VE_FAIL; /* chown failed */ + } + } + } + + if (retcode == VE_FAIL) + reperr(pkg_gt(ERR_ATTRFAIL)); + return (retcode); +} + +/* + * This is a special fast verify which basically checks the attributes + * and then, if all is OK, checks the size and mod time using the same + * stat and statvfs structures. + */ +int +fverify(int fix, char *ftype, char *path, struct ainfo *ainfo, + struct cinfo *cinfo) +{ + int retval; + + /* return success if attribute checks are disabled */ + + if (get_disable_attribute_check()) { + return (0); + } + + if ((retval = averify(fix, ftype, path, ainfo)) == 0) { + if (*ftype == 'f' || *ftype == 'i') { + if (cinfo->size != status.st_size) { + reperr(pkg_gt(WRN_QV_SIZE), path); + retval = VE_CONT; + } + /* pcfs doesn't support modification times */ + if (strcmp(vfsstatus.f_basetype, "pcfs") != 0) { + if (cinfo->modtime != status.st_mtime) { + reperr(pkg_gt(WRN_QV_MTIME), path); + retval = VE_CONT; + } + } + } + } + + return (retval); +} + +/* + * This function determines whether or not non-ABI symlinks are supported. + */ + +int +nonABI_symlinks(void) +{ + return (nonabi_symlinks); +} + +void +set_nonABI_symlinks(void) +{ + nonabi_symlinks = 1; +} + +/* + * Disable attribute checking. Only disable attribute checking if files + * are guaranteed to exist in the FS. + */ +void +disable_attribute_check(void) +{ + disable_attributes = 1; +} + +/* + * This function determines whether or not to do attribute checking. + * Returns: 0 - Do attribute checking + * !0 - Don't do attribute checking + */ +int +get_disable_attribute_check(void) +{ + return (disable_attributes); +} + +/* + * This function returns the address of the "global" error buffer that + * is populated by the various functions in this module. + */ + +char * +getErrbufAddr(void) +{ + return (theErrBuf); +} + +/* + * This function returns the size of the buffer returned by getErrbufAddr() + */ + +int +getErrbufSize(void) +{ + return (sizeof (theErrBuf)); +} + +/* + * This function returns the current global "error string" + */ + +char * +getErrstr(void) +{ + return (theErrStr); +} + +/* + * This function sets the global "error string" + */ + +void +setErrstr(char *a_errstr) +{ + theErrStr = a_errstr; +} + +/* + * This function enables checksumming + */ + +void +checksum_on(void) +{ + enable_checksum = 1; +} + +/* + * This function disables checksumming + */ + +void +checksum_off(void) +{ + enable_checksum = 0; +} |