Importing bin/ksh

This commit is contained in:
Thomas Cort 2013-03-13 03:41:18 +00:00 committed by Lionel Sambuc
parent 173f4de7a1
commit 2718b5688b
58 changed files with 32827 additions and 1 deletions

View file

@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= cat date echo ed expr kill ln ls \
SUBDIR= cat date echo ed expr kill ksh ln ls \
mkdir pax pwd rm rmdir sync test
.include <bsd.subdir.mk>

50
bin/ksh/Makefile Normal file
View file

@ -0,0 +1,50 @@
# $NetBSD: Makefile,v 1.30 2011/10/16 17:12:11 joerg Exp $
WARNS=3
.include <bsd.own.mk>
CPPFLAGS+= -I.
PROG= ksh
SRCS= alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \
eval.c exec.c expr.c history.c io.c jobs.c lex.c mail.c \
main.c misc.c path.c shf.c sigact.c syn.c table.c trap.c \
tree.c tty.c var.c version.c vi.c
DPSRCS= emacs.out siglist.out
.if (${MKMAN} != "no")
DPSRCS+=ksh.1
.endif
# needs tbl for the man page.
USETBL=
# Environment for scripts executed during build.
SCRIPT_ENV= \
AWK=${TOOL_AWK:Q} \
SED=${TOOL_SED:Q}
CLEANFILES+= siglist.out siglist.out.tmp
# two steps to prevent the creation of a bogus siglist.out
siglist.out: config.h sh.h siglist.in siglist.sh
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/siglist.sh "$(CC) -E $(CPPFLAGS) $(DEFS) -I. -I$(.CURDIR)" < $(.CURDIR)/siglist.in > siglist.out.tmp \
&& mv siglist.out.tmp siglist.out
# two steps to prevent the creation of a bogus emacs.out
CLEANFILES+= emacs.out emacs.out.tmp
emacs.out: emacs.c
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/emacs-gen.sh $(.CURDIR)/emacs.c > emacs.out.tmp \
&& mv emacs.out.tmp emacs.out
CLEANFILES+= ksh.1 ksh.1.tmp
ksh.1: ksh.Man mkman
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/mkman ksh $(.CURDIR)/ksh.Man >ksh.1.tmp \
&& mv ksh.1.tmp ksh.1
.include <bsd.prog.mk>

127
bin/ksh/alloc.c Normal file
View file

@ -0,0 +1,127 @@
/* $NetBSD: alloc.c,v 1.10 2007/12/12 22:55:42 lukem Exp $ */
/*
* Copyright (c) 2002 Marc Espie.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
* PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* area-based allocation built on malloc/free
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: alloc.c,v 1.10 2007/12/12 22:55:42 lukem Exp $");
#include "sh.h"
struct link {
struct link *prev;
struct link *next;
};
Area *
ainit(Area *ap)
{
ap->freelist = NULL;
return ap;
}
void
afreeall(Area *ap)
{
struct link *l, *l2;
for (l = ap->freelist; l != NULL; l = l2) {
l2 = l->next;
free(l);
}
ap->freelist = NULL;
}
#define L2P(l) ( (void *)(((char *)(l)) + sizeof(struct link)) )
#define P2L(p) ( (struct link *)(((char *)(p)) - sizeof(struct link)) )
/* coverity[+alloc] */
void *
alloc(size_t size, Area *ap)
{
struct link *l;
l = malloc(sizeof(struct link) + size);
if (l == NULL)
internal_errorf(1, "unable to allocate memory");
l->next = ap->freelist;
l->prev = NULL;
if (ap->freelist)
ap->freelist->prev = l;
ap->freelist = l;
return L2P(l);
}
/* coverity[+alloc] */
/* coverity[+free : arg-0] */
void *
aresize(void *ptr, size_t size, Area *ap)
{
struct link *l, *l2, *lprev, *lnext;
if (ptr == NULL)
return alloc(size, ap);
l = P2L(ptr);
lprev = l->prev;
lnext = l->next;
l2 = realloc(l, sizeof(struct link) + size);
if (l2 == NULL)
internal_errorf(1, "unable to allocate memory");
if (lprev)
lprev->next = l2;
else
ap->freelist = l2;
if (lnext)
lnext->prev = l2;
return L2P(l2);
}
/* coverity[+free : arg-0] */
void
afree(void *ptr, Area *ap)
{
struct link *l;
if (!ptr)
return;
l = P2L(ptr);
if (l->prev)
l->prev->next = l->next;
else
ap->freelist = l->next;
if (l->next)
l->next->prev = l->prev;
free(l);
}

1490
bin/ksh/c_ksh.c Normal file

File diff suppressed because it is too large Load diff

917
bin/ksh/c_sh.c Normal file
View file

@ -0,0 +1,917 @@
/* $NetBSD: c_sh.c,v 1.14 2011/08/31 16:24:54 plunky Exp $ */
/*
* built-in Bourne commands
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_sh.c,v 1.14 2011/08/31 16:24:54 plunky Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h" /* umask() */
#include "ksh_time.h"
#include "ksh_times.h"
static char *clocktos ARGS((clock_t t));
/* :, false and true */
int
c_label(wp)
char **wp;
{
return wp[0][0] == 'f' ? 1 : 0;
}
int
c_shift(wp)
char **wp;
{
register struct block *l = e->loc;
register int n;
long val;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (arg) {
evaluate(arg, &val, KSH_UNWIND_ERROR);
n = val;
} else
n = 1;
if (n < 0) {
bi_errorf("%s: bad number", arg);
return (1);
}
if (l->argc < n) {
bi_errorf("nothing to shift");
return (1);
}
l->argv[n] = l->argv[0];
l->argv += n;
l->argc -= n;
return 0;
}
int
c_umask(wp)
char **wp;
{
register int i;
register char *cp;
int symbolic = 0;
int old_umask;
int optc;
while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
switch (optc) {
case 'S':
symbolic = 1;
break;
case '?':
return 1;
}
cp = wp[builtin_opt.optind];
if (cp == NULL) {
old_umask = umask(0);
umask(old_umask);
if (symbolic) {
char buf[18];
int j;
old_umask = ~old_umask;
cp = buf;
for (i = 0; i < 3; i++) {
*cp++ = "ugo"[i];
*cp++ = '=';
for (j = 0; j < 3; j++)
if (old_umask & (1 << (8 - (3*i + j))))
*cp++ = "rwx"[j];
*cp++ = ',';
}
cp[-1] = '\0';
shprintf("%s\n", buf);
} else
shprintf("%#3.3o\n", old_umask);
} else {
int new_umask;
if (digit(*cp)) {
for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
new_umask = new_umask * 8 + (*cp - '0');
if (*cp) {
bi_errorf("bad number");
return 1;
}
} else {
/* symbolic format */
int positions, new_val;
char op;
old_umask = umask(0);
umask(old_umask); /* in case of error */
old_umask = ~old_umask;
new_umask = old_umask;
positions = 0;
while (*cp) {
while (*cp && strchr("augo", *cp))
switch (*cp++) {
case 'a': positions |= 0111; break;
case 'u': positions |= 0100; break;
case 'g': positions |= 0010; break;
case 'o': positions |= 0001; break;
}
if (!positions)
positions = 0111; /* default is a */
if (!strchr("=+-", op = *cp))
break;
cp++;
new_val = 0;
while (*cp && strchr("rwxugoXs", *cp))
switch (*cp++) {
case 'r': new_val |= 04; break;
case 'w': new_val |= 02; break;
case 'x': new_val |= 01; break;
case 'u': new_val |= old_umask >> 6;
break;
case 'g': new_val |= old_umask >> 3;
break;
case 'o': new_val |= old_umask >> 0;
break;
case 'X': if (old_umask & 0111)
new_val |= 01;
break;
case 's': /* ignored */
break;
}
new_val = (new_val & 07) * positions;
switch (op) {
case '-':
new_umask &= ~new_val;
break;
case '=':
new_umask = new_val
| (new_umask & ~(positions * 07));
break;
case '+':
new_umask |= new_val;
}
if (*cp == ',') {
positions = 0;
cp++;
} else if (!strchr("=+-", *cp))
break;
}
if (*cp) {
bi_errorf("bad mask");
return 1;
}
new_umask = ~new_umask;
}
umask(new_umask);
}
return 0;
}
int
c_dot(wp)
char **wp;
{
char *file, *cp;
char **argv;
int argc;
int i;
int err;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
if ((cp = wp[builtin_opt.optind]) == NULL)
return 0;
file = search(cp, path, R_OK, &err);
if (file == NULL) {
bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
return 1;
}
/* Set positional parameters? */
if (wp[builtin_opt.optind + 1]) {
argv = wp + builtin_opt.optind;
argv[0] = e->loc->argv[0]; /* preserve $0 */
for (argc = 0; argv[argc + 1]; argc++)
;
} else {
argc = 0;
argv = (char **) 0;
}
i = include(file, argc, argv, 0);
if (i < 0) { /* should not happen */
bi_errorf("%s: %s", cp, strerror(errno));
return 1;
}
return i;
}
int
c_wait(wp)
char **wp;
{
int UNINITIALIZED(rv);
int sig;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
wp += builtin_opt.optind;
if (*wp == (char *) 0) {
while (waitfor((char *) 0, &sig) >= 0)
;
rv = sig;
} else {
for (; *wp; wp++)
rv = waitfor(*wp, &sig);
if (rv < 0)
rv = sig ? sig : 127; /* magic exit code: bad job-id */
}
return rv;
}
int
c_read(wp)
char **wp;
{
register int c = 0;
int expandv = 1, history = 0;
int expanding;
int ecode = 0;
register char *cp;
int fd = 0;
struct shf *shf;
int optc;
const char *emsg;
XString cs, xs;
struct tbl *vp;
char UNINITIALIZED(*xp);
static char REPLY[] = "REPLY";
while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
switch (optc) {
#ifdef KSH
case 'p':
if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
bi_errorf("-p: %s", emsg);
return 1;
}
break;
#endif /* KSH */
case 'r':
expandv = 0;
break;
case 's':
history = 1;
break;
case 'u':
if (!*(cp = builtin_opt.optarg))
fd = 0;
else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
bi_errorf("-u: %s: %s", cp, emsg);
return 1;
}
break;
case '?':
return 1;
}
wp += builtin_opt.optind;
if (*wp == NULL)
*--wp = REPLY;
/* Since we can't necessarily seek backwards on non-regular files,
* don't buffer them so we can't read too much.
*/
shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
if ((cp = strchr(*wp, '?')) != NULL) {
*cp = 0;
if (isatty(fd)) {
/* at&t ksh says it prints prompt on fd if it's open
* for writing and is a tty, but it doesn't do it
* (it also doesn't check the interactive flag,
* as is indicated in the Kornshell book).
*/
shellf("%s", cp+1);
}
}
#ifdef KSH
/* If we are reading from the co-process for the first time,
* make sure the other side of the pipe is closed first. This allows
* the detection of eof.
*
* This is not compatible with at&t ksh... the fd is kept so another
* coproc can be started with same output, however, this means eof
* can't be detected... This is why it is closed here.
* If this call is removed, remove the eof check below, too.
* coproc_readw_close(fd);
*/
#endif /* KSH */
if (history)
Xinit(xs, xp, 128, ATEMP);
expanding = 0;
Xinit(cs, cp, 128, ATEMP);
for (; *wp != NULL; wp++) {
for (cp = Xstring(cs, cp); ; ) {
if (c == '\n' || c == EOF)
break;
while (1) {
c = shf_getc(shf);
if (c == '\0'
#ifdef OS2
|| c == '\r'
#endif /* OS2 */
)
continue;
if (c == EOF && shf_error(shf)
&& shf_errno(shf) == EINTR)
{
/* Was the offending signal one that
* would normally kill a process?
* If so, pretend the read was killed.
*/
ecode = fatal_trap_check();
/* non fatal (eg, CHLD), carry on */
if (!ecode) {
shf_clearerr(shf);
continue;
}
}
break;
}
if (history) {
Xcheck(xs, xp);
Xput(xs, xp, c);
}
Xcheck(cs, cp);
if (expanding) {
expanding = 0;
if (c == '\n') {
c = 0;
if (Flag(FTALKING_I) && isatty(fd)) {
/* set prompt in case this is
* called from .profile or $ENV
*/
set_prompt(PS2, (Source *) 0);
pprompt(prompt, 0);
}
} else if (c != EOF)
Xput(cs, cp, c);
continue;
}
if (expandv && c == '\\') {
expanding = 1;
continue;
}
if (c == '\n' || c == EOF)
break;
if (ctype(c, C_IFS)) {
if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
continue;
if (wp[1])
break;
}
Xput(cs, cp, c);
}
/* strip trailing IFS white space from last variable */
if (!wp[1])
while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
&& ctype(cp[-1], C_IFSWS))
cp--;
Xput(cs, cp, '\0');
vp = global(*wp);
/* Must be done before setting export. */
if (vp->flag & RDONLY) {
shf_flush(shf);
bi_errorf("%s is read only", *wp);
return 1;
}
if (Flag(FEXPORT))
typeset(*wp, EXPORT, 0, 0, 0);
if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
shf_flush(shf);
return 1;
}
}
shf_flush(shf);
if (history) {
Xput(xs, xp, '\0');
source->line++;
histsave(source->line, Xstring(xs, xp), 1);
Xfree(xs, xp);
}
#ifdef KSH
/* if this is the co-process fd, close the file descriptor
* (can get eof if and only if all processes are have died, ie,
* coproc.njobs is 0 and the pipe is closed).
*/
if (c == EOF && !ecode)
coproc_read_close(fd);
#endif /* KSH */
return ecode ? ecode : c == EOF;
}
int
c_eval(wp)
char **wp;
{
register struct source *s;
int rv;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
s = pushs(SWORDS, ATEMP);
s->u.strv = wp + builtin_opt.optind;
if (!Flag(FPOSIX)) {
/*
* Handle case where the command is empty due to failed
* command substitution, eg, eval "$(false)".
* In this case, shell() will not set/change exstat (because
* compiled tree is empty), so will use this value.
* subst_exstat is cleared in execute(), so should be 0 if
* there were no substitutions.
*
* A strict reading of POSIX says we don't do this (though
* it is traditionally done). [from 1003.2-1992]
* 3.9.1: Simple Commands
* ... If there is a command name, execution shall
* continue as described in 3.9.1.1. If there
* is no command name, but the command contained a command
* substitution, the command shall complete with the exit
* status of the last command substitution
* 3.9.1.1: Command Search and Execution
* ...(1)...(a) If the command name matches the name of
* a special built-in utility, that special built-in
* utility shall be invoked.
* 3.14.5: Eval
* ... If there are no arguments, or only null arguments,
* eval shall return an exit status of zero.
*/
exstat = subst_exstat;
}
rv = shell(s, FALSE);
afree(s, ATEMP);
return rv;
}
int
c_trap(wp)
char **wp;
{
int i;
char *s;
register Trap *p;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
wp += builtin_opt.optind;
if (*wp == NULL) {
int anydfl = 0;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
if (p->trap == NULL)
anydfl = 1;
else {
shprintf("trap -- ");
print_value_quoted(p->trap);
shprintf(" %s\n", p->name);
}
}
#if 0 /* this is ugly and not clear POSIX needs it */
/* POSIX may need this so output of trap can be saved and
* used to restore trap conditions
*/
if (anydfl) {
shprintf("trap -- -");
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->trap == NULL && p->name)
shprintf(" %s", p->name);
shprintf(newline);
}
#endif
return 0;
}
/*
* Use case sensitive lookup for first arg so the
* command 'exit' isn't confused with the pseudo-signal
* 'EXIT'.
*/
s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */
if (s != NULL && s[0] == '-' && s[1] == '\0')
s = NULL;
/* set/clear traps */
while (*wp != NULL) {
p = gettrap(*wp++, TRUE);
if (p == NULL) {
bi_errorf("bad signal %s", wp[-1]);
return 1;
}
settrap(p, s);
}
return 0;
}
int
c_exitreturn(wp)
char **wp;
{
int how = LEXIT;
int n;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (arg) {
if (!getn(arg, &n)) {
exstat = 1;
warningf(TRUE, "%s: bad number", arg);
} else
exstat = n;
}
if (wp[0][0] == 'r') { /* return */
struct env *ep;
/* need to tell if this is exit or return so trap exit will
* work right (POSIX)
*/
for (ep = e; ep; ep = ep->oenv)
if (STOP_RETURN(ep->type)) {
how = LRETURN;
break;
}
}
if (how == LEXIT && !really_exit && j_stopped_running()) {
really_exit = 1;
how = LSHELL;
}
quitenv(); /* get rid of any i/o redirections */
unwind(how);
/*NOTREACHED*/
return 0;
}
int
c_brkcont(wp)
char **wp;
{
int n, quit;
struct env *ep, *last_ep = (struct env *) 0;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (!arg)
n = 1;
else if (!bi_getn(arg, &n))
return 1;
quit = n;
if (quit <= 0) {
/* at&t ksh does this for non-interactive shells only - weird */
bi_errorf("%s: bad value", arg);
return 1;
}
/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
if (ep->type == E_LOOP) {
if (--quit == 0)
break;
ep->flags |= EF_BRKCONT_PASS;
last_ep = ep;
}
if (quit) {
/* at&t ksh doesn't print a message - just does what it
* can. We print a message 'cause it helps in debugging
* scripts, but don't generate an error (ie, keep going).
*/
if (n == quit) {
warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
return 0;
}
/* POSIX says if n is too big, the last enclosing loop
* shall be used. Doesn't say to print an error but we
* do anyway 'cause the user messed up.
*/
if (last_ep)
last_ep->flags &= ~EF_BRKCONT_PASS;
warningf(TRUE, "%s: can only %s %d level(s)",
wp[0], wp[0], n - quit);
}
unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
/*NOTREACHED*/
}
int
c_set(wp)
char **wp;
{
int argi, setargs;
struct block *l = e->loc;
register char **owp = wp;
if (wp[1] == NULL) {
static const char *const args [] = { "set", "-", NULL };
return c_typeset((char **)__UNCONST(args));
}
argi = parse_args(wp, OF_SET, &setargs);
if (argi < 0)
return 1;
/* set $# and $* */
if (setargs) {
owp = wp += argi - 1;
wp[0] = l->argv[0]; /* save $0 */
while (*++wp != NULL)
*wp = str_save(*wp, &l->area);
l->argc = wp - owp - 1;
l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
for (wp = l->argv; (*wp++ = *owp++) != NULL; )
;
}
/* POSIX says set exit status is 0, but old scripts that use
* getopt(1), use the construct: set -- `getopt ab:c "$@"`
* which assumes the exit value set will be that of the ``
* (subst_exstat is cleared in execute() so that it will be 0
* if there are no command substitutions).
*/
return Flag(FPOSIX) ? 0 : subst_exstat;
}
int
c_unset(wp)
char **wp;
{
register char *id;
int optc, unset_var = 1;
int ret = 0;
while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
switch (optc) {
case 'f':
unset_var = 0;
break;
case 'v':
unset_var = 1;
break;
case '?':
return 1;
}
wp += builtin_opt.optind;
for (; (id = *wp) != NULL; wp++)
if (unset_var) { /* unset variable */
struct tbl *vp = global(id);
if (!(vp->flag & ISSET))
ret = 1;
if ((vp->flag&RDONLY)) {
bi_errorf("%s is read only", vp->name);
return 1;
}
unset(vp, strchr(id, '[') ? 1 : 0);
} else { /* unset function */
if (define(id, NULL))
ret = 1;
}
return ret;
}
int
c_times(wp)
char **wp;
{
struct tms all;
(void) ksh_times(&all);
shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
shprintf("%8ss system\n", clocktos(all.tms_stime));
shprintf("Kids: %8ss user ", clocktos(all.tms_cutime));
shprintf("%8ss system\n", clocktos(all.tms_cstime));
return 0;
}
/*
* time pipeline (really a statement, not a built-in command)
*/
int
timex(t, f)
struct op *t;
int f;
{
#define TF_NOARGS BIT(0)
#define TF_NOREAL BIT(1) /* don't report real time */
#define TF_POSIX BIT(2) /* report in posix format */
int rv = 0;
struct tms t0, t1, tms;
clock_t t0t, t1t = 0;
int tf = 0;
extern clock_t j_usrtime, j_systime; /* computed by j_wait */
char opts[1];
t0t = ksh_times(&t0);
if (t->left) {
/*
* Two ways of getting cpu usage of a command: just use t0
* and t1 (which will get cpu usage from other jobs that
* finish while we are executing t->left), or get the
* cpu usage of t->left. at&t ksh does the former, while
* pdksh tries to do the later (the j_usrtime hack doesn't
* really work as it only counts the last job).
*/
j_usrtime = j_systime = 0;
if (t->left->type == TCOM)
t->left->str = opts;
opts[0] = 0;
rv = execute(t->left, f | XTIME);
tf |= opts[0];
t1t = ksh_times(&t1);
} else
tf = TF_NOARGS;
if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
tf |= TF_NOREAL;
tms.tms_utime = t0.tms_utime + t0.tms_cutime;
tms.tms_stime = t0.tms_stime + t0.tms_cstime;
} else {
tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
}
if (!(tf & TF_NOREAL))
shf_fprintf(shl_out,
tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
clocktos(t1t - t0t));
shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
clocktos(tms.tms_utime));
shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n",
clocktos(tms.tms_stime));
shf_flush(shl_out);
return rv;
}
void
timex_hook(t, app)
struct op *t;
char ** volatile *app;
{
char **wp = *app;
int optc;
int i, j;
Getopt opt;
ksh_getopt_reset(&opt, 0);
opt.optind = 0; /* start at the start */
while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
switch (optc) {
case 'p':
t->str[0] |= TF_POSIX;
break;
case '?':
errorf("time: -%s unknown option", opt.optarg);
case ':':
errorf("time: -%s requires an argument",
opt.optarg);
}
/* Copy command words down over options. */
if (opt.optind != 0) {
for (i = 0; i < opt.optind; i++)
afree(wp[i], ATEMP);
for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
;
}
if (!wp[0])
t->str[0] |= TF_NOARGS;
*app = wp;
}
static char *
clocktos(t)
clock_t t;
{
static char temp[22]; /* enough for 64 bit clock_t */
register int i;
register char *cp = temp + sizeof(temp);
/* note: posix says must use max precision, ie, if clk_tck is
* 1000, must print 3 places after decimal (if non-zero, else 1).
*/
if (CLK_TCK != 100) /* convert to 1/100'ths */
t = (t < (clock_t)(1000000000/CLK_TCK)) ?
(t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
*--cp = '\0';
for (i = -2; i <= 0 || t > 0; i++) {
if (i == 0)
*--cp = '.';
*--cp = '0' + (char)(t%10);
t /= 10;
}
return cp;
}
/* exec with no args - args case is taken care of in comexec() */
int
c_exec(wp)
char ** wp;
{
int i;
/* make sure redirects stay in place */
if (e->savefd != NULL) {
for (i = 0; i < NUFILE; i++) {
if (e->savefd[i] > 0)
close(e->savefd[i]);
/*
* For ksh keep anything > 2 private,
* for sh, let them be (POSIX says what
* happens is unspecified and the bourne shell
* keeps them open).
*/
#ifdef KSH
if (i > 2 && e->savefd[i])
fd_clexec(i);
#endif /* KSH */
}
e->savefd = NULL;
}
return 0;
}
/* dummy function, special case in comexec() */
int
c_builtin(wp)
char ** wp;
{
return 0;
}
extern int c_test ARGS((char **wp)); /* in c_test.c */
extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */
/* A leading = means assignments before command are kept;
* a leading * means a POSIX special builtin;
* a leading + means a POSIX regular builtin
* (* and + should not be combined).
*/
const struct builtin shbuiltins [] = {
{"*=.", c_dot},
{"*=:", c_label},
{"[", c_test},
{"*=break", c_brkcont},
{"=builtin", c_builtin},
{"*=continue", c_brkcont},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
{"+false", c_label},
{"*=return", c_exitreturn},
{"*=set", c_set},
{"*=shift", c_shift},
{"=times", c_times},
{"*=trap", c_trap},
{"+=wait", c_wait},
{"+read", c_read},
{"test", c_test},
{"+true", c_label},
{"ulimit", c_ulimit},
{"+umask", c_umask},
{"*=unset", c_unset},
#ifdef OS2
/* In OS2, the first line of a file can be "extproc name", which
* tells the command interpreter (cmd.exe) to use name to execute
* the file. For this to be useful, ksh must ignore commands
* starting with extproc and this does the trick...
*/
{"extproc", c_label},
#endif /* OS2 */
{NULL, NULL}
};

666
bin/ksh/c_test.c Normal file
View file

@ -0,0 +1,666 @@
/* $NetBSD: c_test.c,v 1.6 2005/06/26 19:09:00 christos Exp $ */
/*
* test(1); version 7-like -- author Erik Baalbergen
* modified by Eric Gisin to be used as built-in.
* modified by Arnold Robbins to add SVR3 compatibility
* (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
* modified by Michael Rendell to add Korn's [[ .. ]] expressions.
* modified by J.T. Conklin to add POSIX compatibility.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_test.c,v 1.6 2005/06/26 19:09:00 christos Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h"
#include "c_test.h"
/* test(1) accepts the following grammar:
oexpr ::= aexpr | aexpr "-o" oexpr ;
aexpr ::= nexpr | nexpr "-a" aexpr ;
nexpr ::= primary | "!" nexpr ;
primary ::= unary-operator operand
| operand binary-operator operand
| operand
| "(" oexpr ")"
;
unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
"-L"|"-h"|"-S"|"-H";
binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef"|
"<"|">" # rules used for [[ .. ]] expressions
;
operand ::= <any thing>
*/
#define T_ERR_EXIT 2 /* POSIX says > 1 for errors */
struct t_op {
char op_text[4];
Test_op op_num;
};
static const struct t_op u_ops [] = {
{"-a", TO_FILAXST },
{"-b", TO_FILBDEV },
{"-c", TO_FILCDEV },
{"-d", TO_FILID },
{"-e", TO_FILEXST },
{"-f", TO_FILREG },
{"-G", TO_FILGID },
{"-g", TO_FILSETG },
{"-h", TO_FILSYM },
{"-H", TO_FILCDF },
{"-k", TO_FILSTCK },
{"-L", TO_FILSYM },
{"-n", TO_STNZE },
{"-O", TO_FILUID },
{"-o", TO_OPTION },
{"-p", TO_FILFIFO },
{"-r", TO_FILRD },
{"-s", TO_FILGZ },
{"-S", TO_FILSOCK },
{"-t", TO_FILTT },
{"-u", TO_FILSETU },
{"-w", TO_FILWR },
{"-x", TO_FILEX },
{"-z", TO_STZER },
{"", TO_NONOP }
};
static const struct t_op b_ops [] = {
{"=", TO_STEQL },
#ifdef KSH
{"==", TO_STEQL },
#endif /* KSH */
{"!=", TO_STNEQ },
{"<", TO_STLT },
{">", TO_STGT },
{"-eq", TO_INTEQ },
{"-ne", TO_INTNE },
{"-gt", TO_INTGT },
{"-ge", TO_INTGE },
{"-lt", TO_INTLT },
{"-le", TO_INTLE },
{"-ef", TO_FILEQ },
{"-nt", TO_FILNT },
{"-ot", TO_FILOT },
{"", TO_NONOP }
};
static int test_stat ARGS((const char *, struct stat *));
static int test_eaccess ARGS((const char *, int));
static int test_oexpr ARGS((Test_env *, int));
static int test_aexpr ARGS((Test_env *, int));
static int test_nexpr ARGS((Test_env *, int));
static int test_primary ARGS((Test_env *, int));
static int ptest_isa ARGS((Test_env *, Test_meta));
static const char *ptest_getopnd ARGS((Test_env *, Test_op, int));
static int ptest_eval ARGS((Test_env *, Test_op, const char *,
const char *, int));
static void ptest_error ARGS((Test_env *, int, const char *));
int
c_test(wp)
char **wp;
{
int argc;
int res;
Test_env te;
te.flags = 0;
te.isa = ptest_isa;
te.getopnd = ptest_getopnd;
te.eval = ptest_eval;
te.error = ptest_error;
for (argc = 0; wp[argc]; argc++)
;
if (strcmp(wp[0], "[") == 0) {
if (strcmp(wp[--argc], "]") != 0) {
bi_errorf("missing ]");
return T_ERR_EXIT;
}
}
te.pos.wp = wp + 1;
te.wp_end = wp + argc;
/*
* Handle the special cases from POSIX.2, section 4.62.4.
* Implementation of all the rules isn't necessary since
* our parser does the right thing for the omitted steps.
*/
if (argc <= 5) {
char **owp = wp;
int invert = 0;
Test_op op;
const char *opnd1, *opnd2;
while (--argc >= 0) {
if ((*te.isa)(&te, TM_END))
return !0;
if (argc == 3) {
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
if ((op = (Test_op) (*te.isa)(&te, TM_BINOP))) {
opnd2 = (*te.getopnd)(&te, op, 1);
res = (*te.eval)(&te, op, opnd1, opnd2,
1);
if (te.flags & TEF_ERROR)
return T_ERR_EXIT;
if (invert & 1)
res = !res;
return !res;
}
/* back up to opnd1 */
te.pos.wp--;
}
if (argc == 1) {
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
/* Historically, -t by itself test if fd 1
* is a file descriptor, but POSIX says its
* a string test...
*/
if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
break;
res = (*te.eval)(&te, TO_STNZE, opnd1,
(char *) 0, 1);
if (invert & 1)
res = !res;
return !res;
}
if ((*te.isa)(&te, TM_NOT)) {
invert++;
} else
break;
}
te.pos.wp = owp + 1;
}
return test_parse(&te);
}
/*
* Generic test routines.
*/
Test_op
test_isop(te, meta, s)
Test_env *te;
Test_meta meta;
const char *s;
{
char sc1;
const struct t_op *otab;
otab = meta == TM_UNOP ? u_ops : b_ops;
if (*s) {
sc1 = s[1];
for (; otab->op_text[0]; otab++)
if (sc1 == otab->op_text[1]
&& strcmp(s, otab->op_text) == 0
&& ((te->flags & TEF_DBRACKET)
|| (otab->op_num != TO_STLT
&& otab->op_num != TO_STGT)))
return otab->op_num;
}
return TO_NONOP;
}
int
test_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
int res;
int not;
struct stat b1, b2;
if (!do_eval)
return 0;
switch ((int) op) {
/*
* Unary Operators
*/
case TO_STNZE: /* -n */
return *opnd1 != '\0';
case TO_STZER: /* -z */
return *opnd1 == '\0';
case TO_OPTION: /* -o */
if ((not = *opnd1 == '!'))
opnd1++;
if ((res = option(opnd1)) < 0)
res = 0;
else {
res = Flag(res);
if (not)
res = !res;
}
return res;
case TO_FILRD: /* -r */
return test_eaccess(opnd1, R_OK) == 0;
case TO_FILWR: /* -w */
return test_eaccess(opnd1, W_OK) == 0;
case TO_FILEX: /* -x */
return test_eaccess(opnd1, X_OK) == 0;
case TO_FILAXST: /* -a */
return test_stat(opnd1, &b1) == 0;
case TO_FILEXST: /* -e */
/* at&t ksh does not appear to do the /dev/fd/ thing for
* this (unless the os itself handles it)
*/
return stat(opnd1, &b1) == 0;
case TO_FILREG: /* -r */
return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode);
case TO_FILID: /* -d */
return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode);
case TO_FILCDEV: /* -c */
#ifdef S_ISCHR
return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode);
#else
return 0;
#endif
case TO_FILBDEV: /* -b */
#ifdef S_ISBLK
return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode);
#else
return 0;
#endif
case TO_FILFIFO: /* -p */
#ifdef S_ISFIFO
return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode);
#else
return 0;
#endif
case TO_FILSYM: /* -h -L */
#ifdef S_ISLNK
return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode);
#else
return 0;
#endif
case TO_FILSOCK: /* -S */
#ifdef S_ISSOCK
return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode);
#else
return 0;
#endif
case TO_FILCDF:/* -H HP context dependent files (directories) */
#ifdef S_ISCDF
{
/* Append a + to filename and check to see if result is a
* setuid directory. CDF stuff in general is hookey, since
* it breaks for the following sequence: echo hi > foo+;
* mkdir foo; echo bye > foo/default; chmod u+s foo
* (foo+ refers to the file with hi in it, there is no way
* to get at the file with bye in it - please correct me if
* I'm wrong about this).
*/
int len = strlen(opnd1);
char *p = str_nsave(opnd1, len + 1, ATEMP);
p[len++] = '+';
p[len] = '\0';
return stat(p, &b1) == 0 && S_ISCDF(b1.st_mode);
}
#else
return 0;
#endif
case TO_FILSETU: /* -u */
#ifdef S_ISUID
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISUID) == S_ISUID;
#else
return 0;
#endif
case TO_FILSETG: /* -g */
#ifdef S_ISGID
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISGID) == S_ISGID;
#else
return 0;
#endif
case TO_FILSTCK: /* -k */
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISVTX) == S_ISVTX;
case TO_FILGZ: /* -s */
return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L;
case TO_FILTT: /* -t */
if (opnd1 && !bi_getn(opnd1, &res)) {
te->flags |= TEF_ERROR;
res = 0;
} else {
/* generate error if in FPOSIX mode? */
res = isatty(opnd1 ? res : 0);
}
return res;
case TO_FILUID: /* -O */
return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
case TO_FILGID: /* -G */
return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid();
/*
* Binary Operators
*/
case TO_STEQL: /* = */
if (te->flags & TEF_DBRACKET)
return gmatch(opnd1, opnd2, FALSE);
return strcmp(opnd1, opnd2) == 0;
case TO_STNEQ: /* != */
if (te->flags & TEF_DBRACKET)
return !gmatch(opnd1, opnd2, FALSE);
return strcmp(opnd1, opnd2) != 0;
case TO_STLT: /* < */
return strcmp(opnd1, opnd2) < 0;
case TO_STGT: /* > */
return strcmp(opnd1, opnd2) > 0;
case TO_INTEQ: /* -eq */
case TO_INTNE: /* -ne */
case TO_INTGE: /* -ge */
case TO_INTGT: /* -gt */
case TO_INTLE: /* -le */
case TO_INTLT: /* -lt */
{
long v1, v2;
if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR)
|| !evaluate(opnd2, &v2, KSH_RETURN_ERROR))
{
/* error already printed.. */
te->flags |= TEF_ERROR;
return 1;
}
switch ((int) op) {
case TO_INTEQ:
return v1 == v2;
case TO_INTNE:
return v1 != v2;
case TO_INTGE:
return v1 >= v2;
case TO_INTGT:
return v1 > v2;
case TO_INTLE:
return v1 <= v2;
case TO_INTLT:
return v1 < v2;
}
}
case TO_FILNT: /* -nt */
{
int s2;
/* ksh88/ksh93 succeed if file2 can't be stated
* (subtly different from `does not exist').
*/
return stat(opnd1, &b1) == 0
&& (((s2 = stat(opnd2, &b2)) == 0
&& b1.st_mtime > b2.st_mtime) || s2 < 0);
}
case TO_FILOT: /* -ot */
{
int s1;
/* ksh88/ksh93 succeed if file1 can't be stated
* (subtly different from `does not exist').
*/
return stat(opnd2, &b2) == 0
&& (((s1 = stat(opnd1, &b1)) == 0
&& b1.st_mtime < b2.st_mtime) || s1 < 0);
}
case TO_FILEQ: /* -ef */
return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
&& b1.st_dev == b2.st_dev
&& b1.st_ino == b2.st_ino;
}
(*te->error)(te, 0, "internal error: unknown op");
return 1;
}
/* Nasty kludge to handle Korn's bizarre /dev/fd hack */
static int
test_stat(pathx, statb)
const char *pathx;
struct stat *statb;
{
#if !defined(HAVE_DEV_FD)
int fd;
if (strncmp(pathx, "/dev/fd/", 8) == 0 && getn(pathx + 8, &fd))
return fstat(fd, statb);
#endif /* !HAVE_DEV_FD */
return stat(pathx, statb);
}
/* Routine to handle Korn's /dev/fd hack, and to deal with X_OK on
* non-directories when running as root.
*/
static int
test_eaccess(pathx, mode)
const char *pathx;
int mode;
{
int res;
#if !defined(HAVE_DEV_FD)
int fd;
/* Note: doesn't handle //dev/fd, etc.. (this is ok) */
if (strncmp(pathx, "/dev/fd/", 8) == 0 && getn(pathx + 8, &fd)) {
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) < 0
|| (mode & X_OK)
|| ((mode & W_OK) && (flags & O_ACCMODE) == O_RDONLY)
|| ((mode & R_OK) && (flags & O_ACCMODE) == O_WRONLY))
return -1;
return 0;
}
#endif /* !HAVE_DEV_FD */
res = eaccess(pathx, mode);
/*
* On most (all?) unixes, access() says everything is executable for
* root - avoid this on files by using stat().
*/
if (res == 0 && ksheuid == 0 && (mode & X_OK)) {
struct stat statb;
if (stat(pathx, &statb) < 0)
res = -1;
else if (S_ISDIR(statb.st_mode))
res = 0;
else
res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
? 0 : -1;
}
return res;
}
int
test_parse(te)
Test_env *te;
{
int res;
res = test_oexpr(te, 1);
if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
(*te->error)(te, 0, "unexpected operator/operand");
return (te->flags & TEF_ERROR) ? T_ERR_EXIT : !res;
}
static int
test_oexpr(te, do_eval)
Test_env *te;
int do_eval;
{
int res;
res = test_aexpr(te, do_eval);
if (res)
do_eval = 0;
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
return test_oexpr(te, do_eval) || res;
return res;
}
static int
test_aexpr(te, do_eval)
Test_env *te;
int do_eval;
{
int res;
res = test_nexpr(te, do_eval);
if (!res)
do_eval = 0;
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
return test_aexpr(te, do_eval) && res;
return res;
}
static int
test_nexpr(te, do_eval)
Test_env *te;
int do_eval;
{
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
return !test_nexpr(te, do_eval);
return test_primary(te, do_eval);
}
static int
test_primary(te, do_eval)
Test_env *te;
int do_eval;
{
const char *opnd1, *opnd2;
int res;
Test_op op;
if (te->flags & TEF_ERROR)
return 0;
if ((*te->isa)(te, TM_OPAREN)) {
res = test_oexpr(te, do_eval);
if (te->flags & TEF_ERROR)
return 0;
if (!(*te->isa)(te, TM_CPAREN)) {
(*te->error)(te, 0, "missing closing paren");
return 0;
}
return res;
}
if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
/* unary expression */
opnd1 = (*te->getopnd)(te, op, do_eval);
if (!opnd1) {
(*te->error)(te, -1, "missing argument");
return 0;
}
return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval);
}
opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
if (!opnd1) {
(*te->error)(te, 0, "expression expected");
return 0;
}
if ((op = (Test_op) (*te->isa)(te, TM_BINOP))) {
/* binary expression */
opnd2 = (*te->getopnd)(te, op, do_eval);
if (!opnd2) {
(*te->error)(te, -1, "missing second argument");
return 0;
}
return (*te->eval)(te, op, opnd1, opnd2, do_eval);
}
if (te->flags & TEF_DBRACKET) {
(*te->error)(te, -1, "missing expression operator");
return 0;
}
return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval);
}
/*
* Plain test (test and [ .. ]) specific routines.
*/
/* Test if the current token is a whatever. Accepts the current token if
* it is. Returns 0 if it is not, non-zero if it is (in the case of
* TM_UNOP and TM_BINOP, the returned value is a Test_op).
*/
static int
ptest_isa(te, meta)
Test_env *te;
Test_meta meta;
{
/* Order important - indexed by Test_meta values */
static const char *const tokens[] = {
"-o", "-a", "!", "(", ")"
};
int ret;
if (te->pos.wp >= te->wp_end)
return meta == TM_END;
if (meta == TM_UNOP || meta == TM_BINOP)
ret = (int) test_isop(te, meta, *te->pos.wp);
else if (meta == TM_END)
ret = 0;
else
ret = strcmp(*te->pos.wp, tokens[(int) meta]) == 0;
/* Accept the token? */
if (ret)
te->pos.wp++;
return ret;
}
static const char *
ptest_getopnd(te, op, do_eval)
Test_env *te;
Test_op op;
int do_eval;
{
if (te->pos.wp >= te->wp_end)
return op == TO_FILTT ? "1" : (const char *) 0;
return *te->pos.wp++;
}
static int
ptest_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
return test_eval(te, op, opnd1, opnd2, do_eval);
}
static void
ptest_error(te, offset, msg)
Test_env *te;
int offset;
const char *msg;
{
const char *op = te->pos.wp + offset >= te->wp_end ?
(const char *) 0 : te->pos.wp[offset];
te->flags |= TEF_ERROR;
if (op)
bi_errorf("%s: %s", op, msg);
else
bi_errorf("%s", msg);
}

