Beispiel #1
0
void executeCommand(struct command *c)
{
	int i, first, n;
	int fds[2], nextHasReadPipe = 0;
	char **args;
	pid_t child;
	struct command *p;
	struct argument *a;
	struct redirection *tail, *r;
	
	/* Walk through the list and:
	 * 1) resolve redirections to files
	 * 2) set up pipes and add them as redirections
	 */
	for(p = c; p; p = p->next)
	{
		if(p->redir)
			resolveRedirections(p->redir);
		
		/* Pipe setup */
		tail = NULL;
		if(nextHasReadPipe)
		{
			/* Set up the read end of the previous pipe */
			r = safeMalloc(sizeof(struct redirection));
			r->filename = NULL;
			r->mode = READ | PIPE;
			r->fromfd = 0;
			r->tofd = fds[0];
			r->next = NULL;
			
			/* Add to the redirections list */
			if(!p->redir)
				p->redir = tail = r;
			else
			{
				/* Find the tail */
				tail = p->redir;
				while(tail->next)
					tail = tail->next;
				tail->next = r;
				tail = r;
			}
			
			nextHasReadPipe = 0;
		}
		if(p->next && (p->mode & PIPED))
		{
			
			/* Create pipe */
			pipe(fds);
			
			/* Set up the write end */
			r = safeMalloc(sizeof(struct redirection));
			r->filename = NULL;
			r->mode = WRITE | PIPE;
			r->fromfd = 1;
			r->tofd = fds[1];
			r->next = NULL;
			
			/* Add to the redirections list */
			if(!p->redir)
				p->redir = r;
			else
			{
				if(!tail)
				{
					/* Find the tail */
					tail = p->redir;
					while(tail->next)
						tail = tail->next;
				}
				tail->next = r;
			}
			nextHasReadPipe = 1;
		}
	}

	
	/* Now walk through the list and fork processes */
	i = 0;
	first = 1;
	for(p = c; p; p = p->next)
	{
		child = fork();
		if(child < 0)
		{
			perror("fork");
			exit(EXIT_FAILURE);
		}
		if(child > 0)
			/* Parent process */
			p->pid = child;
		else
		{
			/* Child process */
			if(p->redir)
				setupRedirections(p->redir);
			closeOtherPipes(c, p);
			
			/* Count the number of arguments */
			n = 0;
			for(a = c->firstArg; a; a = a->next)
				n++;
			/* Allocate and fill args array */
			args = safeMalloc((n + 1)*sizeof(char *));
			for(n = 0, a = p->firstArg; a; n++, a = a->next)
				args[n] = a->s;
			args[n] = NULL;
			
			execvp(args[0], args);
			
			/* If we're alive here, execvp() failed */
			perror(args[0]);
			exit(EXIT_FAILURE);
		}
		first = 0;
	}
	
	/* Close pipes in the parent */
	closeOtherPipes(c, NULL);
}
Beispiel #2
0
int runCommand(struct job newJob, struct jobSet * jobList, 
               int inBg) {
    struct job * job;
    char * newdir, * buf;
    int i, len;
    int nextin, nextout;
    int pipefds[2];             /* pipefd[0] is for reading */
    char * statusString;
    int jobNum;

    /* handle built-ins here -- we don't fork() so we can't background
       these very easily */
    if (!strcmp(newJob.progs[0].argv[0], "exit")) {
        /* this should return a real exit code */
        exit(0);
    } else if (!strcmp(newJob.progs[0].argv[0], "pwd")) {
        len = 50;
        buf = malloc(len);
        while (!getcwd(buf, len) && errno == ERANGE) {
            len += 50;
            buf = realloc(buf, len);
        }
        printf("%s\n", buf);
        free(buf);
        return 0;
    } else if (!strcmp(newJob.progs[0].argv[0], "cd")) {
        if (!newJob.progs[0].argv[1] == 1) 
            newdir = getenv("HOME");
        else 
            newdir = newJob.progs[0].argv[1];
        if (chdir(newdir)) 
            printf("failed to change current directory: %s\n",
                    strerror(errno));
        return 0;
    } else if (!strcmp(newJob.progs[0].argv[0], "jobs")) {
        for (job = jobList->head; job; job = job->next) {
            if (job->runningProgs == job->stoppedProgs)
                statusString = "Stopped";
            else
                statusString = "Running";

            printf(JOB_STATUS_FORMAT, job->jobId, statusString,
                    job->text);
        }
        return 0;
    } else if (!strcmp(newJob.progs[0].argv[0], "fg") ||
               !strcmp(newJob.progs[0].argv[0], "bg")) {
        if (!newJob.progs[0].argv[1] || newJob.progs[0].argv[2]) {
            fprintf(stderr, "%s: exactly one argument is expected\n",
                    newJob.progs[0].argv[0]);
            return 1;
        }

        if (sscanf(newJob.progs[0].argv[1], "%%%d", &jobNum) != 1) {
            fprintf(stderr, "%s: bad argument '%s'\n",
                    newJob.progs[0].argv[0], newJob.progs[0].argv[1]);
            return 1;
        }

        for (job = jobList->head; job; job = job->next) 
            if (job->jobId == jobNum) break;

        if (!job) {
            fprintf(stderr, "%s: unknown job %d\n",
                    newJob.progs[0].argv[0], jobNum);
            return 1;
        }

        if (*newJob.progs[0].argv[0] == 'f') {
            /* Make this job the foreground job */

            if (tcsetpgrp(0, job->pgrp))
                perror("tcsetpgrp");
            jobList->fg = job;
        }

        /* Restart the processes in the job */
        for (i = 0; i < job->numProgs; i++) 
            job->progs[i].isStopped = 0;

        kill(-job->pgrp, SIGCONT);

        job->stoppedProgs = 0;
        
        return 0;
    }

    nextin = 0, nextout = 1;
    for (i = 0; i < newJob.numProgs; i++) {
        if ((i + 1) < newJob.numProgs) {
            pipe(pipefds);
            nextout = pipefds[1];
        } else {
            nextout = 1;
        }

        if (!(newJob.progs[i].pid = fork())) {
            signal(SIGTTOU, SIG_DFL);

            if (nextin != 0) {
                dup2(nextin, 0);
                close(nextin);
            }

            if (nextout != 1) {
                dup2(nextout, 1);
                close(nextout);
            }

            /* explicit redirections override pipes */
            setupRedirections(newJob.progs + i);

            execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
            fprintf(stderr, "exec() of %s failed: %s\n", 
                    newJob.progs[i].argv[0], 
                    strerror(errno));
            exit(1);
        }

        /* put our child in the process group whose leader is the
           first process in this pipe */
        setpgid(newJob.progs[i].pid, newJob.progs[0].pid);

        if (nextin != 0) close(nextin);
        if (nextout != 1) close(nextout);

        /* If there isn't another process, nextin is garbage 
           but it doesn't matter */
        nextin = pipefds[0];
    }

    newJob.pgrp = newJob.progs[0].pid;

    /* find the ID for the job to use */
    newJob.jobId = 1;
    for (job = jobList->head; job; job = job->next)
        if (job->jobId >= newJob.jobId)
            newJob.jobId = job->jobId + 1;

    /* add the job to the list of running jobs */
    if (!jobList->head) {
        job = jobList->head = malloc(sizeof(*job));
    } else {
        for (job = jobList->head; job->next; job = job->next);
        job->next = malloc(sizeof(*job));
        job = job->next;
    }

    *job = newJob;
    job->next = NULL;
    job->runningProgs = job->numProgs;
    job->stoppedProgs = 0;

    if (inBg) {
        /* we don't wait for background jobs to return -- append it 
           to the list of backgrounded jobs and leave it alone */

        printf("[%d] %d\n", job->jobId, 
               newJob.progs[newJob.numProgs - 1].pid);
    } else {
        jobList->fg = job;

        /* move the new process group into the foreground */
        
        if (tcsetpgrp(0, newJob.pgrp))
            perror("tcsetpgrp");
    }

    return 0;
}