+1 678 648 4277 

Use our Linux shell in C assignment samples for revision.

Not decided on who to hire to complete your Linux shell in C assignment? The below provided Linux shell in C assignment sample will help you make a decision. One of our experts prepared the sample, and it shows what to expect when you hire an expert from us to complete your assignment. Therefore, if you are looking for quality Linux shell in C assignment help, submit your assignment here immediately.

Table Of Contents
  • Linux Shell in C Assignment Sample

Linux Shell in C Assignment Sample

The regular command line shell is called BASH and you will be writing a replacement. You need to parse the command line, and call the external function. The commands cd and pwd should be implemented as internal commands (cd = change directory, pwd = print working directory). If & is present in the command then the process should be run in the background. Support > for redirect output to a file, and >> to redirect output to a file (in append mode). Add support for < redirecting input from stdin, and the | character is used to direct output from one function to the input from another. For more C programming assignment help contact us for a quote.

Solution:

cshell.c

//
// cshell.c
//

#include
#include
#include
#include
#include
#include
#include
#include

#include

/* CANNOT BE CHANGED */
#define BUFFERSIZE 256
/* ——————–*/
#define PROMPT “myShell >> ”
#define PROMPTSIZE sizeof(PROMPT)

/* Structure used to save command data */
typedef struct
{
char **argv;
int argc;
int background;
char redir; /* redirection type 0 = no redirection, 1 = < , 2= >, 3 = >> */
char *redir_file; /* file to use for redirection if not NULL*/
int pipe_fd[2]; /* pipe connections */
}command_t;

/* Structure used to save an array of commands for the history */
typedef struct
{
char **commands;
int n_commands;
}history_t;

/*
Reads a char from stdin without blocking, if no character is ready returns 0
*/
char
_getch(){
int c;
static struct termios oldt, newt;

tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
newt.c_cc[VTIME] = 1;
newt.c_cc[VMIN] = 0;
tcsetattr( STDIN_FILENO, TCSANOW, &newt);

if(read(STDIN_FILENO, &c, 1) != 1) /* read one char */
c = 0;
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return c;
}

/*
Prints a message directly on the screen (avoid buffering)
*/
void
print(char *msg)
{
write(STDOUT_FILENO, msg, strlen(msg));
}

