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 + -
显示快捷键?