xref: /onnv-gate/usr/src/cmd/sh/service.c (revision 0)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  * Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.22.5.1 */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * UNIX shell
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include	"defs.h"
38*0Sstevel@tonic-gate #include	<errno.h>
39*0Sstevel@tonic-gate #include	<fcntl.h>
40*0Sstevel@tonic-gate #include	"sh_policy.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #define	ARGMK	01
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate static unsigned char	*execs();
45*0Sstevel@tonic-gate static int	gsort();
46*0Sstevel@tonic-gate static int	split();
47*0Sstevel@tonic-gate extern const char	*sysmsg[];
48*0Sstevel@tonic-gate extern short topfd;
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * service routines for `execute'
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate initio(iop, save)
56*0Sstevel@tonic-gate 	struct ionod	*iop;
57*0Sstevel@tonic-gate 	int		save;
58*0Sstevel@tonic-gate {
59*0Sstevel@tonic-gate 	register unsigned char	*ion;
60*0Sstevel@tonic-gate 	register int	iof, fd;
61*0Sstevel@tonic-gate 	int		ioufd;
62*0Sstevel@tonic-gate 	short	lastfd;
63*0Sstevel@tonic-gate 	int	newmode;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	lastfd = topfd;
66*0Sstevel@tonic-gate 	while (iop) {
67*0Sstevel@tonic-gate 		iof = iop->iofile;
68*0Sstevel@tonic-gate 		ion = mactrim(iop->ioname);
69*0Sstevel@tonic-gate 		ioufd = iof & IOUFD;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 		if (*ion && (flags&noexec) == 0) {
72*0Sstevel@tonic-gate 			if (save) {
73*0Sstevel@tonic-gate 				fdmap[topfd].org_fd = ioufd;
74*0Sstevel@tonic-gate 				fdmap[topfd++].dup_fd = savefd(ioufd);
75*0Sstevel@tonic-gate 			}
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 			if (iof & IODOC) {
78*0Sstevel@tonic-gate 				struct tempblk tb;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 				subst(chkopen(ion, 0), (fd = tmpfil(&tb)));
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 				/*
83*0Sstevel@tonic-gate 				 * pushed in tmpfil() --
84*0Sstevel@tonic-gate 				 * bug fix for problem with
85*0Sstevel@tonic-gate 				 * in-line scripts
86*0Sstevel@tonic-gate 				 */
87*0Sstevel@tonic-gate 				poptemp();
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 				fd = chkopen(tmpout, 0);
90*0Sstevel@tonic-gate 				unlink((const char *)tmpout);
91*0Sstevel@tonic-gate 			} else if (iof & IOMOV) {
92*0Sstevel@tonic-gate 				if (eq(minus, ion)) {
93*0Sstevel@tonic-gate 					fd = -1;
94*0Sstevel@tonic-gate 					close(ioufd);
95*0Sstevel@tonic-gate 				} else if ((fd = stoi(ion)) >= USERIO) {
96*0Sstevel@tonic-gate 					failed(ion, badfile);
97*0Sstevel@tonic-gate 				}
98*0Sstevel@tonic-gate 				else
99*0Sstevel@tonic-gate 					fd = dup(fd);
100*0Sstevel@tonic-gate 			} else if (((iof & IOPUT) == 0) && ((iof & IORDW) == 0))
101*0Sstevel@tonic-gate 				fd = chkopen(ion, 0);
102*0Sstevel@tonic-gate 			else if (iof & IORDW) /* For <> */ {
103*0Sstevel@tonic-gate 				newmode = O_RDWR|O_CREAT;
104*0Sstevel@tonic-gate 				fd = chkopen(ion, newmode);
105*0Sstevel@tonic-gate 			} else if (flags & rshflg) {
106*0Sstevel@tonic-gate 				failed(ion, restricted);
107*0Sstevel@tonic-gate 			} else if (iof & IOAPP &&
108*0Sstevel@tonic-gate 			    (fd = open((char *)ion, 1)) >= 0) {
109*0Sstevel@tonic-gate 				lseek(fd, (off_t)0, SEEK_END);
110*0Sstevel@tonic-gate 			} else {
111*0Sstevel@tonic-gate 				fd = create(ion);
112*0Sstevel@tonic-gate 			}
113*0Sstevel@tonic-gate 			if (fd >= 0)
114*0Sstevel@tonic-gate 				renamef(fd, ioufd);
115*0Sstevel@tonic-gate 		}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 		iop = iop->ionxt;
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 	return (lastfd);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate unsigned char *
123*0Sstevel@tonic-gate simple(s)
124*0Sstevel@tonic-gate unsigned char	*s;
125*0Sstevel@tonic-gate {
126*0Sstevel@tonic-gate 	unsigned char	*sname;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	sname = s;
129*0Sstevel@tonic-gate 	while (1) {
130*0Sstevel@tonic-gate 		if (any('/', sname))
131*0Sstevel@tonic-gate 			while (*sname++ != '/')
132*0Sstevel@tonic-gate 				;
133*0Sstevel@tonic-gate 		else
134*0Sstevel@tonic-gate 			return (sname);
135*0Sstevel@tonic-gate 	}
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate unsigned char *
139*0Sstevel@tonic-gate getpath(s)
140*0Sstevel@tonic-gate 	unsigned char	*s;
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	register unsigned char	*path, *newpath;
143*0Sstevel@tonic-gate 	register int pathlen;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	if (any('/', s))
146*0Sstevel@tonic-gate 	{
147*0Sstevel@tonic-gate 		if (flags & rshflg)
148*0Sstevel@tonic-gate 			failed(s, restricted);
149*0Sstevel@tonic-gate 		else
150*0Sstevel@tonic-gate 			return ((unsigned char *)nullstr);
151*0Sstevel@tonic-gate 	} else if ((path = pathnod.namval) == 0)
152*0Sstevel@tonic-gate 		return ((unsigned char *)defpath);
153*0Sstevel@tonic-gate 	else {
154*0Sstevel@tonic-gate 		pathlen = length(path)-1;
155*0Sstevel@tonic-gate 		/* Add extra ':' if PATH variable ends in ':' */
156*0Sstevel@tonic-gate 		if (pathlen > 2 && path[pathlen - 1] == ':' &&
157*0Sstevel@tonic-gate 				path[pathlen - 2] != ':') {
158*0Sstevel@tonic-gate 			newpath = locstak();
159*0Sstevel@tonic-gate 			(void) memcpystak(newpath, path, pathlen);
160*0Sstevel@tonic-gate 			newpath[pathlen] = ':';
161*0Sstevel@tonic-gate 			endstak(newpath + pathlen + 1);
162*0Sstevel@tonic-gate 			return (newpath);
163*0Sstevel@tonic-gate 		} else
164*0Sstevel@tonic-gate 			return (cpystak(path));
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate pathopen(path, name)
169*0Sstevel@tonic-gate register unsigned char *path, *name;
170*0Sstevel@tonic-gate {
171*0Sstevel@tonic-gate 	register int	f;
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	do
174*0Sstevel@tonic-gate 	{
175*0Sstevel@tonic-gate 		path = catpath(path, name);
176*0Sstevel@tonic-gate 	} while ((f = open((char *)curstak(), 0)) < 0 && path);
177*0Sstevel@tonic-gate 	return (f);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate unsigned char *
181*0Sstevel@tonic-gate catpath(path, name)
182*0Sstevel@tonic-gate register unsigned char	*path;
183*0Sstevel@tonic-gate unsigned char	*name;
184*0Sstevel@tonic-gate {
185*0Sstevel@tonic-gate 	/*
186*0Sstevel@tonic-gate 	 * leaves result on top of stack
187*0Sstevel@tonic-gate 	 */
188*0Sstevel@tonic-gate 	register unsigned char	*scanp = path;
189*0Sstevel@tonic-gate 	register unsigned char	*argp = locstak();
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	while (*scanp && *scanp != COLON)
192*0Sstevel@tonic-gate 	{
193*0Sstevel@tonic-gate 		if (argp >= brkend)
194*0Sstevel@tonic-gate 			growstak(argp);
195*0Sstevel@tonic-gate 		*argp++ = *scanp++;
196*0Sstevel@tonic-gate 	}
197*0Sstevel@tonic-gate 	if (scanp != path)
198*0Sstevel@tonic-gate 	{
199*0Sstevel@tonic-gate 		if (argp >= brkend)
200*0Sstevel@tonic-gate 			growstak(argp);
201*0Sstevel@tonic-gate 		*argp++ = '/';
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	if (*scanp == COLON)
204*0Sstevel@tonic-gate 		scanp++;
205*0Sstevel@tonic-gate 	path = (*scanp ? scanp : 0);
206*0Sstevel@tonic-gate 	scanp = name;
207*0Sstevel@tonic-gate 	do
208*0Sstevel@tonic-gate 	{
209*0Sstevel@tonic-gate 		if (argp >= brkend)
210*0Sstevel@tonic-gate 			growstak(argp);
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 	while (*argp++ = *scanp++);
213*0Sstevel@tonic-gate 	return (path);
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate unsigned char *
217*0Sstevel@tonic-gate nextpath(path)
218*0Sstevel@tonic-gate 	register unsigned char	*path;
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	register unsigned char	*scanp = path;
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	while (*scanp && *scanp != COLON)
223*0Sstevel@tonic-gate 		scanp++;
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	if (*scanp == COLON)
226*0Sstevel@tonic-gate 		scanp++;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	return (*scanp ? scanp : 0);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate static unsigned char	*xecmsg;
232*0Sstevel@tonic-gate static unsigned char	**xecenv;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate int
235*0Sstevel@tonic-gate execa(at, pos)
236*0Sstevel@tonic-gate     unsigned char *at[];
237*0Sstevel@tonic-gate     short pos;
238*0Sstevel@tonic-gate {
239*0Sstevel@tonic-gate 	register unsigned char	*path;
240*0Sstevel@tonic-gate 	register unsigned char	**t = at;
241*0Sstevel@tonic-gate 	int		cnt;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	if ((flags & noexec) == 0)
244*0Sstevel@tonic-gate 	{
245*0Sstevel@tonic-gate 		xecmsg = (unsigned char *)notfound;
246*0Sstevel@tonic-gate 		path = getpath(*t);
247*0Sstevel@tonic-gate 		xecenv = local_setenv();
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 		if (pos > 0)
250*0Sstevel@tonic-gate 		{
251*0Sstevel@tonic-gate 			cnt = 1;
252*0Sstevel@tonic-gate 			while (cnt != pos)
253*0Sstevel@tonic-gate 			{
254*0Sstevel@tonic-gate 				++cnt;
255*0Sstevel@tonic-gate 				path = nextpath(path);
256*0Sstevel@tonic-gate 			}
257*0Sstevel@tonic-gate 			execs(path, t);
258*0Sstevel@tonic-gate 			path = getpath(*t);
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 		while (path = execs(path, t))
261*0Sstevel@tonic-gate 			;
262*0Sstevel@tonic-gate 		failed(*t, xecmsg);
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate static unsigned char *
267*0Sstevel@tonic-gate execs(ap, t)
268*0Sstevel@tonic-gate unsigned char	*ap;
269*0Sstevel@tonic-gate register unsigned char	*t[];
270*0Sstevel@tonic-gate {
271*0Sstevel@tonic-gate 	register int		pfstatus = NOATTRS;
272*0Sstevel@tonic-gate 	register unsigned char	*p, *prefix;
273*0Sstevel@tonic-gate 	unsigned char		*savptr;
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	prefix = catpath(ap, t[0]);
276*0Sstevel@tonic-gate 	trim(p = curstak());
277*0Sstevel@tonic-gate 	sigchk();
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (flags & pfshflg) {
280*0Sstevel@tonic-gate 		/*
281*0Sstevel@tonic-gate 		 * Need to save the stack information, or the
282*0Sstevel@tonic-gate 		 * first memory allocation in secpolicy_profile_lookup()
283*0Sstevel@tonic-gate 		 * will clobber it.
284*0Sstevel@tonic-gate 		 */
285*0Sstevel@tonic-gate 		savptr = endstak(p + strlen((const char *)p) + 1);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 		pfstatus = secpolicy_pfexec((const char *)p,
288*0Sstevel@tonic-gate 		    (char **)t, (const char **)xecenv);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 		if (pfstatus != NOATTRS) {
291*0Sstevel@tonic-gate 			errno = pfstatus;
292*0Sstevel@tonic-gate 		}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 		tdystak(savptr);
295*0Sstevel@tonic-gate 	}
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	if (pfstatus == NOATTRS) {
298*0Sstevel@tonic-gate 		execve((const char *)p, (char *const *)&t[0],
299*0Sstevel@tonic-gate 		    (char *const *)xecenv);
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	switch (errno)
303*0Sstevel@tonic-gate 	{
304*0Sstevel@tonic-gate 	case ENOEXEC:		/* could be a shell script */
305*0Sstevel@tonic-gate 		funcnt = 0;
306*0Sstevel@tonic-gate 		flags = 0;
307*0Sstevel@tonic-gate 		*flagadr = 0;
308*0Sstevel@tonic-gate 		comdiv = 0;
309*0Sstevel@tonic-gate 		ioset = 0;
310*0Sstevel@tonic-gate 		clearup();	/* remove open files and for loop junk */
311*0Sstevel@tonic-gate 		if (input)
312*0Sstevel@tonic-gate 			close(input);
313*0Sstevel@tonic-gate 		input = chkopen(p, 0);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate #ifdef ACCT
316*0Sstevel@tonic-gate 		preacct(p);	/* reset accounting */
317*0Sstevel@tonic-gate #endif
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 		/*
320*0Sstevel@tonic-gate 		 * set up new args
321*0Sstevel@tonic-gate 		 */
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 		setargs(t);
324*0Sstevel@tonic-gate 		longjmp(subshell, 1);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	case ENOMEM:
327*0Sstevel@tonic-gate 		failed(p, toobig);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	case E2BIG:
330*0Sstevel@tonic-gate 		failed(p, arglist);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	case ETXTBSY:
333*0Sstevel@tonic-gate 		failed(p, txtbsy);
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	case ELIBACC:
336*0Sstevel@tonic-gate 		failed(p, libacc);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	case ELIBBAD:
339*0Sstevel@tonic-gate 		failed(p, libbad);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	case ELIBSCN:
342*0Sstevel@tonic-gate 		failed(p, libscn);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	case ELIBMAX:
345*0Sstevel@tonic-gate 		failed(p, libmax);
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	default:
348*0Sstevel@tonic-gate 		xecmsg = (unsigned char *)badexec;
349*0Sstevel@tonic-gate 	case ENOENT:
350*0Sstevel@tonic-gate 		return (prefix);
351*0Sstevel@tonic-gate 	}
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate BOOL		nosubst;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate trim(at)
357*0Sstevel@tonic-gate unsigned char	*at;
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	register unsigned char	*last;
360*0Sstevel@tonic-gate 	register unsigned char 	*current;
361*0Sstevel@tonic-gate 	register unsigned char	c;
362*0Sstevel@tonic-gate 	int	len;
363*0Sstevel@tonic-gate 	wchar_t	wc;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	nosubst = 0;
366*0Sstevel@tonic-gate 	if (current = at)
367*0Sstevel@tonic-gate 	{
368*0Sstevel@tonic-gate 		last = at;
369*0Sstevel@tonic-gate 		while (c = *current) {
370*0Sstevel@tonic-gate 			if ((len = mbtowc(&wc, (char *)current,
371*0Sstevel@tonic-gate 					MB_LEN_MAX)) <= 0) {
372*0Sstevel@tonic-gate 				*last++ = c;
373*0Sstevel@tonic-gate 				current++;
374*0Sstevel@tonic-gate 				continue;
375*0Sstevel@tonic-gate 			}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 			if (wc != '\\') {
378*0Sstevel@tonic-gate 				memcpy(last, current, len);
379*0Sstevel@tonic-gate 				last += len;
380*0Sstevel@tonic-gate 				current += len;
381*0Sstevel@tonic-gate 				continue;
382*0Sstevel@tonic-gate 			}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 			/* remove \ and quoted nulls */
385*0Sstevel@tonic-gate 			nosubst = 1;
386*0Sstevel@tonic-gate 			current++;
387*0Sstevel@tonic-gate 			if (c = *current) {
388*0Sstevel@tonic-gate 				if ((len = mbtowc(&wc, (char *)current,
389*0Sstevel@tonic-gate 						MB_LEN_MAX)) <= 0) {
390*0Sstevel@tonic-gate 					*last++ = c;
391*0Sstevel@tonic-gate 					current++;
392*0Sstevel@tonic-gate 					continue;
393*0Sstevel@tonic-gate 				}
394*0Sstevel@tonic-gate 				memcpy(last, current, len);
395*0Sstevel@tonic-gate 				last += len;
396*0Sstevel@tonic-gate 				current += len;
397*0Sstevel@tonic-gate 			} else
398*0Sstevel@tonic-gate 				current++;
399*0Sstevel@tonic-gate 		}
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 		*last = 0;
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate }
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate /* Same as trim, but only removes backlashes before slashes */
406*0Sstevel@tonic-gate trims(at)
407*0Sstevel@tonic-gate unsigned char	*at;
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	register unsigned char	*last;
410*0Sstevel@tonic-gate 	register unsigned char 	*current;
411*0Sstevel@tonic-gate 	register unsigned char	c;
412*0Sstevel@tonic-gate 	int	len;
413*0Sstevel@tonic-gate 	wchar_t	wc;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	if (current = at)
416*0Sstevel@tonic-gate 	{
417*0Sstevel@tonic-gate 		last = at;
418*0Sstevel@tonic-gate 		while (c = *current) {
419*0Sstevel@tonic-gate 			if ((len = mbtowc(&wc, (char *)current,
420*0Sstevel@tonic-gate 					MB_LEN_MAX)) <= 0) {
421*0Sstevel@tonic-gate 				*last++ = c;
422*0Sstevel@tonic-gate 				current++;
423*0Sstevel@tonic-gate 				continue;
424*0Sstevel@tonic-gate 			}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 			if (wc != '\\') {
427*0Sstevel@tonic-gate 				memcpy(last, current, len);
428*0Sstevel@tonic-gate 				last += len; current += len;
429*0Sstevel@tonic-gate 				continue;
430*0Sstevel@tonic-gate 			}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 			/* remove \ and quoted nulls */
433*0Sstevel@tonic-gate 			current++;
434*0Sstevel@tonic-gate 			if (!(c = *current)) {
435*0Sstevel@tonic-gate 				current++;
436*0Sstevel@tonic-gate 				continue;
437*0Sstevel@tonic-gate 			}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 			if (c == '/') {
440*0Sstevel@tonic-gate 				*last++ = c;
441*0Sstevel@tonic-gate 				current++;
442*0Sstevel@tonic-gate 				continue;
443*0Sstevel@tonic-gate 			}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 			*last++ = '\\';
446*0Sstevel@tonic-gate 			if ((len = mbtowc(&wc, (char *)current,
447*0Sstevel@tonic-gate 					MB_LEN_MAX)) <= 0) {
448*0Sstevel@tonic-gate 				*last++ = c;
449*0Sstevel@tonic-gate 				current++;
450*0Sstevel@tonic-gate 				continue;
451*0Sstevel@tonic-gate 			}
452*0Sstevel@tonic-gate 			memcpy(last, current, len);
453*0Sstevel@tonic-gate 			last += len; current += len;
454*0Sstevel@tonic-gate 		}
455*0Sstevel@tonic-gate 		*last = 0;
456*0Sstevel@tonic-gate 	}
457*0Sstevel@tonic-gate }
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate unsigned char *
460*0Sstevel@tonic-gate mactrim(s)
461*0Sstevel@tonic-gate unsigned char	*s;
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	register unsigned char	*t = macro(s);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	trim(t);
466*0Sstevel@tonic-gate 	return (t);
467*0Sstevel@tonic-gate }
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate unsigned char **
470*0Sstevel@tonic-gate scan(argn)
471*0Sstevel@tonic-gate int	argn;
472*0Sstevel@tonic-gate {
473*0Sstevel@tonic-gate 	register struct argnod *argp =
474*0Sstevel@tonic-gate 			(struct argnod *)(Rcheat(gchain) & ~ARGMK);
475*0Sstevel@tonic-gate 	register unsigned char **comargn, **comargm;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	comargn = (unsigned char **)getstak(BYTESPERWORD * argn + BYTESPERWORD);
478*0Sstevel@tonic-gate 	comargm = comargn += argn;
479*0Sstevel@tonic-gate 	*comargn = ENDARGS;
480*0Sstevel@tonic-gate 	while (argp)
481*0Sstevel@tonic-gate 	{
482*0Sstevel@tonic-gate 		*--comargn = argp->argval;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 		trim(*comargn);
485*0Sstevel@tonic-gate 		argp = argp->argnxt;
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 		if (argp == 0 || Rcheat(argp) & ARGMK)
488*0Sstevel@tonic-gate 		{
489*0Sstevel@tonic-gate 			gsort(comargn, comargm);
490*0Sstevel@tonic-gate 			comargm = comargn;
491*0Sstevel@tonic-gate 		}
492*0Sstevel@tonic-gate 		argp = (struct argnod *)(Rcheat(argp) & ~ARGMK);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 	return (comargn);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate static int
498*0Sstevel@tonic-gate gsort(from, to)
499*0Sstevel@tonic-gate unsigned char	*from[], *to[];
500*0Sstevel@tonic-gate {
501*0Sstevel@tonic-gate 	int	k, m, n;
502*0Sstevel@tonic-gate 	register int	i, j;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	if ((n = to - from) <= 1)
505*0Sstevel@tonic-gate 		return;
506*0Sstevel@tonic-gate 	for (j = 1; j <= n; j *= 2)
507*0Sstevel@tonic-gate 		;
508*0Sstevel@tonic-gate 	for (m = 2 * j - 1; m /= 2; )
509*0Sstevel@tonic-gate 	{
510*0Sstevel@tonic-gate 		k = n - m;
511*0Sstevel@tonic-gate 		for (j = 0; j < k; j++)
512*0Sstevel@tonic-gate 		{
513*0Sstevel@tonic-gate 			for (i = j; i >= 0; i -= m)
514*0Sstevel@tonic-gate 			{
515*0Sstevel@tonic-gate 				register unsigned char **fromi;
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 				fromi = &from[i];
518*0Sstevel@tonic-gate 				if (cf(fromi[m], fromi[0]) > 0)
519*0Sstevel@tonic-gate 				{
520*0Sstevel@tonic-gate 					break;
521*0Sstevel@tonic-gate 				}
522*0Sstevel@tonic-gate 				else
523*0Sstevel@tonic-gate 				{
524*0Sstevel@tonic-gate 					unsigned char *s;
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 					s = fromi[m];
527*0Sstevel@tonic-gate 					fromi[m] = fromi[0];
528*0Sstevel@tonic-gate 					fromi[0] = s;
529*0Sstevel@tonic-gate 				}
530*0Sstevel@tonic-gate 			}
531*0Sstevel@tonic-gate 		}
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate /*
536*0Sstevel@tonic-gate  * Argument list generation
537*0Sstevel@tonic-gate  */
538*0Sstevel@tonic-gate getarg(ac)
539*0Sstevel@tonic-gate struct comnod	*ac;
540*0Sstevel@tonic-gate {
541*0Sstevel@tonic-gate 	register struct argnod	*argp;
542*0Sstevel@tonic-gate 	register int		count = 0;
543*0Sstevel@tonic-gate 	register struct comnod	*c;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	if (c = ac)
546*0Sstevel@tonic-gate 	{
547*0Sstevel@tonic-gate 		argp = c->comarg;
548*0Sstevel@tonic-gate 		while (argp)
549*0Sstevel@tonic-gate 		{
550*0Sstevel@tonic-gate 			count += split(macro(argp->argval), 1);
551*0Sstevel@tonic-gate 			argp = argp->argnxt;
552*0Sstevel@tonic-gate 		}
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 	return (count);
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate static int
558*0Sstevel@tonic-gate split(s)		/* blank interpretation routine */
559*0Sstevel@tonic-gate unsigned char	*s;
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	register unsigned char	*argp;
562*0Sstevel@tonic-gate 	register int	c;
563*0Sstevel@tonic-gate 	int		count = 0;
564*0Sstevel@tonic-gate 	for (;;)
565*0Sstevel@tonic-gate 	{
566*0Sstevel@tonic-gate 		register int length;
567*0Sstevel@tonic-gate 		sigchk();
568*0Sstevel@tonic-gate 		argp = locstak() + BYTESPERWORD;
569*0Sstevel@tonic-gate 		while (c = *s) {
570*0Sstevel@tonic-gate 			wchar_t wc;
571*0Sstevel@tonic-gate 			if ((length = mbtowc(&wc, (char *)s,
572*0Sstevel@tonic-gate 					MB_LEN_MAX)) <= 0) {
573*0Sstevel@tonic-gate 				wc = (unsigned char)*s;
574*0Sstevel@tonic-gate 				length = 1;
575*0Sstevel@tonic-gate 			}
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 			if (c == '\\') { /* skip over quoted characters */
578*0Sstevel@tonic-gate 				if (argp >= brkend)
579*0Sstevel@tonic-gate 					growstak(argp);
580*0Sstevel@tonic-gate 				*argp++ = c;
581*0Sstevel@tonic-gate 				s++;
582*0Sstevel@tonic-gate 				/* get rest of multibyte character */
583*0Sstevel@tonic-gate 				if ((length = mbtowc(&wc, (char *)s,
584*0Sstevel@tonic-gate 						MB_LEN_MAX)) <= 0) {
585*0Sstevel@tonic-gate 					wc = (unsigned char)*s;
586*0Sstevel@tonic-gate 					length = 1;
587*0Sstevel@tonic-gate 				}
588*0Sstevel@tonic-gate 				if (argp >= brkend)
589*0Sstevel@tonic-gate 					growstak(argp);
590*0Sstevel@tonic-gate 				*argp++ = *s++;
591*0Sstevel@tonic-gate 				while (--length > 0) {
592*0Sstevel@tonic-gate 					if (argp >= brkend)
593*0Sstevel@tonic-gate 						growstak(argp);
594*0Sstevel@tonic-gate 					*argp++ = *s++;
595*0Sstevel@tonic-gate 				}
596*0Sstevel@tonic-gate 				continue;
597*0Sstevel@tonic-gate 			}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 			if (anys(s, ifsnod.namval)) {
600*0Sstevel@tonic-gate 				/* skip to next character position */
601*0Sstevel@tonic-gate 				s += length;
602*0Sstevel@tonic-gate 				break;
603*0Sstevel@tonic-gate 			}
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 			if (argp >= brkend)
606*0Sstevel@tonic-gate 				growstak(argp);
607*0Sstevel@tonic-gate 			*argp++ = c;
608*0Sstevel@tonic-gate 			s++;
609*0Sstevel@tonic-gate 			while (--length > 0) {
610*0Sstevel@tonic-gate 				if (argp >= brkend)
611*0Sstevel@tonic-gate 					growstak(argp);
612*0Sstevel@tonic-gate 				*argp++ = *s++;
613*0Sstevel@tonic-gate 			}
614*0Sstevel@tonic-gate 		}
615*0Sstevel@tonic-gate 		if (argp == staktop + BYTESPERWORD)
616*0Sstevel@tonic-gate 		{
617*0Sstevel@tonic-gate 			if (c)
618*0Sstevel@tonic-gate 			{
619*0Sstevel@tonic-gate 				continue;
620*0Sstevel@tonic-gate 			}
621*0Sstevel@tonic-gate 			else
622*0Sstevel@tonic-gate 			{
623*0Sstevel@tonic-gate 				return (count);
624*0Sstevel@tonic-gate 			}
625*0Sstevel@tonic-gate 		}
626*0Sstevel@tonic-gate 		/*
627*0Sstevel@tonic-gate 		 * file name generation
628*0Sstevel@tonic-gate 		 */
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 		argp = endstak(argp);
631*0Sstevel@tonic-gate 		trims(((struct argnod *)argp)->argval);
632*0Sstevel@tonic-gate 		if ((flags & nofngflg) == 0 &&
633*0Sstevel@tonic-gate 			(c = expand(((struct argnod *)argp)->argval, 0)))
634*0Sstevel@tonic-gate 			count += c;
635*0Sstevel@tonic-gate 		else
636*0Sstevel@tonic-gate 		{
637*0Sstevel@tonic-gate 			makearg(argp);
638*0Sstevel@tonic-gate 			count++;
639*0Sstevel@tonic-gate 		}
640*0Sstevel@tonic-gate 		gchain = (struct argnod *)((int)gchain | ARGMK);
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate #ifdef ACCT
645*0Sstevel@tonic-gate #include	<sys/types.h>
646*0Sstevel@tonic-gate #include	<sys/acct.h>
647*0Sstevel@tonic-gate #include 	<sys/times.h>
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate struct acct sabuf;
650*0Sstevel@tonic-gate struct tms buffer;
651*0Sstevel@tonic-gate static clock_t before;
652*0Sstevel@tonic-gate static int shaccton;	/* 0 implies do not write record on exit */
653*0Sstevel@tonic-gate 			/* 1 implies write acct record on exit */
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate /*
657*0Sstevel@tonic-gate  *	suspend accounting until turned on by preacct()
658*0Sstevel@tonic-gate  */
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate suspacct()
661*0Sstevel@tonic-gate {
662*0Sstevel@tonic-gate 	shaccton = 0;
663*0Sstevel@tonic-gate }
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate preacct(cmdadr)
666*0Sstevel@tonic-gate 	unsigned char *cmdadr;
667*0Sstevel@tonic-gate {
668*0Sstevel@tonic-gate 	unsigned char *simple();
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	if (acctnod.namval && *acctnod.namval)
671*0Sstevel@tonic-gate 	{
672*0Sstevel@tonic-gate 		sabuf.ac_btime = time((time_t *)0);
673*0Sstevel@tonic-gate 		before = times(&buffer);
674*0Sstevel@tonic-gate 		sabuf.ac_uid = getuid();
675*0Sstevel@tonic-gate 		sabuf.ac_gid = getgid();
676*0Sstevel@tonic-gate 		movstrn(simple(cmdadr), sabuf.ac_comm, sizeof (sabuf.ac_comm));
677*0Sstevel@tonic-gate 		shaccton = 1;
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate }
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate doacct()
683*0Sstevel@tonic-gate {
684*0Sstevel@tonic-gate 	int fd;
685*0Sstevel@tonic-gate 	clock_t after;
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	if (shaccton) {
688*0Sstevel@tonic-gate 		after = times(&buffer);
689*0Sstevel@tonic-gate 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
690*0Sstevel@tonic-gate 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
691*0Sstevel@tonic-gate 		sabuf.ac_etime = compress(after - before);
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		if ((fd = open((char *)acctnod.namval,
694*0Sstevel@tonic-gate 				O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) {
695*0Sstevel@tonic-gate 			write(fd, &sabuf, sizeof (sabuf));
696*0Sstevel@tonic-gate 			close(fd);
697*0Sstevel@tonic-gate 		}
698*0Sstevel@tonic-gate 	}
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate /*
702*0Sstevel@tonic-gate  *	Produce a pseudo-floating point representation
703*0Sstevel@tonic-gate  *	with 3 bits base-8 exponent, 13 bits fraction
704*0Sstevel@tonic-gate  */
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate compress(t)
707*0Sstevel@tonic-gate 	register clock_t t;
708*0Sstevel@tonic-gate {
709*0Sstevel@tonic-gate 	register exp = 0;
710*0Sstevel@tonic-gate 	register rund = 0;
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	while (t >= 8192)
713*0Sstevel@tonic-gate 	{
714*0Sstevel@tonic-gate 		exp++;
715*0Sstevel@tonic-gate 		rund = t & 04;
716*0Sstevel@tonic-gate 		t >>= 3;
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	if (rund)
720*0Sstevel@tonic-gate 	{
721*0Sstevel@tonic-gate 		t++;
722*0Sstevel@tonic-gate 		if (t >= 8192)
723*0Sstevel@tonic-gate 		{
724*0Sstevel@tonic-gate 			t >>= 3;
725*0Sstevel@tonic-gate 			exp++;
726*0Sstevel@tonic-gate 		}
727*0Sstevel@tonic-gate 	}
728*0Sstevel@tonic-gate 	return ((exp << 13) + t);
729*0Sstevel@tonic-gate }
730*0Sstevel@tonic-gate #endif
731