xref: /xv6-public/sh.c (revision 9863fea7)
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
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
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
1451b25f3b0Srsc main(void)
146d7b3b802Skaashoek {
1471b25f3b0Srsc   static char buf[100];
148a759b8a4Srsc   int fd;
1498b58e810Skaashoek 
150a759b8a4Srsc   // Assumes three file descriptors 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){
160*9863fea7Srsc     if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
161*9863fea7Srsc       // Clumsy but will have to do for now.
162*9863fea7Srsc       // Chdir has no effect on the parent if run in the child.
163*9863fea7Srsc       buf[strlen(buf)-1] = 0;  // chop \n
164*9863fea7Srsc       if(chdir(buf+3) < 0)
165*9863fea7Srsc         printf(2, "cannot cd %s\n", buf+3);
166*9863fea7Srsc       continue;
167*9863fea7Srsc     }
1681b25f3b0Srsc     if(fork1() == 0)
1691b25f3b0Srsc       runcmd(parsecmd(buf));
1701b25f3b0Srsc     wait();
17121a88dd0Skaashoek   }
1721b25f3b0Srsc   exit();
1738b58e810Skaashoek }
1748b58e810Skaashoek 
1758b58e810Skaashoek void
1761b25f3b0Srsc panic(char *s)
1778b58e810Skaashoek {
1781b25f3b0Srsc   printf(2, "%s\n", s);
179d7b3b802Skaashoek   exit();
180d7b3b802Skaashoek }
18121a88dd0Skaashoek 
182a759b8a4Srsc int
183a759b8a4Srsc fork1(void)
184a759b8a4Srsc {
185a759b8a4Srsc   int pid;
186a759b8a4Srsc 
187a759b8a4Srsc   pid = fork();
188a759b8a4Srsc   if(pid == -1)
189a759b8a4Srsc     panic("fork");
190a759b8a4Srsc   return pid;
191a759b8a4Srsc }
192a759b8a4Srsc 
193a759b8a4Srsc //PAGEBREAK!
1941b25f3b0Srsc // Constructors
1951b25f3b0Srsc 
1961b25f3b0Srsc struct cmd*
1971b25f3b0Srsc execcmd(void)
1981b25f3b0Srsc {
1991b25f3b0Srsc   struct execcmd *cmd;
2001b25f3b0Srsc 
2011b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2021b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2031b25f3b0Srsc   cmd->type = EXEC;
2041b25f3b0Srsc   return (struct cmd*)cmd;
20521a88dd0Skaashoek }
2061b25f3b0Srsc 
2071b25f3b0Srsc struct cmd*
2081b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
2091b25f3b0Srsc {
2101b25f3b0Srsc   struct redircmd *cmd;
2111b25f3b0Srsc 
2121b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2131b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2141b25f3b0Srsc   cmd->type = REDIR;
2151b25f3b0Srsc   cmd->cmd = subcmd;
2161b25f3b0Srsc   cmd->file = file;
2171b25f3b0Srsc   cmd->efile = efile;
2181b25f3b0Srsc   cmd->mode = mode;
2191b25f3b0Srsc   cmd->fd = fd;
2201b25f3b0Srsc   return (struct cmd*)cmd;
221d7b3b802Skaashoek }
2221b25f3b0Srsc 
2231b25f3b0Srsc struct cmd*
2241b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right)
2251b25f3b0Srsc {
2261b25f3b0Srsc   struct pipecmd *cmd;
2271b25f3b0Srsc 
2281b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2291b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2301b25f3b0Srsc   cmd->type = PIPE;
2311b25f3b0Srsc   cmd->left = left;
2321b25f3b0Srsc   cmd->right = right;
2331b25f3b0Srsc   return (struct cmd*)cmd;
234d7b3b802Skaashoek }
2351b25f3b0Srsc 
2361b25f3b0Srsc struct cmd*
2371b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right)
2381b25f3b0Srsc {
2391b25f3b0Srsc   struct listcmd *cmd;
2401b25f3b0Srsc 
2411b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2421b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2431b25f3b0Srsc   cmd->type = LIST;
2441b25f3b0Srsc   cmd->left = left;
2451b25f3b0Srsc   cmd->right = right;
2461b25f3b0Srsc   return (struct cmd*)cmd;
24721a88dd0Skaashoek }
2481b25f3b0Srsc 
2491b25f3b0Srsc struct cmd*
2501b25f3b0Srsc backcmd(struct cmd *subcmd)
2511b25f3b0Srsc {
2521b25f3b0Srsc   struct backcmd *cmd;
2531b25f3b0Srsc 
2541b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
2551b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
2561b25f3b0Srsc   cmd->type = BACK;
2571b25f3b0Srsc   cmd->cmd = subcmd;
2581b25f3b0Srsc   return (struct cmd*)cmd;
2591b25f3b0Srsc }
260a759b8a4Srsc //PAGEBREAK!
2611b25f3b0Srsc // Parsing
2621b25f3b0Srsc 
2631b25f3b0Srsc char whitespace[] = " \t\r\n\v";
2641b25f3b0Srsc char symbols[] = "<|>&;()";
2651b25f3b0Srsc 
2661b25f3b0Srsc int
2671b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq)
2688b58e810Skaashoek {
2691b25f3b0Srsc   char *s;
2701b25f3b0Srsc   int ret;
2718b58e810Skaashoek 
2721b25f3b0Srsc   s = *ps;
2731b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
2741b25f3b0Srsc     s++;
2751b25f3b0Srsc   if(q)
2761b25f3b0Srsc     *q = s;
2771b25f3b0Srsc   ret = *s;
2781b25f3b0Srsc   switch(*s){
2791b25f3b0Srsc   case 0:
2801b25f3b0Srsc     break;
2811b25f3b0Srsc   case '|':
2821b25f3b0Srsc   case '(':
2831b25f3b0Srsc   case ')':
2841b25f3b0Srsc   case ';':
2851b25f3b0Srsc   case '&':
2868b58e810Skaashoek   case '<':
2871b25f3b0Srsc     s++;
2888b58e810Skaashoek     break;
2898b58e810Skaashoek   case '>':
2901b25f3b0Srsc     s++;
2911b25f3b0Srsc     if(*s == '>'){
2921b25f3b0Srsc       ret = '+';
2931b25f3b0Srsc       s++;
2948b58e810Skaashoek     }
2951b25f3b0Srsc     break;
2961b25f3b0Srsc   default:
2971b25f3b0Srsc     ret = 'a';
2981b25f3b0Srsc     while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
2991b25f3b0Srsc       s++;
3001b25f3b0Srsc     break;
3011b25f3b0Srsc   }
3021b25f3b0Srsc   if(eq)
3031b25f3b0Srsc     *eq = s;
3041b25f3b0Srsc 
3051b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
3061b25f3b0Srsc     s++;
3071b25f3b0Srsc   *ps = s;
3081b25f3b0Srsc   return ret;
3091b25f3b0Srsc }
3101b25f3b0Srsc 
311a759b8a4Srsc int
312a759b8a4Srsc peek(char **ps, char *es, char *toks)
313a759b8a4Srsc {
314a759b8a4Srsc   char *s;
315a759b8a4Srsc 
316a759b8a4Srsc   s = *ps;
317a759b8a4Srsc   while(s < es && strchr(whitespace, *s))
318a759b8a4Srsc     s++;
319a759b8a4Srsc   *ps = s;
320a759b8a4Srsc   return *s && strchr(toks, *s);
321a759b8a4Srsc }
322a759b8a4Srsc 
3231b25f3b0Srsc struct cmd *parseline(char**, char*);
3241b25f3b0Srsc struct cmd *parsepipe(char**, char*);
3251b25f3b0Srsc struct cmd *parseexec(char**, char*);
326a759b8a4Srsc struct cmd *nulterminate(struct cmd*);
3271b25f3b0Srsc 
3281b25f3b0Srsc struct cmd*
3291b25f3b0Srsc parsecmd(char *s)
3301b25f3b0Srsc {
3311b25f3b0Srsc   char *es;
3321b25f3b0Srsc   struct cmd *cmd;
3331b25f3b0Srsc 
3341b25f3b0Srsc   es = s + strlen(s);
3351b25f3b0Srsc   cmd = parseline(&s, es);
3361b25f3b0Srsc   peek(&s, es, "");
3371b25f3b0Srsc   if(s != es){
3381b25f3b0Srsc     printf(2, "leftovers: %s\n", s);
3391b25f3b0Srsc     panic("syntax");
3401b25f3b0Srsc   }
3411b25f3b0Srsc   nulterminate(cmd);
3421b25f3b0Srsc   return cmd;
3431b25f3b0Srsc }
3441b25f3b0Srsc 
3451b25f3b0Srsc struct cmd*
3461b25f3b0Srsc parseline(char **ps, char *es)
3471b25f3b0Srsc {
3481b25f3b0Srsc   struct cmd *cmd;
3491b25f3b0Srsc 
3501b25f3b0Srsc   cmd = parsepipe(ps, es);
3511b25f3b0Srsc   while(peek(ps, es, "&")){
3521b25f3b0Srsc     gettoken(ps, es, 0, 0);
3531b25f3b0Srsc     cmd = backcmd(cmd);
3541b25f3b0Srsc   }
3551b25f3b0Srsc   if(peek(ps, es, ";")){
3561b25f3b0Srsc     gettoken(ps, es, 0, 0);
3571b25f3b0Srsc     cmd = listcmd(cmd, parseline(ps, es));
3581b25f3b0Srsc   }
3591b25f3b0Srsc   return cmd;
3601b25f3b0Srsc }
3611b25f3b0Srsc 
3621b25f3b0Srsc struct cmd*
3631b25f3b0Srsc parsepipe(char **ps, char *es)
3641b25f3b0Srsc {
3651b25f3b0Srsc   struct cmd *cmd;
3661b25f3b0Srsc 
3671b25f3b0Srsc   cmd = parseexec(ps, es);
3681b25f3b0Srsc   if(peek(ps, es, "|")){
3691b25f3b0Srsc     gettoken(ps, es, 0, 0);
3701b25f3b0Srsc     cmd = pipecmd(cmd, parsepipe(ps, es));
3711b25f3b0Srsc   }
3721b25f3b0Srsc   return cmd;
3731b25f3b0Srsc }
3741b25f3b0Srsc 
3751b25f3b0Srsc struct cmd*
3761b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es)
3771b25f3b0Srsc {
3781b25f3b0Srsc   int tok;
3791b25f3b0Srsc   char *q, *eq;
3801b25f3b0Srsc 
3811b25f3b0Srsc   while(peek(ps, es, "<>")){
3821b25f3b0Srsc     tok = gettoken(ps, es, 0, 0);
3831b25f3b0Srsc     if(gettoken(ps, es, &q, &eq) != 'a')
3841b25f3b0Srsc       panic("missing file for redirection");
3851b25f3b0Srsc     switch(tok){
3861b25f3b0Srsc     case '<':
3871b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
3881b25f3b0Srsc       break;
3891b25f3b0Srsc     case '>':
3901b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
3911b25f3b0Srsc       break;
3921b25f3b0Srsc     case '+':  // >>
3931b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
3948b58e810Skaashoek       break;
3958b58e810Skaashoek     }
3968b58e810Skaashoek   }
3971b25f3b0Srsc   return cmd;
3988b58e810Skaashoek }
3998b58e810Skaashoek 
4001b25f3b0Srsc struct cmd*
401a759b8a4Srsc parseblock(char **ps, char *es)
402a759b8a4Srsc {
403a759b8a4Srsc   struct cmd *cmd;
404a759b8a4Srsc 
405a759b8a4Srsc   if(!peek(ps, es, "("))
406a759b8a4Srsc     panic("parseblock");
407a759b8a4Srsc   gettoken(ps, es, 0, 0);
408a759b8a4Srsc   cmd = parseline(ps, es);
409a759b8a4Srsc   if(!peek(ps, es, ")"))
410a759b8a4Srsc     panic("syntax - missing )");
411a759b8a4Srsc   gettoken(ps, es, 0, 0);
412a759b8a4Srsc   cmd = parseredirs(cmd, ps, es);
413a759b8a4Srsc   return cmd;
414a759b8a4Srsc }
415a759b8a4Srsc 
416a759b8a4Srsc struct cmd*
4171b25f3b0Srsc parseexec(char **ps, char *es)
4188b58e810Skaashoek {
4191b25f3b0Srsc   char *q, *eq;
4201b25f3b0Srsc   int tok, argc;
4211b25f3b0Srsc   struct execcmd *cmd;
4221b25f3b0Srsc   struct cmd *ret;
4238b58e810Skaashoek 
4241b25f3b0Srsc   if(peek(ps, es, "("))
4251b25f3b0Srsc     return parseblock(ps, es);
4261b25f3b0Srsc 
4271b25f3b0Srsc   ret = execcmd();
4281b25f3b0Srsc   cmd = (struct execcmd*)ret;
4291b25f3b0Srsc 
4301b25f3b0Srsc   argc = 0;
4311b25f3b0Srsc   ret = parseredirs(ret, ps, es);
4321b25f3b0Srsc   while(!peek(ps, es, "|)&;")){
4331b25f3b0Srsc     if((tok=gettoken(ps, es, &q, &eq)) == 0)
4341b25f3b0Srsc       break;
4351b25f3b0Srsc     if(tok != 'a')
4361b25f3b0Srsc       panic("syntax");
4371b25f3b0Srsc     cmd->argv[argc] = q;
4381b25f3b0Srsc     cmd->eargv[argc] = eq;
4391b25f3b0Srsc     argc++;
4401b25f3b0Srsc     if(argc >= MAXARGS)
4411b25f3b0Srsc       panic("too many args");
4421b25f3b0Srsc     ret = parseredirs(ret, ps, es);
4438b58e810Skaashoek   }
4441b25f3b0Srsc   cmd->argv[argc] = 0;
4451b25f3b0Srsc   cmd->eargv[argc] = 0;
4461b25f3b0Srsc   return ret;
4478b58e810Skaashoek }
4488b58e810Skaashoek 
4491b25f3b0Srsc // NUL-terminate all the counted strings.
4501baead53Srsc struct cmd*
4511b25f3b0Srsc nulterminate(struct cmd *cmd)
4528b58e810Skaashoek {
4531b25f3b0Srsc   int i;
4541b25f3b0Srsc   struct backcmd *bcmd;
4551b25f3b0Srsc   struct execcmd *ecmd;
4561b25f3b0Srsc   struct listcmd *lcmd;
4571b25f3b0Srsc   struct pipecmd *pcmd;
4581b25f3b0Srsc   struct redircmd *rcmd;
4598b58e810Skaashoek 
4601b25f3b0Srsc   if(cmd == 0)
461a759b8a4Srsc     return 0;
4628b58e810Skaashoek 
4631b25f3b0Srsc   switch(cmd->type){
4641b25f3b0Srsc   case EXEC:
4651b25f3b0Srsc     ecmd = (struct execcmd*)cmd;
4661b25f3b0Srsc     for(i=0; ecmd->argv[i]; i++)
4671b25f3b0Srsc       *ecmd->eargv[i] = 0;
4681b25f3b0Srsc     break;
4698b58e810Skaashoek 
4701b25f3b0Srsc   case REDIR:
4711b25f3b0Srsc     rcmd = (struct redircmd*)cmd;
4721b25f3b0Srsc     nulterminate(rcmd->cmd);
4731b25f3b0Srsc     *rcmd->efile = 0;
4741b25f3b0Srsc     break;
4758b58e810Skaashoek 
4761b25f3b0Srsc   case PIPE:
4771b25f3b0Srsc     pcmd = (struct pipecmd*)cmd;
4781b25f3b0Srsc     nulterminate(pcmd->left);
4791b25f3b0Srsc     nulterminate(pcmd->right);
4801b25f3b0Srsc     break;
4818b58e810Skaashoek 
4821b25f3b0Srsc   case LIST:
4831b25f3b0Srsc     lcmd = (struct listcmd*)cmd;
4841b25f3b0Srsc     nulterminate(lcmd->left);
4851b25f3b0Srsc     nulterminate(lcmd->right);
4861b25f3b0Srsc     break;
4871b25f3b0Srsc 
4881b25f3b0Srsc   case BACK:
4891b25f3b0Srsc     bcmd = (struct backcmd*)cmd;
4901b25f3b0Srsc     nulterminate(bcmd->cmd);
4911b25f3b0Srsc     break;
4921b25f3b0Srsc   }
493a759b8a4Srsc   return cmd;
4941b25f3b0Srsc }
495