xref: /freebsd/contrib/bmake/main.c (revision 06b9b3e0ad0dc3f0166b3e8f26ced68c271cf527)
1*06b9b3e0SSimon J. Gerraty /*	$NetBSD: main.c,v 1.512 2021/01/10 23:59:53 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
71*06b9b3e0SSimon J. Gerraty /*
72*06b9b3e0SSimon J. Gerraty  * The main file for this entire program. Exit routines etc. reside here.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Utility functions defined in this file:
753955d011SMarcel Moolenaar  *
76e2eeea75SSimon J. Gerraty  *	Main_ParseArgLine	Parse and process command line arguments from
77e2eeea75SSimon J. Gerraty  *				a single string.  Used to implement the
78e2eeea75SSimon J. Gerraty  *				special targets .MFLAGS and .MAKEFLAGS.
793955d011SMarcel Moolenaar  *
80e2eeea75SSimon J. Gerraty  *	Error			Print a tagged error message.
813955d011SMarcel Moolenaar  *
82e2eeea75SSimon J. Gerraty  *	Fatal			Print an error message and exit.
83e2eeea75SSimon J. Gerraty  *
84e2eeea75SSimon J. Gerraty  *	Punt			Abort all jobs and exit with a message.
853955d011SMarcel Moolenaar  *
863955d011SMarcel Moolenaar  *	Finish			Finish things up by printing the number of
87e2eeea75SSimon J. Gerraty  *				errors which occurred, and exit.
883955d011SMarcel Moolenaar  */
893955d011SMarcel Moolenaar 
903955d011SMarcel Moolenaar #include <sys/types.h>
913955d011SMarcel Moolenaar #include <sys/time.h>
923955d011SMarcel Moolenaar #include <sys/param.h>
933955d011SMarcel Moolenaar #include <sys/resource.h>
943955d011SMarcel Moolenaar #include <sys/stat.h>
950dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL)
960dede8b0SSimon J. Gerraty #include <sys/sysctl.h>
970dede8b0SSimon J. Gerraty #endif
983955d011SMarcel Moolenaar #include <sys/utsname.h>
993955d011SMarcel Moolenaar #include "wait.h"
1003955d011SMarcel Moolenaar 
1013955d011SMarcel Moolenaar #include <errno.h>
10251ee2c1cSSimon J. Gerraty #include <signal.h>
1033955d011SMarcel Moolenaar #include <stdarg.h>
1043955d011SMarcel Moolenaar #include <time.h>
1053955d011SMarcel Moolenaar 
1063955d011SMarcel Moolenaar #include "make.h"
1073955d011SMarcel Moolenaar #include "dir.h"
1083955d011SMarcel Moolenaar #include "job.h"
1093955d011SMarcel Moolenaar #include "pathnames.h"
1103955d011SMarcel Moolenaar #include "trace.h"
1113955d011SMarcel Moolenaar 
112956e45f6SSimon J. Gerraty /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
113*06b9b3e0SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.512 2021/01/10 23:59:53 rillig Exp $");
114956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && !defined(lint)
115956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
116956e45f6SSimon J. Gerraty 	    "The Regents of the University of California.  "
117956e45f6SSimon J. Gerraty 	    "All rights reserved.");
1183955d011SMarcel Moolenaar #endif
1193955d011SMarcel Moolenaar 
1200dede8b0SSimon J. Gerraty #ifndef __arraycount
1210dede8b0SSimon J. Gerraty # define __arraycount(__x)	(sizeof(__x) / sizeof(__x[0]))
1220dede8b0SSimon J. Gerraty #endif
1230dede8b0SSimon J. Gerraty 
124956e45f6SSimon J. Gerraty CmdOpts opts;
1253955d011SMarcel Moolenaar time_t now;			/* Time at start of make */
126e2eeea75SSimon J. Gerraty GNode *defaultNode;		/* .DEFAULT node */
1273955d011SMarcel Moolenaar Boolean allPrecious;		/* .PRECIOUS given on line by itself */
12845447996SSimon J. Gerraty Boolean deleteOnError;		/* .DELETE_ON_ERROR: set */
1293955d011SMarcel Moolenaar 
1303955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1314c620fe5SSimon J. Gerraty Boolean enterFlagObj;		/* -w and objdir != srcdir */
132956e45f6SSimon J. Gerraty 
1333955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
1343955d011SMarcel Moolenaar Boolean doing_depend;		/* Set while reading .depend */
1353955d011SMarcel Moolenaar static Boolean jobsRunning;	/* TRUE if the jobs might be running */
1363955d011SMarcel Moolenaar static const char *tracefile;
1372c3632d1SSimon J. Gerraty static int ReadMakefile(const char *);
138e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1393955d011SMarcel Moolenaar 
1403955d011SMarcel Moolenaar static Boolean ignorePWD;	/* if we use -C, PWD is meaningless */
1413955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
1423955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1];	/* Startup directory */
143*06b9b3e0SSimon J. Gerraty const char *progname;
1443955d011SMarcel Moolenaar char *makeDependfile;
1453955d011SMarcel Moolenaar pid_t myPid;
14651ee2c1cSSimon J. Gerraty int makelevel;
1473955d011SMarcel Moolenaar 
1483955d011SMarcel Moolenaar Boolean forceJobs = FALSE;
149*06b9b3e0SSimon J. Gerraty static int main_errors = 0;
150e2eeea75SSimon J. Gerraty static HashTable cached_realpaths;
1513955d011SMarcel Moolenaar 
15251ee2c1cSSimon J. Gerraty /*
15351ee2c1cSSimon J. Gerraty  * For compatibility with the POSIX version of MAKEFLAGS that includes
154e2eeea75SSimon J. Gerraty  * all the options without '-', convert 'flags' to '-f -l -a -g -s'.
15551ee2c1cSSimon J. Gerraty  */
15651ee2c1cSSimon J. Gerraty static char *
15751ee2c1cSSimon J. Gerraty explode(const char *flags)
15851ee2c1cSSimon J. Gerraty {
15951ee2c1cSSimon J. Gerraty 	size_t len;
16051ee2c1cSSimon J. Gerraty 	char *nf, *st;
16151ee2c1cSSimon J. Gerraty 	const char *f;
16251ee2c1cSSimon J. Gerraty 
16351ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16451ee2c1cSSimon J. Gerraty 		return NULL;
16551ee2c1cSSimon J. Gerraty 
166*06b9b3e0SSimon J. Gerraty 	for (f = flags; *f != '\0'; f++)
167956e45f6SSimon J. Gerraty 		if (!ch_isalpha(*f))
16851ee2c1cSSimon J. Gerraty 			break;
16951ee2c1cSSimon J. Gerraty 
170*06b9b3e0SSimon J. Gerraty 	if (*f != '\0')
17151ee2c1cSSimon J. Gerraty 		return bmake_strdup(flags);
17251ee2c1cSSimon J. Gerraty 
17351ee2c1cSSimon J. Gerraty 	len = strlen(flags);
17451ee2c1cSSimon J. Gerraty 	st = nf = bmake_malloc(len * 3 + 1);
175*06b9b3e0SSimon J. Gerraty 	while (*flags != '\0') {
17651ee2c1cSSimon J. Gerraty 		*nf++ = '-';
17751ee2c1cSSimon J. Gerraty 		*nf++ = *flags++;
17851ee2c1cSSimon J. Gerraty 		*nf++ = ' ';
17951ee2c1cSSimon J. Gerraty 	}
18051ee2c1cSSimon J. Gerraty 	*nf = '\0';
18151ee2c1cSSimon J. Gerraty 	return st;
18251ee2c1cSSimon J. Gerraty }
18351ee2c1cSSimon J. Gerraty 
184e2eeea75SSimon J. Gerraty /*
185e2eeea75SSimon J. Gerraty  * usage --
186e2eeea75SSimon J. Gerraty  *	exit with usage message
187e2eeea75SSimon J. Gerraty  */
188e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
189e2eeea75SSimon J. Gerraty usage(void)
190e2eeea75SSimon J. Gerraty {
191e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
192e2eeea75SSimon J. Gerraty 
193e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
194e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
195e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
196e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
197e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
198e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
199e2eeea75SSimon J. Gerraty 	exit(2);
200e2eeea75SSimon J. Gerraty }
201e2eeea75SSimon J. Gerraty 
2023955d011SMarcel Moolenaar static void
203956e45f6SSimon J. Gerraty parse_debug_option_F(const char *modules)
2043955d011SMarcel Moolenaar {
2053955d011SMarcel Moolenaar 	const char *mode;
206956e45f6SSimon J. Gerraty 	size_t len;
2073955d011SMarcel Moolenaar 	char *fname;
2083955d011SMarcel Moolenaar 
209956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
210956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
211956e45f6SSimon J. Gerraty 
212956e45f6SSimon J. Gerraty 	if (*modules == '+') {
2133955d011SMarcel Moolenaar 		modules++;
2143955d011SMarcel Moolenaar 		mode = "a";
2153955d011SMarcel Moolenaar 	} else
2163955d011SMarcel Moolenaar 		mode = "w";
217956e45f6SSimon J. Gerraty 
2183955d011SMarcel Moolenaar 	if (strcmp(modules, "stdout") == 0) {
219956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
220956e45f6SSimon J. Gerraty 		return;
2213955d011SMarcel Moolenaar 	}
2223955d011SMarcel Moolenaar 	if (strcmp(modules, "stderr") == 0) {
223956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
224956e45f6SSimon J. Gerraty 		return;
2253955d011SMarcel Moolenaar 	}
226956e45f6SSimon J. Gerraty 
2273955d011SMarcel Moolenaar 	len = strlen(modules);
228e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
2293955d011SMarcel Moolenaar 	memcpy(fname, modules, len + 1);
230956e45f6SSimon J. Gerraty 
2313955d011SMarcel Moolenaar 	/* Let the filename be modified by the pid */
2323955d011SMarcel Moolenaar 	if (strcmp(fname + len - 3, ".%d") == 0)
2333955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
234956e45f6SSimon J. Gerraty 
235956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
236e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
2373955d011SMarcel Moolenaar 		fprintf(stderr, "Cannot open debug file %s\n",
2383955d011SMarcel Moolenaar 		    fname);
2393955d011SMarcel Moolenaar 		usage();
2403955d011SMarcel Moolenaar 	}
2413955d011SMarcel Moolenaar 	free(fname);
242956e45f6SSimon J. Gerraty }
243956e45f6SSimon J. Gerraty 
244956e45f6SSimon J. Gerraty static void
245956e45f6SSimon J. Gerraty parse_debug_options(const char *argvalue)
246956e45f6SSimon J. Gerraty {
247956e45f6SSimon J. Gerraty 	const char *modules;
248e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
249956e45f6SSimon J. Gerraty 
250*06b9b3e0SSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; ++modules) {
251956e45f6SSimon J. Gerraty 		switch (*modules) {
252956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
253e2eeea75SSimon J. Gerraty 			debug = DEBUG_NONE;
254956e45f6SSimon J. Gerraty 			break;
255956e45f6SSimon J. Gerraty 		case 'A':
256e2eeea75SSimon J. Gerraty 			debug = DEBUG_ALL;
257956e45f6SSimon J. Gerraty 			break;
258956e45f6SSimon J. Gerraty 		case 'a':
259e2eeea75SSimon J. Gerraty 			debug |= DEBUG_ARCH;
260956e45f6SSimon J. Gerraty 			break;
261956e45f6SSimon J. Gerraty 		case 'C':
262e2eeea75SSimon J. Gerraty 			debug |= DEBUG_CWD;
263956e45f6SSimon J. Gerraty 			break;
264956e45f6SSimon J. Gerraty 		case 'c':
265e2eeea75SSimon J. Gerraty 			debug |= DEBUG_COND;
266956e45f6SSimon J. Gerraty 			break;
267956e45f6SSimon J. Gerraty 		case 'd':
268e2eeea75SSimon J. Gerraty 			debug |= DEBUG_DIR;
269956e45f6SSimon J. Gerraty 			break;
270956e45f6SSimon J. Gerraty 		case 'e':
271e2eeea75SSimon J. Gerraty 			debug |= DEBUG_ERROR;
272956e45f6SSimon J. Gerraty 			break;
273956e45f6SSimon J. Gerraty 		case 'f':
274e2eeea75SSimon J. Gerraty 			debug |= DEBUG_FOR;
275956e45f6SSimon J. Gerraty 			break;
276956e45f6SSimon J. Gerraty 		case 'g':
277956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
278e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH1;
279e2eeea75SSimon J. Gerraty 				modules++;
280e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
281e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH2;
282e2eeea75SSimon J. Gerraty 				modules++;
283e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
284e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH3;
285e2eeea75SSimon J. Gerraty 				modules++;
286956e45f6SSimon J. Gerraty 			}
287956e45f6SSimon J. Gerraty 			break;
288956e45f6SSimon J. Gerraty 		case 'h':
289e2eeea75SSimon J. Gerraty 			debug |= DEBUG_HASH;
290956e45f6SSimon J. Gerraty 			break;
291956e45f6SSimon J. Gerraty 		case 'j':
292e2eeea75SSimon J. Gerraty 			debug |= DEBUG_JOB;
293956e45f6SSimon J. Gerraty 			break;
294956e45f6SSimon J. Gerraty 		case 'L':
295*06b9b3e0SSimon J. Gerraty 			opts.strict = TRUE;
296956e45f6SSimon J. Gerraty 			break;
297956e45f6SSimon J. Gerraty 		case 'l':
298e2eeea75SSimon J. Gerraty 			debug |= DEBUG_LOUD;
299956e45f6SSimon J. Gerraty 			break;
300956e45f6SSimon J. Gerraty 		case 'M':
301e2eeea75SSimon J. Gerraty 			debug |= DEBUG_META;
302956e45f6SSimon J. Gerraty 			break;
303956e45f6SSimon J. Gerraty 		case 'm':
304e2eeea75SSimon J. Gerraty 			debug |= DEBUG_MAKE;
305956e45f6SSimon J. Gerraty 			break;
306956e45f6SSimon J. Gerraty 		case 'n':
307e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SCRIPT;
308956e45f6SSimon J. Gerraty 			break;
309956e45f6SSimon J. Gerraty 		case 'p':
310e2eeea75SSimon J. Gerraty 			debug |= DEBUG_PARSE;
311956e45f6SSimon J. Gerraty 			break;
312956e45f6SSimon J. Gerraty 		case 's':
313e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SUFF;
314956e45f6SSimon J. Gerraty 			break;
315956e45f6SSimon J. Gerraty 		case 't':
316e2eeea75SSimon J. Gerraty 			debug |= DEBUG_TARG;
317956e45f6SSimon J. Gerraty 			break;
318956e45f6SSimon J. Gerraty 		case 'V':
319956e45f6SSimon J. Gerraty 			opts.debugVflag = TRUE;
320956e45f6SSimon J. Gerraty 			break;
321956e45f6SSimon J. Gerraty 		case 'v':
322e2eeea75SSimon J. Gerraty 			debug |= DEBUG_VAR;
323956e45f6SSimon J. Gerraty 			break;
324956e45f6SSimon J. Gerraty 		case 'x':
325e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SHELL;
326956e45f6SSimon J. Gerraty 			break;
327956e45f6SSimon J. Gerraty 		case 'F':
328956e45f6SSimon J. Gerraty 			parse_debug_option_F(modules + 1);
3293955d011SMarcel Moolenaar 			goto debug_setbuf;
3303955d011SMarcel Moolenaar 		default:
3313955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3323955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3333955d011SMarcel Moolenaar 			    progname, *modules);
3343955d011SMarcel Moolenaar 			usage();
3353955d011SMarcel Moolenaar 		}
3363955d011SMarcel Moolenaar 	}
337e2eeea75SSimon J. Gerraty 
3383955d011SMarcel Moolenaar debug_setbuf:
339e2eeea75SSimon J. Gerraty 	opts.debug = debug;
340e2eeea75SSimon J. Gerraty 
3413955d011SMarcel Moolenaar 	/*
3423955d011SMarcel Moolenaar 	 * Make the debug_file unbuffered, and make
3433955d011SMarcel Moolenaar 	 * stdout line buffered (unless debugfile == stdout).
3443955d011SMarcel Moolenaar 	 */
345956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
346956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout) {
3473955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3483955d011SMarcel Moolenaar 	}
3493955d011SMarcel Moolenaar }
3503955d011SMarcel Moolenaar 
351e1cee40dSSimon J. Gerraty /*
352e1cee40dSSimon J. Gerraty  * does path contain any relative components
353e1cee40dSSimon J. Gerraty  */
3542c3632d1SSimon J. Gerraty static Boolean
355e1cee40dSSimon J. Gerraty is_relpath(const char *path)
356e1cee40dSSimon J. Gerraty {
357e1cee40dSSimon J. Gerraty 	const char *cp;
358e1cee40dSSimon J. Gerraty 
359e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
360e1cee40dSSimon J. Gerraty 		return TRUE;
361e1cee40dSSimon J. Gerraty 	cp = path;
3622c3632d1SSimon J. Gerraty 	while ((cp = strstr(cp, "/.")) != NULL) {
363e1cee40dSSimon J. Gerraty 		cp += 2;
364e2eeea75SSimon J. Gerraty 		if (*cp == '.')
365e2eeea75SSimon J. Gerraty 			cp++;
366e1cee40dSSimon J. Gerraty 		if (cp[0] == '/' || cp[0] == '\0')
367e1cee40dSSimon J. Gerraty 			return TRUE;
3682c3632d1SSimon J. Gerraty 	}
369e1cee40dSSimon J. Gerraty 	return FALSE;
370e1cee40dSSimon J. Gerraty }
371e1cee40dSSimon J. Gerraty 
372956e45f6SSimon J. Gerraty static void
373956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
374956e45f6SSimon J. Gerraty {
375956e45f6SSimon J. Gerraty 	struct stat sa, sb;
376956e45f6SSimon J. Gerraty 
377956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
378956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
379956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
380*06b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
381956e45f6SSimon J. Gerraty 	}
382956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
383956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
384956e45f6SSimon J. Gerraty 		exit(2);
385956e45f6SSimon J. Gerraty 	}
386956e45f6SSimon J. Gerraty 	if (!is_relpath(argvalue) &&
387956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
388956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
389956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
390956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
391956e45f6SSimon J. Gerraty 		strncpy(curdir, argvalue, MAXPATHLEN);
392956e45f6SSimon J. Gerraty 	ignorePWD = TRUE;
393956e45f6SSimon J. Gerraty }
394956e45f6SSimon J. Gerraty 
395956e45f6SSimon J. Gerraty static void
396956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
397956e45f6SSimon J. Gerraty {
398e2eeea75SSimon J. Gerraty 	char end;
399e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
400956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
401956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
402956e45f6SSimon J. Gerraty 		    progname, argvalue);
403956e45f6SSimon J. Gerraty 		usage();
404956e45f6SSimon J. Gerraty 	}
405956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
406956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
407956e45f6SSimon J. Gerraty #if 0
408956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
409956e45f6SSimon J. Gerraty 		    "%s: ###### warning -- J descriptors were closed!\n",
410956e45f6SSimon J. Gerraty 		    progname);
411956e45f6SSimon J. Gerraty 		exit(2);
412956e45f6SSimon J. Gerraty #endif
413956e45f6SSimon J. Gerraty 		jp_0 = -1;
414956e45f6SSimon J. Gerraty 		jp_1 = -1;
415956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
416956e45f6SSimon J. Gerraty 	} else {
417956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
418956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
419956e45f6SSimon J. Gerraty 	}
420956e45f6SSimon J. Gerraty }
421956e45f6SSimon J. Gerraty 
422956e45f6SSimon J. Gerraty static void
423956e45f6SSimon J. Gerraty MainParseArgJobs(const char *argvalue)
424956e45f6SSimon J. Gerraty {
425956e45f6SSimon J. Gerraty 	char *p;
426956e45f6SSimon J. Gerraty 
427956e45f6SSimon J. Gerraty 	forceJobs = TRUE;
428956e45f6SSimon J. Gerraty 	opts.maxJobs = (int)strtol(argvalue, &p, 0);
429956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
430956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
431956e45f6SSimon J. Gerraty 		    "%s: illegal argument to -j -- must be positive integer!\n",
432956e45f6SSimon J. Gerraty 		    progname);
433*06b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
434956e45f6SSimon J. Gerraty 	}
435956e45f6SSimon J. Gerraty 	Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
436956e45f6SSimon J. Gerraty 	Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
437956e45f6SSimon J. Gerraty 	Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL);
438956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
439956e45f6SSimon J. Gerraty }
440956e45f6SSimon J. Gerraty 
441956e45f6SSimon J. Gerraty static void
442956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
443956e45f6SSimon J. Gerraty {
444956e45f6SSimon J. Gerraty 	/* look for magic parent directory search string */
445956e45f6SSimon J. Gerraty 	if (strncmp(".../", argvalue, 4) == 0) {
446956e45f6SSimon J. Gerraty 		char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
447956e45f6SSimon J. Gerraty 		if (found_path == NULL)
448956e45f6SSimon J. Gerraty 			return;
449956e45f6SSimon J. Gerraty 		(void)Dir_AddDir(sysIncPath, found_path);
450956e45f6SSimon J. Gerraty 		free(found_path);
451956e45f6SSimon J. Gerraty 	} else {
452956e45f6SSimon J. Gerraty 		(void)Dir_AddDir(sysIncPath, argvalue);
453956e45f6SSimon J. Gerraty 	}
454956e45f6SSimon J. Gerraty 	Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
455956e45f6SSimon J. Gerraty 	Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
456956e45f6SSimon J. Gerraty }
457956e45f6SSimon J. Gerraty 
458956e45f6SSimon J. Gerraty static Boolean
459956e45f6SSimon J. Gerraty MainParseArg(char c, const char *argvalue)
460956e45f6SSimon J. Gerraty {
461956e45f6SSimon J. Gerraty 	switch (c) {
462956e45f6SSimon J. Gerraty 	case '\0':
463956e45f6SSimon J. Gerraty 		break;
464956e45f6SSimon J. Gerraty 	case 'B':
465956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
466956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
467956e45f6SSimon J. Gerraty 		Var_Set(MAKE_MODE, "compat", VAR_GLOBAL);
468956e45f6SSimon J. Gerraty 		break;
469956e45f6SSimon J. Gerraty 	case 'C':
470956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
471956e45f6SSimon J. Gerraty 		break;
472956e45f6SSimon J. Gerraty 	case 'D':
473956e45f6SSimon J. Gerraty 		if (argvalue[0] == '\0') return FALSE;
474956e45f6SSimon J. Gerraty 		Var_Set(argvalue, "1", VAR_GLOBAL);
475956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
476956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
477956e45f6SSimon J. Gerraty 		break;
478956e45f6SSimon J. Gerraty 	case 'I':
479956e45f6SSimon J. Gerraty 		Parse_AddIncludeDir(argvalue);
480956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
481956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
482956e45f6SSimon J. Gerraty 		break;
483956e45f6SSimon J. Gerraty 	case 'J':
484956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
485956e45f6SSimon J. Gerraty 		break;
486956e45f6SSimon J. Gerraty 	case 'N':
487956e45f6SSimon J. Gerraty 		opts.noExecute = TRUE;
488956e45f6SSimon J. Gerraty 		opts.noRecursiveExecute = TRUE;
489956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL);
490956e45f6SSimon J. Gerraty 		break;
491956e45f6SSimon J. Gerraty 	case 'S':
492956e45f6SSimon J. Gerraty 		opts.keepgoing = FALSE;
493956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
494956e45f6SSimon J. Gerraty 		break;
495956e45f6SSimon J. Gerraty 	case 'T':
496956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
497956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL);
498956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
499956e45f6SSimon J. Gerraty 		break;
500956e45f6SSimon J. Gerraty 	case 'V':
501956e45f6SSimon J. Gerraty 	case 'v':
502e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
503*06b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
504956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
505956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
506956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
507956e45f6SSimon J. Gerraty 		break;
508956e45f6SSimon J. Gerraty 	case 'W':
509956e45f6SSimon J. Gerraty 		opts.parseWarnFatal = TRUE;
510e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
511956e45f6SSimon J. Gerraty 		break;
512956e45f6SSimon J. Gerraty 	case 'X':
513956e45f6SSimon J. Gerraty 		opts.varNoExportEnv = TRUE;
514956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL);
515956e45f6SSimon J. Gerraty 		break;
516956e45f6SSimon J. Gerraty 	case 'd':
517956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
518956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
519956e45f6SSimon J. Gerraty 			argvalue++;
520956e45f6SSimon J. Gerraty 		else {
521956e45f6SSimon J. Gerraty 			Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
522956e45f6SSimon J. Gerraty 			Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
523956e45f6SSimon J. Gerraty 		}
524956e45f6SSimon J. Gerraty 		parse_debug_options(argvalue);
525956e45f6SSimon J. Gerraty 		break;
526956e45f6SSimon J. Gerraty 	case 'e':
527956e45f6SSimon J. Gerraty 		opts.checkEnvFirst = TRUE;
528956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
529956e45f6SSimon J. Gerraty 		break;
530956e45f6SSimon J. Gerraty 	case 'f':
531*06b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
532956e45f6SSimon J. Gerraty 		break;
533956e45f6SSimon J. Gerraty 	case 'i':
534956e45f6SSimon J. Gerraty 		opts.ignoreErrors = TRUE;
535956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
536956e45f6SSimon J. Gerraty 		break;
537956e45f6SSimon J. Gerraty 	case 'j':
538956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
539956e45f6SSimon J. Gerraty 		break;
540956e45f6SSimon J. Gerraty 	case 'k':
541956e45f6SSimon J. Gerraty 		opts.keepgoing = TRUE;
542956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
543956e45f6SSimon J. Gerraty 		break;
544956e45f6SSimon J. Gerraty 	case 'm':
545956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
546e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
547956e45f6SSimon J. Gerraty 		break;
548956e45f6SSimon J. Gerraty 	case 'n':
549956e45f6SSimon J. Gerraty 		opts.noExecute = TRUE;
550956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
551956e45f6SSimon J. Gerraty 		break;
552956e45f6SSimon J. Gerraty 	case 'q':
553956e45f6SSimon J. Gerraty 		opts.queryFlag = TRUE;
554956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
555956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
556956e45f6SSimon J. Gerraty 		break;
557956e45f6SSimon J. Gerraty 	case 'r':
558956e45f6SSimon J. Gerraty 		opts.noBuiltins = TRUE;
559956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
560956e45f6SSimon J. Gerraty 		break;
561956e45f6SSimon J. Gerraty 	case 's':
562956e45f6SSimon J. Gerraty 		opts.beSilent = TRUE;
563956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
564956e45f6SSimon J. Gerraty 		break;
565956e45f6SSimon J. Gerraty 	case 't':
566956e45f6SSimon J. Gerraty 		opts.touchFlag = TRUE;
567956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
568956e45f6SSimon J. Gerraty 		break;
569956e45f6SSimon J. Gerraty 	case 'w':
570956e45f6SSimon J. Gerraty 		opts.enterFlag = TRUE;
571956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL);
572956e45f6SSimon J. Gerraty 		break;
573956e45f6SSimon J. Gerraty 	default:
574956e45f6SSimon J. Gerraty 	case '?':
575956e45f6SSimon J. Gerraty 		usage();
576956e45f6SSimon J. Gerraty 	}
577956e45f6SSimon J. Gerraty 	return TRUE;
578956e45f6SSimon J. Gerraty }
579956e45f6SSimon J. Gerraty 
580*06b9b3e0SSimon J. Gerraty /*
581*06b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5823955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5833955d011SMarcel Moolenaar  *
584956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
585956e45f6SSimon J. Gerraty  * call.
5863955d011SMarcel Moolenaar  *
587*06b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
588*06b9b3e0SSimon J. Gerraty  */
5893955d011SMarcel Moolenaar static void
5903955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5913955d011SMarcel Moolenaar {
592956e45f6SSimon J. Gerraty 	char c;
5933955d011SMarcel Moolenaar 	int arginc;
5943955d011SMarcel Moolenaar 	char *argvalue;
5953955d011SMarcel Moolenaar 	char *optscan;
5963955d011SMarcel Moolenaar 	Boolean inOption, dashDash = FALSE;
5973955d011SMarcel Moolenaar 
598956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
5993955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
6003955d011SMarcel Moolenaar 
6013955d011SMarcel Moolenaar rearg:
6023955d011SMarcel Moolenaar 	inOption = FALSE;
6033955d011SMarcel Moolenaar 	optscan = NULL;
6043955d011SMarcel Moolenaar 	while (argc > 1) {
605956e45f6SSimon J. Gerraty 		const char *optspec;
6063955d011SMarcel Moolenaar 		if (!inOption)
6073955d011SMarcel Moolenaar 			optscan = argv[1];
6083955d011SMarcel Moolenaar 		c = *optscan++;
6093955d011SMarcel Moolenaar 		arginc = 0;
6103955d011SMarcel Moolenaar 		if (inOption) {
6113955d011SMarcel Moolenaar 			if (c == '\0') {
612e2eeea75SSimon J. Gerraty 				argv++;
613e2eeea75SSimon J. Gerraty 				argc--;
6143955d011SMarcel Moolenaar 				inOption = FALSE;
6153955d011SMarcel Moolenaar 				continue;
6163955d011SMarcel Moolenaar 			}
6173955d011SMarcel Moolenaar 		} else {
6183955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6193955d011SMarcel Moolenaar 				break;
6203955d011SMarcel Moolenaar 			inOption = TRUE;
6213955d011SMarcel Moolenaar 			c = *optscan++;
6223955d011SMarcel Moolenaar 		}
6233955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
624956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
625956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6263955d011SMarcel Moolenaar 			/* -<something> found, and <something> should have an arg */
6273955d011SMarcel Moolenaar 			inOption = FALSE;
6283955d011SMarcel Moolenaar 			arginc = 1;
6293955d011SMarcel Moolenaar 			argvalue = optscan;
6303955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6313955d011SMarcel Moolenaar 				if (argc < 3)
6323955d011SMarcel Moolenaar 					goto noarg;
6333955d011SMarcel Moolenaar 				argvalue = argv[2];
6343955d011SMarcel Moolenaar 				arginc = 2;
6353955d011SMarcel Moolenaar 			}
6363955d011SMarcel Moolenaar 		} else {
6373955d011SMarcel Moolenaar 			argvalue = NULL;
6383955d011SMarcel Moolenaar 		}
6393955d011SMarcel Moolenaar 		switch (c) {
6403955d011SMarcel Moolenaar 		case '\0':
6413955d011SMarcel Moolenaar 			arginc = 1;
6423955d011SMarcel Moolenaar 			inOption = FALSE;
6433955d011SMarcel Moolenaar 			break;
6443955d011SMarcel Moolenaar 		case '-':
6453955d011SMarcel Moolenaar 			dashDash = TRUE;
6463955d011SMarcel Moolenaar 			break;
6473955d011SMarcel Moolenaar 		default:
648956e45f6SSimon J. Gerraty 			if (!MainParseArg(c, argvalue))
649956e45f6SSimon J. Gerraty 				goto noarg;
6503955d011SMarcel Moolenaar 		}
6513955d011SMarcel Moolenaar 		argv += arginc;
6523955d011SMarcel Moolenaar 		argc -= arginc;
6533955d011SMarcel Moolenaar 	}
6543955d011SMarcel Moolenaar 
6553955d011SMarcel Moolenaar 	/*
6563955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6573955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6583955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6593955d011SMarcel Moolenaar 	 */
660956e45f6SSimon J. Gerraty 	for (; argc > 1; ++argv, --argc) {
661956e45f6SSimon J. Gerraty 		VarAssign var;
662956e45f6SSimon J. Gerraty 		if (Parse_IsVar(argv[1], &var)) {
663956e45f6SSimon J. Gerraty 			Parse_DoVar(&var, VAR_CMDLINE);
6643955d011SMarcel Moolenaar 		} else {
665e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6663955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
667e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6683955d011SMarcel Moolenaar 				goto rearg;
669*06b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
670956e45f6SSimon J. Gerraty 		}
6713955d011SMarcel Moolenaar 	}
6723955d011SMarcel Moolenaar 
6733955d011SMarcel Moolenaar 	return;
6743955d011SMarcel Moolenaar noarg:
6753955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6763955d011SMarcel Moolenaar 	    progname, c);
6773955d011SMarcel Moolenaar 	usage();
6783955d011SMarcel Moolenaar }
6793955d011SMarcel Moolenaar 
680*06b9b3e0SSimon J. Gerraty /*
681*06b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6823955d011SMarcel Moolenaar  *
683956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
684*06b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
685*06b9b3e0SSimon J. Gerraty  */
6863955d011SMarcel Moolenaar void
6873955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6883955d011SMarcel Moolenaar {
6892c3632d1SSimon J. Gerraty 	Words words;
6902c3632d1SSimon J. Gerraty 	char *buf;
6913955d011SMarcel Moolenaar 
6923955d011SMarcel Moolenaar 	if (line == NULL)
6933955d011SMarcel Moolenaar 		return;
694*06b9b3e0SSimon J. Gerraty 	/* XXX: don't use line as an iterator variable */
6953955d011SMarcel Moolenaar 	for (; *line == ' '; ++line)
6963955d011SMarcel Moolenaar 		continue;
697e2eeea75SSimon J. Gerraty 	if (line[0] == '\0')
6983955d011SMarcel Moolenaar 		return;
6993955d011SMarcel Moolenaar 
7003955d011SMarcel Moolenaar #ifndef POSIX
7013955d011SMarcel Moolenaar 	{
7023955d011SMarcel Moolenaar 		/*
7033955d011SMarcel Moolenaar 		 * $MAKE may simply be naming the make(1) binary
7043955d011SMarcel Moolenaar 		 */
7053955d011SMarcel Moolenaar 		char *cp;
7063955d011SMarcel Moolenaar 
7073955d011SMarcel Moolenaar 		if (!(cp = strrchr(line, '/')))
7083955d011SMarcel Moolenaar 			cp = line;
7093955d011SMarcel Moolenaar 		if ((cp = strstr(cp, "make")) &&
7103955d011SMarcel Moolenaar 		    strcmp(cp, "make") == 0)
7113955d011SMarcel Moolenaar 			return;
7123955d011SMarcel Moolenaar 	}
7133955d011SMarcel Moolenaar #endif
714e2eeea75SSimon J. Gerraty 	{
715*06b9b3e0SSimon J. Gerraty 		FStr argv0 = Var_Value(".MAKE", VAR_GLOBAL);
716*06b9b3e0SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", line);
717*06b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
718e2eeea75SSimon J. Gerraty 	}
7193955d011SMarcel Moolenaar 
7202c3632d1SSimon J. Gerraty 	words = Str_Words(buf, TRUE);
7212c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7223955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7233955d011SMarcel Moolenaar 		free(buf);
7243955d011SMarcel Moolenaar 		return;
7253955d011SMarcel Moolenaar 	}
7263955d011SMarcel Moolenaar 	free(buf);
7272c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7283955d011SMarcel Moolenaar 
7292c3632d1SSimon J. Gerraty 	Words_Free(words);
7303955d011SMarcel Moolenaar }
7313955d011SMarcel Moolenaar 
7323955d011SMarcel Moolenaar Boolean
733e2eeea75SSimon J. Gerraty Main_SetObjdir(Boolean writable, const char *fmt, ...)
7343955d011SMarcel Moolenaar {
7353955d011SMarcel Moolenaar 	struct stat sb;
736b46b9039SSimon J. Gerraty 	char *path;
737b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
738e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
7393955d011SMarcel Moolenaar 	Boolean rc = FALSE;
74045447996SSimon J. Gerraty 	va_list ap;
74145447996SSimon J. Gerraty 
74245447996SSimon J. Gerraty 	va_start(ap, fmt);
743b46b9039SSimon J. Gerraty 	vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
74445447996SSimon J. Gerraty 	va_end(ap);
7453955d011SMarcel Moolenaar 
7463955d011SMarcel Moolenaar 	if (path[0] != '/') {
747e1cee40dSSimon J. Gerraty 		snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
748e1cee40dSSimon J. Gerraty 		path = buf2;
7493955d011SMarcel Moolenaar 	}
7503955d011SMarcel Moolenaar 
7513955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7523955d011SMarcel Moolenaar 	if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
753e2eeea75SSimon J. Gerraty 		if ((writable && access(path, W_OK) != 0) ||
754e2eeea75SSimon J. Gerraty 		    (chdir(path) != 0)) {
755e2eeea75SSimon J. Gerraty 			(void)fprintf(stderr, "%s warning: %s: %s.\n",
756e2eeea75SSimon J. Gerraty 			    progname, path, strerror(errno));
7573955d011SMarcel Moolenaar 		} else {
7582c3632d1SSimon J. Gerraty 			snprintf(objdir, sizeof objdir, "%s", path);
7593841c287SSimon J. Gerraty 			Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
7603955d011SMarcel Moolenaar 			setenv("PWD", objdir, 1);
7613955d011SMarcel Moolenaar 			Dir_InitDot();
762e2eeea75SSimon J. Gerraty 			purge_relative_cached_realpaths();
7633955d011SMarcel Moolenaar 			rc = TRUE;
764956e45f6SSimon J. Gerraty 			if (opts.enterFlag && strcmp(objdir, curdir) != 0)
7654c620fe5SSimon J. Gerraty 				enterFlagObj = TRUE;
7663955d011SMarcel Moolenaar 		}
7673955d011SMarcel Moolenaar 	}
7683955d011SMarcel Moolenaar 
7693955d011SMarcel Moolenaar 	return rc;
7703955d011SMarcel Moolenaar }
7713955d011SMarcel Moolenaar 
77245447996SSimon J. Gerraty static Boolean
773e2eeea75SSimon J. Gerraty SetVarObjdir(Boolean writable, const char *var, const char *suffix)
77445447996SSimon J. Gerraty {
775*06b9b3e0SSimon J. Gerraty 	FStr path = Var_Value(var, VAR_CMDLINE);
776*06b9b3e0SSimon J. Gerraty 	FStr xpath;
777b46b9039SSimon J. Gerraty 
778*06b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
779*06b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
78045447996SSimon J. Gerraty 		return FALSE;
7812c3632d1SSimon J. Gerraty 	}
78245447996SSimon J. Gerraty 
783b46b9039SSimon J. Gerraty 	/* expand variable substitutions */
784*06b9b3e0SSimon J. Gerraty 	xpath = FStr_InitRefer(path.str);
785*06b9b3e0SSimon J. Gerraty 	if (strchr(path.str, '$') != 0) {
786*06b9b3e0SSimon J. Gerraty 		char *expanded;
787*06b9b3e0SSimon J. Gerraty 		(void)Var_Subst(path.str, VAR_GLOBAL, VARE_WANTRES, &expanded);
788956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
789*06b9b3e0SSimon J. Gerraty 		xpath = FStr_InitOwn(expanded);
790956e45f6SSimon J. Gerraty 	}
791b46b9039SSimon J. Gerraty 
792*06b9b3e0SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix);
793b46b9039SSimon J. Gerraty 
794*06b9b3e0SSimon J. Gerraty 	FStr_Done(&xpath);
795*06b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
79645447996SSimon J. Gerraty 	return TRUE;
79745447996SSimon J. Gerraty }
79845447996SSimon J. Gerraty 
799*06b9b3e0SSimon J. Gerraty /*
800*06b9b3e0SSimon J. Gerraty  * Splits str into words, adding them to the list.
801*06b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
802*06b9b3e0SSimon J. Gerraty  */
8033955d011SMarcel Moolenaar int
804e2eeea75SSimon J. Gerraty str2Lst_Append(StringList *lp, char *str)
8053955d011SMarcel Moolenaar {
8063955d011SMarcel Moolenaar 	char *cp;
8073955d011SMarcel Moolenaar 	int n;
8083955d011SMarcel Moolenaar 
809e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
8103955d011SMarcel Moolenaar 
811*06b9b3e0SSimon J. Gerraty 	for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) {
8122c3632d1SSimon J. Gerraty 		Lst_Append(lp, cp);
8133955d011SMarcel Moolenaar 		n++;
8143955d011SMarcel Moolenaar 	}
8153841c287SSimon J. Gerraty 	return n;
8163955d011SMarcel Moolenaar }
8173955d011SMarcel Moolenaar 
8183955d011SMarcel Moolenaar #ifdef SIGINFO
8193955d011SMarcel Moolenaar /*ARGSUSED*/
8203955d011SMarcel Moolenaar static void
8213955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED)
8223955d011SMarcel Moolenaar {
8233955d011SMarcel Moolenaar 	char dir[MAXPATHLEN];
8243955d011SMarcel Moolenaar 	char str[2 * MAXPATHLEN];
8253955d011SMarcel Moolenaar 	int len;
826e2eeea75SSimon J. Gerraty 	if (getcwd(dir, sizeof dir) == NULL)
8273955d011SMarcel Moolenaar 		return;
828e2eeea75SSimon J. Gerraty 	len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
8293955d011SMarcel Moolenaar 	if (len > 0)
8303955d011SMarcel Moolenaar 		(void)write(STDERR_FILENO, str, (size_t)len);
8313955d011SMarcel Moolenaar }
8323955d011SMarcel Moolenaar #endif
8333955d011SMarcel Moolenaar 
834*06b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */
835*06b9b3e0SSimon J. Gerraty static void
836*06b9b3e0SSimon J. Gerraty MakeMode(void)
8373955d011SMarcel Moolenaar {
838*06b9b3e0SSimon J. Gerraty 	FStr mode = FStr_InitRefer(NULL);
8393955d011SMarcel Moolenaar 
840*06b9b3e0SSimon J. Gerraty 	if (mode.str == NULL) {
841*06b9b3e0SSimon J. Gerraty 		char *expanded;
842956e45f6SSimon J. Gerraty 		(void)Var_Subst("${" MAKE_MODE ":tl}",
843*06b9b3e0SSimon J. Gerraty 		    VAR_GLOBAL, VARE_WANTRES, &expanded);
844956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
845*06b9b3e0SSimon J. Gerraty 		mode = FStr_InitOwn(expanded);
846956e45f6SSimon J. Gerraty 	}
8473955d011SMarcel Moolenaar 
848*06b9b3e0SSimon J. Gerraty 	if (mode.str[0] != '\0') {
849*06b9b3e0SSimon J. Gerraty 		if (strstr(mode.str, "compat") != NULL) {
850956e45f6SSimon J. Gerraty 			opts.compatMake = TRUE;
8513955d011SMarcel Moolenaar 			forceJobs = FALSE;
8523955d011SMarcel Moolenaar 		}
8533955d011SMarcel Moolenaar #if USE_META
854*06b9b3e0SSimon J. Gerraty 		if (strstr(mode.str, "meta") != NULL)
855*06b9b3e0SSimon J. Gerraty 			meta_mode_init(mode.str);
8563955d011SMarcel Moolenaar #endif
8573955d011SMarcel Moolenaar 	}
858be19d90bSSimon J. Gerraty 
859*06b9b3e0SSimon J. Gerraty 	FStr_Done(&mode);
8603955d011SMarcel Moolenaar }
8613955d011SMarcel Moolenaar 
8628695518cSSimon J. Gerraty static void
863956e45f6SSimon J. Gerraty PrintVar(const char *varname, Boolean expandVars)
864956e45f6SSimon J. Gerraty {
865*06b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
866956e45f6SSimon J. Gerraty 		char *evalue;
867956e45f6SSimon J. Gerraty 		(void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue);
868956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
869956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
870956e45f6SSimon J. Gerraty 		bmake_free(evalue);
871956e45f6SSimon J. Gerraty 
872956e45f6SSimon J. Gerraty 	} else if (expandVars) {
873956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
874956e45f6SSimon J. Gerraty 		char *evalue;
875956e45f6SSimon J. Gerraty 		(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue);
876956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
877956e45f6SSimon J. Gerraty 		free(expr);
878956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
879956e45f6SSimon J. Gerraty 		bmake_free(evalue);
880956e45f6SSimon J. Gerraty 
881956e45f6SSimon J. Gerraty 	} else {
882*06b9b3e0SSimon J. Gerraty 		FStr value = Var_Value(varname, VAR_GLOBAL);
883*06b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
884*06b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
885956e45f6SSimon J. Gerraty 	}
886956e45f6SSimon J. Gerraty }
887956e45f6SSimon J. Gerraty 
888e2eeea75SSimon J. Gerraty /*
889e2eeea75SSimon J. Gerraty  * Return a Boolean based on a variable.
890e2eeea75SSimon J. Gerraty  *
891e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
892e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
893e2eeea75SSimon J. Gerraty  * is FALSE, otherwise TRUE.
894e2eeea75SSimon J. Gerraty  */
895e2eeea75SSimon J. Gerraty Boolean
896e2eeea75SSimon J. Gerraty GetBooleanVar(const char *varname, Boolean fallback)
897e2eeea75SSimon J. Gerraty {
898e2eeea75SSimon J. Gerraty 	char *expr = str_concat3("${", varname, ":U}");
899e2eeea75SSimon J. Gerraty 	char *value;
900e2eeea75SSimon J. Gerraty 	Boolean res;
901e2eeea75SSimon J. Gerraty 
902e2eeea75SSimon J. Gerraty 	(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value);
903e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
904e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
905e2eeea75SSimon J. Gerraty 	free(value);
906e2eeea75SSimon J. Gerraty 	free(expr);
907e2eeea75SSimon J. Gerraty 	return res;
908e2eeea75SSimon J. Gerraty }
909e2eeea75SSimon J. Gerraty 
910956e45f6SSimon J. Gerraty static void
9118695518cSSimon J. Gerraty doPrintVars(void)
9128695518cSSimon J. Gerraty {
913956e45f6SSimon J. Gerraty 	StringListNode *ln;
9148695518cSSimon J. Gerraty 	Boolean expandVars;
9158695518cSSimon J. Gerraty 
916e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
9178695518cSSimon J. Gerraty 		expandVars = TRUE;
918956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
9198695518cSSimon J. Gerraty 		expandVars = FALSE;
9208695518cSSimon J. Gerraty 	else
921e2eeea75SSimon J. Gerraty 		expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE);
9228695518cSSimon J. Gerraty 
923*06b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
924956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
925956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
9268695518cSSimon J. Gerraty 	}
9278695518cSSimon J. Gerraty }
9288695518cSSimon J. Gerraty 
9298695518cSSimon J. Gerraty static Boolean
9308695518cSSimon J. Gerraty runTargets(void)
9318695518cSSimon J. Gerraty {
932*06b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
9338695518cSSimon J. Gerraty 	Boolean outOfDate;	/* FALSE if all targets up to date */
9348695518cSSimon J. Gerraty 
9358695518cSSimon J. Gerraty 	/*
9368695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9378695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9388695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9398695518cSSimon J. Gerraty 	 * to create.
9408695518cSSimon J. Gerraty 	 */
941*06b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
942*06b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9438695518cSSimon J. Gerraty 	else
944*06b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9458695518cSSimon J. Gerraty 
946956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9478695518cSSimon J. Gerraty 		/*
9488695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9498695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9508695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9518695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9528695518cSSimon J. Gerraty 		 * it exist).
9538695518cSSimon J. Gerraty 		 */
954956e45f6SSimon J. Gerraty 		if (!opts.queryFlag) {
9558695518cSSimon J. Gerraty 			Job_Init();
9568695518cSSimon J. Gerraty 			jobsRunning = TRUE;
9578695518cSSimon J. Gerraty 		}
9588695518cSSimon J. Gerraty 
9598695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
960*06b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9618695518cSSimon J. Gerraty 	} else {
9628695518cSSimon J. Gerraty 		/*
9638695518cSSimon J. Gerraty 		 * Compat_Init will take care of creating all the
9648695518cSSimon J. Gerraty 		 * targets as well as initializing the module.
9658695518cSSimon J. Gerraty 		 */
966*06b9b3e0SSimon J. Gerraty 		Compat_Run(&targs);
9678695518cSSimon J. Gerraty 		outOfDate = FALSE;
9688695518cSSimon J. Gerraty 	}
969*06b9b3e0SSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the nodes. */
9708695518cSSimon J. Gerraty 	return outOfDate;
9718695518cSSimon J. Gerraty }
9728695518cSSimon J. Gerraty 
973956e45f6SSimon J. Gerraty /*
974956e45f6SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be
975956e45f6SSimon J. Gerraty  * created. If none specified, make the variable empty -- the parser
976956e45f6SSimon J. Gerraty  * will fill the thing in with the default or .MAIN target.
977956e45f6SSimon J. Gerraty  */
978956e45f6SSimon J. Gerraty static void
979956e45f6SSimon J. Gerraty InitVarTargets(void)
980956e45f6SSimon J. Gerraty {
981956e45f6SSimon J. Gerraty 	StringListNode *ln;
982956e45f6SSimon J. Gerraty 
983*06b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
984956e45f6SSimon J. Gerraty 		Var_Set(".TARGETS", "", VAR_GLOBAL);
985956e45f6SSimon J. Gerraty 		return;
986956e45f6SSimon J. Gerraty 	}
987956e45f6SSimon J. Gerraty 
988*06b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
989956e45f6SSimon J. Gerraty 		char *name = ln->datum;
990956e45f6SSimon J. Gerraty 		Var_Append(".TARGETS", name, VAR_GLOBAL);
991956e45f6SSimon J. Gerraty 	}
992956e45f6SSimon J. Gerraty }
993956e45f6SSimon J. Gerraty 
994956e45f6SSimon J. Gerraty static void
995956e45f6SSimon J. Gerraty InitRandom(void)
996956e45f6SSimon J. Gerraty {
997956e45f6SSimon J. Gerraty 	struct timeval tv;
998956e45f6SSimon J. Gerraty 
999956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
1000956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
1001956e45f6SSimon J. Gerraty }
1002956e45f6SSimon J. Gerraty 
1003956e45f6SSimon J. Gerraty static const char *
1004e2eeea75SSimon J. Gerraty InitVarMachine(const struct utsname *utsname)
1005956e45f6SSimon J. Gerraty {
1006956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
1007e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
1008956e45f6SSimon J. Gerraty #else
1009956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
1010e2eeea75SSimon J. Gerraty 
1011956e45f6SSimon J. Gerraty 	if (machine != NULL)
1012956e45f6SSimon J. Gerraty 		return machine;
1013956e45f6SSimon J. Gerraty 
1014e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
1015956e45f6SSimon J. Gerraty 	return utsname->machine;
1016e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
1017956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
1018956e45f6SSimon J. Gerraty #else
1019956e45f6SSimon J. Gerraty 	return "unknown";
1020956e45f6SSimon J. Gerraty #endif
1021956e45f6SSimon J. Gerraty #endif
1022956e45f6SSimon J. Gerraty }
1023956e45f6SSimon J. Gerraty 
1024956e45f6SSimon J. Gerraty static const char *
1025e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
1026956e45f6SSimon J. Gerraty {
1027e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
1028e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
1029e2eeea75SSimon J. Gerraty #else
1030956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
1031956e45f6SSimon J. Gerraty 	if (env != NULL)
1032956e45f6SSimon J. Gerraty 		return env;
1033956e45f6SSimon J. Gerraty 
1034956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
1035956e45f6SSimon J. Gerraty 	{
1036956e45f6SSimon J. Gerraty 		struct utsname utsname;
1037e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
1038956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1039e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1040956e45f6SSimon J. Gerraty 
1041*06b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
1042*06b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
1043*06b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
1044*06b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1045956e45f6SSimon J. Gerraty 			exit(2);
1046956e45f6SSimon J. Gerraty 		}
1047956e45f6SSimon J. Gerraty 
1048956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1049956e45f6SSimon J. Gerraty 	}
1050e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1051e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1052e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1053956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1054956e45f6SSimon J. Gerraty #else
1055956e45f6SSimon J. Gerraty 	return "unknown";
1056956e45f6SSimon J. Gerraty #endif
1057956e45f6SSimon J. Gerraty #endif
1058956e45f6SSimon J. Gerraty }
1059956e45f6SSimon J. Gerraty 
1060956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1061956e45f6SSimon J. Gerraty /*
1062956e45f6SSimon J. Gerraty  * All this code is so that we know where we are when we start up
1063956e45f6SSimon J. Gerraty  * on a different machine with pmake.
1064956e45f6SSimon J. Gerraty  *
1065956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1066956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1067956e45f6SSimon J. Gerraty  * here.  Ie sitting at a shell prompt (shell that provides $PWD)
1068956e45f6SSimon J. Gerraty  * or via subdir.mk in which case its likely a shell which does
1069956e45f6SSimon J. Gerraty  * not provide it.
1070956e45f6SSimon J. Gerraty  *
1071956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1072956e45f6SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression.
1073956e45f6SSimon J. Gerraty  */
1074956e45f6SSimon J. Gerraty static void
1075956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1076956e45f6SSimon J. Gerraty {
1077956e45f6SSimon J. Gerraty 	char *pwd;
1078*06b9b3e0SSimon J. Gerraty 	FStr prefix, makeobjdir;
1079956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1080956e45f6SSimon J. Gerraty 
1081956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1082956e45f6SSimon J. Gerraty 		return;
1083956e45f6SSimon J. Gerraty 
1084*06b9b3e0SSimon J. Gerraty 	prefix = Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE);
1085*06b9b3e0SSimon J. Gerraty 	if (prefix.str != NULL) {
1086*06b9b3e0SSimon J. Gerraty 		FStr_Done(&prefix);
1087956e45f6SSimon J. Gerraty 		return;
1088956e45f6SSimon J. Gerraty 	}
1089956e45f6SSimon J. Gerraty 
1090*06b9b3e0SSimon J. Gerraty 	makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE);
1091*06b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1092956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1093956e45f6SSimon J. Gerraty 
1094956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1095956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1096956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
1097956e45f6SSimon J. Gerraty 		(void)strncpy(curdir, pwd, MAXPATHLEN);
1098956e45f6SSimon J. Gerraty 
1099956e45f6SSimon J. Gerraty ignore_pwd:
1100*06b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1101956e45f6SSimon J. Gerraty }
1102956e45f6SSimon J. Gerraty #endif
1103956e45f6SSimon J. Gerraty 
1104956e45f6SSimon J. Gerraty /*
1105956e45f6SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that,
1106956e45f6SSimon J. Gerraty  * MAKEOBJDIR is set in the environment, try only that value
1107956e45f6SSimon J. Gerraty  * and fall back to .CURDIR if it does not exist.
1108956e45f6SSimon J. Gerraty  *
1109956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
1110956e45f6SSimon J. Gerraty  * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none
1111956e45f6SSimon J. Gerraty  * of these paths exist, just use .CURDIR.
1112956e45f6SSimon J. Gerraty  */
1113956e45f6SSimon J. Gerraty static void
1114956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1115956e45f6SSimon J. Gerraty {
1116e2eeea75SSimon J. Gerraty 	Boolean writable;
1117956e45f6SSimon J. Gerraty 
1118*06b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1119e2eeea75SSimon J. Gerraty 	writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE);
1120e2eeea75SSimon J. Gerraty 	(void)Main_SetObjdir(FALSE, "%s", curdir);
1121e2eeea75SSimon J. Gerraty 
1122e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1123e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1124e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1125e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1126e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1127e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1128956e45f6SSimon J. Gerraty }
1129956e45f6SSimon J. Gerraty 
1130956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1131956e45f6SSimon J. Gerraty static void
1132956e45f6SSimon J. Gerraty UnlimitFiles(void)
1133956e45f6SSimon J. Gerraty {
1134956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
1135956e45f6SSimon J. Gerraty 	struct rlimit rl;
1136956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1137956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
1138956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1139956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1140956e45f6SSimon J. Gerraty 	}
1141956e45f6SSimon J. Gerraty #endif
1142956e45f6SSimon J. Gerraty }
1143956e45f6SSimon J. Gerraty 
1144956e45f6SSimon J. Gerraty static void
1145956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1146956e45f6SSimon J. Gerraty {
1147*06b9b3e0SSimon J. Gerraty 	opts.compatMake = FALSE;
1148*06b9b3e0SSimon J. Gerraty 	opts.debug = DEBUG_NONE;
1149956e45f6SSimon J. Gerraty 	/* opts.debug_file has been initialized earlier */
1150*06b9b3e0SSimon J. Gerraty 	opts.strict = FALSE;
1151956e45f6SSimon J. Gerraty 	opts.debugVflag = FALSE;
1152956e45f6SSimon J. Gerraty 	opts.checkEnvFirst = FALSE;
1153*06b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1154956e45f6SSimon J. Gerraty 	opts.ignoreErrors = FALSE;	/* Pay attention to non-zero returns */
1155*06b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1156956e45f6SSimon J. Gerraty 	opts.keepgoing = FALSE;		/* Stop on error */
1157956e45f6SSimon J. Gerraty 	opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
1158956e45f6SSimon J. Gerraty 	opts.noExecute = FALSE;		/* Execute all commands */
1159*06b9b3e0SSimon J. Gerraty 	opts.queryFlag = FALSE;
1160956e45f6SSimon J. Gerraty 	opts.noBuiltins = FALSE;	/* Read the built-in rules */
1161956e45f6SSimon J. Gerraty 	opts.beSilent = FALSE;		/* Print commands as executed */
1162*06b9b3e0SSimon J. Gerraty 	opts.touchFlag = FALSE;
1163e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
1164*06b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1165956e45f6SSimon J. Gerraty 	opts.parseWarnFatal = FALSE;
1166956e45f6SSimon J. Gerraty 	opts.enterFlag = FALSE;
1167956e45f6SSimon J. Gerraty 	opts.varNoExportEnv = FALSE;
1168*06b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1169956e45f6SSimon J. Gerraty }
1170956e45f6SSimon J. Gerraty 
1171*06b9b3e0SSimon J. Gerraty /*
1172*06b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1173956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1174956e45f6SSimon J. Gerraty  *
1175956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
1176*06b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
1177*06b9b3e0SSimon J. Gerraty  */
1178956e45f6SSimon J. Gerraty static void
1179956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1180956e45f6SSimon J. Gerraty {
1181956e45f6SSimon J. Gerraty 	const char *make = argv0;
1182956e45f6SSimon J. Gerraty 
1183956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1184956e45f6SSimon J. Gerraty 		char pathbuf[MAXPATHLEN];
1185*06b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1186956e45f6SSimon J. Gerraty 		struct stat st;
1187*06b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
1188*06b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
1189*06b9b3e0SSimon J. Gerraty 			make = abspath;
1190956e45f6SSimon J. Gerraty 	}
1191956e45f6SSimon J. Gerraty 
1192956e45f6SSimon J. Gerraty 	Var_Set("MAKE", make, VAR_GLOBAL);
1193956e45f6SSimon J. Gerraty 	Var_Set(".MAKE", make, VAR_GLOBAL);
1194956e45f6SSimon J. Gerraty }
1195956e45f6SSimon J. Gerraty 
1196*06b9b3e0SSimon J. Gerraty /*
1197*06b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
1198*06b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
1199*06b9b3e0SSimon J. Gerraty  */
1200956e45f6SSimon J. Gerraty static void
1201956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1202956e45f6SSimon J. Gerraty {
1203956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1204956e45f6SSimon J. Gerraty 	char *start, *cp;
1205956e45f6SSimon J. Gerraty 
1206956e45f6SSimon J. Gerraty 	/*
1207956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1208956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1209956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1210956e45f6SSimon J. Gerraty 	 */
1211956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1212956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1213956e45f6SSimon J. Gerraty 	else
1214956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1215956e45f6SSimon J. Gerraty 
1216956e45f6SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = cp) {
1217956e45f6SSimon J. Gerraty 		for (cp = start; *cp != '\0' && *cp != ':'; cp++)
1218956e45f6SSimon J. Gerraty 			continue;
1219e2eeea75SSimon J. Gerraty 		if (*cp == ':')
1220956e45f6SSimon J. Gerraty 			*cp++ = '\0';
1221e2eeea75SSimon J. Gerraty 
1222956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1223e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1224956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1225956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1226956e45f6SSimon J. Gerraty 				(void)Dir_AddDir(defSysIncPath, dir);
1227956e45f6SSimon J. Gerraty 				free(dir);
1228956e45f6SSimon J. Gerraty 			}
1229e2eeea75SSimon J. Gerraty 		} else {
1230e2eeea75SSimon J. Gerraty 			(void)Dir_AddDir(defSysIncPath, start);
1231956e45f6SSimon J. Gerraty 		}
1232956e45f6SSimon J. Gerraty 	}
1233956e45f6SSimon J. Gerraty 
1234956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1235956e45f6SSimon J. Gerraty 		free(syspath);
1236956e45f6SSimon J. Gerraty }
1237956e45f6SSimon J. Gerraty 
1238956e45f6SSimon J. Gerraty static void
1239956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1240956e45f6SSimon J. Gerraty {
1241e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1242*06b9b3e0SSimon J. Gerraty 	StringList sysMkPath = LST_INIT;
1243e2eeea75SSimon J. Gerraty 
1244956e45f6SSimon J. Gerraty 	Dir_Expand(_PATH_DEFSYSMK,
1245956e45f6SSimon J. Gerraty 	    Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath,
1246*06b9b3e0SSimon J. Gerraty 	    &sysMkPath);
1247*06b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkPath))
1248956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1249e2eeea75SSimon J. Gerraty 
1250*06b9b3e0SSimon J. Gerraty 	for (ln = sysMkPath.first; ln != NULL; ln = ln->next)
1251e2eeea75SSimon J. Gerraty 		if (ReadMakefile(ln->datum) == 0)
1252e2eeea75SSimon J. Gerraty 			break;
1253e2eeea75SSimon J. Gerraty 
1254e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1255e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1256*06b9b3e0SSimon J. Gerraty 		    progname, (const char *)sysMkPath.first->datum);
1257e2eeea75SSimon J. Gerraty 
1258e2eeea75SSimon J. Gerraty 	/* Free the list but not the actual filenames since these may still
1259e2eeea75SSimon J. Gerraty 	 * be used in GNodes. */
1260*06b9b3e0SSimon J. Gerraty 	Lst_Done(&sysMkPath);
1261956e45f6SSimon J. Gerraty }
1262956e45f6SSimon J. Gerraty 
1263956e45f6SSimon J. Gerraty static void
1264956e45f6SSimon J. Gerraty InitMaxJobs(void)
1265956e45f6SSimon J. Gerraty {
1266956e45f6SSimon J. Gerraty 	char *value;
1267956e45f6SSimon J. Gerraty 	int n;
1268956e45f6SSimon J. Gerraty 
1269956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1270956e45f6SSimon J. Gerraty 	    !Var_Exists(".MAKE.JOBS", VAR_GLOBAL))
1271956e45f6SSimon J. Gerraty 		return;
1272956e45f6SSimon J. Gerraty 
1273956e45f6SSimon J. Gerraty 	(void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value);
1274956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1275956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1276956e45f6SSimon J. Gerraty 	if (n < 1) {
1277956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1278956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1279956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1280956e45f6SSimon J. Gerraty 		    progname);
1281*06b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1282956e45f6SSimon J. Gerraty 	}
1283956e45f6SSimon J. Gerraty 
1284956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1285956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
1286956e45f6SSimon J. Gerraty 		Var_Append(MAKEFLAGS, value, VAR_GLOBAL);
1287956e45f6SSimon J. Gerraty 	}
1288956e45f6SSimon J. Gerraty 
1289956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1290956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1291956e45f6SSimon J. Gerraty 	forceJobs = TRUE;
1292956e45f6SSimon J. Gerraty 	free(value);
1293956e45f6SSimon J. Gerraty }
1294956e45f6SSimon J. Gerraty 
1295956e45f6SSimon J. Gerraty /*
1296956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1297956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1298956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1299956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1300956e45f6SSimon J. Gerraty  */
1301956e45f6SSimon J. Gerraty static void
1302956e45f6SSimon J. Gerraty InitVpath(void)
1303956e45f6SSimon J. Gerraty {
1304956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1305956e45f6SSimon J. Gerraty 	if (!Var_Exists("VPATH", VAR_CMDLINE))
1306956e45f6SSimon J. Gerraty 		return;
1307956e45f6SSimon J. Gerraty 
1308956e45f6SSimon J. Gerraty 	(void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath);
1309956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1310956e45f6SSimon J. Gerraty 	path = vpath;
1311956e45f6SSimon J. Gerraty 	do {
1312956e45f6SSimon J. Gerraty 		char *cp;
1313956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1314956e45f6SSimon J. Gerraty 		for (cp = path; *cp != ':' && *cp != '\0'; cp++)
1315956e45f6SSimon J. Gerraty 			continue;
1316956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1317956e45f6SSimon J. Gerraty 		savec = *cp;
1318956e45f6SSimon J. Gerraty 		*cp = '\0';
1319956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1320*06b9b3e0SSimon J. Gerraty 		(void)Dir_AddDir(&dirSearchPath, path);
1321956e45f6SSimon J. Gerraty 		*cp = savec;
1322956e45f6SSimon J. Gerraty 		path = cp + 1;
1323956e45f6SSimon J. Gerraty 	} while (savec == ':');
1324956e45f6SSimon J. Gerraty 	free(vpath);
1325956e45f6SSimon J. Gerraty }
1326956e45f6SSimon J. Gerraty 
1327956e45f6SSimon J. Gerraty static void
1328e2eeea75SSimon J. Gerraty ReadAllMakefiles(StringList *makefiles)
1329956e45f6SSimon J. Gerraty {
1330956e45f6SSimon J. Gerraty 	StringListNode *ln;
1331956e45f6SSimon J. Gerraty 
1332e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1333e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
1334e2eeea75SSimon J. Gerraty 		if (ReadMakefile(fname) != 0)
1335e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1336956e45f6SSimon J. Gerraty 	}
1337956e45f6SSimon J. Gerraty }
1338956e45f6SSimon J. Gerraty 
1339956e45f6SSimon J. Gerraty static void
1340e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1341956e45f6SSimon J. Gerraty {
1342e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1343e2eeea75SSimon J. Gerraty 	char *prefs;
1344956e45f6SSimon J. Gerraty 
1345e2eeea75SSimon J. Gerraty 	(void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}",
1346e2eeea75SSimon J. Gerraty 	    VAR_CMDLINE, VARE_WANTRES, &prefs);
1347e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1348956e45f6SSimon J. Gerraty 
1349e2eeea75SSimon J. Gerraty 	/* XXX: This should use a local list instead of opts.makefiles
1350e2eeea75SSimon J. Gerraty 	 * since these makefiles do not come from the command line.  They
1351e2eeea75SSimon J. Gerraty 	 * also have different semantics in that only the first file that
1352e2eeea75SSimon J. Gerraty 	 * is found is processed.  See ReadAllMakefiles. */
1353*06b9b3e0SSimon J. Gerraty 	(void)str2Lst_Append(&opts.makefiles, prefs);
1354956e45f6SSimon J. Gerraty 
1355*06b9b3e0SSimon J. Gerraty 	for (ln = opts.makefiles.first; ln != NULL; ln = ln->next)
1356e2eeea75SSimon J. Gerraty 		if (ReadMakefile(ln->datum) == 0)
1357e2eeea75SSimon J. Gerraty 			break;
1358956e45f6SSimon J. Gerraty 
1359e2eeea75SSimon J. Gerraty 	free(prefs);
1360956e45f6SSimon J. Gerraty }
1361956e45f6SSimon J. Gerraty 
1362*06b9b3e0SSimon J. Gerraty /*
1363*06b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1364e2eeea75SSimon J. Gerraty  * Initialize a few modules.
1365*06b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
1366*06b9b3e0SSimon J. Gerraty  */
1367e2eeea75SSimon J. Gerraty static void
1368e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13693955d011SMarcel Moolenaar {
1370956e45f6SSimon J. Gerraty 	struct stat sa;
1371956e45f6SSimon J. Gerraty 	const char *machine;
1372956e45f6SSimon J. Gerraty 	const char *machine_arch;
13733955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13743955d011SMarcel Moolenaar 	struct utsname utsname;
13753955d011SMarcel Moolenaar 
13763955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1377956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13783955d011SMarcel Moolenaar 
1379e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1380e2eeea75SSimon J. Gerraty 
13813955d011SMarcel Moolenaar #ifdef SIGINFO
13823955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13833955d011SMarcel Moolenaar #endif
1384956e45f6SSimon J. Gerraty 
1385956e45f6SSimon J. Gerraty 	InitRandom();
13863955d011SMarcel Moolenaar 
1387*06b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1388956e45f6SSimon J. Gerraty 
1389956e45f6SSimon J. Gerraty 	UnlimitFiles();
13903955d011SMarcel Moolenaar 
13911748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13921748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13931748de26SSimon J. Gerraty 		    strerror(errno));
13941748de26SSimon J. Gerraty 		exit(2);
13951748de26SSimon J. Gerraty 	}
13961748de26SSimon J. Gerraty 
13973955d011SMarcel Moolenaar 	/*
13983955d011SMarcel Moolenaar 	 * Get the name of this type of MACHINE from utsname
13993955d011SMarcel Moolenaar 	 * so we can share an executable for similar machines.
14003955d011SMarcel Moolenaar 	 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
14013955d011SMarcel Moolenaar 	 *
14023955d011SMarcel Moolenaar 	 * Note that both MACHINE and MACHINE_ARCH are decided at
14033955d011SMarcel Moolenaar 	 * run-time.
14043955d011SMarcel Moolenaar 	 */
1405e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1406e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
14073955d011SMarcel Moolenaar 
14083955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
14093955d011SMarcel Moolenaar 
14103955d011SMarcel Moolenaar 	/*
14113955d011SMarcel Moolenaar 	 * Just in case MAKEOBJDIR wants us to do something tricky.
14123955d011SMarcel Moolenaar 	 */
1413e2eeea75SSimon J. Gerraty 	Targ_Init();
1414e2eeea75SSimon J. Gerraty 	Var_Init();
14153841c287SSimon J. Gerraty 	Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL);
14163841c287SSimon J. Gerraty 	Var_Set("MACHINE", machine, VAR_GLOBAL);
14173841c287SSimon J. Gerraty 	Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
14183955d011SMarcel Moolenaar #ifdef MAKE_VERSION
14193841c287SSimon J. Gerraty 	Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL);
14203955d011SMarcel Moolenaar #endif
14213841c287SSimon J. Gerraty 	Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */
14223955d011SMarcel Moolenaar 	/*
14233955d011SMarcel Moolenaar 	 * This is the traditional preference for makefiles.
14243955d011SMarcel Moolenaar 	 */
14253955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
14263955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
14273955d011SMarcel Moolenaar #endif
1428e2eeea75SSimon J. Gerraty 	Var_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, VAR_GLOBAL);
14293841c287SSimon J. Gerraty 	Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL);
14303955d011SMarcel Moolenaar 
1431956e45f6SSimon J. Gerraty 	CmdOpts_Init();
14323955d011SMarcel Moolenaar 	allPrecious = FALSE;	/* Remove targets when interrupted */
143345447996SSimon J. Gerraty 	deleteOnError = FALSE;	/* Historical default behavior */
14343955d011SMarcel Moolenaar 	jobsRunning = FALSE;
14353955d011SMarcel Moolenaar 
1436956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
14373955d011SMarcel Moolenaar 	ignorePWD = FALSE;
14383955d011SMarcel Moolenaar 
14393955d011SMarcel Moolenaar 	/*
14403955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
14413955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
14423955d011SMarcel Moolenaar 	 * command line
14433955d011SMarcel Moolenaar 	 */
14443955d011SMarcel Moolenaar 
14453955d011SMarcel Moolenaar 	/*
14463955d011SMarcel Moolenaar 	 * Initialize various variables.
14473955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
14483955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14493955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14503955d011SMarcel Moolenaar 	 */
14513955d011SMarcel Moolenaar 	Parse_Init();
1452956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
14533841c287SSimon J. Gerraty 	Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
14543841c287SSimon J. Gerraty 	Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL);
14553841c287SSimon J. Gerraty 	Var_Set("MFLAGS", "", VAR_GLOBAL);
14563841c287SSimon J. Gerraty 	Var_Set(".ALLTARGETS", "", VAR_GLOBAL);
145751ee2c1cSSimon J. Gerraty 	/* some makefiles need to know this */
1458956e45f6SSimon J. Gerraty 	Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE);
14593955d011SMarcel Moolenaar 
1460e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14613955d011SMarcel Moolenaar 	{
1462e2eeea75SSimon J. Gerraty 		char tmp[64], *ep = getenv(MAKE_LEVEL_ENV);
14633955d011SMarcel Moolenaar 
1464e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
146551ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
146651ee2c1cSSimon J. Gerraty 			makelevel = 0;
1467e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%d", makelevel);
14683841c287SSimon J. Gerraty 		Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
1469e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", myPid);
14703841c287SSimon J. Gerraty 		Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
1471e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getppid());
14723841c287SSimon J. Gerraty 		Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
1473*06b9b3e0SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getuid());
1474*06b9b3e0SSimon J. Gerraty 		Var_Set(".MAKE.UID", tmp, VAR_GLOBAL);
1475*06b9b3e0SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getgid());
1476*06b9b3e0SSimon J. Gerraty 		Var_Set(".MAKE.GID", tmp, VAR_GLOBAL);
14773955d011SMarcel Moolenaar 	}
147851ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
147951ee2c1cSSimon J. Gerraty 		char pn[1024];
1480e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
148151ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
148251ee2c1cSSimon J. Gerraty 	}
14833955d011SMarcel Moolenaar 
14841748de26SSimon J. Gerraty #ifdef USE_META
14851748de26SSimon J. Gerraty 	meta_init();
14861748de26SSimon J. Gerraty #endif
14872c3632d1SSimon J. Gerraty 	Dir_Init();
14881ce939a7SSimon J. Gerraty 
14893955d011SMarcel Moolenaar 	/*
14903955d011SMarcel Moolenaar 	 * First snag any flags out of the MAKE environment variable.
14913955d011SMarcel Moolenaar 	 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
14923955d011SMarcel Moolenaar 	 * in a different format).
14933955d011SMarcel Moolenaar 	 */
14943955d011SMarcel Moolenaar #ifdef POSIX
1495956e45f6SSimon J. Gerraty 	{
1496956e45f6SSimon J. Gerraty 		char *p1 = explode(getenv("MAKEFLAGS"));
149751ee2c1cSSimon J. Gerraty 		Main_ParseArgLine(p1);
149851ee2c1cSSimon J. Gerraty 		free(p1);
1499956e45f6SSimon J. Gerraty 	}
15003955d011SMarcel Moolenaar #else
15013955d011SMarcel Moolenaar 	Main_ParseArgLine(getenv("MAKE"));
15023955d011SMarcel Moolenaar #endif
15033955d011SMarcel Moolenaar 
15043955d011SMarcel Moolenaar 	/*
15053955d011SMarcel Moolenaar 	 * Find where we are (now).
15063955d011SMarcel Moolenaar 	 * We take care of PWD for the automounter below...
15073955d011SMarcel Moolenaar 	 */
15083955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
15093955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
15103955d011SMarcel Moolenaar 		    progname, strerror(errno));
15113955d011SMarcel Moolenaar 		exit(2);
15123955d011SMarcel Moolenaar 	}
15133955d011SMarcel Moolenaar 
15143955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
15153955d011SMarcel Moolenaar 
1516956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
151751ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
151851ee2c1cSSimon J. Gerraty 
15193955d011SMarcel Moolenaar 	/*
15203955d011SMarcel Moolenaar 	 * Verify that cwd is sane.
15213955d011SMarcel Moolenaar 	 */
15223955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
15233955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
15243955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
15253955d011SMarcel Moolenaar 		exit(2);
15263955d011SMarcel Moolenaar 	}
15273955d011SMarcel Moolenaar 
15283955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1529956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
15303955d011SMarcel Moolenaar #endif
15313841c287SSimon J. Gerraty 	Var_Set(".CURDIR", curdir, VAR_GLOBAL);
15323955d011SMarcel Moolenaar 
1533956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
15343955d011SMarcel Moolenaar 
15353955d011SMarcel Moolenaar 	/*
15363955d011SMarcel Moolenaar 	 * Initialize archive, target and suffix modules in preparation for
15373955d011SMarcel Moolenaar 	 * parsing the makefile(s)
15383955d011SMarcel Moolenaar 	 */
15393955d011SMarcel Moolenaar 	Arch_Init();
15403955d011SMarcel Moolenaar 	Suff_Init();
15413955d011SMarcel Moolenaar 	Trace_Init(tracefile);
15423955d011SMarcel Moolenaar 
1543e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
15443955d011SMarcel Moolenaar 	(void)time(&now);
15453955d011SMarcel Moolenaar 
15463955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
15473955d011SMarcel Moolenaar 
1548956e45f6SSimon J. Gerraty 	InitVarTargets();
15493955d011SMarcel Moolenaar 
1550956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1551e2eeea75SSimon J. Gerraty }
15523955d011SMarcel Moolenaar 
1553*06b9b3e0SSimon J. Gerraty /*
1554*06b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
1555*06b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
1556*06b9b3e0SSimon J. Gerraty  */
1557e2eeea75SSimon J. Gerraty static void
1558e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1559e2eeea75SSimon J. Gerraty {
1560e2eeea75SSimon J. Gerraty 
1561956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1562956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
15633955d011SMarcel Moolenaar 
1564*06b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
1565*06b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1566e2eeea75SSimon J. Gerraty 	else
1567e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1568e2eeea75SSimon J. Gerraty }
1569e2eeea75SSimon J. Gerraty 
1570e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1571e2eeea75SSimon J. Gerraty static void
1572e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1573e2eeea75SSimon J. Gerraty {
15743955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1575e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
1576*06b9b3e0SSimon J. Gerraty 		(void)Var_Subst("${.MAKE.DEPENDFILE}",
1577956e45f6SSimon J. Gerraty 		    VAR_CMDLINE, VARE_WANTRES, &makeDependfile);
1578956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1579956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
15803955d011SMarcel Moolenaar 			doing_depend = TRUE;
15812c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
15823955d011SMarcel Moolenaar 			doing_depend = FALSE;
15833955d011SMarcel Moolenaar 		}
1584956e45f6SSimon J. Gerraty 	}
15853955d011SMarcel Moolenaar 
15864c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15874c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15884c620fe5SSimon J. Gerraty 
1589*06b9b3e0SSimon J. Gerraty 	MakeMode();
15903955d011SMarcel Moolenaar 
1591956e45f6SSimon J. Gerraty 	{
1592*06b9b3e0SSimon J. Gerraty 		FStr makeflags = Var_Value(MAKEFLAGS, VAR_GLOBAL);
1593*06b9b3e0SSimon J. Gerraty 		Var_Append("MFLAGS", makeflags.str, VAR_GLOBAL);
1594*06b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1595956e45f6SSimon J. Gerraty 	}
1596e48f47ddSSimon J. Gerraty 
1597956e45f6SSimon J. Gerraty 	InitMaxJobs();
1598e48f47ddSSimon J. Gerraty 
1599e48f47ddSSimon J. Gerraty 	/*
1600e2eeea75SSimon J. Gerraty 	 * Be compatible if the user did not specify -j and did not explicitly
1601e2eeea75SSimon J. Gerraty 	 * turn compatibility on.
1602e48f47ddSSimon J. Gerraty 	 */
1603e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1604956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
1605e48f47ddSSimon J. Gerraty 
1606956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
16073955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1608956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1609956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
16103955d011SMarcel Moolenaar 
1611e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
16123955d011SMarcel Moolenaar 		Main_ExportMAKEFLAGS(TRUE);	/* initial export */
16133955d011SMarcel Moolenaar 
1614956e45f6SSimon J. Gerraty 	InitVpath();
16153955d011SMarcel Moolenaar 
16163955d011SMarcel Moolenaar 	/*
16173955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
16183955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
16193955d011SMarcel Moolenaar 	 */
16203955d011SMarcel Moolenaar 	Suff_DoPaths();
16213955d011SMarcel Moolenaar 
16223955d011SMarcel Moolenaar 	/*
16233955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
16243955d011SMarcel Moolenaar 	 */
16253955d011SMarcel Moolenaar 	Targ_Propagate();
16263955d011SMarcel Moolenaar 
16273955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
16283955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
16293955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
16303955d011SMarcel Moolenaar }
16313955d011SMarcel Moolenaar 
1632*06b9b3e0SSimon J. Gerraty /*
1633*06b9b3e0SSimon J. Gerraty  * Make the targets.
1634e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
1635*06b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
1636*06b9b3e0SSimon J. Gerraty  */
1637e2eeea75SSimon J. Gerraty static Boolean
1638e2eeea75SSimon J. Gerraty main_Run(void)
1639e2eeea75SSimon J. Gerraty {
1640e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1641e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1642e2eeea75SSimon J. Gerraty 		doPrintVars();
1643e2eeea75SSimon J. Gerraty 		return FALSE;
1644e2eeea75SSimon J. Gerraty 	} else {
1645e2eeea75SSimon J. Gerraty 		return runTargets();
1646e2eeea75SSimon J. Gerraty 	}
1647e2eeea75SSimon J. Gerraty }
16483955d011SMarcel Moolenaar 
1649e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1650e2eeea75SSimon J. Gerraty static void
1651e2eeea75SSimon J. Gerraty main_CleanUp(void)
1652e2eeea75SSimon J. Gerraty {
1653e2eeea75SSimon J. Gerraty #ifdef CLEANUP
1654*06b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.variables, free);
1655*06b9b3e0SSimon J. Gerraty 	/*
1656*06b9b3e0SSimon J. Gerraty 	 * Don't free the actual strings from opts.makefiles, they may be
1657*06b9b3e0SSimon J. Gerraty 	 * used in GNodes.
1658*06b9b3e0SSimon J. Gerraty 	 */
1659*06b9b3e0SSimon J. Gerraty 	Lst_Done(&opts.makefiles);
1660*06b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.create, free);
1661e2eeea75SSimon J. Gerraty #endif
1662e2eeea75SSimon J. Gerraty 
1663e2eeea75SSimon J. Gerraty 	/* print the graph now it's been processed if the user requested it */
1664e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1665e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1666e2eeea75SSimon J. Gerraty 
1667e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1668e2eeea75SSimon J. Gerraty 
1669e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1670e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1671e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1672e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1673e2eeea75SSimon J. Gerraty 
1674e2eeea75SSimon J. Gerraty #ifdef USE_META
1675e2eeea75SSimon J. Gerraty 	meta_finish();
1676e2eeea75SSimon J. Gerraty #endif
1677e2eeea75SSimon J. Gerraty 	Suff_End();
1678e2eeea75SSimon J. Gerraty 	Targ_End();
1679e2eeea75SSimon J. Gerraty 	Arch_End();
1680e2eeea75SSimon J. Gerraty 	Var_End();
1681e2eeea75SSimon J. Gerraty 	Parse_End();
1682e2eeea75SSimon J. Gerraty 	Dir_End();
1683e2eeea75SSimon J. Gerraty 	Job_End();
1684e2eeea75SSimon J. Gerraty 	Trace_End();
1685e2eeea75SSimon J. Gerraty }
1686e2eeea75SSimon J. Gerraty 
1687e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1688e2eeea75SSimon J. Gerraty static int
1689e2eeea75SSimon J. Gerraty main_Exit(Boolean outOfDate)
1690e2eeea75SSimon J. Gerraty {
1691*06b9b3e0SSimon J. Gerraty 	if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0))
1692956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16933955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16943955d011SMarcel Moolenaar }
16953955d011SMarcel Moolenaar 
1696e2eeea75SSimon J. Gerraty int
1697e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1698e2eeea75SSimon J. Gerraty {
1699e2eeea75SSimon J. Gerraty 	Boolean outOfDate;
1700e2eeea75SSimon J. Gerraty 
1701e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1702e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1703e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1704e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1705e2eeea75SSimon J. Gerraty 	main_CleanUp();
1706e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1707e2eeea75SSimon J. Gerraty }
1708e2eeea75SSimon J. Gerraty 
1709*06b9b3e0SSimon J. Gerraty /*
1710*06b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
17113955d011SMarcel Moolenaar  *
17123955d011SMarcel Moolenaar  * Results:
17133955d011SMarcel Moolenaar  *	0 if ok. -1 if couldn't open file.
17143955d011SMarcel Moolenaar  */
17153955d011SMarcel Moolenaar static int
17162c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
17173955d011SMarcel Moolenaar {
17183955d011SMarcel Moolenaar 	int fd;
17192c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
17203955d011SMarcel Moolenaar 
1721e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
17223955d011SMarcel Moolenaar 		Parse_File(NULL /*stdin*/, -1);
17233841c287SSimon J. Gerraty 		Var_Set("MAKEFILE", "", VAR_INTERNAL);
17243955d011SMarcel Moolenaar 	} else {
17253955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1726e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
17272c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
17283955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
17293955d011SMarcel Moolenaar 			if (fd != -1) {
17303955d011SMarcel Moolenaar 				fname = path;
17313955d011SMarcel Moolenaar 				goto found;
17323955d011SMarcel Moolenaar 			}
17332c3632d1SSimon J. Gerraty 			free(path);
17343955d011SMarcel Moolenaar 
17353955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
17362c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
17373955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
17383955d011SMarcel Moolenaar 			if (fd != -1) {
17393955d011SMarcel Moolenaar 				fname = path;
17403955d011SMarcel Moolenaar 				goto found;
17413955d011SMarcel Moolenaar 			}
17423955d011SMarcel Moolenaar 		} else {
17433955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
17443955d011SMarcel Moolenaar 			if (fd != -1)
17453955d011SMarcel Moolenaar 				goto found;
17463955d011SMarcel Moolenaar 		}
17473955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
17483955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1749e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1750956e45f6SSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(sysIncPath)
1751956e45f6SSimon J. Gerraty 					     ? defSysIncPath : sysIncPath;
1752956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1753956e45f6SSimon J. Gerraty 		}
1754e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
17553955d011SMarcel Moolenaar 			free(name);
17563955d011SMarcel Moolenaar 			free(path);
17573841c287SSimon J. Gerraty 			return -1;
17583955d011SMarcel Moolenaar 		}
17593955d011SMarcel Moolenaar 		fname = name;
17603955d011SMarcel Moolenaar 		/*
17613955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
17623955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
17633955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
17643955d011SMarcel Moolenaar 		 */
17653955d011SMarcel Moolenaar found:
17663955d011SMarcel Moolenaar 		if (!doing_depend)
17673841c287SSimon J. Gerraty 			Var_Set("MAKEFILE", fname, VAR_INTERNAL);
17683955d011SMarcel Moolenaar 		Parse_File(fname, fd);
17693955d011SMarcel Moolenaar 	}
17703955d011SMarcel Moolenaar 	free(path);
17713841c287SSimon J. Gerraty 	return 0;
17723955d011SMarcel Moolenaar }
17733955d011SMarcel Moolenaar 
17743955d011SMarcel Moolenaar /*-
17753955d011SMarcel Moolenaar  * Cmd_Exec --
17763955d011SMarcel Moolenaar  *	Execute the command in cmd, and return the output of that command
17772c3632d1SSimon J. Gerraty  *	in a string.  In the output, newlines are replaced with spaces.
17783955d011SMarcel Moolenaar  *
17793955d011SMarcel Moolenaar  * Results:
17802c3632d1SSimon J. Gerraty  *	A string containing the output of the command, or the empty string.
17812c3632d1SSimon J. Gerraty  *	*errfmt returns a format string describing the command failure,
17822c3632d1SSimon J. Gerraty  *	if any, using a single %s conversion specification.
17833955d011SMarcel Moolenaar  *
17843955d011SMarcel Moolenaar  * Side Effects:
17853955d011SMarcel Moolenaar  *	The string must be freed by the caller.
17863955d011SMarcel Moolenaar  */
17873955d011SMarcel Moolenaar char *
17882c3632d1SSimon J. Gerraty Cmd_Exec(const char *cmd, const char **errfmt)
17893955d011SMarcel Moolenaar {
17903955d011SMarcel Moolenaar 	const char *args[4];	/* Args for invoking the shell */
1791*06b9b3e0SSimon J. Gerraty 	int pipefds[2];
17923955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17933955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1794e2eeea75SSimon J. Gerraty 	int status;		/* command exit status */
17953955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17962c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17972c3632d1SSimon J. Gerraty 	char *res;		/* result */
17982c3632d1SSimon J. Gerraty 	size_t res_len;
17993955d011SMarcel Moolenaar 	char *cp;
1800db29cad8SSimon J. Gerraty 	int savederr;		/* saved errno */
18013955d011SMarcel Moolenaar 
18022c3632d1SSimon J. Gerraty 	*errfmt = NULL;
18033955d011SMarcel Moolenaar 
1804*06b9b3e0SSimon J. Gerraty 	if (shellName == NULL)
18053955d011SMarcel Moolenaar 		Shell_Init();
18063955d011SMarcel Moolenaar 	/*
18073955d011SMarcel Moolenaar 	 * Set up arguments for shell
18083955d011SMarcel Moolenaar 	 */
18093955d011SMarcel Moolenaar 	args[0] = shellName;
18103955d011SMarcel Moolenaar 	args[1] = "-c";
18113955d011SMarcel Moolenaar 	args[2] = cmd;
18123955d011SMarcel Moolenaar 	args[3] = NULL;
18133955d011SMarcel Moolenaar 
18143955d011SMarcel Moolenaar 	/*
18153955d011SMarcel Moolenaar 	 * Open a pipe for fetching its output
18163955d011SMarcel Moolenaar 	 */
1817*06b9b3e0SSimon J. Gerraty 	if (pipe(pipefds) == -1) {
18182c3632d1SSimon J. Gerraty 		*errfmt = "Couldn't create pipe for \"%s\"";
18193955d011SMarcel Moolenaar 		goto bad;
18203955d011SMarcel Moolenaar 	}
18213955d011SMarcel Moolenaar 
1822*06b9b3e0SSimon J. Gerraty 	Var_ReexportVars();
1823*06b9b3e0SSimon J. Gerraty 
18243955d011SMarcel Moolenaar 	/*
18253955d011SMarcel Moolenaar 	 * Fork
18263955d011SMarcel Moolenaar 	 */
18273955d011SMarcel Moolenaar 	switch (cpid = vFork()) {
18283955d011SMarcel Moolenaar 	case 0:
1829*06b9b3e0SSimon J. Gerraty 		(void)close(pipefds[0]); /* Close input side of pipe */
18303955d011SMarcel Moolenaar 
18313955d011SMarcel Moolenaar 		/*
18323955d011SMarcel Moolenaar 		 * Duplicate the output stream to the shell's output, then
18333955d011SMarcel Moolenaar 		 * shut the extra thing down. Note we don't fetch the error
18343955d011SMarcel Moolenaar 		 * stream...why not? Why?
18353955d011SMarcel Moolenaar 		 */
1836*06b9b3e0SSimon J. Gerraty 		(void)dup2(pipefds[1], 1);
1837*06b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
18383955d011SMarcel Moolenaar 
18393955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
18403955d011SMarcel Moolenaar 		_exit(1);
18413955d011SMarcel Moolenaar 		/*NOTREACHED*/
18423955d011SMarcel Moolenaar 
18433955d011SMarcel Moolenaar 	case -1:
18442c3632d1SSimon J. Gerraty 		*errfmt = "Couldn't exec \"%s\"";
18453955d011SMarcel Moolenaar 		goto bad;
18463955d011SMarcel Moolenaar 
18473955d011SMarcel Moolenaar 	default:
1848*06b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]); /* No need for the writing half */
18493955d011SMarcel Moolenaar 
1850db29cad8SSimon J. Gerraty 		savederr = 0;
1851e2eeea75SSimon J. Gerraty 		Buf_Init(&buf);
18523955d011SMarcel Moolenaar 
18533955d011SMarcel Moolenaar 		do {
18543955d011SMarcel Moolenaar 			char result[BUFSIZ];
1855*06b9b3e0SSimon J. Gerraty 			bytes_read = read(pipefds[0], result, sizeof result);
18562c3632d1SSimon J. Gerraty 			if (bytes_read > 0)
18572c3632d1SSimon J. Gerraty 				Buf_AddBytes(&buf, result, (size_t)bytes_read);
1858e2eeea75SSimon J. Gerraty 		} while (bytes_read > 0 ||
1859e2eeea75SSimon J. Gerraty 			 (bytes_read == -1 && errno == EINTR));
18602c3632d1SSimon J. Gerraty 		if (bytes_read == -1)
1861db29cad8SSimon J. Gerraty 			savederr = errno;
18623955d011SMarcel Moolenaar 
1863*06b9b3e0SSimon J. Gerraty 		(void)close(pipefds[0]); /* Close the input side of the pipe. */
18643955d011SMarcel Moolenaar 
1865e2eeea75SSimon J. Gerraty 		/* Wait for the process to exit. */
1866e2eeea75SSimon J. Gerraty 		while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
18673955d011SMarcel Moolenaar 			JobReapChild(pid, status, FALSE);
1868e2eeea75SSimon J. Gerraty 
1869956e45f6SSimon J. Gerraty 		res_len = Buf_Len(&buf);
18703955d011SMarcel Moolenaar 		res = Buf_Destroy(&buf, FALSE);
18713955d011SMarcel Moolenaar 
1872db29cad8SSimon J. Gerraty 		if (savederr != 0)
18732c3632d1SSimon J. Gerraty 			*errfmt = "Couldn't read shell's output for \"%s\"";
18743955d011SMarcel Moolenaar 
18753955d011SMarcel Moolenaar 		if (WIFSIGNALED(status))
18762c3632d1SSimon J. Gerraty 			*errfmt = "\"%s\" exited on a signal";
18773955d011SMarcel Moolenaar 		else if (WEXITSTATUS(status) != 0)
18782c3632d1SSimon J. Gerraty 			*errfmt = "\"%s\" returned non-zero status";
18793955d011SMarcel Moolenaar 
18802c3632d1SSimon J. Gerraty 		/* Convert newlines to spaces.  A final newline is just stripped */
18812c3632d1SSimon J. Gerraty 		if (res_len > 0 && res[res_len - 1] == '\n')
18822c3632d1SSimon J. Gerraty 			res[res_len - 1] = '\0';
18832c3632d1SSimon J. Gerraty 		for (cp = res; *cp != '\0'; cp++)
18842c3632d1SSimon J. Gerraty 			if (*cp == '\n')
18853955d011SMarcel Moolenaar 				*cp = ' ';
18863955d011SMarcel Moolenaar 		break;
18873955d011SMarcel Moolenaar 	}
18883955d011SMarcel Moolenaar 	return res;
18893955d011SMarcel Moolenaar bad:
18902c3632d1SSimon J. Gerraty 	return bmake_strdup("");
18913955d011SMarcel Moolenaar }
18923955d011SMarcel Moolenaar 
1893*06b9b3e0SSimon J. Gerraty /*
1894*06b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18953955d011SMarcel Moolenaar  *
1896e2eeea75SSimon J. Gerraty  * In default mode, this error message has no consequences, in particular it
1897*06b9b3e0SSimon J. Gerraty  * does not affect the exit status.  Only in lint mode (-dL) it does.
1898*06b9b3e0SSimon J. Gerraty  */
18993955d011SMarcel Moolenaar void
19003955d011SMarcel Moolenaar Error(const char *fmt, ...)
19013955d011SMarcel Moolenaar {
19023955d011SMarcel Moolenaar 	va_list ap;
19033955d011SMarcel Moolenaar 	FILE *err_file;
19043955d011SMarcel Moolenaar 
1905956e45f6SSimon J. Gerraty 	err_file = opts.debug_file;
19063955d011SMarcel Moolenaar 	if (err_file == stdout)
19073955d011SMarcel Moolenaar 		err_file = stderr;
19083955d011SMarcel Moolenaar 	(void)fflush(stdout);
19093955d011SMarcel Moolenaar 	for (;;) {
19103955d011SMarcel Moolenaar 		va_start(ap, fmt);
19113955d011SMarcel Moolenaar 		fprintf(err_file, "%s: ", progname);
19123955d011SMarcel Moolenaar 		(void)vfprintf(err_file, fmt, ap);
19133955d011SMarcel Moolenaar 		va_end(ap);
19143955d011SMarcel Moolenaar 		(void)fprintf(err_file, "\n");
19153955d011SMarcel Moolenaar 		(void)fflush(err_file);
19163955d011SMarcel Moolenaar 		if (err_file == stderr)
19173955d011SMarcel Moolenaar 			break;
19183955d011SMarcel Moolenaar 		err_file = stderr;
19193955d011SMarcel Moolenaar 	}
1920*06b9b3e0SSimon J. Gerraty 	main_errors++;
19213955d011SMarcel Moolenaar }
19223955d011SMarcel Moolenaar 
1923*06b9b3e0SSimon J. Gerraty /*
1924*06b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1925e2eeea75SSimon J. Gerraty  * finally exit immediately.
19263955d011SMarcel Moolenaar  *
1927e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
1928*06b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
1929*06b9b3e0SSimon J. Gerraty  */
19303955d011SMarcel Moolenaar void
19313955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
19323955d011SMarcel Moolenaar {
19333955d011SMarcel Moolenaar 	va_list ap;
19343955d011SMarcel Moolenaar 
19353955d011SMarcel Moolenaar 	if (jobsRunning)
19363955d011SMarcel Moolenaar 		Job_Wait();
19373955d011SMarcel Moolenaar 
19383955d011SMarcel Moolenaar 	(void)fflush(stdout);
1939e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
19403955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19413955d011SMarcel Moolenaar 	va_end(ap);
19423955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19433955d011SMarcel Moolenaar 	(void)fflush(stderr);
19443955d011SMarcel Moolenaar 
19453955d011SMarcel Moolenaar 	PrintOnError(NULL, NULL);
19463955d011SMarcel Moolenaar 
19473955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
19483955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1949e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
19503955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
19513955d011SMarcel Moolenaar }
19523955d011SMarcel Moolenaar 
1953*06b9b3e0SSimon J. Gerraty /*
1954*06b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
1955*06b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
1956*06b9b3e0SSimon J. Gerraty  */
19573955d011SMarcel Moolenaar void
19583955d011SMarcel Moolenaar Punt(const char *fmt, ...)
19593955d011SMarcel Moolenaar {
19603955d011SMarcel Moolenaar 	va_list ap;
19613955d011SMarcel Moolenaar 
19623955d011SMarcel Moolenaar 	va_start(ap, fmt);
19633955d011SMarcel Moolenaar 	(void)fflush(stdout);
19643955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
19653955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19663955d011SMarcel Moolenaar 	va_end(ap);
19673955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19683955d011SMarcel Moolenaar 	(void)fflush(stderr);
19693955d011SMarcel Moolenaar 
19703955d011SMarcel Moolenaar 	PrintOnError(NULL, NULL);
19713955d011SMarcel Moolenaar 
19723955d011SMarcel Moolenaar 	DieHorribly();
19733955d011SMarcel Moolenaar }
19743955d011SMarcel Moolenaar 
1975956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19763955d011SMarcel Moolenaar void
19773955d011SMarcel Moolenaar DieHorribly(void)
19783955d011SMarcel Moolenaar {
19793955d011SMarcel Moolenaar 	if (jobsRunning)
19803955d011SMarcel Moolenaar 		Job_AbortAll();
19813955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19823955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1983e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
1984*06b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19853955d011SMarcel Moolenaar }
19863955d011SMarcel Moolenaar 
1987*06b9b3e0SSimon J. Gerraty /*
1988*06b9b3e0SSimon J. Gerraty  * Called when aborting due to errors in child shell to signal abnormal exit.
1989956e45f6SSimon J. Gerraty  * The program exits.
1990*06b9b3e0SSimon J. Gerraty  * Errors is the number of errors encountered in Make_Make.
1991*06b9b3e0SSimon J. Gerraty  */
19923955d011SMarcel Moolenaar void
1993956e45f6SSimon J. Gerraty Finish(int errs)
19943955d011SMarcel Moolenaar {
1995e2eeea75SSimon J. Gerraty 	if (shouldDieQuietly(NULL, -1))
19963841c287SSimon J. Gerraty 		exit(2);
1997956e45f6SSimon J. Gerraty 	Fatal("%d error%s", errs, errs == 1 ? "" : "s");
19983955d011SMarcel Moolenaar }
19993955d011SMarcel Moolenaar 
20003955d011SMarcel Moolenaar /*
20011748de26SSimon J. Gerraty  * eunlink --
20023955d011SMarcel Moolenaar  *	Remove a file carefully, avoiding directories.
20033955d011SMarcel Moolenaar  */
20043955d011SMarcel Moolenaar int
20053955d011SMarcel Moolenaar eunlink(const char *file)
20063955d011SMarcel Moolenaar {
20073955d011SMarcel Moolenaar 	struct stat st;
20083955d011SMarcel Moolenaar 
20093955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
20103955d011SMarcel Moolenaar 		return -1;
20113955d011SMarcel Moolenaar 
20123955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
20133955d011SMarcel Moolenaar 		errno = EISDIR;
20143955d011SMarcel Moolenaar 		return -1;
20153955d011SMarcel Moolenaar 	}
20163955d011SMarcel Moolenaar 	return unlink(file);
20173955d011SMarcel Moolenaar }
20183955d011SMarcel Moolenaar 
2019956e45f6SSimon J. Gerraty static void
2020956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
2021956e45f6SSimon J. Gerraty {
2022956e45f6SSimon J. Gerraty 	const char *mem = data;
2023956e45f6SSimon J. Gerraty 
2024956e45f6SSimon J. Gerraty 	while (n > 0) {
2025956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
2026956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
2027956e45f6SSimon J. Gerraty 			continue;
2028956e45f6SSimon J. Gerraty 		if (written == -1)
2029956e45f6SSimon J. Gerraty 			break;
2030956e45f6SSimon J. Gerraty 		mem += written;
2031956e45f6SSimon J. Gerraty 		n -= (size_t)written;
2032956e45f6SSimon J. Gerraty 	}
2033956e45f6SSimon J. Gerraty }
2034956e45f6SSimon J. Gerraty 
20353955d011SMarcel Moolenaar /*
2036956e45f6SSimon J. Gerraty  * execDie --
20373955d011SMarcel Moolenaar  *	Print why exec failed, avoiding stdio.
20383955d011SMarcel Moolenaar  */
2039956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
2040956e45f6SSimon J. Gerraty execDie(const char *af, const char *av)
20413955d011SMarcel Moolenaar {
2042956e45f6SSimon J. Gerraty 	Buffer buf;
20433955d011SMarcel Moolenaar 
2044e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
2045956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, progname);
2046956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ": ");
2047956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, af);
2048956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
2049956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, av);
2050956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ") failed (");
2051956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, strerror(errno));
2052956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ")\n");
20533955d011SMarcel Moolenaar 
2054956e45f6SSimon J. Gerraty 	write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf));
2055956e45f6SSimon J. Gerraty 
2056956e45f6SSimon J. Gerraty 	Buf_Destroy(&buf, TRUE);
2057956e45f6SSimon J. Gerraty 	_exit(1);
20583955d011SMarcel Moolenaar }
20593955d011SMarcel Moolenaar 
2060b46b9039SSimon J. Gerraty /* purge any relative paths */
2061e1cee40dSSimon J. Gerraty static void
2062e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
2063e1cee40dSSimon J. Gerraty {
2064956e45f6SSimon J. Gerraty 	HashEntry *he, *nhe;
2065956e45f6SSimon J. Gerraty 	HashIter hi;
2066b778b302SSimon J. Gerraty 
2067e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
2068956e45f6SSimon J. Gerraty 	he = HashIter_Next(&hi);
2069956e45f6SSimon J. Gerraty 	while (he != NULL) {
2070956e45f6SSimon J. Gerraty 		nhe = HashIter_Next(&hi);
2071956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
2072e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
2073e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
2074e2eeea75SSimon J. Gerraty 			/* XXX: What about the allocated he->value? Either
2075e2eeea75SSimon J. Gerraty 			 * free them or document why they cannot be freed. */
2076b46b9039SSimon J. Gerraty 		}
2077b46b9039SSimon J. Gerraty 		he = nhe;
2078b46b9039SSimon J. Gerraty 	}
2079b46b9039SSimon J. Gerraty }
2080e1cee40dSSimon J. Gerraty 
2081e1cee40dSSimon J. Gerraty char *
2082e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2083e1cee40dSSimon J. Gerraty {
20842c3632d1SSimon J. Gerraty 	const char *rp;
2085e1cee40dSSimon J. Gerraty 
2086e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2087e1cee40dSSimon J. Gerraty 		return NULL;
2088e1cee40dSSimon J. Gerraty 
2089e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2090e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2091b778b302SSimon J. Gerraty 		/* a hit */
2092e2eeea75SSimon J. Gerraty 		strncpy(resolved, rp, MAXPATHLEN);
2093e2eeea75SSimon J. Gerraty 		resolved[MAXPATHLEN - 1] = '\0';
2094e2eeea75SSimon J. Gerraty 		return resolved;
2095e2eeea75SSimon J. Gerraty 	}
20963841c287SSimon J. Gerraty 
2097e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2098e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2099e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2100e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2101e2eeea75SSimon J. Gerraty 		return resolved;
2102e2eeea75SSimon J. Gerraty 	}
2103e2eeea75SSimon J. Gerraty 
2104e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2105e2eeea75SSimon J. Gerraty 	return NULL;
2106b778b302SSimon J. Gerraty }
2107b778b302SSimon J. Gerraty 
21083841c287SSimon J. Gerraty /*
21093841c287SSimon J. Gerraty  * Return true if we should die without noise.
2110e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
21113841c287SSimon J. Gerraty  */
2112e2eeea75SSimon J. Gerraty Boolean
2113e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
21143841c287SSimon J. Gerraty {
21153841c287SSimon J. Gerraty 	static int quietly = -1;
21163841c287SSimon J. Gerraty 
21173841c287SSimon J. Gerraty 	if (quietly < 0) {
2118e2eeea75SSimon J. Gerraty 		if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE))
21193841c287SSimon J. Gerraty 			quietly = 0;
21203841c287SSimon J. Gerraty 		else if (bf >= 0)
21213841c287SSimon J. Gerraty 			quietly = bf;
21223841c287SSimon J. Gerraty 		else
2123*06b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
21243841c287SSimon J. Gerraty 	}
21253841c287SSimon J. Gerraty 	return quietly;
21263841c287SSimon J. Gerraty }
21273841c287SSimon J. Gerraty 
2128956e45f6SSimon J. Gerraty static void
2129956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2130956e45f6SSimon J. Gerraty {
2131956e45f6SSimon J. Gerraty 	StringListNode *ln;
2132956e45f6SSimon J. Gerraty 
2133956e45f6SSimon J. Gerraty 	/*
2134956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2135956e45f6SSimon J. Gerraty 	 */
2136956e45f6SSimon J. Gerraty 	Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL);
2137956e45f6SSimon J. Gerraty 	Var_Delete(".ERROR_CMD", VAR_GLOBAL);
2138956e45f6SSimon J. Gerraty 
2139*06b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2140956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2141956e45f6SSimon J. Gerraty 
2142956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2143956e45f6SSimon J. Gerraty 			break;
2144956e45f6SSimon J. Gerraty 		Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL);
2145956e45f6SSimon J. Gerraty 	}
2146956e45f6SSimon J. Gerraty }
2147956e45f6SSimon J. Gerraty 
2148*06b9b3e0SSimon J. Gerraty /*
2149*06b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
2150*06b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
2151*06b9b3e0SSimon J. Gerraty  */
21523955d011SMarcel Moolenaar void
2153e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
21543955d011SMarcel Moolenaar {
2155e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
21563955d011SMarcel Moolenaar 
21572c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
21582c3632d1SSimon J. Gerraty 		Targ_Stats();
21592c3632d1SSimon J. Gerraty 		Var_Stats();
21602c3632d1SSimon J. Gerraty 	}
21612c3632d1SSimon J. Gerraty 
2162*06b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
2163*06b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
21643841c287SSimon J. Gerraty 
2165e2eeea75SSimon J. Gerraty 	if (msg != NULL)
2166e2eeea75SSimon J. Gerraty 		printf("%s", msg);
21673955d011SMarcel Moolenaar 	printf("\n%s: stopped in %s\n", progname, curdir);
21683955d011SMarcel Moolenaar 
2169*06b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
2170*06b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
2171*06b9b3e0SSimon J. Gerraty 		return;
2172e2eeea75SSimon J. Gerraty 
2173e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2174956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2175e2eeea75SSimon J. Gerraty 
2176e2eeea75SSimon J. Gerraty 	{
2177e2eeea75SSimon J. Gerraty 		char *errorVarsValues;
2178e2eeea75SSimon J. Gerraty 		(void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
2179e2eeea75SSimon J. Gerraty 				VAR_GLOBAL, VARE_WANTRES, &errorVarsValues);
2180956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2181e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2182e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2183e2eeea75SSimon J. Gerraty 	}
2184e2eeea75SSimon J. Gerraty 
2185ac3446e9SSimon J. Gerraty 	fflush(stdout);
2186ac3446e9SSimon J. Gerraty 
21873955d011SMarcel Moolenaar 	/*
21883955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21893955d011SMarcel Moolenaar 	 */
2190e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2191e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2192e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2193e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21943955d011SMarcel Moolenaar 	}
21953955d011SMarcel Moolenaar }
21963955d011SMarcel Moolenaar 
21973955d011SMarcel Moolenaar void
21983955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(Boolean first)
21993955d011SMarcel Moolenaar {
22002c3632d1SSimon J. Gerraty 	static Boolean once = TRUE;
22012c3632d1SSimon J. Gerraty 	const char *expr;
22023955d011SMarcel Moolenaar 	char *s;
22033955d011SMarcel Moolenaar 
22043955d011SMarcel Moolenaar 	if (once != first)
22053955d011SMarcel Moolenaar 		return;
22062c3632d1SSimon J. Gerraty 	once = FALSE;
22073955d011SMarcel Moolenaar 
22082c3632d1SSimon J. Gerraty 	expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
2209956e45f6SSimon J. Gerraty 	(void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s);
2210956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
22112c3632d1SSimon J. Gerraty 	if (s[0] != '\0') {
22123955d011SMarcel Moolenaar #ifdef POSIX
22133955d011SMarcel Moolenaar 		setenv("MAKEFLAGS", s, 1);
22143955d011SMarcel Moolenaar #else
22153955d011SMarcel Moolenaar 		setenv("MAKE", s, 1);
22163955d011SMarcel Moolenaar #endif
22173955d011SMarcel Moolenaar 	}
22183955d011SMarcel Moolenaar }
22193955d011SMarcel Moolenaar 
22203955d011SMarcel Moolenaar char *
22213955d011SMarcel Moolenaar getTmpdir(void)
22223955d011SMarcel Moolenaar {
22233955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
22243955d011SMarcel Moolenaar 	struct stat st;
22253955d011SMarcel Moolenaar 
2226e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2227e2eeea75SSimon J. Gerraty 		return tmpdir;
2228e2eeea75SSimon J. Gerraty 
2229e2eeea75SSimon J. Gerraty 	/* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */
2230e2eeea75SSimon J. Gerraty 	(void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/",
2231e2eeea75SSimon J. Gerraty 	    VAR_GLOBAL, VARE_WANTRES, &tmpdir);
2232956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2233e2eeea75SSimon J. Gerraty 
22343955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
22353955d011SMarcel Moolenaar 		free(tmpdir);
22363955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
22373955d011SMarcel Moolenaar 	}
22383955d011SMarcel Moolenaar 	return tmpdir;
22393955d011SMarcel Moolenaar }
22403955d011SMarcel Moolenaar 
22413955d011SMarcel Moolenaar /*
22423955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2243956e45f6SSimon J. Gerraty  * If out_fname is provided, set it to a copy of the filename created.
22443955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
22453955d011SMarcel Moolenaar  */
22463955d011SMarcel Moolenaar int
2247956e45f6SSimon J. Gerraty mkTempFile(const char *pattern, char **out_fname)
22483955d011SMarcel Moolenaar {
22493955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
22503955d011SMarcel Moolenaar 	char tfile[MAXPATHLEN];
22513955d011SMarcel Moolenaar 	int fd;
22523955d011SMarcel Moolenaar 
2253e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
22543955d011SMarcel Moolenaar 		pattern = TMPPAT;
2255956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
22563955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
22573955d011SMarcel Moolenaar 	if (pattern[0] == '/') {
2258e2eeea75SSimon J. Gerraty 		snprintf(tfile, sizeof tfile, "%s", pattern);
22593955d011SMarcel Moolenaar 	} else {
2260e2eeea75SSimon J. Gerraty 		snprintf(tfile, sizeof tfile, "%s%s", tmpdir, pattern);
22613955d011SMarcel Moolenaar 	}
22623955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2263e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2264e2eeea75SSimon J. Gerraty 		    strerror(errno));
2265*06b9b3e0SSimon J. Gerraty 	if (out_fname != NULL) {
2266956e45f6SSimon J. Gerraty 		*out_fname = bmake_strdup(tfile);
22673955d011SMarcel Moolenaar 	} else {
2268*06b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
22693955d011SMarcel Moolenaar 	}
22703955d011SMarcel Moolenaar 	return fd;
22713955d011SMarcel Moolenaar }
22723955d011SMarcel Moolenaar 
2273be19d90bSSimon J. Gerraty /*
2274e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2275e2eeea75SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is FALSE,
2276e2eeea75SSimon J. Gerraty  * the empty string is the fallback, everything else is TRUE.
2277be19d90bSSimon J. Gerraty  */
2278be19d90bSSimon J. Gerraty Boolean
2279e2eeea75SSimon J. Gerraty ParseBoolean(const char *s, Boolean fallback)
2280be19d90bSSimon J. Gerraty {
2281e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2282e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2283e2eeea75SSimon J. Gerraty 		return fallback;
2284e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2285956e45f6SSimon J. Gerraty 		return FALSE;
2286e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2287e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2288956e45f6SSimon J. Gerraty 	return TRUE;
2289be19d90bSSimon J. Gerraty }
2290