1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <unistd.h>
5
+ #include <sys/wait.h>
6
+ #include <stdbool.h>
7
+ #include <errno.h>
8
+
9
+
10
+ void takeIn (char in []){
11
+
12
+ fgets (in ,512 ,stdin );
13
+
14
+ //exclude '\n' character (enter) from string-input
15
+ int i = 0 ;
16
+ while (in [i ]!= '\0' ){
17
+ i ++ ;
18
+ }
19
+ in [i - 1 ]= '\0' ;
20
+ }
21
+
22
+
23
+ void parse (char input [], char * toks [],const char delimeter []){
24
+ //general parsing function
25
+ char * token ;
26
+ int i = 0 ;
27
+ token = strtok (input , delimeter );
28
+
29
+ while ( token != NULL ) {
30
+
31
+ toks [i ]= token ;
32
+ i ++ ;
33
+ token = strtok (NULL , delimeter );
34
+
35
+ }
36
+ toks [i ] = NULL ;
37
+
38
+ }
39
+
40
+
41
+ int seperateCommands (char input [],char * cmds [], bool * success ){
42
+ char * token ;
43
+ int i = 0 ,pos = 0 ;
44
+
45
+ //find all delimiters
46
+ for (int j = 0 ;j < strlen (input )- 1 ;j ++ ){
47
+ if (input [j ]== '&' && input [j + 1 ]== '&' ){
48
+ success [pos ]= true;
49
+ pos ++ ;
50
+ }else if (input [j ]== ';' ){
51
+ success [pos ]= false;
52
+ pos ++ ;
53
+ }
54
+ }
55
+
56
+ //split the commands
57
+
58
+ parse (input , cmds , ";&&" ); //parse iput in ';' or '&&'
59
+
60
+ return pos + 1 ; //pos+1 = number of commands
61
+ }
62
+
63
+
64
+ int executeCmd (char * tokens []){
65
+ int status ;
66
+ pid_t child_pid ;
67
+
68
+ child_pid = fork ();
69
+
70
+ if (child_pid == 0 ) {
71
+ /*child process. */
72
+ if (execvp (tokens [0 ], tokens )< 0 ){
73
+ perror (tokens [0 ]);
74
+ return -1 ;
75
+ }
76
+ }else if (child_pid < 0 ){
77
+ perror ("Fork failed" );
78
+ return 1 ;
79
+ } else {
80
+ waitpid (child_pid , & status , WUNTRACED );
81
+ }
82
+ if (status == 0 ){
83
+ return 0 ;
84
+ }else {
85
+ return -1 ;
86
+ }
87
+ }
88
+
89
+ int findPipe (char cmds []){
90
+ if (strchr (cmds , '|' )!= NULL ){
91
+ return 1 ;
92
+ }else {
93
+ return 0 ;
94
+ }
95
+ }
96
+
97
+ int findRedirection (char cmds []){
98
+
99
+ if (strchr (cmds , '>' )!= NULL ){
100
+ return 1 ;
101
+ }else if (strchr (cmds , '<' )!= NULL ){
102
+ return 2 ;
103
+ }else {
104
+ return 0 ;
105
+ }
106
+ }
107
+
108
+ int executeRedirection (char cmds [], int f ){
109
+
110
+ char * tokens1 [512 ];
111
+ char * tokens2 [512 ];
112
+ int status ;
113
+ pid_t child_pid ;
114
+
115
+ parse (cmds , tokens1 , "<>" ); //parse in spaces or '<' or '>'
116
+
117
+ parse (tokens1 [0 ], tokens2 , " \t" );
118
+
119
+ char * token = strtok (tokens1 [1 ], " \t" );
120
+
121
+ while ( tokens1 [1 ] == " \t" ) {
122
+
123
+ token = strtok (NULL , " \t" );
124
+
125
+ }
126
+
127
+ char * fileName = token ;
128
+
129
+ FILE * file = fopen (fileName , "a+" );
130
+
131
+ child_pid = fork ();
132
+
133
+ if (child_pid == 0 ) {
134
+ /* This is done by the child process. */
135
+ if (f == 1 ){
136
+ close (1 ); //close stdout
137
+ dup2 (fileno (file ),fileno (stdout )); //stout goes to file
138
+
139
+ }else if (f == 2 ){
140
+ close (0 ); //close stdin
141
+ dup2 (fileno (file ),fileno (stdin )); //stdin is in file
142
+ }
143
+
144
+ if (execvp (tokens2 [0 ], tokens2 )< 0 ){
145
+ perror (tokens2 [0 ]);
146
+ exit (1 );
147
+ }
148
+ }else if (child_pid < 0 ){
149
+ perror ("Fork failed" );
150
+ dup2 (fileno (file ),fileno (stderr )); //stderr goes to file
151
+ exit (1 );
152
+ } else {
153
+ fclose (file );
154
+ waitpid (child_pid , & status , WUNTRACED );
155
+ }
156
+
157
+ if (status == 0 ){
158
+ return 0 ;
159
+ }else {
160
+ return -1 ;
161
+ }
162
+
163
+ }
164
+
165
+
166
+
167
+ int executePipe (char cmds []){
168
+ int stat1 , stat2 ; //process1 status1,process2 status2
169
+ pid_t pid1 , pid2 ;
170
+ int fd [2 ];
171
+ char * tokens1 [512 ];
172
+ char * tokens2 [512 ];
173
+ char * tokens3 [512 ];
174
+
175
+ parse (cmds , tokens1 , "|" ); //tokens1 contains the cmds
176
+
177
+ // Create a pipe.
178
+ if (pipe (fd ) == -1 ){
179
+ perror ("Pipe failed" );
180
+ return -1 ;
181
+ }
182
+
183
+ int r1 ,r2 ;
184
+ r1 = findRedirection (tokens1 [0 ]);
185
+ r2 = findRedirection (tokens1 [1 ]);
186
+
187
+ // Create our first process.
188
+ pid1 = fork ();
189
+ if (pid1 < 0 ) {
190
+ perror ("Fork failed" );
191
+ exit (1 );
192
+ }else if (pid1 == 0 ) {
193
+ dup2 (fd [1 ], 1 );
194
+ close (fd [0 ]);
195
+ if (r1 == 0 ){
196
+ parse (tokens1 [0 ], tokens2 , " \t" ); //tokens2 the 1st cmd(pefore pipe)
197
+ execvp (tokens2 [0 ], tokens2 ); // run command BEFORE pipe character in userinput
198
+ perror ("Execvp failed" );
199
+ exit (1 );
200
+ }else {
201
+ executeRedirection (tokens1 [0 ],r1 );
202
+ exit (0 );
203
+ }
204
+
205
+ }
206
+ close (fd [1 ]);
207
+ // Wait for everything to finish and exit.
208
+ waitpid (pid1 , & stat1 , WUNTRACED );
209
+
210
+ // Create our second process.
211
+ pid2 = fork ();
212
+ if (pid2 < 0 ) {
213
+ perror ("Fork failed" );
214
+ exit (1 );
215
+ }else if (pid2 == 0 ) {
216
+ dup2 (fd [0 ], 0 );
217
+ close (fd [1 ]);
218
+ if (r2 == 0 ){
219
+ parse (tokens1 [1 ], tokens3 , " \t" ); //tokens3 the 2nd cmd(after pipe)
220
+ execvp (tokens3 [0 ], tokens3 ); // run command AFTER pipe character in userinput
221
+ perror ("Execvp failed" );
222
+ exit (1 );
223
+ }else {
224
+ executeRedirection (tokens1 [1 ],r2 );
225
+ exit (0 );
226
+ }
227
+ }
228
+ close (fd [0 ]);
229
+ waitpid (pid2 , & stat2 , WUNTRACED );
230
+
231
+
232
+ if (stat1 == 0 && stat2 == 0 ){
233
+ return 0 ;
234
+ }else {
235
+ return -1 ;
236
+ }
237
+
238
+
239
+ }
240
+
241
+ void parseExec (char * input ){
242
+
243
+ int redirectionFound = -10 ; //random non valid initialization
244
+ int pipeFound = -10 ;
245
+ int numOfCmds = 0 ;
246
+ char * cmds [512 ]; //commands stored seperately
247
+ char * toks [512 ]; //parts of each command stored seperately
248
+ bool * success = (bool * )malloc (512 * sizeof (bool ));
249
+ //**********parse multiple commands**************
250
+ numOfCmds = seperateCommands (input , cmds , success );
251
+ //***********parse/execute each command**************************
252
+ for (int i = 0 ; i < numOfCmds ; i ++ ){
253
+ //check for exit
254
+ if (strcmp (cmds [i ],"quit" ) == 0 ){
255
+ exit (0 );
256
+ }
257
+
258
+ pipeFound = findPipe (cmds [i ]);
259
+ redirectionFound = findRedirection (cmds [i ]);
260
+
261
+ if (pipeFound == 0 && redirectionFound == 0 ){
262
+ //Neither pipe nor redirection found
263
+ parse (cmds [i ], toks , " \t" ); //parse space
264
+ if (executeCmd (toks )== -1 && success [i ]== 1 ){
265
+ break ;
266
+ }
267
+
268
+ }else if (pipeFound == 0 && (redirectionFound == 1 || redirectionFound == 2 )){
269
+ //Redirection only
270
+ if (executeRedirection (cmds [i ],redirectionFound )== -1 && success [i ]== 1 ){
271
+ break ;
272
+ }
273
+ }else {
274
+ //pipe only
275
+ if (executePipe (cmds [i ])== -1 && success [i ]== 1 ){
276
+ break ;
277
+ }
278
+ }
279
+ }
280
+
281
+ }
282
+
283
+
284
+ void shell (){
285
+ //user_aem
286
+ printf ("gonidelis_8794>" );
287
+
288
+ //*************initiallization*****************
289
+ char in [512 ]; //string-input from user
290
+
291
+ //***********take input from user****************
292
+ takeIn (in );
293
+ parseExec (in );
294
+ shell ();
295
+ }
296
+
297
+ int batchfile_mode (char * argv []){
298
+
299
+ char str [512 ];
300
+ char * batch_cmds [512 ];
301
+ int i = 0 , j = 0 ;
302
+ int n ; //number of batchfile commands
303
+
304
+ FILE * fp ;
305
+ fp = fopen (argv [1 ], "r" );
306
+
307
+ if (fp == NULL ) {
308
+ perror ("Error opening file" );
309
+ return (-1 );
310
+ }
311
+
312
+ while (fgets (str ,512 , fp )!= NULL ){
313
+ batch_cmds [i ] = strdup (str );
314
+ i ++ ;
315
+ n = i ;
316
+ }
317
+
318
+ for (i = 0 ;i < n ;i ++ ){
319
+
320
+
321
+ batch_cmds [i ] = strtok (batch_cmds [i ], "\n" );
322
+
323
+ parseExec (batch_cmds [i ]);
324
+ }
325
+
326
+
327
+ fclose (fp );
328
+
329
+ return 0 ;
330
+ }
331
+
332
+
333
+ int main (int argc , char * argv []){
334
+ if (argc >=2 ){
335
+ //batchfile mode
336
+ batchfile_mode (argv );
337
+
338
+ }else {
339
+ //interactive mode
340
+ shell (); //shell() called recursively
341
+ }
342
+
343
+ return 0 ;
344
+ }
0 commit comments