xref: /xv6-public/sh.c (revision 1b25f3b0)
1*1b25f3b0Srsc // Shell.
2*1b25f3b0Srsc 
317a85657Srtm #include "types.h"
4d7b3b802Skaashoek #include "user.h"
517a85657Srtm #include "fcntl.h"
617a85657Srtm 
7*1b25f3b0Srsc // Parsed command representation
8*1b25f3b0Srsc #define EXEC  1
9*1b25f3b0Srsc #define REDIR 2
10*1b25f3b0Srsc #define PIPE  3
11*1b25f3b0Srsc #define LIST  4
12*1b25f3b0Srsc #define BACK  5
13*1b25f3b0Srsc 
148b58e810Skaashoek #define MAXARGS 10
158b58e810Skaashoek 
1621a88dd0Skaashoek struct cmd {
17*1b25f3b0Srsc   int type;
1821a88dd0Skaashoek };
19*1b25f3b0Srsc 
20*1b25f3b0Srsc struct execcmd {
21*1b25f3b0Srsc   int type;
22*1b25f3b0Srsc   char *argv[MAXARGS];
23*1b25f3b0Srsc   char *eargv[MAXARGS];
24*1b25f3b0Srsc };
25*1b25f3b0Srsc 
26*1b25f3b0Srsc struct redircmd {
27*1b25f3b0Srsc   int type;
28e00baa9fSkaashoek   struct cmd *cmd;
29*1b25f3b0Srsc   char *file;
30*1b25f3b0Srsc   char *efile;
31*1b25f3b0Srsc   int mode;
32*1b25f3b0Srsc   int fd;
33*1b25f3b0Srsc };
348b58e810Skaashoek 
35*1b25f3b0Srsc struct pipecmd {
36*1b25f3b0Srsc   int type;
37*1b25f3b0Srsc   struct cmd *left;
38*1b25f3b0Srsc   struct cmd *right;
39*1b25f3b0Srsc };
408b58e810Skaashoek 
41*1b25f3b0Srsc struct listcmd {
42*1b25f3b0Srsc   int type;
43*1b25f3b0Srsc   struct cmd *left;
44*1b25f3b0Srsc   struct cmd *right;
45*1b25f3b0Srsc };
46*1b25f3b0Srsc 
47*1b25f3b0Srsc struct backcmd {
48*1b25f3b0Srsc   int type;
49*1b25f3b0Srsc   struct cmd *cmd;
50*1b25f3b0Srsc };
51*1b25f3b0Srsc 
52*1b25f3b0Srsc struct cmd *parsecmd(char*);
53*1b25f3b0Srsc void panic(char*);
5417a85657Srtm 
5517a85657Srtm int
56*1b25f3b0Srsc fork1(void)
5717a85657Srtm {
58*1b25f3b0Srsc   int pid;
59*1b25f3b0Srsc 
60*1b25f3b0Srsc   pid = fork();
61*1b25f3b0Srsc   if(pid == -1)
62*1b25f3b0Srsc     panic("fork");
63*1b25f3b0Srsc   return pid;
64*1b25f3b0Srsc }
65*1b25f3b0Srsc 
66*1b25f3b0Srsc // Execute cmd.  Never returns.
67*1b25f3b0Srsc void
68*1b25f3b0Srsc runcmd(struct cmd *cmd)
69*1b25f3b0Srsc {
70*1b25f3b0Srsc   int p[2];
71*1b25f3b0Srsc   struct backcmd *bcmd;
72*1b25f3b0Srsc   struct execcmd *ecmd;
73*1b25f3b0Srsc   struct listcmd *lcmd;
74*1b25f3b0Srsc   struct pipecmd *pcmd;
75*1b25f3b0Srsc   struct redircmd *rcmd;
76*1b25f3b0Srsc 
77*1b25f3b0Srsc   if(cmd == 0)
78*1b25f3b0Srsc     return;
79*1b25f3b0Srsc 
80*1b25f3b0Srsc   switch(cmd->type){
81*1b25f3b0Srsc   default:
82*1b25f3b0Srsc     panic("runcmd");
83*1b25f3b0Srsc 
84*1b25f3b0Srsc   case EXEC:
85*1b25f3b0Srsc     ecmd = (struct execcmd*)cmd;
86*1b25f3b0Srsc     if(ecmd->argv[0] == 0)
87*1b25f3b0Srsc       exit();
88*1b25f3b0Srsc     exec(ecmd->argv[0], ecmd->argv);
89*1b25f3b0Srsc     printf(2, "exec %s failed\n", ecmd->argv[0]);
90*1b25f3b0Srsc     break;
91*1b25f3b0Srsc 
92*1b25f3b0Srsc   case REDIR:
93*1b25f3b0Srsc     rcmd = (struct redircmd*)cmd;
94*1b25f3b0Srsc     close(rcmd->fd);
95*1b25f3b0Srsc     if(open(rcmd->file, rcmd->mode) < 0){
96*1b25f3b0Srsc       printf(2, "open %s failed\n", rcmd->file);
97*1b25f3b0Srsc       exit();
98*1b25f3b0Srsc     }
99*1b25f3b0Srsc     runcmd(rcmd->cmd);
100*1b25f3b0Srsc     break;
101*1b25f3b0Srsc 
102*1b25f3b0Srsc   case PIPE:
103*1b25f3b0Srsc     pcmd = (struct pipecmd*)cmd;
104*1b25f3b0Srsc     if(pipe(p) < 0)
105*1b25f3b0Srsc       panic("pipe");
106*1b25f3b0Srsc     if(fork1() == 0){
107*1b25f3b0Srsc       close(1);
108*1b25f3b0Srsc       dup(p[1]);
109*1b25f3b0Srsc       close(p[0]);
110*1b25f3b0Srsc       close(p[1]);
111*1b25f3b0Srsc       runcmd(pcmd->left);
112*1b25f3b0Srsc     }
113*1b25f3b0Srsc     if(fork1() == 0){
114*1b25f3b0Srsc       close(0);
115*1b25f3b0Srsc       dup(p[0]);
116*1b25f3b0Srsc       close(p[0]);
117*1b25f3b0Srsc       close(p[1]);
118*1b25f3b0Srsc       runcmd(pcmd->right);
119*1b25f3b0Srsc     }
120*1b25f3b0Srsc     close(p[0]);
121*1b25f3b0Srsc     close(p[1]);
122*1b25f3b0Srsc     wait();
123*1b25f3b0Srsc     wait();
124*1b25f3b0Srsc     break;
125*1b25f3b0Srsc 
126*1b25f3b0Srsc   case LIST:
127*1b25f3b0Srsc     lcmd = (struct listcmd*)cmd;
128*1b25f3b0Srsc     if(fork1() == 0)
129*1b25f3b0Srsc       runcmd(lcmd->left);
130*1b25f3b0Srsc     wait();
131*1b25f3b0Srsc     runcmd(lcmd->right);
132*1b25f3b0Srsc     break;
133*1b25f3b0Srsc 
134*1b25f3b0Srsc   case BACK:
135*1b25f3b0Srsc     bcmd = (struct backcmd*)cmd;
136*1b25f3b0Srsc     if(fork1() == 0)
137*1b25f3b0Srsc       runcmd(bcmd->cmd);
138*1b25f3b0Srsc     break;
13917a85657Srtm   }
140f8f7fcbeSrsc   exit();
14117a85657Srtm }
142d7b3b802Skaashoek 
1438b58e810Skaashoek int
1449736728dSrsc getcmd(char *buf, int nbuf)
1459736728dSrsc {
1461b789e1dSrsc   printf(2, "$ ");
1479736728dSrsc   memset(buf, 0, nbuf);
1489736728dSrsc   gets(buf, nbuf);
1499736728dSrsc   if(buf[0] == 0) // EOF
1509736728dSrsc     return -1;
1519736728dSrsc   return 0;
1529736728dSrsc }
1539736728dSrsc 
1549736728dSrsc int
155*1b25f3b0Srsc main(void)
156d7b3b802Skaashoek {
157*1b25f3b0Srsc   static char buf[100];
1588b58e810Skaashoek 
159*1b25f3b0Srsc   while(getcmd(buf, sizeof(buf)) >= 0) {
160*1b25f3b0Srsc     if(fork1() == 0)
161*1b25f3b0Srsc       runcmd(parsecmd(buf));
162*1b25f3b0Srsc     wait();
16321a88dd0Skaashoek   }
164*1b25f3b0Srsc   exit();
1658b58e810Skaashoek }
1668b58e810Skaashoek 
1678b58e810Skaashoek void
168*1b25f3b0Srsc panic(char *s)
1698b58e810Skaashoek {
170*1b25f3b0Srsc   printf(2, "%s\n", s);
171d7b3b802Skaashoek   exit();
172d7b3b802Skaashoek }
17321a88dd0Skaashoek 
174*1b25f3b0Srsc // Constructors
175*1b25f3b0Srsc 
176*1b25f3b0Srsc struct cmd*
177*1b25f3b0Srsc execcmd(void)
178*1b25f3b0Srsc {
179*1b25f3b0Srsc   struct execcmd *cmd;
180*1b25f3b0Srsc 
181*1b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
182*1b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
183*1b25f3b0Srsc   cmd->type = EXEC;
184*1b25f3b0Srsc   return (struct cmd*)cmd;
18521a88dd0Skaashoek }
186*1b25f3b0Srsc 
187*1b25f3b0Srsc struct cmd*
188*1b25f3b0Srsc redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
189*1b25f3b0Srsc {
190*1b25f3b0Srsc   struct redircmd *cmd;
191*1b25f3b0Srsc 
192*1b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
193*1b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
194*1b25f3b0Srsc   cmd->type = REDIR;
195*1b25f3b0Srsc   cmd->cmd = subcmd;
196*1b25f3b0Srsc   cmd->file = file;
197*1b25f3b0Srsc   cmd->efile = efile;
198*1b25f3b0Srsc   cmd->mode = mode;
199*1b25f3b0Srsc   cmd->fd = fd;
200*1b25f3b0Srsc   return (struct cmd*)cmd;
201d7b3b802Skaashoek }
202*1b25f3b0Srsc 
203*1b25f3b0Srsc struct cmd*
204*1b25f3b0Srsc pipecmd(struct cmd *left, struct cmd *right)
205*1b25f3b0Srsc {
206*1b25f3b0Srsc   struct pipecmd *cmd;
207*1b25f3b0Srsc 
208*1b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
209*1b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
210*1b25f3b0Srsc   cmd->type = PIPE;
211*1b25f3b0Srsc   cmd->left = left;
212*1b25f3b0Srsc   cmd->right = right;
213*1b25f3b0Srsc   return (struct cmd*)cmd;
214d7b3b802Skaashoek }
215*1b25f3b0Srsc 
216*1b25f3b0Srsc struct cmd*
217*1b25f3b0Srsc listcmd(struct cmd *left, struct cmd *right)
218*1b25f3b0Srsc {
219*1b25f3b0Srsc   struct listcmd *cmd;
220*1b25f3b0Srsc 
221*1b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
222*1b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
223*1b25f3b0Srsc   cmd->type = LIST;
224*1b25f3b0Srsc   cmd->left = left;
225*1b25f3b0Srsc   cmd->right = right;
226*1b25f3b0Srsc   return (struct cmd*)cmd;
22721a88dd0Skaashoek }
228*1b25f3b0Srsc 
229*1b25f3b0Srsc struct cmd*
230*1b25f3b0Srsc backcmd(struct cmd *subcmd)
231*1b25f3b0Srsc {
232*1b25f3b0Srsc   struct backcmd *cmd;
233*1b25f3b0Srsc 
234*1b25f3b0Srsc   cmd = malloc(sizeof(*cmd));
235*1b25f3b0Srsc   memset(cmd, 0, sizeof(*cmd));
236*1b25f3b0Srsc   cmd->type = BACK;
237*1b25f3b0Srsc   cmd->cmd = subcmd;
238*1b25f3b0Srsc   return (struct cmd*)cmd;
239*1b25f3b0Srsc }
240*1b25f3b0Srsc 
241*1b25f3b0Srsc // Parsing
242*1b25f3b0Srsc 
243*1b25f3b0Srsc char whitespace[] = " \t\r\n\v";
244*1b25f3b0Srsc char symbols[] = "<|>&;()";
245*1b25f3b0Srsc 
246*1b25f3b0Srsc int
247*1b25f3b0Srsc peek(char **ps, char *es, char *toks)
248*1b25f3b0Srsc {
249*1b25f3b0Srsc   char *s;
250*1b25f3b0Srsc 
251*1b25f3b0Srsc   s = *ps;
252*1b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
253*1b25f3b0Srsc     s++;
254*1b25f3b0Srsc   *ps = s;
255*1b25f3b0Srsc   return *s && strchr(toks, *s);
25621a88dd0Skaashoek }
2578b58e810Skaashoek 
2588b58e810Skaashoek int
259*1b25f3b0Srsc gettoken(char **ps, char *es, char **q, char **eq)
2608b58e810Skaashoek {
261*1b25f3b0Srsc   char *s;
262*1b25f3b0Srsc   int ret;
2638b58e810Skaashoek 
264*1b25f3b0Srsc   s = *ps;
265*1b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
266*1b25f3b0Srsc     s++;
267*1b25f3b0Srsc   if(q)
268*1b25f3b0Srsc     *q = s;
269*1b25f3b0Srsc   ret = *s;
270*1b25f3b0Srsc   switch(*s){
271*1b25f3b0Srsc   case 0:
272*1b25f3b0Srsc     break;
273*1b25f3b0Srsc   case '|':
274*1b25f3b0Srsc   case '(':
275*1b25f3b0Srsc   case ')':
276*1b25f3b0Srsc   case ';':
277*1b25f3b0Srsc   case '&':
2788b58e810Skaashoek   case '<':
279*1b25f3b0Srsc     s++;
2808b58e810Skaashoek     break;
2818b58e810Skaashoek   case '>':
282*1b25f3b0Srsc     s++;
283*1b25f3b0Srsc     if(*s == '>'){
284*1b25f3b0Srsc       ret = '+';
285*1b25f3b0Srsc       s++;
2868b58e810Skaashoek     }
287*1b25f3b0Srsc     break;
288*1b25f3b0Srsc   default:
289*1b25f3b0Srsc     ret = 'a';
290*1b25f3b0Srsc     while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
291*1b25f3b0Srsc       s++;
292*1b25f3b0Srsc     break;
293*1b25f3b0Srsc   }
294*1b25f3b0Srsc   if(eq)
295*1b25f3b0Srsc     *eq = s;
296*1b25f3b0Srsc 
297*1b25f3b0Srsc   while(s < es && strchr(whitespace, *s))
298*1b25f3b0Srsc     s++;
299*1b25f3b0Srsc   *ps = s;
300*1b25f3b0Srsc   return ret;
301*1b25f3b0Srsc }
302*1b25f3b0Srsc 
303*1b25f3b0Srsc void nulterminate(struct cmd*);
304*1b25f3b0Srsc struct cmd *parseline(char**, char*);
305*1b25f3b0Srsc struct cmd *parsepipe(char**, char*);
306*1b25f3b0Srsc struct cmd *parseredirs(struct cmd*, char**, char*);
307*1b25f3b0Srsc struct cmd *parseblock(char**, char*);
308*1b25f3b0Srsc struct cmd *parseexec(char**, char*);
309*1b25f3b0Srsc 
310*1b25f3b0Srsc struct cmd*
311*1b25f3b0Srsc parsecmd(char *s)
312*1b25f3b0Srsc {
313*1b25f3b0Srsc   char *es;
314*1b25f3b0Srsc   struct cmd *cmd;
315*1b25f3b0Srsc 
316*1b25f3b0Srsc   es = s + strlen(s);
317*1b25f3b0Srsc   cmd = parseline(&s, es);
318*1b25f3b0Srsc   peek(&s, es, "");
319*1b25f3b0Srsc   if(s != es){
320*1b25f3b0Srsc     printf(2, "leftovers: %s\n", s);
321*1b25f3b0Srsc     panic("syntax");
322*1b25f3b0Srsc   }
323*1b25f3b0Srsc   nulterminate(cmd);
324*1b25f3b0Srsc   return cmd;
325*1b25f3b0Srsc }
326*1b25f3b0Srsc 
327*1b25f3b0Srsc struct cmd*
328*1b25f3b0Srsc parseline(char **ps, char *es)
329*1b25f3b0Srsc {
330*1b25f3b0Srsc   struct cmd *cmd;
331*1b25f3b0Srsc 
332*1b25f3b0Srsc   cmd = parsepipe(ps, es);
333*1b25f3b0Srsc   while(peek(ps, es, "&")){
334*1b25f3b0Srsc     gettoken(ps, es, 0, 0);
335*1b25f3b0Srsc     cmd = backcmd(cmd);
336*1b25f3b0Srsc   }
337*1b25f3b0Srsc   if(peek(ps, es, ";")){
338*1b25f3b0Srsc     gettoken(ps, es, 0, 0);
339*1b25f3b0Srsc     cmd = listcmd(cmd, parseline(ps, es));
340*1b25f3b0Srsc   }
341*1b25f3b0Srsc   return cmd;
342*1b25f3b0Srsc }
343*1b25f3b0Srsc 
344*1b25f3b0Srsc struct cmd*
345*1b25f3b0Srsc parsepipe(char **ps, char *es)
346*1b25f3b0Srsc {
347*1b25f3b0Srsc   struct cmd *cmd;
348*1b25f3b0Srsc 
349*1b25f3b0Srsc   cmd = parseexec(ps, es);
350*1b25f3b0Srsc   if(peek(ps, es, "|")){
351*1b25f3b0Srsc     gettoken(ps, es, 0, 0);
352*1b25f3b0Srsc     cmd = pipecmd(cmd, parsepipe(ps, es));
353*1b25f3b0Srsc   }
354*1b25f3b0Srsc   return cmd;
355*1b25f3b0Srsc }
356*1b25f3b0Srsc 
357*1b25f3b0Srsc struct cmd*
358*1b25f3b0Srsc parseblock(char **ps, char *es)
359*1b25f3b0Srsc {
360*1b25f3b0Srsc   struct cmd *cmd;
361*1b25f3b0Srsc 
362*1b25f3b0Srsc   if(!peek(ps, es, "("))
363*1b25f3b0Srsc     panic("parseblock");
364*1b25f3b0Srsc   gettoken(ps, es, 0, 0);
365*1b25f3b0Srsc   cmd = parseline(ps, es);
366*1b25f3b0Srsc   if(!peek(ps, es, ")"))
367*1b25f3b0Srsc     panic("syntax - missing )");
368*1b25f3b0Srsc   gettoken(ps, es, 0, 0);
369*1b25f3b0Srsc   cmd = parseredirs(cmd, ps, es);
370*1b25f3b0Srsc   return cmd;
371*1b25f3b0Srsc }
372*1b25f3b0Srsc 
373*1b25f3b0Srsc struct cmd*
374*1b25f3b0Srsc parseredirs(struct cmd *cmd, char **ps, char *es)
375*1b25f3b0Srsc {
376*1b25f3b0Srsc   int tok;
377*1b25f3b0Srsc   char *q, *eq;
378*1b25f3b0Srsc 
379*1b25f3b0Srsc   while(peek(ps, es, "<>")){
380*1b25f3b0Srsc     tok = gettoken(ps, es, 0, 0);
381*1b25f3b0Srsc     if(gettoken(ps, es, &q, &eq) != 'a')
382*1b25f3b0Srsc       panic("missing file for redirection");
383*1b25f3b0Srsc     switch(tok){
384*1b25f3b0Srsc     case '<':
385*1b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
386*1b25f3b0Srsc       break;
387*1b25f3b0Srsc     case '>':
388*1b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
389*1b25f3b0Srsc       break;
390*1b25f3b0Srsc     case '+':  // >>
391*1b25f3b0Srsc       cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
3928b58e810Skaashoek       break;
3938b58e810Skaashoek     }
3948b58e810Skaashoek   }
395*1b25f3b0Srsc   return cmd;
3968b58e810Skaashoek }
3978b58e810Skaashoek 
398*1b25f3b0Srsc struct cmd*
399*1b25f3b0Srsc parseexec(char **ps, char *es)
4008b58e810Skaashoek {
401*1b25f3b0Srsc   char *q, *eq;
402*1b25f3b0Srsc   int tok, argc;
403*1b25f3b0Srsc   struct execcmd *cmd;
404*1b25f3b0Srsc   struct cmd *ret;
4058b58e810Skaashoek 
406*1b25f3b0Srsc   if(peek(ps, es, "("))
407*1b25f3b0Srsc     return parseblock(ps, es);
408*1b25f3b0Srsc 
409*1b25f3b0Srsc   ret = execcmd();
410*1b25f3b0Srsc   cmd = (struct execcmd*)ret;
411*1b25f3b0Srsc 
412*1b25f3b0Srsc   argc = 0;
413*1b25f3b0Srsc   ret = parseredirs(ret, ps, es);
414*1b25f3b0Srsc   while(!peek(ps, es, "|)&;")){
415*1b25f3b0Srsc     if((tok=gettoken(ps, es, &q, &eq)) == 0)
416*1b25f3b0Srsc       break;
417*1b25f3b0Srsc     if(tok != 'a')
418*1b25f3b0Srsc       panic("syntax");
419*1b25f3b0Srsc     cmd->argv[argc] = q;
420*1b25f3b0Srsc     cmd->eargv[argc] = eq;
421*1b25f3b0Srsc     argc++;
422*1b25f3b0Srsc     if(argc >= MAXARGS)
423*1b25f3b0Srsc       panic("too many args");
424*1b25f3b0Srsc     ret = parseredirs(ret, ps, es);
4258b58e810Skaashoek   }
426*1b25f3b0Srsc   cmd->argv[argc] = 0;
427*1b25f3b0Srsc   cmd->eargv[argc] = 0;
428*1b25f3b0Srsc   return ret;
4298b58e810Skaashoek }
4308b58e810Skaashoek 
431*1b25f3b0Srsc // NUL-terminate all the counted strings.
432*1b25f3b0Srsc void
433*1b25f3b0Srsc nulterminate(struct cmd *cmd)
4348b58e810Skaashoek {
435*1b25f3b0Srsc   int i;
436*1b25f3b0Srsc   struct backcmd *bcmd;
437*1b25f3b0Srsc   struct execcmd *ecmd;
438*1b25f3b0Srsc   struct listcmd *lcmd;
439*1b25f3b0Srsc   struct pipecmd *pcmd;
440*1b25f3b0Srsc   struct redircmd *rcmd;
4418b58e810Skaashoek 
442*1b25f3b0Srsc   if(cmd == 0)
443*1b25f3b0Srsc     return;
4448b58e810Skaashoek 
445*1b25f3b0Srsc   switch(cmd->type){
446*1b25f3b0Srsc   case EXEC:
447*1b25f3b0Srsc     ecmd = (struct execcmd*)cmd;
448*1b25f3b0Srsc     for(i=0; ecmd->argv[i]; i++)
449*1b25f3b0Srsc       *ecmd->eargv[i] = 0;
450*1b25f3b0Srsc     break;
4518b58e810Skaashoek 
452*1b25f3b0Srsc   case REDIR:
453*1b25f3b0Srsc     rcmd = (struct redircmd*)cmd;
454*1b25f3b0Srsc     nulterminate(rcmd->cmd);
455*1b25f3b0Srsc     *rcmd->efile = 0;
456*1b25f3b0Srsc     break;
4578b58e810Skaashoek 
458*1b25f3b0Srsc   case PIPE:
459*1b25f3b0Srsc     pcmd = (struct pipecmd*)cmd;
460*1b25f3b0Srsc     nulterminate(pcmd->left);
461*1b25f3b0Srsc     nulterminate(pcmd->right);
462*1b25f3b0Srsc     break;
4638b58e810Skaashoek 
464*1b25f3b0Srsc   case LIST:
465*1b25f3b0Srsc     lcmd = (struct listcmd*)cmd;
466*1b25f3b0Srsc     nulterminate(lcmd->left);
467*1b25f3b0Srsc     nulterminate(lcmd->right);
468*1b25f3b0Srsc     break;
469*1b25f3b0Srsc 
470*1b25f3b0Srsc   case BACK:
471*1b25f3b0Srsc     bcmd = (struct backcmd*)cmd;
472*1b25f3b0Srsc     nulterminate(bcmd->cmd);
473*1b25f3b0Srsc     break;
474*1b25f3b0Srsc   }
475*1b25f3b0Srsc }
476