sh.C 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /* sh - simple shell - great for early stages of porting */
  2. #include "u.h"
  3. #include "libc.h"
  4. #define MAXLINE 200 /* maximum line length */
  5. #define WORD 256 /* token code for words */
  6. #define EOF -1 /* token code for end of file */
  7. #define ispunct(c) (c=='|' || c=='&' || c==';' || c=='<' || \
  8. c=='>' || c=='(' || c==')' || c=='\n')
  9. #define isspace(c) (c==' ' || c=='\t')
  10. #define execute(np) (np? (*(np)->op)(np) : 0)
  11. typedef struct Node Node;
  12. struct Node{ /* parse tree node */
  13. int (*op)(Node *); /* operator function */
  14. Node *args[2]; /* argument nodes */
  15. char *argv[100]; /* argument pointers */
  16. char *io[3]; /* i/o redirection */
  17. };
  18. Node nodes[25]; /* node pool */
  19. Node *nfree; /* next available node */
  20. char strspace[10*MAXLINE]; /* string storage */
  21. char *sfree; /* next free character in strspace */
  22. int t; /* current token code */
  23. char *token; /* current token text (in strspace) */
  24. int putback = 0; /* lookahead */
  25. Waitmsg status; /* exit status of most recent command */
  26. int cflag = 0; /* command is argument to sh */
  27. int tflag = 0; /* read only one line */
  28. int interactive = 0; /* prompt */
  29. char *cflagp; /* command line for cflag */
  30. char *path[] ={"/bin", 0};
  31. Node *alloc(int (*op)(Node *));
  32. int builtin(Node *np);
  33. Node *command(void);
  34. int getch(void);
  35. int gettoken(void);
  36. Node *list(void);
  37. void error(char *s, char *t);
  38. Node *pipeline(void);
  39. void redirect(Node *np);
  40. int setio(Node *np);
  41. Node *simple(void);
  42. int xpipeline(Node *np);
  43. int xsimple(Node *np);
  44. int xsubshell(Node *np);
  45. int xnowait(Node *np);
  46. int xwait(Node *np);
  47. main(int argc, char *argv[])
  48. {
  49. Node *np;
  50. if(argc>1 && strcmp(argv[1], "-t")==0)
  51. tflag++;
  52. else if(argc>2 && strcmp(argv[1], "-c")==0){
  53. cflag++;
  54. cflagp = argv[2];
  55. }else if(argc>1){
  56. close(0);
  57. if(open(argv[1], 0) != 0){
  58. error(": can't open", argv[1]);
  59. exits("argument");
  60. }
  61. }else
  62. interactive = 1;
  63. for(;;){
  64. if(interactive)
  65. fprint(2, "%d$ ", getpid());
  66. nfree = nodes;
  67. sfree = strspace;
  68. if((t=gettoken()) == EOF)
  69. break;
  70. if(t != '\n')
  71. if(np = list())
  72. execute(np);
  73. else
  74. error("syntax error", "");
  75. while(t!=EOF && t!='\n') /* flush syntax errors */
  76. t = gettoken();
  77. }
  78. exits(status.msg);
  79. }
  80. /* alloc - allocate for op and return a node */
  81. Node*
  82. alloc(int (*op)(Node *))
  83. {
  84. if(nfree < nodes+sizeof(nodes)){
  85. nfree->op = op;
  86. nfree->args[0] = nfree->args[1] = 0;
  87. nfree->argv[0] = nfree->argv[1] = 0;
  88. nfree->io[0] = nfree->io[1] = nfree->io[2] = 0;
  89. return nfree++;
  90. }
  91. error("node storage overflow", "");
  92. exits("node storage overflow");
  93. }
  94. /* builtin - check np for builtin command and, if found, execute it */
  95. int
  96. builtin(Node *np)
  97. {
  98. int n = 0;
  99. char *s, name[MAXLINE];
  100. if(np->argv[1])
  101. n = strtoul(np->argv[1], 0, 0);
  102. if(strcmp(np->argv[0], "cd") == 0){
  103. if(chdir(np->argv[1]? np->argv[1] : "/") == -1)
  104. error(": bad directory", np->argv[0]);
  105. return 1;
  106. }else if(strcmp(np->argv[0], "exit") == 0)
  107. exits(np->argv[1]? np->argv[1] : status.msg);
  108. else if(strcmp(np->argv[0], "bind") == 0){
  109. if(np->argv[1]==0 || np->argv[2]==0)
  110. error("usage: bind new old", "");
  111. else if(bind(np->argv[1], np->argv[2], 0)==-1)
  112. error("bind failed", "");
  113. return 1;
  114. #ifdef asdf
  115. }else if(strcmp(np->argv[0], "unmount") == 0){
  116. if(np->argv[1] == 0)
  117. error("usage: unmount [new] old", "");
  118. else if(np->argv[2] == 0){
  119. if(unmount((char *)0, np->argv[1]) == -1)
  120. error("unmount:", "");
  121. }else if(unmount(np->argv[1], np->argv[2]) == -1)
  122. error("unmount", "");
  123. return 1;
  124. #endif
  125. }else if(strcmp(np->argv[0], "wait") == 0){
  126. while(wait(&status) != -1)
  127. if(n && status.pid==n){
  128. n = 0;
  129. break;
  130. }
  131. if(n)
  132. error("wait error", "");
  133. return 1;
  134. }else if(strcmp(np->argv[0], "newpgrp") == 0){
  135. int i;
  136. i = forkpgrp(0);
  137. if(i < 0)
  138. error("forkpgrp error", "");
  139. else
  140. fprint(2, "%d\n", i);
  141. return 1;
  142. }else if(strcmp(np->argv[0], "exec") == 0){
  143. redirect(np);
  144. if(np->argv[1] == (char *) 0)
  145. return 1;
  146. exec(np->argv[1], &np->argv[1]);
  147. n = np->argv[1][0];
  148. if(n!='/' && n!='#' && (n!='.' || np->argv[1][1]!='/'))
  149. for(n = 0; path[n]; n++){
  150. sprint(name, "%s/%s", path[n], np->argv[1]);
  151. exec(name, &np->argv[1]);
  152. }
  153. error(": not found", np->argv[1]);
  154. return 1;
  155. }
  156. return 0;
  157. }
  158. /* command - ( list ) [ ( < | > | >> ) word ]* | simple */
  159. Node*
  160. command(void)
  161. {
  162. Node *np;
  163. if(t != '(')
  164. return simple();
  165. np = alloc(xsubshell);
  166. t = gettoken();
  167. if((np->args[0]=list())==0 || t!=')')
  168. return 0;
  169. while((t=gettoken())=='<' || t=='>')
  170. if(!setio(np))
  171. return 0;
  172. return np;
  173. }
  174. /* getch - get next, possibly pushed back, input character */
  175. int
  176. getch(void)
  177. {
  178. unsigned char c;
  179. static done=0;
  180. if(putback){
  181. c = putback;
  182. putback = 0;
  183. }else if(tflag){
  184. if(done || read(0, &c, 1)!=1){
  185. done = 1;
  186. return EOF;
  187. }
  188. if(c == '\n')
  189. done = 1;
  190. }else if(cflag){
  191. if(done)
  192. return EOF;
  193. if((c=*cflagp++) == 0){
  194. done = 1;
  195. c = '\n';
  196. }
  197. }else if(read(0, &c, 1) != 1)
  198. return EOF;
  199. return c;
  200. }
  201. /* gettoken - get next token into string space, return token code */
  202. int
  203. gettoken(void)
  204. {
  205. int c;
  206. while((c = getch()) != EOF)
  207. if(!isspace(c))
  208. break;
  209. if(c==EOF || ispunct(c))
  210. return c;
  211. token = sfree;
  212. do{
  213. if(sfree >= strspace+sizeof(strspace) - 1){
  214. error("string storage overflow", "");
  215. exits("string storage overflow");
  216. }
  217. *sfree++ = c;
  218. }while((c=getch()) != EOF && !ispunct(c) && !isspace(c));
  219. *sfree++ = 0;
  220. putback = c;
  221. return WORD;
  222. }
  223. /* list - pipeline ( ( ; | & ) pipeline )* [ ; | & ] (not LL(1), but ok) */
  224. Node*
  225. list(void)
  226. {
  227. Node *np, *np1;
  228. np = alloc(0);
  229. if((np->args[1]=pipeline()) == 0)
  230. return 0;
  231. while(t==';' || t=='&'){
  232. np->op = (t==';')? xwait : xnowait;
  233. t = gettoken();
  234. if(t==')' || t=='\n') /* tests ~first(pipeline) */
  235. break;
  236. np1 = alloc(0);
  237. np1->args[0] = np;
  238. if((np1->args[1]=pipeline()) == 0)
  239. return 0;
  240. np = np1;
  241. }
  242. if(np->op == 0)
  243. np->op = xwait;
  244. return np;
  245. }
  246. /* error - print error message s, prefixed by t */
  247. void
  248. error(char *s, char *t)
  249. {
  250. char buf[ERRLEN];
  251. fprint(2, "%s%s", t, s);
  252. errstr(buf);
  253. fprint(2, ": %s\n", buf);
  254. }
  255. /* pipeline - command ( | command )* */
  256. Node*
  257. pipeline(void)
  258. {
  259. Node *np, *np1;
  260. if((np=command()) == 0)
  261. return 0;
  262. while(t == '|'){
  263. np1 = alloc(xpipeline);
  264. np1->args[0] = np;
  265. t = gettoken();
  266. if((np1->args[1]=command()) == 0)
  267. return 0;
  268. np = np1;
  269. }
  270. return np;
  271. }
  272. /* redirect - redirect i/o according to np->io[] values */
  273. void
  274. redirect(Node *np)
  275. {
  276. int fd;
  277. if(np->io[0]){
  278. if((fd = open(np->io[0], 0)) < 0){
  279. error(": can't open", np->io[0]);
  280. exits("open");
  281. }
  282. dup(fd, 0);
  283. close(fd);
  284. }
  285. if(np->io[1]){
  286. if((fd = create(np->io[1], 1, 0666L)) < 0){
  287. error(": can't create", np->io[1]);
  288. exits("create");
  289. }
  290. dup(fd, 1);
  291. close(fd);
  292. }
  293. if(np->io[2]){
  294. if((fd = open(np->io[2], 1)) < 0 && (fd = create(np->io[2], 1, 0666L)) < 0){
  295. error(": can't write", np->io[2]);
  296. exits("write");
  297. }
  298. dup(fd, 1);
  299. close(fd);
  300. seek(1, 0, 2);
  301. }
  302. }
  303. /* setio - ( < | > | >> ) word; fill in np->io[] */
  304. int
  305. setio(Node *np)
  306. {
  307. if(t == '<'){
  308. t = gettoken();
  309. np->io[0] = token;
  310. }else if(t == '>'){
  311. t = gettoken();
  312. if(t == '>'){
  313. t = gettoken();
  314. np->io[2] = token;
  315. }else
  316. np->io[1] = token;
  317. }else
  318. return 0;
  319. if(t != WORD)
  320. return 0;
  321. return 1;
  322. }
  323. /* simple - word ( [ < | > | >> ] word )* */
  324. Node*
  325. simple(void)
  326. {
  327. Node *np;
  328. int n = 1;
  329. if(t != WORD)
  330. return 0;
  331. np = alloc(xsimple);
  332. np->argv[0] = token;
  333. while((t = gettoken())==WORD || t=='<' || t=='>')
  334. if(t == WORD)
  335. np->argv[n++] = token;
  336. else if(!setio(np))
  337. return 0;
  338. np->argv[n] = 0;
  339. return np;
  340. }
  341. /* xpipeline - execute cmd | cmd */
  342. int
  343. xpipeline(Node *np)
  344. {
  345. int pid, fd[2];
  346. if(pipe(fd) < 0){
  347. error("can't create pipe", "");
  348. return 0;
  349. }
  350. if((pid=fork()) == 0){ /* left side; redirect stdout */
  351. dup(fd[1], 1);
  352. close(fd[0]);
  353. close(fd[1]);
  354. execute(np->args[0]);
  355. exits(status.msg);
  356. }else if(pid == -1){
  357. error("can't create process", "");
  358. return 0;
  359. }
  360. if((pid=fork()) == 0){ /* right side; redirect stdin */
  361. dup(fd[0], 0);
  362. close(fd[0]);
  363. close(fd[1]);
  364. pid = execute(np->args[1]); /*BUG: this is wrong sometimes*/
  365. if(pid > 0)
  366. while(wait(&status)!=-1 && status.pid!=pid)
  367. ;
  368. exits(0);
  369. }else if(pid == -1){
  370. error("can't create process", "");
  371. return 0;
  372. }
  373. close(fd[0]); /* avoid using up fd's */
  374. close(fd[1]);
  375. return pid;
  376. }
  377. /* xsimple - execute a simple command */
  378. int
  379. xsimple(Node *np)
  380. {
  381. char name[MAXLINE];
  382. int pid, i;
  383. if(builtin(np))
  384. return 0;
  385. if(pid = fork()){
  386. if(pid == -1)
  387. error(": can't create process", np->argv[0]);
  388. return pid;
  389. }
  390. redirect(np); /* child process */
  391. exec(np->argv[0], &np->argv[0]);
  392. i = np->argv[0][0];
  393. if(i!='/' && i!='#' && (i!='.' || np->argv[0][1]!='/'))
  394. for(i = 0; path[i]; i++){
  395. sprint(name, "%s/%s", path[i], np->argv[0]);
  396. exec(name, &np->argv[0]);
  397. }
  398. error(": not found", np->argv[0]);
  399. exits("not found");
  400. }
  401. /* xsubshell - execute (cmd) */
  402. int
  403. xsubshell(Node *np)
  404. {
  405. int pid;
  406. if(pid = fork()){
  407. if(pid == -1)
  408. error("can't create process", "");
  409. return pid;
  410. }
  411. redirect(np); /* child process */
  412. execute(np->args[0]);
  413. exits(status.msg);
  414. }
  415. /* xnowait - execute cmd & */
  416. int
  417. xnowait(Node *np)
  418. {
  419. int pid;
  420. execute(np->args[0]);
  421. pid = execute(np->args[1]);
  422. if(interactive)
  423. fprint(2, "%d\n", pid);
  424. return 0;
  425. }
  426. /* xwait - execute cmd ; */
  427. int xwait(Node *np)
  428. {
  429. int pid;
  430. execute(np->args[0]);
  431. pid = execute(np->args[1]);
  432. if(pid > 0){
  433. while(wait(&status) != -1 && status.pid != pid)
  434. ;
  435. if(status.pid != pid)
  436. error("wait error", "");
  437. }
  438. return 0;
  439. }