main.c revision 49938
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 371590Srgrimes */ 381590Srgrimes 391590Srgrimes#ifndef lint 4027644Scharnierstatic const char copyright[] = 411590Srgrimes"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\ 421590Srgrimes The Regents of the University of California. All rights reserved.\n"; 431590Srgrimes#endif /* not lint */ 441590Srgrimes 451590Srgrimes#ifndef lint 4627644Scharnier#if 0 471590Srgrimesstatic char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 4849938Shoek#else 4949938Shoekstatic const char rcsid[] = 5049938Shoek "$Id: main.c,v 1.32 1999/07/31 20:53:01 hoek Exp $"; 5127644Scharnier#endif 521590Srgrimes#endif /* not lint */ 531590Srgrimes 541590Srgrimes/*- 551590Srgrimes * main.c -- 561590Srgrimes * The main file for this entire program. Exit routines etc 571590Srgrimes * reside here. 581590Srgrimes * 591590Srgrimes * Utility functions defined in this file: 601590Srgrimes * Main_ParseArgLine Takes a line of arguments, breaks them and 611590Srgrimes * treats them as if they were given when first 621590Srgrimes * invoked. Used by the parse module to implement 631590Srgrimes * the .MFLAGS target. 641590Srgrimes * 651590Srgrimes * Error Print a tagged error message. The global 661590Srgrimes * MAKE variable must have been defined. This 671590Srgrimes * takes a format string and two optional 681590Srgrimes * arguments for it. 691590Srgrimes * 701590Srgrimes * Fatal Print an error message and exit. Also takes 711590Srgrimes * a format string and two arguments. 721590Srgrimes * 731590Srgrimes * Punt Aborts all jobs and exits with a message. Also 741590Srgrimes * takes a format string and two arguments. 751590Srgrimes * 761590Srgrimes * Finish Finish things up by printing the number of 771590Srgrimes * errors which occured, as passed to it, and 781590Srgrimes * exiting. 791590Srgrimes */ 801590Srgrimes 811590Srgrimes#include <sys/types.h> 821590Srgrimes#include <sys/time.h> 831590Srgrimes#include <sys/param.h> 841590Srgrimes#include <sys/resource.h> 851590Srgrimes#include <sys/signal.h> 861590Srgrimes#include <sys/stat.h> 8739006Skato#if defined(__i386__) 8839006Skato#include <sys/sysctl.h> 8939006Skato#endif 9018730Ssteve#ifndef MACHINE 915814Sjkh#include <sys/utsname.h> 9218730Ssteve#endif 9318730Ssteve#include <sys/wait.h> 9427644Scharnier#include <err.h> 9529957Simp#include <stdlib.h> 961590Srgrimes#include <errno.h> 971590Srgrimes#include <fcntl.h> 981590Srgrimes#include <stdio.h> 9949331Shoek#include <sysexits.h> 10049938Shoek#ifdef __STDC__ 1011590Srgrimes#include <stdarg.h> 1021590Srgrimes#else 1031590Srgrimes#include <varargs.h> 1041590Srgrimes#endif 1051590Srgrimes#include "make.h" 1061590Srgrimes#include "hash.h" 1071590Srgrimes#include "dir.h" 1081590Srgrimes#include "job.h" 1091590Srgrimes#include "pathnames.h" 1101590Srgrimes 1111590Srgrimes#ifndef DEFMAXLOCAL 1121590Srgrimes#define DEFMAXLOCAL DEFMAXJOBS 11318730Ssteve#endif /* DEFMAXLOCAL */ 1141590Srgrimes 1151590Srgrimes#define MAKEFLAGS ".MAKEFLAGS" 1161590Srgrimes 1171590SrgrimesLst create; /* Targets to be made */ 1181590Srgrimestime_t now; /* Time at start of make */ 1191590SrgrimesGNode *DEFAULT; /* .DEFAULT node */ 1201590SrgrimesBoolean allPrecious; /* .PRECIOUS given on line by itself */ 1211590Srgrimes 1221590Srgrimesstatic Boolean noBuiltins; /* -r flag */ 1231590Srgrimesstatic Lst makefiles; /* ordered list of makefiles to read */ 12417193Sbdestatic Boolean printVars; /* print value of one or more vars */ 12517193Sbdestatic Lst variables; /* list of variables to print */ 12618730Ssteveint maxJobs; /* -j argument */ 12728228Sfsmpstatic Boolean forceJobs; /* -j argument given */ 1281590Srgrimesstatic int maxLocal; /* -L argument */ 1291590SrgrimesBoolean compatMake; /* -B argument */ 1301590SrgrimesBoolean debug; /* -d flag */ 1311590SrgrimesBoolean noExecute; /* -n flag */ 1321590SrgrimesBoolean keepgoing; /* -k flag */ 1331590SrgrimesBoolean queryFlag; /* -q flag */ 1341590SrgrimesBoolean touchFlag; /* -t flag */ 1351590SrgrimesBoolean usePipes; /* !-P flag */ 1361590SrgrimesBoolean ignoreErrors; /* -i flag */ 1371590SrgrimesBoolean beSilent; /* -s flag */ 13841151SdgBoolean beVerbose; /* -v flag */ 1391590SrgrimesBoolean oldVars; /* variable substitution style */ 1401590SrgrimesBoolean checkEnvFirst; /* -e flag */ 14149332ShoekLst envFirstVars; /* (-E) vars to override from env */ 1421590Srgrimesstatic Boolean jobsRunning; /* TRUE if the jobs might be running */ 1431590Srgrimes 14418730Sstevestatic void MainParseArgs __P((int, char **)); 14518730Sstevechar * chdir_verify_path __P((char *, char *)); 14618730Sstevestatic int ReadMakefile __P((ClientData, ClientData)); 14718730Sstevestatic void usage __P((void)); 1481590Srgrimes 1491590Srgrimesstatic char *curdir; /* startup directory */ 1501590Srgrimesstatic char *objdir; /* where we chdir'ed to */ 1511590Srgrimes 1521590Srgrimes/*- 1531590Srgrimes * MainParseArgs -- 1541590Srgrimes * Parse a given argument vector. Called from main() and from 1551590Srgrimes * Main_ParseArgLine() when the .MAKEFLAGS target is used. 1561590Srgrimes * 1571590Srgrimes * XXX: Deal with command line overriding .MAKEFLAGS in makefile 1581590Srgrimes * 1591590Srgrimes * Results: 1601590Srgrimes * None 1611590Srgrimes * 1621590Srgrimes * Side Effects: 1631590Srgrimes * Various global and local flags will be set depending on the flags 1641590Srgrimes * given 1651590Srgrimes */ 1661590Srgrimesstatic void 1671590SrgrimesMainParseArgs(argc, argv) 1681590Srgrimes int argc; 1691590Srgrimes char **argv; 1701590Srgrimes{ 1711590Srgrimes extern int optind; 1721590Srgrimes extern char *optarg; 17336942Speter char *p; 1745814Sjkh int c; 1751590Srgrimes 1761590Srgrimes optind = 1; /* since we're called more than once */ 17718730Ssteve#ifdef REMOTE 17849332Shoek# define OPTFLAGS "BD:E:I:L:PSV:d:ef:ij:km:nqrstv" 1791590Srgrimes#else 18049332Shoek# define OPTFLAGS "BD:E:I:PSV:d:ef:ij:km:nqrstv" 1811590Srgrimes#endif 18224360Simprearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) { 1831590Srgrimes switch(c) { 1841590Srgrimes case 'D': 1851590Srgrimes Var_Set(optarg, "1", VAR_GLOBAL); 1861590Srgrimes Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 1871590Srgrimes Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 1881590Srgrimes break; 1891590Srgrimes case 'I': 1901590Srgrimes Parse_AddIncludeDir(optarg); 1911590Srgrimes Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 1921590Srgrimes Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 1931590Srgrimes break; 19417193Sbde case 'V': 19517193Sbde printVars = TRUE; 19637872Simp p = malloc(strlen(optarg) + 1 + 3); 19736942Speter if (!p) 19836942Speter Punt("make: cannot allocate memory."); 19937872Simp /* This sprintf is safe, because of the malloc above */ 20037872Simp (void)sprintf(p, "${%s}", optarg); 20136942Speter (void)Lst_AtEnd(variables, (ClientData)p); 20217193Sbde Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 20317193Sbde Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 20417193Sbde break; 2051590Srgrimes case 'B': 2061590Srgrimes compatMake = TRUE; 20728746Sfsmp Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 2081590Srgrimes break; 20918730Ssteve#ifdef REMOTE 21049331Shoek case 'L': { 21149331Shoek char *endptr; 21249331Shoek 21349331Shoek maxLocal = strtol(optarg, &endptr, 10); 21449331Shoek if (maxLocal < 0 || *endptr != '\0') { 21549938Shoek warnx("illegal number, -L argument -- %s", 21649938Shoek optarg); 21749938Shoek usage(); 21849331Shoek } 2191590Srgrimes Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); 2201590Srgrimes Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 2211590Srgrimes break; 22249331Shoek } 22318730Ssteve#endif 2241590Srgrimes case 'P': 2251590Srgrimes usePipes = FALSE; 2261590Srgrimes Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); 2271590Srgrimes break; 2281590Srgrimes case 'S': 2291590Srgrimes keepgoing = FALSE; 2301590Srgrimes Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 2311590Srgrimes break; 2321590Srgrimes case 'd': { 2331590Srgrimes char *modules = optarg; 2341590Srgrimes 2351590Srgrimes for (; *modules; ++modules) 2361590Srgrimes switch (*modules) { 2371590Srgrimes case 'A': 2381590Srgrimes debug = ~0; 2391590Srgrimes break; 2401590Srgrimes case 'a': 2411590Srgrimes debug |= DEBUG_ARCH; 2421590Srgrimes break; 2431590Srgrimes case 'c': 2441590Srgrimes debug |= DEBUG_COND; 2451590Srgrimes break; 2461590Srgrimes case 'd': 2471590Srgrimes debug |= DEBUG_DIR; 2481590Srgrimes break; 2491590Srgrimes case 'f': 2501590Srgrimes debug |= DEBUG_FOR; 2511590Srgrimes break; 2521590Srgrimes case 'g': 2531590Srgrimes if (modules[1] == '1') { 2541590Srgrimes debug |= DEBUG_GRAPH1; 2551590Srgrimes ++modules; 2561590Srgrimes } 2571590Srgrimes else if (modules[1] == '2') { 2581590Srgrimes debug |= DEBUG_GRAPH2; 2591590Srgrimes ++modules; 2601590Srgrimes } 2611590Srgrimes break; 2621590Srgrimes case 'j': 2631590Srgrimes debug |= DEBUG_JOB; 2641590Srgrimes break; 2651590Srgrimes case 'm': 2661590Srgrimes debug |= DEBUG_MAKE; 2671590Srgrimes break; 2681590Srgrimes case 's': 2691590Srgrimes debug |= DEBUG_SUFF; 2701590Srgrimes break; 2711590Srgrimes case 't': 2721590Srgrimes debug |= DEBUG_TARG; 2731590Srgrimes break; 2741590Srgrimes case 'v': 2751590Srgrimes debug |= DEBUG_VAR; 2761590Srgrimes break; 2771590Srgrimes default: 27827644Scharnier warnx("illegal argument to d option -- %c", *modules); 2791590Srgrimes usage(); 2801590Srgrimes } 2811590Srgrimes Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 2821590Srgrimes Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 2831590Srgrimes break; 2841590Srgrimes } 28549332Shoek case 'E': 28649332Shoek p = malloc(strlen(optarg) + 1); 28749332Shoek if (!p) 28849332Shoek Punt("make: cannot allocate memory."); 28949332Shoek (void)strcpy(p, optarg); 29049332Shoek (void)Lst_AtEnd(envFirstVars, (ClientData)p); 29149332Shoek Var_Append(MAKEFLAGS, "-E", VAR_GLOBAL); 29249332Shoek Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 29349332Shoek break; 2941590Srgrimes case 'e': 2951590Srgrimes checkEnvFirst = TRUE; 2961590Srgrimes Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 2971590Srgrimes break; 2981590Srgrimes case 'f': 2991590Srgrimes (void)Lst_AtEnd(makefiles, (ClientData)optarg); 3001590Srgrimes break; 3011590Srgrimes case 'i': 3021590Srgrimes ignoreErrors = TRUE; 3031590Srgrimes Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 3041590Srgrimes break; 30549331Shoek case 'j': { 30649331Shoek char *endptr; 30749331Shoek 30818730Ssteve forceJobs = TRUE; 30949331Shoek maxJobs = strtol(optarg, &endptr, 10); 31049331Shoek if (maxJobs <= 0 || *endptr != '\0') { 31149938Shoek warnx("illegal number, -j argument -- %s", 31249938Shoek optarg); 31349938Shoek usage(); 31449331Shoek } 31518730Ssteve#ifndef REMOTE 31618730Ssteve maxLocal = maxJobs; 31718730Ssteve#endif 3181590Srgrimes Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 3191590Srgrimes Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 3201590Srgrimes break; 32149331Shoek } 3221590Srgrimes case 'k': 3231590Srgrimes keepgoing = TRUE; 3241590Srgrimes Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 3251590Srgrimes break; 32618730Ssteve case 'm': 32718730Ssteve Dir_AddDir(sysIncPath, optarg); 32818730Ssteve Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 32918730Ssteve Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 33018730Ssteve break; 3311590Srgrimes case 'n': 3321590Srgrimes noExecute = TRUE; 3331590Srgrimes Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 3341590Srgrimes break; 3351590Srgrimes case 'q': 3361590Srgrimes queryFlag = TRUE; 3371590Srgrimes /* Kind of nonsensical, wot? */ 3381590Srgrimes Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 3391590Srgrimes break; 3401590Srgrimes case 'r': 3411590Srgrimes noBuiltins = TRUE; 3421590Srgrimes Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 3431590Srgrimes break; 3441590Srgrimes case 's': 3451590Srgrimes beSilent = TRUE; 3461590Srgrimes Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 3471590Srgrimes break; 3481590Srgrimes case 't': 3491590Srgrimes touchFlag = TRUE; 3501590Srgrimes Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 3511590Srgrimes break; 35241151Sdg case 'v': 35341151Sdg beVerbose = TRUE; 35441151Sdg Var_Append(MAKEFLAGS, "-v", VAR_GLOBAL); 35541151Sdg break; 3561590Srgrimes default: 3571590Srgrimes case '?': 3581590Srgrimes usage(); 3591590Srgrimes } 3601590Srgrimes } 3611590Srgrimes 3621590Srgrimes oldVars = TRUE; 3631590Srgrimes 3641590Srgrimes /* 3651590Srgrimes * See if the rest of the arguments are variable assignments and 3661590Srgrimes * perform them if so. Else take them to be targets and stuff them 3671590Srgrimes * on the end of the "create" list. 3681590Srgrimes */ 3691590Srgrimes for (argv += optind, argc -= optind; *argv; ++argv, --argc) 3701590Srgrimes if (Parse_IsVar(*argv)) 3711590Srgrimes Parse_DoVar(*argv, VAR_CMD); 3721590Srgrimes else { 3731590Srgrimes if (!**argv) 3741590Srgrimes Punt("illegal (null) argument."); 3751590Srgrimes if (**argv == '-') { 3761590Srgrimes if ((*argv)[1]) 3771590Srgrimes optind = 0; /* -flag... */ 3781590Srgrimes else 3791590Srgrimes optind = 1; /* - */ 3801590Srgrimes goto rearg; 3811590Srgrimes } 38218730Ssteve (void)Lst_AtEnd(create, (ClientData)estrdup(*argv)); 3831590Srgrimes } 3841590Srgrimes} 3851590Srgrimes 3861590Srgrimes/*- 3871590Srgrimes * Main_ParseArgLine -- 3881590Srgrimes * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 3891590Srgrimes * is encountered and by main() when reading the .MAKEFLAGS envariable. 3901590Srgrimes * Takes a line of arguments and breaks it into its 3911590Srgrimes * component words and passes those words and the number of them to the 3921590Srgrimes * MainParseArgs function. 3931590Srgrimes * The line should have all its leading whitespace removed. 3941590Srgrimes * 3951590Srgrimes * Results: 3961590Srgrimes * None 3971590Srgrimes * 3981590Srgrimes * Side Effects: 3991590Srgrimes * Only those that come from the various arguments. 4001590Srgrimes */ 4011590Srgrimesvoid 4021590SrgrimesMain_ParseArgLine(line) 4031590Srgrimes char *line; /* Line to fracture */ 4041590Srgrimes{ 4051590Srgrimes char **argv; /* Manufactured argument vector */ 4061590Srgrimes int argc; /* Number of arguments in argv */ 4071590Srgrimes 4081590Srgrimes if (line == NULL) 4091590Srgrimes return; 4101590Srgrimes for (; *line == ' '; ++line) 4111590Srgrimes continue; 4121590Srgrimes if (!*line) 4131590Srgrimes return; 4141590Srgrimes 4155814Sjkh argv = brk_string(line, &argc, TRUE); 4161590Srgrimes MainParseArgs(argc, argv); 4171590Srgrimes} 4181590Srgrimes 41918339Sswallacechar * 42018339Sswallacechdir_verify_path(path, obpath) 42118339Sswallace char *path; 42218339Sswallace char *obpath; 42318339Sswallace{ 42418339Sswallace struct stat sb; 42518339Sswallace 42618339Sswallace if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 42718339Sswallace if (chdir(path)) { 42827644Scharnier warn("warning: %s", path); 42918339Sswallace return 0; 43018339Sswallace } 43118339Sswallace else { 43218339Sswallace if (path[0] != '/') { 43318339Sswallace (void) snprintf(obpath, MAXPATHLEN, "%s/%s", 43418339Sswallace curdir, path); 43518339Sswallace return obpath; 43618339Sswallace } 43718339Sswallace else 43818339Sswallace return path; 43918339Sswallace } 44018339Sswallace } 44118339Sswallace 44218339Sswallace return 0; 44318339Sswallace} 44418339Sswallace 44518339Sswallace 4461590Srgrimes/*- 4471590Srgrimes * main -- 4481590Srgrimes * The main function, for obvious reasons. Initializes variables 4491590Srgrimes * and a few modules, then parses the arguments give it in the 4501590Srgrimes * environment and on the command line. Reads the system makefile 4511590Srgrimes * followed by either Makefile, makefile or the file given by the 4521590Srgrimes * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 4531590Srgrimes * flags it has received by then uses either the Make or the Compat 4541590Srgrimes * module to create the initial list of targets. 4551590Srgrimes * 4561590Srgrimes * Results: 4571590Srgrimes * If -q was given, exits -1 if anything was out-of-date. Else it exits 4581590Srgrimes * 0. 4591590Srgrimes * 4601590Srgrimes * Side Effects: 4611590Srgrimes * The program exits when done. Targets are created. etc. etc. etc. 4621590Srgrimes */ 4631590Srgrimesint 4641590Srgrimesmain(argc, argv) 4651590Srgrimes int argc; 4661590Srgrimes char **argv; 4671590Srgrimes{ 4681590Srgrimes Lst targs; /* target nodes to create -- passed to Make_Init */ 4691590Srgrimes Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ 47040500Sobrien struct stat sa; 47140500Sobrien char *p, *p1, *path, *pathp; 47240500Sobrien#ifdef WANT_ENV_PWD 47340500Sobrien struct stat sb; 47440500Sobrien char *pwd; 47540500Sobrien#endif 4761590Srgrimes char mdpath[MAXPATHLEN + 1]; 4771590Srgrimes char obpath[MAXPATHLEN + 1]; 4781590Srgrimes char cdpath[MAXPATHLEN + 1]; 4795814Sjkh char *machine = getenv("MACHINE"); 48044362Simp char *machine_arch = getenv("MACHINE_ARCH"); 48118730Ssteve Lst sysMkPath; /* Path of sys.mk */ 48218730Ssteve char *cp = NULL, *start; 48318730Ssteve /* avoid faults on read-only strings */ 48418730Ssteve static char syspath[] = _PATH_DEFSYSPATH; 4851590Srgrimes 48618730Ssteve#ifdef RLIMIT_NOFILE 4871590Srgrimes /* 48818730Ssteve * get rid of resource limit on file descriptors 48918730Ssteve */ 49018730Ssteve { 49118730Ssteve struct rlimit rl; 49218730Ssteve if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 49318730Ssteve rl.rlim_cur != rl.rlim_max) { 49418730Ssteve rl.rlim_cur = rl.rlim_max; 49518730Ssteve (void) setrlimit(RLIMIT_NOFILE, &rl); 49618730Ssteve } 49718730Ssteve } 49818730Ssteve#endif 49918730Ssteve /* 5001590Srgrimes * Find where we are and take care of PWD for the automounter... 5011590Srgrimes * All this code is so that we know where we are when we start up 5021590Srgrimes * on a different machine with pmake. 5031590Srgrimes */ 5041590Srgrimes curdir = cdpath; 50527644Scharnier if (getcwd(curdir, MAXPATHLEN) == NULL) 50627644Scharnier err(2, NULL); 5071590Srgrimes 50827644Scharnier if (stat(curdir, &sa) == -1) 50927644Scharnier err(2, "%s", curdir); 5101590Srgrimes 51140500Sobrien#ifdef WANT_ENV_PWD 51216885Sjkh if ((pwd = getenv("PWD")) != NULL) { 51316885Sjkh if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && 51416885Sjkh sa.st_dev == sb.st_dev) 51516885Sjkh (void) strcpy(curdir, pwd); 51616885Sjkh } 51740500Sobrien#endif 51816885Sjkh 51939006Skato#if defined(__i386__) 5205814Sjkh /* 52139006Skato * PC-98 kernel sets the `i386' string to the utsname.machine and 52239006Skato * it cannot be distinguished from IBM-PC by uname(3). Therefore, 52339006Skato * we check machine.ispc98 and adjust the machine variable before 52439006Skato * using usname(3) below. 52539006Skato */ 52639006Skato if (!machine) { 52739006Skato int ispc98; 52839006Skato size_t len; 52939006Skato 53039006Skato len = sizeof(ispc98); 53139006Skato if (!sysctlbyname("machdep.ispc98", &ispc98, &len, NULL, 0)) { 53239006Skato if (ispc98) 53339006Skato machine = "pc98"; 53439006Skato } 53539006Skato } 53639006Skato#endif 53739006Skato 53839006Skato /* 5395814Sjkh * Get the name of this type of MACHINE from utsname 5405814Sjkh * so we can share an executable for similar machines. 5415814Sjkh * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 5425814Sjkh * 5435814Sjkh * Note that while MACHINE is decided at run-time, 5445814Sjkh * MACHINE_ARCH is always known at compile time. 5455814Sjkh */ 54618864Ssteve if (!machine) { 54718339Sswallace#ifndef MACHINE 54818730Ssteve struct utsname utsname; 54918730Ssteve 55018339Sswallace if (uname(&utsname) == -1) { 5515814Sjkh perror("make: uname"); 5525814Sjkh exit(2); 5535814Sjkh } 5545814Sjkh machine = utsname.machine; 55518339Sswallace#else 55618339Sswallace machine = MACHINE; 55718339Sswallace#endif 5585814Sjkh } 5591590Srgrimes 56044362Simp if (!machine_arch) { 56144362Simp#ifndef MACHINE_ARCH 56244362Simp machine_arch = "unknown"; 56344362Simp#else 56444362Simp machine_arch = MACHINE_ARCH; 56544362Simp#endif 56644362Simp } 56744362Simp 5681590Srgrimes /* 56918759Ssteve * The object directory location is determined using the 57018759Ssteve * following order of preference: 57118759Ssteve * 57218759Ssteve * 1. MAKEOBJDIRPREFIX`cwd` 57318759Ssteve * 2. MAKEOBJDIR 57418759Ssteve * 3. _PATH_OBJDIR.${MACHINE} 57518759Ssteve * 4. _PATH_OBJDIR 57649938Shoek * 5. _PATH_OBJDIRPREFIX`cwd` 57718759Ssteve * 57849938Shoek * If one of the first two fails, use the current directory. 57949938Shoek * If the remaining three all fail, use the current directory. 58018339Sswallace * 58118339Sswallace * Once things are initted, 58218339Sswallace * have to add the original directory to the search path, 5831590Srgrimes * and modify the paths for the Makefiles apropriately. The 5841590Srgrimes * current directory is also placed as a variable for make scripts. 5851590Srgrimes */ 58618339Sswallace if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) { 58718339Sswallace if (!(path = getenv("MAKEOBJDIR"))) { 58818339Sswallace path = _PATH_OBJDIR; 58918339Sswallace pathp = _PATH_OBJDIRPREFIX; 59018339Sswallace (void) snprintf(mdpath, MAXPATHLEN, "%s.%s", 59118339Sswallace path, machine); 59218339Sswallace if (!(objdir = chdir_verify_path(mdpath, obpath))) 59318339Sswallace if (!(objdir=chdir_verify_path(path, obpath))) { 59418339Sswallace (void) snprintf(mdpath, MAXPATHLEN, 59518339Sswallace "%s%s", pathp, curdir); 59618339Sswallace if (!(objdir=chdir_verify_path(mdpath, 59718339Sswallace obpath))) 59818339Sswallace objdir = curdir; 59918339Sswallace } 60018339Sswallace } 60118339Sswallace else if (!(objdir = chdir_verify_path(path, obpath))) 6021590Srgrimes objdir = curdir; 6031590Srgrimes } 60418339Sswallace else { 60518339Sswallace (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir); 60618339Sswallace if (!(objdir = chdir_verify_path(mdpath, obpath))) 60718339Sswallace objdir = curdir; 60818339Sswallace } 6091590Srgrimes 61040500Sobrien#ifdef WANT_ENV_PWD 6111590Srgrimes setenv("PWD", objdir, 1); 61240500Sobrien#endif 6131590Srgrimes 6141590Srgrimes create = Lst_Init(FALSE); 6151590Srgrimes makefiles = Lst_Init(FALSE); 61649332Shoek envFirstVars = Lst_Init(FALSE); 61717193Sbde printVars = FALSE; 61817193Sbde variables = Lst_Init(FALSE); 6191590Srgrimes beSilent = FALSE; /* Print commands as executed */ 6201590Srgrimes ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 6211590Srgrimes noExecute = FALSE; /* Execute all commands */ 6221590Srgrimes keepgoing = FALSE; /* Stop on error */ 6231590Srgrimes allPrecious = FALSE; /* Remove targets when interrupted */ 6241590Srgrimes queryFlag = FALSE; /* This is not just a check-run */ 6251590Srgrimes noBuiltins = FALSE; /* Read the built-in rules */ 6261590Srgrimes touchFlag = FALSE; /* Actually update targets */ 6271590Srgrimes usePipes = TRUE; /* Catch child output in pipes */ 6281590Srgrimes debug = 0; /* No debug verbosity, please. */ 6291590Srgrimes jobsRunning = FALSE; 6301590Srgrimes 63118730Ssteve maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ 63218730Ssteve#ifdef REMOTE 6331590Srgrimes maxJobs = DEFMAXJOBS; /* Set default max concurrency */ 6341590Srgrimes#else 63518730Ssteve maxJobs = maxLocal; 6361590Srgrimes#endif 63728228Sfsmp forceJobs = FALSE; /* No -j flag */ 63818730Ssteve compatMake = FALSE; /* No compat mode */ 6391590Srgrimes 6408874Srgrimes 6411590Srgrimes /* 6421590Srgrimes * Initialize the parsing, directory and variable modules to prepare 6431590Srgrimes * for the reading of inclusion paths and variable settings on the 6441590Srgrimes * command line 6451590Srgrimes */ 6461590Srgrimes Dir_Init(); /* Initialize directory structures so -I flags 6471590Srgrimes * can be processed correctly */ 6481590Srgrimes Parse_Init(); /* Need to initialize the paths of #include 6491590Srgrimes * directories */ 6501590Srgrimes Var_Init(); /* As well as the lists of variables for 6511590Srgrimes * parsing arguments */ 6525814Sjkh str_init(); 6531590Srgrimes if (objdir != curdir) 6541590Srgrimes Dir_AddDir(dirSearchPath, curdir); 6551590Srgrimes Var_Set(".CURDIR", curdir, VAR_GLOBAL); 6561590Srgrimes Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 6571590Srgrimes 6581590Srgrimes /* 6591590Srgrimes * Initialize various variables. 6601590Srgrimes * MAKE also gets this name, for compatibility 6611590Srgrimes * .MAKEFLAGS gets set to the empty string just in case. 6621590Srgrimes * MFLAGS also gets initialized empty, for compatibility. 6631590Srgrimes */ 6641590Srgrimes Var_Set("MAKE", argv[0], VAR_GLOBAL); 6651590Srgrimes Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 6661590Srgrimes Var_Set("MFLAGS", "", VAR_GLOBAL); 6675814Sjkh Var_Set("MACHINE", machine, VAR_GLOBAL); 66844362Simp Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 6691590Srgrimes 6701590Srgrimes /* 6711590Srgrimes * First snag any flags out of the MAKE environment variable. 6721590Srgrimes * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 6731590Srgrimes * in a different format). 6741590Srgrimes */ 6751590Srgrimes#ifdef POSIX 6761590Srgrimes Main_ParseArgLine(getenv("MAKEFLAGS")); 6771590Srgrimes#else 6781590Srgrimes Main_ParseArgLine(getenv("MAKE")); 6791590Srgrimes#endif 6808874Srgrimes 6811590Srgrimes MainParseArgs(argc, argv); 6821590Srgrimes 6831590Srgrimes /* 68428228Sfsmp * Be compatible if user did not specify -j and did not explicitly 68528228Sfsmp * turned compatibility on 68628228Sfsmp */ 68728228Sfsmp if (!compatMake && !forceJobs) 68828228Sfsmp compatMake = TRUE; 68928228Sfsmp 69028228Sfsmp /* 6911590Srgrimes * Initialize archive, target and suffix modules in preparation for 6921590Srgrimes * parsing the makefile(s) 6931590Srgrimes */ 6941590Srgrimes Arch_Init(); 6951590Srgrimes Targ_Init(); 6961590Srgrimes Suff_Init(); 6971590Srgrimes 6981590Srgrimes DEFAULT = NILGNODE; 6991590Srgrimes (void)time(&now); 7001590Srgrimes 7011590Srgrimes /* 7021590Srgrimes * Set up the .TARGETS variable to contain the list of targets to be 7031590Srgrimes * created. If none specified, make the variable empty -- the parser 7041590Srgrimes * will fill the thing in with the default or .MAIN target. 7051590Srgrimes */ 7061590Srgrimes if (!Lst_IsEmpty(create)) { 7071590Srgrimes LstNode ln; 7081590Srgrimes 7091590Srgrimes for (ln = Lst_First(create); ln != NILLNODE; 7101590Srgrimes ln = Lst_Succ(ln)) { 7111590Srgrimes char *name = (char *)Lst_Datum(ln); 7121590Srgrimes 7131590Srgrimes Var_Append(".TARGETS", name, VAR_GLOBAL); 7141590Srgrimes } 7151590Srgrimes } else 7161590Srgrimes Var_Set(".TARGETS", "", VAR_GLOBAL); 7171590Srgrimes 71818730Ssteve 7191590Srgrimes /* 72018730Ssteve * If no user-supplied system path was given (through the -m option) 72118730Ssteve * add the directories from the DEFSYSPATH (more than one may be given 72218730Ssteve * as dir1:...:dirn) to the system include path. 7231590Srgrimes */ 72418730Ssteve if (Lst_IsEmpty(sysIncPath)) { 72518730Ssteve for (start = syspath; *start != '\0'; start = cp) { 72618730Ssteve for (cp = start; *cp != '\0' && *cp != ':'; cp++) 72718730Ssteve continue; 72818730Ssteve if (*cp == '\0') { 72918730Ssteve Dir_AddDir(sysIncPath, start); 73018730Ssteve } else { 73118730Ssteve *cp++ = '\0'; 73218730Ssteve Dir_AddDir(sysIncPath, start); 73318730Ssteve } 73418730Ssteve } 73518730Ssteve } 7361590Srgrimes 73718730Ssteve /* 73818730Ssteve * Read in the built-in rules first, followed by the specified 73918730Ssteve * makefile, if it was (makefile != (char *) NULL), or the default 74018730Ssteve * Makefile and makefile, in that order, if it wasn't. 74118730Ssteve */ 74218730Ssteve if (!noBuiltins) { 74318730Ssteve LstNode ln; 74418730Ssteve 74518730Ssteve sysMkPath = Lst_Init (FALSE); 74618730Ssteve Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath); 74718730Ssteve if (Lst_IsEmpty(sysMkPath)) 74818730Ssteve Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); 74918730Ssteve ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); 75018730Ssteve if (ln != NILLNODE) 75118730Ssteve Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); 75218730Ssteve } 75318730Ssteve 7541590Srgrimes if (!Lst_IsEmpty(makefiles)) { 7551590Srgrimes LstNode ln; 7561590Srgrimes 7571590Srgrimes ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); 7581590Srgrimes if (ln != NILLNODE) 7591590Srgrimes Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); 76018730Ssteve } else if (!ReadMakefile("makefile", NULL)) 76118730Ssteve (void)ReadMakefile("Makefile", NULL); 7621590Srgrimes 76318730Ssteve (void)ReadMakefile(".depend", NULL); 7641590Srgrimes 7655814Sjkh Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 76649938Shoek efree(p1); 7671590Srgrimes 7681590Srgrimes /* Install all the flags into the MAKE envariable. */ 7695814Sjkh if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p) 7701590Srgrimes#ifdef POSIX 7711590Srgrimes setenv("MAKEFLAGS", p, 1); 7721590Srgrimes#else 7731590Srgrimes setenv("MAKE", p, 1); 7741590Srgrimes#endif 77549938Shoek efree(p1); 7761590Srgrimes 7771590Srgrimes /* 7781590Srgrimes * For compatibility, look at the directories in the VPATH variable 7791590Srgrimes * and add them to the search path, if the variable is defined. The 7801590Srgrimes * variable's value is in the same format as the PATH envariable, i.e. 7811590Srgrimes * <directory>:<directory>:<directory>... 7821590Srgrimes */ 7831590Srgrimes if (Var_Exists("VPATH", VAR_CMD)) { 7841590Srgrimes char *vpath, *path, *cp, savec; 7851590Srgrimes /* 7861590Srgrimes * GCC stores string constants in read-only memory, but 7871590Srgrimes * Var_Subst will want to write this thing, so store it 7881590Srgrimes * in an array 7891590Srgrimes */ 7901590Srgrimes static char VPATH[] = "${VPATH}"; 7911590Srgrimes 7921590Srgrimes vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 7931590Srgrimes path = vpath; 7941590Srgrimes do { 7951590Srgrimes /* skip to end of directory */ 7961590Srgrimes for (cp = path; *cp != ':' && *cp != '\0'; cp++) 7971590Srgrimes continue; 7981590Srgrimes /* Save terminator character so know when to stop */ 7991590Srgrimes savec = *cp; 8001590Srgrimes *cp = '\0'; 8011590Srgrimes /* Add directory to search path */ 8021590Srgrimes Dir_AddDir(dirSearchPath, path); 8031590Srgrimes *cp = savec; 8041590Srgrimes path = cp + 1; 8051590Srgrimes } while (savec == ':'); 8061590Srgrimes (void)free((Address)vpath); 8071590Srgrimes } 8081590Srgrimes 8091590Srgrimes /* 8101590Srgrimes * Now that all search paths have been read for suffixes et al, it's 8111590Srgrimes * time to add the default search path to their lists... 8121590Srgrimes */ 8131590Srgrimes Suff_DoPaths(); 8141590Srgrimes 8151590Srgrimes /* print the initial graph, if the user requested it */ 8161590Srgrimes if (DEBUG(GRAPH1)) 8171590Srgrimes Targ_PrintGraph(1); 8181590Srgrimes 81917193Sbde /* print the values of any variables requested by the user */ 82017193Sbde if (printVars) { 82117193Sbde LstNode ln; 82217193Sbde 82317193Sbde for (ln = Lst_First(variables); ln != NILLNODE; 82417193Sbde ln = Lst_Succ(ln)) { 82536942Speter char *value = Var_Subst(NULL, (char *)Lst_Datum(ln), 82636942Speter VAR_GLOBAL, FALSE); 82717193Sbde 82817193Sbde printf("%s\n", value ? value : ""); 82917193Sbde } 83017193Sbde } 83117193Sbde 8321590Srgrimes /* 8331590Srgrimes * Have now read the entire graph and need to make a list of targets 8341590Srgrimes * to create. If none was given on the command line, we consult the 8351590Srgrimes * parsing module to find the main target(s) to create. 8361590Srgrimes */ 8371590Srgrimes if (Lst_IsEmpty(create)) 8381590Srgrimes targs = Parse_MainName(); 8391590Srgrimes else 8401590Srgrimes targs = Targ_FindList(create, TARG_CREATE); 8411590Srgrimes 84217193Sbde if (!compatMake && !printVars) { 8431590Srgrimes /* 8441590Srgrimes * Initialize job module before traversing the graph, now that 8451590Srgrimes * any .BEGIN and .END targets have been read. This is done 8461590Srgrimes * only if the -q flag wasn't given (to prevent the .BEGIN from 8471590Srgrimes * being executed should it exist). 8481590Srgrimes */ 8491590Srgrimes if (!queryFlag) { 8501590Srgrimes if (maxLocal == -1) 8511590Srgrimes maxLocal = maxJobs; 8521590Srgrimes Job_Init(maxJobs, maxLocal); 8531590Srgrimes jobsRunning = TRUE; 8541590Srgrimes } 8551590Srgrimes 8561590Srgrimes /* Traverse the graph, checking on all the targets */ 8571590Srgrimes outOfDate = Make_Run(targs); 85817193Sbde } else if (!printVars) { 8591590Srgrimes /* 8601590Srgrimes * Compat_Init will take care of creating all the targets as 8611590Srgrimes * well as initializing the module. 8621590Srgrimes */ 8631590Srgrimes Compat_Run(targs); 86417193Sbde } 8658874Srgrimes 8665814Sjkh Lst_Destroy(targs, NOFREE); 86717193Sbde Lst_Destroy(variables, NOFREE); 8685814Sjkh Lst_Destroy(makefiles, NOFREE); 8695814Sjkh Lst_Destroy(create, (void (*) __P((ClientData))) free); 8705814Sjkh 8711590Srgrimes /* print the graph now it's been processed if the user requested it */ 8721590Srgrimes if (DEBUG(GRAPH2)) 8731590Srgrimes Targ_PrintGraph(2); 8741590Srgrimes 8755814Sjkh Suff_End(); 8765814Sjkh Targ_End(); 8775814Sjkh Arch_End(); 8785814Sjkh str_end(); 8795814Sjkh Var_End(); 8805814Sjkh Parse_End(); 8815814Sjkh Dir_End(); 8825814Sjkh 8831590Srgrimes if (queryFlag && outOfDate) 8841590Srgrimes return(1); 8851590Srgrimes else 8861590Srgrimes return(0); 8871590Srgrimes} 8881590Srgrimes 8891590Srgrimes/*- 8901590Srgrimes * ReadMakefile -- 8911590Srgrimes * Open and parse the given makefile. 8921590Srgrimes * 8931590Srgrimes * Results: 8941590Srgrimes * TRUE if ok. FALSE if couldn't open file. 8951590Srgrimes * 8961590Srgrimes * Side Effects: 8971590Srgrimes * lots 8981590Srgrimes */ 8991590Srgrimesstatic Boolean 90018730SsteveReadMakefile(p, q) 90118730Ssteve ClientData p, q; 9021590Srgrimes{ 90318730Ssteve char *fname = p; /* makefile to read */ 90418730Ssteve extern Lst parseIncPath; 9051590Srgrimes FILE *stream; 9061590Srgrimes char *name, path[MAXPATHLEN + 1]; 9071590Srgrimes 9081590Srgrimes if (!strcmp(fname, "-")) { 9091590Srgrimes Parse_File("(stdin)", stdin); 9101590Srgrimes Var_Set("MAKEFILE", "", VAR_GLOBAL); 9111590Srgrimes } else { 9121590Srgrimes /* if we've chdir'd, rebuild the path name */ 9131590Srgrimes if (curdir != objdir && *fname != '/') { 9141590Srgrimes (void)sprintf(path, "%s/%s", curdir, fname); 9151590Srgrimes if ((stream = fopen(path, "r")) != NULL) { 9161590Srgrimes fname = path; 9171590Srgrimes goto found; 9181590Srgrimes } 91928828Sjkh } else if ((stream = fopen(fname, "r")) != NULL) 92028828Sjkh goto found; 9211590Srgrimes /* look in -I and system include directories. */ 9221590Srgrimes name = Dir_FindFile(fname, parseIncPath); 9231590Srgrimes if (!name) 9241590Srgrimes name = Dir_FindFile(fname, sysIncPath); 9251590Srgrimes if (!name || !(stream = fopen(name, "r"))) 9261590Srgrimes return(FALSE); 9271590Srgrimes fname = name; 9281590Srgrimes /* 9291590Srgrimes * set the MAKEFILE variable desired by System V fans -- the 9301590Srgrimes * placement of the setting here means it gets set to the last 9311590Srgrimes * makefile specified, as it is set by SysV make. 9321590Srgrimes */ 9331590Srgrimesfound: Var_Set("MAKEFILE", fname, VAR_GLOBAL); 9341590Srgrimes Parse_File(fname, stream); 9351590Srgrimes (void)fclose(stream); 9361590Srgrimes } 9371590Srgrimes return(TRUE); 9381590Srgrimes} 9391590Srgrimes 9401590Srgrimes/*- 94118730Ssteve * Cmd_Exec -- 94218730Ssteve * Execute the command in cmd, and return the output of that command 94318730Ssteve * in a string. 94418730Ssteve * 94518730Ssteve * Results: 94618730Ssteve * A string containing the output of the command, or the empty string 94718730Ssteve * If err is not NULL, it contains the reason for the command failure 94818730Ssteve * 94918730Ssteve * Side Effects: 95018730Ssteve * The string must be freed by the caller. 95118730Ssteve */ 95218730Sstevechar * 95318730SsteveCmd_Exec(cmd, err) 95418730Ssteve char *cmd; 95518730Ssteve char **err; 95618730Ssteve{ 95718730Ssteve char *args[4]; /* Args for invoking the shell */ 95818730Ssteve int fds[2]; /* Pipe streams */ 95918730Ssteve int cpid; /* Child PID */ 96018730Ssteve int pid; /* PID from wait() */ 96118730Ssteve char *res; /* result */ 96218730Ssteve int status; /* command exit status */ 96318730Ssteve Buffer buf; /* buffer to store the result */ 96418730Ssteve char *cp; 96518730Ssteve int cc; 96618730Ssteve 96718730Ssteve 96818730Ssteve *err = NULL; 96918730Ssteve 97018730Ssteve /* 97118730Ssteve * Set up arguments for shell 97218730Ssteve */ 97318730Ssteve args[0] = "sh"; 97418730Ssteve args[1] = "-c"; 97518730Ssteve args[2] = cmd; 97618730Ssteve args[3] = NULL; 97718730Ssteve 97818730Ssteve /* 97918730Ssteve * Open a pipe for fetching its output 98018730Ssteve */ 98118730Ssteve if (pipe(fds) == -1) { 98218730Ssteve *err = "Couldn't create pipe for \"%s\""; 98318730Ssteve goto bad; 98418730Ssteve } 98518730Ssteve 98618730Ssteve /* 98718730Ssteve * Fork 98818730Ssteve */ 98918730Ssteve switch (cpid = vfork()) { 99018730Ssteve case 0: 99118730Ssteve /* 99218730Ssteve * Close input side of pipe 99318730Ssteve */ 99418730Ssteve (void) close(fds[0]); 99518730Ssteve 99618730Ssteve /* 99718730Ssteve * Duplicate the output stream to the shell's output, then 99818730Ssteve * shut the extra thing down. Note we don't fetch the error 99918730Ssteve * stream...why not? Why? 100018730Ssteve */ 100118730Ssteve (void) dup2(fds[1], 1); 100218730Ssteve (void) close(fds[1]); 100318730Ssteve 100418730Ssteve (void) execv("/bin/sh", args); 100518730Ssteve _exit(1); 100618730Ssteve /*NOTREACHED*/ 100718730Ssteve 100818730Ssteve case -1: 100918730Ssteve *err = "Couldn't exec \"%s\""; 101018730Ssteve goto bad; 101118730Ssteve 101218730Ssteve default: 101318730Ssteve /* 101418730Ssteve * No need for the writing half 101518730Ssteve */ 101618730Ssteve (void) close(fds[1]); 101718730Ssteve 101818730Ssteve buf = Buf_Init (MAKE_BSIZE); 101918730Ssteve 102018730Ssteve do { 102118730Ssteve char result[BUFSIZ]; 102218730Ssteve cc = read(fds[0], result, sizeof(result)); 102318730Ssteve if (cc > 0) 102418730Ssteve Buf_AddBytes(buf, cc, (Byte *) result); 102518730Ssteve } 102618730Ssteve while (cc > 0 || (cc == -1 && errno == EINTR)); 102718730Ssteve 102818730Ssteve /* 102918730Ssteve * Close the input side of the pipe. 103018730Ssteve */ 103118730Ssteve (void) close(fds[0]); 103218730Ssteve 103318730Ssteve /* 103418730Ssteve * Wait for the process to exit. 103518730Ssteve */ 103618730Ssteve while(((pid = wait(&status)) != cpid) && (pid >= 0)) 103718730Ssteve continue; 103818730Ssteve 103918877Ssteve if (cc == -1) 104018877Ssteve *err = "Error reading shell's output for \"%s\""; 104118864Ssteve 104218730Ssteve res = (char *)Buf_GetAll (buf, &cc); 104318730Ssteve Buf_Destroy (buf, FALSE); 104418730Ssteve 104518730Ssteve if (status) 104618730Ssteve *err = "\"%s\" returned non-zero status"; 104718730Ssteve 104818730Ssteve /* 104918730Ssteve * Null-terminate the result, convert newlines to spaces and 105018730Ssteve * install it in the variable. 105118730Ssteve */ 105218730Ssteve res[cc] = '\0'; 105318730Ssteve cp = &res[cc] - 1; 105418730Ssteve 105518730Ssteve if (*cp == '\n') { 105618730Ssteve /* 105718730Ssteve * A final newline is just stripped 105818730Ssteve */ 105918730Ssteve *cp-- = '\0'; 106018730Ssteve } 106118730Ssteve while (cp >= res) { 106218730Ssteve if (*cp == '\n') { 106318730Ssteve *cp = ' '; 106418730Ssteve } 106518730Ssteve cp--; 106618730Ssteve } 106718730Ssteve break; 106818730Ssteve } 106918730Ssteve return res; 107018730Sstevebad: 107118730Ssteve res = emalloc(1); 107218730Ssteve *res = '\0'; 107318730Ssteve return res; 107418730Ssteve} 107518730Ssteve 107618730Ssteve/*- 10771590Srgrimes * Error -- 10781590Srgrimes * Print an error message given its format. 10791590Srgrimes * 10801590Srgrimes * Results: 10811590Srgrimes * None. 10821590Srgrimes * 10831590Srgrimes * Side Effects: 10841590Srgrimes * The message is printed. 10851590Srgrimes */ 10861590Srgrimes/* VARARGS */ 10871590Srgrimesvoid 108849938Shoek#ifdef __STDC__ 10895814SjkhError(char *fmt, ...) 10901590Srgrimes#else 10911590SrgrimesError(va_alist) 10921590Srgrimes va_dcl 10931590Srgrimes#endif 10941590Srgrimes{ 10951590Srgrimes va_list ap; 109649938Shoek#ifdef __STDC__ 10971590Srgrimes va_start(ap, fmt); 10981590Srgrimes#else 10991590Srgrimes char *fmt; 11001590Srgrimes 11011590Srgrimes va_start(ap); 11021590Srgrimes fmt = va_arg(ap, char *); 11031590Srgrimes#endif 11041590Srgrimes (void)vfprintf(stderr, fmt, ap); 11051590Srgrimes va_end(ap); 11061590Srgrimes (void)fprintf(stderr, "\n"); 11071590Srgrimes (void)fflush(stderr); 11081590Srgrimes} 11091590Srgrimes 11101590Srgrimes/*- 11111590Srgrimes * Fatal -- 11121590Srgrimes * Produce a Fatal error message. If jobs are running, waits for them 11131590Srgrimes * to finish. 11141590Srgrimes * 11151590Srgrimes * Results: 11161590Srgrimes * None 11171590Srgrimes * 11181590Srgrimes * Side Effects: 11191590Srgrimes * The program exits 11201590Srgrimes */ 11211590Srgrimes/* VARARGS */ 11221590Srgrimesvoid 112349938Shoek#ifdef __STDC__ 11245814SjkhFatal(char *fmt, ...) 11251590Srgrimes#else 11261590SrgrimesFatal(va_alist) 11271590Srgrimes va_dcl 11281590Srgrimes#endif 11291590Srgrimes{ 11301590Srgrimes va_list ap; 113149938Shoek#ifdef __STDC__ 11321590Srgrimes va_start(ap, fmt); 11331590Srgrimes#else 11341590Srgrimes char *fmt; 11351590Srgrimes 11361590Srgrimes va_start(ap); 11371590Srgrimes fmt = va_arg(ap, char *); 11381590Srgrimes#endif 11391590Srgrimes if (jobsRunning) 11401590Srgrimes Job_Wait(); 11411590Srgrimes 11421590Srgrimes (void)vfprintf(stderr, fmt, ap); 11431590Srgrimes va_end(ap); 11441590Srgrimes (void)fprintf(stderr, "\n"); 11451590Srgrimes (void)fflush(stderr); 11461590Srgrimes 11471590Srgrimes if (DEBUG(GRAPH2)) 11481590Srgrimes Targ_PrintGraph(2); 11491590Srgrimes exit(2); /* Not 1 so -q can distinguish error */ 11501590Srgrimes} 11511590Srgrimes 11521590Srgrimes/* 11531590Srgrimes * Punt -- 11541590Srgrimes * Major exception once jobs are being created. Kills all jobs, prints 11551590Srgrimes * a message and exits. 11561590Srgrimes * 11571590Srgrimes * Results: 11588874Srgrimes * None 11591590Srgrimes * 11601590Srgrimes * Side Effects: 11611590Srgrimes * All children are killed indiscriminately and the program Lib_Exits 11621590Srgrimes */ 11631590Srgrimes/* VARARGS */ 11641590Srgrimesvoid 116549938Shoek#ifdef __STDC__ 11665814SjkhPunt(char *fmt, ...) 11671590Srgrimes#else 11681590SrgrimesPunt(va_alist) 11691590Srgrimes va_dcl 11701590Srgrimes#endif 11711590Srgrimes{ 11721590Srgrimes va_list ap; 11731590Srgrimes#if __STDC__ 11741590Srgrimes va_start(ap, fmt); 11751590Srgrimes#else 11761590Srgrimes char *fmt; 11771590Srgrimes 11781590Srgrimes va_start(ap); 11791590Srgrimes fmt = va_arg(ap, char *); 11801590Srgrimes#endif 11811590Srgrimes 11821590Srgrimes (void)fprintf(stderr, "make: "); 11831590Srgrimes (void)vfprintf(stderr, fmt, ap); 11841590Srgrimes va_end(ap); 11851590Srgrimes (void)fprintf(stderr, "\n"); 11861590Srgrimes (void)fflush(stderr); 11871590Srgrimes 11881590Srgrimes DieHorribly(); 11891590Srgrimes} 11901590Srgrimes 11911590Srgrimes/*- 11921590Srgrimes * DieHorribly -- 11931590Srgrimes * Exit without giving a message. 11941590Srgrimes * 11951590Srgrimes * Results: 11961590Srgrimes * None 11971590Srgrimes * 11981590Srgrimes * Side Effects: 11991590Srgrimes * A big one... 12001590Srgrimes */ 12011590Srgrimesvoid 12021590SrgrimesDieHorribly() 12031590Srgrimes{ 12041590Srgrimes if (jobsRunning) 12051590Srgrimes Job_AbortAll(); 12061590Srgrimes if (DEBUG(GRAPH2)) 12071590Srgrimes Targ_PrintGraph(2); 12081590Srgrimes exit(2); /* Not 1, so -q can distinguish error */ 12091590Srgrimes} 12101590Srgrimes 12111590Srgrimes/* 12121590Srgrimes * Finish -- 12131590Srgrimes * Called when aborting due to errors in child shell to signal 12148874Srgrimes * abnormal exit. 12151590Srgrimes * 12161590Srgrimes * Results: 12178874Srgrimes * None 12181590Srgrimes * 12191590Srgrimes * Side Effects: 12201590Srgrimes * The program exits 12211590Srgrimes */ 12221590Srgrimesvoid 12231590SrgrimesFinish(errors) 12241590Srgrimes int errors; /* number of errors encountered in Make_Make */ 12251590Srgrimes{ 12261590Srgrimes Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 12271590Srgrimes} 12281590Srgrimes 12291590Srgrimes/* 12301590Srgrimes * emalloc -- 12311590Srgrimes * malloc, but die on error. 12321590Srgrimes */ 123318730Sstevevoid * 12341590Srgrimesemalloc(len) 12355814Sjkh size_t len; 12361590Srgrimes{ 123718730Ssteve void *p; 123818730Ssteve 123918730Ssteve if ((p = malloc(len)) == NULL) 124018730Ssteve enomem(); 124118730Ssteve return(p); 124218730Ssteve} 124318730Ssteve 124418730Ssteve/* 124518730Ssteve * estrdup -- 124618730Ssteve * strdup, but die on error. 124718730Ssteve */ 124818730Sstevechar * 124918730Ssteveestrdup(str) 125018730Ssteve const char *str; 125118730Ssteve{ 12521590Srgrimes char *p; 12531590Srgrimes 125418730Ssteve if ((p = strdup(str)) == NULL) 12551590Srgrimes enomem(); 12561590Srgrimes return(p); 12571590Srgrimes} 12581590Srgrimes 12591590Srgrimes/* 126018730Ssteve * erealloc -- 126118730Ssteve * realloc, but die on error. 126218730Ssteve */ 126318730Sstevevoid * 126418730Ssteveerealloc(ptr, size) 126518730Ssteve void *ptr; 126618730Ssteve size_t size; 126718730Ssteve{ 126818730Ssteve if ((ptr = realloc(ptr, size)) == NULL) 126918730Ssteve enomem(); 127018730Ssteve return(ptr); 127118730Ssteve} 127218730Ssteve 127318730Ssteve/* 12741590Srgrimes * enomem -- 12751590Srgrimes * die when out of memory. 12761590Srgrimes */ 12771590Srgrimesvoid 12781590Srgrimesenomem() 12791590Srgrimes{ 128027644Scharnier err(2, NULL); 12811590Srgrimes} 12821590Srgrimes 12831590Srgrimes/* 128418730Ssteve * enunlink -- 128518730Ssteve * Remove a file carefully, avoiding directories. 128618730Ssteve */ 128718730Ssteveint 128818730Ssteveeunlink(file) 128918730Ssteve const char *file; 129018730Ssteve{ 129118730Ssteve struct stat st; 129218730Ssteve 129318730Ssteve if (lstat(file, &st) == -1) 129418730Ssteve return -1; 129518730Ssteve 129618730Ssteve if (S_ISDIR(st.st_mode)) { 129718730Ssteve errno = EISDIR; 129818730Ssteve return -1; 129918730Ssteve } 130018730Ssteve return unlink(file); 130118730Ssteve} 130218730Ssteve 130318730Ssteve/* 13041590Srgrimes * usage -- 13051590Srgrimes * exit with usage message 13061590Srgrimes */ 13071590Srgrimesstatic void 13081590Srgrimesusage() 13091590Srgrimes{ 131027644Scharnier (void)fprintf(stderr, "%s\n%s\n%s\n", 131149332Shoek"usage: make [-Beiknqrstv] [-D variable] [-d flags] [-E variable] [-f makefile]", 131227644Scharnier" [-I directory] [-j max_jobs] [-m directory] [-V variable]", 131327644Scharnier" [variable=value] [target ...]"); 13141590Srgrimes exit(2); 13151590Srgrimes} 13165814Sjkh 13175814Sjkh 13185814Sjkhint 13195814SjkhPrintAddr(a, b) 13205814Sjkh ClientData a; 13215814Sjkh ClientData b; 13225814Sjkh{ 13235814Sjkh printf("%lx ", (unsigned long) a); 13245814Sjkh return b ? 0 : 0; 13255814Sjkh} 1326