0% found this document useful (0 votes)
11 views14 pages

FinalProject 1

The document describes a solution to implement input and output redirection in a shell program. It involves parsing commands to detect the ">" and "<" redirection operators. File descriptors are orchestrated using dup2() to facilitate redirection. The code opens files associated with redirection and executes commands involving input or output files. The goal is to seamlessly integrate redirection capabilities into the shell's functionality.

Uploaded by

Minh Mai
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views14 pages

FinalProject 1

The document describes a solution to implement input and output redirection in a shell program. It involves parsing commands to detect the ">" and "<" redirection operators. File descriptors are orchestrated using dup2() to facilitate redirection. The code opens files associated with redirection and executes commands involving input or output files. The goal is to seamlessly integrate redirection capabilities into the shell's functionality.

Uploaded by

Minh Mai
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Họ và tên: Đặng Thành Đạt

Mã số sinh viên: 21521928


Lớp: CS4323.O11.CTTT

OPERATING SYSTEM
Final Project – Homework
~~~*~~~
PROBLEM 1
Implement Section 3: Creating a History Feature

Solution:
For this solution we need to create an array to store the user’s command and when the
user types input as “!!” the command will be executed again.
We must declare the history variable and create a function to add the user commands
to the above array. For details, the user inputs the commands as a string value, so we
need to use the strcpy function to pass the command value to the array history. To
know the situation in this array we also need to write the function to give the signal if
the array did not have any value on itself.
Code:
//---------------------------------
// Author: Đặng Thành Đạt
// Student ID: 21521928
//---------------------------------
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

#define MAXLINE 100


#define HISTORY_SIZE 20

char history[HISTORY_SIZE][MAXLINE];

void addToHistory(const char *command) {


for (int i = HISTORY_SIZE - 1; i > 0; --i) {
strcpy(history[i], history[i - 1]);
}
strcpy(history[0], command);
}
int main(void) {
char args[MAXLINE / 2 + 1];
int should_run = 1;

while (should_run) {
printf("21521928>");
fflush(stdout);

fgets(args, sizeof(args), stdin);


args[strcspn(args, "\n")] = 0;

if (strcmp(args, "exit") == 0) {
should_run = 0;
} else if (strcmp(args, "!!") == 0) {
if (history[0][0] == '\0') {
printf("No commands in history.\n");
} else {
printf("%s\n", history[0]);
addToHistory(history[0]);
pid_t pid = fork();
if (pid == 0) {
char *token;
char *tokens[MAXLINE / 2 + 1];
int i = 0;

token = strtok(history[0], " ");


while (token != NULL) {
tokens[i++] = token;
token = strtok(NULL, " ");
}
tokens[i] = NULL;

execvp(tokens[0], tokens);
fprintf(stderr, "Exec failed\n");
return 1;
}
if (pid > 0) {
wait(NULL);
}
}
} else {
addToHistory(args);
pid_t pid = fork();
if (pid == 0) {
char *token;
char *tokens[MAXLINE / 2 + 1];
int i = 0;
token = strtok(args, " ");
while (token != NULL) {
tokens[i++] = token;
token = strtok(NULL, " ");
}
tokens[i] = NULL;

execvp(tokens[0], tokens);
fprintf(stderr, "Exec failed\n");
return 1;
}
if (pid > 0) {
wait(NULL);
}
}
}
return 0;
}

Explanation:
Step 1: Declaring the array variable and creating the function to add a new
command:

Explain:
I declare that variable – char variables and a function that takes responsibility for
adding new commands to the commands history in the array. It will replace the
commands' position by one unit to make a free space for the new command and then
copy the new command to the first row of the array, then, the array with the most
recent command will be updated.
Step 2: Handling when the user types input as the “!!” symbol.
Explain:
When the type inputs as “!!” symbol, if the array is empty It will be displayed as
“There is no command in history”. Unless the array is empty it will execute the latest
command in the array by the “axecvp” function.
Testing:
Explain:
At the results when I input “!!”, the screen displays “There is no command in history”,
which means there are not any commands to execute.
When I type “echo ThanhDat” the program will execute the command and store the
command in the array.
When an invalid command is input into a shell, it is not executed but is retained in the
command history. Subsequently, if the user enters '!!,' the shell will execute the last
command from the history, including any previously entered invalid commands."
When I type “ls” It is going to do the same thing with “echo ThanhDat”.
Video demo: https://drive.google.com/drive/u/0/folders/1IFthYyl-
3cM3ZMztCnkP1Ht3INopIlSu

PROBLEM 2
Implement Section 4: Redirecting Input and Output

The solution for this problem:


To enable input and output redirection in the shell, enhancements must be made
to the existing code structure. This entails introducing functionality for
detecting '>' to signify output redirection and '<' to indicate input redirection
within user-entered commands. This requires parsing the input, recognizing
redirection operators, and orchestrating file descriptors using functions like
dup2 to facilitate redirection. Essential libraries need to be imported, and the
code should be implemented to seamlessly handle the ">" and "<" symbols for
redirection. Additionally, the system should be able to execute commands that
involve input and output files when such redirection commands are provided
by the user. This involves incorporating file operations, such as opening, to
manage the creation or opening of files associated with the redirection process.
The overarching goal is to create a comprehensive solution that seamlessly
integrates input and output redirection capabilities into the shell's functionality.
Code:
//---------------------------------
// Author: Đặng Thành Đạt
// Student ID: 21521928
//---------------------------------
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>

#define MAXLINE 100


#define HISTORY_SIZE 20

char history[HISTORY_SIZE][MAXLINE];

void addToHistory(const char *command) {


for (int i = HISTORY_SIZE - 1; i > 0; --i) {
strcpy(history[i], history[i - 1]);
}
strcpy(history[0], command);
}

int main(void) {
char args[MAXLINE / 2 + 1];
int should_run = 1;

while (should_run) {
printf("21521928>");
fflush(stdout);

fgets(args, sizeof(args), stdin);


args[strcspn(args, "\n")] = 0;

if (strcmp(args, "exit") == 0) {
should_run = 0;
} else if (strcmp(args, "!!") == 0) {
if (history[0][0] == '\0') {
printf("No commands in history.\n");
} else {
printf("%s\n", history[0]);
addToHistory(history[0]);

char *token;
char *tokens[MAXLINE / 2 + 1];
int i = 0;

token = strtok(history[0], " ");


while (token != NULL) {
tokens[i++] = token;
token = strtok(NULL, " ");
}
tokens[i] = NULL;
int redirectInput = 0;
int redirectOutput = 0;
for (int j = 0; tokens[j] != NULL; ++j) {
if (strcmp(tokens[j], ">") == 0) {
redirectOutput = 1;
tokens[j] = NULL;
break;
} else if (strcmp(tokens[j], "<") == 0) {
redirectInput = 1;
tokens[j] = NULL;
break;
}
}

pid_t pid = fork();


if (pid == 0) {
if (redirectInput) {
int fd = open(tokens[i - 1], O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
dup2(fd, STDIN_FILENO);
close(fd);
}

if (redirectOutput) {
int fd = open(tokens[i - 1], O_WRONLY | O_CREAT | O_TRUNC,
0644);
if (fd == -1) {
perror("open");
return 1;
}
dup2(fd, STDOUT_FILENO);
close(fd);
}

execvp(tokens[0], tokens);
fprintf(stderr, "Exec failed\n");
return 1;
}
if (pid > 0) {
wait(NULL);
}
}
} else {
addToHistory(args);

char *token;
char *tokens[MAXLINE / 2 + 1];
int i = 0;
token = strtok(args, " ");
while (token != NULL) {
tokens[i++] = token;
token = strtok(NULL, " ");
}
tokens[i] = NULL;
int redirectInput = 0;
int redirectOutput = 0;
for (int j = 0; tokens[j] != NULL; ++j) {
if (strcmp(tokens[j], ">") == 0) {
redirectOutput = 1;
tokens[j] = NULL;
break;
} else if (strcmp(tokens[j], "<") == 0) {
redirectInput = 1;
tokens[j] = NULL;
break;
}
}
pid_t pid = fork();
if (pid == 0) {
if (redirectInput) {
int fd = open(tokens[i - 1], O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
dup2(fd, STDIN_FILENO);
close(fd);
}

if (redirectOutput) {
int fd = open(tokens[i - 1], O_WRONLY | O_CREAT | O_TRUNC,
0644);
if (fd == -1) {
perror("open");
return 1;
}
dup2(fd, STDOUT_FILENO);
close(fd);
}

execvp(tokens[0], tokens);
fprintf(stderr, "Exec failed\n");
return 1;
}
if (pid > 0) {
wait(NULL);
}
}
}
return 0;
}

Explanation:

Two flags, redirect_input and redirect_output, serve to signal the necessity of input or
output redirection.

Output Redirection (>):


The program scrutinizes each token to identify the output redirection symbol
(>). Upon detection, the redirect_output flag is set to 1, indicating the need for
output redirection. The token is then set to NULL, removing the '>' from the
command. The loop is exited since only one redirection symbol is expected.
Input Redirection (<):
A similar approach is employed for input redirection handling. The program
examines each token for the input redirection symbol (<). Upon identification,
the redirect_input flag is set to 1, signifying the requirement for input
redirection. The token is then set to NULL, eliminating the '<' from the
command. The loop is terminated, recognizing that only one redirection symbol
is anticipated.
This modification introduces a mechanism for the program to ascertain the
necessity of input or output redirection without immediately altering the
command in the tokens array. The flags, redirect_input and redirect_output, can
subsequently be employed to selectively execute redirection in the child
process based on their values.

To facilitate output redirection:


Upon detecting the ">" operator in the command, the code proceeds to locate
the subsequent token (tokens[j + 1]), presuming it to be the filename where the
output should be redirected.The open system call is employed to open the file
in write-only (O_WRONLY) mode, creating it if it doesn't exist (O_CREAT),
and truncating it to zero length (O_TRUNC). The file permissions are set to
0644. Using dup2(fd, STDOUT_FILENO), the file descriptor fd is duplicated
onto the standard output file descriptor (STDOUT_FILENO), effectively
redirecting standard output to the specified file. Subsequently, close(fd) is
invoked to close the file descriptor, as it becomes unnecessary post-redirection.
For input redirection:
Detection of the "<" operator triggers the code to search for the subsequent
token (tokens[j + 1]), assumed to be the filename from which the input should
be redirected.The open system call is utilized to open the file in read-only
(O_RDONLY) mode. dup2(fd, STDIN_FILENO) duplicates the file descriptor
fd onto the standard input file descriptor (STDIN_FILENO), redirecting
standard input from the specified file.Following this, close(fd) is executed to
close the file descriptor, as it is no longer required after redirection.
Post-establishing the file configurations, the system will execute the user command,
incorporating the respective type of redirection based on the user-inputted redirection
signal (">" or "<").
Testing:
Output file

Input file

Explain:
When entering the command "ls > out.txt," it creates a file named "out.txt" and stores
the output of the "ls" command in this file. Similarly, if an "in.txt" file is created with
text content and the command "cat < in.txt" is used, it prints the text values from the
"in.txt" file. When a list of integers is placed in "in.txt," and the command "sort <
in.txt" is executed, the values in the file are sorted, and the sorted list of integers is
printed. Using the command "!!" subsequently prints the last entered command along
with its output.
However, if a non-command such as "wertyufgh" is entered, the system responds with
"Exec failed," signaling that the input is not a valid command. This message indicates
that the attempted execution of the given input failed, typically because the command
is not recognized or executable.
In summary, the described commands showcase the functionality of input and output
redirection, command repetition with "!!," and the indication of execution failure for
invalid commands.
Video demo: https://drive.google.com/drive/u/0/folders/1IFthYyl-
3cM3ZMztCnkP1Ht3INopIlSu
./END

You might also like