📄 job.c
字号:
} 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 + -