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