sh.c 9.3 KB

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