1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 11:42:21 +00:00
Commit graph

983 commits

Author SHA1 Message Date
Johnothan King
cd562b16e2 Port more shell lint improvements from illumos and ksh93v- (#374)
This commit adds onto <https://github.com/ksh93/ksh/pull/353> by porting
over two additional improvements to the shell linter:

1) The changes in the aforementioned pull request were merged into
   illumos-gate with an additional change.[*] The illumos revision of
   the patch improved the warning for (( $foo = $? )) to specify '$foo'
   causes the warning.[**] Example:
      $ ksh -n -c '(( $? != $bar ))'
      ksh: warning: line 1: in '(( $? != $bar ))', using '$' as in '$bar' is slower and can introduce rounding errors
   While I was porting the illumos patch I did notice one problem. The
   string it uses from paramsub() skips over the initial '{' in
   '${var}', resulting in the warning printing '$var}' instead:
      $ ksh -n -c '(( ${.sh.pid} != $$ ))'
      ...  in '(( ${.sh.pid} != $$ ))', using '$' as in '$.sh.pid}' is slower  ...
   This was fixed by including the missing '{' in the string returned by
   paramsub for ${var} variables.

2) In ksh93v-, parsing x=$((expr)) with the shell linter will cause ksh
   to warn the user x=$((expr)) is slower than ((x=expr)). This
   improvement has been backported with a modified warning:
      # Result from this commit
      $ ksh -n -c 'x=$((1 + 2))'
      ksh: warning: line 1: x=$((1 + 2)) is slower than ((x=1 + 2))
      # Result from ksh93v-
      $ ksh93v -n -c 'x=$((1 + 2))'
      ksh93v: warning: line 1: ((x=1 + 2)) is more efficient than x=$((1 + 2))
   Minor note: the ksh93v- patch had an invalid use of memcmp; this
   version of the patch uses strncmp instead.