55
bin/ksh/c_test.h Normal file
View file

@ -0,0 +1,55 @@
/* $NetBSD: c_test.h,v 1.3 2004/07/07 19:20:09 mycroft Exp $ */
/* Various types of operations. Keeping things grouped nicely
* (unary,binary) makes switch() statements more efficient.
*/
enum Test_op {
TO_NONOP = 0, /* non-operator */
/* unary operators */
TO_STNZE, TO_STZER, TO_OPTION,
TO_FILAXST,
TO_FILEXST,
TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID,
TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX,
/* binary operators */
TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT,
TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT
};
typedef enum Test_op Test_op;
/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */
enum Test_meta {
TM_OR, /* -o or || */
TM_AND, /* -a or && */
TM_NOT, /* ! */
TM_OPAREN, /* ( */
TM_CPAREN, /* ) */
TM_UNOP, /* unary operator */
TM_BINOP, /* binary operator */
TM_END /* end of input */
};
typedef enum Test_meta Test_meta;
#define TEF_ERROR BIT(0) /* set if we've hit an error */
#define TEF_DBRACKET BIT(1) /* set if [[ .. ]] test */
typedef struct test_env Test_env;
struct test_env {
int flags; /* TEF_* */
union {
char **wp; /* used by ptest_* */
XPtrV *av; /* used by dbtestp_* */
} pos;
char **wp_end; /* used by ptest_* */
int (*isa) ARGS((Test_env *te, Test_meta meta));
const char *(*getopnd) ARGS((Test_env *te, Test_op op, int do_eval));
int (*eval) ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
void (*error) ARGS((Test_env *te, int offset, const char *msg));
};
Test_op test_isop ARGS((Test_env *te, Test_meta meta, const char *s));
int test_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
int test_parse ARGS((Test_env *te));

285
bin/ksh/c_ulimit.c Normal file
View file

