Last active
September 17, 2015 05:13
-
-
Save markjgap/dfacab11c36f6b7845bf to your computer and use it in GitHub Desktop.
Simulates a Linux shell that can execute built-in commands like changing directories or deleting files as well as customized commands like listing command history as a foreground or background process.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include "parse_args.h" | |
#include "history_queue.h" | |
/* | |
* Simulates a Linux shell that can execute simple commands as foreground or background processes | |
*/ | |
void signal_handler(int sig); // defines a signal handler | |
int main( ){ | |
char cmdline[MAXLINE]; | |
char *argv[MAXARGS]; | |
int bg; | |
int cmd_num = 1; | |
// signal handler for SIGCHLD | |
void signal_handler(int sig){ | |
while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {} | |
} | |
// registers SIGCHLD to be handled by signal_handler | |
signal(SIGCHLD, signal_handler); | |
while(1) { | |
// print the shell prompt | |
fprintf(stdout, "ttsh> "); | |
fflush(stdout); | |
// read in the next command entered by the user | |
if ((fgets(cmdline, MAXLINE, stdin) == NULL) | |
&& ferror(stdin)) { | |
perror("fgets error"); | |
} | |
if (feof(stdin)) { /* End of file (ctrl-d) */ | |
fflush(stdout); | |
exit(0); | |
} | |
HistoryEntry he; // history queue | |
he.cmd_num = cmd_num; // history process id | |
strcpy(he.cmdline, cmdline); | |
bg = parseArguments(cmdline, argv); | |
// if no input will not exit shell. | |
if(argv[0] == NULL){ | |
printf("No command entered\n"); | |
continue; | |
} | |
// if exit, shell will exit | |
else if(!strcmp(argv[0], "exit")){ | |
exit(0); | |
} | |
// if history, will add to history queue and print last 10 commands | |
else if(!strcmp(argv[0], "history")){ | |
add_queue(he); | |
cmd_num++; | |
print_queue(); | |
} | |
// if !<num>, will execute command with a matching command ID | |
// from command history. | |
else if(argv[0][0] == '!'){ | |
// check to make sure proper usage (i.e. !5) | |
if (strlen(cmdline) > 2){ | |
char num[strlen(cmdline)]; | |
int n; | |
for(n=1; n <= strlen(cmdline); n++){ | |
num[n-1] = (argv[0][n]); | |
} | |
unsigned int i = atoi(num); | |
char* cmdHist = commandLine_history(i); | |
strcpy(he.cmdline, commandLine_history(i)); | |
bg = parseArguments(commandLine_history(i), argv); | |
if(!strcmp(cmdHist, "History ID not found!\n")){ | |
printf("ID not found: %s", cmdline); | |
} | |
else if(!strcmp(argv[0], "history")){ | |
add_queue(he); | |
cmd_num++; | |
print_queue(); | |
} | |
else { | |
int pid = fork(); | |
int ret; | |
if(pid == 0){ | |
ret = execvp(argv[0], argv); | |
if(ret == -1){ | |
exit(0); | |
} | |
} | |
// if '&' in command line | |
// run process in background | |
if(bg == 1){ | |
kill(pid, SIGCHLD); | |
} | |
// else run process in foreground | |
else waitpid(pid, NULL, 0); | |
cmd_num++; | |
add_queue(he); | |
} | |
} | |
// improper call to !<num> | |
else { | |
printf("Invalid history entry\n"); | |
printf("Usage: !<num>\n"); | |
printf("Example: !5\n"); | |
} | |
} | |
// run built in shell commands | |
else { | |
int ret; | |
add_queue(he); | |
int pid = fork(); | |
if(pid == 0){ | |
ret = execvp(argv[0], argv); | |
if(ret == -1){ | |
printf("%s: Command not found\n", argv[0]); | |
exit(0); | |
} | |
} | |
// if '&' included in command line | |
// run process in background | |
if(bg == 1){ | |
kill(pid, SIGCHLD); | |
} | |
// else run process in foreground | |
else waitpid(pid, NULL, 0); | |
cmd_num++; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment