xref: /xv6-public/sh.c (revision 7894fcd2)
11b25f3b0Srsc // Shell.
21b25f3b0Srsc 
317a85657Srtm #include "types.h"
4d7b3b802Skaashoek #include "user.h"
517a85657Srtm #include "fcntl.h"
617a85657Srtm 
71b25f3b0Srsc // Parsed command representation
81b25f3b0Srsc #define EXEC  1
91b25f3b0Srsc #define REDIR 2
101b25f3b0Srsc #define PIPE  3
111b25f3b0Srsc #define LIST  4
121b25f3b0Srsc #define BACK  5
131b25f3b0Srsc 
148b58e810Skaashoek #define MAXARGS 10
158b58e810Skaashoek 
1621a88dd0Skaashoek struct cmd {
171b25f3b0Srsc   int type;
1821a88dd0Skaashoek };
191b25f3b0Srsc 
201b25f3b0Srsc struct execcmd {
211b25f3b0Srsc   int type;
221b25f3b0Srsc   char *argv[MAXARGS];
231b25f3b0Srsc   char *eargv[MAXARGS];
241b25f3b0Srsc };
251b25f3b0Srsc 
261b25f3b0Srsc struct redircmd {
271b25f3b0Srsc   int type;
28e00baa9fSkaashoek   struct cmd *cmd;
291b25f3b0Srsc   char *file;
301b25f3b0Srsc   char *efile;
311b25f3b0Srsc   int mode;
321b25f3b0Srsc   int fd;
331b25f3b0Srsc };
348b58e810Skaashoek 
351b25f3b0Srsc struct pipecmd {
361b25f3b0Srsc   int type;
371b25f3b0Srsc   struct cmd *left;
381b25f3b0Srsc   struct cmd *right;
391b25f3b0Srsc };
408b58e810Skaashoek 
411b25f3b0Srsc struct listcmd {
421b25f3b0Srsc   int type;
431b25f3b0Srsc   struct cmd *left;
441b25f3b0Srsc   struct cmd *right;
451b25f3b0Srsc };
461b25f3b0Srsc 
471b25f3b0Srsc struct backcmd {
481b25f3b0Srsc   int type;
491b25f3b0Srsc   struct cmd *cmd;
501b25f3b0Srsc };
511b25f3b0Srsc 
52a759b8a4Srsc int fork1(void);  // Fork but panics on failure.
531b25f3b0Srsc void panic(char*);
54a759b8a4Srsc struct cmd *parsecmd(char*);
551b25f3b0Srsc 
561b25f3b0Srsc // Execute cmd.  Never returns.
571b25f3b0Srsc void
runcmd(struct cmd * cmd)581b25f3b0Srsc runcmd(struct cmd *cmd)
591b25f3b0Srsc {
601b25f3b0Srsc   int p[2];
611b25f3b0Srsc   struct backcmd *bcmd;
621b25f3b0Srsc   struct execcmd *ecmd;
631b25f3b0Srsc   struct listcmd *lcmd;
641b25f3b0Srsc   struct pipecmd *pcmd;
651b25f3b0Srsc   struct redircmd *rcmd;
661b25f3b0Srsc 
671b25f3b0Srsc   if(cmd == 0)
68b52dea08Srsc     exit();
691b25f3b0Srsc 
701b25f3b0Srsc   switch(cmd->type){
711b25f3b0Srsc   default:
721b25f3b0Srsc     panic("runcmd");
731b25f3b0Srsc 
741b25f3b0Srsc   case EXEC:
751b25f3b0Srsc     ecmd = (struct execcmd*)cmd;
761b25f3b0Srsc     if(ecmd->argv[0] == 0)
771b25f3b0Srsc       exit();
781b25f3b0Srsc     exec(ecmd->argv[0], ecmd->argv);
791b25f3b0Srsc     printf(2, "exec %s failed\n", ecmd->argv[0]);
801b25f3b0Srsc     break;
811b25f3b0Srsc 
821b25f3b0Srsc   case REDIR:
831b25f3b0Srsc     rcmd = (struct redircmd*)cmd;
841b25f3b0Srsc     close(rcmd->fd);
851b25f3b0Srsc     if(open(rcmd->file, rcmd->mode) < 0){
861b25f3b0Srsc       printf(2, "open %s failed\n", rcmd->file);
871b25f3b0Srsc       exit();
881b25f3b0Srsc     }
891b25f3b0Srsc     runcmd(rcmd->cmd);
901b25f3b0Srsc     break;
911b25f3b0Srsc 
92a759b8a4Srsc   case LIST:
93a759b8a4Srsc     lcmd = (struct listcmd*)cmd;
94a759b8a4Srsc     if(fork1() == 0)
95a759b8a4Srsc       runcmd(lcmd->left);
96a759b8a4Srsc     wait();
97a759b8a4Srsc     runcmd(lcmd->right);
98a759b8a4Srsc     break;
99a759b8a4Srsc 
1001b25f3b0Srsc   case PIPE:
1011b25f3b0Srsc     pcmd = (struct pipecmd*)cmd;
1021b25f3b0Srsc     if(pipe(p) < 0)
1031b25f3b0Srsc       panic("pipe");
1041b25f3b0Srsc     if(fork1() == 0){
1051b25f3b0Srsc       close(1);
1061b25f3b0Srsc       dup(p[1]);
1071b25f3b0Srsc       close(p[0]);
1081b25f3b0Srsc       close(p[1]);
1091b25f3b0Srsc       runcmd(pcmd->left);
1101b25f3b0Srsc     }
1111b25f3b0Srsc     if(fork1() == 0){
1121b25f3b0Srsc       close(0);
1131b25f3b0Srsc       dup(p[0]);
1141b25f3b0Srsc       close(p[0]);
1151b25f3b0Srsc       close(p[1]);
1161b25f3b0Srsc       runcmd(pcmd->right);
1171b25f3b0Srsc     }
1181b25f3b0Srsc     close(p[0]);
1191b25f3b0Srsc     close(p[1]);
1201b25f3b0Srsc     wait();
1211b25f3b0Srsc     wait();
1221b25f3b0Srsc     break;
1231b25f3b0Srsc 
1241b25f3b0Srsc   case BACK:
1251b25f3b0Srsc     bcmd = (struct backcmd*)cmd;
1261b25f3b0Srsc     if(fork1() == 0)
1271b25f3b0Srsc       runcmd(bcmd->cmd);
1281b25f3b0Srsc     break;
12917a85657Srtm   }
130f8f7fcbeSrsc   exit();
13117a85657Srtm }
132d7b3b802Skaashoek 
1338b58e810Skaashoek int
getcmd(char * buf,int nbuf)1349736728dSrsc getcmd(char *buf, int nbuf)
1359736728dSrsc {
1361b789e1dSrsc   printf(2, "$ ");
1379736728dSrsc   memset(buf, 0, nbuf);
1389736728dSrsc   gets(buf, nbuf);
1399736728dSrsc   if(buf[0] == 0) // EOF
1409736728dSrsc     return -1;
1419736728dSrsc   return 0;
1429736728dSrsc }
1439736728dSrsc 
1449736728dSrsc int
main(void)1451b25f3b0Srsc main(void)
146d7b3b802Skaashoek {
1471b25f3b0Srsc   static char buf[100];
148a759b8a4Srsc   int fd;
1498b58e810Skaashoek 
150*0a4a4230SRobert Morris   // Ensure that three file descriptors are open.
151a759b8a4Srsc   while((fd = open("console", O_RDWR)) >= 0){
152a759b8a4Srsc     if(fd >= 3){
153a759b8a4Srsc       close(fd);
154a759b8a4Srsc       break;
155a759b8a4Srsc     }
156a759b8a4Srsc   }
157a759b8a4Srsc 
158a759b8a4Srsc   // Read and run input commands.
1591b25f3b0Srsc   while(getcmd(buf, sizeof(buf)) >= 0){
1609863fea7Srsc     if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
161*0a4a4230SRobert Morris       // Chdir must be called by the parent, not the child.
1629863fea7Srsc       buf[strlen(buf)-1] = 0;  // chop \n
1639863fea7Srsc       if(chdir(buf+3) < 0)
1649863fea7Srsc         printf(2, "cannot cd %s\n", buf+3);
1659863fea7Srsc       continue;
1669863fea7Srsc     }
1671b25f3b0Srsc     if(fork1() == 0)
1681b25f3b0Srsc       runcmd(parsecmd(buf));
1691b25f3b0Srsc     wait();
17021a88dd0Skaashoek   }
1711b25f3b0Srsc   exit();
1728b58e810Skaashoek }
1738b58e810Skaashoek 
1748b58e810Skaashoek void
panic(char * s)1751b25f3b0Srsc panic(char *s)
1768b58e810Skaashoek {
1771b25f3b0Srsc   printf(2, "%s\n", s);
178d7b3b802Skaashoek   exit();
179d7b3b802Skaashoek }
18021a88dd0Skaashoek 
181a759b8a4Srsc int
fork1(void)182a759b8a4Srsc fork1(void)
183a759b8a4Srsc {
184a759b8a4Srsc   int pid;
185a759b8a4Srsc 
186a759b8a4Srsc   pid = fork();
187a759b8a4Srsc   if(pid == -1)
188a759b8a4Srsc     panic("fork");
189a759b8a4Srsc   return pid;
190a759b8a4Srsc }
191a759b8a4Srsc 
192a759b8a4Srsc //PAGEBREAK!
1931b25f3b0Srsc // Constructors
1941b25f3b0Srsc 
1951b25f3b0Srsc struct cmd*
execcmd(void)1961b25f3b0Srsc execcmd(void)
1971b25f3b0Srsc {
1981b25f3b0Srsc   struct execcmd *cmd;
1991b25f3b0Srsc 
2001b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2011b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2021b25f3b0Srsc   cmd->type = EXEC;
2031b25f3b0Srsc   return (struct cmd*)cmd;
20421a88dd0Skaashoek }
2051b25f3b0Srsc 
2061b25f3b0Srsc struct cmd*
redircmd(struct cmd * subcmd,char * file,char * efile,int mode,int fd)2071b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
2081b25f3b0Srsc {
2091b25f3b0Srsc   struct redircmd *cmd;
2101b25f3b0Srsc 
2111b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2121b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2131b25f3b0Srsc   cmd->type = REDIR;
2141b25f3b0Srsc   cmd->cmd = subcmd;
2151b25f3b0Srsc   cmd->file = file;
2161b25f3b0Srsc   cmd->efile = efile;
2171b25f3b0Srsc   cmd->mode = mode;
2181b25f3b0Srsc   cmd->fd = fd;
2191b25f3b0Srsc   return (struct cmd*)cmd;
220d7b3b802Skaashoek }
2211b25f3b0Srsc 
2221b25f3b0Srsc struct cmd*
pipecmd(struct cmd * left,struct cmd * right)2231b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right)
2241b25f3b0Srsc {
2251b25f3b0Srsc   struct pipecmd *cmd;
2261b25f3b0Srsc 
2271b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2281b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2291b25f3b0Srsc   cmd->type = PIPE;
2301b25f3b0Srsc   cmd->left = left;
2311b25f3b0Srsc   cmd->right = right;
2321b25f3b0Srsc   return (struct cmd*)cmd;
233d7b3b802Skaashoek }
2341b25f3b0Srsc 
2351b25f3b0Srsc struct cmd*
listcmd(struct cmd * left,struct cmd * right)2361b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right)
2371b25f3b0Srsc {
2381b25f3b0Srsc   struct listcmd *cmd;
2391b25f3b0Srsc 
2401b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2411b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2421b25f3b0Srsc   cmd->type = LIST;
2431b25f3b0Srsc   cmd->left = left;
2441b25f3b0Srsc   cmd->right = right;
2451b25f3b0Srsc   return (struct cmd*)cmd;
24621a88dd0Skaashoek }
2471b25f3b0Srsc 
2481b25f3b0Srsc struct cmd*
backcmd(struct cmd * subcmd)2491b25f3b0Srsc backcmd(struct cmd *subcmd)
2501b25f3b0Srsc {
2511b25f3b0Srsc   struct backcmd *cmd;
2521b25f3b0Srsc 
2531b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2541b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2551b25f3b0Srsc   cmd->type = BACK;
2561b25f3b0Srsc   cmd->cmd = subcmd;
2571b25f3b0Srsc   return (struct cmd*)cmd;
2581b25f3b0Srsc }
259a759b8a4Srsc //PAGEBREAK!
2601b25f3b0Srsc // Parsing
2611b25f3b0Srsc 
2621b25f3b0Srsc char whitespace[] = " \t\r\n\v";
2631b25f3b0Srsc char symbols[] = "<|>&;()";
2641b25f3b0Srsc 
2651b25f3b0Srsc int
gettoken(char ** ps,char * es,char ** q,char ** eq)2661b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq)
2678b58e810Skaashoek {
2681b25f3b0Srsc   char *s;
2691b25f3b0Srsc   int ret;
2708b58e810Skaashoek 
2711b25f3b0Srsc   s = *ps;
2721b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
2731b25f3b0Srsc     s++;
2741b25f3b0Srsc   if(q)
2751b25f3b0Srsc     *q = s;
2761b25f3b0Srsc   ret = *s;
2771b25f3b0Srsc   switch(*s){
2781b25f3b0Srsc   case 0:
2791b25f3b0Srsc     break;
2801b25f3b0Srsc   case '|':
2811b25f3b0Srsc   case '(':
2821b25f3b0Srsc   case ')':
2831b25f3b0Srsc   case ';':
2841b25f3b0Srsc   case '&':
2858b58e810Skaashoek   case '<':
2861b25f3b0Srsc     s++;
2878b58e810Skaashoek     break;
2888b58e810Skaashoek   case '>':
2891b25f3b0Srsc     s++;
2901b25f3b0Srsc     if(*s == '>'){
2911b25f3b0Srsc       ret = '+';
2921b25f3b0Srsc       s++;
2938b58e810Skaashoek     }
2941b25f3b0Srsc     break;
2951b25f3b0Srsc   default:
2961b25f3b0Srsc     ret = 'a';
2971b25f3b0Srsc     while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
2981b25f3b0Srsc       s++;
2991b25f3b0Srsc     break;
3001b25f3b0Srsc   }
3011b25f3b0Srsc   if(eq)
3021b25f3b0Srsc     *eq = s;
3031b25f3b0Srsc 
3041b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
3051b25f3b0Srsc     s++;
3061b25f3b0Srsc   *ps = s;
3071b25f3b0Srsc   return ret;
3081b25f3b0Srsc }
3091b25f3b0Srsc 
310a759b8a4Srsc int
peek(char ** ps,char * es,char * toks)311a759b8a4Srsc peek(char **ps, char *es, char *toks)
312a759b8a4Srsc {
313a759b8a4Srsc   char *s;
314a759b8a4Srsc 
315a759b8a4Srsc   s = *ps;
316a759b8a4Srsc   while(s < es && strchr(whitespace, *s))
317a759b8a4Srsc     s++;
318a759b8a4Srsc   *ps = s;
319a759b8a4Srsc   return *s && strchr(toks, *s);
320a759b8a4Srsc }
321a759b8a4Srsc 
3221b25f3b0Srsc struct cmd *parseline(char**, char*);
3231b25f3b0Srsc struct cmd *parsepipe(char**, char*);
3241b25f3b0Srsc struct cmd *parseexec(char**, char*);
325a759b8a4Srsc struct cmd *nulterminate(struct cmd*);
3261b25f3b0Srsc 
3271b25f3b0Srsc struct cmd*
parsecmd(char * s)3281b25f3b0Srsc parsecmd(char *s)
3291b25f3b0Srsc {
3301b25f3b0Srsc   char *es;
3311b25f3b0Srsc   struct cmd *cmd;
3321b25f3b0Srsc 
3331b25f3b0Srsc   es = s + strlen(s);
3341b25f3b0Srsc   cmd = parseline(&s, es);
3351b25f3b0Srsc   peek(&s, es, "");
3361b25f3b0Srsc   if(s != es){
3371b25f3b0Srsc     printf(2, "leftovers: %s\n", s);
3381b25f3b0Srsc     panic("syntax");
3391b25f3b0Srsc   }
3401b25f3b0Srsc   nulterminate(cmd);
3411b25f3b0Srsc   return cmd;
3421b25f3b0Srsc }
3431b25f3b0Srsc 
3441b25f3b0Srsc struct cmd*
parseline(char ** ps,char * es)3451b25f3b0Srsc parseline(char **ps, char *es)
3461b25f3b0Srsc {
3471b25f3b0Srsc   struct cmd *cmd;
3481b25f3b0Srsc 
3491b25f3b0Srsc   cmd = parsepipe(ps, es);
3501b25f3b0Srsc   while(peek(ps, es, "&")){
3511b25f3b0Srsc     gettoken(ps, es, 0, 0);
3521b25f3b0Srsc     cmd = backcmd(cmd);
3531b25f3b0Srsc   }
3541b25f3b0Srsc   if(peek(ps, es, ";")){
3551b25f3b0Srsc     gettoken(ps, es, 0, 0);
3561b25f3b0Srsc     cmd = listcmd(cmd, parseline(ps, es));
3571b25f3b0Srsc   }
3581b25f3b0Srsc   return cmd;
3591b25f3b0Srsc }
3601b25f3b0Srsc 
3611b25f3b0Srsc struct cmd*
parsepipe(char ** ps,char * es)3621b25f3b0Srsc parsepipe(char **ps, char *es)
3631b25f3b0Srsc {
3641b25f3b0Srsc   struct cmd *cmd;
3651b25f3b0Srsc 
3661b25f3b0Srsc   cmd = parseexec(ps, es);
3671b25f3b0Srsc   if(peek(ps, es, "|")){
3681b25f3b0Srsc     gettoken(ps, es, 0, 0);
3691b25f3b0Srsc     cmd = pipecmd(cmd, parsepipe(ps, es));
3701b25f3b0Srsc   }
3711b25f3b0Srsc   return cmd;
3721b25f3b0Srsc }
3731b25f3b0Srsc 
3741b25f3b0Srsc struct cmd*
parseredirs(struct cmd * cmd,char ** ps,char * es)3751b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es)
3761b25f3b0Srsc {
3771b25f3b0Srsc   int tok;
3781b25f3b0Srsc   char *q, *eq;
3791b25f3b0Srsc 
3801b25f3b0Srsc   while(peek(ps, es, "<>")){
3811b25f3b0Srsc     tok = gettoken(ps, es, 0, 0);
3821b25f3b0Srsc     if(gettoken(ps, es, &q, &eq) != 'a')
3831b25f3b0Srsc       panic("missing file for redirection");
3841b25f3b0Srsc     switch(tok){
3851b25f3b0Srsc     case '<':
3861b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
3871b25f3b0Srsc       break;
3881b25f3b0Srsc     case '>':
3891b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
3901b25f3b0Srsc       break;
3911b25f3b0Srsc     case '+':  // >>
3921b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
3938b58e810Skaashoek       break;
3948b58e810Skaashoek     }
3958b58e810Skaashoek   }
3961b25f3b0Srsc   return cmd;
3978b58e810Skaashoek }
3988b58e810Skaashoek 
3991b25f3b0Srsc struct cmd*
parseblock(char ** ps,char * es)400a759b8a4Srsc parseblock(char **ps, char *es)
401a759b8a4Srsc {
402a759b8a4Srsc   struct cmd *cmd;
403a759b8a4Srsc 
404a759b8a4Srsc   if(!peek(ps, es, "("))
405a759b8a4Srsc     panic("parseblock");
406a759b8a4Srsc   gettoken(ps, es, 0, 0);
407a759b8a4Srsc   cmd = parseline(ps, es);
408a759b8a4Srsc   if(!peek(ps, es, ")"))
409a759b8a4Srsc     panic("syntax - missing )");
410a759b8a4Srsc   gettoken(ps, es, 0, 0);
411a759b8a4Srsc   cmd = parseredirs(cmd, ps, es);
412a759b8a4Srsc   return cmd;
413a759b8a4Srsc }
414a759b8a4Srsc 
415a759b8a4Srsc struct cmd*
parseexec(char ** ps,char * es)4161b25f3b0Srsc parseexec(char **ps, char *es)
4178b58e810Skaashoek {
4181b25f3b0Srsc   char *q, *eq;
4191b25f3b0Srsc   int tok, argc;
4201b25f3b0Srsc   struct execcmd *cmd;
4211b25f3b0Srsc   struct cmd *ret;
4228b58e810Skaashoek 
4231b25f3b0Srsc   if(peek(ps, es, "("))
4241b25f3b0Srsc     return parseblock(ps, es);
4251b25f3b0Srsc 
4261b25f3b0Srsc   ret = execcmd();
4271b25f3b0Srsc   cmd = (struct execcmd*)ret;
4281b25f3b0Srsc 
4291b25f3b0Srsc   argc = 0;
4301b25f3b0Srsc   ret = parseredirs(ret, ps, es);
4311b25f3b0Srsc   while(!peek(ps, es, "|)&;")){
4321b25f3b0Srsc     if((tok=gettoken(ps, es, &q, &eq)) == 0)
4331b25f3b0Srsc       break;
4341b25f3b0Srsc     if(tok != 'a')
4351b25f3b0Srsc       panic("syntax");
4361b25f3b0Srsc     cmd->argv[argc] = q;
4371b25f3b0Srsc     cmd->eargv[argc] = eq;
4381b25f3b0Srsc     argc++;
4391b25f3b0Srsc     if(argc >= MAXARGS)
4401b25f3b0Srsc       panic("too many args");
4411b25f3b0Srsc     ret = parseredirs(ret, ps, es);
4428b58e810Skaashoek   }
4431b25f3b0Srsc   cmd->argv[argc] = 0;
4441b25f3b0Srsc   cmd->eargv[argc] = 0;
4451b25f3b0Srsc   return ret;
4468b58e810Skaashoek }
4478b58e810Skaashoek 
4481b25f3b0Srsc // NUL-terminate all the counted strings.
4491baead53Srsc struct cmd*
nulterminate(struct cmd * cmd)4501b25f3b0Srsc nulterminate(struct cmd *cmd)
4518b58e810Skaashoek {
4521b25f3b0Srsc   int i;
4531b25f3b0Srsc   struct backcmd *bcmd;
4541b25f3b0Srsc   struct execcmd *ecmd;
4551b25f3b0Srsc   struct listcmd *lcmd;
4561b25f3b0Srsc   struct pipecmd *pcmd;
4571b25f3b0Srsc   struct redircmd *rcmd;
4588b58e810Skaashoek 
4591b25f3b0Srsc   if(cmd == 0)
460a759b8a4Srsc     return 0;
4618b58e810Skaashoek 
4621b25f3b0Srsc   switch(cmd->type){
4631b25f3b0Srsc   case EXEC:
4641b25f3b0Srsc     ecmd = (struct execcmd*)cmd;
4651b25f3b0Srsc     for(i=0; ecmd->argv[i]; i++)
4661b25f3b0Srsc       *ecmd->eargv[i] = 0;
4671b25f3b0Srsc     break;
4688b58e810Skaashoek 
4691b25f3b0Srsc   case REDIR:
4701b25f3b0Srsc     rcmd = (struct redircmd*)cmd;
4711b25f3b0Srsc     nulterminate(rcmd->cmd);
4721b25f3b0Srsc     *rcmd->efile = 0;
4731b25f3b0Srsc     break;
4748b58e810Skaashoek 
4751b25f3b0Srsc   case PIPE:
4761b25f3b0Srsc     pcmd = (struct pipecmd*)cmd;
4771b25f3b0Srsc     nulterminate(pcmd->left);
4781b25f3b0Srsc     nulterminate(pcmd->right);
4791b25f3b0Srsc     break;
4808b58e810Skaashoek 
4811b25f3b0Srsc   case LIST:
4821b25f3b0Srsc     lcmd = (struct listcmd*)cmd;
4831b25f3b0Srsc     nulterminate(lcmd->left);
4841b25f3b0Srsc     nulterminate(lcmd->right);
4851b25f3b0Srsc     break;
4861b25f3b0Srsc 
4871b25f3b0Srsc   case BACK:
4881b25f3b0Srsc     bcmd = (struct backcmd*)cmd;
4891b25f3b0Srsc     nulterminate(bcmd->cmd);
4901b25f3b0Srsc     break;
4911b25f3b0Srsc   }
492a759b8a4Srsc   return cmd;
4931b25f3b0Srsc }
494