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