1 /* $NetBSD: main.c,v 1.533 2021/02/05 19:19:17 sjg Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 /* 72 * The main file for this entire program. Exit routines etc. reside here. 73 * 74 * Utility functions defined in this file: 75 * 76 * Main_ParseArgLine 77 * Parse and process command line arguments from a 78 * single string. Used to implement the special targets 79 * .MFLAGS and .MAKEFLAGS. 80 * 81 * Error Print a tagged error message. 82 * 83 * Fatal Print an error message and exit. 84 * 85 * Punt Abort all jobs and exit with a message. 86 * 87 * Finish Finish things up by printing the number of errors 88 * that occurred, and exit. 89 */ 90 91 #include <sys/types.h> 92 #include <sys/time.h> 93 #include <sys/param.h> 94 #include <sys/resource.h> 95 #include <sys/stat.h> 96 #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 97 #include <sys/sysctl.h> 98 #endif 99 #include <sys/utsname.h> 100 #include "wait.h" 101 102 #include <errno.h> 103 #include <signal.h> 104 #include <stdarg.h> 105 #include <time.h> 106 107 #include "make.h" 108 #include "dir.h" 109 #include "job.h" 110 #include "pathnames.h" 111 #include "trace.h" 112 113 /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 114 MAKE_RCSID("$NetBSD: main.c,v 1.533 2021/02/05 19:19:17 sjg Exp $"); 115 #if defined(MAKE_NATIVE) && !defined(lint) 116 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 117 "The Regents of the University of California. " 118 "All rights reserved."); 119 #endif 120 121 #ifndef __arraycount 122 # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 123 #endif 124 125 CmdOpts opts; 126 time_t now; /* Time at start of make */ 127 GNode *defaultNode; /* .DEFAULT node */ 128 Boolean allPrecious; /* .PRECIOUS given on line by itself */ 129 Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 130 131 static int maxJobTokens; /* -j argument */ 132 Boolean enterFlagObj; /* -w and objdir != srcdir */ 133 134 static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 135 Boolean doing_depend; /* Set while reading .depend */ 136 static Boolean jobsRunning; /* TRUE if the jobs might be running */ 137 static const char *tracefile; 138 static int ReadMakefile(const char *); 139 static void purge_relative_cached_realpaths(void); 140 141 static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 142 static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 143 char curdir[MAXPATHLEN + 1]; /* Startup directory */ 144 const char *progname; 145 char *makeDependfile; 146 pid_t myPid; 147 int makelevel; 148 149 Boolean forceJobs = FALSE; 150 static int main_errors = 0; 151 static HashTable cached_realpaths; 152 153 /* 154 * For compatibility with the POSIX version of MAKEFLAGS that includes 155 * all the options without '-', convert 'flags' to '-f -l -a -g -s'. 156 */ 157 static char * 158 explode(const char *flags) 159 { 160 size_t len; 161 char *nf, *st; 162 const char *f; 163 164 if (flags == NULL) 165 return NULL; 166 167 for (f = flags; *f != '\0'; f++) 168 if (!ch_isalpha(*f)) 169 break; 170 171 if (*f != '\0') 172 return bmake_strdup(flags); 173 174 len = strlen(flags); 175 st = nf = bmake_malloc(len * 3 + 1); 176 while (*flags != '\0') { 177 *nf++ = '-'; 178 *nf++ = *flags++; 179 *nf++ = ' '; 180 } 181 *nf = '\0'; 182 return st; 183 } 184 185 /* 186 * usage -- 187 * exit with usage message 188 */ 189 MAKE_ATTR_DEAD static void 190 usage(void) 191 { 192 size_t prognameLen = strcspn(progname, "["); 193 194 (void)fprintf(stderr, 195 "usage: %.*s [-BeikNnqrSstWwX]\n" 196 " [-C directory] [-D variable] [-d flags] [-f makefile]\n" 197 " [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 198 " [-V variable] [-v variable] [variable=value] [target ...]\n", 199 (int)prognameLen, progname); 200 exit(2); 201 } 202 203 static void 204 MainParseArgDebugFile(const char *arg) 205 { 206 const char *mode; 207 size_t len; 208 char *fname; 209 210 if (opts.debug_file != stdout && opts.debug_file != stderr) 211 fclose(opts.debug_file); 212 213 if (*arg == '+') { 214 arg++; 215 mode = "a"; 216 } else 217 mode = "w"; 218 219 if (strcmp(arg, "stdout") == 0) { 220 opts.debug_file = stdout; 221 return; 222 } 223 if (strcmp(arg, "stderr") == 0) { 224 opts.debug_file = stderr; 225 return; 226 } 227 228 len = strlen(arg); 229 fname = bmake_malloc(len + 20); 230 memcpy(fname, arg, len + 1); 231 232 /* Let the filename be modified by the pid */ 233 if (strcmp(fname + len - 3, ".%d") == 0) 234 snprintf(fname + len - 2, 20, "%d", getpid()); 235 236 opts.debug_file = fopen(fname, mode); 237 if (opts.debug_file == NULL) { 238 fprintf(stderr, "Cannot open debug file %s\n", 239 fname); 240 usage(); 241 } 242 free(fname); 243 } 244 245 static void 246 MainParseArgDebug(const char *argvalue) 247 { 248 const char *modules; 249 DebugFlags debug = opts.debug; 250 251 for (modules = argvalue; *modules != '\0'; modules++) { 252 switch (*modules) { 253 case '0': /* undocumented, only intended for tests */ 254 debug = DEBUG_NONE; 255 break; 256 case 'A': 257 debug = DEBUG_ALL; 258 break; 259 case 'a': 260 debug |= DEBUG_ARCH; 261 break; 262 case 'C': 263 debug |= DEBUG_CWD; 264 break; 265 case 'c': 266 debug |= DEBUG_COND; 267 break; 268 case 'd': 269 debug |= DEBUG_DIR; 270 break; 271 case 'e': 272 debug |= DEBUG_ERROR; 273 break; 274 case 'f': 275 debug |= DEBUG_FOR; 276 break; 277 case 'g': 278 if (modules[1] == '1') { 279 debug |= DEBUG_GRAPH1; 280 modules++; 281 } else if (modules[1] == '2') { 282 debug |= DEBUG_GRAPH2; 283 modules++; 284 } else if (modules[1] == '3') { 285 debug |= DEBUG_GRAPH3; 286 modules++; 287 } 288 break; 289 case 'h': 290 debug |= DEBUG_HASH; 291 break; 292 case 'j': 293 debug |= DEBUG_JOB; 294 break; 295 case 'L': 296 opts.strict = TRUE; 297 break; 298 case 'l': 299 debug |= DEBUG_LOUD; 300 break; 301 case 'M': 302 debug |= DEBUG_META; 303 break; 304 case 'm': 305 debug |= DEBUG_MAKE; 306 break; 307 case 'n': 308 debug |= DEBUG_SCRIPT; 309 break; 310 case 'p': 311 debug |= DEBUG_PARSE; 312 break; 313 case 's': 314 debug |= DEBUG_SUFF; 315 break; 316 case 't': 317 debug |= DEBUG_TARG; 318 break; 319 case 'V': 320 opts.debugVflag = TRUE; 321 break; 322 case 'v': 323 debug |= DEBUG_VAR; 324 break; 325 case 'x': 326 debug |= DEBUG_SHELL; 327 break; 328 case 'F': 329 MainParseArgDebugFile(modules + 1); 330 goto debug_setbuf; 331 default: 332 (void)fprintf(stderr, 333 "%s: illegal argument to d option -- %c\n", 334 progname, *modules); 335 usage(); 336 } 337 } 338 339 debug_setbuf: 340 opts.debug = debug; 341 342 /* 343 * Make the debug_file unbuffered, and make 344 * stdout line buffered (unless debugfile == stdout). 345 */ 346 setvbuf(opts.debug_file, NULL, _IONBF, 0); 347 if (opts.debug_file != stdout) { 348 setvbuf(stdout, NULL, _IOLBF, 0); 349 } 350 } 351 352 /* Is path relative, or does it contain any relative component "." or ".."? */ 353 static Boolean 354 IsRelativePath(const char *path) 355 { 356 const char *cp; 357 358 if (path[0] != '/') 359 return TRUE; 360 cp = path; 361 while ((cp = strstr(cp, "/.")) != NULL) { 362 cp += 2; 363 if (*cp == '.') 364 cp++; 365 if (cp[0] == '/' || cp[0] == '\0') 366 return TRUE; 367 } 368 return FALSE; 369 } 370 371 static void 372 MainParseArgChdir(const char *argvalue) 373 { 374 struct stat sa, sb; 375 376 if (chdir(argvalue) == -1) { 377 (void)fprintf(stderr, "%s: chdir %s: %s\n", 378 progname, argvalue, strerror(errno)); 379 exit(2); /* Not 1 so -q can distinguish error */ 380 } 381 if (getcwd(curdir, MAXPATHLEN) == NULL) { 382 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 383 exit(2); 384 } 385 if (!IsRelativePath(argvalue) && 386 stat(argvalue, &sa) != -1 && 387 stat(curdir, &sb) != -1 && 388 sa.st_ino == sb.st_ino && 389 sa.st_dev == sb.st_dev) 390 strncpy(curdir, argvalue, MAXPATHLEN); 391 ignorePWD = TRUE; 392 } 393 394 static void 395 MainParseArgJobsInternal(const char *argvalue) 396 { 397 char end; 398 if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { 399 (void)fprintf(stderr, 400 "%s: internal error -- J option malformed (%s)\n", 401 progname, argvalue); 402 usage(); 403 } 404 if ((fcntl(jp_0, F_GETFD, 0) < 0) || 405 (fcntl(jp_1, F_GETFD, 0) < 0)) { 406 #if 0 407 (void)fprintf(stderr, 408 "%s: ###### warning -- J descriptors were closed!\n", 409 progname); 410 exit(2); 411 #endif 412 jp_0 = -1; 413 jp_1 = -1; 414 opts.compatMake = TRUE; 415 } else { 416 Global_Append(MAKEFLAGS, "-J"); 417 Global_Append(MAKEFLAGS, argvalue); 418 } 419 } 420 421 static void 422 MainParseArgJobs(const char *argvalue) 423 { 424 char *p; 425 426 forceJobs = TRUE; 427 opts.maxJobs = (int)strtol(argvalue, &p, 0); 428 if (*p != '\0' || opts.maxJobs < 1) { 429 (void)fprintf(stderr, 430 "%s: illegal argument to -j -- must be positive integer!\n", 431 progname); 432 exit(2); /* Not 1 so -q can distinguish error */ 433 } 434 Global_Append(MAKEFLAGS, "-j"); 435 Global_Append(MAKEFLAGS, argvalue); 436 Global_Set(".MAKE.JOBS", argvalue); 437 maxJobTokens = opts.maxJobs; 438 } 439 440 static void 441 MainParseArgSysInc(const char *argvalue) 442 { 443 /* look for magic parent directory search string */ 444 if (strncmp(".../", argvalue, 4) == 0) { 445 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 446 if (found_path == NULL) 447 return; 448 (void)SearchPath_Add(sysIncPath, found_path); 449 free(found_path); 450 } else { 451 (void)SearchPath_Add(sysIncPath, argvalue); 452 } 453 Global_Append(MAKEFLAGS, "-m"); 454 Global_Append(MAKEFLAGS, argvalue); 455 } 456 457 static Boolean 458 MainParseArg(char c, const char *argvalue) 459 { 460 switch (c) { 461 case '\0': 462 break; 463 case 'B': 464 opts.compatMake = TRUE; 465 Global_Append(MAKEFLAGS, "-B"); 466 Global_Set(MAKE_MODE, "compat"); 467 break; 468 case 'C': 469 MainParseArgChdir(argvalue); 470 break; 471 case 'D': 472 if (argvalue[0] == '\0') return FALSE; 473 Global_SetExpand(argvalue, "1"); 474 Global_Append(MAKEFLAGS, "-D"); 475 Global_Append(MAKEFLAGS, argvalue); 476 break; 477 case 'I': 478 Parse_AddIncludeDir(argvalue); 479 Global_Append(MAKEFLAGS, "-I"); 480 Global_Append(MAKEFLAGS, argvalue); 481 break; 482 case 'J': 483 MainParseArgJobsInternal(argvalue); 484 break; 485 case 'N': 486 opts.noExecute = TRUE; 487 opts.noRecursiveExecute = TRUE; 488 Global_Append(MAKEFLAGS, "-N"); 489 break; 490 case 'S': 491 opts.keepgoing = FALSE; 492 Global_Append(MAKEFLAGS, "-S"); 493 break; 494 case 'T': 495 tracefile = bmake_strdup(argvalue); 496 Global_Append(MAKEFLAGS, "-T"); 497 Global_Append(MAKEFLAGS, argvalue); 498 break; 499 case 'V': 500 case 'v': 501 opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED; 502 Lst_Append(&opts.variables, bmake_strdup(argvalue)); 503 /* XXX: Why always -V? */ 504 Global_Append(MAKEFLAGS, "-V"); 505 Global_Append(MAKEFLAGS, argvalue); 506 break; 507 case 'W': 508 opts.parseWarnFatal = TRUE; 509 /* XXX: why no Var_Append? */ 510 break; 511 case 'X': 512 opts.varNoExportEnv = TRUE; 513 Global_Append(MAKEFLAGS, "-X"); 514 break; 515 case 'd': 516 /* If '-d-opts' don't pass to children */ 517 if (argvalue[0] == '-') 518 argvalue++; 519 else { 520 Global_Append(MAKEFLAGS, "-d"); 521 Global_Append(MAKEFLAGS, argvalue); 522 } 523 MainParseArgDebug(argvalue); 524 break; 525 case 'e': 526 opts.checkEnvFirst = TRUE; 527 Global_Append(MAKEFLAGS, "-e"); 528 break; 529 case 'f': 530 Lst_Append(&opts.makefiles, bmake_strdup(argvalue)); 531 break; 532 case 'i': 533 opts.ignoreErrors = TRUE; 534 Global_Append(MAKEFLAGS, "-i"); 535 break; 536 case 'j': 537 MainParseArgJobs(argvalue); 538 break; 539 case 'k': 540 opts.keepgoing = TRUE; 541 Global_Append(MAKEFLAGS, "-k"); 542 break; 543 case 'm': 544 MainParseArgSysInc(argvalue); 545 /* XXX: why no Var_Append? */ 546 break; 547 case 'n': 548 opts.noExecute = TRUE; 549 Global_Append(MAKEFLAGS, "-n"); 550 break; 551 case 'q': 552 opts.queryFlag = TRUE; 553 /* Kind of nonsensical, wot? */ 554 Global_Append(MAKEFLAGS, "-q"); 555 break; 556 case 'r': 557 opts.noBuiltins = TRUE; 558 Global_Append(MAKEFLAGS, "-r"); 559 break; 560 case 's': 561 opts.beSilent = TRUE; 562 Global_Append(MAKEFLAGS, "-s"); 563 break; 564 case 't': 565 opts.touchFlag = TRUE; 566 Global_Append(MAKEFLAGS, "-t"); 567 break; 568 case 'w': 569 opts.enterFlag = TRUE; 570 Global_Append(MAKEFLAGS, "-w"); 571 break; 572 default: 573 case '?': 574 usage(); 575 } 576 return TRUE; 577 } 578 579 /* 580 * Parse the given arguments. Called from main() and from 581 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 582 * 583 * The arguments must be treated as read-only and will be freed after the 584 * call. 585 * 586 * XXX: Deal with command line overriding .MAKEFLAGS in makefile 587 */ 588 static void 589 MainParseArgs(int argc, char **argv) 590 { 591 char c; 592 int arginc; 593 char *argvalue; 594 char *optscan; 595 Boolean inOption, dashDash = FALSE; 596 597 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 598 /* Can't actually use getopt(3) because rescanning is not portable */ 599 600 rearg: 601 inOption = FALSE; 602 optscan = NULL; 603 while (argc > 1) { 604 const char *optspec; 605 if (!inOption) 606 optscan = argv[1]; 607 c = *optscan++; 608 arginc = 0; 609 if (inOption) { 610 if (c == '\0') { 611 argv++; 612 argc--; 613 inOption = FALSE; 614 continue; 615 } 616 } else { 617 if (c != '-' || dashDash) 618 break; 619 inOption = TRUE; 620 c = *optscan++; 621 } 622 /* '-' found at some earlier point */ 623 optspec = strchr(optspecs, c); 624 if (c != '\0' && optspec != NULL && optspec[1] == ':') { 625 /* -<something> found, and <something> should have an arg */ 626 inOption = FALSE; 627 arginc = 1; 628 argvalue = optscan; 629 if (*argvalue == '\0') { 630 if (argc < 3) 631 goto noarg; 632 argvalue = argv[2]; 633 arginc = 2; 634 } 635 } else { 636 argvalue = NULL; 637 } 638 switch (c) { 639 case '\0': 640 arginc = 1; 641 inOption = FALSE; 642 break; 643 case '-': 644 dashDash = TRUE; 645 break; 646 default: 647 if (!MainParseArg(c, argvalue)) 648 goto noarg; 649 } 650 argv += arginc; 651 argc -= arginc; 652 } 653 654 /* 655 * See if the rest of the arguments are variable assignments and 656 * perform them if so. Else take them to be targets and stuff them 657 * on the end of the "create" list. 658 */ 659 for (; argc > 1; argv++, argc--) { 660 VarAssign var; 661 if (Parse_IsVar(argv[1], &var)) { 662 Parse_DoVar(&var, SCOPE_CMDLINE); 663 } else { 664 if (argv[1][0] == '\0') 665 Punt("illegal (null) argument."); 666 if (argv[1][0] == '-' && !dashDash) 667 goto rearg; 668 Lst_Append(&opts.create, bmake_strdup(argv[1])); 669 } 670 } 671 672 return; 673 noarg: 674 (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 675 progname, c); 676 usage(); 677 } 678 679 /* 680 * Break a line of arguments into words and parse them. 681 * 682 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 683 * by main() when reading the MAKEFLAGS environment variable. 684 */ 685 void 686 Main_ParseArgLine(const char *line) 687 { 688 Words words; 689 char *buf; 690 691 if (line == NULL) 692 return; 693 /* XXX: don't use line as an iterator variable */ 694 for (; *line == ' '; line++) 695 continue; 696 if (line[0] == '\0') 697 return; 698 699 #ifndef POSIX 700 { 701 /* 702 * $MAKE may simply be naming the make(1) binary 703 */ 704 char *cp; 705 706 if (!(cp = strrchr(line, '/'))) 707 cp = line; 708 if ((cp = strstr(cp, "make")) && 709 strcmp(cp, "make") == 0) 710 return; 711 } 712 #endif 713 { 714 FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE"); 715 buf = str_concat3(argv0.str, " ", line); 716 FStr_Done(&argv0); 717 } 718 719 words = Str_Words(buf, TRUE); 720 if (words.words == NULL) { 721 Error("Unterminated quoted string [%s]", buf); 722 free(buf); 723 return; 724 } 725 free(buf); 726 MainParseArgs((int)words.len, words.words); 727 728 Words_Free(words); 729 } 730 731 Boolean 732 Main_SetObjdir(Boolean writable, const char *fmt, ...) 733 { 734 struct stat sb; 735 char *path; 736 char buf[MAXPATHLEN + 1]; 737 char buf2[MAXPATHLEN + 1]; 738 Boolean rc = FALSE; 739 va_list ap; 740 741 va_start(ap, fmt); 742 vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 743 va_end(ap); 744 745 if (path[0] != '/') { 746 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 747 path = buf2; 748 } 749 750 /* look for the directory and try to chdir there */ 751 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 752 if ((writable && access(path, W_OK) != 0) || 753 (chdir(path) != 0)) { 754 (void)fprintf(stderr, "%s warning: %s: %s.\n", 755 progname, path, strerror(errno)); 756 } else { 757 snprintf(objdir, sizeof objdir, "%s", path); 758 Global_Set(".OBJDIR", objdir); 759 setenv("PWD", objdir, 1); 760 Dir_InitDot(); 761 purge_relative_cached_realpaths(); 762 rc = TRUE; 763 if (opts.enterFlag && strcmp(objdir, curdir) != 0) 764 enterFlagObj = TRUE; 765 } 766 } 767 768 return rc; 769 } 770 771 static Boolean 772 SetVarObjdir(Boolean writable, const char *var, const char *suffix) 773 { 774 FStr path = Var_Value(SCOPE_CMDLINE, var); 775 FStr xpath; 776 777 if (path.str == NULL || path.str[0] == '\0') { 778 FStr_Done(&path); 779 return FALSE; 780 } 781 782 /* expand variable substitutions */ 783 xpath = FStr_InitRefer(path.str); 784 if (strchr(path.str, '$') != 0) { 785 char *expanded; 786 (void)Var_Subst(path.str, SCOPE_GLOBAL, VARE_WANTRES, &expanded); 787 /* TODO: handle errors */ 788 xpath = FStr_InitOwn(expanded); 789 } 790 791 (void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix); 792 793 FStr_Done(&xpath); 794 FStr_Done(&path); 795 return TRUE; 796 } 797 798 /* 799 * Splits str into words, adding them to the list. 800 * The string must be kept alive as long as the list. 801 */ 802 int 803 str2Lst_Append(StringList *lp, char *str) 804 { 805 char *cp; 806 int n; 807 808 const char *sep = " \t"; 809 810 for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) { 811 Lst_Append(lp, cp); 812 n++; 813 } 814 return n; 815 } 816 817 #ifdef SIGINFO 818 /*ARGSUSED*/ 819 static void 820 siginfo(int signo MAKE_ATTR_UNUSED) 821 { 822 char dir[MAXPATHLEN]; 823 char str[2 * MAXPATHLEN]; 824 int len; 825 if (getcwd(dir, sizeof dir) == NULL) 826 return; 827 len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir); 828 if (len > 0) 829 (void)write(STDERR_FILENO, str, (size_t)len); 830 } 831 #endif 832 833 /* Allow makefiles some control over the mode we run in. */ 834 static void 835 MakeMode(void) 836 { 837 char *mode; 838 839 (void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode); 840 /* TODO: handle errors */ 841 842 if (mode[0] != '\0') { 843 if (strstr(mode, "compat") != NULL) { 844 opts.compatMake = TRUE; 845 forceJobs = FALSE; 846 } 847 #if USE_META 848 if (strstr(mode, "meta") != NULL) 849 meta_mode_init(mode); 850 #endif 851 } 852 853 free(mode); 854 } 855 856 static void 857 PrintVar(const char *varname, Boolean expandVars) 858 { 859 if (strchr(varname, '$') != NULL) { 860 char *evalue; 861 (void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue); 862 /* TODO: handle errors */ 863 printf("%s\n", evalue); 864 bmake_free(evalue); 865 866 } else if (expandVars) { 867 char *expr = str_concat3("${", varname, "}"); 868 char *evalue; 869 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue); 870 /* TODO: handle errors */ 871 free(expr); 872 printf("%s\n", evalue); 873 bmake_free(evalue); 874 875 } else { 876 FStr value = Var_Value(SCOPE_GLOBAL, varname); 877 printf("%s\n", value.str != NULL ? value.str : ""); 878 FStr_Done(&value); 879 } 880 } 881 882 /* 883 * Return a Boolean based on a variable. 884 * 885 * If the knob is not set, return the fallback. 886 * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 887 * is FALSE, otherwise TRUE. 888 */ 889 Boolean 890 GetBooleanVar(const char *varname, Boolean fallback) 891 { 892 char *expr = str_concat3("${", varname, ":U}"); 893 char *value; 894 Boolean res; 895 896 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value); 897 /* TODO: handle errors */ 898 res = ParseBoolean(value, fallback); 899 free(value); 900 free(expr); 901 return res; 902 } 903 904 static void 905 doPrintVars(void) 906 { 907 StringListNode *ln; 908 Boolean expandVars; 909 910 if (opts.printVars == PVM_EXPANDED) 911 expandVars = TRUE; 912 else if (opts.debugVflag) 913 expandVars = FALSE; 914 else 915 expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE); 916 917 for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 918 const char *varname = ln->datum; 919 PrintVar(varname, expandVars); 920 } 921 } 922 923 static Boolean 924 runTargets(void) 925 { 926 GNodeList targs = LST_INIT; /* target nodes to create */ 927 Boolean outOfDate; /* FALSE if all targets up to date */ 928 929 /* 930 * Have now read the entire graph and need to make a list of 931 * targets to create. If none was given on the command line, 932 * we consult the parsing module to find the main target(s) 933 * to create. 934 */ 935 if (Lst_IsEmpty(&opts.create)) 936 Parse_MainName(&targs); 937 else 938 Targ_FindList(&targs, &opts.create); 939 940 if (!opts.compatMake) { 941 /* 942 * Initialize job module before traversing the graph 943 * now that any .BEGIN and .END targets have been read. 944 * This is done only if the -q flag wasn't given 945 * (to prevent the .BEGIN from being executed should 946 * it exist). 947 */ 948 if (!opts.queryFlag) { 949 Job_Init(); 950 jobsRunning = TRUE; 951 } 952 953 /* Traverse the graph, checking on all the targets */ 954 outOfDate = Make_Run(&targs); 955 } else { 956 /* 957 * Compat_Init will take care of creating all the 958 * targets as well as initializing the module. 959 */ 960 Compat_Run(&targs); 961 outOfDate = FALSE; 962 } 963 Lst_Done(&targs); /* Don't free the targets themselves. */ 964 return outOfDate; 965 } 966 967 /* 968 * Set up the .TARGETS variable to contain the list of targets to be 969 * created. If none specified, make the variable empty -- the parser 970 * will fill the thing in with the default or .MAIN target. 971 */ 972 static void 973 InitVarTargets(void) 974 { 975 StringListNode *ln; 976 977 if (Lst_IsEmpty(&opts.create)) { 978 Global_Set(".TARGETS", ""); 979 return; 980 } 981 982 for (ln = opts.create.first; ln != NULL; ln = ln->next) { 983 const char *name = ln->datum; 984 Global_Append(".TARGETS", name); 985 } 986 } 987 988 static void 989 InitRandom(void) 990 { 991 struct timeval tv; 992 993 gettimeofday(&tv, NULL); 994 srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 995 } 996 997 static const char * 998 InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED) 999 { 1000 #ifdef FORCE_MACHINE 1001 return FORCE_MACHINE; 1002 #else 1003 const char *machine = getenv("MACHINE"); 1004 1005 if (machine != NULL) 1006 return machine; 1007 1008 #if defined(MAKE_NATIVE) 1009 return utsname->machine; 1010 #elif defined(MAKE_MACHINE) 1011 return MAKE_MACHINE; 1012 #else 1013 return "unknown"; 1014 #endif 1015 #endif 1016 } 1017 1018 static const char * 1019 InitVarMachineArch(void) 1020 { 1021 #ifdef FORCE_MACHINE_ARCH 1022 return FORCE_MACHINE_ARCH; 1023 #else 1024 const char *env = getenv("MACHINE_ARCH"); 1025 if (env != NULL) 1026 return env; 1027 1028 #if defined(MAKE_NATIVE) && defined(CTL_HW) 1029 { 1030 struct utsname utsname; 1031 static char machine_arch_buf[sizeof utsname.machine]; 1032 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1033 size_t len = sizeof machine_arch_buf; 1034 1035 if (sysctl(mib, (unsigned int)__arraycount(mib), 1036 machine_arch_buf, &len, NULL, 0) < 0) { 1037 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 1038 progname, strerror(errno)); 1039 exit(2); 1040 } 1041 1042 return machine_arch_buf; 1043 } 1044 #elif defined(MACHINE_ARCH) 1045 return MACHINE_ARCH; 1046 #elif defined(MAKE_MACHINE_ARCH) 1047 return MAKE_MACHINE_ARCH; 1048 #else 1049 return "unknown"; 1050 #endif 1051 #endif 1052 } 1053 1054 #ifndef NO_PWD_OVERRIDE 1055 /* 1056 * All this code is so that we know where we are when we start up 1057 * on a different machine with pmake. 1058 * 1059 * XXX: Make no longer has "local" and "remote" mode. Is this code still 1060 * necessary? 1061 * 1062 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1063 * since the value of curdir can vary depending on how we got 1064 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1065 * or via subdir.mk in which case its likely a shell which does 1066 * not provide it. 1067 * 1068 * So, to stop it breaking this case only, we ignore PWD if 1069 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1070 */ 1071 static void 1072 HandlePWD(const struct stat *curdir_st) 1073 { 1074 char *pwd; 1075 FStr prefix, makeobjdir; 1076 struct stat pwd_st; 1077 1078 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1079 return; 1080 1081 prefix = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"); 1082 if (prefix.str != NULL) { 1083 FStr_Done(&prefix); 1084 return; 1085 } 1086 1087 makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR"); 1088 if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1089 goto ignore_pwd; 1090 1091 if (stat(pwd, &pwd_st) == 0 && 1092 curdir_st->st_ino == pwd_st.st_ino && 1093 curdir_st->st_dev == pwd_st.st_dev) 1094 (void)strncpy(curdir, pwd, MAXPATHLEN); 1095 1096 ignore_pwd: 1097 FStr_Done(&makeobjdir); 1098 } 1099 #endif 1100 1101 /* 1102 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1103 * MAKEOBJDIR is set in the environment, try only that value 1104 * and fall back to .CURDIR if it does not exist. 1105 * 1106 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1107 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1108 * of these paths exist, just use .CURDIR. 1109 */ 1110 static void 1111 InitObjdir(const char *machine, const char *machine_arch) 1112 { 1113 Boolean writable; 1114 1115 Dir_InitCur(curdir); 1116 writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE); 1117 (void)Main_SetObjdir(FALSE, "%s", curdir); 1118 1119 if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1120 !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1121 !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1122 !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1123 !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1124 (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1125 } 1126 1127 /* get rid of resource limit on file descriptors */ 1128 static void 1129 UnlimitFiles(void) 1130 { 1131 #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1132 struct rlimit rl; 1133 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1134 rl.rlim_cur != rl.rlim_max) { 1135 rl.rlim_cur = rl.rlim_max; 1136 (void)setrlimit(RLIMIT_NOFILE, &rl); 1137 } 1138 #endif 1139 } 1140 1141 static void 1142 CmdOpts_Init(void) 1143 { 1144 opts.compatMake = FALSE; 1145 opts.debug = DEBUG_NONE; 1146 /* opts.debug_file has already been initialized earlier */ 1147 opts.strict = FALSE; 1148 opts.debugVflag = FALSE; 1149 opts.checkEnvFirst = FALSE; 1150 Lst_Init(&opts.makefiles); 1151 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1152 opts.maxJobs = 1; 1153 opts.keepgoing = FALSE; /* Stop on error */ 1154 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1155 opts.noExecute = FALSE; /* Execute all commands */ 1156 opts.queryFlag = FALSE; 1157 opts.noBuiltins = FALSE; /* Read the built-in rules */ 1158 opts.beSilent = FALSE; /* Print commands as executed */ 1159 opts.touchFlag = FALSE; 1160 opts.printVars = PVM_NONE; 1161 Lst_Init(&opts.variables); 1162 opts.parseWarnFatal = FALSE; 1163 opts.enterFlag = FALSE; 1164 opts.varNoExportEnv = FALSE; 1165 Lst_Init(&opts.create); 1166 } 1167 1168 /* 1169 * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1170 * found by execvp(3) and the shells, even after a chdir. 1171 * 1172 * If it's a relative path and contains a '/', resolve it to an absolute path. 1173 * Otherwise keep it as is, assuming it will be found in the PATH. 1174 */ 1175 static void 1176 InitVarMake(const char *argv0) 1177 { 1178 const char *make = argv0; 1179 1180 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1181 char pathbuf[MAXPATHLEN]; 1182 const char *abspath = cached_realpath(argv0, pathbuf); 1183 struct stat st; 1184 if (abspath != NULL && abspath[0] == '/' && 1185 stat(make, &st) == 0) 1186 make = abspath; 1187 } 1188 1189 Global_Set("MAKE", make); 1190 Global_Set(".MAKE", make); 1191 } 1192 1193 /* 1194 * Add the directories from the colon-separated syspath to defSysIncPath. 1195 * After returning, the contents of syspath is unspecified. 1196 */ 1197 static void 1198 InitDefSysIncPath(char *syspath) 1199 { 1200 static char defsyspath[] = _PATH_DEFSYSPATH; 1201 char *start, *cp; 1202 1203 /* 1204 * If no user-supplied system path was given (through the -m option) 1205 * add the directories from the DEFSYSPATH (more than one may be given 1206 * as dir1:...:dirn) to the system include path. 1207 */ 1208 if (syspath == NULL || syspath[0] == '\0') 1209 syspath = defsyspath; 1210 else 1211 syspath = bmake_strdup(syspath); 1212 1213 for (start = syspath; *start != '\0'; start = cp) { 1214 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1215 continue; 1216 if (*cp == ':') 1217 *cp++ = '\0'; 1218 1219 /* look for magic parent directory search string */ 1220 if (strncmp(start, ".../", 4) == 0) { 1221 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1222 if (dir != NULL) { 1223 (void)SearchPath_Add(defSysIncPath, dir); 1224 free(dir); 1225 } 1226 } else { 1227 (void)SearchPath_Add(defSysIncPath, start); 1228 } 1229 } 1230 1231 if (syspath != defsyspath) 1232 free(syspath); 1233 } 1234 1235 static void 1236 ReadBuiltinRules(void) 1237 { 1238 StringListNode *ln; 1239 StringList sysMkFiles = LST_INIT; 1240 1241 SearchPath_Expand( 1242 Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath, 1243 _PATH_DEFSYSMK, 1244 &sysMkFiles); 1245 if (Lst_IsEmpty(&sysMkFiles)) 1246 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1247 1248 for (ln = sysMkFiles.first; ln != NULL; ln = ln->next) 1249 if (ReadMakefile(ln->datum) == 0) 1250 break; 1251 1252 if (ln == NULL) 1253 Fatal("%s: cannot open %s.", 1254 progname, (const char *)sysMkFiles.first->datum); 1255 1256 /* Free the list nodes but not the actual filenames since these may 1257 * still be used in GNodes. */ 1258 Lst_Done(&sysMkFiles); 1259 } 1260 1261 static void 1262 InitMaxJobs(void) 1263 { 1264 char *value; 1265 int n; 1266 1267 if (forceJobs || opts.compatMake || 1268 !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) 1269 return; 1270 1271 (void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value); 1272 /* TODO: handle errors */ 1273 n = (int)strtol(value, NULL, 0); 1274 if (n < 1) { 1275 (void)fprintf(stderr, 1276 "%s: illegal value for .MAKE.JOBS " 1277 "-- must be positive integer!\n", 1278 progname); 1279 exit(2); /* Not 1 so -q can distinguish error */ 1280 } 1281 1282 if (n != opts.maxJobs) { 1283 Global_Append(MAKEFLAGS, "-j"); 1284 Global_Append(MAKEFLAGS, value); 1285 } 1286 1287 opts.maxJobs = n; 1288 maxJobTokens = opts.maxJobs; 1289 forceJobs = TRUE; 1290 free(value); 1291 } 1292 1293 /* 1294 * For compatibility, look at the directories in the VPATH variable 1295 * and add them to the search path, if the variable is defined. The 1296 * variable's value is in the same format as the PATH environment 1297 * variable, i.e. <directory>:<directory>:<directory>... 1298 */ 1299 static void 1300 InitVpath(void) 1301 { 1302 char *vpath, savec, *path; 1303 if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) 1304 return; 1305 1306 (void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath); 1307 /* TODO: handle errors */ 1308 path = vpath; 1309 do { 1310 char *cp; 1311 /* skip to end of directory */ 1312 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1313 continue; 1314 /* Save terminator character so know when to stop */ 1315 savec = *cp; 1316 *cp = '\0'; 1317 /* Add directory to search path */ 1318 (void)SearchPath_Add(&dirSearchPath, path); 1319 *cp = savec; 1320 path = cp + 1; 1321 } while (savec == ':'); 1322 free(vpath); 1323 } 1324 1325 static void 1326 ReadAllMakefiles(StringList *makefiles) 1327 { 1328 StringListNode *ln; 1329 1330 for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1331 const char *fname = ln->datum; 1332 if (ReadMakefile(fname) != 0) 1333 Fatal("%s: cannot open %s.", progname, fname); 1334 } 1335 } 1336 1337 static void 1338 ReadFirstDefaultMakefile(void) 1339 { 1340 StringListNode *ln; 1341 char *prefs; 1342 1343 (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", 1344 SCOPE_CMDLINE, VARE_WANTRES, &prefs); 1345 /* TODO: handle errors */ 1346 1347 /* XXX: This should use a local list instead of opts.makefiles 1348 * since these makefiles do not come from the command line. They 1349 * also have different semantics in that only the first file that 1350 * is found is processed. See ReadAllMakefiles. */ 1351 (void)str2Lst_Append(&opts.makefiles, prefs); 1352 1353 for (ln = opts.makefiles.first; ln != NULL; ln = ln->next) 1354 if (ReadMakefile(ln->datum) == 0) 1355 break; 1356 1357 free(prefs); 1358 } 1359 1360 /* 1361 * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1362 * Initialize a few modules. 1363 * Parse the arguments from MAKEFLAGS and the command line. 1364 */ 1365 static void 1366 main_Init(int argc, char **argv) 1367 { 1368 struct stat sa; 1369 const char *machine; 1370 const char *machine_arch; 1371 char *syspath = getenv("MAKESYSPATH"); 1372 struct utsname utsname; 1373 1374 /* default to writing debug to stderr */ 1375 opts.debug_file = stderr; 1376 1377 HashTable_Init(&cached_realpaths); 1378 1379 #ifdef SIGINFO 1380 (void)bmake_signal(SIGINFO, siginfo); 1381 #endif 1382 1383 InitRandom(); 1384 1385 progname = str_basename(argv[0]); 1386 1387 UnlimitFiles(); 1388 1389 if (uname(&utsname) == -1) { 1390 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1391 strerror(errno)); 1392 exit(2); 1393 } 1394 1395 /* 1396 * Get the name of this type of MACHINE from utsname 1397 * so we can share an executable for similar machines. 1398 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1399 * 1400 * Note that both MACHINE and MACHINE_ARCH are decided at 1401 * run-time. 1402 */ 1403 machine = InitVarMachine(&utsname); 1404 machine_arch = InitVarMachineArch(); 1405 1406 myPid = getpid(); /* remember this for vFork() */ 1407 1408 /* 1409 * Just in case MAKEOBJDIR wants us to do something tricky. 1410 */ 1411 Targ_Init(); 1412 Var_Init(); 1413 Global_Set(".MAKE.OS", utsname.sysname); 1414 Global_Set("MACHINE", machine); 1415 Global_Set("MACHINE_ARCH", machine_arch); 1416 #ifdef MAKE_VERSION 1417 Global_Set("MAKE_VERSION", MAKE_VERSION); 1418 #endif 1419 Global_Set(".newline", "\n"); /* handy for :@ loops */ 1420 /* 1421 * This is the traditional preference for makefiles. 1422 */ 1423 #ifndef MAKEFILE_PREFERENCE_LIST 1424 # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1425 #endif 1426 Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST); 1427 Global_Set(MAKE_DEPENDFILE, ".depend"); 1428 1429 CmdOpts_Init(); 1430 allPrecious = FALSE; /* Remove targets when interrupted */ 1431 deleteOnError = FALSE; /* Historical default behavior */ 1432 jobsRunning = FALSE; 1433 1434 maxJobTokens = opts.maxJobs; 1435 ignorePWD = FALSE; 1436 1437 /* 1438 * Initialize the parsing, directory and variable modules to prepare 1439 * for the reading of inclusion paths and variable settings on the 1440 * command line 1441 */ 1442 1443 /* 1444 * Initialize various variables. 1445 * MAKE also gets this name, for compatibility 1446 * .MAKEFLAGS gets set to the empty string just in case. 1447 * MFLAGS also gets initialized empty, for compatibility. 1448 */ 1449 Parse_Init(); 1450 InitVarMake(argv[0]); 1451 Global_Set(MAKEFLAGS, ""); 1452 Global_Set(MAKEOVERRIDES, ""); 1453 Global_Set("MFLAGS", ""); 1454 Global_Set(".ALLTARGETS", ""); 1455 /* some makefiles need to know this */ 1456 Var_Set(SCOPE_CMDLINE, MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV); 1457 1458 /* Set some other useful variables. */ 1459 { 1460 char tmp[64], *ep = getenv(MAKE_LEVEL_ENV); 1461 1462 makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 1463 if (makelevel < 0) 1464 makelevel = 0; 1465 snprintf(tmp, sizeof tmp, "%d", makelevel); 1466 Global_Set(MAKE_LEVEL, tmp); 1467 snprintf(tmp, sizeof tmp, "%u", myPid); 1468 Global_Set(".MAKE.PID", tmp); 1469 snprintf(tmp, sizeof tmp, "%u", getppid()); 1470 Global_Set(".MAKE.PPID", tmp); 1471 snprintf(tmp, sizeof tmp, "%u", getuid()); 1472 Global_Set(".MAKE.UID", tmp); 1473 snprintf(tmp, sizeof tmp, "%u", getgid()); 1474 Global_Set(".MAKE.GID", tmp); 1475 } 1476 if (makelevel > 0) { 1477 char pn[1024]; 1478 snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 1479 progname = bmake_strdup(pn); 1480 } 1481 1482 #ifdef USE_META 1483 meta_init(); 1484 #endif 1485 Dir_Init(); 1486 1487 /* 1488 * First snag any flags out of the MAKE environment variable. 1489 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1490 * in a different format). 1491 */ 1492 #ifdef POSIX 1493 { 1494 char *p1 = explode(getenv("MAKEFLAGS")); 1495 Main_ParseArgLine(p1); 1496 free(p1); 1497 } 1498 #else 1499 Main_ParseArgLine(getenv("MAKE")); 1500 #endif 1501 1502 /* 1503 * Find where we are (now). 1504 * We take care of PWD for the automounter below... 1505 */ 1506 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1507 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1508 progname, strerror(errno)); 1509 exit(2); 1510 } 1511 1512 MainParseArgs(argc, argv); 1513 1514 if (opts.enterFlag) 1515 printf("%s: Entering directory `%s'\n", progname, curdir); 1516 1517 /* 1518 * Verify that cwd is sane. 1519 */ 1520 if (stat(curdir, &sa) == -1) { 1521 (void)fprintf(stderr, "%s: %s: %s.\n", 1522 progname, curdir, strerror(errno)); 1523 exit(2); 1524 } 1525 1526 #ifndef NO_PWD_OVERRIDE 1527 HandlePWD(&sa); 1528 #endif 1529 Global_Set(".CURDIR", curdir); 1530 1531 InitObjdir(machine, machine_arch); 1532 1533 /* 1534 * Initialize archive, target and suffix modules in preparation for 1535 * parsing the makefile(s) 1536 */ 1537 Arch_Init(); 1538 Suff_Init(); 1539 Trace_Init(tracefile); 1540 1541 defaultNode = NULL; 1542 (void)time(&now); 1543 1544 Trace_Log(MAKESTART, NULL); 1545 1546 InitVarTargets(); 1547 1548 InitDefSysIncPath(syspath); 1549 } 1550 1551 /* 1552 * Read the system makefile followed by either makefile, Makefile or the 1553 * files given by the -f option. Exit on parse errors. 1554 */ 1555 static void 1556 main_ReadFiles(void) 1557 { 1558 1559 if (!opts.noBuiltins) 1560 ReadBuiltinRules(); 1561 1562 if (!Lst_IsEmpty(&opts.makefiles)) 1563 ReadAllMakefiles(&opts.makefiles); 1564 else 1565 ReadFirstDefaultMakefile(); 1566 } 1567 1568 /* Compute the dependency graph. */ 1569 static void 1570 main_PrepareMaking(void) 1571 { 1572 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1573 if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 1574 (void)Var_Subst("${.MAKE.DEPENDFILE}", 1575 SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile); 1576 if (makeDependfile[0] != '\0') { 1577 /* TODO: handle errors */ 1578 doing_depend = TRUE; 1579 (void)ReadMakefile(makeDependfile); 1580 doing_depend = FALSE; 1581 } 1582 } 1583 1584 if (enterFlagObj) 1585 printf("%s: Entering directory `%s'\n", progname, objdir); 1586 1587 MakeMode(); 1588 1589 { 1590 FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS); 1591 Global_Append("MFLAGS", makeflags.str); 1592 FStr_Done(&makeflags); 1593 } 1594 1595 InitMaxJobs(); 1596 1597 /* 1598 * Be compatible if the user did not specify -j and did not explicitly 1599 * turn compatibility on. 1600 */ 1601 if (!opts.compatMake && !forceJobs) 1602 opts.compatMake = TRUE; 1603 1604 if (!opts.compatMake) 1605 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1606 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1607 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1608 1609 if (opts.printVars == PVM_NONE) 1610 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1611 1612 InitVpath(); 1613 1614 /* 1615 * Now that all search paths have been read for suffixes et al, it's 1616 * time to add the default search path to their lists... 1617 */ 1618 Suff_DoPaths(); 1619 1620 /* 1621 * Propagate attributes through :: dependency lists. 1622 */ 1623 Targ_Propagate(); 1624 1625 /* print the initial graph, if the user requested it */ 1626 if (DEBUG(GRAPH1)) 1627 Targ_PrintGraph(1); 1628 } 1629 1630 /* 1631 * Make the targets. 1632 * If the -v or -V options are given, print variables instead. 1633 * Return whether any of the targets is out-of-date. 1634 */ 1635 static Boolean 1636 main_Run(void) 1637 { 1638 if (opts.printVars != PVM_NONE) { 1639 /* print the values of any variables requested by the user */ 1640 doPrintVars(); 1641 return FALSE; 1642 } else { 1643 return runTargets(); 1644 } 1645 } 1646 1647 /* Clean up after making the targets. */ 1648 static void 1649 main_CleanUp(void) 1650 { 1651 #ifdef CLEANUP 1652 Lst_DoneCall(&opts.variables, free); 1653 /* 1654 * Don't free the actual strings from opts.makefiles, they may be 1655 * used in GNodes. 1656 */ 1657 Lst_Done(&opts.makefiles); 1658 Lst_DoneCall(&opts.create, free); 1659 #endif 1660 1661 /* print the graph now it's been processed if the user requested it */ 1662 if (DEBUG(GRAPH2)) 1663 Targ_PrintGraph(2); 1664 1665 Trace_Log(MAKEEND, NULL); 1666 1667 if (enterFlagObj) 1668 printf("%s: Leaving directory `%s'\n", progname, objdir); 1669 if (opts.enterFlag) 1670 printf("%s: Leaving directory `%s'\n", progname, curdir); 1671 1672 #ifdef USE_META 1673 meta_finish(); 1674 #endif 1675 Suff_End(); 1676 Targ_End(); 1677 Arch_End(); 1678 Var_End(); 1679 Parse_End(); 1680 Dir_End(); 1681 Job_End(); 1682 Trace_End(); 1683 } 1684 1685 /* Determine the exit code. */ 1686 static int 1687 main_Exit(Boolean outOfDate) 1688 { 1689 if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0)) 1690 return 2; /* Not 1 so -q can distinguish error */ 1691 return outOfDate ? 1 : 0; 1692 } 1693 1694 int 1695 main(int argc, char **argv) 1696 { 1697 Boolean outOfDate; 1698 1699 main_Init(argc, argv); 1700 main_ReadFiles(); 1701 main_PrepareMaking(); 1702 outOfDate = main_Run(); 1703 main_CleanUp(); 1704 return main_Exit(outOfDate); 1705 } 1706 1707 /* 1708 * Open and parse the given makefile, with all its side effects. 1709 * 1710 * Results: 1711 * 0 if ok. -1 if couldn't open file. 1712 */ 1713 static int 1714 ReadMakefile(const char *fname) 1715 { 1716 int fd; 1717 char *name, *path = NULL; 1718 1719 if (strcmp(fname, "-") == 0) { 1720 Parse_File(NULL /*stdin*/, -1); 1721 Var_Set(SCOPE_INTERNAL, "MAKEFILE", ""); 1722 } else { 1723 /* if we've chdir'd, rebuild the path name */ 1724 if (strcmp(curdir, objdir) != 0 && *fname != '/') { 1725 path = str_concat3(curdir, "/", fname); 1726 fd = open(path, O_RDONLY); 1727 if (fd != -1) { 1728 fname = path; 1729 goto found; 1730 } 1731 free(path); 1732 1733 /* If curdir failed, try objdir (ala .depend) */ 1734 path = str_concat3(objdir, "/", fname); 1735 fd = open(path, O_RDONLY); 1736 if (fd != -1) { 1737 fname = path; 1738 goto found; 1739 } 1740 } else { 1741 fd = open(fname, O_RDONLY); 1742 if (fd != -1) 1743 goto found; 1744 } 1745 /* look in -I and system include directories. */ 1746 name = Dir_FindFile(fname, parseIncPath); 1747 if (name == NULL) { 1748 SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs) 1749 ? defSysIncPath : sysIncPath; 1750 name = Dir_FindFile(fname, sysInc); 1751 } 1752 if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 1753 free(name); 1754 free(path); 1755 return -1; 1756 } 1757 fname = name; 1758 /* 1759 * set the MAKEFILE variable desired by System V fans -- the 1760 * placement of the setting here means it gets set to the last 1761 * makefile specified, as it is set by SysV make. 1762 */ 1763 found: 1764 if (!doing_depend) 1765 Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname); 1766 Parse_File(fname, fd); 1767 } 1768 free(path); 1769 return 0; 1770 } 1771 1772 /* 1773 * Cmd_Exec -- 1774 * Execute the command in cmd, and return the output of that command 1775 * in a string. In the output, newlines are replaced with spaces. 1776 * 1777 * Results: 1778 * A string containing the output of the command, or the empty string. 1779 * *errfmt returns a format string describing the command failure, 1780 * if any, using a single %s conversion specification. 1781 * 1782 * Side Effects: 1783 * The string must be freed by the caller. 1784 */ 1785 char * 1786 Cmd_Exec(const char *cmd, const char **errfmt) 1787 { 1788 const char *args[4]; /* Args for invoking the shell */ 1789 int pipefds[2]; 1790 int cpid; /* Child PID */ 1791 int pid; /* PID from wait() */ 1792 int status; /* command exit status */ 1793 Buffer buf; /* buffer to store the result */ 1794 ssize_t bytes_read; 1795 char *res; /* result */ 1796 size_t res_len; 1797 char *cp; 1798 int savederr; /* saved errno */ 1799 1800 *errfmt = NULL; 1801 1802 if (shellName == NULL) 1803 Shell_Init(); 1804 /* 1805 * Set up arguments for shell 1806 */ 1807 args[0] = shellName; 1808 args[1] = "-c"; 1809 args[2] = cmd; 1810 args[3] = NULL; 1811 1812 /* 1813 * Open a pipe for fetching its output 1814 */ 1815 if (pipe(pipefds) == -1) { 1816 *errfmt = "Couldn't create pipe for \"%s\""; 1817 goto bad; 1818 } 1819 1820 Var_ReexportVars(); 1821 1822 /* 1823 * Fork 1824 */ 1825 switch (cpid = vfork()) { 1826 case 0: 1827 (void)close(pipefds[0]); /* Close input side of pipe */ 1828 1829 /* 1830 * Duplicate the output stream to the shell's output, then 1831 * shut the extra thing down. Note we don't fetch the error 1832 * stream...why not? Why? 1833 */ 1834 (void)dup2(pipefds[1], 1); 1835 (void)close(pipefds[1]); 1836 1837 (void)execv(shellPath, UNCONST(args)); 1838 _exit(1); 1839 /*NOTREACHED*/ 1840 1841 case -1: 1842 *errfmt = "Couldn't exec \"%s\""; 1843 goto bad; 1844 1845 default: 1846 (void)close(pipefds[1]); /* No need for the writing half */ 1847 1848 savederr = 0; 1849 Buf_Init(&buf); 1850 1851 do { 1852 char result[BUFSIZ]; 1853 bytes_read = read(pipefds[0], result, sizeof result); 1854 if (bytes_read > 0) 1855 Buf_AddBytes(&buf, result, (size_t)bytes_read); 1856 } while (bytes_read > 0 || 1857 (bytes_read == -1 && errno == EINTR)); 1858 if (bytes_read == -1) 1859 savederr = errno; 1860 1861 (void)close(pipefds[0]); /* Close the input side of the pipe. */ 1862 1863 /* Wait for the process to exit. */ 1864 while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 1865 JobReapChild(pid, status, FALSE); 1866 1867 res_len = buf.len; 1868 res = Buf_DoneData(&buf); 1869 1870 if (savederr != 0) 1871 *errfmt = "Couldn't read shell's output for \"%s\""; 1872 1873 if (WIFSIGNALED(status)) 1874 *errfmt = "\"%s\" exited on a signal"; 1875 else if (WEXITSTATUS(status) != 0) 1876 *errfmt = "\"%s\" returned non-zero status"; 1877 1878 /* Convert newlines to spaces. A final newline is just stripped */ 1879 if (res_len > 0 && res[res_len - 1] == '\n') 1880 res[res_len - 1] = '\0'; 1881 for (cp = res; *cp != '\0'; cp++) 1882 if (*cp == '\n') 1883 *cp = ' '; 1884 break; 1885 } 1886 return res; 1887 bad: 1888 return bmake_strdup(""); 1889 } 1890 1891 /* 1892 * Print a printf-style error message. 1893 * 1894 * In default mode, this error message has no consequences, in particular it 1895 * does not affect the exit status. Only in lint mode (-dL) it does. 1896 */ 1897 void 1898 Error(const char *fmt, ...) 1899 { 1900 va_list ap; 1901 FILE *err_file; 1902 1903 err_file = opts.debug_file; 1904 if (err_file == stdout) 1905 err_file = stderr; 1906 (void)fflush(stdout); 1907 for (;;) { 1908 va_start(ap, fmt); 1909 fprintf(err_file, "%s: ", progname); 1910 (void)vfprintf(err_file, fmt, ap); 1911 va_end(ap); 1912 (void)fprintf(err_file, "\n"); 1913 (void)fflush(err_file); 1914 if (err_file == stderr) 1915 break; 1916 err_file = stderr; 1917 } 1918 main_errors++; 1919 } 1920 1921 /* 1922 * Wait for any running jobs to finish, then produce an error message, 1923 * finally exit immediately. 1924 * 1925 * Exiting immediately differs from Parse_Error, which exits only after the 1926 * current top-level makefile has been parsed completely. 1927 */ 1928 void 1929 Fatal(const char *fmt, ...) 1930 { 1931 va_list ap; 1932 1933 if (jobsRunning) 1934 Job_Wait(); 1935 1936 (void)fflush(stdout); 1937 va_start(ap, fmt); 1938 (void)vfprintf(stderr, fmt, ap); 1939 va_end(ap); 1940 (void)fprintf(stderr, "\n"); 1941 (void)fflush(stderr); 1942 1943 PrintOnError(NULL, NULL); 1944 1945 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1946 Targ_PrintGraph(2); 1947 Trace_Log(MAKEERROR, NULL); 1948 exit(2); /* Not 1 so -q can distinguish error */ 1949 } 1950 1951 /* 1952 * Major exception once jobs are being created. 1953 * Kills all jobs, prints a message and exits. 1954 */ 1955 void 1956 Punt(const char *fmt, ...) 1957 { 1958 va_list ap; 1959 1960 va_start(ap, fmt); 1961 (void)fflush(stdout); 1962 (void)fprintf(stderr, "%s: ", progname); 1963 (void)vfprintf(stderr, fmt, ap); 1964 va_end(ap); 1965 (void)fprintf(stderr, "\n"); 1966 (void)fflush(stderr); 1967 1968 PrintOnError(NULL, NULL); 1969 1970 DieHorribly(); 1971 } 1972 1973 /* Exit without giving a message. */ 1974 void 1975 DieHorribly(void) 1976 { 1977 if (jobsRunning) 1978 Job_AbortAll(); 1979 if (DEBUG(GRAPH2)) 1980 Targ_PrintGraph(2); 1981 Trace_Log(MAKEERROR, NULL); 1982 exit(2); /* Not 1 so -q can distinguish error */ 1983 } 1984 1985 /* 1986 * Called when aborting due to errors in child shell to signal abnormal exit. 1987 * The program exits. 1988 * Errors is the number of errors encountered in Make_Make. 1989 */ 1990 void 1991 Finish(int errs) 1992 { 1993 if (shouldDieQuietly(NULL, -1)) 1994 exit(2); 1995 Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 1996 } 1997 1998 /* 1999 * eunlink -- 2000 * Remove a file carefully, avoiding directories. 2001 */ 2002 int 2003 eunlink(const char *file) 2004 { 2005 struct stat st; 2006 2007 if (lstat(file, &st) == -1) 2008 return -1; 2009 2010 if (S_ISDIR(st.st_mode)) { 2011 errno = EISDIR; 2012 return -1; 2013 } 2014 return unlink(file); 2015 } 2016 2017 static void 2018 write_all(int fd, const void *data, size_t n) 2019 { 2020 const char *mem = data; 2021 2022 while (n > 0) { 2023 ssize_t written = write(fd, mem, n); 2024 if (written == -1 && errno == EAGAIN) 2025 continue; 2026 if (written == -1) 2027 break; 2028 mem += written; 2029 n -= (size_t)written; 2030 } 2031 } 2032 2033 /* 2034 * execDie -- 2035 * Print why exec failed, avoiding stdio. 2036 */ 2037 void MAKE_ATTR_DEAD 2038 execDie(const char *af, const char *av) 2039 { 2040 Buffer buf; 2041 2042 Buf_Init(&buf); 2043 Buf_AddStr(&buf, progname); 2044 Buf_AddStr(&buf, ": "); 2045 Buf_AddStr(&buf, af); 2046 Buf_AddStr(&buf, "("); 2047 Buf_AddStr(&buf, av); 2048 Buf_AddStr(&buf, ") failed ("); 2049 Buf_AddStr(&buf, strerror(errno)); 2050 Buf_AddStr(&buf, ")\n"); 2051 2052 write_all(STDERR_FILENO, buf.data, buf.len); 2053 2054 Buf_Done(&buf); 2055 _exit(1); 2056 } 2057 2058 /* purge any relative paths */ 2059 static void 2060 purge_relative_cached_realpaths(void) 2061 { 2062 HashEntry *he, *nhe; 2063 HashIter hi; 2064 2065 HashIter_Init(&hi, &cached_realpaths); 2066 he = HashIter_Next(&hi); 2067 while (he != NULL) { 2068 nhe = HashIter_Next(&hi); 2069 if (he->key[0] != '/') { 2070 DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 2071 HashTable_DeleteEntry(&cached_realpaths, he); 2072 /* XXX: What about the allocated he->value? Either 2073 * free them or document why they cannot be freed. */ 2074 } 2075 he = nhe; 2076 } 2077 } 2078 2079 char * 2080 cached_realpath(const char *pathname, char *resolved) 2081 { 2082 const char *rp; 2083 2084 if (pathname == NULL || pathname[0] == '\0') 2085 return NULL; 2086 2087 rp = HashTable_FindValue(&cached_realpaths, pathname); 2088 if (rp != NULL) { 2089 /* a hit */ 2090 strncpy(resolved, rp, MAXPATHLEN); 2091 resolved[MAXPATHLEN - 1] = '\0'; 2092 return resolved; 2093 } 2094 2095 rp = realpath(pathname, resolved); 2096 if (rp != NULL) { 2097 HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2098 DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2099 return resolved; 2100 } 2101 2102 /* should we negative-cache? */ 2103 return NULL; 2104 } 2105 2106 /* 2107 * Return true if we should die without noise. 2108 * For example our failing child was a sub-make or failure happened elsewhere. 2109 */ 2110 Boolean 2111 shouldDieQuietly(GNode *gn, int bf) 2112 { 2113 static int quietly = -1; 2114 2115 if (quietly < 0) { 2116 if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE)) 2117 quietly = 0; 2118 else if (bf >= 0) 2119 quietly = bf; 2120 else 2121 quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0; 2122 } 2123 return quietly != 0; 2124 } 2125 2126 static void 2127 SetErrorVars(GNode *gn) 2128 { 2129 StringListNode *ln; 2130 2131 /* 2132 * We can print this even if there is no .ERROR target. 2133 */ 2134 Global_Set(".ERROR_TARGET", gn->name); 2135 Global_Delete(".ERROR_CMD"); 2136 2137 for (ln = gn->commands.first; ln != NULL; ln = ln->next) { 2138 const char *cmd = ln->datum; 2139 2140 if (cmd == NULL) 2141 break; 2142 Global_Append(".ERROR_CMD", cmd); 2143 } 2144 } 2145 2146 /* 2147 * Print some helpful information in case of an error. 2148 * The caller should exit soon after calling this function. 2149 */ 2150 void 2151 PrintOnError(GNode *gn, const char *msg) 2152 { 2153 static GNode *errorNode = NULL; 2154 2155 if (DEBUG(HASH)) { 2156 Targ_Stats(); 2157 Var_Stats(); 2158 } 2159 2160 if (errorNode != NULL) 2161 return; /* we've been here! */ 2162 2163 if (msg != NULL) 2164 printf("%s", msg); 2165 printf("\n%s: stopped in %s\n", progname, curdir); 2166 2167 /* we generally want to keep quiet if a sub-make died */ 2168 if (shouldDieQuietly(gn, -1)) 2169 return; 2170 2171 if (gn != NULL) 2172 SetErrorVars(gn); 2173 2174 { 2175 char *errorVarsValues; 2176 (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 2177 SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues); 2178 /* TODO: handle errors */ 2179 printf("%s", errorVarsValues); 2180 free(errorVarsValues); 2181 } 2182 2183 fflush(stdout); 2184 2185 /* 2186 * Finally, see if there is a .ERROR target, and run it if so. 2187 */ 2188 errorNode = Targ_FindNode(".ERROR"); 2189 if (errorNode != NULL) { 2190 errorNode->type |= OP_SPECIAL; 2191 Compat_Make(errorNode, errorNode); 2192 } 2193 } 2194 2195 void 2196 Main_ExportMAKEFLAGS(Boolean first) 2197 { 2198 static Boolean once = TRUE; 2199 const char *expr; 2200 char *s; 2201 2202 if (once != first) 2203 return; 2204 once = FALSE; 2205 2206 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2207 (void)Var_Subst(expr, SCOPE_CMDLINE, VARE_WANTRES, &s); 2208 /* TODO: handle errors */ 2209 if (s[0] != '\0') { 2210 #ifdef POSIX 2211 setenv("MAKEFLAGS", s, 1); 2212 #else 2213 setenv("MAKE", s, 1); 2214 #endif 2215 } 2216 } 2217 2218 char * 2219 getTmpdir(void) 2220 { 2221 static char *tmpdir = NULL; 2222 struct stat st; 2223 2224 if (tmpdir != NULL) 2225 return tmpdir; 2226 2227 /* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */ 2228 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", 2229 SCOPE_GLOBAL, VARE_WANTRES, &tmpdir); 2230 /* TODO: handle errors */ 2231 2232 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2233 free(tmpdir); 2234 tmpdir = bmake_strdup(_PATH_TMP); 2235 } 2236 return tmpdir; 2237 } 2238 2239 /* 2240 * Create and open a temp file using "pattern". 2241 * If out_fname is provided, set it to a copy of the filename created. 2242 * Otherwise unlink the file once open. 2243 */ 2244 int 2245 mkTempFile(const char *pattern, char *tfile, size_t tfile_sz) 2246 { 2247 static char *tmpdir = NULL; 2248 char tbuf[MAXPATHLEN]; 2249 int fd; 2250 2251 if (pattern == NULL) 2252 pattern = TMPPAT; 2253 if (tmpdir == NULL) 2254 tmpdir = getTmpdir(); 2255 if (tfile == NULL) { 2256 tfile = tbuf; 2257 tfile_sz = sizeof tbuf; 2258 } 2259 if (pattern[0] == '/') { 2260 snprintf(tfile, tfile_sz, "%s", pattern); 2261 } else { 2262 snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern); 2263 } 2264 if ((fd = mkstemp(tfile)) < 0) 2265 Punt("Could not create temporary file %s: %s", tfile, 2266 strerror(errno)); 2267 if (tfile == tbuf) { 2268 unlink(tfile); /* we just want the descriptor */ 2269 } 2270 return fd; 2271 } 2272 2273 /* 2274 * Convert a string representation of a boolean into a boolean value. 2275 * Anything that looks like "No", "False", "Off", "0" etc. is FALSE, 2276 * the empty string is the fallback, everything else is TRUE. 2277 */ 2278 Boolean 2279 ParseBoolean(const char *s, Boolean fallback) 2280 { 2281 char ch = ch_tolower(s[0]); 2282 if (ch == '\0') 2283 return fallback; 2284 if (ch == '0' || ch == 'f' || ch == 'n') 2285 return FALSE; 2286 if (ch == 'o') 2287 return ch_tolower(s[1]) != 'f'; 2288 return TRUE; 2289 } 2290