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