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