@ -0,0 +1,285 @@
/* $NetBSD: c_ulimit.c,v 1.10 2012/06/09 02:51:50 christos Exp $ */
/*
ulimit -- handle "ulimit" builtin
Reworked to use getrusage() and ulimit() at once (as needed on
some schizophrenic systems, eg, HP-UX 9.01), made argument parsing
conform to at&t ksh, added autoconf support. Michael Rendell, May, '94
Eric Gisin, September 1988
Adapted to PD KornShell. Removed AT&T code.
last edit: 06-Jun-1987 D A Gwyn
This started out as the BRL UNIX System V system call emulation
for 4.nBSD, and was later extended by Doug Kingston to handle
the extended 4.nBSD resource limits. It now includes the code
that was originally under case SYSULIMIT in source file "xec.c".
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_ulimit.c,v 1.10 2012/06/09 02:51:50 christos Exp $");
#endif
#include "sh.h"
#include "ksh_time.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif /* HAVE_SYS_RESOURCE_H */
#ifdef HAVE_ULIMIT_H
# include <ulimit.h>
#else /* HAVE_ULIMIT_H */
# ifdef HAVE_ULIMIT
extern long ulimit();
# endif /* HAVE_ULIMIT */
#endif /* HAVE_ULIMIT_H */
#define SOFT 0x1
#define HARD 0x2
#ifdef RLIM_INFINITY
# define KSH_RLIM_INFINITY RLIM_INFINITY
#else
# define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
#endif /* RLIM_INFINITY */
int
c_ulimit(wp)
char **wp;
{
static const struct limits {
const char *name;
enum { RLIMIT, ULIMIT } which;
int gcmd; /* get command */
int scmd; /* set command (or -1, if no set command) */
int factor; /* multiply by to get rlim_{cur,max} values */
char option;
} limits[] = {
/* Do not use options -H, -S or -a */
#ifdef RLIMIT_CPU
{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
#else /* RLIMIT_FSIZE */
# ifdef UL_GETFSIZE /* x/open */
{ "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
# else /* UL_GETFSIZE */
# ifdef UL_GFILLIM /* svr4/xenix */
{ "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
# else /* UL_GFILLIM */
{ "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
# endif /* UL_GFILLIM */
# endif /* UL_GETFSIZE */
#endif /* RLIMIT_FSIZE */
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_DATA
{ "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_RSS
{ "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
#else /* RLIMIT_NOFILE */
# ifdef UL_GDESLIM /* svr4/xenix */
{ "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
# endif /* UL_GDESLIM */
#endif /* RLIMIT_NOFILE */
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_NTHR
{ "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' },
#endif
#ifdef RLIMIT_VMEM
{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
#else /* RLIMIT_VMEM */
/* These are not quite right - really should subtract etext or something */
# ifdef UL_GMEMLIM /* svr4/xenix */
{ "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
# else /* UL_GMEMLIM */
# ifdef UL_GETBREAK /* osf/1 */
{ "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
# else /* UL_GETBREAK */
# ifdef UL_GETMAXBRK /* hpux */
{ "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
# endif /* UL_GETMAXBRK */
# endif /* UL_GETBREAK */
# endif /* UL_GMEMLIM */
#endif /* RLIMIT_VMEM */
#ifdef RLIMIT_SWAP
{ "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
#endif
#ifdef RLIMIT_SBSIZE
{ "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
#endif
{ .name = NULL }
};
static char options[3 + NELEM(limits)];
rlim_t UNINITIALIZED(val);
int how = SOFT | HARD;
const struct limits *l;
int set, all = 0;
int optc, what;
#ifdef HAVE_SETRLIMIT
struct rlimit limit;
#endif /* HAVE_SETRLIMIT */
if (!options[0]) {
/* build options string on first call - yuck */
char *p = options;
*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
for (l = limits; l->name; l++)
*p++ = l->option;
*p = '\0';
}
what = 'f';
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
switch (optc) {
case 'H':
how = HARD;
break;
case 'S':
how = SOFT;
break;
case 'a':
all = 1;
break;
case '?':
return 1;
default:
what = optc;
}
for (l = limits; l->name && l->option != what; l++)
;
if (!l->name) {
internal_errorf(0, "ulimit: %c", what);
return 1;
}
wp += builtin_opt.optind;
set = *wp ? 1 : 0;
if (set) {
if (all || wp[1]) {
bi_errorf("too many arguments");
return 1;
}
if (strcmp(wp[0], "unlimited") == 0)
val = KSH_RLIM_INFINITY;
else {
long rval;
if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
return 1;
/* Avoid problems caused by typos that
* evaluate misses due to evaluating unset
* parameters to 0...
* If this causes problems, will have to
* add parameter to evaluate() to control
* if unset params are 0 or an error.
*/
if (!rval && !digit(wp[0][0])) {
bi_errorf("invalid limit: %s", wp[0]);
return 1;
}
val = (u_long)rval * l->factor;
}
}
if (all) {
for (l = limits; l->name; l++) {
#ifdef HAVE_SETRLIMIT
if (l->which == RLIMIT) {
getrlimit(l->gcmd, &limit);
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
} else
#endif /* HAVE_SETRLIMIT */
#ifdef HAVE_ULIMIT
{
val = ulimit(l->gcmd, (rlim_t) 0);
}
#else /* HAVE_ULIMIT */
;
#endif /* HAVE_ULIMIT */
shprintf("%-20s ", l->name);
#ifdef RLIM_INFINITY
if (val == RLIM_INFINITY)
shprintf("unlimited\n");
else
#endif /* RLIM_INFINITY */
{
val /= l->factor;
shprintf("%ld\n", (long) val);
}
}
return 0;
}
#ifdef HAVE_SETRLIMIT
if (l->which == RLIMIT) {
getrlimit(l->gcmd, &limit);
if (set) {
if (how & SOFT)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (setrlimit(l->scmd, &limit) < 0) {
if (errno == EPERM)
bi_errorf("exceeds allowable limit");
else
bi_errorf("bad limit: %s",
strerror(errno));
return 1;
}
} else {
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
}
} else
#endif /* HAVE_SETRLIMIT */
#ifdef HAVE_ULIMIT
{
if (set) {
if (l->scmd == -1) {
bi_errorf("can't change limit");
return 1;
} else if (ulimit(l->scmd, val) < 0) {
bi_errorf("bad limit: %s", strerror(errno));
return 1;
}
} else
val = ulimit(l->gcmd, (rlim_t) 0);
}
#else /* HAVE_ULIMIT */
;
#endif /* HAVE_ULIMIT */
if (!set) {
#ifdef RLIM_INFINITY
if (val == RLIM_INFINITY)
shprintf("unlimited\n");
else
#endif /* RLIM_INFINITY */
{
val /= l->factor;
shprintf("%ld\n", (long) val);
}
}
return 0;
}

57
bin/ksh/conf-end.h Normal file
View file

@ -0,0 +1,57 @@
/* $NetBSD: conf-end.h,v 1.2 1997/01/12 19:11:43 tls Exp $ */
/*
* End of configuration stuff for PD ksh.
*
* RCSid: $NetBSD: conf-end.h,v 1.2 1997/01/12 19:11:43 tls Exp $
*/
#if defined(EMACS) || defined(VI)
# define EDIT
#else
# undef EDIT
#endif
/* Editing implies history */
#if defined(EDIT) && !defined(HISTORY)
# define HISTORY
#endif /* EDIT */
/*
* if you don't have mmap() you can't use Peter Collinson's history
* mechanism. If that is the case, then define EASY_HISTORY
*/
#if defined(HISTORY) && (!defined(COMPLEX_HISTORY) || !defined(HAVE_MMAP) || !defined(HAVE_FLOCK))
# undef COMPLEX_HISTORY
# define EASY_HISTORY /* sjg's trivial history file */
#endif
/* Can we safely catch sigchld and wait for processes? */
#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT3)) \
&& (defined(POSIX_SIGNALS) || defined(BSD42_SIGNALS))
# define JOB_SIGS
#endif
#if !defined(JOB_SIGS) || !(defined(POSIX_PGRP) || defined(BSD_PGRP))
# undef JOBS /* if no JOB_SIGS, no job control support */
#endif
/* pdksh assumes system calls return EINTR if a signal happened (this so
* the signal handler doesn't have to longjmp()). I don't know if this
* happens (or can be made to happen) with sigset() et. al. (the bsd41 signal
* routines), so, the autoconf stuff checks what they do and defines
* SIGNALS_DONT_INTERRUPT if signals don't interrupt read().
* If SIGNALS_DONT_INTERRUPT isn't defined and your compiler chokes on this,
* delete the hash in front of the error (and file a bug report).
*/
#ifdef SIGNALS_DONT_INTERRUPT
# error pdksh needs interruptable system calls.
#endif /* SIGNALS_DONT_INTERRUPT */
#ifdef HAVE_GCC_FUNC_ATTR
# define GCC_FUNC_ATTR(x) __attribute__((x))
# define GCC_FUNC_ATTR2(x,y) __attribute__((x,y))
#else
# define GCC_FUNC_ATTR(x)
# define GCC_FUNC_ATTR2(x,y)
#endif /* HAVE_GCC_FUNC_ATTR */

366
bin/ksh/config.h Normal file
View file

@ -0,0 +1,366 @@
/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader. */
/*
* This file, acconfig.h, which is a part of pdksh (the public domain ksh),
* is placed in the public domain. It comes with no licence, warranty
* or guarantee of any kind (i.e., at your own risk).
*/
#ifndef CONFIG_H
#define CONFIG_H
/* Define if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Define if the closedir function returns void instead of int. */
/* #undef CLOSEDIR_VOID */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */
/* Define if you have a working `mmap' system call. */
/* #undef HAVE_MMAP */
/* Define if your struct stat has st_rdev. */
#define HAVE_ST_RDEV 1
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define if you have <unistd.h>. */
#define HAVE_UNISTD_H 1
/* Define if on MINIX. */
#define _MINIX 1
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef mode_t */
/* Define to `long' if <sys/types.h> doesn't define. */
/* #undef off_t */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef pid_t */
/* Define if the system does not provide POSIX.1 features except
with this defined. */
#define _POSIX_1_SOURCE 2
/* Define if you need to in order for stat and other things to work. */
#define _POSIX_SOURCE 1
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define if `sys_siglist' is declared by <signal.h>. */
#define SYS_SIGLIST_DECLARED 1
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */
/* Define if the closedir function returns void instead of int. */
/* #undef VOID_CLOSEDIR */
/* Define if your kernal doesn't handle scripts starting with #! */
/* #undef SHARPBANG */
/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */
/* #undef DUP2_BROKEN */
/* Define as the return value of signal handlers (0 or ). */
#define RETSIGVAL
/* Define if you have posix signal routines (sigaction(), et. al.) */
#define POSIX_SIGNALS 1
/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */
/* #undef BSD42_SIGNALS */
/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */
/* #undef BSD41_SIGNALS */
/* Define if you have v7 signal routines (signal(), signal reset on delivery) */
/* #undef V7_SIGNALS */
/* Define to use the fake posix signal routines (sigact.[ch]) */
/* #undef USE_FAKE_SIGACT */
/* Define if signals don't interrupt read() */
/* #undef SIGNALS_DONT_INTERRUPT */
/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */
/* #undef BSD_PGRP */
/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */
/* #undef POSIX_PGRP */
/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */
/* #undef SYSV_PGRP */
/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */
#define NO_PGRP 1
/* Define to char if your compiler doesn't like the void keyword */
/* #undef void */
/* Define to nothing if compiler doesn't like the volatile keyword */
/* #undef volatile */
/* Define if C compiler groks function prototypes */
#define HAVE_PROTOTYPES 1
/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */
#define HAVE_GCC_FUNC_ATTR 1
/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */
/* #undef clock_t */
/* Define to the type of struct rlimit fields if the rlim_t type is missing */
/* #undef rlim_t */
/* Define if time() is declared in <time.h> */
#define TIME_DECLARED 1
/* Define to `unsigned' if <signal.h> doesn't define */
/* #undef sigset_t */
/* Define if sys_errlist[] and sys_nerr are in the C library */
#define HAVE_SYS_ERRLIST 1
/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */
#define SYS_ERRLIST_DECLARED 1
/* Define if sys_siglist[] is in the C library */
/* #undef HAVE_SYS_SIGLIST */
/* Define if you have a sane <termios.h> header file */
#define HAVE_TERMIOS_H 1
/* Define if you have a memset() function in your C library */
#define HAVE_MEMSET 1
/* Define if you have a memmove() function in your C library */
#define HAVE_MEMMOVE 1
/* Define if you have a bcopy() function in your C library */
/* #undef HAVE_BCOPY */
/* Define if you have a lstat() function in your C library */
#define HAVE_LSTAT 1
/* Define if you have a sane <termio.h> header file */
/* #undef HAVE_TERMIO_H */
/* Define if you don't have times() or if it always returns 0 */
/* #undef TIMES_BROKEN */
/* Define if opendir() will open non-directory files */
/* #undef OPENDIR_DOES_NONDIR */
/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */
/* #undef NEED_PGRP_SYNC */
/* Define if you arg running SCO unix */
/* #undef OS_SCO */
/* Define if you arg running ISC unix */
/* #undef OS_ISC */
/* Define if you arg running OS2 with the EMX library */
/* #undef OS2 */
/* Define if you have a POSIX.1 compatiable <sys/wait.h> */
#define POSIX_SYS_WAIT 1
/* Define if your OS maps references to /dev/fd/n to file descriptor n */
/* #undef HAVE_DEV_FD */
/* Define if your C library's getwd/getcwd function dumps core in unreadable
* directories. */
/* #undef HPUX_GETWD_BUG */
/* Default PATH (see comments in configure.in for more details) */
#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb"
/* Include ksh features? (see comments in configure.in for more details) */
#define KSH 1
/* Include emacs editing? (see comments in configure.in for more details) */
#define EMACS 1
/* Include vi editing? (see comments in configure.in for more details) */
#define VI 1
/* Include job control? (see comments in configure.in for more details) */
#define JOBS 1
/* Include brace-expansion? (see comments in configure.in for more details) */
#define BRACE_EXPAND 1
/* Include any history? (see comments in configure.in for more details) */
#define HISTORY 1
/* Include complex history? (see comments in configure.in for more details) */
/* #undef COMPLEX_HISTORY */
/* Strict POSIX behaviour? (see comments in configure.in for more details) */
/* #undef POSIXLY_CORRECT */
/* Specify default $ENV? (see comments in configure.in for more details) */
/* #undef DEFAULT_ENV */
/* Include shl(1) support? (see comments in configure.in for more details) */
/* #undef SWTCH */
/* Include game-of-life? (see comments in configure.in for more details) */
/* #undef SILLY */
/* The number of bytes in a int. */
#define SIZEOF_INT 4
/* The number of bytes in a long. */
#define SIZEOF_LONG 4
/* Define if you have the _setjmp function. */
/* #undef HAVE__SETJMP */
/* Define if you have the confstr function. */
/* #undef HAVE_CONFSTR */
/* Define if you have the dup2 function. */
#define HAVE_DUP2 1
/* Define if you have the flock function. */
#define HAVE_FLOCK 1
/* Define if you have the getcwd function. */
#define HAVE_GETCWD 1
/* Define if you have the getgroups function. */
/* #undef HAVE_GETGROUPS */
/* Define if you have the getpagesize function. */
#define HAVE_GETPAGESIZE 1
/* Define if you have the getrusage function. */
/* #undef HAVE_GETRUSAGE */
/* Define if you have the getwd function. */
/* #undef HAVE_GETWD */
/* Define if you have the killpg function. */
#define HAVE_KILLPG 1
/* Define if you have the nice function. */
#define HAVE_NICE 1
/* Define if you have the setrlimit function. */
/* #undef HAVE_SETRLIMIT */
/* Define if you have the sigsetjmp function. */
#define HAVE_SIGSETJMP 1
/* Define if you have the strcasecmp function. */
#define HAVE_STRCASECMP 1
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the strlcat function. */
#define HAVE_STRLCAT 1
/* Define if you have the strlcpy function. */
#define HAVE_STRLCPY 1
/* Define if you have the strstr function. */
#define HAVE_STRSTR 1
/* Define if you have the sysconf function. */
#define HAVE_SYSCONF 1
/* Define if you have the tcsetpgrp function. */
#define HAVE_TCSETPGRP 1
/* Define if you have the ulimit function. */
#define HAVE_ULIMIT 1
/* Define if you have the valloc function. */
#define HAVE_VALLOC 1
/* Define if you have the wait3 function. */
/* #undef HAVE_WAIT3 */
/* Define if you have the waitpid function. */
#define HAVE_WAITPID 1
/* Define if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if you have the <ndir.h> header file. */
/* #undef HAVE_NDIR_H */
/* Define if you have the <paths.h> header file. */
#define HAVE_PATHS_H 1
/* Define if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1
/* Define if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define if you have the <sys/dir.h> header file. */
/* #undef HAVE_SYS_DIR_H */
/* Define if you have the <sys/ndir.h> header file. */
/* #undef HAVE_SYS_NDIR_H */
/* Define if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define if you have the <sys/wait.h> header file. */
#define HAVE_SYS_WAIT_H 1
/* Define if you have the <ulimit.h> header file. */
#define HAVE_ULIMIT_H 1
/* Define if you have the <values.h> header file. */
/* #undef HAVE_VALUES_H */
/* Need to use a separate file to keep the configure script from commenting
* out the undefs....
*/
#include "conf-end.h"
#endif /* CONFIG_H */

1095
bin/ksh/edit.c Normal file

File diff suppressed because it is too large Load diff

87
bin/ksh/edit.h Normal file
View file

@ -0,0 +1,87 @@
/* $NetBSD: edit.h,v 1.3 1999/11/02 22:06:45 jdolecek Exp $ */
/* NAME:
* edit.h - globals for edit modes
*
* DESCRIPTION:
* This header defines various global edit objects.
*
* SEE ALSO:
*
*
* RCSid:
* $NetBSD: edit.h,v 1.3 1999/11/02 22:06:45 jdolecek Exp $
*
*/
/* some useful #defines */
#ifdef EXTERN
# define I__(i) = i
#else
# define I__(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
#define BEL 0x07
/* tty driver characters we are interested in */
typedef struct {
int erase;
int kill;
int werase;
int intr;
int quit;
int eof;
} X_chars;
EXTERN X_chars edchars;
/* x_fc_glob() flags */
#define XCF_COMMAND BIT(0) /* Do command completion */
#define XCF_FILE BIT(1) /* Do file completion */
#define XCF_FULLPATH BIT(2) /* command completion: store full path */
#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
/* edit.c */
int x_getc ARGS((void));
void x_flush ARGS((void));
void x_putc ARGS((int c));
void x_puts ARGS((const char *s));
bool_t x_mode ARGS((bool_t onoff));
int promptlen ARGS((const char *cp, const char **spp));
int x_do_comment ARGS((char *buf, int bsize, int *lenp));
void x_print_expansions ARGS((int nwords, char *const *words, int is_command));
int x_cf_glob ARGS((int flags, const char *buf, int buflen, int pos, int *startp,
int *endp, char ***wordsp, int *is_commandp));
int x_longest_prefix ARGS((int nwords, char *const *words));
int x_basename ARGS((const char *s, const char *se));
void x_free_words ARGS((int nwords, char **words));
int x_escape ARGS((const char *, size_t, int (*)(const char *s, size_t len)));
/* emacs.c */
int x_emacs ARGS((char *buf, size_t len));
void x_init_emacs ARGS((void));
void x_emacs_keys ARGS((X_chars *ec));
/* vi.c */
int x_vi ARGS((char *buf, size_t len));
#ifdef DEBUG
# define D__(x) x
#else
# define D__(x)
#endif
/* This lot goes at the END */
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef I__
/*
* Local Variables:
* version-control:t
* comment-column:40
* End:
*/

47
bin/ksh/emacs-gen.sh Executable file
View file

@ -0,0 +1,47 @@
#!/bin/sh
# $NetBSD: emacs-gen.sh,v 1.4 2008/10/25 22:18:15 apb Exp $
: ${AWK:=awk}
: ${SED:=sed}
case $# in
1) file=$1;;
*)
echo "$0: Usage: $0 path-to-emacs.c" 1>&2
exit 1
esac;
if [ ! -r "$file" ] ;then
echo "$0: can't read $file" 1>&2
exit 1
fi
cat << E_O_F || exit 1
/*
* NOTE: THIS FILE WAS GENERATED AUTOMATICALLY FROM $file
*
* DO NOT BOTHER EDITING THIS FILE
*/
E_O_F
# Pass 1: print out lines before @START-FUNC-TAB@
# and generate defines and function declarations,
${SED} -e '1,/@START-FUNC-TAB@/d' -e '/@END-FUNC-TAB@/,$d' < $file |
${AWK} 'BEGIN { nfunc = 0; }
/^[ ]*#/ {
print $0;
next;
}
{
fname = $2;
c = substr(fname, length(fname), 1);
if (c == ",")
fname = substr(fname, 1, length(fname) - 1);
if (fname != "0") {
printf "#define XFUNC_%s %d\n", substr(fname, 3, length(fname) - 2), nfunc;
printf "static int %s ARGS((int c));\n", fname;
nfunc++;
}
}' || exit 1
exit 0

2221
bin/ksh/emacs.c Normal file

File diff suppressed because it is too large Load diff

1405
bin/ksh/eval.c Normal file

File diff suppressed because it is too large Load diff

1749
bin/ksh/exec.c Normal file

File diff suppressed because it is too large Load diff

108
bin/ksh/expand.h Normal file
View file

@ -0,0 +1,108 @@
/* $NetBSD: expand.h,v 1.4 2001/07/26 15:05:07 wiz Exp $ */
/*
* Expanding strings
*/
/* $Id: expand.h,v 1.4 2001/07/26 15:05:07 wiz Exp $ */
#define X_EXTRA 8 /* this many extra bytes in X string */
#if 0 /* Usage */
XString xs;
char *xp;
Xinit(xs, xp, 128, ATEMP); /* allocate initial string */
while ((c = generate()) {
Xcheck(xs, xp); /* expand string if necessary */
Xput(xs, xp, c); /* add character */
}
return Xclose(xs, xp); /* resize string */
/*
* NOTE:
* The Xcheck and Xinit macros have a magic + X_EXTRA in the lengths.
* This is so that you can put up to X_EXTRA characters in a XString
* before calling Xcheck. (See yylex in lex.c)
*/
#endif /* 0 */
typedef struct XString {
char *end, *beg; /* end, begin of string */
size_t len; /* length */
Area *areap; /* area to allocate/free from */
} XString;
typedef char * XStringP;
/* initialize expandable string */
#define Xinit(xs, xp, length, area) do { \
(xs).len = length; \
(xs).areap = (area); \
(xs).beg = alloc((xs).len + X_EXTRA, (xs).areap); \
(xs).end = (xs).beg + (xs).len; \
xp = (xs).beg; \
} while (0)
/* stuff char into string */
#define Xput(xs, xp, c) (*xp++ = (c))
/* check if there are at least n bytes left */
#define XcheckN(xs, xp, n) do { \
int more = ((xp) + (n)) - (xs).end; \
if (more > 0) \
xp = Xcheck_grow_(&xs, xp, more); \
} while (0)
/* check for overflow, expand string */
#define Xcheck(xs, xp) XcheckN(xs, xp, 1)
/* free string */
#define Xfree(xs, xp) afree((void*) (xs).beg, (xs).areap)
/* close, return string */
#define Xclose(xs, xp) (char*) aresize((void*)(xs).beg, \
(size_t)((xp) - (xs).beg), (xs).areap)
/* begin of string */
#define Xstring(xs, xp) ((xs).beg)
#define Xnleft(xs, xp) ((xs).end - (xp)) /* may be less than 0 */
#define Xlength(xs, xp) ((xp) - (xs).beg)
#define Xsize(xs, xp) ((xs).end - (xs).beg)
#define Xsavepos(xs, xp) ((xp) - (xs).beg)
#define Xrestpos(xs, xp, n) ((xs).beg + (n))
char * Xcheck_grow_ ARGS((XString *xsp, char *xp, int more));
/*
* expandable vector of generic pointers
*/
typedef struct XPtrV {
void **cur; /* next avail pointer */
void **beg, **end; /* begin, end of vector */
} XPtrV;
#define XPinit(x, n) do { \
register void **vp__; \
vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \
(x).cur = (x).beg = vp__; \
(x).end = vp__ + n; \
} while (0)
#define XPput(x, p) do { \
if ((x).cur >= (x).end) { \
int n = XPsize(x); \
(x).beg = (void**) aresize((void*) (x).beg, \
sizeofN(void*, n*2), ATEMP); \
(x).cur = (x).beg + n; \
(x).end = (x).cur + n; \
} \
*(x).cur++ = (p); \
} while (0)
#define XPptrv(x) ((x).beg)
#define XPsize(x) ((x).cur - (x).beg)
#define XPclose(x) (void**) aresize((void*)(x).beg, \
sizeofN(void*, XPsize(x)), ATEMP)
#define XPfree(x) afree((void*) (x).beg, ATEMP)

613
bin/ksh/expr.c Normal file
View file

@ -0,0 +1,613 @@
/* $NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $ */
/*
* Korn expression evaluation
*/
/*
* todo: better error handling: if in builtin, should be builtin error, etc.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $");
#endif
#include "sh.h"
#include <ctype.h>
/* The order of these enums is constrained by the order of opinfo[] */
enum token {
/* some (long) unary operators */
O_PLUSPLUS = 0, O_MINUSMINUS,
/* binary operators */
O_EQ, O_NE,
/* assignments are assumed to be in range O_ASN .. O_BORASN */
O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
O_LSHIFT, O_RSHIFT,
O_LE, O_GE, O_LT, O_GT,
O_LAND,
O_LOR,
O_TIMES, O_DIV, O_MOD,
O_PLUS, O_MINUS,
O_BAND,
O_BXOR,
O_BOR,
O_TERN,
O_COMMA,
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
O_BNOT, O_LNOT,
/* misc */
OPEN_PAREN, CLOSE_PAREN, CTERN,
/* things that don't appear in the opinfo[] table */
VAR, LIT, END, BAD
};
#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
enum prec {
P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */
P_MULT, /* * / % */
P_ADD, /* + - */
P_SHIFT, /* << >> */
P_RELATION, /* < <= > >= */
P_EQUALITY, /* == != */
P_BAND, /* & */
P_BXOR, /* ^ */
P_BOR, /* | */
P_LAND, /* && */
P_LOR, /* || */
P_TERN, /* ?: */
P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */
P_COMMA /* , */
};
#define MAX_PREC P_COMMA
struct opinfo {
char name[4];
int len; /* name length */
enum prec prec; /* precedence: lower is higher */
};
/* Tokens in this table must be ordered so the longest are first
* (eg, += before +). If you change something, change the order
* of enum token too.
*/
static const struct opinfo opinfo[] = {
{ "++", 2, P_PRIMARY }, /* before + */
{ "--", 2, P_PRIMARY }, /* before - */
{ "==", 2, P_EQUALITY }, /* before = */
{ "!=", 2, P_EQUALITY }, /* before ! */
{ "=", 1, P_ASSIGN }, /* keep assigns in a block */
{ "*=", 2, P_ASSIGN },
{ "/=", 2, P_ASSIGN },
{ "%=", 2, P_ASSIGN },
{ "+=", 2, P_ASSIGN },
{ "-=", 2, P_ASSIGN },
{ "<<=", 3, P_ASSIGN },
{ ">>=", 3, P_ASSIGN },
{ "&=", 2, P_ASSIGN },
{ "^=", 2, P_ASSIGN },
{ "|=", 2, P_ASSIGN },
{ "<<", 2, P_SHIFT },
{ ">>", 2, P_SHIFT },
{ "<=", 2, P_RELATION },
{ ">=", 2, P_RELATION },
{ "<", 1, P_RELATION },
{ ">", 1, P_RELATION },
{ "&&", 2, P_LAND },
{ "||", 2, P_LOR },
{ "*", 1, P_MULT },
{ "/", 1, P_MULT },
{ "%", 1, P_MULT },
{ "+", 1, P_ADD },
{ "-", 1, P_ADD },
{ "&", 1, P_BAND },
{ "^", 1, P_BXOR },
{ "|", 1, P_BOR },
{ "?", 1, P_TERN },
{ ",", 1, P_COMMA },
{ "~", 1, P_PRIMARY },
{ "!", 1, P_PRIMARY },
{ "(", 1, P_PRIMARY },
{ ")", 1, P_PRIMARY },
{ ":", 1, P_PRIMARY },
{ "", 0, P_PRIMARY } /* end of table */
};
typedef struct expr_state Expr_state;
struct expr_state {
const char *expression; /* expression being evaluated */
const char *tokp; /* lexical position */
enum token tok; /* token from token() */
int noassign; /* don't do assigns (for ?:,&&,||) */
struct tbl *val; /* value from token() */
struct tbl *evaling; /* variable that is being recursively
* expanded (EXPRINEVAL flag set)
*/
};
enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
ET_LVALUE, ET_RDONLY, ET_STR };
static void evalerr ARGS((Expr_state *es, enum error_type type,
const char *str)) GCC_FUNC_ATTR(noreturn);
static struct tbl *evalexpr ARGS((Expr_state *es, enum prec prec));
static void token ARGS((Expr_state *es));
static struct tbl *do_ppmm ARGS((Expr_state *es, enum token op,
struct tbl *vasn, bool_t is_prefix));
static void assign_check ARGS((Expr_state *es, enum token op,
struct tbl *vasn));
static struct tbl *tempvar ARGS((void));
static struct tbl *intvar ARGS((Expr_state *es, struct tbl *vp));
/*
* parse and evaluate expression
*/
int
evaluate(expr, rval, error_ok)
const char *expr;
long *rval;
int error_ok;
{
struct tbl v;
int ret;
v.flag = DEFINED|INTEGER;
v.type = 0;
ret = v_evaluate(&v, expr, error_ok);
*rval = v.val.i;
return ret;
}
/*
* parse and evaluate expression, storing result in vp.
*/
int
v_evaluate(vp, expr, error_ok)
struct tbl *vp;
const char *expr;
volatile int error_ok;
{
struct tbl *v;
Expr_state curstate;
Expr_state * const es = &curstate;
int i;
/* save state to allow recursive calls */
curstate.expression = curstate.tokp = expr;
curstate.noassign = 0;
curstate.evaling = (struct tbl *) 0;
newenv(E_ERRH);
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
/* Clear EXPRINEVAL in of any variables we were playing with */
if (curstate.evaling)
curstate.evaling->flag &= ~EXPRINEVAL;
quitenv();
if (i == LAEXPR) {
if (error_ok == KSH_RETURN_ERROR)
return 0;
errorf("%s", null);
}
unwind(i);
/*NOTREACHED*/
}
token(es);
#if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
if (es->tok == END) {
es->tok = LIT;
es->val = tempvar();
}
#endif /* 0 */
v = intvar(es, evalexpr(es, MAX_PREC));
if (es->tok != END)
evalerr(es, ET_UNEXPECTED, (char *) 0);
if (vp->flag & INTEGER)
setint_v(vp, v);
else
/* can fail if readonly */
setstr(vp, str_val(v), error_ok);
quitenv();
return 1;
}
static void
evalerr(es, type, str)
Expr_state *es;
enum error_type type;
const char *str;
{
char tbuf[2];
const char *s;
switch (type) {
case ET_UNEXPECTED:
switch (es->tok) {
case VAR:
s = es->val->name;
break;
case LIT:
s = str_val(es->val);
break;
case END:
s = "end of expression";
break;
case BAD:
tbuf[0] = *es->tokp;
tbuf[1] = '\0';
s = tbuf;
break;
default:
s = opinfo[(int)es->tok].name;
}
warningf(TRUE, "%s: unexpected `%s'", es->expression, s);
break;
case ET_BADLIT:
warningf(TRUE, "%s: bad number `%s'", es->expression, str);
break;
case ET_RECURSIVE:
warningf(TRUE, "%s: expression recurses on parameter `%s'",
es->expression, str);
break;
case ET_LVALUE:
warningf(TRUE, "%s: %s requires lvalue",
es->expression, str);
break;
case ET_RDONLY:
warningf(TRUE, "%s: %s applied to read only variable",
es->expression, str);
break;
default: /* keep gcc happy */
case ET_STR:
warningf(TRUE, "%s: %s", es->expression, str);
break;
}
unwind(LAEXPR);
}
static struct tbl *
evalexpr(es, prec)
Expr_state *es;
enum prec prec;
{
struct tbl *vl, UNINITIALIZED(*vr), *vasn;
enum token op;
long UNINITIALIZED(res);
if (prec == P_PRIMARY) {
op = es->tok;
if (op == O_BNOT || op == O_LNOT || op == O_MINUS
|| op == O_PLUS)
{
token(es);
vl = intvar(es, evalexpr(es, P_PRIMARY));
if (op == O_BNOT)
vl->val.i = ~vl->val.i;
else if (op == O_LNOT)
vl->val.i = !vl->val.i;
else if (op == O_MINUS)
vl->val.i = -vl->val.i;
/* op == O_PLUS is a no-op */
} else if (op == OPEN_PAREN) {
token(es);
vl = evalexpr(es, MAX_PREC);
if (es->tok != CLOSE_PAREN)
evalerr(es, ET_STR, "missing )");
token(es);
} else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
token(es);
vl = do_ppmm(es, op, es->val, TRUE);
token(es);
} else if (op == VAR || op == LIT) {
vl = es->val;
token(es);
} else {
evalerr(es, ET_UNEXPECTED, (char *) 0);
/*NOTREACHED*/
}
if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
vl = do_ppmm(es, es->tok, vl, FALSE);
token(es);
}
return vl;
}
vl = evalexpr(es, ((int) prec) - 1);
for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
op = es->tok)
{
token(es);
vasn = vl;
if (op != O_ASN) /* vl may not have a value yet */
vl = intvar(es, vl);
if (IS_ASSIGNOP(op)) {
assign_check(es, op, vasn);
vr = intvar(es, evalexpr(es, P_ASSIGN));
} else if (op != O_TERN && op != O_LAND && op != O_LOR)
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
if ((op == O_DIV || op == O_MOD || op == O_DIVASN
|| op == O_MODASN) && vr->val.i == 0)
{
if (es->noassign)
vr->val.i = 1;
else
evalerr(es, ET_STR, "zero divisor");
}
switch ((int) op) {
case O_TIMES:
case O_TIMESASN:
res = vl->val.i * vr->val.i;
break;
case O_DIV:
case O_DIVASN:
res = vl->val.i / vr->val.i;
break;
case O_MOD:
case O_MODASN:
res = vl->val.i % vr->val.i;
break;
case O_PLUS:
case O_PLUSASN:
res = vl->val.i + vr->val.i;
break;
case O_MINUS:
case O_MINUSASN:
res = vl->val.i - vr->val.i;
break;
case O_LSHIFT:
case O_LSHIFTASN:
res = vl->val.i << vr->val.i;
break;
case O_RSHIFT:
case O_RSHIFTASN:
res = vl->val.i >> vr->val.i;
break;
case O_LT:
res = vl->val.i < vr->val.i;
break;
case O_LE:
res = vl->val.i <= vr->val.i;
break;
case O_GT:
res = vl->val.i > vr->val.i;
break;
case O_GE:
res = vl->val.i >= vr->val.i;
break;
case O_EQ:
res = vl->val.i == vr->val.i;
break;
case O_NE:
res = vl->val.i != vr->val.i;
break;
case O_BAND:
case O_BANDASN:
res = vl->val.i & vr->val.i;
break;
case O_BXOR:
case O_BXORASN:
res = vl->val.i ^ vr->val.i;
break;
case O_BOR:
case O_BORASN:
res = vl->val.i | vr->val.i;
break;
case O_LAND:
if (!vl->val.i)
es->noassign++;
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
res = vl->val.i && vr->val.i;
if (!vl->val.i)
es->noassign--;
break;
case O_LOR:
if (vl->val.i)
es->noassign++;
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
res = vl->val.i || vr->val.i;
if (vl->val.i)
es->noassign--;
break;
case O_TERN:
{
int ex = vl->val.i != 0;
if (!ex)
es->noassign++;
vl = evalexpr(es, MAX_PREC);
if (!ex)
es->noassign--;
if (es->tok != CTERN)
evalerr(es, ET_STR, "missing :");
token(es);
if (ex)
es->noassign++;
vr = evalexpr(es, P_TERN);
if (ex)
es->noassign--;
vl = ex ? vl : vr;
}
break;
case O_ASN:
res = vr->val.i;
break;
case O_COMMA:
res = vr->val.i;
break;
}
if (IS_ASSIGNOP(op)) {
vr->val.i = res;
if (vasn->flag & INTEGER)
setint_v(vasn, vr);
else
setint(vasn, res);
vl = vr;
} else if (op != O_TERN)
vl->val.i = res;
}
return vl;
}
static void
token(es)
Expr_state *es;
{
const char *cp;
int c;
char *tvar;
/* skip white space */
for (cp = es->tokp; (c = *cp), isspace((unsigned char)c); cp++)
;
es->tokp = cp;
if (c == '\0')
es->tok = END;
else if (letter(c)) {
for (; letnum(c); c = *cp)
cp++;
if (c == '[') {
int len;
len = array_ref_len(cp);
if (len == 0)
evalerr(es, ET_STR, "missing ]");
cp += len;
}
#ifdef KSH
else if (c == '(' /*)*/ ) {
/* todo: add math functions (all take single argument):
* abs acos asin atan cos cosh exp int log sin sinh sqrt
* tan tanh
*/
;
}
#endif /* KSH */
if (es->noassign) {
es->val = tempvar();
es->val->flag |= EXPRLVALUE;
} else {
tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
es->val = global(tvar);
afree(tvar, ATEMP);
}
es->tok = VAR;
} else if (digit(c)) {
for (; c != '_' && (letnum(c) || c == '#'); c = *cp++)
;
tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
es->val = tempvar();
es->val->flag &= ~INTEGER;
es->val->type = 0;
es->val->val.s = tvar;
if (setint_v(es->val, es->val) == NULL)
evalerr(es, ET_BADLIT, tvar);
afree(tvar, ATEMP);
es->tok = LIT;
} else {
int i, n0;
for (i = 0; (n0 = opinfo[i].name[0]); i++)
if (c == n0
&& strncmp(cp, opinfo[i].name, opinfo[i].len) == 0)
{
es->tok = (enum token) i;
cp += opinfo[i].len;
break;
}
if (!n0)
es->tok = BAD;
}
es->tokp = cp;
}
/* Do a ++ or -- operation */
static struct tbl *
do_ppmm(es, op, vasn, is_prefix)
Expr_state *es;
enum token op;
struct tbl *vasn;
bool_t is_prefix;
{
struct tbl *vl;
int oval;
assign_check(es, op, vasn);
vl = intvar(es, vasn);
oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
if (vasn->flag & INTEGER)
setint_v(vasn, vl);
else
setint(vasn, vl->val.i);
if (!is_prefix) /* undo the inc/dec */
vl->val.i = oval;
return vl;
}
static void
assign_check(es, op, vasn)
Expr_state *es;
enum token op;
struct tbl *vasn;
{
if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
evalerr(es, ET_LVALUE, opinfo[(int) op].name);
else if (vasn->flag & RDONLY)
evalerr(es, ET_RDONLY, opinfo[(int) op].name);
}
static struct tbl *
tempvar()
{
register struct tbl *vp;
vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
vp->flag = ISSET|INTEGER;
vp->type = 0;
vp->areap = ATEMP;
vp->val.i = 0;
vp->name[0] = '\0';
return vp;
}
/* cast (string) variable to temporary integer variable */
static struct tbl *
intvar(es, vp)
Expr_state *es;
struct tbl *vp;
{
struct tbl *vq;
/* try to avoid replacing a temp var with another temp var */
if (vp->name[0] == '\0'
&& (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
return vp;
vq = tempvar();
if (setint_v(vq, vp) == NULL) {
if (vp->flag & EXPRINEVAL)
evalerr(es, ET_RECURSIVE, vp->name);
es->evaling = vp;
vp->flag |= EXPRINEVAL;
v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR);
vp->flag &= ~EXPRINEVAL;
es->evaling = (struct tbl *) 0;
}
return vq;
}

1229
bin/ksh/history.c Normal file

File diff suppressed because it is too large Load diff

568
bin/ksh/io.c Normal file
View file

@ -0,0 +1,568 @@
/* $NetBSD: io.c,v 1.9 2005/06/26 19:09:00 christos Exp $ */
/*
* shell buffered IO and formatted output
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: io.c,v 1.9 2005/06/26 19:09:00 christos Exp $");
#endif
#include <ctype.h>
#include "sh.h"
#include "ksh_stat.h"
static int initio_done;
/*
* formatted output functions
*/
/* A shell error occurred (eg, syntax error, etc.) */
void
#ifdef HAVE_PROTOTYPES
errorf(const char *fmt, ...)
#else
errorf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
shl_stdout_ok = 0; /* debugging: note that stdout not valid */
exstat = 1;
if (*fmt) {
error_prefix(TRUE);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
unwind(LERROR);
}
/* like errorf(), but no unwind is done */
void
#ifdef HAVE_PROTOTYPES
warningf(int fileline, const char *fmt, ...)
#else
warningf(fileline, fmt, va_alist)
int fileline;
const char *fmt;
va_dcl
#endif
{
va_list va;
error_prefix(fileline);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
}
/* Used by built-in utilities to prefix shell and utility name to message
* (also unwinds environments for special builtins).
*/
void
#ifdef HAVE_PROTOTYPES
bi_errorf(const char *fmt, ...)
#else
bi_errorf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
shl_stdout_ok = 0; /* debugging: note that stdout not valid */
exstat = 1;
if (*fmt) {
error_prefix(TRUE);
/* not set when main() calls parse_args() */
if (builtin_argv0)
shf_fprintf(shl_out, "%s: ", builtin_argv0);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
/* POSIX special builtins and ksh special builtins cause
* non-interactive shells to exit.
* XXX odd use of KEEPASN; also may not want LERROR here
*/
if ((builtin_flag & SPEC_BI)
|| (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
{
builtin_argv0 = (char *) 0;
unwind(LERROR);
}
}
/* Called when something that shouldn't happen does */
void
#ifdef HAVE_PROTOTYPES
internal_errorf(int jump, const char *fmt, ...)
#else
internal_errorf(jump, fmt, va_alist)
int jump;
const char *fmt;
va_dcl
#endif
{
va_list va;
error_prefix(TRUE);
shf_fprintf(shl_out, "internal error: ");
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
if (jump)
unwind(LERROR);
}
/* used by error reporting functions to print "ksh: .kshrc[25]: " */
void
error_prefix(fileline)
int fileline;
{
/* Avoid foo: foo[2]: ... */
if (!fileline || !source || !source->file
|| strcmp(source->file, kshname) != 0)
shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
if (fileline && source && source->file != NULL) {
shf_fprintf(shl_out, "%s[%d]: ", source->file,
source->errline > 0 ? source->errline : source->line);
source->errline = 0;
}
}
/* printf to shl_out (stderr) with flush */
void
#ifdef HAVE_PROTOTYPES
shellf(const char *fmt, ...)
#else
shellf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
if (!initio_done) /* shl_out may not be set up yet... */
return;
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_flush(shl_out);
}
/* printf to shl_stdout (stdout) */
void
#ifdef HAVE_PROTOTYPES
shprintf(const char *fmt, ...)
#else
shprintf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
if (!shl_stdout_ok)
internal_errorf(1, "shl_stdout not valid");
SH_VA_START(va, fmt);
shf_vfprintf(shl_stdout, fmt, va);
va_end(va);
}
#ifdef KSH_DEBUG
static struct shf *kshdebug_shf;
void
kshdebug_init_()
{
if (kshdebug_shf)
shf_close(kshdebug_shf);
kshdebug_shf = shf_open("/tmp/ksh-debug.log",
O_WRONLY|O_APPEND|O_CREAT, 0600,
SHF_WR|SHF_MAPHI);
if (kshdebug_shf) {
shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
shf_flush(kshdebug_shf);
}
}
/* print to debugging log */
void
# ifdef HAVE_PROTOTYPES
kshdebug_printf_(const char *fmt, ...)
# else
kshdebug_printf_(fmt, va_alist)
const char *fmt;
va_dcl
# endif
{
va_list va;
if (!kshdebug_shf)
return;
SH_VA_START(va, fmt);
shf_fprintf(kshdebug_shf, "[%d] ", getpid());
shf_vfprintf(kshdebug_shf, fmt, va);
va_end(va);
shf_flush(kshdebug_shf);
}
void
kshdebug_dump_(str, mem, nbytes)
const char *str;
const void *mem;
int nbytes;
{
int i, j;
int nprow = 16;
if (!kshdebug_shf)
return;
shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
for (i = 0; i < nbytes; i += nprow) {
char c = '\t';
for (j = 0; j < nprow && i + j < nbytes; j++) {
shf_fprintf(kshdebug_shf, "%c%02x",
c, ((const unsigned char *) mem)[i + j]);
c = ' ';
}
shf_fprintf(kshdebug_shf, "\n");
}
shf_flush(kshdebug_shf);
}
#endif /* KSH_DEBUG */
/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
int
can_seek(fd)
int fd;
{
struct stat statb;
return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
SHF_UNBUF : 0;
}
struct shf shf_iob[3];
void
initio()
{
shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
shf_fdopen(2, SHF_WR, shl_out);
shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
initio_done = 1;
kshdebug_init();
}
/* A dup2() with error checking */
int
ksh_dup2(ofd, nfd, errok)
int ofd;
int nfd;
int errok;
{
int ret = dup2(ofd, nfd);
if (ret < 0 && errno != EBADF && !errok)
errorf("too many files open in shell");
#ifdef DUP2_BROKEN
/* Ultrix systems like to preserve the close-on-exec flag */
if (ret >= 0)
(void) fcntl(nfd, F_SETFD, 0);
#endif /* DUP2_BROKEN */
return ret;
}
/*
* move fd from user space (0<=fd<10) to shell space (fd>=10),
* set close-on-exec flag.
*/
int
savefd(fd, noclose)
int fd;
int noclose;
{
int nfd;
if (fd < FDBASE) {
nfd = ksh_dupbase(fd, FDBASE);
if (nfd < 0) {
if (errno == EBADF)
return -1;
else
errorf("too many files open in shell");
}
if (!noclose)
close(fd);
} else
nfd = fd;
fd_clexec(nfd);
return nfd;
}
void
restfd(fd, ofd)
int fd, ofd;
{
if (fd == 2)
shf_flush(&shf_iob[fd]);
if (ofd < 0) /* original fd closed */
close(fd);
else if (fd != ofd) {
ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
close(ofd);
}
}
void
openpipe(pv)
register int *pv;
{
if (pipe(pv) < 0)
errorf("can't create pipe - try again");
pv[0] = savefd(pv[0], 0);
pv[1] = savefd(pv[1], 0);
}
void
closepipe(pv)
register int *pv;
{
close(pv[0]);
close(pv[1]);
}
/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
* a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
*/
int
check_fd(name, mode, emsgp)
char *name;
int mode;
const char **emsgp;
{
int fd, fl;
if (isdigit((unsigned char)name[0]) && !name[1]) {
fd = name[0] - '0';
if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
if (emsgp)
*emsgp = "bad file descriptor";
return -1;
}
fl &= O_ACCMODE;
#ifdef OS2
if (mode == W_OK ) {
if (setmode(fd, O_TEXT) == -1) {
if (emsgp)
*emsgp = "couldn't set write mode";
return -1;
}
} else if (mode == R_OK)
if (setmode(fd, O_BINARY) == -1) {
if (emsgp)
*emsgp = "couldn't set read mode";
return -1;
}
#else /* OS2 */
/* X_OK is a kludge to disable this check for dups (x<&1):
* historical shells never did this check (XXX don't know what
* posix has to say).
*/
if (!(mode & X_OK) && fl != O_RDWR
&& (((mode & R_OK) && fl != O_RDONLY)
|| ((mode & W_OK) && fl != O_WRONLY)))
{
if (emsgp)
*emsgp = (fl == O_WRONLY) ?
"fd not open for reading"
: "fd not open for writing";
return -1;
}
#endif /* OS2 */
return fd;
}
#ifdef KSH
else if (name[0] == 'p' && !name[1])
return coproc_getfd(mode, emsgp);
#endif /* KSH */
if (emsgp)
*emsgp = "illegal file descriptor name";
return -1;
}
#ifdef KSH
/* Called once from main */
void
coproc_init()
{
coproc.read = coproc.readw = coproc.write = -1;
coproc.njobs = 0;
coproc.id = 0;
}
/* Called by c_read() when eof is read - close fd if it is the co-process fd */
void
coproc_read_close(fd)
int fd;
{
if (coproc.read >= 0 && fd == coproc.read) {
coproc_readw_close(fd);
close(coproc.read);
coproc.read = -1;
}
}
/* Called by c_read() and by iosetup() to close the other side of the
* read pipe, so reads will actually terminate.
*/
void
coproc_readw_close(fd)
int fd;
{
if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
close(coproc.readw);
coproc.readw = -1;
}
}
/* Called by c_print when a write to a fd fails with EPIPE and by iosetup
* when co-process input is dup'd
*/
void
coproc_write_close(fd)
int fd;
{
if (coproc.write >= 0 && fd == coproc.write) {
close(coproc.write);
coproc.write = -1;
}
}
/* Called to check for existence of/value of the co-process file descriptor.
* (Used by check_fd() and by c_read/c_print to deal with -p option).
*/
int
coproc_getfd(mode, emsgp)
int mode;
const char **emsgp;
{
int fd = (mode & R_OK) ? coproc.read : coproc.write;
if (fd >= 0)
return fd;
if (emsgp)
*emsgp = "no coprocess";
return -1;
}
/* called to close file descriptors related to the coprocess (if any)
* Should be called with SIGCHLD blocked.
*/
void
coproc_cleanup(reuse)
int reuse;
{
/* This to allow co-processes to share output pipe */
if (!reuse || coproc.readw < 0 || coproc.read < 0) {
if (coproc.read >= 0) {
close(coproc.read);
coproc.read = -1;
}
if (coproc.readw >= 0) {
close(coproc.readw);
coproc.readw = -1;
}
}
if (coproc.write >= 0) {
close(coproc.write);
coproc.write = -1;
}
}
#endif /* KSH */
/*
* temporary files
*/
struct temp *
maketemp(ap, type, tlist)
Area *ap;
Temp_type type;
struct temp **tlist;
{
#ifndef __NetBSD__
static unsigned int inc;
#endif
struct temp *tp;
int len;
int fd;
char *pathx;
const char *dir;
dir = tmpdir ? tmpdir : "/tmp";
/* The 20 + 20 is a paranoid worst case for pid/inc */
len = strlen(dir) + 3 + 20 + 20 + 1;
tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
tp->name = pathx = (char *) &tp[1];
tp->shf = (struct shf *) 0;
tp->type = type;
#ifdef __NetBSD__
shf_snprintf(pathx, len, "%s/shXXXXXXXX", dir);
fd = mkstemp(pathx);
if (fd >= 0)
tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
#else
while (1) {
/* Note that temp files need to fit 8.3 DOS limits */
shf_snprintf(pathx, len, "%s/sh%05u.%03x",
dir, (unsigned) procpid, inc++);
/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
* really there.
*/
fd = open(pathx, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
if (fd >= 0) {
tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
break;
}
if (errno != EINTR
#ifdef EEXIST
&& errno != EEXIST
#endif /* EEXIST */
#ifdef EISDIR
&& errno != EISDIR
#endif /* EISDIR */
)
/* Error must be printed by caller: don't know here if
* errorf() or bi_errorf() should be used.
*/
break;
}
#endif /* __NetBSD__ */
tp->pid = procpid;
tp->next = *tlist;
*tlist = tp;
return tp;
}

1860
bin/ksh/jobs.c Normal file

File diff suppressed because it is too large Load diff

3617
bin/ksh/ksh.Man Normal file

File diff suppressed because it is too large Load diff

27
bin/ksh/ksh_dir.h Normal file
View file

@ -0,0 +1,27 @@
/* $NetBSD: ksh_dir.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
/* Wrapper around the ugly dir includes/ifdefs */
/* $NetBSD: ksh_dir.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
#if defined(HAVE_DIRENT_H)
# include <dirent.h>
# define NLENGTH(dirent) (strlen(dirent->d_name))
#else
# define dirent direct
# define NLENGTH(dirent) (dirent->d_namlen)
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYSDIR_H */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif /* HAVE_NDIR_H */
#endif /* HAVE_DIRENT_H */
#ifdef OPENDIR_DOES_NONDIR
extern DIR *ksh_opendir ARGS((const char *d));
#else /* OPENDIR_DOES_NONDIR */
# define ksh_opendir(d) opendir(d)
#endif /* OPENDIR_DOES_NONDIR */

25
bin/ksh/ksh_limval.h Normal file
View file

@ -0,0 +1,25 @@
/* $NetBSD: ksh_limval.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
/* Wrapper around the values.h/limits.h includes/ifdefs */
/* $NetBSD: ksh_limval.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
#ifdef HAVE_VALUES_H
# include <values.h>
#endif /* HAVE_VALUES_H */
/* limits.h is included in sh.h */
#ifndef DMAXEXP
# define DMAXEXP 128 /* should be big enough */
#endif
#ifndef BITSPERBYTE
# ifdef CHAR_BIT
# define BITSPERBYTE CHAR_BIT
# else
# define BITSPERBYTE 8 /* probably true.. */
# endif
#endif
#ifndef BITS
# define BITS(t) (BITSPERBYTE * sizeof(t))
#endif

60
bin/ksh/ksh_stat.h Normal file
View file

@ -0,0 +1,60 @@
/* $NetBSD: ksh_stat.h,v 1.2 1997/01/12 19:12:00 tls Exp $ */
/* Wrapper around the ugly sys/stat includes/ifdefs */
/* $NetBSD: ksh_stat.h,v 1.2 1997/01/12 19:12:00 tls Exp $ */
/* assumes <sys/types.h> already included */
#include <sys/stat.h>
#ifndef HAVE_LSTAT
# define lstat(path, buf) stat(path, buf)
#endif /* HAVE_LSTAT */
#ifdef STAT_MACROS_BROKEN
# undef S_ISREG
# undef S_ISDIR
# undef S_ISCHR
# undef S_ISBLK
# undef S_ISFIFO
# undef S_ISSOCK
# undef S_ISLNK
#endif /* STAT_MACROS_BROKEN */
#if !defined(S_ISREG) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif /* S_ISREG */
#if !defined(S_ISDIR) && defined(S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif /* S_ISDIR */
#if !defined(S_ISCHR) && defined(S_IFCHR)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif /* S_ISCHR */
#if !defined(S_ISBLK) && defined(S_IFBLK)
# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#endif /* S_ISBLK */
#if !defined(S_ISFIFO) && defined(S_IFIFO)
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#endif /* S_ISFIFO */
#if !defined(S_ISLNK) && defined(S_IFLNK)
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif /* S_ISLNK */
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#endif /* S_ISSOCK */
#if !defined(S_ISCDF) && defined(S_CDF)
# define S_ISCDF(m) (S_ISDIR(m) && ((m) & S_CDF))
#endif /* S_ISSOCK */
#ifndef S_ISVTX
# define S_ISVTX 01000 /* sticky bit */
#endif /* S_ISVTX */
#ifndef S_IXUSR
# define S_IXUSR 00100 /* user execute bit */
#endif /* S_IXUSR */
#ifndef S_IXGRP
# define S_IXGRP 00010 /* user execute bit */
#endif /* S_IXGRP */
#ifndef S_IXOTH
# define S_IXOTH 00001 /* user execute bit */
#endif /* S_IXOTH */

27
bin/ksh/ksh_time.h Normal file
View file

@ -0,0 +1,27 @@
/* $NetBSD: ksh_time.h,v 1.2 1997/01/12 19:12:01 tls Exp $ */
#ifndef KSH_TIME_H
# define KSH_TIME_H
/* Wrapper around the ugly time.h,sys/time.h includes/ifdefs */
/* $NetBSD: ksh_time.h,v 1.2 1997/01/12 19:12:01 tls Exp $ */
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else /* TIME_WITH_SYS_TIME */
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif /* TIME_WITH_SYS_TIME */
#ifndef TIME_DECLARED
extern time_t time ARGS((time_t *));
#endif
#ifndef CLK_TCK
# define CLK_TCK 60 /* 60HZ */
#endif
#endif /* KSH_TIME_H */

20
bin/ksh/ksh_times.h Normal file
View file

@ -0,0 +1,20 @@
/* $NetBSD: ksh_times.h,v 1.2 1997/01/12 19:12:02 tls Exp $ */
#ifndef KSH_TIMES_H
# define KSH_TIMES_H
/* Needed for clock_t on some systems (ie, NeXT in non-posix mode) */
#include "ksh_time.h"
#include <sys/times.h>
#ifdef TIMES_BROKEN
extern clock_t ksh_times ARGS((struct tms *));
#else /* TIMES_BROKEN */
# define ksh_times times
#endif /* TIMES_BROKEN */
#ifdef HAVE_TIMES
extern clock_t times ARGS((struct tms *));
#endif /* HAVE_TIMES */
#endif /* KSH_TIMES_H */

52
bin/ksh/ksh_wait.h Normal file
View file

@ -0,0 +1,52 @@
/* $NetBSD: ksh_wait.h,v 1.2 1997/01/12 19:12:03 tls Exp $ */
/* Wrapper around the ugly sys/wait includes/ifdefs */
/* $NetBSD: ksh_wait.h,v 1.2 1997/01/12 19:12:03 tls Exp $ */
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef POSIX_SYS_WAIT
/* Get rid of system macros (which probably use union wait) */
# undef WIFCORED
# undef WIFEXITED
# undef WEXITSTATUS
# undef WIFSIGNALED
# undef WTERMSIG
# undef WIFSTOPPED
# undef WSTOPSIG
#endif /* POSIX_SYS_WAIT */
typedef int WAIT_T;
#ifndef WIFCORED
# define WIFCORED(s) ((s) & 0x80)
#endif
#define WSTATUS(s) (s)
#ifndef WIFEXITED
# define WIFEXITED(s) (((s) & 0xff) == 0)
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(s) (((s) & 0xff) != 0 && ((s) & 0xff) != 0x7f)
#endif
#ifndef WTERMSIG
# define WTERMSIG(s) ((s) & 0x7f)
#endif
#ifndef WIFSTOPPED
# define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
#endif
#ifndef WSTOPSIG
# define WSTOPSIG(s) (((s) >> 8) & 0xff)
#endif
#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT3)
/* always used with p == -1 */
# define ksh_waitpid(p, s, o) wait3((s), (o), (struct rusage *) 0)
#else /* !HAVE_WAITPID && HAVE_WAIT3 */
# define ksh_waitpid(p, s, o) waitpid((p), (s), (o))
#endif /* !HAVE_WAITPID && HAVE_WAIT3 */

1398
bin/ksh/lex.c Normal file

File diff suppressed because it is too large Load diff

133
bin/ksh/lex.h Normal file
View file

@ -0,0 +1,133 @@
/* $NetBSD: lex.h,v 1.7 2005/09/11 22:16:00 christos Exp $ */
/*
* Source input, lexer and parser
*/
/* $Id: lex.h,v 1.7 2005/09/11 22:16:00 christos Exp $ */
#define IDENT 64
typedef struct source Source;
struct source {
const char *str; /* input pointer */
int type; /* input type */
const char *start; /* start of current buffer */
union {
char **strv; /* string [] */
struct shf *shf; /* shell file */
struct tbl *tblp; /* alias (SALIAS) */
char *freeme; /* also for SREREAD */
} u;
char ugbuf[2]; /* buffer for ungetsc() (SREREAD) and
* alias (SALIAS) */
int line; /* line number */
int errline; /* line the error occurred on (0 if not set) */
const char *file; /* input file name */
int flags; /* SF_* */
Area *areap;
XString xs; /* input buffer */
Source *next; /* stacked source */
};
/* Source.type values */
#define SEOF 0 /* input EOF */
#define SFILE 1 /* file input */
#define SSTDIN 2 /* read stdin */
#define SSTRING 3 /* string */
#define SWSTR 4 /* string without \n */
#define SWORDS 5 /* string[] */
#define SWORDSEP 6 /* string[] separator */
#define SALIAS 7 /* alias expansion */
#define SREREAD 8 /* read ahead to be re-scanned */
/* Source.flags values */
#define SF_ECHO BIT(0) /* echo input to shlout */
#define SF_ALIAS BIT(1) /* faking space at end of alias */
#define SF_ALIASEND BIT(2) /* faking space at end of alias */
#define SF_TTY BIT(3) /* type == SSTDIN & it is a tty */
/*
* states while lexing word
*/
#define SBASE 0 /* outside any lexical constructs */
#define SWORD 1 /* implicit quoting for substitute() */
#ifdef KSH
#define SLETPAREN 2 /* inside (( )), implicit quoting */
#endif /* KSH */
#define SSQUOTE 3 /* inside '' */
#define SDQUOTE 4 /* inside "" */
#define SBRACE 5 /* inside ${} */
#define SCSPAREN 6 /* inside $() */
#define SBQUOTE 7 /* inside `` */
#define SASPAREN 8 /* inside $(( )) */
#define SHEREDELIM 9 /* parsing <<,<<- delimiter */
#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */
#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 12 /* parsing ${..[#%]..} */
typedef union {
int i;
char *cp;
char **wp;
struct op *o;
struct ioword *iop;
} YYSTYPE;
/* If something is added here, add it to tokentab[] in syn.c as well */
#define LWORD 256
#define LOGAND 257 /* && */
#define LOGOR 258 /* || */
#define BREAK 259 /* ;; */
#define IF 260
#define THEN 261
#define ELSE 262
#define ELIF 263
#define FI 264
#define CASE 265
#define ESAC 266
#define FOR 267
#define SELECT 268
#define WHILE 269
#define UNTIL 270
#define DO 271
#define DONE 272
#define IN 273
#define FUNCTION 274
#define TIME 275
#define REDIR 276
#ifdef KSH
#define MDPAREN 277 /* (( )) */
#endif /* KSH */
#define BANG 278 /* ! */
#define DBRACKET 279 /* [[ .. ]] */
#define COPROC 280 /* |& */
#define YYERRCODE 300
/* flags to yylex */
#define CONTIN BIT(0) /* skip new lines to complete command */
#define ONEWORD BIT(1) /* single word for substitute() */
#define ALIAS BIT(2) /* recognize alias */
#define KEYWORD BIT(3) /* recognize keywords */
#define LETEXPR BIT(4) /* get expression inside (( )) */
#define VARASN BIT(5) /* check for var=word */
#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
#define ESACONLY BIT(7) /* only accept esac keyword */
#define CMDWORD BIT(8) /* parsing simple command (alias related) */
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define HEREDOC BIT(10) /* parsing heredoc */
#define HERES 10 /* max << in line */
EXTERN Source *source; /* yyparse/yylex source */
EXTERN YYSTYPE yylval; /* result from yylex */
EXTERN struct ioword *heres [HERES], **herep;
EXTERN char ident [IDENT+1];
#ifdef HISTORY
# define HISTORYSIZE 128 /* size of saved history */
EXTERN char **histlist; /* saved commands */
EXTERN char **histptr; /* last history item */
EXTERN int histsize; /* history size */
#endif /* HISTORY */

202
bin/ksh/mail.c Normal file
View file

@ -0,0 +1,202 @@
/* $NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $ */
/*
* Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
* John R. MacMillan
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $");
#endif
#include "config.h"
#ifdef KSH
#include "sh.h"
#include "ksh_stat.h"
#include "ksh_time.h"
#define MBMESSAGE "You have mail in $_"
typedef struct mbox {
struct mbox *mb_next; /* next mbox in list */
char *mb_path; /* path to mail file */
char *mb_msg; /* to announce arrival of new mail */
time_t mb_mtime; /* mtime of mail file */
} mbox_t;
/*
* $MAILPATH is a linked list of mboxes. $MAIL is a treated as a
* special case of $MAILPATH, where the list has only one node. The
* same list is used for both since they are exclusive.
*/
static mbox_t *mplist;
static mbox_t mbox;
static time_t mlastchkd; /* when mail was last checked */
static time_t mailcheck_interval;
static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */
static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */
static void mprintit ARGS((mbox_t *mbp));
void
mcheck()
{
register mbox_t *mbp;
time_t now;
struct tbl *vp;
struct stat stbuf;
now = time((time_t *) 0);
if (mlastchkd == 0)
mlastchkd = now;
if (now - mlastchkd >= mailcheck_interval) {
mlastchkd = now;
if (mplist)
mbp = mplist;
else if ((vp = global("MAIL")) && (vp->flag & ISSET))
mbp = &mbox;
else
mbp = NULL;
while (mbp) {
if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
&& S_ISREG(stbuf.st_mode))
{
if (stbuf.st_size
&& mbp->mb_mtime != stbuf.st_mtime
&& stbuf.st_atime <= stbuf.st_mtime)
mprintit(mbp);
mbp->mb_mtime = stbuf.st_mtime;
} else {
/*
* Some mail readers remove the mail
* file if all mail is read. If file
* does not exist, assume this is the
* case and set mtime to zero.
*/
mbp->mb_mtime = 0;
}
mbp = mbp->mb_next;
}
}
}
void
mcset(interval)
long interval;
{
mailcheck_interval = interval;
}
void
mbset(p)
register char *p;
{
struct stat stbuf;
if (mbox.mb_msg)
afree((void *)mbox.mb_msg, APERM);
if (mbox.mb_path)
afree((void *)mbox.mb_path, APERM);
/* Save a copy to protect from export (which munges the string) */
mbox.mb_path = str_save(p, APERM);
mbox.mb_msg = NULL;
if (p && stat(p, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
mbox.mb_mtime = stbuf.st_mtime;
else
mbox.mb_mtime = 0;
}
void
mpset(mptoparse)
register char *mptoparse;
{
register mbox_t *mbp;
register char *mpath, *mmsg, *mval;
char *p;
munset( mplist );
mplist = NULL;
mval = str_save(mptoparse, APERM);
while (mval) {
mpath = mval;
if ((mval = strchr(mval, PATHSEP)) != NULL) {
*mval = '\0', mval++;
}
/* POSIX/bourne-shell say file%message */
for (p = mpath; (mmsg = strchr(p, '%')); ) {
/* a literal percent? (POSIXism) */
if (mmsg[-1] == '\\') {
/* use memmove() to avoid overlap problems */
memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
p = mmsg + 1;
continue;
}
break;
}
/* at&t ksh says file?message */
if (!mmsg && !Flag(FPOSIX))
mmsg = strchr(mpath, '?');
if (mmsg) {
*mmsg = '\0';
mmsg++;
}
mbp = mballoc(mpath, mmsg);
mbp->mb_next = mplist;
mplist = mbp;
}
}
static void
munset(mlist)
register mbox_t *mlist;
{
register mbox_t *mbp;
while (mlist != NULL) {
mbp = mlist;
mlist = mbp->mb_next;
if (!mlist)
afree((void *)mbp->mb_path, APERM);
afree((void *)mbp, APERM);
}
}
static mbox_t *
mballoc(p, m)
char *p;
char *m;
{
struct stat stbuf;
register mbox_t *mbp;
mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
mbp->mb_next = NULL;
mbp->mb_path = p;
mbp->mb_msg = m;
if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
mbp->mb_mtime = stbuf.st_mtime;
else
mbp->mb_mtime = 0;
return(mbp);
}
static void
mprintit( mbp )
mbox_t *mbp;
{
struct tbl *vp;
/* Ignore setstr errors here (arbitrary) */
setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR);
shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
unset(vp, 0);
}
#endif /* KSH */

869
bin/ksh/main.c Normal file
View file

@ -0,0 +1,869 @@
/* $NetBSD: main.c,v 1.15 2011/10/16 17:12:11 joerg Exp $ */
/*
* startup, main loop, environments and error handling
*/
#include <sys/cdefs.h>
#include <locale.h>
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.15 2011/10/16 17:12:11 joerg Exp $");
#endif
#define EXTERN /* define EXTERNs in sh.h */
#include "sh.h"
#include "ksh_stat.h"
#include "ksh_time.h"
extern char **environ;
/*
* global data
*/
static void reclaim ARGS((void));
static void remove_temps ARGS((struct temp *tp));
static int is_restricted ARGS((char *name));
/*
* shell initialization
*/
static const char initifs[] = "IFS= \t\n";
static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
static const char version_param[] =
#ifdef KSH
"KSH_VERSION"
#else /* KSH */
"SH_VERSION"
#endif /* KSH */
;
static const char *const initcoms [] = {
"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
"typeset", "-r", version_param, NULL,
"typeset", "-i", "PPID", NULL,
"typeset", "-i", "OPTIND=1", NULL,
#ifdef KSH
"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
#endif /* KSH */
"alias",
/* Standard ksh aliases */
"hash=alias -t", /* not "alias -t --": hash -r needs to work */
"type=whence -v",
#ifdef JOBS
"stop=kill -STOP",
"suspend=kill -STOP $$",
#endif
#ifdef KSH
"autoload=typeset -fu",
"functions=typeset -f",
# ifdef HISTORY
"history=fc -l",
# endif /* HISTORY */
"integer=typeset -i",
"nohup=nohup ",
"local=typeset",
"r=fc -e -",
#endif /* KSH */
#ifdef KSH
/* Aliases that are builtin commands in at&t */
"login=exec login",
#ifndef __NetBSD__
"newgrp=exec newgrp",
#endif /* __NetBSD__ */
#endif /* KSH */
NULL,
/* this is what at&t ksh seems to track, with the addition of emacs */
"alias", "-tU",
"cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
"mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
NULL,
#ifdef EXTRA_INITCOMS
EXTRA_INITCOMS, NULL,
#endif /* EXTRA_INITCOMS */
NULL
};
int
main(int argc, char *argv[])
{
register int i;
int argi;
Source *s;
struct block *l;
int restricted, errexit;
char **wp;
struct env env;
pid_t ppid;
#ifdef MEM_DEBUG
chmem_set_defaults("ct", 1);
/* chmem_push("+c", 1); */
#endif /* MEM_DEBUG */
#ifdef OS2
setmode (0, O_BINARY);
setmode (1, O_TEXT);
#endif
/* make sure argv[] is sane */
if (!*argv) {
static const char *empty_argv[] = {
"pdksh", (char *) 0
};
argv = (char **)__UNCONST(empty_argv);
argc = 1;
}
kshname = *argv;
ainit(&aperm); /* initialize permanent Area */
/* set up base environment */
memset(&env, 0, sizeof(env));
env.type = E_NONE;
ainit(&env.area);
e = &env;
newblock(); /* set up global l->vars and l->funs */
/* Do this first so output routines (eg, errorf, shellf) can work */
initio();
initvar();
initctypes();
inittraps();
#ifdef KSH
coproc_init();
#endif /* KSH */
/* set up variable and command dictionaries */
tinit(&taliases, APERM, 0);
tinit(&aliases, APERM, 0);
tinit(&homedirs, APERM, 0);
/* define shell keywords */
initkeywords();
/* define built-in commands */
tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
for (i = 0; shbuiltins[i].name != NULL; i++)
builtin(shbuiltins[i].name, shbuiltins[i].func);
for (i = 0; kshbuiltins[i].name != NULL; i++)
builtin(kshbuiltins[i].name, kshbuiltins[i].func);
init_histvec();
def_path = DEFAULT__PATH;
#if defined(HAVE_CONFSTR) && defined(_CS_PATH)
{
size_t len = confstr(_CS_PATH, (char *) 0, 0);
char *new;
if (len > 0) {
confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
def_path = new;
}
}
#endif /* HAVE_CONFSTR && _CS_PATH */
/* Set PATH to def_path (will set the path global variable).
* (import of environment below will probably change this setting).
*/
{
struct tbl *vp = global("PATH");
/* setstr can't fail here */
setstr(vp, def_path, KSH_RETURN_ERROR);
}
/* Turn on nohup by default for now - will change to off
* by default once people are aware of its existence
* (at&t ksh does not have a nohup option - it always sends
* the hup).
*/
Flag(FNOHUP) = 1;
/* Turn on brace expansion by default. At&t ksh's that have
* alternation always have it on. BUT, posix doesn't have
* brace expansion, so set this before setting up FPOSIX
* (change_flag() clears FBRACEEXPAND when FPOSIX is set).
*/
#ifdef BRACE_EXPAND
Flag(FBRACEEXPAND) = 1;
#endif /* BRACE_EXPAND */
/* set posix flag just before environment so that it will have
* exactly the same effect as the POSIXLY_CORRECT environment
* variable. If this needs to be done sooner to ensure correct posix
* operation, an initial scan of the environment will also have
* done sooner.
*/
#ifdef POSIXLY_CORRECT
change_flag(FPOSIX, OF_SPECIAL, 1);
#endif /* POSIXLY_CORRECT */
/* Set edit mode to emacs by default, may be overridden
* by the environment or the user. Also, we want tab completion
* on in vi by default. */
#if defined(EDIT) && defined(EMACS)
change_flag(FEMACS, OF_SPECIAL, 1);
#endif /* EDIT && EMACS */
#if defined(EDIT) && defined(VI)
Flag(FVITABCOMPLETE) = 1;
#endif /* EDIT && VI */
/* import environment */
if (environ != NULL)
for (wp = environ; *wp != NULL; wp++)
typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
kshpid = procpid = getpid();
typeset(initifs, 0, 0, 0, 0); /* for security */
/* assign default shell variable values */
substitute(initsubs, 0);
/* Figure out the current working directory and set $PWD */
{
struct stat s_pwd, s_dot;
struct tbl *pwd_v = global("PWD");
char *pwd = str_val(pwd_v);
char *pwdx = pwd;
/* Try to use existing $PWD if it is valid */
if (!ISABSPATH(pwd)
|| stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
|| s_pwd.st_dev != s_dot.st_dev
|| s_pwd.st_ino != s_dot.st_ino)
pwdx = (char *) 0;
set_current_wd(pwdx);
if (current_wd[0])
simplify_path(current_wd);
/* Only set pwd if we know where we are or if it had a
* bogus value
*/
if (current_wd[0] || pwd != null)
/* setstr can't fail here */
setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
}
ppid = getppid();
setint(global("PPID"), (long) ppid);
#ifdef KSH
setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
#endif /* KSH */
/* setstr can't fail here */
setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
/* execute initialization statements */
for (wp = (char**)__UNCONST(initcoms); *wp != NULL; wp++) {
shcomexec(wp);
for (; *wp != NULL; wp++)
;
}
ksheuid = geteuid();
safe_prompt = ksheuid ? "$ " : "# ";
{
struct tbl *vp = global("PS1");
/* Set PS1 if it isn't set, or we are root and prompt doesn't
* contain a #.
*/
if (!(vp->flag & ISSET)
|| (!ksheuid && !strchr(str_val(vp), '#')))
/* setstr can't fail here */
setstr(vp, safe_prompt, KSH_RETURN_ERROR);
}
/* Set this before parsing arguments */
Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
/* this to note if monitor is set on command line (see below) */
Flag(FMONITOR) = 127;
argi = parse_args(argv, OF_CMDLINE, (int *) 0);
if (argi < 0) {
exit(1);
/* NOTREACHED */
}
if (Flag(FCOMMAND)) {
s = pushs(SSTRING, ATEMP);
if (!(s->start = s->str = argv[argi++]))
errorf("-c requires an argument");
if (argv[argi])
kshname = argv[argi++];
} else if (argi < argc && !Flag(FSTDIN)) {
s = pushs(SFILE, ATEMP);
#ifdef OS2
/* a bug in os2 extproc shell processing doesn't
* pass full pathnames so we have to search for it.
* This changes the behavior of 'ksh arg' to search
* the users search path but it can't be helped.
*/
s->file = search(argv[argi++], path, R_OK, (int *) 0);
if (!s->file || !*s->file)
s->file = argv[argi - 1];
#else
s->file = argv[argi++];
#endif /* OS2 */
s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
if (s->u.shf == NULL) {
exstat = 127; /* POSIX */
errorf("%s: %s", s->file, strerror(errno));
}
kshname = s->file;
} else {
Flag(FSTDIN) = 1;
s = pushs(SSTDIN, ATEMP);
s->file = "<stdin>";
s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
(struct shf *) 0);
if (isatty(0) && isatty(2)) {
Flag(FTALKING) = Flag(FTALKING_I) = 1;
/* The following only if isatty(0) */
s->flags |= SF_TTY;
s->u.shf->flags |= SHF_INTERRUPT;
s->file = (char *) 0;
}
}
/* This bizarreness is mandated by POSIX */
{
struct stat s_stdin;
if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
Flag(FTALKING))
reset_nonblock(0);
}
/* initialize job control */
i = Flag(FMONITOR) != 127;
Flag(FMONITOR) = 0;
j_init(i);
#ifdef EDIT
/* Do this after j_init(), as tty_fd is not initialized 'til then */
if (Flag(FTALKING))
x_init();
#endif
l = e->loc;
l->argv = &argv[argi - 1];
l->argc = argc - argi;
l->argv[0] = (char *)__UNCONST(kshname);
getopts_reset(1);
/* Disable during .profile/ENV reading */
restricted = Flag(FRESTRICTED);
Flag(FRESTRICTED) = 0;
errexit = Flag(FERREXIT);
Flag(FERREXIT) = 0;
/* Do this before profile/$ENV so that if it causes problems in them,
* user will know why things broke.
*/
if (!current_wd[0] && Flag(FTALKING))
warningf(FALSE, "Cannot determine current working directory");
if (Flag(FLOGIN)) {
#ifdef OS2
char *profile;
/* Try to find a profile - first see if $INIT has a value,
* then try /etc/profile.ksh, then c:/usr/etc/profile.ksh.
*/
if (!Flag(FPRIVILEGED)
&& strcmp(profile = substitute("$INIT/profile.ksh", 0),
"/profile.ksh"))
include(profile, 0, (char **) 0, 1);
else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0)
include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1);
if (!Flag(FPRIVILEGED))
include(substitute("$HOME/profile.ksh", 0), 0,
(char **) 0, 1);
#else /* OS2 */
include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
if (!Flag(FPRIVILEGED))
include(substitute("$HOME/.profile", 0), 0,
(char **) 0, 1);
#endif /* OS2 */
}
if (Flag(FPRIVILEGED))
include("/etc/suid_profile", 0, (char **) 0, 1);
else {
char *env_file;
#ifndef KSH
if (!Flag(FPOSIX))
env_file = null;
else
#endif /* !KSH */
/* include $ENV */
env_file = str_val(global("ENV"));
#ifdef DEFAULT_ENV
/* If env isn't set, include default environment */
if (env_file == null)
env_file = __UNCONST(DEFAULT_ENV);
#endif /* DEFAULT_ENV */
env_file = substitute(env_file, DOTILDE);
if (*env_file != '\0')
include(env_file, 0, (char **) 0, 1);
#ifdef OS2
else if (Flag(FTALKING))
include(substitute("$HOME/kshrc.ksh", 0), 0,
(char **) 0, 1);
#endif /* OS2 */
}
if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
restricted = 1;
if (restricted) {
static const char *const restr_com[] = {
"typeset", "-r", "PATH",
"ENV", "SHELL",
(char *) 0
};
shcomexec((char **)__UNCONST(restr_com));
/* After typeset command... */
Flag(FRESTRICTED) = 1;
}
if (errexit)
Flag(FERREXIT) = 1;
if (Flag(FTALKING)) {
hist_init(s);
#ifdef KSH
alarm_init();
#endif /* KSH */
} else
Flag(FTRACKALL) = 1; /* set after ENV */
setlocale(LC_CTYPE, "");
shell(s, TRUE); /* doesn't return */
return 0;
}
int
include(name, argc, argv, intr_ok)
const char *name;
int argc;
char **argv;
int intr_ok;
{
register Source *volatile s = NULL;
struct shf *shf;
char **volatile old_argv;
volatile int old_argc;
int i;
shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
if (shf == NULL)
return -1;
if (argv) {
old_argv = e->loc->argv;
old_argc = e->loc->argc;
} else {
old_argv = (char **) 0;
old_argc = 0;
}
newenv(E_INCL);
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
if (s) /* Do this before quitenv(), which frees the memory */
shf_close(s->u.shf);
quitenv();
if (old_argv) {
e->loc->argv = old_argv;
e->loc->argc = old_argc;
}
switch (i) {
case LRETURN:
case LERROR:
return exstat & 0xff; /* see below */
case LINTR:
/* intr_ok is set if we are including .profile or $ENV.
* If user ^C's out, we don't want to kill the shell...
*/
if (intr_ok && (exstat - 128) != SIGTERM)
return 1;
/* fall through... */
case LEXIT:
case LLEAVE:
case LSHELL:
unwind(i);
/*NOREACHED*/
default:
internal_errorf(1, "include: %d", i);
/*NOREACHED*/
}
}
if (argv) {
e->loc->argv = argv;
e->loc->argc = argc;
}
s = pushs(SFILE, ATEMP);
s->u.shf = shf;
s->file = str_save(name, ATEMP);
i = shell(s, FALSE);
shf_close(s->u.shf);
quitenv();
if (old_argv) {
e->loc->argv = old_argv;
e->loc->argc = old_argc;
}
return i & 0xff; /* & 0xff to ensure value not -1 */
}
int
command(comm)
const char *comm;
{
register Source *s;
int r;
s = pushs(SSTRING, ATEMP);
s->start = s->str = comm;
r = shell(s, FALSE);
afree(s, ATEMP);
return r;
}
/*
* run the commands from the input source, returning status.
*/
int
shell(s, toplevel)
Source *volatile s; /* input source */
int volatile toplevel;
{
struct op *t;
volatile int wastty = s->flags & SF_TTY;
volatile int attempts = 13;
volatile int interactive = Flag(FTALKING) && toplevel;
Source *volatile old_source = source;
int i;
newenv(E_PARSE);
if (interactive)
really_exit = 0;
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
switch (i) {
case LINTR: /* we get here if SIGINT not caught or ignored */
case LERROR:
case LSHELL:
if (interactive) {
if (i == LINTR)
shellf("%s", newline);
/* Reset any eof that was read as part of a
* multiline command.
*/
if (Flag(FIGNOREEOF) && s->type == SEOF
&& wastty)
s->type = SSTDIN;
/* Used by exit command to get back to
* top level shell. Kind of strange since
* interactive is set if we are reading from
* a tty, but to have stopped jobs, one only
* needs FMONITOR set (not FTALKING/SF_TTY)...
*/
/* toss any input we have so far */
s->start = s->str = null;
break;
}
/* fall through... */
case LEXIT:
case LLEAVE:
case LRETURN:
source = old_source;
quitenv();
unwind(i); /* keep on going */
/*NOREACHED*/
default:
source = old_source;
quitenv();
internal_errorf(1, "shell: %d", i);
/*NOREACHED*/
}
}
while (1) {
if (trap)
runtraps(0);
if (s->next == NULL) {
if (Flag(FVERBOSE))
s->flags |= SF_ECHO;
else
s->flags &= ~SF_ECHO;
}
if (interactive) {
j_notify();
#ifdef KSH
mcheck();
#endif /* KSH */
set_prompt(PS1, s);
}
t = compile(s);
if (t != NULL && t->type == TEOF) {
if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
shellf("Use `exit' to leave ksh\n");
s->type = SSTDIN;
} else if (wastty && !really_exit
&& j_stopped_running())
{
really_exit = 1;
s->type = SSTDIN;
} else {
/* this for POSIX, which says EXIT traps
* shall be taken in the environment
* immediately after the last command
* executed.
*/
if (toplevel)
unwind(LEXIT);
break;
}
}
if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
exstat = execute(t, 0);
if (t != NULL && t->type != TEOF && interactive && really_exit)
really_exit = 0;
reclaim();
}
quitenv();
source = old_source;
return exstat;
}
/* return to closest error handler or shell(), exit if none found */
void
unwind(i)
int i;
{
/* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
&& sigtraps[SIGEXIT_].trap))
{
runtrap(&sigtraps[SIGEXIT_]);
i = LLEAVE;
} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
runtrap(&sigtraps[SIGERR_]);
i = LLEAVE;
}
while (1) {
switch (e->type) {
case E_PARSE:
case E_FUNC:
case E_INCL:
case E_LOOP:
case E_ERRH:
ksh_siglongjmp(e->jbuf, i);
/*NOTREACHED*/
case E_NONE:
if (i == LINTR)
e->flags |= EF_FAKE_SIGDIE;
/* Fall through... */
default:
quitenv();
}
}
}
void
newenv(type)
int type;
{
register struct env *ep;
ep = (struct env *) alloc(sizeof(*ep), ATEMP);
ep->type = type;
ep->flags = 0;
ainit(&ep->area);
ep->loc = e->loc;
ep->savefd = NULL;
ep->oenv = e;
ep->temps = NULL;
e = ep;
}
void
quitenv()
{
register struct env *ep = e;
register int fd;
if (ep->oenv && ep->oenv->loc != ep->loc)
popblock();
if (ep->savefd != NULL) {
for (fd = 0; fd < NUFILE; fd++)
/* if ep->savefd[fd] < 0, means fd was closed */
if (ep->savefd[fd])
restfd(fd, ep->savefd[fd]);
if (ep->savefd[2]) /* Clear any write errors */
shf_reopen(2, SHF_WR, shl_out);
}
reclaim();
/* Bottom of the stack.
* Either main shell is exiting or cleanup_parents_env() was called.
*/
if (ep->oenv == NULL) {
if (ep->type == E_NONE) { /* Main shell exiting? */
if (Flag(FTALKING))
hist_finish();
j_exit();
if (ep->flags & EF_FAKE_SIGDIE) {
int sig = exstat - 128;
/* ham up our death a bit (at&t ksh
* only seems to do this for SIGTERM)
* Don't do it for SIGQUIT, since we'd
* dump a core..
*/
if (sig == SIGINT || sig == SIGTERM) {
setsig(&sigtraps[sig], SIG_DFL,
SS_RESTORE_CURR|SS_FORCE);
kill(0, sig);
}
}
#ifdef MEM_DEBUG
chmem_allfree();
#endif /* MEM_DEBUG */
}
exit(exstat);
}
e = e->oenv;
afree(ep, ATEMP);
}
/* Called after a fork to cleanup stuff left over from parents environment */
void
cleanup_parents_env()
{
struct env *ep;
int fd;
/* Don't clean up temporary files - parent will probably need them.
* Also, can't easily reclaim memory since variables, etc. could be
* anywhere.
*/
/* close all file descriptors hiding in savefd */
for (ep = e; ep; ep = ep->oenv) {
if (ep->savefd) {
for (fd = 0; fd < NUFILE; fd++)
if (ep->savefd[fd] > 0)
close(ep->savefd[fd]);
afree(ep->savefd, &ep->area);
ep->savefd = (short *) 0;
}
}
e->oenv = (struct env *) 0;
}
/* Called just before an execve cleanup stuff temporary files */
void
cleanup_proc_env()
{
struct env *ep;
for (ep = e; ep; ep = ep->oenv)
remove_temps(ep->temps);
}
/* remove temp files and free ATEMP Area */
static void
reclaim()
{
remove_temps(e->temps);
e->temps = NULL;
afreeall(&e->area);
}
static void
remove_temps(tp)
struct temp *tp;
{
#ifdef OS2
static struct temp *delayed_remove;
struct temp *t, **tprev;
if (delayed_remove) {
for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev)
/* No need to check t->pid here... */
if (unlink(t->name) >= 0 || errno == ENOENT) {
*tprev = t->next;
afree(t, APERM);
} else
tprev = &t->next;
}
#endif /* OS2 */
for (; tp != NULL; tp = tp->next)
if (tp->pid == procpid) {
#ifdef OS2
/* OS/2 (and dos) do not allow files that are currently
* open to be removed, so we cache it away for future
* removal.
* XXX should only do this if errno
* is Efile-still-open-can't-remove
* (but I don't know what that is...)
*/
if (unlink(tp->name) < 0 && errno != ENOENT) {
t = (struct temp *) alloc(
sizeof(struct temp) + strlen(tp->name) + 1,
APERM);
memset(t, 0, sizeof(struct temp));
t->name = (char *) &t[1];
strlcpy(t->name, tp->name, strlen(tp->name) + 1);
t->next = delayed_remove;
delayed_remove = t;
}
#else /* OS2 */
unlink(tp->name);
#endif /* OS2 */
}
}
/* Returns true if name refers to a restricted shell */
static int
is_restricted(name)
char *name;
{
char *p;
if ((p = ksh_strrchr_dirsep(name)))
name = p;
/* accepts rsh, rksh, rpdksh, pdrksh, etc. */
return (p = strchr(name, 'r')) && strstr(p, "sh");
}
void
aerror(ap, msg)
Area *ap;
const char *msg;
{
internal_errorf(1, "alloc: %s", msg);
errorf("%s", null); /* this is never executed - keeps gcc quiet */
/*NOTREACHED*/
}

