compat.c

来自「早期freebsd实现」· C语言 代码 · 共 642 行 · 第 1/2 页

C
642
字号
/* * 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. */#ifndef lintstatic char sccsid[] = "@(#)compat.c	8.2 (Berkeley) 3/19/94";#endif /* not lint *//*- * compat.c -- *	The routines in this file implement the full-compatibility *	mode of PMake. Most of the special functionality of PMake *	is available in this mode. Things not supported: *	    - different shells. *	    - friendly variable substitution. * * Interface: *	Compat_Run	    Initialize things for this module and recreate *	    	  	    thems as need creatin' */#include    <sys/types.h>#include    <sys/stat.h>#include    <sys/wait.h>#include    <ctype.h>#include    <errno.h>#include    <signal.h>#include    <stdio.h>#include    "make.h"#include    "hash.h"#include    "dir.h"#include    "job.h"extern int errno;/* * The following array is used to make a fast determination of which * characters are interpreted specially by the shell.  If a command * contains any of these characters, it is executed by the shell, not * directly by us. */static char 	    meta[256];static GNode	    *curTarg = NILGNODE;static GNode	    *ENDNode;static void CompatInterrupt __P((int));static int CompatRunCommand __P((char *, GNode *));static int CompatMake __P((GNode *, GNode *));/*- *----------------------------------------------------------------------- * CompatInterrupt -- *	Interrupt the creation of the current target and remove it if *	it ain't precious. * * Results: *	None. * * Side Effects: *	The target is removed and the process exits. If .INTERRUPT exists, *	its commands are run first WITH INTERRUPTS IGNORED.. * *----------------------------------------------------------------------- */static voidCompatInterrupt (signo)    int	    signo;{    struct stat sb;    GNode   *gn;        if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {	char 	  *file = Var_Value (TARGET, curTarg);	if (!stat(file, &sb) && S_ISREG(sb.st_mode) &&	    unlink (file) == SUCCESS) {	    printf ("*** %s removed\n", file);	}	/*	 * Run .INTERRUPT only if hit with interrupt signal	 */	if (signo == SIGINT) {	    gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);	    if (gn != NILGNODE) {		Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);	    }	}    }    exit (0);}/*- *----------------------------------------------------------------------- * CompatRunCommand -- *	Execute the next command for a target. If the command returns an *	error, the node's made field is set to ERROR and creation stops. * * Results: *	0 if the command succeeded, 1 if an error occurred. * * Side Effects: *	The node's 'made' field may be set to ERROR. * *----------------------------------------------------------------------- */static intCompatRunCommand (cmd, gn)    char    	  *cmd;	    	/* Command to execute */    GNode   	  *gn;    	/* Node from which the command came */{    char    	  *cmdStart;	/* Start of expanded command */    register char *cp;    Boolean 	  silent,   	/* Don't print command */		  errCheck; 	/* Check errors */    union wait 	  reason;   	/* Reason for child's death */    int	    	  status;   	/* Description of child's death */    int	    	  cpid;	    	/* Child actually found */    ReturnStatus  stat;	    	/* Status of fork */    LstNode 	  cmdNode;  	/* Node where current command is located */    char    	  **av;	    	/* Argument vector for thing to exec */    int	    	  argc;	    	/* Number of arguments in av or 0 if not				 * dynamically allocated */    Boolean 	  local;    	/* TRUE if command should be executed				 * locally */    /*       * Avoid clobbered variable warnings by forcing the compiler     * to ``unregister'' variables     */ #if __GNUC__    (void) &av;     (void) &errCheck;#endif     silent = gn->type & OP_SILENT;    errCheck = !(gn->type & OP_IGNORE);    cmdNode = Lst_Member (gn->commands, (ClientData)cmd);    cmdStart = Var_Subst (NULL, cmd, gn, FALSE);    /*     * brk_string will return an argv with a NULL in av[1], thus causing     * execvp to choke and die horribly. Besides, how can we execute a null     * command? In any case, we warn the user that the command expanded to     * nothing (is this the right thing to do?).     */         if (*cmdStart == '\0') {	Error("%s expands to empty string", cmd);	return(0);    } else {	cmd = cmdStart;    }    Lst_Replace (cmdNode, (ClientData)cmdStart);    if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {	(void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);	return(0);    } else if (strcmp(cmdStart, "...") == 0) {	gn->type |= OP_SAVE_CMDS;	return(0);    }    while ((*cmd == '@') || (*cmd == '-')) {	if (*cmd == '@') {	    silent = TRUE;	} else {	    errCheck = FALSE;	}	cmd++;    }    while (isspace((unsigned char)*cmd))	cmd++;        /*     * Search for meta characters in the command. If there are no meta     * characters, there's no need to execute a shell to execute the     * command.     */    for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {	continue;    }    /*     * Print the command before echoing if we're not supposed to be quiet for     * this one. We also print the command if -n given.     */    if (!silent || noExecute) {	printf ("%s\n", cmd);	fflush(stdout);    }    /*     * If we're not supposed to execute any commands, this is as far as     * we go...     */    if (noExecute) {	return (0);    }        if (*cp != '\0') {	/*	 * If *cp isn't the null character, we hit a "meta" character and	 * need to pass the command off to the shell. We give the shell the	 * -e flag as well as -c if it's supposed to exit when it hits an	 * error.	 */	static char	*shargv[4] = { "/bin/sh" };	shargv[1] = (errCheck ? "-ec" : "-c");	shargv[2] = cmd;	shargv[3] = (char *)NULL;	av = shargv;	argc = 0;    } else {	/*	 * No meta-characters, so no need to exec a shell. Break the command	 * into words to form an argument vector we can execute.	 * brk_string sticks our name in av[0], so we have to	 * skip over it...	 */	av = brk_string(cmd, &argc);	av += 1;    }        local = TRUE;    /*     * Fork and execute the single command. If the fork fails, we abort.     */    cpid = vfork();    if (cpid < 0) {	Fatal("Could not fork");    }    if (cpid == 0) {	if (local) {	    execvp(av[0], av);	    (void) write (2, av[0], strlen (av[0]));	    (void) write (2, ": not found\n", sizeof(": not found"));	} else {	    (void)execv(av[0], av);	}	exit(1);    }        /*     * The child is off and running. Now all we can do is wait...     */    while (1) {	int 	  id;	if (!local) {	    id = 0;	}	while ((stat = wait((int *)&reason)) != cpid) {	    if (stat == -1 && errno != EINTR) {		break;	    }	}		if (stat > -1) {	    if (WIFSTOPPED(reason)) {		status = reason.w_stopval;		/* stopped */	    } else if (WIFEXITED(reason)) {		status = reason.w_retcode;		/* exited */		if (status != 0) {		    printf ("*** Error code %d", status);		}	    } else {		status = reason.w_termsig;		/* signaled */		printf ("*** Signal %d", status);	    } 	    	    if (!WIFEXITED(reason) || (status != 0)) {		if (errCheck) {		    gn->made = ERROR;		    if (keepgoing) {			/*			 * Abort the current target, but let others			 * continue.			 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?