• more comment and int→bool cleanup, add and improve some comments
• in interactive mode, always look up {LC_{ALL,CTYPE},LANG} environment variables if setlocale/nl_langinfo(CODESET) doesn’t suffice • add the ability to call any builtin (some don't make sense or wouldn't work) directly by analysing argv[0] • for direct builtin calls, the {LC_{ALL,CTYPE},LANG} environment variables determine utf8-mode, even if MKSH_ASSUME_UTF8 was set • when called as builtin, echo behaves POSIXish • add domainname as alias for true on MirBSD only, to be able to link it • sync mksh Makefiles with Build.sh output • adjust manpage wrt release plans • link some things to mksh now that we have callable builtins: bin/echo bin/kill bin/pwd bin/sleep (exact matches) bin/test bin/[ (were scripts before) bin/domainname=usr/bin/true usr/bin/false (move to /bin/ now) • drop linked utilities and, except for echo and kill, their manpages • adjust instbin and link a few more there as well
This commit is contained in:
274
main.c
274
main.c
@ -33,7 +33,7 @@
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.175 2011/01/21 21:07:11 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.176 2011/02/11 01:18:18 tg Exp $");
|
||||
|
||||
extern char **environ;
|
||||
|
||||
@ -67,7 +67,8 @@ static const char *initcoms[] = {
|
||||
T_alias,
|
||||
"integer=typeset -i",
|
||||
T_local_typeset,
|
||||
"hash=alias -t", /* not "alias -t --": hash -r needs to work */
|
||||
/* not "alias -t --": hash -r needs to work */
|
||||
"hash=alias -t",
|
||||
"type=whence -v",
|
||||
#if !defined(ANDROID) && !defined(MKSH_UNEMPLOYED)
|
||||
/* not in Android for political reasons */
|
||||
@ -111,12 +112,18 @@ rndsetup(void)
|
||||
char *cp;
|
||||
|
||||
cp = alloc(sizeof(*bufptr) - ALLOC_SIZE, APERM);
|
||||
bufptr = (void *)(cp - ALLOC_SIZE); /* undo what alloc() did */
|
||||
bufptr->dataptr = &rndsetupstate; /* PIE or something */
|
||||
bufptr->stkptr = &bufptr; /* ASLR in Win/Lin */
|
||||
bufptr->mallocptr = bufptr; /* randomised malloc in BSD */
|
||||
sigsetjmp(bufptr->jbuf, 1); /* glibc pointer guard */
|
||||
gettimeofday(&bufptr->tv, &bufptr->tz); /* introduce variation */
|
||||
/* undo what alloc() did to the malloc result address */
|
||||
bufptr = (void *)(cp - ALLOC_SIZE);
|
||||
/* PIE or something similar provides us with deltas here */
|
||||
bufptr->dataptr = &rndsetupstate;
|
||||
/* ASLR in at least Windows, Linux, some BSDs */
|
||||
bufptr->stkptr = &bufptr;
|
||||
/* randomised malloc in BSD (and possibly others) */
|
||||
bufptr->mallocptr = bufptr;
|
||||
/* glibc pointer guard */
|
||||
sigsetjmp(bufptr->jbuf, 1);
|
||||
/* introduce variation */
|
||||
gettimeofday(&bufptr->tv, &bufptr->tz);
|
||||
|
||||
oaat1_init_impl(h);
|
||||
/* variation through pid, ppid, and the works */
|
||||
@ -138,14 +145,18 @@ chvt_reinit(void)
|
||||
kshppid = getppid();
|
||||
}
|
||||
|
||||
static const char *empty_argv[] = {
|
||||
"mksh", NULL
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
int argi, i;
|
||||
Source *s;
|
||||
Source *s = NULL;
|
||||
struct block *l;
|
||||
unsigned char restricted, errexit, utf_flag;
|
||||
const char **wp;
|
||||
const char *ccp, **wp;
|
||||
struct tbl *vp;
|
||||
struct stat s_stdin;
|
||||
#if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
|
||||
@ -158,16 +169,13 @@ main(int argc, const char *argv[])
|
||||
|
||||
/* make sure argv[] is sane */
|
||||
if (!*argv) {
|
||||
static const char *empty_argv[] = {
|
||||
"mksh", NULL
|
||||
};
|
||||
|
||||
argv = empty_argv;
|
||||
argc = 1;
|
||||
}
|
||||
kshname = *argv;
|
||||
kshname = argv[0];
|
||||
|
||||
ainit(&aperm); /* initialise permanent Area */
|
||||
/* initialise permanent Area */
|
||||
ainit(&aperm);
|
||||
|
||||
/* set up base environment */
|
||||
env.type = E_NONE;
|
||||
@ -178,9 +186,41 @@ main(int argc, const char *argv[])
|
||||
/* Do this first so output routines (eg, errorf, shellf) can work */
|
||||
initio();
|
||||
|
||||
argi = parse_args(argv, OF_FIRSTTIME, NULL);
|
||||
if (argi < 0)
|
||||
return (1);
|
||||
/* determine the basename (without '-' or path) of the executable */
|
||||
ccp = kshname;
|
||||
goto begin_parse_kshname;
|
||||
while ((i = ccp[argi++])) {
|
||||
if (i == '/') {
|
||||
ccp += argi;
|
||||
begin_parse_kshname:
|
||||
argi = 0;
|
||||
if (*ccp == '-')
|
||||
++ccp;
|
||||
}
|
||||
}
|
||||
if (!*ccp)
|
||||
ccp = empty_argv[0];
|
||||
|
||||
/* define built-in commands and see if we were called as one */
|
||||
ktinit(&builtins, APERM,
|
||||
/* must be 80% of 2^n (currently 44 builtins) */ 64);
|
||||
for (i = 0; mkshbuiltins[i].name != NULL; i++)
|
||||
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
|
||||
mkshbuiltins[i].func)))
|
||||
Flag(FAS_BUILTIN) = 1;
|
||||
|
||||
if (!Flag(FAS_BUILTIN)) {
|
||||
/* check for -T option early */
|
||||
argi = parse_args(argv, OF_FIRSTTIME, NULL);
|
||||
if (argi < 0)
|
||||
return (1);
|
||||
|
||||
#ifdef MKSH_BINSHREDUCED
|
||||
/* set FSH if we're called as -sh or /bin/sh or so */
|
||||
if (!strcmp(ccp, "sh"))
|
||||
change_flag(FSH, OF_FIRSTTIME, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
initvar();
|
||||
|
||||
@ -200,12 +240,6 @@ main(int argc, const char *argv[])
|
||||
/* define shell keywords */
|
||||
initkeywords();
|
||||
|
||||
/* define built-in commands */
|
||||
ktinit(&builtins, APERM,
|
||||
/* must be 80% of 2^n (currently 44 builtins) */ 64);
|
||||
for (i = 0; mkshbuiltins[i].name != NULL; i++)
|
||||
builtin(mkshbuiltins[i].name, mkshbuiltins[i].func);
|
||||
|
||||
init_histvec();
|
||||
|
||||
#ifdef _PATH_DEFPATH
|
||||
@ -260,28 +294,13 @@ main(int argc, const char *argv[])
|
||||
Flag(FVITABCOMPLETE) = 1;
|
||||
#endif
|
||||
|
||||
#ifdef MKSH_BINSHREDUCED
|
||||
/* set FSH if we're called as -sh or /bin/sh or so */
|
||||
{
|
||||
const char *cc;
|
||||
|
||||
cc = kshname;
|
||||
i = 0; argi = 0;
|
||||
while (cc[i] != '\0')
|
||||
/* the following line matches '-' and '/' ;-) */
|
||||
if ((cc[i++] | 2) == '/')
|
||||
argi = i;
|
||||
if (((cc[argi] | 0x20) == 's') && ((cc[argi + 1] | 0x20) == 'h'))
|
||||
change_flag(FSH, OF_FIRSTTIME, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* import environment */
|
||||
if (environ != NULL)
|
||||
for (wp = (const char **)environ; *wp != NULL; wp++)
|
||||
typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
|
||||
|
||||
typeset(initifs, 0, 0, 0, 0); /* for security */
|
||||
/* for security */
|
||||
typeset(initifs, 0, 0, 0, 0);
|
||||
|
||||
/* assign default shell variable values */
|
||||
substitute(initsubs, 0);
|
||||
@ -356,15 +375,20 @@ main(int argc, const char *argv[])
|
||||
/* this to note if utf-8 mode is set on command line (see below) */
|
||||
UTFMODE = 2;
|
||||
|
||||
argi = parse_args(argv, OF_CMDLINE, NULL);
|
||||
if (argi < 0)
|
||||
return (1);
|
||||
if (!Flag(FAS_BUILTIN)) {
|
||||
argi = parse_args(argv, OF_CMDLINE, NULL);
|
||||
if (argi < 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* process this later only, default to off (hysterical raisins) */
|
||||
utf_flag = UTFMODE;
|
||||
UTFMODE = 0;
|
||||
|
||||
if (Flag(FCOMMAND)) {
|
||||
if (Flag(FAS_BUILTIN)) {
|
||||
/* auto-detect from environment variables, always */
|
||||
utf_flag = 3;
|
||||
} else if (Flag(FCOMMAND)) {
|
||||
s = pushs(SSTRING, ATEMP);
|
||||
if (!(s->start = s->str = argv[argi++]))
|
||||
errorf("%s %s", "-c", "requires an argument");
|
||||
@ -410,37 +434,17 @@ main(int argc, const char *argv[])
|
||||
|
||||
/* initialise job control */
|
||||
j_init();
|
||||
/* set: 0/1; unset: 2->0 */
|
||||
UTFMODE = utf_flag & 1;
|
||||
/* Do this after j_init(), as tty_fd is not initialised until then */
|
||||
if (Flag(FTALKING)) {
|
||||
if (utf_flag == 2) {
|
||||
#ifndef MKSH_ASSUME_UTF8
|
||||
#define isuc(x) (((x) != NULL) && \
|
||||
(stristr((x), "UTF-8") || stristr((x), "utf8")))
|
||||
/* Check if we're in a UTF-8 locale */
|
||||
const char *ccp;
|
||||
|
||||
#if HAVE_SETLOCALE_CTYPE
|
||||
ccp = setlocale(LC_CTYPE, "");
|
||||
#if HAVE_LANGINFO_CODESET
|
||||
if (!isuc(ccp))
|
||||
ccp = nl_langinfo(CODESET);
|
||||
#endif
|
||||
#else
|
||||
/* these were imported from environ earlier */
|
||||
ccp = str_val(global("LC_ALL"));
|
||||
if (ccp == null)
|
||||
ccp = str_val(global("LC_CTYPE"));
|
||||
if (ccp == null)
|
||||
ccp = str_val(global("LANG"));
|
||||
#endif
|
||||
UTFMODE = isuc(ccp);
|
||||
#undef isuc
|
||||
/* auto-detect from locale or environment */
|
||||
utf_flag = 4;
|
||||
#elif MKSH_ASSUME_UTF8
|
||||
UTFMODE = 1;
|
||||
utf_flag = 1;
|
||||
#else
|
||||
UTFMODE = 0;
|
||||
/* always disable UTF-8 (for interactive) */
|
||||
utf_flag = 0;
|
||||
#endif
|
||||
}
|
||||
x_init();
|
||||
@ -453,10 +457,62 @@ main(int argc, const char *argv[])
|
||||
#endif
|
||||
|
||||
l = e->loc;
|
||||
l->argv = &argv[argi - 1];
|
||||
l->argc = argc - argi;
|
||||
l->argv[0] = kshname;
|
||||
getopts_reset(1);
|
||||
if (Flag(FAS_BUILTIN)) {
|
||||
l->argc = argc;
|
||||
l->argv = argv;
|
||||
l->argv[0] = ccp;
|
||||
} else {
|
||||
l->argc = argc - argi;
|
||||
l->argv = &argv[argi - 1];
|
||||
l->argv[0] = kshname;
|
||||
getopts_reset(1);
|
||||
}
|
||||
|
||||
/* divine the initial state of the utf8-mode Flag */
|
||||
#define isuc(x) (((x) != NULL) && \
|
||||
(stristr((x), "UTF-8") || stristr((x), "utf8")))
|
||||
ccp = null;
|
||||
switch (utf_flag) {
|
||||
|
||||
/* auto-detect from locale or environment */
|
||||
case 4:
|
||||
#if HAVE_SETLOCALE_CTYPE
|
||||
ccp = setlocale(LC_CTYPE, "");
|
||||
#if HAVE_LANGINFO_CODESET
|
||||
if (!isuc(ccp))
|
||||
ccp = nl_langinfo(CODESET);
|
||||
#endif
|
||||
if (!isuc(ccp))
|
||||
ccp = null;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
|
||||
/* auto-detect from environment */
|
||||
case 3:
|
||||
/* these were imported from environ earlier */
|
||||
if (ccp == null)
|
||||
ccp = str_val(global("LC_ALL"));
|
||||
if (ccp == null)
|
||||
ccp = str_val(global("LC_CTYPE"));
|
||||
if (ccp == null)
|
||||
ccp = str_val(global("LANG"));
|
||||
UTFMODE = isuc(ccp);
|
||||
break;
|
||||
|
||||
/* not set on command line, not FTALKING */
|
||||
case 2:
|
||||
/* unknown values */
|
||||
default:
|
||||
utf_flag = 0;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
/* known values */
|
||||
case 1:
|
||||
case 0:
|
||||
UTFMODE = utf_flag;
|
||||
break;
|
||||
}
|
||||
#undef isuc
|
||||
|
||||
/* Disable during .profile/ENV reading */
|
||||
restricted = Flag(FRESTRICTED);
|
||||
@ -505,7 +561,11 @@ main(int argc, const char *argv[])
|
||||
hist_init(s);
|
||||
alarm_init();
|
||||
} else
|
||||
Flag(FTRACKALL) = 1; /* set after ENV */
|
||||
/* set after ENV */
|
||||
Flag(FTRACKALL) = 1;
|
||||
|
||||
if (Flag(FAS_BUILTIN))
|
||||
return (shcomexec(l->argv));
|
||||
|
||||
/* doesn't return */
|
||||
shell(s, true);
|
||||
@ -543,7 +603,8 @@ include(const char *name, int argc, const char **argv, int intr_ok)
|
||||
switch (i) {
|
||||
case LRETURN:
|
||||
case LERROR:
|
||||
return (exstat & 0xff); /* see below */
|
||||
/* see below */
|
||||
return (exstat & 0xFF);
|
||||
case LINTR:
|
||||
/*
|
||||
* intr_ok is set if we are including .profile or $ENV.
|
||||
@ -575,7 +636,8 @@ include(const char *name, int argc, const char **argv, int intr_ok)
|
||||
e->loc->argv = old_argv;
|
||||
e->loc->argc = old_argc;
|
||||
}
|
||||
return (i & 0xff); /* & 0xff to ensure value not -1 */
|
||||
/* & 0xff to ensure value not -1 */
|
||||
return (i & 0xFF);
|
||||
}
|
||||
|
||||
/* spawn a command into a shell optionally keeping track of the line number */
|
||||
@ -603,7 +665,8 @@ shell(Source * volatile s, volatile int toplevel)
|
||||
Source *volatile old_source = source;
|
||||
int i;
|
||||
|
||||
s->flags |= SF_FIRST; /* enable UTF-8 BOM check */
|
||||
/* enable UTF-8 BOM check */
|
||||
s->flags |= SF_FIRST;
|
||||
|
||||
newenv(E_PARSE);
|
||||
if (interactive)
|
||||
@ -611,7 +674,8 @@ shell(Source * volatile s, volatile int toplevel)
|
||||
i = sigsetjmp(e->jbuf, 0);
|
||||
if (i) {
|
||||
switch (i) {
|
||||
case LINTR: /* we get here if SIGINT not caught or ignored */
|
||||
case LINTR:
|
||||
/* we get here if SIGINT not caught or ignored */
|
||||
case LERROR:
|
||||
case LSHELL:
|
||||
if (interactive) {
|
||||
@ -641,7 +705,8 @@ shell(Source * volatile s, volatile int toplevel)
|
||||
case LRETURN:
|
||||
source = old_source;
|
||||
quitenv(NULL);
|
||||
unwind(i); /* keep on going */
|
||||
/* keep on going */
|
||||
unwind(i);
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
source = old_source;
|
||||
@ -745,7 +810,8 @@ newenv(int type)
|
||||
* so first get the actually used memory, then assign it
|
||||
*/
|
||||
cp = alloc(sizeof(struct env) - ALLOC_SIZE, ATEMP);
|
||||
ep = (void *)(cp - ALLOC_SIZE); /* undo what alloc() did */
|
||||
/* undo what alloc() did to the malloc result address */
|
||||
ep = (void *)(cp - ALLOC_SIZE);
|
||||
/* initialise public members of struct env (not the ALLOC_ITEM) */
|
||||
ainit(&ep->area);
|
||||
ep->oenv = e;
|
||||
@ -772,7 +838,8 @@ quitenv(struct shf *shf)
|
||||
/* 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 */
|
||||
if (ep->savefd[2])
|
||||
/* Clear any write errors */
|
||||
shf_reopen(2, SHF_WR, shl_out);
|
||||
}
|
||||
/*
|
||||
@ -780,7 +847,8 @@ quitenv(struct shf *shf)
|
||||
* Either main shell is exiting or cleanup_parents_env() was called.
|
||||
*/
|
||||
if (ep->oenv == NULL) {
|
||||
if (ep->type == E_NONE) { /* Main shell exiting? */
|
||||
if (ep->type == E_NONE) {
|
||||
/* Main shell exiting? */
|
||||
#if HAVE_PERSISTENT_HISTORY
|
||||
if (Flag(FTALKING))
|
||||
hist_finish();
|
||||
@ -946,7 +1014,9 @@ errorf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
shl_stdout_ok = false; /* debugging: note that stdout not valid */
|
||||
/* debugging: note that stdout not valid */
|
||||
shl_stdout_ok = false;
|
||||
|
||||
exstat = 1;
|
||||
if (*fmt != 1) {
|
||||
error_prefix(true);
|
||||
@ -982,12 +1052,14 @@ bi_errorf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
shl_stdout_ok = false; /* debugging: note that stdout not valid */
|
||||
/* debugging: note that stdout not valid */
|
||||
shl_stdout_ok = false;
|
||||
|
||||
exstat = 1;
|
||||
if (*fmt != 1) {
|
||||
error_prefix(true);
|
||||
/* not set when main() calls parse_args() */
|
||||
if (builtin_argv0)
|
||||
if (builtin_argv0 && builtin_argv0 != kshname)
|
||||
shf_fprintf(shl_out, "%s: ", builtin_argv0);
|
||||
va_start(va, fmt);
|
||||
shf_vfprintf(shl_out, fmt, va);
|
||||
@ -1058,7 +1130,8 @@ shellf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
if (!initio_done) /* shl_out may not be set up yet... */
|
||||
if (!initio_done)
|
||||
/* shl_out may not be set up yet... */
|
||||
return;
|
||||
va_start(va, fmt);
|
||||
shf_vfprintf(shl_out, fmt, va);
|
||||
@ -1094,9 +1167,11 @@ struct shf shf_iob[3];
|
||||
void
|
||||
initio(void)
|
||||
{
|
||||
shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
|
||||
/* force buffer allocation */
|
||||
shf_fdopen(1, SHF_WR, shl_stdout);
|
||||
shf_fdopen(2, SHF_WR, shl_out);
|
||||
shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
|
||||
/* force buffer allocation */
|
||||
shf_fdopen(2, SHF_WR, shl_spare);
|
||||
initio_done = 1;
|
||||
}
|
||||
|
||||
@ -1110,7 +1185,7 @@ ksh_dup2(int ofd, int nfd, bool errok)
|
||||
errorf("too many files open in shell");
|
||||
|
||||
#ifdef __ultrix
|
||||
/* XXX imake style */
|
||||
/*XXX imake style */
|
||||
if (rv >= 0)
|
||||
fcntl(nfd, F_SETFD, 0);
|
||||
#endif
|
||||
@ -1119,8 +1194,8 @@ ksh_dup2(int ofd, int nfd, bool errok)
|
||||
}
|
||||
|
||||
/*
|
||||
* move fd from user space (0<=fd<10) to shell space (fd>=10),
|
||||
* set close-on-exec flag.
|
||||
* Move fd from user space (0 <= fd < 10) to shell space (fd >= 10),
|
||||
* set close-on-exec flag. See FDBASE in sh.h, maybe 24 not 10 here.
|
||||
*/
|
||||
short
|
||||
savefd(int fd)
|
||||
@ -1141,10 +1216,12 @@ restfd(int fd, int ofd)
|
||||
{
|
||||
if (fd == 2)
|
||||
shf_flush(&shf_iob[fd]);
|
||||
if (ofd < 0) /* original fd closed */
|
||||
if (ofd < 0)
|
||||
/* original fd closed */
|
||||
close(fd);
|
||||
else if (fd != ofd) {
|
||||
ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */
|
||||
/*XXX: what to do if this dup fails? */
|
||||
ksh_dup2(ofd, fd, true);
|
||||
close(ofd);
|
||||
}
|
||||
}
|
||||
@ -1366,11 +1443,14 @@ texpand(struct table *tp, size_t nsize)
|
||||
for (i = 0; i < nsize; i++)
|
||||
ntblp[i] = NULL;
|
||||
tp->size = nsize;
|
||||
tp->nfree = (nsize * 4) / 5; /* table can get 80% full */
|
||||
/* table can get 80% full */
|
||||
tp->nfree = (nsize * 4) / 5;
|
||||
tp->tbls = ntblp;
|
||||
if (otblp == NULL)
|
||||
return;
|
||||
nsize--; /* from here on nsize := mask */
|
||||
|
||||
/* from here on nsize := mask */
|
||||
nsize--;
|
||||
for (i = 0; i < osize; i++)
|
||||
if ((tblp = otblp[i]) != NULL) {
|
||||
if ((tblp->flag & DEFINED)) {
|
||||
|
Reference in New Issue
Block a user