1364
bin/ksh/misc.c Normal file

File diff suppressed because it is too large Load diff

46
bin/ksh/mkman Executable file
View file

@ -0,0 +1,46 @@
#!/bin/sh
: ${AWK:=awk}
verbose=no
if [ X"$1" = X-v ] ; then
verbose=yes
shift
fi
if [ $# != 2 ] ; then
echo "usage: $0 [-v] which-shell ksh.Man-file" 1>&2
exit 1;
fi
shell=$1
man=$2
case $shell in
sh) which=0;;
ksh) which=1;;
*)
echo "$0: bad shell option (must be sh or ksh)" 1>&2
exit 1
;;
esac
if [ ! -r "$man" ] ; then
echo "$0: can't read $man file" 1>&2
exit 1;
fi
#
# Now generate the appropriate man page...
#
[ $verbose = yes ] && echo "$0: Generating $which man page (0=sh,1=ksh)..." 1>&2
${AWK} 'BEGIN { ksh = '$which'; pr = 1 }
/^\.sh\(/ { pr = ksh - 1; next }
/^\.sh\)/ { pr = 1; next }
/^\.ksh\(/ { pr = ksh; next }
/^\.ksh\)/ { pr = 1; next }
{ if (pr) print $0 } ' < $man
[ $verbose = yes ] && echo "$0: All done" 1>&2
exit 0

318
bin/ksh/path.c Normal file
View file

@ -0,0 +1,318 @@
/* $NetBSD: path.c,v 1.8 2009/04/25 05:11:37 lukem Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: path.c,v 1.8 2009/04/25 05:11:37 lukem Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h"
/*
* Contains a routine to search a : separated list of
* paths (a la CDPATH) and make appropriate file names.
* Also contains a routine to simplify .'s and ..'s out of
* a path name.
*
* Larry Bouzane (larry@cs.mun.ca)
*/
#ifdef S_ISLNK
static char *do_phys_path ARGS((XString *, char *, const char *));
#endif /* S_ISLNK */
/*
* Makes a filename into result using the following algorithm.
* - make result NULL
* - if file starts with '/', append file to result & set cdpathp to NULL
* - if file starts with ./ or ../ append cwd and file to result
* and set cdpathp to NULL
* - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
* then cwd is appended to result.
* - the first element of cdpathp is appended to result
* - file is appended to result
* - cdpathp is set to the start of the next element in cdpathp (or NULL
* if there are no more elements.
* The return value indicates whether a non-null element from cdpathp
* was appended to result.
*/
int
make_path(cwd, file, cdpathp, xsp, phys_pathp)
const char *cwd;
const char *file;
char **cdpathp; /* & of : separated list */
XString *xsp;
int *phys_pathp;
{
int rval = 0;
int use_cdpath = 1;
char *plist;
int len;
int plen = 0;
char *xp = Xstring(*xsp, xp);
if (!file)
file = null;
if (!ISRELPATH(file)) {
*phys_pathp = 0;
use_cdpath = 0;
} else {
if (file[0] == '.') {
char c = file[1];
if (c == '.')
c = file[2];
if (ISDIRSEP(c) || c == '\0')
use_cdpath = 0;
}
plist = *cdpathp;
if (!plist)
use_cdpath = 0;
else if (use_cdpath) {
char *pend;
for (pend = plist; *pend && *pend != PATHSEP; pend++)
;
plen = pend - plist;
*cdpathp = *pend ? ++pend : (char *) 0;
}
if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
&& (cwd && *cwd))
{
len = strlen(cwd);
XcheckN(*xsp, xp, len);
memcpy(xp, cwd, len);
xp += len;
if (!ISDIRSEP(cwd[len - 1]))
Xput(*xsp, xp, DIRSEP);
}
*phys_pathp = Xlength(*xsp, xp);
if (use_cdpath && plen) {
XcheckN(*xsp, xp, plen);
memcpy(xp, plist, plen);
xp += plen;
if (!ISDIRSEP(plist[plen - 1]))
Xput(*xsp, xp, DIRSEP);
rval = 1;
}
}
len = strlen(file) + 1;
XcheckN(*xsp, xp, len);
memcpy(xp, file, len);
if (!use_cdpath)
*cdpathp = (char *) 0;
return rval;
}
/*
* Simplify pathnames containing "." and ".." entries.
* ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
*/
void
simplify_path(pathx)
char *pathx;
{
char *cur;
char *t;
int isrooted;
char *very_start = pathx;
char *start;
if (!*pathx)
return;
if ((isrooted = ISROOTEDPATH(pathx)))
very_start++;
#if defined (OS2) || defined (__CYGWIN__)
if (pathx[0] && pathx[1] == ':') /* skip a: */
very_start += 2;
#endif /* OS2 || __CYGWIN__ */
/* Before After
* /foo/ /foo
* /foo/../../bar /bar
* /foo/./blah/.. /foo
* . .
* .. ..
* ./foo foo
* foo/../../../bar ../../bar
* OS2 and CYGWIN:
* a:/foo/../.. a:/
* a:. a:
* a:.. a:..
* a:foo/../../blah a:../blah
*/
#ifdef __CYGWIN__
/* preserve leading double-slash on pathnames (for UNC paths) */
if (pathx[0] && ISDIRSEP(pathx[0]) && pathx[1] && ISDIRSEP(pathx[1]))
very_start++;
#endif /* __CYGWIN__ */
for (cur = t = start = very_start; ; ) {
/* treat multiple '/'s as one '/' */
while (ISDIRSEP(*t))
t++;
if (*t == '\0') {
if (cur == pathx)
/* convert empty path to dot */
*cur++ = '.';
*cur = '\0';
break;
}
if (t[0] == '.') {
if (!t[1] || ISDIRSEP(t[1])) {
t += 1;
continue;
} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
if (!isrooted && cur == start) {
if (cur != very_start)
*cur++ = DIRSEP;
*cur++ = '.';
*cur++ = '.';
start = cur;
} else if (cur != start)
while (--cur > start && !ISDIRSEP(*cur))
;
t += 2;
continue;
}
}
if (cur != very_start)
*cur++ = DIRSEP;
/* find/copy next component of pathname */
while (*t && !ISDIRSEP(*t))
*cur++ = *t++;
}
}
void
set_current_wd(pathx)
char *pathx;
{
int len;
char *p = pathx;
if (!p && !(p = ksh_get_wd((char *) 0, 0)))
p = null;
len = strlen(p) + 1;
if (len > current_wd_size)
current_wd = aresize(current_wd, current_wd_size = len, APERM);
memcpy(current_wd, p, len);
if (p != pathx && p != null)
afree(p, ATEMP);
}
#ifdef S_ISLNK
char *
get_phys_path(pathx)
const char *pathx;
{
XString xs;
char *xp;
Xinit(xs, xp, strlen(pathx) + 1, ATEMP);
xp = do_phys_path(&xs, xp, pathx);
if (!xp)
return (char *) 0;
if (Xlength(xs, xp) == 0)
Xput(xs, xp, DIRSEP);
Xput(xs, xp, '\0');
return Xclose(xs, xp);
}
static char *
do_phys_path(xsp, xp, pathx)
XString *xsp;
char *xp;
const char *pathx;
{
const char *p, *q;
int len, llen;
int savepos;
char lbuf[PATH];
Xcheck(*xsp, xp);
for (p = pathx; p; p = q) {
while (ISDIRSEP(*p))
p++;
if (!*p)
break;
len = (q = ksh_strchr_dirsep(p)) ? q - p : (int)strlen(p);
if (len == 1 && p[0] == '.')
continue;
if (len == 2 && p[0] == '.' && p[1] == '.') {
while (xp > Xstring(*xsp, xp)) {
xp--;
if (ISDIRSEP(*xp))
break;
}
continue;
}
savepos = Xsavepos(*xsp, xp);
Xput(*xsp, xp, DIRSEP);
XcheckN(*xsp, xp, len + 1);
memcpy(xp, p, len);
xp += len;
*xp = '\0';
llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
if (llen < 0) {
/* EINVAL means it wasn't a symlink... */
if (errno != EINVAL)
return (char *) 0;
continue;
}
lbuf[llen] = '\0';
/* If absolute path, start from scratch.. */
xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
: Xrestpos(*xsp, xp, savepos);
if (!(xp = do_phys_path(xsp, xp, lbuf)))
return (char *) 0;
}
return xp;
}
#endif /* S_ISLNK */
#ifdef TEST
main(argc, argv)
{
int rv;
char *cp, cdpath[256], pwd[256], file[256], result[256];
printf("enter CDPATH: "); gets(cdpath);
printf("enter PWD: "); gets(pwd);
while (1) {
if (printf("Enter file: "), gets(file) == 0)
return 0;
cp = cdpath;
do {
rv = make_path(pwd, file, &cp, result, sizeof(result));
printf("make_path returns (%d), \"%s\" ", rv, result);
simplify_path(result);
printf("(simpifies to \"%s\")\n", result);
} while (cp);
}
}
#endif /* TEST */

