sh.c 9.2 KB

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