sh.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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. if(fork1() == 0)
  198. runcmd(parsecmd(buf));
  199. int code;
  200. wait(&code);
  201. }
  202. _exit(0);
  203. }
  204. void __attribute__((noreturn))
  205. panic(char *s)
  206. {
  207. printf("%s\n", s);
  208. _exit(-1);
  209. }
  210. int
  211. fork1(void)
  212. {
  213. int pid;
  214. pid = fork();
  215. if(pid == -1)
  216. panic("fork");
  217. return pid;
  218. }
  219. //PAGEBREAK!
  220. // Constructors
  221. struct cmd*
  222. execcmd(void)
  223. {
  224. struct execcmd *cmd;
  225. cmd = malloc(sizeof(*cmd));
  226. memset(cmd, 0, sizeof(*cmd));
  227. cmd->type = EXEC;
  228. return (struct cmd*)cmd;
  229. }
  230. struct cmd*
  231. redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
  232. {
  233. struct redircmd *cmd;
  234. cmd = malloc(sizeof(*cmd));
  235. memset(cmd, 0, sizeof(*cmd));
  236. cmd->type = REDIR;
  237. cmd->cmd = subcmd;
  238. cmd->file = file;
  239. cmd->efile = efile;
  240. cmd->mode = mode;
  241. cmd->fd = fd;
  242. return (struct cmd*)cmd;
  243. }
  244. struct cmd*
  245. pipecmd(struct cmd *left, struct cmd *right)
  246. {
  247. struct pipecmd *cmd;
  248. cmd = malloc(sizeof(*cmd));
  249. memset(cmd, 0, sizeof(*cmd));
  250. cmd->type = PIPE;
  251. cmd->left = left;
  252. cmd->right = right;
  253. return (struct cmd*)cmd;
  254. }
  255. struct cmd*
  256. listcmd(struct cmd *left, struct cmd *right)
  257. {
  258. struct listcmd *cmd;
  259. cmd = malloc(sizeof(*cmd));
  260. memset(cmd, 0, sizeof(*cmd));
  261. cmd->type = LIST;
  262. cmd->left = left;
  263. cmd->right = right;
  264. return (struct cmd*)cmd;
  265. }
  266. struct cmd*
  267. backcmd(struct cmd *subcmd)
  268. {
  269. struct backcmd *cmd;
  270. cmd = malloc(sizeof(*cmd));
  271. memset(cmd, 0, sizeof(*cmd));
  272. cmd->type = BACK;
  273. cmd->cmd = subcmd;
  274. return (struct cmd*)cmd;
  275. }
  276. //PAGEBREAK!
  277. // Parsing
  278. char whitespace[] = " \t\r\n\v";
  279. char symbols[] = "<|>&;()";
  280. int
  281. gettoken(char **ps, char *es, char **q, char **eq)
  282. {
  283. char *s;
  284. int ret;
  285. s = *ps;
  286. while(s < es && strchr(whitespace, *s))
  287. s++;
  288. if(q)
  289. *q = s;
  290. ret = *s;
  291. switch(*s){
  292. case 0:
  293. break;
  294. case '|':
  295. case '(':
  296. case ')':
  297. case ';':
  298. case '&':
  299. case '<':
  300. s++;
  301. break;
  302. case '>':
  303. s++;
  304. if(*s == '>'){
  305. ret = '+';
  306. s++;
  307. }
  308. break;
  309. default:
  310. ret = 'a';
  311. while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
  312. s++;
  313. break;
  314. }
  315. if(eq)
  316. *eq = s;
  317. while(s < es && strchr(whitespace, *s))
  318. s++;
  319. *ps = s;
  320. return ret;
  321. }
  322. int
  323. peek(char **ps, char *es, char *toks)
  324. {
  325. char *s;
  326. s = *ps;
  327. while(s < es && strchr(whitespace, *s))
  328. s++;
  329. *ps = s;
  330. return *s && strchr(toks, *s);
  331. }
  332. struct cmd *parseline(char**, char*);
  333. struct cmd *parsepipe(char**, char*);
  334. struct cmd *parseexec(char**, char*);
  335. struct cmd *nulterminate(struct cmd*);
  336. struct cmd*
  337. parsecmd(char *s)
  338. {
  339. char *es;
  340. struct cmd *cmd;
  341. es = s + strlen(s);
  342. cmd = parseline(&s, es);
  343. peek(&s, es, "");
  344. if(s != es){
  345. printf("leftovers: %s\n", s);
  346. panic("syntax");
  347. }
  348. nulterminate(cmd);
  349. return cmd;
  350. }
  351. struct cmd*
  352. parseline(char **ps, char *es)
  353. {
  354. struct cmd *cmd;
  355. cmd = parsepipe(ps, es);
  356. while(peek(ps, es, "&")){
  357. gettoken(ps, es, 0, 0);
  358. cmd = backcmd(cmd);
  359. }
  360. if(peek(ps, es, ";")){
  361. gettoken(ps, es, 0, 0);
  362. cmd = listcmd(cmd, parseline(ps, es));
  363. }
  364. return cmd;
  365. }
  366. struct cmd*
  367. parsepipe(char **ps, char *es)
  368. {
  369. struct cmd *cmd;
  370. cmd = parseexec(ps, es);
  371. if(peek(ps, es, "|")){
  372. gettoken(ps, es, 0, 0);
  373. cmd = pipecmd(cmd, parsepipe(ps, es));
  374. }
  375. return cmd;
  376. }
  377. struct cmd*
  378. parseredirs(struct cmd *cmd, char **ps, char *es)
  379. {
  380. int tok;
  381. char *q, *eq;
  382. while(peek(ps, es, "<>")){
  383. tok = gettoken(ps, es, 0, 0);
  384. if(gettoken(ps, es, &q, &eq) != 'a')
  385. panic("missing file for redirection");
  386. switch(tok){
  387. case '<':
  388. cmd = redircmd(cmd, q, eq, 0, 0);
  389. break;
  390. case '>':
  391. cmd = redircmd(cmd, q, eq, 0, 1);
  392. break;
  393. case '+': // >>
  394. cmd = redircmd(cmd, q, eq, 0, 1);
  395. break;
  396. }
  397. }
  398. return cmd;
  399. }
  400. struct cmd*
  401. parseblock(char **ps, char *es)
  402. {
  403. struct cmd *cmd;
  404. if(!peek(ps, es, "("))
  405. panic("parseblock");
  406. gettoken(ps, es, 0, 0);
  407. cmd = parseline(ps, es);
  408. if(!peek(ps, es, ")"))
  409. panic("syntax - missing )");
  410. gettoken(ps, es, 0, 0);
  411. cmd = parseredirs(cmd, ps, es);
  412. return cmd;
  413. }
  414. struct cmd*
  415. parseexec(char **ps, char *es)
  416. {
  417. char *q, *eq;
  418. int tok, argc;
  419. struct execcmd *cmd;
  420. struct cmd *ret;
  421. if(peek(ps, es, "("))
  422. return parseblock(ps, es);
  423. ret = execcmd();
  424. cmd = (struct execcmd*)ret;
  425. argc = 0;
  426. ret = parseredirs(ret, ps, es);
  427. while(!peek(ps, es, "|)&;")){
  428. if((tok=gettoken(ps, es, &q, &eq)) == 0)
  429. break;
  430. if(tok != 'a')
  431. panic("syntax");
  432. cmd->argv[argc] = q;
  433. cmd->eargv[argc] = eq;
  434. argc++;
  435. if(argc >= MAXARGS)
  436. panic("too many args");
  437. ret = parseredirs(ret, ps, es);
  438. }
  439. cmd->argv[argc] = 0;
  440. cmd->eargv[argc] = 0;
  441. return ret;
  442. }
  443. // NUL-terminate all the counted strings.
  444. struct cmd*
  445. nulterminate(struct cmd *cmd)
  446. {
  447. int i;
  448. struct backcmd *bcmd;
  449. struct execcmd *ecmd;
  450. struct listcmd *lcmd;
  451. struct pipecmd *pcmd;
  452. struct redircmd *rcmd;
  453. if(cmd == 0)
  454. return 0;
  455. switch(cmd->type){
  456. case EXEC:
  457. ecmd = (struct execcmd*)cmd;
  458. for(i=0; ecmd->argv[i]; i++)
  459. *ecmd->eargv[i] = 0;
  460. break;
  461. case REDIR:
  462. rcmd = (struct redircmd*)cmd;
  463. nulterminate(rcmd->cmd);
  464. *rcmd->efile = 0;
  465. break;
  466. case PIPE:
  467. pcmd = (struct pipecmd*)cmd;
  468. nulterminate(pcmd->left);
  469. nulterminate(pcmd->right);
  470. break;
  471. case LIST:
  472. lcmd = (struct listcmd*)cmd;
  473. nulterminate(lcmd->left);
  474. nulterminate(lcmd->right);
  475. break;
  476. case BACK:
  477. bcmd = (struct backcmd*)cmd;
  478. nulterminate(bcmd->cmd);
  479. break;
  480. }
  481. return cmd;
  482. }