SHARE
TWEET

Untitled

a guest Oct 19th, 2019 94 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <signal.h>
  8.  
  9. #define BUFFER_SIZE 80
  10. #define HALF_BUFFER_SIZE 40
  11. #define ARGS_SIZE 32
  12.  
  13. // navigates to a destination from the current directory
  14. void cd(char* dest) {
  15.     if (chdir(dest) != 0) {
  16.         printf("changing directory to %s failed\n", dest);
  17.     } else {
  18.         char curr[200];
  19.         printf("directory changed to %s\n", getcwd(curr, 200));
  20.     }
  21. }
  22.  
  23. // prints out built in commands
  24. void help() {
  25.     printf("List of built-in commands:\n");
  26.     printf("cd\n");
  27.     printf("help\n");
  28.     printf("repeat\n");
  29.     printf("exit\n");
  30. }
  31.  
  32. // executes a bash command with given arguments
  33. void executeCommand(char** argv) {
  34.     if (execvp(argv[0], argv) == -1) {
  35.         // check for command without /bin (ie ./shell)
  36.         if (execvp(argv[0] + 5, argv) == -1) {
  37.             printf("%s is not a valid command!\n", argv[0]);
  38.             exit(1);
  39.         }
  40.     }
  41. }
  42.  
  43. // creates a signal handler for exiting via ctrl-c
  44. void sigintHandler(int sig) {
  45.     write(1, "\nmini-shell terminated\n", 24);
  46.     exit(0);
  47. }
  48.  
  49. // sets an array of strings with the first element being the command and the rest being args
  50. void setArgs(char* command, char* token, char** args, char* cmdPath) {
  51.     strcpy(cmdPath, "");
  52.     // concat the command to the /bin path
  53.     strcat(cmdPath, "/bin/");
  54.     strcat(cmdPath, command);
  55.     // first argument is the command
  56.     args[0] = cmdPath;
  57.     int i = 1;
  58.  
  59.     // Built in commands:
  60.     // cd command
  61.     if (!strcmp(command, "cd")) {
  62.         token = strtok(NULL, " ");
  63.         cd(token);
  64.         return;
  65.     }
  66.     // help command
  67.     if (!strcmp(command, "help")) {
  68.         help();
  69.         return;
  70.     }
  71.     // exit command
  72.     if (!strcmp(command, "exit")) {
  73.         exit(0);
  74.     }
  75.  
  76.     // Bash commands:
  77.     while (1) {
  78.         token = strtok(NULL, " ");
  79.         if (token != NULL) {
  80.             args[i] = (char*) malloc(sizeof(char) * strlen(token));
  81.             strcpy(args[i], token);
  82.             i++;
  83.         } else {
  84.             args[i] = NULL;
  85.             break;
  86.         }
  87.     }
  88. }
  89.  
  90. // parses a line of input for commands and acts accordingly
  91. void parse(char* input) {
  92.     char* inputCopy = (char*) malloc(sizeof(char) * strlen(input));
  93.     strcpy(inputCopy, input);
  94.     char* token = strtok(input, " ");
  95.     char* command = token;
  96.     // since the line limit is 80 bytes there has to be a limited number of arguments
  97.     char* args[ARGS_SIZE];
  98.     char cmdPath[16];
  99.  
  100.     // check for the repeat command
  101.     if (!strcmp(command, "repeat")) {
  102.         free(inputCopy);
  103.         // arg after 'repeat' is the number of times to repeat
  104.         token = strtok(NULL, " ");
  105.         if (token != NULL) {
  106.             int n = atoi(token);
  107.             // everything after n is the command to repeat
  108.             token = strtok(NULL, "");
  109.  
  110.             if (token != NULL) {
  111.                 int i;
  112.                 for (i = 0; i < n; i++) {
  113.                     // recursively call parse on the given command n times
  114.                     char* tokenCopy = (char*) malloc(sizeof(char) * strlen(token));
  115.                     strcpy(tokenCopy, token);
  116.  
  117.                     parse(tokenCopy);
  118.  
  119.                     free(tokenCopy);
  120.                 }
  121.             }
  122.             else {
  123.                 printf("repeat must take in a command to repeat\n");
  124.             }
  125.         }
  126.  
  127.         return;
  128.     }
  129.     // check if there is a pipe
  130.     else if (strchr(inputCopy, '|') != NULL) {
  131.         // take the first half of the string split by |
  132.         char* pipeToken = strtok(inputCopy, "|");
  133.         char* pipeTokenCopy = (char*) malloc(sizeof(char) * strlen(pipeToken));
  134.         strcpy(pipeTokenCopy, pipeToken);
  135.        
  136.         pipeToken = strtok(NULL, "|");
  137.  
  138.         char* firstCommand = strtok(pipeTokenCopy, " ");
  139.         setArgs(firstCommand, pipeTokenCopy, args, cmdPath);
  140.         free(pipeTokenCopy);
  141.  
  142.         int pid = fork();
  143.  
  144.         if (pid == 0) {
  145.             // set up pipe
  146.             int pipes[2];
  147.             pipe(pipes);
  148.             pid = fork();
  149.  
  150.             // child process
  151.             if (pid == 0) {
  152.                 // write to standard output and pipe it
  153.                 close(pipes[0]);
  154.                 dup2(pipes[1], 1);
  155.                 // execute first command
  156.                 executeCommand(args);
  157.             }
  158.             // parent process
  159.             else {
  160.                 // read what was piped from standard output as input
  161.                 close(pipes[1]);
  162.                 dup2(pipes[0], 0);
  163.  
  164.                 // execute second command
  165.                 char* pipeTokenCopy2 = (char*) malloc(sizeof(char) * strlen(pipeToken));
  166.                 strcpy(pipeTokenCopy2, pipeToken);
  167.  
  168.                 char* secondCommand = strtok(pipeTokenCopy2, " ");
  169.                 setArgs(secondCommand, pipeTokenCopy2, args, cmdPath);
  170.                 free(pipeTokenCopy2);
  171.  
  172.                 executeCommand(args);
  173.             }
  174.         }
  175.         else {
  176.             wait(NULL);
  177.         }
  178.     } else {
  179.         setArgs(command, token, args, cmdPath);
  180.         if (fork() == 0) {
  181.             executeCommand(args);
  182.         }
  183.         else {
  184.             wait(NULL);
  185.         }
  186.     }
  187.  
  188.     // free malloc'd variables
  189.     free(inputCopy);
  190.     int a;
  191.     for (a = 1; a < ARGS_SIZE; a++) {
  192.         if (args[a] != NULL) free(args[a]);
  193.         else break;
  194.     }
  195. }
  196.  
  197. int main() {
  198.     // install signal handler
  199.     signal(SIGINT, sigintHandler);
  200.  
  201.     char buffer[BUFFER_SIZE];
  202.  
  203.     // main loop for input
  204.     while (1) {
  205.         printf("mini-shell>");
  206.         scanf(" %[^\n]", buffer);
  207.         parse(buffer);
  208.     }
  209.  
  210.     return 0;
  211. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top