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