xref: /freebsd/contrib/bmake/main.c (revision d5e0a182cf153f8993a633b93d9220c99a89e760)
1*d5e0a182SSimon J. Gerraty /*	$NetBSD: main.c,v 1.609 2024/01/07 01:33:57 sjg 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 
7106b9b3e0SSimon J. Gerraty /*
7206b9b3e0SSimon 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  *
76dba7b0efSSimon J. Gerraty  *	Main_ParseArgLine
77dba7b0efSSimon J. Gerraty  *			Parse and process command line arguments from a
78dba7b0efSSimon J. Gerraty  *			single string.  Used to implement the special targets
79dba7b0efSSimon J. Gerraty  *			.MFLAGS and .MAKEFLAGS.
803955d011SMarcel Moolenaar  *
81e2eeea75SSimon J. Gerraty  *	Error		Print a tagged error message.
823955d011SMarcel Moolenaar  *
83e2eeea75SSimon J. Gerraty  *	Fatal		Print an error message and exit.
84e2eeea75SSimon J. Gerraty  *
85e2eeea75SSimon J. Gerraty  *	Punt		Abort all jobs and exit with a message.
863955d011SMarcel Moolenaar  *
87dba7b0efSSimon J. Gerraty  *	Finish		Finish things up by printing the number of errors
88dba7b0efSSimon J. Gerraty  *			that occurred, and exit.
893955d011SMarcel Moolenaar  */
903955d011SMarcel Moolenaar 
913955d011SMarcel Moolenaar #include <sys/types.h>
923955d011SMarcel Moolenaar #include <sys/time.h>
933955d011SMarcel Moolenaar #include <sys/param.h>
943955d011SMarcel Moolenaar #include <sys/resource.h>
953955d011SMarcel Moolenaar #include <sys/stat.h>
960dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL)
970dede8b0SSimon J. Gerraty #include <sys/sysctl.h>
980dede8b0SSimon J. Gerraty #endif
993955d011SMarcel Moolenaar #include <sys/utsname.h>
1003955d011SMarcel Moolenaar #include "wait.h"
1013955d011SMarcel Moolenaar 
1023955d011SMarcel Moolenaar #include <errno.h>
10351ee2c1cSSimon J. Gerraty #include <signal.h>
1043955d011SMarcel Moolenaar #include <stdarg.h>
1053955d011SMarcel Moolenaar #include <time.h>
1063955d011SMarcel Moolenaar 
1073955d011SMarcel Moolenaar #include "make.h"
1083955d011SMarcel Moolenaar #include "dir.h"
1093955d011SMarcel Moolenaar #include "job.h"
1103955d011SMarcel Moolenaar #include "pathnames.h"
1113955d011SMarcel Moolenaar #include "trace.h"
1123955d011SMarcel Moolenaar 
113956e45f6SSimon J. Gerraty /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
114*d5e0a182SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.609 2024/01/07 01:33:57 sjg Exp $");
115*d5e0a182SSimon J. Gerraty #if defined(MAKE_NATIVE)
116956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
117956e45f6SSimon J. Gerraty 	    "The Regents of the University of California.  "
118956e45f6SSimon J. Gerraty 	    "All rights reserved.");
1193955d011SMarcel Moolenaar #endif
1203955d011SMarcel Moolenaar 
1210dede8b0SSimon J. Gerraty #ifndef __arraycount
1220dede8b0SSimon J. Gerraty # define __arraycount(__x)	(sizeof(__x) / sizeof(__x[0]))
1230dede8b0SSimon J. Gerraty #endif
1240dede8b0SSimon J. Gerraty 
125956e45f6SSimon J. Gerraty CmdOpts opts;
1263955d011SMarcel Moolenaar time_t now;			/* Time at start of make */
127e2eeea75SSimon J. Gerraty GNode *defaultNode;		/* .DEFAULT node */
128*d5e0a182SSimon J. Gerraty bool allPrecious;		/* .PRECIOUS given on a line by itself */
129b0c40a00SSimon J. Gerraty bool deleteOnError;		/* .DELETE_ON_ERROR: set */
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1328c973ee2SSimon J. Gerraty static bool enterFlagObj;	/* -w and objdir != srcdir */
133956e45f6SSimon J. Gerraty 
1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
135b0c40a00SSimon J. Gerraty bool doing_depend;		/* Set while reading .depend */
136b0c40a00SSimon J. Gerraty static bool jobsRunning;	/* true if the jobs might be running */
1373955d011SMarcel Moolenaar static const char *tracefile;
1389f45a3c8SSimon J. Gerraty static bool ReadMakefile(const char *);
139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1403955d011SMarcel Moolenaar 
141b0c40a00SSimon J. Gerraty static bool ignorePWD;		/* if we use -C, PWD is meaningless */
1423955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
1433955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1];	/* Startup directory */
14406b9b3e0SSimon J. Gerraty const char *progname;
1453955d011SMarcel Moolenaar char *makeDependfile;
1463955d011SMarcel Moolenaar pid_t myPid;
14751ee2c1cSSimon J. Gerraty int makelevel;
1483955d011SMarcel Moolenaar 
149b0c40a00SSimon J. Gerraty bool forceJobs = false;
15006b9b3e0SSimon J. Gerraty static int main_errors = 0;
151e2eeea75SSimon J. Gerraty static HashTable cached_realpaths;
1523955d011SMarcel Moolenaar 
15351ee2c1cSSimon J. Gerraty /*
15451ee2c1cSSimon J. Gerraty  * For compatibility with the POSIX version of MAKEFLAGS that includes
155e2eeea75SSimon J. Gerraty  * all the options without '-', convert 'flags' to '-f -l -a -g -s '.
15651ee2c1cSSimon J. Gerraty  */
15751ee2c1cSSimon J. Gerraty static char *
15851ee2c1cSSimon J. Gerraty explode(const char *flags)
15951ee2c1cSSimon J. Gerraty {
1609f45a3c8SSimon J. Gerraty 	char *exploded, *ep;
1619f45a3c8SSimon J. Gerraty 	const char *p;
16251ee2c1cSSimon J. Gerraty 
16351ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16451ee2c1cSSimon J. Gerraty 		return NULL;
16551ee2c1cSSimon J. Gerraty 
1669f45a3c8SSimon J. Gerraty 	for (p = flags; *p != '\0'; p++)
1679f45a3c8SSimon J. Gerraty 		if (!ch_isalpha(*p))
16851ee2c1cSSimon J. Gerraty 			return bmake_strdup(flags);
16951ee2c1cSSimon J. Gerraty 
1709f45a3c8SSimon J. Gerraty 	exploded = bmake_malloc((size_t)(p - flags) * 3 + 1);
1719f45a3c8SSimon J. Gerraty 	for (p = flags, ep = exploded; *p != '\0'; p++) {
1729f45a3c8SSimon J. Gerraty 		*ep++ = '-';
1739f45a3c8SSimon J. Gerraty 		*ep++ = *p;
1749f45a3c8SSimon J. Gerraty 		*ep++ = ' ';
17551ee2c1cSSimon J. Gerraty 	}
1769f45a3c8SSimon J. Gerraty 	*ep = '\0';
1779f45a3c8SSimon J. Gerraty 	return exploded;
17851ee2c1cSSimon J. Gerraty }
17951ee2c1cSSimon J. Gerraty 
180e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
181e2eeea75SSimon J. Gerraty usage(void)
182e2eeea75SSimon J. Gerraty {
183e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
184e2eeea75SSimon J. Gerraty 
185e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
186e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
187e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
188e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
189e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
190e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
191e2eeea75SSimon J. Gerraty 	exit(2);
192e2eeea75SSimon J. Gerraty }
193e2eeea75SSimon J. Gerraty 
1943955d011SMarcel Moolenaar static void
195dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg)
1963955d011SMarcel Moolenaar {
1973955d011SMarcel Moolenaar 	const char *mode;
198956e45f6SSimon J. Gerraty 	size_t len;
1993955d011SMarcel Moolenaar 	char *fname;
2003955d011SMarcel Moolenaar 
201956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
202956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
203956e45f6SSimon J. Gerraty 
204dba7b0efSSimon J. Gerraty 	if (*arg == '+') {
205dba7b0efSSimon J. Gerraty 		arg++;
2063955d011SMarcel Moolenaar 		mode = "a";
2073955d011SMarcel Moolenaar 	} else
2083955d011SMarcel Moolenaar 		mode = "w";
209956e45f6SSimon J. Gerraty 
210dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stdout") == 0) {
211956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
212956e45f6SSimon J. Gerraty 		return;
2133955d011SMarcel Moolenaar 	}
214dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stderr") == 0) {
215956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
216956e45f6SSimon J. Gerraty 		return;
2173955d011SMarcel Moolenaar 	}
218956e45f6SSimon J. Gerraty 
219dba7b0efSSimon J. Gerraty 	len = strlen(arg);
220e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
221dba7b0efSSimon J. Gerraty 	memcpy(fname, arg, len + 1);
222956e45f6SSimon J. Gerraty 
2239f45a3c8SSimon J. Gerraty 	/* Replace the trailing '%d' after '.%d' with the pid. */
2249f45a3c8SSimon J. Gerraty 	if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0)
2253955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
226956e45f6SSimon J. Gerraty 
227956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
228e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
229*d5e0a182SSimon J. Gerraty 		fprintf(stderr, "Cannot open debug file \"%s\"\n", fname);
2309f45a3c8SSimon J. Gerraty 		exit(2);
2313955d011SMarcel Moolenaar 	}
2323955d011SMarcel Moolenaar 	free(fname);
233956e45f6SSimon J. Gerraty }
234956e45f6SSimon J. Gerraty 
235956e45f6SSimon J. Gerraty static void
236dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue)
237956e45f6SSimon J. Gerraty {
238956e45f6SSimon J. Gerraty 	const char *modules;
239e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
240956e45f6SSimon J. Gerraty 
241dba7b0efSSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; modules++) {
242956e45f6SSimon J. Gerraty 		switch (*modules) {
243956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
2449f45a3c8SSimon J. Gerraty 			memset(&debug, 0, sizeof(debug));
245956e45f6SSimon J. Gerraty 			break;
246956e45f6SSimon J. Gerraty 		case 'A':
2479f45a3c8SSimon J. Gerraty 			memset(&debug, ~0, sizeof(debug));
248956e45f6SSimon J. Gerraty 			break;
249956e45f6SSimon J. Gerraty 		case 'a':
2509f45a3c8SSimon J. Gerraty 			debug.DEBUG_ARCH = true;
251956e45f6SSimon J. Gerraty 			break;
252956e45f6SSimon J. Gerraty 		case 'C':
2539f45a3c8SSimon J. Gerraty 			debug.DEBUG_CWD = true;
254956e45f6SSimon J. Gerraty 			break;
255956e45f6SSimon J. Gerraty 		case 'c':
2569f45a3c8SSimon J. Gerraty 			debug.DEBUG_COND = true;
257956e45f6SSimon J. Gerraty 			break;
258956e45f6SSimon J. Gerraty 		case 'd':
2599f45a3c8SSimon J. Gerraty 			debug.DEBUG_DIR = true;
260956e45f6SSimon J. Gerraty 			break;
261956e45f6SSimon J. Gerraty 		case 'e':
2629f45a3c8SSimon J. Gerraty 			debug.DEBUG_ERROR = true;
263956e45f6SSimon J. Gerraty 			break;
264956e45f6SSimon J. Gerraty 		case 'f':
2659f45a3c8SSimon J. Gerraty 			debug.DEBUG_FOR = true;
266956e45f6SSimon J. Gerraty 			break;
267956e45f6SSimon J. Gerraty 		case 'g':
268956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
2699f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH1 = true;
270e2eeea75SSimon J. Gerraty 				modules++;
271e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
2729f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH2 = true;
273e2eeea75SSimon J. Gerraty 				modules++;
274e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
2759f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH3 = true;
276e2eeea75SSimon J. Gerraty 				modules++;
277956e45f6SSimon J. Gerraty 			}
278956e45f6SSimon J. Gerraty 			break;
279956e45f6SSimon J. Gerraty 		case 'h':
2809f45a3c8SSimon J. Gerraty 			debug.DEBUG_HASH = true;
281956e45f6SSimon J. Gerraty 			break;
282956e45f6SSimon J. Gerraty 		case 'j':
2839f45a3c8SSimon J. Gerraty 			debug.DEBUG_JOB = true;
284956e45f6SSimon J. Gerraty 			break;
285956e45f6SSimon J. Gerraty 		case 'L':
286b0c40a00SSimon J. Gerraty 			opts.strict = true;
287956e45f6SSimon J. Gerraty 			break;
288956e45f6SSimon J. Gerraty 		case 'l':
2899f45a3c8SSimon J. Gerraty 			debug.DEBUG_LOUD = true;
290956e45f6SSimon J. Gerraty 			break;
291956e45f6SSimon J. Gerraty 		case 'M':
2929f45a3c8SSimon J. Gerraty 			debug.DEBUG_META = true;
293956e45f6SSimon J. Gerraty 			break;
294956e45f6SSimon J. Gerraty 		case 'm':
2959f45a3c8SSimon J. Gerraty 			debug.DEBUG_MAKE = true;
296956e45f6SSimon J. Gerraty 			break;
297956e45f6SSimon J. Gerraty 		case 'n':
2989f45a3c8SSimon J. Gerraty 			debug.DEBUG_SCRIPT = true;
299956e45f6SSimon J. Gerraty 			break;
300956e45f6SSimon J. Gerraty 		case 'p':
3019f45a3c8SSimon J. Gerraty 			debug.DEBUG_PARSE = true;
302956e45f6SSimon J. Gerraty 			break;
303956e45f6SSimon J. Gerraty 		case 's':
3049f45a3c8SSimon J. Gerraty 			debug.DEBUG_SUFF = true;
305956e45f6SSimon J. Gerraty 			break;
306956e45f6SSimon J. Gerraty 		case 't':
3079f45a3c8SSimon J. Gerraty 			debug.DEBUG_TARG = true;
308956e45f6SSimon J. Gerraty 			break;
309956e45f6SSimon J. Gerraty 		case 'V':
310b0c40a00SSimon J. Gerraty 			opts.debugVflag = true;
311956e45f6SSimon J. Gerraty 			break;
312956e45f6SSimon J. Gerraty 		case 'v':
3139f45a3c8SSimon J. Gerraty 			debug.DEBUG_VAR = true;
314956e45f6SSimon J. Gerraty 			break;
315956e45f6SSimon J. Gerraty 		case 'x':
3169f45a3c8SSimon J. Gerraty 			debug.DEBUG_SHELL = true;
317956e45f6SSimon J. Gerraty 			break;
318956e45f6SSimon J. Gerraty 		case 'F':
319dba7b0efSSimon J. Gerraty 			MainParseArgDebugFile(modules + 1);
3201d3f2ddcSSimon J. Gerraty 			goto finish;
3213955d011SMarcel Moolenaar 		default:
3223955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3233955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3243955d011SMarcel Moolenaar 			    progname, *modules);
3253955d011SMarcel Moolenaar 			usage();
3263955d011SMarcel Moolenaar 		}
3273955d011SMarcel Moolenaar 	}
328e2eeea75SSimon J. Gerraty 
3291d3f2ddcSSimon J. Gerraty finish:
330e2eeea75SSimon J. Gerraty 	opts.debug = debug;
331e2eeea75SSimon J. Gerraty 
332956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
3331d3f2ddcSSimon J. Gerraty 	if (opts.debug_file != stdout)
3343955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3353955d011SMarcel Moolenaar }
3363955d011SMarcel Moolenaar 
3371d3f2ddcSSimon J. Gerraty /* Is path relative or does it contain any relative component "." or ".."? */
338b0c40a00SSimon J. Gerraty static bool
339dba7b0efSSimon J. Gerraty IsRelativePath(const char *path)
340e1cee40dSSimon J. Gerraty {
341b0c40a00SSimon J. Gerraty 	const char *p;
342e1cee40dSSimon J. Gerraty 
343e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
344b0c40a00SSimon J. Gerraty 		return true;
345b0c40a00SSimon J. Gerraty 	p = path;
346b0c40a00SSimon J. Gerraty 	while ((p = strstr(p, "/.")) != NULL) {
347b0c40a00SSimon J. Gerraty 		p += 2;
348b0c40a00SSimon J. Gerraty 		if (*p == '.')
349b0c40a00SSimon J. Gerraty 			p++;
350b0c40a00SSimon J. Gerraty 		if (*p == '/' || *p == '\0')
351b0c40a00SSimon J. Gerraty 			return true;
3522c3632d1SSimon J. Gerraty 	}
353b0c40a00SSimon J. Gerraty 	return false;
354e1cee40dSSimon J. Gerraty }
355e1cee40dSSimon J. Gerraty 
356956e45f6SSimon J. Gerraty static void
357956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
358956e45f6SSimon J. Gerraty {
359956e45f6SSimon J. Gerraty 	struct stat sa, sb;
360956e45f6SSimon J. Gerraty 
361956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
362956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
363956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
36406b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
365956e45f6SSimon J. Gerraty 	}
366956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
367956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
368956e45f6SSimon J. Gerraty 		exit(2);
369956e45f6SSimon J. Gerraty 	}
370dba7b0efSSimon J. Gerraty 	if (!IsRelativePath(argvalue) &&
371956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
372956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
373956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
374956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
375956e45f6SSimon J. Gerraty 		strncpy(curdir, argvalue, MAXPATHLEN);
376b0c40a00SSimon J. Gerraty 	ignorePWD = true;
377956e45f6SSimon J. Gerraty }
378956e45f6SSimon J. Gerraty 
379956e45f6SSimon J. Gerraty static void
380956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
381956e45f6SSimon J. Gerraty {
382e2eeea75SSimon J. Gerraty 	char end;
383e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
384956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
385956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
386956e45f6SSimon J. Gerraty 		    progname, argvalue);
387956e45f6SSimon J. Gerraty 		usage();
388956e45f6SSimon J. Gerraty 	}
389956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
390956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
391956e45f6SSimon J. Gerraty 		jp_0 = -1;
392956e45f6SSimon J. Gerraty 		jp_1 = -1;
393b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
394956e45f6SSimon J. Gerraty 	} else {
395dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-J");
396dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
397956e45f6SSimon J. Gerraty 	}
398956e45f6SSimon J. Gerraty }
399956e45f6SSimon J. Gerraty 
400956e45f6SSimon J. Gerraty static void
40198875883SSimon J. Gerraty MainParseArgJobs(const char *arg)
402956e45f6SSimon J. Gerraty {
40398875883SSimon J. Gerraty 	const char *p;
40498875883SSimon J. Gerraty 	char *end;
40598875883SSimon J. Gerraty 	char v[12];
406956e45f6SSimon J. Gerraty 
407b0c40a00SSimon J. Gerraty 	forceJobs = true;
40898875883SSimon J. Gerraty 	opts.maxJobs = (int)strtol(arg, &end, 0);
409*d5e0a182SSimon J. Gerraty 	p = end;
41098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
41198875883SSimon J. Gerraty 	if (*p != '\0') {
41298875883SSimon J. Gerraty 		double d;
41398875883SSimon J. Gerraty 
414*d5e0a182SSimon J. Gerraty 		if (*p == 'C')
41598875883SSimon J. Gerraty 			d = (opts.maxJobs > 0) ? opts.maxJobs : 1;
416*d5e0a182SSimon J. Gerraty 		else if (*p == '.') {
41798875883SSimon J. Gerraty 			d = strtod(arg, &end);
418*d5e0a182SSimon J. Gerraty 			p = end;
41998875883SSimon J. Gerraty 		} else
420*d5e0a182SSimon J. Gerraty 			d = 0.0;
421*d5e0a182SSimon J. Gerraty 		if (d > 0.0) {
42298875883SSimon J. Gerraty 			p = "";
42398875883SSimon J. Gerraty 			opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN);
42498875883SSimon J. Gerraty 			opts.maxJobs = (int)(d * (double)opts.maxJobs);
42598875883SSimon J. Gerraty 		}
42698875883SSimon J. Gerraty 	}
42798875883SSimon J. Gerraty #endif
428956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
429956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
43098875883SSimon J. Gerraty 		    "%s: argument '%s' to option '-j' "
43198875883SSimon J. Gerraty 		    "must be a positive number\n",
43298875883SSimon J. Gerraty 		    progname, arg);
43306b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
434956e45f6SSimon J. Gerraty 	}
43598875883SSimon J. Gerraty 	snprintf(v, sizeof(v), "%d", opts.maxJobs);
436dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-j");
43798875883SSimon J. Gerraty 	Global_Append(MAKEFLAGS, v);
43898875883SSimon J. Gerraty 	Global_Set(".MAKE.JOBS", v);
439956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
440956e45f6SSimon J. Gerraty }
441956e45f6SSimon J. Gerraty 
442956e45f6SSimon J. Gerraty static void
443956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
444956e45f6SSimon J. Gerraty {
445*d5e0a182SSimon 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;
449dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, found_path);
450956e45f6SSimon J. Gerraty 		free(found_path);
451956e45f6SSimon J. Gerraty 	} else {
452dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, argvalue);
453956e45f6SSimon J. Gerraty 	}
454dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-m");
455dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
4564fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
457956e45f6SSimon J. Gerraty }
458956e45f6SSimon J. Gerraty 
459b0c40a00SSimon J. Gerraty static bool
4608c973ee2SSimon J. Gerraty MainParseOption(char c, const char *argvalue)
461956e45f6SSimon J. Gerraty {
462956e45f6SSimon J. Gerraty 	switch (c) {
463956e45f6SSimon J. Gerraty 	case '\0':
464956e45f6SSimon J. Gerraty 		break;
465956e45f6SSimon J. Gerraty 	case 'B':
466b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
467dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-B");
4688c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.MODE", "compat");
469956e45f6SSimon J. Gerraty 		break;
470956e45f6SSimon J. Gerraty 	case 'C':
471956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
472956e45f6SSimon J. Gerraty 		break;
473956e45f6SSimon J. Gerraty 	case 'D':
4749f45a3c8SSimon J. Gerraty 		if (argvalue[0] == '\0')
4759f45a3c8SSimon J. Gerraty 			return false;
4769f45a3c8SSimon J. Gerraty 		Var_SetExpand(SCOPE_GLOBAL, argvalue, "1");
477dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-D");
478dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
479956e45f6SSimon J. Gerraty 		break;
480956e45f6SSimon J. Gerraty 	case 'I':
481*d5e0a182SSimon J. Gerraty 		SearchPath_Add(parseIncPath, argvalue);
482dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-I");
483dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
484956e45f6SSimon J. Gerraty 		break;
485956e45f6SSimon J. Gerraty 	case 'J':
486956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
487956e45f6SSimon J. Gerraty 		break;
488956e45f6SSimon J. Gerraty 	case 'N':
489b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
490b0c40a00SSimon J. Gerraty 		opts.noRecursiveExecute = true;
491dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-N");
492956e45f6SSimon J. Gerraty 		break;
493956e45f6SSimon J. Gerraty 	case 'S':
494b0c40a00SSimon J. Gerraty 		opts.keepgoing = false;
495dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-S");
496956e45f6SSimon J. Gerraty 		break;
497956e45f6SSimon J. Gerraty 	case 'T':
498956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
499dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-T");
500dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
501956e45f6SSimon J. Gerraty 		break;
502956e45f6SSimon J. Gerraty 	case 'V':
503956e45f6SSimon J. Gerraty 	case 'v':
504e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
50506b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
506956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
507dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-V");
508dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
509956e45f6SSimon J. Gerraty 		break;
510956e45f6SSimon J. Gerraty 	case 'W':
511b0c40a00SSimon J. Gerraty 		opts.parseWarnFatal = true;
5129f45a3c8SSimon J. Gerraty 		/* XXX: why no Global_Append? */
513956e45f6SSimon J. Gerraty 		break;
514956e45f6SSimon J. Gerraty 	case 'X':
515b0c40a00SSimon J. Gerraty 		opts.varNoExportEnv = true;
516dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-X");
517956e45f6SSimon J. Gerraty 		break;
518956e45f6SSimon J. Gerraty 	case 'd':
519956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
520956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
521956e45f6SSimon J. Gerraty 			argvalue++;
522956e45f6SSimon J. Gerraty 		else {
523dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, "-d");
524dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, argvalue);
525956e45f6SSimon J. Gerraty 		}
526dba7b0efSSimon J. Gerraty 		MainParseArgDebug(argvalue);
527956e45f6SSimon J. Gerraty 		break;
528956e45f6SSimon J. Gerraty 	case 'e':
529b0c40a00SSimon J. Gerraty 		opts.checkEnvFirst = true;
530dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-e");
531956e45f6SSimon J. Gerraty 		break;
532956e45f6SSimon J. Gerraty 	case 'f':
53306b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
534956e45f6SSimon J. Gerraty 		break;
535956e45f6SSimon J. Gerraty 	case 'i':
536b0c40a00SSimon J. Gerraty 		opts.ignoreErrors = true;
537dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-i");
538956e45f6SSimon J. Gerraty 		break;
539956e45f6SSimon J. Gerraty 	case 'j':
540956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
541956e45f6SSimon J. Gerraty 		break;
542956e45f6SSimon J. Gerraty 	case 'k':
543b0c40a00SSimon J. Gerraty 		opts.keepgoing = true;
544dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-k");
545956e45f6SSimon J. Gerraty 		break;
546956e45f6SSimon J. Gerraty 	case 'm':
547956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
548e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
549956e45f6SSimon J. Gerraty 		break;
550956e45f6SSimon J. Gerraty 	case 'n':
551b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
552dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-n");
553956e45f6SSimon J. Gerraty 		break;
554956e45f6SSimon J. Gerraty 	case 'q':
5559f45a3c8SSimon J. Gerraty 		opts.query = true;
556956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
557dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-q");
558956e45f6SSimon J. Gerraty 		break;
559956e45f6SSimon J. Gerraty 	case 'r':
560b0c40a00SSimon J. Gerraty 		opts.noBuiltins = true;
561dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-r");
562956e45f6SSimon J. Gerraty 		break;
563956e45f6SSimon J. Gerraty 	case 's':
5649f45a3c8SSimon J. Gerraty 		opts.silent = true;
565dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-s");
566956e45f6SSimon J. Gerraty 		break;
567956e45f6SSimon J. Gerraty 	case 't':
5689f45a3c8SSimon J. Gerraty 		opts.touch = true;
569dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-t");
570956e45f6SSimon J. Gerraty 		break;
571956e45f6SSimon J. Gerraty 	case 'w':
572b0c40a00SSimon J. Gerraty 		opts.enterFlag = true;
573dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-w");
574956e45f6SSimon J. Gerraty 		break;
575956e45f6SSimon J. Gerraty 	default:
576956e45f6SSimon J. Gerraty 		usage();
577956e45f6SSimon J. Gerraty 	}
578b0c40a00SSimon J. Gerraty 	return true;
579956e45f6SSimon J. Gerraty }
580956e45f6SSimon J. Gerraty 
58106b9b3e0SSimon J. Gerraty /*
58206b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5833955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5843955d011SMarcel Moolenaar  *
585956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
586956e45f6SSimon J. Gerraty  * call.
5873955d011SMarcel Moolenaar  *
58806b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
58906b9b3e0SSimon J. Gerraty  */
5903955d011SMarcel Moolenaar static void
5913955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5923955d011SMarcel Moolenaar {
593956e45f6SSimon J. Gerraty 	char c;
5943955d011SMarcel Moolenaar 	int arginc;
5953955d011SMarcel Moolenaar 	char *argvalue;
5963955d011SMarcel Moolenaar 	char *optscan;
597b0c40a00SSimon J. Gerraty 	bool inOption, dashDash = false;
5983955d011SMarcel Moolenaar 
599956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
6003955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
6013955d011SMarcel Moolenaar 
6023955d011SMarcel Moolenaar rearg:
603b0c40a00SSimon J. Gerraty 	inOption = false;
6043955d011SMarcel Moolenaar 	optscan = NULL;
6053955d011SMarcel Moolenaar 	while (argc > 1) {
606956e45f6SSimon J. Gerraty 		const char *optspec;
6073955d011SMarcel Moolenaar 		if (!inOption)
6083955d011SMarcel Moolenaar 			optscan = argv[1];
6093955d011SMarcel Moolenaar 		c = *optscan++;
6103955d011SMarcel Moolenaar 		arginc = 0;
6113955d011SMarcel Moolenaar 		if (inOption) {
6123955d011SMarcel Moolenaar 			if (c == '\0') {
613e2eeea75SSimon J. Gerraty 				argv++;
614e2eeea75SSimon J. Gerraty 				argc--;
615b0c40a00SSimon J. Gerraty 				inOption = false;
6163955d011SMarcel Moolenaar 				continue;
6173955d011SMarcel Moolenaar 			}
6183955d011SMarcel Moolenaar 		} else {
6193955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6203955d011SMarcel Moolenaar 				break;
621b0c40a00SSimon J. Gerraty 			inOption = true;
6223955d011SMarcel Moolenaar 			c = *optscan++;
6233955d011SMarcel Moolenaar 		}
6243955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
625956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
626956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6279f45a3c8SSimon J. Gerraty 			/*
6289f45a3c8SSimon J. Gerraty 			 * -<something> found, and <something> should have an
6299f45a3c8SSimon J. Gerraty 			 * argument
6309f45a3c8SSimon J. Gerraty 			 */
631b0c40a00SSimon J. Gerraty 			inOption = false;
6323955d011SMarcel Moolenaar 			arginc = 1;
6333955d011SMarcel Moolenaar 			argvalue = optscan;
6343955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6353955d011SMarcel Moolenaar 				if (argc < 3)
6363955d011SMarcel Moolenaar 					goto noarg;
6373955d011SMarcel Moolenaar 				argvalue = argv[2];
6383955d011SMarcel Moolenaar 				arginc = 2;
6393955d011SMarcel Moolenaar 			}
6403955d011SMarcel Moolenaar 		} else {
6413955d011SMarcel Moolenaar 			argvalue = NULL;
6423955d011SMarcel Moolenaar 		}
6433955d011SMarcel Moolenaar 		switch (c) {
6443955d011SMarcel Moolenaar 		case '\0':
6453955d011SMarcel Moolenaar 			arginc = 1;
646b0c40a00SSimon J. Gerraty 			inOption = false;
6473955d011SMarcel Moolenaar 			break;
6483955d011SMarcel Moolenaar 		case '-':
649b0c40a00SSimon J. Gerraty 			dashDash = true;
6503955d011SMarcel Moolenaar 			break;
6513955d011SMarcel Moolenaar 		default:
6528c973ee2SSimon J. Gerraty 			if (!MainParseOption(c, argvalue))
653956e45f6SSimon J. Gerraty 				goto noarg;
6543955d011SMarcel Moolenaar 		}
6553955d011SMarcel Moolenaar 		argv += arginc;
6563955d011SMarcel Moolenaar 		argc -= arginc;
6573955d011SMarcel Moolenaar 	}
6583955d011SMarcel Moolenaar 
6593955d011SMarcel Moolenaar 	/*
6603955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6613955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6623955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6633955d011SMarcel Moolenaar 	 */
664dba7b0efSSimon J. Gerraty 	for (; argc > 1; argv++, argc--) {
6659f45a3c8SSimon J. Gerraty 		if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) {
666e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6673955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
668e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6693955d011SMarcel Moolenaar 				goto rearg;
67006b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
671956e45f6SSimon J. Gerraty 		}
6723955d011SMarcel Moolenaar 	}
6733955d011SMarcel Moolenaar 
6743955d011SMarcel Moolenaar 	return;
6753955d011SMarcel Moolenaar noarg:
6763955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6773955d011SMarcel Moolenaar 	    progname, c);
6783955d011SMarcel Moolenaar 	usage();
6793955d011SMarcel Moolenaar }
6803955d011SMarcel Moolenaar 
68106b9b3e0SSimon J. Gerraty /*
68206b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6833955d011SMarcel Moolenaar  *
684956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
68506b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
68606b9b3e0SSimon J. Gerraty  */
6873955d011SMarcel Moolenaar void
6883955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6893955d011SMarcel Moolenaar {
6902c3632d1SSimon J. Gerraty 	Words words;
6912c3632d1SSimon J. Gerraty 	char *buf;
692*d5e0a182SSimon J. Gerraty 	const char *p;
6933955d011SMarcel Moolenaar 
6943955d011SMarcel Moolenaar 	if (line == NULL)
6953955d011SMarcel Moolenaar 		return;
696*d5e0a182SSimon J. Gerraty 	for (p = line; *p == ' '; p++)
6973955d011SMarcel Moolenaar 		continue;
698*d5e0a182SSimon J. Gerraty 	if (p[0] == '\0')
6993955d011SMarcel Moolenaar 		return;
7003955d011SMarcel Moolenaar 
7013955d011SMarcel Moolenaar #ifndef POSIX
7023955d011SMarcel Moolenaar 	{
7033955d011SMarcel Moolenaar 		/*
7043955d011SMarcel Moolenaar 		 * $MAKE may simply be naming the make(1) binary
7053955d011SMarcel Moolenaar 		 */
7063955d011SMarcel Moolenaar 		char *cp;
7073955d011SMarcel Moolenaar 
7083955d011SMarcel Moolenaar 		if (!(cp = strrchr(line, '/')))
7093955d011SMarcel Moolenaar 			cp = line;
7103955d011SMarcel Moolenaar 		if ((cp = strstr(cp, "make")) &&
7113955d011SMarcel Moolenaar 		    strcmp(cp, "make") == 0)
7123955d011SMarcel Moolenaar 			return;
7133955d011SMarcel Moolenaar 	}
7143955d011SMarcel Moolenaar #endif
715e2eeea75SSimon J. Gerraty 	{
716dba7b0efSSimon J. Gerraty 		FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
717*d5e0a182SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", p);
71806b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
719e2eeea75SSimon J. Gerraty 	}
7203955d011SMarcel Moolenaar 
721b0c40a00SSimon J. Gerraty 	words = Str_Words(buf, true);
7222c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7233955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7243955d011SMarcel Moolenaar 		free(buf);
7253955d011SMarcel Moolenaar 		return;
7263955d011SMarcel Moolenaar 	}
7273955d011SMarcel Moolenaar 	free(buf);
7282c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7293955d011SMarcel Moolenaar 
7302c3632d1SSimon J. Gerraty 	Words_Free(words);
7313955d011SMarcel Moolenaar }
7323955d011SMarcel Moolenaar 
733b0c40a00SSimon J. Gerraty bool
734b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...)
7353955d011SMarcel Moolenaar {
7363955d011SMarcel Moolenaar 	struct stat sb;
737b46b9039SSimon J. Gerraty 	char *path;
738b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
739e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
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] != '/') {
7474fde40d9SSimon J. Gerraty 		if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN)
748e1cee40dSSimon J. Gerraty 			path = buf2;
7494fde40d9SSimon J. Gerraty 		else
7504fde40d9SSimon J. Gerraty 			return false;
7513955d011SMarcel Moolenaar 	}
7523955d011SMarcel Moolenaar 
7533955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7549f45a3c8SSimon J. Gerraty 	if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
7559f45a3c8SSimon J. Gerraty 		return false;
7569f45a3c8SSimon J. Gerraty 
7579f45a3c8SSimon J. Gerraty 	if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
7581d3f2ddcSSimon J. Gerraty 		(void)fprintf(stderr, "%s: warning: %s: %s.\n",
759e2eeea75SSimon J. Gerraty 		    progname, path, strerror(errno));
7609f45a3c8SSimon J. Gerraty 		return false;
7619f45a3c8SSimon J. Gerraty 	}
7629f45a3c8SSimon J. Gerraty 
7632c3632d1SSimon J. Gerraty 	snprintf(objdir, sizeof objdir, "%s", path);
764dba7b0efSSimon J. Gerraty 	Global_Set(".OBJDIR", objdir);
7653955d011SMarcel Moolenaar 	setenv("PWD", objdir, 1);
7663955d011SMarcel Moolenaar 	Dir_InitDot();
767e2eeea75SSimon J. Gerraty 	purge_relative_cached_realpaths();
768956e45f6SSimon J. Gerraty 	if (opts.enterFlag && strcmp(objdir, curdir) != 0)
769b0c40a00SSimon J. Gerraty 		enterFlagObj = true;
7709f45a3c8SSimon J. Gerraty 	return true;
7713955d011SMarcel Moolenaar }
7723955d011SMarcel Moolenaar 
773b0c40a00SSimon J. Gerraty static bool
774b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix)
77545447996SSimon J. Gerraty {
776dba7b0efSSimon J. Gerraty 	FStr path = Var_Value(SCOPE_CMDLINE, var);
777b46b9039SSimon J. Gerraty 
77806b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
77906b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
780b0c40a00SSimon J. Gerraty 		return false;
7812c3632d1SSimon J. Gerraty 	}
78245447996SSimon J. Gerraty 
7839f45a3c8SSimon J. Gerraty 	Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES);
784b46b9039SSimon J. Gerraty 
7859f45a3c8SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
786b46b9039SSimon J. Gerraty 
78706b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
788b0c40a00SSimon J. Gerraty 	return true;
78945447996SSimon J. Gerraty }
79045447996SSimon J. Gerraty 
79106b9b3e0SSimon J. Gerraty /*
792*d5e0a182SSimon J. Gerraty  * Splits str into words (in-place, modifying it), adding them to the list.
79306b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
79406b9b3e0SSimon J. Gerraty  */
795*d5e0a182SSimon J. Gerraty void
796*d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str)
7973955d011SMarcel Moolenaar {
798*d5e0a182SSimon J. Gerraty 	char *p;
799e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
8003955d011SMarcel Moolenaar 
801*d5e0a182SSimon J. Gerraty 	for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep))
802*d5e0a182SSimon J. Gerraty 		Lst_Append(lp, p);
8033955d011SMarcel Moolenaar }
8043955d011SMarcel Moolenaar 
8053955d011SMarcel Moolenaar #ifdef SIGINFO
8063955d011SMarcel Moolenaar /*ARGSUSED*/
8073955d011SMarcel Moolenaar static void
8083955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED)
8093955d011SMarcel Moolenaar {
8103955d011SMarcel Moolenaar 	char dir[MAXPATHLEN];
8113955d011SMarcel Moolenaar 	char str[2 * MAXPATHLEN];
8123955d011SMarcel Moolenaar 	int len;
813e2eeea75SSimon J. Gerraty 	if (getcwd(dir, sizeof dir) == NULL)
8143955d011SMarcel Moolenaar 		return;
815e2eeea75SSimon J. Gerraty 	len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
8163955d011SMarcel Moolenaar 	if (len > 0)
8173955d011SMarcel Moolenaar 		(void)write(STDERR_FILENO, str, (size_t)len);
8183955d011SMarcel Moolenaar }
8193955d011SMarcel Moolenaar #endif
8203955d011SMarcel Moolenaar 
82106b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */
82206b9b3e0SSimon J. Gerraty static void
82306b9b3e0SSimon J. Gerraty MakeMode(void)
8243955d011SMarcel Moolenaar {
8258c973ee2SSimon J. Gerraty 	char *mode = Var_Subst("${.MAKE.MODE:tl}",
8268c973ee2SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_WANTRES);
827956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
8283955d011SMarcel Moolenaar 
829dba7b0efSSimon J. Gerraty 	if (mode[0] != '\0') {
830dba7b0efSSimon J. Gerraty 		if (strstr(mode, "compat") != NULL) {
831b0c40a00SSimon J. Gerraty 			opts.compatMake = true;
832b0c40a00SSimon J. Gerraty 			forceJobs = false;
8333955d011SMarcel Moolenaar 		}
8343955d011SMarcel Moolenaar #if USE_META
835dba7b0efSSimon J. Gerraty 		if (strstr(mode, "meta") != NULL)
836dba7b0efSSimon J. Gerraty 			meta_mode_init(mode);
8373955d011SMarcel Moolenaar #endif
838954401e6SSimon J. Gerraty 		if (strstr(mode, "randomize-targets") != NULL)
839954401e6SSimon J. Gerraty 			opts.randomizeTargets = true;
8403955d011SMarcel Moolenaar 	}
841be19d90bSSimon J. Gerraty 
842dba7b0efSSimon J. Gerraty 	free(mode);
8433955d011SMarcel Moolenaar }
8443955d011SMarcel Moolenaar 
8458695518cSSimon J. Gerraty static void
846b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars)
847956e45f6SSimon J. Gerraty {
84806b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
8498c973ee2SSimon J. Gerraty 		char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES);
850956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
851956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8529f45a3c8SSimon J. Gerraty 		free(evalue);
853956e45f6SSimon J. Gerraty 
854956e45f6SSimon J. Gerraty 	} else if (expandVars) {
855956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
8568c973ee2SSimon J. Gerraty 		char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
857956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
858956e45f6SSimon J. Gerraty 		free(expr);
859956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8609f45a3c8SSimon J. Gerraty 		free(evalue);
861956e45f6SSimon J. Gerraty 
862956e45f6SSimon J. Gerraty 	} else {
863dba7b0efSSimon J. Gerraty 		FStr value = Var_Value(SCOPE_GLOBAL, varname);
86406b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
86506b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
866956e45f6SSimon J. Gerraty 	}
867956e45f6SSimon J. Gerraty }
868956e45f6SSimon J. Gerraty 
869e2eeea75SSimon J. Gerraty /*
870b0c40a00SSimon J. Gerraty  * Return a bool based on a variable.
871e2eeea75SSimon J. Gerraty  *
872e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
873e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
874b0c40a00SSimon J. Gerraty  * is false, otherwise true.
875e2eeea75SSimon J. Gerraty  */
876b0c40a00SSimon J. Gerraty bool
877b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback)
878e2eeea75SSimon J. Gerraty {
879e2eeea75SSimon J. Gerraty 	char *value;
880b0c40a00SSimon J. Gerraty 	bool res;
881e2eeea75SSimon J. Gerraty 
8828c973ee2SSimon J. Gerraty 	value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
883e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
884e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
885e2eeea75SSimon J. Gerraty 	free(value);
886e2eeea75SSimon J. Gerraty 	return res;
887e2eeea75SSimon J. Gerraty }
888e2eeea75SSimon J. Gerraty 
889956e45f6SSimon J. Gerraty static void
8908695518cSSimon J. Gerraty doPrintVars(void)
8918695518cSSimon J. Gerraty {
892956e45f6SSimon J. Gerraty 	StringListNode *ln;
893b0c40a00SSimon J. Gerraty 	bool expandVars;
8948695518cSSimon J. Gerraty 
895e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
896b0c40a00SSimon J. Gerraty 		expandVars = true;
897956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
898b0c40a00SSimon J. Gerraty 		expandVars = false;
8998695518cSSimon J. Gerraty 	else
900b0c40a00SSimon J. Gerraty 		expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}",
901b0c40a00SSimon J. Gerraty 		    false);
9028695518cSSimon J. Gerraty 
90306b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
904956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
905956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
9068695518cSSimon J. Gerraty 	}
9078695518cSSimon J. Gerraty }
9088695518cSSimon J. Gerraty 
909b0c40a00SSimon J. Gerraty static bool
9108695518cSSimon J. Gerraty runTargets(void)
9118695518cSSimon J. Gerraty {
91206b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
913b0c40a00SSimon J. Gerraty 	bool outOfDate;		/* false if all targets up to date */
9148695518cSSimon J. Gerraty 
9158695518cSSimon J. Gerraty 	/*
9168695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9178695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9188695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9198695518cSSimon J. Gerraty 	 * to create.
9208695518cSSimon J. Gerraty 	 */
92106b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
92206b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9238695518cSSimon J. Gerraty 	else
92406b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9258695518cSSimon J. Gerraty 
926956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9278695518cSSimon J. Gerraty 		/*
9288695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9298695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9308695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9318695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9328695518cSSimon J. Gerraty 		 * it exist).
9338695518cSSimon J. Gerraty 		 */
9349f45a3c8SSimon J. Gerraty 		if (!opts.query) {
9358695518cSSimon J. Gerraty 			Job_Init();
936b0c40a00SSimon J. Gerraty 			jobsRunning = true;
9378695518cSSimon J. Gerraty 		}
9388695518cSSimon J. Gerraty 
9398695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
94006b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9418695518cSSimon J. Gerraty 	} else {
942954401e6SSimon J. Gerraty 		Compat_MakeAll(&targs);
943b0c40a00SSimon J. Gerraty 		outOfDate = false;
9448695518cSSimon J. Gerraty 	}
945dba7b0efSSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the targets themselves. */
9468695518cSSimon J. Gerraty 	return outOfDate;
9478695518cSSimon J. Gerraty }
9488695518cSSimon J. Gerraty 
949956e45f6SSimon J. Gerraty /*
9509f45a3c8SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be created.
9519f45a3c8SSimon J. Gerraty  * If none specified, make the variable empty for now, the parser will fill
9529f45a3c8SSimon J. Gerraty  * in the default or .MAIN target later.
953956e45f6SSimon J. Gerraty  */
954956e45f6SSimon J. Gerraty static void
955956e45f6SSimon J. Gerraty InitVarTargets(void)
956956e45f6SSimon J. Gerraty {
957956e45f6SSimon J. Gerraty 	StringListNode *ln;
958956e45f6SSimon J. Gerraty 
95906b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
960dba7b0efSSimon J. Gerraty 		Global_Set(".TARGETS", "");
961956e45f6SSimon J. Gerraty 		return;
962956e45f6SSimon J. Gerraty 	}
963956e45f6SSimon J. Gerraty 
96406b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
965dba7b0efSSimon J. Gerraty 		const char *name = ln->datum;
966dba7b0efSSimon J. Gerraty 		Global_Append(".TARGETS", name);
967956e45f6SSimon J. Gerraty 	}
968956e45f6SSimon J. Gerraty }
969956e45f6SSimon J. Gerraty 
970956e45f6SSimon J. Gerraty static void
971956e45f6SSimon J. Gerraty InitRandom(void)
972956e45f6SSimon J. Gerraty {
973956e45f6SSimon J. Gerraty 	struct timeval tv;
974956e45f6SSimon J. Gerraty 
975956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
976956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
977956e45f6SSimon J. Gerraty }
978956e45f6SSimon J. Gerraty 
979956e45f6SSimon J. Gerraty static const char *
980dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED)
981956e45f6SSimon J. Gerraty {
982956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
983e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
984956e45f6SSimon J. Gerraty #else
985956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
986e2eeea75SSimon J. Gerraty 
987956e45f6SSimon J. Gerraty 	if (machine != NULL)
988956e45f6SSimon J. Gerraty 		return machine;
989956e45f6SSimon J. Gerraty 
990e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
991956e45f6SSimon J. Gerraty 	return utsname->machine;
992e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
993956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
994956e45f6SSimon J. Gerraty #else
995956e45f6SSimon J. Gerraty 	return "unknown";
996956e45f6SSimon J. Gerraty #endif
997956e45f6SSimon J. Gerraty #endif
998956e45f6SSimon J. Gerraty }
999956e45f6SSimon J. Gerraty 
1000956e45f6SSimon J. Gerraty static const char *
1001e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
1002956e45f6SSimon J. Gerraty {
1003e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
1004e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
1005e2eeea75SSimon J. Gerraty #else
1006956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
1007956e45f6SSimon J. Gerraty 	if (env != NULL)
1008956e45f6SSimon J. Gerraty 		return env;
1009956e45f6SSimon J. Gerraty 
1010956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
1011956e45f6SSimon J. Gerraty 	{
1012956e45f6SSimon J. Gerraty 		struct utsname utsname;
1013e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
1014956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1015e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1016956e45f6SSimon J. Gerraty 
101706b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
101806b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
101906b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
102006b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1021956e45f6SSimon J. Gerraty 			exit(2);
1022956e45f6SSimon J. Gerraty 		}
1023956e45f6SSimon J. Gerraty 
1024956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1025956e45f6SSimon J. Gerraty 	}
1026e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1027e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1028e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1029956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1030956e45f6SSimon J. Gerraty #else
1031956e45f6SSimon J. Gerraty 	return "unknown";
1032956e45f6SSimon J. Gerraty #endif
1033956e45f6SSimon J. Gerraty #endif
1034956e45f6SSimon J. Gerraty }
1035956e45f6SSimon J. Gerraty 
1036956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1037956e45f6SSimon J. Gerraty /*
1038956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1039956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1040*d5e0a182SSimon J. Gerraty  * here.  That is, sitting at a shell prompt (shell that provides $PWD)
1041*d5e0a182SSimon J. Gerraty  * or via subdir.mk, in which case it's likely a shell which does
1042956e45f6SSimon J. Gerraty  * not provide it.
1043956e45f6SSimon J. Gerraty  *
1044956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1045*d5e0a182SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression.
1046956e45f6SSimon J. Gerraty  */
1047956e45f6SSimon J. Gerraty static void
1048956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1049956e45f6SSimon J. Gerraty {
1050956e45f6SSimon J. Gerraty 	char *pwd;
10519f45a3c8SSimon J. Gerraty 	FStr makeobjdir;
1052956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1053956e45f6SSimon J. Gerraty 
1054956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1055956e45f6SSimon J. Gerraty 		return;
1056956e45f6SSimon J. Gerraty 
10579f45a3c8SSimon J. Gerraty 	if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"))
1058956e45f6SSimon J. Gerraty 		return;
1059956e45f6SSimon J. Gerraty 
1060dba7b0efSSimon J. Gerraty 	makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
106106b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1062956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1063956e45f6SSimon J. Gerraty 
1064956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1065956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1066956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
1067956e45f6SSimon J. Gerraty 		(void)strncpy(curdir, pwd, MAXPATHLEN);
1068956e45f6SSimon J. Gerraty 
1069956e45f6SSimon J. Gerraty ignore_pwd:
107006b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1071956e45f6SSimon J. Gerraty }
1072956e45f6SSimon J. Gerraty #endif
1073956e45f6SSimon J. Gerraty 
1074956e45f6SSimon J. Gerraty /*
10759f45a3c8SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set
10769f45a3c8SSimon J. Gerraty  * in the environment, try only that value and fall back to .CURDIR if it
10779f45a3c8SSimon J. Gerraty  * does not exist.
1078956e45f6SSimon J. Gerraty  *
1079956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
10809f45a3c8SSimon J. Gerraty  * and finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none of these
10819f45a3c8SSimon J. Gerraty  * paths exist, just use .CURDIR.
1082956e45f6SSimon J. Gerraty  */
1083956e45f6SSimon J. Gerraty static void
1084956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1085956e45f6SSimon J. Gerraty {
1086b0c40a00SSimon J. Gerraty 	bool writable;
1087956e45f6SSimon J. Gerraty 
108806b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1089b0c40a00SSimon J. Gerraty 	writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true);
1090b0c40a00SSimon J. Gerraty 	(void)Main_SetObjdir(false, "%s", curdir);
1091e2eeea75SSimon J. Gerraty 
1092e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1093e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1094e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1095e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1096e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1097e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1098956e45f6SSimon J. Gerraty }
1099956e45f6SSimon J. Gerraty 
1100956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1101956e45f6SSimon J. Gerraty static void
1102956e45f6SSimon J. Gerraty UnlimitFiles(void)
1103956e45f6SSimon J. Gerraty {
110412904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
1105956e45f6SSimon J. Gerraty 	struct rlimit rl;
1106956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1107956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
11088c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX
11098c973ee2SSimon J. Gerraty 		if (BMAKE_NOFILE_MAX < rl.rlim_max)
11108c973ee2SSimon J. Gerraty 			rl.rlim_cur = BMAKE_NOFILE_MAX;
11118c973ee2SSimon J. Gerraty 		else
11128c973ee2SSimon J. Gerraty #endif
1113956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1114956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1115956e45f6SSimon J. Gerraty 	}
1116956e45f6SSimon J. Gerraty #endif
1117956e45f6SSimon J. Gerraty }
1118956e45f6SSimon J. Gerraty 
1119956e45f6SSimon J. Gerraty static void
1120956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1121956e45f6SSimon J. Gerraty {
1122b0c40a00SSimon J. Gerraty 	opts.compatMake = false;
11239f45a3c8SSimon J. Gerraty 	memset(&opts.debug, 0, sizeof(opts.debug));
1124dba7b0efSSimon J. Gerraty 	/* opts.debug_file has already been initialized earlier */
1125b0c40a00SSimon J. Gerraty 	opts.strict = false;
1126b0c40a00SSimon J. Gerraty 	opts.debugVflag = false;
1127b0c40a00SSimon J. Gerraty 	opts.checkEnvFirst = false;
112806b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1129b0c40a00SSimon J. Gerraty 	opts.ignoreErrors = false;	/* Pay attention to non-zero returns */
113006b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1131b0c40a00SSimon J. Gerraty 	opts.keepgoing = false;		/* Stop on error */
1132b0c40a00SSimon J. Gerraty 	opts.noRecursiveExecute = false; /* Execute all .MAKE targets */
1133b0c40a00SSimon J. Gerraty 	opts.noExecute = false;		/* Execute all commands */
11349f45a3c8SSimon J. Gerraty 	opts.query = false;
1135b0c40a00SSimon J. Gerraty 	opts.noBuiltins = false;	/* Read the built-in rules */
11369f45a3c8SSimon J. Gerraty 	opts.silent = false;		/* Print commands as executed */
11379f45a3c8SSimon J. Gerraty 	opts.touch = false;
1138e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
113906b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1140b0c40a00SSimon J. Gerraty 	opts.parseWarnFatal = false;
1141b0c40a00SSimon J. Gerraty 	opts.enterFlag = false;
1142b0c40a00SSimon J. Gerraty 	opts.varNoExportEnv = false;
114306b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1144956e45f6SSimon J. Gerraty }
1145956e45f6SSimon J. Gerraty 
114606b9b3e0SSimon J. Gerraty /*
114706b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1148956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1149956e45f6SSimon J. Gerraty  *
1150956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
115106b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
115206b9b3e0SSimon J. Gerraty  */
1153956e45f6SSimon J. Gerraty static void
1154956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1155956e45f6SSimon J. Gerraty {
1156956e45f6SSimon J. Gerraty 	const char *make = argv0;
1157956e45f6SSimon J. Gerraty 
1158956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1159956e45f6SSimon J. Gerraty 		char pathbuf[MAXPATHLEN];
116006b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1161956e45f6SSimon J. Gerraty 		struct stat st;
116206b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
116306b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
116406b9b3e0SSimon J. Gerraty 			make = abspath;
1165956e45f6SSimon J. Gerraty 	}
1166956e45f6SSimon J. Gerraty 
1167dba7b0efSSimon J. Gerraty 	Global_Set("MAKE", make);
1168dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE", make);
1169956e45f6SSimon J. Gerraty }
1170956e45f6SSimon J. Gerraty 
117106b9b3e0SSimon J. Gerraty /*
117206b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
117306b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
117406b9b3e0SSimon J. Gerraty  */
1175956e45f6SSimon J. Gerraty static void
1176956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1177956e45f6SSimon J. Gerraty {
1178956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1179*d5e0a182SSimon J. Gerraty 	char *start, *p;
1180956e45f6SSimon J. Gerraty 
1181956e45f6SSimon J. Gerraty 	/*
1182956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1183956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1184956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1185956e45f6SSimon J. Gerraty 	 */
1186956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1187956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1188956e45f6SSimon J. Gerraty 	else
1189956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1190956e45f6SSimon J. Gerraty 
1191*d5e0a182SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = p) {
1192*d5e0a182SSimon J. Gerraty 		for (p = start; *p != '\0' && *p != ':'; p++)
1193956e45f6SSimon J. Gerraty 			continue;
1194*d5e0a182SSimon J. Gerraty 		if (*p == ':')
1195*d5e0a182SSimon J. Gerraty 			*p++ = '\0';
1196e2eeea75SSimon J. Gerraty 
1197956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1198e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1199956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1200956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1201dba7b0efSSimon J. Gerraty 				(void)SearchPath_Add(defSysIncPath, dir);
1202956e45f6SSimon J. Gerraty 				free(dir);
1203956e45f6SSimon J. Gerraty 			}
1204e2eeea75SSimon J. Gerraty 		} else {
1205dba7b0efSSimon J. Gerraty 			(void)SearchPath_Add(defSysIncPath, start);
1206956e45f6SSimon J. Gerraty 		}
1207956e45f6SSimon J. Gerraty 	}
1208956e45f6SSimon J. Gerraty 
1209956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1210956e45f6SSimon J. Gerraty 		free(syspath);
1211956e45f6SSimon J. Gerraty }
1212956e45f6SSimon J. Gerraty 
1213956e45f6SSimon J. Gerraty static void
1214956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1215956e45f6SSimon J. Gerraty {
1216e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1217dba7b0efSSimon J. Gerraty 	StringList sysMkFiles = LST_INIT;
1218e2eeea75SSimon J. Gerraty 
1219dba7b0efSSimon J. Gerraty 	SearchPath_Expand(
1220dba7b0efSSimon J. Gerraty 	    Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath,
1221dba7b0efSSimon J. Gerraty 	    _PATH_DEFSYSMK,
1222dba7b0efSSimon J. Gerraty 	    &sysMkFiles);
1223dba7b0efSSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkFiles))
1224956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1225e2eeea75SSimon J. Gerraty 
1226dba7b0efSSimon J. Gerraty 	for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
12279f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1228e2eeea75SSimon J. Gerraty 			break;
1229e2eeea75SSimon J. Gerraty 
1230e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1231e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1232dba7b0efSSimon J. Gerraty 		    progname, (const char *)sysMkFiles.first->datum);
1233e2eeea75SSimon J. Gerraty 
12349f45a3c8SSimon J. Gerraty 	Lst_DoneCall(&sysMkFiles, free);
1235956e45f6SSimon J. Gerraty }
1236956e45f6SSimon J. Gerraty 
1237956e45f6SSimon J. Gerraty static void
1238956e45f6SSimon J. Gerraty InitMaxJobs(void)
1239956e45f6SSimon J. Gerraty {
1240956e45f6SSimon J. Gerraty 	char *value;
1241956e45f6SSimon J. Gerraty 	int n;
1242956e45f6SSimon J. Gerraty 
1243956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1244dba7b0efSSimon J. Gerraty 	    !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
1245956e45f6SSimon J. Gerraty 		return;
1246956e45f6SSimon J. Gerraty 
12478c973ee2SSimon J. Gerraty 	value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES);
1248956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1249956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1250956e45f6SSimon J. Gerraty 	if (n < 1) {
1251956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1252956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1253956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1254956e45f6SSimon J. Gerraty 		    progname);
125506b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1256956e45f6SSimon J. Gerraty 	}
1257956e45f6SSimon J. Gerraty 
1258956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1259dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-j");
1260dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, value);
1261956e45f6SSimon J. Gerraty 	}
1262956e45f6SSimon J. Gerraty 
1263956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1264956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1265b0c40a00SSimon J. Gerraty 	forceJobs = true;
1266956e45f6SSimon J. Gerraty 	free(value);
1267956e45f6SSimon J. Gerraty }
1268956e45f6SSimon J. Gerraty 
1269956e45f6SSimon J. Gerraty /*
1270956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1271956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1272956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1273956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1274956e45f6SSimon J. Gerraty  */
1275956e45f6SSimon J. Gerraty static void
1276956e45f6SSimon J. Gerraty InitVpath(void)
1277956e45f6SSimon J. Gerraty {
1278956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1279dba7b0efSSimon J. Gerraty 	if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
1280956e45f6SSimon J. Gerraty 		return;
1281956e45f6SSimon J. Gerraty 
12828c973ee2SSimon J. Gerraty 	vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES);
1283956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1284956e45f6SSimon J. Gerraty 	path = vpath;
1285956e45f6SSimon J. Gerraty 	do {
1286*d5e0a182SSimon J. Gerraty 		char *p;
1287956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1288*d5e0a182SSimon J. Gerraty 		for (p = path; *p != ':' && *p != '\0'; p++)
1289956e45f6SSimon J. Gerraty 			continue;
1290956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1291*d5e0a182SSimon J. Gerraty 		savec = *p;
1292*d5e0a182SSimon J. Gerraty 		*p = '\0';
1293956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1294dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(&dirSearchPath, path);
1295*d5e0a182SSimon J. Gerraty 		*p = savec;
1296*d5e0a182SSimon J. Gerraty 		path = p + 1;
1297956e45f6SSimon J. Gerraty 	} while (savec == ':');
1298956e45f6SSimon J. Gerraty 	free(vpath);
1299956e45f6SSimon J. Gerraty }
1300956e45f6SSimon J. Gerraty 
1301956e45f6SSimon J. Gerraty static void
13029f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles)
1303956e45f6SSimon J. Gerraty {
1304956e45f6SSimon J. Gerraty 	StringListNode *ln;
1305956e45f6SSimon J. Gerraty 
1306e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1307e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
13089f45a3c8SSimon J. Gerraty 		if (!ReadMakefile(fname))
1309e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1310956e45f6SSimon J. Gerraty 	}
1311956e45f6SSimon J. Gerraty }
1312956e45f6SSimon J. Gerraty 
1313956e45f6SSimon J. Gerraty static void
1314e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1315956e45f6SSimon J. Gerraty {
13169f45a3c8SSimon J. Gerraty 	StringList makefiles = LST_INIT;
1317e2eeea75SSimon J. Gerraty 	StringListNode *ln;
13188c973ee2SSimon J. Gerraty 	char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
13198c973ee2SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_WANTRES);
1320e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1321956e45f6SSimon J. Gerraty 
1322*d5e0a182SSimon J. Gerraty 	AppendWords(&makefiles, prefs);
1323956e45f6SSimon J. Gerraty 
13249f45a3c8SSimon J. Gerraty 	for (ln = makefiles.first; ln != NULL; ln = ln->next)
13259f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1326e2eeea75SSimon J. Gerraty 			break;
1327956e45f6SSimon J. Gerraty 
13289f45a3c8SSimon J. Gerraty 	Lst_Done(&makefiles);
1329e2eeea75SSimon J. Gerraty 	free(prefs);
1330956e45f6SSimon J. Gerraty }
1331956e45f6SSimon J. Gerraty 
133206b9b3e0SSimon J. Gerraty /*
133306b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1334e2eeea75SSimon J. Gerraty  * Initialize a few modules.
133506b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
133606b9b3e0SSimon J. Gerraty  */
1337e2eeea75SSimon J. Gerraty static void
1338e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13393955d011SMarcel Moolenaar {
1340956e45f6SSimon J. Gerraty 	struct stat sa;
1341956e45f6SSimon J. Gerraty 	const char *machine;
1342956e45f6SSimon J. Gerraty 	const char *machine_arch;
13433955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13443955d011SMarcel Moolenaar 	struct utsname utsname;
13453955d011SMarcel Moolenaar 
13463955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1347956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13483955d011SMarcel Moolenaar 
13499f45a3c8SSimon J. Gerraty 	Str_Intern_Init();
1350e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1351e2eeea75SSimon J. Gerraty 
13523955d011SMarcel Moolenaar #ifdef SIGINFO
13533955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13543955d011SMarcel Moolenaar #endif
1355956e45f6SSimon J. Gerraty 
1356956e45f6SSimon J. Gerraty 	InitRandom();
13573955d011SMarcel Moolenaar 
135806b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1359956e45f6SSimon J. Gerraty 
1360956e45f6SSimon J. Gerraty 	UnlimitFiles();
13613955d011SMarcel Moolenaar 
13621748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13631748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13641748de26SSimon J. Gerraty 		    strerror(errno));
13651748de26SSimon J. Gerraty 		exit(2);
13661748de26SSimon J. Gerraty 	}
13671748de26SSimon J. Gerraty 
1368e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1369e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
13703955d011SMarcel Moolenaar 
13713955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
13723955d011SMarcel Moolenaar 
1373*d5e0a182SSimon J. Gerraty 	/* Just in case MAKEOBJDIR wants us to do something tricky. */
1374e2eeea75SSimon J. Gerraty 	Targ_Init();
1375e2eeea75SSimon J. Gerraty 	Var_Init();
13764fde40d9SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", utsname.sysname);
1377dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE", machine);
1378dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE_ARCH", machine_arch);
13793955d011SMarcel Moolenaar #ifdef MAKE_VERSION
1380dba7b0efSSimon J. Gerraty 	Global_Set("MAKE_VERSION", MAKE_VERSION);
13813955d011SMarcel Moolenaar #endif
1382*d5e0a182SSimon J. Gerraty 	Global_Set_ReadOnly(".newline", "\n");
13833955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
13849f45a3c8SSimon J. Gerraty 	/* This is the traditional preference for makefiles. */
13853955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
13863955d011SMarcel Moolenaar #endif
13878c973ee2SSimon J. Gerraty 	Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
13884fde40d9SSimon J. Gerraty 	Global_Set(".MAKE.DEPENDFILE", ".depend");
138998875883SSimon J. Gerraty 	/* Tell makefiles like jobs.mk whether we support -jC */
139098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
139198875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "yes");
139298875883SSimon J. Gerraty #else
139398875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "no");
139498875883SSimon J. Gerraty #endif
13953955d011SMarcel Moolenaar 
1396956e45f6SSimon J. Gerraty 	CmdOpts_Init();
1397b0c40a00SSimon J. Gerraty 	allPrecious = false;	/* Remove targets when interrupted */
1398b0c40a00SSimon J. Gerraty 	deleteOnError = false;	/* Historical default behavior */
1399b0c40a00SSimon J. Gerraty 	jobsRunning = false;
14003955d011SMarcel Moolenaar 
1401956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1402b0c40a00SSimon J. Gerraty 	ignorePWD = false;
14033955d011SMarcel Moolenaar 
14043955d011SMarcel Moolenaar 	/*
14053955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
14063955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
14073955d011SMarcel Moolenaar 	 * command line
14083955d011SMarcel Moolenaar 	 */
14093955d011SMarcel Moolenaar 
14103955d011SMarcel Moolenaar 	/*
14113955d011SMarcel Moolenaar 	 * Initialize various variables.
14123955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
14133955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14143955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14153955d011SMarcel Moolenaar 	 */
14163955d011SMarcel Moolenaar 	Parse_Init();
1417956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
1418dba7b0efSSimon J. Gerraty 	Global_Set(MAKEFLAGS, "");
14198c973ee2SSimon J. Gerraty 	Global_Set(".MAKEOVERRIDES", "");
1420dba7b0efSSimon J. Gerraty 	Global_Set("MFLAGS", "");
1421dba7b0efSSimon J. Gerraty 	Global_Set(".ALLTARGETS", "");
14224fde40d9SSimon J. Gerraty 	Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
14233955d011SMarcel Moolenaar 
1424e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14253955d011SMarcel Moolenaar 	{
14269f45a3c8SSimon J. Gerraty 		char buf[64], *ep = getenv(MAKE_LEVEL_ENV);
14273955d011SMarcel Moolenaar 
1428e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
142951ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
143051ee2c1cSSimon J. Gerraty 			makelevel = 0;
14319f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%d", makelevel);
14328c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.LEVEL", buf);
14339f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", myPid);
14344fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PID", buf);
14359f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getppid());
14364fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PPID", buf);
14379f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getuid());
14384fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.UID", buf);
14399f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getgid());
14404fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.GID", buf);
14413955d011SMarcel Moolenaar 	}
144251ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
144351ee2c1cSSimon J. Gerraty 		char pn[1024];
1444e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
144551ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
144651ee2c1cSSimon J. Gerraty 	}
14473955d011SMarcel Moolenaar 
14481748de26SSimon J. Gerraty #ifdef USE_META
14491748de26SSimon J. Gerraty 	meta_init();
14501748de26SSimon J. Gerraty #endif
14512c3632d1SSimon J. Gerraty 	Dir_Init();
14521ce939a7SSimon J. Gerraty 
14539f45a3c8SSimon J. Gerraty #ifdef POSIX
14549f45a3c8SSimon J. Gerraty 	{
14559f45a3c8SSimon J. Gerraty 		char *makeflags = explode(getenv("MAKEFLAGS"));
14569f45a3c8SSimon J. Gerraty 		Main_ParseArgLine(makeflags);
14579f45a3c8SSimon J. Gerraty 		free(makeflags);
14589f45a3c8SSimon J. Gerraty 	}
14599f45a3c8SSimon J. Gerraty #else
14603955d011SMarcel Moolenaar 	/*
14613955d011SMarcel Moolenaar 	 * First snag any flags out of the MAKE environment variable.
14623955d011SMarcel Moolenaar 	 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
14633955d011SMarcel Moolenaar 	 * in a different format).
14643955d011SMarcel Moolenaar 	 */
14653955d011SMarcel Moolenaar 	Main_ParseArgLine(getenv("MAKE"));
14663955d011SMarcel Moolenaar #endif
14673955d011SMarcel Moolenaar 
14683955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
14693955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
14703955d011SMarcel Moolenaar 		    progname, strerror(errno));
14713955d011SMarcel Moolenaar 		exit(2);
14723955d011SMarcel Moolenaar 	}
14733955d011SMarcel Moolenaar 
14743955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
14753955d011SMarcel Moolenaar 
1476956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
147751ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
147851ee2c1cSSimon J. Gerraty 
14793955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
14803955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
14813955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
14823955d011SMarcel Moolenaar 		exit(2);
14833955d011SMarcel Moolenaar 	}
14843955d011SMarcel Moolenaar 
14853955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1486956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
14873955d011SMarcel Moolenaar #endif
1488dba7b0efSSimon J. Gerraty 	Global_Set(".CURDIR", curdir);
14893955d011SMarcel Moolenaar 
1490956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
14913955d011SMarcel Moolenaar 
14923955d011SMarcel Moolenaar 	Arch_Init();
14933955d011SMarcel Moolenaar 	Suff_Init();
14943955d011SMarcel Moolenaar 	Trace_Init(tracefile);
14953955d011SMarcel Moolenaar 
1496e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
14973955d011SMarcel Moolenaar 	(void)time(&now);
14983955d011SMarcel Moolenaar 
14993955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
15003955d011SMarcel Moolenaar 
1501956e45f6SSimon J. Gerraty 	InitVarTargets();
15023955d011SMarcel Moolenaar 
1503956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1504e2eeea75SSimon J. Gerraty }
15053955d011SMarcel Moolenaar 
150606b9b3e0SSimon J. Gerraty /*
150706b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
150806b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
150906b9b3e0SSimon J. Gerraty  */
1510e2eeea75SSimon J. Gerraty static void
1511e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1512e2eeea75SSimon J. Gerraty {
1513e2eeea75SSimon J. Gerraty 
15144fde40d9SSimon J. Gerraty 	if (Lst_IsEmpty(&sysIncPath->dirs))
15154fde40d9SSimon J. Gerraty 		SearchPath_AddAll(sysIncPath, defSysIncPath);
15164fde40d9SSimon J. Gerraty 
15174fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
1518956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1519956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
15203955d011SMarcel Moolenaar 
15212f2a5ecdSSimon J. Gerraty 	posix_state = PS_MAYBE_NEXT_LINE;
152206b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
152306b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1524e2eeea75SSimon J. Gerraty 	else
1525e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1526e2eeea75SSimon J. Gerraty }
1527e2eeea75SSimon J. Gerraty 
1528e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1529e2eeea75SSimon J. Gerraty static void
1530e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1531e2eeea75SSimon J. Gerraty {
15323955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1533e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
15348c973ee2SSimon J. Gerraty 		makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
15358c973ee2SSimon J. Gerraty 		    SCOPE_CMDLINE, VARE_WANTRES);
1536956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1537956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
1538b0c40a00SSimon J. Gerraty 			doing_depend = true;
15392c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
1540b0c40a00SSimon J. Gerraty 			doing_depend = false;
15413955d011SMarcel Moolenaar 		}
1542956e45f6SSimon J. Gerraty 	}
15433955d011SMarcel Moolenaar 
15444c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15454c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15464c620fe5SSimon J. Gerraty 
154706b9b3e0SSimon J. Gerraty 	MakeMode();
15483955d011SMarcel Moolenaar 
1549956e45f6SSimon J. Gerraty 	{
1550dba7b0efSSimon J. Gerraty 		FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS);
1551dba7b0efSSimon J. Gerraty 		Global_Append("MFLAGS", makeflags.str);
155206b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1553956e45f6SSimon J. Gerraty 	}
1554e48f47ddSSimon J. Gerraty 
1555956e45f6SSimon J. Gerraty 	InitMaxJobs();
1556e48f47ddSSimon J. Gerraty 
1557e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1558b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
1559e48f47ddSSimon J. Gerraty 
1560956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
15613955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1562956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1563956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
15643955d011SMarcel Moolenaar 
1565e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
1566b0c40a00SSimon J. Gerraty 		Main_ExportMAKEFLAGS(true);	/* initial export */
15673955d011SMarcel Moolenaar 
1568956e45f6SSimon J. Gerraty 	InitVpath();
15693955d011SMarcel Moolenaar 
15703955d011SMarcel Moolenaar 	/*
15713955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
15723955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
15733955d011SMarcel Moolenaar 	 */
1574b0c40a00SSimon J. Gerraty 	Suff_ExtendPaths();
15753955d011SMarcel Moolenaar 
15763955d011SMarcel Moolenaar 	/*
15773955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
15783955d011SMarcel Moolenaar 	 */
15793955d011SMarcel Moolenaar 	Targ_Propagate();
15803955d011SMarcel Moolenaar 
15813955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
15823955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
15833955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
15843955d011SMarcel Moolenaar }
15853955d011SMarcel Moolenaar 
158606b9b3e0SSimon J. Gerraty /*
158706b9b3e0SSimon J. Gerraty  * Make the targets.
1588e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
158906b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
159006b9b3e0SSimon J. Gerraty  */
1591b0c40a00SSimon J. Gerraty static bool
1592e2eeea75SSimon J. Gerraty main_Run(void)
1593e2eeea75SSimon J. Gerraty {
1594e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1595e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1596e2eeea75SSimon J. Gerraty 		doPrintVars();
1597b0c40a00SSimon J. Gerraty 		return false;
1598e2eeea75SSimon J. Gerraty 	} else {
1599e2eeea75SSimon J. Gerraty 		return runTargets();
1600e2eeea75SSimon J. Gerraty 	}
1601e2eeea75SSimon J. Gerraty }
16023955d011SMarcel Moolenaar 
1603e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1604e2eeea75SSimon J. Gerraty static void
1605e2eeea75SSimon J. Gerraty main_CleanUp(void)
1606e2eeea75SSimon J. Gerraty {
1607e2eeea75SSimon J. Gerraty #ifdef CLEANUP
160806b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.variables, free);
16099f45a3c8SSimon J. Gerraty 	Lst_DoneCall(&opts.makefiles, free);
161006b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.create, free);
1611e2eeea75SSimon J. Gerraty #endif
1612e2eeea75SSimon J. Gerraty 
1613e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1614e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1615e2eeea75SSimon J. Gerraty 
1616e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1617e2eeea75SSimon J. Gerraty 
1618e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1619e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1620e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1621e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1622e2eeea75SSimon J. Gerraty 
1623e2eeea75SSimon J. Gerraty #ifdef USE_META
1624e2eeea75SSimon J. Gerraty 	meta_finish();
1625e2eeea75SSimon J. Gerraty #endif
1626e2eeea75SSimon J. Gerraty 	Suff_End();
1627e2eeea75SSimon J. Gerraty 	Targ_End();
1628e2eeea75SSimon J. Gerraty 	Arch_End();
1629e2eeea75SSimon J. Gerraty 	Var_End();
1630e2eeea75SSimon J. Gerraty 	Parse_End();
1631e2eeea75SSimon J. Gerraty 	Dir_End();
1632e2eeea75SSimon J. Gerraty 	Job_End();
1633e2eeea75SSimon J. Gerraty 	Trace_End();
16349f45a3c8SSimon J. Gerraty 	Str_Intern_End();
1635e2eeea75SSimon J. Gerraty }
1636e2eeea75SSimon J. Gerraty 
1637e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1638e2eeea75SSimon J. Gerraty static int
1639b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate)
1640e2eeea75SSimon J. Gerraty {
164112904384SSimon J. Gerraty 	if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0))
1642956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16433955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16443955d011SMarcel Moolenaar }
16453955d011SMarcel Moolenaar 
1646e2eeea75SSimon J. Gerraty int
1647e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1648e2eeea75SSimon J. Gerraty {
1649b0c40a00SSimon J. Gerraty 	bool outOfDate;
1650e2eeea75SSimon J. Gerraty 
1651e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1652e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1653e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1654e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1655e2eeea75SSimon J. Gerraty 	main_CleanUp();
1656e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1657e2eeea75SSimon J. Gerraty }
1658e2eeea75SSimon J. Gerraty 
165906b9b3e0SSimon J. Gerraty /*
166006b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
16619f45a3c8SSimon J. Gerraty  * Return false if the file could not be opened.
16623955d011SMarcel Moolenaar  */
16639f45a3c8SSimon J. Gerraty static bool
16642c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
16653955d011SMarcel Moolenaar {
16663955d011SMarcel Moolenaar 	int fd;
16672c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
16683955d011SMarcel Moolenaar 
1669e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
16709f45a3c8SSimon J. Gerraty 		Parse_File("(stdin)", -1);
1671dba7b0efSSimon J. Gerraty 		Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
16723955d011SMarcel Moolenaar 	} else {
16733955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1674e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
16752c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
16763955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16773955d011SMarcel Moolenaar 			if (fd != -1) {
16783955d011SMarcel Moolenaar 				fname = path;
16793955d011SMarcel Moolenaar 				goto found;
16803955d011SMarcel Moolenaar 			}
16812c3632d1SSimon J. Gerraty 			free(path);
16823955d011SMarcel Moolenaar 
16833955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
16842c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
16853955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16863955d011SMarcel Moolenaar 			if (fd != -1) {
16873955d011SMarcel Moolenaar 				fname = path;
16883955d011SMarcel Moolenaar 				goto found;
16893955d011SMarcel Moolenaar 			}
16903955d011SMarcel Moolenaar 		} else {
16913955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
16923955d011SMarcel Moolenaar 			if (fd != -1)
16933955d011SMarcel Moolenaar 				goto found;
16943955d011SMarcel Moolenaar 		}
16953955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
16963955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1697e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1698dba7b0efSSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
1699956e45f6SSimon J. Gerraty 			    ? defSysIncPath : sysIncPath;
1700956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1701956e45f6SSimon J. Gerraty 		}
1702e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
17033955d011SMarcel Moolenaar 			free(name);
17043955d011SMarcel Moolenaar 			free(path);
17059f45a3c8SSimon J. Gerraty 			return false;
17063955d011SMarcel Moolenaar 		}
17073955d011SMarcel Moolenaar 		fname = name;
17083955d011SMarcel Moolenaar 		/*
17093955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
17103955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
17113955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
17123955d011SMarcel Moolenaar 		 */
17133955d011SMarcel Moolenaar found:
17143955d011SMarcel Moolenaar 		if (!doing_depend)
1715dba7b0efSSimon J. Gerraty 			Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname);
17163955d011SMarcel Moolenaar 		Parse_File(fname, fd);
17173955d011SMarcel Moolenaar 	}
17183955d011SMarcel Moolenaar 	free(path);
17199f45a3c8SSimon J. Gerraty 	return true;
17203955d011SMarcel Moolenaar }
17213955d011SMarcel Moolenaar 
1722dba7b0efSSimon J. Gerraty /*
17239f45a3c8SSimon J. Gerraty  * Execute the command in cmd, and return its output (only stdout, not
17249f45a3c8SSimon J. Gerraty  * stderr, possibly empty).  In the output, replace newlines with spaces.
17253955d011SMarcel Moolenaar  */
17263955d011SMarcel Moolenaar char *
17279f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error)
17283955d011SMarcel Moolenaar {
17299f45a3c8SSimon J. Gerraty 	const char *args[4];	/* Arguments for invoking the shell */
173006b9b3e0SSimon J. Gerraty 	int pipefds[2];
17313955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17323955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1733e2eeea75SSimon J. Gerraty 	int status;		/* command exit status */
17343955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17352c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17369f45a3c8SSimon J. Gerraty 	char *output;
1737*d5e0a182SSimon J. Gerraty 	char *p;
17389f45a3c8SSimon J. Gerraty 	int saved_errno;
1739*d5e0a182SSimon J. Gerraty 	char cmd_file[MAXPATHLEN];
1740*d5e0a182SSimon J. Gerraty 	size_t cmd_len;
1741*d5e0a182SSimon J. Gerraty 	int cmd_fd = -1;
17423955d011SMarcel Moolenaar 
1743*d5e0a182SSimon J. Gerraty 	if (shellPath == NULL)
17443955d011SMarcel Moolenaar 		Shell_Init();
17459f45a3c8SSimon J. Gerraty 
1746*d5e0a182SSimon J. Gerraty 	cmd_len = strlen(cmd);
1747*d5e0a182SSimon J. Gerraty 	if (cmd_len > 1000) {
1748*d5e0a182SSimon J. Gerraty 		cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file));
1749*d5e0a182SSimon J. Gerraty 		if (cmd_fd >= 0) {
1750*d5e0a182SSimon J. Gerraty 			ssize_t n;
1751*d5e0a182SSimon J. Gerraty 
1752*d5e0a182SSimon J. Gerraty 			n = write(cmd_fd, cmd, cmd_len);
1753*d5e0a182SSimon J. Gerraty 			close(cmd_fd);
1754*d5e0a182SSimon J. Gerraty 			if (n < (ssize_t)cmd_len) {
1755*d5e0a182SSimon J. Gerraty 				unlink(cmd_file);
1756*d5e0a182SSimon J. Gerraty 				cmd_fd = -1;
1757*d5e0a182SSimon J. Gerraty 			}
1758*d5e0a182SSimon J. Gerraty 		}
1759*d5e0a182SSimon J. Gerraty 	}
1760*d5e0a182SSimon J. Gerraty 
17613955d011SMarcel Moolenaar 	args[0] = shellName;
1762*d5e0a182SSimon J. Gerraty 	if (cmd_fd >= 0) {
1763*d5e0a182SSimon J. Gerraty 		args[1] = cmd_file;
1764*d5e0a182SSimon J. Gerraty 		args[2] = NULL;
1765*d5e0a182SSimon J. Gerraty 	} else {
1766*d5e0a182SSimon J. Gerraty 		cmd_file[0] = '\0';
17673955d011SMarcel Moolenaar 		args[1] = "-c";
17683955d011SMarcel Moolenaar 		args[2] = cmd;
17693955d011SMarcel Moolenaar 		args[3] = NULL;
1770*d5e0a182SSimon J. Gerraty 	}
17719f45a3c8SSimon J. Gerraty 	DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
17723955d011SMarcel Moolenaar 
177306b9b3e0SSimon J. Gerraty 	if (pipe(pipefds) == -1) {
17749f45a3c8SSimon J. Gerraty 		*error = str_concat3(
17759f45a3c8SSimon J. Gerraty 		    "Couldn't create pipe for \"", cmd, "\"");
17769f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17773955d011SMarcel Moolenaar 	}
17783955d011SMarcel Moolenaar 
177906b9b3e0SSimon J. Gerraty 	Var_ReexportVars();
178006b9b3e0SSimon J. Gerraty 
1781dba7b0efSSimon J. Gerraty 	switch (cpid = vfork()) {
17823955d011SMarcel Moolenaar 	case 0:
17839f45a3c8SSimon J. Gerraty 		(void)close(pipefds[0]);
17849f45a3c8SSimon J. Gerraty 		(void)dup2(pipefds[1], STDOUT_FILENO);
178506b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
17863955d011SMarcel Moolenaar 
17873955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
17883955d011SMarcel Moolenaar 		_exit(1);
17893955d011SMarcel Moolenaar 		/* NOTREACHED */
17903955d011SMarcel Moolenaar 
17913955d011SMarcel Moolenaar 	case -1:
17929f45a3c8SSimon J. Gerraty 		*error = str_concat3("Couldn't exec \"", cmd, "\"");
17939f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17949f45a3c8SSimon J. Gerraty 	}
17953955d011SMarcel Moolenaar 
179606b9b3e0SSimon J. Gerraty 	(void)close(pipefds[1]);	/* No need for the writing half */
17973955d011SMarcel Moolenaar 
17989f45a3c8SSimon J. Gerraty 	saved_errno = 0;
1799e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
18003955d011SMarcel Moolenaar 
18013955d011SMarcel Moolenaar 	do {
18023955d011SMarcel Moolenaar 		char result[BUFSIZ];
180306b9b3e0SSimon J. Gerraty 		bytes_read = read(pipefds[0], result, sizeof result);
18042c3632d1SSimon J. Gerraty 		if (bytes_read > 0)
18052c3632d1SSimon J. Gerraty 			Buf_AddBytes(&buf, result, (size_t)bytes_read);
18069f45a3c8SSimon J. Gerraty 	} while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
18072c3632d1SSimon J. Gerraty 	if (bytes_read == -1)
18089f45a3c8SSimon J. Gerraty 		saved_errno = errno;
18093955d011SMarcel Moolenaar 
181006b9b3e0SSimon J. Gerraty 	(void)close(pipefds[0]); /* Close the input side of the pipe. */
18113955d011SMarcel Moolenaar 
1812e2eeea75SSimon J. Gerraty 	while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
1813b0c40a00SSimon J. Gerraty 		JobReapChild(pid, status, false);
1814e2eeea75SSimon J. Gerraty 
18159f45a3c8SSimon J. Gerraty 	if (Buf_EndsWith(&buf, '\n'))
18169f45a3c8SSimon J. Gerraty 		buf.data[buf.len - 1] = '\0';
18173955d011SMarcel Moolenaar 
18189f45a3c8SSimon J. Gerraty 	output = Buf_DoneData(&buf);
1819*d5e0a182SSimon J. Gerraty 	for (p = output; *p != '\0'; p++)
1820*d5e0a182SSimon J. Gerraty 		if (*p == '\n')
1821*d5e0a182SSimon J. Gerraty 			*p = ' ';
18229f45a3c8SSimon J. Gerraty 
18239f45a3c8SSimon J. Gerraty 	if (WIFSIGNALED(status))
18249f45a3c8SSimon J. Gerraty 		*error = str_concat3("\"", cmd, "\" exited on a signal");
18259f45a3c8SSimon J. Gerraty 	else if (WEXITSTATUS(status) != 0)
18269f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18279f45a3c8SSimon J. Gerraty 		    "\"", cmd, "\" returned non-zero status");
18289f45a3c8SSimon J. Gerraty 	else if (saved_errno != 0)
18299f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18309f45a3c8SSimon J. Gerraty 		    "Couldn't read shell's output for \"", cmd, "\"");
18319f45a3c8SSimon J. Gerraty 	else
18329f45a3c8SSimon J. Gerraty 		*error = NULL;
1833*d5e0a182SSimon J. Gerraty 	if (cmd_file[0] != '\0')
1834*d5e0a182SSimon J. Gerraty 		unlink(cmd_file);
18359f45a3c8SSimon J. Gerraty 	return output;
18363955d011SMarcel Moolenaar }
18373955d011SMarcel Moolenaar 
183806b9b3e0SSimon J. Gerraty /*
183906b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18403955d011SMarcel Moolenaar  *
18419f45a3c8SSimon J. Gerraty  * In default mode, this error message has no consequences, for compatibility
18429f45a3c8SSimon J. Gerraty  * reasons, in particular it does not affect the exit status.  Only in lint
18439f45a3c8SSimon J. Gerraty  * mode (-dL) it does.
184406b9b3e0SSimon J. Gerraty  */
18453955d011SMarcel Moolenaar void
18463955d011SMarcel Moolenaar Error(const char *fmt, ...)
18473955d011SMarcel Moolenaar {
18483955d011SMarcel Moolenaar 	va_list ap;
18499f45a3c8SSimon J. Gerraty 	FILE *f;
18503955d011SMarcel Moolenaar 
18519f45a3c8SSimon J. Gerraty 	f = opts.debug_file;
18529f45a3c8SSimon J. Gerraty 	if (f == stdout)
18539f45a3c8SSimon J. Gerraty 		f = stderr;
18543955d011SMarcel Moolenaar 	(void)fflush(stdout);
18559f45a3c8SSimon J. Gerraty 
18563955d011SMarcel Moolenaar 	for (;;) {
18579f45a3c8SSimon J. Gerraty 		fprintf(f, "%s: ", progname);
18583955d011SMarcel Moolenaar 		va_start(ap, fmt);
18599f45a3c8SSimon J. Gerraty 		(void)vfprintf(f, fmt, ap);
18603955d011SMarcel Moolenaar 		va_end(ap);
18619f45a3c8SSimon J. Gerraty 		(void)fprintf(f, "\n");
18629f45a3c8SSimon J. Gerraty 		(void)fflush(f);
18639f45a3c8SSimon J. Gerraty 		if (f == stderr)
18643955d011SMarcel Moolenaar 			break;
18659f45a3c8SSimon J. Gerraty 		f = stderr;
18663955d011SMarcel Moolenaar 	}
186706b9b3e0SSimon J. Gerraty 	main_errors++;
18683955d011SMarcel Moolenaar }
18693955d011SMarcel Moolenaar 
187006b9b3e0SSimon J. Gerraty /*
187106b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1872e2eeea75SSimon J. Gerraty  * finally exit immediately.
18733955d011SMarcel Moolenaar  *
1874e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
187506b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
187606b9b3e0SSimon J. Gerraty  */
18773955d011SMarcel Moolenaar void
18783955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
18793955d011SMarcel Moolenaar {
18803955d011SMarcel Moolenaar 	va_list ap;
18813955d011SMarcel Moolenaar 
18823955d011SMarcel Moolenaar 	if (jobsRunning)
18833955d011SMarcel Moolenaar 		Job_Wait();
18843955d011SMarcel Moolenaar 
18853955d011SMarcel Moolenaar 	(void)fflush(stdout);
1886*d5e0a182SSimon J. Gerraty 	fprintf(stderr, "%s: ", progname);
1887e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
18883955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
18893955d011SMarcel Moolenaar 	va_end(ap);
18903955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
18913955d011SMarcel Moolenaar 	(void)fflush(stderr);
18929f45a3c8SSimon J. Gerraty 	PrintStackTrace(true);
18933955d011SMarcel Moolenaar 
18949f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
18953955d011SMarcel Moolenaar 
18963955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
18973955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1898e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
18993955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
19003955d011SMarcel Moolenaar }
19013955d011SMarcel Moolenaar 
190206b9b3e0SSimon J. Gerraty /*
190306b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
190406b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
190506b9b3e0SSimon J. Gerraty  */
19063955d011SMarcel Moolenaar void
19073955d011SMarcel Moolenaar Punt(const char *fmt, ...)
19083955d011SMarcel Moolenaar {
19093955d011SMarcel Moolenaar 	va_list ap;
19103955d011SMarcel Moolenaar 
19113955d011SMarcel Moolenaar 	(void)fflush(stdout);
19123955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
19139f45a3c8SSimon J. Gerraty 	va_start(ap, fmt);
19143955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19153955d011SMarcel Moolenaar 	va_end(ap);
19163955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19173955d011SMarcel Moolenaar 	(void)fflush(stderr);
19183955d011SMarcel Moolenaar 
19199f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
19203955d011SMarcel Moolenaar 
19213955d011SMarcel Moolenaar 	DieHorribly();
19223955d011SMarcel Moolenaar }
19233955d011SMarcel Moolenaar 
1924956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19253955d011SMarcel Moolenaar void
19263955d011SMarcel Moolenaar DieHorribly(void)
19273955d011SMarcel Moolenaar {
19283955d011SMarcel Moolenaar 	if (jobsRunning)
19293955d011SMarcel Moolenaar 		Job_AbortAll();
19303955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19313955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1932e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
193306b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19343955d011SMarcel Moolenaar }
19353955d011SMarcel Moolenaar 
193606b9b3e0SSimon J. Gerraty /*
193706b9b3e0SSimon J. Gerraty  * Called when aborting due to errors in child shell to signal abnormal exit.
1938956e45f6SSimon J. Gerraty  * The program exits.
193906b9b3e0SSimon J. Gerraty  * Errors is the number of errors encountered in Make_Make.
194006b9b3e0SSimon J. Gerraty  */
19413955d011SMarcel Moolenaar void
1942956e45f6SSimon J. Gerraty Finish(int errs)
19433955d011SMarcel Moolenaar {
1944e2eeea75SSimon J. Gerraty 	if (shouldDieQuietly(NULL, -1))
19453841c287SSimon J. Gerraty 		exit(2);
1946956e45f6SSimon J. Gerraty 	Fatal("%d error%s", errs, errs == 1 ? "" : "s");
19473955d011SMarcel Moolenaar }
19483955d011SMarcel Moolenaar 
19494fde40d9SSimon J. Gerraty int
19509f45a3c8SSimon J. Gerraty unlink_file(const char *file)
19513955d011SMarcel Moolenaar {
19523955d011SMarcel Moolenaar 	struct stat st;
19533955d011SMarcel Moolenaar 
19543955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
19554fde40d9SSimon J. Gerraty 		return -1;
19563955d011SMarcel Moolenaar 
19573955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
19584fde40d9SSimon J. Gerraty 		/*
19594fde40d9SSimon J. Gerraty 		 * POSIX says for unlink: "The path argument shall not name
19604fde40d9SSimon J. Gerraty 		 * a directory unless [...]".
19614fde40d9SSimon J. Gerraty 		 */
19623955d011SMarcel Moolenaar 		errno = EISDIR;
19634fde40d9SSimon J. Gerraty 		return -1;
19643955d011SMarcel Moolenaar 	}
19654fde40d9SSimon J. Gerraty 	return unlink(file);
19663955d011SMarcel Moolenaar }
19673955d011SMarcel Moolenaar 
1968956e45f6SSimon J. Gerraty static void
1969956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
1970956e45f6SSimon J. Gerraty {
1971956e45f6SSimon J. Gerraty 	const char *mem = data;
1972956e45f6SSimon J. Gerraty 
1973956e45f6SSimon J. Gerraty 	while (n > 0) {
1974956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
19759f45a3c8SSimon J. Gerraty 		/* XXX: Should this EAGAIN be EINTR? */
1976956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
1977956e45f6SSimon J. Gerraty 			continue;
1978956e45f6SSimon J. Gerraty 		if (written == -1)
1979956e45f6SSimon J. Gerraty 			break;
1980956e45f6SSimon J. Gerraty 		mem += written;
1981956e45f6SSimon J. Gerraty 		n -= (size_t)written;
1982956e45f6SSimon J. Gerraty 	}
1983956e45f6SSimon J. Gerraty }
1984956e45f6SSimon J. Gerraty 
19859f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */
1986956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
1987956e45f6SSimon J. Gerraty execDie(const char *af, const char *av)
19883955d011SMarcel Moolenaar {
1989956e45f6SSimon J. Gerraty 	Buffer buf;
19903955d011SMarcel Moolenaar 
1991e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
1992956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, progname);
1993956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ": ");
1994956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, af);
1995956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
1996956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, av);
1997956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ") failed (");
1998956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, strerror(errno));
1999956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ")\n");
20003955d011SMarcel Moolenaar 
2001dba7b0efSSimon J. Gerraty 	write_all(STDERR_FILENO, buf.data, buf.len);
2002956e45f6SSimon J. Gerraty 
2003dba7b0efSSimon J. Gerraty 	Buf_Done(&buf);
2004956e45f6SSimon J. Gerraty 	_exit(1);
20053955d011SMarcel Moolenaar }
20063955d011SMarcel Moolenaar 
2007e1cee40dSSimon J. Gerraty static void
2008e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
2009e1cee40dSSimon J. Gerraty {
2010*d5e0a182SSimon J. Gerraty 	HashEntry *he, *next;
2011956e45f6SSimon J. Gerraty 	HashIter hi;
2012b778b302SSimon J. Gerraty 
2013e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
2014956e45f6SSimon J. Gerraty 	he = HashIter_Next(&hi);
2015956e45f6SSimon J. Gerraty 	while (he != NULL) {
2016*d5e0a182SSimon J. Gerraty 		next = HashIter_Next(&hi);
2017956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
2018e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
2019e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
20209f45a3c8SSimon J. Gerraty 			/*
20219f45a3c8SSimon J. Gerraty 			 * XXX: What about the allocated he->value? Either
20229f45a3c8SSimon J. Gerraty 			 * free them or document why they cannot be freed.
20239f45a3c8SSimon J. Gerraty 			 */
2024b46b9039SSimon J. Gerraty 		}
2025*d5e0a182SSimon J. Gerraty 		he = next;
2026b46b9039SSimon J. Gerraty 	}
2027b46b9039SSimon J. Gerraty }
2028e1cee40dSSimon J. Gerraty 
20299f45a3c8SSimon J. Gerraty const char *
2030e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2031e1cee40dSSimon J. Gerraty {
20322c3632d1SSimon J. Gerraty 	const char *rp;
2033e1cee40dSSimon J. Gerraty 
2034e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2035e1cee40dSSimon J. Gerraty 		return NULL;
2036e1cee40dSSimon J. Gerraty 
2037e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2038e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2039b778b302SSimon J. Gerraty 		/* a hit */
2040e2eeea75SSimon J. Gerraty 		strncpy(resolved, rp, MAXPATHLEN);
2041e2eeea75SSimon J. Gerraty 		resolved[MAXPATHLEN - 1] = '\0';
2042e2eeea75SSimon J. Gerraty 		return resolved;
2043e2eeea75SSimon J. Gerraty 	}
20443841c287SSimon J. Gerraty 
2045e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2046e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2047e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2048e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2049e2eeea75SSimon J. Gerraty 		return resolved;
2050e2eeea75SSimon J. Gerraty 	}
2051e2eeea75SSimon J. Gerraty 
2052e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2053e2eeea75SSimon J. Gerraty 	return NULL;
2054b778b302SSimon J. Gerraty }
2055b778b302SSimon J. Gerraty 
20563841c287SSimon J. Gerraty /*
20573841c287SSimon J. Gerraty  * Return true if we should die without noise.
2058e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
20593841c287SSimon J. Gerraty  */
2060b0c40a00SSimon J. Gerraty bool
2061e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
20623841c287SSimon J. Gerraty {
20633841c287SSimon J. Gerraty 	static int quietly = -1;
20643841c287SSimon J. Gerraty 
20653841c287SSimon J. Gerraty 	if (quietly < 0) {
2066b0c40a00SSimon J. Gerraty 		if (DEBUG(JOB) ||
2067b0c40a00SSimon J. Gerraty 		    !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true))
20683841c287SSimon J. Gerraty 			quietly = 0;
20693841c287SSimon J. Gerraty 		else if (bf >= 0)
20703841c287SSimon J. Gerraty 			quietly = bf;
20713841c287SSimon J. Gerraty 		else
207206b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
20733841c287SSimon J. Gerraty 	}
2074dba7b0efSSimon J. Gerraty 	return quietly != 0;
20753841c287SSimon J. Gerraty }
20763841c287SSimon J. Gerraty 
2077956e45f6SSimon J. Gerraty static void
2078956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2079956e45f6SSimon J. Gerraty {
2080956e45f6SSimon J. Gerraty 	StringListNode *ln;
2081956e45f6SSimon J. Gerraty 
2082956e45f6SSimon J. Gerraty 	/*
2083956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2084956e45f6SSimon J. Gerraty 	 */
2085dba7b0efSSimon J. Gerraty 	Global_Set(".ERROR_TARGET", gn->name);
2086dba7b0efSSimon J. Gerraty 	Global_Delete(".ERROR_CMD");
2087956e45f6SSimon J. Gerraty 
208806b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2089956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2090956e45f6SSimon J. Gerraty 
2091956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2092956e45f6SSimon J. Gerraty 			break;
2093dba7b0efSSimon J. Gerraty 		Global_Append(".ERROR_CMD", cmd);
2094956e45f6SSimon J. Gerraty 	}
2095956e45f6SSimon J. Gerraty }
2096956e45f6SSimon J. Gerraty 
209706b9b3e0SSimon J. Gerraty /*
209806b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
209906b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
210006b9b3e0SSimon J. Gerraty  */
21013955d011SMarcel Moolenaar void
2102e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
21033955d011SMarcel Moolenaar {
2104e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
21053955d011SMarcel Moolenaar 
21062c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
21072c3632d1SSimon J. Gerraty 		Targ_Stats();
21082c3632d1SSimon J. Gerraty 		Var_Stats();
21092c3632d1SSimon J. Gerraty 	}
21102c3632d1SSimon J. Gerraty 
211106b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
211206b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
21133841c287SSimon J. Gerraty 
21149f45a3c8SSimon J. Gerraty 	printf("%s%s: stopped in %s\n", msg, progname, curdir);
21153955d011SMarcel Moolenaar 
211606b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
211706b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
211806b9b3e0SSimon J. Gerraty 		return;
2119e2eeea75SSimon J. Gerraty 
2120e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2121956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2122e2eeea75SSimon J. Gerraty 
2123e2eeea75SSimon J. Gerraty 	{
21248c973ee2SSimon J. Gerraty 		char *errorVarsValues = Var_Subst(
21258c973ee2SSimon J. Gerraty 		    "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
21268c973ee2SSimon J. Gerraty 		    SCOPE_GLOBAL, VARE_WANTRES);
2127956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2128e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2129e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2130e2eeea75SSimon J. Gerraty 	}
2131e2eeea75SSimon J. Gerraty 
2132ac3446e9SSimon J. Gerraty 	fflush(stdout);
2133ac3446e9SSimon J. Gerraty 
21343955d011SMarcel Moolenaar 	/*
21353955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21363955d011SMarcel Moolenaar 	 */
2137e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2138e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2139e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2140e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21413955d011SMarcel Moolenaar 	}
21423955d011SMarcel Moolenaar }
21433955d011SMarcel Moolenaar 
21443955d011SMarcel Moolenaar void
2145b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first)
21463955d011SMarcel Moolenaar {
2147b0c40a00SSimon J. Gerraty 	static bool once = true;
21489f45a3c8SSimon J. Gerraty 	char *flags;
21493955d011SMarcel Moolenaar 
21503955d011SMarcel Moolenaar 	if (once != first)
21513955d011SMarcel Moolenaar 		return;
2152b0c40a00SSimon J. Gerraty 	once = false;
21533955d011SMarcel Moolenaar 
21548c973ee2SSimon J. Gerraty 	flags = Var_Subst(
21559f45a3c8SSimon J. Gerraty 	    "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
21568c973ee2SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_WANTRES);
2157956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
21589f45a3c8SSimon J. Gerraty 	if (flags[0] != '\0') {
21593955d011SMarcel Moolenaar #ifdef POSIX
21609f45a3c8SSimon J. Gerraty 		setenv("MAKEFLAGS", flags, 1);
21613955d011SMarcel Moolenaar #else
21629f45a3c8SSimon J. Gerraty 		setenv("MAKE", flags, 1);
21633955d011SMarcel Moolenaar #endif
21643955d011SMarcel Moolenaar 	}
21653955d011SMarcel Moolenaar }
21663955d011SMarcel Moolenaar 
21673955d011SMarcel Moolenaar char *
21683955d011SMarcel Moolenaar getTmpdir(void)
21693955d011SMarcel Moolenaar {
21703955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
21713955d011SMarcel Moolenaar 	struct stat st;
21723955d011SMarcel Moolenaar 
2173e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2174e2eeea75SSimon J. Gerraty 		return tmpdir;
2175e2eeea75SSimon J. Gerraty 
21769f45a3c8SSimon J. Gerraty 	/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
21778c973ee2SSimon J. Gerraty 	tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
21788c973ee2SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_WANTRES);
2179956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2180e2eeea75SSimon J. Gerraty 
21813955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
21823955d011SMarcel Moolenaar 		free(tmpdir);
21833955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
21843955d011SMarcel Moolenaar 	}
21853955d011SMarcel Moolenaar 	return tmpdir;
21863955d011SMarcel Moolenaar }
21873955d011SMarcel Moolenaar 
21883955d011SMarcel Moolenaar /*
21893955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2190*d5e0a182SSimon J. Gerraty  * If tfile is provided, set it to a copy of the filename created.
21913955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
21923955d011SMarcel Moolenaar  */
21933955d011SMarcel Moolenaar int
2194dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
21953955d011SMarcel Moolenaar {
21963955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
2197dba7b0efSSimon J. Gerraty 	char tbuf[MAXPATHLEN];
21983955d011SMarcel Moolenaar 	int fd;
21993955d011SMarcel Moolenaar 
2200e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
22013955d011SMarcel Moolenaar 		pattern = TMPPAT;
2202956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
22033955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
2204dba7b0efSSimon J. Gerraty 	if (tfile == NULL) {
2205dba7b0efSSimon J. Gerraty 		tfile = tbuf;
2206dba7b0efSSimon J. Gerraty 		tfile_sz = sizeof tbuf;
2207dba7b0efSSimon J. Gerraty 	}
22089f45a3c8SSimon J. Gerraty 
22099f45a3c8SSimon J. Gerraty 	if (pattern[0] == '/')
2210dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s", pattern);
22119f45a3c8SSimon J. Gerraty 	else
2212dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
22139f45a3c8SSimon J. Gerraty 
22143955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2215e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2216e2eeea75SSimon J. Gerraty 		    strerror(errno));
22179f45a3c8SSimon J. Gerraty 	if (tfile == tbuf)
221806b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
22199f45a3c8SSimon J. Gerraty 
22203955d011SMarcel Moolenaar 	return fd;
22213955d011SMarcel Moolenaar }
22223955d011SMarcel Moolenaar 
2223be19d90bSSimon J. Gerraty /*
2224e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2225b0c40a00SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is false,
2226b0c40a00SSimon J. Gerraty  * the empty string is the fallback, everything else is true.
2227be19d90bSSimon J. Gerraty  */
2228b0c40a00SSimon J. Gerraty bool
2229b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback)
2230be19d90bSSimon J. Gerraty {
2231e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2232e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2233e2eeea75SSimon J. Gerraty 		return fallback;
2234e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2235b0c40a00SSimon J. Gerraty 		return false;
2236e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2237e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2238b0c40a00SSimon J. Gerraty 	return true;
2239be19d90bSSimon J. Gerraty }
2240