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

📄 job.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	A new Job node is created and added to the list of running *	jobs. PMake is forked and a child shell created. *----------------------------------------------------------------------- */static intJobStart (gn, flags, previous)    GNode         *gn;	      /* target to create */    short	  flags;      /* flags for the job to override normal ones.			       * e.g. JOB_SPECIAL or JOB_IGNDOTS */    Job 	  *previous;  /* The previous Job structure for this node,			       * if any. */{    register Job  *job;       /* new job descriptor */    char	  *argv[4];   /* Argument vector to shell */    static int    jobno = 0;  /* job number of catching output in a file */    Boolean	  cmdsOK;     /* true if the nodes commands were all right */    Boolean 	  local;      /* Set true if the job was run locally */    Boolean 	  noExec;     /* Set true if we decide not to run the job */    if (previous != (Job *)NULL) {	previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);	job = previous;    } else {	job = (Job *) emalloc (sizeof (Job));	if (job == (Job *)NULL) {	    Punt("JobStart out of memory");	}	flags |= JOB_FIRST;    }    job->node = gn;    job->tailCmds = NILLNODE;    /*     * Set the initial value of the flags for this job based on the global     * ones and the node's attributes... Any flags supplied by the caller     * are also added to the field.     */    job->flags = 0;    if (Targ_Ignore (gn)) {	job->flags |= JOB_IGNERR;    }    if (Targ_Silent (gn)) {	job->flags |= JOB_SILENT;    }    job->flags |= flags;    /*     * Check the commands now so any attributes from .DEFAULT have a chance     * to migrate to the node     */    if (job->flags & JOB_FIRST) {	cmdsOK = Job_CheckCommands(gn, Error);    } else {	cmdsOK = TRUE;    }        /*     * If the -n flag wasn't given, we open up OUR (not the child's)     * temporary file to stuff commands in it. The thing is rd/wr so we don't     * need to reopen it to feed it to the shell. If the -n flag *was* given,     * we just set the file to be stdout. Cute, huh?     */    if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {	/*	 * We're serious here, but if the commands were bogus, we're	 * also dead...	 */	if (!cmdsOK) {	    DieHorribly();	}		job->cmdFILE = fopen (tfile, "w+");	if (job->cmdFILE == (FILE *) NULL) {	    Punt ("Could not open %s", tfile);	}	fcntl(fileno(job->cmdFILE), F_SETFD, 1);	/*	 * Send the commands to the command file, flush all its buffers then	 * rewind and remove the thing.	 */	noExec = FALSE;	/*	 * used to be backwards; replace when start doing multiple commands	 * per shell.	 */	if (compatMake) {	    /*	     * Be compatible: If this is the first time for this node,	     * verify its commands are ok and open the commands list for	     * sequential access by later invocations of JobStart.	     * Once that is done, we take the next command off the list	     * and print it to the command file. If the command was an	     * ellipsis, note that there's nothing more to execute.	     */	    if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){		cmdsOK = FALSE;	    } else {		LstNode	ln = Lst_Next (gn->commands);		    		if ((ln == NILLNODE) ||		    JobPrintCommand ((char *)Lst_Datum (ln), job))		{		    noExec = TRUE;		    Lst_Close (gn->commands);		}		if (noExec && !(job->flags & JOB_FIRST)) {		    /*		     * If we're not going to execute anything, the job		     * is done and we need to close down the various		     * file descriptors we've opened for output, then		     * call JobDoOutput to catch the final characters or		     * send the file to the screen... Note that the i/o streams		     * are only open if this isn't the first job.		     * Note also that this could not be done in		     * Job_CatchChildren b/c it wasn't clear if there were		     * more commands to execute or not...		     */		    if (usePipes) {#ifdef RMT_WILL_WATCH			Rmt_Ignore(job->inPipe);#else			FD_CLR(job->inPipe, &outputs);#endif			if (job->outPipe != job->inPipe) {			    (void)close (job->outPipe);			}			JobDoOutput (job, TRUE);			(void)close (job->inPipe);		    } else {			(void)close (job->outFd);			JobDoOutput (job, TRUE);		    }		}	    }	} else {	    /*	     * We can do all the commands at once. hooray for sanity	     */	    numCommands = 0;	    Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job);	    	    /*	     * If we didn't print out any commands to the shell script,	     * there's not much point in executing the shell, is there?	     */	    if (numCommands == 0) {		noExec = TRUE;	    }	}    } else if (noExecute) {	/*	 * Not executing anything -- just print all the commands to stdout	 * in one fell swoop. This will still set up job->tailCmds correctly.	 */	if (lastNode != gn) {	    printf (targFmt, gn->name);	    lastNode = gn;	}	job->cmdFILE = stdout;	/*	 * Only print the commands if they're ok, but don't die if they're	 * not -- just let the user know they're bad and keep going. It	 * doesn't do any harm in this case and may do some good.	 */	if (cmdsOK) {	    Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);	}	/*	 * Don't execute the shell, thank you.	 */	noExec = TRUE;    } else {	/*	 * Just touch the target and note that no shell should be executed.	 * Set cmdFILE to stdout to make life easier. Check the commands, too,	 * but don't die if they're no good -- it does no harm to keep working	 * up the graph.	 */	job->cmdFILE = stdout;    	Job_Touch (gn, job->flags&JOB_SILENT);	noExec = TRUE;    }    /*     * If we're not supposed to execute a shell, don't.      */    if (noExec) {	/*	 * Unlink and close the command file if we opened one	 */	if (job->cmdFILE != stdout) {	    (void) unlink (tfile);	    fclose(job->cmdFILE);	} else {	    fflush (stdout);	}	/*	 * We only want to work our way up the graph if we aren't here because	 * the commands for the job were no good.	 */	if (cmdsOK) {	    if (aborting == 0) {		if (job->tailCmds != NILLNODE) {		    Lst_ForEachFrom(job->node->commands, job->tailCmds,				    JobSaveCommand,				    (ClientData)job->node);		}		Make_Update(job->node);	    }	    free((Address)job);	    return(JOB_FINISHED);	} else {	    free((Address)job);	    return(JOB_ERROR);	}    } else {	fflush (job->cmdFILE);	(void) unlink (tfile);    }    /*     * Set up the control arguments to the shell. This is based on the flags     * set earlier for this job.     */    JobMakeArgv(job, argv);    /*     * If we're using pipes to catch output, create the pipe by which we'll     * get the shell's output. If we're using files, print out that we're     * starting a job and then set up its temporary-file name. This is just     * tfile with two extra digits tacked on -- jobno.     */    if (job->flags & JOB_FIRST) {	if (usePipes) {	    int fd[2];	    (void) pipe(fd); 	    job->inPipe = fd[0];	    job->outPipe = fd[1];	    (void)fcntl (job->inPipe, F_SETFD, 1);	    (void)fcntl (job->outPipe, F_SETFD, 1);	} else {	    printf ("Remaking `%s'\n", gn->name);	    fflush (stdout);	    sprintf (job->outFile, "%s%02d", tfile, jobno);	    jobno = (jobno + 1) % 100;	    job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);	    (void)fcntl (job->outFd, F_SETFD, 1);	}    }    local = TRUE;    if (local && (((nLocal >= maxLocal) &&	 !(job->flags & JOB_SPECIAL) &&	 (maxLocal != 0))))    {	/*	 * The job can only be run locally, but we've hit the limit of	 * local concurrency, so put the job on hold until some other job	 * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)	 * may be run locally even when the local limit has been reached	 * (e.g. when maxLocal == 0), though they will be exported if at	 * all possible. 	 */	jobFull = TRUE;		if (DEBUG(JOB)) {	    printf("Can only run job locally.\n");	}	job->flags |= JOB_RESTART;	(void)Lst_AtEnd(stoppedJobs, (ClientData)job);    } else {	if ((nLocal >= maxLocal) && local) {	    /*	     * If we're running this job locally as a special case (see above),	     * at least say the table is full.	     */	    jobFull = TRUE;	    if (DEBUG(JOB)) {		printf("Local job queue is full.\n");	    }	}	JobExec(job, argv);    }    return(JOB_RUNNING);}/*- *----------------------------------------------------------------------- * JobDoOutput  -- *	This function is called at different times depending on *	whether the user has specified that output is to be collected *	via pipes or temporary files. In the former case, we are called *	whenever there is something to read on the pipe. We collect more *	output from the given job and store it in the job's outBuf. If *	this makes up a line, we print it tagged by the job's identifier, *	as necessary. *	If output has been collected in a temporary file, we open the *	file and read it line by line, transfering it to our own *	output channel until the file is empty. At which point we *	remove the temporary file. *	In both cases, however, we keep our figurative eye out for the *	'noPrint' line for the shell from which the output came. If *	we recognize a line, we don't print it. If the command is not *	alone on the line (the character after it is not \0 or \n), we *	do print whatever follows it. * * Results: *	None * * Side Effects: *	curPos may be shifted as may the contents of outBuf. *----------------------------------------------------------------------- */static voidJobDoOutput (job, finish)    register Job   *job;	  /* the job whose output needs printing */    Boolean	   finish;	  /* TRUE if this is the last time we'll be				   * called for this job */{    Boolean       gotNL = FALSE;  /* true if got a newline */    register int  nr;	      	  /* number of bytes read */    register int  i;	      	  /* auxiliary index into outBuf */    register int  max;	      	  /* limit for i (end of current data) */    int		  nRead;      	  /* (Temporary) number of bytes read */    FILE      	  *oFILE;	  /* Stream pointer to shell's output file */    char          inLine[132];        if (usePipes) {	/*	 * Read as many bytes as will fit in the buffer.	 */end_loop:		nRead = read (job->inPipe, &job->outBuf[job->curPos],			 JOB_BUFSIZE - job->curPos);	if (nRead < 0) {	    if (DEBUG(JOB)) {		perror("JobDoOutput(piperead)");	    }	    nr = 0;	} else {	    nr = nRead;	}	/*	 * If we hit the end-of-file (the job is dead), we must flush its	 * remaining output, so pretend we read a newline if there's any	 * output remaining in the buffer.	 * Also clear the 'finish' flag so we stop looping.	 */	if ((nr == 0) && (job->curPos != 0)) {	    job->outBuf[job->curPos] = '\n';	    nr = 1;	    finish = FALSE;	} else if (nr == 0) {	    finish = FALSE;	}		/*	 * Look for the last newline in the bytes we just got. If there is	 * one, break out of the loop with 'i' as its index and gotNL set	 * TRUE. 	 */	max = job->curPos + nr;	for (i = job->curPos + nr - 1; i >= job->curPos; i--) {	    if (job->outBuf[i] == '\n') {		gotNL = TRUE;		break;	    } else if (job->outBuf[i] == '\0') {		/*		 * Why?		 */		job->outBuf[i] = ' ';	    }	}		if (!gotNL) {	    job->curPos += nr;	    if (job->curPos == JOB_BUFSIZE) {		/*		 * If we've run out of buffer space, we have no choice		 * but to print the stuff. sigh. 		 */		gotNL = TRUE;		i = job->curPos;	    }	}	if (gotNL) {	    /*	     * Need to send the output to the screen. Null terminate it	     * first, overwriting the newline character if there was one.	     * So long as the line isn't one we should filter (according	     * to the shell description), we print the line, preceeded	     * by a target banner if this target isn't the same as the	     * one for which we last printed something.	     * The rest of the data in the buffer are then shifted down	     * to the start of the buffer and curPos is set accordingly. 	     */	    job->outBuf[i] = '\0';	    if (i >= job->curPos) {		register char	*cp, *ecp;		cp = job->outBuf;		if (commandShell->noPrint) {		    ecp = Str_FindSubstring(job->outBuf,					    commandShell->noPrint);		    while (ecp != (char *)NULL) {			if (cp != ecp) {			    *ecp = '\0';			    if (job->node != lastNode) {				printf (targFmt, job->node->name);				lastNode = job->node;			    }			    /*			     * The only way there wouldn't be a newline after			     * this line is if it were the last in the buffer.			     * however, since the non-printable comes after it,			     * there must be a newline, so we don't print one.			     */			    printf ("%s", cp);			}			cp = ecp + commandShell->noPLen;			if (cp != &job->outBuf[i]) {			    /*			     * Still more to print, look again after skipping			     * the whitespace following the non-printable			     * command....			     */			    cp++;			    while (*cp == ' ' || *cp == '\t' || *cp == '\n') {				cp++;			    }			    ecp = Str_FindSubstring (cp,						     commandShell->noPrint);			} else {			    break;			}		    }		}		/*		 * There's still more in that thar buffer. This time, though,		 * we know there's no newline at the end, so we add one of		 * our own free will.		 */		if (*cp != '\0') {

⌨️ 快捷键说明

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