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