sh.c 9.2 KB

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