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