root / prex-0.9.0 / usr / bin / sh / sh.c @ 03e9c04a
History | View | Annotate | Download (9.12 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2005-2009, Kohsuke Ohtani
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions
|
7 |
* are met:
|
8 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
#include <sys/prex.h> |
31 |
#include <sys/keycode.h> |
32 |
#include <sys/syslog.h> |
33 |
#include <sys/wait.h> |
34 |
#include <sys/fcntl.h> |
35 |
|
36 |
#include <limits.h> |
37 |
#include <dirent.h> |
38 |
#include <termios.h> |
39 |
#include <ctype.h> |
40 |
#include <unistd.h> |
41 |
#include <string.h> |
42 |
#include <stdio.h> |
43 |
#include <stdlib.h> |
44 |
#include <errno.h> |
45 |
#include <setjmp.h> |
46 |
#include <libgen.h> /* for basename() */ |
47 |
|
48 |
#include "sh.h" |
49 |
|
50 |
#define ARGMAX 32 |
51 |
|
52 |
#define CMD_PIPE 1 |
53 |
#define CMD_BACKGND 2 |
54 |
#define CMD_BUILTIN 4 |
55 |
|
56 |
extern const struct cmdentry shell_cmds[]; |
57 |
#ifdef CMDBOX
|
58 |
extern const struct cmdentry builtin_cmds[]; |
59 |
#define main(argc, argv) sh_main(argc, argv)
|
60 |
#endif
|
61 |
|
62 |
static pid_t shpid = 0; /* pid of shell */ |
63 |
char retval; /* return value for shell */ |
64 |
unsigned interact; /* if shell reads from stdin */ |
65 |
|
66 |
jmp_buf jmpbuf; |
67 |
|
68 |
static void |
69 |
error(const char *msg, ...) |
70 |
{ |
71 |
va_list ap; |
72 |
|
73 |
va_start(ap, msg); |
74 |
if (msg != NULL) { |
75 |
vfprintf(stderr, msg, ap); |
76 |
fprintf(stderr, "\n");
|
77 |
} |
78 |
va_end(ap); |
79 |
if (getpid() != shpid)
|
80 |
_exit(1);
|
81 |
|
82 |
if (!interact)
|
83 |
_exit(1);
|
84 |
retval = 1;
|
85 |
} |
86 |
|
87 |
static void |
88 |
showsignal(int pid, int s) |
89 |
{ |
90 |
int signo = WTERMSIG(s);
|
91 |
|
92 |
signo &= 0x7f;
|
93 |
if (signo < NSIG && sys_siglist[signo])
|
94 |
error(" %d: %s", pid, sys_siglist[signo]);
|
95 |
else
|
96 |
error(" %d: Signal %d", pid, signo);
|
97 |
|
98 |
retval = signo + 0200;
|
99 |
} |
100 |
|
101 |
static void |
102 |
showprompt(void)
|
103 |
{ |
104 |
static char cwd[PATH_MAX]; |
105 |
static char prompt[PATH_MAX+20]; |
106 |
|
107 |
getcwd(cwd, PATH_MAX); |
108 |
sprintf(prompt, "\033[32m[prex:%s]\033[0m# ", cwd);
|
109 |
write(1, prompt, strlen(prompt));
|
110 |
} |
111 |
|
112 |
static void |
113 |
execute(int argc, char *argv[], int *redir, int flags, cmdfn_t cmdfn) |
114 |
{ |
115 |
int pid, i;
|
116 |
int status;
|
117 |
static char **arg; |
118 |
char *file;
|
119 |
char spid[20]; |
120 |
|
121 |
arg = argc > 1 ? &argv[1] : NULL; |
122 |
file = argv[0];
|
123 |
pid = vfork(); |
124 |
if (pid == -1) { |
125 |
for (i = 0; i < 2; i++) |
126 |
if (redir[i] != -1) |
127 |
close(redir[i]); |
128 |
error("Cannot fork");
|
129 |
return;
|
130 |
} |
131 |
if (pid == 0) { |
132 |
/* Child only */
|
133 |
setpgid(0, 0); |
134 |
tcsetpgrp(2, getpgrp());
|
135 |
|
136 |
for (i = 0; i < 2; i++) { |
137 |
if (redir[i] != -1) { |
138 |
if (dup2(redir[i], i) == -1) |
139 |
error("Cannot redirect %d", i);
|
140 |
close(redir[i]); |
141 |
} |
142 |
} |
143 |
signal(SIGINT, SIG_DFL); |
144 |
signal(SIGQUIT, SIG_DFL); |
145 |
signal(SIGTERM, SIG_DFL); |
146 |
|
147 |
if (flags & CMD_BACKGND) {
|
148 |
signal(SIGINT, SIG_IGN); |
149 |
signal(SIGQUIT, SIG_IGN); |
150 |
if (redir[0] == -1) { |
151 |
close(0);
|
152 |
open("/dev/null", O_RDWR);
|
153 |
} |
154 |
} |
155 |
errno = 0;
|
156 |
if (cmdfn) {
|
157 |
task_setname(task_self(), basename(file)); |
158 |
if (cmdfn(argc, argv) != 0) |
159 |
fprintf(stderr, "%s: %s\n", argv[0], |
160 |
strerror(errno)); |
161 |
} else {
|
162 |
execv(file, arg); |
163 |
/* Try $PATH */
|
164 |
if (errno == ENOENT)
|
165 |
execvp(file, arg); |
166 |
if (errno == ENOENT || errno == ENOTDIR)
|
167 |
error("%s: command not found", argv[0]); |
168 |
else if (errno == EACCES) |
169 |
error("Permission denied");
|
170 |
else
|
171 |
error("%s cannot execute", argv[0]); |
172 |
} |
173 |
exit(1);
|
174 |
/* NOTREACHED */
|
175 |
} |
176 |
/* Parent */
|
177 |
for (i = 0; i < 2; i++) { |
178 |
if (redir[i] != -1) |
179 |
close(redir[i]); |
180 |
} |
181 |
if (flags & CMD_PIPE)
|
182 |
return;
|
183 |
if (flags & CMD_BACKGND) {
|
184 |
sprintf(spid, "%u\n", pid);
|
185 |
write(1, spid, strlen(spid));
|
186 |
return;
|
187 |
} |
188 |
|
189 |
while (wait(&status) != pid);
|
190 |
if (status) {
|
191 |
if (WIFSIGNALED(status))
|
192 |
showsignal(pid, status); |
193 |
else if (WIFEXITED(status)) |
194 |
retval = WEXITSTATUS(status); |
195 |
} else
|
196 |
retval = 0;
|
197 |
return;
|
198 |
} |
199 |
|
200 |
static int |
201 |
redirect(char **args, int *redir) |
202 |
{ |
203 |
unsigned int i, io, append = 0; |
204 |
int fd, argc;
|
205 |
char *p, *file;
|
206 |
|
207 |
for (i = 0; args[i] != NULL; i++) { |
208 |
p = args[i]; |
209 |
switch (*p) {
|
210 |
case '<': |
211 |
io = 0;
|
212 |
break;
|
213 |
case '>': |
214 |
io = 1;
|
215 |
if (*(p + 1) == '>') { |
216 |
append = 1;
|
217 |
p++; |
218 |
} |
219 |
break;
|
220 |
default:
|
221 |
continue;
|
222 |
} |
223 |
|
224 |
/* get file name */
|
225 |
args[i] = (char *)-1; |
226 |
if (*(p + 1) == '\0') { |
227 |
file = args[++i]; |
228 |
args[i] = (char *)-1; |
229 |
} else
|
230 |
file = p + 1;
|
231 |
|
232 |
/* if redirected from pipe, ignore */
|
233 |
if (redir[io] == -1) { |
234 |
if (io == 1) { |
235 |
if (append)
|
236 |
fd = open(file, O_WRONLY | O_APPEND); |
237 |
else
|
238 |
fd = creat(file, 0666);
|
239 |
} else
|
240 |
fd = open(file, O_RDONLY); |
241 |
|
242 |
if (fd == -1) { |
243 |
error("%s: cannot open", file);
|
244 |
return -1; |
245 |
} |
246 |
redir[io] = fd; |
247 |
} |
248 |
} |
249 |
|
250 |
/* strip redirection info */
|
251 |
argc = 0;
|
252 |
for (i = 0; args[i]; i++) { |
253 |
if (args[i] != (char *)-1) |
254 |
args[argc++] = args[i]; |
255 |
} |
256 |
args[argc] = NULL;
|
257 |
return argc;
|
258 |
} |
259 |
|
260 |
static cmdfn_t
|
261 |
findcmd(const struct cmdentry cmds[], char *cmd) |
262 |
{ |
263 |
int i = 0; |
264 |
|
265 |
while (cmds[i].cmd != NULL) { |
266 |
if (!strcmp(cmd, cmds[i].cmd))
|
267 |
return cmds[i].func;
|
268 |
i++; |
269 |
} |
270 |
return 0; |
271 |
} |
272 |
|
273 |
static void |
274 |
parsecmd(char *cmds, int *redir, int flags) |
275 |
{ |
276 |
static char cmdbox[] = "cmdbox"; |
277 |
static char *args[ARGMAX]; |
278 |
char *p, *word = NULL; |
279 |
cmdfn_t fn; |
280 |
int i, argc = 0; |
281 |
|
282 |
optind = 1; /* for nommu */ |
283 |
|
284 |
if (cmds[0] != ' ' && cmds[0] != '\t') |
285 |
word = cmds; |
286 |
|
287 |
p = cmds; |
288 |
while (*p) {
|
289 |
if (word == NULL) { |
290 |
/* Skip white space. */
|
291 |
if (*p != ' ' && *p != '\t') |
292 |
word = p; |
293 |
} else {
|
294 |
if (*p == ' ' || *p == '\t') { |
295 |
*p = '\0';
|
296 |
args[argc++] = word; |
297 |
word = NULL;
|
298 |
if (argc >= ARGMAX - 1) { |
299 |
error("Too many args");
|
300 |
return;
|
301 |
} |
302 |
} |
303 |
} |
304 |
p++; |
305 |
} |
306 |
if (argc == 0 && word == NULL) |
307 |
return;
|
308 |
|
309 |
if (word)
|
310 |
args[argc++] = word; |
311 |
args[argc] = NULL;
|
312 |
|
313 |
/* Handle variable */
|
314 |
if ((p = strchr(args[0], '=')) != NULL) { |
315 |
*p++ = '\0';
|
316 |
if (*p == '\0') |
317 |
unsetvar(args[0]);
|
318 |
else
|
319 |
setvar(args[0], p);
|
320 |
return;
|
321 |
} |
322 |
|
323 |
fn = findcmd(shell_cmds, args[0]);
|
324 |
if (fn) {
|
325 |
/* Run as shell internal command */
|
326 |
if ((*fn)(argc, args) != 0) |
327 |
error("%s: %s", args[0], strerror(errno)); |
328 |
return;
|
329 |
} |
330 |
argc = redirect(args, redir); |
331 |
if (argc == -1) |
332 |
return;
|
333 |
|
334 |
fn = findcmd(builtin_cmds, args[0]);
|
335 |
|
336 |
/*
|
337 |
* Alias: 'sh' => 'cmdbox sh'
|
338 |
*/
|
339 |
if (fn == NULL && !strcmp(args[0], "sh")) { |
340 |
for (i = argc; i >= 0; i--) |
341 |
args[i + 1] = args[i];
|
342 |
args[0] = cmdbox;
|
343 |
argc++; |
344 |
} |
345 |
execute(argc, args, redir, flags, fn); |
346 |
} |
347 |
|
348 |
static void |
349 |
parsepipe(char *str, int flags) |
350 |
{ |
351 |
int pip[2] = { -1, -1 }; |
352 |
int redir[2] = { -1, -1 }; |
353 |
char *p, *cmds;
|
354 |
|
355 |
p = cmds = str; |
356 |
while (*cmds) {
|
357 |
switch (*p) {
|
358 |
case '|': |
359 |
*p = '\0';
|
360 |
redir[0] = pip[0]; |
361 |
if (pipe(pip) == -1) { |
362 |
error("Cannot pipe");
|
363 |
return;
|
364 |
} |
365 |
redir[1] = pip[1]; |
366 |
parsecmd(cmds, redir, flags | CMD_PIPE); |
367 |
cmds = p + 1;
|
368 |
break;
|
369 |
case '\0': |
370 |
redir[0] = pip[0]; |
371 |
redir[1] = -1; |
372 |
parsecmd(cmds, redir, flags); |
373 |
return;
|
374 |
} |
375 |
p++; |
376 |
} |
377 |
} |
378 |
|
379 |
static void |
380 |
parseline(char *line)
|
381 |
{ |
382 |
char *p, *cmds;
|
383 |
|
384 |
p = cmds = line; |
385 |
while (*cmds) {
|
386 |
switch (*p) {
|
387 |
case ';': |
388 |
*p = '\0';
|
389 |
parsepipe(cmds, 0);
|
390 |
cmds = p + 1;
|
391 |
break;
|
392 |
case '&': |
393 |
*p = '\0';
|
394 |
parsepipe(cmds, CMD_BACKGND); |
395 |
cmds = p + 1;
|
396 |
break;
|
397 |
case '\0': |
398 |
case '\n': |
399 |
case '#': |
400 |
*p = '\0';
|
401 |
parsepipe(cmds, 0);
|
402 |
return;
|
403 |
} |
404 |
p++; |
405 |
} |
406 |
} |
407 |
|
408 |
static char * |
409 |
readline(int fd, char *line, int len) |
410 |
{ |
411 |
char *p = line;
|
412 |
int nleft = len;
|
413 |
int cnt;
|
414 |
|
415 |
while (--nleft > 0) { |
416 |
cnt = read(fd, p, 1);
|
417 |
if (cnt == -1) |
418 |
return (char *)-1; /* error */ |
419 |
if (cnt == 0) { |
420 |
if (p == line)
|
421 |
return NULL; /* EOF */ |
422 |
break;
|
423 |
} |
424 |
if (*p == '\n') |
425 |
break;
|
426 |
p++; |
427 |
} |
428 |
*p = '\0';
|
429 |
return line;
|
430 |
} |
431 |
|
432 |
static void |
433 |
cmdloop(int fd)
|
434 |
{ |
435 |
static char line[LINE_MAX]; |
436 |
char *p;
|
437 |
|
438 |
for (;;) {
|
439 |
if (interact)
|
440 |
showprompt(); |
441 |
|
442 |
line[0] = '\0'; |
443 |
p = readline(fd, line, sizeof(line));
|
444 |
if (p == (char *)-1) |
445 |
continue;
|
446 |
if (p == NULL) |
447 |
break;
|
448 |
parseline(line); |
449 |
tcsetpgrp(2, shpid);
|
450 |
} |
451 |
} |
452 |
|
453 |
int
|
454 |
main(int argc, char **argv) |
455 |
{ |
456 |
int input;
|
457 |
|
458 |
if (shpid == 0) |
459 |
shpid = getpid(); |
460 |
|
461 |
if (setjmp(jmpbuf)) {
|
462 |
argv = (char **)0; |
463 |
argc = 1;
|
464 |
} |
465 |
interact = 1;
|
466 |
initvar(); |
467 |
|
468 |
if (argc == 1) { |
469 |
input = 0;
|
470 |
if (isatty(0) && isatty(1)) { |
471 |
interact = 1;
|
472 |
signal(SIGINT, SIG_IGN); |
473 |
signal(SIGQUIT, SIG_IGN); |
474 |
signal(SIGTERM, SIG_IGN); |
475 |
} |
476 |
} else {
|
477 |
interact = 0;
|
478 |
close(0);
|
479 |
input = open(argv[1], O_RDONLY);
|
480 |
if (input < 0) { |
481 |
fprintf(stderr, "%s: cannot open\n", argv[1]); |
482 |
interact = 1;
|
483 |
exit(1);
|
484 |
} |
485 |
} |
486 |
cmdloop(input); |
487 |
exit(retval); |
488 |
return 0; |
489 |
} |