1*2bc7c627SLionel Sambuc /* $NetBSD: compat.c,v 1.90 2012/10/07 19:17:31 sjg Exp $ */ 22e2caf59SThomas Veerman 32e2caf59SThomas Veerman /* 42e2caf59SThomas Veerman * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 52e2caf59SThomas Veerman * All rights reserved. 62e2caf59SThomas Veerman * 72e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by 82e2caf59SThomas Veerman * Adam de Boor. 92e2caf59SThomas Veerman * 102e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without 112e2caf59SThomas Veerman * modification, are permitted provided that the following conditions 122e2caf59SThomas Veerman * are met: 132e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright 142e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer. 152e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright 162e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the 172e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution. 182e2caf59SThomas Veerman * 3. Neither the name of the University nor the names of its contributors 192e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software 202e2caf59SThomas Veerman * without specific prior written permission. 212e2caf59SThomas Veerman * 222e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 232e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 242e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 252e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 262e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 272e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 282e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 292e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 302e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 312e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 322e2caf59SThomas Veerman * SUCH DAMAGE. 332e2caf59SThomas Veerman */ 342e2caf59SThomas Veerman 352e2caf59SThomas Veerman /* 362e2caf59SThomas Veerman * Copyright (c) 1988, 1989 by Adam de Boor 372e2caf59SThomas Veerman * Copyright (c) 1989 by Berkeley Softworks 382e2caf59SThomas Veerman * All rights reserved. 392e2caf59SThomas Veerman * 402e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by 412e2caf59SThomas Veerman * Adam de Boor. 422e2caf59SThomas Veerman * 432e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without 442e2caf59SThomas Veerman * modification, are permitted provided that the following conditions 452e2caf59SThomas Veerman * are met: 462e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright 472e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer. 482e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright 492e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the 502e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution. 512e2caf59SThomas Veerman * 3. All advertising materials mentioning features or use of this software 522e2caf59SThomas Veerman * must display the following acknowledgement: 532e2caf59SThomas Veerman * This product includes software developed by the University of 542e2caf59SThomas Veerman * California, Berkeley and its contributors. 552e2caf59SThomas Veerman * 4. Neither the name of the University nor the names of its contributors 562e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software 572e2caf59SThomas Veerman * without specific prior written permission. 582e2caf59SThomas Veerman * 592e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 602e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 612e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 622e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 632e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 642e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 652e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 662e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 672e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 682e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 692e2caf59SThomas Veerman * SUCH DAMAGE. 702e2caf59SThomas Veerman */ 712e2caf59SThomas Veerman 722e2caf59SThomas Veerman #ifndef MAKE_NATIVE 73*2bc7c627SLionel Sambuc static char rcsid[] = "$NetBSD: compat.c,v 1.90 2012/10/07 19:17:31 sjg Exp $"; 742e2caf59SThomas Veerman #else 752e2caf59SThomas Veerman #include <sys/cdefs.h> 762e2caf59SThomas Veerman #ifndef lint 772e2caf59SThomas Veerman #if 0 782e2caf59SThomas Veerman static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; 792e2caf59SThomas Veerman #else 80*2bc7c627SLionel Sambuc __RCSID("$NetBSD: compat.c,v 1.90 2012/10/07 19:17:31 sjg Exp $"); 812e2caf59SThomas Veerman #endif 822e2caf59SThomas Veerman #endif /* not lint */ 832e2caf59SThomas Veerman #endif 842e2caf59SThomas Veerman 852e2caf59SThomas Veerman /*- 862e2caf59SThomas Veerman * compat.c -- 872e2caf59SThomas Veerman * The routines in this file implement the full-compatibility 882e2caf59SThomas Veerman * mode of PMake. Most of the special functionality of PMake 892e2caf59SThomas Veerman * is available in this mode. Things not supported: 902e2caf59SThomas Veerman * - different shells. 912e2caf59SThomas Veerman * - friendly variable substitution. 922e2caf59SThomas Veerman * 932e2caf59SThomas Veerman * Interface: 942e2caf59SThomas Veerman * Compat_Run Initialize things for this module and recreate 952e2caf59SThomas Veerman * thems as need creatin' 962e2caf59SThomas Veerman */ 972e2caf59SThomas Veerman 982e2caf59SThomas Veerman #include <sys/types.h> 992e2caf59SThomas Veerman #include <sys/stat.h> 1002e2caf59SThomas Veerman #include <sys/wait.h> 1012e2caf59SThomas Veerman 1022e2caf59SThomas Veerman #include <ctype.h> 1032e2caf59SThomas Veerman #include <errno.h> 1042e2caf59SThomas Veerman #include <signal.h> 1052e2caf59SThomas Veerman #include <stdio.h> 1062e2caf59SThomas Veerman 1072e2caf59SThomas Veerman #include "make.h" 1082e2caf59SThomas Veerman #include "hash.h" 1092e2caf59SThomas Veerman #include "dir.h" 1102e2caf59SThomas Veerman #include "job.h" 1112e2caf59SThomas Veerman #include "pathnames.h" 1122e2caf59SThomas Veerman 1132e2caf59SThomas Veerman /* 1142e2caf59SThomas Veerman * The following array is used to make a fast determination of which 1152e2caf59SThomas Veerman * characters are interpreted specially by the shell. If a command 1162e2caf59SThomas Veerman * contains any of these characters, it is executed by the shell, not 1172e2caf59SThomas Veerman * directly by us. 1182e2caf59SThomas Veerman */ 1192e2caf59SThomas Veerman 1202e2caf59SThomas Veerman static char meta[256]; 1212e2caf59SThomas Veerman 1222e2caf59SThomas Veerman static GNode *curTarg = NULL; 1232e2caf59SThomas Veerman static GNode *ENDNode; 124*2bc7c627SLionel Sambuc static void CompatInterrupt(int); 1252e2caf59SThomas Veerman 1262e2caf59SThomas Veerman static void 1272e2caf59SThomas Veerman Compat_Init(void) 1282e2caf59SThomas Veerman { 1292e2caf59SThomas Veerman const char *cp; 1302e2caf59SThomas Veerman 1312e2caf59SThomas Veerman Shell_Init(); /* setup default shell */ 1322e2caf59SThomas Veerman 1332e2caf59SThomas Veerman for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 1342e2caf59SThomas Veerman meta[(unsigned char) *cp] = 1; 1352e2caf59SThomas Veerman } 1362e2caf59SThomas Veerman /* 1372e2caf59SThomas Veerman * The null character serves as a sentinel in the string. 1382e2caf59SThomas Veerman */ 1392e2caf59SThomas Veerman meta[0] = 1; 1402e2caf59SThomas Veerman } 1412e2caf59SThomas Veerman 1422e2caf59SThomas Veerman /*- 1432e2caf59SThomas Veerman *----------------------------------------------------------------------- 1442e2caf59SThomas Veerman * CompatInterrupt -- 1452e2caf59SThomas Veerman * Interrupt the creation of the current target and remove it if 1462e2caf59SThomas Veerman * it ain't precious. 1472e2caf59SThomas Veerman * 1482e2caf59SThomas Veerman * Results: 1492e2caf59SThomas Veerman * None. 1502e2caf59SThomas Veerman * 1512e2caf59SThomas Veerman * Side Effects: 1522e2caf59SThomas Veerman * The target is removed and the process exits. If .INTERRUPT exists, 1532e2caf59SThomas Veerman * its commands are run first WITH INTERRUPTS IGNORED.. 1542e2caf59SThomas Veerman * 1552e2caf59SThomas Veerman *----------------------------------------------------------------------- 1562e2caf59SThomas Veerman */ 1572e2caf59SThomas Veerman static void 1582e2caf59SThomas Veerman CompatInterrupt(int signo) 1592e2caf59SThomas Veerman { 1602e2caf59SThomas Veerman GNode *gn; 1612e2caf59SThomas Veerman 1622e2caf59SThomas Veerman if ((curTarg != NULL) && !Targ_Precious (curTarg)) { 1632e2caf59SThomas Veerman char *p1; 1642e2caf59SThomas Veerman char *file = Var_Value(TARGET, curTarg, &p1); 1652e2caf59SThomas Veerman 1662e2caf59SThomas Veerman if (!noExecute && eunlink(file) != -1) { 1672e2caf59SThomas Veerman Error("*** %s removed", file); 1682e2caf59SThomas Veerman } 1692e2caf59SThomas Veerman if (p1) 1702e2caf59SThomas Veerman free(p1); 1712e2caf59SThomas Veerman 1722e2caf59SThomas Veerman /* 1732e2caf59SThomas Veerman * Run .INTERRUPT only if hit with interrupt signal 1742e2caf59SThomas Veerman */ 1752e2caf59SThomas Veerman if (signo == SIGINT) { 1762e2caf59SThomas Veerman gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 1772e2caf59SThomas Veerman if (gn != NULL) { 1782e2caf59SThomas Veerman Compat_Make(gn, gn); 1792e2caf59SThomas Veerman } 1802e2caf59SThomas Veerman } 1812e2caf59SThomas Veerman 1822e2caf59SThomas Veerman } 183*2bc7c627SLionel Sambuc if (signo == SIGQUIT) 184*2bc7c627SLionel Sambuc _exit(signo); 185*2bc7c627SLionel Sambuc bmake_signal(signo, SIG_DFL); 186*2bc7c627SLionel Sambuc kill(myPid, signo); 1872e2caf59SThomas Veerman } 1882e2caf59SThomas Veerman 1892e2caf59SThomas Veerman /*- 1902e2caf59SThomas Veerman *----------------------------------------------------------------------- 1912e2caf59SThomas Veerman * CompatRunCommand -- 1922e2caf59SThomas Veerman * Execute the next command for a target. If the command returns an 1932e2caf59SThomas Veerman * error, the node's made field is set to ERROR and creation stops. 1942e2caf59SThomas Veerman * 1952e2caf59SThomas Veerman * Input: 1962e2caf59SThomas Veerman * cmdp Command to execute 1972e2caf59SThomas Veerman * gnp Node from which the command came 1982e2caf59SThomas Veerman * 1992e2caf59SThomas Veerman * Results: 2002e2caf59SThomas Veerman * 0 if the command succeeded, 1 if an error occurred. 2012e2caf59SThomas Veerman * 2022e2caf59SThomas Veerman * Side Effects: 2032e2caf59SThomas Veerman * The node's 'made' field may be set to ERROR. 2042e2caf59SThomas Veerman * 2052e2caf59SThomas Veerman *----------------------------------------------------------------------- 2062e2caf59SThomas Veerman */ 2072e2caf59SThomas Veerman int 2082e2caf59SThomas Veerman CompatRunCommand(void *cmdp, void *gnp) 2092e2caf59SThomas Veerman { 2102e2caf59SThomas Veerman char *cmdStart; /* Start of expanded command */ 2112e2caf59SThomas Veerman char *cp, *bp; 2122e2caf59SThomas Veerman Boolean silent, /* Don't print command */ 2132e2caf59SThomas Veerman doIt; /* Execute even if -n */ 2142e2caf59SThomas Veerman volatile Boolean errCheck; /* Check errors */ 2152e2caf59SThomas Veerman int reason; /* Reason for child's death */ 2162e2caf59SThomas Veerman int status; /* Description of child's death */ 2172e2caf59SThomas Veerman pid_t cpid; /* Child actually found */ 2182e2caf59SThomas Veerman pid_t retstat; /* Result of wait */ 2192e2caf59SThomas Veerman LstNode cmdNode; /* Node where current command is located */ 2202e2caf59SThomas Veerman const char ** volatile av; /* Argument vector for thing to exec */ 2212e2caf59SThomas Veerman char ** volatile mav;/* Copy of the argument vector for freeing */ 2222e2caf59SThomas Veerman int argc; /* Number of arguments in av or 0 if not 2232e2caf59SThomas Veerman * dynamically allocated */ 2242e2caf59SThomas Veerman Boolean local; /* TRUE if command should be executed 2252e2caf59SThomas Veerman * locally */ 2262e2caf59SThomas Veerman Boolean useShell; /* TRUE if command should be executed 2272e2caf59SThomas Veerman * using a shell */ 2282e2caf59SThomas Veerman char * volatile cmd = (char *)cmdp; 2292e2caf59SThomas Veerman GNode *gn = (GNode *)gnp; 2302e2caf59SThomas Veerman 2312e2caf59SThomas Veerman silent = gn->type & OP_SILENT; 2322e2caf59SThomas Veerman errCheck = !(gn->type & OP_IGNORE); 2332e2caf59SThomas Veerman doIt = FALSE; 2342e2caf59SThomas Veerman 2352e2caf59SThomas Veerman cmdNode = Lst_Member(gn->commands, cmd); 2362e2caf59SThomas Veerman cmdStart = Var_Subst(NULL, cmd, gn, FALSE); 2372e2caf59SThomas Veerman 2382e2caf59SThomas Veerman /* 2392e2caf59SThomas Veerman * brk_string will return an argv with a NULL in av[0], thus causing 2402e2caf59SThomas Veerman * execvp to choke and die horribly. Besides, how can we execute a null 2412e2caf59SThomas Veerman * command? In any case, we warn the user that the command expanded to 2422e2caf59SThomas Veerman * nothing (is this the right thing to do?). 2432e2caf59SThomas Veerman */ 2442e2caf59SThomas Veerman 2452e2caf59SThomas Veerman if (*cmdStart == '\0') { 2462e2caf59SThomas Veerman free(cmdStart); 2472e2caf59SThomas Veerman return(0); 2482e2caf59SThomas Veerman } 2492e2caf59SThomas Veerman cmd = cmdStart; 2502e2caf59SThomas Veerman Lst_Replace(cmdNode, cmdStart); 2512e2caf59SThomas Veerman 2522e2caf59SThomas Veerman if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 2532e2caf59SThomas Veerman (void)Lst_AtEnd(ENDNode->commands, cmdStart); 2542e2caf59SThomas Veerman return(0); 2552e2caf59SThomas Veerman } 2562e2caf59SThomas Veerman if (strcmp(cmdStart, "...") == 0) { 2572e2caf59SThomas Veerman gn->type |= OP_SAVE_CMDS; 2582e2caf59SThomas Veerman return(0); 2592e2caf59SThomas Veerman } 2602e2caf59SThomas Veerman 2612e2caf59SThomas Veerman while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { 2622e2caf59SThomas Veerman switch (*cmd) { 2632e2caf59SThomas Veerman case '@': 2642e2caf59SThomas Veerman silent = DEBUG(LOUD) ? FALSE : TRUE; 2652e2caf59SThomas Veerman break; 2662e2caf59SThomas Veerman case '-': 2672e2caf59SThomas Veerman errCheck = FALSE; 2682e2caf59SThomas Veerman break; 2692e2caf59SThomas Veerman case '+': 2702e2caf59SThomas Veerman doIt = TRUE; 2712e2caf59SThomas Veerman if (!meta[0]) /* we came here from jobs */ 2722e2caf59SThomas Veerman Compat_Init(); 2732e2caf59SThomas Veerman break; 2742e2caf59SThomas Veerman } 2752e2caf59SThomas Veerman cmd++; 2762e2caf59SThomas Veerman } 2772e2caf59SThomas Veerman 2782e2caf59SThomas Veerman while (isspace((unsigned char)*cmd)) 2792e2caf59SThomas Veerman cmd++; 2802e2caf59SThomas Veerman 281*2bc7c627SLionel Sambuc /* 282*2bc7c627SLionel Sambuc * If we did not end up with a command, just skip it. 283*2bc7c627SLionel Sambuc */ 284*2bc7c627SLionel Sambuc if (!*cmd) 285*2bc7c627SLionel Sambuc return (0); 286*2bc7c627SLionel Sambuc 2872e2caf59SThomas Veerman #if !defined(MAKE_NATIVE) 2882e2caf59SThomas Veerman /* 2892e2caf59SThomas Veerman * In a non-native build, the host environment might be weird enough 2902e2caf59SThomas Veerman * that it's necessary to go through a shell to get the correct 2912e2caf59SThomas Veerman * behaviour. Or perhaps the shell has been replaced with something 2922e2caf59SThomas Veerman * that does extra logging, and that should not be bypassed. 2932e2caf59SThomas Veerman */ 2942e2caf59SThomas Veerman useShell = TRUE; 2952e2caf59SThomas Veerman #else 2962e2caf59SThomas Veerman /* 2972e2caf59SThomas Veerman * Search for meta characters in the command. If there are no meta 2982e2caf59SThomas Veerman * characters, there's no need to execute a shell to execute the 2992e2caf59SThomas Veerman * command. 3002e2caf59SThomas Veerman */ 3012e2caf59SThomas Veerman for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 3022e2caf59SThomas Veerman continue; 3032e2caf59SThomas Veerman } 3042e2caf59SThomas Veerman useShell = (*cp != '\0'); 3052e2caf59SThomas Veerman #endif 3062e2caf59SThomas Veerman 3072e2caf59SThomas Veerman /* 3082e2caf59SThomas Veerman * Print the command before echoing if we're not supposed to be quiet for 3092e2caf59SThomas Veerman * this one. We also print the command if -n given. 3102e2caf59SThomas Veerman */ 3112e2caf59SThomas Veerman if (!silent || NoExecute(gn)) { 3122e2caf59SThomas Veerman printf("%s\n", cmd); 3132e2caf59SThomas Veerman fflush(stdout); 3142e2caf59SThomas Veerman } 3152e2caf59SThomas Veerman 3162e2caf59SThomas Veerman /* 3172e2caf59SThomas Veerman * If we're not supposed to execute any commands, this is as far as 3182e2caf59SThomas Veerman * we go... 3192e2caf59SThomas Veerman */ 3202e2caf59SThomas Veerman if (!doIt && NoExecute(gn)) { 3212e2caf59SThomas Veerman return (0); 3222e2caf59SThomas Veerman } 3232e2caf59SThomas Veerman if (DEBUG(JOB)) 3242e2caf59SThomas Veerman fprintf(debug_file, "Execute: '%s'\n", cmd); 3252e2caf59SThomas Veerman 3262e2caf59SThomas Veerman again: 3272e2caf59SThomas Veerman if (useShell) { 3282e2caf59SThomas Veerman /* 3292e2caf59SThomas Veerman * We need to pass the command off to the shell, typically 3302e2caf59SThomas Veerman * because the command contains a "meta" character. 3312e2caf59SThomas Veerman */ 3322e2caf59SThomas Veerman static const char *shargv[4]; 3332e2caf59SThomas Veerman 3342e2caf59SThomas Veerman shargv[0] = shellPath; 3352e2caf59SThomas Veerman /* 3362e2caf59SThomas Veerman * The following work for any of the builtin shell specs. 3372e2caf59SThomas Veerman */ 3382e2caf59SThomas Veerman if (DEBUG(SHELL)) 3392e2caf59SThomas Veerman shargv[1] = "-xc"; 3402e2caf59SThomas Veerman else 3412e2caf59SThomas Veerman shargv[1] = "-c"; 3422e2caf59SThomas Veerman shargv[2] = cmd; 3432e2caf59SThomas Veerman shargv[3] = NULL; 3442e2caf59SThomas Veerman av = shargv; 3452e2caf59SThomas Veerman argc = 0; 3462e2caf59SThomas Veerman bp = NULL; 3472e2caf59SThomas Veerman mav = NULL; 3482e2caf59SThomas Veerman } else { 3492e2caf59SThomas Veerman /* 3502e2caf59SThomas Veerman * No meta-characters, so no need to exec a shell. Break the command 3512e2caf59SThomas Veerman * into words to form an argument vector we can execute. 3522e2caf59SThomas Veerman */ 3532e2caf59SThomas Veerman mav = brk_string(cmd, &argc, TRUE, &bp); 3542e2caf59SThomas Veerman if (mav == NULL) { 3552e2caf59SThomas Veerman useShell = 1; 3562e2caf59SThomas Veerman goto again; 3572e2caf59SThomas Veerman } 3582e2caf59SThomas Veerman av = (void *)mav; 3592e2caf59SThomas Veerman } 3602e2caf59SThomas Veerman 3612e2caf59SThomas Veerman local = TRUE; 3622e2caf59SThomas Veerman 3632e2caf59SThomas Veerman #ifdef USE_META 3642e2caf59SThomas Veerman if (useMeta) { 3652e2caf59SThomas Veerman meta_compat_start(); 3662e2caf59SThomas Veerman } 3672e2caf59SThomas Veerman #endif 3682e2caf59SThomas Veerman 3692e2caf59SThomas Veerman /* 3702e2caf59SThomas Veerman * Fork and execute the single command. If the fork fails, we abort. 3712e2caf59SThomas Veerman */ 3722e2caf59SThomas Veerman cpid = vFork(); 3732e2caf59SThomas Veerman if (cpid < 0) { 3742e2caf59SThomas Veerman Fatal("Could not fork"); 3752e2caf59SThomas Veerman } 3762e2caf59SThomas Veerman if (cpid == 0) { 3772e2caf59SThomas Veerman Check_Cwd(av); 3782e2caf59SThomas Veerman Var_ExportVars(); 3792e2caf59SThomas Veerman #ifdef USE_META 3802e2caf59SThomas Veerman if (useMeta) { 3812e2caf59SThomas Veerman meta_compat_child(); 3822e2caf59SThomas Veerman } 3832e2caf59SThomas Veerman #endif 3842e2caf59SThomas Veerman if (local) 3852e2caf59SThomas Veerman (void)execvp(av[0], (char *const *)UNCONST(av)); 3862e2caf59SThomas Veerman else 3872e2caf59SThomas Veerman (void)execv(av[0], (char *const *)UNCONST(av)); 3882e2caf59SThomas Veerman execError("exec", av[0]); 3892e2caf59SThomas Veerman _exit(1); 3902e2caf59SThomas Veerman } 3912e2caf59SThomas Veerman if (mav) 3922e2caf59SThomas Veerman free(mav); 3932e2caf59SThomas Veerman if (bp) 3942e2caf59SThomas Veerman free(bp); 3952e2caf59SThomas Veerman Lst_Replace(cmdNode, NULL); 3962e2caf59SThomas Veerman 3972e2caf59SThomas Veerman #ifdef USE_META 3982e2caf59SThomas Veerman if (useMeta) { 3992e2caf59SThomas Veerman meta_compat_parent(); 4002e2caf59SThomas Veerman } 4012e2caf59SThomas Veerman #endif 4022e2caf59SThomas Veerman 4032e2caf59SThomas Veerman /* 4042e2caf59SThomas Veerman * The child is off and running. Now all we can do is wait... 4052e2caf59SThomas Veerman */ 4062e2caf59SThomas Veerman while (1) { 4072e2caf59SThomas Veerman 4082e2caf59SThomas Veerman while ((retstat = wait(&reason)) != cpid) { 4092e2caf59SThomas Veerman if (retstat > 0) 4102e2caf59SThomas Veerman JobReapChild(retstat, reason, FALSE); /* not ours? */ 4112e2caf59SThomas Veerman if (retstat == -1 && errno != EINTR) { 4122e2caf59SThomas Veerman break; 4132e2caf59SThomas Veerman } 4142e2caf59SThomas Veerman } 4152e2caf59SThomas Veerman 4162e2caf59SThomas Veerman if (retstat > -1) { 4172e2caf59SThomas Veerman if (WIFSTOPPED(reason)) { 4182e2caf59SThomas Veerman status = WSTOPSIG(reason); /* stopped */ 4192e2caf59SThomas Veerman } else if (WIFEXITED(reason)) { 4202e2caf59SThomas Veerman status = WEXITSTATUS(reason); /* exited */ 4212e2caf59SThomas Veerman #if defined(USE_META) && defined(USE_FILEMON_ONCE) 4222e2caf59SThomas Veerman if (useMeta) { 4232e2caf59SThomas Veerman meta_cmd_finish(NULL); 4242e2caf59SThomas Veerman } 4252e2caf59SThomas Veerman #endif 4262e2caf59SThomas Veerman if (status != 0) { 4272e2caf59SThomas Veerman if (DEBUG(ERROR)) { 4282e2caf59SThomas Veerman fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", 4292e2caf59SThomas Veerman gn->name); 4302e2caf59SThomas Veerman for (cp = cmd; *cp; ) { 4312e2caf59SThomas Veerman if (isspace((unsigned char)*cp)) { 4322e2caf59SThomas Veerman fprintf(debug_file, " "); 4332e2caf59SThomas Veerman while (isspace((unsigned char)*cp)) 4342e2caf59SThomas Veerman cp++; 4352e2caf59SThomas Veerman } else { 4362e2caf59SThomas Veerman fprintf(debug_file, "%c", *cp); 4372e2caf59SThomas Veerman cp++; 4382e2caf59SThomas Veerman } 4392e2caf59SThomas Veerman } 4402e2caf59SThomas Veerman fprintf(debug_file, "\n"); 4412e2caf59SThomas Veerman } 4422e2caf59SThomas Veerman printf("*** Error code %d", status); 4432e2caf59SThomas Veerman } 4442e2caf59SThomas Veerman } else { 4452e2caf59SThomas Veerman status = WTERMSIG(reason); /* signaled */ 4462e2caf59SThomas Veerman printf("*** Signal %d", status); 4472e2caf59SThomas Veerman } 4482e2caf59SThomas Veerman 4492e2caf59SThomas Veerman 4502e2caf59SThomas Veerman if (!WIFEXITED(reason) || (status != 0)) { 4512e2caf59SThomas Veerman if (errCheck) { 4522e2caf59SThomas Veerman #ifdef USE_META 4532e2caf59SThomas Veerman if (useMeta) { 4542e2caf59SThomas Veerman meta_job_error(NULL, gn, 0, status); 4552e2caf59SThomas Veerman } 4562e2caf59SThomas Veerman #endif 4572e2caf59SThomas Veerman gn->made = ERROR; 4582e2caf59SThomas Veerman if (keepgoing) { 4592e2caf59SThomas Veerman /* 4602e2caf59SThomas Veerman * Abort the current target, but let others 4612e2caf59SThomas Veerman * continue. 4622e2caf59SThomas Veerman */ 4632e2caf59SThomas Veerman printf(" (continuing)\n"); 4642e2caf59SThomas Veerman } 4652e2caf59SThomas Veerman } else { 4662e2caf59SThomas Veerman /* 4672e2caf59SThomas Veerman * Continue executing commands for this target. 4682e2caf59SThomas Veerman * If we return 0, this will happen... 4692e2caf59SThomas Veerman */ 4702e2caf59SThomas Veerman printf(" (ignored)\n"); 4712e2caf59SThomas Veerman status = 0; 4722e2caf59SThomas Veerman } 4732e2caf59SThomas Veerman } 4742e2caf59SThomas Veerman break; 4752e2caf59SThomas Veerman } else { 4762e2caf59SThomas Veerman Fatal("error in wait: %d: %s", retstat, strerror(errno)); 4772e2caf59SThomas Veerman /*NOTREACHED*/ 4782e2caf59SThomas Veerman } 4792e2caf59SThomas Veerman } 4802e2caf59SThomas Veerman free(cmdStart); 4812e2caf59SThomas Veerman 4822e2caf59SThomas Veerman return (status); 4832e2caf59SThomas Veerman } 4842e2caf59SThomas Veerman 4852e2caf59SThomas Veerman /*- 4862e2caf59SThomas Veerman *----------------------------------------------------------------------- 4872e2caf59SThomas Veerman * Compat_Make -- 4882e2caf59SThomas Veerman * Make a target. 4892e2caf59SThomas Veerman * 4902e2caf59SThomas Veerman * Input: 4912e2caf59SThomas Veerman * gnp The node to make 4922e2caf59SThomas Veerman * pgnp Parent to abort if necessary 4932e2caf59SThomas Veerman * 4942e2caf59SThomas Veerman * Results: 4952e2caf59SThomas Veerman * 0 4962e2caf59SThomas Veerman * 4972e2caf59SThomas Veerman * Side Effects: 4982e2caf59SThomas Veerman * If an error is detected and not being ignored, the process exits. 4992e2caf59SThomas Veerman * 5002e2caf59SThomas Veerman *----------------------------------------------------------------------- 5012e2caf59SThomas Veerman */ 5022e2caf59SThomas Veerman int 5032e2caf59SThomas Veerman Compat_Make(void *gnp, void *pgnp) 5042e2caf59SThomas Veerman { 5052e2caf59SThomas Veerman GNode *gn = (GNode *)gnp; 5062e2caf59SThomas Veerman GNode *pgn = (GNode *)pgnp; 5072e2caf59SThomas Veerman 5082e2caf59SThomas Veerman if (!meta[0]) /* we came here from jobs */ 5092e2caf59SThomas Veerman Compat_Init(); 5102e2caf59SThomas Veerman if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { 5112e2caf59SThomas Veerman /* 5122e2caf59SThomas Veerman * First mark ourselves to be made, then apply whatever transformations 5132e2caf59SThomas Veerman * the suffix module thinks are necessary. Once that's done, we can 5142e2caf59SThomas Veerman * descend and make all our children. If any of them has an error 5152e2caf59SThomas Veerman * but the -k flag was given, our 'make' field will be set FALSE again. 5162e2caf59SThomas Veerman * This is our signal to not attempt to do anything but abort our 5172e2caf59SThomas Veerman * parent as well. 5182e2caf59SThomas Veerman */ 5192e2caf59SThomas Veerman gn->flags |= REMAKE; 5202e2caf59SThomas Veerman gn->made = BEINGMADE; 5212e2caf59SThomas Veerman if ((gn->type & OP_MADE) == 0) 5222e2caf59SThomas Veerman Suff_FindDeps(gn); 5232e2caf59SThomas Veerman Lst_ForEach(gn->children, Compat_Make, gn); 5242e2caf59SThomas Veerman if ((gn->flags & REMAKE) == 0) { 5252e2caf59SThomas Veerman gn->made = ABORTED; 5262e2caf59SThomas Veerman pgn->flags &= ~REMAKE; 5272e2caf59SThomas Veerman goto cohorts; 5282e2caf59SThomas Veerman } 5292e2caf59SThomas Veerman 5302e2caf59SThomas Veerman if (Lst_Member(gn->iParents, pgn) != NULL) { 5312e2caf59SThomas Veerman char *p1; 5322e2caf59SThomas Veerman Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 5332e2caf59SThomas Veerman if (p1) 5342e2caf59SThomas Veerman free(p1); 5352e2caf59SThomas Veerman } 5362e2caf59SThomas Veerman 5372e2caf59SThomas Veerman /* 5382e2caf59SThomas Veerman * All the children were made ok. Now cmgn->mtime contains the 5392e2caf59SThomas Veerman * modification time of the newest child, we need to find out if we 5402e2caf59SThomas Veerman * exist and when we were modified last. The criteria for datedness 5412e2caf59SThomas Veerman * are defined by the Make_OODate function. 5422e2caf59SThomas Veerman */ 5432e2caf59SThomas Veerman if (DEBUG(MAKE)) { 5442e2caf59SThomas Veerman fprintf(debug_file, "Examining %s...", gn->name); 5452e2caf59SThomas Veerman } 5462e2caf59SThomas Veerman if (! Make_OODate(gn)) { 5472e2caf59SThomas Veerman gn->made = UPTODATE; 5482e2caf59SThomas Veerman if (DEBUG(MAKE)) { 5492e2caf59SThomas Veerman fprintf(debug_file, "up-to-date.\n"); 5502e2caf59SThomas Veerman } 5512e2caf59SThomas Veerman goto cohorts; 5522e2caf59SThomas Veerman } else if (DEBUG(MAKE)) { 5532e2caf59SThomas Veerman fprintf(debug_file, "out-of-date.\n"); 5542e2caf59SThomas Veerman } 5552e2caf59SThomas Veerman 5562e2caf59SThomas Veerman /* 5572e2caf59SThomas Veerman * If the user is just seeing if something is out-of-date, exit now 5582e2caf59SThomas Veerman * to tell him/her "yes". 5592e2caf59SThomas Veerman */ 5602e2caf59SThomas Veerman if (queryFlag) { 5612e2caf59SThomas Veerman exit(1); 5622e2caf59SThomas Veerman } 5632e2caf59SThomas Veerman 5642e2caf59SThomas Veerman /* 5652e2caf59SThomas Veerman * We need to be re-made. We also have to make sure we've got a $? 5662e2caf59SThomas Veerman * variable. To be nice, we also define the $> variable using 5672e2caf59SThomas Veerman * Make_DoAllVar(). 5682e2caf59SThomas Veerman */ 5692e2caf59SThomas Veerman Make_DoAllVar(gn); 5702e2caf59SThomas Veerman 5712e2caf59SThomas Veerman /* 5722e2caf59SThomas Veerman * Alter our type to tell if errors should be ignored or things 5732e2caf59SThomas Veerman * should not be printed so CompatRunCommand knows what to do. 5742e2caf59SThomas Veerman */ 5752e2caf59SThomas Veerman if (Targ_Ignore(gn)) { 5762e2caf59SThomas Veerman gn->type |= OP_IGNORE; 5772e2caf59SThomas Veerman } 5782e2caf59SThomas Veerman if (Targ_Silent(gn)) { 5792e2caf59SThomas Veerman gn->type |= OP_SILENT; 5802e2caf59SThomas Veerman } 5812e2caf59SThomas Veerman 5822e2caf59SThomas Veerman if (Job_CheckCommands(gn, Fatal)) { 5832e2caf59SThomas Veerman /* 5842e2caf59SThomas Veerman * Our commands are ok, but we still have to worry about the -t 5852e2caf59SThomas Veerman * flag... 5862e2caf59SThomas Veerman */ 5872e2caf59SThomas Veerman if (!touchFlag || (gn->type & OP_MAKE)) { 5882e2caf59SThomas Veerman curTarg = gn; 5892e2caf59SThomas Veerman #ifdef USE_META 5902e2caf59SThomas Veerman if (useMeta && !NoExecute(gn)) { 5912e2caf59SThomas Veerman meta_job_start(NULL, gn); 5922e2caf59SThomas Veerman } 5932e2caf59SThomas Veerman #endif 5942e2caf59SThomas Veerman Lst_ForEach(gn->commands, CompatRunCommand, gn); 5952e2caf59SThomas Veerman curTarg = NULL; 5962e2caf59SThomas Veerman } else { 5972e2caf59SThomas Veerman Job_Touch(gn, gn->type & OP_SILENT); 5982e2caf59SThomas Veerman } 5992e2caf59SThomas Veerman } else { 6002e2caf59SThomas Veerman gn->made = ERROR; 6012e2caf59SThomas Veerman } 6022e2caf59SThomas Veerman #ifdef USE_META 6032e2caf59SThomas Veerman if (useMeta && !NoExecute(gn)) { 6042e2caf59SThomas Veerman meta_job_finish(NULL); 6052e2caf59SThomas Veerman } 6062e2caf59SThomas Veerman #endif 6072e2caf59SThomas Veerman 6082e2caf59SThomas Veerman if (gn->made != ERROR) { 6092e2caf59SThomas Veerman /* 6102e2caf59SThomas Veerman * If the node was made successfully, mark it so, update 6112e2caf59SThomas Veerman * its modification time and timestamp all its parents. Note 6122e2caf59SThomas Veerman * that for .ZEROTIME targets, the timestamping isn't done. 6132e2caf59SThomas Veerman * This is to keep its state from affecting that of its parent. 6142e2caf59SThomas Veerman */ 6152e2caf59SThomas Veerman gn->made = MADE; 6162e2caf59SThomas Veerman pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; 6172e2caf59SThomas Veerman if (!(gn->type & OP_EXEC)) { 6182e2caf59SThomas Veerman pgn->flags |= CHILDMADE; 6192e2caf59SThomas Veerman Make_TimeStamp(pgn, gn); 6202e2caf59SThomas Veerman } 6212e2caf59SThomas Veerman } else if (keepgoing) { 6222e2caf59SThomas Veerman pgn->flags &= ~REMAKE; 6232e2caf59SThomas Veerman } else { 6242e2caf59SThomas Veerman PrintOnError(gn, "\n\nStop."); 6252e2caf59SThomas Veerman exit(1); 6262e2caf59SThomas Veerman } 6272e2caf59SThomas Veerman } else if (gn->made == ERROR) { 6282e2caf59SThomas Veerman /* 6292e2caf59SThomas Veerman * Already had an error when making this beastie. Tell the parent 6302e2caf59SThomas Veerman * to abort. 6312e2caf59SThomas Veerman */ 6322e2caf59SThomas Veerman pgn->flags &= ~REMAKE; 6332e2caf59SThomas Veerman } else { 6342e2caf59SThomas Veerman if (Lst_Member(gn->iParents, pgn) != NULL) { 6352e2caf59SThomas Veerman char *p1; 6362e2caf59SThomas Veerman Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 6372e2caf59SThomas Veerman if (p1) 6382e2caf59SThomas Veerman free(p1); 6392e2caf59SThomas Veerman } 6402e2caf59SThomas Veerman switch(gn->made) { 6412e2caf59SThomas Veerman case BEINGMADE: 6422e2caf59SThomas Veerman Error("Graph cycles through %s", gn->name); 6432e2caf59SThomas Veerman gn->made = ERROR; 6442e2caf59SThomas Veerman pgn->flags &= ~REMAKE; 6452e2caf59SThomas Veerman break; 6462e2caf59SThomas Veerman case MADE: 6472e2caf59SThomas Veerman if ((gn->type & OP_EXEC) == 0) { 6482e2caf59SThomas Veerman pgn->flags |= CHILDMADE; 6492e2caf59SThomas Veerman Make_TimeStamp(pgn, gn); 6502e2caf59SThomas Veerman } 6512e2caf59SThomas Veerman break; 6522e2caf59SThomas Veerman case UPTODATE: 6532e2caf59SThomas Veerman if ((gn->type & OP_EXEC) == 0) { 6542e2caf59SThomas Veerman Make_TimeStamp(pgn, gn); 6552e2caf59SThomas Veerman } 6562e2caf59SThomas Veerman break; 6572e2caf59SThomas Veerman default: 6582e2caf59SThomas Veerman break; 6592e2caf59SThomas Veerman } 6602e2caf59SThomas Veerman } 6612e2caf59SThomas Veerman 6622e2caf59SThomas Veerman cohorts: 6632e2caf59SThomas Veerman Lst_ForEach(gn->cohorts, Compat_Make, pgnp); 6642e2caf59SThomas Veerman return (0); 6652e2caf59SThomas Veerman } 6662e2caf59SThomas Veerman 6672e2caf59SThomas Veerman /*- 6682e2caf59SThomas Veerman *----------------------------------------------------------------------- 6692e2caf59SThomas Veerman * Compat_Run -- 6702e2caf59SThomas Veerman * Initialize this mode and start making. 6712e2caf59SThomas Veerman * 6722e2caf59SThomas Veerman * Input: 6732e2caf59SThomas Veerman * targs List of target nodes to re-create 6742e2caf59SThomas Veerman * 6752e2caf59SThomas Veerman * Results: 6762e2caf59SThomas Veerman * None. 6772e2caf59SThomas Veerman * 6782e2caf59SThomas Veerman * Side Effects: 6792e2caf59SThomas Veerman * Guess what? 6802e2caf59SThomas Veerman * 6812e2caf59SThomas Veerman *----------------------------------------------------------------------- 6822e2caf59SThomas Veerman */ 6832e2caf59SThomas Veerman void 6842e2caf59SThomas Veerman Compat_Run(Lst targs) 6852e2caf59SThomas Veerman { 6862e2caf59SThomas Veerman GNode *gn = NULL;/* Current root target */ 6872e2caf59SThomas Veerman int errors; /* Number of targets not remade due to errors */ 6882e2caf59SThomas Veerman 6892e2caf59SThomas Veerman Compat_Init(); 6902e2caf59SThomas Veerman 6912e2caf59SThomas Veerman if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { 6922e2caf59SThomas Veerman bmake_signal(SIGINT, CompatInterrupt); 6932e2caf59SThomas Veerman } 6942e2caf59SThomas Veerman if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { 6952e2caf59SThomas Veerman bmake_signal(SIGTERM, CompatInterrupt); 6962e2caf59SThomas Veerman } 6972e2caf59SThomas Veerman if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { 6982e2caf59SThomas Veerman bmake_signal(SIGHUP, CompatInterrupt); 6992e2caf59SThomas Veerman } 7002e2caf59SThomas Veerman if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 7012e2caf59SThomas Veerman bmake_signal(SIGQUIT, CompatInterrupt); 7022e2caf59SThomas Veerman } 7032e2caf59SThomas Veerman 7042e2caf59SThomas Veerman ENDNode = Targ_FindNode(".END", TARG_CREATE); 7052e2caf59SThomas Veerman ENDNode->type = OP_SPECIAL; 7062e2caf59SThomas Veerman /* 7072e2caf59SThomas Veerman * If the user has defined a .BEGIN target, execute the commands attached 7082e2caf59SThomas Veerman * to it. 7092e2caf59SThomas Veerman */ 7102e2caf59SThomas Veerman if (!queryFlag) { 7112e2caf59SThomas Veerman gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 7122e2caf59SThomas Veerman if (gn != NULL) { 7132e2caf59SThomas Veerman Compat_Make(gn, gn); 7142e2caf59SThomas Veerman if (gn->made == ERROR) { 7152e2caf59SThomas Veerman PrintOnError(gn, "\n\nStop."); 7162e2caf59SThomas Veerman exit(1); 7172e2caf59SThomas Veerman } 7182e2caf59SThomas Veerman } 7192e2caf59SThomas Veerman } 7202e2caf59SThomas Veerman 7212e2caf59SThomas Veerman /* 7222e2caf59SThomas Veerman * Expand .USE nodes right now, because they can modify the structure 7232e2caf59SThomas Veerman * of the tree. 7242e2caf59SThomas Veerman */ 7252e2caf59SThomas Veerman Make_ExpandUse(targs); 7262e2caf59SThomas Veerman 7272e2caf59SThomas Veerman /* 7282e2caf59SThomas Veerman * For each entry in the list of targets to create, call Compat_Make on 7292e2caf59SThomas Veerman * it to create the thing. Compat_Make will leave the 'made' field of gn 7302e2caf59SThomas Veerman * in one of several states: 7312e2caf59SThomas Veerman * UPTODATE gn was already up-to-date 7322e2caf59SThomas Veerman * MADE gn was recreated successfully 7332e2caf59SThomas Veerman * ERROR An error occurred while gn was being created 7342e2caf59SThomas Veerman * ABORTED gn was not remade because one of its inferiors 7352e2caf59SThomas Veerman * could not be made due to errors. 7362e2caf59SThomas Veerman */ 7372e2caf59SThomas Veerman errors = 0; 7382e2caf59SThomas Veerman while (!Lst_IsEmpty (targs)) { 7392e2caf59SThomas Veerman gn = (GNode *)Lst_DeQueue(targs); 7402e2caf59SThomas Veerman Compat_Make(gn, gn); 7412e2caf59SThomas Veerman 7422e2caf59SThomas Veerman if (gn->made == UPTODATE) { 7432e2caf59SThomas Veerman printf("`%s' is up to date.\n", gn->name); 7442e2caf59SThomas Veerman } else if (gn->made == ABORTED) { 7452e2caf59SThomas Veerman printf("`%s' not remade because of errors.\n", gn->name); 7462e2caf59SThomas Veerman errors += 1; 7472e2caf59SThomas Veerman } 7482e2caf59SThomas Veerman } 7492e2caf59SThomas Veerman 7502e2caf59SThomas Veerman /* 7512e2caf59SThomas Veerman * If the user has defined a .END target, run its commands. 7522e2caf59SThomas Veerman */ 7532e2caf59SThomas Veerman if (errors == 0) { 7542e2caf59SThomas Veerman Compat_Make(ENDNode, ENDNode); 7552e2caf59SThomas Veerman if (gn->made == ERROR) { 7562e2caf59SThomas Veerman PrintOnError(gn, "\n\nStop."); 7572e2caf59SThomas Veerman exit(1); 7582e2caf59SThomas Veerman } 7592e2caf59SThomas Veerman } 7602e2caf59SThomas Veerman } 761