• implement KSHEGID, KSHGID, KSHUID variables by suggestion of Richard K.

(KSHEUID aka USER_ID already exists)
• simplify, speed up LCG and $RANDOM handling again
This commit is contained in:
tg 2011-01-21 21:04:48 +00:00
parent 1d6e0470e0
commit cc31d86e3b
6 changed files with 284 additions and 270 deletions

103
jobs.c
View File

@ -1,7 +1,7 @@
/* $OpenBSD: jobs.c,v 1.38 2009/12/12 04:28:44 deraadt Exp $ */ /* $OpenBSD: jobs.c,v 1.38 2009/12/12 04:28:44 deraadt Exp $ */
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
* Thorsten Glaser <tg@mirbsd.org> * Thorsten Glaser <tg@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.72 2010/08/28 20:22:19 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.73 2011/01/21 21:04:44 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
#define mksh_killpg killpg #define mksh_killpg killpg
@ -342,11 +342,9 @@ exchild(struct op *t, int flags,
int rv = 0, forksleep; int rv = 0, forksleep;
sigset_t omask; sigset_t omask;
struct {
Proc *p; Proc *p;
Job *j; Job *j;
pid_t cldpid; pid_t cldpid;
} pi;
if (flags & XEXEC) if (flags & XEXEC)
/* /*
@ -358,11 +356,11 @@ exchild(struct op *t, int flags,
/* no SIGCHLDs while messing with job and process lists */ /* no SIGCHLDs while messing with job and process lists */
sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
pi.p = new_proc(); p = new_proc();
pi.p->next = NULL; p->next = NULL;
pi.p->state = PRUNNING; p->state = PRUNNING;
pi.p->status = 0; p->status = 0;
pi.p->pid = 0; p->pid = 0;
/* link process into jobs list */ /* link process into jobs list */
if (flags & XPIPEI) { if (flags & XPIPEI) {
@ -371,78 +369,76 @@ exchild(struct op *t, int flags,
internal_errorf("%s %d", internal_errorf("%s %d",
"exchild: XPIPEI and no last_job - pid", "exchild: XPIPEI and no last_job - pid",
(int)procpid); (int)procpid);
pi.j = last_job; j = last_job;
if (last_proc) if (last_proc)
last_proc->next = pi.p; last_proc->next = p;
last_proc = pi.p; last_proc = p;
} else { } else {
pi.j = new_job(); /* fills in pi.j->job */ /* fills in j->job */
j = new_job();
/* /*
* we don't consider XXCOMs foreground since they don't get * we don't consider XXCOMs foreground since they don't get
* tty process group and we don't save or restore tty modes. * tty process group and we don't save or restore tty modes.
*/ */
pi.j->flags = (flags & XXCOM) ? JF_XXCOM : j->flags = (flags & XXCOM) ? JF_XXCOM :
((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE)); ((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE));
timerclear(&pi.j->usrtime); timerclear(&j->usrtime);
timerclear(&pi.j->systime); timerclear(&j->systime);
pi.j->state = PRUNNING; j->state = PRUNNING;
pi.j->pgrp = 0; j->pgrp = 0;
pi.j->ppid = procpid; j->ppid = procpid;
pi.j->age = ++njobs; j->age = ++njobs;
pi.j->proc_list = pi.p; j->proc_list = p;
pi.j->coproc_id = 0; j->coproc_id = 0;
last_job = pi.j; last_job = j;
last_proc = pi.p; last_proc = p;
put_job(pi.j, PJ_PAST_STOPPED); put_job(j, PJ_PAST_STOPPED);
} }
snptreef(pi.p->command, sizeof(pi.p->command), "%T", t); snptreef(p->command, sizeof(p->command), "%T", t);
/* create child process */ /* create child process */
forksleep = 1; forksleep = 1;
while ((pi.cldpid = fork()) < 0 && errno == EAGAIN && forksleep < 32) { while ((cldpid = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
if (intrsig) /* allow user to ^C out... */ if (intrsig) /* allow user to ^C out... */
break; break;
sleep(forksleep); sleep(forksleep);
forksleep <<= 1; forksleep <<= 1;
} }
if (pi.cldpid < 0) { /* ensure $RANDOM changes between parent and child */
kill_job(pi.j, SIGKILL); rndset((long)cldpid);
remove_job(pi.j, "fork failed"); /* fork failed? */
if (cldpid < 0) {
kill_job(j, SIGKILL);
remove_job(j, "fork failed");
sigprocmask(SIG_SETMASK, &omask, NULL); sigprocmask(SIG_SETMASK, &omask, NULL);
errorf("can't fork - try again"); errorf("can't fork - try again");
} }
pi.p->pid = pi.cldpid ? pi.cldpid : (procpid = getpid()); p->pid = cldpid ? cldpid : (procpid = getpid());
/*
* ensure next child gets a (slightly) different $RANDOM sequence
* from its parent process and other child processes
*/
change_random(&pi, sizeof(pi));
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED
/* job control set up */ /* job control set up */
if (Flag(FMONITOR) && !(flags&XXCOM)) { if (Flag(FMONITOR) && !(flags&XXCOM)) {
int dotty = 0; int dotty = 0;
if (pi.j->pgrp == 0) { /* First process */ if (j->pgrp == 0) { /* First process */
pi.j->pgrp = pi.p->pid; j->pgrp = p->pid;
dotty = 1; dotty = 1;
} }
/* set pgrp in both parent and child to deal with race /* set pgrp in both parent and child to deal with race
* condition * condition
*/ */
setpgid(pi.p->pid, pi.j->pgrp); setpgid(p->pid, j->pgrp);
if (ttypgrp_ok && dotty && !(flags & XBGND)) if (ttypgrp_ok && dotty && !(flags & XBGND))
tcsetpgrp(tty_fd, pi.j->pgrp); tcsetpgrp(tty_fd, j->pgrp);
} }
#endif #endif
/* used to close pipe input fd */ /* used to close pipe input fd */
if (close_fd >= 0 && (((flags & XPCLOSE) && pi.cldpid) || if (close_fd >= 0 && (((flags & XPCLOSE) && cldpid) ||
((flags & XCCLOSE) && !pi.cldpid))) ((flags & XCCLOSE) && !cldpid)))
close(close_fd); close(close_fd);
if (!pi.cldpid) { if (!cldpid) {
/* child */ /* child */
/* Do this before restoring signal */ /* Do this before restoring signal */
@ -480,7 +476,7 @@ exchild(struct op *t, int flags,
close(forksleep); close(forksleep);
} }
} }
remove_job(pi.j, "child"); /* in case of $(jobs) command */ remove_job(j, "child"); /* in case of $(jobs) command */
nzombie = 0; nzombie = 0;
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED
ttypgrp_ok = false; ttypgrp_ok = false;
@ -505,27 +501,26 @@ exchild(struct op *t, int flags,
/* shell (parent) stuff */ /* shell (parent) stuff */
if (!(flags & XPIPEO)) { /* last process in a job */ if (!(flags & XPIPEO)) { /* last process in a job */
j_startjob(pi.j); j_startjob(j);
if (flags & XCOPROC) { if (flags & XCOPROC) {
pi.j->coproc_id = coproc.id; j->coproc_id = coproc.id;
/* n jobs using co-process output */ /* n jobs using co-process output */
coproc.njobs++; coproc.njobs++;
/* j using co-process input */ /* j using co-process input */
coproc.job = (void *)pi.j; coproc.job = (void *)j;
} }
if (flags & XBGND) { if (flags & XBGND) {
j_set_async(pi.j); j_set_async(j);
if (Flag(FTALKING)) { if (Flag(FTALKING)) {
shf_fprintf(shl_out, "[%d]", pi.j->job); shf_fprintf(shl_out, "[%d]", j->job);
for (pi.p = pi.j->proc_list; pi.p; for (p = j->proc_list; p; p = p->next)
pi.p = pi.p->next)
shf_fprintf(shl_out, " %d", shf_fprintf(shl_out, " %d",
(int)pi.p->pid); (int)p->pid);
shf_putchar('\n', shl_out); shf_putchar('\n', shl_out);
shf_flush(shl_out); shf_flush(shl_out);
} }
} else } else
rv = j_waitj(pi.j, JW_NONE, "jw:last proc"); rv = j_waitj(j, JW_NONE, "jw:last proc");
} }
sigprocmask(SIG_SETMASK, &omask, NULL); sigprocmask(SIG_SETMASK, &omask, NULL);

172
main.c
View File

@ -4,7 +4,7 @@
/* $OpenBSD: table.c,v 1.13 2009/01/17 22:06:44 millert Exp $ */ /* $OpenBSD: table.c,v 1.13 2009/01/17 22:06:44 millert Exp $ */
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
* Thorsten Glaser <tg@mirbsd.org> * Thorsten Glaser <tg@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -33,15 +33,10 @@
#include <locale.h> #include <locale.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.173 2010/11/01 17:29:04 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/main.c,v 1.174 2011/01/21 21:04:44 tg Exp $");
extern char **environ; extern char **environ;
#if !HAVE_SETRESUGID
extern uid_t kshuid;
extern gid_t kshgid, kshegid;
#endif
#ifndef MKSHRC_PATH #ifndef MKSHRC_PATH
#define MKSHRC_PATH "~/.mkshrc" #define MKSHRC_PATH "~/.mkshrc"
#endif #endif
@ -50,10 +45,10 @@ extern gid_t kshgid, kshegid;
#define MKSH_DEFAULT_TMPDIR "/tmp" #define MKSH_DEFAULT_TMPDIR "/tmp"
#endif #endif
void chvt_reinit(void);
static void reclaim(void); static void reclaim(void);
static void remove_temps(struct temp *); static void remove_temps(struct temp *);
void chvt_reinit(void); static mksh_uari_t rndsetup(void);
Source *mksh_init(int, const char *[]);
#ifdef SIGWINCH #ifdef SIGWINCH
static void x_sigwinch(int); static void x_sigwinch(int);
#endif #endif
@ -66,8 +61,9 @@ static const char initsubs[] =
static const char *initcoms[] = { static const char *initcoms[] = {
T_typeset, "-r", initvsn, NULL, T_typeset, "-r", initvsn, NULL,
T_typeset, "-x", "HOME", "PATH", "RANDOM", "SHELL", NULL, T_typeset, "-x", "HOME", "PATH", "RANDOM", "SHELL", NULL,
T_typeset, "-i10", "COLUMNS", "LINES", "OPTIND", "PGRP", "PPID", T_typeset, "-i10", "COLUMNS", "KSHEGID", "KSHGID", "KSHUID", "LINES",
"RANDOM", "SECONDS", "TMOUT", "USER_ID", NULL, "OPTIND", "PGRP", "PPID", "RANDOM", "SECONDS", "TMOUT", "USER_ID",
NULL,
T_alias, T_alias,
"integer=typeset -i", "integer=typeset -i",
T_local_typeset, T_local_typeset,
@ -97,7 +93,41 @@ static const char *initcoms[] = {
static int initio_done; static int initio_done;
struct env *e = &kshstate_v.env_; /* top-level parsing and execution environment */
static struct env env;
struct env *e = &env;
static mksh_uari_t
rndsetup(void)
{
register uint32_t h;
struct {
ALLOC_ITEM __alloc_i;
void *dataptr, *stkptr, *mallocptr;
sigjmp_buf jbuf;
struct timeval tv;
struct timezone tz;
} *bufptr;
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 */
oaat1_init_impl(h);
/* variation through pid, ppid, and the works */
oaat1_addmem_impl(h, &rndsetupstate, sizeof(rndsetupstate));
/* some variation, some possibly entropy, depending on OE */
oaat1_addmem_impl(h, bufptr, sizeof(*bufptr));
oaat1_fini_impl(h);
afree(cp, APERM);
return ((mksh_uari_t)h);
}
void void
chvt_reinit(void) chvt_reinit(void)
@ -108,8 +138,8 @@ chvt_reinit(void)
kshppid = getppid(); kshppid = getppid();
} }
Source * int
mksh_init(int argc, const char *argv[]) main(int argc, const char *argv[])
{ {
int argi, i; int argi, i;
Source *s; Source *s;
@ -140,16 +170,17 @@ mksh_init(int argc, const char *argv[])
ainit(&aperm); /* initialise permanent Area */ ainit(&aperm); /* initialise permanent Area */
/* set up base environment */ /* set up base environment */
kshstate_v.env_.type = E_NONE; env.type = E_NONE;
ainit(&kshstate_v.env_.area); ainit(&env.area);
newblock(); /* set up global l->vars and l->funs */ /* set up global l->vars and l->funs */
newblock();
/* Do this first so output routines (eg, errorf, shellf) can work */ /* Do this first so output routines (eg, errorf, shellf) can work */
initio(); initio();
argi = parse_args(argv, OF_FIRSTTIME, NULL); argi = parse_args(argv, OF_FIRSTTIME, NULL);
if (argi < 0) if (argi < 0)
return (NULL); return (1);
initvar(); initvar();
@ -197,28 +228,33 @@ mksh_init(int argc, const char *argv[])
def_path = "/bin:/usr/bin:/sbin:/usr/sbin"; def_path = "/bin:/usr/bin:/sbin:/usr/sbin";
#endif #endif
/* Set PATH to def_path (will set the path global variable). /*
* Set PATH to def_path (will set the path global variable).
* (import of environment below will probably change this setting). * (import of environment below will probably change this setting).
*/ */
vp = global("PATH"); vp = global("PATH");
/* setstr can't fail here */ /* setstr can't fail here */
setstr(vp, def_path, KSH_RETURN_ERROR); setstr(vp, def_path, KSH_RETURN_ERROR);
/* Turn on nohup by default for now - will change to off /*
* Turn on nohup by default for now - will change to off
* by default once people are aware of its existence * by default once people are aware of its existence
* (AT&T ksh does not have a nohup option - it always sends * (AT&T ksh does not have a nohup option - it always sends
* the hup). * the hup).
*/ */
Flag(FNOHUP) = 1; Flag(FNOHUP) = 1;
/* Turn on brace expansion by default. AT&T kshs that have /*
* Turn on brace expansion by default. AT&T kshs that have
* alternation always have it on. * alternation always have it on.
*/ */
Flag(FBRACEEXPAND) = 1; Flag(FBRACEEXPAND) = 1;
/* Set edit mode to emacs by default, may be overridden /*
* Set edit mode to emacs by default, may be overridden
* by the environment or the user. Also, we want tab completion * by the environment or the user. Also, we want tab completion
* on in vi by default. */ * on in vi by default.
*/
change_flag(FEMACS, OF_SPECIAL, 1); change_flag(FEMACS, OF_SPECIAL, 1);
#if !MKSH_S_NOVI #if !MKSH_S_NOVI
Flag(FVITABCOMPLETE) = 1; Flag(FVITABCOMPLETE) = 1;
@ -266,7 +302,8 @@ mksh_init(int argc, const char *argv[])
set_current_wd(pwdx); set_current_wd(pwdx);
if (current_wd[0]) if (current_wd[0])
simplify_path(current_wd); simplify_path(current_wd);
/* Only set pwd if we know where we are or if it had a /*
* Only set pwd if we know where we are or if it had a
* bogus value * bogus value
*/ */
if (current_wd[0] || pwd != null) if (current_wd[0] || pwd != null)
@ -283,6 +320,10 @@ mksh_init(int argc, const char *argv[])
setint(global("LINES"), 0); setint(global("LINES"), 0);
setint(global("OPTIND"), 1); setint(global("OPTIND"), 1);
kshuid = getuid();
kshgid = getgid();
kshegid = getegid();
safe_prompt = ksheuid ? "$ " : "# "; safe_prompt = ksheuid ? "$ " : "# ";
vp = global("PS1"); vp = global("PS1");
/* Set PS1 if unset or we are root and prompt doesn't contain a # */ /* Set PS1 if unset or we are root and prompt doesn't contain a # */
@ -294,18 +335,19 @@ mksh_init(int argc, const char *argv[])
vp->flag |= INT_U; vp->flag |= INT_U;
setint((vp = global("PPID")), (mksh_uari_t)kshppid); setint((vp = global("PPID")), (mksh_uari_t)kshppid);
vp->flag |= INT_U; vp->flag |= INT_U;
setint((vp = global("RANDOM")), (mksh_uari_t)evilhash(kshname));
vp->flag |= INT_U;
setint((vp = global("USER_ID")), (mksh_uari_t)ksheuid); setint((vp = global("USER_ID")), (mksh_uari_t)ksheuid);
vp->flag |= INT_U; vp->flag |= INT_U;
setint((vp = global("KSHUID")), (mksh_uari_t)kshuid);
vp->flag |= INT_U;
setint((vp = global("KSHEGID")), (mksh_uari_t)kshegid);
vp->flag |= INT_U;
setint((vp = global("KSHGID")), (mksh_uari_t)kshgid);
vp->flag |= INT_U;
setint((vp = global("RANDOM")), rndsetup());
vp->flag |= INT_U;
/* Set this before parsing arguments */ /* Set this before parsing arguments */
#if HAVE_SETRESUGID Flag(FPRIVILEGED) = kshuid != ksheuid || kshgid != kshegid;
Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
#else
Flag(FPRIVILEGED) = (kshuid = getuid()) != ksheuid ||
(kshgid = getgid()) != (kshegid = getegid());
#endif
/* this to note if monitor is set on command line (see below) */ /* this to note if monitor is set on command line (see below) */
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED
@ -316,7 +358,7 @@ mksh_init(int argc, const char *argv[])
argi = parse_args(argv, OF_CMDLINE, NULL); argi = parse_args(argv, OF_CMDLINE, NULL);
if (argi < 0) if (argi < 0)
return (NULL); return (1);
/* process this later only, default to off (hysterical raisins) */ /* process this later only, default to off (hysterical raisins) */
utf_flag = UTFMODE; utf_flag = UTFMODE;
@ -422,7 +464,8 @@ mksh_init(int argc, const char *argv[])
errexit = Flag(FERREXIT); errexit = Flag(FERREXIT);
Flag(FERREXIT) = 0; Flag(FERREXIT) = 0;
/* Do this before profile/$ENV so that if it causes problems in them, /*
* Do this before profile/$ENV so that if it causes problems in them,
* user will know why things broke. * user will know why things broke.
*/ */
if (!current_wd[0] && Flag(FTALKING)) if (!current_wd[0] && Flag(FTALKING))
@ -464,23 +507,9 @@ mksh_init(int argc, const char *argv[])
} else } else
Flag(FTRACKALL) = 1; /* set after ENV */ Flag(FTRACKALL) = 1; /* set after ENV */
return (s);
}
int
main(int argc, const char *argv[])
{
Source *s;
kshstate_v.lcg_state_ = 5381;
if ((s = mksh_init(argc, argv))) {
/* put more entropy into the LCG */
change_random(s, sizeof(*s));
/* doesn't return */ /* doesn't return */
shell(s, true); shell(s, true);
} return (0);
return (1);
} }
int int
@ -516,7 +545,8 @@ include(const char *name, int argc, const char **argv, int intr_ok)
case LERROR: case LERROR:
return (exstat & 0xff); /* see below */ return (exstat & 0xff); /* see below */
case LINTR: case LINTR:
/* intr_ok is set if we are including .profile or $ENV. /*
* intr_ok is set if we are including .profile or $ENV.
* If user ^Cs out, we don't want to kill the shell... * If user ^Cs out, we don't want to kill the shell...
*/ */
if (intr_ok && (exstat - 128) != SIGTERM) if (intr_ok && (exstat - 128) != SIGTERM)
@ -587,13 +617,15 @@ shell(Source * volatile s, volatile int toplevel)
if (interactive) { if (interactive) {
if (i == LINTR) if (i == LINTR)
shellf("\n"); shellf("\n");
/* Reset any eof that was read as part of a /*
* Reset any eof that was read as part of a
* multiline command. * multiline command.
*/ */
if (Flag(FIGNOREEOF) && s->type == SEOF && if (Flag(FIGNOREEOF) && s->type == SEOF &&
wastty) wastty)
s->type = SSTDIN; s->type = SSTDIN;
/* Used by exit command to get back to /*
* Used by exit command to get back to
* top level shell. Kind of strange since * top level shell. Kind of strange since
* interactive is set if we are reading from * interactive is set if we are reading from
* a tty, but to have stopped jobs, one only * a tty, but to have stopped jobs, one only
@ -642,7 +674,8 @@ shell(Source * volatile s, volatile int toplevel)
really_exit = 1; really_exit = 1;
s->type = SSTDIN; s->type = SSTDIN;
} else { } else {
/* this for POSIX which says EXIT traps /*
* this for POSIX which says EXIT traps
* shall be taken in the environment * shall be taken in the environment
* immediately after the last command * immediately after the last command
* executed. * executed.
@ -742,7 +775,8 @@ quitenv(struct shf *shf)
if (ep->savefd[2]) /* Clear any write errors */ if (ep->savefd[2]) /* Clear any write errors */
shf_reopen(2, SHF_WR, shl_out); shf_reopen(2, SHF_WR, shl_out);
} }
/* Bottom of the stack. /*
* Bottom of the stack.
* Either main shell is exiting or cleanup_parents_env() was called. * Either main shell is exiting or cleanup_parents_env() was called.
*/ */
if (ep->oenv == NULL) { if (ep->oenv == NULL) {
@ -755,7 +789,8 @@ quitenv(struct shf *shf)
if (ep->flags & EF_FAKE_SIGDIE) { if (ep->flags & EF_FAKE_SIGDIE) {
int sig = exstat - 128; int sig = exstat - 128;
/* ham up our death a bit (AT&T ksh /*
* ham up our death a bit (AT&T ksh
* only seems to do this for SIGTERM) * only seems to do this for SIGTERM)
* Don't do it for SIGQUIT, since we'd * Don't do it for SIGQUIT, since we'd
* dump a core.. * dump a core..
@ -839,7 +874,8 @@ remove_temps(struct temp *tp)
unlink(tp->name); unlink(tp->name);
} }
/* Initialise tty_fd. Used for saving/reseting tty modes upon /*
* Initialise tty_fd. Used for saving/reseting tty modes upon
* foreground job completion and for setting up tty process group. * foreground job completion and for setting up tty process group.
*/ */
void void
@ -937,7 +973,8 @@ warningf(bool fileline, const char *fmt, ...)
shf_flush(shl_out); shf_flush(shl_out);
} }
/* Used by built-in utilities to prefix shell and utility name to message /*
* Used by built-in utilities to prefix shell and utility name to message
* (also unwinds environments for special builtins). * (also unwinds environments for special builtins).
*/ */
void void
@ -958,7 +995,8 @@ bi_errorf(const char *fmt, ...)
shf_putchar('\n', shl_out); shf_putchar('\n', shl_out);
} }
shf_flush(shl_out); shf_flush(shl_out);
/* POSIX special builtins and ksh special builtins cause /*
* POSIX special builtins and ksh special builtins cause
* non-interactive shells to exit. * non-interactive shells to exit.
* XXX odd use of KEEPASN; also may not want LERROR here * XXX odd use of KEEPASN; also may not want LERROR here
*/ */
@ -1133,7 +1171,8 @@ closepipe(int *pv)
close(pv[1]); close(pv[1]);
} }
/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn /*
* 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. * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
*/ */
int int
@ -1156,7 +1195,8 @@ check_fd(const char *name, int mode, const char **emsgp)
return (-1); return (-1);
} }
fl &= O_ACCMODE; fl &= O_ACCMODE;
/* X_OK is a kludge to disable this check for dups (x<&1): /*
* X_OK is a kludge to disable this check for dups (x<&1):
* historical shells never did this check (XXX don't know what * historical shells never did this check (XXX don't know what
* POSIX has to say). * POSIX has to say).
*/ */
@ -1192,7 +1232,8 @@ coproc_read_close(int fd)
} }
} }
/* Called by c_read() and by iosetup() to close the other side of the /*
* Called by c_read() and by iosetup() to close the other side of the
* read pipe, so reads will actually terminate. * read pipe, so reads will actually terminate.
*/ */
void void
@ -1204,7 +1245,8 @@ coproc_readw_close(int fd)
} }
} }
/* Called by c_print when a write to a fd fails with EPIPE and by iosetup /*
* Called by c_print when a write to a fd fails with EPIPE and by iosetup
* when co-process input is dup'd * when co-process input is dup'd
*/ */
void void
@ -1216,7 +1258,8 @@ coproc_write_close(int fd)
} }
} }
/* Called to check for existence of/value of the co-process file descriptor. /*
* 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). * (Used by check_fd() and by c_read/c_print to deal with -p option).
*/ */
int int
@ -1231,7 +1274,8 @@ coproc_getfd(int mode, const char **emsgp)
return (-1); return (-1);
} }
/* called to close file descriptors related to the coprocess (if any) /*
* called to close file descriptors related to the coprocess (if any)
* Should be called with SIGCHLD blocked. * Should be called with SIGCHLD blocked.
*/ */
void void

