1*8462SApril.Chin@Sun.COM /***********************************************************************
2*8462SApril.Chin@Sun.COM *                                                                      *
3*8462SApril.Chin@Sun.COM *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
5*8462SApril.Chin@Sun.COM *                      and is licensed under the                       *
6*8462SApril.Chin@Sun.COM *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
8*8462SApril.Chin@Sun.COM *                                                                      *
9*8462SApril.Chin@Sun.COM *                A copy of the License is available at                 *
10*8462SApril.Chin@Sun.COM *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*8462SApril.Chin@Sun.COM *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*8462SApril.Chin@Sun.COM *                                                                      *
13*8462SApril.Chin@Sun.COM *              Information and Software Systems Research               *
14*8462SApril.Chin@Sun.COM *                            AT&T Research                             *
15*8462SApril.Chin@Sun.COM *                           Florham Park NJ                            *
16*8462SApril.Chin@Sun.COM *                                                                      *
17*8462SApril.Chin@Sun.COM *                 Glenn Fowler <gsf@research.att.com>                  *
18*8462SApril.Chin@Sun.COM *                  David Korn <dgk@research.att.com>                   *
19*8462SApril.Chin@Sun.COM *                   Phong Vo <kpv@research.att.com>                    *
20*8462SApril.Chin@Sun.COM *                                                                      *
21*8462SApril.Chin@Sun.COM ***********************************************************************/
22*8462SApril.Chin@Sun.COM #pragma prototyped
23*8462SApril.Chin@Sun.COM /*
24*8462SApril.Chin@Sun.COM  * Glenn Fowler
25*8462SApril.Chin@Sun.COM  * AT&T Research
26*8462SApril.Chin@Sun.COM  *
27*8462SApril.Chin@Sun.COM  * xargs/tw command arg list support
28*8462SApril.Chin@Sun.COM  */
29*8462SApril.Chin@Sun.COM 
30*8462SApril.Chin@Sun.COM #include <ast.h>
31*8462SApril.Chin@Sun.COM #include <ctype.h>
32*8462SApril.Chin@Sun.COM #include <error.h>
33*8462SApril.Chin@Sun.COM #include <proc.h>
34*8462SApril.Chin@Sun.COM 
35*8462SApril.Chin@Sun.COM #include "cmdarg.h"
36*8462SApril.Chin@Sun.COM 
37*8462SApril.Chin@Sun.COM #ifndef EXIT_QUIT
38*8462SApril.Chin@Sun.COM #define EXIT_QUIT	255
39*8462SApril.Chin@Sun.COM #endif
40*8462SApril.Chin@Sun.COM 
41*8462SApril.Chin@Sun.COM static const char*	echo[] = { "echo", 0 };
42*8462SApril.Chin@Sun.COM 
43*8462SApril.Chin@Sun.COM /*
44*8462SApril.Chin@Sun.COM  * open a cmdarg stream
45*8462SApril.Chin@Sun.COM  * initialize the command for execution
46*8462SApril.Chin@Sun.COM  * argv[-1] is reserved for procrun(PROC_ARGMOD)
47*8462SApril.Chin@Sun.COM  */
48*8462SApril.Chin@Sun.COM 
49*8462SApril.Chin@Sun.COM Cmdarg_t*
50*8462SApril.Chin@Sun.COM cmdopen(char** argv, int argmax, int size, const char* argpat, int flags)
51*8462SApril.Chin@Sun.COM {
52*8462SApril.Chin@Sun.COM 	register Cmdarg_t*	cmd;
53*8462SApril.Chin@Sun.COM 	register int		n;
54*8462SApril.Chin@Sun.COM 	register char**		p;
55*8462SApril.Chin@Sun.COM 	register char*		s;
56*8462SApril.Chin@Sun.COM 	char*			sh;
57*8462SApril.Chin@Sun.COM 	int			c;
58*8462SApril.Chin@Sun.COM 	int			m;
59*8462SApril.Chin@Sun.COM 	int			argc;
60*8462SApril.Chin@Sun.COM 	long			x;
61*8462SApril.Chin@Sun.COM 
62*8462SApril.Chin@Sun.COM 	char**			post = 0;
63*8462SApril.Chin@Sun.COM 
64*8462SApril.Chin@Sun.COM 	n = sizeof(char**);
65*8462SApril.Chin@Sun.COM 	if (*argv)
66*8462SApril.Chin@Sun.COM 	{
67*8462SApril.Chin@Sun.COM 		for (p = argv + 1; *p; p++)
68*8462SApril.Chin@Sun.COM 		{
69*8462SApril.Chin@Sun.COM 			if ((flags & CMD_POST) && argpat && streq(*p, argpat))
70*8462SApril.Chin@Sun.COM 			{
71*8462SApril.Chin@Sun.COM 				*p = 0;
72*8462SApril.Chin@Sun.COM 				post = p + 1;
73*8462SApril.Chin@Sun.COM 				argpat = 0;
74*8462SApril.Chin@Sun.COM 			}
75*8462SApril.Chin@Sun.COM 			else
76*8462SApril.Chin@Sun.COM 				n += strlen(*p) + 1;
77*8462SApril.Chin@Sun.COM 		}
78*8462SApril.Chin@Sun.COM 		argc = p - argv;
79*8462SApril.Chin@Sun.COM 	}
80*8462SApril.Chin@Sun.COM 	else
81*8462SApril.Chin@Sun.COM 		argc = 0;
82*8462SApril.Chin@Sun.COM 	for (p = environ; *p; p++)
83*8462SApril.Chin@Sun.COM 		n += sizeof(char**) + strlen(*p) + 1;
84*8462SApril.Chin@Sun.COM 	if ((x = strtol(astconf("ARG_MAX", NiL, NiL), NiL, 0)) <= 0)
85*8462SApril.Chin@Sun.COM 		x = ARG_MAX;
86*8462SApril.Chin@Sun.COM 	if (size <= 0 || size > x)
87*8462SApril.Chin@Sun.COM 		size = x;
88*8462SApril.Chin@Sun.COM 	sh = pathshell();
89*8462SApril.Chin@Sun.COM 	m = n + (argc + 4) * sizeof(char**) + strlen(sh) + 1;
90*8462SApril.Chin@Sun.COM 	m = roundof(m, sizeof(char**));
91*8462SApril.Chin@Sun.COM 	if (size < m)
92*8462SApril.Chin@Sun.COM 	{
93*8462SApril.Chin@Sun.COM 		error(2, "size must be at least %d", m);
94*8462SApril.Chin@Sun.COM 		return 0;
95*8462SApril.Chin@Sun.COM 	}
96*8462SApril.Chin@Sun.COM 	if ((m = x / 10) > 2048)
97*8462SApril.Chin@Sun.COM 		m = 2048;
98*8462SApril.Chin@Sun.COM 	if (size > (x - m))
99*8462SApril.Chin@Sun.COM 		size = x - m;
100*8462SApril.Chin@Sun.COM 	n = size - n;
101*8462SApril.Chin@Sun.COM 	m = ((flags & CMD_INSERT) && argpat) ? (strlen(argpat) + 1) : 0;
102*8462SApril.Chin@Sun.COM 	if (!(cmd = newof(0, Cmdarg_t, 1, n + m)))
103*8462SApril.Chin@Sun.COM 	{
104*8462SApril.Chin@Sun.COM 		error(ERROR_SYSTEM|2, "out of space");
105*8462SApril.Chin@Sun.COM 		return 0;
106*8462SApril.Chin@Sun.COM 	}
107*8462SApril.Chin@Sun.COM 	c = n / sizeof(char**);
108*8462SApril.Chin@Sun.COM 	if (argmax <= 0 || argmax > c)
109*8462SApril.Chin@Sun.COM 		argmax = c;
110*8462SApril.Chin@Sun.COM 	s = cmd->buf;
111*8462SApril.Chin@Sun.COM 	if (!argv[0])
112*8462SApril.Chin@Sun.COM 	{
113*8462SApril.Chin@Sun.COM 		argv = (char**)echo;
114*8462SApril.Chin@Sun.COM 		cmd->echo = 1;
115*8462SApril.Chin@Sun.COM 	}
116*8462SApril.Chin@Sun.COM 	else if (streq(argv[0], echo[0]))
117*8462SApril.Chin@Sun.COM 	{
118*8462SApril.Chin@Sun.COM 		cmd->echo = 1;
119*8462SApril.Chin@Sun.COM 		flags &= ~CMD_NEWLINE;
120*8462SApril.Chin@Sun.COM 	}
121*8462SApril.Chin@Sun.COM 	else if (!(flags & CMD_CHECKED))
122*8462SApril.Chin@Sun.COM 	{
123*8462SApril.Chin@Sun.COM 		if (!pathpath(s, argv[0], NiL, PATH_REGULAR|PATH_EXECUTE))
124*8462SApril.Chin@Sun.COM 		{
125*8462SApril.Chin@Sun.COM 			if (!(flags & CMD_SILENT))
126*8462SApril.Chin@Sun.COM 			{
127*8462SApril.Chin@Sun.COM 				error(ERROR_SYSTEM|2, "%s: command not found", argv[0]);
128*8462SApril.Chin@Sun.COM 				exit(EXIT_NOTFOUND);
129*8462SApril.Chin@Sun.COM 			}
130*8462SApril.Chin@Sun.COM 			free(cmd);
131*8462SApril.Chin@Sun.COM 			return 0;
132*8462SApril.Chin@Sun.COM 		}
133*8462SApril.Chin@Sun.COM 		argv[0] = s;
134*8462SApril.Chin@Sun.COM 	}
135*8462SApril.Chin@Sun.COM 	s += strlen(s) + 1;
136*8462SApril.Chin@Sun.COM 	if (m)
137*8462SApril.Chin@Sun.COM 	{
138*8462SApril.Chin@Sun.COM 		cmd->insert = strcpy(s, argpat);
139*8462SApril.Chin@Sun.COM 		cmd->insertlen = m - 1;
140*8462SApril.Chin@Sun.COM 		s += m;
141*8462SApril.Chin@Sun.COM 	}
142*8462SApril.Chin@Sun.COM 	s += sizeof(char**) - (s - cmd->buf) % sizeof(char**);
143*8462SApril.Chin@Sun.COM 	p = (char**)s;
144*8462SApril.Chin@Sun.COM 	n -= strlen(*p++ = sh) + 1;
145*8462SApril.Chin@Sun.COM 	cmd->argv = p;
146*8462SApril.Chin@Sun.COM 	while (*p = *argv++)
147*8462SApril.Chin@Sun.COM 		p++;
148*8462SApril.Chin@Sun.COM 	if (m)
149*8462SApril.Chin@Sun.COM 	{
150*8462SApril.Chin@Sun.COM 		argmax = 1;
151*8462SApril.Chin@Sun.COM 		*p++ = 0;
152*8462SApril.Chin@Sun.COM 		cmd->insertarg = p;
153*8462SApril.Chin@Sun.COM 		argv = cmd->argv;
154*8462SApril.Chin@Sun.COM 		c = *cmd->insert;
155*8462SApril.Chin@Sun.COM 		while (s = *argv)
156*8462SApril.Chin@Sun.COM 		{
157*8462SApril.Chin@Sun.COM 			while ((s = strchr(s, c)) && strncmp(cmd->insert, s, cmd->insertlen))
158*8462SApril.Chin@Sun.COM 				s++;
159*8462SApril.Chin@Sun.COM 			*p++ = s ? *argv : (char*)0;
160*8462SApril.Chin@Sun.COM 			argv++;
161*8462SApril.Chin@Sun.COM 		}
162*8462SApril.Chin@Sun.COM 		*p++ = 0;
163*8462SApril.Chin@Sun.COM 	}
164*8462SApril.Chin@Sun.COM 	cmd->firstarg = cmd->nextarg = p;
165*8462SApril.Chin@Sun.COM 	cmd->laststr = cmd->nextstr = cmd->buf + n;
166*8462SApril.Chin@Sun.COM 	cmd->argmax = argmax;
167*8462SApril.Chin@Sun.COM 	cmd->flags = flags;
168*8462SApril.Chin@Sun.COM 	cmd->offset = ((cmd->postarg = post) ? (argc - (post - argv)) : 0) + 3;
169*8462SApril.Chin@Sun.COM 	return cmd;
170*8462SApril.Chin@Sun.COM }
171*8462SApril.Chin@Sun.COM 
172*8462SApril.Chin@Sun.COM /*
173*8462SApril.Chin@Sun.COM  * flush outstanding command file args
174*8462SApril.Chin@Sun.COM  */
175*8462SApril.Chin@Sun.COM 
176*8462SApril.Chin@Sun.COM int
177*8462SApril.Chin@Sun.COM cmdflush(register Cmdarg_t* cmd)
178*8462SApril.Chin@Sun.COM {
179*8462SApril.Chin@Sun.COM 	register char*	s;
180*8462SApril.Chin@Sun.COM 	register char**	p;
181*8462SApril.Chin@Sun.COM 	register int	n;
182*8462SApril.Chin@Sun.COM 
183*8462SApril.Chin@Sun.COM 	if (cmd->flags & CMD_EMPTY)
184*8462SApril.Chin@Sun.COM 		cmd->flags &= ~CMD_EMPTY;
185*8462SApril.Chin@Sun.COM 	else if (cmd->nextarg <= cmd->firstarg)
186*8462SApril.Chin@Sun.COM 		return 0;
187*8462SApril.Chin@Sun.COM 	if ((cmd->flags & CMD_MINIMUM) && cmd->argcount < cmd->argmax)
188*8462SApril.Chin@Sun.COM 	{
189*8462SApril.Chin@Sun.COM 		if (!(cmd->flags & CMD_SILENT))
190*8462SApril.Chin@Sun.COM 			error(2, "%d arg command would be too long", cmd->argcount);
191*8462SApril.Chin@Sun.COM 		return -1;
192*8462SApril.Chin@Sun.COM 	}
193*8462SApril.Chin@Sun.COM 	cmd->total.args += cmd->argcount;
194*8462SApril.Chin@Sun.COM 	cmd->total.commands++;
195*8462SApril.Chin@Sun.COM 	cmd->argcount = 0;
196*8462SApril.Chin@Sun.COM 	if (p = cmd->postarg)
197*8462SApril.Chin@Sun.COM 		while (*cmd->nextarg++ = *p++);
198*8462SApril.Chin@Sun.COM 	else
199*8462SApril.Chin@Sun.COM 		*cmd->nextarg = 0;
200*8462SApril.Chin@Sun.COM 	if (s = cmd->insert)
201*8462SApril.Chin@Sun.COM 	{
202*8462SApril.Chin@Sun.COM 		char*	a;
203*8462SApril.Chin@Sun.COM 		char*	b;
204*8462SApril.Chin@Sun.COM 		char*	e;
205*8462SApril.Chin@Sun.COM 		char*	t;
206*8462SApril.Chin@Sun.COM 		char*	u;
207*8462SApril.Chin@Sun.COM 		int	c;
208*8462SApril.Chin@Sun.COM 		int	m;
209*8462SApril.Chin@Sun.COM 
210*8462SApril.Chin@Sun.COM 		a = cmd->firstarg[0];
211*8462SApril.Chin@Sun.COM 		b = (char*)&cmd->nextarg[1];
212*8462SApril.Chin@Sun.COM 		e = cmd->nextstr;
213*8462SApril.Chin@Sun.COM 		c = *s;
214*8462SApril.Chin@Sun.COM 		m = cmd->insertlen;
215*8462SApril.Chin@Sun.COM 		for (n = 1; cmd->argv[n]; n++)
216*8462SApril.Chin@Sun.COM 			if (t = cmd->insertarg[n])
217*8462SApril.Chin@Sun.COM 			{
218*8462SApril.Chin@Sun.COM 				cmd->argv[n] = b;
219*8462SApril.Chin@Sun.COM 				for (;;)
220*8462SApril.Chin@Sun.COM 				{
221*8462SApril.Chin@Sun.COM 					if (!(u = strchr(t, c)))
222*8462SApril.Chin@Sun.COM 					{
223*8462SApril.Chin@Sun.COM 						b += sfsprintf(b, e - b, "%s", t);
224*8462SApril.Chin@Sun.COM 						break;
225*8462SApril.Chin@Sun.COM 					}
226*8462SApril.Chin@Sun.COM 					if (!strncmp(s, u, m))
227*8462SApril.Chin@Sun.COM 					{
228*8462SApril.Chin@Sun.COM 						b += sfsprintf(b, e - b, "%-.*s%s", u - t, t, a);
229*8462SApril.Chin@Sun.COM 						t = u + m;
230*8462SApril.Chin@Sun.COM 					}
231*8462SApril.Chin@Sun.COM 					else if (b >= e)
232*8462SApril.Chin@Sun.COM 						break;
233*8462SApril.Chin@Sun.COM 					else
234*8462SApril.Chin@Sun.COM 					{
235*8462SApril.Chin@Sun.COM 						*b++ = *u++;
236*8462SApril.Chin@Sun.COM 						t = u;
237*8462SApril.Chin@Sun.COM 					}
238*8462SApril.Chin@Sun.COM 				}
239*8462SApril.Chin@Sun.COM 				if (b < e)
240*8462SApril.Chin@Sun.COM 					*b++ = 0;
241*8462SApril.Chin@Sun.COM 			}
242*8462SApril.Chin@Sun.COM 		if (b >= e)
243*8462SApril.Chin@Sun.COM 		{
244*8462SApril.Chin@Sun.COM 			if (!(cmd->flags & CMD_SILENT))
245*8462SApril.Chin@Sun.COM 				error(2, "%s: command too large after insert", a);
246*8462SApril.Chin@Sun.COM 			return -1;
247*8462SApril.Chin@Sun.COM 		}
248*8462SApril.Chin@Sun.COM 	}
249*8462SApril.Chin@Sun.COM 	cmd->nextarg = cmd->firstarg;
250*8462SApril.Chin@Sun.COM 	cmd->nextstr = cmd->laststr;
251*8462SApril.Chin@Sun.COM 	if (cmd->flags & (CMD_QUERY|CMD_TRACE))
252*8462SApril.Chin@Sun.COM 	{
253*8462SApril.Chin@Sun.COM 		p = cmd->argv;
254*8462SApril.Chin@Sun.COM 		sfprintf(sfstderr, "+ %s", *p);
255*8462SApril.Chin@Sun.COM 		while (s = *++p)
256*8462SApril.Chin@Sun.COM 			sfprintf(sfstderr, " %s", s);
257*8462SApril.Chin@Sun.COM 		if (!(cmd->flags & CMD_QUERY))
258*8462SApril.Chin@Sun.COM 			sfprintf(sfstderr, "\n");
259*8462SApril.Chin@Sun.COM 		else if (astquery(1, "? "))
260*8462SApril.Chin@Sun.COM 			return 0;
261*8462SApril.Chin@Sun.COM 	}
262*8462SApril.Chin@Sun.COM 	if (cmd->echo)
263*8462SApril.Chin@Sun.COM 	{
264*8462SApril.Chin@Sun.COM 		n = (cmd->flags & CMD_NEWLINE) ? '\n' : ' ';
265*8462SApril.Chin@Sun.COM 		for (p = cmd->argv + 1; s = *p++;)
266*8462SApril.Chin@Sun.COM 			sfputr(sfstdout, s, *p ? n : '\n');
267*8462SApril.Chin@Sun.COM 		n = 0;
268*8462SApril.Chin@Sun.COM 	}
269*8462SApril.Chin@Sun.COM 	else if ((n = procrun(*cmd->argv, cmd->argv, PROC_ARGMOD|PROC_IGNOREPATH)) == -1)
270*8462SApril.Chin@Sun.COM 	{
271*8462SApril.Chin@Sun.COM 		if (!(cmd->flags & CMD_SILENT))
272*8462SApril.Chin@Sun.COM 		{
273*8462SApril.Chin@Sun.COM 			error(ERROR_SYSTEM|2, "%s: command exec error", *cmd->argv);
274*8462SApril.Chin@Sun.COM 			exit(EXIT_NOTFOUND - 1);
275*8462SApril.Chin@Sun.COM 		}
276*8462SApril.Chin@Sun.COM 		return -1;
277*8462SApril.Chin@Sun.COM 	}
278*8462SApril.Chin@Sun.COM 	else if (n >= EXIT_NOTFOUND - 1)
279*8462SApril.Chin@Sun.COM 	{
280*8462SApril.Chin@Sun.COM 		if (!(cmd->flags & CMD_SILENT))
281*8462SApril.Chin@Sun.COM 			exit(n);
282*8462SApril.Chin@Sun.COM 	}
283*8462SApril.Chin@Sun.COM 	else if (!(cmd->flags & CMD_IGNORE))
284*8462SApril.Chin@Sun.COM 	{
285*8462SApril.Chin@Sun.COM 		if (n == EXIT_QUIT && !(cmd->flags & CMD_SILENT))
286*8462SApril.Chin@Sun.COM 			exit(2);
287*8462SApril.Chin@Sun.COM 		if (n)
288*8462SApril.Chin@Sun.COM 			error_info.errors++;
289*8462SApril.Chin@Sun.COM 	}
290*8462SApril.Chin@Sun.COM 	return n;
291*8462SApril.Chin@Sun.COM }
292*8462SApril.Chin@Sun.COM 
293*8462SApril.Chin@Sun.COM /*
294*8462SApril.Chin@Sun.COM  * add file to the command arg list
295*8462SApril.Chin@Sun.COM  */
296*8462SApril.Chin@Sun.COM 
297*8462SApril.Chin@Sun.COM int
298*8462SApril.Chin@Sun.COM cmdarg(register Cmdarg_t* cmd, const char* file, register int len)
299*8462SApril.Chin@Sun.COM {
300*8462SApril.Chin@Sun.COM 	int	i;
301*8462SApril.Chin@Sun.COM 	int	r;
302*8462SApril.Chin@Sun.COM 
303*8462SApril.Chin@Sun.COM 	r = 0;
304*8462SApril.Chin@Sun.COM 	if (len)
305*8462SApril.Chin@Sun.COM 	{
306*8462SApril.Chin@Sun.COM 		while ((cmd->nextstr -= len + 1) < (char*)(cmd->nextarg + cmd->offset))
307*8462SApril.Chin@Sun.COM 		{
308*8462SApril.Chin@Sun.COM 			if (cmd->nextarg == cmd->firstarg)
309*8462SApril.Chin@Sun.COM 			{
310*8462SApril.Chin@Sun.COM 				error(2, "%s: path too long for exec args", file);
311*8462SApril.Chin@Sun.COM 				return -1;
312*8462SApril.Chin@Sun.COM 			}
313*8462SApril.Chin@Sun.COM 			if (i = cmdflush(cmd))
314*8462SApril.Chin@Sun.COM 			{
315*8462SApril.Chin@Sun.COM 				if (r < i)
316*8462SApril.Chin@Sun.COM 					r = i;
317*8462SApril.Chin@Sun.COM 				if (!(cmd->flags & CMD_IGNORE))
318*8462SApril.Chin@Sun.COM 					return r;
319*8462SApril.Chin@Sun.COM 			}
320*8462SApril.Chin@Sun.COM 		}
321*8462SApril.Chin@Sun.COM 		*cmd->nextarg++ = cmd->nextstr;
322*8462SApril.Chin@Sun.COM 		memcpy(cmd->nextstr, file, len);
323*8462SApril.Chin@Sun.COM 		cmd->nextstr[len] = 0;
324*8462SApril.Chin@Sun.COM 		cmd->argcount++;
325*8462SApril.Chin@Sun.COM 		if (cmd->argcount >= cmd->argmax && (i = cmdflush(cmd)) > r)
326*8462SApril.Chin@Sun.COM 			r = i;
327*8462SApril.Chin@Sun.COM 	}
328*8462SApril.Chin@Sun.COM 	return r;
329*8462SApril.Chin@Sun.COM }
330*8462SApril.Chin@Sun.COM 
331*8462SApril.Chin@Sun.COM /*
332*8462SApril.Chin@Sun.COM  * close a cmdarg stream
333*8462SApril.Chin@Sun.COM  */
334*8462SApril.Chin@Sun.COM 
335*8462SApril.Chin@Sun.COM int
336*8462SApril.Chin@Sun.COM cmdclose(Cmdarg_t* cmd)
337*8462SApril.Chin@Sun.COM {
338*8462SApril.Chin@Sun.COM 	int	n;
339*8462SApril.Chin@Sun.COM 
340*8462SApril.Chin@Sun.COM 	if ((cmd->flags & CMD_EXACT) && cmd->argcount < cmd->argmax)
341*8462SApril.Chin@Sun.COM 	{
342*8462SApril.Chin@Sun.COM 		if (!(cmd->flags & CMD_SILENT))
343*8462SApril.Chin@Sun.COM 			error(2, "only %d arguments for last command", cmd->argcount);
344*8462SApril.Chin@Sun.COM 		return -1;
345*8462SApril.Chin@Sun.COM 	}
346*8462SApril.Chin@Sun.COM 	cmd->flags &= ~CMD_MINIMUM;
347*8462SApril.Chin@Sun.COM 	n = cmdflush(cmd);
348*8462SApril.Chin@Sun.COM 	free(cmd);
349*8462SApril.Chin@Sun.COM 	return n;
350*8462SApril.Chin@Sun.COM }
351