1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * UNIX shell
23 *
24 * S. R. Bourne
25 * Rewritten By David Korn
26 * AT&T Labs
27 *
28 */
29
30#include	<ast.h>
31#include	<sfio.h>
32#include	<stak.h>
33#include	<ls.h>
34#include	<fcin.h>
35#include	"defs.h"
36#include	"variables.h"
37#include	"path.h"
38#include	"io.h"
39#include	"jobs.h"
40#include	"shlex.h"
41#include	"shnodes.h"
42#include	"history.h"
43#include	"timeout.h"
44#include	"FEATURE/time"
45#include	"FEATURE/pstat"
46#include	"FEATURE/execargs"
47#include	"FEATURE/externs"
48#ifdef	_hdr_nc
49#   include	<nc.h>
50#endif	/* _hdr_nc */
51
52#define CMD_LENGTH	64
53
54/* These routines are referenced by this module */
55static void	exfile(Shell_t*, Sfio_t*,int);
56static void	chkmail(Shell_t *shp, char*);
57#if defined(_lib_fork) && !defined(_NEXT_SOURCE)
58    static void	fixargs(char**,int);
59#else
60#   define fixargs(a,b)
61#endif
62
63#ifndef environ
64    extern char	**environ;
65#endif
66
67static struct stat lastmail;
68static time_t	mailtime;
69static char	beenhere = 0;
70
71#ifdef _lib_sigvec
72    void clearsigmask(register int sig)
73    {
74	struct sigvec vec;
75	if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
76	{
77		vec.sv_mask = 0;
78		sigvec(sig,&vec,NIL(struct sigvec*));
79	}
80    }
81#endif /* _lib_sigvec */
82
83#ifdef _lib_fts_notify
84#   include	<fts.h>
85    /* check for interrupts during tree walks */
86    static int fts_sigcheck(FTS* fp, FTSENT* ep, void* context)
87    {
88	Shell_t *shp = (Shell_t*)context;
89	NOT_USED(fp);
90	NOT_USED(ep);
91	if(shp->trapnote&SH_SIGSET)
92	{
93		errno = EINTR;
94		return(-1);
95	}
96	return(0);
97    }
98#endif /* _lib_fts_notify */
99
100#ifdef PATH_BFPATH
101#define PATHCOMP	NIL(Pathcomp_t*)
102#else
103#define PATHCOMP	""
104#endif
105
106/*
107 * search for file and exfile() it if it exists
108 * 1 returned if file found, 0 otherwise
109 */
110
111int sh_source(Shell_t *shp, Sfio_t *iop, const char *file)
112{
113	char*	oid;
114	char*	nid;
115	int	fd;
116
117	if (!file || !*file || (fd = path_open(file, PATHCOMP)) < 0)
118	{
119		REGRESS(source, "sh_source", ("%s:ENOENT", file));
120		return 0;
121	}
122	oid = error_info.id;
123	nid = error_info.id = strdup(file);
124	shp->st.filename = path_fullname(stakptr(PATH_OFFSET));
125	REGRESS(source, "sh_source", ("%s", file));
126	exfile(shp, iop, fd);
127	error_info.id = oid;
128	free(nid);
129	return 1;
130}
131
132#ifdef S_ISSOCK
133#define REMOTE(m)	(S_ISSOCK(m)||!(m))
134#else
135#define REMOTE(m)	!(m)
136#endif
137
138int sh_main(int ac, char *av[], Shinit_f userinit)
139{
140	register char	*name;
141	register int	fdin;
142	register Sfio_t  *iop;
143	register Shell_t *shp;
144	struct stat	statb;
145	int i, rshflag;		/* set for restricted shell */
146	char *command;
147#ifdef _lib_sigvec
148	/* This is to clear mask that may be left on by rlogin */
149	clearsigmask(SIGALRM);
150	clearsigmask(SIGHUP);
151	clearsigmask(SIGCHLD);
152#endif /* _lib_sigvec */
153#ifdef	_hdr_nc
154	_NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
155#endif	/* _hdr_nc */
156	fixargs(av,0);
157	shp = sh_init(ac,av,userinit);
158	time(&mailtime);
159	if(rshflag=sh_isoption(SH_RESTRICTED))
160		sh_offoption(SH_RESTRICTED);
161#ifdef _lib_fts_notify
162	fts_notify(fts_sigcheck,(void*)shp);
163#endif /* _lib_fts_notify */
164	if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
165	{
166		/* begin script execution here */
167		sh_reinit((char**)0);
168	}
169	shp->fn_depth = shp->dot_depth = 0;
170	command = error_info.id;
171	/* set pidname '$$' */
172	shp->pid = getpid();
173	srand(shp->pid&0x7fff);
174	shp->ppid = getppid();
175	if(nv_isnull(PS4NOD))
176		nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
177	path_pwd(1);
178	iop = (Sfio_t*)0;
179#if SHOPT_BRACEPAT
180	sh_onoption(SH_BRACEEXPAND);
181#endif
182	if((beenhere++)==0)
183	{
184		sh_onstate(SH_PROFILE);
185		((Lex_t*)shp->lex_context)->nonstandard = 0;
186		if(shp->ppid==1)
187			shp->login_sh++;
188		if(shp->login_sh >= 2)
189			sh_onoption(SH_LOGIN_SHELL);
190		/* decide whether shell is interactive */
191		if(!sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) &&
192		   sh_isoption(SH_SFLAG) && tty_check(0) && tty_check(ERRIO))
193			sh_onoption(SH_INTERACTIVE);
194		if(sh_isoption(SH_INTERACTIVE))
195		{
196			sh_onoption(SH_BGNICE);
197			sh_onoption(SH_RC);
198		}
199		if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)
200#if SHOPT_REMOTE
201		   || !fstat(0, &statb) && REMOTE(statb.st_mode)
202#endif
203		  ))
204			sh_onoption(SH_RC);
205		for(i=0; i<elementsof(shp->offoptions.v); i++)
206			shp->options.v[i] &= ~shp->offoptions.v[i];
207		if(sh_isoption(SH_INTERACTIVE))
208		{
209#ifdef SIGXCPU
210			signal(SIGXCPU,SIG_DFL);
211#endif /* SIGXCPU */
212#ifdef SIGXFSZ
213			signal(SIGXFSZ,SIG_DFL);
214#endif /* SIGXFSZ */
215			sh_onoption(SH_MONITOR);
216		}
217		job_init(shp,sh_isoption(SH_LOGIN_SHELL));
218		if(sh_isoption(SH_LOGIN_SHELL))
219		{
220			/*	system profile	*/
221			sh_source(shp, iop, e_sysprofile);
222			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED))
223			{
224				char **files = shp->login_files;
225				while ((name = *files++) && !sh_source(shp, iop, sh_mactry(shp,name)));
226			}
227		}
228		/* make sure PWD is set up correctly */
229		path_pwd(1);
230		if(!sh_isoption(SH_NOEXEC))
231		{
232			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC))
233			{
234#if SHOPT_BASH
235				if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX))
236				{
237#if SHOPT_SYSRC
238					sh_source(shp, iop, e_bash_sysrc);
239#endif
240					sh_source(shp, iop, shp->rcfile ? shp->rcfile : sh_mactry(shp,(char*)e_bash_rc));
241				}
242				else
243#endif
244				{
245					if(name = sh_mactry(shp,nv_getval(ENVNOD)))
246						name = *name ? strdup(name) : (char*)0;
247#if SHOPT_SYSRC
248					if(!strmatch(name, "?(.)/./*"))
249						sh_source(shp, iop, e_sysrc);
250#endif
251					if(name)
252					{
253						sh_source(shp, iop, name);
254						free(name);
255					}
256				}
257			}
258			else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED))
259				sh_source(shp, iop, e_suidprofile);
260		}
261		shp->st.cmdname = error_info.id = command;
262		sh_offstate(SH_PROFILE);
263		if(rshflag)
264			sh_onoption(SH_RESTRICTED);
265		/* open input file if specified */
266		if(shp->comdiv)
267		{
268		shell_c:
269			iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
270		}
271		else
272		{
273			name = error_info.id;
274			error_info.id = shp->shname;
275			if(sh_isoption(SH_SFLAG))
276				fdin = 0;
277			else
278			{
279				char *sp;
280				/* open stream should have been passed into shell */
281				if(strmatch(name,e_devfdNN))
282				{
283#if !_WINIX
284					char *cp;
285					int type;
286#endif
287					fdin = (int)strtol(name+8, (char**)0, 10);
288					if(fstat(fdin,&statb)<0)
289						errormsg(SH_DICT,ERROR_system(1),e_open,name);
290#if !_WINIX
291					/*
292					 * try to undo effect of solaris 2.5+
293					 * change for argv for setuid scripts
294					 */
295					if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
296					{
297						av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
298						/*  exec to change $0 for ps */
299						execv(pathshell(),av);
300						/* exec fails */
301						shp->st.dolv[0] = av[0];
302						fixargs(shp->st.dolv,1);
303					}
304#endif
305					name = av[0];
306					sh_offoption(SH_VERBOSE);
307					sh_offoption(SH_XTRACE);
308				}
309				else
310				{
311					int isdir = 0;
312					if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
313					{
314						close(fdin);
315						isdir = 1;
316						fdin = -1;
317					}
318					else
319						shp->st.filename = path_fullname(name);
320					sp = 0;
321					if(fdin < 0 && !strchr(name,'/'))
322					{
323#ifdef PATH_BFPATH
324						if(path_absolute(name,NIL(Pathcomp_t*)))
325							sp = stakptr(PATH_OFFSET);
326#else
327							sp = path_absolute(name,NIL(char*));
328#endif
329						if(sp)
330						{
331							if((fdin=sh_open(sp,O_RDONLY,0))>=0)
332								shp->st.filename = path_fullname(sp);
333						}
334					}
335					if(fdin<0)
336					{
337						if(isdir)
338							errno = EISDIR;
339						 error_info.id = av[0];
340						if(sp || errno!=ENOENT)
341							errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name);
342						/* try sh -c 'name "$@"' */
343						sh_onoption(SH_CFLAG);
344						shp->comdiv = (char*)malloc(strlen(name)+7);
345						name = strcopy(shp->comdiv,name);
346						if(shp->st.dolc)
347							strcopy(name," \"$@\"");
348						goto shell_c;
349					}
350					if(fdin==0)
351						fdin = sh_iomovefd(fdin);
352				}
353				shp->readscript = shp->shname;
354			}
355			error_info.id = name;
356			shp->comdiv--;
357#if SHOPT_ACCT
358			sh_accinit();
359			if(fdin != 0)
360				sh_accbegin(error_info.id);
361#endif	/* SHOPT_ACCT */
362		}
363	}
364	else
365	{
366		fdin = shp->infd;
367		fixargs(shp->st.dolv,1);
368	}
369	if(sh_isoption(SH_INTERACTIVE))
370		sh_onstate(SH_INTERACTIVE);
371	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
372	exfile(shp,iop,fdin);
373	sh_done(shp,0);
374	/* NOTREACHED */
375	return(0);
376}
377
378/*
379 * iop is not null when the input is a string
380 * fdin is the input file descriptor
381 */
382
383static void	exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
384{
385	time_t curtime;
386	Shnode_t *t;
387	int maxtry=IOMAXTRY, tdone=0, execflags;
388	int states,jmpval;
389	struct checkpt buff;
390	sh_pushcontext(&buff,SH_JMPERREXIT);
391	/* open input stream */
392	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
393	if(!iop)
394	{
395		if(fno > 0)
396		{
397			int r;
398			if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
399			{
400				shp->fdstatus[r] = shp->fdstatus[fno];
401				sh_close(fno);
402				fno = r;
403			}
404			fcntl(fno,F_SETFD,FD_CLOEXEC);
405			shp->fdstatus[fno] |= IOCLEX;
406			iop = sh_iostream((void*)shp,fno);
407		}
408		else
409			iop = sfstdin;
410	}
411	else
412		fno = -1;
413	shp->infd = fno;
414	if(sh_isstate(SH_INTERACTIVE))
415	{
416		if(nv_isnull(PS1NOD))
417			nv_putval(PS1NOD,(shp->euserid?e_stdprompt:e_supprompt),NV_RDONLY);
418		sh_sigdone();
419		if(sh_histinit((void*)shp))
420			sh_onoption(SH_HISTORY);
421	}
422	else
423	{
424		if(!sh_isstate(SH_PROFILE))
425		{
426			buff.mode = SH_JMPEXIT;
427			sh_onoption(SH_TRACKALL);
428			sh_offoption(SH_MONITOR);
429		}
430		sh_offstate(SH_INTERACTIVE);
431		sh_offstate(SH_MONITOR);
432		sh_offstate(SH_HISTORY);
433		sh_offoption(SH_HISTORY);
434	}
435	states = sh_getstate();
436	jmpval = sigsetjmp(buff.buff,0);
437	if(jmpval)
438	{
439		Sfio_t *top;
440		sh_iorestore((void*)shp,0,jmpval);
441		hist_flush(shp->hist_ptr);
442		sfsync(shp->outpool);
443		shp->st.execbrk = shp->st.breakcnt = 0;
444		/* check for return from profile or env file */
445		if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
446		{
447			sh_setstate(states);
448			goto done;
449		}
450		if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close(shp) >=0))
451		{
452			sh_offstate(SH_INTERACTIVE);
453			sh_offstate(SH_MONITOR);
454			goto done;
455		}
456		/* skip over remaining input */
457		if(top = fcfile())
458		{
459			while(fcget()>0);
460			fcclose();
461			while(top=sfstack(iop,SF_POPSTACK))
462				sfclose(top);
463		}
464		/* make sure that we own the terminal */
465#ifdef SIGTSTP
466		tcsetpgrp(job.fd,shp->pid);
467#endif /* SIGTSTP */
468	}
469	/* error return here */
470	sfclrerr(iop);
471	sh_setstate(states);
472	shp->st.optindex = 1;
473	opt_info.offset = 0;
474	shp->st.loopcnt = 0;
475	shp->trapnote = 0;
476	shp->intrap = 0;
477	error_info.line = 1;
478	shp->inlineno = 1;
479	shp->binscript = 0;
480	if(sfeof(iop))
481		goto eof_or_error;
482	/* command loop */
483	while(1)
484	{
485		shp->nextprompt = 1;
486		sh_freeup(shp);
487		stakset(NIL(char*),0);
488		exitset();
489		sh_offstate(SH_STOPOK);
490		sh_offstate(SH_ERREXIT);
491		sh_offstate(SH_VERBOSE);
492		sh_offstate(SH_TIMING);
493		sh_offstate(SH_GRACE);
494		sh_offstate(SH_TTYWAIT);
495		if(sh_isoption(SH_VERBOSE))
496			sh_onstate(SH_VERBOSE);
497		sh_onstate(SH_ERREXIT);
498		/* -eim  flags don't apply to profiles */
499		if(sh_isstate(SH_PROFILE))
500		{
501			sh_offstate(SH_INTERACTIVE);
502			sh_offstate(SH_ERREXIT);
503			sh_offstate(SH_MONITOR);
504		}
505		if(sh_isstate(SH_INTERACTIVE) && !tdone)
506		{
507			register char *mail;
508#ifdef JOBS
509			sh_offstate(SH_MONITOR);
510			if(sh_isoption(SH_MONITOR))
511				sh_onstate(SH_MONITOR);
512			if(job.pwlist)
513			{
514				job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
515				job_wait((pid_t)0);
516			}
517#endif	/* JOBS */
518			if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
519			{
520				time(&curtime);
521				if ((curtime - mailtime) >= sh_mailchk)
522				{
523					chkmail(shp,mail);
524					mailtime = curtime;
525				}
526			}
527			if(shp->hist_ptr)
528				hist_eof(shp->hist_ptr);
529			/* sets timeout for command entry */
530			shp->timeout = shp->st.tmout;
531#if SHOPT_TIMEOUT
532			if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT)
533				shp->timeout = SHOPT_TIMEOUT;
534#endif /* SHOPT_TIMEOUT */
535			shp->inlineno = 1;
536			error_info.line = 1;
537			shp->exitval = 0;
538			shp->trapnote = 0;
539			if(buff.mode == SH_JMPEXIT)
540			{
541				buff.mode = SH_JMPERREXIT;
542#ifdef DEBUG
543				errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
544#endif
545			}
546		}
547		errno = 0;
548		if(tdone || !sfreserve(iop,0,0))
549		{
550		eof_or_error:
551			if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
552			{
553				if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
554					 !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY))
555				{
556					sfclrerr(iop);
557					errormsg(SH_DICT,0,e_logout);
558					continue;
559				}
560				else if(job_close(shp)<0)
561					continue;
562			}
563			if(errno==0 && sferror(iop) && --maxtry>0)
564			{
565				sfclrlock(iop);
566				sfclrerr(iop);
567				continue;
568			}
569			goto done;
570		}
571		maxtry = IOMAXTRY;
572		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
573		{
574			job_wait((pid_t)0);
575			hist_eof(shp->hist_ptr);
576			sfsync(sfstderr);
577		}
578		if(sh_isoption(SH_HISTORY))
579			sh_onstate(SH_HISTORY);
580		job.waitall = job.curpgid = 0;
581		error_info.flags |= ERROR_INTERACTIVE;
582		t = (Shnode_t*)sh_parse(shp,iop,0);
583		if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG))
584			error_info.flags &= ~ERROR_INTERACTIVE;
585		shp->readscript = 0;
586		if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr)
587			hist_flush(shp->hist_ptr);
588		sh_offstate(SH_HISTORY);
589		if(t)
590		{
591			execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE);
592			/* The last command may not have to fork */
593			if(!sh_isstate(SH_PROFILE) && !sh_isstate(SH_INTERACTIVE) &&
594				(fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK)))
595				&& !sfreserve(iop,0,0))
596			{
597					execflags |= sh_state(SH_NOFORK);
598			}
599			shp->st.execbrk = 0;
600			sh_exec(t,execflags);
601			if(shp->forked)
602			{
603				sh_offstate(SH_INTERACTIVE);
604				goto done;
605			}
606			/* This is for sh -t */
607			if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
608				tdone++;
609		}
610	}
611done:
612	sh_popcontext(&buff);
613	if(sh_isstate(SH_INTERACTIVE))
614	{
615		sfputc(sfstderr,'\n');
616		job_close(shp);
617	}
618	if(jmpval == SH_JMPSCRIPT)
619		siglongjmp(*shp->jmplist,jmpval);
620	else if(jmpval == SH_JMPEXIT)
621		sh_done(shp,0);
622	if(fno>0)
623		sh_close(fno);
624	if(shp->st.filename)
625		free((void*)shp->st.filename);
626	shp->st.filename = 0;
627}
628
629
630/* prints out messages if files in list have been modified since last call */
631static void chkmail(Shell_t *shp, char *files)
632{
633	register char *cp,*sp,*qp;
634	register char save;
635	struct argnod *arglist=0;
636	int	offset = staktell();
637	char 	*savstak=stakptr(0);
638	struct stat	statb;
639	if(*(cp=files) == 0)
640		return;
641	sp = cp;
642	do
643	{
644		/* skip to : or end of string saving first '?' */
645		for(qp=0;*sp && *sp != ':';sp++)
646			if((*sp == '?' || *sp=='%') && qp == 0)
647				qp = sp;
648		save = *sp;
649		*sp = 0;
650		/* change '?' to end-of-string */
651		if(qp)
652			*qp = 0;
653		do
654		{
655			/* see if time has been modified since last checked
656			 * and the access time <= the modification time
657			 */
658			if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
659				&& statb.st_atime <= statb.st_mtime)
660			{
661				/* check for directory */
662				if(!arglist && S_ISDIR(statb.st_mode))
663				{
664					/* generate list of directory entries */
665					path_complete(cp,"/*",&arglist);
666				}
667				else
668				{
669					/*
670					 * If the file has shrunk,
671					 * or if the size is zero
672					 * then don't print anything
673					 */
674					if(statb.st_size &&
675						(  statb.st_ino != lastmail.st_ino
676						|| statb.st_dev != lastmail.st_dev
677						|| statb.st_size > lastmail.st_size))
678					{
679						/* save and restore $_ */
680						char *save = shp->lastarg;
681						shp->lastarg = cp;
682						errormsg(SH_DICT,0,sh_mactry(shp,qp?qp+1:(char*)e_mailmsg));
683						shp->lastarg = save;
684					}
685					lastmail = statb;
686					break;
687				}
688			}
689			if(arglist)
690			{
691				cp = arglist->argval;
692				arglist = arglist->argchn.ap;
693			}
694			else
695				cp = 0;
696		}
697		while(cp);
698		if(qp)
699			*qp = '?';
700		*sp++ = save;
701		cp = sp;
702	}
703	while(save);
704	stakset(savstak,offset);
705}
706
707#undef EXECARGS
708#undef PSTAT
709#if defined(_hdr_execargs) && defined(pdp11)
710#   include	<execargs.h>
711#   define EXECARGS	1
712#endif
713
714#if defined(_lib_pstat) && defined(_sys_pstat)
715#   include	<sys/pstat.h>
716#   define PSTAT	1
717#endif
718
719#if defined(_lib_fork) && !defined(_NEXT_SOURCE)
720/*
721 * fix up command line for ps command
722 * mode is 0 for initialization
723 */
724static void fixargs(char **argv, int mode)
725{
726#if EXECARGS
727	*execargs=(char *)argv;
728#else
729	static char *buff;
730	static int command_len;
731	register char *cp;
732	int offset=0,size;
733#   ifdef PSTAT
734	union pstun un;
735	if(mode==0)
736	{
737		struct pst_static st;
738		un.pst_static = &st;
739		if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
740			return;
741		command_len = st.command_length;
742		return;
743	}
744	stakseek(command_len+2);
745	buff = stakseek(0);
746#   else
747	if(mode==0)
748	{
749		buff = argv[0];
750		while(cp = *argv++)
751			command_len += strlen(cp)+1;
752		if(environ && *environ==buff+command_len)
753		{
754			for(argv=environ; cp = *argv; cp++)
755			{
756				if(command_len > CMD_LENGTH)
757				{
758					command_len = CMD_LENGTH;
759					break;
760				}
761				*argv++ = strdup(cp);
762				command_len += strlen(cp)+1;
763			}
764		}
765		command_len -= 1;
766		return;
767	}
768#   endif /* PSTAT */
769	if(command_len==0)
770		return;
771	while((cp = *argv++) && offset < command_len)
772	{
773		if(offset + (size=strlen(cp)) >= command_len)
774			size = command_len - offset;
775		memcpy(buff+offset,cp,size);
776		offset += size;
777		buff[offset++] = ' ';
778	}
779	buff[offset-1] = 0;
780#   ifdef PSTAT
781	un.pst_command = stakptr(0);
782	pstat(PSTAT_SETCMD,un,0,0,0);
783#   endif /* PSTAT */
784#endif /* EXECARGS */
785}
786#endif /* _lib_fork */
787