8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libpkg / common / gpkgmap.c
bloba8bd01c87ce3c179ab4e1520b168abbcfc71f51c
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2017 Peter Tribble.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
36 #include <stdio.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #include "pkgstrct.h"
47 #include "pkglib.h"
48 #include "pkglibmsgs.h"
49 #include "pkglocale.h"
51 #define ERR_CANT_READ_LCLPATH "unable to read local pathname"
52 #define ERR_BAD_VOLUME_NUMBER "bad volume number"
53 #define ERR_CANNOT_READ_PATHNAME_FIELD "unable to read pathname field"
54 #define ERR_CANNOT_READ_CONTENT_INFO "unable to read content info"
55 #define ERR_EXTRA_TOKENS_PRESENT "extra tokens on input line"
56 #define ERR_CANNOT_READ_CLASS_TOKEN "unable to read class token"
57 #define ERR_BAD_LINK_SPEC "missing or invalid link specification"
58 #define ERR_UNKNOWN_FTYPE "unknown ftype"
59 #define ERR_NO_LINKSOURCE "no link source specified"
60 #define ERR_CANNOT_READ_MM_DEVNUMS "unable to read major/minor "\
61 "device numbers"
62 static int eatwhite(FILE *fp);
63 static int getend(FILE *fp);
64 static int getstr(FILE *fp, char *sep, int n, char *str);
65 static int getnum(FILE *fp, int base, long *d, long bad);
66 static int getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad);
67 static int getvalmode(FILE *fp, mode_t *d, long bad, int map);
69 static int getendvfp(char **cp);
70 static void findendvfp(char **cp);
71 static int getstrvfp(char **cp, char *sep, int n, char *str);
72 static int getvalmodevfp(char **cp, mode_t *d, long bad, int map);
73 int getnumvfp(char **cp, int base, long *d, long bad);
74 int getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad);
76 static char mypath[PATH_MAX];
77 static char mylocal[PATH_MAX];
78 static int mapmode = MAPNONE;
79 static char *maptype = "";
80 static mode_t d_mode = BADMODE;
81 static char *d_owner = BADOWNER;
82 static char *d_group = BADGROUP;
85 * These determine how gpkgmap() deals with mode, owner and group defaults.
86 * It is assumed that the owner and group arguments represent static fields
87 * which will persist until attrdefault() is called.
89 void
90 attrpreset(int mode, char *owner, char *group)
92 d_mode = mode;
93 d_owner = owner;
94 d_group = group;
97 void
98 attrdefault()
100 d_mode = NOMODE;
101 d_owner = NOOWNER;
102 d_group = NOGROUP;
106 * This determines how gpkgmap() deals with environment variables in the
107 * mode, owner and group. Path is evaluated at a higher level based upon
108 * other circumstances.
110 void
111 setmapmode(int mode)
113 if (mode >= 0 || mode <= 3) {
114 mapmode = mode;
115 if (mode == MAPBUILD)
116 maptype = " build";
117 else if (mode == MAPINSTALL)
118 maptype = " install";
119 else
120 maptype = "";
124 /* This is the external query interface for mapmode. */
126 getmapmode(void)
128 return (mapmode);
132 * Unpack the pkgmap or the contents file or whatever file is in that format.
133 * Based upon mapmode, environment parameters will be resolved for mode,
134 * owner and group.
138 gpkgmap(struct cfent *ept, FILE *fp)
140 int c;
141 boolean_t first_char = B_TRUE;
143 setErrstr(NULL);
144 ept->volno = 0;
145 ept->ftype = BADFTYPE;
146 (void) strcpy(ept->pkg_class, BADCLASS);
147 ept->pkg_class_idx = -1;
148 ept->path = NULL;
149 ept->ainfo.local = NULL;
150 /* default attributes were supplied, so don't reset */
151 ept->ainfo.mode = d_mode;
152 (void) strcpy(ept->ainfo.owner, d_owner);
153 (void) strcpy(ept->ainfo.group, d_group);
154 ept->ainfo.major = BADMAJOR;
155 ept->ainfo.minor = BADMINOR;
156 ept->cinfo.cksum = ept->cinfo.modtime = ept->cinfo.size = (-1L);
158 ept->npkgs = 0;
160 if (!fp)
161 return (-1);
162 readline:
163 c = eatwhite(fp);
166 * If the first character is not a digit, we assume that the
167 * volume number is 1.
169 if (first_char && !isdigit(c)) {
170 ept->volno = 1;
172 first_char = B_FALSE;
174 switch (c) {
175 case EOF:
176 return (0);
178 case '0':
179 case '1':
180 case '2':
181 case '3':
182 case '4':
183 case '5':
184 case '6':
185 case '7':
186 case '8':
187 case '9':
188 if (ept->volno) {
189 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
190 goto error;
192 do {
193 ept->volno = (ept->volno*10)+c-'0';
194 c = getc(fp);
195 } while (isdigit(c));
196 if (ept->volno == 0)
197 ept->volno = 1;
199 goto readline;
201 case ':':
202 case '#':
203 (void) getend(fp);
204 /*FALLTHRU*/
205 case '\n':
207 * Since we are going to scan the next line,
208 * we need to reset volume number and first_char.
210 ept->volno = 0;
211 first_char = B_TRUE;
212 goto readline;
214 case 'i':
215 ept->ftype = (char)c;
216 c = eatwhite(fp);
217 /*FALLTHRU*/
218 case '.':
219 case '/':
220 (void) ungetc(c, fp);
222 if (getstr(fp, "=", PATH_MAX, mypath)) {
223 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
224 goto error;
226 ept->path = mypath;
227 c = getc(fp);
228 if (c == '=') {
229 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
230 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
231 goto error;
233 ept->ainfo.local = mylocal;
234 } else
235 (void) ungetc(c, fp);
237 if (ept->ftype == 'i') {
238 /* content info might exist */
239 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size,
240 BADCONT) &&
241 (getnum(fp, 10, (long *)&ept->cinfo.cksum,
242 BADCONT) ||
243 getnum(fp, 10, (long *)&ept->cinfo.modtime,
244 BADCONT))) {
245 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
246 goto error;
249 if (getend(fp)) {
250 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
251 return (-1);
253 return (1);
255 case '?':
256 case 'f':
257 case 'v':
258 case 'e':
259 case 'l':
260 case 's':
261 case 'p':
262 case 'c':
263 case 'b':
264 case 'd':
265 case 'x':
266 ept->ftype = (char)c;
267 if (getstr(fp, NULL, CLSSIZ, ept->pkg_class)) {
268 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
269 goto error;
271 if (getstr(fp, "=", PATH_MAX, mypath)) {
272 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
273 goto error;
275 ept->path = mypath;
277 c = getc(fp);
278 if (c == '=') {
279 /* local path */
280 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
281 if (ept->ftype == 's' || ept->ftype == 'l') {
282 setErrstr(pkg_gt(ERR_READLINK));
283 } else {
284 setErrstr(
285 pkg_gt(ERR_CANT_READ_LCLPATH));
287 goto error;
289 ept->ainfo.local = mylocal;
290 } else if (strchr("sl", ept->ftype)) {
291 if ((c != EOF) && (c != '\n'))
292 (void) getend(fp);
293 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
294 return (-1);
295 } else
296 (void) ungetc(c, fp);
297 break;
299 default:
300 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
301 error:
302 (void) getend(fp);
303 return (-1);
306 if (strchr("sl", ept->ftype) && (ept->ainfo.local == NULL)) {
307 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
308 goto error;
311 if (strchr("cb", ept->ftype)) {
312 ept->ainfo.major = BADMAJOR;
313 ept->ainfo.minor = BADMINOR;
314 if (getnum(fp, 10, (long *)&ept->ainfo.major, BADMAJOR) ||
315 getnum(fp, 10, (long *)&ept->ainfo.minor, BADMINOR)) {
316 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
317 goto error;
322 * Links and information files don't have attributes associated with
323 * them. The following either resolves potential variables or passes
324 * them through. Mode is tested for validity to some degree. BAD???
325 * is returned to indicate that no meaningful mode was provided. A
326 * higher authority will decide if that's OK or not. CUR??? means that
327 * the prototype file specifically requires a wildcard ('?') for
328 * that entry. We issue an error if attributes were entered wrong.
329 * We just return BAD??? if there was no entry at all.
331 if (strchr("cbdxpfve", ept->ftype)) {
332 int retval;
334 if ((retval = getvalmode(fp, &(ept->ainfo.mode), CURMODE,
335 (mapmode != MAPNONE))) == 1)
336 goto end; /* nothing else on the line */
337 else if (retval == 2)
338 goto error; /* mode is too no good */
340 /* owner & group should be here */
341 if ((retval = getstr(fp, NULL, ATRSIZ,
342 ept->ainfo.owner)) == 1)
343 goto end; /* no owner or group - warning */
344 if (retval == -1) {
345 setErrstr(pkg_gt(ERR_OWNTOOLONG));
346 goto error;
349 if ((retval = getstr(fp, NULL, ATRSIZ,
350 ept->ainfo.group)) == 1)
351 goto end; /* no group - warning */
352 if (retval == -1) {
353 setErrstr(pkg_gt(ERR_GRPTOOLONG));
354 goto error;
357 /* Resolve the parameters if required. */
358 if (mapmode != MAPNONE) {
359 if (mapvar(mapmode, ept->ainfo.owner)) {
360 (void) snprintf(getErrbufAddr(),
361 getErrbufSize(),
362 pkg_gt(ERR_NOVAR),
363 maptype, ept->ainfo.owner);
364 setErrstr(getErrbufAddr());
365 goto error;
367 if (mapvar(mapmode, ept->ainfo.group)) {
368 (void) snprintf(getErrbufAddr(),
369 getErrbufSize(), pkg_gt(ERR_NOVAR),
370 maptype, ept->ainfo.group);
371 setErrstr(getErrbufAddr());
372 goto error;
377 if (strchr("ifve", ept->ftype)) {
378 /* look for content description */
379 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
380 (getnum(fp, 10, (long *)&ept->cinfo.cksum, BADCONT) ||
381 getnum(fp, 10, (long *)&ept->cinfo.modtime, BADCONT))) {
382 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
383 goto error;
387 if (ept->ftype == 'i')
388 goto end;
390 end:
391 if (getend(fp) && ept->pinfo) {
392 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
393 return (-1);
396 return (1);
400 * Get and validate the mode attribute. This returns an error if
401 * 1. the mode string is too long
402 * 2. the mode string includes alpha characters
403 * 3. the mode string is not octal
404 * 4. mode string is an install parameter
405 * 5. mode is an unresolved build parameter and MAPBUILD is
406 * in effect.
407 * If the mode is a build parameter, it is
408 * 1. returned as is if MAPNONE is in effect
409 * 2. evaluated if MAPBUILD is in effect
411 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
412 * time. At install time we just fix a mode with bad bits set by
413 * setting it to CURMODE. This should be an error in a few releases
414 * (2.8 maybe) but faulty modes are so common in existing packages
415 * that this is a reasonable exception. -- JST 1994-11-9
417 * RETURNS
418 * 0 if mode is being returned as a valid value
419 * 1 if no attributes are present on the line
420 * 2 if there was a fundamental error
422 static int
423 getvalmode(FILE *fp, mode_t *d, long bad, int map)
425 char tempmode[20];
426 mode_t tempmode_t;
427 int retval;
429 if ((retval = getstr(fp, NULL, ATRSIZ, tempmode)) == 1)
430 return (1);
431 else if (retval == -1) {
432 setErrstr(pkg_gt(ERR_MODELONG));
433 return (2);
434 } else {
436 * If it isn't a '?' (meaning go with whatever mode is
437 * there), validate the mode and convert it to a mode_t. The
438 * "bad" variable here is a misnomer. It doesn't necessarily
439 * mean bad.
441 if (tempmode[0] == '?') {
442 *d = WILDCARD;
443 } else {
445 * Mode may not be an install parameter or a
446 * non-build parameter.
448 if (tempmode[0] == '$' &&
449 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
450 setErrstr(pkg_gt(ERR_IMODE));
451 return (2);
454 if ((map) && (mapvar(mapmode, tempmode))) {
455 (void) snprintf(getErrbufAddr(),
456 getErrbufSize(),
457 pkg_gt(ERR_NOVAR),
458 maptype, tempmode);
459 setErrstr(getErrbufAddr());
460 return (2);
464 if (tempmode[0] == '$') {
465 *d = BADMODE; /* may be a problem */
466 } else {
468 * At this point it's supposed to be
469 * something we can convert to a number.
471 int n = 0;
474 * We reject it if it contains nonnumbers or
475 * it's not octal.
477 while (tempmode[n] && !isspace(tempmode[n])) {
478 if (!isdigit(tempmode[n])) {
479 setErrstr(
480 pkg_gt(ERR_MODEALPHA));
481 return (2);
484 if (strchr("89abcdefABCDEF",
485 tempmode[n])) {
486 setErrstr(
487 pkg_gt(ERR_BASEINVAL));
488 return (2);
490 n++;
493 tempmode_t = strtol(tempmode, NULL, 8);
496 * We reject it if it contains inappropriate
497 * bits.
499 if (tempmode_t & ~(S_IAMB |
500 S_ISUID | S_ISGID | S_ISVTX)) {
501 if (mapmode != MAPBUILD) {
502 tempmode_t = bad;
503 } else {
504 setErrstr(pkg_gt(ERR_MODEBITS));
505 return (2);
508 *d = tempmode_t;
511 return (0);
515 static int
516 getnum(FILE *fp, int base, long *d, long bad)
518 int c, b;
520 /* leading white space ignored */
521 c = eatwhite(fp);
522 if (c == '?') {
523 *d = bad;
524 return (0);
527 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
528 (void) ungetc(c, fp);
529 return (1);
532 *d = 0;
533 while (isdigit(c)) {
534 b = (c & 017);
535 if (b >= base)
536 return (2);
537 *d = (*d * base) + b;
538 c = getc(fp);
540 (void) ungetc(c, fp);
541 return (0);
544 static int
545 getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad)
547 int c, b;
549 /* leading white space ignored */
550 c = eatwhite(fp);
551 if (c == '?') {
552 *d = bad;
553 return (0);
556 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
557 (void) ungetc(c, fp);
558 return (1);
561 *d = 0;
562 while (isdigit(c)) {
563 b = (c & 017);
564 if (b >= base)
565 return (2);
566 *d = (*d * base) + b;
567 c = getc(fp);
569 (void) ungetc(c, fp);
570 return (0);
574 * Get a string from the file. Returns
575 * 0 if all OK
576 * 1 if nothing there
577 * -1 if string is too long
579 static int
580 getstr(FILE *fp, char *sep, int n, char *str)
582 int c;
584 /* leading white space ignored */
585 c = eatwhite(fp);
586 if ((c == EOF) || (c == '\n')) {
587 (void) ungetc(c, fp);
588 return (1); /* nothing there */
591 /* fill up string until space, tab, or separator */
592 while (!strchr(" \t", c) && (!sep || !strchr(sep, c))) {
593 if (n-- < 1) {
594 *str = '\0';
595 return (-1); /* too long */
597 *str++ = (char)c;
598 c = getc(fp);
599 if ((c == EOF) || (c == '\n'))
600 break; /* no more on this line */
602 *str = '\0';
603 (void) ungetc(c, fp);
605 return (0);
608 static int
609 getend(FILE *fp)
611 int c;
612 int n;
614 n = 0;
615 do {
616 if ((c = getc(fp)) == EOF)
617 return (n);
618 if (!isspace(c))
619 n++;
620 } while (c != '\n');
621 return (n);
624 static int
625 eatwhite(FILE *fp)
627 int c;
629 /* this test works around a side effect of getc() */
630 if (feof(fp))
631 return (EOF);
633 c = getc(fp);
634 while ((c == ' ') || (c == '\t'));
635 return (c);
639 gpkgmapvfp(struct cfent *ept, VFP_T *vfp)
641 int c;
642 boolean_t first_char = B_TRUE;
643 (void) strlcpy(ept->pkg_class, BADCLASS, sizeof (ept->pkg_class));
644 (void) strlcpy(ept->ainfo.owner, d_owner, sizeof (ept->ainfo.owner));
645 (void) strlcpy(ept->ainfo.group, d_group, sizeof (ept->ainfo.group));
647 setErrstr(NULL);
648 ept->volno = 0;
649 ept->ftype = BADFTYPE;
650 ept->pkg_class_idx = -1;
651 ept->path = NULL;
652 ept->ainfo.local = NULL;
653 ept->ainfo.mode = d_mode;
654 ept->ainfo.major = BADMAJOR;
655 ept->ainfo.minor = BADMINOR;
656 ept->cinfo.cksum = (-1L);
657 ept->cinfo.modtime = (-1L);
658 ept->cinfo.size = (-1L);
660 ept->npkgs = 0;
662 /* return error if no vfp specified */
664 if (vfp == (VFP_T *)NULL) {
665 return (-1);
668 readline:
669 while (((c = vfpGetcNoInc(vfp)) != '\0') && (isspace(vfpGetc(vfp))))
673 * If the first character is not a digit, we assume that the
674 * volume number is 1.
676 if (first_char && !isdigit(c)) {
677 ept->volno = 1;
679 first_char = B_FALSE;
682 * In case of hsfs the zero-padding of partial pages
683 * returned by mmap is not done properly. A separate bug has been filed
684 * on this.
687 if (vfp->_vfpCurr && (vfp->_vfpCurr > vfp->_vfpEnd)) {
688 return (0);
691 switch (c) {
692 case '\0':
693 return (0);
695 case '0':
696 case '1':
697 case '2':
698 case '3':
699 case '4':
700 case '5':
701 case '6':
702 case '7':
703 case '8':
704 case '9':
705 if (ept->volno) {
706 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
707 goto error;
709 do {
710 ept->volno = (ept->volno*10)+c-'0';
711 c = vfpGetc(vfp);
712 } while (isdigit(c));
713 if (ept->volno == 0) {
714 ept->volno = 1;
717 goto readline;
719 case ':':
720 case '#':
721 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
722 /*FALLTHRU*/
723 case '\n':
725 * Since we are going to scan the next line,
726 * we need to reset volume number and first_char.
728 ept->volno = 0;
729 first_char = B_TRUE;
730 goto readline;
732 case 'i':
733 ept->ftype = (char)c;
734 while (((c = vfpGetcNoInc(vfp)) != '\0') &&
735 (isspace(vfpGetc(vfp))))
737 /*FALLTHRU*/
738 case '.':
739 case '/':
740 vfpDecCurrPtr(vfp);
742 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
743 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
744 goto error;
746 ept->path = mypath;
747 c = vfpGetc(vfp);
748 if (c == '=') {
749 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, PATH_MAX,
750 mylocal)) {
751 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
752 goto error;
754 ept->ainfo.local = mylocal;
755 } else {
756 vfpDecCurrPtr(vfp);
759 if (ept->ftype == 'i') {
760 /* content info might exist */
761 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
762 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
763 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
764 (long *)&ept->cinfo.cksum, BADCONT) ||
765 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
766 (long *)&ept->cinfo.modtime, BADCONT))) {
767 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
768 goto error;
772 if (getendvfp(&vfpGetCurrCharPtr(vfp))) {
773 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
774 return (-1);
776 return (1);
778 case '?':
779 case 'f':
780 case 'v':
781 case 'e':
782 case 'l':
783 case 's':
784 case 'p':
785 case 'c':
786 case 'b':
787 case 'd':
788 case 'x':
789 ept->ftype = (char)c;
790 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
791 CLSSIZ, ept->pkg_class)) {
792 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
793 goto error;
795 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
796 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
797 goto error;
799 ept->path = mypath;
801 c = vfpGetc(vfp);
802 if (c == '=') {
803 /* local path */
804 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
805 PATH_MAX, mylocal)) {
806 if (ept->ftype == 's' || ept->ftype == 'l') {
807 setErrstr(pkg_gt(ERR_READLINK));
808 } else {
809 setErrstr(
810 pkg_gt(ERR_CANT_READ_LCLPATH));
812 goto error;
814 ept->ainfo.local = mylocal;
815 } else if ((ept->ftype == 's') || (ept->ftype == 'l')) {
816 if ((c != '\0') && (c != '\n'))
817 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
818 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
819 return (-1);
820 } else {
821 vfpDecCurrPtr(vfp);
823 break;
825 default:
826 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
827 error:
828 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
829 return (-1);
832 if (((ept->ftype == 's') || (ept->ftype == 'l')) &&
833 (ept->ainfo.local == NULL)) {
834 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
835 goto error;
838 if (((ept->ftype == 'c') || (ept->ftype == 'b'))) {
839 ept->ainfo.major = BADMAJOR;
840 ept->ainfo.minor = BADMINOR;
842 if (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
843 (long *)&ept->ainfo.major, BADMAJOR) ||
844 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
845 (long *)&ept->ainfo.minor, BADMINOR)) {
846 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
847 goto error;
852 * Links and information files don't have attributes associated with
853 * them. The following either resolves potential variables or passes
854 * them through. Mode is tested for validity to some degree. BAD???
855 * is returned to indicate that no meaningful mode was provided. A
856 * higher authority will decide if that's OK or not. CUR??? means that
857 * the prototype file specifically requires a wildcard ('?') for
858 * that entry. We issue an error if attributes were entered wrong.
859 * We just return BAD??? if there was no entry at all.
861 if ((ept->ftype == 'd') || (ept->ftype == 'x') || (ept->ftype == 'c') ||
862 (ept->ftype == 'b') || (ept->ftype == 'p') ||
863 (ept->ftype == 'f') || (ept->ftype == 'v') ||
864 (ept->ftype == 'e')) {
865 int retval;
867 retval = getvalmodevfp(&vfpGetCurrCharPtr(vfp),
868 &(ept->ainfo.mode),
869 CURMODE, (mapmode != MAPNONE));
871 if (retval == 1) {
872 goto end; /* nothing else on the line */
873 } else if (retval == 2) {
874 goto error; /* mode is too no good */
877 /* owner & group should be here */
878 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
879 ept->ainfo.owner)) == 1)
880 goto end; /* no owner or group - warning */
881 if (retval == -1) {
882 setErrstr(pkg_gt(ERR_OWNTOOLONG));
883 goto error;
886 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
887 ept->ainfo.group)) == 1)
888 goto end; /* no group - warning */
889 if (retval == -1) {
890 setErrstr(pkg_gt(ERR_GRPTOOLONG));
891 goto error;
894 /* Resolve the parameters if required. */
895 if (mapmode != MAPNONE) {
896 if (mapvar(mapmode, ept->ainfo.owner)) {
897 (void) snprintf(getErrbufAddr(),
898 getErrbufSize(), pkg_gt(ERR_NOVAR),
899 maptype, ept->ainfo.owner);
900 setErrstr(getErrbufAddr());
901 goto error;
903 if (mapvar(mapmode, ept->ainfo.group)) {
904 (void) snprintf(getErrbufAddr(),
905 getErrbufSize(), pkg_gt(ERR_NOVAR),
906 maptype, ept->ainfo.group);
907 setErrstr(getErrbufAddr());
908 goto error;
913 if ((ept->ftype == 'i') || (ept->ftype == 'f') ||
914 (ept->ftype == 'v') || (ept->ftype == 'e')) {
915 /* look for content description */
916 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
917 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
918 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
919 (long *)&ept->cinfo.cksum, BADCONT) ||
920 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
921 (long *)&ept->cinfo.modtime, BADCONT))) {
922 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
923 goto error;
927 if (ept->ftype == 'i')
928 goto end;
930 end:
931 if (getendvfp(&vfpGetCurrCharPtr(vfp)) && ept->pinfo) {
932 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
933 return (-1);
936 return (1);
940 * Get and validate the mode attribute. This returns an error if
941 * 1. the mode string is too long
942 * 2. the mode string includes alpha characters
943 * 3. the mode string is not octal
944 * 4. mode string is an install parameter
945 * 5. mode is an unresolved build parameter and MAPBUILD is
946 * in effect.
947 * If the mode is a build parameter, it is
948 * 1. returned as is if MAPNONE is in effect
949 * 2. evaluated if MAPBUILD is in effect
951 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
952 * time. At install time we just fix a mode with bad bits set by
953 * setting it to CURMODE. This should be an error in a few releases
954 * (2.8 maybe) but faulty modes are so common in existing packages
955 * that this is a reasonable exception. -- JST 1994-11-9
957 * RETURNS
958 * 0 if mode is being returned as a valid value
959 * 1 if no attributes are present on the line
960 * 2 if there was a fundamental error
962 static int
963 getvalmodevfp(char **cp, mode_t *d, long bad, int map)
965 char tempmode[ATRSIZ+1];
966 mode_t tempmode_t;
967 int retval;
968 int n;
970 if ((retval = getstrvfp(cp, NULL, sizeof (tempmode), tempmode)) == 1) {
971 return (1);
972 } else if (retval == -1) {
973 setErrstr(pkg_gt(ERR_MODELONG));
974 return (2);
978 * If it isn't a '?' (meaning go with whatever mode is
979 * there), validate the mode and convert it to a mode_t. The
980 * "bad" variable here is a misnomer. It doesn't necessarily
981 * mean bad.
983 if (tempmode[0] == '?') {
984 *d = WILDCARD;
985 return (0);
989 * Mode may not be an install parameter or a
990 * non-build parameter.
993 if (tempmode[0] == '$' &&
994 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
995 setErrstr(pkg_gt(ERR_IMODE));
996 return (2);
999 if ((map) && (mapvar(mapmode, tempmode))) {
1000 (void) snprintf(getErrbufAddr(), getErrbufSize(),
1001 pkg_gt(ERR_NOVAR), maptype, tempmode);
1002 setErrstr(getErrbufAddr());
1003 return (2);
1006 if (tempmode[0] == '$') {
1007 *d = BADMODE; /* may be a problem */
1008 return (0);
1011 /* it's supposed to be something we can convert to a number */
1013 n = 0;
1015 /* reject it if it contains nonnumbers or it's not octal */
1017 while (tempmode[n] && !isspace(tempmode[n])) {
1018 if (!isdigit(tempmode[n])) {
1019 setErrstr(pkg_gt(ERR_MODEALPHA));
1020 return (2);
1023 if (strchr("89abcdefABCDEF", tempmode[n])) {
1024 setErrstr(pkg_gt(ERR_BASEINVAL));
1025 return (2);
1027 n++;
1030 tempmode_t = strtol(tempmode, NULL, 8);
1033 * We reject it if it contains inappropriate
1034 * bits.
1036 if (tempmode_t & (~(S_IAMB | S_ISUID | S_ISGID | S_ISVTX))) {
1037 if (mapmode == MAPBUILD) {
1038 setErrstr(pkg_gt(ERR_MODEBITS));
1039 return (2);
1041 tempmode_t = bad;
1044 *d = tempmode_t;
1046 return (0);
1050 getnumvfp(char **cp, int base, long *d, long bad)
1052 int c;
1053 char *p = *cp;
1055 if (*p == '\0') {
1056 return (0);
1059 /* leading white space ignored */
1060 while (((c = *p) != '\0') && (isspace(*p++)))
1062 if (c == '?') {
1063 *d = bad;
1064 *cp = p;
1065 return (0);
1068 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1069 p--;
1070 *cp = p;
1071 return (1);
1074 *d = 0;
1075 while (isdigit(c)) {
1076 *d = (*d * base) + (c & 017);
1077 c = *p++;
1079 p--;
1080 *cp = p;
1081 return (0);
1085 getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad)
1087 int c;
1088 char *p = *cp;
1090 if (*p == '\0') {
1091 return (0);
1094 /* leading white space ignored */
1095 while (((c = *p) != '\0') && (isspace(*p++)))
1097 if (c == '?') {
1098 *d = bad;
1099 *cp = p;
1100 return (0);
1103 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1104 p--;
1105 *cp = p;
1106 return (1);
1109 *d = 0;
1110 while (isdigit(c)) {
1111 *d = (*d * base) + (c & 017);
1112 c = *p++;
1114 p--;
1115 *cp = p;
1116 return (0);
1119 static int
1120 getstrvfp(char **cp, char *sep, int n, char *str)
1122 char delims[256];
1123 int c;
1124 char *p = *cp;
1125 char *p1;
1126 size_t len;
1128 if (*p == '\0') {
1129 return (1);
1132 /* leading white space ignored */
1134 while (((c = *p) != '\0') && (isspace(*p++)))
1136 if ((c == '\0') || (c == '\n')) {
1137 p--;
1138 *cp = p;
1139 return (1); /* nothing there */
1142 p--;
1144 /* generate complete list of delimiters to scan for */
1146 (void) strlcpy(delims, " \t\n", sizeof (delims));
1147 if ((sep != (char *)NULL) && (*sep != '\0')) {
1148 (void) strlcat(delims, sep, sizeof (delims));
1151 /* compute length based on delimiter found or not */
1153 p1 = strpbrk(p, delims);
1154 if (p1 == (char *)NULL) {
1155 len = strlen(p);
1156 } else {
1157 len = (ptrdiff_t)p1 - (ptrdiff_t)p;
1160 /* if string will fit in result buffer copy string and return success */
1162 if (len < n) {
1163 (void) memcpy(str, p, len);
1164 str[len] = '\0';
1165 p += len;
1166 *cp = p;
1167 return (0);
1170 /* result buffer too small; copy partial string, return error */
1171 (void) memcpy(str, p, n-1);
1172 str[n-1] = '\0';
1173 p += n;
1174 *cp = p;
1175 return (-1);
1179 * Name: getendvfp
1180 * Description: Locate the end of the current line given a pointer into a buffer
1181 * containing characters that is null terminated.
1182 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1183 * Returns: int == 0 -- no non-space characters preceeded the newline
1184 * != 0 -- one or more non-space characters preceeded newline
1185 * Effects: cp is updated to point to the first character PAST the first new
1186 * line character found. If no newline character is found, cp is
1187 * updated to point to the '\0' at the end of the buffer.
1190 static int
1191 getendvfp(char **cp)
1193 int n;
1194 char *p = *cp;
1196 n = 0;
1198 /* if at end of buffer return no more characters left */
1200 if (*p == '\0') {
1201 return (0);
1204 /* find the first null or end of line character */
1206 while ((*p != '\0') && (*p != '\n')) {
1207 if (n == 0) {
1208 if (!isspace(*p)) {
1209 n++;
1212 p++;
1215 /* if at newline, increment pointer to first character past newline */
1217 if (*p == '\n') {
1218 p++;
1221 /* set return pointer to null or first character past newline */
1223 *cp = p;
1225 /* return space/nospace indicator */
1227 return (n);
1231 * Name: findendvfp
1232 * Description: Locate the end of the current line given a pointer into a buffer
1233 * containing characters that is null terminated.
1234 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1235 * Returns: none
1236 * Effects: cp is updated to point to the first character PAST the first new
1237 * line character found. If no newline character is found, cp is
1238 * updated to point to the '\0' at the end of the buffer.
1241 static void
1242 findendvfp(char **cp)
1244 char *p1;
1245 char *p = *cp;
1247 /* if at end of buffer return no more characters left */
1249 if (*p == '\0') {
1250 return;
1253 /* find the end of the line */
1255 p1 = strchr(p, '\n');
1256 if (p1 != (char *)NULL) {
1257 *cp = ++p1;
1258 return;
1261 /* no newline found - point to null terminator */
1263 *cp = strchr(p, '\0');