-
Notifications
You must be signed in to change notification settings - Fork 0
/
shell.c
210 lines (194 loc) · 5.93 KB
/
shell.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "shell.h"
char ** parse_args( char * line, char * delimiter ) {
/*
* Processes the line, including pipes and redirects.
* Ignores whitespace.
*
* Takes in parameters line, which is a terminal command, and a delimiter, with which parse_args strseps by.
* Returns an array derived from the line using strsep.
*/
char ** array = calloc(256, sizeof(char *)); //mem issues
int index = 0;
int id;
int i = 0;
// strip the line of trailing and leading whitespace
line = strip(line);
if(strcmp(line, "") == 0){
return array;
}
char * ptr = line;
char * back_ptr;
// printf("ptr:%s\n", ptr);
while (ptr && index < 256) {
if (strcmp(delimiter, ";") == 0 ){
back_ptr = ptr;
line = strsep(&ptr, ";");
back_ptr = strip(back_ptr);
// printf("Back pointer: %s Ptr: %s\n", back_ptr, ptr);
array = parse_args(back_ptr, " ");
// Account for exit and cd
if (strcmp(array[0], "exit") == 0) {
free(array);
return NULL;
}
// if cd
else if (strcmp(array[0], "cd") == 0) {
if(chdir(array[1]) == -1) {
printf("%s\n",strerror(errno));
}
}
// general case
else{
// have a child process run the command
id = fork();
// printf("Array[0]: %s array[1]: %s array[2]: %s\n", array[0], array[1], array[2]);
// increment to find if there is a redirect symbol in the command
int index;
for(index = 0; array[index] != NULL && (strcmp(array[index], ">") != 0 && strcmp(array[index], ">>") != 0 && strcmp(array[index], "<") != 0 && strcmp(array[index], "|") != 0); index++);
if (id == 0){
// if it is a redirection command, leave it to respective functions
if(array[index] != NULL && (strstr(array[index], ">") || (strstr(array[index], ">>")))) {
redirect_stdout(array, index);
}
else if(array[index] != NULL && (strstr(array[index], "<") || (strstr(array[index], "<<")))) {
redirect_stdin(array, index);
}
else if(array[index] != NULL && (strstr(array[index], "|"))) {
piping(array, index);
}
else {
if (execvp(array[0], array) == -1){ //run ze process
printf("%s\n", strerror(errno));
}
}
}
// wait for the child process to finish before proceeding
int status;
wait(NULL);
}
}
else{
// strsep through whitespace
// deal with multiple semicolons by strsepping them too
array[index] = strsep(&ptr, " ");
// printf("parse_args ptr: %s array[%d] : \'%s\'\n", ptr, index, array[index]);
index++;
}
}
return array;
}
char * strip( char * string){
/*
* Strips leading and trailing whitespace.
*
* Takes in a string.
* Returns a char array that has been stripped of leading/trailing whitespace.
*/
// Make the string mutable
char * arr_string = calloc(256, sizeof(char));
char * start_ptr = arr_string;
int start_index = 0;
strcpy(arr_string, string);
int end_index = strlen(string) - 1;
//leading whitespace
if (strstr((start_ptr), " ") != NULL){
while(arr_string[start_index] == ' '){
start_index++;
start_ptr++;
}
//trailing whitespace
while(arr_string[end_index] == ' '){
end_index--;
}
}
// printf("String: %s\n", start_ptr);
arr_string[end_index+1] = 0;
return start_ptr;
}
void redirect_stdout(char ** arr, int index) {
/*
* Takes in the command and executes redirection into a text file.
*
* Takes in an array of strings, and an index such that array[index] points to the > or >> symbol.
* Executes the redirect, deos not return.
*/
int fd;
// check if redirect symbol is > or >>. If >, write to the file. If >>, append to the file.
if(strcmp(arr[index], ">") == 0) {
fd = open(arr[index+1], O_CREAT | O_WRONLY, 0644);
}
else {
fd = open(arr[index+1], O_CREAT | O_WRONLY | O_APPEND, 0644);
}
if(fd == -1){
printf("error: %s\n", strerror(errno));
}
dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);
arr[index] = NULL;
if (execvp(arr[0], arr) == -1){ // execute redirection
printf("%s\n", strerror(errno));
}
close(fd); // close file
}
void redirect_stdin(char ** arr, int index) {
/*
* Takes in the command and redirects text file in to stdin.
*
* Takes in an array of strings, and an index such that array[index] points to the < symbol.
* Executes the redirect, deos not return.
*/
int fd;
fd = open(arr[index+1], O_RDONLY);
dup(STDIN_FILENO);
dup2(fd, STDIN_FILENO);
arr[index] = NULL;
if (execvp(arr[0], arr) == -1){ // execute redirection
printf("%s\n", strerror(errno));
}
close(fd); // close file
}
void piping(char ** arr, int index) {
/*
* Takes in the command and executes piping.
*
* Takes in an array of strings, and an index such that array[index] points to the < symbol.
* Executes the pipe, deos not return.
*/
int fds[] = {0,0};
if(pipe(fds) == -1) {
printf("pipe error: %s\n", strerror(errno));
}
// config pipe
int alt_stdout = dup(STDOUT_FILENO);
int f = fork();
// subchild process
if(f == 0) {
// set up the redirection
// printf("stdout: %d\n", STDOUT_FILENO);
dup2(fds[READ], STDOUT_FILENO);
close(fds[READ]);
close(fds[WRITE]);
arr[index] = NULL;
if (execvp(arr[0], arr) == -1){ // execute
printf("%s\n", strerror(errno));
}
}
// child process
else {
//wait(NULL);
dup2(fds[WRITE], STDIN_FILENO);
close(fds[READ]);
close(fds[WRITE]);
char ** secondary_arr = calloc(256, sizeof(char *));
int i;
for (i = index+1; arr[i]; i++){
secondary_arr[i - (index+1)] = arr[i];
//printf("secondary_arr[%d]: %s \n", i - (index+1), secondary_arr[i - (index+1)]);
}
free(arr);
if (execvp(secondary_arr[0], secondary_arr) == -1){
printf("%s\n", strerror(errno));
}
}
}