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.
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System
Operating System