Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <signal.h>
- #define BUFFER_SIZE 80
- #define HALF_BUFFER_SIZE 40
- #define ARGS_SIZE 32
- // navigates to a destination from the current directory
- void cd(char* dest) {
- if (chdir(dest) != 0) {
- printf("changing directory to %s failed\n", dest);
- } else {
- char curr[200];
- printf("directory changed to %s\n", getcwd(curr, 200));
- }
- }
- // prints out built in commands
- void help() {
- printf("List of built-in commands:\n");
- printf("cd\n");
- printf("help\n");
- printf("repeat\n");
- printf("exit\n");
- }
- // executes a bash command with given arguments
- void executeCommand(char** argv) {
- if (execvp(argv[0], argv) == -1) {
- // check for command without /bin (ie ./shell)
- if (execvp(argv[0] + 5, argv) == -1) {
- printf("%s is not a valid command!\n", argv[0]);
- exit(1);
- }
- }
- }
- // creates a signal handler for exiting via ctrl-c
- void sigintHandler(int sig) {
- write(1, "\nmini-shell terminated\n", 24);
- exit(0);
- }
- // sets an array of strings with the first element being the command and the rest being args
- void setArgs(char* command, char* token, char** args, char* cmdPath) {
- strcpy(cmdPath, "");
- // concat the command to the /bin path
- strcat(cmdPath, "/bin/");
- strcat(cmdPath, command);
- // first argument is the command
- args[0] = cmdPath;
- int i = 1;
- // Built in commands:
- // cd command
- if (!strcmp(command, "cd")) {
- token = strtok(NULL, " ");
- cd(token);
- return;
- }
- // help command
- if (!strcmp(command, "help")) {
- help();
- return;
- }
- // exit command
- if (!strcmp(command, "exit")) {
- exit(0);
- }
- // Bash commands:
- while (1) {
- token = strtok(NULL, " ");
- if (token != NULL) {
- args[i] = (char*) malloc(sizeof(char) * strlen(token));
- strcpy(args[i], token);
- i++;
- } else {
- args[i] = NULL;
- break;
- }
- }
- }
- // parses a line of input for commands and acts accordingly
- void parse(char* input) {
- char* inputCopy = (char*) malloc(sizeof(char) * strlen(input));
- strcpy(inputCopy, input);
- char* token = strtok(input, " ");
- char* command = token;
- // since the line limit is 80 bytes there has to be a limited number of arguments
- char* args[ARGS_SIZE];
- char cmdPath[16];
- // check for the repeat command
- if (!strcmp(command, "repeat")) {
- free(inputCopy);
- // arg after 'repeat' is the number of times to repeat
- token = strtok(NULL, " ");
- if (token != NULL) {
- int n = atoi(token);
- // everything after n is the command to repeat
- token = strtok(NULL, "");
- if (token != NULL) {
- int i;
- for (i = 0; i < n; i++) {
- // recursively call parse on the given command n times
- char* tokenCopy = (char*) malloc(sizeof(char) * strlen(token));
- strcpy(tokenCopy, token);
- parse(tokenCopy);
- free(tokenCopy);
- }
- }
- else {
- printf("repeat must take in a command to repeat\n");
- }
- }
- return;
- }
- // check if there is a pipe
- else if (strchr(inputCopy, '|') != NULL) {
- // take the first half of the string split by |
- char* pipeToken = strtok(inputCopy, "|");
- char* pipeTokenCopy = (char*) malloc(sizeof(char) * strlen(pipeToken));
- strcpy(pipeTokenCopy, pipeToken);
- pipeToken = strtok(NULL, "|");
- char* firstCommand = strtok(pipeTokenCopy, " ");
- setArgs(firstCommand, pipeTokenCopy, args, cmdPath);
- free(pipeTokenCopy);
- int pid = fork();
- if (pid == 0) {
- // set up pipe
- int pipes[2];
- pipe(pipes);
- pid = fork();
- // child process
- if (pid == 0) {
- // write to standard output and pipe it
- close(pipes[0]);
- dup2(pipes[1], 1);
- // execute first command
- executeCommand(args);
- }
- // parent process
- else {
- // read what was piped from standard output as input
- close(pipes[1]);
- dup2(pipes[0], 0);
- // execute second command
- char* pipeTokenCopy2 = (char*) malloc(sizeof(char) * strlen(pipeToken));
- strcpy(pipeTokenCopy2, pipeToken);
- char* secondCommand = strtok(pipeTokenCopy2, " ");
- setArgs(secondCommand, pipeTokenCopy2, args, cmdPath);
- free(pipeTokenCopy2);
- executeCommand(args);
- }
- }
- else {
- wait(NULL);
- }
- } else {
- setArgs(command, token, args, cmdPath);
- if (fork() == 0) {
- executeCommand(args);
- }
- else {
- wait(NULL);
- }
- }
- // free malloc'd variables
- free(inputCopy);
- int a;
- for (a = 1; a < ARGS_SIZE; a++) {
- if (args[a] != NULL) free(args[a]);
- else break;
- }
- }
- int main() {
- // install signal handler
- signal(SIGINT, sigintHandler);
- char buffer[BUFFER_SIZE];
- // main loop for input
- while (1) {
- printf("mini-shell>");
- scanf(" %[^\n]", buffer);
- parse(buffer);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement