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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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