--- bin/ksh/.patch 1970-01-01 01:00:00 +0100 +++ bin/ksh/.patch 2025-09-12 11:34:13 +0200 @@ -0,0 +1 @@ +This directory has been patched. --- bin/ksh/edit.h 2014-05-19 17:05:13 +0200 +++ bin/ksh/edit.h 2025-10-01 12:02:48 +0200 @@ -35,7 +35,7 @@ int eof; } X_chars; -EXTERN X_chars edchars; +EXTERN __thread X_chars edchars; /* x_cf_glob() flags */ #define XCF_COMMAND BIT(0) /* Do command completion */ --- bin/ksh/eval.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/eval.c 2025-10-01 12:02:48 +0200 @@ -854,6 +854,7 @@ if (t == NULL) return XBASE; +__DEBUG_SUBST("comsub(enter): xp(0x%x) type(%s) cp(%s)\n", xp, __T_TYPE[t->type], cp) if (t != NULL && t->type == TCOM && /* $(args == NULL && *t->vars == NULL && t->ioact != NULL) { struct ioword *io = *t->ioact; @@ -884,6 +885,7 @@ } xp->u.shf = shf; +__DEBUG_SUBST("comsub(leave): xp(0x%x) type(%s)\n", xp, __T_TYPE[t->type]) return XCOM; } --- bin/ksh/exec.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/exec.c 2025-10-30 07:23:41 +0100 @@ -57,7 +57,9 @@ } */ if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE) +{__DEBUG("execute(exchild)\n") return exchild(t, flags & ~XTIME, xerrok, -1); /* run in sub-process */ +} newenv(E_EXEC); if (trap) @@ -113,6 +115,7 @@ } } +__DEBUG("execute(enter): type(%s) flags(%s) xerrok(%d)\n", __T_TYPE[t->type], __X_FLAGS(flags), *xerrok) switch (t->type) { case TCOM: rv = comexec(t, tp, ap, flags, xerrok); @@ -356,10 +359,11 @@ break; case TEXEC: /* an eval'd TCOM */ +__DEBUG_SUBST("execute(execve): str(%s)\n", t->str) s = t->args[0]; ap = makenv(); restoresigs(); - cleanup_proc_env(); +// cleanup_proc_env(); execve(t->str, t->args, ap); if (errno == ENOEXEC) scriptexec(t, ap); @@ -371,13 +375,18 @@ quitenv(NULL); /* restores IO */ if ((flags&XEXEC)) - unwind(LEXIT); /* exit child */ +{ +__DEBUG_EXIT("execute(exit)\n") +exit(rv); +} + if (rv != 0 && !(flags & XERROK) && (xerrok == NULL || !*xerrok)) { trapsig(SIGERR_); if (Flag(FERREXIT)) unwind(LERROR); } +__DEBUG("execute(leave): type(%s)\n", __T_TYPE[t->type]) return rv; } @@ -399,6 +408,7 @@ int fcflags = FC_BI|FC_FUNC|FC_PATH; int bourne_function_call = 0; +__DEBUG_SUBST("comexec(enter): flags(%s)\n", __X_FLAGS(flags)) /* snag the last argument for $_ XXX not the same as at&t ksh, * which only seems to set $_ after a newline (but not in * functions/dot scripts, but in interactive and script) - @@ -677,10 +687,13 @@ break; } Leave: - if (flags & XEXEC) { + if (rv != 0 && (flags & XEXEC)){ +__DEBUG_EXIT("comexec(exit): rv(%d)\n", rv) exstat = rv; +exit(rv); unwind(LLEAVE); } +__DEBUG_SUBST("comexec(leave): rv(%d)\n", rv) return rv; } @@ -1008,6 +1021,7 @@ { int rv; +__DEBUG_SUBST("call_builtin(%s)\n", *wp) builtin_argv0 = wp[0]; builtin_flag = tp->flag; shf_reopen(1, SHF_WR, shl_stdout); --- bin/ksh/io.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/io.c 2025-10-01 12:02:48 +0200 @@ -93,6 +93,7 @@ va_end(va); shf_putchar('\n', shl_out); shf_flush(shl_out); +abort(); if (jump) unwind(LERROR); } @@ -203,7 +204,7 @@ SHF_UNBUF : 0; } -struct shf shf_iob[3]; +__thread struct shf shf_iob[3]; void initio(void) --- bin/ksh/jobs.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/jobs.c 2025-10-31 06:39:19 +0100 @@ -105,24 +105,24 @@ struct timeval j_systime, j_usrtime; /* user and system time of last j_waitjed job */ -static Job *job_list; /* job list */ -static Job *last_job; -static Job *async_job; -static pid_t async_pid; - -static int nzombie; /* # of zombies owned by this process */ -INT32 njobs; /* # of jobs started */ -static int child_max; /* CHILD_MAX */ +static __thread Job *job_list; /* job list */ +static __thread Job *last_job; +static __thread Job *async_job; +static __thread pid_t async_pid; + +static __thread int nzombie; /* # of zombies owned by this process */ +__thread INT32 njobs; /* # of jobs started */ +static __thread int child_max; /* CHILD_MAX */ /* held_sigchld is set if sigchld occurs before a job is completely started */ -static volatile sig_atomic_t held_sigchld; +static __thread volatile sig_atomic_t held_sigchld; #ifdef JOBS -static struct shf *shl_j; -static int ttypgrp_ok; /* set if can use tty pgrps */ +static __thread struct shf *shl_j; +static __thread int ttypgrp_ok; /* set if can use tty pgrps */ static pid_t restore_ttypgrp = -1; -static pid_t our_pgrp; +static __thread pid_t our_pgrp; static int const tt_sigs[] = { SIGTSTP, SIGTTIN, SIGTTOU }; #endif /* JOBS */ @@ -247,6 +247,7 @@ Job *j; int killed = 0; +__DEBUG_EXIT("j_exit(enter)\n") for (j = job_list; j != (Job *) 0; j = j->next) { if (j->ppid == procpid && (j->state == PSTOPPED || @@ -330,6 +331,7 @@ ttypgrp_ok = 0; break; } +__DEBUG("j_change(): ttypgrp(%d) our_pgrp(%d)\n", ttypgrp, our_pgrp) if (ttypgrp == our_pgrp) break; kill(0, SIGTTIN); @@ -401,8 +403,11 @@ /* Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND * (also done in another execute() below) */ +{__DEBUG("exchild(execute)\n") return execute(t, flags & (XEXEC | XERROK), xerrok); +} +__DEBUG_JOBS("exchild(enter): flags(%s)\n", __X_FLAGS(flags)) /* no SIGCHLD's while messing with job and process lists */ sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); @@ -495,7 +500,6 @@ if (flags & XCOPROC) coproc_cleanup(false); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); - cleanup_parents_env(); #ifdef JOBS /* If FMONITOR or FTALKING is set, these signals are ignored, * if neither FMONITOR nor FTALKING are set, the signals have @@ -522,7 +526,8 @@ } } } - remove_job(j, "child"); /* in case of `jobs` command */ +last_job = (Job *) 0; +async_job = (Job *) 0; nzombie = 0; #ifdef JOBS ttypgrp_ok = 0; @@ -530,7 +535,7 @@ #endif /* JOBS */ Flag(FTALKING) = 0; tty_close(); - cleartraps(); +// cleartraps(); /* segfaults when sending things to bg */ execute(t, (flags & XERROK) | XEXEC, NULL); /* no return */ internal_errorf(0, "exchild: execute() returned"); unwind(LLEAVE); @@ -540,6 +545,7 @@ /* shell (parent) stuff */ /* Ensure next child gets a (slightly) different $RANDOM sequence */ change_random(); +__DEBUG_JOBS("exchild(j_waitj): flags(%s)\n", __X_FLAGS(flags)) if (!(flags & XPIPEO)) { /* last process in a job */ #ifdef JOBS /* YYY: Is this needed? (see also YYY above) @@ -565,6 +571,7 @@ } else rv = j_waitj(j, JW_NONE, "jw:last proc"); } +//else sleep(1); // eval.c:expand() hangs in pipe (switch(XCOM)/read()) sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); @@ -598,6 +605,7 @@ sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); j = last_job; +__DEBUG_JOBS("waitlast(0x%x)\n", j) if (!j || !(j->flags & JF_STARTED)) { if (!j) warningf(true, "waitlast: no last job"); @@ -1027,6 +1035,7 @@ while ((volatile int) j->state == PRUNNING || ((flags & JW_STOPPEDWAIT) && (volatile int) j->state == PSTOPPED)) { +__DEBUG_JOBS("j_waitj(enter): where(%s) flags(%s) state(%s)\n", where, __JW_FLAGS(flags), __STATE[j->state]) sigsuspend(&sm_default); if (fatal_trap) { int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY); @@ -1129,6 +1138,7 @@ (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY))) remove_job(j, where); +__DEBUG_JOBS("j_waitj(leave): where(%s)\n", where) return rv; } @@ -1147,6 +1157,7 @@ int status; struct rusage ru0, ru1; +__DEBUG_JOBS("j_sigchld(enter)\n") /* Don't wait for any processes if a job is partially started. * This is so we don't do away with the process group leader * before all the processes in a pipe line are started (so the @@ -1200,6 +1211,7 @@ check_job(j); /* check to see if entire job is done */ } while (1); +__DEBUG_JOBS("j_sigchld(leave)\n") finished: errno = errno_; @@ -1228,6 +1240,7 @@ jstate = PRUNNING; for (p=j->proc_list; p != (Proc *) 0; p = p->next) { +__DEBUG_JOBS("check_job(0x%x): proc(%d) state(%s)\n", j, p->pid, __STATE[p->state]) if (p->state == PRUNNING) return; /* some processes still running */ if (p->state > jstate) @@ -1510,8 +1523,8 @@ return (Job *) 0; } -static Job *free_jobs; -static Proc *free_procs; +static __thread Job *free_jobs; +static __thread Proc *free_procs; /* allocate a new job and fill in the job number. * @@ -1570,6 +1583,7 @@ Proc *p, *tmp; Job **prev, *curr; +__DEBUG_JOBS("remove_job(0x%x): where(%s)\n", j, where); prev = &job_list; curr = *prev; for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev) --- bin/ksh/ksh.1 2014-05-19 17:05:13 +0200 +++ bin/ksh/ksh.1 2025-10-01 12:02:48 +0200 @@ -5609,7 +5609,7 @@ System Interface (POSIX) \- Part 2: Shell and Utilities .Re .Sh VERSION -This page documents version @(#)PD KSH v5.2.14 99/07/13.2 of the public +This page documents version @(#)PD KSH v5.2.15 20/07/31.1 of the public domain Korn shell. .Sh AUTHORS .An -nosplit --- bin/ksh/main.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/main.c 2025-10-28 12:11:23 +0100 @@ -512,6 +512,7 @@ if (interactive) really_exit = 0; i = sigsetjmp(e->jbuf, 0); +__DEBUG("shell(%s)\n", __L_TYPE[i]) if (i) { switch (i) { case LINTR: /* we get here if SIGINT not caught or ignored */ @@ -608,6 +609,7 @@ void unwind(int i) { +__DEBUG("unwind(enter): type(%s)\n", __L_TYPE[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)) { @@ -622,6 +624,7 @@ i = LLEAVE; } while (1) { +__DEBUG_EXIT("unwind(%s): type(%s)\n", __L_TYPE[i], __E_TYPE[e->type]) switch (e->type) { case E_PARSE: case E_FUNC: @@ -675,6 +678,7 @@ shf_reopen(2, SHF_WR, shl_out); } +__DEBUG_EXIT("quitenv(%s): oenv(0x%x) pid(%d)\n", __E_TYPE[ep->type], ep->oenv, getpid()) /* Bottom of the stack. * Either main shell is exiting or cleanup_parents_env() was called. */ @@ -743,6 +747,7 @@ { struct env *ep; +__DEBUG_JOBS("cleanup_proc_env()\n") for (ep = e; ep; ep = ep->oenv) remove_temps(ep->temps); } --- bin/ksh/path.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/path.c 2025-10-01 12:02:48 +0200 @@ -42,6 +42,7 @@ int plen = 0; char *xp = Xstring(*xsp, xp); +__DEBUG("make_path(%s): file(%s)\n", cwd, file) if (!file) file = null; @@ -182,11 +183,13 @@ len = strlen(p) + 1; - if (len > current_wd_size) - current_wd = aresize(current_wd, current_wd_size = len, APERM); +/* aresize() calling realloc(), destroys parent's path */ +current_wd = alloc(current_wd_size = len, APERM); + memcpy(current_wd, p, len); if (p != path && p != null) afree(p, ATEMP); +__DEBUG("set_current_wd(0x%x): path(%s)\n", current_wd, path) } char * --- bin/ksh/sh.h 2014-05-19 17:05:13 +0200 +++ bin/ksh/sh.h 2025-10-29 07:18:01 +0100 @@ -69,13 +69,13 @@ #define LINE 2048 /* input line size */ #define PATH 1024 /* pathname size (todo: PATH_MAX/pathconf()) */ -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 */ +EXTERN __thread const char *kshname; /* $0 */ +EXTERN __thread pid_t kshpid; /* $$, shell pid */ +EXTERN __thread pid_t procpid; /* pid of executing process */ +EXTERN __thread uid_t ksheuid; /* effective uid of shell */ +EXTERN __thread int exstat; /* exit status */ +EXTERN __thread int subst_exstat; /* exit status of last $(..)/`..` */ +EXTERN __thread const char *safe_prompt; /* safe prompt if PS1 substitution fails */ EXTERN char username[]; /* username for \u prompt expansion */ /* @@ -85,7 +85,7 @@ struct link *freelist; /* free list */ } Area; -EXTERN Area aperm; /* permanent object space */ +EXTERN __thread Area aperm; /* permanent object space */ #define APERM &aperm #define ATEMP &e->area @@ -102,7 +102,7 @@ /* * parsing & execution environment */ -EXTERN struct env { +EXTERN __thread struct env { short type; /* environment type - see below */ short flags; /* EF_* */ Area area; /* temporary allocation area */ @@ -215,7 +215,7 @@ #define Flag(f) (shell_flags[(int) (f)]) -EXTERN char shell_flags [FNFLAGS]; +EXTERN __thread char shell_flags [FNFLAGS]; EXTERN char null [] I__(""); /* null value for variable */ EXTERN char space [] I__(" "); @@ -242,7 +242,7 @@ #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; +EXTERN __thread int shl_stdout_ok; /* * trap handlers @@ -283,11 +283,11 @@ #define SIGEXIT_ 0 /* for trap EXIT */ #define SIGERR_ NSIG /* for trap ERR */ -EXTERN volatile sig_atomic_t trap; /* traps pending? */ -EXTERN volatile sig_atomic_t intrsig; /* pending trap interrupts command */ -EXTERN volatile sig_atomic_t fatal_trap;/* received a fatal signal */ +EXTERN __thread volatile sig_atomic_t trap; /* traps pending? */ +EXTERN __thread volatile sig_atomic_t intrsig; /* pending trap interrupts command */ +EXTERN __thread volatile sig_atomic_t fatal_trap;/* received a fatal signal */ extern volatile sig_atomic_t got_sigwinch; -extern Trap sigtraps[NSIG+1]; +extern __thread Trap sigtraps[NSIG+1]; /* * TMOUT support @@ -298,11 +298,11 @@ TMOUT_READING, /* waiting for input */ TMOUT_LEAVING /* have timed out */ }; -EXTERN unsigned int ksh_tmout; +EXTERN __thread unsigned int ksh_tmout; EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING); /* For "You have stopped jobs" message */ -EXTERN int really_exit; +EXTERN __thread int really_exit; /* * fast character classes @@ -348,8 +348,8 @@ 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 */ +EXTERN __thread Getopt builtin_opt; /* for shell builtin commands */ +EXTERN __thread Getopt user_opt; /* parsing state for getopts builtin command */ /* This for co-processes */ @@ -362,20 +362,20 @@ int njobs; /* number of live jobs using output pipe */ void *job; /* 0 or job of co-process using input pipe */ }; -EXTERN struct coproc coproc; +EXTERN __thread struct coproc coproc; /* Used in jobs.c and by coprocess stuff in exec.c */ -EXTERN sigset_t sm_default, sm_sigchld; +EXTERN __thread sigset_t sm_default, sm_sigchld; extern const 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.) */ +EXTERN __thread char *builtin_argv0; +EXTERN __thread 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; +EXTERN __thread char *current_wd; +EXTERN __thread int current_wd_size; #ifdef EDIT /* Minimum required space to work with on a line - if the prompt leaves less @@ -411,6 +411,7 @@ #include "expand.h" #include "lex.h" #include "proto.h" +#include "debug.h" /* be sure not to interfere with anyone else's idea about EXTERN */ #ifdef EXTERN_DEFINED --- bin/ksh/shf.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/shf.c 2025-10-01 12:02:48 +0200 @@ -214,6 +214,7 @@ { int ret = 0; +__DEBUG_JOBS("shf_close(0x%x)\n", shf) if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) --- bin/ksh/shf.h 2014-05-19 17:05:13 +0200 +++ bin/ksh/shf.h 2025-10-01 12:02:48 +0200 @@ -57,7 +57,7 @@ Area *areap; /* area shf/buf were allocated in */ }; -extern struct shf shf_iob[]; +extern __thread struct shf shf_iob[]; struct shf *shf_open(const char *, int, int, int); struct shf *shf_fdopen(int, int, struct shf *); --- bin/ksh/syn.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/syn.c 2025-10-01 12:02:48 +0200 @@ -40,12 +40,12 @@ int); static void dbtestp_error(Test_env *, int, const char *); -static struct op *outtree; /* yyparse output */ +static __thread struct op *outtree; /* yyparse output */ -static struct nesting_state nesting; /* \n changed to ; */ +static __thread struct nesting_state nesting; /* \n changed to ; */ -static int reject; /* token(cf) gets symbol again */ -static int symbol; /* yylex value */ +static __thread int reject; /* token(cf) gets symbol again */ +static __thread int symbol; /* yylex value */ #define REJECT (reject = 1) #define ACCEPT (reject = 0) --- bin/ksh/trap.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/trap.c 2025-10-30 16:04:34 +0100 @@ -6,7 +6,7 @@ #include "sh.h" -Trap sigtraps[NSIG + 1]; +__thread Trap sigtraps[NSIG + 1]; static struct sigaction Sigact_ign, Sigact_trap; @@ -45,6 +45,7 @@ setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG); setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG); setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG); +__DEBUG_TRAPS("inittraps: trapsig(0x%x)\n", trapsig) } static void alarm_catcher(int sig); @@ -115,6 +116,7 @@ Trap *p = &sigtraps[i]; int errno_ = errno; +__DEBUG_TRAPS("trapsig(%s) flags(%s)\n", p->name, __TF_FLAGS(p->flags)) trap = p->set = 1; if (p->flags & TF_DFL_INTR) intrsig = 1; @@ -122,6 +124,8 @@ fatal_trap = 1; intrsig = 1; } +__DEBUG_TRAPS("trapsig(%s): cursig(0x%x) shtrap(0x%x) trap(%s) set(%d) intrsig(%d)\n", + p->name, p->cursig, p->shtrap, p->trap, p->set, intrsig) if (p->shtrap) (*p->shtrap)(i); errno = errno_; @@ -133,8 +137,10 @@ void intrcheck(void) { - if (intrsig) + if (intrsig){ +__DEBUG_TRAPS("intrcheck()\n") runtraps(TF_DFL_INTR|TF_FATAL); + } } /* called after EINTR to check if a signal with normally causes process @@ -181,6 +187,7 @@ int i; Trap *p; +__DEBUG_TRAPS("runtraps(0x%x) intrsig(%d)\n", flag, intrsig) if (ksh_tmout_state == TMOUT_LEAVING) { ksh_tmout_state = TMOUT_EXECUTING; warningf(false, "timed out waiting for input"); @@ -210,6 +217,8 @@ int oexstat; int old_changed = 0; +__DEBUG_TRAPS("runtrap(%s): cursig(0x%x) shtrap(0x%x) trap(%s) set(%d) flags(%s)\n", + p->name, p->cursig, p->shtrap, p->trap, p->set, __TF_FLAGS(p->flags)) p->set = 0; if (trapstr == (char *) 0) { /* SIG_DFL */ if (p->flags & TF_FATAL) { @@ -390,6 +399,8 @@ sigaction(p->signal, &sigact, (struct sigaction *) 0); } +__DEBUG_TRAPS("setsig(%s): cursig(0x%x) shtrap(0x%x) trap(%s) set(%d) flags(%s)\n", + p->name, p->cursig, p->shtrap, p->trap, p->set, __TF_FLAGS(p->flags)) return 1; } --- bin/ksh/tty.h 2014-05-19 17:05:13 +0200 +++ bin/ksh/tty.h 2025-10-01 12:02:48 +0200 @@ -22,7 +22,7 @@ #include -EXTERN int tty_fd I__(-1); /* dup'd tty file descriptor */ +EXTERN __thread int tty_fd I__(-1); /* dup'd tty file descriptor */ EXTERN int tty_devtty; /* true if tty_fd is from /dev/tty */ EXTERN struct termios tty_state; /* saved tty state */ --- bin/ksh/version.c 2014-05-19 17:05:13 +0200 +++ bin/ksh/version.c 2025-10-01 12:02:48 +0200 @@ -7,4 +7,4 @@ #include "sh.h" const char ksh_version [] = - "@(#)PD KSH v5.2.14 99/07/13.2"; + "@(#)PD KSH v5.2.15 20/07/31.1";