References:
be548e87bc
https://code.illumos.org/c/illumos-gate/+/1834/comment/65722363_22fdf8e7/
2021-12-13 01:49:37 +01:00
Ryan Schmidt
66a50ece82 Include <unistd.h> in "fd is * arg to poll" tests (#376)
The "fd is first arg to poll()" and "fd is second arg to poll()" tests
use write() but don't include the system header in which that function
is declared, leading to "error: implicit declaration of function 'write'
is invalid in C99'" when trying to compile the test. By including the
header, the test can now compile and run as intended.
2021-12-13 01:49:29 +01:00
Ryan Schmidt
b31fe887b8 Include <string.h> in "mmap is worth using" test (#375)
The "mmap is worth using" test uses memcpy but doesn't include the
system header in which that function is declared, leading to
"error: implicitly declaring library function 'memcpy'" when trying
to compile the test. By including the header, the test can now
compile and run as intended.

On macOS, the result is still negative. The test seems to time
using mmap and another method and only picks mmap if it's faster.
Editing the test to print out timing information on a few runs, I
see that mmap is 2–3✕ slower than the other method:

$ for i in $(seq 1 5); do ./mmap_worth_using; done
/* mmtm=11 rdtm=3 */
/* 4*mmtm=44 3*rdtm=9 */
/* 4*mmtm=44 5*rdtm=15 */
/* mmtm=9 rdtm=5 */
/* 4*mmtm=36 3*rdtm=15 */
/* 4*mmtm=36 5*rdtm=25 */
/* mmtm=10 rdtm=4 */
/* 4*mmtm=40 3*rdtm=12 */
/* 4*mmtm=40 5*rdtm=20 */
/* mmtm=12 rdtm=4 */
/* 4*mmtm=48 3*rdtm=12 */
/* 4*mmtm=48 5*rdtm=20 */
/* mmtm=12 rdtm=4 */
/* 4*mmtm=48 3*rdtm=12 */
/* 4*mmtm=48 5*rdtm=20 */
2021-12-13 01:49:24 +01:00
Martijn Dekker
0eb857041d libast: fix memccpy(3) feature test
If you passed CC=/some/compiler, the build broke on macOS because the
cc.darwin compiler wrapper wasn't used. Among other things, this
wrapper adds a -D_lib_memccpy flag, defining _lib_memccpy as 1
during the build. That was used to override a false negative result
of the lib_memccpy feature test. This commit fixes that feature
test instead, so it correctly returns positive on macOS.

Thanks to Ryan Smith (@ryandesign) for the bug report and for the
fix to the lib_memccpy test.

src/lib/libast/features/lib:
- Fix the lib_memccpy feature test. It was checking the result of
  mmap(2) incorrectly, resulting in the test crashing on macOS.
  Failure does not return NULL, it returns MAP_FAILED which is
  usually -1.

src/cmd/INIT/cc.darwin*:
- Removed. Any other flags in these wrappers are either related to
  building dynamic libraries, which is not currently supported, or
  were determined to be unnecessary. See the GitHub issue for
  discussion. This now makes it possible to pass `CC` to use any
  compiler you like on the Mac. Notes:
  - Apple's -D_ast_int8_t=int64_t is a no-op; another AST feature
    test already defines _ast_int8_t a 64-bit integer type, even on
    32-bit systems (on which it is defined as 'long long').
  - The -search_paths_first linker flag is the default since 2010.
    But even on my museum-grade Power Mac G5 with Mac OS X 10.3
    (from 2004), it builds and runs just fine without.
  - DCLK_TCK=100 is a no-op as even that ancient Mac system already
    defines it as 100. Plus, it's not even actually used.
  If a need is found for any of these, please report this in a new
  issue so I can special-case it elsewhere in the code.

Resolves: https://github.com/ksh93/ksh/issues/373
2021-12-12 03:12:15 +01:00
Martijn Dekker
65feb9641a Fix two more PS2/SIGINT crashing bugs (re: 3023d53b)
*** Crash 1: ***

ksh crashed if the PS1 prompt contains one or more command
substitutions and you enter a multi-line command substitution
on the command line, then interrupt while on the PS2 prompt.

    $ ENV=/./dev/null /usr/local/bin/ksh -o emacs
    $ PS1='$(echo foo) $(echo bar) $(echo baz) ! % '
    foo bar baz 16999 % echo $(
    > true		<-- here, press Ctrl+C instead of Return

    Memory fault

The crash occurred due to a corrupted lexer state while trying to
display the PS1 prompt.

Analysis: My fix for the crashing bug with Ctrl+C in commit
3023d53b is incorrect and only worked accidentally. sh_fault() is
not the right place to reset the lexer state because, when we press
Ctrl+C on a PS2 prompt, ksh had been waiting for input to finish
lexing a multi-line command, so sh_lex() and other lexer functions
are on the function call stack and will be returned to.

src/cmd/ksh93/sh/fault.c: sh_fault():
- Remove incorrect SIGINT fix.

src/cmd/ksh93/sh/io.c: io_prompt():
- Reset the lexer state immediately before printing every PS1
  prompt. Even in situations where this is redundant it should be
  perfectly safe, the overhead is negligible, and it resolves this
  crash. It may pre-empt other problems as well.

*** Crash 2: ***

If an INT trap is set, and you start entering a multi-line command
substitution, then press Ctrl+C on the PS2 prompt to trigger the
crash, the lexer state is corrupted because the lexer is invoked to
eval the trap action. A crash then occurs on entering the final ')'
of the command substitution.

    $ trap 'echo TRAPPED' INT
    $ echo $(
    > trueTRAPPED	<-- press Ctrl+C to output "TRAPPED"
    > )
    Memory fault

Technically, as SIGINT is trapped, it should not interrupt, so ksh
should execute the trap, then continue with the PS2 prompt to let
the user finish inputting the command. But I have been unsuccessful
in many different attempts to make this work properly. I managed to
get multi-line command substitutions to lex correctly by saving and
restoring the lexer state, but command substitutions were still
corrupted at the parser and/or execution level and I have not
managed to trace the cause of that.

My testing showed that all other shells interrupt the PS2 prompt
and return to PS1 when the user presses Ctrl+C, even if SIGINT is
trapped. I think that is a reasonable alternative, and it is
something I managed to make work.

src/cmd/ksh93/sh/fault.c: sh_chktrap():
- Immediately after invoking sh_trap() to run a trap action, check
  if we're in a PS2 prompt (sh.nextprompt == 2). If so, assume the
  lexer state is now overwritten. Closing the fcin stream with
  fcclose() seems to reliably force the lexer to stop doing
  anything else. Then we can just reset the prompt to PS1 and
  invoke sh_exit() to start new command line, which will now reset
  the lexer state as per above.
2021-12-11 04:29:53 +01:00
Martijn Dekker
0180a65bbf emacs.c: fix compiler warning (re: aa304888) 2021-12-11 04:29:12 +01:00
Martijn Dekker
feedc05037 Reset lexer state on syntax error and on SIGINT (Ctrl+C)
ksh crashed if you pressed Ctrl+C or Ctrl+D on a PS2 prompt while
you haven't finished entering a $(command substitution). It
corrupts subsequent command substitutions. Sometimes the situation
recovers, sometimes the shell crashes.

Simple crash reproducer:

  $ PS1="\$(echo foo) \$(echo bar) \$(echo baz) > "
  foo bar baz > echo $(                        <-- now press Ctrl+D
  > ksh: syntax error: `(' unmatched
  Memory fault

The same happens with Ctrl+C, minus the syntax error message.

The problem is that the lexer state becomes inconsistent when the
lexer is interrupted in the middle of reading a command
substitution of the form $( ... ). This is tracked in the
'lexd.dolparen' variable in the lexer state struct.

Resetting that variable is sufficient to fix this issue. However,
in this commit I prefer to just reinitialise the lexer state
completely to pre-empt any other possible issues. Whether there was
a syntax error or the user pressed Ctrl+C, we just interrupted all
lexing and parsing, so the lexer *should* restart from scratch.

src/cmd/ksh93/sh/fault.c: sh_fault():
- If the shell is in an interactive state (e.g. not a subshell) and
  SIGINT was received, reinitialise the lexer state. This fixes the
  crash with Ctrl+C.

src/cmd/ksh93/sh/lex.c: sh_syntax():
- When handling a syntax error, reset the lexer state. This fixes
  the crash with Ctrl+D.

NEWS:
- Also add the forgotten item for the previous fix (re: 2322f939).
2021-12-09 07:35:12 +01:00
Martijn Dekker
350e52877b Revert "[1.0 release prep] Remove tilde expansion discipline"
This reverts c0334e32, thereby restoring 936a1939.

After the fixes in 0a343244 and a2bc49be, the tilde expansion
disciplines work nicely, so they can come back to the 1.0 branch.
2021-12-09 07:31:37 +01:00
Martijn Dekker
a2bc49bed1 Further robustify .get and .set discipline functions (re: 0a343244) (#368)
This should fix various crashes that remain, at least:
* when running a PS2 discipline at parse time
* when pressing Ctrl+C on a PS2 prompt
* when a special builtin within a discipline throws an error within
  a virtual subshell

src/cmd/ksh93/sh/nvdisc.c:
- In both assign() which handles .set disciplines and lookup()
  which handles .get disciplines, to stop errors in discipline
  functions from wreaking havoc:
  - Save, reinitialise and restore the lexer state in case the
    discipline is run at parse time. This happens with PS2; I'm not
    currently aware of other contexts but that doesn't mean there
    aren't any or that there won't be any. Plus, I determined by
    experimenting that doing this here seems to be the only way to
    make it work reliably. Thankfully the overhead is low.
  - Check the topfd redirection state and run sh_iorestore() if
    needed. Without this, if a special builtin with a redirection
    throws an error in a discipline function, its redirection(s)
    remain permanent. For example, 'trap --bad-option 2>/dev/null'
    in a PS2.get() discipline would kill standard error, including
    all your prompts.

src/cmd/ksh93/sh/io.c: io_prompt():
- Before getting the value of the PS2 prompt, save the stack state
  and restore it after. This stops a PS2.get discipline function
  from corrupting a command substitution that the user is typing.
  Doing this in assign()/lookup() is ineffective, so do it here.

Fixes: https://github.com/ksh93/ksh/issues/347
2021-12-09 07:31:30 +01:00
Johnothan King
1f5ad85cd4 Minor improvements to the regression tests (#366)
- tests/basic.sh: Fix a regression test that was failing under dtksh by
  allowing the error message to name ksh 'lt-dtksh'. Additionally, fix
  the test's inaccurate failure message (a version string is not what
  the regression test expects).

- test/builtins.sh: Exclude the expr builtin from the unrecognized
  options test because it's incompatible. Additionally, put the
  unrecognized options test inside of a function to ensure that it works
  with the future local builtin (https://github.com/ksh93/ksh/issues/123).

- tests/io.sh: The long seek test may fail to seek past the 2 GiB
  boundary on 32-bit systems, so only allow it to run on 64-bit.
  References:
  3222ac2b59/f/ksh-1.0.0-beta.1-regre-tests.patch
  a5c692e1bd

- tests/substring.sh: Add a regression test for the ${.sh.match}
  crashing bug fixed in commit 1bf1d2f8.
2021-12-09 06:43:39 +01:00
Martijn Dekker
caae7dd7c9 ksh93/Mamfile: add missing header dependencies
src/cmd/ksh93/sh/Mamfile:
- For edit/edit.c, add include/shlex.h (re: f99ce517).
- For sh/shcomp.c, add include/{path,terminal}.h (re: 141fa68e).

Thanks to @JohnoKing for flagging these up.
2021-12-09 06:43:30 +01:00
Martijn Dekker
aa3048880b cleanup: get rid of KSHELL and _BLD_shell preprocessor macros
Once upon a time it might have been possible to build certain parts
of ksh, such as the emacs and vi editors and possibly even the
name/value library (nval(3)) as independent libraries. But given
the depressing amount of bit rot in the code that we inherited, I
am certain that disabling either of these macros had been resulting
in a broken build for many years before AT&T abandoned this code
base. These are certainly not going to be useful now.

Meanwhile the KSHELL macro got in the way of me today, because the
Mamfile did not define it for all the .c files, but some headers
declared some functionality conditionally upon that macro. So
including <io.h> in, e.g., nvdisc.c did not declare the same
functions as including that header in files with KSHELL defined.
This inconsistency is now gone as well, for various files.

I'm currently working on making it possible once again to build
libshell as a dynamic library; that should be good enough. And that
never involved disabling either of these macros.
2021-12-09 06:43:22 +01:00
Johnothan King
2b8eaa6609 Fix handling of files without newlines in the head and tail builtins (#365)
The head and tail builtins don't correctly handle files that lack
newlines[*]:
    $ print -n foo > /tmp/bar
    $ /opt/ast/bin/head -1 /tmp/bar  # No output
    $ print -n 'foo\nbar' > /tmp/bar
    $ /opt/ast/bin/tail -1 /tmp/bar
    foo
    bar$
This commit backports the required changes from ksh93v- to handle files
without a newline in the head and tail builtins. (Also note that the
required fix to sfmove was already backported in commit 1bd06207.)

src/lib/libcmd/{head,tail}.c:
- Backport the relevant ksh93v- code for handling files
  without newlines.

src/cmd/ksh93/tests/builtins.sh:
- Add a few regression tests for using 'head -1' and 'tail -1' on a file
  missing and ending newline.

[*]: https://www.illumos.org/issues/4149
2021-12-09 06:43:10 +01:00
Johnothan King
beccb93fd4 Fix various compiler warnings and minor issues (#362)
List of changes:
- Fixed some -Wuninitialized warnings and removed some unused variables.

- Removed the unused extern for B_login (re: d8eba9d1).

- The libcmd builtins and the vmalloc memfatal function now handle
  memory errors with 'ERROR_SYSTEM|ERROR_PANIC' for consistency with how
  ksh itself handles out of memory errors.

- Added usage of UNREACHABLE() where it was missing from error handling.

- Extend many variables from short to int to prevent overflows (most
  variables involve file descriptors).

- Backported a ksh2020 patch to fix unused value Coverity issues
  (https://github.com/att/ast/pull/740).

- Note in src/cmd/ksh93/README that ksh compiles with Cygwin on
  Windows 10 and Windows 11, albeit with many test failures.

- Add comments to detail some sections of code. Extensive list of
  commits related to this change:
  ca2443b5, 7e7f1372, 2db9953a, 7003aba4, 6f50ff64, b1a41311,
  222515bf, a0dcdeea, 0aa9e03f, 61437b27, 352e68da, 88e8fa67,
  bc8b36fa, 6e515f1d, 017d088c, 035a4cb3, 588a1ff7, 6d63b57d,
  a2f13c19, 794d1c86, ab98ec65, 1026006d

- Removed a lot of dead ifdef code.

- edit/emacs.c: Hide an assignment to avoid a -Wunused warning. (See
  also https://github.com/att/ast/pull/753, which removed the assignment
  because ksh2020 removed the !SHOPT_MULTIBYTE code.)

- sh/nvdisc.c: The sh_newof macro cannot return a null pointer because
  it will instead cause the shell to exit if memory cannot be allocated.
  That makes the if statement here a no-op, so remove it.

- sh/xec.c: Fixed one unused variable warning in sh_funscope().

- sh/xec.c: Remove a fallthrough comment added in commit ed478ab7
  because the TFORK code doesn't fall through (GCC also produces no
  -Wimplicit-fallthrough warning here).

- data/builtins.c: The cd and pwd man pages state that these builtins
  default to -P if PATH_RESOLVE is 'physical', which isn't accurate:
     $ /opt/ast/bin/getconf PATH_RESOLVE
     physical
     $ mkdir /tmp/dir; ln -s /tmp/dir /tmp/sym
     $ cd /tmp/sym
     $ pwd
     /tmp/sym
     $ cd -P /tmp/sym
     $ pwd
     /tmp/dir
  The behavior described by these man pages isn't specified in the ksh
  man page or by POSIX, so to avoid changing these builtin's behavior
  the inaccurate PATH_RESOLVE information has been removed.

- Mamfiles: Preserve multi-line errors by quoting the $x variable.
  This fix was backported from 93v-.
  (See also <https://github.com/lkujaw/ast/commit/a7e9cc82>.)

- sh/subshell.c: Remove set but not used sp->errcontext variable.
2021-12-09 06:42:59 +01:00
Martijn Dekker
b3050769ea Fix 'return' emitting signals; allow arbitrary return values
When a global EXIT trap is set, and a ksh-style function exits with
a status > 256 that could have been the result of a signal, then
the shell incorrectly issues that signal to itself. Depending on
the signal, this causes ksh to terminate itself ungracefully:

    $ cat /tmp/exit267
    trap 'echo OK' EXIT  # This trap triggers the crash
    function foo { return 267; }
    foo
    $ bash /tmp/exit267
    OK
    $ ksh-3aee10d7 /tmp/exit267
    OK
    $ ksh /tmp/exit267
    Memory fault(coredump)

On most systems, status 267 corresponds to SIGSEGV. The reported
memory fault is not real; it results from ksh incorrectly killing
itself with that signal.

The problem is caused by two factors:

1. As of 93u+ 2012-08-01, ksh explicitly allows 'return' to use an
   exit status corresponding to a signal (from 257 to end of signal
   range). The rest of the integer range is trunctated to 8 bits.
   This is contrary to both 'man ksh' and 'return --man' which both
   say it's always truncated to 8 bits. Plus, combined with point 2
   below, this new behaviour is nonsensical, as 'return' has no
   business actually generating signals. However, a couple of
   regression tests now depend on this, as may some scripts.

2. When a ksh-style function does not handle a signal, the signal
   is passed down to the parent environment and ksh does this by
   reissuing the signal to its own process after leaving the
   function scope. However, it does this by checking the exit
   status, which is very bad practice as there is no guarantee
   that an exit status corresponding to a signal was in fact
   produced by a signal, particularly after they changed the
   behaviour of 'return' per 1 above.

This commit fixes both issues. It also takes a proper decision on
allowable 'return' exit status arguments. Since 93u+ was released
nearly a decade ago and some scripts may now rely on being able to
pass certain exit statuses out of the 8-bit range, we should not
disallow this now. But neither should we be half-hearted in
allowing only some arbitrary selection of 9-bit statuses; 'return'
values categorically should have nothing to do with signals, so
this is no basis for limiting them. We're now allowing the full
unsigned integer range, which is usually 32 bits. This is like zsh,
and may create some interesting possibilities for scripts.
Just don't forget that $? will still lose all but its 8 least
significant bits when leaving the current (sub)shell environment.

src/cmd/ksh93/sh/xec.c: sh_funscope():
- Fix passing down unhandled signals from interrupted ksh functions
  (jumpval==SH_JMPFUN) to the parent environment. Do not pay any
  attention to the exit status. Instead, use sh.lastsig (a.k.a.
  shp->lastsig). It is set by sh_fault() in fault.c for just this
  purpose and contains the last signal handled for the current
  command. It is reset in sh_exec() before running any new command.
  So if it contains a signal, that is the one that interrupted the
  ksh function, so it's the correct one to pass down. (Further
  evidence: sh_subshell() was already using this in the same way.)

src/cmd/ksh93/bltins/cflow.c: b_return():
- Allow any signed int return value when invoked as and behaving
  like 'return'.
- Add warning if a passed value is out of int range. Set the exit
  status to 128 in that case; int overflow is undefined behaviour
  in C and we want consistent behaviour across platforms. It should
  be safe enough to check if the long and int values are equal.
- Refactor for clarity.

src/cmd/ksh93/sh/subshell.c: sh_subshell():
- If a function returns with a status out of the 8 bit range in a
  virtual subshell, this status could be passed down to the parent
  shell in full. However, if the subshell forks, then the kernel
  will enforce an 8-bit exit status. That is inconsistent. Scripts
  should not be able to tell the difference between forked and
  non-forked subshells, so artificially enforce that limit here.

Other changed files:
- Documentation updates and copy-edits.
- Update an AT&T functions.sh regress test to allow arbitrary
  integer return values for functions.
- Add regression tests based in part on @JohnoKing's reproducers.
- Rework some vaguely related regression tests to fail gracefully.

Thanks to Johnothan King for the report and the testing.

Fixes: https://github.com/ksh93/ksh/issues/364
2021-12-09 06:41:39 +01:00
Martijn Dekker
7fb814e186 iffe: include OS standards macros in iffe tests by default
In iffe tests, some C functions are found in system libraries, but
then are not declared by the system headers on some systems because
the expected standards macros aren't defined, causing the system
headers to hide the function declarations. This may cause warnings
about invalid implicit function declarations in some tests (which
only show up if you export IFFEFLAGS=-d1), but may also cause false
negative test results. The iffe tests should be given the same
environment that their test results are going to be used in.

libast's first-run and most central feature test, 'standards',
figures out what standards macros need to be used on the current
system to get the system headers to declare the expected
functionality. All code that links to libast depends on the header
generated by this feature test. So iffe should use this result for
the tests as well, as soon as it's available (which is early in
libast's compilation cycle).

Concrete example: on Cygwin, in src/cmd/builtin/features/pty, the
'lib ptsname' test detects ptsname(3) in the system library, but
the output{...}end block that uses the _lib_ptsname feature test
result throws an 'implicit function definition' warning because
Cygwin's stdlib.h does not define this function without the
appropriate standards macros being defined first.

src/cmd/INIT/iffe.sh:
- If ${INSTALLROOT}/src/lib/libast/FEATURE/standards is available,
  incorporate it directly into iffe's own block of compiler
  massaging macros. Do not use #include as the necessary -I flags
  are not added for every test.
- Centrally define the iffe version once, not twice.
- Update and tweak getopts self-documentation (iffe --man).
- While we're here, add macOS/Darwin's DYLD_LIBRARY_PATH to the
  supported dynamic library search variables. On macOS, this is
  normally disabled by System Integrity Protection, plus this
  distribution uses static libraries at build time, so this is for
  completeness' sake and not much else. This was ported from
  @lkujaw's fork: https://github.com/lkujaw/ast/commit/48ff05442994
  (thanks to @JohnoKing for pointing it out).

src/lib/libast/features/standards:
- Add a comment. This is to update the file's timestamp, ensuring
  that everything will be recompiled after this commit.
2021-12-07 05:25:06 +01:00
Martijn Dekker
c842f46bbd tests/leaks.sh: increase tolerances again
Another day, another attempt to quash regress test fails caused by
implausibly small memory "leaks".

Apparently, on later macOS versions, 'ps' got more unreliable, so
increase tolerance from 8 to 12 bytes. Maximum reported leaks.sh
failure was 188 KiB after 16384 iterations (11 bytes/iteration).

And on some Linux versions, /proc sometimes acts weird. The
following is apparently consistent on Arch Linux:
	shcomp-leaks.ksh[177]: memory leak with read -C when using
	<<< (leaked approx 65536 bytes after 4096 iterations)
...which is 16 bytes per iteration, still not large enough to make
a real leak plausible.

Resolves: https://github.com/ksh93/ksh/issues/363
2021-12-06 10:05:36 +01:00
Martijn Dekker
17f13345dc Build & getconf fixes for macOS (and UnixWare)
src/lib/libast/features/standards:
- Add heuristic (u_long availability) for systems that hide rather
  than reveal functionality in the presence of _POSIX_SOURCE, etc.
- Define _DARWIN_C_SOURCE, like _GNU_SOURCE, to enable the full
  range of definitions on macOS systems.
- Due to the above, remove MACH (macOS)-specific hack.
- These changes ported from https://github.com/att/ast/pull/1492 -
  thanks to Lev Kujawski (@lkujaw). His PR indicates that this
  fixes the standards macros on UnixWare, too. Therefore, no longer
  exclude UnixWare from standards macros (re: ff70c27f).

src/lib/libast/comp/conf.sh:
- Promote the 'op' member in Conf_t (struct Conf_s) from short to
  int. This allows some Darwin/macOS values, now exposed, to fit
  that would otherwise be truncated, namely:
  _CS_DARWIN_USER_CACHE_DIR               65538
  _CS_DARWIN_USER_DIR                     65536
  _CS_DARWIN_USER_TEMP_DIR                65537
  Thus, the following AST getconf values are now correct on macOS:
  $ /opt/ast/bin/getconf | grep ^DARWIN
  DARWIN_USER_CACHE_DIR=/var/folders/nx/(REDACTED)/C/
  DARWIN_USER_DIR=/var/folders/nx/(REDACTED)/0/
  DARWIN_USER_TEMP_DIR=/var/folders/nx/(REDACTED)/T/

src/lib/libast/features/tty:
- Include <sys/ioctl.h> if available. This silences a compiler
  warning in src/lib/libast/misc/procopen.c about an invalid
  implicit declaration of ioctl(2).
2021-12-06 10:05:30 +01:00
Martijn Dekker
0d2d6bb47b Documentation tweaks (re: cd8c48cc)
The information about an out of memory error does not apply
to the version of the PR that was eventually committed since
it does not use getcwd() which might cause such an error.
See https://github.com/ksh93/ksh/pull/358#issuecomment-986294934
2021-12-06 06:58:34 +01:00
Johnothan King
cd8c48cc5a Add the '-e' flag to the 'cd' builtin (#358)
This change adds the -e flag to the cd builtin, as specified in
<https://www.austingroupbugs.net/view.php?id=253>. The -e flag is
used to verify if the the current working directory after 'cd -P'
successfully changes the directory, and returns with exit status 1
if the cwd couldn't be determined. Additionally, it causes all
other errors to return with exit status >1 (i.e., status 2 unless
ENOMEM occurs) if -e and -P are both active.

src/cmd/ksh93/bltins/cd_pwd.c:
- Add -e option to the cd builtin command. It verifies $PWD by
  using test_inode() to execute the equivalent of [[ . -ef $PWD ]].
- The check for restricted mode has been moved after optget to
  allow 'cd -eP' to return with exit status 2 when in restricted
  mode. To avoid changing the previous behavior of cd when -e isn't
  passed, extra checks have been added to prevent cd from printing
  usage information in restricted mode.

src/cmd/ksh93/tests/builtins.sh:
- Add regression tests for the exit status when using the cd -P
  flag with and without -e.

src/cmd/ksh93/data/builtins.c,
src/cmd/ksh93/sh.1:
- Document the addition of -e to the cd builtin.
2021-12-06 06:58:11 +01:00
Martijn Dekker
a3f4b5efd1 out of memory checks: add missing sh_getcwd() wrapper (re: 7ad274f8)
getcwd() with 0/NULL arguments also mallocs, so needs a check.
2021-12-05 22:02:41 +01:00
Johnothan King
f6a6d236f1 Port over illumos fixes for conf.sh (#361)
This commit ports over two of Andy Fiddaman's bugfixes to conf.sh
on illumos:

- The compiler isn't passed on to an invocation of iffe. The bugfix is
  from this commit: <https://github.com/citrus-it/ast/commit/63563232>
- The getconf builtin is missing several parameters on illumos.
  Reproducer:
     $ /opt/ast/bin/getconf ADDRESS_WIDTH
     getconf: Invalid argument (ADDRESS_WIDTH)  # Should output '64'
  This bug occurs because conf.sh expects GNU sed and fails to work
  properly with other sed implementations. The bugfix and original bug
  report can be found here:
  https://www.illumos.org/issues/14044
  https://github.com/citrus-it/ast/commit/ba443cfd
2021-12-05 19:57:15 +01:00
Martijn Dekker
6faf43791b Disable vmalloc by default; fix build on Cygwin
Vmalloc is incompatible with Cygwin, but the code to disable it on
Cygwin did not work properly, somehow causing the build to freeze
at a seemingly unrelated point (i.e., when iffe feature tests
attempt to write to sfstdout).

Vmalloc has wasted my time for the last time, so now it's getting
disabled by default even on development builds and you'll have to
pass -D_AST_vmalloc in CCFLAGS to enable it for testing purposes.

This commit has a few other build tweaks as well.

src/lib/libast/features/vmalloc:
- tst map_malloc: Remove no-op #if __CYGWIN__ block which was in
  the #else clause of another #if __CYGWIN__ block.
- Output block ('cat{'):
  - Instead of disabling vmalloc for certain systems, disable it
    unless _AST_vmalloc is defined.
  - To disable it, set _AST_std_malloc as well as _std_malloc, just
    to be sure.

src/lib/libast/vmalloc/malloc.c:
- Remove ineffective Cygwin special-casing.

src/lib/libcmd/vmstate.c:
- This is only useful for vmalloc, so do not pointlessly compile it
  if vmalloc is disabled.

src/lib/libast/man/vmalloc.3:
- Add deprecation notice.

Resolves: https://github.com/ksh93/ksh/issues/360
2021-12-05 19:28:45 +01:00
Martijn Dekker
6e1e9b738b sh.1: correct doc on format used by ${.sh.command} (re: a959a352)
It actually uses the same format as xtrace, which is *not* always
shellquoted and eval-safe.
2021-12-05 19:28:31 +01:00
Johnothan King
0a343244c1 nvdisc.c: Fix crash after an error or signal in discipline function (#356)
This patch fixes the crashes experienced when a discipline function
exited because of a signal or an error from a special builtin. The
crashes were caused by ksh entering an inconsistent state after
performing a longjmp away from the assign() and lookup() functions in
nvdisc.c. Fixing the crash requires entering a new context, then setting
a nonlocal goto with sigsetjmp(3). Any longjmps that happen while
running the discipline function will go back to assign/lookup, allowing
ksh to do a proper cleanup afterwards.

Resolves: https://github.com/ksh93/ksh/issues/346
2021-12-05 19:28:09 +01:00
Martijn Dekker
520f530198 lex.c: add default, though it should never happen (re: b0282f26)
If a bug is ever introduced that causes a [[ ... ]] operator to be
unhandled by the linter, we should at least avoid writing random
memory contents to standard error. In non-release builds, let's
abort() so the problem can be more easily backtraced.
2021-12-05 19:27:38 +01:00
Johnothan King
6904585f49 Port illumos' shell linter improvements (#353)
This commit ports over two improvements to the shell linter from
illumos (original patch written by Andy Fiddaman). Links to the
relevant bug reports and the original patch:
https://www.illumos.org/issues/13601
https://www.illumos.org/issues/13631
c7b656fc71

The first improvement is to the lint warning for arithmetic
operators in [[ ... ]]. The ksh linter now suggests the correct
equivalent operator to use in ((...)). Example:
  $ ksh -nc '[[ 30 -gt 25 ]]'
  # Original warning
  warning: line 1: -gt within [[ ... ]] obsolete, use ((...))
  # New warning
  warning: line 1: [[ ... -gt ... ]] obsolete, use ((... > ...))

The second improvement pertains to variable expansion in arithmetic
expressions. The ksh linter now suggests referencing variable names
directly:
  $ ksh -nc 'integer foo=40; (($foo < 50 ))'
  # Old warning
  warning: line 1: variable expansion makes arithmetic evaluation less efficient
  # New warning
  warning: line 1: in '(($foo < 50))', using '$' is slower and can introduce rounding errors

src/cmd/ksh93/{data/lexstates,sh/lex,sh/parse}.c:
- Port the improved shell lint warnings from illumos to ksh93u+m.
- The original checks for arithmetic operators involved a bunch of
  if statements with inefficient calls to strcmp(3). These were
  replaced with a more efficient switch statement that avoids
  strcmp.
2021-12-05 19:27:16 +01:00
Johnothan King
370440473e Fix KEYBD trap crash when inputting a command substitution (#355)
This change fixes a crash that can occur after setting a KEYBD trap
then inputting a multi-line command substitution. The crash is
similar to issue #347, but it's easier to reproduce since it
doesn't require you to setup a kshrc file. Reproducer for the
crash:

  $ ENV=/./dev/null ksh
  $ trap : KEYBD
  $ : $(
  > true)
  Memory fault(coredump)

The bugfix was backported (with considerable changes) from ksh93v-
2013-10-08. The crash was first reported on the old mailing list:
https://www.mail-archive.com/ast-users@lists.research.att.com/msg00313.html

src/cmd/ksh93/{include/shlex.h,sh/lex.c}:
- To fix this properly, we need sizeof(Lex_t) to work as expected
  in edit.c, but that is thwarted by the _SHLEX_PRIVATE macro in
  lex.c which shlex.h uses to add private structs to the Lex_t type
  in lex.c only. So get rid of that _SHLEX_PRIVATE macro and make
  those members part of the centrally defined struct, renaming them
  to make it clear they're considered private to lex.c.

src/cmd/ksh93/edit/edit.c:
- Now that we can get its size, save and restore the shell lexing
  context when a KEYBD trap is present.

src/cmd/ksh93/tests/pty.sh:
- Add a regression test for the KEYBD trap crash.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
2021-11-30 04:27:31 +01:00
Johnothan King
bfad44e56d Fix memory fault on ARM-based Macs (#354)
Ksh segfaults on M1 Macs, apparently because Apple's compiler
optimizer can't cope with overriding bzero(3) with libast's
implementation (though it's nothing more than "memset(b, 0, n);").

Apple has disabled libast's bzero function since 2018-12-04:
https://opensource.apple.com/source/ksh/ksh-27/patches/src__lib__libast__comp__omitted.c.diff.auto.html

src/lib/libast/comp/omitted.c:
- Only fall back to the libast bzero function if the OS lacks an
  implementation of bzero.
- Remove the bzero undef since this fallback is only reached if the
  OS doesn't have bzero.

NEWS:
- Add compat info for macOS on ARM64. This notes that macOS
  Monterey can now compile and run ksh, although there is one
  regression test failure:
        builtins.sh[345]: printf %H: invalid UTF-8 characters
        (expected %3F%C2%86%3F%3F%3F; got %3F%C2%86%3F%3Fv%3F%3F)

Thanks to @DesantBucie for the report and the testing.

Resolves: https://github.com/ksh93/ksh/issues/329
2021-11-29 20:12:57 +01:00
Johnothan King
a0eeb14787 Stop the time keyword overriding errexit (#351)
This bug was first reported in <https://www.illumos.org/issues/7694>.
The time keyword currently overrides the errexit shell option,
allowing failing scripts to continue after an error:

  $ cat 1.sh
  #!/bin/sh
  time false   # This should cause the script to exit
  echo FAILURE
  true
  $ ksh -o errexit 1.sh

  real    0m0.00s
  user    0m0.00s
  sys     0m0.00s
  FAILURE

src/cmd/ksh93/sh/xec.c:
- When the time keyword runs a command, pass the errexit state flag
  to the sh_exec call. This state flag is required for ksh to exit
  when a command fails while the errexit option is on.

src/cmd/ksh93/tests/basic.sh:
- Add a regression test based on the reproducer.
2021-11-29 20:12:15 +01:00
Martijn Dekker
f508660ddf Revert "Fix defining types conditionally and/or in subshells (re: 8ced1daa)"
This reverts commit 2b9cbbbc8e.

This is not ready for prime time. Crashses when running a $PS2
discipline function. This needs fixing and more testing in
development before making it into the 1.0 branch. In the meantime,
that terrible problem with types is back, sorry about that.
2021-11-29 20:08:53 +01:00
Martijn Dekker
2b9cbbbc8e Fix defining types conditionally and/or in subshells (re: 8ced1daa)
This commit mitigates the effects of the hack explained in the
referenced commit so that dummy built-in command nodes added by the
parser for declaration/assignment purposes do not leak out into the
execution level, except in a relatively harmless corner case.

Something like

	if false; then
		typeset -T Foo_t=(integer -i bar)
	fi

will no longer leave a broken dummy Foo_t declaration command. The
same applies to declaration commands created with enum.

The corner case remaining is:

$ ksh -c 'false && enum E_t=(a b c); E_t -a x=(b b a c)'
ksh: E_t: not found

Since the 'enum' command is not executed, this should have thrown
a syntax error on the 'E_t -a' declaration:
ksh: syntax error at line 1: `(' unexpected

This is because the -c script is parsed entirely before being
executed, so E_t is recognised as a declaration built-in at parse
time. However, the 'not found' error shows that it was successfully
eliminated at execution time, so the inconsistent state will no
longer persist.

This fix now allows another fix to be effective as well: since
built-ins do not know about virtual subshells, fork a virtual
subshell into a real subshell before adding any built-ins.

src/cmd/ksh93/sh/parse.c:

- Add a pair of functions, dcl_hactivate() and dcl_dehacktivate(),
  that (de)activate an internal declaration built-ins tree into
  which check_typedef() can pre-add dummy type declaration command
  nodes. A viewpath from the main built-ins tree to this internal
  tree is added, unifying the two for search purposes and causing
  new nodes to be added to the internal tree. When parsing is done,
  we close that viewpath. This hides those pre-added nodes at
  execution time. Since the parser is sometimes called recursively
  (e.g. for command substitutions), keep track of this and only
  activate and deactivate at the first level.

- We also need to catch errors. This is done by setting libast's
  error_info.exit variable to a dcl_exit() function that tidies up
  and then passes control to the original (usually sh_exit()).

- sh_cmd(): This is the most central function in the parser. You'd
  think it was sh_parse(), but $(modern)-form command substitutions
  use sh_dolparen() instead. Both call sh_cmd(). So let's simply
  add a dcl_hacktivate() call at the beginning and a
  dcl_deactivate() call at the end.

- assign(): This function calls path_search(), which among many
  other things executes an FATH search, which may execute arbitrary
  code at parse time (!!!). So, regardless of recursion level,
  forcibly dehacktivate() to avoid those ugly parser side effects
  returning in that context.

src/cmd/ksh93/bltins/enum.c: b_enum():

- Fork a virtual subshell before adding a built-in.

src/cmd/ksh93/sh/xec.c: sh_exec():

- Fork a virtual subshell when detecting typeset's -T option.

Improves fix to https://github.com/ksh93/ksh/issues/256
2021-11-29 09:02:07 +01:00
Martijn Dekker
43cd8da2fe Fix 'command' prefix in enum type def pre-parsing (re: 1dc18346)
Symptom:

$ ksh -c 'command enum -i P_t=(a b); P_t -A v=([f]=b); typeset -p v'
ksh: syntax error at line 1: `(' unexpected

Expected: no syntax error, and output of 'P_t -A v=([f]=b)'.

src/cmd/ksh93/sh/parse.c: check_typedef():
- For enum, skip over any possible 'command' prefixes before
  pre-parsing options with optget (or, technically, skip anything
  else that might come before 'enum', though I don't think anything
  else is possible).
- The sh_addbuiltin() call at the end to pre-add the builtin
  obtained the node pointer to the built-in and the node flags from
  the parser tree. This did not work if a 'command' prefix was
  present. However, we don't actually need this. For parsing
  purposes, the BLT_DCL flag for a declaration built-in is
  sufficient; this is what gets the parser to accept
  assignment-arguments including parentheses. So just apply that.
  In addition, let's point it to an actual dummy built-in, 'true'
  (SYSTRUE), so that if a user does run something like 'if false;
  then enum Foo_t=(...); fi', the leaked Foo_t dummy at least won't
  do anything (not even crash).
2021-11-28 21:16:19 +01:00
Martijn Dekker
c9ca0ff531 typeset equivalents: use 'typeset' in error messages (re: 1fbbeaa1)
When giving an invalid or incompatible option to a typeset option
equivalent command (former default alias) such as 'compound' or
'integer', the resulting usage messages are incorrect. Example:

$ ksh -c 'compound -T foo=(typeset -a bar[1]=23)'
ksh: compound: -T cannot be used with other options
Usage: compound [-bflmnprstuxACHS] [-a[[type]]] [-i[base]] [-E[n]]
                [-F[n]] [-L[n]] [-M[mapping]] [-R[n]] [-X[n]]
                [-h string] [-T[tname]] [-Z[n]] [name[=value]...]
   Or: compound -f [name...]
   Or: compound -m [name=name...]
   Or: compound -n [name=name...]
   Or: compound -T [tname[=(type definition)]...]
 Help: compound [ --help | --man ] 2>&1

The error message is wrong (there were no other options) and some
of the listed usages are invalid, like 'compound -f'.

Typeset option equivalent commands should just use 'typeset' in all
their error messages to avoid confusion. This is done by setting
error_info.id to the name of the typeset builtin.
2021-11-28 21:16:17 +01:00
Martijn Dekker
7318afc278 jobs.c: refactor SIGHUP handling; document bug fixed (re: 62cf88d0)
There is quite a bit of no-op code in the job_hup() function due
to conditions that always test false. This commit removes that code
and clarifies the rest, making the purpose of this function clear.

job_hup() (before 62cf88d0: job_terminate()) is called via
job_walk() by sh_done() in fault.c to issue SIGHUP, the "hang up"
signal, to every background job's process group when the current
session is ungracefully disconnected. (One way to trigger such a
disconnection is to forcibly terminate a ssh session by typing '~.'
on a new prompt.)

The bug that Solaris patch 260-22964338 fixed is that ksh then
killed all non-disowned jobs' process groups without considering
that ksh still remembers a job even when all its processes are
finished (have the P_DONE flag). In that condition, the process
group ID may well be reused by another process by now, so it is
dangerous to killpg() it; we risk killing unrelated processes!

This is *not* a hypothetical problem; the Solaris patch exists
because this happened to a Solaris customer. However, the bug
exists on all operating systems. It's rarely triggered but serious,
and it's more likely to occur on heavy workloads that re-use
process/group IDs a lot. And it's on every currently released
non-Solaris version of ksh93. Eesh.

src/cmd/ksh93/sh/jobs.c:
src/cmd/ksh93/include/jobs.h:
- Remove job_terminate() which was unused as of 62cf88d0.
  It could have been fixed instead of replaced. Oh well.
- Refactor job_hup():
  - Remove code that will never be executed because, at
    those points, it is known that pw->p_pgrp != 0.
  - Simplify the loop that checks that there is at least
    one non-P_DONE process so it doesn't need a flag.

For documentation purposes, below is a reproducer for the bug
before the Solaris patch. It is rather involved.

1. Compile the C program below (cpid).
2. In one terminal, 'ssh localhost'.
3. Within the ssh session:
   - 'exec -a-ksh /path/to/buggy/ksh' to get a ksh login shell.
   - 'sleep 1 &' and let it finish. Note down the reported PID.
     That is the one we will reuse. Let's say 26650.
4. In another terminal, run: ./cpid 26650 (the PID from the
   previous step). Now wait until it says "PID 26650 is ready"; it
   has now succeeded at re-using that PID, and will just sit there.
   This process will never voluntarily terminate. If we have the
   bug, the termination of this process will be the symptom.
5. In the first terminal, forcibly terminate the ssh session by
   typing, on a new prompt: ~. (tilde, dot). This triggers the
   buggy routine to issue SIGHUP to all of ksh's background jobs.
6. In the second terminal, the bug is reproduced if cpid has been
   terminated, reporting 'waitpid return 26650, status 0x0001', so
   ksh just killed this process that it had nothing to do with.
   (Note that status 0x0001 refers to being killed by signal 1
   which is SIGHUP.)

cpid.c follows (written by George Lijo, tweaked by me):

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <signal.h>
 #include <sys/wait.h>

 int main(int argc, char *argv[])
 {
	pid_t	pid, rpid, opid;
	int	i, status, npid;
	if (argc != 2)
	{
		fprintf(stderr, "Usage: cpid <PID to re-use>\n");
		exit(1);
	}
	rpid = atoi(argv[1]);
	opid = getpid();
	for (;;)
	{
		if ((pid = fork()) == 0)
		{
			setpgrp();
			pause();
			_exit(0);
		}
		if (pid == rpid)
			break;
		kill(pid, SIGKILL);
		waitpid(pid, NULL, 0);
		if (opid < rpid && pid > rpid)
			printf("Cannot create PID %d\n", rpid);
		opid = pid;
	}
	printf("PID %d is ready\n", pid);
	i = waitpid(pid, &status, 0);
	printf("waitpid return %d, status 0x%4.4x\n", i, status);
	return status;
 }
2021-11-25 19:29:17 +01:00
Martijn Dekker
f3433a696a Reset sh.arithrecursion in sh_exit() instead (re: d50d3d7c)
Since the arithmetic recursion level only becomes incorrect when
an error interrupts the arithmetic subsystem, and all such error
messages call sh_exit(), it should be good enough to reset it
there, so we don't need to do that for nearly every sh_exec() run.
2021-11-25 10:26:09 +01:00
Martijn Dekker
27ccdd2517 Fix parentheses in sh_{push,pop}context macros
The lack of parentheses around the shp parameter expansion made
it impossible to pass something like &sh as the first parameter.
2021-11-25 04:11:41 +01:00
Johnothan King
84ded2d0c4 Backport the ksh93v- rm builtin to fix 'rm -d' (#348)
The -d flag implemented in the rm builtin is completely broken. No
matter what you do it refuses to remove directories, even if -r is
also passed. Reproducer:

  $ mkdir /tmp/empty
  $ PATH=/opt/ast/bin rm -d /tmp/empty
  rm: /tmp/empty: directory
  $ PATH=/opt/ast/bin rm -dr /tmp/empty
  rm: /tmp/empty: directory not removed [Is a directory]

Additionally, the description of 'rm -d' in the man page contradicts
how it's specified in <https://www.austingroupbugs.net/view.php?id=802>.

The ksh93v- rm builtin fixed nearly all of these issues, so I've
backported it to 93u+m and applied one additional fix for 'rm -rd'.

src/lib/libcmd/rm.c:
- Backported the fixes from the ksh93v- rm builtin's -d flag when
  used on empty directories.
- Backported the man page update for rm(1) from ksh93v-.
- The ksh93v- rm builtin had one additional bug that caused the -r
  option to fail when combined with -d. This was fixed by
  overriding -d if -r is also passed.

src/cmd/ksh93/tests/builtins.sh:
- Add regression tests for the rm builtin's -d option.
2021-11-25 03:52:05 +01:00
Martijn Dekker
2d65148fad arith.c: scope(): de-obfuscate some code
This function adds the NV_ADD flag to its 'flags' variable for
nv_serach() calls subject to some checks. However, every call that
uses that variable explicitly turns off the NV_ADD bit again.

A search in the ast-open-history repo reveals that this check
briefly made a difference between versions 2010-06-25 and
2010-08-11, but it's been a complete no-op ever since.

src/cmd/ksh93/sh/arith.c: scope():
- Remove no-op code.
- Resolve the constant expressions involving the 'flags' variable,
  get rid of the variable, and just indicate the flag bitmasks
  directly in the nv_search() calls.
- Detangle and split up the excessively long 'if' construct.

No change in behaviour.

Previously noticed by Kurtis Rader for ksh2020:
https://github.com/att/ast/commit/d5ce3b05
2021-11-25 03:25:39 +01:00
Martijn Dekker
214308f81e '.': disable ksh function lookup in POSIX mode
POSIXly, '.' loads only files, not functions.

This only applies to '.', not 'source' (which is not in POSIX).

src/cmd/ksh93/bltins/misc.c: b_source():
- For ksh function lookup, add an additional check that we're not
  in POSIX mode and running the '.' (SYSDOT) builtin.
2021-11-24 09:12:39 +01:00
Martijn Dekker
c0334e32a1 [1.0 release prep] Remove tilde expansion discipline
Defining a .sh.tilde.get or .sh.tilde.set discipline function to
extend tilde expansion works well as long as the discipline
function doesn't get interrupted (e.g. with Crtl+C) or produce an
error message. Either of those will cause the shell to become
unstable and crash.

This feature is now removed from the 1.0 branch as it is not ready
for prime time. It can return to a release branch if/when we manage
to fix it on the master branch.

Related: https://github.com/ksh93/ksh/issues/346
2021-11-24 07:46:58 +01:00
Martijn Dekker
40de1e92b0 [1.0 release prep] Block namespace defs in ksh functions
In 93v-/ksh2020, namespace defs in any function are a syntax error.
This commit blocks namespace defs for ksh functions only, at the
execution level. This follows some of AT&T original intention while
working around some of the known bugs with namespaces.

Related: https://github.com/ksh93/ksh/issues/325
2021-11-24 07:31:22 +01:00
Martijn Dekker
e3d91ffa90 nv_associative(): finally use proper check for enum (re: b98e32fc)
As of the previous commit, I finally know how to properly check for
a variable of a type created by 'enum'. We need to check for both
the NV_UINT16 attribute and the ENUM_disc discipline.

Also:
- regression test tweaks
- add missing tests for previous commit (f600a5ea)
2021-11-24 02:06:08 +01:00
Martijn Dekker
a66cd72f7d arith: implement range checking for enum types
Within arithmetic expressions, enumeration values of variables of a
type created with the 'enum' command translate to index numbers
from 0 to the number of elements minus 1. However, there was no
range checking on this in the arithmetic subsystem, allowing the
assignment of out-of-range values that did not correspond to any
enumeration value.

Variables of an enum type are internally unsigned short integers
(NV_UINT16), like those created with 'integer -su', except with an
additional discipline function (ENUM_disc).

src/cmd/ksh93/bltins/enum.c,
src/cmd/ksh93/include/builtins.h:
- To implement range checking, the arithmetic system needs access
  to the 'nelem' (number of elements) member of 'struct Enum'. This
  is only defined locally in enum.c. We could move that to name.h
  so arith.c can access it, but enum.c has code that supports
  compiling as standalone. So, instead, define a quick extern
  function, b_enum_elem(), that does the necessary type conversion
  and returns a type's number of elements.
- Add --man documentation for the arithmetic subsystem behaviour
  for enum types. Tell the enuminfo() function, which dynamically
  inserts values into the documentation, how to process new \f tags
  'lastv' (the last-defined value) and 'lastn' (the number of the
  last element).

src/cmd/ksh93/sh/arith.c: arith():
- For NV_UINT16 variables with an ENUM_disc discipline, check the
  range using b_enum_elem() and error out if necessary.

Resolves: https://github.com/ksh93/ksh/issues/335
2021-11-23 22:10:40 +01:00
Johnothan King
e26937b36a Add support for 'stty size' to the libcmd 'stty' builtin (#342)
This commit adds support for 'stty size' to the stty builtin, as
defined in <https://austingroupbugs.net/view.php?id=1053>. The size
mode is used to display the terminal's number of rows and columns.
Note that stty isn't included in the default list of builtin
commands; testing this addition requires adding CMDLIST(stty) to
the table of builtins in src/cmd/ksh93/data/builtins.c.

src/lib/libcmd/stty.c:
- Add support for the size mode to the stty builtin. This mode is
  only used to display the terminal's number of rows and columns,
  so error out if any arguments are given that attempt to set the
  terminal size.
2021-11-23 15:38:14 +01:00
Martijn Dekker
10ef74e1a2 shtests: unignore SIGCONT
For some reason, Void Linux (with musl libc) sets SIGCONT to
ignored on the Linux console, causing the 'sleep -s' test in
builtins.sh to fail spuriously as it relies on SIGCONT to work.

src/cmd/ksh93/tests/shtests:
- Reset SIGCONT using the unadvertised 'trap + SIGCONT' feature.

Resolves: https://github.com/ksh93/ksh/issues/301
2021-11-22 16:55:51 +01:00
Martijn Dekker
74730c8ac7 test/[: Improve error status > 1 (re: 7003aba4, cd2cf236, ef1f53b5)
As I got to know the code better, it now seems painfully obvious
that getting test/[ to issue an exit status >= 2 on error only
requires a simple check in sh_exit() in fault.c, which is called
whenever the shell issues an error message.
2021-11-22 15:37:04 +01:00
Martijn Dekker
8ced1daadf Fix enum type definition pre-parsing for shcomp and dot/source
Parser limitations prevent shcomp or source from handling enum
types correctly:

    $ cat /tmp/colors.sh
    enum Color_t=(red green blue orange yellow)
    Color_t -A Colors=([foo]=red)

    $ shcomp /tmp/colors.sh > /dev/null
    /tmp/colors.sh: syntax error at line 2: `(' unexpected
    $ source /tmp/colors.sh
    /bin/ksh: source: syntax error: `(' unexpected

Yet, for types created using 'typeset -T', this works. This is done
via a check_typedef() function that preliminarily adds the special
declaration builtin at parse time, with details to be filled in
later at execution time.

This hack will produce ugly undefined behaviour if the definition
command creating that type built-in is then not actually run at
execution time before the type built-in is accessed.

But the hack is necessary because we're dealing with a fundamental
design flaw in the ksh language. Dynamically addable built-ins that
change the syntactic parsing of the shell language on the fly are
an absurdity that violates the separation between parsing and
execution, which muddies the waters and creates the need for some
kind of ugly hack to keep things like shcomp more or less working.

This commit extends that hack to support enum.

src/cmd/ksh93/sh/parse.c:
- check_typedef():
  - Add 'intypeset' parameter that should be set to 1 for typeset
    and friends, 2 for enum.
  - When processing enum arguments, use AST getopt(3) to skip over
    enum's options to find the name of the type to be defined.
    (getopt failed if we were running a -c script; deal with this
    by zeroing opt_info.index first.)
- item(): Update check_typedef() call, passing lexp->intypeset.
- simple(): Set lexp->intypeset to 2 when processing enum.

The rest of the changes are all to support the above and should be
fairly obvious, except:

src/cmd/ksh93/bltins/enum.c:
- enuminfo(): Return on null pointer, avoiding a crash upon
  executing 'Type_t --man' if Type_t has not been fully defined due
  to the definition being pre-added at parse time but not executed.
  It's all still wrong, but a crash is worse.

Resolves: https://github.com/ksh93/ksh/issues/256
2021-11-21 17:43:55 +01:00
Martijn Dekker
996def3141 builtins.h: rm broken check for removed SYSDECLARE (re: 921bbcae) 2021-11-21 17:43:23 +01:00
Martijn Dekker
893c6a9068 nv_associative(): clarify value indicating enum (re: 6b9703ff) 2021-11-21 17:43:14 +01:00