298
bin/ksh/proto.h Normal file
View file

@ -0,0 +1,298 @@
/* $NetBSD: proto.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
/*
* prototypes for PD-KSH
* originally generated using "cproto.c 3.5 92/04/11 19:28:01 cthuang "
* $Id: proto.h,v 1.7 2005/06/26 19:09:00 christos Exp $
*/
/* alloc.c */
Area * ainit ARGS((Area *));
void afreeall ARGS((Area *));
void * alloc ARGS((size_t, Area *));
void * aresize ARGS((void *, size_t, Area *));
void afree ARGS((void *, Area *));
/* c_ksh.c */
int c_hash ARGS((char **));
int c_cd ARGS((char **));
int c_pwd ARGS((char **));
int c_print ARGS((char **));
int c_whence ARGS((char **));
int c_command ARGS((char **));
int c_typeset ARGS((char **));
int c_alias ARGS((char **));
int c_unalias ARGS((char **));
int c_let ARGS((char **));
int c_jobs ARGS((char **));
int c_fgbg ARGS((char **));
int c_kill ARGS((char **));
void getopts_reset ARGS((int));
int c_getopts ARGS((char **));
int c_bind ARGS((char **));
/* c_sh.c */
int c_label ARGS((char **));
int c_shift ARGS((char **));
int c_umask ARGS((char **));
int c_dot ARGS((char **));
int c_wait ARGS((char **));
int c_read ARGS((char **));
int c_eval ARGS((char **));
int c_trap ARGS((char **));
int c_brkcont ARGS((char **));
int c_exitreturn ARGS((char **));
int c_set ARGS((char **));
int c_unset ARGS((char **));
int c_ulimit ARGS((char **));
int c_times ARGS((char **));
int timex ARGS((struct op *, int));
void timex_hook ARGS((struct op *, char ** volatile *));
int c_exec ARGS((char **));
int c_builtin ARGS((char **));
/* c_test.c */
int c_test ARGS((char **));
/* edit.c: most prototypes in edit.h */
void x_init ARGS((void));
int x_read ARGS((char *, size_t));
void set_editmode ARGS((const char *));
/* emacs.c: most prototypes in edit.h */
int x_bind ARGS((const char *, const char *, int, int));
/* eval.c */
char * substitute ARGS((const char *, int));
char ** eval ARGS((char **, int));
char * evalstr ARGS((char *, int));
char * evalonestr ARGS((char *, int));
char *debunk ARGS((char *, const char *, size_t));
void expand ARGS((char *, XPtrV *, int));
int glob_str ARGS((char *, XPtrV *, int));
/* exec.c */
int fd_clexec ARGS((int));
int execute ARGS((struct op * volatile, volatile int));
int shcomexec ARGS((char **));
struct tbl * findfunc ARGS((const char *, unsigned int, int));
int define ARGS((const char *, struct op *));
void builtin ARGS((const char *, int (*)(char **)));
struct tbl * findcom ARGS((const char *, int));
void flushcom ARGS((int all));
char * search ARGS((const char *, const char *, int, int *));
int search_access ARGS((const char *, int, int *));
int pr_menu ARGS((char *const *));
int pr_list ARGS((char *const *));
/* expr.c */
int evaluate ARGS((const char *, long *, int));
int v_evaluate ARGS((struct tbl *, const char *, volatile int));
/* history.c */
void init_histvec ARGS((void));
void hist_init ARGS((Source *));
void hist_finish ARGS((void));
void histsave ARGS((int, const char *, int));
#ifdef HISTORY
int c_fc ARGS((char **));
void sethistsize ARGS((int));
void sethistfile ARGS((const char *));
# ifdef EASY_HISTORY
void histappend ARGS((const char *, int));
# endif
char ** histpos ARGS((void));
int histN ARGS((void));
int histnum ARGS((int));
int findhist ARGS((int, int, const char *, int));
#endif /* HISTORY */
/* io.c */
void errorf ARGS((const char *, ...))
GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
void warningf ARGS((int, const char *, ...))
GCC_FUNC_ATTR(format(printf, 2, 3));
void bi_errorf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void internal_errorf ARGS((int, const char *, ...))
GCC_FUNC_ATTR(format(printf, 2, 3));
void error_prefix ARGS((int));
void shellf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void shprintf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
#ifdef KSH_DEBUG
void kshdebug_init_ ARGS((void));
void kshdebug_printf_ ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void kshdebug_dump_ ARGS((const char *, const void *, int));
#endif /* KSH_DEBUG */
int can_seek ARGS((int));
void initio ARGS((void));
int ksh_dup2 ARGS((int, int, int));
int savefd ARGS((int, int));
void restfd ARGS((int, int));
void openpipe ARGS((int *));
void closepipe ARGS((int *));
int check_fd ARGS((char *, int, const char **));
#ifdef KSH
void coproc_init ARGS((void));
void coproc_read_close ARGS((int));
void coproc_readw_close ARGS((int));
void coproc_write_close ARGS((int));
int coproc_getfd ARGS((int, const char **));
void coproc_cleanup ARGS((int));
#endif /* KSH */
struct temp *maketemp ARGS((Area *, Temp_type, struct temp **));
/* jobs.c */
void j_init ARGS((int));
void j_exit ARGS((void));
void j_change ARGS((void));
int exchild ARGS((struct op *, int, int));
void startlast ARGS((void));
int waitlast ARGS((void));
int waitfor ARGS((const char *, int *));
int j_kill ARGS((const char *, int));
int j_resume ARGS((const char *, int));
int j_jobs ARGS((const char *, int, int));
void j_notify ARGS((void));
pid_t j_async ARGS((void));
int j_stopped_running ARGS((void));
/* lex.c */
int yylex ARGS((int));
void yyerror ARGS((const char *, ...))
GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
Source * pushs ARGS((int, Area *));
void set_prompt ARGS((int, Source *));
void pprompt ARGS((const char *, int));
/* mail.c */
#ifdef KSH
void mcheck ARGS((void));
void mcset ARGS((long));
void mbset ARGS((char *));
void mpset ARGS((char *));
#endif /* KSH */
/* main.c */
int include ARGS((const char *, int, char **, int));
int command ARGS((const char *));
int shell ARGS((Source *volatile, int volatile));
void unwind ARGS((int)) GCC_FUNC_ATTR(noreturn);
void newenv ARGS((int));
void quitenv ARGS((void));
void cleanup_parents_env ARGS((void));
void cleanup_proc_env ARGS((void));
void aerror ARGS((Area *, const char *))
GCC_FUNC_ATTR(noreturn);
/* misc.c */
void setctypes ARGS((const char *, int));
void initctypes ARGS((void));
char * ulton ARGS((unsigned long, int));
char * str_save ARGS((const char *, Area *));
char * str_nsave ARGS((const char *, int, Area *));
int option ARGS((const char *));
char * getoptions ARGS((void));
void change_flag ARGS((enum sh_flag, int, int));
int parse_args ARGS((char **v, int what, int *));
int getn ARGS((const char *, int *));
int bi_getn ARGS((const char *, int *));
int gmatch ARGS((const char *, const char *, int));
int has_globbing ARGS((const char *, const char *));
const unsigned char *pat_scan ARGS((const unsigned char *,
const unsigned char *, int));
void qsortp ARGS((void **, size_t, int (*)(void *, void *)));
int xstrcmp ARGS((void *, void *));
void ksh_getopt_reset ARGS((Getopt *, int));
int ksh_getopt ARGS((char **, Getopt *, const char *));
void print_value_quoted ARGS((const char *));
void print_columns ARGS((struct shf *, int,
char *(*)(void *, int, char *, int),
void *, int, int));
int strip_nuls ARGS((char *, int));
char *str_zcpy ARGS((char *, const char *, int));
int blocking_read ARGS((int, char *, int));
int reset_nonblock ARGS((int));
char *ksh_get_wd ARGS((char *, int));
/* path.c */
int make_path ARGS((const char *, const char *,
char **, XString *, int *));
void simplify_path ARGS((char *));
char *get_phys_path ARGS((const char *));
void set_current_wd ARGS((char *));
/* syn.c */
void initkeywords ARGS((void));
struct op * compile ARGS((Source *));
/* table.c */
unsigned int hash ARGS((const char *));
void tinit ARGS((struct table *, Area *, int));
struct tbl * tsearch ARGS((struct table *, const char *, unsigned int));
struct tbl * tenter ARGS((struct table *, const char *, unsigned int));
void tdelete ARGS((struct tbl *));
void twalk ARGS((struct tstate *, struct table *));
struct tbl * tnext ARGS((struct tstate *));
struct tbl ** tsort ARGS((struct table *));
/* trace.c */
/* trap.c */
void inittraps ARGS((void));
#ifdef KSH
void alarm_init ARGS((void));
#endif /* KSH */
Trap * gettrap ARGS((const char *, int));
RETSIGTYPE trapsig ARGS((int));
void intrcheck ARGS((void));
int fatal_trap_check ARGS((void));
int trap_pending ARGS((void));
void runtraps ARGS((int));
void runtrap ARGS((Trap *));
void cleartraps ARGS((void));
void restoresigs ARGS((void));
void settrap ARGS((Trap *, char *));
int block_pipe ARGS((void));
void restore_pipe ARGS((int));
int setsig ARGS((Trap *, handler_t, int));
void setexecsig ARGS((Trap *, int));
/* tree.c */
int fptreef ARGS((struct shf *, int, const char *, ...));
char * snptreef ARGS((char *, int, const char *, ...));
struct op * tcopy ARGS((struct op *, Area *));
char * wdcopy ARGS((const char *, Area *));
char * wdscan ARGS((const char *, int));
char * wdstrip ARGS((const char *));
void tfree ARGS((struct op *, Area *));
/* var.c */
void newblock ARGS((void));
void popblock ARGS((void));
void initvar ARGS((void));
struct tbl * global ARGS((const char *));
struct tbl * local ARGS((const char *, bool_t));
char * str_val ARGS((struct tbl *));
long intval ARGS((struct tbl *));
int setstr ARGS((struct tbl *, const char *, int));
struct tbl *setint_v ARGS((struct tbl *, struct tbl *));
void setint ARGS((struct tbl *, long));
int getint ARGS((struct tbl *, long *));
struct tbl * typeset ARGS((const char *, Tflag, Tflag, int, int));
void unset ARGS((struct tbl *, int));
char * skip_varname ARGS((const char *, int));
char *skip_wdvarname ARGS((const char *, int));
int is_wdvarname ARGS((const char *, int));
int is_wdvarassign ARGS((const char *));
char ** makenv ARGS((void));
void change_random ARGS((void));
int array_ref_len ARGS((const char *));
char * arrayname ARGS((const char *));
void set_array ARGS((const char *, int, char **));
/* version.c */
/* vi.c: see edit.h */
/* Hack to avoid billions of compile warnings on SunOS 4.1.x */
#if defined(MUN) && defined(sun) && !defined(__svr4__)
extern void bcopy ARGS((const void *, void *, size_t));
extern intclose ARGS((FILE *));
extern intprintf ARGS((FILE *, const char *, ...));
extern intread ARGS((void *, int, int, FILE *));
extern int ioctl ARGS((int, int, void *));
extern int killpg ARGS((int, int));
extern int nice ARGS((int));
extern int readlink ARGS((const char *, char *, int));
extern int setpgrp ARGS((int, int));
extern int strcasecmp ARGS((const char *, const char *));
extern int tolower ARGS((int));
extern int toupper ARGS((int));
/* Include files aren't included yet */
extern int getrlimit ARGS(( /* int, struct rlimit * */ ));
extern int getrusage ARGS(( /* int, struct rusage * */ ));
extern int gettimeofday ARGS(( /* struct timeval *, struct timezone * */ ));
extern int setrlimit ARGS(( /* int, struct rlimit * */ ));
extern int lstat ARGS(( /* const char *, struct stat * */ ));
#endif

735
bin/ksh/sh.h Normal file
View file

@ -0,0 +1,735 @@
/* $NetBSD: sh.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
/*
* Public Domain Bourne/Korn shell
*/
/* $Id: sh.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
#include "config.h" /* system and option configuration info */
#ifdef HAVE_PROTOTYPES
# define ARGS(args) args /* prototype declaration */
#else
# define ARGS(args) () /* K&R declaration */
#endif
/* Start of common headers */
#include <stdio.h>
#include <sys/types.h>
#include <setjmp.h>
#ifdef HAVE_STDDEF_H
# include <stddef.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#else
/* just a useful subset of what stdlib.h would have */
extern char * getenv ARGS((const char *));
extern void * malloc ARGS((size_t));
extern void * realloc ARGS((void *, size_t));
extern int free ARGS((void *));
extern int exit ARGS((int));
extern int rand ARGS((void));
extern void srand ARGS((unsigned int));
extern int atoi ARGS((const char *));
#endif /* HAVE_STDLIB_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#else
/* just a useful subset of what unistd.h would have */
extern int access ARGS((const char *, int));
extern int open ARGS((const char *, int, ...));
extern int creat ARGS((const char *, mode_t));
extern int read ARGS((int, char *, unsigned));
extern int write ARGS((int, const char *, unsigned));
extern off_t lseek ARGS((int, off_t, int));
extern int close ARGS((int));
extern int pipe ARGS((int []));
extern int dup2 ARGS((int, int));
extern int unlink ARGS((const char *));
extern int fork ARGS((void));
extern int execve ARGS((const char *, char * const[], char * const[]));
extern int chdir ARGS((const char *));
extern int kill ARGS((pid_t, int));
extern char *getcwd(); /* no ARGS here - differs on different machines */
extern int geteuid ARGS((void));
extern int readlink ARGS((const char *, char *, int));
extern int getegid ARGS((void));
extern int getpid ARGS((void));
extern int getppid ARGS((void));
extern unsigned int sleep ARGS((unsigned int));
extern int isatty ARGS((int));
# ifdef POSIX_PGRP
extern int getpgrp ARGS((void));
extern int setpgid ARGS((pid_t, pid_t));
# endif /* POSIX_PGRP */
# ifdef BSD_PGRP
extern int getpgrp ARGS((pid_t));
extern int setpgrp ARGS((pid_t, pid_t));
# endif /* BSD_PGRP */
# ifdef SYSV_PGRP
extern int getpgrp ARGS((void));
extern int setpgrp ARGS((void));
# endif /* SYSV_PGRP */
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
# define strchr index
# define strrchr rindex
#endif /* HAVE_STRING_H */
#ifndef HAVE_STRSTR
char *strstr ARGS((const char *s, const char *p));
#endif /* HAVE_STRSTR */
#ifndef HAVE_STRCASECMP
int strcasecmp ARGS((const char *s1, const char *s2));
int strncasecmp ARGS((const char *s1, const char *s2, int n));
#endif /* HAVE_STRCASECMP */
#ifdef HAVE_MEMORY_H
# include <memory.h>
#endif
#ifndef HAVE_MEMSET
# define memcpy(d, s, n) bcopy(s, d, n)
# define memcmp(s1, s2, n) bcmp(s1, s2, n)
void *memset ARGS((void *d, int c, size_t n));
#endif /* HAVE_MEMSET */
#ifndef HAVE_MEMMOVE
# ifdef HAVE_BCOPY
# define memmove(d, s, n) bcopy(s, d, n)
# else
void *memmove ARGS((void *d, const void *s, size_t n));
# endif
#endif /* HAVE_MEMMOVE */
#ifdef HAVE_PROTOTYPES
# include <stdarg.h>
# define SH_VA_START(va, argn) va_start(va, argn)
#else
# include <varargs.h>
# define SH_VA_START(va, argn) va_start(va)
#endif /* HAVE_PROTOTYPES */
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif /* HAVE_FCNTL_H */
#ifndef O_ACCMODE
# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
#endif /* !O_ACCMODE */
#ifndef F_OK /* access() arguments */
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
#endif /* !F_OK */
#ifndef SEEK_SET
# ifdef L_SET
# define SEEK_SET L_SET
# define SEEK_CUR L_INCR
# define SEEK_END L_XTND
# else /* L_SET */
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
# endif /* L_SET */
#endif /* !SEEK_SET */
/* Some machines (eg, FreeBSD 1.1.5) define CLK_TCK in limits.h
* (ksh_limval.h assumes limits has been included, if available)
*/
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif /* HAVE_LIMITS_H */
#include <signal.h>
#ifdef NSIG
# define SIGNALS NSIG
#else
# ifdef _MINIX
# define SIGNALS (_NSIG+1) /* _NSIG is # of signals used, excluding 0. */
# else
# ifdef _SIGMAX /* QNX */
# define SIGNALS _SIGMAX
# else /* _SIGMAX */
# define SIGNALS 32
# endif /* _SIGMAX */
# endif /* _MINIX */
#endif /* NSIG */
#ifndef SIGCHLD
# define SIGCHLD SIGCLD
#endif
/* struct sigaction.sa_flags is set to KSH_SA_FLAGS. Used to ensure
* system calls are interrupted
*/
#ifdef SA_INTERRUPT
# define KSH_SA_FLAGS SA_INTERRUPT
#else /* SA_INTERRUPT */
# define KSH_SA_FLAGS 0
#endif /* SA_INTERRUPT */
typedef RETSIGTYPE (*handler_t) ARGS((int)); /* signal handler */
#ifdef USE_FAKE_SIGACT
# include "sigact.h" /* use sjg's fake sigaction() */
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif /* HAVE_PATHS_H */
#ifdef _PATH_DEFPATH
# define DEFAULT__PATH _PATH_DEFPATH
#else /* _PATH_DEFPATH */
# define DEFAULT__PATH DEFAULT_PATH
#endif /* _PATH_DEFPATH */
#ifndef offsetof
# define offsetof(type,id) ((size_t)&((type*)NULL)->id)
#endif
#ifndef HAVE_KILLPG
# define killpg(p, s) kill(-(p), (s))
#endif /* !HAVE_KILLPG */
/* Special cases for execve(2) */
#ifdef OS2
extern int ksh_execve(char *cmd, char **args, char **env, int flags);
#else /* OS2 */
# if defined(OS_ISC) && defined(_POSIX_SOURCE)
/* Kludge for ISC 3.2 (and other versions?) so programs will run correctly. */
# define ksh_execve(p, av, ev, flags) \
do { \
__setostype(0); \
execve(p, av, ev); \
__setostype(1); \
} while (0)
# else /* OS_ISC && _POSIX */
# define ksh_execve(p, av, ev, flags) execve(p, av, ev)
# endif /* OS_ISC && _POSIX */
#endif /* OS2 */
/* this is a hang-over from older versions of the os2 port */
#define ksh_dupbase(fd, base) fcntl(fd, F_DUPFD, base)
#ifdef HAVE_SIGSETJMP
# define ksh_sigsetjmp(env,sm) sigsetjmp((env), (sm))
# define ksh_siglongjmp(env,v) siglongjmp((env), (v))
# define ksh_jmp_buf sigjmp_buf
#else /* HAVE_SIGSETJMP */
# ifdef HAVE__SETJMP
# define ksh_sigsetjmp(env,sm) _setjmp(env)
# define ksh_siglongjmp(env,v) _longjmp((env), (v))
# else /* HAVE__SETJMP */
# define ksh_sigsetjmp(env,sm) setjmp(env)
# define ksh_siglongjmp(env,v) longjmp((env), (v))
# endif /* HAVE__SETJMP */
# define ksh_jmp_buf jmp_buf
#endif /* HAVE_SIGSETJMP */
#ifndef HAVE_DUP2
extern int dup2 ARGS((int, int));
#endif /* !HAVE_DUP2 */
/* Find a integer type that is at least 32 bits (or die) - SIZEOF_* defined
* by autoconf (assumes an 8 bit byte, but I'm not concerned).
* NOTE: INT32 may end up being more than 32 bits.
*/
#if SIZEOF_INT >= 4
# define INT32 int
#else /* SIZEOF_INT */
# if SIZEOF_LONG >= 4
# define INT32 long
# else /* SIZEOF_LONG */
#error cannot find 32 bit type...
# endif /* SIZEOF_LONG */
#endif /* SIZEOF_INT */
/* end of common headers */
/* Stop gcc and lint from complaining about possibly uninitialized variables */
#if defined(__GNUC__) || defined(lint)
# define UNINITIALIZED(var) var = 0
#else
# define UNINITIALIZED(var) var
#endif /* GNUC || lint */
/* some useful #defines */
#ifdef EXTERN
# define I__(i) = i
#else
# define I__(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
#ifdef OS2
# define inDOS() (!(_emx_env & 0x200))
#endif
#ifndef EXECSHELL
/* shell to exec scripts (see also $SHELL initialization in main.c) */
# ifdef OS2
# define EXECSHELL (inDOS() ? "c:\\command.com" : "c:\\os2\\cmd.exe")
# define EXECSHELL_STR (inDOS() ? "COMSPEC" : "OS2_SHELL")
# else /* OS2 */
# define EXECSHELL "/bin/sh"
# define EXECSHELL_STR "EXECSHELL"
# endif /* OS2 */
#endif
/* ISABSPATH() means path is fully and completely specified,
* ISROOTEDPATH() means a .. as the first component is a no-op,
* ISRELPATH() means $PWD can be tacked on to get an absolute path.
*
* OS Path ISABSPATH ISROOTEDPATH ISRELPATH
* unix /foo yes yes no
* unix foo no no yes
* unix ../foo no no yes
* os2+cyg a:/foo yes yes no
* os2+cyg a:foo no no no
* os2+cyg /foo no yes no
* os2+cyg foo no no yes
* os2+cyg ../foo no no yes
* cyg //foo yes yes no
*/
#ifdef OS2
# define PATHSEP ';'
# define DIRSEP '/' /* even though \ is native */
# define DIRSEPSTR "\\"
# define ISDIRSEP(c) ((c) == '\\' || (c) == '/')
# define ISABSPATH(s) (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])))
# define ISROOTEDPATH(s) (ISDIRSEP((s)[0]) || ISABSPATH(s))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
# define FILECHCONV(c) (isascii(c) && isupper(c) ? tolower(c) : c)
# define FILECMP(s1, s2) stricmp(s1, s2)
# define FILENCMP(s1, s2, n) strnicmp(s1, s2, n)
extern char *ksh_strchr_dirsep(const char *path);
extern char *ksh_strrchr_dirsep(const char *path);
# define chdir _chdir2
# define getcwd _getcwd2
#else
# define PATHSEP ':'
# define DIRSEP '/'
# define DIRSEPSTR "/"
# define ISDIRSEP(c) ((c) == '/')
#ifdef __CYGWIN__
# define ISABSPATH(s) \
(((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])) || ISDIRSEP((s)[0]))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
#else /* __CYGWIN__ */
# define ISABSPATH(s) ISDIRSEP((s)[0])
# define ISRELPATH(s) (!ISABSPATH(s))
#endif /* __CYGWIN__ */
# define ISROOTEDPATH(s) ISABSPATH(s)
# define FILECHCONV(c) c
# define FILECMP(s1, s2) strcmp(s1, s2)
# define FILENCMP(s1, s2, n) strncmp(s1, s2, n)
# define ksh_strchr_dirsep(p) strchr(p, DIRSEP)
# define ksh_strrchr_dirsep(p) strrchr(p, DIRSEP)
#endif
typedef int bool_t;
#define FALSE 0
#define TRUE 1
#define NELEM(a) (sizeof(a) / sizeof((a)[0]))
#define sizeofN(type, n) (sizeof(type) * (n))
#define BIT(i) (1<<(i)) /* define bit in flag */
/* Table flag type - needs > 16 and < 32 bits */
typedef INT32 Tflag;
#define NUFILE 32 /* Number of user-accessible files */
#define FDBASE 10 /* First file usable by Shell */
/* you're not going to run setuid shell scripts, are you? */
#define eaccess(path, mode) access(path, mode)
/* Make MAGIC a char that might be printed to make bugs more obvious, but
* not a char that is used often. Also, can't use the high bit as it causes
* portability problems (calling strchr(x, 0x80|'x') is error prone).
*/
#define MAGIC (7) /* prefix for *?[!{,} during expand */
#define ISMAGIC(c) ((unsigned char)(c) == MAGIC)
#define NOT '!' /* might use ^ (ie, [!...] vs [^..]) */
#define LINE 1024 /* input line size */
#define PATH 1024 /* pathname size (todo: PATH_MAX/pathconf()) */
#define ARRAYMAX 1023 /* max array index */
EXTERN const char *kshname; /* $0 */
EXTERN pid_t kshpid; /* $$, shell pid */
EXTERN pid_t procpid; /* pid of executing process */
EXTERN uid_t ksheuid; /* effective uid of shell */
EXTERN int exstat; /* exit status */
EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
/*
* Area-based allocation built on malloc/free
*/
typedef struct Area {
struct link *freelist; /* free list */
} Area;
EXTERN Area aperm; /* permanent object space */
#define APERM &aperm
#define ATEMP &e->area
#ifdef MEM_DEBUG
# include "chmem.h" /* a debugging front end for malloc et. al. */
#endif /* MEM_DEBUG */
#ifdef KSH_DEBUG
# define kshdebug_init() kshdebug_init_()
# define kshdebug_printf(a) kshdebug_printf_ a
# define kshdebug_dump(a) kshdebug_dump_ a
#else /* KSH_DEBUG */
# define kshdebug_init()
# define kshdebug_printf(a)
# define kshdebug_dump(a)
#endif /* KSH_DEBUG */
/*
* parsing & execution environment
*/
EXTERN struct env {
short type; /* environment type - see below */
short flags; /* EF_* */
Area area; /* temporary allocation area */
struct block *loc; /* local variables and functions */
short *savefd; /* original redirected fd's */
struct env *oenv; /* link to previous environment */
ksh_jmp_buf jbuf; /* long jump back to env creator */
struct temp *temps; /* temp files */
} *e;
/* struct env.type values */
#define E_NONE 0 /* dummy environment */
#define E_PARSE 1 /* parsing command # */
#define E_FUNC 2 /* executing function # */
#define E_INCL 3 /* including a file via . # */
#define E_EXEC 4 /* executing command tree */
#define E_LOOP 5 /* executing for/while # */
#define E_ERRH 6 /* general error handler # */
/* # indicates env has valid jbuf (see unwind()) */
/* struct env.flag values */
#define EF_FUNC_PARSE BIT(0) /* function being parsed */
#define EF_BRKCONT_PASS BIT(1) /* set if E_LOOP must pass break/continue on */
#define EF_FAKE_SIGDIE BIT(2) /* hack to get info from unwind to quitenv */
/* Do breaks/continues stop at env type e? */
#define STOP_BRKCONT(t) ((t) == E_NONE || (t) == E_PARSE \
|| (t) == E_FUNC || (t) == E_INCL)
/* Do returns stop at env type e? */
#define STOP_RETURN(t) ((t) == E_FUNC || (t) == E_INCL)
/* values for ksh_siglongjmp(e->jbuf, 0) */
#define LRETURN 1 /* return statement */
#define LEXIT 2 /* exit statement */
#define LERROR 3 /* errorf() called */
#define LLEAVE 4 /* untrappable exit/error */
#define LINTR 5 /* ^C noticed */
#define LBREAK 6 /* break statement */
#define LCONTIN 7 /* continue statement */
#define LSHELL 8 /* return to interactive shell() */
#define LAEXPR 9 /* error in arithmetic expression */
/* option processing */
#define OF_CMDLINE 0x01 /* command line */
#define OF_SET 0x02 /* set builtin */
#define OF_SPECIAL 0x04 /* a special variable changing */
#define OF_INTERNAL 0x08 /* set internally by shell */
#define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
struct option {
const char *name; /* long name of option */
char c; /* character flag (if any) */
short flags; /* OF_* */
};
extern const struct option goptions[];
/*
* flags (the order of these enums MUST match the order in misc.c(options[]))
*/
enum sh_flag {
FEXPORT = 0, /* -a: export all */
#ifdef BRACE_EXPAND
FBRACEEXPAND, /* enable {} globbing */
#endif
FBGNICE, /* bgnice */
FCOMMAND, /* -c: (invocation) execute specified command */
#ifdef EMACS
FEMACS, /* emacs command editing */
FEMACSUSEMETA, /* use 8th bit as meta */
#endif
FERREXIT, /* -e: quit on error */
#ifdef EMACS
FGMACS, /* gmacs command editing */
#endif
FIGNOREEOF, /* eof does not exit */
FTALKING, /* -i: interactive */
FKEYWORD, /* -k: name=value anywhere */
FLOGIN, /* -l: a login shell */
FMARKDIRS, /* mark dirs with / in file name completion */
FMONITOR, /* -m: job control monitoring */
FNOCLOBBER, /* -C: don't overwrite existing files */
FNOEXEC, /* -n: don't execute any commands */
FNOGLOB, /* -f: don't do file globbing */
FNOHUP, /* -H: don't kill running jobs when login shell exits */
FNOLOG, /* don't save functions in history (ignored) */
#ifdef JOBS
FNOTIFY, /* -b: asynchronous job completion notification */
#endif
FNOUNSET, /* -u: using an unset var is an error */
FPHYSICAL, /* -o physical: don't do logical cd's/pwd's */
FPOSIX, /* -o posix: be posixly correct */
FPRIVILEGED, /* -p: use suid_profile */
FRESTRICTED, /* -r: restricted shell */
FSTDIN, /* -s: (invocation) parse stdin */
FTRACKALL, /* -h: create tracked aliases for all commands */
FVERBOSE, /* -v: echo input */
#ifdef VI
FVI, /* vi command editing */
FVIRAW, /* always read in raw mode (ignored) */
FVISHOW8, /* display chars with 8th bit set as is (versus M-) */
FVITABCOMPLETE, /* enable tab as file name completion char */
FVIESCCOMPLETE, /* enable ESC as file name completion in command mode */
#endif
FXTRACE, /* -x: execution trace */
FTALKING_I, /* (internal): initial shell was interactive */
FNFLAGS /* (place holder: how many flags are there) */
};
#define Flag(f) (shell_flags[(int) (f)])
EXTERN char shell_flags [FNFLAGS];
EXTERN char null [] I__(""); /* null value for variable */
EXTERN char space [] I__(" ");
EXTERN char newline [] I__("\n");
EXTERN char slash [] I__("/");
enum temp_type {
TT_HEREDOC_EXP, /* expanded heredoc */
TT_HIST_EDIT /* temp file used for history editing (fc -e) */
};
typedef enum temp_type Temp_type;
/* temp/heredoc files. The file is removed when the struct is freed. */
struct temp {
struct temp *next;
struct shf *shf;
int pid; /* pid of process parsed here-doc */
Temp_type type;
char *name;
};
/*
* stdio and our IO routines
*/
#define shl_spare (&shf_iob[0]) /* for c_read()/c_print() */
#define shl_stdout (&shf_iob[1])
#define shl_out (&shf_iob[2])
EXTERN int shl_stdout_ok;
/*
* trap handlers
*/
typedef struct trap {
int signal; /* signal number */
const char *name; /* short name */
const char *mess; /* descriptive name */
char *trap; /* trap command */
int volatile set; /* trap pending */
int flags; /* TF_* */
handler_t cursig; /* current handler (valid if TF_ORIG_* set) */
handler_t shtrap; /* shell signal handler */
} Trap;
/* values for Trap.flags */
#define TF_SHELL_USES BIT(0) /* shell uses signal, user can't change */
#define TF_USER_SET BIT(1) /* user has (tried to) set trap */
#define TF_ORIG_IGN BIT(2) /* original action was SIG_IGN */
#define TF_ORIG_DFL BIT(3) /* original action was SIG_DFL */
#define TF_EXEC_IGN BIT(4) /* restore SIG_IGN just before exec */
#define TF_EXEC_DFL BIT(5) /* restore SIG_DFL just before exec */
#define TF_DFL_INTR BIT(6) /* when received, default action is LINTR */
#define TF_TTY_INTR BIT(7) /* tty generated signal (see j_waitj) */
#define TF_CHANGED BIT(8) /* used by runtrap() to detect trap changes */
#define TF_FATAL BIT(9) /* causes termination if not trapped */
/* values for setsig()/setexecsig() flags argument */
#define SS_RESTORE_MASK 0x3 /* how to restore a signal before an exec() */
#define SS_RESTORE_CURR 0 /* leave current handler in place */
#define SS_RESTORE_ORIG 1 /* restore original handler */
#define SS_RESTORE_DFL 2 /* restore to SIG_DFL */
#define SS_RESTORE_IGN 3 /* restore to SIG_IGN */
#define SS_FORCE BIT(3) /* set signal even if original signal ignored */
#define SS_USER BIT(4) /* user is doing the set (ie, trap command) */
#define SS_SHTRAP BIT(5) /* trap for internal use (CHLD,ALRM,WINCH) */
#define SIGEXIT_ 0 /* for trap EXIT */
#define SIGERR_ SIGNALS /* for trap ERR */
EXTERN int volatile trap; /* traps pending? */
EXTERN int volatile intrsig; /* pending trap interrupts executing command */
EXTERN int volatile fatal_trap;/* received a fatal signal */
#ifndef FROM_TRAP_C
/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
extern Trap sigtraps[SIGNALS+1];
#endif /* !FROM_TRAP_C */
#ifdef KSH
/*
* TMOUT support
*/
/* values for ksh_tmout_state */
enum tmout_enum {
TMOUT_EXECUTING = 0, /* executing commands */
TMOUT_READING, /* waiting for input */
TMOUT_LEAVING /* have timed out */
};
EXTERN unsigned int ksh_tmout;
EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING);
#endif /* KSH */
/* For "You have stopped jobs" message */
EXTERN int really_exit;
/*
* fast character classes
*/
#define C_ALPHA BIT(0) /* a-z_A-Z */
#define C_DIGIT BIT(1) /* 0-9 */
#define C_LEX1 BIT(2) /* \0 \t\n|&;<>() */
#define C_VAR1 BIT(3) /* *@#!$-? */
#define C_IFSWS BIT(4) /* \t \n (IFS white space) */
#define C_SUBOP1 BIT(5) /* "=-+?" */
#define C_SUBOP2 BIT(6) /* "#%" */
#define C_IFS BIT(7) /* $IFS */
#define C_QUOTE BIT(8) /* \n\t"#$&'()*;<>?[\`| (needing quoting) */
extern short ctypes [];
#define ctype(c, t) !!(ctypes[(unsigned char)(c)]&(t))
#define letter(c) ctype(c, C_ALPHA)
#define digit(c) ctype(c, C_DIGIT)
#define letnum(c) ctype(c, C_ALPHA|C_DIGIT)
EXTERN int ifs0 I__(' '); /* for "$*" */
/* Argument parsing for built-in commands and getopts command */
/* Values for Getopt.flags */
#define GF_ERROR BIT(0) /* call errorf() if there is an error */
#define GF_PLUSOPT BIT(1) /* allow +c as an option */
#define GF_NONAME BIT(2) /* don't print argv[0] in errors */
/* Values for Getopt.info */
#define GI_MINUS BIT(0) /* an option started with -... */
#define GI_PLUS BIT(1) /* an option started with +... */
#define GI_MINUSMINUS BIT(2) /* arguments were ended with -- */
typedef struct {
int optind;
int uoptind;/* what user sees in $OPTIND */
char *optarg;
int flags; /* see GF_* */
int info; /* see GI_* */
unsigned int p; /* 0 or index into argv[optind - 1] */
char buf[2]; /* for bad option OPTARG value */
} Getopt;
EXTERN Getopt builtin_opt; /* for shell builtin commands */
EXTERN Getopt user_opt; /* parsing state for getopts builtin command */
#ifdef KSH
/* This for co-processes */
typedef INT32 Coproc_id; /* something that won't (realisticly) wrap */
struct coproc {
int read; /* pipe from co-process's stdout */
int readw; /* other side of read (saved temporarily) */
int write; /* pipe to co-process's stdin */
Coproc_id id; /* id of current output pipe */
int njobs; /* number of live jobs using output pipe */
void *job; /* 0 or job of co-process using input pipe */
};
EXTERN struct coproc coproc;
#endif /* KSH */
/* Used in jobs.c and by coprocess stuff in exec.c */
#ifdef JOB_SIGS
EXTERN sigset_t sm_default, sm_sigchld;
#endif /* JOB_SIGS */
extern char ksh_version[];
/* name of called builtin function (used by error functions) */
EXTERN char *builtin_argv0;
EXTERN Tflag builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
/* current working directory, and size of memory allocated for same */
EXTERN char *current_wd;
EXTERN int current_wd_size;
#ifdef EDIT
/* Minimum required space to work with on a line - if the prompt leaves less
* space than this on a line, the prompt is truncated.
*/
# define MIN_EDIT_SPACE 7
/* Minimum allowed value for x_cols: 2 for prompt, 3 for " < " at end of line
*/
# define MIN_COLS (2 + MIN_EDIT_SPACE + 3)
EXTERN int x_cols I__(80); /* tty columns */
#else
# define x_cols 80 /* for pr_menu(exec.c) */
#endif
/* These to avoid bracket matching problems */
#define OPAREN '('
#define CPAREN ')'
#define OBRACK '['
#define CBRACK ']'
#define OBRACE '{'
#define CBRACE '}'
/* Determine the location of the system (common) profile */
#ifndef KSH_SYSTEM_PROFILE
# ifdef __NeXT
# define KSH_SYSTEM_PROFILE "/etc/profile.std"
# else /* __NeXT */
# define KSH_SYSTEM_PROFILE "/etc/profile"
# endif /* __NeXT */
#endif /* KSH_SYSTEM_PROFILE */
/* Used by v_evaluate() and setstr() to control action when error occurs */
#define KSH_UNWIND_ERROR 0 /* unwind the stack (longjmp) */
#define KSH_RETURN_ERROR 1 /* return 1/0 for success/failure */
#include "shf.h"
#include "table.h"
#include "tree.h"
#include "expand.h"
#include "lex.h"
#include "proto.h"
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef I__

