sh.C 10 KB

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