Tue Oct 27 06:59:20 2020 UTC ()
make(1): extract UnlimitFiles from main


(rillig)
diff -r1.392 -r1.393 src/usr.bin/make/main.c

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

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