From bdc3069bfd11885ea426ff8f6cc267baa3c76dd3 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 12 Sep 2021 05:16:51 +0200 Subject: [PATCH] Fix 'ps' output for hashbangless scripts on Linux/macOS When invoking a script without an interpreter (#!hashbang) path, ksh forks, but there is no exec syscall in the child. The existing command line is overwritten in fixargs() with the name of the new script and associated arguments. In the generic/fallback version of fixargs() which is used on Linux and macOS, if the new command line is longer than the existing one, it is truncated. This works well when calling a script with a shorter name. However, it generates a misleading name in the common scenario where a script is invoked from an interactive shell, which typically has a short command line. For instance, if "/tmp/script" is invoked, "ksh" gets replaced with "/tm" in "ps" output. A solution is found in the fact that, on these systems, the environment is stored immediately after the command line arguments. This space can be made available for use by a longer command line by moving the environment strings out of the way. src/cmd/ksh93/sh/main.c: fixargs(): - Refactor BSD setproctitle(3) version to be more self-contained. - In the generic (Linux/macOS) version, on init (i.e. mode==0), if the command line is smaller than 128 bytes and the environment strings have not yet been moved (i.e. if they still immediately follow the command line arguments in memory), then strdup the environment strings, pointing the *environment[] members to the new strings and adding the length of the strings to the maximum command line buffer size. Reported-by: @gkamat Resolves: https://github.com/ksh93/ksh/pull/300 --- NEWS | 5 +++ src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh/main.c | 78 +++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/NEWS b/NEWS index cd493ddf3..a1ffbb7b5 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2021-09-12: + +- When invoking a script without an interpreter/hashbang path on Linux and + macOS, ksh can now update 'ps' output to show longer command lines. + 2021-08-13: - An issue was fixed that could cause old-style `backtick` command diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index c6a458881..cad1e5840 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -21,7 +21,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2021-08-13" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2021-09-12" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c index c23b7fdbe..dfa5fc257 100644 --- a/src/cmd/ksh93/sh/main.c +++ b/src/cmd/ksh93/sh/main.c @@ -56,6 +56,7 @@ static void exfile(Shell_t*, Sfio_t*,int); static void chkmail(Shell_t *shp, char*); #if !defined(_NEXT_SOURCE) && !defined(__sun) static void fixargs(char**,int); +# undef fixargs_disabled #else # define fixargs(a,b) # define fixargs_disabled 1 @@ -715,12 +716,13 @@ static void chkmail(Shell_t *shp, char *files) */ static void fixargs(char **argv, int mode) { -#if EXECARGS +# if EXECARGS + if(mode==0) + return; *execargs=(char *)argv; -#else - register char *cp; +# elif PSTAT + char *cp; int offset=0,size; -# ifdef PSTAT static int command_len; char *buff; union pstun un; @@ -735,21 +737,6 @@ static void fixargs(char **argv, int mode) } stakseek(command_len+2); buff = stakseek(0); -# elif _lib_setproctitle -# define command_len 255 - char buff[command_len + 1]; - if(mode==0) - return; -# else - static int command_len; - static char *buff; - if(mode==0) - { - buff = argv[0]; - command_len = environ[0] - buff - 1; - return; - } -# endif /* PSTAT */ if(command_len==0) return; while((cp = *argv++) && offset < command_len) @@ -762,12 +749,59 @@ static void fixargs(char **argv, int mode) } offset--; memset(&buff[offset], 0, command_len - offset + 1); -# ifdef PSTAT un.pst_command = stakptr(0); pstat(PSTAT_SETCMD,un,0,0,0); # elif _lib_setproctitle +# define CMDMAXLEN 255 + char *cp; + int offset=0,size; + char buff[CMDMAXLEN + 1]; + if(mode==0) + return; + while((cp = *argv++) && offset < CMDMAXLEN) + { + if(offset + (size=strlen(cp)) >= CMDMAXLEN) + size = CMDMAXLEN - offset; + memcpy(buff+offset,cp,size); + offset += size; + buff[offset++] = ' '; + } + buff[--offset] = '\0'; setproctitle("%s",buff); -# endif /* PSTAT */ -#endif /* EXECARGS */ +# undef CMDMAXLEN +# else + /* Generic version, works on at least Linux and macOS */ + char *cp; + int offset=0,size; + static int buffsize; + static char *buff; + if(mode==0) + { + int i; + buff = argv[0]; + for(i=0; argv[i]; i++) + buffsize += strlen(argv[i]) + 1; + if(buffsize < 128 && buff + buffsize == *environ) + { + /* Move the environment to make space for a larger command line buffer */ + for(i=0; environ[i]; i++) + { + buffsize += strlen(environ[i]) + 1;; + environ[i] = sh_strdup(environ[i]); + } + } + return; + } + while((cp = *argv++) && offset < buffsize) + { + if(offset + (size=strlen(cp)) >= buffsize) + size = buffsize - offset; + memcpy(buff+offset,cp,size); + offset += size; + buff[offset++] = ' '; + } + offset--; + memset(&buff[offset], 0, buffsize - offset + 1); +# endif } #endif /* !fixargs_disabled */