Beispiel #1
0
void
meta_job_finish(Job *job)
{
    BuildMon *pbm;

    if (job != NULL) {
	pbm = &job->bm;
    } else {
	pbm = &Mybm;
    }
    if (pbm->mfp != NULL) {
	meta_cmd_finish(pbm);
	fclose(pbm->mfp);
	pbm->mfp = NULL;
	pbm->meta_fname[0] = '\0';
    }
}
Beispiel #2
0
int
meta_job_finish(Job *job)
{
    BuildMon *pbm;
    int error = 0;
    int x;

    if (job != NULL) {
        pbm = &job->bm;
    } else {
        pbm = &Mybm;
    }
    if (pbm->mfp != NULL) {
        error = meta_cmd_finish(pbm);
        x = fclose(pbm->mfp);
        if (error == 0 && x != 0)
            error = errno;
        pbm->mfp = NULL;
        pbm->meta_fname[0] = '\0';
    }
    return error;
}
Beispiel #3
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.
 *
 * Input:
 *	cmdp		Command to execute
 *	gnp		Node from which the command came
 *
 * Results:
 *	0 if the command succeeded, 1 if an error occurred.
 *
 * Side Effects:
 *	The node's 'made' field may be set to ERROR.
 *
 *-----------------------------------------------------------------------
 */
int
CompatRunCommand(void *cmdp, void *gnp)
{
    char    	  *cmdStart;	/* Start of expanded command */
    char 	  *cp, *bp;
    Boolean 	  silent,   	/* Don't print command */
	    	  doIt;		/* Execute even if -n */
    volatile Boolean errCheck; 	/* Check errors */
    WAIT_T 	  reason;   	/* Reason for child's death */
    int	    	  status;   	/* Description of child's death */
    pid_t	  cpid;	    	/* Child actually found */
    pid_t	  retstat;    	/* Result of wait */
    LstNode 	  cmdNode;  	/* Node where current command is located */
    const char  ** volatile av;	/* Argument vector for thing to exec */
    char	** volatile mav;/* Copy of the argument vector for freeing */
    int	    	  argc;	    	/* Number of arguments in av or 0 if not
				 * dynamically allocated */
    Boolean 	  local;    	/* TRUE if command should be executed
				 * locally */
    Boolean 	  useShell;    	/* TRUE if command should be executed
				 * using a shell */
    char	  * volatile cmd = (char *)cmdp;
    GNode	  *gn = (GNode *)gnp;

    silent = gn->type & OP_SILENT;
    errCheck = !(gn->type & OP_IGNORE);
    doIt = FALSE;
    
    cmdNode = Lst_Member(gn->commands, cmd);
    cmdStart = Var_Subst(NULL, cmd, gn, FALSE);

    /*
     * brk_string will return an argv with a NULL in av[0], 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') {
	free(cmdStart);
	Error("%s expands to empty string", cmd);
	return(0);
    }
    cmd = cmdStart;
    Lst_Replace(cmdNode, cmdStart);

    if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
	(void)Lst_AtEnd(ENDNode->commands, cmdStart);
	return(0);
    }
    if (strcmp(cmdStart, "...") == 0) {
	gn->type |= OP_SAVE_CMDS;
	return(0);
    }

    while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) {
	switch (*cmd) {
	case '@':
	    silent = DEBUG(LOUD) ? FALSE : TRUE;
	    break;
	case '-':
	    errCheck = FALSE;
	    break;
	case '+':
	    doIt = TRUE;
	    if (!meta[0])		/* we came here from jobs */
		Compat_Init();
	    break;
	}
	cmd++;
    }

    while (isspace((unsigned char)*cmd))
	cmd++;

#if !defined(MAKE_NATIVE)
    /*
     * In a non-native build, the host environment might be weird enough
     * that it's necessary to go through a shell to get the correct
     * behaviour.  Or perhaps the shell has been replaced with something
     * that does extra logging, and that should not be bypassed.
     */
    useShell = TRUE;
