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 <string.h>
37 #include <ctype.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <errno.h>
42 #include "pkgstrct.h"
43 #include "pkglib.h"
44 #include "pkglibmsgs.h"
45 #include "pkglocale.h"
46
47 #define ERR_CANT_READ_LCLPATH "unable to read local pathname"
48 #define ERR_BAD_VOLUME_NUMBER "bad volume number"
49 #define ERR_CANNOT_READ_PATHNAME_FIELD "unable to read pathname field"
50 #define ERR_CANNOT_READ_CONTENT_INFO "unable to read content info"
51 #define ERR_EXTRA_TOKENS_PRESENT "extra tokens on input line"
52 #define ERR_CANNOT_READ_CLASS_TOKEN "unable to read class token"
53 #define ERR_BAD_LINK_SPEC "missing or invalid link specification"
54 #define ERR_UNKNOWN_FTYPE "unknown ftype"
55 #define ERR_NO_LINKSOURCE "no link source specified"
56 #define ERR_CANNOT_READ_MM_DEVNUMS "unable to read major/minor "\
57 "device numbers"
58 static int eatwhite(FILE *fp);
59 static int getend(FILE *fp);
60 static int getstr(FILE *fp, char *sep, int n, char *str);
61 static int getnum(FILE *fp, int base, long *d, long bad);
62 static int getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad);
63 static int getvalmode(FILE *fp, mode_t *d, long bad, int map);
64
65 static int getendvfp(char **cp);
66 static void findendvfp(char **cp);
67 static int getstrvfp(char **cp, char *sep, int n, char *str);
68 static int getvalmodevfp(char **cp, mode_t *d, long bad, int map);
69 int getnumvfp(char **cp, int base, long *d, long bad);
70 int getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad);
71
72 static char mypath[PATH_MAX];
73 static char mylocal[PATH_MAX];
74 static int mapmode = MAPNONE;
75 static char *maptype = "";
76 static mode_t d_mode = BADMODE;
77 static char *d_owner = BADOWNER;
78 static char *d_group = BADGROUP;
79
80 /*
81 * These determine how gpkgmap() deals with mode, owner and group defaults.
82 * It is assumed that the owner and group arguments represent static fields
83 * which will persist until attrdefault() is called.
84 */
85 void
attrpreset(int mode,char * owner,char * group)86 attrpreset(int mode, char *owner, char *group)
87 {
88 d_mode = mode;
89 d_owner = owner;
90 d_group = group;
91 }
92
93 void
attrdefault()94 attrdefault()
95 {
96 d_mode = NOMODE;
97 d_owner = NOOWNER;
98 d_group = NOGROUP;
99 }
100
101 /*
102 * This determines how gpkgmap() deals with environment variables in the
103 * mode, owner and group. Path is evaluated at a higher level based upon
104 * other circumstances.
105 */
106 void
setmapmode(int mode)107 setmapmode(int mode)
108 {
109 if (mode >= 0 || mode <= 3) {
110 mapmode = mode;
111 if (mode == MAPBUILD)
112 maptype = " build";
113 else if (mode == MAPINSTALL)
114 maptype = " install";
115 else
116 maptype = "";
117 }
118 }
119
120 /* This is the external query interface for mapmode. */
121 int
getmapmode(void)122 getmapmode(void)
123 {
124 return (mapmode);
125 }
126
127 /*
128 * Unpack the pkgmap or the contents file or whatever file is in that format.
129 * Based upon mapmode, environment parameters will be resolved for mode,
130 * owner and group.
131 */
132
133 int
gpkgmap(struct cfent * ept,FILE * fp)134 gpkgmap(struct cfent *ept, FILE *fp)
135 {
136 int c;
137 boolean_t first_char = B_TRUE;
138
139 setErrstr(NULL);
140 ept->volno = 0;
141 ept->ftype = BADFTYPE;
142 (void) strcpy(ept->pkg_class, BADCLASS);
143 ept->pkg_class_idx = -1;
144 ept->path = NULL;
145 ept->ainfo.local = NULL;
146 /* default attributes were supplied, so don't reset */
147 ept->ainfo.mode = d_mode;
148 (void) strcpy(ept->ainfo.owner, d_owner);
149 (void) strcpy(ept->ainfo.group, d_group);
150 ept->ainfo.major = BADMAJOR;
151 ept->ainfo.minor = BADMINOR;
152 ept->cinfo.cksum = ept->cinfo.modtime = ept->cinfo.size = (-1L);
153
154 ept->npkgs = 0;
155
156 if (!fp)
157 return (-1);
158 readline:
159 c = eatwhite(fp);
160
161 /*
162 * If the first character is not a digit, we assume that the
163 * volume number is 1.
164 */
165 if (first_char && !isdigit(c)) {
166 ept->volno = 1;
167 }
168 first_char = B_FALSE;
169
170 switch (c) {
171 case EOF:
172 return (0);
173
174 case '0':
175 case '1':
176 case '2':
177 case '3':
178 case '4':
179 case '5':
180 case '6':
181 case '7':
182 case '8':
183 case '9':
184 if (ept->volno) {
185 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
186 goto error;
187 }
188 do {
189 ept->volno = (ept->volno*10)+c-'0';
190 c = getc(fp);
191 } while (isdigit(c));
192 if (ept->volno == 0)
193 ept->volno = 1;
194
195 goto readline;
196
197 case ':':
198 case '#':
199 (void) getend(fp);
200 /*FALLTHRU*/
201 case '\n':
202 /*
203 * Since we are going to scan the next line,
204 * we need to reset volume number and first_char.
205 */
206 ept->volno = 0;
207 first_char = B_TRUE;
208 goto readline;
209
210 case 'i':
211 ept->ftype = (char)c;
212 c = eatwhite(fp);
213 /*FALLTHRU*/
214 case '.':
215 case '/':
216 (void) ungetc(c, fp);
217
218 if (getstr(fp, "=", PATH_MAX, mypath)) {
219 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
220 goto error;
221 }
222 ept->path = mypath;
223 c = getc(fp);
224 if (c == '=') {
225 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
226 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
227 goto error;
228 }
229 ept->ainfo.local = mylocal;
230 } else
231 (void) ungetc(c, fp);
232
233 if (ept->ftype == 'i') {
234 /* content info might exist */
235 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size,
236 BADCONT) &&
237 (getnum(fp, 10, (long *)&ept->cinfo.cksum,
238 BADCONT) ||
239 getnum(fp, 10, (long *)&ept->cinfo.modtime,
240 BADCONT))) {
241 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
242 goto error;
243 }
244 }
245 if (getend(fp)) {
246 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
247 return (-1);
248 }
249 return (1);
250
251 case '?':
252 case 'f':
253 case 'v':
254 case 'e':
255 case 'l':
256 case 's':
257 case 'p':
258 case 'c':
259 case 'b':
260 case 'd':
261 case 'x':
262 ept->ftype = (char)c;
263 if (getstr(fp, NULL, CLSSIZ, ept->pkg_class)) {
264 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
265 goto error;
266 }
267 if (getstr(fp, "=", PATH_MAX, mypath)) {
268 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
269 goto error;
270 }
271 ept->path = mypath;
272
273 c = getc(fp);
274 if (c == '=') {
275 /* local path */
276 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
277 if (ept->ftype == 's' || ept->ftype == 'l') {
278 setErrstr(pkg_gt(ERR_READLINK));
279 } else {
280 setErrstr(
281 pkg_gt(ERR_CANT_READ_LCLPATH));
282 }
283 goto error;
284 }
285 ept->ainfo.local = mylocal;
286 } else if (strchr("sl", ept->ftype)) {
287 if ((c != EOF) && (c != '\n'))
288 (void) getend(fp);
289 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
290 return (-1);
291 } else
292 (void) ungetc(c, fp);
293 break;
294
295 default:
296 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
297 error:
298 (void) getend(fp);
299 return (-1);
300 }
301
302 if (strchr("sl", ept->ftype) && (ept->ainfo.local == NULL)) {
303 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
304 goto error;
305 }
306
307 if (strchr("cb", ept->ftype)) {
308 ept->ainfo.major = BADMAJOR;
309 ept->ainfo.minor = BADMINOR;
310 if (getnum(fp, 10, (long *)&ept->ainfo.major, BADMAJOR) ||
311 getnum(fp, 10, (long *)&ept->ainfo.minor, BADMINOR)) {
312 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
313 goto error;
314 }
315 }
316
317 /*
318 * Links and information files don't have attributes associated with
319 * them. The following either resolves potential variables or passes
320 * them through. Mode is tested for validity to some degree. BAD???
321 * is returned to indicate that no meaningful mode was provided. A
322 * higher authority will decide if that's OK or not. CUR??? means that
323 * the prototype file specifically requires a wildcard ('?') for
324 * that entry. We issue an error if attributes were entered wrong.
325 * We just return BAD??? if there was no entry at all.
326 */
327 if (strchr("cbdxpfve", ept->ftype)) {
328 int retval;
329
330 if ((retval = getvalmode(fp, &(ept->ainfo.mode), CURMODE,
331 (mapmode != MAPNONE))) == 1)
332 goto end; /* nothing else on the line */
333 else if (retval == 2)
334 goto error; /* mode is too no good */
335
336 /* owner & group should be here */
337 if ((retval = getstr(fp, NULL, ATRSIZ,
338 ept->ainfo.owner)) == 1)
339 goto end; /* no owner or group - warning */
340 if (retval == -1) {
341 setErrstr(pkg_gt(ERR_OWNTOOLONG));
342 goto error;
343 }
344
345 if ((retval = getstr(fp, NULL, ATRSIZ,
346 ept->ainfo.group)) == 1)
347 goto end; /* no group - warning */
348 if (retval == -1) {
349 setErrstr(pkg_gt(ERR_GRPTOOLONG));
350 goto error;
351 }
352
353 /* Resolve the parameters if required. */
354 if (mapmode != MAPNONE) {
355 if (mapvar(mapmode, ept->ainfo.owner)) {
356 (void) snprintf(getErrbufAddr(),
357 getErrbufSize(),
358 pkg_gt(ERR_NOVAR),
359 maptype, ept->ainfo.owner);
360 setErrstr(getErrbufAddr());
361 goto error;
362 }
363 if (mapvar(mapmode, ept->ainfo.group)) {
364 (void) snprintf(getErrbufAddr(),
365 getErrbufSize(), pkg_gt(ERR_NOVAR),
366 maptype, ept->ainfo.group);
367 setErrstr(getErrbufAddr());
368 goto error;
369 }
370 }
371 }
372
373 if (strchr("ifve", ept->ftype)) {
374 /* look for content description */
375 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
376 (getnum(fp, 10, (long *)&ept->cinfo.cksum, BADCONT) ||
377 getnum(fp, 10, (long *)&ept->cinfo.modtime, BADCONT))) {
378 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
379 goto error;
380 }
381 }
382
383 if (ept->ftype == 'i')
384 goto end;
385
386 end:
387 if (getend(fp) && ept->pinfo) {
388 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
389 return (-1);
390 }
391
392 done:
393 return (1);
394 }
395
396 /*
397 * Get and validate the mode attribute. This returns an error if
398 * 1. the mode string is too long
399 * 2. the mode string includes alpha characters
400 * 3. the mode string is not octal
401 * 4. mode string is an install parameter
402 * 5. mode is an unresolved build parameter and MAPBUILD is
403 * in effect.
404 * If the mode is a build parameter, it is
405 * 1. returned as is if MAPNONE is in effect
406 * 2. evaluated if MAPBUILD is in effect
407 *
408 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
409 * time. At install time we just fix a mode with bad bits set by
410 * setting it to CURMODE. This should be an error in a few releases
411 * (2.8 maybe) but faulty modes are so common in existing packages
412 * that this is a reasonable exception. -- JST 1994-11-9
413 *
414 * RETURNS
415 * 0 if mode is being returned as a valid value
416 * 1 if no attributes are present on the line
417 * 2 if there was a fundamental error
418 */
419 static int
getvalmode(FILE * fp,mode_t * d,long bad,int map)420 getvalmode(FILE *fp, mode_t *d, long bad, int map)
421 {
422 char tempmode[20];
423 mode_t tempmode_t;
424 int retval;
425
426 if ((retval = getstr(fp, NULL, ATRSIZ, tempmode)) == 1)
427 return (1);
428 else if (retval == -1) {
429 setErrstr(pkg_gt(ERR_MODELONG));
430 return (2);
431 } else {
432 /*
433 * If it isn't a '?' (meaning go with whatever mode is
434 * there), validate the mode and convert it to a mode_t. The
435 * "bad" variable here is a misnomer. It doesn't necessarily
436 * mean bad.
437 */
438 if (tempmode[0] == '?') {
439 *d = WILDCARD;
440 } else {
441 /*
442 * Mode may not be an install parameter or a
443 * non-build parameter.
444 */
445 if (tempmode[0] == '$' &&
446 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
447 setErrstr(pkg_gt(ERR_IMODE));
448 return (2);
449 }
450
451 if ((map) && (mapvar(mapmode, tempmode))) {
452 (void) snprintf(getErrbufAddr(),
453 getErrbufSize(),
454 pkg_gt(ERR_NOVAR),
455 maptype, tempmode);
456 setErrstr(getErrbufAddr());
457 return (2);
458 }
459
460
461 if (tempmode[0] == '$') {
462 *d = BADMODE; /* may be a problem */
463 } else {
464 /*
465 * At this point it's supposed to be
466 * something we can convert to a number.
467 */
468 int n = 0;
469
470 /*
471 * We reject it if it contains nonnumbers or
472 * it's not octal.
473 */
474 while (tempmode[n] && !isspace(tempmode[n])) {
475 if (!isdigit(tempmode[n])) {
476 setErrstr(
477 pkg_gt(ERR_MODEALPHA));
478 return (2);
479 }
480
481 if (strchr("89abcdefABCDEF",
482 tempmode[n])) {
483 setErrstr(
484 pkg_gt(ERR_BASEINVAL));
485 return (2);
486 }
487 n++;
488 }
489
490 tempmode_t = strtol(tempmode, NULL, 8);
491
492 /*
493 * We reject it if it contains inappropriate
494 * bits.
495 */
496 if (tempmode_t & ~(S_IAMB |
497 S_ISUID | S_ISGID | S_ISVTX)) {
498 if (mapmode != MAPBUILD) {
499 tempmode_t = bad;
500 } else {
501 setErrstr(pkg_gt(ERR_MODEBITS));
502 return (2);
503 }
504 }
505 *d = tempmode_t;
506 }
507 }
508 return (0);
509 }
510 }
511
512 static int
getnum(FILE * fp,int base,long * d,long bad)513 getnum(FILE *fp, int base, long *d, long bad)
514 {
515 int c, b;
516
517 /* leading white space ignored */
518 c = eatwhite(fp);
519 if (c == '?') {
520 *d = bad;
521 return (0);
522 }
523
524 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
525 (void) ungetc(c, fp);
526 return (1);
527 }
528
529 *d = 0;
530 while (isdigit(c)) {
531 b = (c & 017);
532 if (b >= base)
533 return (2);
534 *d = (*d * base) + b;
535 c = getc(fp);
536 }
537 (void) ungetc(c, fp);
538 return (0);
539 }
540
541 static int
getlnum(FILE * fp,int base,fsblkcnt_t * d,long bad)542 getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad)
543 {
544 int c, b;
545
546 /* leading white space ignored */
547 c = eatwhite(fp);
548 if (c == '?') {
549 *d = bad;
550 return (0);
551 }
552
553 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
554 (void) ungetc(c, fp);
555 return (1);
556 }
557
558 *d = 0;
559 while (isdigit(c)) {
560 b = (c & 017);
561 if (b >= base)
562 return (2);
563 *d = (*d * base) + b;
564 c = getc(fp);
565 }
566 (void) ungetc(c, fp);
567 return (0);
568 }
569
570 /*
571 * Get a string from the file. Returns
572 * 0 if all OK
573 * 1 if nothing there
574 * -1 if string is too long
575 */
576 static int
getstr(FILE * fp,char * sep,int n,char * str)577 getstr(FILE *fp, char *sep, int n, char *str)
578 {
579 int c;
580
581 /* leading white space ignored */
582 c = eatwhite(fp);
583 if ((c == EOF) || (c == '\n')) {
584 (void) ungetc(c, fp);
585 return (1); /* nothing there */
586 }
587
588 /* fill up string until space, tab, or separator */
589 while (!strchr(" \t", c) && (!sep || !strchr(sep, c))) {
590 if (n-- < 1) {
591 *str = '\0';
592 return (-1); /* too long */
593 }
594 *str++ = (char)c;
595 c = getc(fp);
596 if ((c == EOF) || (c == '\n'))
597 break; /* no more on this line */
598 }
599 *str = '\0';
600 (void) ungetc(c, fp);
601
602 return (0);
603 }
604
605 static int
getend(FILE * fp)606 getend(FILE *fp)
607 {
608 int c;
609 int n;
610
611 n = 0;
612 do {
613 if ((c = getc(fp)) == EOF)
614 return (n);
615 if (!isspace(c))
616 n++;
617 } while (c != '\n');
618 return (n);
619 }
620
621 static int
eatwhite(FILE * fp)622 eatwhite(FILE *fp)
623 {
624 int c;
625
626 /* this test works around a side effect of getc() */
627 if (feof(fp))
628 return (EOF);
629 do
630 c = getc(fp);
631 while ((c == ' ') || (c == '\t'));
632 return (c);
633 }
634
635 int
gpkgmapvfp(struct cfent * ept,VFP_T * vfp)636 gpkgmapvfp(struct cfent *ept, VFP_T *vfp)
637 {
638 int c;
639 boolean_t first_char = B_TRUE;
640 (void) strlcpy(ept->pkg_class, BADCLASS, sizeof (ept->pkg_class));
641 (void) strlcpy(ept->ainfo.owner, d_owner, sizeof (ept->ainfo.owner));
642 (void) strlcpy(ept->ainfo.group, d_group, sizeof (ept->ainfo.group));
643
644 setErrstr(NULL);
645 ept->volno = 0;
646 ept->ftype = BADFTYPE;
647 ept->pkg_class_idx = -1;
648 ept->path = NULL;
649 ept->ainfo.local = NULL;
650 ept->ainfo.mode = d_mode;
651 ept->ainfo.major = BADMAJOR;
652 ept->ainfo.minor = BADMINOR;
653 ept->cinfo.cksum = (-1L);
654 ept->cinfo.modtime = (-1L);
655 ept->cinfo.size = (-1L);
656
657 ept->npkgs = 0;
658
659 /* return error if no vfp specified */
660
661 if (vfp == (VFP_T *)NULL) {
662 return (-1);
663 }
664
665 readline:
666 while (((c = vfpGetcNoInc(vfp)) != '\0') && (isspace(vfpGetc(vfp))))
667 ;
668
669 /*
670 * If the first character is not a digit, we assume that the
671 * volume number is 1.
672 */
673 if (first_char && !isdigit(c)) {
674 ept->volno = 1;
675 }
676 first_char = B_FALSE;
677
678 /*
679 * In case of hsfs the zero-padding of partial pages
680 * returned by mmap is not done properly. A separate bug has been filed
681 * on this.
682 */
683
684 if (vfp->_vfpCurr && (vfp->_vfpCurr > vfp->_vfpEnd)) {
685 return (0);
686 }
687
688 switch (c) {
689 case '\0':
690 return (0);
691
692 case '0':
693 case '1':
694 case '2':
695 case '3':
696 case '4':
697 case '5':
698 case '6':
699 case '7':
700 case '8':
701 case '9':
702 if (ept->volno) {
703 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
704 goto error;
705 }
706 do {
707 ept->volno = (ept->volno*10)+c-'0';
708 c = vfpGetc(vfp);
709 } while (isdigit(c));
710 if (ept->volno == 0) {
711 ept->volno = 1;
712 }
713
714 goto readline;
715
716 case ':':
717 case '#':
718 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
719 /*FALLTHRU*/
720 case '\n':
721 /*
722 * Since we are going to scan the next line,
723 * we need to reset volume number and first_char.
724 */
725 ept->volno = 0;
726 first_char = B_TRUE;
727 goto readline;
728
729 case 'i':
730 ept->ftype = (char)c;
731 while (((c = vfpGetcNoInc(vfp)) != '\0') &&
732 (isspace(vfpGetc(vfp))))
733 ;
734 /*FALLTHRU*/
735 case '.':
736 case '/':
737 vfpDecCurrPtr(vfp);
738
739 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
740 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
741 goto error;
742 }
743 ept->path = mypath;
744 c = vfpGetc(vfp);
745 if (c == '=') {
746 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, PATH_MAX,
747 mylocal)) {
748 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
749 goto error;
750 }
751 ept->ainfo.local = mylocal;
752 } else {
753 vfpDecCurrPtr(vfp);
754 }
755
756 if (ept->ftype == 'i') {
757 /* content info might exist */
758 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
759 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
760 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
761 (long *)&ept->cinfo.cksum, BADCONT) ||
762 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
763 (long *)&ept->cinfo.modtime, BADCONT))) {
764 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
765 goto error;
766 }
767 }
768
769 if (getendvfp(&vfpGetCurrCharPtr(vfp))) {
770 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
771 return (-1);
772 }
773 return (1);
774
775 case '?':
776 case 'f':
777 case 'v':
778 case 'e':
779 case 'l':
780 case 's':
781 case 'p':
782 case 'c':
783 case 'b':
784 case 'd':
785 case 'x':
786 ept->ftype = (char)c;
787 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
788 CLSSIZ, ept->pkg_class)) {
789 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
790 goto error;
791 }
792 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
793 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
794 goto error;
795 }
796 ept->path = mypath;
797
798 c = vfpGetc(vfp);
799 if (c == '=') {
800 /* local path */
801 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
802 PATH_MAX, mylocal)) {
803 if (ept->ftype == 's' || ept->ftype == 'l') {
804 setErrstr(pkg_gt(ERR_READLINK));
805 } else {
806 setErrstr(
807 pkg_gt(ERR_CANT_READ_LCLPATH));
808 }
809 goto error;
810 }
811 ept->ainfo.local = mylocal;
812 } else if ((ept->ftype == 's') || (ept->ftype == 'l')) {
813 if ((c != '\0') && (c != '\n'))
814 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
815 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
816 return (-1);
817 } else {
818 vfpDecCurrPtr(vfp);
819 }
820 break;
821
822 default:
823 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
824 error:
825 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
826 return (-1);
827 }
828
829 if (((ept->ftype == 's') || (ept->ftype == 'l')) &&
830 (ept->ainfo.local == NULL)) {
831 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
832 goto error;
833 }
834
835 if (((ept->ftype == 'c') || (ept->ftype == 'b'))) {
836 ept->ainfo.major = BADMAJOR;
837 ept->ainfo.minor = BADMINOR;
838
839 if (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
840 (long *)&ept->ainfo.major, BADMAJOR) ||
841 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
842 (long *)&ept->ainfo.minor, BADMINOR)) {
843 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
844 goto error;
845 }
846 }
847
848 /*
849 * Links and information files don't have attributes associated with
850 * them. The following either resolves potential variables or passes
851 * them through. Mode is tested for validity to some degree. BAD???
852 * is returned to indicate that no meaningful mode was provided. A
853 * higher authority will decide if that's OK or not. CUR??? means that
854 * the prototype file specifically requires a wildcard ('?') for
855 * that entry. We issue an error if attributes were entered wrong.
856 * We just return BAD??? if there was no entry at all.
857 */
858 if ((ept->ftype == 'd') || (ept->ftype == 'x') || (ept->ftype == 'c') ||
859 (ept->ftype == 'b') || (ept->ftype == 'p') ||
860 (ept->ftype == 'f') || (ept->ftype == 'v') ||
861 (ept->ftype == 'e')) {
862 int retval;
863
864 retval = getvalmodevfp(&vfpGetCurrCharPtr(vfp),
865 &(ept->ainfo.mode),
866 CURMODE, (mapmode != MAPNONE));
867
868 if (retval == 1) {
869 goto end; /* nothing else on the line */
870 } else if (retval == 2) {
871 goto error; /* mode is too no good */
872 }
873
874 /* owner & group should be here */
875 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
876 ept->ainfo.owner)) == 1)
877 goto end; /* no owner or group - warning */
878 if (retval == -1) {
879 setErrstr(pkg_gt(ERR_OWNTOOLONG));
880 goto error;
881 }
882
883 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
884 ept->ainfo.group)) == 1)
885 goto end; /* no group - warning */
886 if (retval == -1) {
887 setErrstr(pkg_gt(ERR_GRPTOOLONG));
888 goto error;
889 }
890
891 /* Resolve the parameters if required. */
892 if (mapmode != MAPNONE) {
893 if (mapvar(mapmode, ept->ainfo.owner)) {
894 (void) snprintf(getErrbufAddr(),
895 getErrbufSize(), pkg_gt(ERR_NOVAR),
896 maptype, ept->ainfo.owner);
897 setErrstr(getErrbufAddr());
898 goto error;
899 }
900 if (mapvar(mapmode, ept->ainfo.group)) {
901 (void) snprintf(getErrbufAddr(),
902 getErrbufSize(), pkg_gt(ERR_NOVAR),
903 maptype, ept->ainfo.group);
904 setErrstr(getErrbufAddr());
905 goto error;
906 }
907 }
908 }
909
910 if ((ept->ftype == 'i') || (ept->ftype == 'f') ||
911 (ept->ftype == 'v') || (ept->ftype == 'e')) {
912 /* look for content description */
913 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
914 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
915 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
916 (long *)&ept->cinfo.cksum, BADCONT) ||
917 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
918 (long *)&ept->cinfo.modtime, BADCONT))) {
919 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
920 goto error;
921 }
922 }
923
924 if (ept->ftype == 'i')
925 goto end;
926
927 end:
928 if (getendvfp(&vfpGetCurrCharPtr(vfp)) && ept->pinfo) {
929 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
930 return (-1);
931 }
932
933 done:
934 return (1);
935 }
936
937 /*
938 * Get and validate the mode attribute. This returns an error if
939 * 1. the mode string is too long
940 * 2. the mode string includes alpha characters
941 * 3. the mode string is not octal
942 * 4. mode string is an install parameter
943 * 5. mode is an unresolved build parameter and MAPBUILD is
944 * in effect.
945 * If the mode is a build parameter, it is
946 * 1. returned as is if MAPNONE is in effect
947 * 2. evaluated if MAPBUILD is in effect
948 *
949 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
950 * time. At install time we just fix a mode with bad bits set by
951 * setting it to CURMODE. This should be an error in a few releases
952 * (2.8 maybe) but faulty modes are so common in existing packages
953 * that this is a reasonable exception. -- JST 1994-11-9
954 *
955 * RETURNS
956 * 0 if mode is being returned as a valid value
957 * 1 if no attributes are present on the line
958 * 2 if there was a fundamental error
959 */
960 static int
getvalmodevfp(char ** cp,mode_t * d,long bad,int map)961 getvalmodevfp(char **cp, mode_t *d, long bad, int map)
962 {
963 char tempmode[ATRSIZ+1];
964 mode_t tempmode_t;
965 int retval;
966 int n;
967
968 if ((retval = getstrvfp(cp, NULL, sizeof (tempmode), tempmode)) == 1) {
969 return (1);
970 } else if (retval == -1) {
971 setErrstr(pkg_gt(ERR_MODELONG));
972 return (2);
973 }
974
975 /*
976 * If it isn't a '?' (meaning go with whatever mode is
977 * there), validate the mode and convert it to a mode_t. The
978 * "bad" variable here is a misnomer. It doesn't necessarily
979 * mean bad.
980 */
981 if (tempmode[0] == '?') {
982 *d = WILDCARD;
983 return (0);
984 }
985
986 /*
987 * Mode may not be an install parameter or a
988 * non-build parameter.
989 */
990
991 if (tempmode[0] == '$' &&
992 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
993 setErrstr(pkg_gt(ERR_IMODE));
994 return (2);
995 }
996
997 if ((map) && (mapvar(mapmode, tempmode))) {
998 (void) snprintf(getErrbufAddr(), getErrbufSize(),
999 pkg_gt(ERR_NOVAR), maptype, tempmode);
1000 setErrstr(getErrbufAddr());
1001 return (2);
1002 }
1003
1004 if (tempmode[0] == '$') {
1005 *d = BADMODE; /* may be a problem */
1006 return (0);
1007 }
1008
1009 /* it's supposed to be something we can convert to a number */
1010
1011 n = 0;
1012
1013 /* reject it if it contains nonnumbers or it's not octal */
1014
1015 while (tempmode[n] && !isspace(tempmode[n])) {
1016 if (!isdigit(tempmode[n])) {
1017 setErrstr(pkg_gt(ERR_MODEALPHA));
1018 return (2);
1019 }
1020
1021 if (strchr("89abcdefABCDEF", tempmode[n])) {
1022 setErrstr(pkg_gt(ERR_BASEINVAL));
1023 return (2);
1024 }
1025 n++;
1026 }
1027
1028 tempmode_t = strtol(tempmode, NULL, 8);
1029
1030 /*
1031 * We reject it if it contains inappropriate
1032 * bits.
1033 */
1034 if (tempmode_t & (~(S_IAMB | S_ISUID | S_ISGID | S_ISVTX))) {
1035 if (mapmode == MAPBUILD) {
1036 setErrstr(pkg_gt(ERR_MODEBITS));
1037 return (2);
1038 }
1039 tempmode_t = bad;
1040 }
1041
1042 *d = tempmode_t;
1043
1044 return (0);
1045 }
1046
1047 int
getnumvfp(char ** cp,int base,long * d,long bad)1048 getnumvfp(char **cp, int base, long *d, long bad)
1049 {
1050 int c;
1051 char *p = *cp;
1052
1053 if (*p == '\0') {
1054 return (0);
1055 }
1056
1057 /* leading white space ignored */
1058 while (((c = *p) != '\0') && (isspace(*p++)))
1059 ;
1060 if (c == '?') {
1061 *d = bad;
1062 *cp = p;
1063 return (0);
1064 }
1065
1066 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1067 p--;
1068 *cp = p;
1069 return (1);
1070 }
1071
1072 *d = 0;
1073 while (isdigit(c)) {
1074 *d = (*d * base) + (c & 017);
1075 c = *p++;
1076 }
1077 p--;
1078 *cp = p;
1079 return (0);
1080 }
1081
1082 int
getlnumvfp(char ** cp,int base,fsblkcnt_t * d,long bad)1083 getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad)
1084 {
1085 int c;
1086 char *p = *cp;
1087
1088 if (*p == '\0') {
1089 return (0);
1090 }
1091
1092 /* leading white space ignored */
1093 while (((c = *p) != '\0') && (isspace(*p++)))
1094 ;
1095 if (c == '?') {
1096 *d = bad;
1097 *cp = p;
1098 return (0);
1099 }
1100
1101 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1102 p--;
1103 *cp = p;
1104 return (1);
1105 }
1106
1107 *d = 0;
1108 while (isdigit(c)) {
1109 *d = (*d * base) + (c & 017);
1110 c = *p++;
1111 }
1112 p--;
1113 *cp = p;
1114 return (0);
1115 }
1116
1117 static int
getstrvfp(char ** cp,char * sep,int n,char * str)1118 getstrvfp(char **cp, char *sep, int n, char *str)
1119 {
1120 char delims[256];
1121 int c;
1122 char *p = *cp;
1123 char *p1;
1124 size_t len;
1125
1126 if (*p == '\0') {
1127 return (1);
1128 }
1129
1130 /* leading white space ignored */
1131
1132 while (((c = *p) != '\0') && (isspace(*p++)))
1133 ;
1134 if ((c == '\0') || (c == '\n')) {
1135 p--;
1136 *cp = p;
1137 return (1); /* nothing there */
1138 }
1139
1140 p--;
1141
1142 /* generate complete list of delimiters to scan for */
1143
1144 (void) strlcpy(delims, " \t\n", sizeof (delims));
1145 if ((sep != (char *)NULL) && (*sep != '\0')) {
1146 (void) strlcat(delims, sep, sizeof (delims));
1147 }
1148
1149 /* compute length based on delimiter found or not */
1150
1151 p1 = strpbrk(p, delims);
1152 if (p1 == (char *)NULL) {
1153 len = strlen(p);
1154 } else {
1155 len = (ptrdiff_t)p1 - (ptrdiff_t)p;
1156 }
1157
1158 /* if string will fit in result buffer copy string and return success */
1159
1160 if (len < n) {
1161 (void) memcpy(str, p, len);
1162 str[len] = '\0';
1163 p += len;
1164 *cp = p;
1165 return (0);
1166 }
1167
1168 /* result buffer too small; copy partial string, return error */
1169 (void) memcpy(str, p, n-1);
1170 str[n-1] = '\0';
1171 p += n;
1172 *cp = p;
1173 return (-1);
1174 }
1175
1176 /*
1177 * Name: getendvfp
1178 * Description: Locate the end of the current line given a pointer into a buffer
1179 * containing characters that is null terminated.
1180 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1181 * Returns: int == 0 -- no non-space characters preceeded the newline
1182 * != 0 -- one or more non-space characters preceeded newline
1183 * Effects: cp is updated to point to the first character PAST the first new
1184 * line character found. If no newline character is found, cp is
1185 * updated to point to the '\0' at the end of the buffer.
1186 */
1187
1188 static int
getendvfp(char ** cp)1189 getendvfp(char **cp)
1190 {
1191 int n;
1192 char *p = *cp;
1193
1194 n = 0;
1195
1196 /* if at end of buffer return no more characters left */
1197
1198 if (*p == '\0') {
1199 return (0);
1200 }
1201
1202 /* find the first null or end of line character */
1203
1204 while ((*p != '\0') && (*p != '\n')) {
1205 if (n == 0) {
1206 if (!isspace(*p)) {
1207 n++;
1208 }
1209 }
1210 p++;
1211 }
1212
1213 /* if at newline, increment pointer to first character past newline */
1214
1215 if (*p == '\n') {
1216 p++;
1217 }
1218
1219 /* set return pointer to null or first character past newline */
1220
1221 *cp = p;
1222
1223 /* return space/nospace indicator */
1224
1225 return (n);
1226 }
1227
1228 /*
1229 * Name: findendvfp
1230 * Description: Locate the end of the current line given a pointer into a buffer
1231 * containing characters that is null terminated.
1232 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1233 * Returns: none
1234 * Effects: cp is updated to point to the first character PAST the first new
1235 * line character found. If no newline character is found, cp is
1236 * updated to point to the '\0' at the end of the buffer.
1237 */
1238
1239 static void
findendvfp(char ** cp)1240 findendvfp(char **cp)
1241 {
1242 char *p1;
1243 char *p = *cp;
1244
1245 /* if at end of buffer return no more characters left */
1246
1247 if (*p == '\0') {
1248 return;
1249 }
1250
1251 /* find the end of the line */
1252
1253 p1 = strchr(p, '\n');
1254 if (p1 != (char *)NULL) {
1255 *cp = ++p1;
1256 return;
1257 }
1258
1259 /* no newline found - point to null terminator */
1260
1261 *cp = strchr(p, '\0');
1262 }
1263