|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/bin/sh/sh.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |