⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 job.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	} else {	    errOff = TRUE;	}	cmd++;    }    while (isspace((unsigned char) *cmd))	cmd++;    if (shutUp) {	if (! (job->flags & JOB_SILENT) && !noSpecials &&	    commandShell->hasEchoCtl) {		DBPRINTF ("%s\n", commandShell->echoOff);	} else {	    shutUp = FALSE;	}    }    if (errOff) {	if ( ! (job->flags & JOB_IGNERR) && !noSpecials) {	    if (commandShell->hasErrCtl) {		/*		 * we don't want the error-control commands showing		 * up either, so we turn off echoing while executing		 * them. We could put another field in the shell		 * structure to tell JobDoOutput to look for this		 * string too, but why make it any more complex than		 * it already is?		 */		if (! (job->flags & JOB_SILENT) && !shutUp &&		    commandShell->hasEchoCtl) {			DBPRINTF ("%s\n", commandShell->echoOff);			DBPRINTF ("%s\n", commandShell->ignErr);			DBPRINTF ("%s\n", commandShell->echoOn);		} else {		    DBPRINTF ("%s\n", commandShell->ignErr);		}	    } else if (commandShell->ignErr &&		       (*commandShell->ignErr != '\0'))	    {		/*		 * The shell has no error control, so we need to be		 * weird to get it to ignore any errors from the command.		 * If echoing is turned on, we turn it off and use the		 * errCheck template to echo the command. Leave echoing		 * off so the user doesn't see the weirdness we go through		 * to ignore errors. Set cmdTemplate to use the weirdness		 * instead of the simple "%s\n" template.		 */		if (! (job->flags & JOB_SILENT) && !shutUp &&		    commandShell->hasEchoCtl) {			DBPRINTF ("%s\n", commandShell->echoOff);			DBPRINTF (commandShell->errCheck, cmd);			shutUp = TRUE;		}		cmdTemplate = commandShell->ignErr;		/*		 * The error ignoration (hee hee) is already taken care		 * of by the ignErr template, so pretend error checking		 * is still on.		 */		errOff = FALSE;	    } else {		errOff = FALSE;	    }	} else {	    errOff = FALSE;	}    }        DBPRINTF (cmdTemplate, cmd);        if (errOff) {	/*	 * If echoing is already off, there's no point in issuing the	 * echoOff command. Otherwise we issue it and pretend it was on	 * for the whole command...	 */	if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){	    DBPRINTF ("%s\n", commandShell->echoOff);	    shutUp = TRUE;	}	DBPRINTF ("%s\n", commandShell->errCheck);    }    if (shutUp) {	DBPRINTF ("%s\n", commandShell->echoOn);    }    return (0);}/*- *----------------------------------------------------------------------- * JobSaveCommand -- *	Save a command to be executed when everything else is done. *	Callback function for JobFinish... * * Results: *	Always returns 0 * * Side Effects: *	The command is tacked onto the end of postCommands's commands list. * *----------------------------------------------------------------------- */static intJobSaveCommand (cmd, gn)    char    *cmd;    GNode   *gn;{    cmd = Var_Subst (NULL, cmd, gn, FALSE);    (void)Lst_AtEnd (postCommands->commands, (ClientData)cmd);    return (0);}/*- *----------------------------------------------------------------------- * JobFinish  -- *	Do final processing for the given job including updating *	parents and starting new jobs as available/necessary. Note *	that we pay no attention to the JOB_IGNERR flag here. *	This is because when we're called because of a noexecute flag *	or something, jstat.w_status is 0 and when called from *	Job_CatchChildren, the status is zeroed if it s/b ignored. * * Results: *	None * * Side Effects: *	Some nodes may be put on the toBeMade queue. *	Final commands for the job are placed on postCommands. * *	If we got an error and are aborting (aborting == ABORT_ERROR) and *	the job list is now empty, we are done for the day. *	If we recognized an error (errors !=0), we set the aborting flag *	to ABORT_ERROR so no more jobs will be started. *----------------------------------------------------------------------- *//*ARGSUSED*/static voidJobFinish (job, status)    Job           *job;	      	  /* job to finish */    union wait	  status;     	  /* sub-why job went away */{    Boolean 	  done;    if ((WIFEXITED(status) &&	  (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) ||	(WIFSIGNALED(status) && (status.w_termsig != SIGCONT)))    {	/*	 * If it exited non-zero and either we're doing things our	 * way or we're not ignoring errors, the job is finished.	 * Similarly, if the shell died because of a signal	 * the job is also finished. In these	 * 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);	}	if (job->cmdFILE != NULL && job->cmdFILE != stdout) {	    fclose(job->cmdFILE);	}	done = TRUE;    } else if (WIFEXITED(status) && status.w_retcode != 0) {	/*	 * 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	 * want to close down any of the streams until we know we're at the	 * end.	 */	done = TRUE;    } else {	/*	 * No need to close things down or anything.	 */	done = FALSE;    }        if (done ||	WIFSTOPPED(status) ||	(WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) ||	DEBUG(JOB))    {	FILE	  *out;		if (!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");	} else {	    out = stdout;	}	if (WIFEXITED(status)) {	    if (status.w_retcode != 0) {		if (usePipes && job->node != lastNode) {		    fprintf (out, targFmt, job->node->name);		    lastNode = job->node;		}		fprintf (out, "*** Error code %d%s\n", status.w_retcode,			 (job->flags & JOB_IGNERR) ? " (ignored)" : "");		if (job->flags & JOB_IGNERR) {		    status.w_status = 0;		}	    } else if (DEBUG(JOB)) {		if (usePipes && job->node != lastNode) {		    fprintf (out, targFmt, job->node->name);		    lastNode = job->node;		}		fprintf (out, "*** Completed successfully\n");	    }	} else if (WIFSTOPPED(status)) {	    if (usePipes && job->node != lastNode) {		fprintf (out, targFmt, job->node->name);		lastNode = job->node;	    }	    if (! (job->flags & JOB_REMIGRATE)) {		fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig);	    }	    job->flags |= JOB_RESUME;	    (void)Lst_AtEnd(stoppedJobs, (ClientData)job);	    fflush(out);	    return;	} else if (status.w_termsig == SIGCONT) {	    /*	     * If the beastie has continued, shift the Job from the stopped	     * list to the running one (or re-stop it if concurrency is	     * exceeded) and go and get another child.	     */	    if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {		if (usePipes && job->node != lastNode) {		    fprintf (out, targFmt, job->node->name);		    lastNode = job->node;		}		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");		    }		}	    }	    fflush(out);	    return;	} else {	    if (usePipes && job->node != lastNode) {		fprintf (out, targFmt, job->node->name);		lastNode = job->node;	    }	    fprintf (out, "*** Signal %d\n", status.w_termsig);	}	fflush (out);    }    /*     * Now handle the -B-mode stuff. If the beast still isn't finished,     * 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;	}    } else {	done = TRUE;    }		    if (done &&	(aborting != ABORT_ERROR) &&	(aborting != ABORT_INTERRUPT) &&	(status.w_status == 0))    {	/*	 * As long as we aren't aborting and the job didn't return a non-zero	 * status that we shouldn't ignore, we call Make_Update to update	 * the parents. In addition, any saved commands for the node are placed	 * on the .END target.	 */	if (job->tailCmds != NILLNODE) {	    Lst_ForEachFrom (job->node->commands, job->tailCmds,			     JobSaveCommand,			     (ClientData)job->node);	}	job->node->made = MADE;	Make_Update (job->node);	free((Address)job);    } else if (status.w_status) {	errors += 1;	free((Address)job);    }    while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) {	JobRestart((Job *)Lst_DeQueue(stoppedJobs));    }    /*     * Set aborting if any error.     */    if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {	/*	 * If we found any errors in this batch of children and the -k flag	 * wasn't given, we set the aborting flag so no more jobs get	 * started.	 */	aborting = ABORT_ERROR;    }        if ((aborting == ABORT_ERROR) && Job_Empty()) {	/*	 * If we are aborting and the job table is now empty, we finish.	 */	(void) unlink (tfile);	Finish (errors);    }}/*- *----------------------------------------------------------------------- * Job_Touch -- *	Touch the given target. Called by JobStart when the -t flag was *	given * * Results: *	None * * Side Effects: *	The data modification of the file is changed. In addition, if the *	file did not exist, it is created. *----------------------------------------------------------------------- */voidJob_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 */    if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) {	/*	 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets	 * and, as such, shouldn't really be created.	 */	return;    }        if (!silent) {	printf ("touch %s\n", gn->name);    }    if (noExecute) {	return;    }    if (gn->type & OP_ARCHV) {	Arch_Touch (gn);    } else if (gn->type & OP_LIB) {	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);	    if (streamID >= 0) {		char	c;		/*		 * Read and write a byte to the file to change the		 * modification time, then close the file.		 */		if (read(streamID, &c, 1) == 1) {		    lseek(streamID, 0L, L_SET);		    write(streamID, &c, 1);		}				(void)close (streamID);	    } else		printf("*** couldn't touch %s: %s", file, strerror(errno));	}    }}/*- *----------------------------------------------------------------------- * Job_CheckCommands -- *	Make sure the given node has all the commands it needs.  * * Results: *	TRUE if the commands list is/was ok. * * Side Effects: *	The node will have commands from the .DEFAULT rule added to it *	if it needs them. *----------------------------------------------------------------------- */BooleanJob_CheckCommands (gn, abortProc)

⌨️ 快捷键说明

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