Lst_AtEnd(jobs, job);
Lst_AtEnd(&jobs, job);
JobExec(job, argv)    Job	    	  *job; 	/* Job to execute */    char    	  **argv;{    int	    	  cpid;	    	/* ID of new child */    if (DEBUG(JOB)) {	int 	  i;	(void) fprintf(stdout, "Running %s %sly\n", job->node->name,		       job->flags&JOB_REMOTE?"remote":"local");	(void) fprintf(stdout, "\tCommand: ");	for (i = 0; argv[i] != NULL; i++) {	    (void) fprintf(stdout, "%s ", argv[i]);	} 	(void) fprintf(stdout, "\n"); 	(void) fflush(stdout);    }    /*     * Some jobs produce no output and it's disconcerting to have     * no feedback of their running (since they produce no output, the     * banner with their name in it never appears). This is an attempt to     * provide that feedback, even if nothing follows it.     */    if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&	!(job->flags & JOB_SILENT)) {	MESSAGE(stdout, job->node);	lastNode = job->node;    }#ifdef RMT_NO_EXEC    if (job->flags & JOB_REMOTE) {	goto jobExecFinish;    }#endif /* RMT_NO_EXEC */    if ((cpid = vfork()) == -1) {	Punt("Cannot fork");    } else if (cpid == 0) {	/*	 * Must duplicate the input stream down to the child's input and	 * reset it to the beginning (again). Since the stream was marked	 * close-on-exec, we must clear that bit in the new input.	 */	if (dup2(FILENO(job->cmdFILE), 0) == -1)	    Punt("Cannot dup2: %s", strerror(errno));	(void) fcntl(0, F_SETFD, 0);	(void) lseek(0, 0, SEEK_SET);	if (usePipes) {	    /*	     * Set up the child's output to be routed through the pipe	     * we've created for it.	     */	    if (dup2(job->outPipe, 1) == -1)		Punt("Cannot dup2: %s", strerror(errno));	} else {	    /*	     * We're capturing output in a file, so we duplicate the	     * descriptor to the temporary file into the standard	     * output.	     */	    if (dup2(job->outFd, 1) == -1)		Punt("Cannot dup2: %s", strerror(errno));	}	/*	 * The output channels are marked close on exec. This bit was	 * duplicated by the dup2 (on some systems), so we have to clear	 * it before routing the shell's error output to the same place as	 * its standard output.	 */	(void) fcntl(1, F_SETFD, 0);	if (dup2(1, 2) == -1)	    Punt("Cannot dup2: %s", strerror(errno));#ifdef USE_PGRP	/*	 * We want to switch the child into a different process family so	 * we can kill it and all its descendants in one fell swoop,	 * by killing its process family, but not commit suicide.	 */# if defined(SYSV)	(void) setsid();# else	(void) setpgid(0, getpid());# endif#endif /* USE_PGRP */#ifdef REMOTE	if (job->flags & JOB_REMOTE) {	    Rmt_Exec(shellPath, argv, FALSE);	} else#endif /* REMOTE */	   (void) execv(shellPath, argv);	(void) write(2, "Could not execute shell\n",		     sizeof("Could not execute shell"));	_exit(1);    } else {#ifdef REMOTE	int omask = sigblock(sigmask(SIGCHLD));#endif	job->pid = cpid;	if (usePipes && (job->flags & JOB_FIRST) ) {	    /*	     * The first time a job is run for a node, we set the current	     * position in the buffer to the beginning and mark another	     * stream to watch in the outputs mask	     */	    job->curPos = 0;#ifdef RMT_WILL_WATCH	    Rmt_Watch(job->inPipe, JobLocalInput, job);#else	    if (outputsp == NULL || job->inPipe > outputsn) {		int bytes = howmany(job->inPipe+1, NFDBITS) * sizeof(fd_mask);		int obytes = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask);		if (outputsp == NULL || obytes != bytes) {			outputsp = realloc(outputsp, bytes);			if (outputsp == NULL)				return;			memset(outputsp + obytes, 0, bytes - obytes);		}		outputsn = job->inPipe;	    }	    FD_SET(job->inPipe, outputsp);#endif /* RMT_WILL_WATCH */	}	if (job->flags & JOB_REMOTE) {#ifndef REMOTE	    job->rmtID = 0;#else	    job->rmtID = Rmt_LastID(job->pid);#endif /* REMOTE */	} else {	    nLocal += 1;	    /*	     * XXX: Used to not happen if REMOTE. Why?	     */	    if (job->cmdFILE != NULL && job->cmdFILE != stdout) {		(void) fclose(job->cmdFILE);		job->cmdFILE = NULL;	    }	}#ifdef REMOTE	(void) sigsetmask(omask);#endif    }#ifdef RMT_NO_EXECjobExecFinish:#endif    /*     * Now the job is actually running, add it to the table.     */    nJobs += 1;    Lst_AtEnd(jobs, job);    if (nJobs == maxJobs) {	jobFull = TRUE;    }}