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