1302
bin/ksh/shf.c Normal file

File diff suppressed because it is too large Load diff

87
bin/ksh/shf.h Normal file
View file

@ -0,0 +1,87 @@
/* $NetBSD: shf.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
#ifndef SHF_H
# define SHF_H
/*
* Shell file I/O routines
*/
/* $Id: shf.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
#define SHF_BSIZE 512
#define shf_fileno(shf) ((shf)->fd)
#define shf_setfileno(shf,nfd) ((shf)->fd = (nfd))
#define shf_getc(shf) ((shf)->rnleft > 0 ? (shf)->rnleft--, *(shf)->rp++ : \
shf_getchar(shf))
#define shf_putc(c, shf) ((shf)->wnleft == 0 ? shf_putchar((c), (shf)) \
: ((shf)->wnleft--, *(shf)->wp++ = (c)))
#define shf_eof(shf) ((shf)->flags & SHF_EOF)
#define shf_error(shf) ((shf)->flags & SHF_ERROR)
#define shf_errno(shf) ((shf)->errno_)
#define shf_clearerr(shf) ((shf)->flags &= ~(SHF_EOF | SHF_ERROR))
/* Flags passed to shf_*open() */
#define SHF_RD 0x0001
#define SHF_WR 0x0002
#define SHF_RDWR (SHF_RD|SHF_WR)
#define SHF_ACCMODE 0x0003 /* mask */
#define SHF_GETFL 0x0004 /* use fcntl() to figure RD/WR flags */
#define SHF_UNBUF 0x0008 /* unbuffered I/O */
#define SHF_CLEXEC 0x0010 /* set close on exec flag */
#define SHF_MAPHI 0x0020 /* make fd > FDBASE (and close orig)
* (shf_open() only) */
#define SHF_DYNAMIC 0x0040 /* string: increase buffer as needed */
#define SHF_INTERRUPT 0x0080 /* EINTR in read/write causes error */
/* Flags used internally */
#define SHF_STRING 0x0100 /* a string, not a file */
#define SHF_ALLOCS 0x0200 /* shf and shf->buf were alloc()ed */
#define SHF_ALLOCB 0x0400 /* shf->buf was alloc()ed */
#define SHF_ERROR 0x0800 /* read()/write() error */
#define SHF_EOF 0x1000 /* read eof (sticky) */
#define SHF_READING 0x2000 /* currently reading: rnleft,rp valid */
#define SHF_WRITING 0x4000 /* currently writing: wnleft,wp valid */
struct shf {
int flags; /* see SHF_* */
unsigned char *rp; /* read: current position in buffer */
int rbsize; /* size of buffer (1 if SHF_UNBUF) */
int rnleft; /* read: how much data left in buffer */
unsigned char *wp; /* write: current position in buffer */
int wbsize; /* size of buffer (0 if SHF_UNBUF) */
int wnleft; /* write: how much space left in buffer */
unsigned char *buf; /* buffer */
int fd; /* file descriptor */
int errno_; /* saved value of errno after error */
int bsize; /* actual size of buf */
Area *areap; /* area shf/buf were allocated in */
};
extern struct shf shf_iob[];
struct shf *shf_open ARGS((const char *name, int oflags, int mode,
int sflags));
struct shf *shf_fdopen ARGS((int fd, int sflags, struct shf *shf));
struct shf *shf_reopen ARGS((int fd, int sflags, struct shf *shf));
struct shf *shf_sopen ARGS((char *buf, int bsize, int sflags,
struct shf *shf));
int shf_close ARGS((struct shf *shf));
int shf_fdclose ARGS((struct shf *shf));
char *shf_sclose ARGS((struct shf *shf));
int shf_finish ARGS((struct shf *shf));
int shf_flush ARGS((struct shf *shf));
int shf_seek ARGS((struct shf *shf, off_t where, int from));
int shf_read ARGS((char *buf, int bsize, struct shf *shf));
char *shf_getse ARGS((char *buf, int bsize, struct shf *shf));
int shf_getchar ARGS((struct shf *shf));
int shf_ungetc ARGS((int c, struct shf *shf));
int shf_putchar ARGS((int c, struct shf *shf));
int shf_puts ARGS((const char *s, struct shf *shf));
int shf_write ARGS((const char *buf, int nbytes, struct shf *shf));
int shf_fprintf ARGS((struct shf *shf, const char *fmt, ...));
int shf_snprintf ARGS((char *buf, int bsize, const char *fmt, ...));
char *shf_smprintf ARGS((const char *fmt, ...));
int shf_vfprintf ARGS((struct shf *, const char *fmt, va_list args));
#endif /* SHF_H */

486
bin/ksh/sigact.c Normal file
View file

@ -0,0 +1,486 @@
/* $NetBSD: sigact.c,v 1.4 2003/06/23 11:39:03 agc Exp $ */
/* NAME:
* sigact.c - fake sigaction(2)
*
* SYNOPSIS:
* #include "sigact.h"
*
* int sigaction(int sig, struct sigaction *act,
* struct sigaction *oact);
* int sigaddset(sigset_t *mask, int sig);
* int sigdelset(sigset_t *mask, int sig);
* int sigemptyset(sigset_t *mask);
* int sigfillset(sigset_t *mask);
* int sigismember(sigset_t *mask, int sig);
* int sigpending(sigset_t *set);
* int sigprocmask(int how, sigset_t *set, sigset_t *oset);
* int sigsuspend(sigset_t *mask);
*
* RETSIGTYPE (*Signal(int sig, RETSIGTYPE (*disp)(int)))(int);
*
* DESCRIPTION:
* This is a fake sigaction implementation. It uses
* sigsetmask(2) et al or sigset(2) and friends if
* available, otherwise it just uses signal(2). If it
* thinks sigaction(2) really exists it compiles to "almost"
* nothing.
*
* In any case it provides a Signal() function that is
* implemented in terms of sigaction().
* If not using signal(2) as part of the underlying
* implementation (USE_SIGNAL or USE_SIGMASK), and
* NO_SIGNAL is not defined, it also provides a signal()
* function that calls Signal().
*
* The need for all this mucking about is the problems
* caused by mixing various signal handling mechanisms in
* the one process. This module allows for a consistent
* POSIX compliant interface to whatever is actually
* available.
*
* sigaction() allows the caller to examine and/or set the
* action to be associated with a given signal. "act" and
* "oact" are pointers to 'sigaction structs':
*.nf
*
* struct sigaction
* {
* RETSIGTYPE (*sa_handler)();
* sigset_t sa_mask;
* int sa_flags;
* };
*.fi
*
* RETSIGTYPE is normally 'void' in the POSIX implementation
* and for most current systems. On some older UNIX
* systems, signal handlers do not return 'void', so
* this implementation keeps 'sa_handler' inline with the
* hosts normal signal handling conventions.
* 'sa_mask' controls which signals will be blocked while
* the selected signal handler is active. It is not used
* in this implementation.
* 'sa_flags' controls various semantics such as whether
* system calls should be automagically restarted
* (SA_RESTART) etc. It is not used in this
* implementation.
* Either "act" or "oact" may be NULL in which case the
* appropriate operation is skipped.
*
* sigaddset() adds "sig" to the sigset_t pointed to by "mask".
*
* sigdelset() removes "sig" from the sigset_t pointed to
* by "mask".
*
* sigemptyset() makes the sigset_t pointed to by "mask" empty.
*
* sigfillset() makes the sigset_t pointed to by "mask"
* full ie. match all signals.
*
* sigismember() returns true if "sig" is found in "*mask".
*
* sigpending() is supposed to return "set" loaded with the
* set of signals that are blocked and pending for the
* calling process. It does nothing in this impementation.
*
* sigprocmask() is used to examine and/or change the
* signal mask for the calling process. Either "set" or
* "oset" may be NULL in which case the appropriate
* operation is skipped. "how" may be one of SIG_BLOCK,
* SIG_UNBLOCK or SIG_SETMASK. If this package is built
* with USE_SIGNAL, then this routine achieves nothing.
*
* sigsuspend() sets the signal mask to "*mask" and waits
* for a signal to be delivered after which the previous
* mask is restored.
*
*
* RETURN VALUE:
* 0==success, -1==failure
*
* BUGS:
* Since we fake most of this, don't expect fancy usage to
* work.
*
* AUTHOR:
* Simon J. Gerraty <sjg@zen.void.oz.au>
*/
/* COPYRIGHT:
* @(#)Copyright (c) 1992 Simon J. Gerraty
*
* This is free software. It comes with NO WARRANTY.
* Permission to use, modify and distribute this source code
* is granted subject to the following conditions.
* 1/ that that the above copyright notice and this notice
* are preserved in all copies and that due credit be given
* to the author.
* 2/ that any changes to this code are clearly commented
* as such so that the author does get blamed for bugs
* other than his own.
*
* Please send copies of changes and bug-fixes to:
* sjg@zen.void.oz.au
*
*/
/* Changes to sigact.c for pdksh, Michael Rendell <michael@cs.mun.ca>:
* - sigsuspend(): pass *mask to bsd4.2 sigpause instead of mask.
* - changed SIG_HDLR to RETSIGTYPE for use with GNU autoconf
* - added and used RETSIGVAL
* - include sh.h instead of signal.h (to get *_SIGNALS macros)
* - changed if !SA_NOCLDSTOP ... to USE_FAKE_SIGACT to avoid confusion
* - set the USE_* defines using the *_SIGNALS defines from autoconf
* - sigaction(): if using BSD signals, use sigvec() (used to use
* signal()) and set the SV_INTERRUPT flag (POSIX says syscalls
* are interrupted and pdksh needs this behaviour).
* - define IS_KSH before including anything; ifdef out routines
* not used in ksh if IS_KSH is defined (same in sigact.h).
* - use ARGS() instead of __P()
* - sigaction(),sigsuspend(),Signal(),signal(): use handler_t typedef
* instead of explicit type.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: sigact.c,v 1.4 2003/06/23 11:39:03 agc Exp $");
#endif
/*
#include <signal.h>
*/
#define IS_KSH
#include "sh.h"
/*
#ifndef __P
# define __P(p) p
#endif
*/
/*
* some systems have a faulty sigaction() implementation!
* Allow us to bypass it.
* Or they may have installed sigact.h as signal.h which is why
* we have SA_NOCLDSTOP defined.
*/
#ifdef USE_FAKE_SIGACT /* let autoconf decide.. */
/* #if !defined(SA_NOCLDSTOP) || defined(_SIGACT_H) || defined(USE_SIGNAL) || defined(USE_SIGSET) || defined(USE_SIGMASK) */
/* Let autoconf decide which to use */
#ifdef BSD42_SIGNALS
# define USE_SIGMASK
#else
# ifdef BSD41_SIGNALS
# define USE_SIGSET
# else
# define USE_SIGNAL
# endif
#endif /* BSD42_SIGNALS */
/*
* if we haven't been told,
* try and guess what we should implement with.
*/
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
# if defined(sigmask) || defined(BSD) || defined(_BSD) && !defined(BSD41)
# define USE_SIGMASK
# else
# ifndef NO_SIGSET
# define USE_SIGSET
# else
# define USE_SIGNAL
# endif
# endif
#endif
/*
* if we still don't know, we're in trouble
*/
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
error must know what to implement with
#endif
#include "sigact.h"
/*
* in case signal() has been mapped to our Signal().
*/
#undef signal
int
sigaction(sig, act, oact)
int sig;
struct sigaction *act, *oact;
{
handler_t oldh;
if (act)
{
#ifdef USE_SIGSET
oldh = sigset(sig, act->sa_handler);
#else
# ifdef USE_SIGMASK
struct sigvec nsv,osv;
nsv.sv_handler = act->sa_handler;
nsv.sv_mask = 0; /* punt */
nsv.sv_flags = SV_INTERRUPT; /* punt */
sigvec(sig, &nsv, &osv);
oldh = osv.sv_handler;
# else /* USE_SIGMASK */
oldh = signal(sig, act->sa_handler);
# endif /* USE_SIGMASK */
#endif
}
else
{
if (oact)
{
#ifdef USE_SIGSET
oldh = sigset(sig, SIG_IGN);
#else
oldh = signal(sig, SIG_IGN);
#endif
if (oldh != SIG_IGN && oldh != SIG_ERR)
{
#ifdef USE_SIGSET
(void) sigset(sig, oldh);
#else
(void) signal(sig, oldh);
#endif
}
}
}
if (oact)
{
oact->sa_handler = oldh;
}
return 0; /* hey we're faking it */
}
int
sigaddset(mask, sig)
sigset_t *mask;
int sig;
{
*mask |= sigmask(sig);
return 0;
}
#ifndef IS_KSH
int
sigdelset(mask, sig)
sigset_t *mask;
int sig;
{
*mask &= ~(sigmask(sig));
return 0;
}
#endif /* IS_KSH */
int
sigemptyset(mask)
sigset_t *mask;
{
*mask = 0;
return 0;
}
#ifndef IS_KSH
int
sigfillset(mask)
sigset_t *mask;
{
*mask = ~0;
return 0;
}
#endif /* IS_KSH */
#ifndef IS_KSH
int
sigismember(mask, sig)
sigset_t *mask;
int sig;
{
return ((*mask) & sigmask(sig));
}
#endif /* IS_KSH */
#ifndef IS_KSH
int
sigpending(set)
sigset_t *set;
{
return 0; /* faking it! */
}
#endif /* IS_KSH */
int
sigprocmask(how, set, oset)
int how;
sigset_t *set, *oset;
{
#ifdef USE_SIGSET
register int i;
#endif
static sigset_t sm;
static int once = 0;
if (!once)
{
/*
* initally we clear sm,
* there after, it represents the last
* thing we did.
*/
once++;
#ifdef USE_SIGMASK
sm = sigblock(0);
#else
sm = 0;
#endif
}
if (oset)
*oset = sm;
if (set)
{
switch (how)
{
case SIG_BLOCK:
sm |= *set;
break;
case SIG_UNBLOCK:
sm &= ~(*set);
break;
case SIG_SETMASK:
sm = *set;
break;
}
#ifdef USE_SIGMASK
(void) sigsetmask(sm);
#else
# ifdef USE_SIGSET
for (i = 1; i < NSIG; i++)
{
if (how == SIG_UNBLOCK)
{
if (*set & sigmask(i))
sigrelse(i);
}
else
if (sm & sigmask(i))
{
sighold(i);
}
}
# endif
#endif
}
return 0;
}
int
sigsuspend(mask)
sigset_t *mask;
{
#ifdef USE_SIGMASK
sigpause(*mask);
#else
register int i;
# ifdef USE_SIGSET
for (i = 1; i < NSIG; i++)
{
if (*mask & sigmask(i))
{
/* not the same sigpause() as above! */
sigpause(i);
break;
}
}
# else /* signal(2) only */
handler_t oldh;
/*
* make sure that signals in mask will not
* be ignored.
*/
for (i = 1; i < NSIG; i++)
{
if (*mask & sigmask(i))
{
if ((oldh = signal(i, SIG_DFL)) != SIG_ERR &&
oldh != SIG_IGN &&
oldh != SIG_DFL)
(void) signal(i, oldh); /* restore handler */
}
}
pause(); /* wait for a signal */
# endif
#endif
return 0;
}
#endif /* USE_FAKE_SIGACT (was ! SA_NOCLDSTOP) */
#if !defined(RETSIGTYPE)
# define RETSIGTYPE void
# define RETSIGVAL
#endif
#if !defined(SIG_ERR)
# define SIG_ERR (RETSIGTYPE (*)())-1
#endif
/*
* an implementation of signal() using sigaction().
*/
#ifndef IS_KSH
handler_t Signal(sig, handler)
int sig;
handler_t handler;
{
struct sigaction act, oact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
#endif /* IS_KSH */
#ifndef IS_KSH
#if !defined(USE_SIGNAL) && !defined(USE_SIGMASK) && !defined(NO_SIGNAL)
/*
* ensure we avoid signal mayhem
*/
handler_t signal(sig, handler)
int sig;
handler_t handler;
{
return (Signal(sig, handler));
}
#endif
#endif /* IS_KSH */
/* This lot (for GNU-Emacs) goes at the end of the file. */
/*
* Local Variables:
* version-control:t
* comment-column:40
* End:
*/

125
bin/ksh/sigact.h Normal file
View file

@ -0,0 +1,125 @@
/* $NetBSD: sigact.h,v 1.3 2002/05/25 23:29:17 wiz Exp $ */
/* NAME:
* sigact.h - sigaction et al
*
* SYNOPSIS:
* #include "sigact.h"
*
* DESCRIPTION:
* This header is the interface to a fake sigaction(2)
* implementation. It provides a POSIX compliant interface
* to whatever signal handling mechanisms are available.
* It also provides a Signal() function that is implemented
* in terms of sigaction().
* If not using signal(2) as part of the underlying
* implementation (USE_SIGNAL or USE_SIGMASK), and
* NO_SIGNAL is not defined, it also provides a signal()
* function that calls Signal().
*
* SEE ALSO:
* sigact.c
*/
/*
* RCSid:
* $NetBSD: sigact.h,v 1.3 2002/05/25 23:29:17 wiz Exp $
*/
/* Changes to sigact.h for pdksh, Michael Rendell <michael@cs.mun.ca>:
* - changed SIG_HDLR to RETSIGTYPE for use with GNU autoconf
* - added RETSIGVAL
* - ifdef'd out ARGS(), volatile and const initializations
* - ifdef'd out sigset_t definition - let autoconf handle it
* - ifdef out routines not used in ksh if IS_KSH is defined
* (same in sigact.c).
*/
#ifndef _SIGACT_H
#define _SIGACT_H
/*
* most modern systems use void for signal handlers but
* not all.
*/
#ifndef RETSIGTYPE
# define RETSIGTYPE void
# define RETSIGVAL
#endif
#if 0 /* ARGS(), volatile and const are already set up in config*.h -mhr */
#undef ARGS
#define ARGS(p) p
#endif
#ifndef IS_KSH
handler_t Signal ARGS((int sig, handler_t disp));
#endif /* IS_KSH */
/*
* if you want to install this header as signal.h,
* modify this to pick up the original signal.h
*/
#ifndef SIGKILL
# include <signal.h>
#endif
#ifndef SIG_ERR
# define SIG_ERR ((handler_t) -1)
#endif
#ifndef BADSIG
# define BADSIG SIG_ERR
#endif
#ifndef SA_NOCLDSTOP
/* we assume we need the fake sigaction */
/* sa_flags */
#define SA_NOCLDSTOP 1 /* don't send SIGCHLD on child stop */
#define SA_RESTART 2 /* re-start I/O */
/* sigprocmask flags */
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 4
#if 0 /* autoconf will define sigset_t if it isn't available */
/*
* this is a bit untidy
*/
#if !defined(__sys_stdtypes_h)
typedef unsigned int sigset_t;
#endif
#endif /* 0 */
/*
* POSIX sa_handler should return void, but since we are
* implementing in terms of something else, it may
* be appropriate to use the normal RETSIGTYPE return type
*/
struct sigaction
{
handler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
};
int sigaction ARGS(( int sig, struct sigaction *act, struct sigaction *oact ));
int sigaddset ARGS(( sigset_t *mask, int sig ));
#ifndef IS_KSH
int sigdelset ARGS(( sigset_t *mask, int sig ));
#endif /* IS_KSH */
int sigemptyset ARGS(( sigset_t *mask ));
#ifndef IS_KSH
int sigfillset ARGS(( sigset_t *mask ));
int sigismember ARGS(( sigset_t *mask, int sig ));
int sigpending ARGS(( sigset_t *set ));
#endif /* IS_KSH */
int sigprocmask ARGS(( int how, sigset_t *set, sigset_t *oset ));
int sigsuspend ARGS(( sigset_t *mask ));
#ifndef sigmask
# define sigmask(s) (1<<((s)-1)) /* convert SIGnum to mask */
#endif
#if !defined(NSIG) && defined(_NSIG)
# define NSIG _NSIG
#endif
#endif /* ! SA_NOCLDSTOP */
#endif /* _SIGACT_H */

56
bin/ksh/siglist.in Normal file
View file

@ -0,0 +1,56 @@
# $NetBSD: siglist.in,v 1.2 1997/01/12 19:12:17 tls Exp $
#
# List of signals used to initialize ksh's signal table (see trap.c
# and siglist.sh).
#
# Note that if a system has multiple defines for the same signal
# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one
# will be seen, so the order in this list is important.
#
HUP Hangup
INT Interrupt
QUIT Quit
ILL Illegal instruction
TRAP Trace trap
# before IOT (ABRT is posix and ABRT is sometimes the same as IOT)
ABRT Abort
IOT IOT instruction
EMT EMT trap
FPE Floating point exception
KILL Killed
# before BUS (linux doesn't really have a BUS, but defines it to UNUSED)
UNUSED Unused
BUS Bus error
SEGV Memory fault
SYS Bad system call
PIPE Broken pipe
ALRM Alarm clock
TERM Terminated
STKFLT Stack fault
IO I/O possible
XCPU CPU time limit exceeded
XFSZ File size limit exceeded
VTALRM Virtual timer expired
PROF Profiling timer expired
WINCH Window size change
LOST File lock lost
USR1 User defined signal 1
USR2 User defined signal 2
PWR Power-fail/Restart
POLL Pollable event occurred
STOP Stopped (signal)
TSTP Stopped
CONT Continued
# before CLD (CHLD is posix and CHLD is sometimes the same as CLD)
CHLD Child exited
CLD Child exited
TTIN Stopped (tty input)
TTOU Stopped (tty output)
INFO Information request
URG Urgent I/O condition
# Solaris (svr4?) signals
WAITING No runnable LWPs
LWP Inter-LWP signal
FREEZE Checkpoint freeze
THAW Checkpoint thaw
CANCEL Thread cancellation

44
bin/ksh/siglist.sh Executable file
View file

@ -0,0 +1,44 @@
#!/bin/sh
# $NetBSD: siglist.sh,v 1.9 2011/01/23 17:11:55 hauke Exp $
#
# Script to generate a sorted, complete list of signals, suitable
# for inclusion in trap.c as array initializer.
#
set -e
: ${AWK:=awk}
: ${SED:=sed}
in=tmpi$$.c
out=tmpo$$.c
ecode=1
trapsigs='0 1 2 13 15'
trap 'rm -f $in $out; trap 0; exit $ecode' $trapsigs
CPP="${1-cc -E}"
# The trap here to make up for a bug in bash (1.14.3(1)) that calls the trap
(trap $trapsigs;
echo '#include "sh.h"';
echo ' { QwErTy SIGNALS , "DUMMY" , "hook for number of signals" },';
${SED} -e '/^[ ]*#/d' -e 's/^[ ]*\([^ ][^ ]*\)[ ][ ]*\(.*[^ ]\)[ ]*$/#ifdef SIG\1\
{ QwErTy .signal = SIG\1 , .name = "\1", .mess = "\2" },\
#endif/') > $in
$CPP $in > $out
${SED} -n 's/{ QwErTy/{/p' < $out | ${AWK} '{print NR, $0}' | sort -k 5n -k 1n |
${SED} 's/^[0-9]* //' |
${AWK} 'BEGIN { last=0; nsigs=0; }
{
if ($4 ~ /^[0-9][0-9]*$/ && $5 == ",") {
n = $4;
if (n > 0 && n != last) {
while (++last < n) {
printf "\t{ .signal = %d , .name = NULL, .mess = `Signal %d` } ,\n", last, last;
}
print;
}
}
}' |
tr '`' '"' | grep -v '"DUMMY"'
ecode=0

958
bin/ksh/syn.c Normal file
View file

@ -0,0 +1,958 @@
/* $NetBSD: syn.c,v 1.9 2006/10/16 00:07:32 christos Exp $ */
/*
* shell parser (C version)
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: syn.c,v 1.9 2006/10/16 00:07:32 christos Exp $");
#endif
#include "sh.h"
#include "c_test.h"
#include <assert.h>
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
int start_line; /* line nesting began on */
};
static void yyparse ARGS((void));
static struct op *pipeline ARGS((int cf));
static struct op *andor ARGS((void));
static struct op *c_list ARGS((int multi));
static struct ioword *synio ARGS((int cf));
static void musthave ARGS((int c, int cf));
static struct op *nested ARGS((int type, int smark, int emark));
static struct op *get_command ARGS((int cf));
static struct op *dogroup ARGS((void));
static struct op *thenpart ARGS((void));
static struct op *elsepart ARGS((void));
static struct op *caselist ARGS((void));
static struct op *casepart ARGS((int endtok));
static struct op *function_body ARGS((char *name, int ksh_func));
static char ** wordlist ARGS((void));
static struct op *block ARGS((int type, struct op *t1, struct op *t2,
char **wp));
static struct op *newtp ARGS((int type));
static void syntaxerr ARGS((const char *what))
GCC_FUNC_ATTR(noreturn);
static void nesting_push ARGS((struct nesting_state *save, int tok));
static void nesting_pop ARGS((struct nesting_state *saved));
static int assign_command ARGS((char *s));
static int inalias ARGS((struct source *s));
#ifdef KSH
static int dbtestp_isa ARGS((Test_env *te, Test_meta meta));
static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op,
int do_eval));
static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg));
#endif /* KSH */
static struct op *outtree; /* yyparse output */
static struct nesting_state nesting; /* \n changed to ; */
static int reject; /* token(cf) gets symbol again */
static int symbol; /* yylex value */
#define REJECT (reject = 1)
#define ACCEPT (reject = 0)
#define token(cf) \
((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
#define tpeek(cf) \
((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
static void
yyparse()
{
int c;
ACCEPT;
outtree = c_list(source->type == SSTRING);
c = tpeek(0);
if (c == 0 && !outtree)
outtree = newtp(TEOF);
else if (c != '\n' && c != 0)
syntaxerr((char *) 0);
}
static struct op *
pipeline(cf)
int cf;
{
register struct op *t, *p, *tl = NULL;
t = get_command(cf);
if (t != NULL) {
while (token(0) == '|') {
if ((p = get_command(CONTIN)) == NULL)
syntaxerr((char *) 0);
if (tl == NULL)
t = tl = block(TPIPE, t, p, NOWORDS);
else
tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct op *
andor()
{
register struct op *t, *p;
register int c;
t = pipeline(0);
if (t != NULL) {
while ((c = token(0)) == LOGAND || c == LOGOR) {
if ((p = pipeline(CONTIN)) == NULL)
syntaxerr((char *) 0);
t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct op *
c_list(multi)
int multi;
{
register struct op *t = NULL, *p, *tl = NULL;
register int c;
int have_sep;
while (1) {
p = andor();
/* Token has always been read/rejected at this point, so
* we don't worry about what flags to pass token()
*/
c = token(0);
have_sep = 1;
if (c == '\n' && (multi || inalias(source))) {
if (!p) /* ignore blank lines */
continue;
} else if (!p)
break;
else if (c == '&' || c == COPROC)
p = block(c == '&' ? TASYNC : TCOPROC,
p, NOBLOCK, NOWORDS);
else if (c != ';')
have_sep = 0;
if (!t)
t = p;
else if (!tl)
t = tl = block(TLIST, t, p, NOWORDS);
else
tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
if (!have_sep)
break;
}
REJECT;
return t;
}
static struct ioword *
synio(cf)
int cf;
{
register struct ioword *iop;
int ishere;
if (tpeek(cf) != REDIR)
return NULL;
ACCEPT;
iop = yylval.iop;
ishere = (iop->flag&IOTYPE) == IOHERE;
musthave(LWORD, ishere ? HEREDELIM : 0);
if (ishere) {
iop->delim = yylval.cp;
if (*ident != 0) /* unquoted */
iop->flag |= IOEVAL;
if (herep >= &heres[HERES])
yyerror("too many <<'s\n");
*herep++ = iop;
} else
iop->name = yylval.cp;
return iop;
}
static void
musthave(c, cf)
int c, cf;
{
if ((token(cf)) != c)
syntaxerr((char *) 0);
}
static struct op *
nested(type, smark, emark)
int type, smark, emark;
{
register struct op *t;
struct nesting_state old_nesting;
nesting_push(&old_nesting, smark);
t = c_list(TRUE);
musthave(emark, KEYWORD|ALIAS);
nesting_pop(&old_nesting);
return (block(type, t, NOBLOCK, NOWORDS));
}
static struct op *
get_command(cf)
int cf;
{
register struct op *t;
register int c, iopn = 0, syniocf;
struct ioword *iop, **iops;
XPtrV args, vars;
struct nesting_state old_nesting;
iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),
ATEMP);
XPinit(args, 16);
XPinit(vars, 16);
syniocf = KEYWORD|ALIAS;
switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
default:
REJECT;
afree((void*) iops, ATEMP);
XPfree(args);
XPfree(vars);
return NULL; /* empty line */
case LWORD:
case REDIR:
REJECT;
syniocf &= ~(KEYWORD|ALIAS);
t = newtp(TCOM);
t->lineno = source->line;
while (1) {
cf = (t->u.evalflags ? ARRAYVAR : 0)
| (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
switch (tpeek(cf)) {
case REDIR:
if (iopn >= NUFILE)
yyerror("too many redirections\n");
iops[iopn++] = synio(cf);
break;
case LWORD:
ACCEPT;
/* the iopn == 0 and XPsize(vars) == 0 are
* dubious but at&t ksh acts this way
*/
if (iopn == 0 && XPsize(vars) == 0
&& XPsize(args) == 0
&& assign_command(ident))
t->u.evalflags = DOVACHECK;
if ((XPsize(args) == 0 || Flag(FKEYWORD))
&& is_wdvarassign(yylval.cp))
XPput(vars, yylval.cp);
else
XPput(args, yylval.cp);
break;
case '(':
/* Check for "> foo (echo hi)", which at&t ksh
* allows (not POSIX, but not disallowed)
*/
afree(t, ATEMP);
if (XPsize(args) == 0 && XPsize(vars) == 0) {
ACCEPT;
goto Subshell;
}
/* Must be a function */
if (iopn != 0 || XPsize(args) != 1
|| XPsize(vars) != 0)
syntaxerr((char *) 0);
ACCEPT;
/*(*/
musthave(')', 0);
t = function_body(XPptrv(args)[0], FALSE);
goto Leave;
default:
goto Leave;
}
}
Leave:
break;
Subshell:
case '(':
t = nested(TPAREN, '(', ')');
break;
case '{': /*}*/
t = nested(TBRACE, '{', '}');
break;
#ifdef KSH
case MDPAREN:
{
static const char let_cmd[] = { CHAR, 'l', CHAR, 'e',
CHAR, 't', EOS };
/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
t = newtp(TCOM);
t->lineno = source->line;
ACCEPT;
XPput(args, wdcopy(let_cmd, ATEMP));
musthave(LWORD,LETEXPR);
XPput(args, yylval.cp);
break;
}
#endif /* KSH */
#ifdef KSH
case DBRACKET: /* [[ .. ]] */
/* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
t = newtp(TDBRACKET);
ACCEPT;
{
Test_env te;
te.flags = TEF_DBRACKET;
te.pos.av = &args;
te.isa = dbtestp_isa;
te.getopnd = dbtestp_getopnd;
te.eval = dbtestp_eval;
te.error = dbtestp_error;
test_parse(&te);
}
break;
#endif /* KSH */
case FOR:
case SELECT:
t = newtp((c == FOR) ? TFOR : TSELECT);
musthave(LWORD, ARRAYVAR);
if (!is_wdvarname(yylval.cp, TRUE))
yyerror("%s: bad identifier\n",
c == FOR ? "for" : "select");
t->str = str_save(ident, ATEMP);
nesting_push(&old_nesting, c);
t->vars = wordlist();
t->left = dogroup();
nesting_pop(&old_nesting);
break;
case WHILE:
case UNTIL:
nesting_push(&old_nesting, c);
t = newtp((c == WHILE) ? TWHILE : TUNTIL);
t->left = c_list(TRUE);
t->right = dogroup();
nesting_pop(&old_nesting);
break;
case CASE:
t = newtp(TCASE);
musthave(LWORD, 0);
t->str = yylval.cp;
nesting_push(&old_nesting, c);
t->left = caselist();
nesting_pop(&old_nesting);
break;
case IF:
nesting_push(&old_nesting, c);
t = newtp(TIF);
t->left = c_list(TRUE);
t->right = thenpart();
musthave(FI, KEYWORD|ALIAS);
nesting_pop(&old_nesting);
break;
case BANG:
syniocf &= ~(KEYWORD|ALIAS);
t = pipeline(0);
if (t == (struct op *) 0)
syntaxerr((char *) 0);
t = block(TBANG, NOBLOCK, t, NOWORDS);
break;
case TIME:
syniocf &= ~(KEYWORD|ALIAS);
t = pipeline(0);
t = block(TTIME, t, NOBLOCK, NOWORDS);
break;
case FUNCTION:
musthave(LWORD, 0);
t = function_body(yylval.cp, TRUE);
break;
}
while ((iop = synio(syniocf)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many redirections\n");
iops[iopn++] = iop;
}
if (iopn == 0) {
afree((void*) iops, ATEMP);
t->ioact = NULL;
} else {
iops[iopn++] = NULL;
iops = (struct ioword **) aresize((void*) iops,
sizeofN(struct ioword *, iopn), ATEMP);
t->ioact = iops;
}
if (t->type == TCOM || t->type == TDBRACKET) {
XPput(args, NULL);
t->args = (char **) XPclose(args);
XPput(vars, NULL);
t->vars = (char **) XPclose(vars);
} else {
XPfree(args);
XPfree(vars);
}
return t;
}
static struct op *
dogroup()
{
register int c;
register struct op *list;
c = token(CONTIN|KEYWORD|ALIAS);
/* A {...} can be used instead of do...done for for/select loops
* but not for while/until loops - we don't need to check if it
* is a while loop because it would have been parsed as part of
* the conditional command list...
*/
if (c == DO)
c = DONE;
else if (c == '{')
c = '}';
else
syntaxerr((char *) 0);
list = c_list(TRUE);
musthave(c, KEYWORD|ALIAS);
return list;
}
static struct op *
thenpart()
{
register struct op *t;
musthave(THEN, KEYWORD|ALIAS);
t = newtp(0);
t->left = c_list(TRUE);
if (t->left == NULL)
syntaxerr((char *) 0);
t->right = elsepart();
return (t);
}
static struct op *
elsepart()
{
register struct op *t;
switch (token(KEYWORD|ALIAS|VARASN)) {
case ELSE:
if ((t = c_list(TRUE)) == NULL)
syntaxerr((char *) 0);
return (t);
case ELIF:
t = newtp(TELIF);
t->left = c_list(TRUE);
t->right = thenpart();
return (t);
default:
REJECT;
}
return NULL;
}
static struct op *
caselist()
{
register struct op *t, *tl;
int c;
c = token(CONTIN|KEYWORD|ALIAS);
/* A {...} can be used instead of in...esac for case statements */
if (c == IN)
c = ESAC;
else if (c == '{')
c = '}';
else
syntaxerr((char *) 0);
t = tl = NULL;
while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */
struct op *tc = casepart(c);
if (tl == NULL)
t = tl = tc, tl->right = NULL;
else
tl->right = tc, tl = tc;
}
musthave(c, KEYWORD|ALIAS);
return (t);
}
static struct op *
casepart(endtok)
int endtok;
{
register struct op *t;
register int c;
XPtrV ptns;
XPinit(ptns, 16);
t = newtp(TPAT);
c = token(CONTIN|KEYWORD); /* no ALIAS here */
if (c != '(')
REJECT;
do {
musthave(LWORD, 0);
XPput(ptns, yylval.cp);
} while ((c = token(0)) == '|');
REJECT;
XPput(ptns, NULL);
t->vars = (char **) XPclose(ptns);
musthave(')', 0);
t->left = c_list(TRUE);
/* Note: Posix requires the ;; */
if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
musthave(BREAK, CONTIN|KEYWORD|ALIAS);
return (t);
}
static struct op *
function_body(name, ksh_func)
char *name;
int ksh_func; /* function foo { ... } vs foo() { .. } */
{
char *sname, *p;
struct op *t;
int old_func_parse;
sname = wdstrip(name);
/* Check for valid characters in name. posix and ksh93 say only
* allow [a-zA-Z_0-9] but this allows more as old pdksh's have
* allowed more (the following were never allowed:
* nul space nl tab $ ' " \ ` ( ) & | ; = < >
* C_QUOTE covers all but = and adds # [ ? *)
*/
for (p = sname; *p; p++)
if (ctype(*p, C_QUOTE) || *p == '=')
yyerror("%s: invalid function name\n", sname);
t = newtp(TFUNCT);
t->str = sname;
t->u.ksh_func = ksh_func;
t->lineno = source->line;
/* Note that POSIX allows only compound statements after foo(), sh and
* at&t ksh allow any command, go with the later since it shouldn't
* break anything. However, for function foo, at&t ksh only accepts
* an open-brace.
*/
if (ksh_func) {
musthave('{', CONTIN|KEYWORD|ALIAS); /* } */
REJECT;
}
old_func_parse = e->flags & EF_FUNC_PARSE;
e->flags |= EF_FUNC_PARSE;
if ((t->left = get_command(CONTIN)) == (struct op *) 0) {
/*
* Probably something like foo() followed by eof or ;.
* This is accepted by sh and ksh88.
* To make "typeset -f foo" work reliably (so its output can
* be used as input), we pretend there is a colon here.
*/
t->left = newtp(TCOM);
t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP);
t->left->args[0] = alloc(sizeof(char) * 3, ATEMP);
t->left->args[0][0] = CHAR;
t->left->args[0][1] = ':';
t->left->args[0][2] = EOS;
t->left->args[1] = (char *) 0;
t->left->vars = (char **) alloc(sizeof(char *), ATEMP);
t->left->vars[0] = (char *) 0;
t->left->lineno = 1;
}
if (!old_func_parse)
e->flags &= ~EF_FUNC_PARSE;
return t;
}
static char **
wordlist()
{
register int c;
XPtrV args;
XPinit(args, 16);
/* Posix does not do alias expansion here... */
if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {
if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */
REJECT;
return NULL;
}
while ((c = token(0)) == LWORD)
XPput(args, yylval.cp);
if (c != '\n' && c != ';')
syntaxerr((char *) 0);
if (XPsize(args) == 0) {
XPfree(args);
return NULL;
} else {
XPput(args, NULL);
return (char **) XPclose(args);
}
}
/*
* supporting functions
*/
static struct op *
block(type, t1, t2, wp)
int type;
struct op *t1, *t2;
char **wp;
{
register struct op *t;
t = newtp(type);
t->left = t1;
t->right = t2;
t->vars = wp;
return (t);
}
const struct tokeninfo {
const char *name;
short val;
short reserved;
} tokentab[] = {
/* Reserved words */
{ "if", IF, TRUE },
{ "then", THEN, TRUE },
{ "else", ELSE, TRUE },
{ "elif", ELIF, TRUE },
{ "fi", FI, TRUE },
{ "case", CASE, TRUE },
{ "esac", ESAC, TRUE },
{ "for", FOR, TRUE },
#ifdef KSH
{ "select", SELECT, TRUE },
#endif /* KSH */
{ "while", WHILE, TRUE },
{ "until", UNTIL, TRUE },
{ "do", DO, TRUE },
{ "done", DONE, TRUE },
{ "in", IN, TRUE },
{ "function", FUNCTION, TRUE },
{ "time", TIME, TRUE },
{ "{", '{', TRUE },
{ "}", '}', TRUE },
{ "!", BANG, TRUE },
#ifdef KSH
{ "[[", DBRACKET, TRUE },
#endif /* KSH */
/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
{ "&&", LOGAND, FALSE },
{ "||", LOGOR, FALSE },
{ ";;", BREAK, FALSE },
#ifdef KSH
{ "((", MDPAREN, FALSE },
{ "|&", COPROC, FALSE },
#endif /* KSH */
/* and some special cases... */
{ "newline", '\n', FALSE },
{ .name = NULL }
};
void
initkeywords()
{
register struct tokeninfo const *tt;
register struct tbl *p;
tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */
for (tt = tokentab; tt->name; tt++) {
if (tt->reserved) {
p = tenter(&keywords, tt->name, hash(tt->name));
p->flag |= DEFINED|ISSET;
p->type = CKEYWD;
p->val.i = tt->val;
}
}
}
static void
syntaxerr(what)
const char *what;
{
char redir[6]; /* 2<<- is the longest redirection, I think */
const char *s;
struct tokeninfo const *tt;
int c;
if (!what)
what = "unexpected";
REJECT;
c = token(0);
Again:
switch (c) {
case 0:
if (nesting.start_token) {
c = nesting.start_token;
source->errline = nesting.start_line;
what = "unmatched";
goto Again;
}
/* don't quote the EOF */
yyerror("syntax error: unexpected EOF\n");
/*NOTREACHED*/
case LWORD:
s = snptreef((char *) 0, 32, "%S", yylval.cp);
break;
case REDIR:
s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
break;
default:
for (tt = tokentab; tt->name; tt++)
if (tt->val == c)
break;
if (tt->name)
s = tt->name;
else {
if (c > 0 && c < 256) {
redir[0] = c;
redir[1] = '\0';
} else
shf_snprintf(redir, sizeof(redir),
"?%d", c);
s = redir;
}
}
yyerror("syntax error: `%s' %s\n", s, what);
}
static void
nesting_push(save, tok)
struct nesting_state *save;
int tok;
{
*save = nesting;
nesting.start_token = tok;
nesting.start_line = source->line;
}
static void
nesting_pop(saved)
struct nesting_state *saved;
{
nesting = *saved;
}
static struct op *
newtp(type)
int type;
{
register struct op *t;
t = (struct op *) alloc(sizeof(*t), ATEMP);
t->type = type;
t->u.evalflags = 0;
t->args = t->vars = NULL;
t->ioact = NULL;
t->left = t->right = NULL;
t->str = NULL;
return (t);
}
struct op *
compile(s)
Source *s;
{
nesting.start_token = 0;
nesting.start_line = 0;
herep = heres;
source = s;
yyparse();
return outtree;
}
/* This kludge exists to take care of sh/at&t ksh oddity in which
* the arguments of alias/export/readonly/typeset have no field
* splitting, file globbing, or (normal) tilde expansion done.
* at&t ksh seems to do something similar to this since
* $ touch a=a; typeset a=[ab]; echo "$a"
* a=[ab]
* $ x=typeset; $x a=[ab]; echo "$a"
* a=a
* $
*/
static int
assign_command(s)
char *s;
{
char c = *s;
if (Flag(FPOSIX) || !*s)
return 0;
return (c == 'a' && strcmp(s, "alias") == 0)
|| (c == 'e' && strcmp(s, "export") == 0)
|| (c == 'r' && strcmp(s, "readonly") == 0)
|| (c == 't' && strcmp(s, "typeset") == 0);
}
/* Check if we are in the middle of reading an alias */
static int
inalias(s)
struct source *s;
{
for (; s && s->type == SALIAS; s = s->next)
if (!(s->flags & SF_ALIASEND))
return 1;
return 0;
}
#ifdef KSH
/* Order important - indexed by Test_meta values
* Note that ||, &&, ( and ) can't appear in as unquoted strings
* in normal shell input, so these can be interpreted unambiguously
* in the evaluation pass.
*/
static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
static const char dbtest_not[] = { CHAR, '!', EOS };
static const char dbtest_oparen[] = { CHAR, '(', EOS };
static const char dbtest_cparen[] = { CHAR, ')', EOS };
const char *const dbtest_tokens[] = {
dbtest_or, dbtest_and, dbtest_not,
dbtest_oparen, dbtest_cparen
};
const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
const char db_lthan[] = { CHAR, '<', EOS };
const char db_gthan[] = { CHAR, '>', EOS };
/* Test if the current token is a whatever. Accepts the current token if
* it is. Returns 0 if it is not, non-zero if it is (in the case of
* TM_UNOP and TM_BINOP, the returned value is a Test_op).
*/
static int
dbtestp_isa(te, meta)
Test_env *te;
Test_meta meta;
{
int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
int uqword = 0;
char *save = (char *) 0;
int ret = 0;
/* unquoted word? */
uqword = c == LWORD && *ident;
if (meta == TM_OR)
ret = c == LOGOR;
else if (meta == TM_AND)
ret = c == LOGAND;
else if (meta == TM_NOT)
ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0;
else if (meta == TM_OPAREN)
ret = c == '(' /*)*/;
else if (meta == TM_CPAREN)
ret = c == /*(*/ ')';
else if (meta == TM_UNOP || meta == TM_BINOP) {
if (meta == TM_BINOP && c == REDIR
&& (yylval.iop->flag == IOREAD
|| yylval.iop->flag == IOWRITE))
{
ret = 1;
save = wdcopy(yylval.iop->flag == IOREAD ?
db_lthan : db_gthan, ATEMP);
} else if (uqword && (ret = (int) test_isop(te, meta, ident)))
save = yylval.cp;
} else /* meta == TM_END */
ret = uqword && strcmp(yylval.cp, db_close) == 0;
if (ret) {
ACCEPT;
if (meta != TM_END) {
if (!save) {
assert(/* meta >= 0 && */
meta < sizeof(dbtest_tokens) /
sizeof(dbtest_tokens[0]));
save = wdcopy(dbtest_tokens[(int) meta], ATEMP);
}
XPput(*te->pos.av, save);
}
}
return ret;
}
static const char *
dbtestp_getopnd(te, op, do_eval)
Test_env *te;
Test_op op;
int do_eval;
{
int c = tpeek(ARRAYVAR);
if (c != LWORD)
return (const char *) 0;
ACCEPT;
XPput(*te->pos.av, yylval.cp);
return null;
}
static int
dbtestp_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
return 1;
}
static void
dbtestp_error(te, offset, msg)
Test_env *te;
int offset;
const char *msg;
{
te->flags |= TEF_ERROR;
if (offset < 0) {
REJECT;
/* Kludgy to say the least... */
symbol = LWORD;
yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av)
+ offset);
}
syntaxerr(msg);
}
#endif /* KSH */

247
bin/ksh/table.c Normal file
View file

@ -0,0 +1,247 @@
/* $NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $ */
/*
* dynamic hashed associative table for commands and variables
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $");
#endif
#include "sh.h"
#define INIT_TBLS 8 /* initial table size (power of 2) */
static void texpand ARGS((struct table *tp, int nsize));
static int tnamecmp ARGS((void *p1, void *p2));
unsigned int
hash(n)
register const char * n;
{
register unsigned int h = 0;
while (*n != '\0')
h = 2*h + *n++;
return h * 32821; /* scatter bits */
}
void
tinit(tp, ap, tsize)
register struct table *tp;
register Area *ap;
int tsize;
{
tp->areap = ap;
tp->tbls = NULL;
tp->size = tp->nfree = 0;
if (tsize)
texpand(tp, tsize);
}
static void
texpand(tp, nsize)
register struct table *tp;
int nsize;
{
register int i;
register struct tbl *tblp, **p;
register struct tbl **ntblp, **otblp = tp->tbls;
int osize = tp->size;
ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
for (i = 0; i < nsize; i++)
ntblp[i] = NULL;
tp->size = nsize;
tp->nfree = 8*nsize/10; /* table can get 80% full */
tp->tbls = ntblp;
if (otblp == NULL)
return;
for (i = 0; i < osize; i++) {
if ((tblp = otblp[i]) != NULL) {
if ((tblp->flag&DEFINED)) {
for (p = &ntblp[hash(tblp->name)
& (tp->size-1)];
*p != NULL; p--)
if (p == ntblp) /* wrap */
p += tp->size;
*p = tblp;
tp->nfree--;
} else if (!(tblp->flag & FINUSE)) {
afree((void*)tblp, tp->areap);
}
}
}
afree((void*)otblp, tp->areap);
}
struct tbl *
tsearch(tp, n, h)
register struct table *tp; /* table */
register const char *n; /* name to enter */
unsigned int h; /* hash(n) */
{
register struct tbl **pp, *p;
if (tp->size == 0)
return NULL;
/* search for name in hashed table */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
if (*p->name == *n && strcmp(p->name, n) == 0
&& (p->flag&DEFINED))
return p;
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
return NULL;
}
struct tbl *
tenter(tp, n, h)
register struct table *tp; /* table */
register const char *n; /* name to enter */
unsigned int h; /* hash(n) */
{
register struct tbl **pp, *p;
register int len;
if (tp->size == 0)
texpand(tp, INIT_TBLS);
Search:
/* search for name in hashed table */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
if (*p->name == *n && strcmp(p->name, n) == 0)
return p; /* found */
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
if (tp->nfree <= 0) { /* too full */
texpand(tp, 2*tp->size);
goto Search;
}
/* create new tbl entry */
len = strlen(n) + 1;
p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len,
tp->areap);
p->flag = 0;
p->type = 0;
p->areap = tp->areap;
p->u2.field = 0;
p->u.array = (struct tbl *)0;
memcpy(p->name, n, len);
/* enter in tp->tbls */
tp->nfree--;
*pp = p;
return p;
}
void
tdelete(p)
register struct tbl *p;
{
p->flag = 0;
}
void
twalk(ts, tp)
struct tstate *ts;
struct table *tp;
{
ts->left = tp->size;
ts->next = tp->tbls;
}
struct tbl *
tnext(ts)
struct tstate *ts;
{
while (--ts->left >= 0) {
struct tbl *p = *ts->next++;
if (p != NULL && (p->flag&DEFINED))
return p;
}
return NULL;
}
static int
tnamecmp(p1, p2)
void *p1, *p2;
{
return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
}
struct tbl **
tsort(tp)
register struct table *tp;
{
register int i;
register struct tbl **p, **sp, **dp;
p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
sp = tp->tbls; /* source */
dp = p; /* dest */
for (i = 0; i < tp->size; i++)
if ((*dp = *sp++) != NULL && (((*dp)->flag&DEFINED) ||
((*dp)->flag&ARRAY)))
dp++;
i = dp - p;
qsortp((void**)p, (size_t)i, tnamecmp);
p[i] = NULL;
return p;
}
#ifdef PERF_DEBUG /* performance debugging */
void tprintinfo ARGS((struct table *tp));
void
tprintinfo(tp)
struct table *tp;
{
struct tbl *te;
char *n;
unsigned int h;
int ncmp;
int totncmp = 0, maxncmp = 0;
int nentries = 0;
struct tstate ts;
shellf("table size %d, nfree %d\n", tp->size, tp->nfree);
shellf(" Ncmp name\n");
twalk(&ts, tp);
while ((te = tnext(&ts))) {
register struct tbl **pp, *p;
h = hash(n = te->name);
ncmp = 0;
/* taken from tsearch() and added counter */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp); pp--) {
ncmp++;
if (*p->name == *n && strcmp(p->name, n) == 0
&& (p->flag&DEFINED))
break; /* return p; */
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
shellf(" %4d %s\n", ncmp, n);
totncmp += ncmp;
nentries++;
if (ncmp > maxncmp)
maxncmp = ncmp;
}
if (nentries)
shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
nentries, maxncmp,
totncmp / nentries,
(totncmp % nentries) * 100 / nentries);
}
#endif /* PERF_DEBUG */

181
bin/ksh/table.h Normal file
View file

@ -0,0 +1,181 @@
/* $NetBSD: table.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
/*
* generic hashed associative table for commands and variables.
*/
struct table {
Area *areap; /* area to allocate entries */
short size, nfree; /* hash size (always 2^^n), free entries */
struct tbl **tbls; /* hashed table items */
};
struct tbl { /* table item */
Tflag flag; /* flags */
int type; /* command type (see below), base (if INTEGER),
* or offset from val.s of value (if EXPORT) */
Area *areap; /* area to allocate from */
union {
char *s; /* string */
long i; /* integer */
int (*f) ARGS((char **)); /* int function */
struct op *t; /* "function" tree */
} val; /* value */
int index; /* index for an array */
union {
int field; /* field with for -L/-R/-Z */
int errno_; /* CEXEC/CTALIAS */
} u2;
union {
struct tbl *array; /* array values */
char *fpath; /* temporary path to undef function */
} u;
char name[4]; /* name -- variable length */
};
/* common flag bits */
#define ALLOC BIT(0) /* val.s has been allocated */
#define DEFINED BIT(1) /* is defined in block */
#define ISSET BIT(2) /* has value, vp->val.[si] */
#define EXPORT BIT(3) /* exported variable/function */
#define TRACE BIT(4) /* var: user flagged, func: execution tracing */
/* (start non-common flags at 8) */
/* flag bits used for variables */
#define SPECIAL BIT(8) /* PATH, IFS, SECONDS, etc */
#define INTEGER BIT(9) /* val.i contains integer value */
#define RDONLY BIT(10) /* read-only variable */
#define LOCAL BIT(11) /* for local typeset() */
#define ARRAY BIT(13) /* array */
#define LJUST BIT(14) /* left justify */
#define RJUST BIT(15) /* right justify */
#define ZEROFIL BIT(16) /* 0 filled if RJUSTIFY, strip 0s if LJUSTIFY */
#define LCASEV BIT(17) /* convert to lower case */
#define UCASEV_AL BIT(18)/* convert to upper case / autoload function */
#define INT_U BIT(19) /* unsigned integer */
#define INT_L BIT(20) /* long integer (no-op) */
#define IMPORT BIT(21) /* flag to typeset(): no arrays, must have = */
#define LOCAL_COPY BIT(22) /* with LOCAL - copy attrs from existing var */
#define EXPRINEVAL BIT(23) /* contents currently being evaluated */
#define EXPRLVALUE BIT(24) /* useable as lvalue (temp flag) */
/* flag bits used for taliases/builtins/aliases/keywords/functions */
#define KEEPASN BIT(8) /* keep command assignments (eg, var=x cmd) */
#define FINUSE BIT(9) /* function being executed */
#define FDELETE BIT(10) /* function deleted while it was executing */
#define FKSH BIT(11) /* function defined with function x (vs x()) */
#define SPEC_BI BIT(12) /* a POSIX special builtin */
#define REG_BI BIT(13) /* a POSIX regular builtin */
/* Attributes that can be set by the user (used to decide if an unset param
* should be repoted by set/typeset). Does not include ARRAY or LOCAL.
*/
#define USERATTRIB (EXPORT|INTEGER|RDONLY|LJUST|RJUST|ZEROFIL\
|LCASEV|UCASEV_AL|INT_U|INT_L)
/* command types */
#define CNONE 0 /* undefined */
#define CSHELL 1 /* built-in */
#define CFUNC 2 /* function */
#define CEXEC 4 /* executable command */
#define CALIAS 5 /* alias */
#define CKEYWD 6 /* keyword */
#define CTALIAS 7 /* tracked alias */
/* Flags for findcom()/comexec() */
#define FC_SPECBI BIT(0) /* special builtin */
#define FC_FUNC BIT(1) /* function builtin */
#define FC_REGBI BIT(2) /* regular builtin */
#define FC_UNREGBI BIT(3) /* un-regular builtin (!special,!regular) */
#define FC_BI (FC_SPECBI|FC_REGBI|FC_UNREGBI)
#define FC_PATH BIT(4) /* do path search */
#define FC_DEFPATH BIT(5) /* use default path in path search */
#define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */
#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */
#define AI_ARGV(a, i) ((i) == 0 ? (a).argv[0] : (a).argv[(i) - (a).skip])
#define AI_ARGC(a) ((a).argc_ - (a).skip)
/* Argument info. Used for $#, $* for shell, functions, includes, etc. */
struct arg_info {
int flags; /* AF_* */
char **argv;
int argc_;
int skip; /* first arg is argv[0], second is argv[1 + skip] */
};
/*
* activation record for function blocks
*/
struct block {
Area area; /* area to allocate things */
/*struct arg_info argi;*/
char **argv;
int argc;
int flags; /* see BF_* */
struct table vars; /* local variables */
struct table funs; /* local functions */
Getopt getopts_state;
#if 1
char * error; /* error handler */
char * exit; /* exit handler */
#else
Trap error, exit;
#endif
struct block *next; /* enclosing block */
};
/* Values for struct block.flags */
#define BF_DOGETOPTS BIT(0) /* save/restore getopts state */
/*
* Used by twalk() and tnext() routines.
*/
struct tstate {
int left;
struct tbl **next;
};
EXTERN struct table taliases; /* tracked aliases */
EXTERN struct table builtins; /* built-in commands */
EXTERN struct table aliases; /* aliases */
EXTERN struct table keywords; /* keywords */
EXTERN struct table homedirs; /* homedir() cache */
struct builtin {
const char *name;
int (*func) ARGS((char **));
};
/* these really are externs! Look in table.c for them */
extern const struct builtin shbuiltins [], kshbuiltins [];
/* var spec values */
#define V_NONE 0
#define V_PATH 1
#define V_IFS 2
#define V_SECONDS 3
#define V_OPTIND 4
#define V_MAIL 5
#define V_MAILPATH 6
#define V_MAILCHECK 7
#define V_RANDOM 8
#define V_HISTSIZE 9
#define V_HISTFILE 10
#define V_VISUAL 11
#define V_EDITOR 12
#define V_COLUMNS 13
#define V_POSIXLY_CORRECT 14
#define V_TMOUT 15
#define V_TMPDIR 16
#define V_LINENO 17
/* values for set_prompt() */
#define PS1 0 /* command */
#define PS2 1 /* command continuation */
EXTERN char *path; /* copy of either PATH or def_path */
EXTERN const char *def_path; /* path to use if PATH not set */
EXTERN char *tmpdir; /* TMPDIR value */
EXTERN const char *prompt;
EXTERN int cur_prompt; /* PS1 or PS2 */
EXTERN int current_lineno; /* LINENO value */