/*
Clears the current line and prints the prompt again
*/
void
reprint_prompt(char *prompt)
{
print(“\r\x1b[2K”); /* clear all line */
print(prompt); /* show prompt */
}

/*
Reads a line, handles up and down arrow commands to browse history, ESC to
clear the input and Del to delete characters
*/
void
read_line(char *buffer, int max_len, char *prompt, history_t *history)
{
int i, end;
char c, d, e;
int cur_history;

cur_history = history->n_commands;

i = 0;
end = 0;
while(!end)
{
while(!(c = _getch()));
if (c == 27) /* escape key */
{
if ((d = _getch()) != 0) /* second escape code*/
{
e = _getch(); /* third escape code*/
if (e == 0x41 && cur_history > 0) /* up key */
{
cur_history–; /* display previous command in history */
reprint_prompt(prompt);
strcpy(buffer, history->commands[cur_history]);
print(buffer);
i = strlen(buffer);
}
if (e == 0x42) /* down key */
{
cur_history++;
if (cur_history < history->n_commands) /* display next command in history */
{
reprint_prompt(prompt);
strcpy(buffer, history->commands[cur_history]);
print(buffer);
i = strlen(buffer);
}
else
{
cur_history = history->n_commands;
reprint_prompt(prompt);
i = 0;
}
}
}
else
{
reprint_prompt(prompt);
i = 0; /* discard previous read chars */
}
}
else if (c == 127 && i > 0) /* delete */
{
write(STDOUT_FILENO, “\x1b[D\x1b[K”, 6); /* move left one char, clear line */
i–;
}
else if (c == 10 || (c >=32 && c < 127))
{
write(STDOUT_FILENO, &c, 1);
buffer[i] = c; /* save in buffer */
if (c == ‘\n’) /* if newline, end input */
end = 1;
else if (i + 1 >= max_len) /* if we ran out of buffer space, end*/
end = 1;
else
i++;
}
}
buffer[i] = 0; /* insert end of string*/
}

/*
Split a string using the given sepatator, returns an array of pointers to the
split parts, it updates argc with the number of parts found
*/
char**
split(char *string, char *separator, int *argc)
{
char *token;
char **argv;

argv = (char **) malloc(sizeof(char *));
*argc = 0;
token = strtok(string, separator);
while(token != NULL)
{
argv[(*argc)++] = token;
argv = (char **) realloc(argv, ((*argc) + 1)*sizeof(char *));
token = strtok(NULL, separator);
}
argv[*argc] = NULL;
return argv;
}

/*
Parses a command, splitting a command line by spaces and looking for redirection
characters, it also looks for the backround execution character &
*/
command_t*
get_command(char *string)
{
command_t *command;

command = (command_t *) malloc(sizeof(command_t));
command->background = 0;
command->redir = 0;
command->redir_file = NULL;
command->pipe_fd[0] = -1;
command->pipe_fd[1] = -1;
command->argv = split(string, ” \t”, &(command->argc)); /* split by spaces */

if (command->argc > 1 && !strcmp(command->argv[command->argc – 1], “&”)) /* if it’s a background command */
{
command->argv[command->argc – 1] = NULL; /* remove char from argv */
command->background = 1;
command->argc–;
}
if (command->argc > 2)
{
if (!strcmp(command->argv[command->argc – 2], “<“)) /* if it’s a < redirection */
{
command->argv[command->argc – 2] = NULL; /* remove redirection from argv */
command->redir = 1;
command->redir_file = command->argv[command->argc – 1];
command->argc -= 2;
}
else if (!strcmp(command->argv[command->argc – 2], “>”)) /* if it’s a > redirection */
{
command->argv[command->argc – 2] = NULL; /* remove redirection from argv */
command->redir = 2;
command->redir_file = command->argv[command->argc – 1];
command->argc -= 2;
}
else if (!strcmp(command->argv[command->argc – 2], “>>”)) /* if it’s a >> redirection */
{
command->argv[command->argc – 2] = NULL; /* remove redirection from argv */
command->redir = 3;
command->redir_file = command->argv[command->argc – 1];
command->argc -= 2;
}
}
return command;
}

/*
Frees the space allocated for a command structure
*/
void
free_command(command_t *command)
{
free(command->argv);
free(command);
}

/*
Redirects standard input and output based on the command redirection data
and the pipes connected to it
*/
void
redirect_io(command_t *command)
{
int fd;
if (command->redir_file != NULL) /* if redirecting to a file */
{
switch (command->redir)
{
case 1: /* input redirection */
if (command->pipe_fd[0] != -1) /* if input was connected to pipe, close pipe input */
{
close(command->pipe_fd[0]);
command->pipe_fd[0] = -1;
}
fd = open(command->redir_file, O_RDONLY); /* open file for reading */
if (fd == -1)
{
fprintf(stderr, “Unable to open file ‘%s’\n”, command->redir_file);
exit(1);
}
dup2(fd, STDIN_FILENO); /* redirect input to file*/
close(fd); /* close duplicate */
break;
case 2: /* output redirection */
if (command->pipe_fd[1] != -1) /* if input was connected to pipe, close pipe output */
{
close(command->pipe_fd[1]);
command->pipe_fd[1] = -1;
}
/* open and truncate or create new file for writing */
fd = open(command->redir_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
fprintf(stderr, “Unable to open file ‘%s’\n”, command->redir_file);
exit(1);
}
dup2(fd, STDOUT_FILENO); /* redirect output to file*/
close(fd); /* close duplicate */
break;
case 3: /* output redirection, appending */
if (command->pipe_fd[1] != -1) /* if input was connected to pipe, close pipe output */
{
close(command->pipe_fd[1]);
command->pipe_fd[1] = -1;
}
/* open and truncate or create new file for writing */
fd = open(command->redir_file, O_WRONLY | O_CREAT | O_APPEND, 0666);
if (fd == -1)
{
fprintf(stderr, “Unable to open file ‘%s’\n”, command->redir_file);
exit(1);
}
dup2(fd, STDOUT_FILENO); /* redirect output to file*/
close(fd); /* close duplicate */
break;
}
}
if (command->pipe_fd[0] != -1) /* if input was connected to pipe */
{
dup2(command->pipe_fd[0], STDIN_FILENO); /* redirect input to file*/
close(command->pipe_fd[0]); /* close duplicate */
}
if (command->pipe_fd[1] != -1) /* if output was connected to pipe */
{
dup2(command->pipe_fd[1], STDOUT_FILENO); /* redirect input to file*/
close(command->pipe_fd[1]); /* close duplicate */
}
}

/*
Executes the cd command, it executes on the parent process
*/
void
execute_cd(command_t *command)
{
if (command->pipe_fd[0] != -1) /* if input was connected to pipe */
close(command->pipe_fd[0]);
if (command->pipe_fd[1] != -1) /* if output was connected to pipe */
close(command->pipe_fd[1]);
if (command->argc != 2)
fprintf(stderr, “Invalid number of commands for cd\n”);
else if( chdir(command->argv[1]) < 0)
fprintf(stderr, “Unable to change to ‘%s’\n”, command->argv[1]);
}

/*
Executes the pwd command, it assumes it’s running in a child process
*/
void
execute_pwd(command_t *command)
{
char cur_dir[BUFFERSIZE];
if (command->argc != 1)
{
fprintf(stderr, “Invalid number of commands for pwd\n”);
exit(1);
}
else
{
getcwd(cur_dir, BUFFERSIZE);
printf(“%s\n”, cur_dir);
exit(0);
}
}

/*
Executes a command whose data has been saved on the command structure,
it creates a child process to run it and it returns the child pid
*/
pid_t
execute_command(command_t *command)
{
pid_t pid;

if (!strcmp(command->argv[0], “cd”))
{
execute_cd(command);
pid = -1;
}
else {
pid = fork(); /* fork the process */
if (pid == -1) /* if there was an error */
{
fprintf(stderr, “Error forking process\n”);
return -1;
}
else if (pid == 0) /* if we are in the child process */
{
redirect_io(command); /* redirect input and output */
if (!strcmp(command->argv[0], “pwd”))
execute_pwd(command);
else if (execvp(command->argv[0], command->argv) < 0)
{
fprintf(stderr, “Invalid command ‘%s’\n”, command->argv[0]);
exit(1);
}
}
}
return pid;
}

/*
Starts the execution of a command line which can consist of single or piped
commands, it dispatches the execute command as required. It handles the
pipe connections between piped commands
*/
void
execute_command_line(char *cmd_line)
{
char **cmds;
int n_cmds;
int **pipe_fd;
int i, status;
command_t *command;
pid_t pid;

cmds = split(cmd_line, “|”, &n_cmds); /* split by pipes */

if (n_cmds == 1) /* single command */
{
command = get_command(cmds[0]);
pid = execute_command(command);
if (pid != -1 && !command->background)
waitpid(pid, &status, 0);
free_command(command);
}
else
{
pipe_fd = (int **) malloc((n_cmds – 1)*sizeof(int *));

for (i = 0; i < n_cmds; i++)
{
if (i < n_cmds – 1)
{
pipe_fd[i] = (int *) malloc(2*sizeof(int));
pipe(pipe_fd[i]); /* create pipe */
}

command = get_command(cmds[i]);
if (i > 0)
command->pipe_fd[0] = pipe_fd[i – 1][0]; /* connect previous pipe */
if(i < n_cmds – 1)
command->pipe_fd[1] = pipe_fd[i][1]; /* connect to pipe */

pid = execute_command(command);
if (i == n_cmds – 1 && pid != -1 && !command->background)
{
waitpid(pid, &status, 0);
}
free_command(command);
if (i < n_cmds – 1)
close(pipe_fd[i][1]);
}
for (i = 0; i < n_cmds – 1; i++)
{
close(pipe_fd[i][0]);
close(pipe_fd[i][1]);
free(pipe_fd[i]);
}
free(pipe_fd);
}
free(cmds);
}

/*
Looks for the home directory in the environment variables and returns a
pointer to it
*/
char*
get_home_directory(char **env)
{
char *home;
int i = 0;

home = NULL;
while(env[i]!=NULL && home == NULL)
{
if (!strncmp(env[i], “HOME=”,5)) /* search for home variable */
home = &env[i][5];
i++;
}
return home;
}

/*
It saves the current prompt that includes the current directory. It replaces
the home directory in the currend path by a ~ character
*/
void
update_prompt(char *home, char *prompt)
{
char cur_dir[BUFFERSIZE];
int len;

sprintf(prompt, “myShell “);

getcwd(cur_dir, BUFFERSIZE); /* get current directory */
len = strlen(home);
if (!strncmp(cur_dir, home, len)) /* if the path starts with the home directory */
{
strcat(prompt, “~/”);
if (cur_dir[len] == ‘/’) /* avoid printing double /*/
len++;
strcat(prompt, &cur_dir[len]); /* print the rest of the path */
}
else
strcat(prompt, cur_dir);
strcat(prompt, ” >> “);
}

/*
Creates a new history structure and initializes its fields
*/
history_t*
create_history()
{
history_t *history;

history = (history_t *) malloc(sizeof(history_t));
history->commands = NULL;
history->n_commands = 0;
return history;
}

/*
Adds a command line to the history
*/
void
add_to_history(char *command, history_t *history)
{
if (history->commands == NULL)
history->commands = (char **) malloc(sizeof(char *));
else
history->commands = (char **) realloc(history->commands, (history->n_commands + 1) * sizeof(char *));
history->commands[history->n_commands++] = strdup(command);
}

/*
Frees the space allocated for the history structure and all the commands
saved within
*/
void
free_history(history_t *history)
{
int i;
if (history != NULL)
{
for (i = 0; i < history->n_commands; i++)
free(history->commands[i]);
if (history->commands)
free(history->commands);
free(history);
}
}

/*
Main program, it shows the prompt, reads input and executes the commands.
Initializes the home directory variable and the history array. It frees all
allocated memory before exit.
*/
int
main(int argc, char **argv, char **env)
{
char buffer[BUFFERSIZE];
int quit = 0;
char *home;
char prompt[BUFFERSIZE];
history_t *history;

home = get_home_directory(env);
history = create_history();

while (!quit)
{
update_prompt(home, prompt); /* update prompt based on current dir */
write(STDOUT_FILENO, prompt, strlen(prompt)); /* print prompt */

read_line(buffer, BUFFERSIZE, prompt, history); /* read command line */
if(buffer[0] != ‘\0’)
{
if (!strcmp(buffer, “exit”))
quit = 1;
else
{
add_to_history(buffer, history);
execute_command_line(buffer);
}
}
}
free_history(history);
return 0;
}