1*2bc7c627SLionel Sambuc /* $NetBSD: main.c,v 1.203 2012/08/31 07:00:36 sjg Exp $ */ 22e2caf59SThomas Veerman 32e2caf59SThomas Veerman /* 42e2caf59SThomas Veerman * Copyright (c) 1988, 1989, 1990, 1993 52e2caf59SThomas Veerman * The Regents of the University of California. All rights reserved. 62e2caf59SThomas Veerman * 72e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by 82e2caf59SThomas Veerman * Adam de Boor. 92e2caf59SThomas Veerman * 102e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without 112e2caf59SThomas Veerman * modification, are permitted provided that the following conditions 122e2caf59SThomas Veerman * are met: 132e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright 142e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer. 152e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright 162e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the 172e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution. 182e2caf59SThomas Veerman * 3. Neither the name of the University nor the names of its contributors 192e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software 202e2caf59SThomas Veerman * without specific prior written permission. 212e2caf59SThomas Veerman * 222e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 232e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 242e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 252e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 262e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 272e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 282e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 292e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 302e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 312e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 322e2caf59SThomas Veerman * SUCH DAMAGE. 332e2caf59SThomas Veerman */ 342e2caf59SThomas Veerman 352e2caf59SThomas Veerman /* 362e2caf59SThomas Veerman * Copyright (c) 1989 by Berkeley Softworks 372e2caf59SThomas Veerman * All rights reserved. 382e2caf59SThomas Veerman * 392e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by 402e2caf59SThomas Veerman * Adam de Boor. 412e2caf59SThomas Veerman * 422e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without 432e2caf59SThomas Veerman * modification, are permitted provided that the following conditions 442e2caf59SThomas Veerman * are met: 452e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright 462e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer. 472e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright 482e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the 492e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution. 502e2caf59SThomas Veerman * 3. All advertising materials mentioning features or use of this software 512e2caf59SThomas Veerman * must display the following acknowledgement: 522e2caf59SThomas Veerman * This product includes software developed by the University of 532e2caf59SThomas Veerman * California, Berkeley and its contributors. 542e2caf59SThomas Veerman * 4. Neither the name of the University nor the names of its contributors 552e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software 562e2caf59SThomas Veerman * without specific prior written permission. 572e2caf59SThomas Veerman * 582e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 592e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 602e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 612e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 622e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 632e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 642e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 652e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 662e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 672e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 682e2caf59SThomas Veerman * SUCH DAMAGE. 692e2caf59SThomas Veerman */ 702e2caf59SThomas Veerman 712e2caf59SThomas Veerman #ifndef MAKE_NATIVE 72*2bc7c627SLionel Sambuc static char rcsid[] = "$NetBSD: main.c,v 1.203 2012/08/31 07:00:36 sjg Exp $"; 732e2caf59SThomas Veerman #else 742e2caf59SThomas Veerman #include <sys/cdefs.h> 752e2caf59SThomas Veerman #ifndef lint 762e2caf59SThomas Veerman __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ 772e2caf59SThomas Veerman The Regents of the University of California. All rights reserved."); 782e2caf59SThomas Veerman #endif /* not lint */ 792e2caf59SThomas Veerman 802e2caf59SThomas Veerman #ifndef lint 812e2caf59SThomas Veerman #if 0 822e2caf59SThomas Veerman static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 832e2caf59SThomas Veerman #else 84*2bc7c627SLionel Sambuc __RCSID("$NetBSD: main.c,v 1.203 2012/08/31 07:00:36 sjg Exp $"); 852e2caf59SThomas Veerman #endif 862e2caf59SThomas Veerman #endif /* not lint */ 872e2caf59SThomas Veerman #endif 882e2caf59SThomas Veerman 892e2caf59SThomas Veerman /*- 902e2caf59SThomas Veerman * main.c -- 912e2caf59SThomas Veerman * The main file for this entire program. Exit routines etc 922e2caf59SThomas Veerman * reside here. 932e2caf59SThomas Veerman * 942e2caf59SThomas Veerman * Utility functions defined in this file: 952e2caf59SThomas Veerman * Main_ParseArgLine Takes a line of arguments, breaks them and 962e2caf59SThomas Veerman * treats them as if they were given when first 972e2caf59SThomas Veerman * invoked. Used by the parse module to implement 982e2caf59SThomas Veerman * the .MFLAGS target. 992e2caf59SThomas Veerman * 1002e2caf59SThomas Veerman * Error Print a tagged error message. The global 1012e2caf59SThomas Veerman * MAKE variable must have been defined. This 1022e2caf59SThomas Veerman * takes a format string and two optional 1032e2caf59SThomas Veerman * arguments for it. 1042e2caf59SThomas Veerman * 1052e2caf59SThomas Veerman * Fatal Print an error message and exit. Also takes 1062e2caf59SThomas Veerman * a format string and two arguments. 1072e2caf59SThomas Veerman * 1082e2caf59SThomas Veerman * Punt Aborts all jobs and exits with a message. Also 1092e2caf59SThomas Veerman * takes a format string and two arguments. 1102e2caf59SThomas Veerman * 1112e2caf59SThomas Veerman * Finish Finish things up by printing the number of 1122e2caf59SThomas Veerman * errors which occurred, as passed to it, and 1132e2caf59SThomas Veerman * exiting. 1142e2caf59SThomas Veerman */ 1152e2caf59SThomas Veerman 1162e2caf59SThomas Veerman #include <sys/types.h> 1172e2caf59SThomas Veerman #include <sys/time.h> 1182e2caf59SThomas Veerman #include <sys/param.h> 1192e2caf59SThomas Veerman #include <sys/resource.h> 1202e2caf59SThomas Veerman #include <sys/signal.h> 1212e2caf59SThomas Veerman #include <sys/stat.h> 1222e2caf59SThomas Veerman #ifdef MAKE_NATIVE 1232e2caf59SThomas Veerman #include <sys/utsname.h> 1242e2caf59SThomas Veerman #endif 1252e2caf59SThomas Veerman #include <sys/wait.h> 1262e2caf59SThomas Veerman 1272e2caf59SThomas Veerman #include <errno.h> 1282e2caf59SThomas Veerman #include <fcntl.h> 1292e2caf59SThomas Veerman #include <stdarg.h> 1302e2caf59SThomas Veerman #include <stdio.h> 1312e2caf59SThomas Veerman #include <stdlib.h> 1322e2caf59SThomas Veerman #include <time.h> 1332e2caf59SThomas Veerman 1342e2caf59SThomas Veerman #include "make.h" 1352e2caf59SThomas Veerman #include "hash.h" 1362e2caf59SThomas Veerman #include "dir.h" 1372e2caf59SThomas Veerman #include "job.h" 1382e2caf59SThomas Veerman #include "pathnames.h" 1392e2caf59SThomas Veerman #include "trace.h" 1402e2caf59SThomas Veerman 1412e2caf59SThomas Veerman #ifdef USE_IOVEC 1422e2caf59SThomas Veerman #include <sys/uio.h> 1432e2caf59SThomas Veerman #endif 1442e2caf59SThomas Veerman 1452e2caf59SThomas Veerman #ifndef DEFMAXLOCAL 1462e2caf59SThomas Veerman #define DEFMAXLOCAL DEFMAXJOBS 1472e2caf59SThomas Veerman #endif /* DEFMAXLOCAL */ 1482e2caf59SThomas Veerman 1492e2caf59SThomas Veerman Lst create; /* Targets to be made */ 1502e2caf59SThomas Veerman time_t now; /* Time at start of make */ 1512e2caf59SThomas Veerman GNode *DEFAULT; /* .DEFAULT node */ 1522e2caf59SThomas Veerman Boolean allPrecious; /* .PRECIOUS given on line by itself */ 1532e2caf59SThomas Veerman 1542e2caf59SThomas Veerman static Boolean noBuiltins; /* -r flag */ 1552e2caf59SThomas Veerman static Lst makefiles; /* ordered list of makefiles to read */ 1562e2caf59SThomas Veerman static Boolean printVars; /* print value of one or more vars */ 1572e2caf59SThomas Veerman static Lst variables; /* list of variables to print */ 1582e2caf59SThomas Veerman int maxJobs; /* -j argument */ 1592e2caf59SThomas Veerman static int maxJobTokens; /* -j argument */ 1602e2caf59SThomas Veerman Boolean compatMake; /* -B argument */ 1612e2caf59SThomas Veerman int debug; /* -d argument */ 162*2bc7c627SLionel Sambuc Boolean debugVflag; /* -dV */ 1632e2caf59SThomas Veerman Boolean noExecute; /* -n flag */ 1642e2caf59SThomas Veerman Boolean noRecursiveExecute; /* -N flag */ 1652e2caf59SThomas Veerman Boolean keepgoing; /* -k flag */ 1662e2caf59SThomas Veerman Boolean queryFlag; /* -q flag */ 1672e2caf59SThomas Veerman Boolean touchFlag; /* -t flag */ 1682e2caf59SThomas Veerman Boolean ignoreErrors; /* -i flag */ 1692e2caf59SThomas Veerman Boolean beSilent; /* -s flag */ 1702e2caf59SThomas Veerman Boolean oldVars; /* variable substitution style */ 1712e2caf59SThomas Veerman Boolean checkEnvFirst; /* -e flag */ 1722e2caf59SThomas Veerman Boolean parseWarnFatal; /* -W flag */ 1732e2caf59SThomas Veerman Boolean jobServer; /* -J flag */ 1742e2caf59SThomas Veerman static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 1752e2caf59SThomas Veerman Boolean varNoExportEnv; /* -X flag */ 1762e2caf59SThomas Veerman Boolean doing_depend; /* Set while reading .depend */ 1772e2caf59SThomas Veerman static Boolean jobsRunning; /* TRUE if the jobs might be running */ 1782e2caf59SThomas Veerman static const char * tracefile; 1792e2caf59SThomas Veerman static char * Check_Cwd_av(int, char **, int); 1802e2caf59SThomas Veerman static void MainParseArgs(int, char **); 1812e2caf59SThomas Veerman static int ReadMakefile(const void *, const void *); 182*2bc7c627SLionel Sambuc static void usage(void) MAKE_ATTR_DEAD; 1832e2caf59SThomas Veerman 1842e2caf59SThomas Veerman static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 1852e2caf59SThomas Veerman static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 1862e2caf59SThomas Veerman char curdir[MAXPATHLEN + 1]; /* Startup directory */ 1872e2caf59SThomas Veerman char *progname; /* the program name */ 1882e2caf59SThomas Veerman char *makeDependfile; 1892e2caf59SThomas Veerman pid_t myPid; 1902e2caf59SThomas Veerman 1912e2caf59SThomas Veerman Boolean forceJobs = FALSE; 1922e2caf59SThomas Veerman 1932e2caf59SThomas Veerman extern Lst parseIncPath; 1942e2caf59SThomas Veerman 1952e2caf59SThomas Veerman static void 1962e2caf59SThomas Veerman parse_debug_options(const char *argvalue) 1972e2caf59SThomas Veerman { 1982e2caf59SThomas Veerman const char *modules; 1992e2caf59SThomas Veerman const char *mode; 2002e2caf59SThomas Veerman char *fname; 2012e2caf59SThomas Veerman int len; 2022e2caf59SThomas Veerman 2032e2caf59SThomas Veerman for (modules = argvalue; *modules; ++modules) { 2042e2caf59SThomas Veerman switch (*modules) { 2052e2caf59SThomas Veerman case 'A': 2062e2caf59SThomas Veerman debug = ~0; 2072e2caf59SThomas Veerman break; 2082e2caf59SThomas Veerman case 'a': 2092e2caf59SThomas Veerman debug |= DEBUG_ARCH; 2102e2caf59SThomas Veerman break; 2112e2caf59SThomas Veerman case 'C': 2122e2caf59SThomas Veerman debug |= DEBUG_CWD; 2132e2caf59SThomas Veerman break; 2142e2caf59SThomas Veerman case 'c': 2152e2caf59SThomas Veerman debug |= DEBUG_COND; 2162e2caf59SThomas Veerman break; 2172e2caf59SThomas Veerman case 'd': 2182e2caf59SThomas Veerman debug |= DEBUG_DIR; 2192e2caf59SThomas Veerman break; 2202e2caf59SThomas Veerman case 'e': 2212e2caf59SThomas Veerman debug |= DEBUG_ERROR; 2222e2caf59SThomas Veerman break; 2232e2caf59SThomas Veerman case 'f': 2242e2caf59SThomas Veerman debug |= DEBUG_FOR; 2252e2caf59SThomas Veerman break; 2262e2caf59SThomas Veerman case 'g': 2272e2caf59SThomas Veerman if (modules[1] == '1') { 2282e2caf59SThomas Veerman debug |= DEBUG_GRAPH1; 2292e2caf59SThomas Veerman ++modules; 2302e2caf59SThomas Veerman } 2312e2caf59SThomas Veerman else if (modules[1] == '2') { 2322e2caf59SThomas Veerman debug |= DEBUG_GRAPH2; 2332e2caf59SThomas Veerman ++modules; 2342e2caf59SThomas Veerman } 2352e2caf59SThomas Veerman else if (modules[1] == '3') { 2362e2caf59SThomas Veerman debug |= DEBUG_GRAPH3; 2372e2caf59SThomas Veerman ++modules; 2382e2caf59SThomas Veerman } 2392e2caf59SThomas Veerman break; 2402e2caf59SThomas Veerman case 'j': 2412e2caf59SThomas Veerman debug |= DEBUG_JOB; 2422e2caf59SThomas Veerman break; 2432e2caf59SThomas Veerman case 'l': 2442e2caf59SThomas Veerman debug |= DEBUG_LOUD; 2452e2caf59SThomas Veerman break; 2462e2caf59SThomas Veerman case 'M': 2472e2caf59SThomas Veerman debug |= DEBUG_META; 2482e2caf59SThomas Veerman break; 2492e2caf59SThomas Veerman case 'm': 2502e2caf59SThomas Veerman debug |= DEBUG_MAKE; 2512e2caf59SThomas Veerman break; 2522e2caf59SThomas Veerman case 'n': 2532e2caf59SThomas Veerman debug |= DEBUG_SCRIPT; 2542e2caf59SThomas Veerman break; 2552e2caf59SThomas Veerman case 'p': 2562e2caf59SThomas Veerman debug |= DEBUG_PARSE; 2572e2caf59SThomas Veerman break; 2582e2caf59SThomas Veerman case 's': 2592e2caf59SThomas Veerman debug |= DEBUG_SUFF; 2602e2caf59SThomas Veerman break; 2612e2caf59SThomas Veerman case 't': 2622e2caf59SThomas Veerman debug |= DEBUG_TARG; 2632e2caf59SThomas Veerman break; 264*2bc7c627SLionel Sambuc case 'V': 265*2bc7c627SLionel Sambuc debugVflag = TRUE; 266*2bc7c627SLionel Sambuc break; 2672e2caf59SThomas Veerman case 'v': 2682e2caf59SThomas Veerman debug |= DEBUG_VAR; 2692e2caf59SThomas Veerman break; 2702e2caf59SThomas Veerman case 'x': 2712e2caf59SThomas Veerman debug |= DEBUG_SHELL; 2722e2caf59SThomas Veerman break; 2732e2caf59SThomas Veerman case 'F': 2742e2caf59SThomas Veerman if (debug_file != stdout && debug_file != stderr) 2752e2caf59SThomas Veerman fclose(debug_file); 276*2bc7c627SLionel Sambuc if (*++modules == '+') { 277*2bc7c627SLionel Sambuc modules++; 2782e2caf59SThomas Veerman mode = "a"; 279*2bc7c627SLionel Sambuc } else 2802e2caf59SThomas Veerman mode = "w"; 2812e2caf59SThomas Veerman if (strcmp(modules, "stdout") == 0) { 2822e2caf59SThomas Veerman debug_file = stdout; 2832e2caf59SThomas Veerman goto debug_setbuf; 2842e2caf59SThomas Veerman } 2852e2caf59SThomas Veerman if (strcmp(modules, "stderr") == 0) { 2862e2caf59SThomas Veerman debug_file = stderr; 2872e2caf59SThomas Veerman goto debug_setbuf; 2882e2caf59SThomas Veerman } 2892e2caf59SThomas Veerman len = strlen(modules); 2902e2caf59SThomas Veerman fname = malloc(len + 20); 2912e2caf59SThomas Veerman memcpy(fname, modules, len + 1); 2922e2caf59SThomas Veerman /* Let the filename be modified by the pid */ 2932e2caf59SThomas Veerman if (strcmp(fname + len - 3, ".%d") == 0) 2942e2caf59SThomas Veerman snprintf(fname + len - 2, 20, "%d", getpid()); 2952e2caf59SThomas Veerman debug_file = fopen(fname, mode); 2962e2caf59SThomas Veerman if (!debug_file) { 2972e2caf59SThomas Veerman fprintf(stderr, "Cannot open debug file %s\n", 2982e2caf59SThomas Veerman fname); 2992e2caf59SThomas Veerman usage(); 3002e2caf59SThomas Veerman } 3012e2caf59SThomas Veerman free(fname); 3022e2caf59SThomas Veerman goto debug_setbuf; 3032e2caf59SThomas Veerman default: 3042e2caf59SThomas Veerman (void)fprintf(stderr, 3052e2caf59SThomas Veerman "%s: illegal argument to d option -- %c\n", 3062e2caf59SThomas Veerman progname, *modules); 3072e2caf59SThomas Veerman usage(); 3082e2caf59SThomas Veerman } 3092e2caf59SThomas Veerman } 3102e2caf59SThomas Veerman debug_setbuf: 3112e2caf59SThomas Veerman /* 3122e2caf59SThomas Veerman * Make the debug_file unbuffered, and make 3132e2caf59SThomas Veerman * stdout line buffered (unless debugfile == stdout). 3142e2caf59SThomas Veerman */ 3152e2caf59SThomas Veerman setvbuf(debug_file, NULL, _IONBF, 0); 3162e2caf59SThomas Veerman if (debug_file != stdout) { 3172e2caf59SThomas Veerman setvbuf(stdout, NULL, _IOLBF, 0); 3182e2caf59SThomas Veerman } 3192e2caf59SThomas Veerman } 3202e2caf59SThomas Veerman 3212e2caf59SThomas Veerman /*- 3222e2caf59SThomas Veerman * MainParseArgs -- 3232e2caf59SThomas Veerman * Parse a given argument vector. Called from main() and from 3242e2caf59SThomas Veerman * Main_ParseArgLine() when the .MAKEFLAGS target is used. 3252e2caf59SThomas Veerman * 3262e2caf59SThomas Veerman * XXX: Deal with command line overriding .MAKEFLAGS in makefile 3272e2caf59SThomas Veerman * 3282e2caf59SThomas Veerman * Results: 3292e2caf59SThomas Veerman * None 3302e2caf59SThomas Veerman * 3312e2caf59SThomas Veerman * Side Effects: 3322e2caf59SThomas Veerman * Various global and local flags will be set depending on the flags 3332e2caf59SThomas Veerman * given 3342e2caf59SThomas Veerman */ 3352e2caf59SThomas Veerman static void 3362e2caf59SThomas Veerman MainParseArgs(int argc, char **argv) 3372e2caf59SThomas Veerman { 3382e2caf59SThomas Veerman char *p; 3392e2caf59SThomas Veerman int c = '?'; 3402e2caf59SThomas Veerman int arginc; 3412e2caf59SThomas Veerman char *argvalue; 3422e2caf59SThomas Veerman const char *getopt_def; 3432e2caf59SThomas Veerman char *optscan; 3442e2caf59SThomas Veerman Boolean inOption, dashDash = FALSE; 3452e2caf59SThomas Veerman char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 3462e2caf59SThomas Veerman 3472e2caf59SThomas Veerman #define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrst" 3482e2caf59SThomas Veerman /* Can't actually use getopt(3) because rescanning is not portable */ 3492e2caf59SThomas Veerman 3502e2caf59SThomas Veerman getopt_def = OPTFLAGS; 3512e2caf59SThomas Veerman rearg: 3522e2caf59SThomas Veerman inOption = FALSE; 3532e2caf59SThomas Veerman optscan = NULL; 3542e2caf59SThomas Veerman while(argc > 1) { 3552e2caf59SThomas Veerman char *getopt_spec; 3562e2caf59SThomas Veerman if(!inOption) 3572e2caf59SThomas Veerman optscan = argv[1]; 3582e2caf59SThomas Veerman c = *optscan++; 3592e2caf59SThomas Veerman arginc = 0; 3602e2caf59SThomas Veerman if(inOption) { 3612e2caf59SThomas Veerman if(c == '\0') { 3622e2caf59SThomas Veerman ++argv; 3632e2caf59SThomas Veerman --argc; 3642e2caf59SThomas Veerman inOption = FALSE; 3652e2caf59SThomas Veerman continue; 3662e2caf59SThomas Veerman } 3672e2caf59SThomas Veerman } else { 3682e2caf59SThomas Veerman if (c != '-' || dashDash) 3692e2caf59SThomas Veerman break; 3702e2caf59SThomas Veerman inOption = TRUE; 3712e2caf59SThomas Veerman c = *optscan++; 3722e2caf59SThomas Veerman } 3732e2caf59SThomas Veerman /* '-' found at some earlier point */ 3742e2caf59SThomas Veerman getopt_spec = strchr(getopt_def, c); 3752e2caf59SThomas Veerman if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 3762e2caf59SThomas Veerman /* -<something> found, and <something> should have an arg */ 3772e2caf59SThomas Veerman inOption = FALSE; 3782e2caf59SThomas Veerman arginc = 1; 3792e2caf59SThomas Veerman argvalue = optscan; 3802e2caf59SThomas Veerman if(*argvalue == '\0') { 3812e2caf59SThomas Veerman if (argc < 3) 3822e2caf59SThomas Veerman goto noarg; 3832e2caf59SThomas Veerman argvalue = argv[2]; 3842e2caf59SThomas Veerman arginc = 2; 3852e2caf59SThomas Veerman } 3862e2caf59SThomas Veerman } else { 3872e2caf59SThomas Veerman argvalue = NULL; 3882e2caf59SThomas Veerman } 3892e2caf59SThomas Veerman switch(c) { 3902e2caf59SThomas Veerman case '\0': 3912e2caf59SThomas Veerman arginc = 1; 3922e2caf59SThomas Veerman inOption = FALSE; 3932e2caf59SThomas Veerman break; 3942e2caf59SThomas Veerman case 'B': 3952e2caf59SThomas Veerman compatMake = TRUE; 3962e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 3972e2caf59SThomas Veerman Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 3982e2caf59SThomas Veerman break; 3992e2caf59SThomas Veerman case 'C': 4002e2caf59SThomas Veerman if (chdir(argvalue) == -1) { 4012e2caf59SThomas Veerman (void)fprintf(stderr, 4022e2caf59SThomas Veerman "%s: chdir %s: %s\n", 4032e2caf59SThomas Veerman progname, argvalue, 4042e2caf59SThomas Veerman strerror(errno)); 4052e2caf59SThomas Veerman exit(1); 4062e2caf59SThomas Veerman } 4072e2caf59SThomas Veerman if (getcwd(curdir, MAXPATHLEN) == NULL) { 4082e2caf59SThomas Veerman (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 4092e2caf59SThomas Veerman exit(2); 4102e2caf59SThomas Veerman } 4112e2caf59SThomas Veerman ignorePWD = TRUE; 4122e2caf59SThomas Veerman break; 4132e2caf59SThomas Veerman case 'D': 4142e2caf59SThomas Veerman if (argvalue == NULL || argvalue[0] == 0) goto noarg; 4152e2caf59SThomas Veerman Var_Set(argvalue, "1", VAR_GLOBAL, 0); 4162e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 4172e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4182e2caf59SThomas Veerman break; 4192e2caf59SThomas Veerman case 'I': 4202e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4212e2caf59SThomas Veerman Parse_AddIncludeDir(argvalue); 4222e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 4232e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4242e2caf59SThomas Veerman break; 4252e2caf59SThomas Veerman case 'J': 4262e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4272e2caf59SThomas Veerman if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 4282e2caf59SThomas Veerman (void)fprintf(stderr, 4292e2caf59SThomas Veerman "%s: internal error -- J option malformed (%s)\n", 4302e2caf59SThomas Veerman progname, argvalue); 4312e2caf59SThomas Veerman usage(); 4322e2caf59SThomas Veerman } 4332e2caf59SThomas Veerman if ((fcntl(jp_0, F_GETFD, 0) < 0) || 4342e2caf59SThomas Veerman (fcntl(jp_1, F_GETFD, 0) < 0)) { 4352e2caf59SThomas Veerman #if 0 4362e2caf59SThomas Veerman (void)fprintf(stderr, 4372e2caf59SThomas Veerman "%s: ###### warning -- J descriptors were closed!\n", 4382e2caf59SThomas Veerman progname); 4392e2caf59SThomas Veerman exit(2); 4402e2caf59SThomas Veerman #endif 4412e2caf59SThomas Veerman jp_0 = -1; 4422e2caf59SThomas Veerman jp_1 = -1; 4432e2caf59SThomas Veerman compatMake = TRUE; 4442e2caf59SThomas Veerman } else { 4452e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 4462e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4472e2caf59SThomas Veerman jobServer = TRUE; 4482e2caf59SThomas Veerman } 4492e2caf59SThomas Veerman break; 4502e2caf59SThomas Veerman case 'N': 4512e2caf59SThomas Veerman noExecute = TRUE; 4522e2caf59SThomas Veerman noRecursiveExecute = TRUE; 4532e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 4542e2caf59SThomas Veerman break; 4552e2caf59SThomas Veerman case 'S': 4562e2caf59SThomas Veerman keepgoing = FALSE; 4572e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 4582e2caf59SThomas Veerman break; 4592e2caf59SThomas Veerman case 'T': 4602e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4612e2caf59SThomas Veerman tracefile = bmake_strdup(argvalue); 4622e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 4632e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4642e2caf59SThomas Veerman break; 4652e2caf59SThomas Veerman case 'V': 4662e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4672e2caf59SThomas Veerman printVars = TRUE; 4682e2caf59SThomas Veerman (void)Lst_AtEnd(variables, argvalue); 4692e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 4702e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4712e2caf59SThomas Veerman break; 4722e2caf59SThomas Veerman case 'W': 4732e2caf59SThomas Veerman parseWarnFatal = TRUE; 4742e2caf59SThomas Veerman break; 4752e2caf59SThomas Veerman case 'X': 4762e2caf59SThomas Veerman varNoExportEnv = TRUE; 4772e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 4782e2caf59SThomas Veerman break; 4792e2caf59SThomas Veerman case 'd': 4802e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4812e2caf59SThomas Veerman /* If '-d-opts' don't pass to children */ 4822e2caf59SThomas Veerman if (argvalue[0] == '-') 4832e2caf59SThomas Veerman argvalue++; 4842e2caf59SThomas Veerman else { 4852e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 4862e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 4872e2caf59SThomas Veerman } 4882e2caf59SThomas Veerman parse_debug_options(argvalue); 4892e2caf59SThomas Veerman break; 4902e2caf59SThomas Veerman case 'e': 4912e2caf59SThomas Veerman checkEnvFirst = TRUE; 4922e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 4932e2caf59SThomas Veerman break; 4942e2caf59SThomas Veerman case 'f': 4952e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 4962e2caf59SThomas Veerman (void)Lst_AtEnd(makefiles, argvalue); 4972e2caf59SThomas Veerman break; 4982e2caf59SThomas Veerman case 'i': 4992e2caf59SThomas Veerman ignoreErrors = TRUE; 5002e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 5012e2caf59SThomas Veerman break; 5022e2caf59SThomas Veerman case 'j': 5032e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 5042e2caf59SThomas Veerman forceJobs = TRUE; 5052e2caf59SThomas Veerman maxJobs = strtol(argvalue, &p, 0); 5062e2caf59SThomas Veerman if (*p != '\0' || maxJobs < 1) { 5072e2caf59SThomas Veerman (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 5082e2caf59SThomas Veerman progname); 5092e2caf59SThomas Veerman exit(1); 5102e2caf59SThomas Veerman } 5112e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 5122e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 5132e2caf59SThomas Veerman Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 5142e2caf59SThomas Veerman maxJobTokens = maxJobs; 5152e2caf59SThomas Veerman break; 5162e2caf59SThomas Veerman case 'k': 5172e2caf59SThomas Veerman keepgoing = TRUE; 5182e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 5192e2caf59SThomas Veerman break; 5202e2caf59SThomas Veerman case 'm': 5212e2caf59SThomas Veerman if (argvalue == NULL) goto noarg; 5222e2caf59SThomas Veerman /* look for magic parent directory search string */ 5232e2caf59SThomas Veerman if (strncmp(".../", argvalue, 4) == 0) { 5242e2caf59SThomas Veerman if (!Dir_FindHereOrAbove(curdir, argvalue+4, 5252e2caf59SThomas Veerman found_path, sizeof(found_path))) 5262e2caf59SThomas Veerman break; /* nothing doing */ 5272e2caf59SThomas Veerman (void)Dir_AddDir(sysIncPath, found_path); 5282e2caf59SThomas Veerman } else { 5292e2caf59SThomas Veerman (void)Dir_AddDir(sysIncPath, argvalue); 5302e2caf59SThomas Veerman } 5312e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 5322e2caf59SThomas Veerman Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 5332e2caf59SThomas Veerman break; 5342e2caf59SThomas Veerman case 'n': 5352e2caf59SThomas Veerman noExecute = TRUE; 5362e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 5372e2caf59SThomas Veerman break; 5382e2caf59SThomas Veerman case 'q': 5392e2caf59SThomas Veerman queryFlag = TRUE; 5402e2caf59SThomas Veerman /* Kind of nonsensical, wot? */ 5412e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 5422e2caf59SThomas Veerman break; 5432e2caf59SThomas Veerman case 'r': 5442e2caf59SThomas Veerman noBuiltins = TRUE; 5452e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 5462e2caf59SThomas Veerman break; 5472e2caf59SThomas Veerman case 's': 5482e2caf59SThomas Veerman beSilent = TRUE; 5492e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 5502e2caf59SThomas Veerman break; 5512e2caf59SThomas Veerman case 't': 5522e2caf59SThomas Veerman touchFlag = TRUE; 5532e2caf59SThomas Veerman Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 5542e2caf59SThomas Veerman break; 5552e2caf59SThomas Veerman case '-': 5562e2caf59SThomas Veerman dashDash = TRUE; 5572e2caf59SThomas Veerman break; 5582e2caf59SThomas Veerman default: 5592e2caf59SThomas Veerman case '?': 5602e2caf59SThomas Veerman usage(); 5612e2caf59SThomas Veerman } 5622e2caf59SThomas Veerman argv += arginc; 5632e2caf59SThomas Veerman argc -= arginc; 5642e2caf59SThomas Veerman } 5652e2caf59SThomas Veerman 5662e2caf59SThomas Veerman oldVars = TRUE; 5672e2caf59SThomas Veerman 5682e2caf59SThomas Veerman /* 5692e2caf59SThomas Veerman * See if the rest of the arguments are variable assignments and 5702e2caf59SThomas Veerman * perform them if so. Else take them to be targets and stuff them 5712e2caf59SThomas Veerman * on the end of the "create" list. 5722e2caf59SThomas Veerman */ 5732e2caf59SThomas Veerman for (; argc > 1; ++argv, --argc) 5742e2caf59SThomas Veerman if (Parse_IsVar(argv[1])) { 5752e2caf59SThomas Veerman Parse_DoVar(argv[1], VAR_CMD); 5762e2caf59SThomas Veerman } else { 5772e2caf59SThomas Veerman if (!*argv[1]) 5782e2caf59SThomas Veerman Punt("illegal (null) argument."); 5792e2caf59SThomas Veerman if (*argv[1] == '-' && !dashDash) 5802e2caf59SThomas Veerman goto rearg; 5812e2caf59SThomas Veerman (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 5822e2caf59SThomas Veerman } 5832e2caf59SThomas Veerman 5842e2caf59SThomas Veerman return; 5852e2caf59SThomas Veerman noarg: 5862e2caf59SThomas Veerman (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 5872e2caf59SThomas Veerman progname, c); 5882e2caf59SThomas Veerman usage(); 5892e2caf59SThomas Veerman } 5902e2caf59SThomas Veerman 5912e2caf59SThomas Veerman /*- 5922e2caf59SThomas Veerman * Main_ParseArgLine -- 5932e2caf59SThomas Veerman * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 5942e2caf59SThomas Veerman * is encountered and by main() when reading the .MAKEFLAGS envariable. 5952e2caf59SThomas Veerman * Takes a line of arguments and breaks it into its 5962e2caf59SThomas Veerman * component words and passes those words and the number of them to the 5972e2caf59SThomas Veerman * MainParseArgs function. 5982e2caf59SThomas Veerman * The line should have all its leading whitespace removed. 5992e2caf59SThomas Veerman * 6002e2caf59SThomas Veerman * Input: 6012e2caf59SThomas Veerman * line Line to fracture 6022e2caf59SThomas Veerman * 6032e2caf59SThomas Veerman * Results: 6042e2caf59SThomas Veerman * None 6052e2caf59SThomas Veerman * 6062e2caf59SThomas Veerman * Side Effects: 6072e2caf59SThomas Veerman * Only those that come from the various arguments. 6082e2caf59SThomas Veerman */ 6092e2caf59SThomas Veerman void 6102e2caf59SThomas Veerman Main_ParseArgLine(const char *line) 6112e2caf59SThomas Veerman { 6122e2caf59SThomas Veerman char **argv; /* Manufactured argument vector */ 6132e2caf59SThomas Veerman int argc; /* Number of arguments in argv */ 6142e2caf59SThomas Veerman char *args; /* Space used by the args */ 6152e2caf59SThomas Veerman char *buf, *p1; 6162e2caf59SThomas Veerman char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 6172e2caf59SThomas Veerman size_t len; 6182e2caf59SThomas Veerman 6192e2caf59SThomas Veerman if (line == NULL) 6202e2caf59SThomas Veerman return; 6212e2caf59SThomas Veerman for (; *line == ' '; ++line) 6222e2caf59SThomas Veerman continue; 6232e2caf59SThomas Veerman if (!*line) 6242e2caf59SThomas Veerman return; 6252e2caf59SThomas Veerman 6262e2caf59SThomas Veerman buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 6272e2caf59SThomas Veerman (void)snprintf(buf, len, "%s %s", argv0, line); 6282e2caf59SThomas Veerman if (p1) 6292e2caf59SThomas Veerman free(p1); 6302e2caf59SThomas Veerman 6312e2caf59SThomas Veerman argv = brk_string(buf, &argc, TRUE, &args); 6322e2caf59SThomas Veerman if (argv == NULL) { 6332e2caf59SThomas Veerman Error("Unterminated quoted string [%s]", buf); 6342e2caf59SThomas Veerman free(buf); 6352e2caf59SThomas Veerman return; 6362e2caf59SThomas Veerman } 6372e2caf59SThomas Veerman free(buf); 6382e2caf59SThomas Veerman MainParseArgs(argc, argv); 6392e2caf59SThomas Veerman 6402e2caf59SThomas Veerman free(args); 6412e2caf59SThomas Veerman free(argv); 6422e2caf59SThomas Veerman } 6432e2caf59SThomas Veerman 6442e2caf59SThomas Veerman Boolean 6452e2caf59SThomas Veerman Main_SetObjdir(const char *path) 6462e2caf59SThomas Veerman { 6472e2caf59SThomas Veerman struct stat sb; 6482e2caf59SThomas Veerman char *p = NULL; 6492e2caf59SThomas Veerman char buf[MAXPATHLEN + 1]; 6502e2caf59SThomas Veerman Boolean rc = FALSE; 6512e2caf59SThomas Veerman 6522e2caf59SThomas Veerman /* expand variable substitutions */ 6532e2caf59SThomas Veerman if (strchr(path, '$') != 0) { 6542e2caf59SThomas Veerman snprintf(buf, MAXPATHLEN, "%s", path); 6552e2caf59SThomas Veerman path = p = Var_Subst(NULL, buf, VAR_GLOBAL, 0); 6562e2caf59SThomas Veerman } 6572e2caf59SThomas Veerman 6582e2caf59SThomas Veerman if (path[0] != '/') { 6592e2caf59SThomas Veerman snprintf(buf, MAXPATHLEN, "%s/%s", curdir, path); 6602e2caf59SThomas Veerman path = buf; 6612e2caf59SThomas Veerman } 6622e2caf59SThomas Veerman 6632e2caf59SThomas Veerman /* look for the directory and try to chdir there */ 6642e2caf59SThomas Veerman if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 6652e2caf59SThomas Veerman if (chdir(path)) { 6662e2caf59SThomas Veerman (void)fprintf(stderr, "make warning: %s: %s.\n", 6672e2caf59SThomas Veerman path, strerror(errno)); 6682e2caf59SThomas Veerman } else { 6692e2caf59SThomas Veerman strncpy(objdir, path, MAXPATHLEN); 6702e2caf59SThomas Veerman Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 6712e2caf59SThomas Veerman setenv("PWD", objdir, 1); 6722e2caf59SThomas Veerman Dir_InitDot(); 6732e2caf59SThomas Veerman rc = TRUE; 6742e2caf59SThomas Veerman } 6752e2caf59SThomas Veerman } 6762e2caf59SThomas Veerman 6772e2caf59SThomas Veerman if (p) 6782e2caf59SThomas Veerman free(p); 6792e2caf59SThomas Veerman return rc; 6802e2caf59SThomas Veerman } 6812e2caf59SThomas Veerman 6822e2caf59SThomas Veerman /*- 6832e2caf59SThomas Veerman * ReadAllMakefiles -- 6842e2caf59SThomas Veerman * wrapper around ReadMakefile() to read all. 6852e2caf59SThomas Veerman * 6862e2caf59SThomas Veerman * Results: 6872e2caf59SThomas Veerman * TRUE if ok, FALSE on error 6882e2caf59SThomas Veerman */ 6892e2caf59SThomas Veerman static int 6902e2caf59SThomas Veerman ReadAllMakefiles(const void *p, const void *q) 6912e2caf59SThomas Veerman { 6922e2caf59SThomas Veerman return (ReadMakefile(p, q) == 0); 6932e2caf59SThomas Veerman } 6942e2caf59SThomas Veerman 6952e2caf59SThomas Veerman int 6962e2caf59SThomas Veerman str2Lst_Append(Lst lp, char *str, const char *sep) 6972e2caf59SThomas Veerman { 6982e2caf59SThomas Veerman char *cp; 6992e2caf59SThomas Veerman int n; 7002e2caf59SThomas Veerman 7012e2caf59SThomas Veerman if (!sep) 7022e2caf59SThomas Veerman sep = " \t"; 7032e2caf59SThomas Veerman 7042e2caf59SThomas Veerman for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 7052e2caf59SThomas Veerman (void)Lst_AtEnd(lp, cp); 7062e2caf59SThomas Veerman n++; 7072e2caf59SThomas Veerman } 7082e2caf59SThomas Veerman return (n); 7092e2caf59SThomas Veerman } 7102e2caf59SThomas Veerman 7112e2caf59SThomas Veerman #ifdef SIGINFO 7122e2caf59SThomas Veerman /*ARGSUSED*/ 7132e2caf59SThomas Veerman static void 714*2bc7c627SLionel Sambuc siginfo(int signo MAKE_ATTR_UNUSED) 7152e2caf59SThomas Veerman { 7162e2caf59SThomas Veerman char dir[MAXPATHLEN]; 7172e2caf59SThomas Veerman char str[2 * MAXPATHLEN]; 7182e2caf59SThomas Veerman int len; 7192e2caf59SThomas Veerman if (getcwd(dir, sizeof(dir)) == NULL) 7202e2caf59SThomas Veerman return; 7212e2caf59SThomas Veerman len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 7222e2caf59SThomas Veerman if (len > 0) 7232e2caf59SThomas Veerman (void)write(STDERR_FILENO, str, (size_t)len); 7242e2caf59SThomas Veerman } 7252e2caf59SThomas Veerman #endif 7262e2caf59SThomas Veerman 7272e2caf59SThomas Veerman /* 7282e2caf59SThomas Veerman * Allow makefiles some control over the mode we run in. 7292e2caf59SThomas Veerman */ 7302e2caf59SThomas Veerman void 7312e2caf59SThomas Veerman MakeMode(const char *mode) 7322e2caf59SThomas Veerman { 7332e2caf59SThomas Veerman char *mp = NULL; 7342e2caf59SThomas Veerman 7352e2caf59SThomas Veerman if (!mode) 7362e2caf59SThomas Veerman mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", VAR_GLOBAL, 0); 7372e2caf59SThomas Veerman 7382e2caf59SThomas Veerman if (mode && *mode) { 7392e2caf59SThomas Veerman if (strstr(mode, "compat")) { 7402e2caf59SThomas Veerman compatMake = TRUE; 7412e2caf59SThomas Veerman forceJobs = FALSE; 7422e2caf59SThomas Veerman } 7432e2caf59SThomas Veerman #if USE_META 7442e2caf59SThomas Veerman if (strstr(mode, "meta")) 7452e2caf59SThomas Veerman meta_init(mode); 7462e2caf59SThomas Veerman #endif 7472e2caf59SThomas Veerman } 7482e2caf59SThomas Veerman if (mp) 7492e2caf59SThomas Veerman free(mp); 7502e2caf59SThomas Veerman } 7512e2caf59SThomas Veerman 7522e2caf59SThomas Veerman /*- 7532e2caf59SThomas Veerman * main -- 7542e2caf59SThomas Veerman * The main function, for obvious reasons. Initializes variables 7552e2caf59SThomas Veerman * and a few modules, then parses the arguments give it in the 7562e2caf59SThomas Veerman * environment and on the command line. Reads the system makefile 7572e2caf59SThomas Veerman * followed by either Makefile, makefile or the file given by the 7582e2caf59SThomas Veerman * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 7592e2caf59SThomas Veerman * flags it has received by then uses either the Make or the Compat 7602e2caf59SThomas Veerman * module to create the initial list of targets. 7612e2caf59SThomas Veerman * 7622e2caf59SThomas Veerman * Results: 7632e2caf59SThomas Veerman * If -q was given, exits -1 if anything was out-of-date. Else it exits 7642e2caf59SThomas Veerman * 0. 7652e2caf59SThomas Veerman * 7662e2caf59SThomas Veerman * Side Effects: 7672e2caf59SThomas Veerman * The program exits when done. Targets are created. etc. etc. etc. 7682e2caf59SThomas Veerman */ 7692e2caf59SThomas Veerman int 7702e2caf59SThomas Veerman main(int argc, char **argv) 7712e2caf59SThomas Veerman { 7722e2caf59SThomas Veerman Lst targs; /* target nodes to create -- passed to Make_Init */ 7732e2caf59SThomas Veerman Boolean outOfDate = FALSE; /* FALSE if all targets up to date */ 7742e2caf59SThomas Veerman struct stat sb, sa; 7752e2caf59SThomas Veerman char *p1, *path, *pwd; 7762e2caf59SThomas Veerman char mdpath[MAXPATHLEN]; 7772e2caf59SThomas Veerman const char *machine = getenv("MACHINE"); 7782e2caf59SThomas Veerman const char *machine_arch = getenv("MACHINE_ARCH"); 7792e2caf59SThomas Veerman char *syspath = getenv("MAKESYSPATH"); 7802e2caf59SThomas Veerman Lst sysMkPath; /* Path of sys.mk */ 7812e2caf59SThomas Veerman char *cp = NULL, *start; 7822e2caf59SThomas Veerman /* avoid faults on read-only strings */ 7832e2caf59SThomas Veerman static char defsyspath[] = _PATH_DEFSYSPATH; 7842e2caf59SThomas Veerman char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 7852e2caf59SThomas Veerman struct timeval rightnow; /* to initialize random seed */ 7862e2caf59SThomas Veerman #ifdef MAKE_NATIVE 7872e2caf59SThomas Veerman struct utsname utsname; 7882e2caf59SThomas Veerman #endif 7892e2caf59SThomas Veerman 7902e2caf59SThomas Veerman /* default to writing debug to stderr */ 7912e2caf59SThomas Veerman debug_file = stderr; 7922e2caf59SThomas Veerman 7932e2caf59SThomas Veerman #ifdef SIGINFO 7942e2caf59SThomas Veerman (void)bmake_signal(SIGINFO, siginfo); 7952e2caf59SThomas Veerman #endif 7962e2caf59SThomas Veerman /* 7972e2caf59SThomas Veerman * Set the seed to produce a different random sequence 7982e2caf59SThomas Veerman * on each program execution. 7992e2caf59SThomas Veerman */ 8002e2caf59SThomas Veerman gettimeofday(&rightnow, NULL); 8012e2caf59SThomas Veerman srandom(rightnow.tv_sec + rightnow.tv_usec); 8022e2caf59SThomas Veerman 8032e2caf59SThomas Veerman if ((progname = strrchr(argv[0], '/')) != NULL) 8042e2caf59SThomas Veerman progname++; 8052e2caf59SThomas Veerman else 8062e2caf59SThomas Veerman progname = argv[0]; 8072e2caf59SThomas Veerman #if defined(RLIMIT_NOFILE) && !defined(__minix) 8082e2caf59SThomas Veerman /* 8092e2caf59SThomas Veerman * get rid of resource limit on file descriptors 8102e2caf59SThomas Veerman */ 8112e2caf59SThomas Veerman { 8122e2caf59SThomas Veerman struct rlimit rl; 8132e2caf59SThomas Veerman if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 8142e2caf59SThomas Veerman rl.rlim_cur != rl.rlim_max) { 8152e2caf59SThomas Veerman rl.rlim_cur = rl.rlim_max; 8162e2caf59SThomas Veerman (void)setrlimit(RLIMIT_NOFILE, &rl); 8172e2caf59SThomas Veerman } 8182e2caf59SThomas Veerman } 8192e2caf59SThomas Veerman #endif 8202e2caf59SThomas Veerman 8212e2caf59SThomas Veerman /* 8222e2caf59SThomas Veerman * Get the name of this type of MACHINE from utsname 8232e2caf59SThomas Veerman * so we can share an executable for similar machines. 8242e2caf59SThomas Veerman * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 8252e2caf59SThomas Veerman * 8262e2caf59SThomas Veerman * Note that both MACHINE and MACHINE_ARCH are decided at 8272e2caf59SThomas Veerman * run-time. 8282e2caf59SThomas Veerman */ 8292e2caf59SThomas Veerman if (!machine) { 8302e2caf59SThomas Veerman #ifdef MAKE_NATIVE 8312e2caf59SThomas Veerman if (uname(&utsname) == -1) { 8322e2caf59SThomas Veerman (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 8332e2caf59SThomas Veerman strerror(errno)); 8342e2caf59SThomas Veerman exit(2); 8352e2caf59SThomas Veerman } 8362e2caf59SThomas Veerman machine = utsname.machine; 8372e2caf59SThomas Veerman #else 8382e2caf59SThomas Veerman #ifdef MAKE_MACHINE 8392e2caf59SThomas Veerman machine = MAKE_MACHINE; 8402e2caf59SThomas Veerman #else 8412e2caf59SThomas Veerman machine = "unknown"; 8422e2caf59SThomas Veerman #endif 8432e2caf59SThomas Veerman #endif 8442e2caf59SThomas Veerman } 8452e2caf59SThomas Veerman 8462e2caf59SThomas Veerman if (!machine_arch) { 8472e2caf59SThomas Veerman #ifndef MACHINE_ARCH 8482e2caf59SThomas Veerman #ifdef MAKE_MACHINE_ARCH 8492e2caf59SThomas Veerman machine_arch = MAKE_MACHINE_ARCH; 8502e2caf59SThomas Veerman #else 8512e2caf59SThomas Veerman machine_arch = "unknown"; 8522e2caf59SThomas Veerman #endif 8532e2caf59SThomas Veerman #else 8542e2caf59SThomas Veerman machine_arch = MACHINE_ARCH; 8552e2caf59SThomas Veerman #endif 8562e2caf59SThomas Veerman } 8572e2caf59SThomas Veerman 8582e2caf59SThomas Veerman myPid = getpid(); /* remember this for vFork() */ 8592e2caf59SThomas Veerman 8602e2caf59SThomas Veerman /* 8612e2caf59SThomas Veerman * Just in case MAKEOBJDIR wants us to do something tricky. 8622e2caf59SThomas Veerman */ 8632e2caf59SThomas Veerman Var_Init(); /* Initialize the lists of variables for 8642e2caf59SThomas Veerman * parsing arguments */ 8652e2caf59SThomas Veerman Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 8662e2caf59SThomas Veerman Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 8672e2caf59SThomas Veerman #ifdef MAKE_VERSION 8682e2caf59SThomas Veerman Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 8692e2caf59SThomas Veerman #endif 8702e2caf59SThomas Veerman Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 8712e2caf59SThomas Veerman /* 8722e2caf59SThomas Veerman * This is the traditional preference for makefiles. 8732e2caf59SThomas Veerman */ 8742e2caf59SThomas Veerman #ifndef MAKEFILE_PREFERENCE_LIST 8752e2caf59SThomas Veerman # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 8762e2caf59SThomas Veerman #endif 8772e2caf59SThomas Veerman Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 8782e2caf59SThomas Veerman VAR_GLOBAL, 0); 8792e2caf59SThomas Veerman Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 8802e2caf59SThomas Veerman 8812e2caf59SThomas Veerman create = Lst_Init(FALSE); 8822e2caf59SThomas Veerman makefiles = Lst_Init(FALSE); 8832e2caf59SThomas Veerman printVars = FALSE; 884*2bc7c627SLionel Sambuc debugVflag = FALSE; 8852e2caf59SThomas Veerman variables = Lst_Init(FALSE); 8862e2caf59SThomas Veerman beSilent = FALSE; /* Print commands as executed */ 8872e2caf59SThomas Veerman ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 8882e2caf59SThomas Veerman noExecute = FALSE; /* Execute all commands */ 8892e2caf59SThomas Veerman noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 8902e2caf59SThomas Veerman keepgoing = FALSE; /* Stop on error */ 8912e2caf59SThomas Veerman allPrecious = FALSE; /* Remove targets when interrupted */ 8922e2caf59SThomas Veerman queryFlag = FALSE; /* This is not just a check-run */ 8932e2caf59SThomas Veerman noBuiltins = FALSE; /* Read the built-in rules */ 8942e2caf59SThomas Veerman touchFlag = FALSE; /* Actually update targets */ 8952e2caf59SThomas Veerman debug = 0; /* No debug verbosity, please. */ 8962e2caf59SThomas Veerman jobsRunning = FALSE; 8972e2caf59SThomas Veerman 8982e2caf59SThomas Veerman maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 8992e2caf59SThomas Veerman maxJobTokens = maxJobs; 9002e2caf59SThomas Veerman compatMake = FALSE; /* No compat mode */ 9012e2caf59SThomas Veerman ignorePWD = FALSE; 9022e2caf59SThomas Veerman 9032e2caf59SThomas Veerman /* 9042e2caf59SThomas Veerman * Initialize the parsing, directory and variable modules to prepare 9052e2caf59SThomas Veerman * for the reading of inclusion paths and variable settings on the 9062e2caf59SThomas Veerman * command line 9072e2caf59SThomas Veerman */ 9082e2caf59SThomas Veerman 9092e2caf59SThomas Veerman /* 9102e2caf59SThomas Veerman * Initialize various variables. 9112e2caf59SThomas Veerman * MAKE also gets this name, for compatibility 9122e2caf59SThomas Veerman * .MAKEFLAGS gets set to the empty string just in case. 9132e2caf59SThomas Veerman * MFLAGS also gets initialized empty, for compatibility. 9142e2caf59SThomas Veerman */ 9152e2caf59SThomas Veerman Parse_Init(); 9162e2caf59SThomas Veerman if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 9172e2caf59SThomas Veerman /* 9182e2caf59SThomas Veerman * Leave alone if it is an absolute path, or if it does 9192e2caf59SThomas Veerman * not contain a '/' in which case we need to find it in 9202e2caf59SThomas Veerman * the path, like execvp(3) and the shells do. 9212e2caf59SThomas Veerman */ 9222e2caf59SThomas Veerman p1 = argv[0]; 9232e2caf59SThomas Veerman } else { 9242e2caf59SThomas Veerman /* 9252e2caf59SThomas Veerman * A relative path, canonicalize it. 9262e2caf59SThomas Veerman */ 9272e2caf59SThomas Veerman p1 = realpath(argv[0], mdpath); 9282e2caf59SThomas Veerman if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 9292e2caf59SThomas Veerman p1 = argv[0]; /* realpath failed */ 9302e2caf59SThomas Veerman } 9312e2caf59SThomas Veerman } 9322e2caf59SThomas Veerman Var_Set("MAKE", p1, VAR_GLOBAL, 0); 9332e2caf59SThomas Veerman Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 9342e2caf59SThomas Veerman Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 9352e2caf59SThomas Veerman Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 9362e2caf59SThomas Veerman Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 9372e2caf59SThomas Veerman Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 9382e2caf59SThomas Veerman 9392e2caf59SThomas Veerman /* 9402e2caf59SThomas Veerman * Set some other useful macros 9412e2caf59SThomas Veerman */ 9422e2caf59SThomas Veerman { 9432e2caf59SThomas Veerman char tmp[64]; 9442e2caf59SThomas Veerman const char *ep; 9452e2caf59SThomas Veerman 9462e2caf59SThomas Veerman if (!(ep = getenv(MAKE_LEVEL))) { 9472e2caf59SThomas Veerman ep = "0"; 9482e2caf59SThomas Veerman } 9492e2caf59SThomas Veerman Var_Set(MAKE_LEVEL, ep, VAR_GLOBAL, 0); 9502e2caf59SThomas Veerman snprintf(tmp, sizeof(tmp), "%u", myPid); 9512e2caf59SThomas Veerman Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 9522e2caf59SThomas Veerman snprintf(tmp, sizeof(tmp), "%u", getppid()); 9532e2caf59SThomas Veerman Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 9542e2caf59SThomas Veerman } 9552e2caf59SThomas Veerman Job_SetPrefix(); 9562e2caf59SThomas Veerman 9572e2caf59SThomas Veerman /* 9582e2caf59SThomas Veerman * First snag any flags out of the MAKE environment variable. 9592e2caf59SThomas Veerman * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 9602e2caf59SThomas Veerman * in a different format). 9612e2caf59SThomas Veerman */ 9622e2caf59SThomas Veerman #ifdef POSIX 9632e2caf59SThomas Veerman Main_ParseArgLine(getenv("MAKEFLAGS")); 9642e2caf59SThomas Veerman #else 9652e2caf59SThomas Veerman Main_ParseArgLine(getenv("MAKE")); 9662e2caf59SThomas Veerman #endif 9672e2caf59SThomas Veerman 9682e2caf59SThomas Veerman /* 9692e2caf59SThomas Veerman * Find where we are (now). 9702e2caf59SThomas Veerman * We take care of PWD for the automounter below... 9712e2caf59SThomas Veerman */ 9722e2caf59SThomas Veerman if (getcwd(curdir, MAXPATHLEN) == NULL) { 9732e2caf59SThomas Veerman (void)fprintf(stderr, "%s: getcwd: %s.\n", 9742e2caf59SThomas Veerman progname, strerror(errno)); 9752e2caf59SThomas Veerman exit(2); 9762e2caf59SThomas Veerman } 9772e2caf59SThomas Veerman 9782e2caf59SThomas Veerman MainParseArgs(argc, argv); 9792e2caf59SThomas Veerman 9802e2caf59SThomas Veerman /* 9812e2caf59SThomas Veerman * Verify that cwd is sane. 9822e2caf59SThomas Veerman */ 9832e2caf59SThomas Veerman if (stat(curdir, &sa) == -1) { 9842e2caf59SThomas Veerman (void)fprintf(stderr, "%s: %s: %s.\n", 9852e2caf59SThomas Veerman progname, curdir, strerror(errno)); 9862e2caf59SThomas Veerman exit(2); 9872e2caf59SThomas Veerman } 9882e2caf59SThomas Veerman 9892e2caf59SThomas Veerman /* 9902e2caf59SThomas Veerman * All this code is so that we know where we are when we start up 9912e2caf59SThomas Veerman * on a different machine with pmake. 9922e2caf59SThomas Veerman * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 9932e2caf59SThomas Veerman * since the value of curdir can vary depending on how we got 9942e2caf59SThomas Veerman * here. Ie sitting at a shell prompt (shell that provides $PWD) 9952e2caf59SThomas Veerman * or via subdir.mk in which case its likely a shell which does 9962e2caf59SThomas Veerman * not provide it. 9972e2caf59SThomas Veerman * So, to stop it breaking this case only, we ignore PWD if 9982e2caf59SThomas Veerman * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 9992e2caf59SThomas Veerman */ 10002e2caf59SThomas Veerman if (!ignorePWD && 10012e2caf59SThomas Veerman (pwd = getenv("PWD")) != NULL && 10022e2caf59SThomas Veerman getenv("MAKEOBJDIRPREFIX") == NULL) { 10032e2caf59SThomas Veerman const char *makeobjdir = getenv("MAKEOBJDIR"); 10042e2caf59SThomas Veerman 10052e2caf59SThomas Veerman if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 10062e2caf59SThomas Veerman if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && 10072e2caf59SThomas Veerman sa.st_dev == sb.st_dev) 10082e2caf59SThomas Veerman (void)strncpy(curdir, pwd, MAXPATHLEN); 10092e2caf59SThomas Veerman } 10102e2caf59SThomas Veerman } 10112e2caf59SThomas Veerman Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 10122e2caf59SThomas Veerman 10132e2caf59SThomas Veerman /* 10142e2caf59SThomas Veerman * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 10152e2caf59SThomas Veerman * MAKEOBJDIR is set in the environment, try only that value 10162e2caf59SThomas Veerman * and fall back to .CURDIR if it does not exist. 10172e2caf59SThomas Veerman * 10182e2caf59SThomas Veerman * Otherwise, try _PATH_OBJDIR.MACHINE, _PATH_OBJDIR, and 10192e2caf59SThomas Veerman * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 10202e2caf59SThomas Veerman * of these paths exist, just use .CURDIR. 10212e2caf59SThomas Veerman */ 10222e2caf59SThomas Veerman Dir_Init(curdir); 10232e2caf59SThomas Veerman (void)Main_SetObjdir(curdir); 10242e2caf59SThomas Veerman 10252e2caf59SThomas Veerman if ((path = getenv("MAKEOBJDIRPREFIX")) != NULL) { 10262e2caf59SThomas Veerman (void)snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir); 10272e2caf59SThomas Veerman (void)Main_SetObjdir(mdpath); 10282e2caf59SThomas Veerman } else if ((path = getenv("MAKEOBJDIR")) != NULL) { 10292e2caf59SThomas Veerman (void)Main_SetObjdir(path); 10302e2caf59SThomas Veerman } else { 10312e2caf59SThomas Veerman (void)snprintf(mdpath, MAXPATHLEN, "%s.%s", _PATH_OBJDIR, machine); 10322e2caf59SThomas Veerman if (!Main_SetObjdir(mdpath) && !Main_SetObjdir(_PATH_OBJDIR)) { 10332e2caf59SThomas Veerman (void)snprintf(mdpath, MAXPATHLEN, "%s%s", 10342e2caf59SThomas Veerman _PATH_OBJDIRPREFIX, curdir); 10352e2caf59SThomas Veerman (void)Main_SetObjdir(mdpath); 10362e2caf59SThomas Veerman } 10372e2caf59SThomas Veerman } 10382e2caf59SThomas Veerman 10392e2caf59SThomas Veerman /* 10402e2caf59SThomas Veerman * Be compatible if user did not specify -j and did not explicitly 10412e2caf59SThomas Veerman * turned compatibility on 10422e2caf59SThomas Veerman */ 10432e2caf59SThomas Veerman if (!compatMake && !forceJobs) { 10442e2caf59SThomas Veerman compatMake = TRUE; 10452e2caf59SThomas Veerman } 10462e2caf59SThomas Veerman 10472e2caf59SThomas Veerman /* 10482e2caf59SThomas Veerman * Initialize archive, target and suffix modules in preparation for 10492e2caf59SThomas Veerman * parsing the makefile(s) 10502e2caf59SThomas Veerman */ 10512e2caf59SThomas Veerman Arch_Init(); 10522e2caf59SThomas Veerman Targ_Init(); 10532e2caf59SThomas Veerman Suff_Init(); 10542e2caf59SThomas Veerman Trace_Init(tracefile); 10552e2caf59SThomas Veerman 10562e2caf59SThomas Veerman DEFAULT = NULL; 10572e2caf59SThomas Veerman (void)time(&now); 10582e2caf59SThomas Veerman 10592e2caf59SThomas Veerman Trace_Log(MAKESTART, NULL); 10602e2caf59SThomas Veerman 10612e2caf59SThomas Veerman /* 10622e2caf59SThomas Veerman * Set up the .TARGETS variable to contain the list of targets to be 10632e2caf59SThomas Veerman * created. If none specified, make the variable empty -- the parser 10642e2caf59SThomas Veerman * will fill the thing in with the default or .MAIN target. 10652e2caf59SThomas Veerman */ 10662e2caf59SThomas Veerman if (!Lst_IsEmpty(create)) { 10672e2caf59SThomas Veerman LstNode ln; 10682e2caf59SThomas Veerman 10692e2caf59SThomas Veerman for (ln = Lst_First(create); ln != NULL; 10702e2caf59SThomas Veerman ln = Lst_Succ(ln)) { 10712e2caf59SThomas Veerman char *name = (char *)Lst_Datum(ln); 10722e2caf59SThomas Veerman 10732e2caf59SThomas Veerman Var_Append(".TARGETS", name, VAR_GLOBAL); 10742e2caf59SThomas Veerman } 10752e2caf59SThomas Veerman } else 10762e2caf59SThomas Veerman Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 10772e2caf59SThomas Veerman 10782e2caf59SThomas Veerman 10792e2caf59SThomas Veerman /* 10802e2caf59SThomas Veerman * If no user-supplied system path was given (through the -m option) 10812e2caf59SThomas Veerman * add the directories from the DEFSYSPATH (more than one may be given 10822e2caf59SThomas Veerman * as dir1:...:dirn) to the system include path. 10832e2caf59SThomas Veerman */ 10842e2caf59SThomas Veerman if (syspath == NULL || *syspath == '\0') 10852e2caf59SThomas Veerman syspath = defsyspath; 10862e2caf59SThomas Veerman else 10872e2caf59SThomas Veerman syspath = bmake_strdup(syspath); 10882e2caf59SThomas Veerman 10892e2caf59SThomas Veerman for (start = syspath; *start != '\0'; start = cp) { 10902e2caf59SThomas Veerman for (cp = start; *cp != '\0' && *cp != ':'; cp++) 10912e2caf59SThomas Veerman continue; 10922e2caf59SThomas Veerman if (*cp == ':') { 10932e2caf59SThomas Veerman *cp++ = '\0'; 10942e2caf59SThomas Veerman } 10952e2caf59SThomas Veerman /* look for magic parent directory search string */ 10962e2caf59SThomas Veerman if (strncmp(".../", start, 4) != 0) { 10972e2caf59SThomas Veerman (void)Dir_AddDir(defIncPath, start); 10982e2caf59SThomas Veerman } else { 10992e2caf59SThomas Veerman if (Dir_FindHereOrAbove(curdir, start+4, 11002e2caf59SThomas Veerman found_path, sizeof(found_path))) { 11012e2caf59SThomas Veerman (void)Dir_AddDir(defIncPath, found_path); 11022e2caf59SThomas Veerman } 11032e2caf59SThomas Veerman } 11042e2caf59SThomas Veerman } 11052e2caf59SThomas Veerman if (syspath != defsyspath) 11062e2caf59SThomas Veerman free(syspath); 11072e2caf59SThomas Veerman 11082e2caf59SThomas Veerman /* 11092e2caf59SThomas Veerman * Read in the built-in rules first, followed by the specified 11102e2caf59SThomas Veerman * makefile, if it was (makefile != NULL), or the default 11112e2caf59SThomas Veerman * makefile and Makefile, in that order, if it wasn't. 11122e2caf59SThomas Veerman */ 11132e2caf59SThomas Veerman if (!noBuiltins) { 11142e2caf59SThomas Veerman LstNode ln; 11152e2caf59SThomas Veerman 11162e2caf59SThomas Veerman sysMkPath = Lst_Init(FALSE); 11172e2caf59SThomas Veerman Dir_Expand(_PATH_DEFSYSMK, 11182e2caf59SThomas Veerman Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 11192e2caf59SThomas Veerman sysMkPath); 11202e2caf59SThomas Veerman if (Lst_IsEmpty(sysMkPath)) 11212e2caf59SThomas Veerman Fatal("%s: no system rules (%s).", progname, 11222e2caf59SThomas Veerman _PATH_DEFSYSMK); 11232e2caf59SThomas Veerman ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 11242e2caf59SThomas Veerman if (ln == NULL) 11252e2caf59SThomas Veerman Fatal("%s: cannot open %s.", progname, 11262e2caf59SThomas Veerman (char *)Lst_Datum(ln)); 11272e2caf59SThomas Veerman } 11282e2caf59SThomas Veerman 11292e2caf59SThomas Veerman if (!Lst_IsEmpty(makefiles)) { 11302e2caf59SThomas Veerman LstNode ln; 11312e2caf59SThomas Veerman 11322e2caf59SThomas Veerman ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 11332e2caf59SThomas Veerman if (ln != NULL) 11342e2caf59SThomas Veerman Fatal("%s: cannot open %s.", progname, 11352e2caf59SThomas Veerman (char *)Lst_Datum(ln)); 11362e2caf59SThomas Veerman } else { 11372e2caf59SThomas Veerman p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 11382e2caf59SThomas Veerman VAR_CMD, 0); 11392e2caf59SThomas Veerman if (p1) { 11402e2caf59SThomas Veerman (void)str2Lst_Append(makefiles, p1, NULL); 11412e2caf59SThomas Veerman (void)Lst_Find(makefiles, NULL, ReadMakefile); 11422e2caf59SThomas Veerman free(p1); 11432e2caf59SThomas Veerman } 11442e2caf59SThomas Veerman } 11452e2caf59SThomas Veerman 11462e2caf59SThomas Veerman /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 11472e2caf59SThomas Veerman if (!noBuiltins || !printVars) { 11482e2caf59SThomas Veerman makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 11492e2caf59SThomas Veerman VAR_CMD, 0); 11502e2caf59SThomas Veerman doing_depend = TRUE; 11512e2caf59SThomas Veerman (void)ReadMakefile(makeDependfile, NULL); 11522e2caf59SThomas Veerman doing_depend = FALSE; 11532e2caf59SThomas Veerman } 11542e2caf59SThomas Veerman 11552e2caf59SThomas Veerman MakeMode(NULL); 11562e2caf59SThomas Veerman 11572e2caf59SThomas Veerman Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 11582e2caf59SThomas Veerman if (p1) 11592e2caf59SThomas Veerman free(p1); 11602e2caf59SThomas Veerman 11612e2caf59SThomas Veerman if (!compatMake) 11622e2caf59SThomas Veerman Job_ServerStart(maxJobTokens, jp_0, jp_1); 11632e2caf59SThomas Veerman if (DEBUG(JOB)) 11642e2caf59SThomas Veerman fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 11652e2caf59SThomas Veerman jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 11662e2caf59SThomas Veerman 11672e2caf59SThomas Veerman Main_ExportMAKEFLAGS(TRUE); /* initial export */ 11682e2caf59SThomas Veerman 11692e2caf59SThomas Veerman Check_Cwd_av(0, NULL, 0); /* initialize it */ 11702e2caf59SThomas Veerman 11712e2caf59SThomas Veerman 11722e2caf59SThomas Veerman /* 11732e2caf59SThomas Veerman * For compatibility, look at the directories in the VPATH variable 11742e2caf59SThomas Veerman * and add them to the search path, if the variable is defined. The 11752e2caf59SThomas Veerman * variable's value is in the same format as the PATH envariable, i.e. 11762e2caf59SThomas Veerman * <directory>:<directory>:<directory>... 11772e2caf59SThomas Veerman */ 11782e2caf59SThomas Veerman if (Var_Exists("VPATH", VAR_CMD)) { 11792e2caf59SThomas Veerman char *vpath, savec; 11802e2caf59SThomas Veerman /* 11812e2caf59SThomas Veerman * GCC stores string constants in read-only memory, but 11822e2caf59SThomas Veerman * Var_Subst will want to write this thing, so store it 11832e2caf59SThomas Veerman * in an array 11842e2caf59SThomas Veerman */ 11852e2caf59SThomas Veerman static char VPATH[] = "${VPATH}"; 11862e2caf59SThomas Veerman 11872e2caf59SThomas Veerman vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 11882e2caf59SThomas Veerman path = vpath; 11892e2caf59SThomas Veerman do { 11902e2caf59SThomas Veerman /* skip to end of directory */ 11912e2caf59SThomas Veerman for (cp = path; *cp != ':' && *cp != '\0'; cp++) 11922e2caf59SThomas Veerman continue; 11932e2caf59SThomas Veerman /* Save terminator character so know when to stop */ 11942e2caf59SThomas Veerman savec = *cp; 11952e2caf59SThomas Veerman *cp = '\0'; 11962e2caf59SThomas Veerman /* Add directory to search path */ 11972e2caf59SThomas Veerman (void)Dir_AddDir(dirSearchPath, path); 11982e2caf59SThomas Veerman *cp = savec; 11992e2caf59SThomas Veerman path = cp + 1; 12002e2caf59SThomas Veerman } while (savec == ':'); 12012e2caf59SThomas Veerman free(vpath); 12022e2caf59SThomas Veerman } 12032e2caf59SThomas Veerman 12042e2caf59SThomas Veerman /* 12052e2caf59SThomas Veerman * Now that all search paths have been read for suffixes et al, it's 12062e2caf59SThomas Veerman * time to add the default search path to their lists... 12072e2caf59SThomas Veerman */ 12082e2caf59SThomas Veerman Suff_DoPaths(); 12092e2caf59SThomas Veerman 12102e2caf59SThomas Veerman /* 12112e2caf59SThomas Veerman * Propagate attributes through :: dependency lists. 12122e2caf59SThomas Veerman */ 12132e2caf59SThomas Veerman Targ_Propagate(); 12142e2caf59SThomas Veerman 12152e2caf59SThomas Veerman /* print the initial graph, if the user requested it */ 12162e2caf59SThomas Veerman if (DEBUG(GRAPH1)) 12172e2caf59SThomas Veerman Targ_PrintGraph(1); 12182e2caf59SThomas Veerman 12192e2caf59SThomas Veerman /* print the values of any variables requested by the user */ 12202e2caf59SThomas Veerman if (printVars) { 12212e2caf59SThomas Veerman LstNode ln; 1222*2bc7c627SLionel Sambuc Boolean expandVars; 12232e2caf59SThomas Veerman 1224*2bc7c627SLionel Sambuc if (debugVflag) 1225*2bc7c627SLionel Sambuc expandVars = FALSE; 1226*2bc7c627SLionel Sambuc else 1227*2bc7c627SLionel Sambuc expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 12282e2caf59SThomas Veerman for (ln = Lst_First(variables); ln != NULL; 12292e2caf59SThomas Veerman ln = Lst_Succ(ln)) { 12302e2caf59SThomas Veerman char *var = (char *)Lst_Datum(ln); 12312e2caf59SThomas Veerman char *value; 12322e2caf59SThomas Veerman 12332e2caf59SThomas Veerman if (strchr(var, '$')) { 12342e2caf59SThomas Veerman value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 0); 1235*2bc7c627SLionel Sambuc } else if (expandVars) { 1236*2bc7c627SLionel Sambuc char tmp[128]; 1237*2bc7c627SLionel Sambuc 1238*2bc7c627SLionel Sambuc if (snprintf(tmp, sizeof(tmp), "${%s}", var) >= (int)(sizeof(tmp))) 1239*2bc7c627SLionel Sambuc Fatal("%s: variable name too big: %s", 1240*2bc7c627SLionel Sambuc progname, var); 1241*2bc7c627SLionel Sambuc value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 12422e2caf59SThomas Veerman } else { 12432e2caf59SThomas Veerman value = Var_Value(var, VAR_GLOBAL, &p1); 12442e2caf59SThomas Veerman } 12452e2caf59SThomas Veerman printf("%s\n", value ? value : ""); 12462e2caf59SThomas Veerman if (p1) 12472e2caf59SThomas Veerman free(p1); 12482e2caf59SThomas Veerman } 12492e2caf59SThomas Veerman } else { 12502e2caf59SThomas Veerman /* 12512e2caf59SThomas Veerman * Have now read the entire graph and need to make a list of 12522e2caf59SThomas Veerman * targets to create. If none was given on the command line, 12532e2caf59SThomas Veerman * we consult the parsing module to find the main target(s) 12542e2caf59SThomas Veerman * to create. 12552e2caf59SThomas Veerman */ 12562e2caf59SThomas Veerman if (Lst_IsEmpty(create)) 12572e2caf59SThomas Veerman targs = Parse_MainName(); 12582e2caf59SThomas Veerman else 12592e2caf59SThomas Veerman targs = Targ_FindList(create, TARG_CREATE); 12602e2caf59SThomas Veerman 12612e2caf59SThomas Veerman if (!compatMake) { 12622e2caf59SThomas Veerman /* 12632e2caf59SThomas Veerman * Initialize job module before traversing the graph 12642e2caf59SThomas Veerman * now that any .BEGIN and .END targets have been read. 12652e2caf59SThomas Veerman * This is done only if the -q flag wasn't given 12662e2caf59SThomas Veerman * (to prevent the .BEGIN from being executed should 12672e2caf59SThomas Veerman * it exist). 12682e2caf59SThomas Veerman */ 12692e2caf59SThomas Veerman if (!queryFlag) { 12702e2caf59SThomas Veerman Job_Init(); 12712e2caf59SThomas Veerman jobsRunning = TRUE; 12722e2caf59SThomas Veerman } 12732e2caf59SThomas Veerman 12742e2caf59SThomas Veerman /* Traverse the graph, checking on all the targets */ 12752e2caf59SThomas Veerman outOfDate = Make_Run(targs); 12762e2caf59SThomas Veerman } else { 12772e2caf59SThomas Veerman /* 12782e2caf59SThomas Veerman * Compat_Init will take care of creating all the 12792e2caf59SThomas Veerman * targets as well as initializing the module. 12802e2caf59SThomas Veerman */ 12812e2caf59SThomas Veerman Compat_Run(targs); 12822e2caf59SThomas Veerman } 12832e2caf59SThomas Veerman } 12842e2caf59SThomas Veerman 12852e2caf59SThomas Veerman #ifdef CLEANUP 12862e2caf59SThomas Veerman Lst_Destroy(targs, NULL); 12872e2caf59SThomas Veerman Lst_Destroy(variables, NULL); 12882e2caf59SThomas Veerman Lst_Destroy(makefiles, NULL); 12892e2caf59SThomas Veerman Lst_Destroy(create, (FreeProc *)free); 12902e2caf59SThomas Veerman #endif 12912e2caf59SThomas Veerman 12922e2caf59SThomas Veerman /* print the graph now it's been processed if the user requested it */ 12932e2caf59SThomas Veerman if (DEBUG(GRAPH2)) 12942e2caf59SThomas Veerman Targ_PrintGraph(2); 12952e2caf59SThomas Veerman 12962e2caf59SThomas Veerman Trace_Log(MAKEEND, 0); 12972e2caf59SThomas Veerman 12982e2caf59SThomas Veerman Suff_End(); 12992e2caf59SThomas Veerman Targ_End(); 13002e2caf59SThomas Veerman Arch_End(); 13012e2caf59SThomas Veerman Var_End(); 13022e2caf59SThomas Veerman Parse_End(); 13032e2caf59SThomas Veerman Dir_End(); 13042e2caf59SThomas Veerman Job_End(); 13052e2caf59SThomas Veerman Trace_End(); 13062e2caf59SThomas Veerman 13072e2caf59SThomas Veerman return outOfDate ? 1 : 0; 13082e2caf59SThomas Veerman } 13092e2caf59SThomas Veerman 13102e2caf59SThomas Veerman /*- 13112e2caf59SThomas Veerman * ReadMakefile -- 13122e2caf59SThomas Veerman * Open and parse the given makefile. 13132e2caf59SThomas Veerman * 13142e2caf59SThomas Veerman * Results: 13152e2caf59SThomas Veerman * 0 if ok. -1 if couldn't open file. 13162e2caf59SThomas Veerman * 13172e2caf59SThomas Veerman * Side Effects: 13182e2caf59SThomas Veerman * lots 13192e2caf59SThomas Veerman */ 13202e2caf59SThomas Veerman static int 1321*2bc7c627SLionel Sambuc ReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 13222e2caf59SThomas Veerman { 13232e2caf59SThomas Veerman const char *fname = p; /* makefile to read */ 13242e2caf59SThomas Veerman int fd; 13252e2caf59SThomas Veerman size_t len = MAXPATHLEN; 13262e2caf59SThomas Veerman char *name, *path = bmake_malloc(len); 13272e2caf59SThomas Veerman 13282e2caf59SThomas Veerman if (!strcmp(fname, "-")) { 13292e2caf59SThomas Veerman Parse_File(NULL /*stdin*/, -1); 13302e2caf59SThomas Veerman Var_Set("MAKEFILE", "", VAR_GLOBAL, 0); 13312e2caf59SThomas Veerman } else { 13322e2caf59SThomas Veerman /* if we've chdir'd, rebuild the path name */ 13332e2caf59SThomas Veerman if (strcmp(curdir, objdir) && *fname != '/') { 13342e2caf59SThomas Veerman size_t plen = strlen(curdir) + strlen(fname) + 2; 13352e2caf59SThomas Veerman if (len < plen) 13362e2caf59SThomas Veerman path = bmake_realloc(path, len = 2 * plen); 13372e2caf59SThomas Veerman 13382e2caf59SThomas Veerman (void)snprintf(path, len, "%s/%s", curdir, fname); 13392e2caf59SThomas Veerman fd = open(path, O_RDONLY); 13402e2caf59SThomas Veerman if (fd != -1) { 13412e2caf59SThomas Veerman fname = path; 13422e2caf59SThomas Veerman goto found; 13432e2caf59SThomas Veerman } 13442e2caf59SThomas Veerman 13452e2caf59SThomas Veerman /* If curdir failed, try objdir (ala .depend) */ 13462e2caf59SThomas Veerman plen = strlen(objdir) + strlen(fname) + 2; 13472e2caf59SThomas Veerman if (len < plen) 13482e2caf59SThomas Veerman path = bmake_realloc(path, len = 2 * plen); 13492e2caf59SThomas Veerman (void)snprintf(path, len, "%s/%s", objdir, fname); 13502e2caf59SThomas Veerman fd = open(path, O_RDONLY); 13512e2caf59SThomas Veerman if (fd != -1) { 13522e2caf59SThomas Veerman fname = path; 13532e2caf59SThomas Veerman goto found; 13542e2caf59SThomas Veerman } 13552e2caf59SThomas Veerman } else { 13562e2caf59SThomas Veerman fd = open(fname, O_RDONLY); 13572e2caf59SThomas Veerman if (fd != -1) 13582e2caf59SThomas Veerman goto found; 13592e2caf59SThomas Veerman } 13602e2caf59SThomas Veerman /* look in -I and system include directories. */ 13612e2caf59SThomas Veerman name = Dir_FindFile(fname, parseIncPath); 13622e2caf59SThomas Veerman if (!name) 13632e2caf59SThomas Veerman name = Dir_FindFile(fname, 13642e2caf59SThomas Veerman Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 13652e2caf59SThomas Veerman if (!name || (fd = open(name, O_RDONLY)) == -1) { 13662e2caf59SThomas Veerman if (name) 13672e2caf59SThomas Veerman free(name); 13682e2caf59SThomas Veerman free(path); 13692e2caf59SThomas Veerman return(-1); 13702e2caf59SThomas Veerman } 13712e2caf59SThomas Veerman fname = name; 13722e2caf59SThomas Veerman /* 13732e2caf59SThomas Veerman * set the MAKEFILE variable desired by System V fans -- the 13742e2caf59SThomas Veerman * placement of the setting here means it gets set to the last 13752e2caf59SThomas Veerman * makefile specified, as it is set by SysV make. 13762e2caf59SThomas Veerman */ 13772e2caf59SThomas Veerman found: 13782e2caf59SThomas Veerman if (!doing_depend) 13792e2caf59SThomas Veerman Var_Set("MAKEFILE", fname, VAR_GLOBAL, 0); 13802e2caf59SThomas Veerman Parse_File(fname, fd); 13812e2caf59SThomas Veerman } 13822e2caf59SThomas Veerman free(path); 13832e2caf59SThomas Veerman return(0); 13842e2caf59SThomas Veerman } 13852e2caf59SThomas Veerman 13862e2caf59SThomas Veerman 13872e2caf59SThomas Veerman /* 13882e2caf59SThomas Veerman * If MAKEOBJDIRPREFIX is in use, make ends up not in .CURDIR 13892e2caf59SThomas Veerman * in situations that would not arrise with ./obj (links or not). 13902e2caf59SThomas Veerman * This tends to break things like: 13912e2caf59SThomas Veerman * 13922e2caf59SThomas Veerman * build: 13932e2caf59SThomas Veerman * ${MAKE} includes 13942e2caf59SThomas Veerman * 13952e2caf59SThomas Veerman * This function spots when ${.MAKE:T} or ${.MAKE} is a command (as 13962e2caf59SThomas Veerman * opposed to an argument) in a command line and if so returns 13972e2caf59SThomas Veerman * ${.CURDIR} so caller can chdir() so that the assumptions made by 13982e2caf59SThomas Veerman * the Makefile hold true. 13992e2caf59SThomas Veerman * 14002e2caf59SThomas Veerman * If ${.MAKE} does not contain any '/', then ${.MAKE:T} is skipped. 14012e2caf59SThomas Veerman * 14022e2caf59SThomas Veerman * The chdir() only happens in the child process, and does nothing if 14032e2caf59SThomas Veerman * MAKEOBJDIRPREFIX and MAKEOBJDIR are not in the environment so it 14042e2caf59SThomas Veerman * should not break anything. Also if NOCHECKMAKECHDIR is set we 14052e2caf59SThomas Veerman * do nothing - to ensure historic semantics can be retained. 14062e2caf59SThomas Veerman */ 14072e2caf59SThomas Veerman static int Check_Cwd_Off = 0; 14082e2caf59SThomas Veerman 14092e2caf59SThomas Veerman static char * 14102e2caf59SThomas Veerman Check_Cwd_av(int ac, char **av, int copy) 14112e2caf59SThomas Veerman { 14122e2caf59SThomas Veerman static char *make[4]; 14132e2caf59SThomas Veerman static char *cur_dir = NULL; 14142e2caf59SThomas Veerman char **mp; 14152e2caf59SThomas Veerman char *cp; 14162e2caf59SThomas Veerman int is_cmd, next_cmd; 14172e2caf59SThomas Veerman int i; 14182e2caf59SThomas Veerman int n; 14192e2caf59SThomas Veerman 14202e2caf59SThomas Veerman if (Check_Cwd_Off) { 14212e2caf59SThomas Veerman if (DEBUG(CWD)) 14222e2caf59SThomas Veerman fprintf(debug_file, "check_cwd: check is off.\n"); 14232e2caf59SThomas Veerman return NULL; 14242e2caf59SThomas Veerman } 14252e2caf59SThomas Veerman 14262e2caf59SThomas Veerman if (make[0] == NULL) { 14272e2caf59SThomas Veerman if (Var_Exists("NOCHECKMAKECHDIR", VAR_GLOBAL)) { 14282e2caf59SThomas Veerman Check_Cwd_Off = 1; 14292e2caf59SThomas Veerman if (DEBUG(CWD)) 14302e2caf59SThomas Veerman fprintf(debug_file, "check_cwd: turning check off.\n"); 14312e2caf59SThomas Veerman return NULL; 14322e2caf59SThomas Veerman } 14332e2caf59SThomas Veerman 14342e2caf59SThomas Veerman make[1] = Var_Value(".MAKE", VAR_GLOBAL, &cp); 14352e2caf59SThomas Veerman if ((make[0] = strrchr(make[1], '/')) == NULL) { 14362e2caf59SThomas Veerman make[0] = make[1]; 14372e2caf59SThomas Veerman make[1] = NULL; 14382e2caf59SThomas Veerman } else 14392e2caf59SThomas Veerman ++make[0]; 14402e2caf59SThomas Veerman make[2] = NULL; 14412e2caf59SThomas Veerman cur_dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp); 14422e2caf59SThomas Veerman } 14432e2caf59SThomas Veerman if (ac == 0 || av == NULL) { 14442e2caf59SThomas Veerman if (DEBUG(CWD)) 14452e2caf59SThomas Veerman fprintf(debug_file, "check_cwd: empty command.\n"); 14462e2caf59SThomas Veerman return NULL; /* initialization only */ 14472e2caf59SThomas Veerman } 14482e2caf59SThomas Veerman 14492e2caf59SThomas Veerman if (getenv("MAKEOBJDIR") == NULL && 14502e2caf59SThomas Veerman getenv("MAKEOBJDIRPREFIX") == NULL) { 14512e2caf59SThomas Veerman if (DEBUG(CWD)) 14522e2caf59SThomas Veerman fprintf(debug_file, "check_cwd: no obj dirs.\n"); 14532e2caf59SThomas Veerman return NULL; 14542e2caf59SThomas Veerman } 14552e2caf59SThomas Veerman 14562e2caf59SThomas Veerman 14572e2caf59SThomas Veerman next_cmd = 1; 14582e2caf59SThomas Veerman for (i = 0; i < ac; ++i) { 14592e2caf59SThomas Veerman is_cmd = next_cmd; 14602e2caf59SThomas Veerman 14612e2caf59SThomas Veerman n = strlen(av[i]); 14622e2caf59SThomas Veerman cp = &(av[i])[n - 1]; 14632e2caf59SThomas Veerman if (strspn(av[i], "|&;") == (size_t)n) { 14642e2caf59SThomas Veerman next_cmd = 1; 14652e2caf59SThomas Veerman continue; 14662e2caf59SThomas Veerman } else if (*cp == ';' || *cp == '&' || *cp == '|' || *cp == ')') { 14672e2caf59SThomas Veerman next_cmd = 1; 14682e2caf59SThomas Veerman if (copy) { 14692e2caf59SThomas Veerman do { 14702e2caf59SThomas Veerman *cp-- = '\0'; 14712e2caf59SThomas Veerman } while (*cp == ';' || *cp == '&' || *cp == '|' || 14722e2caf59SThomas Veerman *cp == ')' || *cp == '}') ; 14732e2caf59SThomas Veerman } else { 14742e2caf59SThomas Veerman /* 14752e2caf59SThomas Veerman * XXX this should not happen. 14762e2caf59SThomas Veerman */ 14772e2caf59SThomas Veerman fprintf(stderr, "%s: WARNING: raw arg ends in shell meta '%s'\n", 14782e2caf59SThomas Veerman progname, av[i]); 14792e2caf59SThomas Veerman } 14802e2caf59SThomas Veerman } else 14812e2caf59SThomas Veerman next_cmd = 0; 14822e2caf59SThomas Veerman 14832e2caf59SThomas Veerman cp = av[i]; 14842e2caf59SThomas Veerman if (*cp == ';' || *cp == '&' || *cp == '|') 14852e2caf59SThomas Veerman is_cmd = 1; 14862e2caf59SThomas Veerman 14872e2caf59SThomas Veerman if (DEBUG(CWD)) 14882e2caf59SThomas Veerman fprintf(debug_file, "av[%d] == %s '%s'", 14892e2caf59SThomas Veerman i, (is_cmd) ? "cmd" : "arg", av[i]); 14902e2caf59SThomas Veerman if (is_cmd != 0) { 14912e2caf59SThomas Veerman if (*cp == '(' || *cp == '{' || 14922e2caf59SThomas Veerman *cp == ';' || *cp == '&' || *cp == '|') { 14932e2caf59SThomas Veerman do { 14942e2caf59SThomas Veerman ++cp; 14952e2caf59SThomas Veerman } while (*cp == '(' || *cp == '{' || 14962e2caf59SThomas Veerman *cp == ';' || *cp == '&' || *cp == '|'); 14972e2caf59SThomas Veerman if (*cp == '\0') { 14982e2caf59SThomas Veerman next_cmd = 1; 14992e2caf59SThomas Veerman continue; 15002e2caf59SThomas Veerman } 15012e2caf59SThomas Veerman } 15022e2caf59SThomas Veerman if (strcmp(cp, "cd") == 0 || strcmp(cp, "chdir") == 0) { 15032e2caf59SThomas Veerman if (DEBUG(CWD)) 15042e2caf59SThomas Veerman fprintf(debug_file, " == cd, done.\n"); 15052e2caf59SThomas Veerman return NULL; 15062e2caf59SThomas Veerman } 15072e2caf59SThomas Veerman for (mp = make; *mp != NULL; ++mp) { 15082e2caf59SThomas Veerman n = strlen(*mp); 15092e2caf59SThomas Veerman if (strcmp(cp, *mp) == 0) { 15102e2caf59SThomas Veerman if (DEBUG(CWD)) 15112e2caf59SThomas Veerman fprintf(debug_file, " %s == '%s', chdir(%s)\n", 15122e2caf59SThomas Veerman cp, *mp, cur_dir); 15132e2caf59SThomas Veerman return cur_dir; 15142e2caf59SThomas Veerman } 15152e2caf59SThomas Veerman } 15162e2caf59SThomas Veerman } 15172e2caf59SThomas Veerman if (DEBUG(CWD)) 15182e2caf59SThomas Veerman fprintf(debug_file, "\n"); 15192e2caf59SThomas Veerman } 15202e2caf59SThomas Veerman return NULL; 15212e2caf59SThomas Veerman } 15222e2caf59SThomas Veerman 15232e2caf59SThomas Veerman char * 15242e2caf59SThomas Veerman Check_Cwd_Cmd(const char *cmd) 15252e2caf59SThomas Veerman { 15262e2caf59SThomas Veerman char *cp, *bp; 15272e2caf59SThomas Veerman char **av; 15282e2caf59SThomas Veerman int ac; 15292e2caf59SThomas Veerman 15302e2caf59SThomas Veerman if (Check_Cwd_Off) 15312e2caf59SThomas Veerman return NULL; 15322e2caf59SThomas Veerman 15332e2caf59SThomas Veerman if (cmd) { 15342e2caf59SThomas Veerman av = brk_string(cmd, &ac, TRUE, &bp); 15352e2caf59SThomas Veerman if (DEBUG(CWD)) 15362e2caf59SThomas Veerman fprintf(debug_file, "splitting: '%s' -> %d words\n", 15372e2caf59SThomas Veerman cmd, ac); 15382e2caf59SThomas Veerman } else { 15392e2caf59SThomas Veerman ac = 0; 15402e2caf59SThomas Veerman av = NULL; 15412e2caf59SThomas Veerman bp = NULL; 15422e2caf59SThomas Veerman } 15432e2caf59SThomas Veerman cp = Check_Cwd_av(ac, av, 1); 15442e2caf59SThomas Veerman if (bp) 15452e2caf59SThomas Veerman free(bp); 15462e2caf59SThomas Veerman if (av) 15472e2caf59SThomas Veerman free(av); 15482e2caf59SThomas Veerman return cp; 15492e2caf59SThomas Veerman } 15502e2caf59SThomas Veerman 15512e2caf59SThomas Veerman void 15522e2caf59SThomas Veerman Check_Cwd(const char **argv) 15532e2caf59SThomas Veerman { 15542e2caf59SThomas Veerman char *cp; 15552e2caf59SThomas Veerman int ac; 15562e2caf59SThomas Veerman 15572e2caf59SThomas Veerman if (Check_Cwd_Off) 15582e2caf59SThomas Veerman return; 15592e2caf59SThomas Veerman 15602e2caf59SThomas Veerman for (ac = 0; argv[ac] != NULL; ++ac) 15612e2caf59SThomas Veerman /* NOTHING */; 15622e2caf59SThomas Veerman if (ac == 3 && *argv[1] == '-') { 15632e2caf59SThomas Veerman cp = Check_Cwd_Cmd(argv[2]); 15642e2caf59SThomas Veerman } else { 15652e2caf59SThomas Veerman cp = Check_Cwd_av(ac, UNCONST(argv), 0); 15662e2caf59SThomas Veerman } 15672e2caf59SThomas Veerman if (cp) { 15682e2caf59SThomas Veerman chdir(cp); 15692e2caf59SThomas Veerman } 15702e2caf59SThomas Veerman } 15712e2caf59SThomas Veerman 15722e2caf59SThomas Veerman /*- 15732e2caf59SThomas Veerman * Cmd_Exec -- 15742e2caf59SThomas Veerman * Execute the command in cmd, and return the output of that command 15752e2caf59SThomas Veerman * in a string. 15762e2caf59SThomas Veerman * 15772e2caf59SThomas Veerman * Results: 15782e2caf59SThomas Veerman * A string containing the output of the command, or the empty string 15792e2caf59SThomas Veerman * If errnum is not NULL, it contains the reason for the command failure 15802e2caf59SThomas Veerman * 15812e2caf59SThomas Veerman * Side Effects: 15822e2caf59SThomas Veerman * The string must be freed by the caller. 15832e2caf59SThomas Veerman */ 15842e2caf59SThomas Veerman char * 15852e2caf59SThomas Veerman Cmd_Exec(const char *cmd, const char **errnum) 15862e2caf59SThomas Veerman { 15872e2caf59SThomas Veerman const char *args[4]; /* Args for invoking the shell */ 15882e2caf59SThomas Veerman int fds[2]; /* Pipe streams */ 15892e2caf59SThomas Veerman int cpid; /* Child PID */ 15902e2caf59SThomas Veerman int pid; /* PID from wait() */ 15912e2caf59SThomas Veerman char *res; /* result */ 15922e2caf59SThomas Veerman int status; /* command exit status */ 15932e2caf59SThomas Veerman Buffer buf; /* buffer to store the result */ 15942e2caf59SThomas Veerman char *cp; 15952e2caf59SThomas Veerman int cc; 15962e2caf59SThomas Veerman 15972e2caf59SThomas Veerman 15982e2caf59SThomas Veerman *errnum = NULL; 15992e2caf59SThomas Veerman 16002e2caf59SThomas Veerman if (!shellName) 16012e2caf59SThomas Veerman Shell_Init(); 16022e2caf59SThomas Veerman /* 16032e2caf59SThomas Veerman * Set up arguments for shell 16042e2caf59SThomas Veerman */ 16052e2caf59SThomas Veerman args[0] = shellName; 16062e2caf59SThomas Veerman args[1] = "-c"; 16072e2caf59SThomas Veerman args[2] = cmd; 16082e2caf59SThomas Veerman args[3] = NULL; 16092e2caf59SThomas Veerman 16102e2caf59SThomas Veerman /* 16112e2caf59SThomas Veerman * Open a pipe for fetching its output 16122e2caf59SThomas Veerman */ 16132e2caf59SThomas Veerman if (pipe(fds) == -1) { 16142e2caf59SThomas Veerman *errnum = "Couldn't create pipe for \"%s\""; 16152e2caf59SThomas Veerman goto bad; 16162e2caf59SThomas Veerman } 16172e2caf59SThomas Veerman 16182e2caf59SThomas Veerman /* 16192e2caf59SThomas Veerman * Fork 16202e2caf59SThomas Veerman */ 16212e2caf59SThomas Veerman switch (cpid = vFork()) { 16222e2caf59SThomas Veerman case 0: 16232e2caf59SThomas Veerman /* 16242e2caf59SThomas Veerman * Close input side of pipe 16252e2caf59SThomas Veerman */ 16262e2caf59SThomas Veerman (void)close(fds[0]); 16272e2caf59SThomas Veerman 16282e2caf59SThomas Veerman /* 16292e2caf59SThomas Veerman * Duplicate the output stream to the shell's output, then 16302e2caf59SThomas Veerman * shut the extra thing down. Note we don't fetch the error 16312e2caf59SThomas Veerman * stream...why not? Why? 16322e2caf59SThomas Veerman */ 16332e2caf59SThomas Veerman (void)dup2(fds[1], 1); 16342e2caf59SThomas Veerman (void)close(fds[1]); 16352e2caf59SThomas Veerman 16362e2caf59SThomas Veerman Var_ExportVars(); 16372e2caf59SThomas Veerman 16382e2caf59SThomas Veerman (void)execv(shellPath, UNCONST(args)); 16392e2caf59SThomas Veerman _exit(1); 16402e2caf59SThomas Veerman /*NOTREACHED*/ 16412e2caf59SThomas Veerman 16422e2caf59SThomas Veerman case -1: 16432e2caf59SThomas Veerman *errnum = "Couldn't exec \"%s\""; 16442e2caf59SThomas Veerman goto bad; 16452e2caf59SThomas Veerman 16462e2caf59SThomas Veerman default: 16472e2caf59SThomas Veerman /* 16482e2caf59SThomas Veerman * No need for the writing half 16492e2caf59SThomas Veerman */ 16502e2caf59SThomas Veerman (void)close(fds[1]); 16512e2caf59SThomas Veerman 16522e2caf59SThomas Veerman Buf_Init(&buf, 0); 16532e2caf59SThomas Veerman 16542e2caf59SThomas Veerman do { 16552e2caf59SThomas Veerman char result[BUFSIZ]; 16562e2caf59SThomas Veerman cc = read(fds[0], result, sizeof(result)); 16572e2caf59SThomas Veerman if (cc > 0) 16582e2caf59SThomas Veerman Buf_AddBytes(&buf, cc, result); 16592e2caf59SThomas Veerman } 16602e2caf59SThomas Veerman while (cc > 0 || (cc == -1 && errno == EINTR)); 16612e2caf59SThomas Veerman 16622e2caf59SThomas Veerman /* 16632e2caf59SThomas Veerman * Close the input side of the pipe. 16642e2caf59SThomas Veerman */ 16652e2caf59SThomas Veerman (void)close(fds[0]); 16662e2caf59SThomas Veerman 16672e2caf59SThomas Veerman /* 16682e2caf59SThomas Veerman * Wait for the process to exit. 16692e2caf59SThomas Veerman */ 16702e2caf59SThomas Veerman while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 16712e2caf59SThomas Veerman JobReapChild(pid, status, FALSE); 16722e2caf59SThomas Veerman continue; 16732e2caf59SThomas Veerman } 16742e2caf59SThomas Veerman cc = Buf_Size(&buf); 16752e2caf59SThomas Veerman res = Buf_Destroy(&buf, FALSE); 16762e2caf59SThomas Veerman 16772e2caf59SThomas Veerman if (cc == 0) 16782e2caf59SThomas Veerman *errnum = "Couldn't read shell's output for \"%s\""; 16792e2caf59SThomas Veerman 16802e2caf59SThomas Veerman if (WIFSIGNALED(status)) 16812e2caf59SThomas Veerman *errnum = "\"%s\" exited on a signal"; 16822e2caf59SThomas Veerman else if (WEXITSTATUS(status) != 0) 16832e2caf59SThomas Veerman *errnum = "\"%s\" returned non-zero status"; 16842e2caf59SThomas Veerman 16852e2caf59SThomas Veerman /* 16862e2caf59SThomas Veerman * Null-terminate the result, convert newlines to spaces and 16872e2caf59SThomas Veerman * install it in the variable. 16882e2caf59SThomas Veerman */ 16892e2caf59SThomas Veerman res[cc] = '\0'; 16902e2caf59SThomas Veerman cp = &res[cc]; 16912e2caf59SThomas Veerman 16922e2caf59SThomas Veerman if (cc > 0 && *--cp == '\n') { 16932e2caf59SThomas Veerman /* 16942e2caf59SThomas Veerman * A final newline is just stripped 16952e2caf59SThomas Veerman */ 16962e2caf59SThomas Veerman *cp-- = '\0'; 16972e2caf59SThomas Veerman } 16982e2caf59SThomas Veerman while (cp >= res) { 16992e2caf59SThomas Veerman if (*cp == '\n') { 17002e2caf59SThomas Veerman *cp = ' '; 17012e2caf59SThomas Veerman } 17022e2caf59SThomas Veerman cp--; 17032e2caf59SThomas Veerman } 17042e2caf59SThomas Veerman break; 17052e2caf59SThomas Veerman } 17062e2caf59SThomas Veerman return res; 17072e2caf59SThomas Veerman bad: 17082e2caf59SThomas Veerman res = bmake_malloc(1); 17092e2caf59SThomas Veerman *res = '\0'; 17102e2caf59SThomas Veerman return res; 17112e2caf59SThomas Veerman } 17122e2caf59SThomas Veerman 17132e2caf59SThomas Veerman /*- 17142e2caf59SThomas Veerman * Error -- 17152e2caf59SThomas Veerman * Print an error message given its format. 17162e2caf59SThomas Veerman * 17172e2caf59SThomas Veerman * Results: 17182e2caf59SThomas Veerman * None. 17192e2caf59SThomas Veerman * 17202e2caf59SThomas Veerman * Side Effects: 17212e2caf59SThomas Veerman * The message is printed. 17222e2caf59SThomas Veerman */ 17232e2caf59SThomas Veerman /* VARARGS */ 17242e2caf59SThomas Veerman void 17252e2caf59SThomas Veerman Error(const char *fmt, ...) 17262e2caf59SThomas Veerman { 17272e2caf59SThomas Veerman va_list ap; 17282e2caf59SThomas Veerman FILE *err_file; 17292e2caf59SThomas Veerman 17302e2caf59SThomas Veerman err_file = debug_file; 17312e2caf59SThomas Veerman if (err_file == stdout) 17322e2caf59SThomas Veerman err_file = stderr; 17332e2caf59SThomas Veerman (void)fflush(stdout); 17342e2caf59SThomas Veerman for (;;) { 17352e2caf59SThomas Veerman va_start(ap, fmt); 17362e2caf59SThomas Veerman fprintf(err_file, "%s: ", progname); 17372e2caf59SThomas Veerman (void)vfprintf(err_file, fmt, ap); 17382e2caf59SThomas Veerman va_end(ap); 17392e2caf59SThomas Veerman (void)fprintf(err_file, "\n"); 17402e2caf59SThomas Veerman (void)fflush(err_file); 17412e2caf59SThomas Veerman if (err_file == stderr) 17422e2caf59SThomas Veerman break; 17432e2caf59SThomas Veerman err_file = stderr; 17442e2caf59SThomas Veerman } 17452e2caf59SThomas Veerman } 17462e2caf59SThomas Veerman 17472e2caf59SThomas Veerman /*- 17482e2caf59SThomas Veerman * Fatal -- 17492e2caf59SThomas Veerman * Produce a Fatal error message. If jobs are running, waits for them 17502e2caf59SThomas Veerman * to finish. 17512e2caf59SThomas Veerman * 17522e2caf59SThomas Veerman * Results: 17532e2caf59SThomas Veerman * None 17542e2caf59SThomas Veerman * 17552e2caf59SThomas Veerman * Side Effects: 17562e2caf59SThomas Veerman * The program exits 17572e2caf59SThomas Veerman */ 17582e2caf59SThomas Veerman /* VARARGS */ 17592e2caf59SThomas Veerman void 17602e2caf59SThomas Veerman Fatal(const char *fmt, ...) 17612e2caf59SThomas Veerman { 17622e2caf59SThomas Veerman va_list ap; 17632e2caf59SThomas Veerman 17642e2caf59SThomas Veerman va_start(ap, fmt); 17652e2caf59SThomas Veerman if (jobsRunning) 17662e2caf59SThomas Veerman Job_Wait(); 17672e2caf59SThomas Veerman 17682e2caf59SThomas Veerman (void)fflush(stdout); 17692e2caf59SThomas Veerman (void)vfprintf(stderr, fmt, ap); 17702e2caf59SThomas Veerman va_end(ap); 17712e2caf59SThomas Veerman (void)fprintf(stderr, "\n"); 17722e2caf59SThomas Veerman (void)fflush(stderr); 17732e2caf59SThomas Veerman 17742e2caf59SThomas Veerman PrintOnError(NULL, NULL); 17752e2caf59SThomas Veerman 17762e2caf59SThomas Veerman if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 17772e2caf59SThomas Veerman Targ_PrintGraph(2); 17782e2caf59SThomas Veerman Trace_Log(MAKEERROR, 0); 17792e2caf59SThomas Veerman exit(2); /* Not 1 so -q can distinguish error */ 17802e2caf59SThomas Veerman } 17812e2caf59SThomas Veerman 17822e2caf59SThomas Veerman /* 17832e2caf59SThomas Veerman * Punt -- 17842e2caf59SThomas Veerman * Major exception once jobs are being created. Kills all jobs, prints 17852e2caf59SThomas Veerman * a message and exits. 17862e2caf59SThomas Veerman * 17872e2caf59SThomas Veerman * Results: 17882e2caf59SThomas Veerman * None 17892e2caf59SThomas Veerman * 17902e2caf59SThomas Veerman * Side Effects: 17912e2caf59SThomas Veerman * All children are killed indiscriminately and the program Lib_Exits 17922e2caf59SThomas Veerman */ 17932e2caf59SThomas Veerman /* VARARGS */ 17942e2caf59SThomas Veerman void 17952e2caf59SThomas Veerman Punt(const char *fmt, ...) 17962e2caf59SThomas Veerman { 17972e2caf59SThomas Veerman va_list ap; 17982e2caf59SThomas Veerman 17992e2caf59SThomas Veerman va_start(ap, fmt); 18002e2caf59SThomas Veerman (void)fflush(stdout); 18012e2caf59SThomas Veerman (void)fprintf(stderr, "%s: ", progname); 18022e2caf59SThomas Veerman (void)vfprintf(stderr, fmt, ap); 18032e2caf59SThomas Veerman va_end(ap); 18042e2caf59SThomas Veerman (void)fprintf(stderr, "\n"); 18052e2caf59SThomas Veerman (void)fflush(stderr); 18062e2caf59SThomas Veerman 18072e2caf59SThomas Veerman PrintOnError(NULL, NULL); 18082e2caf59SThomas Veerman 18092e2caf59SThomas Veerman DieHorribly(); 18102e2caf59SThomas Veerman } 18112e2caf59SThomas Veerman 18122e2caf59SThomas Veerman /*- 18132e2caf59SThomas Veerman * DieHorribly -- 18142e2caf59SThomas Veerman * Exit without giving a message. 18152e2caf59SThomas Veerman * 18162e2caf59SThomas Veerman * Results: 18172e2caf59SThomas Veerman * None 18182e2caf59SThomas Veerman * 18192e2caf59SThomas Veerman * Side Effects: 18202e2caf59SThomas Veerman * A big one... 18212e2caf59SThomas Veerman */ 18222e2caf59SThomas Veerman void 18232e2caf59SThomas Veerman DieHorribly(void) 18242e2caf59SThomas Veerman { 18252e2caf59SThomas Veerman if (jobsRunning) 18262e2caf59SThomas Veerman Job_AbortAll(); 18272e2caf59SThomas Veerman if (DEBUG(GRAPH2)) 18282e2caf59SThomas Veerman Targ_PrintGraph(2); 18292e2caf59SThomas Veerman Trace_Log(MAKEERROR, 0); 18302e2caf59SThomas Veerman exit(2); /* Not 1, so -q can distinguish error */ 18312e2caf59SThomas Veerman } 18322e2caf59SThomas Veerman 18332e2caf59SThomas Veerman /* 18342e2caf59SThomas Veerman * Finish -- 18352e2caf59SThomas Veerman * Called when aborting due to errors in child shell to signal 18362e2caf59SThomas Veerman * abnormal exit. 18372e2caf59SThomas Veerman * 18382e2caf59SThomas Veerman * Results: 18392e2caf59SThomas Veerman * None 18402e2caf59SThomas Veerman * 18412e2caf59SThomas Veerman * Side Effects: 18422e2caf59SThomas Veerman * The program exits 18432e2caf59SThomas Veerman */ 18442e2caf59SThomas Veerman void 18452e2caf59SThomas Veerman Finish(int errors) 18462e2caf59SThomas Veerman /* number of errors encountered in Make_Make */ 18472e2caf59SThomas Veerman { 18482e2caf59SThomas Veerman Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 18492e2caf59SThomas Veerman } 18502e2caf59SThomas Veerman 18512e2caf59SThomas Veerman /* 18522e2caf59SThomas Veerman * enunlink -- 18532e2caf59SThomas Veerman * Remove a file carefully, avoiding directories. 18542e2caf59SThomas Veerman */ 18552e2caf59SThomas Veerman int 18562e2caf59SThomas Veerman eunlink(const char *file) 18572e2caf59SThomas Veerman { 18582e2caf59SThomas Veerman struct stat st; 18592e2caf59SThomas Veerman 18602e2caf59SThomas Veerman if (lstat(file, &st) == -1) 18612e2caf59SThomas Veerman return -1; 18622e2caf59SThomas Veerman 18632e2caf59SThomas Veerman if (S_ISDIR(st.st_mode)) { 18642e2caf59SThomas Veerman errno = EISDIR; 18652e2caf59SThomas Veerman return -1; 18662e2caf59SThomas Veerman } 18672e2caf59SThomas Veerman return unlink(file); 18682e2caf59SThomas Veerman } 18692e2caf59SThomas Veerman 18702e2caf59SThomas Veerman /* 18712e2caf59SThomas Veerman * execError -- 18722e2caf59SThomas Veerman * Print why exec failed, avoiding stdio. 18732e2caf59SThomas Veerman */ 18742e2caf59SThomas Veerman void 18752e2caf59SThomas Veerman execError(const char *af, const char *av) 18762e2caf59SThomas Veerman { 18772e2caf59SThomas Veerman #ifdef USE_IOVEC 18782e2caf59SThomas Veerman int i = 0; 18792e2caf59SThomas Veerman struct iovec iov[8]; 18802e2caf59SThomas Veerman #define IOADD(s) \ 18812e2caf59SThomas Veerman (void)(iov[i].iov_base = UNCONST(s), \ 18822e2caf59SThomas Veerman iov[i].iov_len = strlen(iov[i].iov_base), \ 18832e2caf59SThomas Veerman i++) 18842e2caf59SThomas Veerman #else 18852e2caf59SThomas Veerman #define IOADD(void)write(2, s, strlen(s)) 18862e2caf59SThomas Veerman #endif 18872e2caf59SThomas Veerman 18882e2caf59SThomas Veerman IOADD(progname); 18892e2caf59SThomas Veerman IOADD(": "); 18902e2caf59SThomas Veerman IOADD(af); 18912e2caf59SThomas Veerman IOADD("("); 18922e2caf59SThomas Veerman IOADD(av); 18932e2caf59SThomas Veerman IOADD(") failed ("); 18942e2caf59SThomas Veerman IOADD(strerror(errno)); 18952e2caf59SThomas Veerman IOADD(")\n"); 18962e2caf59SThomas Veerman 18972e2caf59SThomas Veerman #ifdef USE_IOVEC 18982e2caf59SThomas Veerman (void)writev(2, iov, 8); 18992e2caf59SThomas Veerman #endif 19002e2caf59SThomas Veerman } 19012e2caf59SThomas Veerman 19022e2caf59SThomas Veerman /* 19032e2caf59SThomas Veerman * usage -- 19042e2caf59SThomas Veerman * exit with usage message 19052e2caf59SThomas Veerman */ 19062e2caf59SThomas Veerman static void 19072e2caf59SThomas Veerman usage(void) 19082e2caf59SThomas Veerman { 19092e2caf59SThomas Veerman (void)fprintf(stderr, 19102e2caf59SThomas Veerman "usage: %s [-BeikNnqrstWX] \n\ 19112e2caf59SThomas Veerman [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 19122e2caf59SThomas Veerman [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 19132e2caf59SThomas Veerman [-V variable] [variable=value] [target ...]\n", progname); 19142e2caf59SThomas Veerman exit(2); 19152e2caf59SThomas Veerman } 19162e2caf59SThomas Veerman 19172e2caf59SThomas Veerman 19182e2caf59SThomas Veerman int 19192e2caf59SThomas Veerman PrintAddr(void *a, void *b) 19202e2caf59SThomas Veerman { 19212e2caf59SThomas Veerman printf("%lx ", (unsigned long) a); 19222e2caf59SThomas Veerman return b ? 0 : 0; 19232e2caf59SThomas Veerman } 19242e2caf59SThomas Veerman 19252e2caf59SThomas Veerman 19262e2caf59SThomas Veerman 19272e2caf59SThomas Veerman void 19282e2caf59SThomas Veerman PrintOnError(GNode *gn, const char *s) 19292e2caf59SThomas Veerman { 19302e2caf59SThomas Veerman static GNode *en = NULL; 19312e2caf59SThomas Veerman char tmp[64]; 19322e2caf59SThomas Veerman char *cp; 19332e2caf59SThomas Veerman 19342e2caf59SThomas Veerman if (s) 19352e2caf59SThomas Veerman printf("%s", s); 19362e2caf59SThomas Veerman 19372e2caf59SThomas Veerman printf("\n%s: stopped in %s\n", progname, curdir); 19382e2caf59SThomas Veerman 19392e2caf59SThomas Veerman if (en) 19402e2caf59SThomas Veerman return; /* we've been here! */ 19412e2caf59SThomas Veerman if (gn) { 19422e2caf59SThomas Veerman /* 19432e2caf59SThomas Veerman * We can print this even if there is no .ERROR target. 19442e2caf59SThomas Veerman */ 19452e2caf59SThomas Veerman Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 19462e2caf59SThomas Veerman } 19472e2caf59SThomas Veerman strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 19482e2caf59SThomas Veerman sizeof(tmp) - 1); 19492e2caf59SThomas Veerman cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 19502e2caf59SThomas Veerman if (cp) { 19512e2caf59SThomas Veerman if (*cp) 19522e2caf59SThomas Veerman printf("%s", cp); 19532e2caf59SThomas Veerman free(cp); 19542e2caf59SThomas Veerman } 19552e2caf59SThomas Veerman /* 19562e2caf59SThomas Veerman * Finally, see if there is a .ERROR target, and run it if so. 19572e2caf59SThomas Veerman */ 19582e2caf59SThomas Veerman en = Targ_FindNode(".ERROR", TARG_NOCREATE); 19592e2caf59SThomas Veerman if (en) { 19602e2caf59SThomas Veerman en->type |= OP_SPECIAL; 19612e2caf59SThomas Veerman Compat_Make(en, en); 19622e2caf59SThomas Veerman } 19632e2caf59SThomas Veerman } 19642e2caf59SThomas Veerman 19652e2caf59SThomas Veerman void 19662e2caf59SThomas Veerman Main_ExportMAKEFLAGS(Boolean first) 19672e2caf59SThomas Veerman { 19682e2caf59SThomas Veerman static int once = 1; 19692e2caf59SThomas Veerman char tmp[64]; 19702e2caf59SThomas Veerman char *s; 19712e2caf59SThomas Veerman 19722e2caf59SThomas Veerman if (once != first) 19732e2caf59SThomas Veerman return; 19742e2caf59SThomas Veerman once = 0; 19752e2caf59SThomas Veerman 19762e2caf59SThomas Veerman strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 19772e2caf59SThomas Veerman sizeof(tmp)); 19782e2caf59SThomas Veerman s = Var_Subst(NULL, tmp, VAR_CMD, 0); 19792e2caf59SThomas Veerman if (s && *s) { 19802e2caf59SThomas Veerman #ifdef POSIX 19812e2caf59SThomas Veerman setenv("MAKEFLAGS", s, 1); 19822e2caf59SThomas Veerman #else 19832e2caf59SThomas Veerman setenv("MAKE", s, 1); 19842e2caf59SThomas Veerman #endif 19852e2caf59SThomas Veerman } 19862e2caf59SThomas Veerman } 19872e2caf59SThomas Veerman 19882e2caf59SThomas Veerman char * 19892e2caf59SThomas Veerman getTmpdir(void) 19902e2caf59SThomas Veerman { 19912e2caf59SThomas Veerman static char *tmpdir = NULL; 19922e2caf59SThomas Veerman 19932e2caf59SThomas Veerman if (!tmpdir) { 19942e2caf59SThomas Veerman struct stat st; 19952e2caf59SThomas Veerman 19962e2caf59SThomas Veerman /* 19972e2caf59SThomas Veerman * Honor $TMPDIR but only if it is valid. 19982e2caf59SThomas Veerman * Ensure it ends with /. 19992e2caf59SThomas Veerman */ 20002e2caf59SThomas Veerman tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 0); 20012e2caf59SThomas Veerman if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 20022e2caf59SThomas Veerman free(tmpdir); 20032e2caf59SThomas Veerman tmpdir = bmake_strdup(_PATH_TMP); 20042e2caf59SThomas Veerman } 20052e2caf59SThomas Veerman } 20062e2caf59SThomas Veerman return tmpdir; 20072e2caf59SThomas Veerman } 20082e2caf59SThomas Veerman 20092e2caf59SThomas Veerman /* 20102e2caf59SThomas Veerman * Create and open a temp file using "pattern". 20112e2caf59SThomas Veerman * If "fnamep" is provided set it to a copy of the filename created. 20122e2caf59SThomas Veerman * Otherwise unlink the file once open. 20132e2caf59SThomas Veerman */ 20142e2caf59SThomas Veerman int 20152e2caf59SThomas Veerman mkTempFile(const char *pattern, char **fnamep) 20162e2caf59SThomas Veerman { 20172e2caf59SThomas Veerman static char *tmpdir = NULL; 20182e2caf59SThomas Veerman char tfile[MAXPATHLEN]; 20192e2caf59SThomas Veerman int fd; 20202e2caf59SThomas Veerman 20212e2caf59SThomas Veerman if (!pattern) 20222e2caf59SThomas Veerman pattern = TMPPAT; 20232e2caf59SThomas Veerman if (!tmpdir) 20242e2caf59SThomas Veerman tmpdir = getTmpdir(); 20252e2caf59SThomas Veerman if (pattern[0] == '/') { 20262e2caf59SThomas Veerman snprintf(tfile, sizeof(tfile), "%s", pattern); 20272e2caf59SThomas Veerman } else { 20282e2caf59SThomas Veerman snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 20292e2caf59SThomas Veerman } 20302e2caf59SThomas Veerman if ((fd = mkstemp(tfile)) < 0) 20312e2caf59SThomas Veerman Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 20322e2caf59SThomas Veerman if (fnamep) { 20332e2caf59SThomas Veerman *fnamep = bmake_strdup(tfile); 20342e2caf59SThomas Veerman } else { 20352e2caf59SThomas Veerman unlink(tfile); /* we just want the descriptor */ 20362e2caf59SThomas Veerman } 20372e2caf59SThomas Veerman return fd; 20382e2caf59SThomas Veerman } 2039*2bc7c627SLionel Sambuc 2040*2bc7c627SLionel Sambuc 2041*2bc7c627SLionel Sambuc /* 2042*2bc7c627SLionel Sambuc * Return a Boolean based on setting of a knob. 2043*2bc7c627SLionel Sambuc * 2044*2bc7c627SLionel Sambuc * If the knob is not set, the supplied default is the return value. 2045*2bc7c627SLionel Sambuc * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 2046*2bc7c627SLionel Sambuc * is FALSE, otherwise TRUE. 2047*2bc7c627SLionel Sambuc */ 2048*2bc7c627SLionel Sambuc Boolean 2049*2bc7c627SLionel Sambuc getBoolean(const char *name, Boolean bf) 2050*2bc7c627SLionel Sambuc { 2051*2bc7c627SLionel Sambuc char tmp[64]; 2052*2bc7c627SLionel Sambuc char *cp; 2053*2bc7c627SLionel Sambuc 2054*2bc7c627SLionel Sambuc if (snprintf(tmp, sizeof(tmp), "${%s:tl}", name) < (int)(sizeof(tmp))) { 2055*2bc7c627SLionel Sambuc cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 2056*2bc7c627SLionel Sambuc 2057*2bc7c627SLionel Sambuc if (cp) { 2058*2bc7c627SLionel Sambuc switch(*cp) { 2059*2bc7c627SLionel Sambuc case '\0': /* not set - the default wins */ 2060*2bc7c627SLionel Sambuc break; 2061*2bc7c627SLionel Sambuc case '0': 2062*2bc7c627SLionel Sambuc case 'f': 2063*2bc7c627SLionel Sambuc case 'n': 2064*2bc7c627SLionel Sambuc bf = FALSE; 2065*2bc7c627SLionel Sambuc break; 2066*2bc7c627SLionel Sambuc case 'o': 2067*2bc7c627SLionel Sambuc switch (cp[1]) { 2068*2bc7c627SLionel Sambuc case 'f': 2069*2bc7c627SLionel Sambuc bf = FALSE; 2070*2bc7c627SLionel Sambuc break; 2071*2bc7c627SLionel Sambuc default: 2072*2bc7c627SLionel Sambuc bf = TRUE; 2073*2bc7c627SLionel Sambuc break; 2074*2bc7c627SLionel Sambuc } 2075*2bc7c627SLionel Sambuc break; 2076*2bc7c627SLionel Sambuc default: 2077*2bc7c627SLionel Sambuc bf = TRUE; 2078*2bc7c627SLionel Sambuc break; 2079*2bc7c627SLionel Sambuc } 2080*2bc7c627SLionel Sambuc free(cp); 2081*2bc7c627SLionel Sambuc } 2082*2bc7c627SLionel Sambuc } 2083*2bc7c627SLionel Sambuc return (bf); 2084*2bc7c627SLionel Sambuc } 2085