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