main.c revision 281812
1281812Ssjg/* $NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg 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 72281812Ssjgstatic char rcsid[] = "$NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg 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 84281812Ssjg__RCSID("$NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg 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 102281812Ssjg * takes a format string and optional arguments 103281812Ssjg * for it. 104236769Sobrien * 105236769Sobrien * Fatal Print an error message and exit. Also takes 106281812Ssjg * a format string and arguments for it. 107236769Sobrien * 108236769Sobrien * Punt Aborts all jobs and exits with a message. Also 109281812Ssjg * takes a format string and arguments for it. 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 <sys/stat.h> 121261212Ssjg#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 122261212Ssjg#include <sys/sysctl.h> 123261212Ssjg#endif 124236769Sobrien#include <sys/utsname.h> 125236769Sobrien#include "wait.h" 126236769Sobrien 127236769Sobrien#include <errno.h> 128236769Sobrien#include <fcntl.h> 129253883Ssjg#include <signal.h> 130236769Sobrien#include <stdarg.h> 131236769Sobrien#include <stdio.h> 132236769Sobrien#include <stdlib.h> 133236769Sobrien#include <time.h> 134253883Ssjg#include <ctype.h> 135236769Sobrien 136236769Sobrien#include "make.h" 137236769Sobrien#include "hash.h" 138236769Sobrien#include "dir.h" 139236769Sobrien#include "job.h" 140236769Sobrien#include "pathnames.h" 141236769Sobrien#include "trace.h" 142236769Sobrien 143236769Sobrien#ifdef USE_IOVEC 144236769Sobrien#include <sys/uio.h> 145236769Sobrien#endif 146236769Sobrien 147236769Sobrien#ifndef DEFMAXLOCAL 148236769Sobrien#define DEFMAXLOCAL DEFMAXJOBS 149236769Sobrien#endif /* DEFMAXLOCAL */ 150236769Sobrien 151261212Ssjg#ifndef __arraycount 152261212Ssjg# define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 153261212Ssjg#endif 154261212Ssjg 155236769SobrienLst create; /* Targets to be made */ 156236769Sobrientime_t now; /* Time at start of make */ 157236769SobrienGNode *DEFAULT; /* .DEFAULT node */ 158236769SobrienBoolean allPrecious; /* .PRECIOUS given on line by itself */ 159236769Sobrien 160236769Sobrienstatic Boolean noBuiltins; /* -r flag */ 161236769Sobrienstatic Lst makefiles; /* ordered list of makefiles to read */ 162236769Sobrienstatic Boolean printVars; /* print value of one or more vars */ 163236769Sobrienstatic Lst variables; /* list of variables to print */ 164236769Sobrienint maxJobs; /* -j argument */ 165236769Sobrienstatic int maxJobTokens; /* -j argument */ 166236769SobrienBoolean compatMake; /* -B argument */ 167236769Sobrienint debug; /* -d argument */ 168240330SmarcelBoolean debugVflag; /* -dV */ 169236769SobrienBoolean noExecute; /* -n flag */ 170236769SobrienBoolean noRecursiveExecute; /* -N flag */ 171236769SobrienBoolean keepgoing; /* -k flag */ 172236769SobrienBoolean queryFlag; /* -q flag */ 173236769SobrienBoolean touchFlag; /* -t flag */ 174253883SsjgBoolean enterFlag; /* -w flag */ 175236769SobrienBoolean ignoreErrors; /* -i flag */ 176236769SobrienBoolean beSilent; /* -s flag */ 177236769SobrienBoolean oldVars; /* variable substitution style */ 178236769SobrienBoolean checkEnvFirst; /* -e flag */ 179236769SobrienBoolean parseWarnFatal; /* -W flag */ 180236769SobrienBoolean jobServer; /* -J flag */ 181236769Sobrienstatic int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 182236769SobrienBoolean varNoExportEnv; /* -X flag */ 183236769SobrienBoolean doing_depend; /* Set while reading .depend */ 184236769Sobrienstatic Boolean jobsRunning; /* TRUE if the jobs might be running */ 185236769Sobrienstatic const char * tracefile; 186236769Sobrienstatic void MainParseArgs(int, char **); 187236769Sobrienstatic int ReadMakefile(const void *, const void *); 188237578Sobrienstatic void usage(void) MAKE_ATTR_DEAD; 189236769Sobrien 190236769Sobrienstatic Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 191236769Sobrienstatic char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 192236769Sobrienchar curdir[MAXPATHLEN + 1]; /* Startup directory */ 193236769Sobrienchar *progname; /* the program name */ 194236769Sobrienchar *makeDependfile; 195236769Sobrienpid_t myPid; 196253883Ssjgint makelevel; 197236769Sobrien 198236769SobrienBoolean forceJobs = FALSE; 199236769Sobrien 200236769Sobrien/* 201236769Sobrien * On some systems MACHINE is defined as something other than 202236769Sobrien * what we want. 203236769Sobrien */ 204236769Sobrien#ifdef FORCE_MACHINE 205236769Sobrien# undef MACHINE 206236769Sobrien# define MACHINE FORCE_MACHINE 207236769Sobrien#endif 208236769Sobrien 209236769Sobrienextern Lst parseIncPath; 210236769Sobrien 211253883Ssjg/* 212253883Ssjg * For compatibility with the POSIX version of MAKEFLAGS that includes 213253883Ssjg * all the options with out -, convert flags to -f -l -a -g -s. 214253883Ssjg */ 215253883Ssjgstatic char * 216253883Ssjgexplode(const char *flags) 217253883Ssjg{ 218253883Ssjg size_t len; 219253883Ssjg char *nf, *st; 220253883Ssjg const char *f; 221253883Ssjg 222253883Ssjg if (flags == NULL) 223253883Ssjg return NULL; 224253883Ssjg 225253883Ssjg for (f = flags; *f; f++) 226253883Ssjg if (!isalpha((unsigned char)*f)) 227253883Ssjg break; 228253883Ssjg 229253883Ssjg if (*f) 230253883Ssjg return bmake_strdup(flags); 231253883Ssjg 232253883Ssjg len = strlen(flags); 233253883Ssjg st = nf = bmake_malloc(len * 3 + 1); 234253883Ssjg while (*flags) { 235253883Ssjg *nf++ = '-'; 236253883Ssjg *nf++ = *flags++; 237253883Ssjg *nf++ = ' '; 238253883Ssjg } 239253883Ssjg *nf = '\0'; 240253883Ssjg return st; 241253883Ssjg} 242253883Ssjg 243236769Sobrienstatic void 244236769Sobrienparse_debug_options(const char *argvalue) 245236769Sobrien{ 246236769Sobrien const char *modules; 247236769Sobrien const char *mode; 248236769Sobrien char *fname; 249236769Sobrien int len; 250236769Sobrien 251236769Sobrien for (modules = argvalue; *modules; ++modules) { 252236769Sobrien switch (*modules) { 253236769Sobrien case 'A': 254236769Sobrien debug = ~0; 255236769Sobrien break; 256236769Sobrien case 'a': 257236769Sobrien debug |= DEBUG_ARCH; 258236769Sobrien break; 259236769Sobrien case 'C': 260236769Sobrien debug |= DEBUG_CWD; 261236769Sobrien break; 262236769Sobrien case 'c': 263236769Sobrien debug |= DEBUG_COND; 264236769Sobrien break; 265236769Sobrien case 'd': 266236769Sobrien debug |= DEBUG_DIR; 267236769Sobrien break; 268236769Sobrien case 'e': 269236769Sobrien debug |= DEBUG_ERROR; 270236769Sobrien break; 271236769Sobrien case 'f': 272236769Sobrien debug |= DEBUG_FOR; 273236769Sobrien break; 274236769Sobrien case 'g': 275236769Sobrien if (modules[1] == '1') { 276236769Sobrien debug |= DEBUG_GRAPH1; 277236769Sobrien ++modules; 278236769Sobrien } 279236769Sobrien else if (modules[1] == '2') { 280236769Sobrien debug |= DEBUG_GRAPH2; 281236769Sobrien ++modules; 282236769Sobrien } 283236769Sobrien else if (modules[1] == '3') { 284236769Sobrien debug |= DEBUG_GRAPH3; 285236769Sobrien ++modules; 286236769Sobrien } 287236769Sobrien break; 288236769Sobrien case 'j': 289236769Sobrien debug |= DEBUG_JOB; 290236769Sobrien break; 291236769Sobrien case 'l': 292236769Sobrien debug |= DEBUG_LOUD; 293236769Sobrien break; 294236769Sobrien case 'M': 295236769Sobrien debug |= DEBUG_META; 296236769Sobrien break; 297236769Sobrien case 'm': 298236769Sobrien debug |= DEBUG_MAKE; 299236769Sobrien break; 300236769Sobrien case 'n': 301236769Sobrien debug |= DEBUG_SCRIPT; 302236769Sobrien break; 303236769Sobrien case 'p': 304236769Sobrien debug |= DEBUG_PARSE; 305236769Sobrien break; 306236769Sobrien case 's': 307236769Sobrien debug |= DEBUG_SUFF; 308236769Sobrien break; 309236769Sobrien case 't': 310236769Sobrien debug |= DEBUG_TARG; 311236769Sobrien break; 312240330Smarcel case 'V': 313240330Smarcel debugVflag = TRUE; 314240330Smarcel break; 315236769Sobrien case 'v': 316236769Sobrien debug |= DEBUG_VAR; 317236769Sobrien break; 318236769Sobrien case 'x': 319236769Sobrien debug |= DEBUG_SHELL; 320236769Sobrien break; 321236769Sobrien case 'F': 322236769Sobrien if (debug_file != stdout && debug_file != stderr) 323236769Sobrien fclose(debug_file); 324236769Sobrien if (*++modules == '+') { 325236769Sobrien modules++; 326236769Sobrien mode = "a"; 327236769Sobrien } else 328236769Sobrien mode = "w"; 329236769Sobrien if (strcmp(modules, "stdout") == 0) { 330236769Sobrien debug_file = stdout; 331236769Sobrien goto debug_setbuf; 332236769Sobrien } 333236769Sobrien if (strcmp(modules, "stderr") == 0) { 334236769Sobrien debug_file = stderr; 335236769Sobrien goto debug_setbuf; 336236769Sobrien } 337236769Sobrien len = strlen(modules); 338236769Sobrien fname = malloc(len + 20); 339236769Sobrien memcpy(fname, modules, len + 1); 340236769Sobrien /* Let the filename be modified by the pid */ 341236769Sobrien if (strcmp(fname + len - 3, ".%d") == 0) 342236769Sobrien snprintf(fname + len - 2, 20, "%d", getpid()); 343236769Sobrien debug_file = fopen(fname, mode); 344236769Sobrien if (!debug_file) { 345236769Sobrien fprintf(stderr, "Cannot open debug file %s\n", 346236769Sobrien fname); 347236769Sobrien usage(); 348236769Sobrien } 349236769Sobrien free(fname); 350236769Sobrien goto debug_setbuf; 351236769Sobrien default: 352236769Sobrien (void)fprintf(stderr, 353236769Sobrien "%s: illegal argument to d option -- %c\n", 354236769Sobrien progname, *modules); 355236769Sobrien usage(); 356236769Sobrien } 357236769Sobrien } 358236769Sobriendebug_setbuf: 359236769Sobrien /* 360236769Sobrien * Make the debug_file unbuffered, and make 361236769Sobrien * stdout line buffered (unless debugfile == stdout). 362236769Sobrien */ 363236769Sobrien setvbuf(debug_file, NULL, _IONBF, 0); 364236769Sobrien if (debug_file != stdout) { 365236769Sobrien setvbuf(stdout, NULL, _IOLBF, 0); 366236769Sobrien } 367236769Sobrien} 368236769Sobrien 369236769Sobrien/*- 370236769Sobrien * MainParseArgs -- 371236769Sobrien * Parse a given argument vector. Called from main() and from 372236769Sobrien * Main_ParseArgLine() when the .MAKEFLAGS target is used. 373236769Sobrien * 374236769Sobrien * XXX: Deal with command line overriding .MAKEFLAGS in makefile 375236769Sobrien * 376236769Sobrien * Results: 377236769Sobrien * None 378236769Sobrien * 379236769Sobrien * Side Effects: 380236769Sobrien * Various global and local flags will be set depending on the flags 381236769Sobrien * given 382236769Sobrien */ 383236769Sobrienstatic void 384236769SobrienMainParseArgs(int argc, char **argv) 385236769Sobrien{ 386236769Sobrien char *p; 387236769Sobrien int c = '?'; 388236769Sobrien int arginc; 389236769Sobrien char *argvalue; 390236769Sobrien const char *getopt_def; 391236769Sobrien char *optscan; 392236769Sobrien Boolean inOption, dashDash = FALSE; 393236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 394236769Sobrien 395253883Ssjg#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstw" 396236769Sobrien/* Can't actually use getopt(3) because rescanning is not portable */ 397236769Sobrien 398236769Sobrien getopt_def = OPTFLAGS; 399236769Sobrienrearg: 400236769Sobrien inOption = FALSE; 401236769Sobrien optscan = NULL; 402236769Sobrien while(argc > 1) { 403236769Sobrien char *getopt_spec; 404236769Sobrien if(!inOption) 405236769Sobrien optscan = argv[1]; 406236769Sobrien c = *optscan++; 407236769Sobrien arginc = 0; 408236769Sobrien if(inOption) { 409236769Sobrien if(c == '\0') { 410236769Sobrien ++argv; 411236769Sobrien --argc; 412236769Sobrien inOption = FALSE; 413236769Sobrien continue; 414236769Sobrien } 415236769Sobrien } else { 416236769Sobrien if (c != '-' || dashDash) 417236769Sobrien break; 418236769Sobrien inOption = TRUE; 419236769Sobrien c = *optscan++; 420236769Sobrien } 421236769Sobrien /* '-' found at some earlier point */ 422236769Sobrien getopt_spec = strchr(getopt_def, c); 423236769Sobrien if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 424236769Sobrien /* -<something> found, and <something> should have an arg */ 425236769Sobrien inOption = FALSE; 426236769Sobrien arginc = 1; 427236769Sobrien argvalue = optscan; 428236769Sobrien if(*argvalue == '\0') { 429236769Sobrien if (argc < 3) 430236769Sobrien goto noarg; 431236769Sobrien argvalue = argv[2]; 432236769Sobrien arginc = 2; 433236769Sobrien } 434236769Sobrien } else { 435236769Sobrien argvalue = NULL; 436236769Sobrien } 437236769Sobrien switch(c) { 438236769Sobrien case '\0': 439236769Sobrien arginc = 1; 440236769Sobrien inOption = FALSE; 441236769Sobrien break; 442236769Sobrien case 'B': 443236769Sobrien compatMake = TRUE; 444236769Sobrien Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 445236769Sobrien Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 446236769Sobrien break; 447236769Sobrien case 'C': 448236769Sobrien if (chdir(argvalue) == -1) { 449236769Sobrien (void)fprintf(stderr, 450236769Sobrien "%s: chdir %s: %s\n", 451236769Sobrien progname, argvalue, 452236769Sobrien strerror(errno)); 453236769Sobrien exit(1); 454236769Sobrien } 455236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 456236769Sobrien (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 457236769Sobrien exit(2); 458236769Sobrien } 459236769Sobrien ignorePWD = TRUE; 460236769Sobrien break; 461236769Sobrien case 'D': 462236769Sobrien if (argvalue == NULL || argvalue[0] == 0) goto noarg; 463236769Sobrien Var_Set(argvalue, "1", VAR_GLOBAL, 0); 464236769Sobrien Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 465236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 466236769Sobrien break; 467236769Sobrien case 'I': 468236769Sobrien if (argvalue == NULL) goto noarg; 469236769Sobrien Parse_AddIncludeDir(argvalue); 470236769Sobrien Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 471236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 472236769Sobrien break; 473236769Sobrien case 'J': 474236769Sobrien if (argvalue == NULL) goto noarg; 475236769Sobrien if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 476236769Sobrien (void)fprintf(stderr, 477236769Sobrien "%s: internal error -- J option malformed (%s)\n", 478236769Sobrien progname, argvalue); 479236769Sobrien usage(); 480236769Sobrien } 481236769Sobrien if ((fcntl(jp_0, F_GETFD, 0) < 0) || 482236769Sobrien (fcntl(jp_1, F_GETFD, 0) < 0)) { 483236769Sobrien#if 0 484236769Sobrien (void)fprintf(stderr, 485236769Sobrien "%s: ###### warning -- J descriptors were closed!\n", 486236769Sobrien progname); 487236769Sobrien exit(2); 488236769Sobrien#endif 489236769Sobrien jp_0 = -1; 490236769Sobrien jp_1 = -1; 491236769Sobrien compatMake = TRUE; 492236769Sobrien } else { 493236769Sobrien Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 494236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 495236769Sobrien jobServer = TRUE; 496236769Sobrien } 497236769Sobrien break; 498236769Sobrien case 'N': 499236769Sobrien noExecute = TRUE; 500236769Sobrien noRecursiveExecute = TRUE; 501236769Sobrien Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 502236769Sobrien break; 503236769Sobrien case 'S': 504236769Sobrien keepgoing = FALSE; 505236769Sobrien Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 506236769Sobrien break; 507236769Sobrien case 'T': 508236769Sobrien if (argvalue == NULL) goto noarg; 509236769Sobrien tracefile = bmake_strdup(argvalue); 510236769Sobrien Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 511236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 512236769Sobrien break; 513236769Sobrien case 'V': 514236769Sobrien if (argvalue == NULL) goto noarg; 515236769Sobrien printVars = TRUE; 516236769Sobrien (void)Lst_AtEnd(variables, argvalue); 517236769Sobrien Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 518236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 519236769Sobrien break; 520236769Sobrien case 'W': 521236769Sobrien parseWarnFatal = TRUE; 522236769Sobrien break; 523236769Sobrien case 'X': 524236769Sobrien varNoExportEnv = TRUE; 525236769Sobrien Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 526236769Sobrien break; 527236769Sobrien case 'd': 528236769Sobrien if (argvalue == NULL) goto noarg; 529236769Sobrien /* If '-d-opts' don't pass to children */ 530236769Sobrien if (argvalue[0] == '-') 531236769Sobrien argvalue++; 532236769Sobrien else { 533236769Sobrien Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 534236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 535236769Sobrien } 536236769Sobrien parse_debug_options(argvalue); 537236769Sobrien break; 538236769Sobrien case 'e': 539236769Sobrien checkEnvFirst = TRUE; 540236769Sobrien Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 541236769Sobrien break; 542236769Sobrien case 'f': 543236769Sobrien if (argvalue == NULL) goto noarg; 544236769Sobrien (void)Lst_AtEnd(makefiles, argvalue); 545236769Sobrien break; 546236769Sobrien case 'i': 547236769Sobrien ignoreErrors = TRUE; 548236769Sobrien Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 549236769Sobrien break; 550236769Sobrien case 'j': 551236769Sobrien if (argvalue == NULL) goto noarg; 552236769Sobrien forceJobs = TRUE; 553236769Sobrien maxJobs = strtol(argvalue, &p, 0); 554236769Sobrien if (*p != '\0' || maxJobs < 1) { 555236769Sobrien (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 556236769Sobrien progname); 557236769Sobrien exit(1); 558236769Sobrien } 559236769Sobrien Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 560236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 561236769Sobrien Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 562236769Sobrien maxJobTokens = maxJobs; 563236769Sobrien break; 564236769Sobrien case 'k': 565236769Sobrien keepgoing = TRUE; 566236769Sobrien Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 567236769Sobrien break; 568236769Sobrien case 'm': 569236769Sobrien if (argvalue == NULL) goto noarg; 570236769Sobrien /* look for magic parent directory search string */ 571236769Sobrien if (strncmp(".../", argvalue, 4) == 0) { 572236769Sobrien if (!Dir_FindHereOrAbove(curdir, argvalue+4, 573236769Sobrien found_path, sizeof(found_path))) 574236769Sobrien break; /* nothing doing */ 575236769Sobrien (void)Dir_AddDir(sysIncPath, found_path); 576236769Sobrien } else { 577236769Sobrien (void)Dir_AddDir(sysIncPath, argvalue); 578236769Sobrien } 579236769Sobrien Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 580236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 581236769Sobrien break; 582236769Sobrien case 'n': 583236769Sobrien noExecute = TRUE; 584236769Sobrien Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 585236769Sobrien break; 586236769Sobrien case 'q': 587236769Sobrien queryFlag = TRUE; 588236769Sobrien /* Kind of nonsensical, wot? */ 589236769Sobrien Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 590236769Sobrien break; 591236769Sobrien case 'r': 592236769Sobrien noBuiltins = TRUE; 593236769Sobrien Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 594236769Sobrien break; 595236769Sobrien case 's': 596236769Sobrien beSilent = TRUE; 597236769Sobrien Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 598236769Sobrien break; 599236769Sobrien case 't': 600236769Sobrien touchFlag = TRUE; 601236769Sobrien Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 602236769Sobrien break; 603253883Ssjg case 'w': 604253883Ssjg enterFlag = TRUE; 605253883Ssjg Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 606253883Ssjg break; 607236769Sobrien case '-': 608236769Sobrien dashDash = TRUE; 609236769Sobrien break; 610236769Sobrien default: 611236769Sobrien case '?': 612236769Sobrien#ifndef MAKE_NATIVE 613236769Sobrien fprintf(stderr, "getopt(%s) -> %d (%c)\n", 614236769Sobrien OPTFLAGS, c, c); 615236769Sobrien#endif 616236769Sobrien usage(); 617236769Sobrien } 618236769Sobrien argv += arginc; 619236769Sobrien argc -= arginc; 620236769Sobrien } 621236769Sobrien 622236769Sobrien oldVars = TRUE; 623236769Sobrien 624236769Sobrien /* 625236769Sobrien * See if the rest of the arguments are variable assignments and 626236769Sobrien * perform them if so. Else take them to be targets and stuff them 627236769Sobrien * on the end of the "create" list. 628236769Sobrien */ 629236769Sobrien for (; argc > 1; ++argv, --argc) 630236769Sobrien if (Parse_IsVar(argv[1])) { 631236769Sobrien Parse_DoVar(argv[1], VAR_CMD); 632236769Sobrien } else { 633236769Sobrien if (!*argv[1]) 634236769Sobrien Punt("illegal (null) argument."); 635236769Sobrien if (*argv[1] == '-' && !dashDash) 636236769Sobrien goto rearg; 637236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 638236769Sobrien } 639236769Sobrien 640236769Sobrien return; 641236769Sobriennoarg: 642236769Sobrien (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 643236769Sobrien progname, c); 644236769Sobrien usage(); 645236769Sobrien} 646236769Sobrien 647236769Sobrien/*- 648236769Sobrien * Main_ParseArgLine -- 649236769Sobrien * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 650236769Sobrien * is encountered and by main() when reading the .MAKEFLAGS envariable. 651236769Sobrien * Takes a line of arguments and breaks it into its 652236769Sobrien * component words and passes those words and the number of them to the 653236769Sobrien * MainParseArgs function. 654236769Sobrien * The line should have all its leading whitespace removed. 655236769Sobrien * 656236769Sobrien * Input: 657236769Sobrien * line Line to fracture 658236769Sobrien * 659236769Sobrien * Results: 660236769Sobrien * None 661236769Sobrien * 662236769Sobrien * Side Effects: 663236769Sobrien * Only those that come from the various arguments. 664236769Sobrien */ 665236769Sobrienvoid 666236769SobrienMain_ParseArgLine(const char *line) 667236769Sobrien{ 668236769Sobrien char **argv; /* Manufactured argument vector */ 669236769Sobrien int argc; /* Number of arguments in argv */ 670236769Sobrien char *args; /* Space used by the args */ 671236769Sobrien char *buf, *p1; 672236769Sobrien char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 673236769Sobrien size_t len; 674236769Sobrien 675236769Sobrien if (line == NULL) 676236769Sobrien return; 677236769Sobrien for (; *line == ' '; ++line) 678236769Sobrien continue; 679236769Sobrien if (!*line) 680236769Sobrien return; 681236769Sobrien 682236769Sobrien#ifndef POSIX 683236769Sobrien { 684236769Sobrien /* 685236769Sobrien * $MAKE may simply be naming the make(1) binary 686236769Sobrien */ 687236769Sobrien char *cp; 688236769Sobrien 689236769Sobrien if (!(cp = strrchr(line, '/'))) 690236769Sobrien cp = line; 691236769Sobrien if ((cp = strstr(cp, "make")) && 692236769Sobrien strcmp(cp, "make") == 0) 693236769Sobrien return; 694236769Sobrien } 695236769Sobrien#endif 696236769Sobrien buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 697236769Sobrien (void)snprintf(buf, len, "%s %s", argv0, line); 698236769Sobrien if (p1) 699236769Sobrien free(p1); 700236769Sobrien 701236769Sobrien argv = brk_string(buf, &argc, TRUE, &args); 702236769Sobrien if (argv == NULL) { 703236769Sobrien Error("Unterminated quoted string [%s]", buf); 704236769Sobrien free(buf); 705236769Sobrien return; 706236769Sobrien } 707236769Sobrien free(buf); 708236769Sobrien MainParseArgs(argc, argv); 709236769Sobrien 710236769Sobrien free(args); 711236769Sobrien free(argv); 712236769Sobrien} 713236769Sobrien 714236769SobrienBoolean 715236769SobrienMain_SetObjdir(const char *path) 716236769Sobrien{ 717236769Sobrien struct stat sb; 718236769Sobrien char *p = NULL; 719236769Sobrien char buf[MAXPATHLEN + 1]; 720236769Sobrien Boolean rc = FALSE; 721236769Sobrien 722236769Sobrien /* expand variable substitutions */ 723236769Sobrien if (strchr(path, '$') != 0) { 724236769Sobrien snprintf(buf, MAXPATHLEN, "%s", path); 725236769Sobrien path = p = Var_Subst(NULL, buf, VAR_GLOBAL, 0); 726236769Sobrien } 727236769Sobrien 728236769Sobrien if (path[0] != '/') { 729236769Sobrien snprintf(buf, MAXPATHLEN, "%s/%s", curdir, path); 730236769Sobrien path = buf; 731236769Sobrien } 732236769Sobrien 733236769Sobrien /* look for the directory and try to chdir there */ 734236769Sobrien if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 735236769Sobrien if (chdir(path)) { 736236769Sobrien (void)fprintf(stderr, "make warning: %s: %s.\n", 737236769Sobrien path, strerror(errno)); 738236769Sobrien } else { 739236769Sobrien strncpy(objdir, path, MAXPATHLEN); 740236769Sobrien Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 741236769Sobrien setenv("PWD", objdir, 1); 742236769Sobrien Dir_InitDot(); 743236769Sobrien rc = TRUE; 744236769Sobrien } 745236769Sobrien } 746236769Sobrien 747236769Sobrien if (p) 748236769Sobrien free(p); 749236769Sobrien return rc; 750236769Sobrien} 751236769Sobrien 752236769Sobrien/*- 753236769Sobrien * ReadAllMakefiles -- 754236769Sobrien * wrapper around ReadMakefile() to read all. 755236769Sobrien * 756236769Sobrien * Results: 757236769Sobrien * TRUE if ok, FALSE on error 758236769Sobrien */ 759236769Sobrienstatic int 760236769SobrienReadAllMakefiles(const void *p, const void *q) 761236769Sobrien{ 762236769Sobrien return (ReadMakefile(p, q) == 0); 763236769Sobrien} 764236769Sobrien 765236769Sobrienint 766236769Sobrienstr2Lst_Append(Lst lp, char *str, const char *sep) 767236769Sobrien{ 768236769Sobrien char *cp; 769236769Sobrien int n; 770236769Sobrien 771236769Sobrien if (!sep) 772236769Sobrien sep = " \t"; 773236769Sobrien 774236769Sobrien for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 775236769Sobrien (void)Lst_AtEnd(lp, cp); 776236769Sobrien n++; 777236769Sobrien } 778236769Sobrien return (n); 779236769Sobrien} 780236769Sobrien 781236769Sobrien#ifdef SIGINFO 782236769Sobrien/*ARGSUSED*/ 783236769Sobrienstatic void 784237578Sobriensiginfo(int signo MAKE_ATTR_UNUSED) 785236769Sobrien{ 786236769Sobrien char dir[MAXPATHLEN]; 787236769Sobrien char str[2 * MAXPATHLEN]; 788236769Sobrien int len; 789236769Sobrien if (getcwd(dir, sizeof(dir)) == NULL) 790236769Sobrien return; 791236769Sobrien len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 792236769Sobrien if (len > 0) 793236769Sobrien (void)write(STDERR_FILENO, str, (size_t)len); 794236769Sobrien} 795236769Sobrien#endif 796236769Sobrien 797236769Sobrien/* 798236769Sobrien * Allow makefiles some control over the mode we run in. 799236769Sobrien */ 800236769Sobrienvoid 801236769SobrienMakeMode(const char *mode) 802236769Sobrien{ 803236769Sobrien char *mp = NULL; 804236769Sobrien 805236769Sobrien if (!mode) 806236769Sobrien mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", VAR_GLOBAL, 0); 807236769Sobrien 808236769Sobrien if (mode && *mode) { 809236769Sobrien if (strstr(mode, "compat")) { 810236769Sobrien compatMake = TRUE; 811236769Sobrien forceJobs = FALSE; 812236769Sobrien } 813236769Sobrien#if USE_META 814236769Sobrien if (strstr(mode, "meta")) 815249033Ssjg meta_mode_init(mode); 816236769Sobrien#endif 817236769Sobrien } 818236769Sobrien if (mp) 819236769Sobrien free(mp); 820236769Sobrien} 821236769Sobrien 822236769Sobrien/*- 823236769Sobrien * main -- 824236769Sobrien * The main function, for obvious reasons. Initializes variables 825236769Sobrien * and a few modules, then parses the arguments give it in the 826236769Sobrien * environment and on the command line. Reads the system makefile 827236769Sobrien * followed by either Makefile, makefile or the file given by the 828236769Sobrien * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 829236769Sobrien * flags it has received by then uses either the Make or the Compat 830236769Sobrien * module to create the initial list of targets. 831236769Sobrien * 832236769Sobrien * Results: 833236769Sobrien * If -q was given, exits -1 if anything was out-of-date. Else it exits 834236769Sobrien * 0. 835236769Sobrien * 836236769Sobrien * Side Effects: 837236769Sobrien * The program exits when done. Targets are created. etc. etc. etc. 838236769Sobrien */ 839236769Sobrienint 840236769Sobrienmain(int argc, char **argv) 841236769Sobrien{ 842236769Sobrien Lst targs; /* target nodes to create -- passed to Make_Init */ 843236769Sobrien Boolean outOfDate = FALSE; /* FALSE if all targets up to date */ 844236769Sobrien struct stat sb, sa; 845250750Ssjg char *p1, *path; 846236769Sobrien char mdpath[MAXPATHLEN]; 847236769Sobrien#ifdef FORCE_MACHINE 848236769Sobrien const char *machine = FORCE_MACHINE; 849236769Sobrien#else 850236769Sobrien const char *machine = getenv("MACHINE"); 851236769Sobrien#endif 852236769Sobrien const char *machine_arch = getenv("MACHINE_ARCH"); 853236769Sobrien char *syspath = getenv("MAKESYSPATH"); 854236769Sobrien Lst sysMkPath; /* Path of sys.mk */ 855236769Sobrien char *cp = NULL, *start; 856236769Sobrien /* avoid faults on read-only strings */ 857236769Sobrien static char defsyspath[] = _PATH_DEFSYSPATH; 858236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 859236769Sobrien struct timeval rightnow; /* to initialize random seed */ 860236769Sobrien struct utsname utsname; 861236769Sobrien 862236769Sobrien /* default to writing debug to stderr */ 863236769Sobrien debug_file = stderr; 864236769Sobrien 865236769Sobrien#ifdef SIGINFO 866236769Sobrien (void)bmake_signal(SIGINFO, siginfo); 867236769Sobrien#endif 868236769Sobrien /* 869236769Sobrien * Set the seed to produce a different random sequence 870236769Sobrien * on each program execution. 871236769Sobrien */ 872236769Sobrien gettimeofday(&rightnow, NULL); 873236769Sobrien srandom(rightnow.tv_sec + rightnow.tv_usec); 874236769Sobrien 875236769Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 876236769Sobrien progname++; 877236769Sobrien else 878236769Sobrien progname = argv[0]; 879249033Ssjg#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 880236769Sobrien /* 881236769Sobrien * get rid of resource limit on file descriptors 882236769Sobrien */ 883236769Sobrien { 884236769Sobrien struct rlimit rl; 885236769Sobrien if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 886236769Sobrien rl.rlim_cur != rl.rlim_max) { 887236769Sobrien rl.rlim_cur = rl.rlim_max; 888236769Sobrien (void)setrlimit(RLIMIT_NOFILE, &rl); 889236769Sobrien } 890236769Sobrien } 891236769Sobrien#endif 892236769Sobrien 893249033Ssjg if (uname(&utsname) == -1) { 894249033Ssjg (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 895249033Ssjg strerror(errno)); 896249033Ssjg exit(2); 897249033Ssjg } 898249033Ssjg 899236769Sobrien /* 900236769Sobrien * Get the name of this type of MACHINE from utsname 901236769Sobrien * so we can share an executable for similar machines. 902236769Sobrien * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 903236769Sobrien * 904236769Sobrien * Note that both MACHINE and MACHINE_ARCH are decided at 905236769Sobrien * run-time. 906236769Sobrien */ 907236769Sobrien if (!machine) { 908236769Sobrien#ifdef MAKE_NATIVE 909236769Sobrien machine = utsname.machine; 910236769Sobrien#else 911236769Sobrien#ifdef MAKE_MACHINE 912236769Sobrien machine = MAKE_MACHINE; 913236769Sobrien#else 914236769Sobrien machine = "unknown"; 915236769Sobrien#endif 916236769Sobrien#endif 917236769Sobrien } 918236769Sobrien 919236769Sobrien if (!machine_arch) { 920261212Ssjg#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_MACHINE_ARCH) 921261212Ssjg static char machine_arch_buf[sizeof(utsname.machine)]; 922261212Ssjg int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 923261212Ssjg size_t len = sizeof(machine_arch_buf); 924261212Ssjg 925261212Ssjg if (sysctl(mib, __arraycount(mib), machine_arch_buf, 926261212Ssjg &len, NULL, 0) < 0) { 927261212Ssjg (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 928261212Ssjg strerror(errno)); 929261212Ssjg exit(2); 930261212Ssjg } 931261212Ssjg 932261212Ssjg machine_arch = machine_arch_buf; 933261212Ssjg#else 934236769Sobrien#ifndef MACHINE_ARCH 935236769Sobrien#ifdef MAKE_MACHINE_ARCH 936236769Sobrien machine_arch = MAKE_MACHINE_ARCH; 937236769Sobrien#else 938236769Sobrien machine_arch = "unknown"; 939236769Sobrien#endif 940236769Sobrien#else 941236769Sobrien machine_arch = MACHINE_ARCH; 942236769Sobrien#endif 943261212Ssjg#endif 944236769Sobrien } 945236769Sobrien 946236769Sobrien myPid = getpid(); /* remember this for vFork() */ 947236769Sobrien 948236769Sobrien /* 949236769Sobrien * Just in case MAKEOBJDIR wants us to do something tricky. 950236769Sobrien */ 951236769Sobrien Var_Init(); /* Initialize the lists of variables for 952236769Sobrien * parsing arguments */ 953249033Ssjg Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL, 0); 954236769Sobrien Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 955236769Sobrien Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 956236769Sobrien#ifdef MAKE_VERSION 957236769Sobrien Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 958236769Sobrien#endif 959236769Sobrien Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 960236769Sobrien /* 961236769Sobrien * This is the traditional preference for makefiles. 962236769Sobrien */ 963236769Sobrien#ifndef MAKEFILE_PREFERENCE_LIST 964236769Sobrien# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 965236769Sobrien#endif 966236769Sobrien Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 967236769Sobrien VAR_GLOBAL, 0); 968236769Sobrien Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 969236769Sobrien 970236769Sobrien create = Lst_Init(FALSE); 971236769Sobrien makefiles = Lst_Init(FALSE); 972236769Sobrien printVars = FALSE; 973240330Smarcel debugVflag = FALSE; 974236769Sobrien variables = Lst_Init(FALSE); 975236769Sobrien beSilent = FALSE; /* Print commands as executed */ 976236769Sobrien ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 977236769Sobrien noExecute = FALSE; /* Execute all commands */ 978236769Sobrien noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 979236769Sobrien keepgoing = FALSE; /* Stop on error */ 980236769Sobrien allPrecious = FALSE; /* Remove targets when interrupted */ 981236769Sobrien queryFlag = FALSE; /* This is not just a check-run */ 982236769Sobrien noBuiltins = FALSE; /* Read the built-in rules */ 983236769Sobrien touchFlag = FALSE; /* Actually update targets */ 984236769Sobrien debug = 0; /* No debug verbosity, please. */ 985236769Sobrien jobsRunning = FALSE; 986236769Sobrien 987236769Sobrien maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 988236769Sobrien maxJobTokens = maxJobs; 989236769Sobrien compatMake = FALSE; /* No compat mode */ 990236769Sobrien ignorePWD = FALSE; 991236769Sobrien 992236769Sobrien /* 993236769Sobrien * Initialize the parsing, directory and variable modules to prepare 994236769Sobrien * for the reading of inclusion paths and variable settings on the 995236769Sobrien * command line 996236769Sobrien */ 997236769Sobrien 998236769Sobrien /* 999236769Sobrien * Initialize various variables. 1000236769Sobrien * MAKE also gets this name, for compatibility 1001236769Sobrien * .MAKEFLAGS gets set to the empty string just in case. 1002236769Sobrien * MFLAGS also gets initialized empty, for compatibility. 1003236769Sobrien */ 1004236769Sobrien Parse_Init(); 1005236769Sobrien if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 1006236769Sobrien /* 1007236769Sobrien * Leave alone if it is an absolute path, or if it does 1008236769Sobrien * not contain a '/' in which case we need to find it in 1009236769Sobrien * the path, like execvp(3) and the shells do. 1010236769Sobrien */ 1011236769Sobrien p1 = argv[0]; 1012236769Sobrien } else { 1013236769Sobrien /* 1014236769Sobrien * A relative path, canonicalize it. 1015236769Sobrien */ 1016236769Sobrien p1 = realpath(argv[0], mdpath); 1017236769Sobrien if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 1018236769Sobrien p1 = argv[0]; /* realpath failed */ 1019236769Sobrien } 1020236769Sobrien } 1021236769Sobrien Var_Set("MAKE", p1, VAR_GLOBAL, 0); 1022236769Sobrien Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 1023236769Sobrien Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 1024236769Sobrien Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 1025236769Sobrien Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 1026236769Sobrien Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 1027253883Ssjg /* some makefiles need to know this */ 1028253883Ssjg Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD, 0); 1029236769Sobrien 1030236769Sobrien /* 1031236769Sobrien * Set some other useful macros 1032236769Sobrien */ 1033236769Sobrien { 1034253883Ssjg char tmp[64], *ep; 1035236769Sobrien 1036253883Ssjg makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1037253883Ssjg if (makelevel < 0) 1038253883Ssjg makelevel = 0; 1039253883Ssjg snprintf(tmp, sizeof(tmp), "%d", makelevel); 1040253883Ssjg Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL, 0); 1041236769Sobrien snprintf(tmp, sizeof(tmp), "%u", myPid); 1042236769Sobrien Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 1043236769Sobrien snprintf(tmp, sizeof(tmp), "%u", getppid()); 1044236769Sobrien Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 1045236769Sobrien } 1046253883Ssjg if (makelevel > 0) { 1047253883Ssjg char pn[1024]; 1048253883Ssjg snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1049253883Ssjg progname = bmake_strdup(pn); 1050253883Ssjg } 1051236769Sobrien 1052249033Ssjg#ifdef USE_META 1053249033Ssjg meta_init(); 1054249033Ssjg#endif 1055236769Sobrien /* 1056236769Sobrien * First snag any flags out of the MAKE environment variable. 1057236769Sobrien * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1058236769Sobrien * in a different format). 1059236769Sobrien */ 1060236769Sobrien#ifdef POSIX 1061253883Ssjg p1 = explode(getenv("MAKEFLAGS")); 1062253883Ssjg Main_ParseArgLine(p1); 1063253883Ssjg free(p1); 1064236769Sobrien#else 1065236769Sobrien Main_ParseArgLine(getenv("MAKE")); 1066236769Sobrien#endif 1067236769Sobrien 1068236769Sobrien /* 1069236769Sobrien * Find where we are (now). 1070236769Sobrien * We take care of PWD for the automounter below... 1071236769Sobrien */ 1072236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 1073236769Sobrien (void)fprintf(stderr, "%s: getcwd: %s.\n", 1074236769Sobrien progname, strerror(errno)); 1075236769Sobrien exit(2); 1076236769Sobrien } 1077236769Sobrien 1078236769Sobrien MainParseArgs(argc, argv); 1079236769Sobrien 1080253883Ssjg if (enterFlag) 1081253883Ssjg printf("%s: Entering directory `%s'\n", progname, curdir); 1082253883Ssjg 1083236769Sobrien /* 1084236769Sobrien * Verify that cwd is sane. 1085236769Sobrien */ 1086236769Sobrien if (stat(curdir, &sa) == -1) { 1087236769Sobrien (void)fprintf(stderr, "%s: %s: %s.\n", 1088236769Sobrien progname, curdir, strerror(errno)); 1089236769Sobrien exit(2); 1090236769Sobrien } 1091236769Sobrien 1092236769Sobrien /* 1093236769Sobrien * All this code is so that we know where we are when we start up 1094236769Sobrien * on a different machine with pmake. 1095236769Sobrien * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1096236769Sobrien * since the value of curdir can vary depending on how we got 1097236769Sobrien * here. Ie sitting at a shell prompt (shell that provides $PWD) 1098236769Sobrien * or via subdir.mk in which case its likely a shell which does 1099236769Sobrien * not provide it. 1100236769Sobrien * So, to stop it breaking this case only, we ignore PWD if 1101236769Sobrien * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 1102236769Sobrien */ 1103236769Sobrien#ifndef NO_PWD_OVERRIDE 1104253883Ssjg if (!ignorePWD) { 1105268437Ssjg char *pwd, *ptmp1 = NULL, *ptmp2 = NULL; 1106236769Sobrien 1107253883Ssjg if ((pwd = getenv("PWD")) != NULL && 1108268437Ssjg Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &ptmp1) == NULL) { 1109268437Ssjg const char *makeobjdir = Var_Value("MAKEOBJDIR", 1110268437Ssjg VAR_CMD, &ptmp2); 1111253883Ssjg 1112253883Ssjg if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 1113253883Ssjg if (stat(pwd, &sb) == 0 && 1114253883Ssjg sa.st_ino == sb.st_ino && 1115253883Ssjg sa.st_dev == sb.st_dev) 1116253883Ssjg (void)strncpy(curdir, pwd, MAXPATHLEN); 1117253883Ssjg } 1118236769Sobrien } 1119268437Ssjg free(ptmp1); 1120268437Ssjg free(ptmp2); 1121236769Sobrien } 1122236769Sobrien#endif 1123236769Sobrien Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 1124236769Sobrien 1125236769Sobrien /* 1126236769Sobrien * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1127236769Sobrien * MAKEOBJDIR is set in the environment, try only that value 1128236769Sobrien * and fall back to .CURDIR if it does not exist. 1129236769Sobrien * 1130236769Sobrien * Otherwise, try _PATH_OBJDIR.MACHINE, _PATH_OBJDIR, and 1131236769Sobrien * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1132236769Sobrien * of these paths exist, just use .CURDIR. 1133236769Sobrien */ 1134236769Sobrien Dir_Init(curdir); 1135236769Sobrien (void)Main_SetObjdir(curdir); 1136236769Sobrien 1137268437Ssjg if ((path = Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &p1)) != NULL) { 1138236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir); 1139236769Sobrien (void)Main_SetObjdir(mdpath); 1140268437Ssjg free(p1); 1141268437Ssjg } else if ((path = Var_Value("MAKEOBJDIR", VAR_CMD, &p1)) != NULL) { 1142236769Sobrien (void)Main_SetObjdir(path); 1143268437Ssjg free(p1); 1144236769Sobrien } else { 1145236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s.%s", _PATH_OBJDIR, machine); 1146236769Sobrien if (!Main_SetObjdir(mdpath) && !Main_SetObjdir(_PATH_OBJDIR)) { 1147236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", 1148236769Sobrien _PATH_OBJDIRPREFIX, curdir); 1149236769Sobrien (void)Main_SetObjdir(mdpath); 1150236769Sobrien } 1151236769Sobrien } 1152236769Sobrien 1153236769Sobrien /* 1154236769Sobrien * Be compatible if user did not specify -j and did not explicitly 1155236769Sobrien * turned compatibility on 1156236769Sobrien */ 1157236769Sobrien if (!compatMake && !forceJobs) { 1158236769Sobrien compatMake = TRUE; 1159236769Sobrien } 1160236769Sobrien 1161236769Sobrien /* 1162236769Sobrien * Initialize archive, target and suffix modules in preparation for 1163236769Sobrien * parsing the makefile(s) 1164236769Sobrien */ 1165236769Sobrien Arch_Init(); 1166236769Sobrien Targ_Init(); 1167236769Sobrien Suff_Init(); 1168236769Sobrien Trace_Init(tracefile); 1169236769Sobrien 1170236769Sobrien DEFAULT = NULL; 1171236769Sobrien (void)time(&now); 1172236769Sobrien 1173236769Sobrien Trace_Log(MAKESTART, NULL); 1174236769Sobrien 1175236769Sobrien /* 1176236769Sobrien * Set up the .TARGETS variable to contain the list of targets to be 1177236769Sobrien * created. If none specified, make the variable empty -- the parser 1178236769Sobrien * will fill the thing in with the default or .MAIN target. 1179236769Sobrien */ 1180236769Sobrien if (!Lst_IsEmpty(create)) { 1181236769Sobrien LstNode ln; 1182236769Sobrien 1183236769Sobrien for (ln = Lst_First(create); ln != NULL; 1184236769Sobrien ln = Lst_Succ(ln)) { 1185236769Sobrien char *name = (char *)Lst_Datum(ln); 1186236769Sobrien 1187236769Sobrien Var_Append(".TARGETS", name, VAR_GLOBAL); 1188236769Sobrien } 1189236769Sobrien } else 1190236769Sobrien Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 1191236769Sobrien 1192236769Sobrien 1193236769Sobrien /* 1194236769Sobrien * If no user-supplied system path was given (through the -m option) 1195236769Sobrien * add the directories from the DEFSYSPATH (more than one may be given 1196236769Sobrien * as dir1:...:dirn) to the system include path. 1197236769Sobrien */ 1198236769Sobrien if (syspath == NULL || *syspath == '\0') 1199236769Sobrien syspath = defsyspath; 1200236769Sobrien else 1201236769Sobrien syspath = bmake_strdup(syspath); 1202236769Sobrien 1203236769Sobrien for (start = syspath; *start != '\0'; start = cp) { 1204236769Sobrien for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1205236769Sobrien continue; 1206236769Sobrien if (*cp == ':') { 1207236769Sobrien *cp++ = '\0'; 1208236769Sobrien } 1209236769Sobrien /* look for magic parent directory search string */ 1210236769Sobrien if (strncmp(".../", start, 4) != 0) { 1211236769Sobrien (void)Dir_AddDir(defIncPath, start); 1212236769Sobrien } else { 1213236769Sobrien if (Dir_FindHereOrAbove(curdir, start+4, 1214236769Sobrien found_path, sizeof(found_path))) { 1215236769Sobrien (void)Dir_AddDir(defIncPath, found_path); 1216236769Sobrien } 1217236769Sobrien } 1218236769Sobrien } 1219236769Sobrien if (syspath != defsyspath) 1220236769Sobrien free(syspath); 1221236769Sobrien 1222236769Sobrien /* 1223236769Sobrien * Read in the built-in rules first, followed by the specified 1224236769Sobrien * makefile, if it was (makefile != NULL), or the default 1225236769Sobrien * makefile and Makefile, in that order, if it wasn't. 1226236769Sobrien */ 1227236769Sobrien if (!noBuiltins) { 1228236769Sobrien LstNode ln; 1229236769Sobrien 1230236769Sobrien sysMkPath = Lst_Init(FALSE); 1231236769Sobrien Dir_Expand(_PATH_DEFSYSMK, 1232236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1233236769Sobrien sysMkPath); 1234236769Sobrien if (Lst_IsEmpty(sysMkPath)) 1235236769Sobrien Fatal("%s: no system rules (%s).", progname, 1236236769Sobrien _PATH_DEFSYSMK); 1237236769Sobrien ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 1238236769Sobrien if (ln == NULL) 1239236769Sobrien Fatal("%s: cannot open %s.", progname, 1240236769Sobrien (char *)Lst_Datum(ln)); 1241236769Sobrien } 1242236769Sobrien 1243236769Sobrien if (!Lst_IsEmpty(makefiles)) { 1244236769Sobrien LstNode ln; 1245236769Sobrien 1246236769Sobrien ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 1247236769Sobrien if (ln != NULL) 1248236769Sobrien Fatal("%s: cannot open %s.", progname, 1249236769Sobrien (char *)Lst_Datum(ln)); 1250236769Sobrien } else { 1251236769Sobrien p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 1252236769Sobrien VAR_CMD, 0); 1253236769Sobrien if (p1) { 1254236769Sobrien (void)str2Lst_Append(makefiles, p1, NULL); 1255236769Sobrien (void)Lst_Find(makefiles, NULL, ReadMakefile); 1256236769Sobrien free(p1); 1257236769Sobrien } 1258236769Sobrien } 1259236769Sobrien 1260236769Sobrien /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1261236769Sobrien if (!noBuiltins || !printVars) { 1262236769Sobrien makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 1263236769Sobrien VAR_CMD, 0); 1264236769Sobrien doing_depend = TRUE; 1265236769Sobrien (void)ReadMakefile(makeDependfile, NULL); 1266236769Sobrien doing_depend = FALSE; 1267236769Sobrien } 1268236769Sobrien 1269236769Sobrien MakeMode(NULL); 1270236769Sobrien 1271236769Sobrien Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1272236769Sobrien if (p1) 1273236769Sobrien free(p1); 1274236769Sobrien 1275236769Sobrien if (!compatMake) 1276236769Sobrien Job_ServerStart(maxJobTokens, jp_0, jp_1); 1277236769Sobrien if (DEBUG(JOB)) 1278236769Sobrien fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1279236769Sobrien jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 1280236769Sobrien 1281236769Sobrien Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1282236769Sobrien 1283236769Sobrien /* 1284236769Sobrien * For compatibility, look at the directories in the VPATH variable 1285236769Sobrien * and add them to the search path, if the variable is defined. The 1286236769Sobrien * variable's value is in the same format as the PATH envariable, i.e. 1287236769Sobrien * <directory>:<directory>:<directory>... 1288236769Sobrien */ 1289236769Sobrien if (Var_Exists("VPATH", VAR_CMD)) { 1290236769Sobrien char *vpath, savec; 1291236769Sobrien /* 1292236769Sobrien * GCC stores string constants in read-only memory, but 1293236769Sobrien * Var_Subst will want to write this thing, so store it 1294236769Sobrien * in an array 1295236769Sobrien */ 1296236769Sobrien static char VPATH[] = "${VPATH}"; 1297236769Sobrien 1298236769Sobrien vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 1299236769Sobrien path = vpath; 1300236769Sobrien do { 1301236769Sobrien /* skip to end of directory */ 1302236769Sobrien for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1303236769Sobrien continue; 1304236769Sobrien /* Save terminator character so know when to stop */ 1305236769Sobrien savec = *cp; 1306236769Sobrien *cp = '\0'; 1307236769Sobrien /* Add directory to search path */ 1308236769Sobrien (void)Dir_AddDir(dirSearchPath, path); 1309236769Sobrien *cp = savec; 1310236769Sobrien path = cp + 1; 1311236769Sobrien } while (savec == ':'); 1312236769Sobrien free(vpath); 1313236769Sobrien } 1314236769Sobrien 1315236769Sobrien /* 1316236769Sobrien * Now that all search paths have been read for suffixes et al, it's 1317236769Sobrien * time to add the default search path to their lists... 1318236769Sobrien */ 1319236769Sobrien Suff_DoPaths(); 1320236769Sobrien 1321236769Sobrien /* 1322236769Sobrien * Propagate attributes through :: dependency lists. 1323236769Sobrien */ 1324236769Sobrien Targ_Propagate(); 1325236769Sobrien 1326236769Sobrien /* print the initial graph, if the user requested it */ 1327236769Sobrien if (DEBUG(GRAPH1)) 1328236769Sobrien Targ_PrintGraph(1); 1329236769Sobrien 1330236769Sobrien /* print the values of any variables requested by the user */ 1331236769Sobrien if (printVars) { 1332236769Sobrien LstNode ln; 1333240330Smarcel Boolean expandVars; 1334236769Sobrien 1335240330Smarcel if (debugVflag) 1336240330Smarcel expandVars = FALSE; 1337240330Smarcel else 1338240330Smarcel expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 1339236769Sobrien for (ln = Lst_First(variables); ln != NULL; 1340236769Sobrien ln = Lst_Succ(ln)) { 1341236769Sobrien char *var = (char *)Lst_Datum(ln); 1342236769Sobrien char *value; 1343236769Sobrien 1344236769Sobrien if (strchr(var, '$')) { 1345236769Sobrien value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 0); 1346240330Smarcel } else if (expandVars) { 1347240330Smarcel char tmp[128]; 1348240330Smarcel 1349240330Smarcel if (snprintf(tmp, sizeof(tmp), "${%s}", var) >= (int)(sizeof(tmp))) 1350240330Smarcel Fatal("%s: variable name too big: %s", 1351240330Smarcel progname, var); 1352240330Smarcel value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1353236769Sobrien } else { 1354236769Sobrien value = Var_Value(var, VAR_GLOBAL, &p1); 1355236769Sobrien } 1356236769Sobrien printf("%s\n", value ? value : ""); 1357236769Sobrien if (p1) 1358236769Sobrien free(p1); 1359236769Sobrien } 1360236769Sobrien } else { 1361236769Sobrien /* 1362236769Sobrien * Have now read the entire graph and need to make a list of 1363236769Sobrien * targets to create. If none was given on the command line, 1364236769Sobrien * we consult the parsing module to find the main target(s) 1365236769Sobrien * to create. 1366236769Sobrien */ 1367236769Sobrien if (Lst_IsEmpty(create)) 1368236769Sobrien targs = Parse_MainName(); 1369236769Sobrien else 1370236769Sobrien targs = Targ_FindList(create, TARG_CREATE); 1371236769Sobrien 1372236769Sobrien if (!compatMake) { 1373236769Sobrien /* 1374236769Sobrien * Initialize job module before traversing the graph 1375236769Sobrien * now that any .BEGIN and .END targets have been read. 1376236769Sobrien * This is done only if the -q flag wasn't given 1377236769Sobrien * (to prevent the .BEGIN from being executed should 1378236769Sobrien * it exist). 1379236769Sobrien */ 1380236769Sobrien if (!queryFlag) { 1381236769Sobrien Job_Init(); 1382236769Sobrien jobsRunning = TRUE; 1383236769Sobrien } 1384236769Sobrien 1385236769Sobrien /* Traverse the graph, checking on all the targets */ 1386236769Sobrien outOfDate = Make_Run(targs); 1387236769Sobrien } else { 1388236769Sobrien /* 1389236769Sobrien * Compat_Init will take care of creating all the 1390236769Sobrien * targets as well as initializing the module. 1391236769Sobrien */ 1392236769Sobrien Compat_Run(targs); 1393236769Sobrien } 1394236769Sobrien } 1395236769Sobrien 1396236769Sobrien#ifdef CLEANUP 1397236769Sobrien Lst_Destroy(targs, NULL); 1398236769Sobrien Lst_Destroy(variables, NULL); 1399236769Sobrien Lst_Destroy(makefiles, NULL); 1400236769Sobrien Lst_Destroy(create, (FreeProc *)free); 1401236769Sobrien#endif 1402236769Sobrien 1403236769Sobrien /* print the graph now it's been processed if the user requested it */ 1404236769Sobrien if (DEBUG(GRAPH2)) 1405236769Sobrien Targ_PrintGraph(2); 1406236769Sobrien 1407236769Sobrien Trace_Log(MAKEEND, 0); 1408236769Sobrien 1409253883Ssjg if (enterFlag) 1410253883Ssjg printf("%s: Leaving directory `%s'\n", progname, curdir); 1411253883Ssjg 1412236769Sobrien Suff_End(); 1413236769Sobrien Targ_End(); 1414236769Sobrien Arch_End(); 1415236769Sobrien Var_End(); 1416236769Sobrien Parse_End(); 1417236769Sobrien Dir_End(); 1418236769Sobrien Job_End(); 1419236769Sobrien Trace_End(); 1420236769Sobrien 1421236769Sobrien return outOfDate ? 1 : 0; 1422236769Sobrien} 1423236769Sobrien 1424236769Sobrien/*- 1425236769Sobrien * ReadMakefile -- 1426236769Sobrien * Open and parse the given makefile. 1427236769Sobrien * 1428236769Sobrien * Results: 1429236769Sobrien * 0 if ok. -1 if couldn't open file. 1430236769Sobrien * 1431236769Sobrien * Side Effects: 1432236769Sobrien * lots 1433236769Sobrien */ 1434236769Sobrienstatic int 1435237578SobrienReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 1436236769Sobrien{ 1437236769Sobrien const char *fname = p; /* makefile to read */ 1438236769Sobrien int fd; 1439236769Sobrien size_t len = MAXPATHLEN; 1440236769Sobrien char *name, *path = bmake_malloc(len); 1441236769Sobrien 1442236769Sobrien if (!strcmp(fname, "-")) { 1443236769Sobrien Parse_File(NULL /*stdin*/, -1); 1444255253Ssjg Var_Set("MAKEFILE", "", VAR_INTERNAL, 0); 1445236769Sobrien } else { 1446236769Sobrien /* if we've chdir'd, rebuild the path name */ 1447236769Sobrien if (strcmp(curdir, objdir) && *fname != '/') { 1448236769Sobrien size_t plen = strlen(curdir) + strlen(fname) + 2; 1449236769Sobrien if (len < plen) 1450236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1451236769Sobrien 1452236769Sobrien (void)snprintf(path, len, "%s/%s", curdir, fname); 1453236769Sobrien fd = open(path, O_RDONLY); 1454236769Sobrien if (fd != -1) { 1455236769Sobrien fname = path; 1456236769Sobrien goto found; 1457236769Sobrien } 1458236769Sobrien 1459236769Sobrien /* If curdir failed, try objdir (ala .depend) */ 1460236769Sobrien plen = strlen(objdir) + strlen(fname) + 2; 1461236769Sobrien if (len < plen) 1462236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1463236769Sobrien (void)snprintf(path, len, "%s/%s", objdir, fname); 1464236769Sobrien fd = open(path, O_RDONLY); 1465236769Sobrien if (fd != -1) { 1466236769Sobrien fname = path; 1467236769Sobrien goto found; 1468236769Sobrien } 1469236769Sobrien } else { 1470236769Sobrien fd = open(fname, O_RDONLY); 1471236769Sobrien if (fd != -1) 1472236769Sobrien goto found; 1473236769Sobrien } 1474236769Sobrien /* look in -I and system include directories. */ 1475236769Sobrien name = Dir_FindFile(fname, parseIncPath); 1476236769Sobrien if (!name) 1477236769Sobrien name = Dir_FindFile(fname, 1478236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1479236769Sobrien if (!name || (fd = open(name, O_RDONLY)) == -1) { 1480236769Sobrien if (name) 1481236769Sobrien free(name); 1482236769Sobrien free(path); 1483236769Sobrien return(-1); 1484236769Sobrien } 1485236769Sobrien fname = name; 1486236769Sobrien /* 1487236769Sobrien * set the MAKEFILE variable desired by System V fans -- the 1488236769Sobrien * placement of the setting here means it gets set to the last 1489236769Sobrien * makefile specified, as it is set by SysV make. 1490236769Sobrien */ 1491236769Sobrienfound: 1492236769Sobrien if (!doing_depend) 1493255253Ssjg Var_Set("MAKEFILE", fname, VAR_INTERNAL, 0); 1494236769Sobrien Parse_File(fname, fd); 1495236769Sobrien } 1496236769Sobrien free(path); 1497236769Sobrien return(0); 1498236769Sobrien} 1499236769Sobrien 1500236769Sobrien 1501236769Sobrien 1502236769Sobrien/*- 1503236769Sobrien * Cmd_Exec -- 1504236769Sobrien * Execute the command in cmd, and return the output of that command 1505236769Sobrien * in a string. 1506236769Sobrien * 1507236769Sobrien * Results: 1508236769Sobrien * A string containing the output of the command, or the empty string 1509236769Sobrien * If errnum is not NULL, it contains the reason for the command failure 1510236769Sobrien * 1511236769Sobrien * Side Effects: 1512236769Sobrien * The string must be freed by the caller. 1513236769Sobrien */ 1514236769Sobrienchar * 1515236769SobrienCmd_Exec(const char *cmd, const char **errnum) 1516236769Sobrien{ 1517236769Sobrien const char *args[4]; /* Args for invoking the shell */ 1518236769Sobrien int fds[2]; /* Pipe streams */ 1519236769Sobrien int cpid; /* Child PID */ 1520236769Sobrien int pid; /* PID from wait() */ 1521236769Sobrien char *res; /* result */ 1522236769Sobrien WAIT_T status; /* command exit status */ 1523236769Sobrien Buffer buf; /* buffer to store the result */ 1524236769Sobrien char *cp; 1525281812Ssjg int cc; /* bytes read, or -1 */ 1526281812Ssjg int savederr; /* saved errno */ 1527236769Sobrien 1528236769Sobrien 1529236769Sobrien *errnum = NULL; 1530236769Sobrien 1531236769Sobrien if (!shellName) 1532236769Sobrien Shell_Init(); 1533236769Sobrien /* 1534236769Sobrien * Set up arguments for shell 1535236769Sobrien */ 1536236769Sobrien args[0] = shellName; 1537236769Sobrien args[1] = "-c"; 1538236769Sobrien args[2] = cmd; 1539236769Sobrien args[3] = NULL; 1540236769Sobrien 1541236769Sobrien /* 1542236769Sobrien * Open a pipe for fetching its output 1543236769Sobrien */ 1544236769Sobrien if (pipe(fds) == -1) { 1545236769Sobrien *errnum = "Couldn't create pipe for \"%s\""; 1546236769Sobrien goto bad; 1547236769Sobrien } 1548236769Sobrien 1549236769Sobrien /* 1550236769Sobrien * Fork 1551236769Sobrien */ 1552236769Sobrien switch (cpid = vFork()) { 1553236769Sobrien case 0: 1554236769Sobrien /* 1555236769Sobrien * Close input side of pipe 1556236769Sobrien */ 1557236769Sobrien (void)close(fds[0]); 1558236769Sobrien 1559236769Sobrien /* 1560236769Sobrien * Duplicate the output stream to the shell's output, then 1561236769Sobrien * shut the extra thing down. Note we don't fetch the error 1562236769Sobrien * stream...why not? Why? 1563236769Sobrien */ 1564236769Sobrien (void)dup2(fds[1], 1); 1565236769Sobrien (void)close(fds[1]); 1566236769Sobrien 1567236769Sobrien Var_ExportVars(); 1568236769Sobrien 1569236769Sobrien (void)execv(shellPath, UNCONST(args)); 1570236769Sobrien _exit(1); 1571236769Sobrien /*NOTREACHED*/ 1572236769Sobrien 1573236769Sobrien case -1: 1574236769Sobrien *errnum = "Couldn't exec \"%s\""; 1575236769Sobrien goto bad; 1576236769Sobrien 1577236769Sobrien default: 1578236769Sobrien /* 1579236769Sobrien * No need for the writing half 1580236769Sobrien */ 1581236769Sobrien (void)close(fds[1]); 1582236769Sobrien 1583281812Ssjg savederr = 0; 1584236769Sobrien Buf_Init(&buf, 0); 1585236769Sobrien 1586236769Sobrien do { 1587236769Sobrien char result[BUFSIZ]; 1588236769Sobrien cc = read(fds[0], result, sizeof(result)); 1589236769Sobrien if (cc > 0) 1590236769Sobrien Buf_AddBytes(&buf, cc, result); 1591236769Sobrien } 1592236769Sobrien while (cc > 0 || (cc == -1 && errno == EINTR)); 1593281812Ssjg if (cc == -1) 1594281812Ssjg savederr = errno; 1595236769Sobrien 1596236769Sobrien /* 1597236769Sobrien * Close the input side of the pipe. 1598236769Sobrien */ 1599236769Sobrien (void)close(fds[0]); 1600236769Sobrien 1601236769Sobrien /* 1602236769Sobrien * Wait for the process to exit. 1603236769Sobrien */ 1604236769Sobrien while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1605236769Sobrien JobReapChild(pid, status, FALSE); 1606236769Sobrien continue; 1607236769Sobrien } 1608236769Sobrien cc = Buf_Size(&buf); 1609236769Sobrien res = Buf_Destroy(&buf, FALSE); 1610236769Sobrien 1611281812Ssjg if (savederr != 0) 1612236769Sobrien *errnum = "Couldn't read shell's output for \"%s\""; 1613236769Sobrien 1614236769Sobrien if (WIFSIGNALED(status)) 1615236769Sobrien *errnum = "\"%s\" exited on a signal"; 1616236769Sobrien else if (WEXITSTATUS(status) != 0) 1617236769Sobrien *errnum = "\"%s\" returned non-zero status"; 1618236769Sobrien 1619236769Sobrien /* 1620236769Sobrien * Null-terminate the result, convert newlines to spaces and 1621236769Sobrien * install it in the variable. 1622236769Sobrien */ 1623236769Sobrien res[cc] = '\0'; 1624236769Sobrien cp = &res[cc]; 1625236769Sobrien 1626236769Sobrien if (cc > 0 && *--cp == '\n') { 1627236769Sobrien /* 1628236769Sobrien * A final newline is just stripped 1629236769Sobrien */ 1630236769Sobrien *cp-- = '\0'; 1631236769Sobrien } 1632236769Sobrien while (cp >= res) { 1633236769Sobrien if (*cp == '\n') { 1634236769Sobrien *cp = ' '; 1635236769Sobrien } 1636236769Sobrien cp--; 1637236769Sobrien } 1638236769Sobrien break; 1639236769Sobrien } 1640236769Sobrien return res; 1641236769Sobrienbad: 1642236769Sobrien res = bmake_malloc(1); 1643236769Sobrien *res = '\0'; 1644236769Sobrien return res; 1645236769Sobrien} 1646236769Sobrien 1647236769Sobrien/*- 1648236769Sobrien * Error -- 1649236769Sobrien * Print an error message given its format. 1650236769Sobrien * 1651236769Sobrien * Results: 1652236769Sobrien * None. 1653236769Sobrien * 1654236769Sobrien * Side Effects: 1655236769Sobrien * The message is printed. 1656236769Sobrien */ 1657236769Sobrien/* VARARGS */ 1658236769Sobrienvoid 1659236769SobrienError(const char *fmt, ...) 1660236769Sobrien{ 1661236769Sobrien va_list ap; 1662236769Sobrien FILE *err_file; 1663236769Sobrien 1664236769Sobrien err_file = debug_file; 1665236769Sobrien if (err_file == stdout) 1666236769Sobrien err_file = stderr; 1667236769Sobrien (void)fflush(stdout); 1668236769Sobrien for (;;) { 1669236769Sobrien va_start(ap, fmt); 1670236769Sobrien fprintf(err_file, "%s: ", progname); 1671236769Sobrien (void)vfprintf(err_file, fmt, ap); 1672236769Sobrien va_end(ap); 1673236769Sobrien (void)fprintf(err_file, "\n"); 1674236769Sobrien (void)fflush(err_file); 1675236769Sobrien if (err_file == stderr) 1676236769Sobrien break; 1677236769Sobrien err_file = stderr; 1678236769Sobrien } 1679236769Sobrien} 1680236769Sobrien 1681236769Sobrien/*- 1682236769Sobrien * Fatal -- 1683236769Sobrien * Produce a Fatal error message. If jobs are running, waits for them 1684236769Sobrien * to finish. 1685236769Sobrien * 1686236769Sobrien * Results: 1687236769Sobrien * None 1688236769Sobrien * 1689236769Sobrien * Side Effects: 1690236769Sobrien * The program exits 1691236769Sobrien */ 1692236769Sobrien/* VARARGS */ 1693236769Sobrienvoid 1694236769SobrienFatal(const char *fmt, ...) 1695236769Sobrien{ 1696236769Sobrien va_list ap; 1697236769Sobrien 1698236769Sobrien va_start(ap, fmt); 1699236769Sobrien if (jobsRunning) 1700236769Sobrien Job_Wait(); 1701236769Sobrien 1702236769Sobrien (void)fflush(stdout); 1703236769Sobrien (void)vfprintf(stderr, fmt, ap); 1704236769Sobrien va_end(ap); 1705236769Sobrien (void)fprintf(stderr, "\n"); 1706236769Sobrien (void)fflush(stderr); 1707236769Sobrien 1708236769Sobrien PrintOnError(NULL, NULL); 1709236769Sobrien 1710236769Sobrien if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1711236769Sobrien Targ_PrintGraph(2); 1712236769Sobrien Trace_Log(MAKEERROR, 0); 1713236769Sobrien exit(2); /* Not 1 so -q can distinguish error */ 1714236769Sobrien} 1715236769Sobrien 1716236769Sobrien/* 1717236769Sobrien * Punt -- 1718236769Sobrien * Major exception once jobs are being created. Kills all jobs, prints 1719236769Sobrien * a message and exits. 1720236769Sobrien * 1721236769Sobrien * Results: 1722236769Sobrien * None 1723236769Sobrien * 1724236769Sobrien * Side Effects: 1725236769Sobrien * All children are killed indiscriminately and the program Lib_Exits 1726236769Sobrien */ 1727236769Sobrien/* VARARGS */ 1728236769Sobrienvoid 1729236769SobrienPunt(const char *fmt, ...) 1730236769Sobrien{ 1731236769Sobrien va_list ap; 1732236769Sobrien 1733236769Sobrien va_start(ap, fmt); 1734236769Sobrien (void)fflush(stdout); 1735236769Sobrien (void)fprintf(stderr, "%s: ", progname); 1736236769Sobrien (void)vfprintf(stderr, fmt, ap); 1737236769Sobrien va_end(ap); 1738236769Sobrien (void)fprintf(stderr, "\n"); 1739236769Sobrien (void)fflush(stderr); 1740236769Sobrien 1741236769Sobrien PrintOnError(NULL, NULL); 1742236769Sobrien 1743236769Sobrien DieHorribly(); 1744236769Sobrien} 1745236769Sobrien 1746236769Sobrien/*- 1747236769Sobrien * DieHorribly -- 1748236769Sobrien * Exit without giving a message. 1749236769Sobrien * 1750236769Sobrien * Results: 1751236769Sobrien * None 1752236769Sobrien * 1753236769Sobrien * Side Effects: 1754236769Sobrien * A big one... 1755236769Sobrien */ 1756236769Sobrienvoid 1757236769SobrienDieHorribly(void) 1758236769Sobrien{ 1759236769Sobrien if (jobsRunning) 1760236769Sobrien Job_AbortAll(); 1761236769Sobrien if (DEBUG(GRAPH2)) 1762236769Sobrien Targ_PrintGraph(2); 1763236769Sobrien Trace_Log(MAKEERROR, 0); 1764236769Sobrien exit(2); /* Not 1, so -q can distinguish error */ 1765236769Sobrien} 1766236769Sobrien 1767236769Sobrien/* 1768236769Sobrien * Finish -- 1769236769Sobrien * Called when aborting due to errors in child shell to signal 1770236769Sobrien * abnormal exit. 1771236769Sobrien * 1772236769Sobrien * Results: 1773236769Sobrien * None 1774236769Sobrien * 1775236769Sobrien * Side Effects: 1776236769Sobrien * The program exits 1777236769Sobrien */ 1778236769Sobrienvoid 1779236769SobrienFinish(int errors) 1780236769Sobrien /* number of errors encountered in Make_Make */ 1781236769Sobrien{ 1782236769Sobrien Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1783236769Sobrien} 1784236769Sobrien 1785236769Sobrien/* 1786249033Ssjg * eunlink -- 1787236769Sobrien * Remove a file carefully, avoiding directories. 1788236769Sobrien */ 1789236769Sobrienint 1790236769Sobrieneunlink(const char *file) 1791236769Sobrien{ 1792236769Sobrien struct stat st; 1793236769Sobrien 1794236769Sobrien if (lstat(file, &st) == -1) 1795236769Sobrien return -1; 1796236769Sobrien 1797236769Sobrien if (S_ISDIR(st.st_mode)) { 1798236769Sobrien errno = EISDIR; 1799236769Sobrien return -1; 1800236769Sobrien } 1801236769Sobrien return unlink(file); 1802236769Sobrien} 1803236769Sobrien 1804236769Sobrien/* 1805236769Sobrien * execError -- 1806236769Sobrien * Print why exec failed, avoiding stdio. 1807236769Sobrien */ 1808236769Sobrienvoid 1809236769SobrienexecError(const char *af, const char *av) 1810236769Sobrien{ 1811236769Sobrien#ifdef USE_IOVEC 1812236769Sobrien int i = 0; 1813236769Sobrien struct iovec iov[8]; 1814236769Sobrien#define IOADD(s) \ 1815236769Sobrien (void)(iov[i].iov_base = UNCONST(s), \ 1816236769Sobrien iov[i].iov_len = strlen(iov[i].iov_base), \ 1817236769Sobrien i++) 1818236769Sobrien#else 1819236769Sobrien#define IOADD(s) (void)write(2, s, strlen(s)) 1820236769Sobrien#endif 1821236769Sobrien 1822236769Sobrien IOADD(progname); 1823236769Sobrien IOADD(": "); 1824236769Sobrien IOADD(af); 1825236769Sobrien IOADD("("); 1826236769Sobrien IOADD(av); 1827236769Sobrien IOADD(") failed ("); 1828236769Sobrien IOADD(strerror(errno)); 1829236769Sobrien IOADD(")\n"); 1830236769Sobrien 1831236769Sobrien#ifdef USE_IOVEC 1832246223Ssjg while (writev(2, iov, 8) == -1 && errno == EAGAIN) 1833246223Ssjg continue; 1834236769Sobrien#endif 1835236769Sobrien} 1836236769Sobrien 1837236769Sobrien/* 1838236769Sobrien * usage -- 1839236769Sobrien * exit with usage message 1840236769Sobrien */ 1841236769Sobrienstatic void 1842236769Sobrienusage(void) 1843236769Sobrien{ 1844253883Ssjg char *p; 1845253883Ssjg if ((p = strchr(progname, '[')) != NULL) 1846253883Ssjg *p = '\0'; 1847253883Ssjg 1848236769Sobrien (void)fprintf(stderr, 1849253883Ssjg"usage: %s [-BeikNnqrstWwX] \n\ 1850236769Sobrien [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 1851236769Sobrien [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1852236769Sobrien [-V variable] [variable=value] [target ...]\n", progname); 1853236769Sobrien exit(2); 1854236769Sobrien} 1855236769Sobrien 1856236769Sobrien 1857236769Sobrienint 1858236769SobrienPrintAddr(void *a, void *b) 1859236769Sobrien{ 1860236769Sobrien printf("%lx ", (unsigned long) a); 1861236769Sobrien return b ? 0 : 0; 1862236769Sobrien} 1863236769Sobrien 1864236769Sobrien 1865236769Sobrien 1866236769Sobrienvoid 1867236769SobrienPrintOnError(GNode *gn, const char *s) 1868236769Sobrien{ 1869236769Sobrien static GNode *en = NULL; 1870236769Sobrien char tmp[64]; 1871236769Sobrien char *cp; 1872236769Sobrien 1873236769Sobrien if (s) 1874236769Sobrien printf("%s", s); 1875236769Sobrien 1876236769Sobrien printf("\n%s: stopped in %s\n", progname, curdir); 1877236769Sobrien 1878236769Sobrien if (en) 1879236769Sobrien return; /* we've been here! */ 1880236769Sobrien if (gn) { 1881236769Sobrien /* 1882236769Sobrien * We can print this even if there is no .ERROR target. 1883236769Sobrien */ 1884236769Sobrien Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 1885236769Sobrien } 1886236769Sobrien strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 1887236769Sobrien sizeof(tmp) - 1); 1888236769Sobrien cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1889236769Sobrien if (cp) { 1890236769Sobrien if (*cp) 1891236769Sobrien printf("%s", cp); 1892236769Sobrien free(cp); 1893236769Sobrien } 1894236769Sobrien /* 1895236769Sobrien * Finally, see if there is a .ERROR target, and run it if so. 1896236769Sobrien */ 1897236769Sobrien en = Targ_FindNode(".ERROR", TARG_NOCREATE); 1898236769Sobrien if (en) { 1899236769Sobrien en->type |= OP_SPECIAL; 1900236769Sobrien Compat_Make(en, en); 1901236769Sobrien } 1902236769Sobrien} 1903236769Sobrien 1904236769Sobrienvoid 1905236769SobrienMain_ExportMAKEFLAGS(Boolean first) 1906236769Sobrien{ 1907236769Sobrien static int once = 1; 1908236769Sobrien char tmp[64]; 1909236769Sobrien char *s; 1910236769Sobrien 1911236769Sobrien if (once != first) 1912236769Sobrien return; 1913236769Sobrien once = 0; 1914236769Sobrien 1915236769Sobrien strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 1916236769Sobrien sizeof(tmp)); 1917236769Sobrien s = Var_Subst(NULL, tmp, VAR_CMD, 0); 1918236769Sobrien if (s && *s) { 1919236769Sobrien#ifdef POSIX 1920236769Sobrien setenv("MAKEFLAGS", s, 1); 1921236769Sobrien#else 1922236769Sobrien setenv("MAKE", s, 1); 1923236769Sobrien#endif 1924236769Sobrien } 1925236769Sobrien} 1926236769Sobrien 1927236769Sobrienchar * 1928236769SobriengetTmpdir(void) 1929236769Sobrien{ 1930236769Sobrien static char *tmpdir = NULL; 1931236769Sobrien 1932236769Sobrien if (!tmpdir) { 1933236769Sobrien struct stat st; 1934236769Sobrien 1935236769Sobrien /* 1936236769Sobrien * Honor $TMPDIR but only if it is valid. 1937236769Sobrien * Ensure it ends with /. 1938236769Sobrien */ 1939236769Sobrien tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 0); 1940236769Sobrien if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 1941236769Sobrien free(tmpdir); 1942236769Sobrien tmpdir = bmake_strdup(_PATH_TMP); 1943236769Sobrien } 1944236769Sobrien } 1945236769Sobrien return tmpdir; 1946236769Sobrien} 1947236769Sobrien 1948236769Sobrien/* 1949236769Sobrien * Create and open a temp file using "pattern". 1950236769Sobrien * If "fnamep" is provided set it to a copy of the filename created. 1951236769Sobrien * Otherwise unlink the file once open. 1952236769Sobrien */ 1953236769Sobrienint 1954236769SobrienmkTempFile(const char *pattern, char **fnamep) 1955236769Sobrien{ 1956236769Sobrien static char *tmpdir = NULL; 1957236769Sobrien char tfile[MAXPATHLEN]; 1958236769Sobrien int fd; 1959236769Sobrien 1960236769Sobrien if (!pattern) 1961236769Sobrien pattern = TMPPAT; 1962236769Sobrien if (!tmpdir) 1963236769Sobrien tmpdir = getTmpdir(); 1964236769Sobrien if (pattern[0] == '/') { 1965236769Sobrien snprintf(tfile, sizeof(tfile), "%s", pattern); 1966236769Sobrien } else { 1967236769Sobrien snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 1968236769Sobrien } 1969236769Sobrien if ((fd = mkstemp(tfile)) < 0) 1970236769Sobrien Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 1971236769Sobrien if (fnamep) { 1972236769Sobrien *fnamep = bmake_strdup(tfile); 1973236769Sobrien } else { 1974236769Sobrien unlink(tfile); /* we just want the descriptor */ 1975236769Sobrien } 1976236769Sobrien return fd; 1977236769Sobrien} 1978240330Smarcel 1979240330Smarcel 1980240330Smarcel/* 1981240330Smarcel * Return a Boolean based on setting of a knob. 1982240330Smarcel * 1983240330Smarcel * If the knob is not set, the supplied default is the return value. 1984240330Smarcel * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 1985240330Smarcel * is FALSE, otherwise TRUE. 1986240330Smarcel */ 1987240330SmarcelBoolean 1988240330SmarcelgetBoolean(const char *name, Boolean bf) 1989240330Smarcel{ 1990240330Smarcel char tmp[64]; 1991240330Smarcel char *cp; 1992240330Smarcel 1993240330Smarcel if (snprintf(tmp, sizeof(tmp), "${%s:tl}", name) < (int)(sizeof(tmp))) { 1994240330Smarcel cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1995240330Smarcel 1996240330Smarcel if (cp) { 1997240330Smarcel switch(*cp) { 1998240330Smarcel case '\0': /* not set - the default wins */ 1999240330Smarcel break; 2000240330Smarcel case '0': 2001240330Smarcel case 'f': 2002240330Smarcel case 'n': 2003240330Smarcel bf = FALSE; 2004240330Smarcel break; 2005240330Smarcel case 'o': 2006240330Smarcel switch (cp[1]) { 2007240330Smarcel case 'f': 2008240330Smarcel bf = FALSE; 2009240330Smarcel break; 2010240330Smarcel default: 2011240330Smarcel bf = TRUE; 2012240330Smarcel break; 2013240330Smarcel } 2014240330Smarcel break; 2015240330Smarcel default: 2016240330Smarcel bf = TRUE; 2017240330Smarcel break; 2018240330Smarcel } 2019240330Smarcel free(cp); 2020240330Smarcel } 2021240330Smarcel } 2022240330Smarcel return (bf); 2023240330Smarcel} 2024