Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.73 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement