3 #define BUFSIZ 1024 /* Find the buffer overrun bug! */
7 // gettoken(s, 0) prepares gettoken for subsequent calls and returns 0.
8 // gettoken(0, token) parses a shell token from the previously set string,
9 // null-terminates that token, stores the token pointer in '*token',
10 // and returns a token ID (0, '<', '>', '|', or 'w').
11 // Subsequent calls to 'gettoken(0, token)' will return subsequent
12 // tokens from the string.
13 int gettoken(char *s
, char **token
);
16 // Parse a shell command from string 's' and execute it.
17 // Do not return until the shell command is finished.
18 // runcmd() is called in a forked child,
19 // so it's OK to manipulate file descriptor state.
24 char *argv
[MAXARGS
], *t
, argv0buf
[BUFSIZ
];
25 int argc
, c
, i
, r
, p
[2], fd
, pipe_child
;
33 switch ((c
= gettoken(0, &t
))) {
35 case 'w': // Add an argument
36 if (argc
== MAXARGS
) {
37 cprintf("too many arguments\n");
43 case '<': // Input redirection
44 // Grab the filename from the argument list
45 if (gettoken(0, &t
) != 'w') {
46 cprintf("syntax error: < not followed by word\n");
49 // Open 't' for reading as file descriptor 0
50 // (which environments use as standard input).
51 // We can't open a file onto a particular descriptor,
52 // so open the file as 'fd',
53 // then check whether 'fd' is 0.
54 // If not, dup 'fd' onto file descriptor 0,
55 // then close the original 'fd'.
57 // LAB 5: Your code here.
58 panic("< redirection not implemented");
61 case '>': // Output redirection
62 // Grab the filename from the argument list
63 if (gettoken(0, &t
) != 'w') {
64 cprintf("syntax error: > not followed by word\n");
67 // Open 't' for writing as file descriptor 1
68 // (which environments use as standard output).
69 // We can't open a file onto a particular descriptor,
70 // so open the file as 'fd',
71 // then check whether 'fd' is 1.
72 // If not, dup 'fd' onto file descriptor 1,
73 // then close the original 'fd'.
76 // LAB 5: Your code here.
77 panic("> redirection not implemented");
81 // Set up pipe redirection.
83 // Allocate a pipe by calling 'pipe(p)'.
84 // Like the Unix version of pipe() (man 2 pipe),
85 // this function allocates two file descriptors;
86 // data written onto 'p[1]' can be read from 'p[0]'.
88 // The child runs the right side of the pipe:
89 // Use dup() to duplicate the read end of the pipe
90 // (p[0]) onto file descriptor 0 (standard input).
91 // Then close the pipe (both p[0] and p[1]).
92 // (The read end will still be open, as file
94 // Then 'goto again', to parse the rest of the
95 // command line as a new command.
96 // The parent runs the left side of the pipe:
97 // Set 'pipe_child' to the child env ID.
98 // dup() the write end of the pipe onto
99 // file descriptor 1 (standard output).
100 // Then close the pipe.
101 // Then 'goto runit', to execute this piece of
104 // LAB 5: Your code here.
105 panic("| not implemented");
108 case 0: // String is complete
109 // Run the current command!
113 panic("bad return %d from gettoken", c
);
120 // Return immediately if command line was empty.
123 cprintf("EMPTY COMMAND\n");
127 // Clean up command line.
128 // Read all commands from the filesystem: add an initial '/' to
130 // This essentially acts like 'PATH=/'.
131 if (argv
[0][0] != '/') {
133 strcpy(argv0buf
+ 1, argv
[0]);
138 // Print the command.
140 cprintf("[%08x] SPAWN:", thisenv
->env_id
);
141 for (i
= 0; argv
[i
]; i
++)
142 cprintf(" %s", argv
[i
]);
146 // Spawn the command!
147 if ((r
= spawn(argv
[0], (const char**) argv
)) < 0)
148 cprintf("spawn %s: %e\n", argv
[0], r
);
150 // In the parent of the spawned command, close all file descriptors
151 // and wait for the spawned command to exit.
155 cprintf("[%08x] WAIT %s %08x\n", thisenv
->env_id
, argv
[0], r
);
158 cprintf("[%08x] wait finished\n", thisenv
->env_id
);
161 // If we were the left-hand part of a pipe,
162 // wait for the right-hand part to finish.
165 cprintf("[%08x] WAIT pipe_child %08x\n", thisenv
->env_id
, pipe_child
);
168 cprintf("[%08x] wait finished\n", thisenv
->env_id
);
176 // Get the next token from string s.
177 // Set *p1 to the beginning of the token and *p2 just past the token.
179 // 0 for end-of-string;
185 // Eventually (once we parse the space where the \0 will go),
186 // words get nul-terminated.
187 #define WHITESPACE " \t\r\n"
188 #define SYMBOLS "<|>&;()"
191 _gettoken(char *s
, char **p1
, char **p2
)
197 cprintf("GETTOKEN NULL\n");
202 cprintf("GETTOKEN: %s\n", s
);
207 while (strchr(WHITESPACE
, *s
))
214 if (strchr(SYMBOLS
, *s
)) {
220 cprintf("TOK %c\n", t
);
224 while (*s
&& !strchr(WHITESPACE SYMBOLS
, *s
))
230 cprintf("WORD: %s\n", *p1
);
237 gettoken(char *s
, char **p1
)
240 static char* np1
, *np2
;
243 nc
= _gettoken(s
, &np1
, &np2
);
248 nc
= _gettoken(np2
, &np1
, &np2
);
256 cprintf("usage: sh [-dix] [command-file]\n");
261 umain(int argc
, char **argv
)
263 int r
, interactive
, echocmds
;
264 struct Argstate args
;
265 cprintf("[%08x] sh\n", thisenv
->env_id
);
269 argstart(&argc
, argv
, &args
);
270 while ((r
= argnext(&args
)) >= 0)
289 if ((r
= open(argv
[1], O_RDONLY
)) < 0)
290 panic("open %s: %e", argv
[1], r
);
293 if (interactive
== '?') {
294 interactive
= iscons(0);
295 assert(interactive
>= 0);
301 buf
= readline(interactive
? "$ " : NULL
);
304 cprintf("EXITING\n");
305 exit(); // end of file
308 cprintf("LINE: %s\n", buf
);
312 fprintf(1, "# %s\n", buf
);
314 cprintf("BEFORE FORK\n");
315 if ((r
= fork()) < 0)
316 panic("fork: %e", r
);
318 cprintf("FORK: %d\n", r
);