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#define FOR_sh
85#include "toys.h"
86
87GLOBALS(
88 char *command;
89
90 long lineno;
91)
92
93
94struct command {
95 struct command *next;
96 int flags;
97 int pid;
98 int argc;
99 char *argv[0];
100};
101
102
103struct pipeline {
104 struct pipeline *next;
105 int job_id;
106 struct command *cmd;
107 char *cmdline;
108 int cmdlinelen;
109};
110
111void cd_main(void)
112{
113 char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
114
115 xchdir(dest ? dest : "/");
116}
117
118void exit_main(void)
119{
120 exit(*toys.optargs ? atoi(*toys.optargs) : 0);
121}
122
123
124
125
126
127static char *parse_word(char *start, struct command **cmd)
128{
129 char *end;
130
131
132 if (strchr("><&|(;", *start)) return 0;
133
134
135 end = start;
136 while (*end && !isspace(*end)) end++;
137 (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start);
138
139
140
141 if (!((*cmd)->argc & 7))
142 *cmd=xrealloc(*cmd,
143 sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *));
144 (*cmd)->argv[(*cmd)->argc] = 0;
145 return end;
146}
147
148
149
150
151static char *parse_pipeline(char *cmdline, struct pipeline *line)
152{
153 struct command **cmd = &(line->cmd);
154 char *start = line->cmdline = cmdline;
155
156 if (!cmdline) return 0;
157
158 line->cmdline = cmdline;
159
160
161 for (;;) {
162 char *end;
163
164
165 while (isspace(*start)) start++;
166 if (!*start || *start=='#') {
167 line->cmdlinelen = start-cmdline;
168 return 0;
169 }
170
171
172 if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *));
173
174
175 end = parse_word(start, cmd);
176
177
178 if (!end) {
179 if (*start) {
180 if (*start==';') {
181 start++;
182 break;
183 }
184
185 }
186 break;
187 }
188 start = end;
189 }
190
191 line->cmdlinelen = start-cmdline;
192
193 return start;
194}
195
196
197static void run_pipeline(struct pipeline *line)
198{
199 struct toy_list *tl;
200 struct command *cmd = line->cmd;
201 if (!cmd || !cmd->argc) return;
202
203 tl = toy_find(cmd->argv[0]);
204
205
206 if (tl && (tl->flags & TOYFLAG_NOFORK)) {
207 struct toy_context temp;
208 jmp_buf rebound;
209
210
211 memcpy(&temp, &toys, sizeof(struct toy_context));
212 memset(&toys, 0, sizeof(struct toy_context));
213
214 if (!setjmp(rebound)) {
215 toys.rebound = &rebound;
216 toy_init(tl, cmd->argv);
217 tl->toy_main();
218 }
219 cmd->pid = toys.exitval;
220 if (toys.optargs != toys.argv+1) free(toys.optargs);
221 if (toys.old_umask) umask(toys.old_umask);
222 memcpy(&toys, &temp, sizeof(struct toy_context));
223 } else {
224 int status;
225
226 cmd->pid = vfork();
227 if (!cmd->pid) xexec(cmd->argv);
228 else waitpid(cmd->pid, &status, 0);
229
230 if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status);
231 if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status);
232 }
233
234 return;
235}
236
237
238static void free_cmd(void *data)
239{
240 struct command *cmd=(struct command *)data;
241
242 while(cmd->argc) free(cmd->argv[--cmd->argc]);
243}
244
245
246
247static void handle(char *command)
248{
249 struct pipeline line;
250 char *start = command;
251
252
253
254 for (;;) {
255
256
257
258 memset(&line,0,sizeof(struct pipeline));
259 start = parse_pipeline(start, &line);
260 if (!line.cmd) break;
261
262
263
264 run_pipeline(&line);
265 llist_traverse(line.cmd, free_cmd);
266 }
267}
268
269static void do_prompt(void)
270{
271 char *prompt = getenv("PS1"), *s, c, cc;
272
273 if (!prompt) prompt = "\\$ ";
274 while (*prompt) {
275 c = *(prompt++);
276
277 if (c=='!') {
278 if (*prompt=='!') prompt++;
279 else {
280 printf("%ld", TT.lineno);
281 continue;
282 }
283 } else if (c=='\\') {
284 cc = *(prompt++);
285 if (!cc) goto down;
286
287
288
289 if (cc=='[' || cc==']') continue;
290 else if (cc=='$') putchar(getuid() ? '$' : '#');
291 else if (cc=='h' || cc=='H') {
292 *toybuf = 0;
293 gethostname(toybuf, sizeof(toybuf)-1);
294 if (cc=='h' && (s = strchr(toybuf, '.'))) *s = 0;
295 fputs(toybuf, stdout);
296 } else if (cc=='s') fputs(getbasename(*toys.argv), stdout);
297 else {
298 if (!(c = unescape(cc))) {
299 c = '\\';
300 prompt--;
301 }
302
303 goto down;
304 }
305 continue;
306 }
307down:
308 putchar(c);
309 }
310}
311
312void sh_main(void)
313{
314 FILE *f = 0;
315
316
317 if (isatty(0)) toys.optflags |= FLAG_i;
318
319 if (*toys.optargs) f = xfopen(*toys.optargs, "r");
320 if (TT.command) handle(xstrdup(TT.command));
321 else {
322 size_t cmdlen = 0;
323 for (;;) {
324 char *command = 0;
325
326
327 if (!f) do_prompt();
328 if (1 > getline(&command, &cmdlen, f ? f : stdin)) break;
329 handle(command);
330 free(command);
331 }
332 }
333
334 toys.exitval = 1;
335}
336