736 lines
11 KiB
C
736 lines
11 KiB
C
/* Copyright (c) 1984 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)service.c 1.1 92/07/30 SMI"; /* from S5R3.1 1.22.2.1 */
|
|
#endif
|
|
|
|
/*
|
|
* UNIX shell
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include <errno.h>
|
|
|
|
#define ARGMK 01
|
|
|
|
extern int gsort();
|
|
extern char *sysmsg[];
|
|
extern short topfd;
|
|
|
|
|
|
|
|
/*
|
|
* service routines for `execute'
|
|
*/
|
|
initio(iop, save)
|
|
struct ionod *iop;
|
|
int save;
|
|
{
|
|
extern long lseek();
|
|
register char *ion;
|
|
register int iof, fd;
|
|
int ioufd;
|
|
short lastfd;
|
|
|
|
lastfd = topfd;
|
|
while (iop)
|
|
{
|
|
iof = iop->iofile;
|
|
ion = mactrim(iop->ioname);
|
|
ioufd = iof & IOUFD;
|
|
|
|
if (*ion && (flags&noexec) == 0)
|
|
{
|
|
if (save)
|
|
{
|
|
fdmap[topfd].org_fd = ioufd;
|
|
fdmap[topfd++].dup_fd = savefd(ioufd);
|
|
}
|
|
|
|
if (iof & IODOC)
|
|
{
|
|
struct tempblk tb;
|
|
|
|
subst(chkopen(ion), (fd = tmpfil(&tb)));
|
|
|
|
poptemp(); /* pushed in tmpfil() --
|
|
bug fix for problem with
|
|
in-line scripts
|
|
*/
|
|
|
|
fd = chkopen(tmpout);
|
|
unlink(tmpout);
|
|
}
|
|
else if (iof & IOMOV)
|
|
{
|
|
if (eq(minus, ion))
|
|
{
|
|
fd = -1;
|
|
close(ioufd);
|
|
}
|
|
else if ((fd = stoi(ion)) >= USERIO)
|
|
failed(ion, badfile);
|
|
else
|
|
fd = dup(fd);
|
|
}
|
|
else if ((iof & IOPUT) == 0)
|
|
fd = chkopen(ion);
|
|
else if (flags & rshflg)
|
|
failed(ion, restricted);
|
|
else if (iof & IOAPP && (fd = open(ion, 1)) >= 0)
|
|
lseek(fd, 0L, 2);
|
|
else
|
|
fd = create(ion);
|
|
if (fd >= 0)
|
|
renamefd(fd, ioufd);
|
|
}
|
|
|
|
iop = iop->ionxt;
|
|
}
|
|
return(lastfd);
|
|
}
|
|
|
|
char *
|
|
simple(s)
|
|
char *s;
|
|
{
|
|
char *sname;
|
|
|
|
sname = s;
|
|
while (1)
|
|
{
|
|
if (any('/', sname))
|
|
while (*sname++ != '/')
|
|
;
|
|
else
|
|
return(sname);
|
|
}
|
|
}
|
|
|
|
char *
|
|
getpath(s)
|
|
char *s;
|
|
{
|
|
register char *path, *newpath;
|
|
register int pathlen;
|
|
|
|
if (any('/', s))
|
|
{
|
|
if (flags & rshflg)
|
|
failed(s, restricted);
|
|
/*NOTREACHED*/
|
|
else
|
|
return(nullstr);
|
|
}
|
|
else if ((path = pathnod.namval) == 0)
|
|
return(defpath);
|
|
else {
|
|
pathlen = length(path)-1;
|
|
/* Add extra ':' if PATH variable ends in ':' */
|
|
if(pathlen > 2 && path[pathlen - 1] == ':' && path[pathlen - 2] != ':') {
|
|
newpath = locstak();
|
|
(void) memcpystak(newpath, path, pathlen);
|
|
newpath[pathlen] = ':';
|
|
endstak(newpath + pathlen + 1);
|
|
return(newpath);
|
|
} else
|
|
return(cpystak(path));
|
|
}
|
|
}
|
|
|
|
pathopen(path, name)
|
|
register char *path, *name;
|
|
{
|
|
register int f;
|
|
|
|
do
|
|
{
|
|
path = catpath(path, name);
|
|
} while ((f = open(curstak(), 0)) < 0
|
|
&& (errno == ENOENT || errno == EACCES || errno == ETIMEDOUT)
|
|
&& path);
|
|
return(f);
|
|
}
|
|
|
|
char *
|
|
catpath(path, name)
|
|
register char *path;
|
|
char *name;
|
|
{
|
|
/*
|
|
* leaves result on top of stack
|
|
*/
|
|
register char *scanp = path;
|
|
register char *argp = locstak();
|
|
|
|
while (*scanp && *scanp != COLON)
|
|
{
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
*argp++ = *scanp++;
|
|
}
|
|
if (scanp != path)
|
|
{
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
*argp++ = '/';
|
|
}
|
|
if (*scanp == COLON)
|
|
scanp++;
|
|
path = (*scanp ? scanp : 0);
|
|
scanp = name;
|
|
do
|
|
{
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
}
|
|
while (*argp++ = *scanp++);
|
|
return(path);
|
|
}
|
|
|
|
char *
|
|
nextpath(path)
|
|
register char *path;
|
|
{
|
|
register char *scanp = path;
|
|
|
|
while (*scanp && *scanp != COLON)
|
|
scanp++;
|
|
|
|
if (*scanp == COLON)
|
|
scanp++;
|
|
|
|
return(*scanp ? scanp : 0);
|
|
}
|
|
|
|
static char *xecmsg;
|
|
static char **xecenv;
|
|
|
|
static char *execs();
|
|
|
|
int execa(at, pos)
|
|
char *at[];
|
|
short pos;
|
|
{
|
|
register char *path;
|
|
register char **t = at;
|
|
int cnt;
|
|
|
|
if ((flags & noexec) == 0)
|
|
{
|
|
xecmsg = notfound;
|
|
path = getpath(*t);
|
|
xecenv = setenv();
|
|
|
|
if (pos > 0)
|
|
{
|
|
cnt = 1;
|
|
while (cnt != pos)
|
|
{
|
|
++cnt;
|
|
path = nextpath(path);
|
|
}
|
|
execs(path, t);
|
|
path = getpath(*t);
|
|
}
|
|
while (path = execs(path,t))
|
|
;
|
|
failed(*t, xecmsg);
|
|
}
|
|
}
|
|
|
|
static char *
|
|
execs(ap, t)
|
|
char *ap;
|
|
register char *t[];
|
|
{
|
|
register char *p, *prefix;
|
|
|
|
prefix = catpath(ap, t[0]);
|
|
trim(p = curstak());
|
|
sigchk();
|
|
|
|
execve(p, &t[0] ,xecenv);
|
|
switch (errno)
|
|
{
|
|
case ENOEXEC: /* could be a shell script */
|
|
funcnt = 0;
|
|
flags = 0;
|
|
*flagadr = 0;
|
|
comdiv = 0;
|
|
ioset = 0;
|
|
clearup(); /* remove open files and for loop junk */
|
|
if (input)
|
|
close(input);
|
|
input = chkopen(p);
|
|
|
|
#ifdef ACCT
|
|
preacct(p); /* reset accounting */
|
|
#endif
|
|
|
|
/* is this really a shell script */
|
|
{
|
|
char c;
|
|
if (!isatty(input)) {
|
|
read(input, &c, 1);
|
|
if ((c < ' ' &&
|
|
c != '\n' && c != '\t' && c != '\f') ||
|
|
c > '~') {
|
|
prs("Cannot exec binary file.\n");
|
|
failed(p, badexec);
|
|
}
|
|
lseek(input, (long) 0, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* set up local variables to match environment
|
|
*/
|
|
|
|
setvars();
|
|
|
|
/*
|
|
* set up new args
|
|
*/
|
|
|
|
setargs(t);
|
|
longjmp(subshell, 1);
|
|
|
|
default:
|
|
scfailed(p);
|
|
/*NOTREACHED*/
|
|
|
|
case EACCES:
|
|
case ETIMEDOUT:
|
|
xecmsg = scerrmsg();
|
|
case ENOENT:
|
|
return(prefix);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* for processes to be waited for
|
|
*/
|
|
#define MAXP 20
|
|
static int pwlist[MAXP];
|
|
static int pwc;
|
|
|
|
postclr()
|
|
{
|
|
register int *pw = pwlist;
|
|
|
|
while (pw <= &pwlist[pwc])
|
|
*pw++ = 0;
|
|
pwc = 0;
|
|
}
|
|
|
|
post(pcsid)
|
|
int pcsid;
|
|
{
|
|
register int *pw = pwlist;
|
|
|
|
if (pcsid)
|
|
{
|
|
while (*pw)
|
|
pw++;
|
|
if (pwc >= MAXP - 1)
|
|
pw--;
|
|
else
|
|
pwc++;
|
|
*pw = pcsid;
|
|
}
|
|
}
|
|
|
|
await(i, bckg)
|
|
int i, bckg;
|
|
{
|
|
int rc = 0, wx = 0;
|
|
int w;
|
|
int ipwc = pwc;
|
|
|
|
post(i);
|
|
while (pwc)
|
|
{
|
|
register int p;
|
|
register int sig;
|
|
int w_hi;
|
|
int found = 0;
|
|
|
|
{
|
|
register int *pw = pwlist;
|
|
|
|
if (setjmp(INTbuf) == 0)
|
|
{
|
|
trapjmp = 1;
|
|
p = wait(&w);
|
|
}
|
|
else
|
|
p = -1;
|
|
trapjmp = 0;
|
|
if (wasintr)
|
|
{
|
|
wasintr = 0;
|
|
if (bckg)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (pw <= &pwlist[ipwc])
|
|
{
|
|
if (*pw == p)
|
|
{
|
|
*pw = 0;
|
|
pwc--;
|
|
found++;
|
|
}
|
|
else
|
|
pw++;
|
|
}
|
|
}
|
|
if (p == -1)
|
|
{
|
|
if (bckg)
|
|
{
|
|
register int *pw = pwlist;
|
|
|
|
while (pw <= &pwlist[ipwc] && i != *pw)
|
|
pw++;
|
|
if (i == *pw)
|
|
{
|
|
*pw = 0;
|
|
pwc--;
|
|
}
|
|
} else if(errno == ECHILD)
|
|
break;
|
|
continue;
|
|
}
|
|
w_hi = (w >> 8) & LOBYTE;
|
|
if (sig = w & 0177)
|
|
{
|
|
if (sig == 0177) /* ptrace! return */
|
|
{
|
|
prs("ptrace: ");
|
|
sig = w_hi;
|
|
}
|
|
if (sig > MAXTRAP || sysmsg[sig])
|
|
{
|
|
if (i != p || (flags & prompt) == 0)
|
|
{
|
|
prp();
|
|
prn(p);
|
|
blank();
|
|
}
|
|
if(sig > MAXTRAP) {
|
|
prs("Signal ");
|
|
prn(sig);
|
|
}
|
|
else
|
|
prs(sysmsg[sig]);
|
|
if (w & 0200)
|
|
prs(coredump);
|
|
newline();
|
|
}
|
|
else if (flags & prompt)
|
|
newline();
|
|
}
|
|
if (rc == 0 && found != 0)
|
|
rc = (sig ? sig | SIGFLG : w_hi);
|
|
wx |= w;
|
|
if (p == i)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (wx && flags & errflg)
|
|
exitsh(rc);
|
|
flags |= eflag;
|
|
exitval = rc;
|
|
exitset();
|
|
}
|
|
|
|
BOOL nosubst;
|
|
|
|
trim(at)
|
|
char *at;
|
|
{
|
|
register char *last;
|
|
register char *current;
|
|
register char c;
|
|
register char q = 0;
|
|
|
|
nosubst = 0;
|
|
if (current = at)
|
|
{
|
|
last = at;
|
|
while (c = *current++)
|
|
{
|
|
if(c == '\\') { /* remove \ and quoted nulls */
|
|
nosubst = 1;
|
|
if(c = *current++)
|
|
*last++ = c;
|
|
} else
|
|
*last++ = c;
|
|
}
|
|
|
|
*last = 0;
|
|
}
|
|
}
|
|
|
|
char *
|
|
mactrim(s)
|
|
char *s;
|
|
{
|
|
register char *t = macro(s);
|
|
|
|
trim(t);
|
|
return(t);
|
|
}
|
|
|
|
char **
|
|
scan(argn)
|
|
int argn;
|
|
{
|
|
register struct argnod *argp = (struct argnod *)(Rcheat(gchain) & ~ARGMK);
|
|
register char **comargn, **comargm;
|
|
|
|
comargn = (char **)getstak(BYTESPERWORD * argn + BYTESPERWORD);
|
|
comargm = comargn += argn;
|
|
*comargn = ENDARGS;
|
|
while (argp)
|
|
{
|
|
*--comargn = argp->argval;
|
|
|
|
trim(*comargn);
|
|
argp = argp->argnxt;
|
|
|
|
if (argp == 0 || Rcheat(argp) & ARGMK)
|
|
{
|
|
gsort(comargn, comargm);
|
|
comargm = comargn;
|
|
}
|
|
/* Lcheat(argp) &= ~ARGMK; */
|
|
argp = (struct argnod *)(Rcheat(argp) & ~ARGMK);
|
|
}
|
|
return(comargn);
|
|
}
|
|
|
|
static int
|
|
gsort(from, to)
|
|
char *from[], *to[];
|
|
{
|
|
int k, m, n;
|
|
register int i, j;
|
|
|
|
if ((n = to - from) <= 1)
|
|
return;
|
|
for (j = 1; j <= n; j *= 2)
|
|
;
|
|
for (m = 2 * j - 1; m /= 2; )
|
|
{
|
|
k = n - m;
|
|
for (j = 0; j < k; j++)
|
|
{
|
|
for (i = j; i >= 0; i -= m)
|
|
{
|
|
register char **fromi;
|
|
|
|
fromi = &from[i];
|
|
if (cf(fromi[m], fromi[0]) > 0)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
char *s;
|
|
|
|
s = fromi[m];
|
|
fromi[m] = fromi[0];
|
|
fromi[0] = s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Argument list generation
|
|
*/
|
|
getarg(ac)
|
|
struct comnod *ac;
|
|
{
|
|
register struct argnod *argp;
|
|
register int count = 0;
|
|
register struct comnod *c;
|
|
|
|
if (c = ac)
|
|
{
|
|
argp = c->comarg;
|
|
while (argp)
|
|
{
|
|
count += split(macro(argp->argval),1);
|
|
argp = argp->argnxt;
|
|
}
|
|
}
|
|
return(count);
|
|
}
|
|
|
|
static int
|
|
split(s) /* blank interpretation routine */
|
|
register char *s;
|
|
{
|
|
register char *argp;
|
|
register int c;
|
|
register int d;
|
|
int count = 0;
|
|
for (;;)
|
|
{
|
|
sigchk();
|
|
argp = locstak() + BYTESPERWORD;
|
|
while (c = *s++) {
|
|
if(c == '\\') { /* skip over quoted characters */
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
*argp++ = c;
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
*argp++ = *s++;
|
|
}
|
|
else if (any(c, ifsnod.namval))
|
|
break;
|
|
else {
|
|
if (argp >= brkend)
|
|
growstak(argp);
|
|
*argp++ = c;
|
|
}
|
|
}
|
|
if (argp == staktop + BYTESPERWORD)
|
|
{
|
|
if (c)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
return(count);
|
|
}
|
|
}
|
|
else if (c == 0)
|
|
s--;
|
|
/*
|
|
* file name generation
|
|
*/
|
|
|
|
argp = endstak(argp);
|
|
|
|
if ((flags & nofngflg) == 0 &&
|
|
(c = expand(((struct argnod *)argp)->argval, 0)))
|
|
count += c;
|
|
else
|
|
{
|
|
makearg(argp);
|
|
count++;
|
|
}
|
|
gchain = (struct argnod *)((int)gchain | ARGMK);
|
|
}
|
|
}
|
|
|
|
#ifdef ACCT
|
|
#include <sys/types.h>
|
|
#include "acctdef.h"
|
|
#include <sys/acct.h>
|
|
#include <sys/times.h>
|
|
|
|
struct acct sabuf;
|
|
struct tms buffer;
|
|
extern long times();
|
|
static long before;
|
|
static int shaccton; /* 0 implies do not write record on exit
|
|
1 implies write acct record on exit
|
|
*/
|
|
|
|
|
|
/*
|
|
* suspend accounting until turned on by preacct()
|
|
*/
|
|
|
|
suspacct()
|
|
{
|
|
shaccton = 0;
|
|
}
|
|
|
|
preacct(cmdadr)
|
|
char *cmdadr;
|
|
{
|
|
char *simple();
|
|
|
|
if (acctnod.namval && *acctnod.namval)
|
|
{
|
|
sabuf.ac_btime = time((long *)0);
|
|
before = times(&buffer);
|
|
sabuf.ac_uid = getuid();
|
|
sabuf.ac_gid = getgid();
|
|
movstrn(simple(cmdadr), sabuf.ac_comm, sizeof(sabuf.ac_comm));
|
|
shaccton = 1;
|
|
}
|
|
}
|
|
|
|
#include <fcntl.h>
|
|
|
|
doacct()
|
|
{
|
|
int fd;
|
|
long int after;
|
|
|
|
if (shaccton)
|
|
{
|
|
after = times(&buffer);
|
|
sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
|
|
sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
|
|
sabuf.ac_etime = compress(after - before);
|
|
|
|
if ((fd = open(acctnod.namval, O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1)
|
|
{
|
|
write(fd, &sabuf, sizeof(sabuf));
|
|
close(fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Produce a pseudo-floating point representation
|
|
* with 3 bits base-8 exponent, 13 bits fraction
|
|
*/
|
|
|
|
compress(t)
|
|
register time_t t;
|
|
{
|
|
register exp = 0;
|
|
register rund = 0;
|
|
|
|
while (t >= 8192)
|
|
{
|
|
exp++;
|
|
rund = t & 04;
|
|
t >>= 3;
|
|
}
|
|
|
|
if (rund)
|
|
{
|
|
t++;
|
|
if (t >= 8192)
|
|
{
|
|
t >>= 3;
|
|
exp++;
|
|
}
|
|
}
|
|
|
|
return((exp << 13) + t);
|
|
}
|
|
#endif
|