xref: /xv6-public/sh.c (revision 8b58e810)
117a85657Srtm #include "types.h"
2d7b3b802Skaashoek #include "stat.h"
3d7b3b802Skaashoek #include "user.h"
417a85657Srtm #include "fs.h"
517a85657Srtm #include "fcntl.h"
617a85657Srtm 
7*8b58e810Skaashoek #define BUFSIZ  512
8*8b58e810Skaashoek #define MAXARGS  10
9*8b58e810Skaashoek #define MAXNODE 2
10*8b58e810Skaashoek 
11*8b58e810Skaashoek // only allocate nodes for i/o redir; at some point we may have to build a
12*8b58e810Skaashoek // a real parse tree.
13*8b58e810Skaashoek struct node {
14*8b58e810Skaashoek   int token;
15*8b58e810Skaashoek   char *s;
16*8b58e810Skaashoek };
17*8b58e810Skaashoek struct node list[MAXNODE];
18*8b58e810Skaashoek int nextnode;
19*8b58e810Skaashoek 
20*8b58e810Skaashoek char buf[BUFSIZ];
21*8b58e810Skaashoek char *argv[MAXARGS];
22*8b58e810Skaashoek char argv0buf[BUFSIZ];
23*8b58e810Skaashoek int argc;
24*8b58e810Skaashoek 
25*8b58e810Skaashoek int debug = 1;
26*8b58e810Skaashoek 
27*8b58e810Skaashoek int parse(char *s);
28*8b58e810Skaashoek void runcmd(void);
29*8b58e810Skaashoek int ioredirection(void);
30*8b58e810Skaashoek int gettoken(char *s, char **token);
31*8b58e810Skaashoek int _gettoken(char *s, char **p1, char **p2);
32*8b58e810Skaashoek void addnode(int token, char *s);
3317a85657Srtm 
3417a85657Srtm int
3517a85657Srtm main(void)
3617a85657Srtm {
3717a85657Srtm   while(1){
3843572072Srtm     puts("$ ");
398787cd01Skaashoek     memset (buf, '\0', sizeof(buf));
4017a85657Srtm     gets(buf, sizeof(buf));
41*8b58e810Skaashoek     if (parse(buf) < 0)
4217a85657Srtm       continue;
43*8b58e810Skaashoek     runcmd();
4417a85657Srtm   }
4517a85657Srtm }
46d7b3b802Skaashoek 
47*8b58e810Skaashoek int
48*8b58e810Skaashoek parse(char *s)
49d7b3b802Skaashoek {
50*8b58e810Skaashoek   char *t;
51*8b58e810Skaashoek   int c;
52*8b58e810Skaashoek 
53*8b58e810Skaashoek   gettoken(s, 0);
54*8b58e810Skaashoek 
55*8b58e810Skaashoek   argc = 0;
56*8b58e810Skaashoek   nextnode = 0;
57*8b58e810Skaashoek   while (1) {
58*8b58e810Skaashoek     switch ((c = gettoken(0, &t))) {
59*8b58e810Skaashoek 
60*8b58e810Skaashoek     case 'w':	// Add an argument
61*8b58e810Skaashoek       if (argc == MAXARGS) {
62*8b58e810Skaashoek 	printf(2, "too many arguments\n");
63*8b58e810Skaashoek 	return -1;
64*8b58e810Skaashoek       }
65*8b58e810Skaashoek       argv[argc++] = t;
66*8b58e810Skaashoek       break;
67*8b58e810Skaashoek 
68*8b58e810Skaashoek     case '<':	// Input redirection
69*8b58e810Skaashoek       // Grab the filename from the argument list
70*8b58e810Skaashoek       if (gettoken(0, &t) != 'w') {
71*8b58e810Skaashoek 	printf(2, "syntax error: < not followed by word\n");
72*8b58e810Skaashoek 	return -1;
73*8b58e810Skaashoek       }
74*8b58e810Skaashoek       addnode('<', t);
75*8b58e810Skaashoek       break;
76*8b58e810Skaashoek 
77*8b58e810Skaashoek     case '>':	// Output redirection
78*8b58e810Skaashoek       // Grab the filename from the argument list
79*8b58e810Skaashoek       if (gettoken(0, &t) != 'w') {
80*8b58e810Skaashoek 	printf(2, "syntax error: > not followed by word\n");
81*8b58e810Skaashoek 	return -1;
82*8b58e810Skaashoek       }
83*8b58e810Skaashoek       addnode('>', t);
84*8b58e810Skaashoek       break;
85*8b58e810Skaashoek 
86*8b58e810Skaashoek     case 0:		// String is complete
87*8b58e810Skaashoek       return 0;
88*8b58e810Skaashoek 
89*8b58e810Skaashoek     default:
90*8b58e810Skaashoek       printf(2, "syntax error: bad return %d from gettoken", c);
91*8b58e810Skaashoek       return -1;
92*8b58e810Skaashoek 
93*8b58e810Skaashoek     }
94*8b58e810Skaashoek   }
95*8b58e810Skaashoek }
96*8b58e810Skaashoek 
97*8b58e810Skaashoek 
98*8b58e810Skaashoek void
99*8b58e810Skaashoek runcmd(void)
100*8b58e810Skaashoek {
101*8b58e810Skaashoek   int i, r, pid;
102*8b58e810Skaashoek 
103*8b58e810Skaashoek   // Return immediately if command line was empty.
104*8b58e810Skaashoek   if(argc == 0) {
105*8b58e810Skaashoek     if (debug)
106*8b58e810Skaashoek       printf(2, "EMPTY COMMAND\n");
107*8b58e810Skaashoek     return;
108*8b58e810Skaashoek   }
109*8b58e810Skaashoek 
110*8b58e810Skaashoek   // Clean up command line.
111*8b58e810Skaashoek   // Read all commands from the filesystem: add an initial '/' to
112*8b58e810Skaashoek   // the command name.
113*8b58e810Skaashoek   // This essentially acts like 'PATH=/'.
114*8b58e810Skaashoek   if (argv[0][0] != '/') {
115*8b58e810Skaashoek     argv0buf[0] = '/';
116*8b58e810Skaashoek     strcpy(argv0buf + 1, argv[0]);
117*8b58e810Skaashoek     argv[0] = argv0buf;
118*8b58e810Skaashoek   }
119*8b58e810Skaashoek   argv[argc] = 0;
120*8b58e810Skaashoek 
121*8b58e810Skaashoek   // Print the command.
122*8b58e810Skaashoek   if (debug) {
123*8b58e810Skaashoek     printf(2, "[%d] SPAWN:", getpid());
124*8b58e810Skaashoek     for (i = 0; argv[i]; i++)
125*8b58e810Skaashoek       printf(2, " %s", argv[i]);
126*8b58e810Skaashoek     for (i = 0; i < nextnode; i++) {
127*8b58e810Skaashoek       printf(2, "%c %s", list[i].token, list[i].s);
128*8b58e810Skaashoek     }
129*8b58e810Skaashoek     printf(2, "\n");
130*8b58e810Skaashoek   }
131*8b58e810Skaashoek 
132*8b58e810Skaashoek   if (strcmp(argv[0], "/cd") == 0) {
133*8b58e810Skaashoek     if (debug) printf (2, "/cd %s is build in\n", argv[1]);
134*8b58e810Skaashoek     chdir(argv[1]);
135*8b58e810Skaashoek     return;
136*8b58e810Skaashoek   }
137*8b58e810Skaashoek 
138*8b58e810Skaashoek   pid = fork();
139*8b58e810Skaashoek   if (pid == 0) {
140*8b58e810Skaashoek     if (ioredirection() < 0)
141*8b58e810Skaashoek       exit();
142*8b58e810Skaashoek     if ((r = exec(argv0buf, (char**) argv)) < 0) {
143*8b58e810Skaashoek       printf(2, "exec %s: %d\n", argv[0], r);
144d7b3b802Skaashoek       exit();
145d7b3b802Skaashoek     }
146d7b3b802Skaashoek   }
147*8b58e810Skaashoek 
148*8b58e810Skaashoek   if (pid > 0) {
149*8b58e810Skaashoek     if (debug)
150*8b58e810Skaashoek       printf(2, "[%d] WAIT %s\n", getpid(), argv[0]);
151*8b58e810Skaashoek     wait();
152*8b58e810Skaashoek     if (debug)
153*8b58e810Skaashoek       printf(2, "[%d] wait finished\n", getpid());
154d7b3b802Skaashoek   }
155d7b3b802Skaashoek }
156*8b58e810Skaashoek 
157*8b58e810Skaashoek int
158*8b58e810Skaashoek ioredirection(void)
159*8b58e810Skaashoek {
160*8b58e810Skaashoek   int i, fd, dfd;
161*8b58e810Skaashoek 
162*8b58e810Skaashoek   for (i = 0; i < nextnode; i++) {
163*8b58e810Skaashoek     switch (list[i].token) {
164*8b58e810Skaashoek     case '<':
165*8b58e810Skaashoek       if ((fd = open(list[i].s, O_RDONLY)) < 0) {
166*8b58e810Skaashoek 	printf(2, "failed to open %s for read: %d", list[i].s, fd);
167*8b58e810Skaashoek 	return -1;
168*8b58e810Skaashoek       }
169*8b58e810Skaashoek 
170*8b58e810Skaashoek       if (debug)
171*8b58e810Skaashoek 	printf(2, "redirect 0 from %s\n", list[i].s);
172*8b58e810Skaashoek 
173*8b58e810Skaashoek       close(0);
174*8b58e810Skaashoek       if ((dfd = dup(fd)) < 0)
175*8b58e810Skaashoek 	printf(2, "dup failed\n");
176*8b58e810Skaashoek       if (debug)
177*8b58e810Skaashoek 	printf(2, "dup returns %d\n", dfd);
178*8b58e810Skaashoek       close(fd);
179*8b58e810Skaashoek       break;
180*8b58e810Skaashoek     case '>':
181*8b58e810Skaashoek       if ((fd = open(list[i].s, O_WRONLY|O_CREATE)) < 0) {
182*8b58e810Skaashoek 	printf(2, "failed to open %s for write: %d", list[i].s, fd);
183*8b58e810Skaashoek 	exit();
184*8b58e810Skaashoek       }
185*8b58e810Skaashoek 
186*8b58e810Skaashoek       if (debug)
187*8b58e810Skaashoek 	printf(2, "redirect 1 to %s\n", list[i].s);
188*8b58e810Skaashoek 
189*8b58e810Skaashoek       if (close(1) < 0)
190*8b58e810Skaashoek 	printf(2, "close 1 failed\n");
191*8b58e810Skaashoek       if ((dfd = dup(fd)) < 0)
192*8b58e810Skaashoek 	printf(2, "dup failed\n");
193*8b58e810Skaashoek       if (debug)
194*8b58e810Skaashoek 	printf(2, "dup returns %d\n", dfd);
195*8b58e810Skaashoek       close(fd);
196*8b58e810Skaashoek       break;
197*8b58e810Skaashoek     }
198*8b58e810Skaashoek   }
199*8b58e810Skaashoek   return 0;
200*8b58e810Skaashoek }
201*8b58e810Skaashoek 
202*8b58e810Skaashoek void
203*8b58e810Skaashoek addnode(int token, char *s)
204*8b58e810Skaashoek {
205*8b58e810Skaashoek   if (nextnode >= MAXNODE) {
206*8b58e810Skaashoek     printf(2, "addnode: ran out of nodes\n");
207*8b58e810Skaashoek     return;
208*8b58e810Skaashoek   }
209*8b58e810Skaashoek 
210*8b58e810Skaashoek   list[nextnode].token = token;
211*8b58e810Skaashoek   list[nextnode].s = s;
212*8b58e810Skaashoek   nextnode++;
213*8b58e810Skaashoek }
214*8b58e810Skaashoek 
215*8b58e810Skaashoek 
216*8b58e810Skaashoek // gettoken(s, 0) prepares gettoken for subsequent calls and returns 0.
217*8b58e810Skaashoek // gettoken(0, token) parses a shell token from the previously set string,
218*8b58e810Skaashoek // null-terminates that token, stores the token pointer in '*token',
219*8b58e810Skaashoek // and returns a token ID (0, '<', '>', '|', or 'w').
220*8b58e810Skaashoek // Subsequent calls to 'gettoken(0, token)' will return subsequent
221*8b58e810Skaashoek // tokens from the string.
222*8b58e810Skaashoek 
223*8b58e810Skaashoek int
224*8b58e810Skaashoek gettoken(char *s, char **p1)
225*8b58e810Skaashoek {
226*8b58e810Skaashoek   static int c, nc;
227*8b58e810Skaashoek   static char* np1, *np2;
228*8b58e810Skaashoek 
229*8b58e810Skaashoek   if (s) {
230*8b58e810Skaashoek     nc = _gettoken(s, &np1, &np2);
231*8b58e810Skaashoek     return 0;
232*8b58e810Skaashoek   }
233*8b58e810Skaashoek   c = nc;
234*8b58e810Skaashoek   *p1 = np1;
235*8b58e810Skaashoek   nc = _gettoken(np2, &np1, &np2);
236*8b58e810Skaashoek   return c;
237*8b58e810Skaashoek }
238*8b58e810Skaashoek 
239*8b58e810Skaashoek 
240*8b58e810Skaashoek // Get the next token from string s.
241*8b58e810Skaashoek // Set *p1 to the beginning of the token and *p2 just past the token.
242*8b58e810Skaashoek // Returns
243*8b58e810Skaashoek //	0 for end-of-string;
244*8b58e810Skaashoek //	< for <;
245*8b58e810Skaashoek //	> for >;
246*8b58e810Skaashoek //	| for |;
247*8b58e810Skaashoek //	w for a word.
248*8b58e810Skaashoek //
249*8b58e810Skaashoek // Eventually (once we parse the space where the \0 will go),
250*8b58e810Skaashoek // words get nul-terminated.
251*8b58e810Skaashoek #define WHITESPACE " \t\r\n"
252*8b58e810Skaashoek #define SYMBOLS "<|>&;()"
253*8b58e810Skaashoek 
254*8b58e810Skaashoek int
255*8b58e810Skaashoek _gettoken(char *s, char **p1, char **p2)
256*8b58e810Skaashoek {
257*8b58e810Skaashoek   int t;
258*8b58e810Skaashoek 
259*8b58e810Skaashoek   if (s == 0) {
260*8b58e810Skaashoek     if (debug > 1)
261*8b58e810Skaashoek       printf(2, "GETTOKEN NULL\n");
262*8b58e810Skaashoek     return 0;
263*8b58e810Skaashoek   }
264*8b58e810Skaashoek 
265*8b58e810Skaashoek   if (debug > 1)
266*8b58e810Skaashoek     printf(2, "GETTOKEN: %s\n", s);
267*8b58e810Skaashoek 
268*8b58e810Skaashoek   *p1 = 0;
269*8b58e810Skaashoek   *p2 = 0;
270*8b58e810Skaashoek 
271*8b58e810Skaashoek   while (strchr(WHITESPACE, *s))
272*8b58e810Skaashoek     *s++ = 0;
273*8b58e810Skaashoek   if (*s == 0) {
274*8b58e810Skaashoek     if (debug > 1)
275*8b58e810Skaashoek       printf(2, "EOL\n");
276*8b58e810Skaashoek     return 0;
277*8b58e810Skaashoek   }
278*8b58e810Skaashoek   if (strchr(SYMBOLS, *s)) {
279*8b58e810Skaashoek     t = *s;
280*8b58e810Skaashoek     *p1 = s;
281*8b58e810Skaashoek     *s++ = 0;
282*8b58e810Skaashoek     *p2 = s;
283*8b58e810Skaashoek     if (debug > 1)
284*8b58e810Skaashoek       printf(2, "TOK %c\n", t);
285*8b58e810Skaashoek     return t;
286*8b58e810Skaashoek   }
287*8b58e810Skaashoek   *p1 = s;
288*8b58e810Skaashoek   while (*s && !strchr(WHITESPACE SYMBOLS, *s))
289*8b58e810Skaashoek     s++;
290*8b58e810Skaashoek   *p2 = s;
291*8b58e810Skaashoek   if (debug > 1) {
292*8b58e810Skaashoek     t = **p2;
293*8b58e810Skaashoek     **p2 = 0;
294*8b58e810Skaashoek     printf(2, "WORD: %s\n", *p1);
295*8b58e810Skaashoek     **p2 = t;
296*8b58e810Skaashoek   }
297*8b58e810Skaashoek   return 'w';
298*8b58e810Skaashoek }
299*8b58e810Skaashoek 
300