25
misc.c
View File

@ -29,15 +29,10 @@
#include <grp.h> #include <grp.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.149 2011/01/09 21:57:27 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.150 2011/01/21 21:04:45 tg Exp $");
unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */ unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */
#if !HAVE_SETRESUGID
uid_t kshuid;
gid_t kshgid, kshegid;
#endif
static int do_gmatch(const unsigned char *, const unsigned char *, static int do_gmatch(const unsigned char *, const unsigned char *,
const unsigned char *, const unsigned char *); const unsigned char *, const unsigned char *);
static const unsigned char *cclass(const unsigned char *, int); static const unsigned char *cclass(const unsigned char *, int);
@ -233,9 +228,10 @@ change_flag(enum sh_flag f, int what, unsigned int newval)
Flag(f) = (unsigned char)newval; Flag(f) = (unsigned char)newval;
} else if (f == FPRIVILEGED && oldval && !newval) { } else if (f == FPRIVILEGED && oldval && !newval) {
/* Turning off -p? */ /* Turning off -p? */
#if HAVE_SETRESUGID
gid_t kshegid = getgid();
/*XXX this can probably be optimised */
kshegid = kshgid = getgid();
#if HAVE_SETRESUGID
DO_SETUID(setresgid, (kshegid, kshegid, kshegid)); DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
#if HAVE_SETGROUPS #if HAVE_SETGROUPS
/* setgroups doesn't EAGAIN on Linux */ /* setgroups doesn't EAGAIN on Linux */
@ -246,7 +242,7 @@ change_flag(enum sh_flag f, int what, unsigned int newval)
/* seteuid, setegid, setgid don't EAGAIN on Linux */ /* seteuid, setegid, setgid don't EAGAIN on Linux */
seteuid(ksheuid = kshuid = getuid()); seteuid(ksheuid = kshuid = getuid());
DO_SETUID(setuid, (ksheuid)); DO_SETUID(setuid, (ksheuid));
setegid(kshegid = kshgid = getgid()); setegid(kshegid);
setgid(kshegid); setgid(kshegid);
#endif #endif
} else if ((f == FPOSIX || f == FSH) && newval) { } else if ((f == FPOSIX || f == FSH) && newval) {
@ -1305,9 +1301,6 @@ chvt(const char *fn)
struct stat sb; struct stat sb;
int fd; int fd;
/* for entropy */
kshstate_f.h = evilhash(fn);
if (*fn == '-') { if (*fn == '-') {
memcpy(dv, "-/dev/null", sizeof("-/dev/null")); memcpy(dv, "-/dev/null", sizeof("-/dev/null"));
fn = dv + 1; fn = dv + 1;
@ -1362,6 +1355,14 @@ chvt(const char *fn)
ksh_dup2(fd, 2, false); ksh_dup2(fd, 2, false);
if (fd > 2) if (fd > 2)
close(fd); close(fd);
{
register uint32_t h;
oaat1_init_impl(h);
oaat1_addmem_impl(h, &rndsetupstate, sizeof(rndsetupstate));
oaat1_fini_impl(h);
rndset((long)h);
}
chvt_reinit(); chvt_reinit();
} }
#endif #endif

10
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.244 2011/01/09 21:57:27 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.245 2011/01/21 21:04:45 tg Exp $
.\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $ .\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -72,7 +72,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" use our own definition. And .Dd must come *first*, always.
.\" .\"
.Dd $Mdocdate: January 9 2011 $ .Dd $Mdocdate: January 21 2011 $
.\" .\"
.\" Check which macro package we use .\" Check which macro package we use
.\" .\"
@ -1768,6 +1768,12 @@ above for details.
.Sy Note : .Sy Note :
This parameter is not imported from the environment when the shell is This parameter is not imported from the environment when the shell is
started. started.
.It Ev KSHEGID
The effective group id of the shell.
.It Ev KSHGID
The real group id of the shell.
.It Ev KSHUID
The real user id of the shell.
.It Ev KSH_VERSION .It Ev KSH_VERSION
The name and version of the shell (read-only). The name and version of the shell (read-only).
See also the version commands in See also the version commands in

99
sh.h
View File

@ -154,7 +154,7 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.421 2011/01/09 21:57:29 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.422 2011/01/21 21:04:47 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2011/01/08" #define MKSH_VERSION "R39 2011/01/08"
@ -519,7 +519,7 @@ enum sh_flag {
FNFLAGS /* (place holder: how many flags are there) */ FNFLAGS /* (place holder: how many flags are there) */
}; };
#define Flag(f) (kshstate_v.shell_flags_[(int)(f)]) #define Flag(f) (shell_flags[(int)(f)])
#define UTFMODE Flag(FUNICODE) #define UTFMODE Flag(FUNICODE)
/* /*
@ -569,46 +569,31 @@ extern struct env {
#define LSHELL 8 /* return to interactive shell() */ #define LSHELL 8 /* return to interactive shell() */
#define LAEXPR 9 /* error in arithmetic expression */ #define LAEXPR 9 /* error in arithmetic expression */
/* /* sort of shell global state */
* some kind of global shell state, for change_random() mostly EXTERN pid_t procpid; /* PID of executing process */
*/ EXTERN int exstat; /* exit status */
EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
EXTERN struct mksh_kshstate_v { EXTERN short trap_exstat; /* exit status before running a trap */
/* for change_random */ EXTERN uint8_t trap_nested; /* running nested traps */
struct timeval cr_tv; /* timestamp */ EXTERN uint8_t shell_flags[FNFLAGS];
const void *cr_dp; /* argument address */ EXTERN const char *kshname; /* $0 */
size_t cr_dsz; /* argument length */ EXTERN struct {
uint32_t lcg_state_; /* previous LCG state */ uid_t kshuid_; /* real UID of shell */
/* global state */
pid_t procpid_; /* PID of executing process */
int exstat_; /* exit status */
int subst_exstat_; /* exit status of last $(..)/`..` */
struct env env_; /* top-level parsing & execution env. */
short trap_exstat_; /* exit status before running a trap */
uint8_t trap_nested_; /* running nested traps */
uint8_t shell_flags_[FNFLAGS];
} kshstate_v;
EXTERN struct mksh_kshstate_f {
const char *kshname_; /* $0 */
pid_t kshpid_; /* $$, shell PID */
pid_t kshpgrp_; /* process group of shell */
uid_t ksheuid_; /* effective UID of shell */ uid_t ksheuid_; /* effective UID of shell */
gid_t kshgid_; /* real GID of shell */
gid_t kshegid_; /* effective GID of shell */
pid_t kshpgrp_; /* process group of shell */
pid_t kshppid_; /* PID of parent of shell */ pid_t kshppid_; /* PID of parent of shell */
uint32_t h; /* some kind of hash */ pid_t kshpid_; /* $$, shell PID */
} kshstate_f; } rndsetupstate;
#define kshname kshstate_f.kshname_
#define kshpid kshstate_f.kshpid_
#define procpid kshstate_v.procpid_
#define kshpgrp kshstate_f.kshpgrp_
#define ksheuid kshstate_f.ksheuid_
#define kshppid kshstate_f.kshppid_
#define exstat kshstate_v.exstat_
#define subst_exstat kshstate_v.subst_exstat_
#define trap_exstat kshstate_v.trap_exstat_
#define trap_nested kshstate_v.trap_nested_
/* evil hack: return hash(kshstate_f concat (kshstate_f'.h:=hash(arg))) */ #define kshpid rndsetupstate.kshpid_
uint32_t evilhash(const char *); #define kshpgrp rndsetupstate.kshpgrp_
#define kshuid rndsetupstate.kshuid_
#define ksheuid rndsetupstate.ksheuid_
#define kshgid rndsetupstate.kshgid_
#define kshegid rndsetupstate.kshegid_
#define kshppid rndsetupstate.kshppid_
/* option processing */ /* option processing */
@ -1407,6 +1392,36 @@ EXTERN struct timeval j_usrtime, j_systime;
'+', (unsigned long)(cnst)); \ '+', (unsigned long)(cnst)); \
} while (/* CONSTCOND */ 0) } while (/* CONSTCOND */ 0)
/* Bob Jenkins' one-at-a-time hash, with better start value */
#define oaat1_init_impl(h) do { \
(h) = 0x100; \
} while (/* CONSTCOND */ 0)
#define oaat1_addmem_impl(h, buf, len) do { \
register const uint8_t *oaat1_addmem_p = (const void *)(buf); \
register size_t oaat1_addmem_n = (len); \
\
while (oaat1_addmem_n--) { \
(h) += *oaat1_addmem_p++; \
(h) += (h) << 10; \
(h) ^= (h) >> 6; \
} \
} while (/* CONSTCOND */ 0)
#define oaat1_addstr_impl(h, s) do { \
register const uint8_t *oaat1_addstr_p = (const void *)(s); \
register uint8_t oaat1_addstr_c; \
\
while ((oaat1_addstr_c = *oaat1_addstr_p++)) { \
h += oaat1_addstr_c; \
(h) += (h) << 10; \
(h) ^= (h) >> 6; \
} \
} while (/* CONSTCOND */ 0)
#define oaat1_fini_impl(h) do { \
(h) += (h) << 3; \
(h) ^= (h) >> 11; \
(h) += (h) << 15; \
} while (/* CONSTCOND */ 0)
/* lalloc.c */ /* lalloc.c */
void ainit(Area *); void ainit(Area *);
void afreeall(Area *); void afreeall(Area *);
@ -1614,9 +1629,6 @@ void coproc_write_close(int);
int coproc_getfd(int, const char **); int coproc_getfd(int, const char **);
void coproc_cleanup(int); void coproc_cleanup(int);
struct temp *maketemp(Area *, Temp_type, struct temp **); struct temp *maketemp(Area *, Temp_type, struct temp **);
#define hash(s) oaathash_full((const uint8_t *)(s))
uint32_t oaathash_full(register const uint8_t *);
uint32_t hashmem(const void *, size_t);
void ktinit(struct table *, Area *, size_t); void ktinit(struct table *, Area *, size_t);
struct tbl *ktsearch(struct table *, const char *, uint32_t); struct tbl *ktsearch(struct table *, const char *, uint32_t);
struct tbl *ktenter(struct table *, const char *, uint32_t); struct tbl *ktenter(struct table *, const char *, uint32_t);
@ -1712,11 +1724,12 @@ const char *skip_wdvarname(const char *, int);
int is_wdvarname(const char *, int); int is_wdvarname(const char *, int);
int is_wdvarassign(const char *); int is_wdvarassign(const char *);
char **makenv(void); char **makenv(void);
void change_random(const void *, size_t);
void change_winsz(void); void change_winsz(void);
int array_ref_len(const char *); int array_ref_len(const char *);
char *arrayname(const char *); char *arrayname(const char *);
mksh_uari_t set_array(const char *, bool, const char **); mksh_uari_t set_array(const char *, bool, const char **);
uint32_t hash(const void *);
void rndset(long);
enum Test_op { enum Test_op {
TO_NONOP = 0, /* non-operator */ TO_NONOP = 0, /* non-operator */

135
var.c
View File

@ -1,7 +1,7 @@
/* $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt Exp $ */ /* $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt Exp $ */
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
* Thorsten Glaser <tg@mirbsd.org> * Thorsten Glaser <tg@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -26,7 +26,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.114 2010/09/19 19:21:20 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/var.c,v 1.115 2011/01/21 21:04:48 tg Exp $");
/* /*
* Variables * Variables
@ -39,6 +39,8 @@ __RCSID("$MirOS: src/bin/mksh/var.c,v 1.114 2010/09/19 19:21:20 tg Exp $");
*/ */
static struct tbl vtemp; static struct tbl vtemp;
static struct table specials; static struct table specials;
static uint32_t lcg_state = 5381;
static char *formatstr(struct tbl *, const char *); static char *formatstr(struct tbl *, const char *);
static void exportprep(struct tbl *, const char *); static void exportprep(struct tbl *, const char *);
static int special(const char *); static int special(const char *);
@ -50,9 +52,6 @@ static int getint(struct tbl *, mksh_ari_t *, bool);
static mksh_ari_t intval(struct tbl *); static mksh_ari_t intval(struct tbl *);
static struct tbl *arraysearch(struct tbl *, uint32_t); static struct tbl *arraysearch(struct tbl *, uint32_t);
static const char *array_index_calc(const char *, bool *, uint32_t *); static const char *array_index_calc(const char *, bool *, uint32_t *);
static uint32_t oaathash_update(register uint32_t, register const uint8_t *,
register size_t);
static uint32_t oaathash_finalise(register uint32_t);
uint8_t set_refflag = 0; uint8_t set_refflag = 0;
@ -986,79 +985,6 @@ makenv(void)
return ((char **)XPclose(denv)); return ((char **)XPclose(denv));
} }
/* Bob Jenkins' one-at-a-time hash */
static uint32_t
oaathash_update(register uint32_t h, register const uint8_t *cp,
register size_t n)
{
while (n--) {
h += *cp++;
h += h << 10;
h ^= h >> 6;
}
return (h);
}
static uint32_t
oaathash_finalise(register uint32_t h)
{
h += h << 3;
h ^= h >> 11;
h += h << 15;
return (h);
}
uint32_t
oaathash_full(register const uint8_t *bp)
{
register uint32_t h = 0;
register uint8_t c;
while ((c = *bp++)) {
h += c;
h += h << 10;
h ^= h >> 6;
}
return (oaathash_finalise(h));
}
void
change_random(const void *vp, size_t n)
{
register uint32_t h = 0x100;
#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
uint32_t i;
#endif
kshstate_v.cr_dp = vp;
kshstate_v.cr_dsz = n;
gettimeofday(&kshstate_v.cr_tv, NULL);
h = oaathash_update(oaathash_update(h, (void *)&kshstate_v,
sizeof(kshstate_v)), vp, n);
kshstate_v.lcg_state_ = oaathash_finalise(h);
#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
/*
* either we have very check entropy get and push available,
* with malloc() pulling in this code already anyway, or the
* user requested us to use the old functions
*/
#if defined(arc4random_pushb_fast)
arc4random_pushb_fast(&kshstate_v.lcg_state_,
sizeof(kshstate_v.lcg_state_));
i = arc4random();
#else
i = arc4random_pushb(&kshstate_v.lcg_state_,
sizeof(kshstate_v.lcg_state_));
#endif
h = oaathash_update(h, (void *)&i, sizeof(i));
kshstate_v.lcg_state_ = oaathash_finalise(h);
#endif
}
/* /*
* handle special variables with side effects - PATH, SECONDS. * handle special variables with side effects - PATH, SECONDS.
*/ */
@ -1113,8 +1039,7 @@ getspec(struct tbl *vp)
* this is the same Linear Congruential PRNG as Borland * this is the same Linear Congruential PRNG as Borland
* C/C++ allegedly uses in its built-in rand() function * C/C++ allegedly uses in its built-in rand() function
*/ */
i = ((kshstate_v.lcg_state_ = i = ((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF;
22695477 * kshstate_v.lcg_state_ + 1) >> 16) & 0x7FFF;
break; break;
case V_HISTSIZE: case V_HISTSIZE:
i = histsize; i = histsize;
@ -1181,17 +1106,17 @@ setspec(struct tbl *vp)
stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
strdupx(tmpdir, s, APERM); strdupx(tmpdir, s, APERM);
} }
break; return;
#if HAVE_PERSISTENT_HISTORY #if HAVE_PERSISTENT_HISTORY
case V_HISTFILE: case V_HISTFILE:
sethistfile(str_val(vp)); sethistfile(str_val(vp));
break; return;
#endif #endif
case V_TMOUT: case V_TMOUT:
/* AT&T ksh seems to do this (only listen if integer) */ /* AT&T ksh seems to do this (only listen if integer) */
if (vp->flag & INTEGER) if (vp->flag & INTEGER)
ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
break; return;
/* common sub-cases */ /* common sub-cases */
case V_OPTIND: case V_OPTIND:
@ -1232,7 +1157,7 @@ setspec(struct tbl *vp)
* mksh R39d+ no longer has the traditional repeatability * mksh R39d+ no longer has the traditional repeatability
* of $RANDOM sequences, but always retains state * of $RANDOM sequences, but always retains state
*/ */
change_random(&i, sizeof(i)); rndset((long)i);
break; break;
case V_SECONDS: case V_SECONDS:
{ {
@ -1476,12 +1401,42 @@ change_winsz(void)
} }
uint32_t uint32_t
evilhash(const char *s) hash(const void *s)
{ {
register uint32_t h = 0x100; register uint32_t h;
h = oaathash_update(h, (void *)&kshstate_f, sizeof(kshstate_f)); oaat1_init_impl(h);
kshstate_f.h = oaathash_full((const uint8_t *)s); oaat1_addstr_impl(h, s);
return (oaathash_finalise(oaathash_update(h, oaat1_fini_impl(h);
(void *)&kshstate_f.h, sizeof(kshstate_f.h)))); return (h);
}
void
rndset(long v)
{
register uint32_t h;
oaat1_init_impl(h);
oaat1_addmem_impl(h, &lcg_state, sizeof(lcg_state));
oaat1_addmem_impl(h, &v, sizeof(v));
#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
/*
* either we have very chap entropy get and push available,
* with malloc() pulling in this code already anyway, or the
* user requested us to use the old functions
*/
lcg_state = h;
oaat1_fini_impl(lcg_state);
#if defined(arc4random_pushb_fast)
arc4random_pushb_fast(&lcg_state, sizeof(lcg_state));
lcg_state = arc4random();
#else
lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state));
#endif
oaat1_addmem_impl(h, &lcg_state, sizeof(lcg_state));
#endif
oaat1_fini_impl(h);
lcg_state = h;
} }