sh.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #include <stdint.h>
  2. #include <stdarg.h>
  3. #include <sys/wait.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. int printf(const char* fmt, ...)
  9. {
  10. va_list args;
  11. va_start(args, fmt);
  12. char buf[256] = {};
  13. int len = vsnprintf(buf, sizeof(buf), fmt, args);
  14. len = write(STDOUT_FILENO, buf, len);
  15. va_end(args);
  16. return len;
  17. }
  18. char* strchr(const char* str, int c)
  19. {
  20. const char* p = str;
  21. while (*p) {
  22. if (*p == c)
  23. return (char*)p;
  24. ++p;
  25. }
  26. return NULL;
  27. }
  28. char* gets(char* buf, int bufsize)
  29. {
  30. int n = read(STDIN_FILENO, buf, bufsize);
  31. if (n > 0) {
  32. if (buf[n-1] == '\n')
  33. buf[n-1] = 0;
  34. else
  35. buf[n] = 0;
  36. return buf;
  37. }
  38. return NULL;
  39. }
  40. int puts(const char* str)
  41. {
  42. int len = strlen(str);
  43. write(STDOUT_FILENO, str, len);
  44. return len + 1;
  45. }
  46. void* malloc(size_t n)
  47. {
  48. static char mems[1024];
  49. static int pos;
  50. int orig_pos = pos;
  51. pos += n;
  52. return mems + orig_pos;
  53. }
  54. // Parsed command representation
  55. #define EXEC 1
  56. #define REDIR 2
  57. #define PIPE 3
  58. #define LIST 4
  59. #define BACK 5
  60. #define MAXARGS 10
  61. struct cmd {
  62. int type;
  63. };
  64. struct execcmd {
  65. int type;
  66. char *argv[MAXARGS];
  67. char *eargv[MAXARGS];
  68. };
  69. struct redircmd {
  70. int type;
  71. struct cmd *cmd;
  72. char *file;
  73. char *efile;
  74. int mode;
  75. int fd;
  76. };
  77. struct pipecmd {
  78. int type;
  79. struct cmd *left;
  80. struct cmd *right;
  81. };
  82. struct listcmd {
  83. int type;
  84. struct cmd *left;
  85. struct cmd *right;
  86. };
  87. struct backcmd {
  88. int type;
  89. struct cmd *cmd;
  90. };
  91. int fork1(void); // Fork but panics on failure.
  92. void panic(char*);
  93. struct cmd *parsecmd(char*);
  94. // Execute cmd. Never returns.
  95. void
  96. runcmd(struct cmd *cmd)
  97. {
  98. int p[2];
  99. int code;
  100. struct backcmd *bcmd;
  101. struct execcmd *ecmd;
  102. struct listcmd *lcmd;
  103. struct pipecmd *pcmd;
  104. struct redircmd *rcmd;
  105. if(cmd == 0)
  106. _exit(-1);
  107. switch(cmd->type){
  108. default:
  109. panic("runcmd");
  110. case EXEC:
  111. ecmd = (struct execcmd*)cmd;
  112. if(ecmd->argv[0] == 0)
  113. _exit(-1);
  114. char* const envp[1] = { NULL };
  115. execve(ecmd->argv[0], ecmd->argv, envp);
  116. printf("exec %s failed\n", ecmd->argv[0]);
  117. break;
  118. case REDIR:
  119. rcmd = (struct redircmd*)cmd;
  120. close(rcmd->fd);
  121. if(open(rcmd->file, rcmd->mode) < 0){
  122. printf("open %s failed\n", rcmd->file);
  123. _exit(-1);
  124. }
  125. runcmd(rcmd->cmd);
  126. break;
  127. case LIST:
  128. lcmd = (struct listcmd*)cmd;
  129. if(fork1() == 0)
  130. runcmd(lcmd->left);
  131. wait(&code);
  132. runcmd(lcmd->right);
  133. break;
  134. case PIPE:
  135. pcmd = (struct pipecmd*)cmd;
  136. if(pipe(p) < 0)
  137. panic("pipe");
  138. if(fork1() == 0){
  139. close(1);
  140. dup(p[1]);
  141. close(p[0]);
  142. close(p[1]);
  143. runcmd(pcmd->left);
  144. }
  145. if(fork1() == 0){
  146. close(0);
  147. dup(p[0]);
  148. close(p[0]);
  149. close(p[1]);
  150. runcmd(pcmd->right);
  151. }
  152. close(p[0]);
  153. close(p[1]);
  154. wait(&code);
  155. wait(&code);
  156. break;
  157. case BACK:
  158. bcmd = (struct backcmd*)cmd;
  159. if(fork1() == 0)
  160. runcmd(bcmd->cmd);
  161. break;
  162. }
  163. _exit(0);
  164. }
  165. int
  166. getcmd(char *buf, int nbuf)
  167. {
  168. printf("$ ");
  169. memset(buf, 0, nbuf);
  170. gets(buf, nbuf);
  171. if(buf[0] == 0) // EOF
  172. return -1;
  173. return 0;
  174. }
  175. int
  176. main(void)
  177. {
  178. static char buf[100];
  179. int fd = 0;
  180. // Assumes three file descriptors open.
  181. while((fd = open("/dev/console", 0)) >= 0){
  182. if(fd >= 3){
  183. close(fd);
  184. break;
  185. }
  186. }
  187. // Read and run input commands.
  188. while(getcmd(buf, sizeof(buf)) >= 0){
  189. if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ')
  190. {
  191. // Clumsy but will have to do for now.
  192. // Chdir has no effect on the parent if run in the child.
  193. if(chdir(buf+3) < 0)
  194. printf("cannot cd %s\n", buf+3);
  195. continue;
  196. }
  197. pid_t pid = 0;
  198. if((pid = fork1()) == 0) {
  199. setpgid(0, 0);
  200. runcmd(parsecmd(buf));
  201. }
  202. tcsetpgrp(STDOUT_FILENO, pid);
  203. setpgid(pid, 0);
  204. int code;
  205. wait(&code);
  206. tcsetpgrp(STDOUT_FILENO, getpid());
  207. printf("[status: %d] ", code);
  208. }
  209. _exit(0);
  210. }
  211. void __attribute__((noreturn))
  212. panic(char *s)
  213. {
  214. printf("%s\n", s);
  215. _exit(-1);
  216. }
  217. int
  218. fork1(void)
  219. {
  220. int pid;
  221. pid = fork();
  222. if(pid == -1)
  223. panic("fork");
  224. return pid;
  225. }
  226. //PAGEBREAK!
  227. // Constructors
  228. struct cmd*
  229. execcmd(void)
  230. {
  231. struct execcmd *cmd;
  232. cmd = malloc(sizeof(*cmd));
  233. memset(cmd, 0, sizeof(*cmd));
  234. cmd->type = EXEC;
  235. return (struct cmd*)cmd;
  236. }
  237. struct cmd*
  238. redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
  239. {
  240. struct redircmd *cmd;
  241. cmd = malloc(sizeof(*cmd));
  242. memset(cmd, 0, sizeof(*cmd));
  243. cmd->type = REDIR;
  244. cmd->cmd = subcmd;
  245. cmd->file = file;
  246. cmd->efile = efile;
  247. cmd->mode = mode;
  248. cmd->fd = fd;
  249. return (struct cmd*)cmd;
  250. }
  251. struct cmd*
  252. pipecmd(struct cmd *left, struct cmd *right)
  253. {
  254. struct pipecmd *cmd;
  255. cmd = malloc(sizeof(*cmd));
  256. memset(cmd, 0, sizeof(*cmd));
  257. cmd->type = PIPE;
  258. cmd->left = left;
  259. cmd->right = right;
  260. return (struct cmd*)cmd;
  261. }
  262. struct cmd*
  263. listcmd(struct cmd *left, struct cmd *right)
  264. {
  265. struct listcmd *cmd;
  266. cmd = malloc(sizeof(*cmd));
  267. memset(cmd, 0, sizeof(*cmd));
  268. cmd->type = LIST;
  269. cmd->left = left;
  270. cmd->right = right;
  271. return (struct cmd*)cmd;
  272. }
  273. struct cmd*
  274. backcmd(struct cmd *subcmd)
  275. {
  276. struct backcmd *cmd;
  277. cmd = malloc(sizeof(*cmd));
  278. memset(cmd, 0, sizeof(*cmd));
  279. cmd->type = BACK;
  280. cmd->cmd = subcmd;
  281. return (struct cmd*)cmd;
  282. }
  283. //PAGEBREAK!
  284. // Parsing
  285. char whitespace[] = " \t\r\n\v";
  286. char symbols[] = "<|>&;()";
  287. int
  288. gettoken(char **ps, char *es, char **q, char **eq)
  289. {
  290. char *s;
  291. int ret;
  292. s = *ps;
  293. while(s < es && strchr(whitespace, *s))
  294. s++;
  295. if(q)
  296. *q = s;
  297. ret = *s;
  298. switch(*s){
  299. case 0:
  300. break;
  301. case '|':
  302. case '(':
  303. case ')':
  304. case ';':
  305. case '&':
  306. case '<':
  307. s++;
  308. break;
  309. case '>':
  310. s++;
  311. if(*s == '>'){
  312. ret = '+';
  313. s++;
  314. }
  315. break;
  316. default:
  317. ret = 'a';
  318. while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
  319. s++;
  320. break;
  321. }
  322. if(eq)
  323. *eq = s;
  324. while(s < es && strchr(whitespace, *s))
  325. s++;
  326. *ps = s;
  327. return ret;
  328. }
  329. int
  330. peek(char **ps, char *es, char *toks)
  331. {
  332. char *s;
  333. s = *ps;
  334. while(s < es && strchr(whitespace, *s))
  335. s++;
  336. *ps = s;
  337. return *s && strchr(toks, *s);
  338. }
  339. struct cmd *parseline(char**, char*);
  340. struct cmd *parsepipe(char**, char*);
  341. struct cmd *parseexec(char**, char*);
  342. struct cmd *nulterminate(struct cmd*);
  343. struct cmd*
  344. parsecmd(char *s)
  345. {
  346. char *es;
  347. struct cmd *cmd;
  348. es = s + strlen(s);
  349. cmd = parseline(&s, es);
  350. peek(&s, es, "");
  351. if(s != es){
  352. printf("leftovers: %s\n", s);
  353. panic("syntax");
  354. }
  355. nulterminate(cmd);
  356. return cmd;
  357. }
  358. struct cmd*
  359. parseline(char **ps, char *es)
  360. {
  361. struct cmd *cmd;
  362. cmd = parsepipe(ps, es);
  363. while(peek(ps, es, "&")){
  364. gettoken(ps, es, 0, 0);
  365. cmd = backcmd(cmd);
  366. }
  367. if(peek(ps, es, ";")){
  368. gettoken(ps, es, 0, 0);
  369. cmd = listcmd(cmd, parseline(ps, es));
  370. }
  371. return cmd;
  372. }
  373. struct cmd*
  374. parsepipe(char **ps, char *es)
  375. {
  376. struct cmd *cmd;
  377. cmd = parseexec(ps, es);
  378. if(peek(ps, es, "|")){
  379. gettoken(ps, es, 0, 0);
  380. cmd = pipecmd(cmd, parsepipe(ps, es));
  381. }
  382. return cmd;
  383. }
  384. struct cmd*
  385. parseredirs(struct cmd *cmd, char **ps, char *es)
  386. {
  387. int tok;
  388. char *q, *eq;
  389. while(peek(ps, es, "<>")){
  390. tok = gettoken(ps, es, 0, 0);
  391. if(gettoken(ps, es, &q, &eq) != 'a')
  392. panic("missing file for redirection");
  393. switch(tok){
  394. case '<':
  395. cmd = redircmd(cmd, q, eq, 0, 0);
  396. break;
  397. case '>':
  398. cmd = redircmd(cmd, q, eq, 0, 1);
  399. break;
  400. case '+': // >>
  401. cmd = redircmd(cmd, q, eq, 0, 1);
  402. break;
  403. }
  404. }
  405. return cmd;
  406. }
  407. struct cmd*
  408. parseblock(char **ps, char *es)
  409. {
  410. struct cmd *cmd;
  411. if(!peek(ps, es, "("))
  412. panic("parseblock");
  413. gettoken(ps, es, 0, 0);
  414. cmd = parseline(ps, es);
  415. if(!peek(ps, es, ")"))
  416. panic("syntax - missing )");
  417. gettoken(ps, es, 0, 0);
  418. cmd = parseredirs(cmd, ps, es);
  419. return cmd;
  420. }
  421. struct cmd*
  422. parseexec(char **ps, char *es)
  423. {
  424. char *q, *eq;
  425. int tok, argc;
  426. struct execcmd *cmd;
  427. struct cmd *ret;
  428. if(peek(ps, es, "("))
  429. return parseblock(ps, es);
  430. ret = execcmd();
  431. cmd = (struct execcmd*)ret;
  432. argc = 0;
  433. ret = parseredirs(ret, ps, es);
  434. while(!peek(ps, es, "|)&;")){
  435. if((tok=gettoken(ps, es, &q, &eq)) == 0)
  436. break;
  437. if(tok != 'a')
  438. panic("syntax");
  439. cmd->argv[argc] = q;
  440. cmd->eargv[argc] = eq;
  441. argc++;
  442. if(argc >= MAXARGS)
  443. panic("too many args");
  444. ret = parseredirs(ret, ps, es);
  445. }
  446. cmd->argv[argc] = 0;
  447. cmd->eargv[argc] = 0;
  448. return ret;
  449. }
  450. // NUL-terminate all the counted strings.
  451. struct cmd*
  452. nulterminate(struct cmd *cmd)
  453. {
  454. int i;
  455. struct backcmd *bcmd;
  456. struct execcmd *ecmd;
  457. struct listcmd *lcmd;
  458. struct pipecmd *pcmd;
  459. struct redircmd *rcmd;
  460. if(cmd == 0)
  461. return 0;
  462. switch(cmd->type){
  463. case EXEC:
  464. ecmd = (struct execcmd*)cmd;
  465. for(i=0; ecmd->argv[i]; i++)
  466. *ecmd->eargv[i] = 0;
  467. break;
  468. case REDIR:
  469. rcmd = (struct redircmd*)cmd;
  470. nulterminate(rcmd->cmd);
  471. *rcmd->efile = 0;
  472. break;
  473. case PIPE:
  474. pcmd = (struct pipecmd*)cmd;
  475. nulterminate(pcmd->left);
  476. nulterminate(pcmd->right);
  477. break;
  478. case LIST:
  479. lcmd = (struct listcmd*)cmd;
  480. nulterminate(lcmd->left);
  481. nulterminate(lcmd->right);
  482. break;
  483. case BACK:
  484. bcmd = (struct backcmd*)cmd;
  485. nulterminate(bcmd->cmd);
  486. break;
  487. }
  488. return cmd;
  489. }