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