sh.c 8.4 KB

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