sh.c 8.4 KB

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