diff options
31 files changed, 2230 insertions, 1042 deletions
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile index 09142d5..df3b43f 100644 --- a/usr.bin/make/Makefile +++ b/usr.bin/make/Makefile @@ -1,10 +1,10 @@ -# from: @(#)Makefile 5.2 (Berkeley) 12/28/90 -# $Id: Makefile,v 1.4 1995/06/16 22:46:38 ache Exp $ +# @(#)Makefile 5.2 (Berkeley) 12/28/90 +# $Id: Makefile,v 1.5 1995/09/22 14:14:28 phk Exp $ PROG= make -CFLAGS+= -I${.CURDIR} -DPOSIX -DSYSVINCLUDE +CFLAGS+= -I${.CURDIR} SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \ - make.c parse.c str.c suff.c targ.c var.c + make.c parse.c str.c suff.c targ.c var.c util.c SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \ lstDatum.c lstDeQueue.c lstDestroy.c lstDupl.c lstEnQueue.c \ lstFind.c lstFindFrom.c lstFirst.c lstForEach.c lstForEachFrom.c \ @@ -12,4 +12,8 @@ SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \ lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c .PATH: ${.CURDIR}/lst.lib +.if make(install) +SUBDIR+= PSD.doc +.endif + .include <bsd.prog.mk> diff --git a/usr.bin/make/PSD.doc/tutorial.ms b/usr.bin/make/PSD.doc/tutorial.ms index eca49d9..18236ee 100644 --- a/usr.bin/make/PSD.doc/tutorial.ms +++ b/usr.bin/make/PSD.doc/tutorial.ms @@ -43,7 +43,7 @@ .\" is numeric, it is taken as the depth for numbering (as for .NH), else .\" the default (1) is assumed. .\" -.\" $Id: tutorial.ms,v 1.4 89/01/08 20:20:22 adam Exp Locker: adam $ +.\" $Id: tutorial.ms,v 1.1.1.1 1994/05/27 12:32:16 rgrimes Exp $ .\" .\" @P The initial paragraph distance. .\" @Q The piece of section number to increment (or 0 if none given) @@ -1272,6 +1272,15 @@ administrator. If locking is on, will turn it off, and vice versa. Note that this locking will not prevent \fIyou\fP from invoking PMake twice in the same place \*- if you own the lock file, PMake will warn you about it but continue to execute. +.IP "\fB\-m\fP \fIdirectory\fP" +.Ix 0 def flags -m +Tells PMake another place to search for included makefiles via the <...> +style. Several +.B \-m +options can be given to form a search path. If this construct is used the +default system makefile search path is completely overridden. +To be explained in chapter 3, section 3.2. +.Rm 2 3.2 .IP \fB\-n\fP .Ix 0 def flags -n This flag tells PMake not to execute the commands needed to update the @@ -1912,11 +1921,15 @@ or this .DE The difference between the two is where PMake searches for the file: the first way, PMake will look for -the file only in the system makefile directory (to find out what that -directory is, give PMake the +the file only in the system makefile directory (or directories) +(to find out what that directory is, give PMake the .B \-h flag). .Ix 0 ref flags -h +The system makefile directory search path can be overridden via the +.B \-m +option. +.Ix 0 ref flags -m For files in double-quotes, the search is more complex: .RS .IP 1) diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c index a015eab..8a21380 100644 --- a/usr.bin/make/arch.c +++ b/usr.bin/make/arch.c @@ -94,7 +94,7 @@ static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; #include <sys/param.h> #include <ctype.h> #include <ar.h> -#include <ranlib.h> +#include <utime.h> #include <stdio.h> #include <stdlib.h> #include "make.h" @@ -108,12 +108,18 @@ typedef struct Arch { char *name; /* Name of archive */ Hash_Table members; /* All the members of the archive described * by <name, struct ar_hdr *> key/value pairs */ + char *fnametab; /* Extended name table strings */ + size_t fnamesize; /* Size of the string table */ } Arch; static int ArchFindArchive __P((ClientData, ClientData)); static void ArchFree __P((ClientData)); static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean)); static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *)); +#if defined(__svr4__) || defined(__SVR4) +#define SVR4ARCHIVES +static int ArchSVR4Entry __P((Arch *, char *, size_t, FILE *)); +#endif /*- *----------------------------------------------------------------------- @@ -143,6 +149,8 @@ ArchFree(ap) free((Address) Hash_GetValue (entry)); free(a->name); + if (a->fnametab) + free(a->fnametab); Hash_DeleteTable(&a->members); free((Address) a); } @@ -486,7 +494,7 @@ ArchStatMember (archive, member, hash) strncpy(copy, member, AR_MAX_NAME_LEN); copy[AR_MAX_NAME_LEN] = '\0'; } - if ( (he = Hash_FindEntry (&ar->members, copy)) ) + if ((he = Hash_FindEntry (&ar->members, copy)) != NULL) return ((struct ar_hdr *) Hash_GetValue (he)); return ((struct ar_hdr *) NULL); } @@ -532,27 +540,58 @@ ArchStatMember (archive, member, hash) } ar = (Arch *)emalloc (sizeof (Arch)); - ar->name = strdup (archive); + ar->name = estrdup (archive); + ar->fnametab = NULL; + ar->fnamesize = 0; Hash_InitTable (&ar->members, -1); memName[AR_MAX_NAME_LEN] = '\0'; while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) { if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) { - /* - * The header is bogus, so the archive is bad - * and there's no way we can recover... - */ - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); + /* + * The header is bogus, so the archive is bad + * and there's no way we can recover... + */ + goto badarch; } else { + /* + * We need to advance the stream's pointer to the start of the + * next header. Files are padded with newlines to an even-byte + * boundary, so we need to extract the size of the file from the + * 'size' field of the header and round it up during the seek. + */ + arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; + size = (int) strtol(arh.ar_size, NULL, 10); + (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { continue; } cp[1] = '\0'; +#ifdef SVR4ARCHIVES + /* + * svr4 names are slash terminated. Also svr4 extended AR format. + */ + if (memName[0] == '/') { + /* + * svr4 magic mode; handle it + */ + switch (ArchSVR4Entry(ar, memName, size, arch)) { + case -1: /* Invalid data */ + goto badarch; + case 0: /* List of files entry */ + continue; + default: /* Got the entry */ + break; + } + } + else { + if (cp[0] == '/') + cp[0] = '\0'; + } +#endif + #ifdef AR_EFMT1 /* * BSD 4.4 extended AR format: #1/<namelen>, with name as the @@ -563,18 +602,10 @@ ArchStatMember (archive, member, hash) unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); - if (elen > MAXPATHLEN) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } - if (fread (memName, elen, 1, arch) != 1) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } + if (elen > MAXPATHLEN) + goto badarch; + if (fread (memName, elen, 1, arch) != 1) + goto badarch; memName[elen] = '\0'; fseek (arch, -elen, 1); if (DEBUG(ARCH) || DEBUG(MAKE)) { @@ -588,14 +619,6 @@ ArchStatMember (archive, member, hash) memcpy ((Address)Hash_GetValue (he), (Address)&arh, sizeof (struct ar_hdr)); } - /* - * We need to advance the stream's pointer to the start of the - * next header. Files are padded with newlines to an even-byte - * boundary, so we need to extract the size of the file from the - * 'size' field of the header and round it up during the seek. - */ - arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; - size = (int) strtol(arh.ar_size, NULL, 10); fseek (arch, (size + 1) & ~1, 1); } @@ -614,8 +637,121 @@ ArchStatMember (archive, member, hash) } else { return ((struct ar_hdr *) NULL); } + +badarch: + fclose (arch); + Hash_DeleteTable (&ar->members); + if (ar->fnametab) + free(ar->fnametab); + free ((Address)ar); + return ((struct ar_hdr *) NULL); } +#ifdef SVR4ARCHIVES +/*- + *----------------------------------------------------------------------- + * ArchSVR4Entry -- + * Parse an SVR4 style entry that begins with a slash. + * If it is "//", then load the table of filenames + * If it is "/<offset>", then try to substitute the long file name + * from offset of a table previously read. + * + * Results: + * -1: Bad data in archive + * 0: A table was loaded from the file + * 1: Name was successfully substituted from table + * 2: Name was not successfully substituted from table + * + * Side Effects: + * If a table is read, the file pointer is moved to the next archive + * member + * + *----------------------------------------------------------------------- + */ +static int +ArchSVR4Entry(ar, name, size, arch) + Arch *ar; + char *name; + size_t size; + FILE *arch; +{ +#define ARLONGNAMES1 "//" +#define ARLONGNAMES2 "/ARFILENAMES" + size_t entry; + char *ptr, *eptr; + + if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || + strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { + + if (ar->fnametab != NULL) { + if (DEBUG(ARCH)) { + printf("Attempted to redefine an SVR4 name table\n"); + } + return -1; + } + + /* + * This is a table of archive names, so we build one for + * ourselves + */ + ar->fnametab = emalloc(size); + ar->fnamesize = size; + + if (fread(ar->fnametab, size, 1, arch) != 1) { + if (DEBUG(ARCH)) { + printf("Reading an SVR4 name table failed\n"); + } + return -1; + } + eptr = ar->fnametab + size; + for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) + switch (*ptr) { + case '/': + entry++; + *ptr = '\0'; + break; + + case '\n': + break; + + default: + break; + } + if (DEBUG(ARCH)) { + printf("Found svr4 archive name table with %d entries\n", entry); + } + return 0; + } + + if (name[1] == ' ' || name[1] == '\0') + return 2; + + entry = (size_t) strtol(&name[1], &eptr, 0); + if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) { + if (DEBUG(ARCH)) { + printf("Could not parse SVR4 name %s\n", name); + } + return 2; + } + if (entry >= ar->fnamesize) { + if (DEBUG(ARCH)) { + printf("SVR4 entry offset %s is greater than %d\n", + name, ar->fnamesize); + } + return 2; + } + + if (DEBUG(ARCH)) { + printf("Replaced %s with %s\n", name, &ar->fnametab[entry]); + } + + (void) strncpy(name, &ar->fnametab[entry], MAXPATHLEN); + name[MAXPATHLEN] = '\0'; + return 1; +} +#endif + + /*- *----------------------------------------------------------------------- * ArchFindMember -- @@ -820,9 +956,10 @@ void Arch_TouchLib (gn) GNode *gn; /* The node of the library to touch */ { +#ifdef RANLIBMAG FILE * arch; /* Stream open to archive */ struct ar_hdr arh; /* Header describing table of contents */ - struct timeval times[2]; /* Times for utimes() call */ + struct utimbuf times; /* Times for utime() call */ arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); sprintf(arh.ar_date, "%-12ld", (long) now); @@ -831,10 +968,10 @@ Arch_TouchLib (gn) (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); fclose (arch); - times[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - utimes(gn->path, times); + times.actime = times.modtime = now; + utime(gn->path, ×); } +#endif } /*- @@ -975,7 +1112,7 @@ Arch_FindLib (gn, path) Var_Set (TARGET, gn->name, gn); #else Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn); -#endif LIBRARIES +#endif /* LIBRARIES */ } /*- @@ -1025,6 +1162,7 @@ Arch_LibOODate (gn) } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { oodate = TRUE; } else { +#ifdef RANLIBMAG struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ int modTimeTOC; /* The table-of-contents's mod time */ @@ -1046,6 +1184,9 @@ Arch_LibOODate (gn) } oodate = TRUE; } +#else + oodate = FALSE; +#endif } return (oodate); } diff --git a/usr.bin/make/bit.h b/usr.bin/make/bit.h deleted file mode 100644 index 1671326..0000000 --- a/usr.bin/make/bit.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1989 by Berkeley Softworks - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)bit.h 8.1 (Berkeley) 6/6/93 - */ - -/* - * bit.h -- - * - * Definition of macros for setting and clearing bits in an array - * of integers. - * - * It is assumed that "int" is 32 bits wide. - */ - -#ifndef _BIT -#define _BIT - -#include "sprite.h" - -#define BIT_NUM_BITS_PER_INT 32 -#define BIT_NUM_BITS_PER_BYTE 8 - -#define Bit_NumInts(numBits) \ - (((numBits)+BIT_NUM_BITS_PER_INT -1)/BIT_NUM_BITS_PER_INT) - -#define Bit_NumBytes(numBits) \ - (Bit_NumInts(numBits) * sizeof(int)) - -#define Bit_Alloc(numBits, bitArrayPtr) \ - bitArrayPtr = (int *)malloc((unsigned)Bit_NumBytes(numBits)); \ - Bit_Zero((numBits), (bitArrayPtr)) - -#define Bit_Free(bitArrayPtr) \ - free((char *)bitArrayPtr) - -#define Bit_Set(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] |= \ - (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_IsSet(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] & \ - (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_Clear(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] &= \ - ~(1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_IsClear(numBits, bitArrayPtr) \ - (!(Bit_IsSet((numBits), (bitArrayPtr)))) - -#define Bit_Copy(numBits, srcArrayPtr, destArrayPtr) \ - bcopy((char *)(srcArrayPtr), (char *)(destArrayPtr), \ - Bit_NumBytes(numBits)) - -#define Bit_Zero(numBits, bitArrayPtr) \ - bzero((char *)(bitArrayPtr), Bit_NumBytes(numBits)) - -extern int Bit_FindFirstSet(); -extern int Bit_FindFirstClear(); -extern Boolean Bit_Intersect(); -extern Boolean Bit_Union(); -extern Boolean Bit_AnySet(); -extern int *Bit_Expand(); - -#endif /* _BIT */ diff --git a/usr.bin/make/buf.c b/usr.bin/make/buf.c index 68315e7..f0bdc75 100644 --- a/usr.bin/make/buf.c +++ b/usr.bin/make/buf.c @@ -63,7 +63,7 @@ static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93"; #define BufExpand(bp,nb) \ if (bp->left < (nb)+1) {\ int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \ - Byte *newBuf = (Byte *) realloc((bp)->buffer, newSize); \ + Byte *newBuf = (Byte *) erealloc((bp)->buffer, newSize); \ \ (bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \ (bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\ diff --git a/usr.bin/make/buf.h b/usr.bin/make/buf.h index 169e004..6461c89 100644 --- a/usr.bin/make/buf.h +++ b/usr.bin/make/buf.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)buf.h 8.1 (Berkeley) 6/6/93 + * from: @(#)buf.h 8.1 (Berkeley) 6/6/93 */ /*- diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c index 0557789..d63ea35 100644 --- a/usr.bin/make/compat.c +++ b/usr.bin/make/compat.c @@ -55,11 +55,11 @@ static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; #include <stdio.h> #include <sys/types.h> -#include <sys/signal.h> -#include <sys/wait.h> -#include <sys/errno.h> #include <sys/stat.h> +#include <sys/wait.h> #include <ctype.h> +#include <errno.h> +#include <signal.h> #include "make.h" #include "hash.h" #include "dir.h" @@ -105,10 +105,8 @@ CompatInterrupt (signo) if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { char *p1; char *file = Var_Value (TARGET, curTarg, &p1); - struct stat st; - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { + if (!noExecute && eunlink(file) != -1) { printf ("*** %s removed\n", file); } if (p1) @@ -151,7 +149,7 @@ CompatRunCommand (cmdp, gnp) register char *cp; Boolean silent, /* Don't print command */ errCheck; /* Check errors */ - union wait reason; /* Reason for child's death */ + int reason; /* Reason for child's death */ int status; /* Description of child's death */ int cpid; /* Child actually found */ ReturnStatus stat; /* Status of fork */ @@ -292,7 +290,7 @@ CompatRunCommand (cmdp, gnp) */ while (1) { - while ((stat = wait((int *)&reason)) != cpid) { + while ((stat = wait(&reason)) != cpid) { if (stat == -1 && errno != EINTR) { break; } @@ -300,14 +298,14 @@ CompatRunCommand (cmdp, gnp) if (stat > -1) { if (WIFSTOPPED(reason)) { - status = reason.w_stopval; /* stopped */ + status = WSTOPSIG(reason); /* stopped */ } else if (WIFEXITED(reason)) { - status = reason.w_retcode; /* exited */ + status = WEXITSTATUS(reason); /* exited */ if (status != 0) { printf ("*** Error code %d", status); } } else { - status = reason.w_termsig; /* signaled */ + status = WTERMSIG(reason); /* signaled */ printf ("*** Signal %d", status); } diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c index 4bf802b..eb6fa5c 100644 --- a/usr.bin/make/cond.c +++ b/usr.bin/make/cond.c @@ -94,6 +94,7 @@ typedef enum { * Structures to handle elegantly the different forms of #if's. The * last two fields are stored in condInvert and condDefProc, respectively. */ +static void CondPushBack __P((Token)); static int CondGetArg __P((char **, char **, char *, Boolean)); static Boolean CondDoDefined __P((int, char *)); static int CondStrMatch __P((ClientData, ClientData)); @@ -110,18 +111,19 @@ static struct If { char *form; /* Form of if */ int formlen; /* Length of form */ Boolean doNot; /* TRUE if default function should be negated */ - Boolean (*defProc)(); /* Default function to apply */ + Boolean (*defProc) __P((int, char *)); /* Default function to apply */ } ifs[] = { { "ifdef", 5, FALSE, CondDoDefined }, { "ifndef", 6, TRUE, CondDoDefined }, { "ifmake", 6, FALSE, CondDoMake }, { "ifnmake", 7, TRUE, CondDoMake }, { "if", 2, FALSE, CondDoDefined }, - { (char *)0, 0, FALSE, (Boolean (*)())0 } + { NULL, 0, FALSE, NULL } }; static Boolean condInvert; /* Invert the default function */ -static Boolean (*condDefProc)(); /* Default function to apply */ +static Boolean (*condDefProc) /* Default function to apply */ + __P((int, char *)); static char *condExpr; /* The expression to parse */ static Token condPushBack=None; /* Single push-back token used in * parsing */ @@ -758,7 +760,7 @@ error: break; } default: { - Boolean (*evalProc)(); + Boolean (*evalProc) __P((int, char *)); Boolean invert = FALSE; char *arg; int arglen; diff --git a/usr.bin/make/config.h b/usr.bin/make/config.h index 18a9e68..81d0ad8 100644 --- a/usr.bin/make/config.h +++ b/usr.bin/make/config.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)config.h 8.1 (Berkeley) 6/6/93 + * from: @(#)config.h 8.1 (Berkeley) 6/6/93 */ #define DEFSHELL 1 /* Bourne shell */ @@ -78,15 +78,40 @@ * re-made, causing later targets to appear up-to-date. On systems * that don't have this problem, you should defined this. Under * NFS you probably should not, unless you aren't exporting jobs. - * - * POSIX - * If the POSIX standard for Make is to be followed. There are - * several areas that I dislike, hence this constant. */ #define LIBSUFF ".a" #define RECHECK -#ifndef RANLIBMAG -#define RANLIBMAG "__.SYMDEF" +/* + * POSIX + * Adhere to the POSIX 1003.2 draft for the make(1) program. + * - Use MAKEFLAGS instead of MAKE to pick arguments from the + * environment. + * - Allow empty command lines if starting with tab. + */ +#define POSIX + +/* + * SYSVINCLUDE + * Recognize system V like include directives [include "filename"] + * SYSVVARSUB + * Recognize system V like ${VAR:x=y} variable substitutions + */ +#define SYSVINCLUDE +#define SYSVVARSUB + +/* + * SUNSHCMD + * Recognize SunOS and Solaris: + * VAR :sh= CMD # Assign VAR to the command substitution of CMD + * ${VAR:sh} # Return the command substitution of the value + * # of ${VAR} + */ +#define SUNSHCMD + +#if !defined(__svr4__) && !defined(__SVR4) +# ifndef RANLIBMAG +# define RANLIBMAG "__.SYMDEF" +# endif #endif /*#define POSIX*/ diff --git a/usr.bin/make/dir.c b/usr.bin/make/dir.c index 70f5038..3f123d9 100644 --- a/usr.bin/make/dir.c +++ b/usr.bin/make/dir.c @@ -348,7 +348,7 @@ DirMatchFiles (pattern, p, expansions) (pattern[0] == '.'))) { (void)Lst_AtEnd(expansions, - (isDot ? strdup(entry->name) : + (isDot ? estrdup(entry->name) : str_concat(p->name, entry->name, STR_ADDSLASH))); } @@ -700,7 +700,7 @@ Dir_FindFile (name, path) } hits += 1; dot->hits += 1; - return (strdup (name)); + return (estrdup (name)); } if (Lst_Open (path) == FAILURE) { @@ -811,7 +811,7 @@ Dir_FindFile (name, path) /* * Checking in dot -- DON'T put a leading ./ on the thing. */ - file = strdup(name); + file = estrdup(name); checkedDot = TRUE; } if (DEBUG(DIR)) { @@ -907,7 +907,7 @@ Dir_FindFile (name, path) } if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { - return (strdup (name)); + return (estrdup (name)); } else { return ((char *) NULL); } @@ -922,7 +922,7 @@ Dir_FindFile (name, path) if (DEBUG(DIR)) { printf("got it (in mtime cache)\n"); } - return(strdup(name)); + return(estrdup(name)); } else if (stat (name, &stb) == 0) { entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL); if (DEBUG(DIR)) { @@ -930,7 +930,7 @@ Dir_FindFile (name, path) name); } Hash_SetValue(entry, (long)stb.st_mtime); - return (strdup (name)); + return (estrdup (name)); } else { if (DEBUG(DIR)) { printf("failed. Returning NULL\n"); @@ -973,7 +973,7 @@ Dir_MTime (gn) } if (fullName == (char *)NULL) { - fullName = strdup(gn->name); + fullName = estrdup(gn->name); } entry = Hash_FindEntry(&mtimes, fullName); @@ -1047,7 +1047,7 @@ Dir_AddDir (path, name) if ((d = opendir (name)) != (DIR *) NULL) { p = (Path *) emalloc (sizeof (Path)); - p->name = strdup (name); + p->name = estrdup (name); p->hits = 0; p->refCount = 1; Hash_InitTable (&p->files, -1); @@ -1059,7 +1059,7 @@ Dir_AddDir (path, name) (void)readdir(d); while ((dp = readdir (d)) != (struct dirent *) NULL) { -#ifdef sun +#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ /* * The sun directory library doesn't check for a 0 inode * (0-inode slots just take up space), so we have to do @@ -1068,7 +1068,7 @@ Dir_AddDir (path, name) if (dp->d_fileno == 0) { continue; } -#endif /* sun */ +#endif /* sun && d_ino */ (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL); } (void) closedir (d); @@ -1131,7 +1131,7 @@ Dir_MakeFlags (flag, path) LstNode ln; /* the node of the current directory */ Path *p; /* the structure describing the current directory */ - str = strdup (""); + str = estrdup (""); if (Lst_Open (path) == SUCCESS) { while ((ln = Lst_Next (path)) != NILLNODE) { diff --git a/usr.bin/make/dir.h b/usr.bin/make/dir.h index dd0c2a7..9e06d0d 100644 --- a/usr.bin/make/dir.h +++ b/usr.bin/make/dir.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)dir.h 8.1 (Berkeley) 6/6/93 + * from: @(#)dir.h 8.1 (Berkeley) 6/6/93 */ /* dir.h -- diff --git a/usr.bin/make/hash.h b/usr.bin/make/hash.h index ebc30e1..22e6b25 100644 --- a/usr.bin/make/hash.h +++ b/usr.bin/make/hash.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)hash.h 8.1 (Berkeley) 6/6/93 + * from: @(#)hash.h 8.1 (Berkeley) 6/6/93 */ /* hash.h -- diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index ed5f2fc..1f4d4ee 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -97,13 +97,13 @@ static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; */ #include <sys/types.h> -#include <sys/signal.h> #include <sys/stat.h> #include <sys/file.h> #include <sys/time.h> #include <sys/wait.h> #include <fcntl.h> #include <errno.h> +#include <utime.h> #include <stdio.h> #include <string.h> #include <signal.h> @@ -112,6 +112,12 @@ static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #include "dir.h" #include "job.h" #include "pathnames.h" +#ifdef REMOTE +#include "rmt.h" +# define STATIC +#else +# define STATIC static +#endif extern int errno; @@ -124,6 +130,11 @@ static int aborting = 0; /* why is the make aborting? */ #define ABORT_INTERRUPT 2 /* Because it was interrupted */ #define ABORT_WAIT 3 /* Waiting for jobs to finish */ +/* + * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file + * is a char! So when we go above 127 we turn negative! + */ +#define FILENO(a) ((unsigned) fileno(a)) /* * post-make command processing. The node postCommands is really just the @@ -136,7 +147,6 @@ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ - /* * Return values from JobStart. */ @@ -176,17 +186,20 @@ static Shell shells[] = { { "sh", TRUE, "set -", "set -v", "set -", 5, + TRUE, "set -e", "set +e", +#ifdef OLDBOURNESHELL FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", +#endif "v", "e", }, /* * UNKNOWN. */ { - (char *)0, - FALSE, (char *)0, (char *)0, (char *)0, 0, - FALSE, (char *)0, (char *)0, - (char *)0, (char *)0, + (char *) 0, + FALSE, (char *) 0, (char *) 0, (char *) 0, 0, + FALSE, (char *) 0, (char *) 0, + (char *) 0, (char *) 0, } }; static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to @@ -194,17 +207,17 @@ static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to * commands in the Makefile. * It is set by the * Job_ParseShell function */ -static char *shellPath = (char *) NULL, /* full pathname of +static char *shellPath = NULL, /* full pathname of * executable image */ *shellName; /* last component of shell */ static int maxJobs; /* The most children we can run at once */ static int maxLocal; /* The most local ones we can have */ -int nJobs; /* The number of children currently running */ -int nLocal; /* The number of local children */ -Lst jobs; /* The structures that describe them */ -Boolean jobFull; /* Flag to tell when the job table is full. It +STATIC int nJobs; /* The number of children currently running */ +STATIC int nLocal; /* The number of local children */ +STATIC Lst jobs; /* The structures that describe them */ +STATIC Boolean jobFull; /* Flag to tell when the job table is full. It * is set TRUE when (1) the total number of * running jobs equals the maximum allowed or * (2) a job can only be run locally, but @@ -214,12 +227,21 @@ static fd_set outputs; /* Set of descriptors of pipes connected to * the output channels of children */ #endif -GNode *lastNode; /* The node for which output was most recently +STATIC GNode *lastNode; /* The node for which output was most recently * produced. */ -char *targFmt; /* Format string to use to head output from a +STATIC char *targFmt; /* Format string to use to head output from a * job when it's not the most-recent job heard * from */ -#define TARG_FMT "--- %s ---\n" /* Default format */ + +#ifdef REMOTE +# define TARG_FMT "--- %s at %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name, gn->rem.hname); +#else +# define TARG_FMT "--- %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name); +#endif /* * When JobStart attempts to run a job remotely but can't, and isn't allowed @@ -227,34 +249,64 @@ char *targFmt; /* Format string to use to head output from a * been migrated home, the job is placed on the stoppedJobs queue to be run * when the next job finishes. */ -Lst stoppedJobs; /* Lst of Job structures describing +STATIC Lst stoppedJobs; /* Lst of Job structures describing * jobs that were stopped due to concurrency * limits or migration home */ #if defined(USE_PGRP) && defined(SYSV) -#define KILL(pid,sig) killpg (-(pid),(sig)) +# define KILL(pid, sig) killpg(-(pid), (sig)) #else # if defined(USE_PGRP) -#define KILL(pid,sig) killpg ((pid),(sig)) +# define KILL(pid, sig) killpg((pid), (sig)) # else -#define KILL(pid,sig) kill ((pid),(sig)) +# define KILL(pid, sig) kill((pid), (sig)) # endif #endif +/* + * Grmpf... There is no way to set bits of the wait structure + * anymore with the stupid W*() macros. I liked the union wait + * stuff much more. So, we devise our own macros... This is + * really ugly, use dramamine sparingly. You have been warned. + */ +#define W_SETMASKED(st, val, fun) \ + { \ + int sh = (int) ~0; \ + int mask = fun(sh); \ + \ + for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ + continue; \ + *(st) = (*(st) & ~mask) | ((val) << sh); \ + } + +#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) +#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) + + static int JobCondPassSig __P((ClientData, ClientData)); static void JobPassSig __P((int)); static int JobCmpPid __P((ClientData, ClientData)); static int JobPrintCommand __P((ClientData, ClientData)); static int JobSaveCommand __P((ClientData, ClientData)); -static void JobFinish __P((Job *, union wait)); +static void JobClose __P((Job *)); +#ifdef REMOTE +static int JobCmpRmtID __P((Job *, int)); +# ifdef RMT_WILL_WATCH +static void JobLocalInput __P((int, Job *)); +# endif +#else +static void JobFinish __P((Job *, int *)); static void JobExec __P((Job *, char **)); +#endif static void JobMakeArgv __P((Job *, char **)); static void JobRestart __P((Job *)); static int JobStart __P((GNode *, int, Job *)); +static char *JobOutput __P((Job *, char *, char *, int)); static void JobDoOutput __P((Job *, Boolean)); static Shell *JobMatchShell __P((char *)); -static void JobInterrupt __P((int)); +static void JobInterrupt __P((int, int)); +static void JobRestartJobs __P((void)); /*- *----------------------------------------------------------------------- @@ -279,7 +331,7 @@ JobCondPassSig(jobp, signop) int signo = *(int *) signop; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { - (void)Rmt_Signal(job, signo); + (void) Rmt_Signal(job, signo); } else { KILL(job->pid, signo); } @@ -288,9 +340,15 @@ JobCondPassSig(jobp, signop) * Assume that sending the signal to job->pid will signal any remote * job as well. */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobCondPassSig passing signal %d to child %d.\n", + signo, job->pid); + (void) fflush(stdout); + } KILL(job->pid, signo); #endif - return(0); + return 0; } /*- @@ -311,9 +369,14 @@ static void JobPassSig(signo) int signo; /* The signal number we've received */ { - int mask; + sigset_t nmask, omask; + struct sigaction act; - Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); + (void) fflush(stdout); + } + Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); /* * Deal with proper cleanup based on the signal received. We only run @@ -321,9 +384,9 @@ JobPassSig(signo) * three termination signals are more of a "get out *now*" command. */ if (signo == SIGINT) { - JobInterrupt(TRUE); + JobInterrupt(TRUE, signo); } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { - JobInterrupt(FALSE); + JobInterrupt(FALSE, signo); } /* @@ -339,18 +402,31 @@ JobPassSig(signo) * This ensures that all our jobs get continued when we wake up before * we take any other signal. */ - mask = sigblock(0); - (void) sigsetmask(~0 & ~(1 << (signo-1))); - signal(signo, SIG_DFL); + sigemptyset(&nmask); + sigaddset(&nmask, signo); + sigprocmask(SIG_SETMASK, &nmask, &omask); + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(signo, &act, NULL); - kill(getpid(), signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobPassSig passing signal to self, mask = %x.\n", + ~0 & ~(1 << (signo-1))); + (void) fflush(stdout); + } + (void) signal(signo, SIG_DFL); + + (void) KILL(getpid(), signo); signo = SIGCONT; Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); - sigsetmask(mask); - signal(signo, JobPassSig); - + (void) sigprocmask(SIG_SETMASK, &omask, NULL); + sigprocmask(SIG_SETMASK, &omask, NULL); + act.sa_handler = JobPassSig; + sigaction(signo, &act, NULL); } /*- @@ -368,12 +444,35 @@ JobPassSig(signo) *----------------------------------------------------------------------- */ static int -JobCmpPid (job, pid) +JobCmpPid(job, pid) ClientData job; /* job to examine */ ClientData pid; /* process id desired */ { - return ( *(int *) pid - ((Job *) job)->pid); + return *(int *) pid - ((Job *) job)->pid; +} + +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobCmpRmtID -- + * Compare the rmtID of the job with the given rmtID and return 0 if they + * are equal. + * + * Results: + * 0 if the rmtID's match + * + * Side Effects: + * None. + *----------------------------------------------------------------------- + */ +static int +JobCmpRmtID(job, rmtID) + ClientData job; /* job to examine */ + ClientData rmtID; /* remote id desired */ +{ + return(*(int *) rmtID - *(int *) job->rmtID); } +#endif /*- *----------------------------------------------------------------------- @@ -403,7 +502,7 @@ JobCmpPid (job, pid) *----------------------------------------------------------------------- */ static int -JobPrintCommand (cmdp, jobp) +JobPrintCommand(cmdp, jobp) ClientData cmdp; /* command string to print */ ClientData jobp; /* job for which to print it */ { @@ -422,19 +521,24 @@ JobPrintCommand (cmdp, jobp) char *cmd = (char *) cmdp; Job *job = (Job *) jobp; - noSpecials = (noExecute && ! (job->node->type & OP_MAKE)); + noSpecials = (noExecute && !(job->node->type & OP_MAKE)); - if (strcmp (cmd, "...") == 0) { + if (strcmp(cmd, "...") == 0) { job->node->type |= OP_SAVE_CMDS; if ((job->flags & JOB_IGNDOTS) == 0) { - job->tailCmds = Lst_Succ (Lst_Member (job->node->commands, - (ClientData)cmd)); - return (1); + job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, + (ClientData)cmd)); + return 1; } - return (0); + return 0; } -#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg) +#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ + (void) fprintf(stdout, fmt, arg); \ + (void) fflush(stdout); \ + } \ + (void) fprintf(job->cmdFILE, fmt, arg); \ + (void) fflush(job->cmdFILE); numCommands += 1; @@ -442,9 +546,9 @@ JobPrintCommand (cmdp, jobp) * For debugging, we replace each command with the result of expanding * the variables in the command. */ - cmdNode = Lst_Member (job->node->commands, (ClientData)cmd); - cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE); - Lst_Replace (cmdNode, (ClientData)cmdStart); + cmdNode = Lst_Member(job->node->commands, (ClientData)cmd); + cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); + Lst_Replace(cmdNode, (ClientData)cmdStart); cmdTemplate = "%s\n"; @@ -464,16 +568,16 @@ JobPrintCommand (cmdp, jobp) cmd++; if (shutUp) { - if (! (job->flags & JOB_SILENT) && !noSpecials && + if (!(job->flags & JOB_SILENT) && !noSpecials && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); } else { shutUp = FALSE; } } if (errOff) { - if ( ! (job->flags & JOB_IGNERR) && !noSpecials) { + if ( !(job->flags & JOB_IGNERR) && !noSpecials) { if (commandShell->hasErrCtl) { /* * we don't want the error-control commands showing @@ -483,16 +587,16 @@ JobPrintCommand (cmdp, jobp) * string too, but why make it any more complex than * it already is? */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF ("%s\n", commandShell->ignErr); - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->echoOn); } else { - DBPRINTF ("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->ignErr); } } else if (commandShell->ignErr && - (*commandShell->ignErr != '\0')) + (*commandShell->ignErr != '\0')) { /* * The shell has no error control, so we need to be @@ -503,10 +607,10 @@ JobPrintCommand (cmdp, jobp) * to ignore errors. Set cmdTemplate to use the weirdness * instead of the simple "%s\n" template. */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF (commandShell->errCheck, cmd); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF(commandShell->errCheck, cmd); shutUp = TRUE; } cmdTemplate = commandShell->ignErr; @@ -524,7 +628,7 @@ JobPrintCommand (cmdp, jobp) } } - DBPRINTF (cmdTemplate, cmd); + DBPRINTF(cmdTemplate, cmd); if (errOff) { /* @@ -533,15 +637,15 @@ JobPrintCommand (cmdp, jobp) * for the whole command... */ if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); shutUp = TRUE; } - DBPRINTF ("%s\n", commandShell->errCheck); + DBPRINTF("%s\n", commandShell->errCheck); } if (shutUp) { - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOn); } - return (0); + return 0; } /*- @@ -559,13 +663,48 @@ JobPrintCommand (cmdp, jobp) *----------------------------------------------------------------------- */ static int -JobSaveCommand (cmd, gn) +JobSaveCommand(cmd, gn) ClientData cmd; ClientData gn; { - cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE); - (void)Lst_AtEnd (postCommands->commands, cmd); - return (0); + cmd = (ClientData) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE); + (void) Lst_AtEnd(postCommands->commands, cmd); + return(0); +} + + +/*- + *----------------------------------------------------------------------- + * JobClose -- + * Called to close both input and output pipes when a job is finished. + * + * Results: + * Nada + * + * Side Effects: + * The file descriptors associated with the job are closed. + * + *----------------------------------------------------------------------- + */ +static void +JobClose(job) + Job *job; +{ + if (usePipes) { +#ifdef RMT_WILL_WATCH + Rmt_Ignore(job->inPipe); +#else + FD_CLR(job->inPipe, &outputs); +#endif + if (job->outPipe != job->inPipe) { + (void) close(job->outPipe); + } + JobDoOutput(job, TRUE); + (void) close(job->inPipe); + } else { + (void) close(job->outFd); + JobDoOutput(job, TRUE); + } } /*- @@ -593,15 +732,15 @@ JobSaveCommand (cmd, gn) */ /*ARGSUSED*/ static void -JobFinish (job, status) - Job *job; /* job to finish */ - union wait status; /* sub-why job went away */ +JobFinish(job, status) + Job *job; /* job to finish */ + int *status; /* sub-why job went away */ { - Boolean done; + Boolean done; - if ((WIFEXITED(status) && - (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) || - (WIFSIGNALED(status) && (status.w_termsig != SIGCONT))) + if ((WIFEXITED(*status) && + (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) { /* * If it exited non-zero and either we're doing things our @@ -611,36 +750,38 @@ JobFinish (job, status) * cases, finish out the job's output before printing the exit * status... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif /* RMT_WILL_WATCH */ - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } - +#ifdef REMOTE + KILL(job->pid, SIGCONT); +#endif + JobClose(job); if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - fclose(job->cmdFILE); + (void) fclose(job->cmdFILE); } done = TRUE; - } else if (WIFEXITED(status) && status.w_retcode != 0) { +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif + } else if (WIFEXITED(*status)) { /* * Deal with ignored errors in -B mode. We need to print a message * telling of the ignored error as well as setting status.w_status * to 0 so the next command gets run. To do this, we set done to be - * TRUE if in -B mode and the job exited non-zero. Note we don't + * TRUE if in -B mode and the job exited non-zero. + */ + done = WEXITSTATUS(*status) != 0; + /* + * Old comment said: "Note we don't * want to close down any of the streams until we know we're at the - * end. + * end." + * But we do. Otherwise when are we going to print the rest of the + * stuff? */ - done = TRUE; + JobClose(job); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif /* REMOTE */ } else { /* * No need to close things down or anything. @@ -649,55 +790,69 @@ JobFinish (job, status) } if (done || - WIFSTOPPED(status) || - (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) || + WIFSTOPPED(*status) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || DEBUG(JOB)) { FILE *out; - if (!usePipes && (job->flags & JOB_IGNERR)) { + if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { /* * If output is going to a file and this job is ignoring * errors, arrange to have the exit status sent to the * output file as well. */ - out = fdopen (job->outFd, "w"); + out = fdopen(job->outFd, "w"); } else { out = stdout; } - if (WIFEXITED(status)) { - if (status.w_retcode != 0) { + if (WIFEXITED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited.\n", job->pid); + (void) fflush(stdout); + } + if (WEXITSTATUS(*status) != 0) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Error code %d%s\n", status.w_retcode, - (job->flags & JOB_IGNERR) ? " (ignored)" : ""); + (void) fprintf(out, "*** Error code %d%s\n", + WEXITSTATUS(*status), + (job->flags & JOB_IGNERR) ? "(ignored)" : ""); if (job->flags & JOB_IGNERR) { - status.w_status = 0; + *status = 0; } } else if (DEBUG(JOB)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Completed successfully\n"); + (void) fprintf(out, "*** Completed successfully\n"); + } + } else if (WIFSTOPPED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d stopped.\n", job->pid); + (void) fflush(stdout); } - } else if (WIFSTOPPED(status)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - if (! (job->flags & JOB_REMIGRATE)) { - fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig); + if (!(job->flags & JOB_REMIGRATE)) { + (void) fprintf(out, "*** Stopped -- signal %d\n", + WSTOPSIG(*status)); } job->flags |= JOB_RESUME; (void)Lst_AtEnd(stoppedJobs, (ClientData)job); - fflush(out); +#ifdef REMOTE + if (job->flags & JOB_REMIGRATE) + JobRestart(job); +#endif + (void) fflush(out); return; - } else if (status.w_termsig == SIGCONT) { + } else if (WTERMSIG(*status) == SIGCONT) { /* * If the beastie has continued, shift the Job from the stopped * list to the running one (or re-stop it if concurrency is @@ -705,37 +860,58 @@ JobFinish (job, status) */ if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Continued\n"); + (void) fprintf(out, "*** Continued\n"); } - if (! (job->flags & JOB_CONTINUING)) { - JobRestart(job); - } else { - Lst_AtEnd(jobs, (ClientData)job); - nJobs += 1; - if (! (job->flags & JOB_REMOTE)) { - nLocal += 1; - } - if (nJobs == maxJobs) { - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } + if (!(job->flags & JOB_CONTINUING)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Warning: process %d was not continuing.\n", + job->pid); + (void) fflush(stdout); } +#ifdef notdef + /* + * We don't really want to restart a job from scratch just + * because it continued, especially not without killing the + * continuing process! That's why this is ifdef'ed out. + * FD - 9/17/90 + */ + JobRestart(job); +#endif } - fflush(out); - return; + job->flags &= ~JOB_CONTINUING; + Lst_AtEnd(jobs, (ClientData)job); + nJobs += 1; + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Process %d is continuing locally.\n", + job->pid); + (void) fflush(stdout); + } + nLocal += 1; + } + if (nJobs == maxJobs) { + jobFull = TRUE; + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); + } + } + (void) fflush(out); + return; } else { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Signal %d\n", status.w_termsig); + (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); } - fflush (out); + (void) fflush(out); } /* @@ -743,30 +919,26 @@ JobFinish (job, status) * try and restart the job on the next command. If JobStart says it's * ok, it's ok. If there's an error, this puppy is done. */ - if ((status.w_status == 0) && - !Lst_IsAtEnd (job->node->commands)) - { - switch (JobStart (job->node, - job->flags & JOB_IGNDOTS, - job)) - { - case JOB_RUNNING: - done = FALSE; - break; - case JOB_ERROR: - done = TRUE; - status.w_retcode = 1; - break; - case JOB_FINISHED: - /* - * If we got back a JOB_FINISHED code, JobStart has already - * called Make_Update and freed the job descriptor. We set - * done to false here to avoid fake cycles and double frees. - * JobStart needs to do the update so we can proceed up the - * graph when given the -n flag.. - */ - done = FALSE; - break; + if (compatMake && (WIFEXITED(*status) && + !Lst_IsAtEnd(job->node->commands))) { + switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { + case JOB_RUNNING: + done = FALSE; + break; + case JOB_ERROR: + done = TRUE; + W_SETEXITSTATUS(status, 1); + break; + case JOB_FINISHED: + /* + * If we got back a JOB_FINISHED code, JobStart has already + * called Make_Update and freed the job descriptor. We set + * done to false here to avoid fake cycles and double frees. + * JobStart needs to do the update so we can proceed up the + * graph when given the -n flag.. + */ + done = FALSE; + break; } } else { done = TRUE; @@ -776,7 +948,7 @@ JobFinish (job, status) if (done && (aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && - (status.w_status == 0)) + (*status == 0)) { /* * As long as we aren't aborting and the job didn't return a non-zero @@ -785,21 +957,19 @@ JobFinish (job, status) * on the .END target. */ if (job->tailCmds != NILLNODE) { - Lst_ForEachFrom (job->node->commands, job->tailCmds, + Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } job->node->made = MADE; - Make_Update (job->node); + Make_Update(job->node); free((Address)job); - } else if (status.w_status) { + } else if (*status != 0) { errors += 1; free((Address)job); } - while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); /* * Set aborting if any error. @@ -817,8 +987,8 @@ JobFinish (job, status) /* * If we are aborting and the job table is now empty, we finish. */ - (void) unlink (tfile); - Finish (errors); + (void) eunlink(tfile); + Finish(errors); } } @@ -837,12 +1007,12 @@ JobFinish (job, status) *----------------------------------------------------------------------- */ void -Job_Touch (gn, silent) +Job_Touch(gn, silent) GNode *gn; /* the node of the file to touch */ Boolean silent; /* TRUE if should not print messages */ { int streamID; /* ID of stream opened to do the touch */ - struct timeval times[2]; /* Times for utimes() call */ + struct utimbuf times; /* Times for utime() call */ if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { /* @@ -853,7 +1023,8 @@ Job_Touch (gn, silent) } if (!silent) { - printf ("touch %s\n", gn->name); + (void) fprintf(stdout, "touch %s\n", gn->name); + (void) fflush(stdout); } if (noExecute) { @@ -861,16 +1032,15 @@ Job_Touch (gn, silent) } if (gn->type & OP_ARCHV) { - Arch_Touch (gn); + Arch_Touch(gn); } else if (gn->type & OP_LIB) { - Arch_TouchLib (gn); + Arch_TouchLib(gn); } else { char *file = gn->path ? gn->path : gn->name; - times[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - if (utimes(file, times) < 0){ - streamID = open (file, O_RDWR | O_CREAT, 0666); + times.actime = times.modtime = now; + if (utime(file, ×) < 0){ + streamID = open(file, O_RDWR | O_CREAT, 0666); if (streamID >= 0) { char c; @@ -880,13 +1050,16 @@ Job_Touch (gn, silent) * modification time, then close the file. */ if (read(streamID, &c, 1) == 1) { - lseek(streamID, 0L, L_SET); - write(streamID, &c, 1); + (void) lseek(streamID, 0L, L_SET); + (void) write(streamID, &c, 1); } - (void)close (streamID); - } else - printf("*** couldn't touch %s: %s", file, strerror(errno)); + (void) close(streamID); + } else { + (void) fprintf(stdout, "*** couldn't touch %s: %s", + file, strerror(errno)); + (void) fflush(stdout); + } } } } @@ -905,13 +1078,13 @@ Job_Touch (gn, silent) *----------------------------------------------------------------------- */ Boolean -Job_CheckCommands (gn, abortProc) +Job_CheckCommands(gn, abortProc) GNode *gn; /* The target whose commands need * verifying */ - void (*abortProc) __P((char *, ...)); + void (*abortProc) __P((char *, ...)); /* Function to abort with message */ { - if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) && + if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && (gn->type & OP_LIB) == 0) { /* * No commands. Look for .DEFAULT rule from which we might infer @@ -929,10 +1102,10 @@ Job_CheckCommands (gn, abortProc) * .DEFAULT itself. */ Make_HandleUse(DEFAULT, gn); - Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn); + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); if (p1) free(p1); - } else if (Dir_MTime (gn) == 0) { + } else if (Dir_MTime(gn) == 0) { /* * The node wasn't the target of an operator we have no .DEFAULT * rule to go on and the target doesn't already exist. There's @@ -940,21 +1113,22 @@ Job_CheckCommands (gn, abortProc) * given, we stop in our tracks, otherwise we just don't update * this node's parents so they never get examined. */ + static const char msg[] = "make: don't know how to make"; + if (gn->type & OP_OPTIONAL) { - printf ("make: don't know how to make %s (ignored)\n", - gn->name); + (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); + (void) fflush(stdout); } else if (keepgoing) { - printf ("make: don't know how to make %s (continuing)\n", - gn->name); - return (FALSE); + (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); + (void) fflush(stdout); + return FALSE; } else { - (*abortProc) ("make: don't know how to make %s. Stop", - gn->name); - return(FALSE); + (*abortProc)("%s %s. Stop", msg, gn->name); + return FALSE; } } } - return (TRUE); + return TRUE; } #ifdef RMT_WILL_WATCH /*- @@ -1005,13 +1179,14 @@ JobExec(job, argv) if (DEBUG(JOB)) { int i; - printf("Running %s %sly\n", job->node->name, - job->flags&JOB_REMOTE?"remote":"local"); - printf("\tCommand: "); - for (i = 0; argv[i] != (char *)NULL; i++) { - printf("%s ", argv[i]); + (void) fprintf(stdout, "Running %s %sly\n", job->node->name, + job->flags&JOB_REMOTE?"remote":"local"); + (void) fprintf(stdout, "\tCommand: "); + for (i = 0; argv[i] != NULL; i++) { + (void) fprintf(stdout, "%s ", argv[i]); } - printf("\n"); + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } /* @@ -1021,9 +1196,8 @@ JobExec(job, argv) * provide that feedback, even if nothing follows it. */ if ((lastNode != job->node) && (job->flags & JOB_FIRST) && - !(job->flags & JOB_SILENT)) - { - printf(targFmt, job->node->name); + !(job->flags & JOB_SILENT)) { + MESSAGE(stdout, job->node); lastNode = job->node; } @@ -1033,8 +1207,8 @@ JobExec(job, argv) } #endif /* RMT_NO_EXEC */ - if ((cpid = vfork()) == -1) { - Punt ("Cannot fork"); + if ((cpid = vfork()) == -1) { + Punt("Cannot fork"); } else if (cpid == 0) { /* @@ -1042,23 +1216,26 @@ JobExec(job, argv) * reset it to the beginning (again). Since the stream was marked * close-on-exec, we must clear that bit in the new input. */ - (void) dup2(fileno(job->cmdFILE), 0); - fcntl(0, F_SETFD, 0); - lseek(0, 0, L_SET); + if (dup2(FILENO(job->cmdFILE), 0) == -1) + Punt("Cannot dup2: %s", strerror(errno)); + (void) fcntl(0, F_SETFD, 0); + (void) lseek(0, 0, L_SET); if (usePipes) { /* * Set up the child's output to be routed through the pipe * we've created for it. */ - (void) dup2 (job->outPipe, 1); + if (dup2(job->outPipe, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } else { /* * We're capturing output in a file, so we duplicate the * descriptor to the temporary file into the standard * output. */ - (void) dup2 (job->outFd, 1); + if (dup2(job->outFd, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } /* * The output channels are marked close on exec. This bit was @@ -1066,8 +1243,9 @@ JobExec(job, argv) * it before routing the shell's error output to the same place as * its standard output. */ - fcntl(1, F_SETFD, 0); - (void) dup2 (1, 2); + (void) fcntl(1, F_SETFD, 0); + if (dup2(1, 2) == -1) + Punt("Cannot dup2: %s", strerror(errno)); #ifdef USE_PGRP /* @@ -1075,15 +1253,27 @@ JobExec(job, argv) * we can kill it and all its descendants in one fell swoop, * by killing its process family, but not commit suicide. */ +# if defined(SYSV) + (void) setsid(); +# else + (void) setpgid(0, getpid()); +# endif +#endif /* USE_PGRP */ - (void) setpgrp(0, getpid()); -#endif USE_PGRP - - (void) execv (shellPath, argv); - (void) write (2, "Could not execute shell\n", - sizeof ("Could not execute shell")); - _exit (1); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) { + Rmt_Exec(shellPath, argv, FALSE); + } else +#endif /* REMOTE */ + (void) execv(shellPath, argv); + + (void) write(2, "Could not execute shell\n", + sizeof("Could not execute shell")); + _exit(1); } else { +#ifdef REMOTE + long omask = sigblock(sigmask(SIGCHLD)); +#endif job->pid = cpid; if (usePipes && (job->flags & JOB_FIRST) ) { @@ -1102,17 +1292,24 @@ JobExec(job, argv) } if (job->flags & JOB_REMOTE) { +#ifndef REMOTE job->rmtID = 0; +#else + job->rmtID = Rmt_LastID(job->pid); +#endif /* REMOTE */ } else { nLocal += 1; /* - * XXX: Used to not happen if CUSTOMS. Why? + * XXX: Used to not happen if REMOTE. Why? */ - if (job->cmdFILE != stdout) { - fclose(job->cmdFILE); + if (job->cmdFILE != NULL && job->cmdFILE != stdout) { + (void) fclose(job->cmdFILE); job->cmdFILE = NULL; } } +#ifdef REMOTE + (void) sigsetmask(omask); +#endif } #ifdef RMT_NO_EXEC @@ -1122,7 +1319,7 @@ jobExecFinish: * Now the job is actually running, add it to the table. */ nJobs += 1; - (void)Lst_AtEnd (jobs, (ClientData)job); + (void) Lst_AtEnd(jobs, (ClientData)job); if (nJobs == maxJobs) { jobFull = TRUE; } @@ -1180,7 +1377,7 @@ JobMakeArgv(job, argv) argc++; } } - argv[argc] = (char *)NULL; + argv[argc] = NULL; } /*- @@ -1200,44 +1397,91 @@ static void JobRestart(job) Job *job; /* Job to restart */ { +#ifdef REMOTE + int host; +#endif + if (job->flags & JOB_REMIGRATE) { - if (DEBUG(JOB)) { - printf("Remigrating %x\n", job->pid); + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** remigrating %x(%s)\n", + job->pid, job->node->name); + (void) fflush(stdout); } - if (nLocal != maxLocal) { + +#ifdef REMOTE + if (!Rmt_ReExport(job->pid, job->node, &host)) { + if (verboseRemigrates || DEBUG(JOB)) { + (void) fprintf(stdout, "*** couldn't migrate...\n"); + (void) fflush(stdout); + } +#endif + if (nLocal != maxLocal) { /* * Job cannot be remigrated, but there's room on the local * machine, so resume the job and note that another * local job has started. */ - if (DEBUG(JOB)) { - printf("resuming on local machine\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** resuming on local machine\n"); + (void) fflush(stdout); + } KILL(job->pid, SIGCONT); nLocal +=1; +#ifdef REMOTE + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); + job->flags |= JOB_CONTINUING; +#else job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); +#endif } else { /* * Job cannot be restarted. Mark the table as full and * place the job back on the list of stopped jobs. */ - if (DEBUG(JOB)) { - printf("holding\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** holding\n"); + (void) fflush(stdout); + } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; + } +#ifdef REMOTE + } else { + /* + * Clear out the remigrate and resume flags. Set the continuing + * flag so we know later on that the process isn't exiting just + * because of a signal. + */ + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); + job->flags |= JOB_CONTINUING; + job->rmtID = host; } +#endif (void)Lst_AtEnd(jobs, (ClientData)job); nJobs += 1; if (nJobs == maxJobs) { jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } else if (job->flags & JOB_RESTART) { @@ -1254,31 +1498,58 @@ JobRestart(job) JobMakeArgv(job, argv); if (DEBUG(JOB)) { - printf("Restarting %s...", job->node->name); + (void) fprintf(stdout, "Restarting %s...", job->node->name); + (void) fflush(stdout); } - if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) { +#ifdef REMOTE + if ((job->node->type&OP_NOEXPORT) || + (nLocal < maxLocal && runLocalFirst) +# ifdef RMT_NO_EXEC + || !Rmt_Export(shellPath, argv, job) +# else + || !Rmt_Begin(shellPath, argv, job->node) +# endif +#endif + { + if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { /* * Can't be exported and not allowed to run locally -- put it * back on the hold queue and mark the table full */ if (DEBUG(JOB)) { - printf("holding\n"); + (void) fprintf(stdout, "holding\n"); + (void) fflush(stdout); } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; - } else { + } else { /* * Job may be run locally. */ if (DEBUG(JOB)) { - printf("running locally\n"); + (void) fprintf(stdout, "running locally\n"); + (void) fflush(stdout); } job->flags &= ~JOB_REMOTE; + } + } +#ifdef REMOTE + else { + /* + * Can be exported. Hooray! + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, "exporting\n"); + (void) fflush(stdout); + } + job->flags |= JOB_REMOTE; } +#endif JobExec(job, argv); } else { /* @@ -1286,13 +1557,20 @@ JobRestart(job) * we don't know... */ if (DEBUG(JOB)) { - printf("Resuming %s...", job->node->name); + (void) fprintf(stdout, "Resuming %s...", job->node->name); + (void) fflush(stdout); } if (((job->flags & JOB_REMOTE) || - (nLocal < maxLocal) || - (((job->flags & JOB_SPECIAL)) && - (maxLocal == 0))) && - (nJobs != maxJobs)) + (nLocal < maxLocal) || +#ifdef REMOTE + (((job->flags & JOB_SPECIAL) && + (job->node->type & OP_NOEXPORT)) && + (maxLocal == 0))) && +#else + ((job->flags & JOB_SPECIAL) && + (maxLocal == 0))) && +#endif + (nJobs != maxJobs)) { /* * If the job is remote, it's ok to resume it as long as the @@ -1303,7 +1581,7 @@ JobRestart(job) */ Boolean error; extern int errno; - union wait status; + int status; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { @@ -1318,19 +1596,20 @@ JobRestart(job) * actually put the thing in the job table. */ job->flags |= JOB_CONTINUING; - status.w_termsig = SIGCONT; - JobFinish(job, status); + W_SETTERMSIG(&status, SIGCONT); + JobFinish(job, &status); job->flags &= ~(JOB_RESUME|JOB_CONTINUING); if (DEBUG(JOB)) { - printf("done\n"); + (void) fprintf(stdout, "done\n"); + (void) fflush(stdout); } } else { Error("couldn't resume %s: %s", job->node->name, strerror(errno)); - status.w_status = 0; - status.w_retcode = 1; - JobFinish(job, status); + status = 0; + W_SETEXITSTATUS(&status, 1); + JobFinish(job, &status); } } else { /* @@ -1338,12 +1617,14 @@ JobRestart(job) * place the job back on the list of stopped jobs. */ if (DEBUG(JOB)) { - printf("table full\n"); + (void) fprintf(stdout, "table full\n"); + (void) fflush(stdout); } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); + (void) Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } @@ -1366,7 +1647,7 @@ JobRestart(job) *----------------------------------------------------------------------- */ static int -JobStart (gn, flags, previous) +JobStart(gn, flags, previous) GNode *gn; /* target to create */ int flags; /* flags for the job to override normal ones. * e.g. JOB_SPECIAL or JOB_IGNDOTS */ @@ -1380,12 +1661,12 @@ JobStart (gn, flags, previous) Boolean local; /* Set true if the job was run locally */ Boolean noExec; /* Set true if we decide not to run the job */ - if (previous != (Job *)NULL) { - previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); + if (previous != NULL) { + previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); job = previous; } else { - job = (Job *) emalloc (sizeof (Job)); - if (job == (Job *)NULL) { + job = (Job *) emalloc(sizeof(Job)); + if (job == NULL) { Punt("JobStart out of memory"); } flags |= JOB_FIRST; @@ -1400,10 +1681,10 @@ JobStart (gn, flags, previous) * are also added to the field. */ job->flags = 0; - if (Targ_Ignore (gn)) { + if (Targ_Ignore(gn)) { job->flags |= JOB_IGNERR; } - if (Targ_Silent (gn)) { + if (Targ_Silent(gn)) { job->flags |= JOB_SILENT; } job->flags |= flags; @@ -1412,7 +1693,7 @@ JobStart (gn, flags, previous) * Check the commands now so any attributes from .DEFAULT have a chance * to migrate to the node */ - if (job->flags & JOB_FIRST) { + if (!compatMake && job->flags & JOB_FIRST) { cmdsOK = Job_CheckCommands(gn, Error); } else { cmdsOK = TRUE; @@ -1433,11 +1714,11 @@ JobStart (gn, flags, previous) DieHorribly(); } - job->cmdFILE = fopen (tfile, "w+"); - if (job->cmdFILE == (FILE *) NULL) { - Punt ("Could not open %s", tfile); + job->cmdFILE = fopen(tfile, "w+"); + if (job->cmdFILE == NULL) { + Punt("Could not open %s", tfile); } - fcntl(fileno(job->cmdFILE), F_SETFD, 1); + (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); /* * Send the commands to the command file, flush all its buffers then * rewind and remove the thing. @@ -1460,13 +1741,14 @@ JobStart (gn, flags, previous) if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ cmdsOK = FALSE; } else { - LstNode ln = Lst_Next (gn->commands); + LstNode ln = Lst_Next(gn->commands); if ((ln == NILLNODE) || - JobPrintCommand ((char *)Lst_Datum (ln), job)) + JobPrintCommand((ClientData) Lst_Datum(ln), + (ClientData) job)) { noExec = TRUE; - Lst_Close (gn->commands); + Lst_Close(gn->commands); } if (noExec && !(job->flags & JOB_FIRST)) { /* @@ -1480,21 +1762,7 @@ JobStart (gn, flags, previous) * Job_CatchChildren b/c it wasn't clear if there were * more commands to execute or not... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } + JobClose(job); } } } else { @@ -1502,7 +1770,7 @@ JobStart (gn, flags, previous) * We can do all the commands at once. hooray for sanity */ numCommands = 0; - Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job); + Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job); /* * If we didn't print out any commands to the shell script, @@ -1518,7 +1786,7 @@ JobStart (gn, flags, previous) * in one fell swoop. This will still set up job->tailCmds correctly. */ if (lastNode != gn) { - printf (targFmt, gn->name); + MESSAGE(stdout, gn); lastNode = gn; } job->cmdFILE = stdout; @@ -1542,7 +1810,7 @@ JobStart (gn, flags, previous) * up the graph. */ job->cmdFILE = stdout; - Job_Touch (gn, job->flags&JOB_SILENT); + Job_Touch(gn, job->flags&JOB_SILENT); noExec = TRUE; } @@ -1554,10 +1822,11 @@ JobStart (gn, flags, previous) * Unlink and close the command file if we opened one */ if (job->cmdFILE != stdout) { - (void) unlink (tfile); - fclose(job->cmdFILE); + (void) eunlink(tfile); + if (job->cmdFILE != NULL) + (void) fclose(job->cmdFILE); } else { - fflush (stdout); + (void) fflush(stdout); } /* @@ -1569,7 +1838,7 @@ JobStart (gn, flags, previous) if (job->tailCmds != NILLNODE) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } Make_Update(job->node); } @@ -1580,8 +1849,8 @@ JobStart (gn, flags, previous) return(JOB_ERROR); } } else { - fflush (job->cmdFILE); - (void) unlink (tfile); + (void) fflush(job->cmdFILE); + (void) eunlink(tfile); } /* @@ -1596,29 +1865,47 @@ JobStart (gn, flags, previous) * starting a job and then set up its temporary-file name. This is just * tfile with two extra digits tacked on -- jobno. */ - if (job->flags & JOB_FIRST) { + if (!compatMake || (job->flags & JOB_FIRST)) { if (usePipes) { int fd[2]; - (void) pipe(fd); + if (pipe(fd) == -1) + Punt("Cannot create pipe: %s", strerror(errno)); job->inPipe = fd[0]; job->outPipe = fd[1]; - (void)fcntl (job->inPipe, F_SETFD, 1); - (void)fcntl (job->outPipe, F_SETFD, 1); + (void) fcntl(job->inPipe, F_SETFD, 1); + (void) fcntl(job->outPipe, F_SETFD, 1); } else { - printf ("Remaking `%s'\n", gn->name); - fflush (stdout); - sprintf (job->outFile, "%s%02d", tfile, jobno); + (void) fprintf(stdout, "Remaking `%s'\n", gn->name); + (void) fflush(stdout); + sprintf(job->outFile, "%s%02d", tfile, jobno); jobno = (jobno + 1) % 100; job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600); - (void)fcntl (job->outFd, F_SETFD, 1); + (void) fcntl(job->outFd, F_SETFD, 1); } } - local = TRUE; +#ifdef REMOTE + if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { +#ifdef RMT_NO_EXEC + local = !Rmt_Export(shellPath, argv, job); +#else + local = !Rmt_Begin(shellPath, argv, job->node); +#endif /* RMT_NO_EXEC */ + if (!local) { + job->flags |= JOB_REMOTE; + } + } else +#endif + local = TRUE; if (local && (((nLocal >= maxLocal) && - !(job->flags & JOB_SPECIAL) && - (maxLocal != 0)))) + !(job->flags & JOB_SPECIAL) && +#ifdef REMOTE + (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) +#else + (maxLocal != 0) +#endif + ))) { /* * The job can only be run locally, but we've hit the limit of @@ -1626,15 +1913,17 @@ JobStart (gn, flags, previous) * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) * may be run locally even when the local limit has been reached * (e.g. when maxLocal == 0), though they will be exported if at - * all possible. + * all possible. In addition, any target marked with .NOEXPORT will + * be run locally if maxLocal is 0. */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Can only run job locally.\n"); + (void) fprintf(stdout, "Can only run job locally.\n"); + (void) fflush(stdout); } job->flags |= JOB_RESTART; - (void)Lst_AtEnd(stoppedJobs, (ClientData)job); + (void) Lst_AtEnd(stoppedJobs, (ClientData)job); } else { if ((nLocal >= maxLocal) && local) { /* @@ -1643,7 +1932,8 @@ JobStart (gn, flags, previous) */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Local job queue is full.\n"); + (void) fprintf(stdout, "Local job queue is full.\n"); + (void) fflush(stdout); } } JobExec(job, argv); @@ -1651,6 +1941,52 @@ JobStart (gn, flags, previous) return(JOB_RUNNING); } +static char * +JobOutput(job, cp, endp, msg) + register Job *job; + register char *cp, *endp; + int msg; +{ + register char *ecp; + + if (commandShell->noPrint) { + ecp = Str_FindSubstring(cp, commandShell->noPrint); + while (ecp != NULL) { + if (cp != ecp) { + *ecp = '\0'; + if (msg && job->node != lastNode) { + MESSAGE(stdout, job->node); + lastNode = job->node; + } + /* + * The only way there wouldn't be a newline after + * this line is if it were the last in the buffer. + * however, since the non-printable comes after it, + * there must be a newline, so we don't print one. + */ + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + } + cp = ecp + commandShell->noPLen; + if (cp != endp) { + /* + * Still more to print, look again after skipping + * the whitespace following the non-printable + * command.... + */ + cp++; + while (*cp == ' ' || *cp == '\t' || *cp == '\n') { + cp++; + } + ecp = Str_FindSubstring(cp, commandShell->noPrint); + } else { + return cp; + } + } + } + return cp; +} + /*- *----------------------------------------------------------------------- * JobDoOutput -- @@ -1678,13 +2014,14 @@ JobStart (gn, flags, previous) * curPos may be shifted as may the contents of outBuf. *----------------------------------------------------------------------- */ -static void -JobDoOutput (job, finish) +STATIC void +JobDoOutput(job, finish) register Job *job; /* the job whose output needs printing */ Boolean finish; /* TRUE if this is the last time we'll be * called for this job */ { Boolean gotNL = FALSE; /* true if got a newline */ + Boolean fbuf; /* true if our buffer filled up */ register int nr; /* number of bytes read */ register int i; /* auxiliary index into outBuf */ register int max; /* limit for i (end of current data) */ @@ -1699,8 +2036,10 @@ JobDoOutput (job, finish) * Read as many bytes as will fit in the buffer. */ end_loop: + gotNL = FALSE; + fbuf = FALSE; - nRead = read (job->inPipe, &job->outBuf[job->curPos], + nRead = read(job->inPipe, &job->outBuf[job->curPos], JOB_BUFSIZE - job->curPos); if (nRead < 0) { if (DEBUG(JOB)) { @@ -1750,11 +2089,11 @@ end_loop: * If we've run out of buffer space, we have no choice * but to print the stuff. sigh. */ - gotNL = TRUE; + fbuf = TRUE; i = job->curPos; } } - if (gotNL) { + if (gotNL || fbuf) { /* * Need to send the output to the screen. Null terminate it * first, overwriting the newline character if there was one. @@ -1767,45 +2106,9 @@ end_loop: */ job->outBuf[i] = '\0'; if (i >= job->curPos) { - register char *cp, *ecp; - - cp = job->outBuf; - if (commandShell->noPrint) { - ecp = Str_FindSubstring(job->outBuf, - commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - if (job->node != lastNode) { - printf (targFmt, job->node->name); - lastNode = job->node; - } - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != &job->outBuf[i]) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring (cp, - commandShell->noPrint); - } else { - break; - } - } - } + char *cp; + + cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); /* * There's still more in that thar buffer. This time, though, @@ -1814,17 +2117,16 @@ end_loop: */ if (*cp != '\0') { if (job->node != lastNode) { - printf (targFmt, job->node->name); + MESSAGE(stdout, job->node); lastNode = job->node; } - printf ("%s\n", cp); + (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); + (void) fflush(stdout); } - - fflush (stdout); } if (i < max - 1) { /* shift the remaining characters down */ - memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1)); + (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); job->curPos = max - (i + 1); } else { @@ -1838,10 +2140,11 @@ end_loop: if (finish) { /* * If the finish flag is true, we must loop until we hit - * end-of-file on the pipe. This is guaranteed to happen eventually - * since the other end of the pipe is now closed (we closed it - * explicitly and the child has exited). When we do get an EOF, - * finish will be set FALSE and we'll fall through and out. + * end-of-file on the pipe. This is guaranteed to happen + * eventually since the other end of the pipe is now closed + * (we closed it explicitly and the child has exited). When + * we do get an EOF, finish will be set FALSE and we'll fall + * through and out. */ goto end_loop; } @@ -1856,62 +2159,36 @@ end_loop: * Change to read in blocks and do FindSubString type things as for * pipes? That would allow for "@echo -n..." */ - oFILE = fopen (job->outFile, "r"); - if (oFILE != (FILE *) NULL) { - printf ("Results of making %s:\n", job->node->name); - while (fgets (inLine, sizeof(inLine), oFILE) != NULL) { - register char *cp, *ecp, *endp; + oFILE = fopen(job->outFile, "r"); + if (oFILE != NULL) { + (void) fprintf(stdout, "Results of making %s:\n", job->node->name); + (void) fflush(stdout); + while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { + register char *cp, *endp, *oendp; cp = inLine; - endp = inLine + strlen(inLine); + oendp = endp = inLine + strlen(inLine); if (endp[-1] == '\n') { *--endp = '\0'; } - if (commandShell->noPrint) { - ecp = Str_FindSubstring(cp, commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != endp) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring(cp, commandShell->noPrint); - } else { - break; - } - } - } + cp = JobOutput(job, inLine, endp, FALSE); /* * There's still more in that thar buffer. This time, though, * we know there's no newline at the end, so we add one of * our own free will. */ - if (*cp != '\0') { - printf ("%s\n", cp); + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + if (endp != oendp) { + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } } - fclose (oFILE); - (void) unlink (job->outFile); + (void) fclose(oFILE); + (void) eunlink(job->outFile); } } - fflush(stdout); } /*- @@ -1934,13 +2211,13 @@ end_loop: *----------------------------------------------------------------------- */ void -Job_CatchChildren (block) +Job_CatchChildren(block) Boolean block; /* TRUE if should block on the wait. */ { int pid; /* pid of dead child */ register Job *job; /* job descriptor for dead child */ LstNode jnode; /* list element for finding job */ - union wait status; /* Exit/termination status */ + int status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. @@ -1949,40 +2226,54 @@ Job_CatchChildren (block) return; } - while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED, - (struct rusage *)0)) > 0) + while ((pid = waitpid((pid_t) -1, &status, + (block?0:WNOHANG)|WUNTRACED)) > 0) { - if (DEBUG(JOB)) - printf("Process %d exited or stopped.\n", pid); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); + (void) fflush(stdout); + } - jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid); + jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); if (jnode == NILLNODE) { - if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) { + if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); if (jnode == NILLNODE) { Error("Resumed child (%d) not in table", pid); continue; } job = (Job *)Lst_Datum(jnode); - (void)Lst_Remove(stoppedJobs, jnode); + (void) Lst_Remove(stoppedJobs, jnode); } else { - Error ("Child (%d) not in table?", pid); + Error("Child (%d) not in table?", pid); continue; } } else { - job = (Job *) Lst_Datum (jnode); - (void)Lst_Remove (jobs, jnode); + job = (Job *) Lst_Datum(jnode); + (void) Lst_Remove(jobs, jnode); nJobs -= 1; if (jobFull && DEBUG(JOB)) { - printf("Job queue is no longer full.\n"); + (void) fprintf(stdout, "Job queue is no longer full.\n"); + (void) fflush(stdout); } jobFull = FALSE; +#ifdef REMOTE + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue has one fewer local process.\n"); + (void) fflush(stdout); + } + nLocal -= 1; + } +#else nLocal -= 1; +#endif } - JobFinish (job, status); + JobFinish(job, &status); } } @@ -2003,7 +2294,7 @@ Job_CatchChildren (block) * ----------------------------------------------------------------------- */ void -Job_CatchOutput () +Job_CatchOutput() { int nfds; struct timeval timeout; @@ -2014,7 +2305,7 @@ Job_CatchOutput () int pnJobs; /* Previous nJobs */ #endif - fflush(stdout); + (void) fflush(stdout); #ifdef RMT_WILL_WATCH pnJobs = nJobs; @@ -2043,21 +2334,21 @@ Job_CatchOutput () timeout.tv_sec = SEL_SEC; timeout.tv_usec = SEL_USEC; - if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0) - { + if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, + (fd_set *) 0, &timeout)) <= 0) return; - } else { - if (Lst_Open (jobs) == FAILURE) { - Punt ("Cannot open job table"); + else { + if (Lst_Open(jobs) == FAILURE) { + Punt("Cannot open job table"); } - while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput (job, FALSE); + JobDoOutput(job, FALSE); nfds -= 1; } } - Lst_Close (jobs); + Lst_Close(jobs); } } #endif /* RMT_WILL_WATCH */ @@ -2078,10 +2369,10 @@ Job_CatchOutput () *----------------------------------------------------------------------- */ void -Job_Make (gn) +Job_Make(gn) GNode *gn; { - (void)JobStart (gn, 0, (Job *)NULL); + (void) JobStart(gn, 0, NULL); } /*- @@ -2097,7 +2388,7 @@ Job_Make (gn) *----------------------------------------------------------------------- */ void -Job_Init (maxproc, maxlocal) +Job_Init(maxproc, maxlocal) int maxproc; /* the greatest number of jobs which may be * running at one time */ int maxlocal; /* the greatest number of local jobs which may @@ -2105,9 +2396,9 @@ Job_Init (maxproc, maxlocal) { GNode *begin; /* node for commands to do at the very start */ - sprintf (tfile, "/tmp/make%05d", getpid()); + (void) sprintf(tfile, "/tmp/make%05d", getpid()); - jobs = Lst_Init (FALSE); + jobs = Lst_Init(FALSE); stoppedJobs = Lst_Init(FALSE); maxJobs = maxproc; maxLocal = maxlocal; @@ -2120,7 +2411,11 @@ Job_Init (maxproc, maxlocal) lastNode = NILGNODE; - if (maxJobs == 1) { + if (maxJobs == 1 +#ifdef REMOTE + || noMessages +#endif + ) { /* * If only one job can run at a time, there's no need for a banner, * no is there? @@ -2130,7 +2425,7 @@ Job_Init (maxproc, maxlocal) targFmt = TARG_FMT; } - if (shellPath == (char *) NULL) { + if (shellPath == NULL) { /* * The user didn't specify a shell to use, so we are using the * default one... Both the absolute path and the last component @@ -2139,13 +2434,13 @@ Job_Init (maxproc, maxlocal) * All default shells are located in _PATH_DEFSHELLDIR. */ shellName = commandShell->name; - shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); + shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); } - if (commandShell->exit == (char *)NULL) { + if (commandShell->exit == NULL) { commandShell->exit = ""; } - if (commandShell->echo == (char *)NULL) { + if (commandShell->echo == NULL) { commandShell->echo = ""; } @@ -2153,17 +2448,17 @@ Job_Init (maxproc, maxlocal) * Catch the four signals that POSIX specifies if they aren't ignored. * JobPassSig will take care of calling JobInterrupt if appropriate. */ - if (signal (SIGINT, SIG_IGN) != SIG_IGN) { - signal (SIGINT, JobPassSig); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, JobPassSig); } - if (signal (SIGHUP, SIG_IGN) != SIG_IGN) { - signal (SIGHUP, JobPassSig); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, JobPassSig); } - if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) { - signal (SIGQUIT, JobPassSig); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGQUIT, JobPassSig); } - if (signal (SIGTERM, SIG_IGN) != SIG_IGN) { - signal (SIGTERM, JobPassSig); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTERM, JobPassSig); } /* * There are additional signals that need to be caught and passed if @@ -2172,32 +2467,32 @@ Job_Init (maxproc, maxlocal) * signals from the terminal driver as we own the terminal) */ #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) - if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) { - signal (SIGTSTP, JobPassSig); + if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTSTP, JobPassSig); } - if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) { - signal (SIGTTOU, JobPassSig); + if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTOU, JobPassSig); } - if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) { - signal (SIGTTIN, JobPassSig); + if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTIN, JobPassSig); } - if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) { - signal (SIGWINCH, JobPassSig); + if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { + (void) signal(SIGWINCH, JobPassSig); } #endif - begin = Targ_FindNode (".BEGIN", TARG_NOCREATE); + begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); if (begin != NILGNODE) { - JobStart (begin, JOB_SPECIAL, (Job *)0); + JobStart(begin, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } - postCommands = Targ_FindNode (".END", TARG_CREATE); + postCommands = Targ_FindNode(".END", TARG_CREATE); } /*- @@ -2215,9 +2510,9 @@ Job_Init (maxproc, maxlocal) *----------------------------------------------------------------------- */ Boolean -Job_Full () +Job_Full() { - return (aborting || jobFull); + return(aborting || jobFull); } /*- @@ -2237,7 +2532,7 @@ Job_Full () * ----------------------------------------------------------------------- */ Boolean -Job_Empty () +Job_Empty() { if (nJobs == 0) { if (!Lst_IsEmpty(stoppedJobs) && !aborting) { @@ -2246,9 +2541,7 @@ Job_Empty () * it...Try and restart the stopped jobs. */ jobFull = FALSE; - while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); return(FALSE); } else { return(TRUE); @@ -2272,7 +2565,7 @@ Job_Empty () *----------------------------------------------------------------------- */ static Shell * -JobMatchShell (name) +JobMatchShell(name) char *name; /* Final component of shell path */ { register Shell *sh; /* Pointer into shells table */ @@ -2281,24 +2574,23 @@ JobMatchShell (name) *cp2; char *eoname; - eoname = name + strlen (name); + eoname = name + strlen(name); - match = (Shell *) NULL; + match = NULL; for (sh = shells; sh->name != NULL; sh++) { - for (cp1 = eoname - strlen (sh->name), cp2 = sh->name; + for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; *cp1 != '\0' && *cp1 == *cp2; cp1++, cp2++) { continue; } if (*cp1 != *cp2) { continue; - } else if (match == (Shell *) NULL || - strlen (match->name) < strlen (sh->name)) { - match = sh; + } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { + match = sh; } } - return (match == (Shell *) NULL ? sh : match); + return(match == NULL ? sh : match); } /*- @@ -2345,7 +2637,7 @@ JobMatchShell (name) *----------------------------------------------------------------------- */ ReturnStatus -Job_ParseShell (line) +Job_ParseShell(line) char *line; /* The shell spec */ { char **words; @@ -2356,64 +2648,64 @@ Job_ParseShell (line) Shell newShell; Boolean fullSpec = FALSE; - while (isspace (*line)) { + while (isspace(*line)) { line++; } - words = brk_string (line, &wordCount, TRUE); + words = brk_string(line, &wordCount, TRUE); - memset ((Address)&newShell, 0, sizeof(newShell)); + memset((Address)&newShell, 0, sizeof(newShell)); /* * Parse the specification by keyword */ - for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1; + for (path = NULL, argc = wordCount - 1, argv = words + 1; argc != 0; argc--, argv++) { - if (strncmp (*argv, "path=", 5) == 0) { + if (strncmp(*argv, "path=", 5) == 0) { path = &argv[0][5]; - } else if (strncmp (*argv, "name=", 5) == 0) { + } else if (strncmp(*argv, "name=", 5) == 0) { newShell.name = &argv[0][5]; } else { - if (strncmp (*argv, "quiet=", 6) == 0) { + if (strncmp(*argv, "quiet=", 6) == 0) { newShell.echoOff = &argv[0][6]; - } else if (strncmp (*argv, "echo=", 5) == 0) { + } else if (strncmp(*argv, "echo=", 5) == 0) { newShell.echoOn = &argv[0][5]; - } else if (strncmp (*argv, "filter=", 7) == 0) { + } else if (strncmp(*argv, "filter=", 7) == 0) { newShell.noPrint = &argv[0][7]; newShell.noPLen = strlen(newShell.noPrint); - } else if (strncmp (*argv, "echoFlag=", 9) == 0) { + } else if (strncmp(*argv, "echoFlag=", 9) == 0) { newShell.echo = &argv[0][9]; - } else if (strncmp (*argv, "errFlag=", 8) == 0) { + } else if (strncmp(*argv, "errFlag=", 8) == 0) { newShell.exit = &argv[0][8]; - } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) { + } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { char c = argv[0][10]; newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && - (c != 'T') && (c != 't')); - } else if (strncmp (*argv, "check=", 6) == 0) { + (c != 'T') && (c != 't')); + } else if (strncmp(*argv, "check=", 6) == 0) { newShell.errCheck = &argv[0][6]; - } else if (strncmp (*argv, "ignore=", 7) == 0) { + } else if (strncmp(*argv, "ignore=", 7) == 0) { newShell.ignErr = &argv[0][7]; } else { - Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"", + Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); - return (FAILURE); + return(FAILURE); } fullSpec = TRUE; } } - if (path == (char *)NULL) { + if (path == NULL) { /* * If no path was given, the user wants one of the pre-defined shells, * yes? So we find the one s/he wants with the help of JobMatchShell * and set things up the right way. shellPath will be set up by * Job_Init. */ - if (newShell.name == (char *)NULL) { - Parse_Error (PARSE_FATAL, "Neither path nor name specified"); - return (FAILURE); + if (newShell.name == NULL) { + Parse_Error(PARSE_FATAL, "Neither path nor name specified"); + return(FAILURE); } else { - commandShell = JobMatchShell (newShell.name); + commandShell = JobMatchShell(newShell.name); shellName = newShell.name; } } else { @@ -2425,19 +2717,19 @@ Job_ParseShell (line) * path the user gave for the shell. */ shellPath = path; - path = strrchr (path, '/'); - if (path == (char *)NULL) { + path = strrchr(path, '/'); + if (path == NULL) { path = shellPath; } else { path += 1; } - if (newShell.name != (char *)NULL) { + if (newShell.name != NULL) { shellName = newShell.name; } else { shellName = path; } if (!fullSpec) { - commandShell = JobMatchShell (shellName); + commandShell = JobMatchShell(shellName); } else { commandShell = (Shell *) emalloc(sizeof(Shell)); *commandShell = newShell; @@ -2449,10 +2741,10 @@ Job_ParseShell (line) } if (!commandShell->hasErrCtl) { - if (commandShell->errCheck == (char *)NULL) { + if (commandShell->errCheck == NULL) { commandShell->errCheck = ""; } - if (commandShell->ignErr == (char *)NULL) { + if (commandShell->ignErr == NULL) { commandShell->ignErr = "%s\n"; } } @@ -2461,7 +2753,7 @@ Job_ParseShell (line) * Do not free up the words themselves, since they might be in use by the * shell specification... */ - free (words); + free(words); return SUCCESS; } @@ -2479,9 +2771,10 @@ Job_ParseShell (line) *----------------------------------------------------------------------- */ static void -JobInterrupt (runINTERRUPT) +JobInterrupt(runINTERRUPT, signo) int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT * target should be executed */ + int signo; /* signal received */ { LstNode ln; /* element in job table */ Job *job; /* job descriptor in that element */ @@ -2489,18 +2782,16 @@ JobInterrupt (runINTERRUPT) aborting = ABORT_INTERRUPT; - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); - if (!Targ_Precious (job->node)) { - char *file = (job->node->path == (char *)NULL ? + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? job->node->name : job->node->path); - struct stat st; - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { - Error ("*** %s removed", file); + if (!noExecute && eunlink(file) != -1) { + Error("*** %s removed", file); } } #ifdef RMT_WANTS_SIGNALS @@ -2508,44 +2799,110 @@ JobInterrupt (runINTERRUPT) /* * If job is remote, let the Rmt module do the killing. */ - if (!Rmt_Signal(job, SIGINT)) { + if (!Rmt_Signal(job, signo)) { /* * If couldn't kill the thing, finish it out now with an * error code, since no exit report will come in likely. */ - union wait status; + int status; status.w_status = 0; status.w_retcode = 1; - JobFinish(job, status); + JobFinish(job, &status); } } else if (job->pid) { - KILL(job->pid, SIGINT); + KILL(job->pid, signo); } #else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing signal to child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, signo); + } +#endif /* RMT_WANTS_SIGNALS */ + } + +#ifdef REMOTE + (void)Lst_Open(stoppedJobs); + while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); + + if (job->flags & JOB_RESTART) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "%s%s", + "JobInterrupt skipping job on stopped queue", + "-- it was waiting to be restarted.\n"); + (void) fflush(stdout); + } + continue; + } + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? + job->node->name : + job->node->path); + if (eunlink(file) == 0) { + Error("*** %s removed", file); + } + } + /* + * Resume the thing so it will take the signal. + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing CONT to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, SIGCONT); +#ifdef RMT_WANTS_SIGNALS + if (job->flags & JOB_REMOTE) { + /* + * If job is remote, let the Rmt module do the killing. + */ + if (!Rmt_Signal(job, SIGINT)) { + /* + * If couldn't kill the thing, finish it out now with an + * error code, since no exit report will come in likely. + */ + int status; + status.w_status = 0; + status.w_retcode = 1; + JobFinish(job, &status); + } + } else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing interrupt to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } KILL(job->pid, SIGINT); } #endif /* RMT_WANTS_SIGNALS */ } - Lst_Close (jobs); +#endif + Lst_Close(stoppedJobs); if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE); + interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (interrupt != NILGNODE) { ignoreErrors = FALSE; - JobStart (interrupt, JOB_IGNDOTS, (Job *)0); + JobStart(interrupt, JOB_IGNDOTS, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); - exit (0); + (void) eunlink(tfile); + exit(signo); } /* @@ -2563,24 +2920,23 @@ JobInterrupt (runINTERRUPT) *----------------------------------------------------------------------- */ int -Job_End () +Job_End() { - if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) { + if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) { if (errors) { - Error ("Errors reported so .END ignored"); + Error("Errors reported so .END ignored"); } else { - JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS, - (Job *)0); + JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); + (void) eunlink(tfile); return(errors); } @@ -2626,9 +2982,9 @@ Job_Wait() *----------------------------------------------------------------------- */ void -Job_AbortAll () +Job_AbortAll() { - LstNode ln; /* element in job table */ + LstNode ln; /* element in job table */ Job *job; /* the job descriptor in that element */ int foo; @@ -2636,9 +2992,9 @@ Job_AbortAll () if (nJobs) { - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); /* * kill the child process with increasingly drastic signals to make @@ -2662,7 +3018,88 @@ Job_AbortAll () /* * Catch as many children as want to report in at first, then give up */ - while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0) + while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) continue; - (void) unlink (tfile); + (void) eunlink(tfile); +} + +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobFlagForMigration -- + * Handle the eviction of a child. Called from RmtStatusChange. + * Flags the child as remigratable and then suspends it. + * + * Results: + * none. + * + * Side Effects: + * The job descriptor is flagged for remigration. + * + *----------------------------------------------------------------------- + */ +void +JobFlagForMigration(hostID) + int hostID; /* ID of host we used, for matching children. */ +{ + register Job *job; /* job descriptor for dead child */ + LstNode jnode; /* list element for finding job */ + + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); + (void) fflush(stdout); + } + jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID); + + if (jnode == NILLNODE) { + jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID); + if (jnode == NILLNODE) { + if (DEBUG(JOB)) { + Error("Evicting host(%d) not in table", hostID); + } + return; + } + } + job = (Job *) Lst_Datum(jnode); + + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobFlagForMigration(%d) found job '%s'.\n", hostID, + job->node->name); + (void) fflush(stdout); + } + + KILL(job->pid, SIGSTOP); + + job->flags |= JOB_REMIGRATE; +} + +#endif + +/*- + *----------------------------------------------------------------------- + * JobRestartJobs -- + * Tries to restart stopped jobs if there are slots available. + * Note that this tries to restart them regardless of pending errors. + * It's not good to leave stopped jobs lying around! + * + * Results: + * None. + * + * Side Effects: + * Resumes(and possibly migrates) jobs. + * + *----------------------------------------------------------------------- + */ +static void +JobRestartJobs() +{ + while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue is not full. Restarting a stopped job.\n"); + (void) fflush(stdout); + } + JobRestart((Job *)Lst_DeQueue(stoppedJobs)); + } } diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h index d16986b..b2d424d 100644 --- a/usr.bin/make/job.h +++ b/usr.bin/make/job.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)job.h 8.1 (Berkeley) 6/6/93 + * from: @(#)job.h 8.1 (Berkeley) 6/6/93 */ /*- diff --git a/usr.bin/make/list.h b/usr.bin/make/list.h index 1b21bfe..b923f5e 100644 --- a/usr.bin/make/list.h +++ b/usr.bin/make/list.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)list.h 8.1 (Berkeley) 6/6/93 + * from: @(#)list.h 8.1 (Berkeley) 6/6/93 */ /* diff --git a/usr.bin/make/lst.h b/usr.bin/make/lst.h index 6131ae3..fd94352 100644 --- a/usr.bin/make/lst.h +++ b/usr.bin/make/lst.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)lst.h 8.1 (Berkeley) 6/6/93 + * from: @(#)lst.h 8.1 (Berkeley) 6/6/93 */ /*- @@ -46,7 +46,7 @@ #define _LST_H_ #include <sprite.h> -#include <sys/cdefs.h> +#include <sys/param.h> #if __STDC__ #include <stdlib.h> #endif diff --git a/usr.bin/make/lst.lib/lstForEachFrom.c b/usr.bin/make/lst.lib/lstForEachFrom.c index 6ae43ef..58bcb47 100644 --- a/usr.bin/make/lst.lib/lstForEachFrom.c +++ b/usr.bin/make/lst.lib/lstForEachFrom.c @@ -66,7 +66,7 @@ void Lst_ForEachFrom (l, ln, proc, d) Lst l; LstNode ln; - register int (*proc)(); + register int (*proc) __P((ClientData, ClientData)); register ClientData d; { register ListNode tln = (ListNode)ln; @@ -109,3 +109,4 @@ Lst_ForEachFrom (l, ln, proc, d) } while (!result && !LstIsEmpty(list) && !done); } + diff --git a/usr.bin/make/lst.lib/lstInt.h b/usr.bin/make/lst.lib/lstInt.h index 0296558..d83ac83 100644 --- a/usr.bin/make/lst.lib/lstInt.h +++ b/usr.bin/make/lst.lib/lstInt.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)lstInt.h 8.1 (Berkeley) 6/6/93 + * from: @(#)lstInt.h 8.1 (Berkeley) 6/6/93 */ /*- @@ -43,6 +43,7 @@ #ifndef _LSTINT_H_ #define _LSTINT_H_ +#include "make.h" #include "lst.h" typedef struct ListNode { @@ -87,7 +88,7 @@ typedef struct { * PAlloc (var, ptype) -- * Allocate a pointer-typedef structure 'ptype' into the variable 'var' */ -#define PAlloc(var,ptype) var = (ptype) malloc (sizeof (*var)) +#define PAlloc(var,ptype) var = (ptype) emalloc (sizeof (*var)) /* * LstValid (l) -- diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index 81c5b39..60804ef 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -79,7 +79,10 @@ static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; #include <sys/resource.h> #include <sys/signal.h> #include <sys/stat.h> +#ifndef MACHINE #include <sys/utsname.h> +#endif +#include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -96,7 +99,7 @@ static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; #ifndef DEFMAXLOCAL #define DEFMAXLOCAL DEFMAXJOBS -#endif DEFMAXLOCAL +#endif /* DEFMAXLOCAL */ #define MAKEFLAGS ".MAKEFLAGS" @@ -109,7 +112,7 @@ static Boolean noBuiltins; /* -r flag */ static Lst makefiles; /* ordered list of makefiles to read */ static Boolean printVars; /* print value of one or more vars */ static Lst variables; /* list of variables to print */ -int maxJobs; /* -J argument */ +int maxJobs; /* -j argument */ static int maxLocal; /* -L argument */ Boolean compatMake; /* -B argument */ Boolean debug; /* -d flag */ @@ -124,8 +127,10 @@ Boolean oldVars; /* variable substitution style */ Boolean checkEnvFirst; /* -e flag */ static Boolean jobsRunning; /* TRUE if the jobs might be running */ -static Boolean ReadMakefile(); -static void usage(); +static void MainParseArgs __P((int, char **)); +char * chdir_verify_path __P((char *, char *)); +static int ReadMakefile __P((ClientData, ClientData)); +static void usage __P((void)); static char *curdir; /* startup directory */ static char *objdir; /* where we chdir'ed to */ @@ -152,12 +157,13 @@ MainParseArgs(argc, argv) extern int optind; extern char *optarg; int c; + int forceJobs = 0; optind = 1; /* since we're called more than once */ -#ifdef notyet -# define OPTFLAGS "BD:I:L:PSV:d:ef:ij:knqrst" +#ifdef REMOTE +# define OPTFLAGS "BD:I:L:PSV:d:ef:ij:km:nqrst" #else -# define OPTFLAGS "D:I:V:d:ef:ij:knqrst" +# define OPTFLAGS "BD:I:PSV:d:ef:ij:km:nqrst" #endif rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { switch(c) { @@ -177,15 +183,16 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; -#ifdef notyet case 'B': compatMake = TRUE; break; +#ifdef REMOTE case 'L': maxLocal = atoi(optarg); Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; +#endif case 'P': usePipes = FALSE; Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); @@ -194,7 +201,6 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { keepgoing = FALSE; Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); break; -#endif case 'd': { char *modules = optarg; @@ -262,7 +268,11 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); break; case 'j': + forceJobs = TRUE; maxJobs = atoi(optarg); +#ifndef REMOTE + maxLocal = maxJobs; +#endif Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; @@ -270,6 +280,11 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { keepgoing = TRUE; Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); break; + case 'm': + Dir_AddDir(sysIncPath, optarg); + Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); + Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); + break; case 'n': noExecute = TRUE; Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); @@ -297,6 +312,13 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { } } + /* + * Be compatible if user did not specify -j and did not explicitly + * turned compatibility on + */ + if (!compatMake && !forceJobs) + compatMake = TRUE; + oldVars = TRUE; /* @@ -317,7 +339,7 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { optind = 1; /* - */ goto rearg; } - (void)Lst_AtEnd(create, (ClientData)strdup(*argv)); + (void)Lst_AtEnd(create, (ClientData)estrdup(*argv)); } } @@ -407,13 +429,29 @@ main(argc, argv) Lst targs; /* target nodes to create -- passed to Make_Init */ Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ struct stat sb, sa; - char *p, *p1, *path, *pathp, *pwd, *getenv(), *getwd(); + char *p, *p1, *path, *pathp, *pwd; char mdpath[MAXPATHLEN + 1]; char obpath[MAXPATHLEN + 1]; char cdpath[MAXPATHLEN + 1]; - struct utsname utsname; char *machine = getenv("MACHINE"); + Lst sysMkPath; /* Path of sys.mk */ + char *cp = NULL, *start; + /* avoid faults on read-only strings */ + static char syspath[] = _PATH_DEFSYSPATH; +#ifdef RLIMIT_NOFILE + /* + * get rid of resource limit on file descriptors + */ + { + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && + rl.rlim_cur != rl.rlim_max) { + rl.rlim_cur = rl.rlim_max; + (void) setrlimit(RLIMIT_NOFILE, &rl); + } + } +#endif /* * Find where we are and take care of PWD for the automounter... * All this code is so that we know where we are when we start up @@ -447,6 +485,8 @@ main(argc, argv) */ if (!machine) { #ifndef MACHINE + struct utsname utsname; + if (uname(&utsname) == -1) { perror("make: uname"); exit(2); @@ -512,13 +552,13 @@ main(argc, argv) debug = 0; /* No debug verbosity, please. */ jobsRunning = FALSE; - maxJobs = DEFMAXJOBS; /* Set default max concurrency */ maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ -#ifdef notyet - compatMake = FALSE; /* No compat mode */ +#ifdef REMOTE + maxJobs = DEFMAXJOBS; /* Set default max concurrency */ #else - compatMake = TRUE; /* No compat mode */ + maxJobs = maxLocal; #endif + compatMake = FALSE; /* No compat mode */ /* @@ -593,13 +633,41 @@ main(argc, argv) } else Var_Set(".TARGETS", "", VAR_GLOBAL); + /* - * Read in the built-in rules first, followed by the specified makefile, - * if it was (makefile != (char *) NULL), or the default Makefile and - * makefile, in that order, if it wasn't. + * If no user-supplied system path was given (through the -m option) + * add the directories from the DEFSYSPATH (more than one may be given + * as dir1:...:dirn) to the system include path. */ - if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK)) - Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); + if (Lst_IsEmpty(sysIncPath)) { + for (start = syspath; *start != '\0'; start = cp) { + for (cp = start; *cp != '\0' && *cp != ':'; cp++) + continue; + if (*cp == '\0') { + Dir_AddDir(sysIncPath, start); + } else { + *cp++ = '\0'; + Dir_AddDir(sysIncPath, start); + } + } + } + + /* + * Read in the built-in rules first, followed by the specified + * makefile, if it was (makefile != (char *) NULL), or the default + * Makefile and makefile, in that order, if it wasn't. + */ + if (!noBuiltins) { + LstNode ln; + + sysMkPath = Lst_Init (FALSE); + Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath); + if (Lst_IsEmpty(sysMkPath)) + Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); + ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); + if (ln != NILLNODE) + Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); + } if (!Lst_IsEmpty(makefiles)) { LstNode ln; @@ -607,10 +675,10 @@ main(argc, argv) ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); if (ln != NILLNODE) Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - } else if (!ReadMakefile("makefile")) - (void)ReadMakefile("Makefile"); + } else if (!ReadMakefile("makefile", NULL)) + (void)ReadMakefile("Makefile", NULL); - (void)ReadMakefile(".depend"); + (void)ReadMakefile(".depend", NULL); Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); if (p1) @@ -693,10 +761,6 @@ main(argc, argv) else targs = Targ_FindList(create, TARG_CREATE); -/* - * this was original amMake -- want to allow parallelism, so put this - * back in, eventually. - */ if (!compatMake && !printVars) { /* * Initialize job module before traversing the graph, now that @@ -755,10 +819,11 @@ main(argc, argv) * lots */ static Boolean -ReadMakefile(fname) - char *fname; /* makefile to read */ +ReadMakefile(p, q) + ClientData p, q; { - extern Lst parseIncPath, sysIncPath; + char *fname = p; /* makefile to read */ + extern Lst parseIncPath; FILE *stream; char *name, path[MAXPATHLEN + 1]; @@ -796,6 +861,142 @@ found: Var_Set("MAKEFILE", fname, VAR_GLOBAL); } /*- + * Cmd_Exec -- + * Execute the command in cmd, and return the output of that command + * in a string. + * + * Results: + * A string containing the output of the command, or the empty string + * If err is not NULL, it contains the reason for the command failure + * + * Side Effects: + * The string must be freed by the caller. + */ +char * +Cmd_Exec(cmd, err) + char *cmd; + char **err; +{ + char *args[4]; /* Args for invoking the shell */ + int fds[2]; /* Pipe streams */ + int cpid; /* Child PID */ + int pid; /* PID from wait() */ + char *res; /* result */ + int status; /* command exit status */ + Buffer buf; /* buffer to store the result */ + char *cp; + int cc; + + + *err = NULL; + + /* + * Set up arguments for shell + */ + args[0] = "sh"; + args[1] = "-c"; + args[2] = cmd; + args[3] = NULL; + + /* + * Open a pipe for fetching its output + */ + if (pipe(fds) == -1) { + *err = "Couldn't create pipe for \"%s\""; + goto bad; + } + + /* + * Fork + */ + switch (cpid = vfork()) { + case 0: + /* + * Close input side of pipe + */ + (void) close(fds[0]); + + /* + * Duplicate the output stream to the shell's output, then + * shut the extra thing down. Note we don't fetch the error + * stream...why not? Why? + */ + (void) dup2(fds[1], 1); + (void) close(fds[1]); + + (void) execv("/bin/sh", args); + _exit(1); + /*NOTREACHED*/ + + case -1: + *err = "Couldn't exec \"%s\""; + goto bad; + + default: + /* + * No need for the writing half + */ + (void) close(fds[1]); + + buf = Buf_Init (MAKE_BSIZE); + + do { + char result[BUFSIZ]; + cc = read(fds[0], result, sizeof(result)); + if (cc > 0) + Buf_AddBytes(buf, cc, (Byte *) result); + } + while (cc > 0 || (cc == -1 && errno == EINTR)); + + /* + * Close the input side of the pipe. + */ + (void) close(fds[0]); + + /* + * Wait for the process to exit. + */ + while(((pid = wait(&status)) != cpid) && (pid >= 0)) + continue; + + res = (char *)Buf_GetAll (buf, &cc); + Buf_Destroy (buf, FALSE); + + if (cc == 0) + *err = "Couldn't read shell's output for \"%s\""; + + if (status) + *err = "\"%s\" returned non-zero status"; + + /* + * Null-terminate the result, convert newlines to spaces and + * install it in the variable. + */ + res[cc] = '\0'; + cp = &res[cc] - 1; + + if (*cp == '\n') { + /* + * A final newline is just stripped + */ + *cp-- = '\0'; + } + while (cp >= res) { + if (*cp == '\n') { + *cp = ' '; + } + cp--; + } + break; + } + return res; +bad: + res = emalloc(1); + *res = '\0'; + return res; +} + +/*- * Error -- * Print an error message given its format. * @@ -952,18 +1153,47 @@ Finish(errors) * emalloc -- * malloc, but die on error. */ -char * +void * emalloc(len) size_t len; { + void *p; + + if ((p = malloc(len)) == NULL) + enomem(); + return(p); +} + +/* + * estrdup -- + * strdup, but die on error. + */ +char * +estrdup(str) + const char *str; +{ char *p; - if ((p = (char *) malloc(len)) == NULL) + if ((p = strdup(str)) == NULL) enomem(); return(p); } /* + * erealloc -- + * realloc, but die on error. + */ +void * +erealloc(ptr, size) + void *ptr; + size_t size; +{ + if ((ptr = realloc(ptr, size)) == NULL) + enomem(); + return(ptr); +} + +/* * enomem -- * die when out of memory. */ @@ -975,6 +1205,26 @@ enomem() } /* + * enunlink -- + * Remove a file carefully, avoiding directories. + */ +int +eunlink(file) + const char *file; +{ + struct stat st; + + if (lstat(file, &st) == -1) + return -1; + + if (S_ISDIR(st.st_mode)) { + errno = EISDIR; + return -1; + } + return unlink(file); +} + +/* * usage -- * exit with usage message */ @@ -982,8 +1232,9 @@ static void usage() { (void)fprintf(stderr, -"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile] [-I directory]\n\ - [-j max_jobs] [-V variable] [variable=value] [target ...]\n"); +"usage: make [-Beiknqrst] [-D variable] [-d flags] [-f makefile ]\n\ + [-I directory] [-j max_jobs] [-m directory] [-V variable]\n\ + [variable=value] [target ...]\n"); exit(2); } diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1 index 523f34f..f50307b 100644 --- a/usr.bin/make/make.1 +++ b/usr.bin/make/make.1 @@ -29,8 +29,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)make.1 8.4 (Berkeley) 3/19/94 -.\" $Id$ +.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 +.\" $Id: make.1,v 1.5 1996/10/05 22:27:13 wosch Exp $ .\" .Dd March 19, 1994 .Dt MAKE 1 @@ -40,13 +40,14 @@ .Nd maintain program dependencies .Sh SYNOPSIS .Nm make -.Op Fl eiknqrst +.Op Fl Beiknqrst .Op Fl D Ar variable .Op Fl d Ar flags .Op Fl f Ar makefile .Op Fl I Ar directory .Bk -words .Op Fl j Ar max_jobs +.Op Fl m Ar directory .Ek .Op Fl V Ar variable .Op Ar variable=value @@ -75,6 +76,9 @@ and makefiles, please refer to .Pp The options are as follows: .Bl -tag -width Ds +.It Fl B +Try to be backwards compatible by executing a single shell per command and +by executing the commands to make the sources of a dependency line in sequence. .It Fl D Ar variable Define .Ar variable @@ -128,8 +132,9 @@ standard input is read. Multiple makefile's may be specified, and are read in the order specified. .It Fl I Ar directory Specify a directory in which to search for makefiles and included makefiles. -The system makefile directory is automatically included as part of this -list. +The system makefile directory (or directories, see the +.Fl m +option) is automatically included as part of this list. .It Fl i Ignore non-zero exit of shell commands in the makefile. Equivalent to specifying @@ -138,10 +143,20 @@ before each command line in the makefile. .It Fl j Ar max_jobs Specify the maximum number of jobs that .Nm make -may have running at any one time. +may have running at any one time. Turns compatibility mode off, unless the +.Ar B +flag is also specified. .It Fl k Continue processing after errors are encountered, but only on those targets that do not depend on the target whose creation caused the error. +.It Fl m Ar directory +Specify a directory in which to search for sys.mk and makefiles included +via the <...> style. Multiple directories can be added to form a search path. +This path will override the default system include path: /usr/share/mk. +Furthermore the system include path will be appended to the search path used +for "..."-style inclusions (see the +.Fl I +option). .It Fl n Display the commands that would have been executed, but do not actually execute them. @@ -291,13 +306,13 @@ between the previous contents of the variable and the appended value. Variables are expanded by surrounding the variable name with either curly braces .Pq Ql {} -or parenthesis +or parentheses .Pq Ql () and preceding it with a dollar sign .Pq Ql \&$ . If the variable name contains only a single letter, the surrounding -braces or parenthesis are not required. +braces or parentheses are not required. This shorter form is not recommended. .Pp Variable substitution occurs at two distinct times, depending on where @@ -386,10 +401,11 @@ i.e. .Ql \&$$ expands to a single dollar sign. -.It Ev MAKE +.It Va .MAKE The name that .Nm make -was executed with. +was executed with +.Pq Va argv Op 0 .It Va .CURDIR A path to the directory where .Nm make @@ -414,7 +430,7 @@ executes. .It Ev PWD Alternate path to the current directory. .Nm make -normally sets +normally sets .Ql Va .CURDIR to the canonical path given by .Xr getcwd 2 . @@ -520,23 +536,23 @@ This is the .At V style variable substitution. It must be the last modifier specified. -If +If .Ar old_string or .Ar new_string do not contain the pattern matching character .Ar % -then it is assumed that they are +then it is assumed that they are anchored at the end of each word, so only suffixes or entire -words may be replaced. Otherwise +words may be replaced. Otherwise .Ar % -is the substring of -.Ar old_string +is the substring of +.Ar old_string to be replaced in .Ar new_string .El .Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS -Makefile inclusion, conditional structures and for loops reminiscent +Makefile inclusion, conditional structures and for loops reminiscent of the C programming language are provided in .Nm make . All such structures are identified by a line beginning with a single @@ -738,14 +754,14 @@ In both cases this continues until a or .Ql Ic .endif is found. -.Pp +.Pp For loops are typically used to apply a set of rules to a list of files. The syntax of a for loop is: .Bl -tag -width Ds .It Xo .Ic \&.for -.Ar variable -.Ic in +.Ar variable +.Ic in .Ar expression .Xc .It Xo @@ -756,12 +772,12 @@ The syntax of a for loop is: .Xc .El After the for -.Ic expression -is evaluated, it is split into words. The +.Ic expression +is evaluated, it is split into words. The iteration .Ic variable -is successively set to each word, and substituted in the -.Ic make-rules +is successively set to each word, and substituted in the +.Ic make-rules inside the body of the for loop. .Sh COMMENTS Comments begin with a hash @@ -815,6 +831,12 @@ If the target already has commands, the .Ic .USE target's commands are appended to them. +.It Ic .WAIT +If special +.Ic .WAIT +source is appears in a dependency line, the sources that precede it are +made before the sources that succeed it in the line. Loops are not being +detected and targets that form loops will be silently ignored. .El .Sh "SPECIAL TARGETS" Special targets may not be included with other targets, i.e. they must be @@ -863,11 +885,30 @@ The flags are as if typed to the shell, though the .Fl f option will have no effect. +.\" XXX: NOT YET!!!! +.\" .It Ic .NOTPARALLEL +.\" The named targets are executed in non parallel mode. If no targets are +.\" specified, then all targets are executed in non parallel mode. +.It Ic .NOTPARALLEL +Disable parallel mode. +.It Ic .NO_PARALLEL +Same as above, for compatibility with other pmake variants. +.It Ic .ORDER +The named targets are made in sequence. +.\" XXX: NOT YET!!!! +.\" .It Ic .PARALLEL +.\" The named targets are executed in parallel mode. If no targets are +.\" specified, then all targets are executed in parallel mode. .It Ic .PATH The sources are directories which are to be searched for files not found in the current directory. If no sources are specified, any previously specified directories are deleted. +.It Ic .PHONY +Apply the +.Ic .PHONY +attribute to any specified sources. Targets with this attribute are always +considered to be out of date. .It Ic .PRECIOUS Apply the .Ic .PRECIOUS diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c index d6959a8..92074fc 100644 --- a/usr.bin/make/make.c +++ b/usr.bin/make/make.c @@ -207,7 +207,7 @@ Make_OODate (gn) printf(".JOIN node..."); } oodate = gn->childMade; - } else if (gn->type & (OP_FORCE|OP_EXEC)) { + } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { /* * A node which is the object of the force (!) operator or which has * the .EXEC attribute is always considered out-of-date. @@ -215,6 +215,8 @@ Make_OODate (gn) if (DEBUG(MAKE)) { if (gn->type & OP_FORCE) { printf("! operator..."); + } else if (gn->type & OP_PHONY) { + printf(".PHONY node..."); } else { printf(".EXEC node..."); } @@ -570,9 +572,16 @@ MakeAddAllSrc (cgnp, pgnp) GNode *pgn = (GNode *) pgnp; if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { char *child; - char *p1; + char *p1 = NULL; - child = Var_Value(TARGET, cgn, &p1); + if (OP_NOP(cgn->type)) { + /* + * this node is only source; use the specific pathname for it + */ + child = cgn->path ? cgn->path : cgn->name; + } + else + child = Var_Value(TARGET, cgn, &p1); Var_Append (ALLSRC, child, pgn); if (pgn->type & OP_JOIN) { if (cgn->made == MADE) { diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h index cdc7950..249d025 100644 --- a/usr.bin/make/make.h +++ b/usr.bin/make/make.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)make.h 8.1 (Berkeley) 6/6/93 + * from: @(#)make.h 8.3 (Berkeley) 6/13/95 */ /*- @@ -50,15 +50,17 @@ #include <stdio.h> #include <string.h> #include <ctype.h> -#ifndef MAKE_BOOTSTRAP +#if !defined(MAKE_BOOTSTRAP) && defined(BSD) #include <sys/cdefs.h> #else +#ifndef __P #if defined(__STDC__) || defined(__cplusplus) #define __P(protos) protos /* full-blown ANSI C */ #else #define __P(protos) () /* traditional C preprocessor */ #endif #endif +#endif #if __STDC__ #include <stdlib.h> #include <unistd.h> @@ -100,6 +102,7 @@ typedef struct GNode { char *name; /* The target's name */ char *path; /* The full pathname of the file */ int type; /* Its type (see the OP flags, below) */ + int order; /* Its wait weight */ Boolean make; /* TRUE if this target needs to be remade */ enum { @@ -192,6 +195,7 @@ typedef struct GNode { * local variables. */ #define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main * target' processing in parse.c */ +#define OP_PHONY 0x00010000 /* Not a file target; run always */ /* Attributes applied by PMake */ #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ #define OP_MEMBER 0x40000000 /* Target is a member of an archive */ @@ -322,6 +326,8 @@ extern time_t now; /* The time at the start of this whole extern Boolean oldVars; /* Do old-style variable substitution */ +extern Lst sysIncPath; /* The system include path. */ + /* * debug control: * There is one bit per module. It is up to the module what debug diff --git a/usr.bin/make/nonints.h b/usr.bin/make/nonints.h index b2efed6..82aa1b1 100644 --- a/usr.bin/make/nonints.h +++ b/usr.bin/make/nonints.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nonints.h 8.3 (Berkeley) 3/19/94 + * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 */ /* arch.c */ @@ -63,14 +63,18 @@ void For_Run __P((void)); /* main.c */ void Main_ParseArgLine __P((char *)); int main __P((int, char **)); +char *Cmd_Exec __P((char *, char **)); void Error __P((char *, ...)); void Fatal __P((char *, ...)); void Punt __P((char *, ...)); void DieHorribly __P((void)); int PrintAddr __P((ClientData, ClientData)); void Finish __P((int)); -char *emalloc __P((size_t)); +char *estrdup __P((const char *)); +void *emalloc __P((size_t)); +void *erealloc __P((void *, size_t)); void enomem __P((void)); +int eunlink __P((const char *)); /* parse.c */ void Parse_Error __P((int, char *, ...)); diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index b241063..9e2713e 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -90,7 +90,6 @@ static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; #include <stdio.h> #include <ctype.h> #include <errno.h> -#include <sys/wait.h> #include "make.h" #include "hash.h" #include "dir.h" @@ -162,16 +161,20 @@ typedef enum { NotParallel, /* .NOTPARALELL */ Null, /* .NULL */ Order, /* .ORDER */ + Parallel, /* .PARALLEL */ ExPath, /* .PATH */ + Phony, /* .PHONY */ Precious, /* .PRECIOUS */ ExShell, /* .SHELL */ Silent, /* .SILENT */ SingleShell, /* .SINGLESHELL */ Suffixes, /* .SUFFIXES */ + Wait, /* .WAIT */ Attribute /* Generic attribute */ } ParseSpecial; static ParseSpecial specType; +static int waiting; /* * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER @@ -207,10 +210,13 @@ static struct { { ".MFLAGS", MFlags, 0 }, { ".NOTMAIN", Attribute, OP_NOTMAIN }, { ".NOTPARALLEL", NotParallel, 0 }, +{ ".NO_PARALLEL", NotParallel, 0 }, { ".NULL", Null, 0 }, { ".OPTIONAL", Attribute, OP_OPTIONAL }, { ".ORDER", Order, 0 }, +{ ".PARALLEL", Parallel, 0 }, { ".PATH", ExPath, 0 }, +{ ".PHONY", Phony, OP_PHONY }, { ".PRECIOUS", Precious, OP_PRECIOUS }, { ".RECURSIVE", Attribute, OP_MAKE }, { ".SHELL", ExShell, 0 }, @@ -218,12 +224,14 @@ static struct { { ".SINGLESHELL", SingleShell, 0 }, { ".SUFFIXES", Suffixes, 0 }, { ".USE", Attribute, OP_USE }, +{ ".WAIT", Wait, 0 }, }; static int ParseFindKeyword __P((char *)); static int ParseLinkSrc __P((ClientData, ClientData)); static int ParseDoOp __P((ClientData, ClientData)); -static void ParseDoSrc __P((int, char *)); +static int ParseAddDep __P((ClientData, ClientData)); +static void ParseDoSrc __P((int, char *, Lst)); static int ParseFindMain __P((ClientData, ClientData)); static int ParseAddDir __P((ClientData, ClientData)); static int ParseClearPath __P((ClientData, ClientData)); @@ -437,6 +445,45 @@ ParseDoOp (gnp, opp) /*- *--------------------------------------------------------------------- + * ParseAddDep -- + * Check if the pair of GNodes given needs to be synchronized. + * This has to be when two nodes are on different sides of a + * .WAIT directive. + * + * Results: + * Returns 1 if the two targets need to be ordered, 0 otherwise. + * If it returns 1, the search can stop + * + * Side Effects: + * A dependency can be added between the two nodes. + * + *--------------------------------------------------------------------- + */ +int +ParseAddDep(pp, sp) + ClientData pp; + ClientData sp; +{ + GNode *p = (GNode *) pp; + GNode *s = (GNode *) sp; + + if (p->order < s->order) { + /* + * XXX: This can cause loops, and loops can cause unmade targets, + * but checking is tedious, and the debugging output can show the + * problem + */ + (void)Lst_AtEnd(p->successors, (ClientData)s); + (void)Lst_AtEnd(s->preds, (ClientData)p); + return 0; + } + else + return 1; +} + + +/*- + *--------------------------------------------------------------------- * ParseDoSrc -- * Given the name of a source, figure out if it is an attribute * and apply it to the targets if it is. Else decide if there is @@ -453,23 +500,30 @@ ParseDoOp (gnp, opp) *--------------------------------------------------------------------- */ static void -ParseDoSrc (tOp, src) +ParseDoSrc (tOp, src, allsrc) int tOp; /* operator (if any) from special targets */ char *src; /* name of the source to handle */ + Lst allsrc; /* List of all sources to wait for */ { - int op; /* operator (if any) from special source */ - GNode *gn; + GNode *gn = NULL; - op = 0; if (*src == '.' && isupper (src[1])) { int keywd = ParseFindKeyword(src); if (keywd != -1) { - op = parseKeywords[keywd].op; + int op = parseKeywords[keywd].op; + if (op != 0) { + Lst_ForEach (targets, ParseDoOp, (ClientData)&op); + return; + } + if (parseKeywords[keywd].spec == Wait) { + waiting++; + return; + } } } - if (op != 0) { - Lst_ForEach (targets, ParseDoOp, (ClientData)&op); - } else if (specType == Main) { + + switch (specType) { + case Main: /* * If we have noted the existence of a .MAIN, it means we need * to add the sources of said target to the list of things @@ -478,13 +532,15 @@ ParseDoSrc (tOp, src) * invoked if the user didn't specify a target on the command * line. This is to allow #ifmake's to succeed, or something... */ - (void) Lst_AtEnd (create, (ClientData)strdup(src)); + (void) Lst_AtEnd (create, (ClientData)estrdup(src)); /* * Add the name to the .TARGETS variable as well, so the user cna * employ that, if desired. */ Var_Append(".TARGETS", src, VAR_GLOBAL); - } else if (specType == Order) { + return; + + case Order: /* * Create proper predecessor/successor links between the previous * source and the current one. @@ -498,7 +554,9 @@ ParseDoSrc (tOp, src) * The current source now becomes the predecessor for the next one. */ predecessor = gn; - } else { + break; + + default: /* * If the source is not an attribute, we need to find/create * a node for it. After that we can apply any operator to it @@ -529,6 +587,13 @@ ParseDoSrc (tOp, src) } } } + break; + } + + gn->order = waiting; + (void)Lst_AtEnd(allsrc, (ClientData)gn); + if (waiting) { + Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn); } } @@ -651,16 +716,20 @@ ParseDoDependency (line) Lst paths; /* List of search paths to alter when parsing * a list of .PATH targets */ int tOp; /* operator from special target */ - Lst sources; /* list of source names after expansion */ + Lst sources; /* list of archive source names after + * expansion */ Lst curTargs; /* list of target names to be found and added * to the targets list */ + Lst curSrcs; /* list of sources in order */ tOp = 0; specType = Not; + waiting = 0; paths = (Lst)NULL; curTargs = Lst_Init(FALSE); + curSrcs = Lst_Init(FALSE); do { for (cp = line; @@ -757,6 +826,7 @@ ParseDoDependency (line) * life easier later, when we'll * use Make_HandleUse to actually * apply the .DEFAULT commands. + * .PHONY The list of targets * .BEGIN * .END * .INTERRUPT Are not to be considered the @@ -1100,7 +1170,7 @@ ParseDoDependency (line) while (!Lst_IsEmpty (sources)) { gn = (GNode *) Lst_DeQueue (sources); - ParseDoSrc (tOp, gn->name); + ParseDoSrc (tOp, gn->name, curSrcs); } Lst_Destroy (sources, NOFREE); cp = line; @@ -1110,7 +1180,7 @@ ParseDoDependency (line) cp += 1; } - ParseDoSrc (tOp, line); + ParseDoSrc (tOp, line, curSrcs); } while (*cp && isspace (*cp)) { cp++; @@ -1129,6 +1199,10 @@ ParseDoDependency (line) Lst_ForEach (targets, ParseFindMain, (ClientData)0); } + /* + * Finally, destroy the list of sources + */ + Lst_Destroy(curSrcs, NOFREE); } /*- @@ -1153,60 +1227,80 @@ Parse_IsVar (line) { register Boolean wasSpace = FALSE; /* set TRUE if found a space */ register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ + int level = 0; +#define ISEQOPERATOR(c) \ + (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) /* * Skip to variable name */ - while ((*line == ' ') || (*line == '\t')) { - line++; - } + for (;(*line == ' ') || (*line == '\t'); line++) + continue; - while (*line != '=') { - if (*line == '\0') { + for (; *line != '=' || level != 0; line++) + switch (*line) { + case '\0': /* * end-of-line -- can't be a variable assignment. */ - return (FALSE); - } else if ((*line == ' ') || (*line == '\t')) { + return FALSE; + + case ' ': + case '\t': /* * there can be as much white space as desired so long as there is * only one word before the operator */ wasSpace = TRUE; - } else if (wasSpace && haveName) { - /* - * Stop when an = operator is found. - */ - if ((*line == '+') || (*line == ':') || (*line == '?') || - (*line == '!')) { - break; - } + break; - /* - * This is the start of another word, so not assignment. - */ - return (FALSE); - } else { - haveName = TRUE; - wasSpace = FALSE; + case '(': + case '{': + level++; + break; + + case '}': + case ')': + level--; + break; + + default: + if (wasSpace && haveName) { + if (ISEQOPERATOR(*line)) { + /* + * We must have a finished word + */ + if (level != 0) + return FALSE; + + /* + * When an = operator [+?!:] is found, the next + * character must be an = or it ain't a valid + * assignment. + */ + if (line[1] == '=') + return haveName; +#ifdef SUNSHCMD + /* + * This is a shell command + */ + if (strncmp(line, ":sh", 3) == 0) + return haveName; +#endif + } + /* + * This is the start of another word, so not assignment. + */ + return FALSE; + } + else { + haveName = TRUE; + wasSpace = FALSE; + } + break; } - line++; - } - /* - * A final check: if we stopped on a +, ?, ! or :, the next character must - * be an = or it ain't a valid assignment - */ - if (((*line == '+') || - (*line == '?') || - (*line == ':') || - (*line == '!')) && - (line[1] != '=')) - { - return (FALSE); - } else { - return (haveName); - } + return haveName; } /*- @@ -1300,6 +1394,17 @@ Parse_DoVar (line, ctxt) break; default: +#ifdef SUNSHCMD + while (*opc != ':') + if (--opc < line) + break; + + if (strncmp(opc, ":sh", 3) == 0) { + type = VAR_SHELL; + *opc = '\0'; + break; + } +#endif type = VAR_NORMAL; break; } @@ -1331,157 +1436,38 @@ Parse_DoVar (line, ctxt) Var_Set(line, cp, ctxt); free(cp); } else if (type == VAR_SHELL) { - char *args[4]; /* Args for invoking the shell */ - int fds[2]; /* Pipe streams */ - int cpid; /* Child PID */ - int pid; /* PID from wait() */ - Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. - * if any variable expansion was performed */ - - /* - * Avoid clobbered variable warnings by forcing the compiler - * to ``unregister'' variables - */ -#if __GNUC__ - (void) &freeCmd; -#endif + Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e. + * if any variable expansion was performed */ + char *res, *err; - /* - * Set up arguments for shell - */ - args[0] = "sh"; - args[1] = "-c"; - if (strchr(cp, '$') != (char *)NULL) { + if (strchr(cp, '$') != NULL) { /* * There's a dollar sign in the command, so perform variable * expansion on the whole thing. The resulting string will need * freeing when we're done, so set freeCmd to TRUE. */ - args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE); + cp = Var_Subst(NULL, cp, VAR_CMD, TRUE); freeCmd = TRUE; - } else { - args[2] = cp; - freeCmd = FALSE; } - args[3] = (char *)NULL; - - /* - * Open a pipe for fetching its output - */ - pipe(fds); - - /* - * Fork - */ - cpid = vfork(); - if (cpid == 0) { - /* - * Close input side of pipe - */ - close(fds[0]); - - /* - * Duplicate the output stream to the shell's output, then - * shut the extra thing down. Note we don't fetch the error - * stream...why not? Why? - */ - dup2(fds[1], 1); - close(fds[1]); - - execv("/bin/sh", args); - _exit(1); - } else if (cpid < 0) { - /* - * Couldn't fork -- tell the user and make the variable null - */ - Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); - Var_Set(line, "", ctxt); - } else { - int status; - int cc; - Buffer buf; - char *res; - - /* - * No need for the writing half - */ - close(fds[1]); - - buf = Buf_Init (MAKE_BSIZE); - - do { - char result[BUFSIZ]; - cc = read(fds[0], result, sizeof(result)); - if (cc > 0) - Buf_AddBytes(buf, cc, (Byte *) result); - } - while (cc > 0 || (cc == -1 && errno == EINTR)); - - /* - * Close the input side of the pipe. - */ - close(fds[0]); - - /* - * Wait for the process to exit. - */ - while(((pid = wait(&status)) != cpid) && (pid >= 0)) - continue; - - if (cc == -1) { - /* - * Couldn't read all of the child's output -- tell the user - * but still use whatever we read. Null output isn't an - * error unless there was an error reading it. - */ - Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); - } - res = (char *)Buf_GetAll (buf, &cc); - Buf_Destroy (buf, FALSE); + res = Cmd_Exec(cp, &err); + Var_Set(line, res, ctxt); + free(res); - if (status) { - /* - * Child returned an error -- tell the user but still use - * the result. - */ - Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); - } + if (err) + Parse_Error(PARSE_WARNING, err, cp); - /* - * Null-terminate the result, convert newlines to spaces and - * install it in the variable. - */ - res[cc] = '\0'; - cp = &res[cc] - 1; - - if (*cp == '\n') { - /* - * A final newline is just stripped - */ - *cp-- = '\0'; - } - while (cp >= res) { - if (*cp == '\n') { - *cp = ' '; - } - cp--; - } - Var_Set(line, res, ctxt); - free(res); - - } - if (freeCmd) { - free(args[2]); - } + if (freeCmd) + free(cp); } else { /* * Normal assignment -- just do it. */ - Var_Set (line, cp, ctxt); + Var_Set(line, cp, ctxt); } } + /*- * ParseAddCmd -- * Lst_ForEach function to add a command line to all targets @@ -1639,17 +1625,20 @@ ParseDoInclude (file) * leading path components and call Dir_FindFile to see if * we can locate the beast. */ - char *prefEnd; + char *prefEnd, *Fname; - prefEnd = strrchr (fname, '/'); + /* Make a temporary copy of this, to be safe. */ + Fname = estrdup(fname); + + prefEnd = strrchr (Fname, '/'); if (prefEnd != (char *)NULL) { char *newName; *prefEnd = '\0'; if (file[0] == '/') - newName = strdup(file); + newName = estrdup(file); else - newName = str_concat (fname, file, STR_ADDSLASH); + newName = str_concat (Fname, file, STR_ADDSLASH); fullname = Dir_FindFile (newName, parseIncPath); if (fullname == (char *)NULL) { fullname = Dir_FindFile(newName, dirSearchPath); @@ -1659,6 +1648,7 @@ ParseDoInclude (file) } else { fullname = (char *)NULL; } + free (Fname); } else { fullname = (char *)NULL; } @@ -1763,7 +1753,7 @@ Parse_FromString(str) curPTR = (PTR *) emalloc (sizeof (PTR)); curPTR->str = curPTR->ptr = str; lineno = 0; - fname = strdup(fname); + fname = estrdup(fname); } @@ -2189,7 +2179,11 @@ test_char: break; case '#': if (!ignComment) { - if (compatMake && (lastc != '\\')) { + if ( +#if 0 + compatMake && +#endif + (lastc != '\\')) { /* * If the character is a hash mark and it isn't escaped * (or we're being compatible), the thing is a comment. @@ -2247,7 +2241,7 @@ test_char: while (*ep) ++ep; while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { - if (ep[-2] == '\\') + if (ep > line + 1 && ep[-2] == '\\') break; --ep; } @@ -2421,13 +2415,13 @@ Parse_File(name, stream) continue; } else { Parse_Error (PARSE_FATAL, - "Unassociated shell command \"%.20s\"", + "Unassociated shell command \"%s\"", cp); } } #ifdef SYSVINCLUDE } else if (strncmp (line, "include", 7) == 0 && - isspace(line[7]) && + isspace((unsigned char) line[7]) && strchr(line, ':') == NULL) { /* * It's an S3/S5-style "include". @@ -2536,30 +2530,11 @@ Parse_File(name, stream) void Parse_Init () { - char *cp = NULL, *start; - /* avoid faults on read-only strings */ - static char syspath[] = _PATH_DEFSYSPATH; - mainNode = NILGNODE; parseIncPath = Lst_Init (FALSE); sysIncPath = Lst_Init (FALSE); includes = Lst_Init (FALSE); targCmds = Lst_Init (FALSE); - - /* - * Add the directories from the DEFSYSPATH (more than one may be given - * as dir1:...:dirn) to the system include path. - */ - for (start = syspath; *start != '\0'; start = cp) { - for (cp = start; *cp != '\0' && *cp != ':'; cp++) - continue; - if (*cp == '\0') { - Dir_AddDir(sysIncPath, start); - } else { - *cp++ = '\0'; - Dir_AddDir(sysIncPath, start); - } - } } void diff --git a/usr.bin/make/pathnames.h b/usr.bin/make/pathnames.h index 74a2e50..fa1d76e 100644 --- a/usr.bin/make/pathnames.h +++ b/usr.bin/make/pathnames.h @@ -31,11 +31,11 @@ * SUCH DAMAGE. * * from: @(#)pathnames.h 5.2 (Berkeley) 6/1/90 - * $Id: pathnames.h,v 1.3 1996/06/24 04:24:35 jkh Exp $ + * $Id: pathnames.h,v 1.4 1996/09/18 06:06:39 swallace Exp $ */ #define _PATH_OBJDIR "obj" #define _PATH_OBJDIRPREFIX "/usr/obj" #define _PATH_DEFSHELLDIR "/bin" -#define _PATH_DEFSYSMK "/usr/share/mk/sys.mk" +#define _PATH_DEFSYSMK "sys.mk" #define _PATH_DEFSYSPATH "/usr/share/mk" diff --git a/usr.bin/make/sprite.h b/usr.bin/make/sprite.h index d5462d5..1e7e765 100644 --- a/usr.bin/make/sprite.h +++ b/usr.bin/make/sprite.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sprite.h 8.1 (Berkeley) 6/6/93 + * from: @(#)sprite.h 8.1 (Berkeley) 6/6/93 */ /* diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c index 2dea338..2962e7e 100644 --- a/usr.bin/make/str.c +++ b/usr.bin/make/str.c @@ -38,7 +38,7 @@ #ifndef lint /* from: static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; */ -static char *rcsid = "$Id: str.c,v 1.4 1995/05/30 06:32:05 rgrimes Exp $"; +static char *rcsid = "$Id: str.c,v 1.5 1995/06/18 12:34:12 ache Exp $"; #endif /* not lint */ #include "make.h" @@ -55,7 +55,7 @@ void str_init() { char *p1; - argv = (char **)emalloc((argmax = 50) * sizeof(char *)); + argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *)); argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1); } @@ -202,9 +202,8 @@ brk_string(str, store_argc, expand) *t++ = '\0'; if (argc == argmax) { argmax *= 2; /* ramp up fast */ - if (!(argv = (char **)realloc(argv, - argmax * sizeof(char *)))) - enomem(); + argv = (char **)erealloc(argv, + (argmax + 1) * sizeof(char *)); } argv[argc++] = start; start = (char *)NULL; diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c index 7340383..a1a7a2e 100644 --- a/usr.bin/make/suff.c +++ b/usr.bin/make/suff.c @@ -95,7 +95,6 @@ static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94"; #include "make.h" #include "hash.h" #include "dir.h" -#include "bit.h" static Lst sufflist; /* Lst of suffixes */ static Lst suffClean; /* Lst of suffixes to be cleaned */ @@ -159,6 +158,7 @@ static int SuffSuffIsSuffixP __P((ClientData, ClientData)); static int SuffSuffHasNameP __P((ClientData, ClientData)); static int SuffSuffIsPrefix __P((ClientData, ClientData)); static int SuffGNHasNameP __P((ClientData, ClientData)); +static void SuffUnRef __P((ClientData, ClientData)); static void SuffFree __P((ClientData)); static void SuffInsert __P((Lst, Suff *)); static void SuffRemove __P((Lst, Suff *)); @@ -796,7 +796,7 @@ Suff_AddSuffix (str) if (ln == NILLNODE) { s = (Suff *) emalloc (sizeof (Suff)); - s->name = strdup (str); + s->name = estrdup (str); s->nameLen = strlen (s->name); s->searchPath = Lst_Init (FALSE); s->children = Lst_Init (FALSE); @@ -1003,7 +1003,7 @@ SuffAddSrc (sp, lsp) * that... */ s2 = (Src *) emalloc (sizeof (Src)); - s2->file = strdup(targ->pref); + s2->file = estrdup(targ->pref); s2->pref = targ->pref; s2->parent = targ; s2->node = NILGNODE; @@ -1266,7 +1266,7 @@ SuffFindCmds (targ, slst) * again (ick)), and return the new structure. */ ret = (Src *)emalloc (sizeof (Src)); - ret->file = strdup(s->name); + ret->file = estrdup(s->name); ret->pref = targ->pref; ret->suff = suff; suff->refCount++; @@ -1841,7 +1841,8 @@ SuffFindNormalDeps(gn, slst) * children, then look for any overriding transformations they imply. * Should we find one, we discard the one we found before. */ - while(ln != NILLNODE) { + + while (ln != NILLNODE) { /* * Look for next possible suffix... */ @@ -1855,7 +1856,7 @@ SuffFindNormalDeps(gn, slst) * Allocate a Src structure to which things can be transformed */ targ = (Src *)emalloc(sizeof (Src)); - targ->file = strdup(gn->name); + targ->file = estrdup(gn->name); targ->suff = (Suff *)Lst_Datum(ln); targ->suff->refCount++; targ->node = gn; @@ -1900,13 +1901,13 @@ SuffFindNormalDeps(gn, slst) } targ = (Src *)emalloc(sizeof (Src)); - targ->file = strdup(gn->name); + targ->file = estrdup(gn->name); targ->suff = suffNull; targ->suff->refCount++; targ->node = gn; targ->parent = (Src *)NULL; targ->children = 0; - targ->pref = strdup(sopref); + targ->pref = estrdup(sopref); #ifdef DEBUG_SRC targ->cp = Lst_Init(FALSE); #endif @@ -1916,7 +1917,7 @@ SuffFindNormalDeps(gn, slst) * or dependencies defined for this gnode */ if (Lst_IsEmpty(gn->commands) && Lst_IsEmpty(gn->children)) - SuffAddLevel(srcs, targ); + SuffAddLevel(srcs, targ); else { if (DEBUG(SUFF)) printf("not "); @@ -1988,6 +1989,7 @@ sfnd_abort: (targ == NULL ? dirSearchPath : targ->suff->searchPath)); if (gn->path != NULL) { + char *ptr; Var_Set(TARGET, gn->path, gn); if (targ != NULL) { @@ -1995,7 +1997,7 @@ sfnd_abort: * Suffix known for the thing -- trim the suffix off * the path to form the proper .PREFIX variable. */ - int len = strlen(gn->path); + int savep = strlen(gn->path) - targ->suff->nameLen; char savec; if (gn->suffix) @@ -2003,12 +2005,17 @@ sfnd_abort: gn->suffix = targ->suff; gn->suffix->refCount++; - savec = gn->path[len-targ->suff->nameLen]; - gn->path[len-targ->suff->nameLen] = '\0'; + savec = gn->path[savep]; + gn->path[savep] = '\0'; - Var_Set(PREFIX, gn->path, gn); + if ((ptr = strrchr(gn->path, '/')) != NULL) + ptr++; + else + ptr = gn->path; - gn->path[len-targ->suff->nameLen] = savec; + Var_Set(PREFIX, ptr, gn); + + gn->path[savep] = savec; } else { /* * The .PREFIX gets the full path if the target has @@ -2018,7 +2025,12 @@ sfnd_abort: gn->suffix->refCount--; gn->suffix = NULL; - Var_Set(PREFIX, gn->path, gn); + if ((ptr = strrchr(gn->path, '/')) != NULL) + ptr++; + else + ptr = gn->path; + + Var_Set(PREFIX, ptr, gn); } } } else { @@ -2034,7 +2046,7 @@ sfnd_abort: gn->suffix->refCount++; if (gn->path != NULL) free(gn->path); - gn->path = strdup(gn->name); + gn->path = estrdup(gn->name); } goto sfnd_return; @@ -2135,7 +2147,7 @@ sfnd_abort: */ if (gn->path) free(gn->path); - gn->path = strdup(gn->name); + gn->path = estrdup(gn->name); /* * Nuke the transformation path and the Src structures left over in the @@ -2316,7 +2328,7 @@ Suff_Init () */ emptySuff = suffNull = (Suff *) emalloc (sizeof (Suff)); - suffNull->name = strdup (""); + suffNull->name = estrdup (""); suffNull->nameLen = 0; suffNull->searchPath = Lst_Init (FALSE); Dir_Concat(suffNull->searchPath, dirSearchPath); diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c index bd2dba8..595c1d0 100644 --- a/usr.bin/make/targ.c +++ b/usr.bin/make/targ.c @@ -158,7 +158,7 @@ Targ_NewGN (name) register GNode *gn; gn = (GNode *) emalloc (sizeof (GNode)); - gn->name = strdup (name); + gn->name = estrdup (name); gn->path = (char *) 0; if (name[0] == '-' && name[1] == 'l') { gn->type = OP_LIB; @@ -169,6 +169,7 @@ Targ_NewGN (name) gn->make = FALSE; gn->made = UNMADE; gn->childMade = FALSE; + gn->order = 0; gn->mtime = gn->cmtime = 0; gn->iParents = Lst_Init (FALSE); gn->cohorts = Lst_Init (FALSE); @@ -467,9 +468,9 @@ Targ_FmtTime (time) parts = localtime(&time); - sprintf (buf, "%d:%02d:%02d %s %d, 19%d", + sprintf (buf, "%d:%02d:%02d %s %d, %d", parts->tm_hour, parts->tm_min, parts->tm_sec, - months[parts->tm_mon], parts->tm_mday, parts->tm_year); + months[parts->tm_mon], parts->tm_mday, 1900 + parts->tm_year); return(buf); } diff --git a/usr.bin/make/util.c b/usr.bin/make/util.c new file mode 100644 index 0000000..df8347c --- /dev/null +++ b/usr.bin/make/util.c @@ -0,0 +1,349 @@ +/* + * Missing stuff from OS's + */ + +#ifndef lint +static char rcsid[] = "$NetBSD: util.c,v 1.7 1996/08/30 17:59:44 thorpej Exp $"; +#endif + +#include <stdio.h> +#include "make.h" + +#if !__STDC__ +# ifndef const +# define const +# endif +#endif + +#ifdef sun + + + +extern int errno, sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(e) + int e; +{ + static char buf[100]; + if (e < 0 || e >= sys_nerr) { + sprintf(buf, "Unknown error %d", e); + return buf; + } + else + return sys_errlist[e]; +} +#endif + +#ifdef ultrix +#include <string.h> + +/* strdup + * + * Make a duplicate of a string. + * For systems which lack this function. + */ +char * +strdup(str) + const char *str; +{ + size_t len; + + if (str == NULL) + return NULL; + len = strlen(str) + 1; + if ((p = malloc(len)) == NULL) + return NULL; + + return memcpy(p, str, len); +} + +#endif + +#if defined(sun) || defined(__hpux) || defined(__sgi) + +int +setenv(name, value, dum) + const char *name; + const char *value; + int dum; +{ + register char *p; + int len = strlen(name) + strlen(value) + 2; /* = \0 */ + char *ptr = (char*) malloc(len); + + (void) dum; + + if (ptr == NULL) + return -1; + + p = ptr; + + while (*name) + *p++ = *name++; + + *p++ = '='; + + while (*value) + *p++ = *value++; + + *p = '\0'; + + len = putenv(ptr); +/* free(ptr); */ + return len; +} +#endif + +#ifdef __hpux +#include <sys/types.h> +#include <sys/param.h> +#include <sys/syscall.h> +#include <sys/signal.h> +#include <sys/stat.h> +#include <stdio.h> +#include <dirent.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> + + +int +killpg(pid, sig) + int pid, sig; +{ + return kill(-pid, sig); +} + +void +srandom(seed) + long seed; +{ + srand48(seed); +} + +long +random() +{ + return lrand48(); +} + +/* turn into bsd signals */ +void (* +signal(s, a)) () + int s; + void (*a)(); +{ + struct sigvec osv, sv; + + (void) sigvector(s, (struct sigvec *) 0, &osv); + sv = osv; + sv.sv_handler = a; +#ifdef SV_BSDSIG + sv.sv_flags = SV_BSDSIG; +#endif + + if (sigvector(s, &sv, (struct sigvec *) 0) == -1) + return (BADSIG); + return (osv.sv_handler); +} + +#if !defined(BSD) && !defined(d_fileno) +# define d_fileno d_ino +#endif + +#ifndef DEV_DEV_COMPARE +# define DEV_DEV_COMPARE(a, b) ((a) == (b)) +#endif +#define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) +#define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) + + +/* strrcpy(): + * Like strcpy, going backwards and returning the new pointer + */ +static char * +strrcpy(ptr, str) + register char *ptr, *str; +{ + register int len = strlen(str); + + while (len) + *--ptr = str[--len]; + + return (ptr); +} /* end strrcpy */ + + +char * +getwd(pathname) + char *pathname; +{ + DIR *dp; + struct dirent *d; + extern int errno; + + struct stat st_root, st_cur, st_next, st_dotdot; + char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2]; + char *pathptr, *nextpathptr, *cur_name_add; + + /* find the inode of root */ + if (stat("/", &st_root) == -1) { + (void) sprintf(pathname, + "getwd: Cannot stat \"/\" (%s)", strerror(errno)); + return (NULL); + } + pathbuf[MAXPATHLEN - 1] = '\0'; + pathptr = &pathbuf[MAXPATHLEN - 1]; + nextpathbuf[MAXPATHLEN - 1] = '\0'; + cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1]; + + /* find the inode of the current directory */ + if (lstat(".", &st_cur) == -1) { + (void) sprintf(pathname, + "getwd: Cannot stat \".\" (%s)", strerror(errno)); + return (NULL); + } + nextpathptr = strrcpy(nextpathptr, "../"); + + /* Descend to root */ + for (;;) { + + /* look if we found root yet */ + if (st_cur.st_ino == st_root.st_ino && + DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { + (void) strcpy(pathname, *pathptr != '/' ? "/" : pathptr); + return (pathname); + } + + /* open the parent directory */ + if (stat(nextpathptr, &st_dotdot) == -1) { + (void) sprintf(pathname, + "getwd: Cannot stat directory \"%s\" (%s)", + nextpathptr, strerror(errno)); + return (NULL); + } + if ((dp = opendir(nextpathptr)) == NULL) { + (void) sprintf(pathname, + "getwd: Cannot open directory \"%s\" (%s)", + nextpathptr, strerror(errno)); + return (NULL); + } + + /* look in the parent for the entry with the same inode */ + if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { + /* Parent has same device. No need to stat every member */ + for (d = readdir(dp); d != NULL; d = readdir(dp)) + if (d->d_fileno == st_cur.st_ino) + break; + } + else { + /* + * Parent has a different device. This is a mount point so we + * need to stat every member + */ + for (d = readdir(dp); d != NULL; d = readdir(dp)) { + if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) + continue; + (void) strcpy(cur_name_add, d->d_name); + if (lstat(nextpathptr, &st_next) == -1) { + (void) sprintf(pathname, "getwd: Cannot stat \"%s\" (%s)", + d->d_name, strerror(errno)); + (void) closedir(dp); + return (NULL); + } + /* check if we found it yet */ + if (st_next.st_ino == st_cur.st_ino && + DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) + break; + } + } + if (d == NULL) { + (void) sprintf(pathname, "getwd: Cannot find \".\" in \"..\""); + (void) closedir(dp); + return (NULL); + } + st_cur = st_dotdot; + pathptr = strrcpy(pathptr, d->d_name); + pathptr = strrcpy(pathptr, "/"); + nextpathptr = strrcpy(nextpathptr, "../"); + (void) closedir(dp); + *cur_name_add = '\0'; + } +} /* end getwd */ + + +char *sys_siglist[] = { + "Signal 0", + "Hangup", /* SIGHUP */ + "Interrupt", /* SIGINT */ + "Quit", /* SIGQUIT */ + "Illegal instruction", /* SIGILL */ + "Trace/BPT trap", /* SIGTRAP */ + "IOT trap", /* SIGIOT */ + "EMT trap", /* SIGEMT */ + "Floating point exception", /* SIGFPE */ + "Killed", /* SIGKILL */ + "Bus error", /* SIGBUS */ + "Segmentation fault", /* SIGSEGV */ + "Bad system call", /* SIGSYS */ + "Broken pipe", /* SIGPIPE */ + "Alarm clock", /* SIGALRM */ + "Terminated", /* SIGTERM */ + "User defined signal 1", /* SIGUSR1 */ + "User defined signal 2", /* SIGUSR2 */ + "Child exited", /* SIGCLD */ + "Power-fail restart", /* SIGPWR */ + "Virtual timer expired", /* SIGVTALRM */ + "Profiling timer expired", /* SIGPROF */ + "I/O possible", /* SIGIO */ + "Window size changes", /* SIGWINDOW */ + "Stopped (signal)", /* SIGSTOP */ + "Stopped", /* SIGTSTP */ + "Continued", /* SIGCONT */ + "Stopped (tty input)", /* SIGTTIN */ + "Stopped (tty output)", /* SIGTTOU */ + "Urgent I/O condition", /* SIGURG */ + "Remote lock lost (NFS)", /* SIGLOST */ + "Signal 31", /* reserved */ + "DIL signal" /* SIGDIL */ +}; + +int +utimes(file, tvp) + char *file; + struct timeval tvp[2]; +{ + struct utimbuf t; + + t.actime = tvp[0].tv_sec; + t.modtime = tvp[1].tv_sec; + return(utime(file, &t)); +} + + +#endif /* __hpux */ + +#if defined(sun) && defined(__svr4__) +#include <signal.h> + +/* turn into bsd signals */ +void (* +signal(s, a)) () + int s; + void (*a)(); +{ + struct sigaction sa, osa; + + sa.sa_handler = a; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(s, &sa, &osa) == -1) + return SIG_ERR; + else + return osa.sa_handler; +} + +#endif diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index c0c9c36..dc367cd 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -158,7 +158,9 @@ static Boolean VarTail __P((char *, Boolean, Buffer, ClientData)); static Boolean VarSuffix __P((char *, Boolean, Buffer, ClientData)); static Boolean VarRoot __P((char *, Boolean, Buffer, ClientData)); static Boolean VarMatch __P((char *, Boolean, Buffer, ClientData)); +#ifdef SYSVVARSUB static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, ClientData)); +#endif static Boolean VarNoMatch __P((char *, Boolean, Buffer, ClientData)); static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData)); static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, @@ -272,7 +274,7 @@ VarFind (name, ctxt, flags) int len; v = (Var *) emalloc(sizeof(Var)); - v->name = strdup(name); + v->name = estrdup(name); len = strlen(env); @@ -325,7 +327,7 @@ VarAdd (name, val, ctxt) v = (Var *) emalloc (sizeof (Var)); - v->name = strdup (name); + v->name = estrdup (name); len = val ? strlen(val) : 0; v->val = Buf_Init(len+1); @@ -775,8 +777,7 @@ VarMatch (word, addSpace, buf, pattern) return(addSpace); } - - +#ifdef SYSVVARSUB /*- *----------------------------------------------------------------------- * VarSYSVMatch -- @@ -818,6 +819,7 @@ VarSYSVMatch (word, addSpace, buf, patp) return(addSpace); } +#endif /*- @@ -1100,7 +1102,7 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) Boolean haveModifier;/* TRUE if have modifiers for the variable */ register char endc; /* Ending character when variable in parens * or braces */ - register char startc; /* Starting character when variable in parens + register char startc=0; /* Starting character when variable in parens * or braces */ int cnt; /* Used to count brace pairs when variable in * in parens or braces */ @@ -1617,7 +1619,22 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) break; } /*FALLTHRU*/ - default: { +#ifdef SUNSHCMD + case 's': + if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { + char *err; + newStr = Cmd_Exec (str, &err); + if (err) + Error (err, str); + cp = tstr + 2; + termc = *cp; + break; + } + /*FALLTHRU*/ +#endif + default: + { +#ifdef SYSVVARSUB /* * This can either be a bogus modifier or a System-V * substitution command. @@ -1684,7 +1701,9 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) pattern.lhs[pattern.leftLen] = '='; pattern.rhs[pattern.rightLen] = endc; termc = endc; - } else { + } else +#endif + { Error ("Unknown modifier '%c'\n", *tstr); for (cp = tstr+1; *cp != ':' && *cp != endc && *cp != '\0'; |