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 2006 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 #include <stdio.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <ctype.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <limits.h> 38 #include <pkgstrct.h> 39 #include <pkginfo.h> 40 #include <locale.h> 41 #include <libintl.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <pkglib.h> 45 #include <install.h> 46 #include <libadm.h> 47 #include <libinst.h> 48 49 extern char *basedir, *root, *rootlist[], **environ; 50 51 /* 52 * IMPORTANT NOTE: PLEASE SEE THE DEFINITION OF temp[] BELOW BEFORE 53 * CHANGING THE DEFINITION OF PATH_LGTH!!!! 54 */ 55 56 #define PATH_LGTH 4096 57 58 #define MAXPARAMS 256 59 #define NRECURS 20 60 61 #define MSG_BPARAMC "parametric class specification for <%s> not allowed" 62 #define MSG_SRCHLOC "no object for <%s> found in local path" 63 #define MSG_SRCHSRCH "no object for <%s> found in search path" 64 #define MSG_SRCHROOT "no object for <%s> found in root directory" 65 #define MSG_CONTENTS "unable to process contents of object <%s>" 66 #define MSG_WRITE "write of entry failed, errno=%d" 67 #define MSG_GARBDEFLT "garbled default settings: %s" 68 #define MSG_BANG "unknown directive: %s" 69 #define MSG_CHDIR "unable to change directory to <%s>" 70 #define MSG_INCOMPLETE "processing of <%s> may be incomplete" 71 #define MSG_NRECURS "too many levels of include (limit is %d)" 72 #define MSG_RDINCLUDE "unable to process include file <%s>, errno=%d" 73 #define MSG_IGNINCLUDE "ignoring include file <%s>" 74 #define MSG_NODEVICE "device numbers cannot be determined for <%s>" 75 76 #define WRN_BADATTR "WARNING: attributes set to %04o %s %s for <%s>" 77 #define WRN_BADATTRM "WARNING: attributes set to %s %s %s for <%s>" 78 #define WRN_FAKEBD "WARNING: parametric paths may ignore BASEDIR" 79 80 #define ERR_TEMP "unable to obtain temporary file resources, errno=%d" 81 #define ERR_ENVBUILD "unable to build parameter environment, errno=%d" 82 #define ERR_MAXPARAMS "too many parameter definitions (limit is %d)" 83 #define ERR_GETCWD "unable to get current directory, errno=%d" 84 #define ERR_PATHVAR "cannot resolve all build parameters associated with " \ 85 "path <%s>." 86 87 static struct cfent entry; 88 static FILE *fp, 89 *sfp[20]; 90 static char *dname[NRECURS], 91 *params[256], 92 *proto[NRECURS], 93 *rootp[NRECURS][16], 94 *srchp[NRECURS][16], 95 *d_own[NRECURS], 96 *d_grp[NRECURS], 97 *rdonly[256]; 98 static mode_t d_mod[NRECURS]; 99 static int nfp = (-1); 100 static int nrdonly = 0; 101 static int errflg = 0; 102 static char *separ = " \t\n, "; 103 104 /* libpkg/gpkgmap.c */ 105 extern void attrpreset(int mode, char *owner, char *group); 106 extern void attrdefault(); 107 static char *findfile(char *path, char *local); 108 static char *srchroot(char *path, char *copy); 109 110 static int popenv(void); 111 112 static int doattrib(void); 113 static void doinclude(void); 114 static void dorsearch(void); 115 static void dosearch(void); 116 static void error(int flag); 117 static void lputenv(char *s); 118 static void pushenv(char *file); 119 static void translate(register char *pt, register char *copy); 120 121 int 122 mkpkgmap(char *outfile, char *protofile, char **envparam) 123 { 124 FILE *tmpfp; 125 char *pt, *path, mybuff[PATH_LGTH]; 126 char **envsave; 127 int c, fakebasedir; 128 int i, n; 129 130 /* 131 * NOTE: THE SIZE OF temp IS HARD CODED INTO CALLS TO fscanf. 132 * YOU *MUST* MAKE SURE TO CHANGE THOSE CALLS IF THE SIZE OF temp 133 * IS EVER CHANGED!!!!!! 134 */ 135 char temp[PATH_LGTH]; 136 137 if ((tmpfp = fopen(outfile, "w")) == NULL) { 138 progerr(gettext(ERR_TEMP), errno); 139 quit(99); 140 } 141 envsave = environ; 142 environ = params; /* use only local environ */ 143 attrdefault(); /* assume no default attributes */ 144 145 /* 146 * Environment parameters are optional, so variable 147 * (envparam[i]) could be NULL. 148 */ 149 for (i = 0; (envparam[i] != NULL) && 150 (pt = strchr(envparam[i], '=')); i++) { 151 *pt = '\0'; 152 rdonly[nrdonly++] = qstrdup(envparam[i]); 153 *pt = '='; 154 if (putenv(qstrdup(envparam[i]))) { /* bugid 1090920 */ 155 progerr(gettext(ERR_ENVBUILD), errno); 156 quit(99); 157 } 158 if (nrdonly >= MAXPARAMS) { 159 progerr(gettext(ERR_MAXPARAMS), MAXPARAMS); 160 quit(1); 161 } 162 } 163 164 pushenv(protofile); 165 errflg = 0; 166 again: 167 fakebasedir = 0; 168 while (!feof(fp)) { 169 c = getc(fp); 170 while (isspace(c)) 171 c = getc(fp); 172 173 if (c == '#') { 174 do c = getc(fp); while ((c != EOF) && (c != '\n')); 175 continue; 176 } 177 if (c == EOF) 178 break; 179 180 if (c == '!') { 181 /* 182 * IMPORTANT NOTE: THE SIZE OF temp IS HARD CODED INTO 183 * the FOLLOWING CALL TO fscanf -- YOU MUST CHANGE THIS 184 * LINE IF THE SIZE OF fscanf IS EVER CHANGED!!! 185 */ 186 (void) fscanf(fp, "%4096s", temp); 187 188 if (strcmp(temp, "include") == 0) 189 doinclude(); 190 else if (strcmp(temp, "rsearch") == 0) 191 dorsearch(); 192 else if (strcmp(temp, "search") == 0) 193 dosearch(); 194 else if (strcmp(temp, "default") == 0) { 195 if (doattrib()) 196 break; 197 } else if (strchr(temp, '=')) { 198 translate(temp, mybuff); 199 /* put this into the local environment */ 200 lputenv(mybuff); 201 (void) fscanf(fp, "%*[^\n]"); /* rest of line */ 202 (void) fscanf(fp, "\n"); /* rest of line */ 203 } else { 204 error(1); 205 logerr(gettext(MSG_BANG), temp); 206 (void) fscanf(fp, "%*[^\n]"); /* read of line */ 207 (void) fscanf(fp, "\n"); /* read of line */ 208 } 209 continue; 210 } 211 (void) ungetc(c, fp); 212 213 if ((n = gpkgmap(&entry, fp)) < 0) { 214 char *errstr; 215 216 error(1); 217 errstr = getErrstr(); 218 logerr(gettext("garbled entry")); 219 logerr(gettext("- pathname: %s"), 220 (entry.path && *entry.path) ? entry.path : 221 "Unknown"); 222 logerr(gettext("- problem: %s"), 223 (errstr && *errstr) ? errstr : "Unknown"); 224 break; 225 } 226 if (n == 0) 227 break; /* done with file */ 228 229 /* don't allow classname to be parametric */ 230 if (entry.ftype != 'i') { 231 if (entry.pkg_class[0] == '$') { 232 error(1); 233 logerr(gettext(MSG_BPARAMC), entry.path); 234 } 235 } 236 237 if (strchr("dxlscbp", entry.ftype)) { 238 /* 239 * We don't need to search for things without any 240 * contents in them. 241 */ 242 if (strchr("cb", entry.ftype)) { 243 if (entry.ainfo.major == BADMAJOR || 244 entry.ainfo.minor == BADMINOR) { 245 error(1); 246 logerr(gettext(MSG_NODEVICE), 247 entry.path); 248 } 249 } 250 path = NULL; 251 } else { 252 path = findfile(entry.path, entry.ainfo.local); 253 if (!path) 254 continue; 255 256 entry.ainfo.local = path; 257 if (strchr("fevin?", entry.ftype)) { 258 if (cverify(0, &entry.ftype, path, 259 &entry.cinfo, 1)) { 260 error(1); 261 logerr(gettext(MSG_CONTENTS), path); 262 } 263 } 264 } 265 266 /* Warn if attributes are not set correctly. */ 267 if (!strchr("isl", entry.ftype)) { 268 int dowarning = 0; 269 int hasbadmode = 0; 270 271 if (entry.ainfo.mode == NOMODE) { 272 entry.ainfo.mode = CURMODE; 273 dowarning = 1; 274 hasbadmode = 1; 275 } 276 277 if (strcmp(entry.ainfo.owner, NOOWNER) == 0) { 278 (void) strlcpy(entry.ainfo.owner, CUROWNER, 279 sizeof (entry.ainfo.owner)); 280 dowarning = 1; 281 } 282 283 if (strcmp(entry.ainfo.group, NOGROUP) == 0) { 284 (void) strlcpy(entry.ainfo.group, CURGROUP, 285 sizeof (entry.ainfo.group)); 286 dowarning = 1; 287 } 288 289 290 if (dowarning) { 291 if (hasbadmode) 292 logerr(gettext(WRN_BADATTRM), 293 "?", 294 entry.ainfo.owner, 295 entry.ainfo.group, 296 entry.path); 297 else 298 logerr(gettext(WRN_BADATTR), 299 (int)entry.ainfo.mode, 300 entry.ainfo.owner, 301 entry.ainfo.group, 302 entry.path); 303 } 304 } 305 306 /* 307 * Resolve build parameters (initial lower case) in 308 * the link and target paths. 309 */ 310 if (strchr("ls", entry.ftype)) { 311 if (!RELATIVE(entry.ainfo.local) || 312 PARAMETRIC(entry.ainfo.local)) { 313 if (mappath(1, entry.ainfo.local)) { 314 error(1); 315 logerr(gettext(ERR_PATHVAR), 316 entry.ainfo.local); 317 break; 318 } 319 320 canonize(entry.ainfo.local); 321 } 322 } 323 324 /* 325 * Warn if top level file or directory is an install 326 * parameter 327 */ 328 if (entry.ftype != 'i') { 329 if (entry.path[0] == '$' && isupper(entry.path[1])) 330 fakebasedir = 1; 331 } 332 333 if (mappath(1, entry.path)) { 334 error(1); 335 logerr(gettext(ERR_PATHVAR), entry.path); 336 break; 337 } 338 339 canonize(entry.path); 340 if (ppkgmap(&entry, tmpfp)) { 341 error(1); 342 logerr(gettext(MSG_WRITE), errno); 343 break; 344 } 345 } 346 347 if (fakebasedir) { 348 logerr(gettext(WRN_FAKEBD)); 349 fakebasedir = 0; 350 } 351 352 if (popenv()) 353 goto again; 354 355 (void) fclose(tmpfp); 356 environ = envsave; /* restore environment */ 357 358 return (errflg ? 1 : 0); 359 } 360 361 static char * 362 findfile(char *path, char *local) 363 { 364 struct stat statbuf; 365 static char host[PATH_MAX]; 366 register char *pt; 367 char temp[PATH_MAX], *basename; 368 int i; 369 370 /* 371 * map any parameters specified in path to their corresponding values 372 * and make sure the path is in its canonical form; any parmeters for 373 * which a value is not defined will be left unexpanded. Since this 374 * is an actual search for a real file (which will not end up in the 375 * package) - we map ALL variables (both build and Install). 376 */ 377 (void) strlcpy(temp, (local && local[0] ? local : path), sizeof (temp)); 378 mappath(0, temp); 379 canonize(temp); 380 381 *host = '\0'; 382 if (rootlist[0] || (basedir && (*temp != '/'))) { 383 /* 384 * search for path in the pseudo-root/basedir directory; note 385 * that package information files should NOT be included in 386 * this list 387 */ 388 if (entry.ftype != 'i') 389 return (srchroot(temp, host)); 390 } 391 392 /* looking for local object file */ 393 if (local && *local) { 394 basepath(temp, dname[nfp], NULL); 395 /* 396 * If it equals "/dev/null", that just means it's an empty 397 * file. Otherwise, we'll really be writing stuff, so we need 398 * to verify the source. 399 */ 400 if (strcmp(temp, "/dev/null") != 0) { 401 if (stat(temp, &statbuf) || 402 !(statbuf.st_mode & S_IFREG)) { 403 error(1); 404 logerr(gettext(MSG_SRCHLOC), path); 405 return (NULL); 406 } 407 } 408 (void) strlcpy(host, temp, sizeof (host)); 409 return (host); 410 } 411 412 for (i = 0; rootp[nfp][i]; i++) { 413 (void) snprintf(host, sizeof (host), "%s/%s", rootp[nfp][i], 414 temp + (*temp == '/' ? 1 : 0)); 415 if ((stat(host, &statbuf) == 0) && 416 (statbuf.st_mode & S_IFREG)) { 417 return (host); 418 } 419 } 420 421 pt = strrchr(temp, '/'); 422 if (!pt++) 423 pt = temp; 424 425 basename = pt; 426 427 for (i = 0; srchp[nfp][i]; i++) { 428 (void) snprintf(host, sizeof (host), "%s/%s", 429 srchp[nfp][i], basename); 430 if ((stat(host, &statbuf) == 0) && 431 (statbuf.st_mode & S_IFREG)) { 432 return (host); 433 } 434 } 435 436 /* check current directory as a last resort */ 437 (void) snprintf(host, sizeof (host), "%s/%s", dname[nfp], basename); 438 if ((stat(host, &statbuf) == 0) && (statbuf.st_mode & S_IFREG)) 439 return (host); 440 441 error(1); 442 logerr(gettext(MSG_SRCHSRCH), path); 443 return (NULL); 444 } 445 446 static void 447 dosearch(void) 448 { 449 char temp[PATH_MAX], lookpath[PATH_MAX], *pt; 450 int n; 451 452 (void) fgets(temp, PATH_MAX, fp); 453 translate(temp, lookpath); 454 455 for (n = 0; srchp[nfp][n]; n++) 456 free(srchp[nfp][n]); 457 458 n = 0; 459 pt = strtok(lookpath, separ); 460 if (pt && *pt) { 461 do { 462 if (*pt != '/') { 463 /* make relative path an absolute directory */ 464 (void) snprintf(temp, sizeof (temp), 465 "%s/%s", dname[nfp], pt); 466 pt = temp; 467 } 468 canonize(pt); 469 srchp[nfp][n++] = qstrdup(pt); 470 } while (pt = strtok(NULL, separ)); 471 srchp[nfp][n] = NULL; 472 } 473 } 474 475 static void 476 dorsearch(void) 477 { 478 char temp[PATH_MAX], lookpath[PATH_MAX], *pt; 479 int n; 480 481 (void) fgets(temp, PATH_MAX, fp); 482 translate(temp, lookpath); 483 484 for (n = 0; rootp[nfp][n]; n++) 485 free(rootp[nfp][n]); 486 487 n = 0; 488 pt = strtok(lookpath, separ); 489 do { 490 if (*pt != '/') { 491 /* make relative path an absolute directory */ 492 (void) snprintf(temp, sizeof (temp), 493 "%s/%s", dname[nfp], pt); 494 pt = temp; 495 } 496 canonize(pt); 497 rootp[nfp][n++] = qstrdup(pt); 498 } while (pt = strtok(NULL, separ)); 499 rootp[nfp][n] = NULL; 500 } 501 502 /* 503 * This function reads the default mode, owner and group from the prototype 504 * file and makes that available. 505 */ 506 static int 507 doattrib(void) 508 { 509 char *pt, attrib[PATH_MAX], *mode_ptr, *owner_ptr, *group_ptr, *eol; 510 int mode; 511 char owner[ATRSIZ+1], group[ATRSIZ+1], attrib_save[(4*ATRSIZ)]; 512 513 (void) fgets(attrib, PATH_MAX, fp); 514 515 (void) strlcpy(attrib_save, attrib, sizeof (attrib_save)); 516 517 /* 518 * Now resolve any variables that may be present. Start on group and 519 * move backward since that keeps the resolved string from 520 * overwriting any of the other entries. This is required since 521 * mapvar() writes the resolved string over the string provided. 522 */ 523 mode_ptr = strtok(attrib, " \t"); 524 owner_ptr = strtok(NULL, " \t"); 525 group_ptr = strtok(NULL, " \t\n"); 526 eol = strtok(NULL, " \t\n"); 527 if (strtok(NULL, " \t\n")) { 528 /* extra tokens on the line */ 529 error(1); 530 logerr(gettext(MSG_GARBDEFLT), (eol) ? eol : 531 gettext("unreadable at end of line")); 532 return (1); 533 } 534 535 if (group_ptr && mapvar(1, group_ptr) == 0) 536 (void) strncpy(group, group_ptr, ATRSIZ); 537 else { 538 error(1); 539 logerr(gettext(MSG_GARBDEFLT), (attrib_save) ? 540 ((attrib_save[0]) ? attrib_save : gettext("none")) : 541 gettext("unreadable at group")); 542 return (1); 543 } 544 545 if (owner_ptr && mapvar(1, owner_ptr) == 0) 546 (void) strncpy(owner, owner_ptr, ATRSIZ); 547 else { 548 error(1); 549 logerr(gettext(MSG_GARBDEFLT), (attrib_save) ? 550 ((attrib_save[0]) ? attrib_save : gettext("none")) : 551 gettext("unreadable at owner")); 552 return (1); 553 } 554 555 /* 556 * For mode, don't use scanf, since we want to force an octal 557 * interpretation and need to limit the length of the owner and group 558 * specifications. 559 */ 560 if (mode_ptr && mapvar(1, mode_ptr) == 0) 561 mode = strtol(mode_ptr, &pt, 8); 562 else { 563 error(1); 564 logerr(gettext(MSG_GARBDEFLT), (attrib_save) ? 565 ((attrib_save[0]) ? attrib_save : gettext("none")) : 566 gettext("unreadable at mode")); 567 return (1); 568 } 569 570 /* free any previous memory from qstrdup */ 571 if (d_own[nfp]) 572 free(d_own[nfp]); 573 if (d_grp[nfp]) 574 free(d_grp[nfp]); 575 576 d_mod[nfp] = mode; 577 d_own[nfp] = qstrdup(owner); 578 d_grp[nfp] = qstrdup(group); 579 580 attrpreset(d_mod[nfp], d_own[nfp], d_grp[nfp]); 581 582 return (0); 583 } 584 585 static void 586 doinclude(void) 587 { 588 char file[PATH_MAX]; 589 char temp[PATH_MAX]; 590 591 (void) fgets(temp, PATH_MAX, fp); 592 593 /* 594 * IMPORTANT NOTE: THE SIZE OF temp IS HARD CODED INTO THE 595 * FOLLOWING CALL TO fscanf -- YOU MUST CHANGE THIS LINE IF 596 * THE SIZE OF fscanf IS EVER CHANGED!!! 597 */ 598 (void) sscanf(temp, "%1024s", file); 599 600 translate(file, temp); 601 canonize(temp); 602 603 if (*temp == '\0') 604 return; 605 else if (*temp != '/') 606 (void) snprintf(file, sizeof (file), "%s/%s", dname[nfp], temp); 607 else 608 (void) strlcpy(file, temp, sizeof (file)); 609 610 canonize(file); 611 pushenv(file); 612 } 613 614 /* 615 * This does what mappath() does except that it does it for ALL variables 616 * using whitespace as a token separator. This is used to resolve search 617 * paths and assignment statements. It doesn't effect the build versus 618 * install decision made for pkgmap variables. 619 */ 620 static void 621 translate(register char *pt, register char *copy) 622 { 623 char *pt2, varname[MAX_PKG_PARAM_LENGTH]; 624 625 token: 626 /* eat white space */ 627 while (isspace(*pt)) 628 pt++; 629 while (*pt && !isspace(*pt)) { 630 if (*pt == '$') { 631 pt2 = varname; 632 while (*++pt && !strchr("/= \t\n\r", *pt)) 633 *pt2++ = *pt; 634 *pt2 = '\0'; 635 if (pt2 = getenv(varname)) { 636 while (*pt2) 637 *copy++ = *pt2++; 638 } 639 } else 640 *copy++ = *pt++; 641 } 642 if (*pt) { 643 *copy++ = ' '; 644 goto token; 645 } 646 *copy = '\0'; 647 } 648 649 static void 650 error(int flag) 651 { 652 static char *lasterr = NULL; 653 654 if (lasterr != proto[nfp]) { 655 lasterr = proto[nfp]; 656 (void) fprintf(stderr, gettext("ERROR in %s:\n"), lasterr); 657 } 658 if (flag) 659 errflg++; 660 } 661 662 /* Set up defaults and change to the build directory. */ 663 static void 664 pushenv(char *file) 665 { 666 register char *pt; 667 static char topdir[PATH_MAX]; 668 669 if ((nfp+1) >= NRECURS) { 670 error(1); 671 logerr(gettext(MSG_NRECURS), NRECURS); 672 logerr(gettext(MSG_IGNINCLUDE), file); 673 return; 674 } 675 676 if (strcmp(file, "-") == 0) { 677 fp = stdin; 678 } else if ((fp = fopen(file, "r")) == NULL) { 679 error(1); 680 logerr(gettext(MSG_RDINCLUDE), file, errno); 681 if (nfp >= 0) { 682 logerr(gettext(MSG_IGNINCLUDE), file); 683 fp = sfp[nfp]; 684 return; 685 } else 686 quit(1); 687 } 688 sfp[++nfp] = fp; 689 srchp[nfp][0] = NULL; 690 rootp[nfp][0] = NULL; 691 d_mod[nfp] = (mode_t)(-1); 692 d_own[nfp] = NULL; 693 d_grp[nfp] = NULL; 694 695 if (!nfp) { 696 /* upper level proto file */ 697 proto[nfp] = file; 698 if (file[0] == '/') 699 pt = strcpy(topdir, file); 700 else { 701 /* path is relative to the prototype file specified */ 702 pt = getcwd(NULL, PATH_MAX); 703 if (pt == NULL) { 704 progerr(gettext(ERR_GETCWD), errno); 705 quit(99); 706 } 707 (void) snprintf(topdir, sizeof (topdir), 708 "%s/%s", pt, file); 709 } 710 if (pt = strrchr(topdir, '/')) 711 *pt = '\0'; /* should always happen */ 712 if (topdir[0] == '\0') 713 (void) strlcpy(topdir, "/", sizeof (topdir)); 714 dname[nfp] = topdir; 715 } else { 716 proto[nfp] = qstrdup(file); 717 dname[nfp] = qstrdup(file); 718 if (pt = strrchr(dname[nfp], '/')) 719 *pt = '\0'; 720 else { 721 /* same directory as the last prototype */ 722 free(dname[nfp]); 723 dname[nfp] = qstrdup(dname[nfp-1]); 724 return; /* no need to canonize() or chdir() */ 725 } 726 } 727 728 canonize(dname[nfp]); 729 730 if (chdir(dname[nfp])) { 731 error(1); 732 logerr(gettext(MSG_CHDIR), dname[nfp]); 733 if (!nfp) 734 quit(1); /* must be able to cd to upper level */ 735 logerr(gettext(MSG_IGNINCLUDE), proto[nfp]); 736 (void) popenv(); 737 } 738 } 739 740 /* Restore defaults and return to the prior directory. */ 741 static int 742 popenv(void) 743 { 744 int i; 745 746 (void) fclose(fp); 747 if (nfp) { 748 if (proto[nfp]) 749 free(proto[nfp]); 750 if (dname[nfp]) 751 free(dname[nfp]); 752 for (i = 0; srchp[nfp][i]; i++) 753 free(srchp[nfp][i]); 754 for (i = 0; rootp[nfp][i]; i++) 755 free(rootp[nfp][i]); 756 if (d_own[nfp]) 757 free(d_own[nfp]); 758 if (d_grp[nfp]) 759 free(d_grp[nfp]); 760 761 fp = sfp[--nfp]; 762 763 if (chdir(dname[nfp])) { 764 error(1); 765 logerr(gettext(MSG_CHDIR), dname[nfp]); 766 logerr(gettext(MSG_INCOMPLETE), proto[nfp]); 767 return (popenv()); 768 } 769 return (1); 770 } 771 return (0); 772 } 773 774 /* 775 * If this parameter isn't already in place, put it into the local 776 * environment. This means that command line directives override prototype 777 * file directives. 778 */ 779 static void 780 lputenv(char *s) 781 { 782 char *pt; 783 int i; 784 785 pt = strchr(s, '='); 786 if (!pt) 787 return; 788 789 *pt = '\0'; 790 for (i = 0; i < nrdonly; i++) { 791 if (strcmp(rdonly[i], s) == 0) { 792 *pt = '='; 793 return; 794 } 795 } 796 *pt = '='; 797 798 if (putenv(qstrdup(s))) { 799 progerr(gettext(ERR_ENVBUILD), errno); 800 quit(99); 801 } 802 } 803 804 static char * 805 srchroot(char *path, char *copy) 806 { 807 struct stat statbuf; 808 int i; 809 810 i = 0; 811 root = rootlist[i++]; 812 do { 813 /* convert with root & basedir info */ 814 cvtpath(path, copy); 815 /* make it pretty again */ 816 canonize(copy); 817 818 if (stat(copy, &statbuf) || !(statbuf.st_mode & S_IFREG)) { 819 root = rootlist[i++]; 820 continue; /* host source must be a regular file */ 821 } 822 return (copy); 823 } while (root != NULL); 824 error(1); 825 logerr(gettext(MSG_SRCHROOT), path); 826 return (NULL); 827 } 828