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