sh.c 8.5 KB

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