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