summaryrefslogtreecommitdiff
path: root/src/cmd/ksh93/sh/main.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/cmd/ksh93/sh/main.c
downloadksh-upstream.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/cmd/ksh93/sh/main.c')
-rw-r--r--src/cmd/ksh93/sh/main.c787
1 files changed, 787 insertions, 0 deletions
diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c
new file mode 100644
index 0000000..85948a6
--- /dev/null
+++ b/src/cmd/ksh93/sh/main.c
@@ -0,0 +1,787 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Rewritten By David Korn
+ * AT&T Labs
+ *
+ */
+
+#include <ast.h>
+#include <sfio.h>
+#include <stak.h>
+#include <ls.h>
+#include <fcin.h>
+#include "defs.h"
+#include "variables.h"
+#include "path.h"
+#include "io.h"
+#include "jobs.h"
+#include "shlex.h"
+#include "shnodes.h"
+#include "history.h"
+#include "timeout.h"
+#include "FEATURE/time"
+#include "FEATURE/pstat"
+#include "FEATURE/execargs"
+#include "FEATURE/externs"
+#ifdef _hdr_nc
+# include <nc.h>
+#endif /* _hdr_nc */
+
+#define CMD_LENGTH 64
+
+/* These routines are referenced by this module */
+static void exfile(Shell_t*, Sfio_t*,int);
+static void chkmail(Shell_t *shp, char*);
+#if defined(_lib_fork) && !defined(_NEXT_SOURCE)
+ static void fixargs(char**,int);
+#else
+# define fixargs(a,b)
+#endif
+
+#ifndef environ
+ extern char **environ;
+#endif
+
+static struct stat lastmail;
+static time_t mailtime;
+static char beenhere = 0;
+
+#ifdef _lib_sigvec
+ void clearsigmask(register int sig)
+ {
+ struct sigvec vec;
+ if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
+ {
+ vec.sv_mask = 0;
+ sigvec(sig,&vec,NIL(struct sigvec*));
+ }
+ }
+#endif /* _lib_sigvec */
+
+#ifdef _lib_fts_notify
+# include <fts.h>
+ /* check for interrupts during tree walks */
+ static int fts_sigcheck(FTS* fp, FTSENT* ep, void* context)
+ {
+ Shell_t *shp = (Shell_t*)context;
+ NOT_USED(fp);
+ NOT_USED(ep);
+ if(shp->trapnote&SH_SIGSET)
+ {
+ errno = EINTR;
+ return(-1);
+ }
+ return(0);
+ }
+#endif /* _lib_fts_notify */
+
+#ifdef PATH_BFPATH
+#define PATHCOMP NIL(Pathcomp_t*)
+#else
+#define PATHCOMP ""
+#endif
+
+/*
+ * search for file and exfile() it if it exists
+ * 1 returned if file found, 0 otherwise
+ */
+
+int sh_source(Shell_t *shp, Sfio_t *iop, const char *file)
+{
+ char* oid;
+ char* nid;
+ int fd;
+
+ if (!file || !*file || (fd = path_open(shp,file, PATHCOMP)) < 0)
+ {
+ REGRESS(source, "sh_source", ("%s:ENOENT", file));
+ return 0;
+ }
+ oid = error_info.id;
+ nid = error_info.id = strdup(file);
+ shp->st.filename = path_fullname(shp,stakptr(PATH_OFFSET));
+ REGRESS(source, "sh_source", ("%s", file));
+ exfile(shp, iop, fd);
+ error_info.id = oid;
+ free(nid);
+ return 1;
+}
+
+#ifdef S_ISSOCK
+#define REMOTE(m) (S_ISSOCK(m)||!(m))
+#else
+#define REMOTE(m) !(m)
+#endif
+
+int sh_main(int ac, char *av[], Shinit_f userinit)
+{
+ register char *name;
+ register int fdin;
+ register Sfio_t *iop;
+ register Shell_t *shp;
+ struct stat statb;
+ int i, rshflag; /* set for restricted shell */
+ char *command;
+ free(malloc(64*1024));
+#ifdef _lib_sigvec
+ /* This is to clear mask that may be left on by rlogin */
+ clearsigmask(SIGALRM);
+ clearsigmask(SIGHUP);
+ clearsigmask(SIGCHLD);
+#endif /* _lib_sigvec */
+#ifdef _hdr_nc
+ _NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
+#endif /* _hdr_nc */
+ fixargs(av,0);
+ shp = sh_init(ac,av,userinit);
+ time(&mailtime);
+ if(rshflag=sh_isoption(SH_RESTRICTED))
+ sh_offoption(SH_RESTRICTED);
+#ifdef _lib_fts_notify
+ fts_notify(fts_sigcheck,(void*)shp);
+#endif /* _lib_fts_notify */
+ if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
+ {
+ /* begin script execution here */
+ sh_reinit((char**)0);
+ shp->gd->pid = getpid();
+ shp->gd->ppid = getppid();
+ }
+ shp->fn_depth = shp->dot_depth = 0;
+ command = error_info.id;
+ /* set pidname '$$' */
+ srand(shp->gd->pid&0x7fff);
+ if(nv_isnull(PS4NOD))
+ nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
+ path_pwd(shp,1);
+ iop = (Sfio_t*)0;
+#if SHOPT_BRACEPAT
+ sh_onoption(SH_BRACEEXPAND);
+#endif
+ if((beenhere++)==0)
+ {
+ sh_onstate(SH_PROFILE);
+ ((Lex_t*)shp->lex_context)->nonstandard = 0;
+ if(shp->gd->ppid==1)
+ shp->login_sh++;
+ if(shp->login_sh >= 2)
+ sh_onoption(SH_LOGIN_SHELL);
+ /* decide whether shell is interactive */
+ if(!sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) &&
+ sh_isoption(SH_SFLAG) && tty_check(0) && tty_check(ERRIO))
+ sh_onoption(SH_INTERACTIVE);
+ if(sh_isoption(SH_INTERACTIVE))
+ {
+ sh_onoption(SH_BGNICE);
+ sh_onoption(SH_RC);
+ }
+ if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)
+#if SHOPT_REMOTE
+ || !fstat(0, &statb) && REMOTE(statb.st_mode)
+#endif
+ ))
+ sh_onoption(SH_RC);
+ for(i=0; i<elementsof(shp->offoptions.v); i++)
+ shp->options.v[i] &= ~shp->offoptions.v[i];
+ if(sh_isoption(SH_INTERACTIVE))
+ {
+#ifdef SIGXCPU
+ signal(SIGXCPU,SIG_DFL);
+#endif /* SIGXCPU */
+#ifdef SIGXFSZ
+ signal(SIGXFSZ,SIG_DFL);
+#endif /* SIGXFSZ */
+ sh_onoption(SH_MONITOR);
+ }
+ job_init(shp,sh_isoption(SH_LOGIN_SHELL));
+ if(sh_isoption(SH_LOGIN_SHELL))
+ {
+ /* system profile */
+ sh_source(shp, iop, e_sysprofile);
+ if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED))
+ {
+ char **files = shp->gd->login_files;
+ while ((name = *files++) && !sh_source(shp, iop, sh_mactry(shp,name)));
+ }
+ }
+ /* make sure PWD is set up correctly */
+ path_pwd(shp,1);
+ if(!sh_isoption(SH_NOEXEC))
+ {
+ if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC))
+ {
+#if SHOPT_BASH
+ if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX))
+ {
+#if SHOPT_SYSRC
+ sh_source(shp, iop, e_bash_sysrc);
+#endif
+ sh_source(shp, iop, shp->gd->rcfile ? shp->gd->rcfile : sh_mactry(shp,(char*)e_bash_rc));
+ }
+ else
+#endif
+ {
+ if(name = sh_mactry(shp,nv_getval(ENVNOD)))
+ name = *name ? strdup(name) : (char*)0;
+#if SHOPT_SYSRC
+ if(!strmatch(name, "?(.)/./*"))
+ sh_source(shp, iop, e_sysrc);
+#endif
+ if(name)
+ {
+ sh_source(shp, iop, name);
+ free(name);
+ }
+ }
+ }
+ else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED))
+ sh_source(shp, iop, e_suidprofile);
+ }
+ shp->st.cmdname = error_info.id = command;
+ sh_offstate(SH_PROFILE);
+ if(rshflag)
+ sh_onoption(SH_RESTRICTED);
+ /* open input file if specified */
+ if(shp->comdiv)
+ {
+ shell_c:
+ iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
+ }
+ else
+ {
+ name = error_info.id;
+ error_info.id = shp->shname;
+ if(sh_isoption(SH_SFLAG))
+ fdin = 0;
+ else
+ {
+ char *sp;
+ /* open stream should have been passed into shell */
+ if(strmatch(name,e_devfdNN))
+ {
+#if !_WINIX
+ char *cp;
+ int type;
+#endif
+ fdin = (int)strtol(name+8, (char**)0, 10);
+ if(fstat(fdin,&statb)<0)
+ errormsg(SH_DICT,ERROR_system(1),e_open,name);
+#if !_WINIX
+ /*
+ * try to undo effect of solaris 2.5+
+ * change for argv for setuid scripts
+ */
+ if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
+ {
+ av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
+ /* exec to change $0 for ps */
+ execv(pathshell(),av);
+ /* exec fails */
+ shp->st.dolv[0] = av[0];
+ fixargs(shp->st.dolv,1);
+ }
+#endif
+ name = av[0];
+ sh_offoption(SH_VERBOSE);
+ sh_offoption(SH_XTRACE);
+ }
+ else
+ {
+ int isdir = 0;
+ if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
+ {
+ close(fdin);
+ isdir = 1;
+ fdin = -1;
+ }
+ else
+ shp->st.filename = path_fullname(shp,name);
+ sp = 0;
+ if(fdin < 0 && !strchr(name,'/'))
+ {
+#ifdef PATH_BFPATH
+ if(path_absolute(shp,name,NIL(Pathcomp_t*)))
+ sp = stakptr(PATH_OFFSET);
+#else
+ sp = path_absolute(shp,name,NIL(char*));
+#endif
+ if(sp)
+ {
+ if((fdin=sh_open(sp,O_RDONLY,0))>=0)
+ shp->st.filename = path_fullname(shp,sp);
+ }
+ }
+ if(fdin<0)
+ {
+ if(isdir)
+ errno = EISDIR;
+ error_info.id = av[0];
+ if(sp || errno!=ENOENT)
+ errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name);
+ /* try sh -c 'name "$@"' */
+ sh_onoption(SH_CFLAG);
+ shp->comdiv = (char*)malloc(strlen(name)+7);
+ name = strcopy(shp->comdiv,name);
+ if(shp->st.dolc)
+ strcopy(name," \"$@\"");
+ goto shell_c;
+ }
+ if(fdin==0)
+ fdin = sh_iomovefd(fdin);
+ }
+ shp->readscript = shp->shname;
+ }
+ error_info.id = name;
+ shp->comdiv--;
+#if SHOPT_ACCT
+ sh_accinit();
+ if(fdin != 0)
+ sh_accbegin(error_info.id);
+#endif /* SHOPT_ACCT */
+ }
+ }
+ else
+ {
+ fdin = shp->infd;
+ fixargs(shp->st.dolv,1);
+ }
+ if(sh_isoption(SH_INTERACTIVE))
+ sh_onstate(SH_INTERACTIVE);
+ nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
+ exfile(shp,iop,fdin);
+ sh_done(shp,0);
+ /* NOTREACHED */
+ return(0);
+}
+
+/*
+ * iop is not null when the input is a string
+ * fdin is the input file descriptor
+ */
+
+static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
+{
+ time_t curtime;
+ Shnode_t *t;
+ int maxtry=IOMAXTRY, tdone=0, execflags;
+ int states,jmpval;
+ struct checkpt buff;
+ sh_pushcontext(shp,&buff,SH_JMPERREXIT);
+ /* open input stream */
+ nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
+ if(!iop)
+ {
+ if(fno > 0)
+ {
+ int r;
+ if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
+ {
+ shp->fdstatus[r] = shp->fdstatus[fno];
+ sh_close(fno);
+ fno = r;
+ }
+ fcntl(fno,F_SETFD,FD_CLOEXEC);
+ shp->fdstatus[fno] |= IOCLEX;
+ iop = sh_iostream((void*)shp,fno);
+ }
+ else
+ iop = sfstdin;
+ }
+ else
+ fno = -1;
+ shp->infd = fno;
+ if(sh_isstate(SH_INTERACTIVE))
+ {
+ if(nv_isnull(PS1NOD))
+ nv_putval(PS1NOD,(shp->gd->euserid?e_stdprompt:e_supprompt),NV_RDONLY);
+ sh_sigdone();
+ if(sh_histinit((void*)shp))
+ sh_onoption(SH_HISTORY);
+ }
+ else
+ {
+ if(!sh_isstate(SH_PROFILE))
+ {
+ buff.mode = SH_JMPEXIT;
+ sh_onoption(SH_TRACKALL);
+ sh_offoption(SH_MONITOR);
+ }
+ sh_offstate(SH_INTERACTIVE);
+ sh_offstate(SH_MONITOR);
+ sh_offstate(SH_HISTORY);
+ sh_offoption(SH_HISTORY);
+ }
+ states = sh_getstate();
+ jmpval = sigsetjmp(buff.buff,0);
+ if(jmpval)
+ {
+ Sfio_t *top;
+ sh_iorestore((void*)shp,0,jmpval);
+ hist_flush(shp->gd->hist_ptr);
+ sfsync(shp->outpool);
+ shp->st.execbrk = shp->st.breakcnt = 0;
+ /* check for return from profile or env file */
+ if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
+ {
+ sh_setstate(states);
+ goto done;
+ }
+ if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close(shp) >=0))
+ {
+ sh_offstate(SH_INTERACTIVE);
+ sh_offstate(SH_MONITOR);
+ goto done;
+ }
+ /* skip over remaining input */
+ if(top = fcfile())
+ {
+ while(fcget()>0);
+ fcclose();
+ while(top=sfstack(iop,SF_POPSTACK))
+ sfclose(top);
+ }
+ /* make sure that we own the terminal */
+#ifdef SIGTSTP
+ tcsetpgrp(job.fd,shp->gd->pid);
+#endif /* SIGTSTP */
+ }
+ /* error return here */
+ sfclrerr(iop);
+ sh_setstate(states);
+ shp->st.optindex = 1;
+ opt_info.offset = 0;
+ shp->st.loopcnt = 0;
+ shp->trapnote = 0;
+ shp->intrap = 0;
+ error_info.line = 1;
+ shp->inlineno = 1;
+ shp->binscript = 0;
+ if(sfeof(iop))
+ goto eof_or_error;
+ /* command loop */
+ while(1)
+ {
+ shp->nextprompt = 1;
+ sh_freeup(shp);
+ stakset(NIL(char*),0);
+ exitset();
+ sh_offstate(SH_STOPOK);
+ sh_offstate(SH_ERREXIT);
+ sh_offstate(SH_VERBOSE);
+ sh_offstate(SH_TIMING);
+ sh_offstate(SH_GRACE);
+ sh_offstate(SH_TTYWAIT);
+ if(sh_isoption(SH_VERBOSE))
+ sh_onstate(SH_VERBOSE);
+ sh_onstate(SH_ERREXIT);
+ /* -eim flags don't apply to profiles */
+ if(sh_isstate(SH_PROFILE))
+ {
+ sh_offstate(SH_INTERACTIVE);
+ sh_offstate(SH_ERREXIT);
+ sh_offstate(SH_MONITOR);
+ }
+ if(sh_isstate(SH_INTERACTIVE) && !tdone)
+ {
+ register char *mail;
+#ifdef JOBS
+ sh_offstate(SH_MONITOR);
+ if(sh_isoption(SH_MONITOR))
+ sh_onstate(SH_MONITOR);
+ if(job.pwlist)
+ {
+ job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
+ job_wait((pid_t)0);
+ }
+#endif /* JOBS */
+ if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
+ {
+ time(&curtime);
+ if ((curtime - mailtime) >= sh_mailchk)
+ {
+ chkmail(shp,mail);
+ mailtime = curtime;
+ }
+ }
+ if(shp->gd->hist_ptr)
+ hist_eof(shp->gd->hist_ptr);
+ /* sets timeout for command entry */
+ shp->timeout = shp->st.tmout;
+#if SHOPT_TIMEOUT
+ if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT)
+ shp->timeout = SHOPT_TIMEOUT;
+#endif /* SHOPT_TIMEOUT */
+ shp->inlineno = 1;
+ error_info.line = 1;
+ shp->exitval = 0;
+ shp->trapnote = 0;
+ if(buff.mode == SH_JMPEXIT)
+ {
+ buff.mode = SH_JMPERREXIT;
+#ifdef DEBUG
+ errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
+#endif
+ }
+ }
+ errno = 0;
+ if(tdone || !sfreserve(iop,0,0))
+ {
+ eof_or_error:
+ if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
+ {
+ if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
+ !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY))
+ {
+ sfclrerr(iop);
+ errormsg(SH_DICT,0,e_logout);
+ continue;
+ }
+ else if(job_close(shp)<0)
+ continue;
+ }
+ if(errno==0 && sferror(iop) && --maxtry>0)
+ {
+ sfclrlock(iop);
+ sfclrerr(iop);
+ continue;
+ }
+ goto done;
+ }
+ maxtry = IOMAXTRY;
+ if(sh_isstate(SH_INTERACTIVE) && shp->gd->hist_ptr)
+ {
+ job_wait((pid_t)0);
+ hist_eof(shp->gd->hist_ptr);
+ sfsync(sfstderr);
+ }
+ if(sh_isoption(SH_HISTORY))
+ sh_onstate(SH_HISTORY);
+ job.waitall = job.curpgid = 0;
+ error_info.flags |= ERROR_INTERACTIVE;
+ t = (Shnode_t*)sh_parse(shp,iop,0);
+ if(!sh_isstate(SH_INTERACTIVE) && !sh_isoption(SH_CFLAG))
+ error_info.flags &= ~ERROR_INTERACTIVE;
+ shp->readscript = 0;
+ if(sh_isstate(SH_INTERACTIVE) && shp->gd->hist_ptr)
+ hist_flush(shp->gd->hist_ptr);
+ sh_offstate(SH_HISTORY);
+ if(t)
+ {
+ execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE);
+ /* The last command may not have to fork */
+ if(!sh_isstate(SH_PROFILE) && sh_isoption(SH_CFLAG) &&
+ (fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK)))
+ && !sfreserve(iop,0,0))
+ {
+ execflags |= sh_state(SH_NOFORK);
+ }
+ shp->st.execbrk = 0;
+ sh_exec(t,execflags);
+ if(shp->forked)
+ {
+ sh_offstate(SH_INTERACTIVE);
+ goto done;
+ }
+ /* This is for sh -t */
+ if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
+ tdone++;
+ }
+ }
+done:
+ sh_popcontext(shp,&buff);
+ if(sh_isstate(SH_INTERACTIVE))
+ {
+ sfputc(sfstderr,'\n');
+ job_close(shp);
+ }
+ if(jmpval == SH_JMPSCRIPT)
+ siglongjmp(*shp->jmplist,jmpval);
+ else if(jmpval == SH_JMPEXIT)
+ sh_done(shp,0);
+ if(fno>0)
+ sh_close(fno);
+ if(shp->st.filename)
+ free((void*)shp->st.filename);
+ shp->st.filename = 0;
+}
+
+
+/* prints out messages if files in list have been modified since last call */
+static void chkmail(Shell_t *shp, char *files)
+{
+ register char *cp,*sp,*qp;
+ register char save;
+ struct argnod *arglist=0;
+ int offset = staktell();
+ char *savstak=stakptr(0);
+ struct stat statb;
+ if(*(cp=files) == 0)
+ return;
+ sp = cp;
+ do
+ {
+ /* skip to : or end of string saving first '?' */
+ for(qp=0;*sp && *sp != ':';sp++)
+ if((*sp == '?' || *sp=='%') && qp == 0)
+ qp = sp;
+ save = *sp;
+ *sp = 0;
+ /* change '?' to end-of-string */
+ if(qp)
+ *qp = 0;
+ do
+ {
+ /* see if time has been modified since last checked
+ * and the access time <= the modification time
+ */
+ if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
+ && statb.st_atime <= statb.st_mtime)
+ {
+ /* check for directory */
+ if(!arglist && S_ISDIR(statb.st_mode))
+ {
+ /* generate list of directory entries */
+ path_complete(shp,cp,"/*",&arglist);
+ }
+ else
+ {
+ /*
+ * If the file has shrunk,
+ * or if the size is zero
+ * then don't print anything
+ */
+ if(statb.st_size &&
+ ( statb.st_ino != lastmail.st_ino
+ || statb.st_dev != lastmail.st_dev
+ || statb.st_size > lastmail.st_size))
+ {
+ /* save and restore $_ */
+ char *save = shp->lastarg;
+ shp->lastarg = cp;
+ errormsg(SH_DICT,0,sh_mactry(shp,qp?qp+1:(char*)e_mailmsg));
+ shp->lastarg = save;
+ }
+ lastmail = statb;
+ break;
+ }
+ }
+ if(arglist)
+ {
+ cp = arglist->argval;
+ arglist = arglist->argchn.ap;
+ }
+ else
+ cp = 0;
+ }
+ while(cp);
+ if(qp)
+ *qp = '?';
+ *sp++ = save;
+ cp = sp;
+ }
+ while(save);
+ stakset(savstak,offset);
+}
+
+#undef EXECARGS
+#undef PSTAT
+#if defined(_hdr_execargs) && defined(pdp11)
+# include <execargs.h>
+# define EXECARGS 1
+#endif
+
+#if defined(_lib_pstat) && defined(_sys_pstat)
+# include <sys/pstat.h>
+# define PSTAT 1
+#endif
+
+#if defined(_lib_fork) && !defined(_NEXT_SOURCE)
+/*
+ * fix up command line for ps command
+ * mode is 0 for initialization
+ */
+static void fixargs(char **argv, int mode)
+{
+#if EXECARGS
+ *execargs=(char *)argv;
+#else
+ static char *buff;
+ static int command_len;
+ register char *cp;
+ int offset=0,size;
+# ifdef PSTAT
+ union pstun un;
+ if(mode==0)
+ {
+ struct pst_static st;
+ un.pst_static = &st;
+ if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
+ return;
+ command_len = st.command_length;
+ return;
+ }
+ stakseek(command_len+2);
+ buff = stakseek(0);
+# else
+ if(mode==0)
+ {
+ buff = argv[0];
+ while(cp = *argv++)
+ command_len += strlen(cp)+1;
+ if(environ && *environ==buff+command_len)
+ {
+ for(argv=environ; cp = *argv; cp++)
+ {
+ if(command_len > CMD_LENGTH)
+ {
+ command_len = CMD_LENGTH;
+ break;
+ }
+ *argv++ = strdup(cp);
+ command_len += strlen(cp)+1;
+ }
+ }
+ command_len -= 1;
+ return;
+ }
+# endif /* PSTAT */
+ if(command_len==0)
+ return;
+ while((cp = *argv++) && offset < command_len)
+ {
+ if(offset + (size=strlen(cp)) >= command_len)
+ size = command_len - offset;
+ memcpy(buff+offset,cp,size);
+ offset += size;
+ buff[offset++] = ' ';
+ }
+ buff[offset-1] = 0;
+# ifdef PSTAT
+ un.pst_command = stakptr(0);
+ pstat(PSTAT_SETCMD,un,0,0,0);
+# endif /* PSTAT */
+#endif /* EXECARGS */
+}
+#endif /* _lib_fork */