×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Shell Creation Assignment Solution in Linux

July 11, 2024
Dr. Alice Davies
Dr. Alice
🇺🇸 United States
Operating System
Dr. Alice Davies, an alumna of Massachusetts Institute of Technology, United States, brings 15 years of experience to Operating System assignments. With a Ph.D. from MIT, her expertise ensures tailored solutions for student success.
Key Topics
  • New Shell Creation
Tip of the day
Familiarize yourself with OCaml's pattern matching; it simplifies handling recursive data structures like lists and trees, making your code concise and easier to debug.
News
In 2024, Girls Who Code introduced a Data Science + AI track in their free summer programs for high school students, fostering skills in cybersecurity and creative coding​

New Shell Creation

Question:

Construct a new Linux shell. Your shell will be called msh (Merrimack Shell).

Solution:

#include < stdio.h> #include < unistd.h> #include < sys times.h=""> #include < time.h> #include < dirent.h> #include < stdio.h> #include < string.h> #include < unistd.h> #include < stdlib.h> #include < ctype.h> #include < sys wait.h=""> #include < sys types.h=""> #include < sys wait.h=""> #include < fcntl.h> #include < stdbool.h> #include < time.h> #include < sys time.h=""> #include < sys stat.h=""> #define MAX_LINE 80 /* The maximum length command */ #define ANSI_COLOR_RESET "\x1b[0m" #define ANSI_COLOR_YELLOW "\x1b[33m" #define ANSI_COLOR_GREEN "\x1b[92m" #define ANSI_COLOR_BLUE "\x1b[94m" #define pipenow (alternate ? _file : file) #define futurepipe (alternate ? file : _file) #define READ 0 #define WRITE 1 #define CHILD 0 #define ERROR -1 #define PARENT default #define previouspipe futurepipe typedef enum { begining, center, ending, pipebool } pipestruct; /***************************** * We will use 2 pipes and * * alternate between them * * for to acheive many pipes * *****************************/ typedef int pipe_io[2]; char **completecmd, **futurecmd, **cmd; char input_file[512], output_file[512], error_file[512]; size_t i, semicolons, next, pipes; bool cmdline, background, alternate; int infile, outfile, errfile; pipe_io file, _file; pid_t pid; void executeWithPipes(char* cmds); void fillPipes(); void startWithPipe(pipestruct pipetype); void redirect(); void redirect_in(size_t index); void redirect_out(size_t index); void redirect_err(size_t index); void start(char** cmd, pipestruct pipetype); void clear(char** cmd); void fillPipes() { size_t i, j; pipestruct pipetype = begining; alternate = false; for (i = 0; cmd[i] != NULL; i++) if (!strcmp(cmd[i], "|")) { clear(&cmd[i]); while (true) { // run a pipe than decrease one from the sum if (pipe(pipenow) != ERROR) { startWithPipe(pipetype); pipes--; if (*cmd == NULL) return; for (j = 0; cmd[j] != NULL; j++) if (!strcmp(cmd[j], "|")) clear(&cmd[j]); ; //if it's the last pipe if (!(pipes > 0)) { startWithPipe(ending); return; } alternate = alternate ? false : true; } else perror("pipe()"); pipetype = center; } }; } void startWithPipe(pipestruct pipetype) { while (*cmd != NULL) { start(cmd, pipetype); // free all old commands for (i = 0; i < next; i++) if (cmd != NULL) clear(&cmd[i]); ; cmd = &cmd[next]; // if there is more pipes if (pipes > 0) break; } } int child_pid = 0; int killall=0; time_t startinternal; int timedout = 0; int timedoutsec = 0; void start(char** cmd, pipestruct pipetype) { void (*getfuturecmd)() = redirect; /* fork a child process*/ switch (pid = fork()) { case ERROR: perror("fork()"); break; case CHILD: if (*cmd == NULL) exit(EXIT_SUCCESS); switch (pipetype) { /* if it's the first element in pipes */ case begining: dup2(pipenow[WRITE], STDOUT_FILENO); break; /* if it's the middle element in pipes */ case center: dup2(previouspipe[READ], STDIN_FILENO); dup2(pipenow[WRITE], STDOUT_FILENO); break; /* if it's the last element in pipes */ case ending: dup2(pipenow[READ], STDIN_FILENO); default: break; } redirect(); execvp(*cmd, cmd); perror(*cmd); _exit(EXIT_FAILURE); /* if it's the parent process decide wether to wait based on & */ PARENT: child_pid = pid; switch (pipetype) { case begining: close(pipenow[WRITE]); break; case center: close(previouspipe[READ]); close(pipenow[WRITE]); break; case ending: close(pipenow[READ]); default: break; } if (!background) { if (timedout == 1) { alarm(timedoutsec); int state; waitpid(pid, &state, 0); printf("(%ld) WIFEXITED: %d\n", time(0), WIFEXITED(state)); } else while (wait(NULL) > 0) ; } getfuturecmd(); } } void redirect() { size_t i; for (i = 0; cmd[i] != NULL; i++) { if (!strcmp(cmd[i], "<")) redirect_in(i++); else if (!strcmp(cmd[i], ">")) redirect_out(i++); else if (!strcmp(cmd[i], "2>")) redirect_err(i++); } if (pipes > 0) i++; next = i; } void redirect_in(size_t i) { if (pid == CHILD) { clear(&cmd[i]); strcpy(input_file, cmd[++i]); clear(&cmd[i]); infile = open(input_file, O_RDONLY); if (infile != ERROR) { dup2(infile, STDIN_FILENO); close(infile); } else { perror(input_file); exit(EXIT_SUCCESS); } } } void redirect_out(size_t i) { if (pid == CHILD) { clear(&cmd[i]); strcpy(output_file, cmd[++i]); clear(&cmd[i]); outfile = open(output_file, O_RDWR | O_CREAT, 0777); if (outfile != ERROR) { dup2(outfile, STDOUT_FILENO); close(outfile); } else { perror(output_file); exit(EXIT_SUCCESS); } } } void redirect_err(size_t i) { if (pid == CHILD) { clear(&cmd[i]); strcpy(error_file, cmd[++i]); clear(&cmd[i]); errfile = open(error_file, O_RDWR | O_CREAT, 0777); if (errfile != ERROR) { dup2(errfile, STDERR_FILENO); close(errfile); } else { perror(error_file); exit(EXIT_SUCCESS); } } } void executeWithPipes(char* cmds) { size_t max = 1024; char* token; i = 0; semicolons = 0; completecmd = malloc(sizeof(char*) * max); token = strtok(cmds, " "); while (token != NULL) { if (!strcmp(token, ";")) { completecmd[i] = NULL; semicolons++; } else { completecmd[i] = malloc(sizeof(char) * (strlen(token) + 1)); strcpy(completecmd[i], token); } token = strtok(NULL, " "); if (i == max) completecmd = realloc(completecmd, max *= 2); i++; } completecmd[i] = NULL; if (!strcmp(completecmd[--i], "&")) { background = true; clear(&completecmd[i]); } else background = false; cmd = completecmd; size_t i; while (true) { pipes = 0; for (i = 0; cmd[i] != NULL; i++) if (!strcmp(cmd[i], "|")) pipes++; ; if (pipes > 0) fillPipes(); else startWithPipe(pipebool); if (semicolons > 0) { cmd = &cmd[1]; semicolons--; } else break; } free(completecmd); } void clear(char** cmd) { free(*cmd); *cmd = NULL; } char** splitstring(char* strs, int* n_spaces) { char** res = NULL; *n_spaces = 0; char* str = (char*)malloc(strlen(strs) + 1); strcpy(str, strs); char* p = strtok(str, " "); /* split string and append tokens to 'res' */ while (p) { *n_spaces = *n_spaces + 1; res = (char**)realloc(res, sizeof(char*) * (*n_spaces)); if (res == NULL) exit(-1); /* memory allocation failed */ res[*n_spaces - 1] = p; p = strtok(NULL, " "); } /* realloc one extra element for the last NULL */ res = (char**)realloc(res, sizeof(char*) * (*n_spaces + 1)); res[*n_spaces] = 0; return res; } void process_terminated(pid_t child_pid) { printf("\n\nterminated\n\n"); } static char* util_cat(char* dest, char* end, const char* str) { while (dest < end && *str) *dest++ = *str++; return dest; } size_t join_str(char* out_string, size_t out_bufsz, const char* delim, char** chararr) { char* ptr = out_string; char* strend = out_string + out_bufsz; while (ptr < strend && *chararr) { ptr = util_cat(ptr, strend, *chararr); chararr++; if (*chararr) ptr = util_cat(ptr, strend, delim); } return ptr - out_string; } time_t timepast24h; time_t timenow; time_t startime; time_t endtime; void printDate(time_t t) { char date[16]; strftime(date, 16, "%d-%m-%y %H:%M", localtime(&t)); printf("Date : %s\n", date); } void printDateraw(time_t t) { char date[36]; strftime(date, 26, "%d-%m-%y " ANSI_COLOR_GREEN " %H:%M " ANSI_COLOR_RESET, localtime(&t)); printf("%s", date); } void printDateraw1(time_t t) { char date[36]; strftime(date, 26, "%d-%m-%y %H:%M ", localtime(&t)); printf("%s", date); } void printHour(time_t t) { char date[16]; strftime(date, 16, "%H:%M", localtime(&t)); printf("Date : %s", date); } int n = 0; void mtime_cmd(char* basePath, const int root, time_t starttime1, time_t endtime1, int iprint) { if (timedout==1 && time(NULL) > startinternal + timedout) return; int i; char path[1000]; struct dirent* dp; DIR* dir = opendir(basePath); if (!dir) return; while ((dp = readdir(dir)) != NULL) { if (timedout==1 && time(NULL) > startinternal + timedout) return; if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) { struct stat attr; char path1[1000]; strcpy(path1, basePath); strcat(path1, "/"); strcat(path1, dp->d_name); stat(path1, &attr); struct tm* ts = localtime(&attr.st_mtime); if (attr.st_mtime > starttime1 && attr.st_mtime <= endtime1) { printf(ANSI_COLOR_BLUE); if (iprint == 1) printf(" "); if (iprint == 1) printDateraw1(mktime(ts)); if (iprint == 1) printf(" --> %s/%s", basePath, dp->d_name); if (iprint == 1) printf("\n"); printf(ANSI_COLOR_RESET); for (i = 0; i < root; i++) { /*if (i%2 == 0 || i == 0) printf("│"); else printf(" ");*/ } //printf("├─%s\n", dp->d_name); n++; } strcpy(path, basePath); strcat(path, "/"); strcat(path, dp->d_name); mtime_cmd(path, root + 2, starttime1, endtime1, iprint); } } closedir(dir); } int main() { int i, j; int sizeCmd = 0; int measure = 0; char cmd[MAX_LINE / 2 + 1]; /* command line arguments */ int should_run = 1, towait = 1; /* flag to determine when to exit program */ char s[256]; int internalcmd = 0; /*******************/ char** history = NULL; int sz_history = 0; /*******************/ while (should_run) { internalcmd = 0; timedout = 0; measure = 0; printf(ANSI_COLOR_GREEN); printf("\nmsh> "); printf(ANSI_COLOR_RESET); int ret = scanf(" %[^\n]s", cmd); //CTRL+D if (ret == EOF) return 0; if (strcmp(cmd, "!!") == 0) { if (sz_history > 0) { strcpy(cmd, history[sz_history - 1]); //history[ sz_history-1] = NULL; printf(ANSI_COLOR_BLUE); printf("\n%s\n", cmd); printf(ANSI_COLOR_RESET); } else { printf("\nNo commands in history.\n"); internalcmd = 1; } }else if(cmd[0]=='!') { cmd[0]='0'; int n=atoi(cmd); if (sz_history >= n) { strcpy(cmd, history[sz_history - n]); //history[ sz_history-1] = NULL; printf(ANSI_COLOR_BLUE); printf("\n%s\n", cmd); printf(ANSI_COLOR_RESET); } else { printf("\nNo commands in history.\n"); internalcmd = 1; } } else { sz_history = sz_history + 1; history = (char**)realloc(history, sizeof(char*) * (sz_history + 1)); char* str = (char*)malloc(strlen(cmd) + 1); strcpy(str, cmd); history[sz_history - 1] = str; history[sz_history] = 0; } redo: killall=0; internalcmd = 0; char** res = splitstring(cmd, &sizeCmd); if (strcmp(res[0], "exit") == 0 || strcmp(res[0], "quit") == 0) { should_run = 0; internalcmd = 1; } printf(ANSI_COLOR_BLUE); if (strcmp(res[0], "pwd") == 0) { printf("%s\n", getcwd(s, 100)); internalcmd = 1; } printf(ANSI_COLOR_RESET); if (strcmp(res[0], "cd") == 0) { if (sizeCmd > 1 && strlen(res[1]) > 0) chdir(res[1]); internalcmd = 1; } towait = 1; if (sizeCmd > 0 && strlen(res[sizeCmd - 1]) > 0) { char c = res[sizeCmd - 1][strlen(res[sizeCmd - 1]) - 1]; if (c == '&') { towait = 0; res[sizeCmd - 1][strlen(res[sizeCmd - 1]) - 1] = 0; } } if (strlen(res[sizeCmd - 1]) == 0) res[sizeCmd - 1] = 0; printf(ANSI_COLOR_RESET); if (internalcmd == 0) { struct tms times_start, times_end; clock_t times_start_retval, times_end_retval; if ((times_start_retval = times(×_start)) == -1) { perror("starting times"); return -1; } struct timeval start, end; gettimeofday(&start, NULL); clock_t t; t = clock(); /************************/ if (timedout == 1) { char path1[1000] = ""; for (j = 2; j < sizeCmd; j++) { strcat(path1, res[j]); strcat(path1, " "); } executeWithPipes(path1); } else if (measure == 1) { char path1[1000] = ""; for (j = 1; j < sizeCmd; j++) { strcat(path1, res[j]); strcat(path1, " "); } executeWithPipes(path1); } else executeWithPipes(cmd); /************************/ t = clock() - t; gettimeofday(&end, NULL); double time_taken = (1000 * (double)t) / CLOCKS_PER_SEC; long seconds = (end.tv_sec - start.tv_sec); long micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); if ((times_end_retval = times(×_end)) == -1) { perror("ending timer"); return -1; } if (measure == 1) { printf("\nCPU Time elpased is %f milliseconds \n", time_taken); printf("Wall Time elpased is %f milliseconds ", (double)micros / 1000); printf("\nSystem Time elpased is %f milliseconds ", (double)times_end.tms_cstime - times_start.tms_cstime / CLOCKS_PER_SEC); } } free(res); fflush(stdout); } return 0; }

Related Samples

Explore our free operating system assignment samples showcasing comprehensive solutions and insights into various OS concepts. Ideal for understanding practical implementations and enhancing your learning experience.