1 /* $NetBSD: main.c,v 1.540 2021/06/18 12:54:17 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.540 2021/06/18 12:54:17 rillig 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 bool allPrecious; /* .PRECIOUS given on line by itself */ 129 bool deleteOnError; /* .DELETE_ON_ERROR: set */ 130 131 static int maxJobTokens; /* -j argument */ 132 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 int 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 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 bool 354 IsRelativePath(const char *path) 355 { 356 const char *p; 357 358 if (path[0] != '/') 359 return true; 360 p = path; 361 while ((p = strstr(p, "/.")) != NULL) { 362 p += 2; 363 if (*p == '.') 364 p++; 365 if (*p == '/' || *p == '\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 bool 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 bool 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_Var(&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 bool 732 Main_SetObjdir(bool writable, const char *fmt, ...) 733 { 734 struct stat sb; 735 char *path; 736 char buf[MAXPATHLEN + 1]; 737 char buf2[MAXPATHLEN + 1]; 738 bool 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 bool 772 SetVarObjdir(bool 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, bool 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 bool 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 bool 890 GetBooleanExpr(const char *expr, bool fallback) 891 { 892 char *value; 893 bool res; 894 895 (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value); 896 /* TODO: handle errors */ 897 res = ParseBoolean(value, fallback); 898 free(value); 899 return res; 900 } 901 902 static void 903 doPrintVars(void) 904 { 905 StringListNode *ln; 906 bool expandVars; 907 908 if (opts.printVars == PVM_EXPANDED) 909 expandVars = true; 910 else if (opts.debugVflag) 911 expandVars = false; 912 else 913 expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}", 914 false); 915 916 for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 917 const char *varname = ln->datum; 918 PrintVar(varname, expandVars); 919 } 920 } 921 922 static bool 923 runTargets(void) 924 { 925 GNodeList targs = LST_INIT; /* target nodes to create */ 926 bool outOfDate; /* false if all targets up to date */ 927 928 /* 929 * Have now read the entire graph and need to make a list of 930 * targets to create. If none was given on the command line, 931 * we consult the parsing module to find the main target(s) 932 * to create. 933 */ 934 if (Lst_IsEmpty(&opts.create)) 935 Parse_MainName(&targs); 936 else 937 Targ_FindList(&targs, &opts.create); 938 939 if (!opts.compatMake) { 940 /* 941 * Initialize job module before traversing the graph 942 * now that any .BEGIN and .END targets have been read. 943 * This is done only if the -q flag wasn't given 944 * (to prevent the .BEGIN from being executed should 945 * it exist). 946 */ 947 if (!opts.queryFlag) { 948 Job_Init(); 949 jobsRunning = true; 950 } 951 952 /* Traverse the graph, checking on all the targets */ 953 outOfDate = Make_Run(&targs); 954 } else { 955 /* 956 * Compat_Init will take care of creating all the 957 * targets as well as initializing the module. 958 */ 959 Compat_Run(&targs); 960 outOfDate = false; 961 } 962 Lst_Done(&targs); /* Don't free the targets themselves. */ 963 return outOfDate; 964 } 965 966 /* 967 * Set up the .TARGETS variable to contain the list of targets to be 968 * created. If none specified, make the variable empty -- the parser 969 * will fill the thing in with the default or .MAIN target. 970 */ 971 static void 972 InitVarTargets(void) 973 { 974 StringListNode *ln; 975 976 if (Lst_IsEmpty(&opts.create)) { 977 Global_Set(".TARGETS", ""); 978 return; 979 } 980 981 for (ln = opts.create.first; ln != NULL; ln = ln->next) { 982 const char *name = ln->datum; 983 Global_Append(".TARGETS", name); 984 } 985 } 986 987 static void 988 InitRandom(void) 989 { 990 struct timeval tv; 991 992 gettimeofday(&tv, NULL); 993 srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 994 } 995 996 static const char * 997 InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED) 998 { 999 #ifdef FORCE_MACHINE 1000 return FORCE_MACHINE; 1001 #else 1002 const char *machine = getenv("MACHINE"); 1003 1004 if (machine != NULL) 1005 return machine; 1006 1007 #if defined(MAKE_NATIVE) 1008 return utsname->machine; 1009 #elif defined(MAKE_MACHINE) 1010 return MAKE_MACHINE; 1011 #else 1012 return "unknown"; 1013 #endif 1014 #endif 1015 } 1016 1017 static const char * 1018 InitVarMachineArch(void) 1019 { 1020 #ifdef FORCE_MACHINE_ARCH 1021 return FORCE_MACHINE_ARCH; 1022 #else 1023 const char *env = getenv("MACHINE_ARCH"); 1024 if (env != NULL) 1025 return env; 1026 1027 #if defined(MAKE_NATIVE) && defined(CTL_HW) 1028 { 1029 struct utsname utsname; 1030 static char machine_arch_buf[sizeof utsname.machine]; 1031 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1032 size_t len = sizeof machine_arch_buf; 1033 1034 if (sysctl(mib, (unsigned int)__arraycount(mib), 1035 machine_arch_buf, &len, NULL, 0) < 0) { 1036 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 1037 progname, strerror(errno)); 1038 exit(2); 1039 } 1040 1041 return machine_arch_buf; 1042 } 1043 #elif defined(MACHINE_ARCH) 1044 return MACHINE_ARCH; 1045 #elif defined(MAKE_MACHINE_ARCH) 1046 return MAKE_MACHINE_ARCH; 1047 #else 1048 return "unknown"; 1049 #endif 1050 #endif 1051 } 1052 1053 #ifndef NO_PWD_OVERRIDE 1054 /* 1055 * All this code is so that we know where we are when we start up 1056 * on a different machine with pmake. 1057 * 1058 * XXX: Make no longer has "local" and "remote" mode. Is this code still 1059 * necessary? 1060 * 1061 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1062 * since the value of curdir can vary depending on how we got 1063 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1064 * or via subdir.mk in which case its likely a shell which does 1065 * not provide it. 1066 * 1067 * So, to stop it breaking this case only, we ignore PWD if 1068 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1069 */ 1070 static void 1071 HandlePWD(const struct stat *curdir_st) 1072 { 1073 char *pwd; 1074 FStr prefix, makeobjdir; 1075 struct stat pwd_st; 1076 1077 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1078 return; 1079 1080 prefix = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"); 1081 if (prefix.str != NULL) { 1082 FStr_Done(&prefix); 1083 return; 1084 } 1085 1086 makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR"); 1087 if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1088 goto ignore_pwd; 1089 1090 if (stat(pwd, &pwd_st) == 0 && 1091 curdir_st->st_ino == pwd_st.st_ino && 1092 curdir_st->st_dev == pwd_st.st_dev) 1093 (void)strncpy(curdir, pwd, MAXPATHLEN); 1094 1095 ignore_pwd: 1096 FStr_Done(&makeobjdir); 1097 } 1098 #endif 1099 1100 /* 1101 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1102 * MAKEOBJDIR is set in the environment, try only that value 1103 * and fall back to .CURDIR if it does not exist. 1104 * 1105 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1106 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1107 * of these paths exist, just use .CURDIR. 1108 */ 1109 static void 1110 InitObjdir(const char *machine, const char *machine_arch) 1111 { 1112 bool writable; 1113 1114 Dir_InitCur(curdir); 1115 writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true); 1116 (void)Main_SetObjdir(false, "%s", curdir); 1117 1118 if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1119 !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1120 !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1121 !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1122 !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1123 (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1124 } 1125 1126 /* get rid of resource limit on file descriptors */ 1127 static void 1128 UnlimitFiles(void) 1129 { 1130 #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1131 struct rlimit rl; 1132 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1133 rl.rlim_cur != rl.rlim_max) { 1134 rl.rlim_cur = rl.rlim_max; 1135 (void)setrlimit(RLIMIT_NOFILE, &rl); 1136 } 1137 #endif 1138 } 1139 1140 static void 1141 CmdOpts_Init(void) 1142 { 1143 opts.compatMake = false; 1144 opts.debug = DEBUG_NONE; 1145 /* opts.debug_file has already been initialized earlier */ 1146 opts.strict = false; 1147 opts.debugVflag = false; 1148 opts.checkEnvFirst = false; 1149 Lst_Init(&opts.makefiles); 1150 opts.ignoreErrors = false; /* Pay attention to non-zero returns */ 1151 opts.maxJobs = 1; 1152 opts.keepgoing = false; /* Stop on error */ 1153 opts.noRecursiveExecute = false; /* Execute all .MAKE targets */ 1154 opts.noExecute = false; /* Execute all commands */ 1155 opts.queryFlag = false; 1156 opts.noBuiltins = false; /* Read the built-in rules */ 1157 opts.beSilent = false; /* Print commands as executed */ 1158 opts.touchFlag = false; 1159 opts.printVars = PVM_NONE; 1160 Lst_Init(&opts.variables); 1161 opts.parseWarnFatal = false; 1162 opts.enterFlag = false; 1163 opts.varNoExportEnv = false; 1164 Lst_Init(&opts.create); 1165 } 1166 1167 /* 1168 * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1169 * found by execvp(3) and the shells, even after a chdir. 1170 * 1171 * If it's a relative path and contains a '/', resolve it to an absolute path. 1172 * Otherwise keep it as is, assuming it will be found in the PATH. 1173 */ 1174 static void 1175 InitVarMake(const char *argv0) 1176 { 1177 const char *make = argv0; 1178 1179 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1180 char pathbuf[MAXPATHLEN]; 1181 const char *abspath = cached_realpath(argv0, pathbuf); 1182 struct stat st; 1183 if (abspath != NULL && abspath[0] == '/' && 1184 stat(make, &st) == 0) 1185 make = abspath; 1186 } 1187 1188 Global_Set("MAKE", make); 1189 Global_Set(".MAKE", make); 1190 } 1191 1192 /* 1193 * Add the directories from the colon-separated syspath to defSysIncPath. 1194 * After returning, the contents of syspath is unspecified. 1195 */ 1196 static void 1197 InitDefSysIncPath(char *syspath) 1198 { 1199 static char defsyspath[] = _PATH_DEFSYSPATH; 1200 char *start, *cp; 1201 1202 /* 1203 * If no user-supplied system path was given (through the -m option) 1204 * add the directories from the DEFSYSPATH (more than one may be given 1205 * as dir1:...:dirn) to the system include path. 1206 */ 1207 if (syspath == NULL || syspath[0] == '\0') 1208 syspath = defsyspath; 1209 else 1210 syspath = bmake_strdup(syspath); 1211 1212 for (start = syspath; *start != '\0'; start = cp) { 1213 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1214 continue; 1215 if (*cp == ':') 1216 *cp++ = '\0'; 1217 1218 /* look for magic parent directory search string */ 1219 if (strncmp(start, ".../", 4) == 0) { 1220 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1221 if (dir != NULL) { 1222 (void)SearchPath_Add(defSysIncPath, dir); 1223 free(dir); 1224 } 1225 } else { 1226 (void)SearchPath_Add(defSysIncPath, start); 1227 } 1228 } 1229 1230 if (syspath != defsyspath) 1231 free(syspath); 1232 } 1233 1234 static void 1235 ReadBuiltinRules(void) 1236 { 1237 StringListNode *ln; 1238 StringList sysMkFiles = LST_INIT; 1239 1240 SearchPath_Expand( 1241 Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath, 1242 _PATH_DEFSYSMK, 1243 &sysMkFiles); 1244 if (Lst_IsEmpty(&sysMkFiles)) 1245 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1246 1247 for (ln = sysMkFiles.first; ln != NULL; ln = ln->next) 1248 if (ReadMakefile(ln->datum) == 0) 1249 break; 1250 1251 if (ln == NULL) 1252 Fatal("%s: cannot open %s.", 1253 progname, (const char *)sysMkFiles.first->datum); 1254 1255 /* Free the list nodes but not the actual filenames since these may 1256 * still be used in GNodes. */ 1257 Lst_Done(&sysMkFiles); 1258 } 1259 1260 static void 1261 InitMaxJobs(void) 1262 { 1263 char *value; 1264 int n; 1265 1266 if (forceJobs || opts.compatMake || 1267 !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) 1268 return; 1269 1270 (void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value); 1271 /* TODO: handle errors */ 1272 n = (int)strtol(value, NULL, 0); 1273 if (n < 1) { 1274 (void)fprintf(stderr, 1275 "%s: illegal value for .MAKE.JOBS " 1276 "-- must be positive integer!\n", 1277 progname); 1278 exit(2); /* Not 1 so -q can distinguish error */ 1279 } 1280 1281 if (n != opts.maxJobs) { 1282 Global_Append(MAKEFLAGS, "-j"); 1283 Global_Append(MAKEFLAGS, value); 1284 } 1285 1286 opts.maxJobs = n; 1287 maxJobTokens = opts.maxJobs; 1288 forceJobs = true; 1289 free(value); 1290 } 1291 1292 /* 1293 * For compatibility, look at the directories in the VPATH variable 1294 * and add them to the search path, if the variable is defined. The 1295 * variable's value is in the same format as the PATH environment 1296 * variable, i.e. <directory>:<directory>:<directory>... 1297 */ 1298 static void 1299 InitVpath(void) 1300 { 1301 char *vpath, savec, *path; 1302 if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) 1303 return; 1304 1305 (void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath); 1306 /* TODO: handle errors */ 1307 path = vpath; 1308 do { 1309 char *cp; 1310 /* skip to end of directory */ 1311 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1312 continue; 1313 /* Save terminator character so know when to stop */ 1314 savec = *cp; 1315 *cp = '\0'; 1316 /* Add directory to search path */ 1317 (void)SearchPath_Add(&dirSearchPath, path); 1318 *cp = savec; 1319 path = cp + 1; 1320 } while (savec == ':'); 1321 free(vpath); 1322 } 1323 1324 static void 1325 ReadAllMakefiles(StringList *makefiles) 1326 { 1327 StringListNode *ln; 1328 1329 for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1330 const char *fname = ln->datum; 1331 if (ReadMakefile(fname) != 0) 1332 Fatal("%s: cannot open %s.", progname, fname); 1333 } 1334 } 1335 1336 static void 1337 ReadFirstDefaultMakefile(void) 1338 { 1339 StringListNode *ln; 1340 char *prefs; 1341 1342 (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", 1343 SCOPE_CMDLINE, VARE_WANTRES, &prefs); 1344 /* TODO: handle errors */ 1345 1346 /* XXX: This should use a local list instead of opts.makefiles 1347 * since these makefiles do not come from the command line. They 1348 * also have different semantics in that only the first file that 1349 * is found is processed. See ReadAllMakefiles. */ 1350 (void)str2Lst_Append(&opts.makefiles, prefs); 1351 1352 for (ln = opts.makefiles.first; ln != NULL; ln = ln->next) 1353 if (ReadMakefile(ln->datum) == 0) 1354 break; 1355 1356 free(prefs); 1357 } 1358 1359 /* 1360 * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1361 * Initialize a few modules. 1362 * Parse the arguments from MAKEFLAGS and the command line. 1363 */ 1364 static void 1365 main_Init(int argc, char **argv) 1366 { 1367 struct stat sa; 1368 const char *machine; 1369 const char *machine_arch; 1370 char *syspath = getenv("MAKESYSPATH"); 1371 struct utsname utsname; 1372 1373 /* default to writing debug to stderr */ 1374 opts.debug_file = stderr; 1375 1376 HashTable_Init(&cached_realpaths); 1377 1378 #ifdef SIGINFO 1379 (void)bmake_signal(SIGINFO, siginfo); 1380 #endif 1381 1382 InitRandom(); 1383 1384 progname = str_basename(argv[0]); 1385 1386 UnlimitFiles(); 1387 1388 if (uname(&utsname) == -1) { 1389 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1390 strerror(errno)); 1391 exit(2); 1392 } 1393 1394 /* 1395 * Get the name of this type of MACHINE from utsname 1396 * so we can share an executable for similar machines. 1397 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1398 * 1399 * Note that both MACHINE and MACHINE_ARCH are decided at 1400 * run-time. 1401 */ 1402 machine = InitVarMachine(&utsname); 1403 machine_arch = InitVarMachineArch(); 1404 1405 myPid = getpid(); /* remember this for vFork() */ 1406 1407 /* 1408 * Just in case MAKEOBJDIR wants us to do something tricky. 1409 */ 1410 Targ_Init(); 1411 Var_Init(); 1412 Global_Set(".MAKE.OS", utsname.sysname); 1413 Global_Set("MACHINE", machine); 1414 Global_Set("MACHINE_ARCH", machine_arch); 1415 #ifdef MAKE_VERSION 1416 Global_Set("MAKE_VERSION", MAKE_VERSION); 1417 #endif 1418 Global_Set(".newline", "\n"); /* handy for :@ loops */ 1419 /* 1420 * This is the traditional preference for makefiles. 1421 */ 1422 #ifndef MAKEFILE_PREFERENCE_LIST 1423 # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1424 #endif 1425 Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST); 1426 Global_Set(MAKE_DEPENDFILE, ".depend"); 1427 1428 CmdOpts_Init(); 1429 allPrecious = false; /* Remove targets when interrupted */ 1430 deleteOnError = false; /* Historical default behavior */ 1431 jobsRunning = false; 1432 1433 maxJobTokens = opts.maxJobs; 1434 ignorePWD = false; 1435 1436 /* 1437 * Initialize the parsing, directory and variable modules to prepare 1438 * for the reading of inclusion paths and variable settings on the 1439 * command line 1440 */ 1441 1442 /* 1443 * Initialize various variables. 1444 * MAKE also gets this name, for compatibility 1445 * .MAKEFLAGS gets set to the empty string just in case. 1446 * MFLAGS also gets initialized empty, for compatibility. 1447 */ 1448 Parse_Init(); 1449 InitVarMake(argv[0]); 1450 Global_Set(MAKEFLAGS, ""); 1451 Global_Set(MAKEOVERRIDES, ""); 1452 Global_Set("MFLAGS", ""); 1453 Global_Set(".ALLTARGETS", ""); 1454 /* some makefiles need to know this */ 1455 Var_Set(SCOPE_CMDLINE, MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV); 1456 1457 /* Set some other useful variables. */ 1458 { 1459 char tmp[64], *ep = getenv(MAKE_LEVEL_ENV); 1460 1461 makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 1462 if (makelevel < 0) 1463 makelevel = 0; 1464 snprintf(tmp, sizeof tmp, "%d", makelevel); 1465 Global_Set(MAKE_LEVEL, tmp); 1466 snprintf(tmp, sizeof tmp, "%u", myPid); 1467 Global_Set(".MAKE.PID", tmp); 1468 snprintf(tmp, sizeof tmp, "%u", getppid()); 1469 Global_Set(".MAKE.PPID", tmp); 1470 snprintf(tmp, sizeof tmp, "%u", getuid()); 1471 Global_Set(".MAKE.UID", tmp); 1472 snprintf(tmp, sizeof tmp, "%u", getgid()); 1473 Global_Set(".MAKE.GID", tmp); 1474 } 1475 if (makelevel > 0) { 1476 char pn[1024]; 1477 snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 1478 progname = bmake_strdup(pn); 1479 } 1480 1481 #ifdef USE_META 1482 meta_init(); 1483 #endif 1484 Dir_Init(); 1485 1486 /* 1487 * First snag any flags out of the MAKE environment variable. 1488 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1489 * in a different format). 1490 */ 1491 #ifdef POSIX 1492 { 1493 char *p1 = explode(getenv("MAKEFLAGS")); 1494 Main_ParseArgLine(p1); 1495 free(p1); 1496 } 1497 #else 1498 Main_ParseArgLine(getenv("MAKE")); 1499 #endif 1500 1501 /* 1502 * Find where we are (now). 1503 * We take care of PWD for the automounter below... 1504 */ 1505 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1506 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1507 progname, strerror(errno)); 1508 exit(2); 1509 } 1510 1511 MainParseArgs(argc, argv); 1512 1513 if (opts.enterFlag) 1514 printf("%s: Entering directory `%s'\n", progname, curdir); 1515 1516 /* 1517 * Verify that cwd is sane. 1518 */ 1519 if (stat(curdir, &sa) == -1) { 1520 (void)fprintf(stderr, "%s: %s: %s.\n", 1521 progname, curdir, strerror(errno)); 1522 exit(2); 1523 } 1524 1525 #ifndef NO_PWD_OVERRIDE 1526 HandlePWD(&sa); 1527 #endif 1528 Global_Set(".CURDIR", curdir); 1529 1530 InitObjdir(machine, machine_arch); 1531 1532 /* 1533 * Initialize archive, target and suffix modules in preparation for 1534 * parsing the makefile(s) 1535 */ 1536 Arch_Init(); 1537 Suff_Init(); 1538 Trace_Init(tracefile); 1539 1540 defaultNode = NULL; 1541 (void)time(&now); 1542 1543 Trace_Log(MAKESTART, NULL); 1544 1545 InitVarTargets(); 1546 1547 InitDefSysIncPath(syspath); 1548 } 1549 1550 /* 1551 * Read the system makefile followed by either makefile, Makefile or the 1552 * files given by the -f option. Exit on parse errors. 1553 */ 1554 static void 1555 main_ReadFiles(void) 1556 { 1557 1558 if (!opts.noBuiltins) 1559 ReadBuiltinRules(); 1560 1561 if (!Lst_IsEmpty(&opts.makefiles)) 1562 ReadAllMakefiles(&opts.makefiles); 1563 else 1564 ReadFirstDefaultMakefile(); 1565 } 1566 1567 /* Compute the dependency graph. */ 1568 static void 1569 main_PrepareMaking(void) 1570 { 1571 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1572 if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 1573 (void)Var_Subst("${.MAKE.DEPENDFILE}", 1574 SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile); 1575 if (makeDependfile[0] != '\0') { 1576 /* TODO: handle errors */ 1577 doing_depend = true; 1578 (void)ReadMakefile(makeDependfile); 1579 doing_depend = false; 1580 } 1581 } 1582 1583 if (enterFlagObj) 1584 printf("%s: Entering directory `%s'\n", progname, objdir); 1585 1586 MakeMode(); 1587 1588 { 1589 FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS); 1590 Global_Append("MFLAGS", makeflags.str); 1591 FStr_Done(&makeflags); 1592 } 1593 1594 InitMaxJobs(); 1595 1596 /* 1597 * Be compatible if the user did not specify -j and did not explicitly 1598 * turn compatibility on. 1599 */ 1600 if (!opts.compatMake && !forceJobs) 1601 opts.compatMake = true; 1602 1603 if (!opts.compatMake) 1604 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1605 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1606 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1607 1608 if (opts.printVars == PVM_NONE) 1609 Main_ExportMAKEFLAGS(true); /* initial export */ 1610 1611 InitVpath(); 1612 1613 /* 1614 * Now that all search paths have been read for suffixes et al, it's 1615 * time to add the default search path to their lists... 1616 */ 1617 Suff_ExtendPaths(); 1618 1619 /* 1620 * Propagate attributes through :: dependency lists. 1621 */ 1622 Targ_Propagate(); 1623 1624 /* print the initial graph, if the user requested it */ 1625 if (DEBUG(GRAPH1)) 1626 Targ_PrintGraph(1); 1627 } 1628 1629 /* 1630 * Make the targets. 1631 * If the -v or -V options are given, print variables instead. 1632 * Return whether any of the targets is out-of-date. 1633 */ 1634 static bool 1635 main_Run(void) 1636 { 1637 if (opts.printVars != PVM_NONE) { 1638 /* print the values of any variables requested by the user */ 1639 doPrintVars(); 1640 return false; 1641 } else { 1642 return runTargets(); 1643 } 1644 } 1645 1646 /* Clean up after making the targets. */ 1647 static void 1648 main_CleanUp(void) 1649 { 1650 #ifdef CLEANUP 1651 Lst_DoneCall(&opts.variables, free); 1652 /* 1653 * Don't free the actual strings from opts.makefiles, they may be 1654 * used in GNodes. 1655 */ 1656 Lst_Done(&opts.makefiles); 1657 Lst_DoneCall(&opts.create, free); 1658 #endif 1659 1660 /* print the graph now it's been processed if the user requested it */ 1661 if (DEBUG(GRAPH2)) 1662 Targ_PrintGraph(2); 1663 1664 Trace_Log(MAKEEND, NULL); 1665 1666 if (enterFlagObj) 1667 printf("%s: Leaving directory `%s'\n", progname, objdir); 1668 if (opts.enterFlag) 1669 printf("%s: Leaving directory `%s'\n", progname, curdir); 1670 1671 #ifdef USE_META 1672 meta_finish(); 1673 #endif 1674 Suff_End(); 1675 Targ_End(); 1676 Arch_End(); 1677 Var_End(); 1678 Parse_End(); 1679 Dir_End(); 1680 Job_End(); 1681 Trace_End(); 1682 } 1683 1684 /* Determine the exit code. */ 1685 static int 1686 main_Exit(bool outOfDate) 1687 { 1688 if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0)) 1689 return 2; /* Not 1 so -q can distinguish error */ 1690 return outOfDate ? 1 : 0; 1691 } 1692 1693 int 1694 main(int argc, char **argv) 1695 { 1696 bool outOfDate; 1697 1698 main_Init(argc, argv); 1699 main_ReadFiles(); 1700 main_PrepareMaking(); 1701 outOfDate = main_Run(); 1702 main_CleanUp(); 1703 return main_Exit(outOfDate); 1704 } 1705 1706 /* 1707 * Open and parse the given makefile, with all its side effects. 1708 * 1709 * Results: 1710 * 0 if ok. -1 if couldn't open file. 1711 */ 1712 static int 1713 ReadMakefile(const char *fname) 1714 { 1715 int fd; 1716 char *name, *path = NULL; 1717 1718 if (strcmp(fname, "-") == 0) { 1719 Parse_File(NULL /*stdin*/, -1); 1720 Var_Set(SCOPE_INTERNAL, "MAKEFILE", ""); 1721 } else { 1722 /* if we've chdir'd, rebuild the path name */ 1723 if (strcmp(curdir, objdir) != 0 && *fname != '/') { 1724 path = str_concat3(curdir, "/", fname); 1725 fd = open(path, O_RDONLY); 1726 if (fd != -1) { 1727 fname = path; 1728 goto found; 1729 } 1730 free(path); 1731 1732 /* If curdir failed, try objdir (ala .depend) */ 1733 path = str_concat3(objdir, "/", fname); 1734 fd = open(path, O_RDONLY); 1735 if (fd != -1) { 1736 fname = path; 1737 goto found; 1738 } 1739 } else { 1740 fd = open(fname, O_RDONLY); 1741 if (fd != -1) 1742 goto found; 1743 } 1744 /* look in -I and system include directories. */ 1745 name = Dir_FindFile(fname, parseIncPath); 1746 if (name == NULL) { 1747 SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs) 1748 ? defSysIncPath : sysIncPath; 1749 name = Dir_FindFile(fname, sysInc); 1750 } 1751 if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 1752 free(name); 1753 free(path); 1754 return -1; 1755 } 1756 fname = name; 1757 /* 1758 * set the MAKEFILE variable desired by System V fans -- the 1759 * placement of the setting here means it gets set to the last 1760 * makefile specified, as it is set by SysV make. 1761 */ 1762 found: 1763 if (!doing_depend) 1764 Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname); 1765 Parse_File(fname, fd); 1766 } 1767 free(path); 1768 return 0; 1769 } 1770 1771 /* 1772 * Cmd_Exec -- 1773 * Execute the command in cmd, and return the output of that command 1774 * in a string. In the output, newlines are replaced with spaces. 1775 * 1776 * Results: 1777 * A string containing the output of the command, or the empty string. 1778 * *errfmt returns a format string describing the command failure, 1779 * if any, using a single %s conversion specification. 1780 * 1781 * Side Effects: 1782 * The string must be freed by the caller. 1783 */ 1784 char * 1785 Cmd_Exec(const char *cmd, const char **errfmt) 1786 { 1787 const char *args[4]; /* Args for invoking the shell */ 1788 int pipefds[2]; 1789 int cpid; /* Child PID */ 1790 int pid; /* PID from wait() */ 1791 int status; /* command exit status */ 1792 Buffer buf; /* buffer to store the result */ 1793 ssize_t bytes_read; 1794 char *res; /* result */ 1795 size_t res_len; 1796 char *cp; 1797 int savederr; /* saved errno */ 1798 1799 *errfmt = NULL; 1800 1801 if (shellName == NULL) 1802 Shell_Init(); 1803 /* 1804 * Set up arguments for shell 1805 */ 1806 args[0] = shellName; 1807 args[1] = "-c"; 1808 args[2] = cmd; 1809 args[3] = NULL; 1810 1811 /* 1812 * Open a pipe for fetching its output 1813 */ 1814 if (pipe(pipefds) == -1) { 1815 *errfmt = "Couldn't create pipe for \"%s\""; 1816 goto bad; 1817 } 1818 1819 Var_ReexportVars(); 1820 1821 /* 1822 * Fork 1823 */ 1824 switch (cpid = vfork()) { 1825 case 0: 1826 (void)close(pipefds[0]); /* Close input side of pipe */ 1827 1828 /* 1829 * Duplicate the output stream to the shell's output, then 1830 * shut the extra thing down. Note we don't fetch the error 1831 * stream...why not? Why? 1832 */ 1833 (void)dup2(pipefds[1], 1); 1834 (void)close(pipefds[1]); 1835 1836 (void)execv(shellPath, UNCONST(args)); 1837 _exit(1); 1838 /*NOTREACHED*/ 1839 1840 case -1: 1841 *errfmt = "Couldn't exec \"%s\""; 1842 goto bad; 1843 1844 default: 1845 (void)close(pipefds[1]); /* No need for the writing half */ 1846 1847 savederr = 0; 1848 Buf_Init(&buf); 1849 1850 do { 1851 char result[BUFSIZ]; 1852 bytes_read = read(pipefds[0], result, sizeof result); 1853 if (bytes_read > 0) 1854 Buf_AddBytes(&buf, result, (size_t)bytes_read); 1855 } while (bytes_read > 0 || 1856 (bytes_read == -1 && errno == EINTR)); 1857 if (bytes_read == -1) 1858 savederr = errno; 1859 1860 (void)close(pipefds[0]); /* Close the input side of the pipe. */ 1861 1862 /* Wait for the process to exit. */ 1863 while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 1864 JobReapChild(pid, status, false); 1865 1866 res_len = buf.len; 1867 res = Buf_DoneData(&buf); 1868 1869 if (savederr != 0) 1870 *errfmt = "Couldn't read shell's output for \"%s\""; 1871 1872 if (WIFSIGNALED(status)) 1873 *errfmt = "\"%s\" exited on a signal"; 1874 else if (WEXITSTATUS(status) != 0) 1875 *errfmt = "\"%s\" returned non-zero status"; 1876 1877 /* Convert newlines to spaces. A final newline is just stripped */ 1878 if (res_len > 0 && res[res_len - 1] == '\n') 1879 res[res_len - 1] = '\0'; 1880 for (cp = res; *cp != '\0'; cp++) 1881 if (*cp == '\n') 1882 *cp = ' '; 1883 break; 1884 } 1885 return res; 1886 bad: 1887 return bmake_strdup(""); 1888 } 1889 1890 /* 1891 * Print a printf-style error message. 1892 * 1893 * In default mode, this error message has no consequences, in particular it 1894 * does not affect the exit status. Only in lint mode (-dL) it does. 1895 */ 1896 void 1897 Error(const char *fmt, ...) 1898 { 1899 va_list ap; 1900 FILE *err_file; 1901 1902 err_file = opts.debug_file; 1903 if (err_file == stdout) 1904 err_file = stderr; 1905 (void)fflush(stdout); 1906 for (;;) { 1907 va_start(ap, fmt); 1908 fprintf(err_file, "%s: ", progname); 1909 (void)vfprintf(err_file, fmt, ap); 1910 va_end(ap); 1911 (void)fprintf(err_file, "\n"); 1912 (void)fflush(err_file); 1913 if (err_file == stderr) 1914 break; 1915 err_file = stderr; 1916 } 1917 main_errors++; 1918 } 1919 1920 /* 1921 * Wait for any running jobs to finish, then produce an error message, 1922 * finally exit immediately. 1923 * 1924 * Exiting immediately differs from Parse_Error, which exits only after the 1925 * current top-level makefile has been parsed completely. 1926 */ 1927 void 1928 Fatal(const char *fmt, ...) 1929 { 1930 va_list ap; 1931 1932 if (jobsRunning) 1933 Job_Wait(); 1934 1935 (void)fflush(stdout); 1936 va_start(ap, fmt); 1937 (void)vfprintf(stderr, fmt, ap); 1938 va_end(ap); 1939 (void)fprintf(stderr, "\n"); 1940 (void)fflush(stderr); 1941 1942 PrintOnError(NULL, NULL); 1943 1944 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1945 Targ_PrintGraph(2); 1946 Trace_Log(MAKEERROR, NULL); 1947 exit(2); /* Not 1 so -q can distinguish error */ 1948 } 1949 1950 /* 1951 * Major exception once jobs are being created. 1952 * Kills all jobs, prints a message and exits. 1953 */ 1954 void 1955 Punt(const char *fmt, ...) 1956 { 1957 va_list ap; 1958 1959 va_start(ap, fmt); 1960 (void)fflush(stdout); 1961 (void)fprintf(stderr, "%s: ", progname); 1962 (void)vfprintf(stderr, fmt, ap); 1963 va_end(ap); 1964 (void)fprintf(stderr, "\n"); 1965 (void)fflush(stderr); 1966 1967 PrintOnError(NULL, NULL); 1968 1969 DieHorribly(); 1970 } 1971 1972 /* Exit without giving a message. */ 1973 void 1974 DieHorribly(void) 1975 { 1976 if (jobsRunning) 1977 Job_AbortAll(); 1978 if (DEBUG(GRAPH2)) 1979 Targ_PrintGraph(2); 1980 Trace_Log(MAKEERROR, NULL); 1981 exit(2); /* Not 1 so -q can distinguish error */ 1982 } 1983 1984 /* 1985 * Called when aborting due to errors in child shell to signal abnormal exit. 1986 * The program exits. 1987 * Errors is the number of errors encountered in Make_Make. 1988 */ 1989 void 1990 Finish(int errs) 1991 { 1992 if (shouldDieQuietly(NULL, -1)) 1993 exit(2); 1994 Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 1995 } 1996 1997 /* 1998 * eunlink -- 1999 * Remove a file carefully, avoiding directories. 2000 */ 2001 int 2002 eunlink(const char *file) 2003 { 2004 struct stat st; 2005 2006 if (lstat(file, &st) == -1) 2007 return -1; 2008 2009 if (S_ISDIR(st.st_mode)) { 2010 errno = EISDIR; 2011 return -1; 2012 } 2013 return unlink(file); 2014 } 2015 2016 static void 2017 write_all(int fd, const void *data, size_t n) 2018 { 2019 const char *mem = data; 2020 2021 while (n > 0) { 2022 ssize_t written = write(fd, mem, n); 2023 if (written == -1 && errno == EAGAIN) 2024 continue; 2025 if (written == -1) 2026 break; 2027 mem += written; 2028 n -= (size_t)written; 2029 } 2030 } 2031 2032 /* 2033 * execDie -- 2034 * Print why exec failed, avoiding stdio. 2035 */ 2036 void MAKE_ATTR_DEAD 2037 execDie(const char *af, const char *av) 2038 { 2039 Buffer buf; 2040 2041 Buf_Init(&buf); 2042 Buf_AddStr(&buf, progname); 2043 Buf_AddStr(&buf, ": "); 2044 Buf_AddStr(&buf, af); 2045 Buf_AddStr(&buf, "("); 2046 Buf_AddStr(&buf, av); 2047 Buf_AddStr(&buf, ") failed ("); 2048 Buf_AddStr(&buf, strerror(errno)); 2049 Buf_AddStr(&buf, ")\n"); 2050 2051 write_all(STDERR_FILENO, buf.data, buf.len); 2052 2053 Buf_Done(&buf); 2054 _exit(1); 2055 } 2056 2057 /* purge any relative paths */ 2058 static void 2059 purge_relative_cached_realpaths(void) 2060 { 2061 HashEntry *he, *nhe; 2062 HashIter hi; 2063 2064 HashIter_Init(&hi, &cached_realpaths); 2065 he = HashIter_Next(&hi); 2066 while (he != NULL) { 2067 nhe = HashIter_Next(&hi); 2068 if (he->key[0] != '/') { 2069 DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 2070 HashTable_DeleteEntry(&cached_realpaths, he); 2071 /* XXX: What about the allocated he->value? Either 2072 * free them or document why they cannot be freed. */ 2073 } 2074 he = nhe; 2075 } 2076 } 2077 2078 char * 2079 cached_realpath(const char *pathname, char *resolved) 2080 { 2081 const char *rp; 2082 2083 if (pathname == NULL || pathname[0] == '\0') 2084 return NULL; 2085 2086 rp = HashTable_FindValue(&cached_realpaths, pathname); 2087 if (rp != NULL) { 2088 /* a hit */ 2089 strncpy(resolved, rp, MAXPATHLEN); 2090 resolved[MAXPATHLEN - 1] = '\0'; 2091 return resolved; 2092 } 2093 2094 rp = realpath(pathname, resolved); 2095 if (rp != NULL) { 2096 HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2097 DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2098 return resolved; 2099 } 2100 2101 /* should we negative-cache? */ 2102 return NULL; 2103 } 2104 2105 /* 2106 * Return true if we should die without noise. 2107 * For example our failing child was a sub-make or failure happened elsewhere. 2108 */ 2109 bool 2110 shouldDieQuietly(GNode *gn, int bf) 2111 { 2112 static int quietly = -1; 2113 2114 if (quietly < 0) { 2115 if (DEBUG(JOB) || 2116 !GetBooleanExpr("${.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(bool first) 2197 { 2198 static bool 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 ":S,/$,,W}/", 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 bool 2279 ParseBoolean(const char *s, bool 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