C - 自定义shell中的后台进程

时间:2017-10-10 04:38:26

标签: c linux shell

所以我正在尝试创建一个自定义shell,因为我将在下学期学习操作系统课程,并希望获得一些先发优势 - 并且制作一个自定义shell看起来很常见去做。所以,我正在试图弄清楚如何执行后台进程,而我真的很难搞清楚如何执行。如果有人能够深入了解我如何能够实施后台流程(显然使用“&”符号),我们将不胜感激。

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

#define MAX_SIZE 20

int getArgs(char *buffer){
int count = 1;
for (int i = 0; i < strlen(buffer); i++){
    if (buffer[i] == ' ') count++;
}
return count;
}

void printError(){
char errorMessage[30] = "An error has occurred\n";
write(STDERR_FILENO, errorMessage, strlen(errorMessage)); 
}

int splitArg(char *buffer, char *args[], int numArgs){
char *tmp = strtok(buffer, " \n");
int i = 0, pipeOrRedir = 0; //pipeOrRedir will store -1 if a redirect ; number position in args if a pipe   

//Traverse args, tokenize at space, newline.
while (tmp != NULL && i < MAX_SIZE -1){
    if (strcmp(tmp, ">") == 0 && i == (numArgs-2)) pipeOrRedir = -1;
    else if (strcmp(tmp, "|") == 0) pipeOrRedir = i;

    //Create args[] from input, tokenize at space, newline
    args[i] = tmp;
    tmp = strtok(NULL, " \n");
    i++;
}
args[i] = NULL;
return pipeOrRedir;
}

int main(int argc, char *argv[]){
char buffer[1024];
int numArgs, output, status, pipeOrRedir;
int count = 1;
pid_t pid;

while(1){
    printf("shell (%d)> ", count);
    fgets(buffer, 1024, stdin); //Get input
    if (strlen(buffer) > 128){
        printError();
        printf("mysh (%d)> ", count);
    }
    numArgs = getArgs(buffer); //Get number of arguments in the command
    char *args[numArgs + 1]; //Array of args (1 larger to hold NULL for execvp
    pipeOrRedir = splitArg(buffer, args, numArgs);

    //Ensure we don't have empty command line
    if (strcmp(buffer, "\n") == 0){
        printError();
        printf("mysh (%d)> ", count);
    }

    //INTERNAL COMMANDS

    //"exit"
    if (strcmp("exit", args[0]) == 0){
        if (numArgs != 1) printError();
        else exit(0); //Successful exit
    }

    //"cd"
    else if (strcmp("cd", args[0]) == 0){
        if (args[1] == NULL) chdir(getenv("HOME"));
        else{
            if (chdir(args[1]) == -1) printError();
        }
    }

    //"pwd"
    else if (strcmp("pwd", args[0]) == 0){
        //printf("%d\n", numArgs);
        if (numArgs != 1) printError();
        else printf("%s\n", getcwd(buffer, 1024));
    }

    //EXTERNAL COMMANDS
    else{
        pid = fork();
        if (pid == 0){
            //Inside child

            //Arguments for execvp
            char *prev[pipeOrRedir+1];
            char *post[numArgs - pipeOrRedir];
            prev[pipeOrRedir] = NULL;
            post[numArgs - pipeOrRedir + 1] = NULL;

            //REDIRECTION
            if (pipeOrRedir == -1){
                output = open(args[numArgs - 1], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);

                if (output < 0) printError();

                //Change output stream stdout -> file
                if (dup2(output, 1) == -1) printError();
                args[numArgs - 1] = NULL;
                args[numArgs - 2] = NULL;
            }
            //PIPING
            else if (pipeOrRedir > 0){

                //Set up pipe
                if (pipeOrRedir == numArgs - 1) printError();

                for (int i = 0; i < pipeOrRedir; i++){
                    prev[i] = args[i];
                }

                for (int j = 0; j < numArgs - pipeOrRedir; j++){
                    post[j] = args[j + pipeOrRedir + 1];
                }
            }

            //EXECVP
            if (pipeOrRedir < 1){
                if (execvp(args[0], args) == -1) printError();
                //If piping
                int pipeFileDescriptor[2];
                int pipeID;

                pipe(pipeFileDescriptor);
                pipeID = fork();

                //Run 1st command, gives us output
                if (pipeID > 0){
                    close(pipeFileDescriptor[0]); //Input pipe unused
                    dup2(pipeFileDescriptor[1], 1); //Close STDOUT, replace with pipe

                    if (execvp(prev[0], prev) == -1) printError();

                    close(pipeFileDescriptor[1]);
                    exit(0);
                }

                //Run 2nd command, takes input
                else{
                    close(pipeFileDescriptor[1]);
                    dup2(pipeFileDescriptor[0], 0);
                    if (execvp(post[1], post) == -1) printError();
                    close(pipeFileDescriptor[0]);
                    exit(0);
                }
            }
            exit(1);
        }
        else wait(&status);
    }
    count++;
}
close(output);
exit(0);
}

0 个答案:

没有答案