Skip to content

Instantly share code, notes, and snippets.

@markjgap
Last active September 17, 2015 05:13
Show Gist options
  • Save markjgap/dfacab11c36f6b7845bf to your computer and use it in GitHub Desktop.
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.
#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