Sat Oct 31 09:23:38 2020 UTC ()
make(1): write s2Boolean in a more compact form


(rillig)
diff -r1.414 -r1.415 src/usr.bin/make/main.c

cvs diff -r1.414 -r1.415 src/usr.bin/make/main.c (switch to unified diff)

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