main.c revision 237578
1237578Sobrien/* $NetBSD: main.c,v 1.200 2012/06/12 19:21:51 joerg Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/* 36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 37236769Sobrien * All rights reserved. 38236769Sobrien * 39236769Sobrien * This code is derived from software contributed to Berkeley by 40236769Sobrien * Adam de Boor. 41236769Sobrien * 42236769Sobrien * Redistribution and use in source and binary forms, with or without 43236769Sobrien * modification, are permitted provided that the following conditions 44236769Sobrien * are met: 45236769Sobrien * 1. Redistributions of source code must retain the above copyright 46236769Sobrien * notice, this list of conditions and the following disclaimer. 47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 48236769Sobrien * notice, this list of conditions and the following disclaimer in the 49236769Sobrien * documentation and/or other materials provided with the distribution. 50236769Sobrien * 3. All advertising materials mentioning features or use of this software 51236769Sobrien * must display the following acknowledgement: 52236769Sobrien * This product includes software developed by the University of 53236769Sobrien * California, Berkeley and its contributors. 54236769Sobrien * 4. Neither the name of the University nor the names of its contributors 55236769Sobrien * may be used to endorse or promote products derived from this software 56236769Sobrien * without specific prior written permission. 57236769Sobrien * 58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68236769Sobrien * SUCH DAMAGE. 69236769Sobrien */ 70236769Sobrien 71236769Sobrien#ifndef MAKE_NATIVE 72237578Sobrienstatic char rcsid[] = "$NetBSD: main.c,v 1.200 2012/06/12 19:21:51 joerg Exp $"; 73236769Sobrien#else 74236769Sobrien#include <sys/cdefs.h> 75236769Sobrien#ifndef lint 76236769Sobrien__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ 77236769Sobrien The Regents of the University of California. All rights reserved."); 78236769Sobrien#endif /* not lint */ 79236769Sobrien 80236769Sobrien#ifndef lint 81236769Sobrien#if 0 82236769Sobrienstatic char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 83236769Sobrien#else 84237578Sobrien__RCSID("$NetBSD: main.c,v 1.200 2012/06/12 19:21:51 joerg Exp $"); 85236769Sobrien#endif 86236769Sobrien#endif /* not lint */ 87236769Sobrien#endif 88236769Sobrien 89236769Sobrien/*- 90236769Sobrien * main.c -- 91236769Sobrien * The main file for this entire program. Exit routines etc 92236769Sobrien * reside here. 93236769Sobrien * 94236769Sobrien * Utility functions defined in this file: 95236769Sobrien * Main_ParseArgLine Takes a line of arguments, breaks them and 96236769Sobrien * treats them as if they were given when first 97236769Sobrien * invoked. Used by the parse module to implement 98236769Sobrien * the .MFLAGS target. 99236769Sobrien * 100236769Sobrien * Error Print a tagged error message. The global 101236769Sobrien * MAKE variable must have been defined. This 102236769Sobrien * takes a format string and two optional 103236769Sobrien * arguments for it. 104236769Sobrien * 105236769Sobrien * Fatal Print an error message and exit. Also takes 106236769Sobrien * a format string and two arguments. 107236769Sobrien * 108236769Sobrien * Punt Aborts all jobs and exits with a message. Also 109236769Sobrien * takes a format string and two arguments. 110236769Sobrien * 111236769Sobrien * Finish Finish things up by printing the number of 112236769Sobrien * errors which occurred, as passed to it, and 113236769Sobrien * exiting. 114236769Sobrien */ 115236769Sobrien 116236769Sobrien#include <sys/types.h> 117236769Sobrien#include <sys/time.h> 118236769Sobrien#include <sys/param.h> 119236769Sobrien#include <sys/resource.h> 120236769Sobrien#include <signal.h> 121236769Sobrien#include <sys/stat.h> 122236769Sobrien#ifdef MAKE_NATIVE 123236769Sobrien#include <sys/utsname.h> 124236769Sobrien#endif 125236769Sobrien#include "wait.h" 126236769Sobrien 127236769Sobrien#include <errno.h> 128236769Sobrien#include <fcntl.h> 129236769Sobrien#include <stdarg.h> 130236769Sobrien#include <stdio.h> 131236769Sobrien#include <stdlib.h> 132236769Sobrien#include <time.h> 133236769Sobrien 134236769Sobrien#include "make.h" 135236769Sobrien#include "hash.h" 136236769Sobrien#include "dir.h" 137236769Sobrien#include "job.h" 138236769Sobrien#include "pathnames.h" 139236769Sobrien#include "trace.h" 140236769Sobrien 141236769Sobrien#ifdef USE_IOVEC 142236769Sobrien#include <sys/uio.h> 143236769Sobrien#endif 144236769Sobrien 145236769Sobrien#ifndef DEFMAXLOCAL 146236769Sobrien#define DEFMAXLOCAL DEFMAXJOBS 147236769Sobrien#endif /* DEFMAXLOCAL */ 148236769Sobrien 149236769SobrienLst create; /* Targets to be made */ 150236769Sobrientime_t now; /* Time at start of make */ 151236769SobrienGNode *DEFAULT; /* .DEFAULT node */ 152236769SobrienBoolean allPrecious; /* .PRECIOUS given on line by itself */ 153236769Sobrien 154236769Sobrienstatic Boolean noBuiltins; /* -r flag */ 155236769Sobrienstatic Lst makefiles; /* ordered list of makefiles to read */ 156236769Sobrienstatic Boolean printVars; /* print value of one or more vars */ 157236769Sobrienstatic Lst variables; /* list of variables to print */ 158236769Sobrienint maxJobs; /* -j argument */ 159236769Sobrienstatic int maxJobTokens; /* -j argument */ 160236769SobrienBoolean compatMake; /* -B argument */ 161236769Sobrienint debug; /* -d argument */ 162236769SobrienBoolean noExecute; /* -n flag */ 163236769SobrienBoolean noRecursiveExecute; /* -N flag */ 164236769SobrienBoolean keepgoing; /* -k flag */ 165236769SobrienBoolean queryFlag; /* -q flag */ 166236769SobrienBoolean touchFlag; /* -t flag */ 167236769SobrienBoolean ignoreErrors; /* -i flag */ 168236769SobrienBoolean beSilent; /* -s flag */ 169236769SobrienBoolean oldVars; /* variable substitution style */ 170236769SobrienBoolean checkEnvFirst; /* -e flag */ 171236769SobrienBoolean parseWarnFatal; /* -W flag */ 172236769SobrienBoolean jobServer; /* -J flag */ 173236769Sobrienstatic int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 174236769SobrienBoolean varNoExportEnv; /* -X flag */ 175236769SobrienBoolean doing_depend; /* Set while reading .depend */ 176236769Sobrienstatic Boolean jobsRunning; /* TRUE if the jobs might be running */ 177236769Sobrienstatic const char * tracefile; 178236769Sobrien#ifndef NO_CHECK_MAKE_CHDIR 179236769Sobrienstatic char * Check_Cwd_av(int, char **, int); 180236769Sobrien#endif 181236769Sobrienstatic void MainParseArgs(int, char **); 182236769Sobrienstatic int ReadMakefile(const void *, const void *); 183237578Sobrienstatic void usage(void) MAKE_ATTR_DEAD; 184236769Sobrien 185236769Sobrienstatic Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 186236769Sobrienstatic char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 187236769Sobrienchar curdir[MAXPATHLEN + 1]; /* Startup directory */ 188236769Sobrienchar *progname; /* the program name */ 189236769Sobrienchar *makeDependfile; 190236769Sobrienpid_t myPid; 191236769Sobrien 192236769SobrienBoolean forceJobs = FALSE; 193236769Sobrien 194236769Sobrien/* 195236769Sobrien * On some systems MACHINE is defined as something other than 196236769Sobrien * what we want. 197236769Sobrien */ 198236769Sobrien#ifdef FORCE_MACHINE 199236769Sobrien# undef MACHINE 200236769Sobrien# define MACHINE FORCE_MACHINE 201236769Sobrien#endif 202236769Sobrien 203236769Sobrienextern Lst parseIncPath; 204236769Sobrien 205236769Sobrienstatic void 206236769Sobrienparse_debug_options(const char *argvalue) 207236769Sobrien{ 208236769Sobrien const char *modules; 209236769Sobrien const char *mode; 210236769Sobrien char *fname; 211236769Sobrien int len; 212236769Sobrien 213236769Sobrien for (modules = argvalue; *modules; ++modules) { 214236769Sobrien switch (*modules) { 215236769Sobrien case 'A': 216236769Sobrien debug = ~0; 217236769Sobrien break; 218236769Sobrien case 'a': 219236769Sobrien debug |= DEBUG_ARCH; 220236769Sobrien break; 221236769Sobrien case 'C': 222236769Sobrien debug |= DEBUG_CWD; 223236769Sobrien break; 224236769Sobrien case 'c': 225236769Sobrien debug |= DEBUG_COND; 226236769Sobrien break; 227236769Sobrien case 'd': 228236769Sobrien debug |= DEBUG_DIR; 229236769Sobrien break; 230236769Sobrien case 'e': 231236769Sobrien debug |= DEBUG_ERROR; 232236769Sobrien break; 233236769Sobrien case 'f': 234236769Sobrien debug |= DEBUG_FOR; 235236769Sobrien break; 236236769Sobrien case 'g': 237236769Sobrien if (modules[1] == '1') { 238236769Sobrien debug |= DEBUG_GRAPH1; 239236769Sobrien ++modules; 240236769Sobrien } 241236769Sobrien else if (modules[1] == '2') { 242236769Sobrien debug |= DEBUG_GRAPH2; 243236769Sobrien ++modules; 244236769Sobrien } 245236769Sobrien else if (modules[1] == '3') { 246236769Sobrien debug |= DEBUG_GRAPH3; 247236769Sobrien ++modules; 248236769Sobrien } 249236769Sobrien break; 250236769Sobrien case 'j': 251236769Sobrien debug |= DEBUG_JOB; 252236769Sobrien break; 253236769Sobrien case 'l': 254236769Sobrien debug |= DEBUG_LOUD; 255236769Sobrien break; 256236769Sobrien case 'M': 257236769Sobrien debug |= DEBUG_META; 258236769Sobrien break; 259236769Sobrien case 'm': 260236769Sobrien debug |= DEBUG_MAKE; 261236769Sobrien break; 262236769Sobrien case 'n': 263236769Sobrien debug |= DEBUG_SCRIPT; 264236769Sobrien break; 265236769Sobrien case 'p': 266236769Sobrien debug |= DEBUG_PARSE; 267236769Sobrien break; 268236769Sobrien case 's': 269236769Sobrien debug |= DEBUG_SUFF; 270236769Sobrien break; 271236769Sobrien case 't': 272236769Sobrien debug |= DEBUG_TARG; 273236769Sobrien break; 274236769Sobrien case 'v': 275236769Sobrien debug |= DEBUG_VAR; 276236769Sobrien break; 277236769Sobrien case 'x': 278236769Sobrien debug |= DEBUG_SHELL; 279236769Sobrien break; 280236769Sobrien case 'F': 281236769Sobrien if (debug_file != stdout && debug_file != stderr) 282236769Sobrien fclose(debug_file); 283236769Sobrien if (*++modules == '+') { 284236769Sobrien modules++; 285236769Sobrien mode = "a"; 286236769Sobrien } else 287236769Sobrien mode = "w"; 288236769Sobrien if (strcmp(modules, "stdout") == 0) { 289236769Sobrien debug_file = stdout; 290236769Sobrien goto debug_setbuf; 291236769Sobrien } 292236769Sobrien if (strcmp(modules, "stderr") == 0) { 293236769Sobrien debug_file = stderr; 294236769Sobrien goto debug_setbuf; 295236769Sobrien } 296236769Sobrien len = strlen(modules); 297236769Sobrien fname = malloc(len + 20); 298236769Sobrien memcpy(fname, modules, len + 1); 299236769Sobrien /* Let the filename be modified by the pid */ 300236769Sobrien if (strcmp(fname + len - 3, ".%d") == 0) 301236769Sobrien snprintf(fname + len - 2, 20, "%d", getpid()); 302236769Sobrien debug_file = fopen(fname, mode); 303236769Sobrien if (!debug_file) { 304236769Sobrien fprintf(stderr, "Cannot open debug file %s\n", 305236769Sobrien fname); 306236769Sobrien usage(); 307236769Sobrien } 308236769Sobrien free(fname); 309236769Sobrien goto debug_setbuf; 310236769Sobrien default: 311236769Sobrien (void)fprintf(stderr, 312236769Sobrien "%s: illegal argument to d option -- %c\n", 313236769Sobrien progname, *modules); 314236769Sobrien usage(); 315236769Sobrien } 316236769Sobrien } 317236769Sobriendebug_setbuf: 318236769Sobrien /* 319236769Sobrien * Make the debug_file unbuffered, and make 320236769Sobrien * stdout line buffered (unless debugfile == stdout). 321236769Sobrien */ 322236769Sobrien setvbuf(debug_file, NULL, _IONBF, 0); 323236769Sobrien if (debug_file != stdout) { 324236769Sobrien setvbuf(stdout, NULL, _IOLBF, 0); 325236769Sobrien } 326236769Sobrien} 327236769Sobrien 328236769Sobrien/*- 329236769Sobrien * MainParseArgs -- 330236769Sobrien * Parse a given argument vector. Called from main() and from 331236769Sobrien * Main_ParseArgLine() when the .MAKEFLAGS target is used. 332236769Sobrien * 333236769Sobrien * XXX: Deal with command line overriding .MAKEFLAGS in makefile 334236769Sobrien * 335236769Sobrien * Results: 336236769Sobrien * None 337236769Sobrien * 338236769Sobrien * Side Effects: 339236769Sobrien * Various global and local flags will be set depending on the flags 340236769Sobrien * given 341236769Sobrien */ 342236769Sobrienstatic void 343236769SobrienMainParseArgs(int argc, char **argv) 344236769Sobrien{ 345236769Sobrien char *p; 346236769Sobrien int c = '?'; 347236769Sobrien int arginc; 348236769Sobrien char *argvalue; 349236769Sobrien const char *getopt_def; 350236769Sobrien char *optscan; 351236769Sobrien Boolean inOption, dashDash = FALSE; 352236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 353236769Sobrien 354236769Sobrien#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrst" 355236769Sobrien/* Can't actually use getopt(3) because rescanning is not portable */ 356236769Sobrien 357236769Sobrien getopt_def = OPTFLAGS; 358236769Sobrienrearg: 359236769Sobrien inOption = FALSE; 360236769Sobrien optscan = NULL; 361236769Sobrien while(argc > 1) { 362236769Sobrien char *getopt_spec; 363236769Sobrien if(!inOption) 364236769Sobrien optscan = argv[1]; 365236769Sobrien c = *optscan++; 366236769Sobrien arginc = 0; 367236769Sobrien if(inOption) { 368236769Sobrien if(c == '\0') { 369236769Sobrien ++argv; 370236769Sobrien --argc; 371236769Sobrien inOption = FALSE; 372236769Sobrien continue; 373236769Sobrien } 374236769Sobrien } else { 375236769Sobrien if (c != '-' || dashDash) 376236769Sobrien break; 377236769Sobrien inOption = TRUE; 378236769Sobrien c = *optscan++; 379236769Sobrien } 380236769Sobrien /* '-' found at some earlier point */ 381236769Sobrien getopt_spec = strchr(getopt_def, c); 382236769Sobrien if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 383236769Sobrien /* -<something> found, and <something> should have an arg */ 384236769Sobrien inOption = FALSE; 385236769Sobrien arginc = 1; 386236769Sobrien argvalue = optscan; 387236769Sobrien if(*argvalue == '\0') { 388236769Sobrien if (argc < 3) 389236769Sobrien goto noarg; 390236769Sobrien argvalue = argv[2]; 391236769Sobrien arginc = 2; 392236769Sobrien } 393236769Sobrien } else { 394236769Sobrien argvalue = NULL; 395236769Sobrien } 396236769Sobrien switch(c) { 397236769Sobrien case '\0': 398236769Sobrien arginc = 1; 399236769Sobrien inOption = FALSE; 400236769Sobrien break; 401236769Sobrien case 'B': 402236769Sobrien compatMake = TRUE; 403236769Sobrien Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 404236769Sobrien Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 405236769Sobrien break; 406236769Sobrien case 'C': 407236769Sobrien if (chdir(argvalue) == -1) { 408236769Sobrien (void)fprintf(stderr, 409236769Sobrien "%s: chdir %s: %s\n", 410236769Sobrien progname, argvalue, 411236769Sobrien strerror(errno)); 412236769Sobrien exit(1); 413236769Sobrien } 414236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 415236769Sobrien (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 416236769Sobrien exit(2); 417236769Sobrien } 418236769Sobrien ignorePWD = TRUE; 419236769Sobrien break; 420236769Sobrien case 'D': 421236769Sobrien if (argvalue == NULL || argvalue[0] == 0) goto noarg; 422236769Sobrien Var_Set(argvalue, "1", VAR_GLOBAL, 0); 423236769Sobrien Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 424236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 425236769Sobrien break; 426236769Sobrien case 'I': 427236769Sobrien if (argvalue == NULL) goto noarg; 428236769Sobrien Parse_AddIncludeDir(argvalue); 429236769Sobrien Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 430236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 431236769Sobrien break; 432236769Sobrien case 'J': 433236769Sobrien if (argvalue == NULL) goto noarg; 434236769Sobrien if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 435236769Sobrien (void)fprintf(stderr, 436236769Sobrien "%s: internal error -- J option malformed (%s)\n", 437236769Sobrien progname, argvalue); 438236769Sobrien usage(); 439236769Sobrien } 440236769Sobrien if ((fcntl(jp_0, F_GETFD, 0) < 0) || 441236769Sobrien (fcntl(jp_1, F_GETFD, 0) < 0)) { 442236769Sobrien#if 0 443236769Sobrien (void)fprintf(stderr, 444236769Sobrien "%s: ###### warning -- J descriptors were closed!\n", 445236769Sobrien progname); 446236769Sobrien exit(2); 447236769Sobrien#endif 448236769Sobrien jp_0 = -1; 449236769Sobrien jp_1 = -1; 450236769Sobrien compatMake = TRUE; 451236769Sobrien } else { 452236769Sobrien Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 453236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 454236769Sobrien jobServer = TRUE; 455236769Sobrien } 456236769Sobrien break; 457236769Sobrien case 'N': 458236769Sobrien noExecute = TRUE; 459236769Sobrien noRecursiveExecute = TRUE; 460236769Sobrien Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 461236769Sobrien break; 462236769Sobrien case 'S': 463236769Sobrien keepgoing = FALSE; 464236769Sobrien Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 465236769Sobrien break; 466236769Sobrien case 'T': 467236769Sobrien if (argvalue == NULL) goto noarg; 468236769Sobrien tracefile = bmake_strdup(argvalue); 469236769Sobrien Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 470236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 471236769Sobrien break; 472236769Sobrien case 'V': 473236769Sobrien if (argvalue == NULL) goto noarg; 474236769Sobrien printVars = TRUE; 475236769Sobrien (void)Lst_AtEnd(variables, argvalue); 476236769Sobrien Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 477236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 478236769Sobrien break; 479236769Sobrien case 'W': 480236769Sobrien parseWarnFatal = TRUE; 481236769Sobrien break; 482236769Sobrien case 'X': 483236769Sobrien varNoExportEnv = TRUE; 484236769Sobrien Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 485236769Sobrien break; 486236769Sobrien case 'd': 487236769Sobrien if (argvalue == NULL) goto noarg; 488236769Sobrien /* If '-d-opts' don't pass to children */ 489236769Sobrien if (argvalue[0] == '-') 490236769Sobrien argvalue++; 491236769Sobrien else { 492236769Sobrien Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 493236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 494236769Sobrien } 495236769Sobrien parse_debug_options(argvalue); 496236769Sobrien break; 497236769Sobrien case 'e': 498236769Sobrien checkEnvFirst = TRUE; 499236769Sobrien Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 500236769Sobrien break; 501236769Sobrien case 'f': 502236769Sobrien if (argvalue == NULL) goto noarg; 503236769Sobrien (void)Lst_AtEnd(makefiles, argvalue); 504236769Sobrien break; 505236769Sobrien case 'i': 506236769Sobrien ignoreErrors = TRUE; 507236769Sobrien Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 508236769Sobrien break; 509236769Sobrien case 'j': 510236769Sobrien if (argvalue == NULL) goto noarg; 511236769Sobrien forceJobs = TRUE; 512236769Sobrien maxJobs = strtol(argvalue, &p, 0); 513236769Sobrien if (*p != '\0' || maxJobs < 1) { 514236769Sobrien (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 515236769Sobrien progname); 516236769Sobrien exit(1); 517236769Sobrien } 518236769Sobrien Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 519236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 520236769Sobrien Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 521236769Sobrien maxJobTokens = maxJobs; 522236769Sobrien break; 523236769Sobrien case 'k': 524236769Sobrien keepgoing = TRUE; 525236769Sobrien Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 526236769Sobrien break; 527236769Sobrien case 'm': 528236769Sobrien if (argvalue == NULL) goto noarg; 529236769Sobrien /* look for magic parent directory search string */ 530236769Sobrien if (strncmp(".../", argvalue, 4) == 0) { 531236769Sobrien if (!Dir_FindHereOrAbove(curdir, argvalue+4, 532236769Sobrien found_path, sizeof(found_path))) 533236769Sobrien break; /* nothing doing */ 534236769Sobrien (void)Dir_AddDir(sysIncPath, found_path); 535236769Sobrien } else { 536236769Sobrien (void)Dir_AddDir(sysIncPath, argvalue); 537236769Sobrien } 538236769Sobrien Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 539236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 540236769Sobrien break; 541236769Sobrien case 'n': 542236769Sobrien noExecute = TRUE; 543236769Sobrien Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 544236769Sobrien break; 545236769Sobrien case 'q': 546236769Sobrien queryFlag = TRUE; 547236769Sobrien /* Kind of nonsensical, wot? */ 548236769Sobrien Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 549236769Sobrien break; 550236769Sobrien case 'r': 551236769Sobrien noBuiltins = TRUE; 552236769Sobrien Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 553236769Sobrien break; 554236769Sobrien case 's': 555236769Sobrien beSilent = TRUE; 556236769Sobrien Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 557236769Sobrien break; 558236769Sobrien case 't': 559236769Sobrien touchFlag = TRUE; 560236769Sobrien Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 561236769Sobrien break; 562236769Sobrien case '-': 563236769Sobrien dashDash = TRUE; 564236769Sobrien break; 565236769Sobrien default: 566236769Sobrien case '?': 567236769Sobrien#ifndef MAKE_NATIVE 568236769Sobrien fprintf(stderr, "getopt(%s) -> %d (%c)\n", 569236769Sobrien OPTFLAGS, c, c); 570236769Sobrien#endif 571236769Sobrien usage(); 572236769Sobrien } 573236769Sobrien argv += arginc; 574236769Sobrien argc -= arginc; 575236769Sobrien } 576236769Sobrien 577236769Sobrien oldVars = TRUE; 578236769Sobrien 579236769Sobrien /* 580236769Sobrien * See if the rest of the arguments are variable assignments and 581236769Sobrien * perform them if so. Else take them to be targets and stuff them 582236769Sobrien * on the end of the "create" list. 583236769Sobrien */ 584236769Sobrien for (; argc > 1; ++argv, --argc) 585236769Sobrien if (Parse_IsVar(argv[1])) { 586236769Sobrien Parse_DoVar(argv[1], VAR_CMD); 587236769Sobrien } else { 588236769Sobrien if (!*argv[1]) 589236769Sobrien Punt("illegal (null) argument."); 590236769Sobrien if (*argv[1] == '-' && !dashDash) 591236769Sobrien goto rearg; 592236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 593236769Sobrien } 594236769Sobrien 595236769Sobrien return; 596236769Sobriennoarg: 597236769Sobrien (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 598236769Sobrien progname, c); 599236769Sobrien usage(); 600236769Sobrien} 601236769Sobrien 602236769Sobrien/*- 603236769Sobrien * Main_ParseArgLine -- 604236769Sobrien * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 605236769Sobrien * is encountered and by main() when reading the .MAKEFLAGS envariable. 606236769Sobrien * Takes a line of arguments and breaks it into its 607236769Sobrien * component words and passes those words and the number of them to the 608236769Sobrien * MainParseArgs function. 609236769Sobrien * The line should have all its leading whitespace removed. 610236769Sobrien * 611236769Sobrien * Input: 612236769Sobrien * line Line to fracture 613236769Sobrien * 614236769Sobrien * Results: 615236769Sobrien * None 616236769Sobrien * 617236769Sobrien * Side Effects: 618236769Sobrien * Only those that come from the various arguments. 619236769Sobrien */ 620236769Sobrienvoid 621236769SobrienMain_ParseArgLine(const char *line) 622236769Sobrien{ 623236769Sobrien char **argv; /* Manufactured argument vector */ 624236769Sobrien int argc; /* Number of arguments in argv */ 625236769Sobrien char *args; /* Space used by the args */ 626236769Sobrien char *buf, *p1; 627236769Sobrien char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 628236769Sobrien size_t len; 629236769Sobrien 630236769Sobrien if (line == NULL) 631236769Sobrien return; 632236769Sobrien for (; *line == ' '; ++line) 633236769Sobrien continue; 634236769Sobrien if (!*line) 635236769Sobrien return; 636236769Sobrien 637236769Sobrien#ifndef POSIX 638236769Sobrien { 639236769Sobrien /* 640236769Sobrien * $MAKE may simply be naming the make(1) binary 641236769Sobrien */ 642236769Sobrien char *cp; 643236769Sobrien 644236769Sobrien if (!(cp = strrchr(line, '/'))) 645236769Sobrien cp = line; 646236769Sobrien if ((cp = strstr(cp, "make")) && 647236769Sobrien strcmp(cp, "make") == 0) 648236769Sobrien return; 649236769Sobrien } 650236769Sobrien#endif 651236769Sobrien buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 652236769Sobrien (void)snprintf(buf, len, "%s %s", argv0, line); 653236769Sobrien if (p1) 654236769Sobrien free(p1); 655236769Sobrien 656236769Sobrien argv = brk_string(buf, &argc, TRUE, &args); 657236769Sobrien if (argv == NULL) { 658236769Sobrien Error("Unterminated quoted string [%s]", buf); 659236769Sobrien free(buf); 660236769Sobrien return; 661236769Sobrien } 662236769Sobrien free(buf); 663236769Sobrien MainParseArgs(argc, argv); 664236769Sobrien 665236769Sobrien free(args); 666236769Sobrien free(argv); 667236769Sobrien} 668236769Sobrien 669236769SobrienBoolean 670236769SobrienMain_SetObjdir(const char *path) 671236769Sobrien{ 672236769Sobrien struct stat sb; 673236769Sobrien char *p = NULL; 674236769Sobrien char buf[MAXPATHLEN + 1]; 675236769Sobrien Boolean rc = FALSE; 676236769Sobrien 677236769Sobrien /* expand variable substitutions */ 678236769Sobrien if (strchr(path, '$') != 0) { 679236769Sobrien snprintf(buf, MAXPATHLEN, "%s", path); 680236769Sobrien path = p = Var_Subst(NULL, buf, VAR_GLOBAL, 0); 681236769Sobrien } 682236769Sobrien 683236769Sobrien if (path[0] != '/') { 684236769Sobrien snprintf(buf, MAXPATHLEN, "%s/%s", curdir, path); 685236769Sobrien path = buf; 686236769Sobrien } 687236769Sobrien 688236769Sobrien /* look for the directory and try to chdir there */ 689236769Sobrien if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 690236769Sobrien if (chdir(path)) { 691236769Sobrien (void)fprintf(stderr, "make warning: %s: %s.\n", 692236769Sobrien path, strerror(errno)); 693236769Sobrien } else { 694236769Sobrien strncpy(objdir, path, MAXPATHLEN); 695236769Sobrien Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 696236769Sobrien setenv("PWD", objdir, 1); 697236769Sobrien Dir_InitDot(); 698236769Sobrien rc = TRUE; 699236769Sobrien } 700236769Sobrien } 701236769Sobrien 702236769Sobrien if (p) 703236769Sobrien free(p); 704236769Sobrien return rc; 705236769Sobrien} 706236769Sobrien 707236769Sobrien/*- 708236769Sobrien * ReadAllMakefiles -- 709236769Sobrien * wrapper around ReadMakefile() to read all. 710236769Sobrien * 711236769Sobrien * Results: 712236769Sobrien * TRUE if ok, FALSE on error 713236769Sobrien */ 714236769Sobrienstatic int 715236769SobrienReadAllMakefiles(const void *p, const void *q) 716236769Sobrien{ 717236769Sobrien return (ReadMakefile(p, q) == 0); 718236769Sobrien} 719236769Sobrien 720236769Sobrienint 721236769Sobrienstr2Lst_Append(Lst lp, char *str, const char *sep) 722236769Sobrien{ 723236769Sobrien char *cp; 724236769Sobrien int n; 725236769Sobrien 726236769Sobrien if (!sep) 727236769Sobrien sep = " \t"; 728236769Sobrien 729236769Sobrien for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 730236769Sobrien (void)Lst_AtEnd(lp, cp); 731236769Sobrien n++; 732236769Sobrien } 733236769Sobrien return (n); 734236769Sobrien} 735236769Sobrien 736236769Sobrien#ifdef SIGINFO 737236769Sobrien/*ARGSUSED*/ 738236769Sobrienstatic void 739237578Sobriensiginfo(int signo MAKE_ATTR_UNUSED) 740236769Sobrien{ 741236769Sobrien char dir[MAXPATHLEN]; 742236769Sobrien char str[2 * MAXPATHLEN]; 743236769Sobrien int len; 744236769Sobrien if (getcwd(dir, sizeof(dir)) == NULL) 745236769Sobrien return; 746236769Sobrien len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 747236769Sobrien if (len > 0) 748236769Sobrien (void)write(STDERR_FILENO, str, (size_t)len); 749236769Sobrien} 750236769Sobrien#endif 751236769Sobrien 752236769Sobrien/* 753236769Sobrien * Allow makefiles some control over the mode we run in. 754236769Sobrien */ 755236769Sobrienvoid 756236769SobrienMakeMode(const char *mode) 757236769Sobrien{ 758236769Sobrien char *mp = NULL; 759236769Sobrien 760236769Sobrien if (!mode) 761236769Sobrien mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", VAR_GLOBAL, 0); 762236769Sobrien 763236769Sobrien if (mode && *mode) { 764236769Sobrien if (strstr(mode, "compat")) { 765236769Sobrien compatMake = TRUE; 766236769Sobrien forceJobs = FALSE; 767236769Sobrien } 768236769Sobrien#if USE_META 769236769Sobrien if (strstr(mode, "meta")) 770236769Sobrien meta_init(mode); 771236769Sobrien#endif 772236769Sobrien } 773236769Sobrien if (mp) 774236769Sobrien free(mp); 775236769Sobrien} 776236769Sobrien 777236769Sobrien/*- 778236769Sobrien * main -- 779236769Sobrien * The main function, for obvious reasons. Initializes variables 780236769Sobrien * and a few modules, then parses the arguments give it in the 781236769Sobrien * environment and on the command line. Reads the system makefile 782236769Sobrien * followed by either Makefile, makefile or the file given by the 783236769Sobrien * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 784236769Sobrien * flags it has received by then uses either the Make or the Compat 785236769Sobrien * module to create the initial list of targets. 786236769Sobrien * 787236769Sobrien * Results: 788236769Sobrien * If -q was given, exits -1 if anything was out-of-date. Else it exits 789236769Sobrien * 0. 790236769Sobrien * 791236769Sobrien * Side Effects: 792236769Sobrien * The program exits when done. Targets are created. etc. etc. etc. 793236769Sobrien */ 794236769Sobrienint 795236769Sobrienmain(int argc, char **argv) 796236769Sobrien{ 797236769Sobrien Lst targs; /* target nodes to create -- passed to Make_Init */ 798236769Sobrien Boolean outOfDate = FALSE; /* FALSE if all targets up to date */ 799236769Sobrien struct stat sb, sa; 800236769Sobrien char *p1, *path, *pwd; 801236769Sobrien char mdpath[MAXPATHLEN]; 802236769Sobrien#ifdef FORCE_MACHINE 803236769Sobrien const char *machine = FORCE_MACHINE; 804236769Sobrien#else 805236769Sobrien const char *machine = getenv("MACHINE"); 806236769Sobrien#endif 807236769Sobrien const char *machine_arch = getenv("MACHINE_ARCH"); 808236769Sobrien char *syspath = getenv("MAKESYSPATH"); 809236769Sobrien Lst sysMkPath; /* Path of sys.mk */ 810236769Sobrien char *cp = NULL, *start; 811236769Sobrien /* avoid faults on read-only strings */ 812236769Sobrien static char defsyspath[] = _PATH_DEFSYSPATH; 813236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 814236769Sobrien struct timeval rightnow; /* to initialize random seed */ 815236769Sobrien#ifdef MAKE_NATIVE 816236769Sobrien struct utsname utsname; 817236769Sobrien#endif 818236769Sobrien 819236769Sobrien /* default to writing debug to stderr */ 820236769Sobrien debug_file = stderr; 821236769Sobrien 822236769Sobrien#ifdef SIGINFO 823236769Sobrien (void)bmake_signal(SIGINFO, siginfo); 824236769Sobrien#endif 825236769Sobrien /* 826236769Sobrien * Set the seed to produce a different random sequence 827236769Sobrien * on each program execution. 828236769Sobrien */ 829236769Sobrien gettimeofday(&rightnow, NULL); 830236769Sobrien srandom(rightnow.tv_sec + rightnow.tv_usec); 831236769Sobrien 832236769Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 833236769Sobrien progname++; 834236769Sobrien else 835236769Sobrien progname = argv[0]; 836236769Sobrien#ifdef RLIMIT_NOFILE 837236769Sobrien /* 838236769Sobrien * get rid of resource limit on file descriptors 839236769Sobrien */ 840236769Sobrien { 841236769Sobrien struct rlimit rl; 842236769Sobrien if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 843236769Sobrien rl.rlim_cur != rl.rlim_max) { 844236769Sobrien rl.rlim_cur = rl.rlim_max; 845236769Sobrien (void)setrlimit(RLIMIT_NOFILE, &rl); 846236769Sobrien } 847236769Sobrien } 848236769Sobrien#endif 849236769Sobrien 850236769Sobrien /* 851236769Sobrien * Get the name of this type of MACHINE from utsname 852236769Sobrien * so we can share an executable for similar machines. 853236769Sobrien * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 854236769Sobrien * 855236769Sobrien * Note that both MACHINE and MACHINE_ARCH are decided at 856236769Sobrien * run-time. 857236769Sobrien */ 858236769Sobrien if (!machine) { 859236769Sobrien#ifdef MAKE_NATIVE 860236769Sobrien if (uname(&utsname) == -1) { 861236769Sobrien (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 862236769Sobrien strerror(errno)); 863236769Sobrien exit(2); 864236769Sobrien } 865236769Sobrien machine = utsname.machine; 866236769Sobrien#else 867236769Sobrien#ifdef MAKE_MACHINE 868236769Sobrien machine = MAKE_MACHINE; 869236769Sobrien#else 870236769Sobrien machine = "unknown"; 871236769Sobrien#endif 872236769Sobrien#endif 873236769Sobrien } 874236769Sobrien 875236769Sobrien if (!machine_arch) { 876236769Sobrien#ifndef MACHINE_ARCH 877236769Sobrien#ifdef MAKE_MACHINE_ARCH 878236769Sobrien machine_arch = MAKE_MACHINE_ARCH; 879236769Sobrien#else 880236769Sobrien machine_arch = "unknown"; 881236769Sobrien#endif 882236769Sobrien#else 883236769Sobrien machine_arch = MACHINE_ARCH; 884236769Sobrien#endif 885236769Sobrien } 886236769Sobrien 887236769Sobrien myPid = getpid(); /* remember this for vFork() */ 888236769Sobrien 889236769Sobrien /* 890236769Sobrien * Just in case MAKEOBJDIR wants us to do something tricky. 891236769Sobrien */ 892236769Sobrien Var_Init(); /* Initialize the lists of variables for 893236769Sobrien * parsing arguments */ 894236769Sobrien Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 895236769Sobrien Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 896236769Sobrien#ifdef MAKE_VERSION 897236769Sobrien Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 898236769Sobrien#endif 899236769Sobrien Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 900236769Sobrien /* 901236769Sobrien * This is the traditional preference for makefiles. 902236769Sobrien */ 903236769Sobrien#ifndef MAKEFILE_PREFERENCE_LIST 904236769Sobrien# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 905236769Sobrien#endif 906236769Sobrien Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 907236769Sobrien VAR_GLOBAL, 0); 908236769Sobrien Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 909236769Sobrien 910236769Sobrien create = Lst_Init(FALSE); 911236769Sobrien makefiles = Lst_Init(FALSE); 912236769Sobrien printVars = FALSE; 913236769Sobrien variables = Lst_Init(FALSE); 914236769Sobrien beSilent = FALSE; /* Print commands as executed */ 915236769Sobrien ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 916236769Sobrien noExecute = FALSE; /* Execute all commands */ 917236769Sobrien noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 918236769Sobrien keepgoing = FALSE; /* Stop on error */ 919236769Sobrien allPrecious = FALSE; /* Remove targets when interrupted */ 920236769Sobrien queryFlag = FALSE; /* This is not just a check-run */ 921236769Sobrien noBuiltins = FALSE; /* Read the built-in rules */ 922236769Sobrien touchFlag = FALSE; /* Actually update targets */ 923236769Sobrien debug = 0; /* No debug verbosity, please. */ 924236769Sobrien jobsRunning = FALSE; 925236769Sobrien 926236769Sobrien maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 927236769Sobrien maxJobTokens = maxJobs; 928236769Sobrien compatMake = FALSE; /* No compat mode */ 929236769Sobrien ignorePWD = FALSE; 930236769Sobrien 931236769Sobrien /* 932236769Sobrien * Initialize the parsing, directory and variable modules to prepare 933236769Sobrien * for the reading of inclusion paths and variable settings on the 934236769Sobrien * command line 935236769Sobrien */ 936236769Sobrien 937236769Sobrien /* 938236769Sobrien * Initialize various variables. 939236769Sobrien * MAKE also gets this name, for compatibility 940236769Sobrien * .MAKEFLAGS gets set to the empty string just in case. 941236769Sobrien * MFLAGS also gets initialized empty, for compatibility. 942236769Sobrien */ 943236769Sobrien Parse_Init(); 944236769Sobrien if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 945236769Sobrien /* 946236769Sobrien * Leave alone if it is an absolute path, or if it does 947236769Sobrien * not contain a '/' in which case we need to find it in 948236769Sobrien * the path, like execvp(3) and the shells do. 949236769Sobrien */ 950236769Sobrien p1 = argv[0]; 951236769Sobrien } else { 952236769Sobrien /* 953236769Sobrien * A relative path, canonicalize it. 954236769Sobrien */ 955236769Sobrien p1 = realpath(argv[0], mdpath); 956236769Sobrien if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 957236769Sobrien p1 = argv[0]; /* realpath failed */ 958236769Sobrien } 959236769Sobrien } 960236769Sobrien Var_Set("MAKE", p1, VAR_GLOBAL, 0); 961236769Sobrien Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 962236769Sobrien Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 963236769Sobrien Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 964236769Sobrien Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 965236769Sobrien Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 966236769Sobrien 967236769Sobrien /* 968236769Sobrien * Set some other useful macros 969236769Sobrien */ 970236769Sobrien { 971236769Sobrien char tmp[64]; 972236769Sobrien const char *ep; 973236769Sobrien 974236769Sobrien if (!(ep = getenv(MAKE_LEVEL))) { 975236769Sobrien#ifdef MAKE_LEVEL_SAFE 976236769Sobrien if (!(ep = getenv(MAKE_LEVEL_SAFE))) 977236769Sobrien#endif 978236769Sobrien ep = "0"; 979236769Sobrien } 980236769Sobrien Var_Set(MAKE_LEVEL, ep, VAR_GLOBAL, 0); 981236769Sobrien snprintf(tmp, sizeof(tmp), "%u", myPid); 982236769Sobrien Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 983236769Sobrien snprintf(tmp, sizeof(tmp), "%u", getppid()); 984236769Sobrien Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 985236769Sobrien } 986236769Sobrien Job_SetPrefix(); 987236769Sobrien 988236769Sobrien /* 989236769Sobrien * First snag any flags out of the MAKE environment variable. 990236769Sobrien * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 991236769Sobrien * in a different format). 992236769Sobrien */ 993236769Sobrien#ifdef POSIX 994236769Sobrien Main_ParseArgLine(getenv("MAKEFLAGS")); 995236769Sobrien#else 996236769Sobrien Main_ParseArgLine(getenv("MAKE")); 997236769Sobrien#endif 998236769Sobrien 999236769Sobrien /* 1000236769Sobrien * Find where we are (now). 1001236769Sobrien * We take care of PWD for the automounter below... 1002236769Sobrien */ 1003236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 1004236769Sobrien (void)fprintf(stderr, "%s: getcwd: %s.\n", 1005236769Sobrien progname, strerror(errno)); 1006236769Sobrien exit(2); 1007236769Sobrien } 1008236769Sobrien 1009236769Sobrien MainParseArgs(argc, argv); 1010236769Sobrien 1011236769Sobrien /* 1012236769Sobrien * Verify that cwd is sane. 1013236769Sobrien */ 1014236769Sobrien if (stat(curdir, &sa) == -1) { 1015236769Sobrien (void)fprintf(stderr, "%s: %s: %s.\n", 1016236769Sobrien progname, curdir, strerror(errno)); 1017236769Sobrien exit(2); 1018236769Sobrien } 1019236769Sobrien 1020236769Sobrien /* 1021236769Sobrien * All this code is so that we know where we are when we start up 1022236769Sobrien * on a different machine with pmake. 1023236769Sobrien * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1024236769Sobrien * since the value of curdir can vary depending on how we got 1025236769Sobrien * here. Ie sitting at a shell prompt (shell that provides $PWD) 1026236769Sobrien * or via subdir.mk in which case its likely a shell which does 1027236769Sobrien * not provide it. 1028236769Sobrien * So, to stop it breaking this case only, we ignore PWD if 1029236769Sobrien * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 1030236769Sobrien */ 1031236769Sobrien#ifndef NO_PWD_OVERRIDE 1032236769Sobrien if (!ignorePWD && 1033236769Sobrien (pwd = getenv("PWD")) != NULL && 1034236769Sobrien getenv("MAKEOBJDIRPREFIX") == NULL) { 1035236769Sobrien const char *makeobjdir = getenv("MAKEOBJDIR"); 1036236769Sobrien 1037236769Sobrien if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 1038236769Sobrien if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && 1039236769Sobrien sa.st_dev == sb.st_dev) 1040236769Sobrien (void)strncpy(curdir, pwd, MAXPATHLEN); 1041236769Sobrien } 1042236769Sobrien } 1043236769Sobrien#endif 1044236769Sobrien Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 1045236769Sobrien 1046236769Sobrien /* 1047236769Sobrien * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1048236769Sobrien * MAKEOBJDIR is set in the environment, try only that value 1049236769Sobrien * and fall back to .CURDIR if it does not exist. 1050236769Sobrien * 1051236769Sobrien * Otherwise, try _PATH_OBJDIR.MACHINE, _PATH_OBJDIR, and 1052236769Sobrien * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1053236769Sobrien * of these paths exist, just use .CURDIR. 1054236769Sobrien */ 1055236769Sobrien Dir_Init(curdir); 1056236769Sobrien (void)Main_SetObjdir(curdir); 1057236769Sobrien 1058236769Sobrien if ((path = getenv("MAKEOBJDIRPREFIX")) != NULL) { 1059236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir); 1060236769Sobrien (void)Main_SetObjdir(mdpath); 1061236769Sobrien } else if ((path = getenv("MAKEOBJDIR")) != NULL) { 1062236769Sobrien (void)Main_SetObjdir(path); 1063236769Sobrien } else { 1064236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s.%s", _PATH_OBJDIR, machine); 1065236769Sobrien if (!Main_SetObjdir(mdpath) && !Main_SetObjdir(_PATH_OBJDIR)) { 1066236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", 1067236769Sobrien _PATH_OBJDIRPREFIX, curdir); 1068236769Sobrien (void)Main_SetObjdir(mdpath); 1069236769Sobrien } 1070236769Sobrien } 1071236769Sobrien 1072236769Sobrien /* 1073236769Sobrien * Be compatible if user did not specify -j and did not explicitly 1074236769Sobrien * turned compatibility on 1075236769Sobrien */ 1076236769Sobrien if (!compatMake && !forceJobs) { 1077236769Sobrien compatMake = TRUE; 1078236769Sobrien } 1079236769Sobrien 1080236769Sobrien /* 1081236769Sobrien * Initialize archive, target and suffix modules in preparation for 1082236769Sobrien * parsing the makefile(s) 1083236769Sobrien */ 1084236769Sobrien Arch_Init(); 1085236769Sobrien Targ_Init(); 1086236769Sobrien Suff_Init(); 1087236769Sobrien Trace_Init(tracefile); 1088236769Sobrien 1089236769Sobrien DEFAULT = NULL; 1090236769Sobrien (void)time(&now); 1091236769Sobrien 1092236769Sobrien Trace_Log(MAKESTART, NULL); 1093236769Sobrien 1094236769Sobrien /* 1095236769Sobrien * Set up the .TARGETS variable to contain the list of targets to be 1096236769Sobrien * created. If none specified, make the variable empty -- the parser 1097236769Sobrien * will fill the thing in with the default or .MAIN target. 1098236769Sobrien */ 1099236769Sobrien if (!Lst_IsEmpty(create)) { 1100236769Sobrien LstNode ln; 1101236769Sobrien 1102236769Sobrien for (ln = Lst_First(create); ln != NULL; 1103236769Sobrien ln = Lst_Succ(ln)) { 1104236769Sobrien char *name = (char *)Lst_Datum(ln); 1105236769Sobrien 1106236769Sobrien Var_Append(".TARGETS", name, VAR_GLOBAL); 1107236769Sobrien } 1108236769Sobrien } else 1109236769Sobrien Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 1110236769Sobrien 1111236769Sobrien 1112236769Sobrien /* 1113236769Sobrien * If no user-supplied system path was given (through the -m option) 1114236769Sobrien * add the directories from the DEFSYSPATH (more than one may be given 1115236769Sobrien * as dir1:...:dirn) to the system include path. 1116236769Sobrien */ 1117236769Sobrien if (syspath == NULL || *syspath == '\0') 1118236769Sobrien syspath = defsyspath; 1119236769Sobrien else 1120236769Sobrien syspath = bmake_strdup(syspath); 1121236769Sobrien 1122236769Sobrien for (start = syspath; *start != '\0'; start = cp) { 1123236769Sobrien for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1124236769Sobrien continue; 1125236769Sobrien if (*cp == ':') { 1126236769Sobrien *cp++ = '\0'; 1127236769Sobrien } 1128236769Sobrien /* look for magic parent directory search string */ 1129236769Sobrien if (strncmp(".../", start, 4) != 0) { 1130236769Sobrien (void)Dir_AddDir(defIncPath, start); 1131236769Sobrien } else { 1132236769Sobrien if (Dir_FindHereOrAbove(curdir, start+4, 1133236769Sobrien found_path, sizeof(found_path))) { 1134236769Sobrien (void)Dir_AddDir(defIncPath, found_path); 1135236769Sobrien } 1136236769Sobrien } 1137236769Sobrien } 1138236769Sobrien if (syspath != defsyspath) 1139236769Sobrien free(syspath); 1140236769Sobrien 1141236769Sobrien /* 1142236769Sobrien * Read in the built-in rules first, followed by the specified 1143236769Sobrien * makefile, if it was (makefile != NULL), or the default 1144236769Sobrien * makefile and Makefile, in that order, if it wasn't. 1145236769Sobrien */ 1146236769Sobrien if (!noBuiltins) { 1147236769Sobrien LstNode ln; 1148236769Sobrien 1149236769Sobrien sysMkPath = Lst_Init(FALSE); 1150236769Sobrien Dir_Expand(_PATH_DEFSYSMK, 1151236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1152236769Sobrien sysMkPath); 1153236769Sobrien if (Lst_IsEmpty(sysMkPath)) 1154236769Sobrien Fatal("%s: no system rules (%s).", progname, 1155236769Sobrien _PATH_DEFSYSMK); 1156236769Sobrien ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 1157236769Sobrien if (ln == NULL) 1158236769Sobrien Fatal("%s: cannot open %s.", progname, 1159236769Sobrien (char *)Lst_Datum(ln)); 1160236769Sobrien } 1161236769Sobrien 1162236769Sobrien if (!Lst_IsEmpty(makefiles)) { 1163236769Sobrien LstNode ln; 1164236769Sobrien 1165236769Sobrien ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 1166236769Sobrien if (ln != NULL) 1167236769Sobrien Fatal("%s: cannot open %s.", progname, 1168236769Sobrien (char *)Lst_Datum(ln)); 1169236769Sobrien } else { 1170236769Sobrien p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 1171236769Sobrien VAR_CMD, 0); 1172236769Sobrien if (p1) { 1173236769Sobrien (void)str2Lst_Append(makefiles, p1, NULL); 1174236769Sobrien (void)Lst_Find(makefiles, NULL, ReadMakefile); 1175236769Sobrien free(p1); 1176236769Sobrien } 1177236769Sobrien } 1178236769Sobrien 1179236769Sobrien /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1180236769Sobrien if (!noBuiltins || !printVars) { 1181236769Sobrien makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 1182236769Sobrien VAR_CMD, 0); 1183236769Sobrien doing_depend = TRUE; 1184236769Sobrien (void)ReadMakefile(makeDependfile, NULL); 1185236769Sobrien doing_depend = FALSE; 1186236769Sobrien } 1187236769Sobrien 1188236769Sobrien MakeMode(NULL); 1189236769Sobrien 1190236769Sobrien Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1191236769Sobrien if (p1) 1192236769Sobrien free(p1); 1193236769Sobrien 1194236769Sobrien if (!compatMake) 1195236769Sobrien Job_ServerStart(maxJobTokens, jp_0, jp_1); 1196236769Sobrien if (DEBUG(JOB)) 1197236769Sobrien fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1198236769Sobrien jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 1199236769Sobrien 1200236769Sobrien Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1201236769Sobrien 1202236769Sobrien#ifndef NO_CHECK_MAKE_CHDIR 1203236769Sobrien Check_Cwd_av(0, NULL, 0); /* initialize it */ 1204236769Sobrien#endif 1205236769Sobrien 1206236769Sobrien /* 1207236769Sobrien * For compatibility, look at the directories in the VPATH variable 1208236769Sobrien * and add them to the search path, if the variable is defined. The 1209236769Sobrien * variable's value is in the same format as the PATH envariable, i.e. 1210236769Sobrien * <directory>:<directory>:<directory>... 1211236769Sobrien */ 1212236769Sobrien if (Var_Exists("VPATH", VAR_CMD)) { 1213236769Sobrien char *vpath, savec; 1214236769Sobrien /* 1215236769Sobrien * GCC stores string constants in read-only memory, but 1216236769Sobrien * Var_Subst will want to write this thing, so store it 1217236769Sobrien * in an array 1218236769Sobrien */ 1219236769Sobrien static char VPATH[] = "${VPATH}"; 1220236769Sobrien 1221236769Sobrien vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 1222236769Sobrien path = vpath; 1223236769Sobrien do { 1224236769Sobrien /* skip to end of directory */ 1225236769Sobrien for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1226236769Sobrien continue; 1227236769Sobrien /* Save terminator character so know when to stop */ 1228236769Sobrien savec = *cp; 1229236769Sobrien *cp = '\0'; 1230236769Sobrien /* Add directory to search path */ 1231236769Sobrien (void)Dir_AddDir(dirSearchPath, path); 1232236769Sobrien *cp = savec; 1233236769Sobrien path = cp + 1; 1234236769Sobrien } while (savec == ':'); 1235236769Sobrien free(vpath); 1236236769Sobrien } 1237236769Sobrien 1238236769Sobrien /* 1239236769Sobrien * Now that all search paths have been read for suffixes et al, it's 1240236769Sobrien * time to add the default search path to their lists... 1241236769Sobrien */ 1242236769Sobrien Suff_DoPaths(); 1243236769Sobrien 1244236769Sobrien /* 1245236769Sobrien * Propagate attributes through :: dependency lists. 1246236769Sobrien */ 1247236769Sobrien Targ_Propagate(); 1248236769Sobrien 1249236769Sobrien /* print the initial graph, if the user requested it */ 1250236769Sobrien if (DEBUG(GRAPH1)) 1251236769Sobrien Targ_PrintGraph(1); 1252236769Sobrien 1253236769Sobrien /* print the values of any variables requested by the user */ 1254236769Sobrien if (printVars) { 1255236769Sobrien LstNode ln; 1256236769Sobrien 1257236769Sobrien for (ln = Lst_First(variables); ln != NULL; 1258236769Sobrien ln = Lst_Succ(ln)) { 1259236769Sobrien char *var = (char *)Lst_Datum(ln); 1260236769Sobrien char *value; 1261236769Sobrien 1262236769Sobrien if (strchr(var, '$')) { 1263236769Sobrien value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 0); 1264236769Sobrien } else { 1265236769Sobrien value = Var_Value(var, VAR_GLOBAL, &p1); 1266236769Sobrien } 1267236769Sobrien printf("%s\n", value ? value : ""); 1268236769Sobrien if (p1) 1269236769Sobrien free(p1); 1270236769Sobrien } 1271236769Sobrien } else { 1272236769Sobrien /* 1273236769Sobrien * Have now read the entire graph and need to make a list of 1274236769Sobrien * targets to create. If none was given on the command line, 1275236769Sobrien * we consult the parsing module to find the main target(s) 1276236769Sobrien * to create. 1277236769Sobrien */ 1278236769Sobrien if (Lst_IsEmpty(create)) 1279236769Sobrien targs = Parse_MainName(); 1280236769Sobrien else 1281236769Sobrien targs = Targ_FindList(create, TARG_CREATE); 1282236769Sobrien 1283236769Sobrien if (!compatMake) { 1284236769Sobrien /* 1285236769Sobrien * Initialize job module before traversing the graph 1286236769Sobrien * now that any .BEGIN and .END targets have been read. 1287236769Sobrien * This is done only if the -q flag wasn't given 1288236769Sobrien * (to prevent the .BEGIN from being executed should 1289236769Sobrien * it exist). 1290236769Sobrien */ 1291236769Sobrien if (!queryFlag) { 1292236769Sobrien Job_Init(); 1293236769Sobrien jobsRunning = TRUE; 1294236769Sobrien } 1295236769Sobrien 1296236769Sobrien /* Traverse the graph, checking on all the targets */ 1297236769Sobrien outOfDate = Make_Run(targs); 1298236769Sobrien } else { 1299236769Sobrien /* 1300236769Sobrien * Compat_Init will take care of creating all the 1301236769Sobrien * targets as well as initializing the module. 1302236769Sobrien */ 1303236769Sobrien Compat_Run(targs); 1304236769Sobrien } 1305236769Sobrien } 1306236769Sobrien 1307236769Sobrien#ifdef CLEANUP 1308236769Sobrien Lst_Destroy(targs, NULL); 1309236769Sobrien Lst_Destroy(variables, NULL); 1310236769Sobrien Lst_Destroy(makefiles, NULL); 1311236769Sobrien Lst_Destroy(create, (FreeProc *)free); 1312236769Sobrien#endif 1313236769Sobrien 1314236769Sobrien /* print the graph now it's been processed if the user requested it */ 1315236769Sobrien if (DEBUG(GRAPH2)) 1316236769Sobrien Targ_PrintGraph(2); 1317236769Sobrien 1318236769Sobrien Trace_Log(MAKEEND, 0); 1319236769Sobrien 1320236769Sobrien Suff_End(); 1321236769Sobrien Targ_End(); 1322236769Sobrien Arch_End(); 1323236769Sobrien Var_End(); 1324236769Sobrien Parse_End(); 1325236769Sobrien Dir_End(); 1326236769Sobrien Job_End(); 1327236769Sobrien Trace_End(); 1328236769Sobrien 1329236769Sobrien return outOfDate ? 1 : 0; 1330236769Sobrien} 1331236769Sobrien 1332236769Sobrien/*- 1333236769Sobrien * ReadMakefile -- 1334236769Sobrien * Open and parse the given makefile. 1335236769Sobrien * 1336236769Sobrien * Results: 1337236769Sobrien * 0 if ok. -1 if couldn't open file. 1338236769Sobrien * 1339236769Sobrien * Side Effects: 1340236769Sobrien * lots 1341236769Sobrien */ 1342236769Sobrienstatic int 1343237578SobrienReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 1344236769Sobrien{ 1345236769Sobrien const char *fname = p; /* makefile to read */ 1346236769Sobrien int fd; 1347236769Sobrien size_t len = MAXPATHLEN; 1348236769Sobrien char *name, *path = bmake_malloc(len); 1349236769Sobrien 1350236769Sobrien if (!strcmp(fname, "-")) { 1351236769Sobrien Parse_File(NULL /*stdin*/, -1); 1352236769Sobrien Var_Set("MAKEFILE", "", VAR_GLOBAL, 0); 1353236769Sobrien } else { 1354236769Sobrien /* if we've chdir'd, rebuild the path name */ 1355236769Sobrien if (strcmp(curdir, objdir) && *fname != '/') { 1356236769Sobrien size_t plen = strlen(curdir) + strlen(fname) + 2; 1357236769Sobrien if (len < plen) 1358236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1359236769Sobrien 1360236769Sobrien (void)snprintf(path, len, "%s/%s", curdir, fname); 1361236769Sobrien fd = open(path, O_RDONLY); 1362236769Sobrien if (fd != -1) { 1363236769Sobrien fname = path; 1364236769Sobrien goto found; 1365236769Sobrien } 1366236769Sobrien 1367236769Sobrien /* If curdir failed, try objdir (ala .depend) */ 1368236769Sobrien plen = strlen(objdir) + strlen(fname) + 2; 1369236769Sobrien if (len < plen) 1370236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1371236769Sobrien (void)snprintf(path, len, "%s/%s", objdir, fname); 1372236769Sobrien fd = open(path, O_RDONLY); 1373236769Sobrien if (fd != -1) { 1374236769Sobrien fname = path; 1375236769Sobrien goto found; 1376236769Sobrien } 1377236769Sobrien } else { 1378236769Sobrien fd = open(fname, O_RDONLY); 1379236769Sobrien if (fd != -1) 1380236769Sobrien goto found; 1381236769Sobrien } 1382236769Sobrien /* look in -I and system include directories. */ 1383236769Sobrien name = Dir_FindFile(fname, parseIncPath); 1384236769Sobrien if (!name) 1385236769Sobrien name = Dir_FindFile(fname, 1386236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1387236769Sobrien if (!name || (fd = open(name, O_RDONLY)) == -1) { 1388236769Sobrien if (name) 1389236769Sobrien free(name); 1390236769Sobrien free(path); 1391236769Sobrien return(-1); 1392236769Sobrien } 1393236769Sobrien fname = name; 1394236769Sobrien /* 1395236769Sobrien * set the MAKEFILE variable desired by System V fans -- the 1396236769Sobrien * placement of the setting here means it gets set to the last 1397236769Sobrien * makefile specified, as it is set by SysV make. 1398236769Sobrien */ 1399236769Sobrienfound: 1400236769Sobrien if (!doing_depend) 1401236769Sobrien Var_Set("MAKEFILE", fname, VAR_GLOBAL, 0); 1402236769Sobrien Parse_File(fname, fd); 1403236769Sobrien } 1404236769Sobrien free(path); 1405236769Sobrien return(0); 1406236769Sobrien} 1407236769Sobrien 1408236769Sobrien 1409236769Sobrien/* 1410236769Sobrien * If MAKEOBJDIRPREFIX is in use, make ends up not in .CURDIR 1411236769Sobrien * in situations that would not arrise with ./obj (links or not). 1412236769Sobrien * This tends to break things like: 1413236769Sobrien * 1414236769Sobrien * build: 1415236769Sobrien * ${MAKE} includes 1416236769Sobrien * 1417236769Sobrien * This function spots when ${.MAKE:T} or ${.MAKE} is a command (as 1418236769Sobrien * opposed to an argument) in a command line and if so returns 1419236769Sobrien * ${.CURDIR} so caller can chdir() so that the assumptions made by 1420236769Sobrien * the Makefile hold true. 1421236769Sobrien * 1422236769Sobrien * If ${.MAKE} does not contain any '/', then ${.MAKE:T} is skipped. 1423236769Sobrien * 1424236769Sobrien * The chdir() only happens in the child process, and does nothing if 1425236769Sobrien * MAKEOBJDIRPREFIX and MAKEOBJDIR are not in the environment so it 1426236769Sobrien * should not break anything. Also if NOCHECKMAKECHDIR is set we 1427236769Sobrien * do nothing - to ensure historic semantics can be retained. 1428236769Sobrien */ 1429236769Sobrien#ifdef NO_CHECK_MAKE_CHDIR 1430236769Sobrienchar * 1431236769SobrienCheck_Cwd_Cmd(cmd) 1432236769Sobrien char *cmd; 1433236769Sobrien{ 1434236769Sobrien return 0; 1435236769Sobrien} 1436236769Sobrien 1437236769Sobrienvoid 1438236769SobrienCheck_Cwd(argv) 1439236769Sobrien char **argv; 1440236769Sobrien{ 1441236769Sobrien return; 1442236769Sobrien} 1443236769Sobrien 1444236769Sobrien#else 1445236769Sobrien 1446236769Sobrienstatic int Check_Cwd_Off = 0; 1447236769Sobrien 1448236769Sobrienstatic char * 1449236769SobrienCheck_Cwd_av(int ac, char **av, int copy) 1450236769Sobrien{ 1451236769Sobrien static char *make[4]; 1452236769Sobrien static char *cur_dir = NULL; 1453236769Sobrien char **mp; 1454236769Sobrien char *cp; 1455236769Sobrien int is_cmd, next_cmd; 1456236769Sobrien int i; 1457236769Sobrien int n; 1458236769Sobrien 1459236769Sobrien if (Check_Cwd_Off) { 1460236769Sobrien if (DEBUG(CWD)) 1461236769Sobrien fprintf(debug_file, "check_cwd: check is off.\n"); 1462236769Sobrien return NULL; 1463236769Sobrien } 1464236769Sobrien 1465236769Sobrien if (make[0] == NULL) { 1466236769Sobrien if (Var_Exists("NOCHECKMAKECHDIR", VAR_GLOBAL)) { 1467236769Sobrien Check_Cwd_Off = 1; 1468236769Sobrien if (DEBUG(CWD)) 1469236769Sobrien fprintf(debug_file, "check_cwd: turning check off.\n"); 1470236769Sobrien return NULL; 1471236769Sobrien } 1472236769Sobrien 1473236769Sobrien make[1] = Var_Value(".MAKE", VAR_GLOBAL, &cp); 1474236769Sobrien if ((make[0] = strrchr(make[1], '/')) == NULL) { 1475236769Sobrien make[0] = make[1]; 1476236769Sobrien make[1] = NULL; 1477236769Sobrien } else 1478236769Sobrien ++make[0]; 1479236769Sobrien make[2] = NULL; 1480236769Sobrien cur_dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp); 1481236769Sobrien } 1482236769Sobrien if (ac == 0 || av == NULL) { 1483236769Sobrien if (DEBUG(CWD)) 1484236769Sobrien fprintf(debug_file, "check_cwd: empty command.\n"); 1485236769Sobrien return NULL; /* initialization only */ 1486236769Sobrien } 1487236769Sobrien 1488236769Sobrien if (getenv("MAKEOBJDIR") == NULL && 1489236769Sobrien getenv("MAKEOBJDIRPREFIX") == NULL) { 1490236769Sobrien if (DEBUG(CWD)) 1491236769Sobrien fprintf(debug_file, "check_cwd: no obj dirs.\n"); 1492236769Sobrien return NULL; 1493236769Sobrien } 1494236769Sobrien 1495236769Sobrien 1496236769Sobrien next_cmd = 1; 1497236769Sobrien for (i = 0; i < ac; ++i) { 1498236769Sobrien is_cmd = next_cmd; 1499236769Sobrien 1500236769Sobrien n = strlen(av[i]); 1501236769Sobrien cp = &(av[i])[n - 1]; 1502236769Sobrien if (strspn(av[i], "|&;") == (size_t)n) { 1503236769Sobrien next_cmd = 1; 1504236769Sobrien continue; 1505236769Sobrien } else if (*cp == ';' || *cp == '&' || *cp == '|' || *cp == ')') { 1506236769Sobrien next_cmd = 1; 1507236769Sobrien if (copy) { 1508236769Sobrien do { 1509236769Sobrien *cp-- = '\0'; 1510236769Sobrien } while (*cp == ';' || *cp == '&' || *cp == '|' || 1511236769Sobrien *cp == ')' || *cp == '}') ; 1512236769Sobrien } else { 1513236769Sobrien /* 1514236769Sobrien * XXX this should not happen. 1515236769Sobrien */ 1516236769Sobrien fprintf(stderr, "%s: WARNING: raw arg ends in shell meta '%s'\n", 1517236769Sobrien progname, av[i]); 1518236769Sobrien } 1519236769Sobrien } else 1520236769Sobrien next_cmd = 0; 1521236769Sobrien 1522236769Sobrien cp = av[i]; 1523236769Sobrien if (*cp == ';' || *cp == '&' || *cp == '|') 1524236769Sobrien is_cmd = 1; 1525236769Sobrien 1526236769Sobrien if (DEBUG(CWD)) 1527236769Sobrien fprintf(debug_file, "av[%d] == %s '%s'", 1528236769Sobrien i, (is_cmd) ? "cmd" : "arg", av[i]); 1529236769Sobrien if (is_cmd != 0) { 1530236769Sobrien if (*cp == '(' || *cp == '{' || 1531236769Sobrien *cp == ';' || *cp == '&' || *cp == '|') { 1532236769Sobrien do { 1533236769Sobrien ++cp; 1534236769Sobrien } while (*cp == '(' || *cp == '{' || 1535236769Sobrien *cp == ';' || *cp == '&' || *cp == '|'); 1536236769Sobrien if (*cp == '\0') { 1537236769Sobrien next_cmd = 1; 1538236769Sobrien continue; 1539236769Sobrien } 1540236769Sobrien } 1541236769Sobrien if (strcmp(cp, "cd") == 0 || strcmp(cp, "chdir") == 0) { 1542236769Sobrien if (DEBUG(CWD)) 1543236769Sobrien fprintf(debug_file, " == cd, done.\n"); 1544236769Sobrien return NULL; 1545236769Sobrien } 1546236769Sobrien for (mp = make; *mp != NULL; ++mp) { 1547236769Sobrien n = strlen(*mp); 1548236769Sobrien if (strcmp(cp, *mp) == 0) { 1549236769Sobrien if (DEBUG(CWD)) 1550236769Sobrien fprintf(debug_file, " %s == '%s', chdir(%s)\n", 1551236769Sobrien cp, *mp, cur_dir); 1552236769Sobrien return cur_dir; 1553236769Sobrien } 1554236769Sobrien } 1555236769Sobrien } 1556236769Sobrien if (DEBUG(CWD)) 1557236769Sobrien fprintf(debug_file, "\n"); 1558236769Sobrien } 1559236769Sobrien return NULL; 1560236769Sobrien} 1561236769Sobrien 1562236769Sobrienchar * 1563236769SobrienCheck_Cwd_Cmd(const char *cmd) 1564236769Sobrien{ 1565236769Sobrien char *cp, *bp; 1566236769Sobrien char **av; 1567236769Sobrien int ac; 1568236769Sobrien 1569236769Sobrien if (Check_Cwd_Off) 1570236769Sobrien return NULL; 1571236769Sobrien 1572236769Sobrien if (cmd) { 1573236769Sobrien av = brk_string(cmd, &ac, TRUE, &bp); 1574236769Sobrien if (DEBUG(CWD)) 1575236769Sobrien fprintf(debug_file, "splitting: '%s' -> %d words\n", 1576236769Sobrien cmd, ac); 1577236769Sobrien } else { 1578236769Sobrien ac = 0; 1579236769Sobrien av = NULL; 1580236769Sobrien bp = NULL; 1581236769Sobrien } 1582236769Sobrien cp = Check_Cwd_av(ac, av, 1); 1583236769Sobrien if (bp) 1584236769Sobrien free(bp); 1585236769Sobrien if (av) 1586236769Sobrien free(av); 1587236769Sobrien return cp; 1588236769Sobrien} 1589236769Sobrien 1590236769Sobrienvoid 1591236769SobrienCheck_Cwd(const char **argv) 1592236769Sobrien{ 1593236769Sobrien char *cp; 1594236769Sobrien int ac; 1595236769Sobrien 1596236769Sobrien if (Check_Cwd_Off) 1597236769Sobrien return; 1598236769Sobrien 1599236769Sobrien for (ac = 0; argv[ac] != NULL; ++ac) 1600236769Sobrien /* NOTHING */; 1601236769Sobrien if (ac == 3 && *argv[1] == '-') { 1602236769Sobrien cp = Check_Cwd_Cmd(argv[2]); 1603236769Sobrien } else { 1604236769Sobrien cp = Check_Cwd_av(ac, UNCONST(argv), 0); 1605236769Sobrien } 1606236769Sobrien if (cp) { 1607236769Sobrien chdir(cp); 1608236769Sobrien } 1609236769Sobrien} 1610236769Sobrien#endif /* NO_CHECK_MAKE_CHDIR */ 1611236769Sobrien 1612236769Sobrien/*- 1613236769Sobrien * Cmd_Exec -- 1614236769Sobrien * Execute the command in cmd, and return the output of that command 1615236769Sobrien * in a string. 1616236769Sobrien * 1617236769Sobrien * Results: 1618236769Sobrien * A string containing the output of the command, or the empty string 1619236769Sobrien * If errnum is not NULL, it contains the reason for the command failure 1620236769Sobrien * 1621236769Sobrien * Side Effects: 1622236769Sobrien * The string must be freed by the caller. 1623236769Sobrien */ 1624236769Sobrienchar * 1625236769SobrienCmd_Exec(const char *cmd, const char **errnum) 1626236769Sobrien{ 1627236769Sobrien const char *args[4]; /* Args for invoking the shell */ 1628236769Sobrien int fds[2]; /* Pipe streams */ 1629236769Sobrien int cpid; /* Child PID */ 1630236769Sobrien int pid; /* PID from wait() */ 1631236769Sobrien char *res; /* result */ 1632236769Sobrien WAIT_T status; /* command exit status */ 1633236769Sobrien Buffer buf; /* buffer to store the result */ 1634236769Sobrien char *cp; 1635236769Sobrien int cc; 1636236769Sobrien 1637236769Sobrien 1638236769Sobrien *errnum = NULL; 1639236769Sobrien 1640236769Sobrien if (!shellName) 1641236769Sobrien Shell_Init(); 1642236769Sobrien /* 1643236769Sobrien * Set up arguments for shell 1644236769Sobrien */ 1645236769Sobrien args[0] = shellName; 1646236769Sobrien args[1] = "-c"; 1647236769Sobrien args[2] = cmd; 1648236769Sobrien args[3] = NULL; 1649236769Sobrien 1650236769Sobrien /* 1651236769Sobrien * Open a pipe for fetching its output 1652236769Sobrien */ 1653236769Sobrien if (pipe(fds) == -1) { 1654236769Sobrien *errnum = "Couldn't create pipe for \"%s\""; 1655236769Sobrien goto bad; 1656236769Sobrien } 1657236769Sobrien 1658236769Sobrien /* 1659236769Sobrien * Fork 1660236769Sobrien */ 1661236769Sobrien switch (cpid = vFork()) { 1662236769Sobrien case 0: 1663236769Sobrien /* 1664236769Sobrien * Close input side of pipe 1665236769Sobrien */ 1666236769Sobrien (void)close(fds[0]); 1667236769Sobrien 1668236769Sobrien /* 1669236769Sobrien * Duplicate the output stream to the shell's output, then 1670236769Sobrien * shut the extra thing down. Note we don't fetch the error 1671236769Sobrien * stream...why not? Why? 1672236769Sobrien */ 1673236769Sobrien (void)dup2(fds[1], 1); 1674236769Sobrien (void)close(fds[1]); 1675236769Sobrien 1676236769Sobrien Var_ExportVars(); 1677236769Sobrien 1678236769Sobrien (void)execv(shellPath, UNCONST(args)); 1679236769Sobrien _exit(1); 1680236769Sobrien /*NOTREACHED*/ 1681236769Sobrien 1682236769Sobrien case -1: 1683236769Sobrien *errnum = "Couldn't exec \"%s\""; 1684236769Sobrien goto bad; 1685236769Sobrien 1686236769Sobrien default: 1687236769Sobrien /* 1688236769Sobrien * No need for the writing half 1689236769Sobrien */ 1690236769Sobrien (void)close(fds[1]); 1691236769Sobrien 1692236769Sobrien Buf_Init(&buf, 0); 1693236769Sobrien 1694236769Sobrien do { 1695236769Sobrien char result[BUFSIZ]; 1696236769Sobrien cc = read(fds[0], result, sizeof(result)); 1697236769Sobrien if (cc > 0) 1698236769Sobrien Buf_AddBytes(&buf, cc, result); 1699236769Sobrien } 1700236769Sobrien while (cc > 0 || (cc == -1 && errno == EINTR)); 1701236769Sobrien 1702236769Sobrien /* 1703236769Sobrien * Close the input side of the pipe. 1704236769Sobrien */ 1705236769Sobrien (void)close(fds[0]); 1706236769Sobrien 1707236769Sobrien /* 1708236769Sobrien * Wait for the process to exit. 1709236769Sobrien */ 1710236769Sobrien while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1711236769Sobrien JobReapChild(pid, status, FALSE); 1712236769Sobrien continue; 1713236769Sobrien } 1714236769Sobrien cc = Buf_Size(&buf); 1715236769Sobrien res = Buf_Destroy(&buf, FALSE); 1716236769Sobrien 1717236769Sobrien if (cc == 0) 1718236769Sobrien *errnum = "Couldn't read shell's output for \"%s\""; 1719236769Sobrien 1720236769Sobrien if (WIFSIGNALED(status)) 1721236769Sobrien *errnum = "\"%s\" exited on a signal"; 1722236769Sobrien else if (WEXITSTATUS(status) != 0) 1723236769Sobrien *errnum = "\"%s\" returned non-zero status"; 1724236769Sobrien 1725236769Sobrien /* 1726236769Sobrien * Null-terminate the result, convert newlines to spaces and 1727236769Sobrien * install it in the variable. 1728236769Sobrien */ 1729236769Sobrien res[cc] = '\0'; 1730236769Sobrien cp = &res[cc]; 1731236769Sobrien 1732236769Sobrien if (cc > 0 && *--cp == '\n') { 1733236769Sobrien /* 1734236769Sobrien * A final newline is just stripped 1735236769Sobrien */ 1736236769Sobrien *cp-- = '\0'; 1737236769Sobrien } 1738236769Sobrien while (cp >= res) { 1739236769Sobrien if (*cp == '\n') { 1740236769Sobrien *cp = ' '; 1741236769Sobrien } 1742236769Sobrien cp--; 1743236769Sobrien } 1744236769Sobrien break; 1745236769Sobrien } 1746236769Sobrien return res; 1747236769Sobrienbad: 1748236769Sobrien res = bmake_malloc(1); 1749236769Sobrien *res = '\0'; 1750236769Sobrien return res; 1751236769Sobrien} 1752236769Sobrien 1753236769Sobrien/*- 1754236769Sobrien * Error -- 1755236769Sobrien * Print an error message given its format. 1756236769Sobrien * 1757236769Sobrien * Results: 1758236769Sobrien * None. 1759236769Sobrien * 1760236769Sobrien * Side Effects: 1761236769Sobrien * The message is printed. 1762236769Sobrien */ 1763236769Sobrien/* VARARGS */ 1764236769Sobrienvoid 1765236769SobrienError(const char *fmt, ...) 1766236769Sobrien{ 1767236769Sobrien va_list ap; 1768236769Sobrien FILE *err_file; 1769236769Sobrien 1770236769Sobrien err_file = debug_file; 1771236769Sobrien if (err_file == stdout) 1772236769Sobrien err_file = stderr; 1773236769Sobrien (void)fflush(stdout); 1774236769Sobrien for (;;) { 1775236769Sobrien va_start(ap, fmt); 1776236769Sobrien fprintf(err_file, "%s: ", progname); 1777236769Sobrien (void)vfprintf(err_file, fmt, ap); 1778236769Sobrien va_end(ap); 1779236769Sobrien (void)fprintf(err_file, "\n"); 1780236769Sobrien (void)fflush(err_file); 1781236769Sobrien if (err_file == stderr) 1782236769Sobrien break; 1783236769Sobrien err_file = stderr; 1784236769Sobrien } 1785236769Sobrien} 1786236769Sobrien 1787236769Sobrien/*- 1788236769Sobrien * Fatal -- 1789236769Sobrien * Produce a Fatal error message. If jobs are running, waits for them 1790236769Sobrien * to finish. 1791236769Sobrien * 1792236769Sobrien * Results: 1793236769Sobrien * None 1794236769Sobrien * 1795236769Sobrien * Side Effects: 1796236769Sobrien * The program exits 1797236769Sobrien */ 1798236769Sobrien/* VARARGS */ 1799236769Sobrienvoid 1800236769SobrienFatal(const char *fmt, ...) 1801236769Sobrien{ 1802236769Sobrien va_list ap; 1803236769Sobrien 1804236769Sobrien va_start(ap, fmt); 1805236769Sobrien if (jobsRunning) 1806236769Sobrien Job_Wait(); 1807236769Sobrien 1808236769Sobrien (void)fflush(stdout); 1809236769Sobrien (void)vfprintf(stderr, fmt, ap); 1810236769Sobrien va_end(ap); 1811236769Sobrien (void)fprintf(stderr, "\n"); 1812236769Sobrien (void)fflush(stderr); 1813236769Sobrien 1814236769Sobrien PrintOnError(NULL, NULL); 1815236769Sobrien 1816236769Sobrien if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1817236769Sobrien Targ_PrintGraph(2); 1818236769Sobrien Trace_Log(MAKEERROR, 0); 1819236769Sobrien exit(2); /* Not 1 so -q can distinguish error */ 1820236769Sobrien} 1821236769Sobrien 1822236769Sobrien/* 1823236769Sobrien * Punt -- 1824236769Sobrien * Major exception once jobs are being created. Kills all jobs, prints 1825236769Sobrien * a message and exits. 1826236769Sobrien * 1827236769Sobrien * Results: 1828236769Sobrien * None 1829236769Sobrien * 1830236769Sobrien * Side Effects: 1831236769Sobrien * All children are killed indiscriminately and the program Lib_Exits 1832236769Sobrien */ 1833236769Sobrien/* VARARGS */ 1834236769Sobrienvoid 1835236769SobrienPunt(const char *fmt, ...) 1836236769Sobrien{ 1837236769Sobrien va_list ap; 1838236769Sobrien 1839236769Sobrien va_start(ap, fmt); 1840236769Sobrien (void)fflush(stdout); 1841236769Sobrien (void)fprintf(stderr, "%s: ", progname); 1842236769Sobrien (void)vfprintf(stderr, fmt, ap); 1843236769Sobrien va_end(ap); 1844236769Sobrien (void)fprintf(stderr, "\n"); 1845236769Sobrien (void)fflush(stderr); 1846236769Sobrien 1847236769Sobrien PrintOnError(NULL, NULL); 1848236769Sobrien 1849236769Sobrien DieHorribly(); 1850236769Sobrien} 1851236769Sobrien 1852236769Sobrien/*- 1853236769Sobrien * DieHorribly -- 1854236769Sobrien * Exit without giving a message. 1855236769Sobrien * 1856236769Sobrien * Results: 1857236769Sobrien * None 1858236769Sobrien * 1859236769Sobrien * Side Effects: 1860236769Sobrien * A big one... 1861236769Sobrien */ 1862236769Sobrienvoid 1863236769SobrienDieHorribly(void) 1864236769Sobrien{ 1865236769Sobrien if (jobsRunning) 1866236769Sobrien Job_AbortAll(); 1867236769Sobrien if (DEBUG(GRAPH2)) 1868236769Sobrien Targ_PrintGraph(2); 1869236769Sobrien Trace_Log(MAKEERROR, 0); 1870236769Sobrien exit(2); /* Not 1, so -q can distinguish error */ 1871236769Sobrien} 1872236769Sobrien 1873236769Sobrien/* 1874236769Sobrien * Finish -- 1875236769Sobrien * Called when aborting due to errors in child shell to signal 1876236769Sobrien * abnormal exit. 1877236769Sobrien * 1878236769Sobrien * Results: 1879236769Sobrien * None 1880236769Sobrien * 1881236769Sobrien * Side Effects: 1882236769Sobrien * The program exits 1883236769Sobrien */ 1884236769Sobrienvoid 1885236769SobrienFinish(int errors) 1886236769Sobrien /* number of errors encountered in Make_Make */ 1887236769Sobrien{ 1888236769Sobrien Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1889236769Sobrien} 1890236769Sobrien 1891236769Sobrien/* 1892236769Sobrien * enunlink -- 1893236769Sobrien * Remove a file carefully, avoiding directories. 1894236769Sobrien */ 1895236769Sobrienint 1896236769Sobrieneunlink(const char *file) 1897236769Sobrien{ 1898236769Sobrien struct stat st; 1899236769Sobrien 1900236769Sobrien if (lstat(file, &st) == -1) 1901236769Sobrien return -1; 1902236769Sobrien 1903236769Sobrien if (S_ISDIR(st.st_mode)) { 1904236769Sobrien errno = EISDIR; 1905236769Sobrien return -1; 1906236769Sobrien } 1907236769Sobrien return unlink(file); 1908236769Sobrien} 1909236769Sobrien 1910236769Sobrien/* 1911236769Sobrien * execError -- 1912236769Sobrien * Print why exec failed, avoiding stdio. 1913236769Sobrien */ 1914236769Sobrienvoid 1915236769SobrienexecError(const char *af, const char *av) 1916236769Sobrien{ 1917236769Sobrien#ifdef USE_IOVEC 1918236769Sobrien int i = 0; 1919236769Sobrien struct iovec iov[8]; 1920236769Sobrien#define IOADD(s) \ 1921236769Sobrien (void)(iov[i].iov_base = UNCONST(s), \ 1922236769Sobrien iov[i].iov_len = strlen(iov[i].iov_base), \ 1923236769Sobrien i++) 1924236769Sobrien#else 1925236769Sobrien#define IOADD(s) (void)write(2, s, strlen(s)) 1926236769Sobrien#endif 1927236769Sobrien 1928236769Sobrien IOADD(progname); 1929236769Sobrien IOADD(": "); 1930236769Sobrien IOADD(af); 1931236769Sobrien IOADD("("); 1932236769Sobrien IOADD(av); 1933236769Sobrien IOADD(") failed ("); 1934236769Sobrien IOADD(strerror(errno)); 1935236769Sobrien IOADD(")\n"); 1936236769Sobrien 1937236769Sobrien#ifdef USE_IOVEC 1938236769Sobrien (void)writev(2, iov, 8); 1939236769Sobrien#endif 1940236769Sobrien} 1941236769Sobrien 1942236769Sobrien/* 1943236769Sobrien * usage -- 1944236769Sobrien * exit with usage message 1945236769Sobrien */ 1946236769Sobrienstatic void 1947236769Sobrienusage(void) 1948236769Sobrien{ 1949236769Sobrien (void)fprintf(stderr, 1950236769Sobrien"usage: %s [-BeikNnqrstWX] \n\ 1951236769Sobrien [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 1952236769Sobrien [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1953236769Sobrien [-V variable] [variable=value] [target ...]\n", progname); 1954236769Sobrien exit(2); 1955236769Sobrien} 1956236769Sobrien 1957236769Sobrien 1958236769Sobrienint 1959236769SobrienPrintAddr(void *a, void *b) 1960236769Sobrien{ 1961236769Sobrien printf("%lx ", (unsigned long) a); 1962236769Sobrien return b ? 0 : 0; 1963236769Sobrien} 1964236769Sobrien 1965236769Sobrien 1966236769Sobrien 1967236769Sobrienvoid 1968236769SobrienPrintOnError(GNode *gn, const char *s) 1969236769Sobrien{ 1970236769Sobrien static GNode *en = NULL; 1971236769Sobrien char tmp[64]; 1972236769Sobrien char *cp; 1973236769Sobrien 1974236769Sobrien if (s) 1975236769Sobrien printf("%s", s); 1976236769Sobrien 1977236769Sobrien printf("\n%s: stopped in %s\n", progname, curdir); 1978236769Sobrien 1979236769Sobrien if (en) 1980236769Sobrien return; /* we've been here! */ 1981236769Sobrien if (gn) { 1982236769Sobrien /* 1983236769Sobrien * We can print this even if there is no .ERROR target. 1984236769Sobrien */ 1985236769Sobrien Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 1986236769Sobrien } 1987236769Sobrien strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 1988236769Sobrien sizeof(tmp) - 1); 1989236769Sobrien cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1990236769Sobrien if (cp) { 1991236769Sobrien if (*cp) 1992236769Sobrien printf("%s", cp); 1993236769Sobrien free(cp); 1994236769Sobrien } 1995236769Sobrien /* 1996236769Sobrien * Finally, see if there is a .ERROR target, and run it if so. 1997236769Sobrien */ 1998236769Sobrien en = Targ_FindNode(".ERROR", TARG_NOCREATE); 1999236769Sobrien if (en) { 2000236769Sobrien en->type |= OP_SPECIAL; 2001236769Sobrien Compat_Make(en, en); 2002236769Sobrien } 2003236769Sobrien} 2004236769Sobrien 2005236769Sobrienvoid 2006236769SobrienMain_ExportMAKEFLAGS(Boolean first) 2007236769Sobrien{ 2008236769Sobrien static int once = 1; 2009236769Sobrien char tmp[64]; 2010236769Sobrien char *s; 2011236769Sobrien 2012236769Sobrien if (once != first) 2013236769Sobrien return; 2014236769Sobrien once = 0; 2015236769Sobrien 2016236769Sobrien strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 2017236769Sobrien sizeof(tmp)); 2018236769Sobrien s = Var_Subst(NULL, tmp, VAR_CMD, 0); 2019236769Sobrien if (s && *s) { 2020236769Sobrien#ifdef POSIX 2021236769Sobrien setenv("MAKEFLAGS", s, 1); 2022236769Sobrien#else 2023236769Sobrien setenv("MAKE", s, 1); 2024236769Sobrien#endif 2025236769Sobrien } 2026236769Sobrien} 2027236769Sobrien 2028236769Sobrienchar * 2029236769SobriengetTmpdir(void) 2030236769Sobrien{ 2031236769Sobrien static char *tmpdir = NULL; 2032236769Sobrien 2033236769Sobrien if (!tmpdir) { 2034236769Sobrien struct stat st; 2035236769Sobrien 2036236769Sobrien /* 2037236769Sobrien * Honor $TMPDIR but only if it is valid. 2038236769Sobrien * Ensure it ends with /. 2039236769Sobrien */ 2040236769Sobrien tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 0); 2041236769Sobrien if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2042236769Sobrien free(tmpdir); 2043236769Sobrien tmpdir = bmake_strdup(_PATH_TMP); 2044236769Sobrien } 2045236769Sobrien } 2046236769Sobrien return tmpdir; 2047236769Sobrien} 2048236769Sobrien 2049236769Sobrien/* 2050236769Sobrien * Create and open a temp file using "pattern". 2051236769Sobrien * If "fnamep" is provided set it to a copy of the filename created. 2052236769Sobrien * Otherwise unlink the file once open. 2053236769Sobrien */ 2054236769Sobrienint 2055236769SobrienmkTempFile(const char *pattern, char **fnamep) 2056236769Sobrien{ 2057236769Sobrien static char *tmpdir = NULL; 2058236769Sobrien char tfile[MAXPATHLEN]; 2059236769Sobrien int fd; 2060236769Sobrien 2061236769Sobrien if (!pattern) 2062236769Sobrien pattern = TMPPAT; 2063236769Sobrien if (!tmpdir) 2064236769Sobrien tmpdir = getTmpdir(); 2065236769Sobrien if (pattern[0] == '/') { 2066236769Sobrien snprintf(tfile, sizeof(tfile), "%s", pattern); 2067236769Sobrien } else { 2068236769Sobrien snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2069236769Sobrien } 2070236769Sobrien if ((fd = mkstemp(tfile)) < 0) 2071236769Sobrien Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2072236769Sobrien if (fnamep) { 2073236769Sobrien *fnamep = bmake_strdup(tfile); 2074236769Sobrien } else { 2075236769Sobrien unlink(tfile); /* we just want the descriptor */ 2076236769Sobrien } 2077236769Sobrien return fd; 2078236769Sobrien} 2079