460
bin/ksh/trap.c Normal file
View file

@ -0,0 +1,460 @@
/* $NetBSD: trap.c,v 1.8 2006/10/16 00:07:32 christos Exp $ */
/*
* signal handling
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: trap.c,v 1.8 2006/10/16 00:07:32 christos Exp $");
#endif
/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
#define FROM_TRAP_C
#include "sh.h"
/* Table is indexed by signal number
*
* The script siglist.sh generates siglist.out, which is a sorted, complete
* list of signals
*/
Trap sigtraps[SIGNALS+1] = {
{ .signal = SIGEXIT_, .name = "EXIT", .mess = "Signal 0" },
#include "siglist.out" /* generated by siglist.sh */
{ .signal = SIGERR_, .name = "ERR", .mess = "Error handler" },
};
static struct sigaction Sigact_ign, Sigact_trap;
void
inittraps()
{
#ifdef HAVE_SYS_SIGLIST
# ifndef SYS_SIGLIST_DECLARED
extern char *sys_siglist[];
# endif
int i;
/* Use system description, if available, for unknown signals... */
for (i = 0; i < NSIG; i++)
if (!sigtraps[i].name && sys_siglist[i] && sys_siglist[i][0])
sigtraps[i].mess = sys_siglist[i];
#endif /* HAVE_SYS_SIGLIST */
sigemptyset(&Sigact_ign.sa_mask);
Sigact_ign.sa_flags = KSH_SA_FLAGS;
Sigact_ign.sa_handler = SIG_IGN;
Sigact_trap = Sigact_ign;
Sigact_trap.sa_handler = trapsig;
sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */
sigtraps[SIGHUP].flags |= TF_FATAL;
sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
/* these are always caught so we can clean up any temporary files. */
setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
}
#ifdef KSH
static RETSIGTYPE alarm_catcher ARGS((int sig));
void
alarm_init()
{
sigtraps[SIGALRM].flags |= TF_SHELL_USES;
setsig(&sigtraps[SIGALRM], alarm_catcher,
SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
}
static RETSIGTYPE
alarm_catcher(sig)
int sig;
{
int errno_ = errno;
if (ksh_tmout_state == TMOUT_READING) {
int left = alarm(0);
if (left == 0) {
ksh_tmout_state = TMOUT_LEAVING;
intrsig = 1;
} else
alarm(left);
}
errno = errno_;
return RETSIGVAL;
}
#endif /* KSH */
Trap *
gettrap(name, igncase)
const char *name;
int igncase;
{
int i;
register Trap *p;
if (digit(*name)) {
int n;
if (getn(name, &n) && 0 <= n && n < SIGNALS)
return &sigtraps[n];
return NULL;
}
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->name) {
if (igncase) {
if (p->name && (!strcasecmp(p->name, name) ||
(strlen(name) > 3 && !strncasecmp("SIG",
p->name, 3) &&
!strcasecmp(p->name, name + 3))))
return p;
} else {
if (p->name && (!strcmp(p->name, name) ||
(strlen(name) > 3 && !strncmp("SIG",
p->name, 3) && !strcmp(p->name, name + 3))))
return p;
}
}
return NULL;
}
/*
* trap signal handler
*/
RETSIGTYPE
trapsig(i)
int i;
{
Trap *p = &sigtraps[i];
int errno_ = errno;
trap = p->set = 1;
if (p->flags & TF_DFL_INTR)
intrsig = 1;
if ((p->flags & TF_FATAL) && !p->trap) {
fatal_trap = 1;
intrsig = 1;
}
if (p->shtrap)
(*p->shtrap)(i);
#ifdef V7_SIGNALS
if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
sigaction(i, &Sigact_trap, (struct sigaction *) 0);
#endif /* V7_SIGNALS */
errno = errno_;
return RETSIGVAL;
}
/* called when we want to allow the user to ^C out of something - won't
* work if user has trapped SIGINT.
*/
void
intrcheck()
{
if (intrsig)
runtraps(TF_DFL_INTR|TF_FATAL);
}
/* called after EINTR to check if a signal with normally causes process
* termination has been received.
*/
int
fatal_trap_check()
{
int i;
Trap *p;
/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
/* return value is used as an exit code */
return 128 + p->signal;
return 0;
}
/* Returns the signal number of any pending traps: ie, a signal which has
* occurred for which a trap has been set or for which the TF_DFL_INTR flag
* is set.
*/
int
trap_pending()
{
int i;
Trap *p;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && ((p->trap && p->trap[0])
|| ((p->flags & (TF_DFL_INTR|TF_FATAL))
&& !p->trap)))
return p->signal;
return 0;
}
/*
* run any pending traps. If intr is set, only run traps that
* can interrupt commands.
*/
void
runtraps(flag)
int flag;
{
int i;
register Trap *p;
#ifdef KSH
if (ksh_tmout_state == TMOUT_LEAVING) {
ksh_tmout_state = TMOUT_EXECUTING;
warningf(FALSE, "timed out waiting for input");
unwind(LEXIT);
} else
/* XXX: this means the alarm will have no effect if a trap
* is caught after the alarm() was started...not good.
*/
ksh_tmout_state = TMOUT_EXECUTING;
#endif /* KSH */
if (!flag)
trap = 0;
if (flag & TF_DFL_INTR)
intrsig = 0;
if (flag & TF_FATAL)
fatal_trap = 0;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && (!flag
|| ((p->flags & flag) && p->trap == (char *) 0)))
runtrap(p);
}
void
runtrap(p)
Trap *p;
{
int i = p->signal;
char *trapstr = p->trap;
int oexstat;
int UNINITIALIZED(old_changed);
p->set = 0;
if (trapstr == (char *) 0) { /* SIG_DFL */
if (p->flags & TF_FATAL) {
/* eg, SIGHUP */
exstat = 128 + i;
unwind(LLEAVE);
}
if (p->flags & TF_DFL_INTR) {
/* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
exstat = 128 + i;
unwind(LINTR);
}
return;
}
if (trapstr[0] == '\0') /* SIG_IGN */
return;
if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
old_changed = p->flags & TF_CHANGED;
p->flags &= ~TF_CHANGED;
p->trap = (char *) 0;
}
oexstat = exstat;
/* Note: trapstr is fully parsed before anything is executed, thus
* no problem with afree(p->trap) in settrap() while still in use.
*/
command(trapstr);
exstat = oexstat;
if (i == SIGEXIT_ || i == SIGERR_) {
if (p->flags & TF_CHANGED)
/* don't clear TF_CHANGED */
afree(trapstr, APERM);
else
p->trap = trapstr;
p->flags |= old_changed;
}
}
/* clear pending traps and reset user's trap handlers; used after fork(2) */
void
cleartraps()
{
int i;
Trap *p;
trap = 0;
intrsig = 0;
fatal_trap = 0;
for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) {
p->set = 0;
if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
settrap(p, (char *) 0);
}
}
/* restore signals just before an exec(2) */
void
restoresigs()
{
int i;
Trap *p;
for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++)
if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
SS_RESTORE_CURR|SS_FORCE);
}
void
settrap(p, s)
Trap *p;
char *s;
{
handler_t f;
if (p->trap)
afree(p->trap, APERM);
p->flags |= TF_CHANGED|TF_USER_SET;
if (s) {
p->trap = str_save(s, APERM);
f = s[0] ? trapsig : SIG_IGN;
} else {
p->trap = NULL;
f = SIG_DFL;
}
if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
f = trapsig;
else if (p->flags & TF_SHELL_USES) {
if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
/* do what user wants at exec time */
p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
if (f == SIG_IGN)
p->flags |= TF_EXEC_IGN;
else
p->flags |= TF_EXEC_DFL;
}
/* assumes handler already set to what shell wants it
* (normally trapsig, but could be j_sigchld() or SIG_IGN)
*/
return;
}
/* todo: should we let user know signal is ignored? how? */
setsig(p, f, SS_RESTORE_CURR|SS_USER);
}
/* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
* kill shell (unless user catches it and exits)
*/
int
block_pipe()
{
int restore_dfl = 0;
Trap *p = &sigtraps[SIGPIPE];
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
setsig(p, SIG_IGN, SS_RESTORE_CURR);
if (p->flags & TF_ORIG_DFL)
restore_dfl = 1;
} else if (p->cursig == SIG_DFL) {
setsig(p, SIG_IGN, SS_RESTORE_CURR);
restore_dfl = 1; /* restore to SIG_DFL */
}
return restore_dfl;
}
/* Called by c_print() to undo whatever block_pipe() did */
void
restore_pipe(restore_dfl)
int restore_dfl;
{
if (restore_dfl)
setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
}
/* Set action for a signal. Action may not be set if original
* action was SIG_IGN, depending on the value of flags and
* FTALKING.
*/
int
setsig(p, f, flags)
Trap *p;
handler_t f;
int flags;
{
struct sigaction sigact;
if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
return 1;
/* First time setting this signal? If so, get and note the current
* setting.
*/
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
sigaction(p->signal, &Sigact_ign, &sigact);
p->flags |= sigact.sa_handler == SIG_IGN ?
TF_ORIG_IGN : TF_ORIG_DFL;
p->cursig = SIG_IGN;
}
/* Generally, an ignored signal stays ignored, except if
* - the user of an interactive shell wants to change it
* - the shell wants for force a change
*/
if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
&& (!(flags & SS_USER) || !Flag(FTALKING)))
return 0;
setexecsig(p, flags & SS_RESTORE_MASK);
/* This is here 'cause there should be a way of clearing shtraps, but
* don't know if this is a sane way of doing it. At the moment,
* all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
*/
if (!(flags & SS_USER))
p->shtrap = (handler_t) 0;
if (flags & SS_SHTRAP) {
p->shtrap = f;
f = trapsig;
}
if (p->cursig != f) {
p->cursig = f;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = KSH_SA_FLAGS;
sigact.sa_handler = f;
sigaction(p->signal, &sigact, (struct sigaction *) 0);
}
return 1;
}
/* control what signal is set to before an exec() */
void
setexecsig(p, restore)
Trap *p;
int restore;
{
/* XXX debugging */
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
internal_errorf(1, "setexecsig: unset signal %d(%s)",
p->signal, p->name);
/* restore original value for exec'd kids */
p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
switch (restore & SS_RESTORE_MASK) {
case SS_RESTORE_CURR: /* leave things as they currently are */
break;
case SS_RESTORE_ORIG:
p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
break;
case SS_RESTORE_DFL:
p->flags |= TF_EXEC_DFL;
break;
case SS_RESTORE_IGN:
p->flags |= TF_EXEC_IGN;
break;
}
}

