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