UNIX Commands Implemented in C

2020-07-25 10:44发布

问题:

For my Operating Systems class I have an assignment due that is built onto a previous assignment. Unfortunately my previous project doesn't work correctly in addition to me not knowing where I need to start for the next project. The code which I have below is suppose to mimic a simple UNIX/Linux shell with some additional commands that cannot be performed with execvp: background processing via the ampersand operator, the 'jobs' shell command: list the pids of all living child processes (i.e. not ones that have terminated), "reaping" of "zombie" processes, and the 'cd' shell command: change the shell's working directory.

I believe, everything but the "jobs" command, and "cd" command work, but I'm not sure why these two don't.

The next assignment is to add some I/O redirection in the form of "mysh$ cmd arg1 arg2 argN > file.out" which I don't know where to even really begin...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>

int main(int argc, char **argv) {
    char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
    int jobs[100];
    int jobList = 0;
    int background;
    ssize_t rBytes;
    int aCount;
    pid_t pid;
    int status;
    while(!feof(stdin)) {
        pid = waitpid(-1, &status, WNOHANG);
        if (pid > 0)
        printf("waitpid reaped child pid %d\n", pid);
        write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
        rBytes = read(0, bBuffer, BUFSIZ-1);
        if(rBytes == -1) {
        perror("read");
        exit(1);
    }

    bBuffer[rBytes-1] = '\0';
    if(!strcasecmp(bBuffer, "exit")){ 
        exit(0);
    }

    sPtr = bBuffer;
    aCount = 0;
    do {
        aPtr = strsep(&sPtr, " ");
        pArgs[aCount++] = aPtr;
    } while(aPtr);
        background = (strcmp(pArgs[aCount-2], "&") == 0);
        if (background)
        pArgs[aCount-2] = NULL;

        if (strlen(pArgs[0]) > 1) {
            pid = fork();
            if (pid == -1) {
                perror("fork");
                exit(1);
            } else if (pid == 0) {
                jobs[jobList] = pid;
                jobList++;

                if(!strcasecmp(pArgs[0], "jobs")){                                         
                    for(int i; i<jobList; i++) {
                        if(kill(jobs[i],0)==0){
                            printf(jobs[i]);    
                        }
                        printf("these are jobs\n");
                        exit(1);
                    }
                    if(!strcasecmp(pArgs[0], "cd")){ 
                        int ret;
                        if (!pArgs[1])
                            strcpy(bBuffer, "pwd");
                        ret = chdir(pArgs[1]);
                        strcpy(bBuffer, "pwd");
                        exit(1);
                    }                                
                    fclose(stdin);
                    fopen("/dev/null", "r");
                    execvp(pArgs[0], pArgs);
                    exit(1);
                } else if (!background) {
                    pid = waitpid(pid, &status, 0);
                    if (pid > 0)
                        printf("waitpid reaped child pid %d\n", pid);
                }
        }
    }
    return 0;
}

回答1:

First you;ll want to parse your line and detect that you need to redirect to a file. So let;s say you use strsep or whatever and you found out output is going to file.out or input is coming from file.in.

At this point you want to redirect output using dup / dup2. For example, to redirect STDOUT:

int
do_redirect(int fileno, const char *name)
{
    int newfd;

    switch (fileno) {
    case STDOUT_FILENO:
        newfd = open(name, O_WRONLY | O_CREAT, S_IRUSR | S_IRUSR);
        break;
    }
    if (newfd == -1) {
        perror("open");
        return -1;
    }

    return dup2(fileno, newfd);
}
/* ... */


pid = fork();
do_redirect(STDOUT_FILENO, name);

Things to note:

  • I didn't test the code - it might not even compile
  • I didn't do much error-checking - you should (the way I did for open)
  • You need to implement STDIN_FILENO redirection on your own
  • Note how I used a separate function, your main is WAY to large as it is
  • Your code has something like 7 levels of indentation - ever heard about arrow code ?


回答2:

Since this is homework, I will not give you code directly.

dup, dup2 and freopen are good to look at for input/output redirection.

fork for starting a concurrent process (ampersand)

You are on the right track using waitpid to reap child processes.