#else
    /*
     * 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;
    }
    useShell = (*cp != '\0');
#endif

    /*
     * 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(gn)) {
	printf("%s\n", cmd);
	fflush(stdout);
    }

    /*
     * If we're not supposed to execute any commands, this is as far as
     * we go...
     */
    if (!doIt && NoExecute(gn)) {
	return (0);
    }
    if (DEBUG(JOB))
	fprintf(debug_file, "Execute: '%s'\n", cmd);

again:
    if (useShell) {
	/*
	 * We need to pass the command off to the shell, typically
	 * because the command contains a "meta" character.
	 */
	static const char *shargv[4];

	shargv[0] = shellPath;
	/*
	 * The following work for any of the builtin shell specs.
	 */
	if (DEBUG(SHELL))
		shargv[1] = "-xc";
	else
		shargv[1] = "-c";
	shargv[2] = cmd;
	shargv[3] = NULL;
	av = shargv;
	argc = 0;
	bp = NULL;
	mav = NULL;
    } else {
	/*
	 * No meta-characters, so no need to exec a shell. Break the command
	 * into words to form an argument vector we can execute.
	 */
	mav = brk_string(cmd, &argc, TRUE, &bp);
	if (mav == NULL) {
		useShell = 1;
		goto again;
	}
	av = (const char **)mav;
    }

    local = TRUE;

#ifdef USE_META
    if (useMeta) {
	meta_compat_start();
    }
#endif
    
    /*
     * Fork and execute the single command. If the fork fails, we abort.
     */
    cpid = vFork();
    if (cpid < 0) {
	Fatal("Could not fork");
    }
    if (cpid == 0) {
	Check_Cwd(av);
	Var_ExportVars();
#ifdef USE_META
	if (useMeta) {
	    meta_compat_child();
	}
#endif
	if (local)
	    (void)execvp(av[0], (char *const *)UNCONST(av));
	else
	    (void)execv(av[0], (char *const *)UNCONST(av));
	execError("exec", av[0]);
	_exit(1);
    }
    if (mav)
	free(mav);
    if (bp)
	free(bp);
    Lst_Replace(cmdNode, NULL);

#ifdef USE_META
    if (useMeta) {
	meta_compat_parent();
    }
#endif

    /*
     * The child is off and running. Now all we can do is wait...
     */
    while (1) {

	while ((retstat = wait(&reason)) != cpid) {
	    if (retstat > 0)
		JobReapChild(retstat, reason, FALSE); /* not ours? */
	    if (retstat == -1 && errno != EINTR) {
		break;
	    }
	}

	if (retstat > -1) {
	    if (WIFSTOPPED(reason)) {
		status = WSTOPSIG(reason);		/* stopped */
	    } else if (WIFEXITED(reason)) {
		status = WEXITSTATUS(reason);		/* exited */
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
		if (useMeta) {
		    meta_cmd_finish(NULL);
		}
#endif
		if (status != 0) {
		    if (DEBUG(ERROR)) {
		        fprintf(debug_file, "\n*** Failed target:  %s\n*** Failed command: ",
			    gn->name);
		        for (cp = cmd; *cp; ) {
    			    if (isspace((unsigned char)*cp)) {
				fprintf(debug_file, " ");
			        while (isspace((unsigned char)*cp))
				    cp++;
			    } else {
				fprintf(debug_file, "%c", *cp);
			        cp++;
			    }
		        }
			fprintf(debug_file, "\n");
		    }
		    printf("*** Error code %d", status);
		}
	    } else {
		status = WTERMSIG(reason);		/* signaled */
		printf("*** Signal %d", status);
	    }


	    if (!WIFEXITED(reason) || (status != 0)) {
		if (errCheck) {
#ifdef USE_META
		    if (useMeta) {
			meta_job_error(NULL, gn, 0, status);
		    }
#endif
		    gn->made = ERROR;
		    if (keepgoing) {
			/*
			 * Abort the current target, but let others
			 * continue.
			 */
			printf(" (continuing)\n");
		    }
		} else {
		    /*
		     * Continue executing commands for this target.
		     * If we return 0, this will happen...
		     */
		    printf(" (ignored)\n");
		    status = 0;
		}
	    }
	    break;
	} else {
	    Fatal("error in wait: %d: %s", retstat, strerror(errno));
	    /*NOTREACHED*/
	}
    }
    free(cmdStart);

    return (status);
}