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