-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest.c
More file actions
362 lines (311 loc) · 8.12 KB
/
test.c
File metadata and controls
362 lines (311 loc) · 8.12 KB
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <fcntl.h>
typedef struct
{
char **argv;
int fdIn, fdOut;
}Command;
//adding comment
//adding comment
void deleteNL(char **);
int count_pipes(char *);
int tokenizer(char **, Command *);
void run_pipe(Command *, int, int);
void redirect(int, int);
void closeFd(int fd);
static int version = 10;
void displayVersion(){
printf("Version: %d\n", version);
}
int main(int argc, char **argv)
{
displayVersion();
const int cmd_limit = 1024;
char *user_input = malloc(sizeof(char) * BUFSIZ);
int num_pipes, num_cmds;
Command cmds[cmd_limit];
while(fgets(user_input, sizeof(char) * BUFSIZ, stdin) != NULL) {
//delete the new line character at the end of input, count pipes, then tokenize usr input
deleteNL(&user_input);
num_pipes = count_pipes(user_input);
num_cmds = tokenizer(&user_input, cmds);
//piping
run_pipe(cmds, num_cmds, num_pipes);
//reset input for next line of input
memset(user_input, 0, sizeof(user_input));
fflush(NULL);
//free command arguments
int i = 0;
for(i; i < num_cmds; i++){
free(cmds[i].argv);
}
}
free(user_input);
}
//counts the number of pipes
int count_pipes(char * input){
int pipe_count = 0;
for(int i = 0; input[i] != '\0'; i++)
{
if(input[i] == '|')
{
pipe_count++;
}
}
printf("Pipe count: %d\n", pipe_count);
return pipe_count;
}
//delete the new line character at the end of user input
void deleteNL(char ** input){
if((*input)[strlen(*input) - 1] == '\n'){
(*input)[strlen(*input) - 1] = '\0';
}
}
//tokenizes user input command, opens any files found in the command. After tokenizing, the tokens are made ready for execvp() and added to Command structure that will be used to execute the commands in pipes
int tokenizer(char ** input, Command * cmds)
{
const char *DELIMS = " ";
char **tokenArg = malloc(sizeof(char) * BUFSIZ); //temp token to store tokens before adding to command agr token
char *token;
int i = 0, j = 0; //counters loops and indexs
int cmd_after_pipe = 0, file_after_r = 0, command_after_semi = 0; //flags for catching commands after pipes and semicolons, and file after redirection
int is_in_r = 0, is_out_r = 0, is_append = 0; //recognizes input or output file redirection and append to file
int num_of_commands = 1, num_tokens = 0; //first one counts comman, there is always at least one command
token = strtok(*input, DELIMS);
while(token != NULL)
{
switch(token[0])
{
case '-':
{
printf("Options: %s\n", token);
break;
}
case '|':
{
num_of_commands++; //once we hit a pipe, we have finished a command
cmd_after_pipe = 1; // set flag to indicate we found a pipe
break;
}
case '<':
{
printf("Redirection: %s\n", token);
file_after_r = 1;
is_in_r = 1;
token = strtok(NULL, DELIMS);
continue; //skip input re token
}
case '>':
{
printf("Redirection: %s\n", token);
//check if we are appending
if(token[1] && token[1] == '>')
{
is_append = 1;
}
file_after_r = 1;
is_out_r = 1;
token = strtok(NULL, DELIMS);
continue; //skip out redirect token
}
case ';':
{
command_after_semi = 1;
token = strtok(NULL, DELIMS);
continue; //skip semicolon token
}
default:
{
//first token is always a command
if ( i == 0 || cmd_after_pipe)
{
printf("Command: %s\n", token);
cmd_after_pipe = 0;
i++;
}
//recognize the file after a redirect
else if ( file_after_r)
{
printf("Redirect file: %s\n", token);
//if input redirect, open input file it exists
if(is_in_r)
{
if((cmds[num_of_commands - 1].fdIn = open(token, O_RDONLY)) == -1)
{
perror("Input file failure: ");
exit(EXIT_FAILURE);
}
is_in_r=0;
}
//if output redirect
else if(is_out_r)
{
//if we are appending to the file, open as appension
if(is_append)
{
printf("Appending\n");
//if it doesn't exists, create it and append
if ((cmds[num_of_commands - 1].fdOut = open(token, O_WRONLY | O_APPEND, 0744)) == -1)
{
if((cmds[num_of_commands - 1].fdOut = open(token, O_WRONLY | O_CREAT | O_APPEND, 0744)) == -1)
{
perror(token);
}
}
//else the file exists, apply only append
else
{
closeFd(cmds[num_of_commands - 1].fdOut);
if((cmds[num_of_commands - 1].fdOut = open(token, O_WRONLY | O_APPEND, 0744)) == -1)
{
perror(token);
}
}
}
//if we are not appending just create and truncate
else
{
if((cmds[num_of_commands - 1].fdOut = open(token, O_WRONLY | O_CREAT | O_TRUNC, 0744)) == -1)
{
perror(token);
}
}
is_out_r = 0;
}
file_after_r = 0;
}
//reconginze the command after a ;
else if ( command_after_semi)
{
printf("Redirection file: %s\n", token);
command_after_semi = 0;
}
//recognize an arg in a cmd
else
{
printf("Arg: %s\n", token);
}
}
}
//making sure the token ends with a null character and not a new line character
if(token[strlen(token) - 1] == '\n')
{
printf("FOUND NEW LINE- DELETING\n");
token[strlen(token) - 1] = '\0';
}
//checking again
else if (token[strlen(token)] == '\n')
{
printf("FOUND NEW LINE - DELETING\n");
token[strlen(token)] = '\0';
}
token[strlen(token)] = '\0';
//add the token to the temp token for arguments
tokenArg[num_tokens] = token;
num_tokens++;
token = strtok(NULL, DELIMS);
}
//alocate space for args
for ( i = 0; i < num_of_commands; i++)
{
cmds[i].argv = malloc(sizeof(char) * BUFSIZ);
}
//build the commands for the args and add them
i = 0;
int argvInd = 0;
for(j = 0; j < num_tokens; j++)
{
if(tokenArg[j][0] == '|')
{
argvInd = 0;
i++;
}
else
{
cmds[i].argv[argvInd] = tokenArg[j];
argvInd++;
}
}
return num_of_commands;
}
void run_pipe(Command *commands, int num_cmds, int num_pipes)
{
int in = STDIN_FILENO;
int status;
int i = 0;
//fork for the number of pipes
for(i; i < num_pipes; i++){
int fds[2];
pid_t child;
if(pipe(fds) == -1){
perror("Pipes: ");
exit(EXIT_FAILURE);
}
if((child = fork()) == -1 ){
perror("Fork: ");
exit(EXIT_FAILURE);
}
if(child == 0){
//child
closeFd(fds[0]);
redirect(in, STDIN_FILENO);
redirect(fds[1], STDOUT_FILENO);
//child executing
execvp(commands[i].argv[0], (char * const *) commands[i].argv);
}
else //parent
{
closeFd(fds[1]);
closeFd(in);
in = fds[0];
}
}
//The children have finished. Now the parent must execute the last stage
//checking io redirection
int j = 0;
for(j; j < num_cmds; j++)
{
if (commands[j].fdIn && commands[j].fdIn != STDIN_FILENO){
redirect(in, commands[j].fdIn);
redirect(STDOUT_FILENO, STDOUT_FILENO);
execvp(commands[i].argv[0], commands[i].argv);
}
else if (commands[j].fdOut && commands[j].fdOut != STDOUT_FILENO){
redirect(in, STDIN_FILENO);
redirect(commands[j].fdOut, STDOUT_FILENO);
execvp(commands[i].argv[0], commands[i].argv);
}
}
redirect(in, STDIN_FILENO);
redirect(STDOUT_FILENO, STDOUT_FILENO);
execvp(commands[i].argv[0], (char * const *) commands[i].argv);
}
void closeFd(int fd){
if(close(fd) == -1 )
{
perror(fd);
exit(EXIT_FAILURE);
}
}
void redirect(int oldfd, int newfd){
if(oldfd != newfd){
if(dup2(oldfd, newfd) == -1){
perror("dup2: ");
exit(EXIT_FAILURE);
}
else{
if(close(oldfd) == -1){
perror(oldfd);
exit(EXIT_FAILURE);
}
}
}
}