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
reperr(char * fmt,...)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
cverify(int fix,char * ftype,char * path,struct cinfo * cinfo,int allow_checksum)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
compute_checksum(int * r_cksumerr,char * a_path)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
clear_target(char * path,char * ftype,int is_a_dir)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
averify(int fix,char * ftype,char * path,struct ainfo * ainfo)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
fverify(int fix,char * ftype,char * path,struct ainfo * ainfo,struct cinfo * cinfo)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
nonABI_symlinks(void)898 nonABI_symlinks(void)
899 {
900 return (nonabi_symlinks);
901 }
902
903 void
set_nonABI_symlinks(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
disable_attribute_check(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
get_disable_attribute_check(void)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 *
getErrbufAddr(void)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
getErrbufSize(void)946 getErrbufSize(void)
947 {
948 return (sizeof (theErrBuf));
949 }
950
951 /*
952 * This function returns the current global "error string"
953 */
954
955 char *
getErrstr(void)956 getErrstr(void)
957 {
958 return (theErrStr);
959 }
960
961 /*
962 * This function sets the global "error string"
963 */
964
965 void
setErrstr(char * a_errstr)966 setErrstr(char *a_errstr)
967 {
968 theErrStr = a_errstr;
969 }
970
971 /*
972 * This function enables checksumming
973 */
974
975 void
checksum_on(void)976 checksum_on(void)
977 {
978 enable_checksum = 1;
979 }
980
981 /*
982 * This function disables checksumming
983 */
984
985 void
checksum_off(void)986 checksum_off(void)
987 {
988 enable_checksum = 0;
989 }
990