766
bin/ksh/tree.c Normal file
View file

@ -0,0 +1,766 @@
/* $NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $ */
/*
* command tree climbing
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $");
#endif
#include "sh.h"
#define INDENT 4
#define tputc(c, shf) shf_putchar(c, shf);
static void ptree ARGS((struct op *t, int indent, struct shf *f));
static void pioact ARGS((struct shf *f, int indent, struct ioword *iop));
static void tputC ARGS((int c, struct shf *shf));
static void tputS ARGS((char *wp, struct shf *shf));
static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va));
static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap));
static void iofree ARGS((struct ioword **iow, Area *ap));
/*
* print a command tree
*/
static void
ptree(t, indent, shf)
register struct op *t;
int indent;
register struct shf *shf;
{
register char **w;
struct ioword **ioact;
struct op *t1;
Chain:
if (t == NULL)
return;
switch (t->type) {
case TCOM:
if (t->vars)
for (w = t->vars; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-vars# ");
if (t->args)
for (w = t->args; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-args# ");
break;
case TEXEC:
#if 0 /* ?not useful - can't be called? */
/* Print original vars */
if (t->left->vars)
for (w = t->left->vars; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-vars# ");
/* Print expanded vars */
if (t->args)
for (w = t->args; *w != NULL; )
fptreef(shf, indent, "%s ", *w++);
else
fptreef(shf, indent, "#no-args# ");
/* Print original io */
t = t->left;
#else
t = t->left;
goto Chain;
#endif
case TPAREN:
fptreef(shf, indent + 2, "( %T) ", t->left);
break;
case TPIPE:
fptreef(shf, indent, "%T| ", t->left);
t = t->right;
goto Chain;
case TLIST:
fptreef(shf, indent, "%T%;", t->left);
t = t->right;
goto Chain;
case TOR:
case TAND:
fptreef(shf, indent, "%T%s %T",
t->left, (t->type==TOR) ? "||" : "&&", t->right);
break;
case TBANG:
fptreef(shf, indent, "! ");
t = t->right;
goto Chain;
case TDBRACKET:
{
int i;
fptreef(shf, indent, "[[");
for (i = 0; t->args[i]; i++)
fptreef(shf, indent, " %S", t->args[i]);
fptreef(shf, indent, " ]] ");
break;
}
#ifdef KSH
case TSELECT:
fptreef(shf, indent, "select %s ", t->str);
/* fall through */
#endif /* KSH */
case TFOR:
if (t->type == TFOR)
fptreef(shf, indent, "for %s ", t->str);
if (t->vars != NULL) {
fptreef(shf, indent, "in ");
for (w = t->vars; *w; )
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, "%;");
}
fptreef(shf, indent + INDENT, "do%N%T", t->left);
fptreef(shf, indent, "%;done ");
break;
case TCASE:
fptreef(shf, indent, "case %S in", t->str);
for (t1 = t->left; t1 != NULL; t1 = t1->right) {
fptreef(shf, indent, "%N(");
for (w = t1->vars; *w != NULL; w++)
fptreef(shf, indent, "%S%c", *w,
(w[1] != NULL) ? '|' : ')');
fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
}
fptreef(shf, indent, "%Nesac ");
break;
case TIF:
case TELIF:
/* 3 == strlen("if ") */
fptreef(shf, indent + 3, "if %T", t->left);
for (;;) {
t = t->right;
if (t->left != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "then%N%T",
t->left);
}
if (t->right == NULL || t->right->type != TELIF)
break;
t = t->right;
fptreef(shf, indent, "%;");
/* 5 == strlen("elif ") */
fptreef(shf, indent + 5, "elif %T", t->left);
}
if (t->right != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "else%;%T", t->right);
}
fptreef(shf, indent, "%;fi ");
break;
case TWHILE:
case TUNTIL:
/* 6 == strlen("while"/"until") */
fptreef(shf, indent + 6, "%s %T",
(t->type==TWHILE) ? "while" : "until",
t->left);
fptreef(shf, indent, "%;do");
fptreef(shf, indent + INDENT, "%;%T", t->right);
fptreef(shf, indent, "%;done ");
break;
case TBRACE:
fptreef(shf, indent + INDENT, "{%;%T", t->left);
fptreef(shf, indent, "%;} ");
break;
case TCOPROC:
fptreef(shf, indent, "%T|& ", t->left);
break;
case TASYNC:
fptreef(shf, indent, "%T& ", t->left);
break;
case TFUNCT:
fptreef(shf, indent,
t->u.ksh_func ? "function %s %T" : "%s() %T",
t->str, t->left);
break;
case TTIME:
fptreef(shf, indent, "time %T", t->left);
break;
default:
fptreef(shf, indent, "<botch>");
break;
}
if ((ioact = t->ioact) != NULL) {
int need_nl = 0;
while (*ioact != NULL)
pioact(shf, indent, *ioact++);
/* Print here documents after everything else... */
for (ioact = t->ioact; *ioact != NULL; ) {
struct ioword *iop = *ioact++;
/* heredoc is 0 when tracing (set -x) */
if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
tputc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
evalstr(iop->delim, 0));
need_nl = 1;
}
}
/* Last delimiter must be followed by a newline (this often
* leads to an extra blank line, but its not worth worrying
* about)
*/
if (need_nl)
tputc('\n', shf);
}
}
static void
pioact(shf, indent, iop)
register struct shf *shf;
int indent;
register struct ioword *iop;
{
int flag = iop->flag;
int type = flag & IOTYPE;
int expected;
expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0
: (type == IOCAT || type == IOWRITE) ? 1
: (type == IODUP && (iop->unit == !(flag & IORDUP))) ?
iop->unit
: iop->unit + 1;
if (iop->unit != expected)
tputc('0' + iop->unit, shf);
switch (type) {
case IOREAD:
fptreef(shf, indent, "< ");
break;
case IOHERE:
if (flag&IOSKIP)
fptreef(shf, indent, "<<- ");
else
fptreef(shf, indent, "<< ");
break;
case IOCAT:
fptreef(shf, indent, ">> ");
break;
case IOWRITE:
if (flag&IOCLOB)
fptreef(shf, indent, ">| ");
else
fptreef(shf, indent, "> ");
break;
case IORDWR:
fptreef(shf, indent, "<> ");
break;
case IODUP:
if (flag & IORDUP)
fptreef(shf, indent, "<&");
else
fptreef(shf, indent, ">&");
break;
}
/* name/delim are 0 when printing syntax errors */
if (type == IOHERE) {
if (iop->delim)
fptreef(shf, indent, "%S ", iop->delim);
} else if (iop->name)
fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
iop->name);
}
/*
* variants of fputc, fputs for ptreef and snptreef
*/
static void
tputC(c, shf)
register int c;
register struct shf *shf;
{
if ((c&0x60) == 0) { /* C0|C1 */
tputc((c&0x80) ? '$' : '^', shf);
tputc(((c&0x7F)|0x40), shf);
} else if ((c&0x7F) == 0x7F) { /* DEL */
tputc((c&0x80) ? '$' : '^', shf);
tputc('?', shf);
} else
tputc(c, shf);
}
static void
tputS(wp, shf)
register char *wp;
register struct shf *shf;
{
register int c, quoted=0;
/* problems:
* `...` -> $(...)
* 'foo' -> "foo"
* could change encoding to:
* OQUOTE ["'] ... CQUOTE ["']
* COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
*/
while (1)
switch ((c = *wp++)) {
case EOS:
return;
case CHAR:
tputC(*wp++, shf);
break;
case QCHAR:
c = *wp++;
if (!quoted || (c == '"' || c == '`' || c == '$'))
tputc('\\', shf);
tputC(c, shf);
break;
case COMSUB:
tputc('$', shf);
tputc('(', shf);
while (*wp != 0)
tputC(*wp++, shf);
tputc(')', shf);
wp++;
break;
case EXPRSUB:
tputc('$', shf);
tputc('(', shf);
tputc('(', shf);
while (*wp != 0)
tputC(*wp++, shf);
tputc(')', shf);
tputc(')', shf);
wp++;
break;
case OQUOTE:
quoted = 1;
tputc('"', shf);
break;
case CQUOTE:
quoted = 0;
tputc('"', shf);
break;
case OSUBST:
tputc('$', shf);
if (*wp++ == '{')
tputc('{', shf);
while ((c = *wp++) != 0)
tputC(c, shf);
break;
case CSUBST:
if (*wp++ == '}')
tputc('}', shf);
break;
#ifdef KSH
case OPAT:
tputc(*wp++, shf);
tputc('(', shf);
break;
case SPAT:
tputc('|', shf);
break;
case CPAT:
tputc(')', shf);
break;
#endif /* KSH */
}
}
/*
* this is the _only_ way to reliably handle
* variable args with an ANSI compiler
*/
/* VARARGS */
int
#ifdef HAVE_PROTOTYPES
fptreef(struct shf *shf, int indent, const char *fmt, ...)
#else
fptreef(shf, indent, fmt, va_alist)
struct shf *shf;
int indent;
const char *fmt;
va_dcl
#endif
{
va_list va;
SH_VA_START(va, fmt);
vfptreef(shf, indent, fmt, va);
va_end(va);
return 0;
}
/* VARARGS */
char *
#ifdef HAVE_PROTOTYPES
snptreef(char *s, int n, const char *fmt, ...)
#else
snptreef(s, n, fmt, va_alist)
char *s;
int n;
const char *fmt;
va_dcl
#endif
{
va_list va;
struct shf shf;
shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
SH_VA_START(va, fmt);
vfptreef(&shf, 0, fmt, va);
va_end(va);
return shf_sclose(&shf); /* null terminates */
}
static void
vfptreef(shf, indent, fmt, va)
register struct shf *shf;
int indent;
const char *fmt;
register va_list va;
{
register int c;
while ((c = *fmt++))
if (c == '%') {
register long n;
register char *p;
int neg;
switch ((c = *fmt++)) {
case 'c':
tputc(va_arg(va, int), shf);
break;
case 's':
p = va_arg(va, char *);
while (*p)
tputc(*p++, shf);
break;
case 'S': /* word */
p = va_arg(va, char *);
tputS(p, shf);
break;
case 'd': case 'u': /* decimal */
n = (c == 'd') ? va_arg(va, int)
: va_arg(va, unsigned int);
neg = c=='d' && n<0;
p = ulton((neg) ? -n : n, 10);
if (neg)
*--p = '-';
while (*p)
tputc(*p++, shf);
break;
case 'T': /* format tree */
ptree(va_arg(va, struct op *), indent, shf);
break;
case ';': /* newline or ; */
case 'N': /* newline or space */
if (shf->flags & SHF_STRING) {
if (c == ';')
tputc(';', shf);
tputc(' ', shf);
} else {
int i;
tputc('\n', shf);
for (i = indent; i >= 8; i -= 8)
tputc('\t', shf);
for (; i > 0; --i)
tputc(' ', shf);
}
break;
case 'R':
pioact(shf, indent, va_arg(va, struct ioword *));
break;
default:
tputc(c, shf);
break;
}
} else
tputc(c, shf);
}
/*
* copy tree (for function definition)
*/
struct op *
tcopy(t, ap)
register struct op *t;
Area *ap;
{
register struct op *r;
register char **tw, **rw;
if (t == NULL)
return NULL;
r = (struct op *) alloc(sizeof(struct op), ap);
r->type = t->type;
r->u.evalflags = t->u.evalflags;
r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
if (t->vars == NULL)
r->vars = NULL;
else {
for (tw = t->vars; *tw++ != NULL; )
;
rw = r->vars = (char **)
alloc((tw - t->vars + 1) * sizeof(*tw), ap);
for (tw = t->vars; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
if (t->args == NULL)
r->args = NULL;
else {
for (tw = t->args; *tw++ != NULL; )
;
rw = r->args = (char **)
alloc((tw - t->args + 1) * sizeof(*tw), ap);
for (tw = t->args; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
r->left = tcopy(t->left, ap);
r->right = tcopy(t->right, ap);
r->lineno = t->lineno;
return r;
}
char *
wdcopy(wp, ap)
const char *wp;
Area *ap;
{
size_t len = wdscan(wp, EOS) - wp;
return memcpy(alloc(len, ap), wp, len);
}
/* return the position of prefix c in wp plus 1 */
char *
wdscan(wp, c)
register const char *wp;
register int c;
{
register int nest = 0;
while (1)
switch (*wp++) {
case EOS:
return (char *) __UNCONST(wp);
case CHAR:
case QCHAR:
wp++;
break;
case COMSUB:
case EXPRSUB:
while (*wp++ != 0)
;
break;
case OQUOTE:
case CQUOTE:
break;
case OSUBST:
nest++;
while (*wp++ != '\0')
;
break;
case CSUBST:
wp++;
if (c == CSUBST && nest == 0)
return (char *) __UNCONST(wp);
nest--;
break;
#ifdef KSH
case OPAT:
nest++;
wp++;
break;
case SPAT:
case CPAT:
if (c == wp[-1] && nest == 0)
return (char *) __UNCONST(wp);
if (wp[-1] == CPAT)
nest--;
break;
#endif /* KSH */
default:
internal_errorf(0,
"wdscan: unknown char 0x%x (carrying on)",
wp[-1]);
}
}
/* return a copy of wp without any of the mark up characters and
* with quote characters (" ' \) stripped.
* (string is allocated from ATEMP)
*/
char *
wdstrip(wp)
const char *wp;
{
struct shf shf;
int c;
shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf);
/* problems:
* `...` -> $(...)
* x${foo:-"hi"} -> x${foo:-hi}
* x${foo:-'hi'} -> x${foo:-hi}
*/
while (1)
switch ((c = *wp++)) {
case EOS:
return shf_sclose(&shf); /* null terminates */
case CHAR:
case QCHAR:
shf_putchar(*wp++, &shf);
break;
case COMSUB:
shf_putchar('$', &shf);
shf_putchar('(', &shf);
while (*wp != 0)
shf_putchar(*wp++, &shf);
shf_putchar(')', &shf);
break;
case EXPRSUB:
shf_putchar('$', &shf);
shf_putchar('(', &shf);
shf_putchar('(', &shf);
while (*wp != 0)
shf_putchar(*wp++, &shf);
shf_putchar(')', &shf);
shf_putchar(')', &shf);
break;
case OQUOTE:
break;
case CQUOTE:
break;
case OSUBST:
shf_putchar('$', &shf);
if (*wp++ == '{')
shf_putchar('{', &shf);
while ((c = *wp++) != 0)
shf_putchar(c, &shf);
break;
case CSUBST:
if (*wp++ == '}')
shf_putchar('}', &shf);
break;
#ifdef KSH
case OPAT:
shf_putchar(*wp++, &shf);
shf_putchar('(', &shf);
break;
case SPAT:
shf_putchar('|', &shf);
break;
case CPAT:
shf_putchar(')', &shf);
break;
#endif /* KSH */
}
}
static struct ioword **
iocopy(iow, ap)
register struct ioword **iow;
Area *ap;
{
register struct ioword **ior;
register int i;
for (ior = iow; *ior++ != NULL; )
;
ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
for (i = 0; iow[i] != NULL; i++) {
register struct ioword *p, *q;
p = iow[i];
q = (struct ioword *) alloc(sizeof(*p), ap);
ior[i] = q;
*q = *p;
if (p->name != (char *) 0)
q->name = wdcopy(p->name, ap);
if (p->delim != (char *) 0)
q->delim = wdcopy(p->delim, ap);
if (p->heredoc != (char *) 0)
q->heredoc = str_save(p->heredoc, ap);
}
ior[i] = NULL;
return ior;
}
/*
* free tree (for function definition)
*/
void
tfree(t, ap)
register struct op *t;
Area *ap;
{
register char **w;
if (t == NULL)
return;
if (t->str != NULL)
afree((void*)t->str, ap);
if (t->vars != NULL) {
for (w = t->vars; *w != NULL; w++)
afree((void*)*w, ap);
afree((void*)t->vars, ap);
}
if (t->args != NULL) {
for (w = t->args; *w != NULL; w++)
afree((void*)*w, ap);
afree((void*)t->args, ap);
}
if (t->ioact != NULL)
iofree(t->ioact, ap);
tfree(t->left, ap);
tfree(t->right, ap);
afree((void*)t, ap);
}
static void
iofree(iow, ap)
struct ioword **iow;
Area *ap;
{
register struct ioword **iop;
register struct ioword *p;
for (iop = iow; (p = *iop++) != NULL; ) {
if (p->name != NULL)
afree((void*)p->name, ap);
if (p->delim != NULL)
afree((void*)p->delim, ap);
if (p->heredoc != NULL)
afree((void*)p->heredoc, ap);
afree((void*)p, ap);
}
}

142
bin/ksh/tree.h Normal file
View file

@ -0,0 +1,142 @@
/* $NetBSD: tree.h,v 1.4 2004/07/07 19:20:09 mycroft Exp $ */
/*
* command trees for compile/execute
*/
/* $Id: tree.h,v 1.4 2004/07/07 19:20:09 mycroft Exp $ */
#define NOBLOCK ((struct op *)NULL)
#define NOWORD ((char *)NULL)
#define NOWORDS ((char **)NULL)
/*
* Description of a command or an operation on commands.
*/
struct op {
short type; /* operation type, see below */
union { /* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
short evalflags; /* TCOM: arg expansion eval() flags */
short ksh_func; /* TFUNC: function x (vs x()) */
} u;
char **args; /* arguments to a command */
char **vars; /* variable assignments */
struct ioword **ioact; /* IO actions (eg, < > >>) */
struct op *left, *right; /* descendents */
char *str; /* word for case; identifier for for,
* select, and functions;
* path to execute for TEXEC;
* time hook for TCOM.
*/
int lineno; /* TCOM/TFUNC: LINENO for this */
};
/* Tree.type values */
#define TEOF 0
#define TCOM 1 /* command */
#define TPAREN 2 /* (c-list) */
#define TPIPE 3 /* a | b */
#define TLIST 4 /* a ; b */
#define TOR 5 /* || */
#define TAND 6 /* && */
#define TBANG 7 /* ! */
#define TDBRACKET 8 /* [[ .. ]] */
#define TFOR 9
#define TSELECT 10
#define TCASE 11
#define TIF 12
#define TWHILE 13
#define TUNTIL 14
#define TELIF 15
#define TPAT 16 /* pattern in case */
#define TBRACE 17 /* {c-list} */
#define TASYNC 18 /* c & */
#define TFUNCT 19 /* function name { command; } */
#define TTIME 20 /* time pipeline */
#define TEXEC 21 /* fork/exec eval'd TCOM */
#define TCOPROC 22 /* coprocess |& */
/*
* prefix codes for words in command tree
*/
#define EOS 0 /* end of string */
#define CHAR 1 /* unquoted character */
#define QCHAR 2 /* quoted character */
#define COMSUB 3 /* $() substitution (0 terminated) */
#define EXPRSUB 4 /* $(()) substitution (0 terminated) */
#define OQUOTE 5 /* opening " or ' */
#define CQUOTE 6 /* closing " or ' */
#define OSUBST 7 /* opening ${ subst (followed by { or X) */
#define CSUBST 8 /* closing } of above (followed by } or X) */
#define OPAT 9 /* open pattern: *(, @(, etc. */
#define SPAT 10 /* separate pattern: | */
#define CPAT 11 /* close pattern: ) */
/*
* IO redirection
*/
struct ioword {
int unit; /* unit affected */
int flag; /* action (below) */
char *name; /* file name (unused if heredoc) */
char *delim; /* delimiter for <<,<<- */
char *heredoc;/* content of heredoc */
};
/* ioword.flag - type of redirection */
#define IOTYPE 0xF /* type: bits 0:3 */
#define IOREAD 0x1 /* < */
#define IOWRITE 0x2 /* > */
#define IORDWR 0x3 /* <>: todo */
#define IOHERE 0x4 /* << (here file) */
#define IOCAT 0x5 /* >> */
#define IODUP 0x6 /* <&/>& */
#define IOEVAL BIT(4) /* expand in << */
#define IOSKIP BIT(5) /* <<-, skip ^\t* */
#define IOCLOB BIT(6) /* >|, override -o noclobber */
#define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */
#define IONAMEXP BIT(8) /* name has been expanded */
/* execute/exchild flags */
#define XEXEC BIT(0) /* execute without forking */
#define XFORK BIT(1) /* fork before executing */
#define XBGND BIT(2) /* command & */
#define XPIPEI BIT(3) /* input is pipe */
#define XPIPEO BIT(4) /* output is pipe */
#define XPIPE (XPIPEI|XPIPEO) /* member of pipe */
#define XXCOM BIT(5) /* `...` command */
#define XPCLOSE BIT(6) /* exchild: close close_fd in parent */
#define XCCLOSE BIT(7) /* exchild: close close_fd in child */
#define XERROK BIT(8) /* non-zero exit ok (for set -e) */
#define XCOPROC BIT(9) /* starting a co-process */
#define XTIME BIT(10) /* timing TCOM command */
#define XINTACT BIT(11) /* OS2: proc started from interactive session */
/*
* flags to control expansion of words (assumed by t->evalflags to fit
* in a short)
*/
#define DOBLANK BIT(0) /* perform blank interpretation */
#define DOGLOB BIT(1) /* expand [?* */
#define DOPAT BIT(2) /* quote *?[ */
#define DOTILDE BIT(3) /* normal ~ expansion (first char) */
#define DONTRUNCOMMAND BIT(4) /* do not run $(command) things */
#define DOASNTILDE BIT(5) /* assignment ~ expansion (after =, :) */
#define DOBRACE_ BIT(6) /* used by expand(): do brace expansion */
#define DOMAGIC_ BIT(7) /* used by expand(): string contains MAGIC */
#define DOTEMP_ BIT(8) /* ditto : in word part of ${..[%#=?]..} */
#define DOVACHECK BIT(9) /* var assign check (for typeset, set, etc) */
#define DOMARKDIRS BIT(10) /* force markdirs behaviour */
/*
* The arguments of [[ .. ]] expressions are kept in t->args[] and flags
* indicating how the arguments have been munged are kept in t->vars[].
* The contents of t->vars[] are stuffed strings (so they can be treated
* like all other t->vars[]) in which the second character is the one that
* is examined. The DB_* defines are the values for these second characters.
*/
#define DB_NORM 1 /* normal argument */
#define DB_OR 2 /* || -> -o conversion */
#define DB_AND 3 /* && -> -a conversion */
#define DB_BE 4 /* an inserted -BE */
#define DB_PAT 5 /* a pattern argument */

187
bin/ksh/tty.c Normal file
View file

@ -0,0 +1,187 @@
/* $NetBSD: tty.c,v 1.4 2003/06/23 11:39:06 agc Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: tty.c,v 1.4 2003/06/23 11:39:06 agc Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h"
#define EXTERN
#include "tty.h"
#undef EXTERN
int
get_tty(fd, ts)
int fd;
TTY_state *ts;
{
int ret;
# ifdef HAVE_TERMIOS_H
ret = tcgetattr(fd, ts);
# else /* HAVE_TERIOS_H */
# ifdef HAVE_TERMIO_H
ret = ioctl(fd, TCGETA, ts);
# else /* HAVE_TERMIO_H */
ret = ioctl(fd, TIOCGETP, &ts->sgttyb);
# ifdef TIOCGATC
if (ioctl(fd, TIOCGATC, &ts->lchars) < 0)
ret = -1;
# else
if (ioctl(fd, TIOCGETC, &ts->tchars) < 0)
ret = -1;
# ifdef TIOCGLTC
if (ioctl(fd, TIOCGLTC, &ts->ltchars) < 0)
ret = -1;
# endif /* TIOCGLTC */
# endif /* TIOCGATC */
# endif /* HAVE_TERMIO_H */
# endif /* HAVE_TERIOS_H */
return ret;
}
int
set_tty(fd, ts, flags)
int fd;
TTY_state *ts;
int flags;
{
int ret = 0;
# ifdef HAVE_TERMIOS_H
ret = tcsetattr(fd, TCSADRAIN, ts);
# else /* HAVE_TERIOS_H */
# ifdef HAVE_TERMIO_H
# ifndef TCSETAW /* e.g. Cray-2 */
/* first wait for output to drain */
# ifdef TCSBRK
if (ioctl(tty_fd, TCSBRK, 1) < 0)
ret = -1;
# else /* the following kludge is minimally intrusive, but sometimes fails */
if (flags & TF_WAIT)
sleep((unsigned)1); /* fake it */
# endif
# endif /* !TCSETAW */
# if defined(_BSD_SYSV) || !defined(TCSETAW)
/* _BSD_SYSV must force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
if (ioctl(tty_fd, TCSETA, ts) < 0)
ret = -1;
# else
if (ioctl(tty_fd, TCSETAW, ts) < 0)
ret = -1;
# endif
# else /* HAVE_TERMIO_H */
# if defined(__mips) && (defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43))
/* Under RISC/os 5.00, bsd43 environment, after a tty driver
* generated interrupt (eg, INTR, TSTP), all output to tty is
* lost until a SETP is done (there must be a better way of
* doing this...).
*/
if (flags & TF_MIPSKLUDGE)
ret = ioctl(fd, TIOCSETP, &ts->sgttyb);
else
# endif /* _SYSTYPE_BSD43 */
ret = ioctl(fd, TIOCSETN, &ts->sgttyb);
# ifdef TIOCGATC
if (ioctl(fd, TIOCSATC, &ts->lchars) < 0)
ret = -1;
# else
if (ioctl(fd, TIOCSETC, &ts->tchars) < 0)
ret = -1;
# ifdef TIOCGLTC
if (ioctl(fd, TIOCSLTC, &ts->ltchars) < 0)
ret = -1;
# endif /* TIOCGLTC */
# endif /* TIOCGATC */
# endif /* HAVE_TERMIO_H */
# endif /* HAVE_TERIOS_H */
return ret;
}
/* Initialize tty_fd. Used for saving/reseting tty modes upon
* foreground job completion and for setting up tty process group.
*/
void
tty_init(init_ttystate)
int init_ttystate;
{
int do_close = 1;
int tfd;
const char *devtty = _PATH_TTY;
if (tty_fd >= 0) {
close(tty_fd);
tty_fd = -1;
}
tty_devtty = 1;
/* SCO can't job control on /dev/tty, so don't try... */
#if !defined(__SCO__)
if ((tfd = open(devtty, O_RDWR, 0)) < 0) {
#ifdef __NeXT
/* rlogin on NeXT boxes does not set up the controlling tty,
* so force it to be done here...
*/
{
extern char *ttyname ARGS((int));
char *s = ttyname(isatty(2) ? 2 : 0);
int fd;
if (s && (fd = open(s, O_RDWR, 0)) >= 0) {
close(fd);
tfd = open(devtty, O_RDWR, 0);
}
}
#endif /* __NeXT */
/* X11R5 xterm on mips doesn't set controlling tty properly - temporary hack */
# if !defined(__mips) || !(defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43))
if (tfd < 0) {
tty_devtty = 0;
warningf(FALSE,
"No controlling tty (open %s: %s)",
devtty, strerror(errno));
}
# endif /* __mips */
}
#else /* !__SCO__ */
tfd = -1;
#endif /* __SCO__ */
if (tfd < 0) {
do_close = 0;
if (isatty(0))
tfd = 0;
else if (isatty(2))
tfd = 2;
else {
warningf(FALSE, "Can't find tty file descriptor");
return;
}
}
if ((tty_fd = ksh_dupbase(tfd, FDBASE)) < 0) {
warningf(FALSE, "j_ttyinit: dup of tty fd failed: %s",
strerror(errno));
} else if (fd_clexec(tty_fd) < 0) {
warningf(FALSE, "j_ttyinit: can't set close-on-exec flag: %s",
strerror(errno));
close(tty_fd);
tty_fd = -1;
} else if (init_ttystate)
get_tty(tty_fd, &tty_state);
if (do_close)
close(tfd);
}
void
tty_close()
{
if (tty_fd >= 0) {
close(tty_fd);
tty_fd = -1;
}
}

110
bin/ksh/tty.h Normal file
View file

@ -0,0 +1,110 @@
/* $NetBSD: tty.h,v 1.2 1997/01/12 19:12:25 tls Exp $ */
/*
tty.h -- centralized definitions for a variety of terminal interfaces
created by DPK, Oct. 1986
Rearranged to work with autoconf, added TTY_state, get_tty/set_tty
Michael Rendell, May '94
last edit: 30-Jul-1987 D A Gwyn
*/
/* $NetBSD: tty.h,v 1.2 1997/01/12 19:12:25 tls Exp $ */
/* some useful #defines */
#ifdef EXTERN
# define I__(i) = i
#else
# define I__(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
/* Don't know of a system on which including sys/ioctl.h with termios.h
* causes problems. If there is one, these lines need to be deleted and
* aclocal.m4 needs to have stuff un-commented.
*/
#ifdef SYS_IOCTL_WITH_TERMIOS
# define SYS_IOCTL_WITH_TERMIOS
#endif /* SYS_IOCTL_WITH_TERMIOS */
#ifdef SYS_IOCTL_WITH_TERMIO
# define SYS_IOCTL_WITH_TERMIO
#endif /* SYS_IOCTL_WITH_TERMIO */
#ifdef HAVE_TERMIOS_H
# include <termios.h>
# ifdef SYS_IOCTL_WITH_TERMIOS
# if !(defined(sun) && !defined(__svr4__)) /* too many warnings on sunos */
/* Need to include sys/ioctl.h on some systems to get the TIOCGWINSZ
* stuff (eg, digital unix).
*/
# include <sys/ioctl.h>
# endif /* !(sun && !__svr4__) */
# endif /* SYS_IOCTL_WITH_TERMIOS */
typedef struct termios TTY_state;
#else
# ifdef HAVE_TERMIO_H
# include <termio.h>
# ifdef SYS_IOCTL_WITH_TERMIO
# include <sys/ioctl.h> /* see comment above in termios stuff */
# endif /* SYS_IOCTL_WITH_TERMIO */
# if _BSD_SYSV /* BRL UNIX System V emulation */
# ifndef NTTYDISC
# define TIOCGETD _IOR( 't', 0, int )
# define TIOCSETD _IOW( 't', 1, int )
# define NTTYDISC 2
# endif
# ifndef TIOCSTI
# define TIOCSTI _IOW( 't', 114, char )
# endif
# ifndef TIOCSPGRP
# define TIOCSPGRP _IOW( 't', 118, int )
# endif
# endif /* _BSD_SYSV */
typedef struct termio TTY_state;
# else /* HAVE_TERMIO_H */
/* Assume BSD tty stuff. Uses TIOCGETP, TIOCSETN; uses TIOCGATC/TIOCSATC if
* available, otherwise it uses TIOCGETC/TIOCSETC (also uses TIOCGLTC/TIOCSLTC
* if available)
*/
# ifdef _MINIX
# include <sgtty.h>
# define TIOCSETN TIOCSETP
# else
# include <sys/ioctl.h>
# endif
typedef struct {
struct sgttyb sgttyb;
# ifdef TIOCGATC
struct lchars lchars;
# else /* TIOCGATC */
struct tchars tchars;
# ifdef TIOCGLTC
struct ltchars ltchars;
# endif /* TIOCGLTC */
# endif /* TIOCGATC */
} TTY_state;
# endif /* HAVE_TERMIO_H */
#endif /* HAVE_TERMIOS_H */
/* Flags for set_tty() */
#define TF_NONE 0x00
#define TF_WAIT 0x01 /* drain output, even it requires sleep() */
#define TF_MIPSKLUDGE 0x02 /* kludge to unwedge RISC/os 5.0 tty driver */
EXTERN int tty_fd I__(-1); /* dup'd tty file descriptor */
EXTERN int tty_devtty; /* true if tty_fd is from /dev/tty */
EXTERN TTY_state tty_state; /* saved tty state */
extern int get_tty ARGS((int fd, TTY_state *ts));
extern int set_tty ARGS((int fd, TTY_state *ts, int flags));
extern void tty_init ARGS((int init_ttystate));
extern void tty_close ARGS((void));
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef I__

1260
bin/ksh/var.c Normal file

File diff suppressed because it is too large Load diff

16
bin/ksh/version.c Normal file
View file

@ -0,0 +1,16 @@
/* $NetBSD: version.c,v 1.5 2005/06/26 19:09:00 christos Exp $ */
/*
* value of $KSH_VERSION (or $SH_VERSION)
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: version.c,v 1.5 2005/06/26 19:09:00 christos Exp $");
#endif
#include "sh.h"
char ksh_version [] =
"@(#)PD KSH v5.2.14 99/07/13.2";

2203
bin/ksh/vi.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@
./bin/halt minix-sys
./bin/intr minix-sys
./bin/kill minix-sys
./bin/ksh minix-sys
./bin/ln minix-sys
./bin/loadkeys minix-sys
./bin/ls minix-sys
@ -1287,6 +1288,7 @@
./usr/man/man1/jobs.1 minix-sys
./usr/man/man1/join.1 minix-sys
./usr/man/man1/kill.1 minix-sys
./usr/man/man1/ksh.1 minix-sys
./usr/man/man1/last.1 minix-sys
./usr/man/man1/ldd.1 minix-sys
./usr/man/man1/ld.elf_so.1 minix-sys

View file

@ -1,3 +1,9 @@
20130312:
/bin/ksh was imported and needs to be added to your /etc/shells.
Run this command to add it:
# echo "/bin/ksh" >> /etc/shells
20130306:
For people building ARM images, the procedure has changed
a bit. You need a full FS to boot now. In short, you need

View file

@ -1 +1,2 @@
/bin/sh
/bin/ksh

View file

@ -12,6 +12,7 @@
2012/01/16 18:47:57,bin/ed
2012/10/17 12:00:00,bin/expr
2012/10/17 12:00:00,bin/kill
2013/03/12 12:00:00,bin/ksh
2012/10/17 12:00:00,bin/ln
2012/10/17 12:00:00,bin/ls
2012/10/17 12:00:00,bin/Makefile