diff options
author | Roland Mainz <roland.mainz@nrubsig.org> | 2009-10-28 10:36:39 -0700 |
---|---|---|
committer | Roland Mainz <roland.mainz@nrubsig.org> | 2009-10-28 10:36:39 -0700 |
commit | 34f9b3eef6fdadbda0a846aa4d68691ac40eace5 (patch) | |
tree | 0b0fdfb35f8eb9324728de5a99e50e939aca650f /usr/src/lib/libshell/common | |
parent | 14969419acb89bb74e6c95fa472119b710224440 (diff) | |
download | illumos-gate-34f9b3eef6fdadbda0a846aa4d68691ac40eace5.tar.gz |
Portions contributed by Olga Kryzhanovska <olga.kryzhanovska@gmail.com>
PSARC/2009/063 ksh93 update 2
PSARC/2009/248 ksh93 update to 2009-03-10
PSARC/2009/249 more ksh93 command conversions
6888396 libast sources should not include localedef.h
6605478 ksh93 profile shell option does not work
6631006 ksh93 hangs in situations that ksh handles okay
6661487 logname reports nothing after running the script command
6705126 first call to read doesn't honor new setting of HISTFILE
6764665 *libpp* Array overrun in libpp
6765756 *libast* Array overruns in libast
6769332 Recursive function+command substitutions terminate shell after 257 iterations
6777491 *ksh93* lacks arithmetric function iszero()
6778077 *ksh93* does not understand "THAW" as a signal for use with trap
6789247 [ku1] libast/ksh93 1-digit hexfloat base conversion rounds incorrectly
6791838 *ksh93* unset of a variable which is not set should return 0
6793714 RFE: Update /usr/bin/comm to AT&T AST "comm"
6793719 RFE: Update /usr/bin/cut to AT&T AST "cut"
6793721 RFE: Update /usr/bin/paste to AT&T AST "paste"
6793722 RFE: Update /usr/bin/cmp to AT&T AST "cmp"
6793726 RFE: Update /usr/bin/uniq to AT&T AST "uniq"
6793735 RFE: Update /usr/bin/wc to AT&T AST "wc"
6793744 RFE: Add /usr/share/doc/ksh/ for ksh93 documentation
6793747 RFE: Provide "print" builtin as /usr/bin/print for external applications
6793763 RFE: Update /usr/bin/ksh93 to ast-ksh.2009-05-05
6794952 RFE: Enable "globstar" mode in /etc/ksh.kshrc (= interactive ksh93 shells)
6805792 [ku1] Moving local compound var into array does not work
6805794 [ku1] printf returns "invalid character constant" for $ printf "%d\n" "'<euro>"
6805795 [ku1] ksh93 does not differ between -0 and +0
6805797 [ku1]Can't append to nodes of an array of compound vars if addressing them via nameref
6805799 Indexed compound variable arrays do not work...
6805800 [ku1] Declaring associative compound array does not work
6805813 RFE: Update /usr/bin/join to AT&T AST "join".
6805819 RFE: Update /usr/bin/tee to AT&T AST "tee".
6809663 shlint missing ending newline on errors
6811916 ksh93 repeatedly segfaults when "tee" builtin is interrupted via <ctrl-c> in interactive mode
6821113 SUNWosdem package issues
6828644 RFE: Update /usr/bin/logname to AT&T AST "logname".
6828692 RFE: Update /usr/bin/cksum to AT&T AST "cksum".
6834184 ksh93 gets SIGSEGV if HISTFILE is changed in place.
6834207 ksh93 gets SIGSEGV on interactive function definition with HISTSIZE unset
6835835 ksh93 "cat" builtin does not handle "-n" correctly
6841442 Need exception list for OS/Net trees managed via Subversion
6848486 "echo ${test}" with test undefined crashes the shell
6850672 ksh93 (VISUAL=vi) crashes with memory fault while scrolling through history
6855875 typeset -X x ; print $x # does not print sufficient digits to restore value
6857344 /usr/bin/hash core dump with invalid arguments
6866676 Need test suite module to test the kernel support for compiled shell scripts
6881017 Subshell doesn't exit, holds pipe open preventing callers from exiting
6884409 fts functions in libast library can result in segv with deep dir trees (similar to CERT VU#590371)
Diffstat (limited to 'usr/src/lib/libshell/common')
203 files changed, 9900 insertions, 2481 deletions
diff --git a/usr/src/lib/libshell/common/RELEASE b/usr/src/lib/libshell/common/RELEASE index f368dd1531..ad43ff6b45 100644 --- a/usr/src/lib/libshell/common/RELEASE +++ b/usr/src/lib/libshell/common/RELEASE @@ -1,3 +1,248 @@ +09-10-12 --- Release ksh93t+ --- +09-10-12 A bug in which a function loaded in a subshell could leave side + effects in the parent shell has been fixed. +09-10-12 A bug in converting a printf %d operand to a number when the operand + contains multiple subscripts for the same variable has been fixed. +09-10-09 A bug in the handling of the escape character \ in directory prefixes + in command completion has been fixed. +09-10-09 $PATH processing has been changed to delay dir stat() and .paths + lookup until the directory is needed in the path search. +09-09-28 Call the ast setlocale() intercept on unset too. +09-09-24 A bug in which LANG=foo; LC_ALL=foo; unset LC_ALL; did not revert + LC_CTYPE etc. to the LANG value has been fixed. +09-09-17 A bug in which unsetting SVLVL could cause a script invoked by + name without #! to core dump has been fixed. +09-09-16 A bug in which a pipeline in a here-document could hang when the + pipefail option was on has been fixed. +09-09-09 A bug in the processing of line joining in here documents which + occurred when a buffer began with <escape><new-line> has been fixed. +09-09-09 A leading ; with commands in a brace group or parenthesis group + no longer causes an error. It now is used for the "showme" option. +09-09-09 A bug in which a subshell containing a background process could + block until the background process completed has been fixed. +09-09-04 A bug in handing ${var[sub]}, where var is a nameref has been fixed. +09-09-03 A bug which caused an index array to have the wrong number of elements + when it was converted from a compound variable by adding an another + element has been fixed. +09-09-03 Specifying export for a compound variable now generates an error. +09-09-02 $"..." localizations strings are no longer recognized inside `...`. +09-09-01 A bug in the for loop optimizer in the handling of type static + variables has been fixed. +09-09-01 An error message is not displayed when * and @ are used as subscripts. +09-09-01 Several bugs in the processing for types that included an associative + array of another type has been fixed. +09-09-01 A bug in the tracing of [[ a < b ]] and [[ a > b ]] has been fixed. +09-08-26 The .sh.file variable was not being set for a script that was run + by name and didn't start with #! and this has been fixed. +09-08-25 A bug in which a function called to deeply from command substitution + did not display an error message has been fixed. +09-08-24 When processing profiles, ksh93 now violates the POSIX standard and + treats &> as a redirection operator similar to bash. +09-08-23 A bug in the handling of the trap on SIGPIPE that could lead to am + memory fault has been fixed. +09-08-21 A bug in the handling of the comma operator in arithmetic expressions + that could cause a core dump on some systems has been fixed. +09-08-20 A bug in which a compound variable containing an array of a type + that doesn't have any elements now expands correctly. +09-08-19 A bug which disabled function tracing inside a function after + a call to another function has been fixed. +09-08-19 A bug in which initializing a compound variable instance to another + compound variable by name has been fixed. +09-08-18 A bug in which compound variable instances could be lost after + an instance that invoked a type method discipline has been fixed. +09-08-18 A bug in which a discipline function for a type applied to an + array instance when invoked in a function ignored the subscript + has been fixed. +09-08-18 A scoping error with variables in arithmetic expression with + type variables when reference with a name reference has been fixed. +09-08-10 Several memory leaks were fixed primarily related to subshells. +09-08-06 A bug in which setting the trap on CHLD to ignore could cause + a script to hang has been fixed. +09-07-08 A bug in the processing of name reference assignments when it + contained pattern expansions with quoting has been fixed. +09-06-22 The default width for typeset -X has been changed so that there + should be no loss of precision when converting to a string. +09-06-19 A bug in the printing of array elements for binary variables with + printf %B has been fixed. +09-06-19 A bug which caused a core dump with trap DEBUG set with an array + assignment with no elements has been fixed. +09-06-19 A bug with read with typeset -b -Z<num> has been fixed. +09-06-19 Two bugs related to read -b for array variables has been fixed. +09-06-19 A bug with typeset for compound variables containing arrays of + compound variables has been fixed. +09-06-18 A bug in appending a compound variable to a an indexed array of + compound variables has been fixed. +09-06-18 A bug which occurs when appending a compound variable to an indexed + array element has been fixed. +09-06-18 Setting VISUAL to a value other than one ending in vi or emacs will + no longer unset the edit mode. +09-06-17 A bug in typeset -m when moving a local compound variable to a + global compound variable via a name reference has been fixed. +09-06-17 A bug in appending to nodes of an array of compound variables when + addressing them via nameref has been fixed. +09-06-17 A bug in typeset -p var, when var is an array of compound variables + in which the output only contained on array element has been fixed. +09-06-17 The prefix expansion ${!y.@} now works when y is a name + reference to an element of an array. +09-06-16 Traps on signals that are ignored when the shell is invoked + no longer display. Previously they were ignored as required but + would be listed with trap -p. +09-06-12 A bug in vi edit mode in which hitting the up arrow key at the + end of a line longer than 40 characters which caused a core dump + has been fixed. +09-06-11 A bug in which "eval non-builtin &" would create two processes, + one for the & and another for non-builtin has been fixed. +09-06-08 When var is an identifier and is unset, ${var} no longer tries to + run command substitution on the command var. +09-06-08 Process substitution arguments of the form <(command) can now be + used following the < redirection operator to redirect from command. +09-05-13 A bug in which redirections of the form 2>&1 1>&5 inside command + substitution could cause the command substitution to hang has been + fixed. +09-05-12 To conform with POSIX, the -u option only checks for unset variables + and subscript elements rather than checking for all parameters. +09-05-12 A bug which could cause a core dump when a variable whose name + begins with a . was referenced as part of a name reference inside + a function has been fixed. +09-05-01 A bug that caused a core dump when SIGWINCH was received and + both vi and emacs mode were off has been fixed. +09-04-22 Default alias compound='typeset -C' added. +09-04-15 A bug that caused ${...;} to hang for large files has ben fixed. +09-04-08 A change was made in the -n option which printed out an incorrect + warning with <>. +09-04-07 The emacs edit command M-_ and M_. and the vi command _ was fixed + to handle the case there there is no history file. +09-04-05 A bug in handling new-lines with read -n has been fixed. +09-04-05 The ENV variable defaults the the file named by $HOME/.kshrc rather + then to the string $HOME/.kshrc. +09-03-31 A bug in which a nested command substitution with redirections could + leave a file descriptor open has been fixed. +09-03-24 ksh now only uses the value of the _ variable on startup if it can + verify that it was set by the invoking process rather than being + inherited by some other ancestor. +09-03-24 When ksh is invoked without -p and ruid!=euid, and the shell is + compiled without SHOPT_P_UID or ruid<SHOPT_P_UID, the shell now + enables the -p option. The previous version instead set the + euid to the ruid as it does for set +p. +09-03-24 When SHOPT_P_UID is defined at compile time and the shell is started + without -p and ruid!=euid and ruid>=SHOPT_P_UID then euid is set + to ruid. A bug that did the wrong test (ruid<SHOPT_P_UID) was fixed. +09-03-17 The sleep(1) builtin now accept and ISO 8601 PnYnMnDTnHnMnS + duration or date(1) compatible date/time operand. +09-03-10 If a variable that was left or right justified or zero-filled was + changed with a typeset statement that was left or right justified + or zero-filled, then the original justification no longer affects + the result. +09-03-10 A bug in the handling of traps when the last command in a script + is a subshell grouping command has been fixed. +09-03-03 A bug in which an expansion of the form ${!prefix@} could generate + an exception after the return from a function has been fixed. +09-02-02 A bug in restricted mode in which the value of ENV could be + changed from within a function has been fixed. +09-02-02 A bug in which an erroneous message indicating that a process + terminated with a coredump has been fixed. +09-02-02 The exit status when exit was called without an argument from + a signal handler was incorrect and has been fixed. +09-02-02 A bug in which a function autoloaded in a subshell could cause + a core dump when the subshell completed has been fixed. +09-02-02 A bug in which 2>&1 inside a command substitution wasn't working + correctly has been fixed. +09-02-02 A bug in the call stack of arithmetic function with 2 args + returning int has been fixed. +09-01-30 A bug in which 'eval print \$0' inside a function was giving the + wrong value for $0 has been fixed. +09-01-28 A bug in which a command substitution could return an exit status + of 127 when the pipefail option is enabled has been fixed. +09-01-26 ksh93 now generates an error message if you attempt to create + a global name reference to a local variable. +09-01-26 The [[ -v var ]] operator was modified to test for array elements. +09-01-23 The redirection operator <>; was added. It is similar to <> + except that if the command it is applied to succeeds, the file + is truncated to the offset at the command completion. +09-01-23 The default file descriptor for <> was changed to 1. +09-01-20 A bug in which the exit status specified in an exit trap was + not used when a process terminated with a signal has been fixed. +09-01-19 A bug in which a signal whose default action is to terminate + a process could be ignored when the process is running a sub-shell + has been fixed. +09-01-19 A bug in which sending SIGWINCH to a process that reads from a pipe + could cause a memory fault has been fixed. +09-01-16 The -R unary operator was added to [[...]] and test to check whether + a variable is a name reference. +09-01-16 The -v unary operator was added to [[...]] and test to check whether + a variable is set. +09-01-14 The unset built-in was modified to return 0 exit status when + unsetting a variable that was unset to conform with the POSIX + standard. +09-01-14 The unset built-in was modified to continue to unset variables + after encountering a variable that it could not unset to + conform to the POSIX standard. +09-01-14 The parameter expansion ${x+value} no longer expands the value of + the variable x when determining whether x is set or not. +09-01-13 A bug in which background jobs and pipelines that were not waited + for could, in rare instances, cause the shell to go into an infinite + loop or fail has been fixed. +09-01-06 A bug in indexed arrays of compound variables in which referencing + non-existent sub-variable in an arithmetic expression could cause + the sub-variable to be created has been fixed. +09-01-05 A bug in which the \ character did not escape extended regular + expression pattern characters has been fixed. +08-12-24 A bug in which killing the last element of a pipe did not cause + a write to the pipe to generate a SIGPIPE has been fixed. +08-12-19 A bug which could cause command substitution to hang when the + last element of a pipeline in a command substitution was a built-in + and the output was more that PIPE_BUFF. +08-12-18 A bug which occurs when a here documented marker embedded in a + command substitution occurs on a buffer boundary has been fixed. +08-12-17 A bug in the output of typeset -p for variables that had attributes + but did not have a value has been fixed. +08-12-16 A bug in which a name reference to a name reference variable that + references an array element has been fixed. +08-12-16 A bug in which a variable given both the -A and -C attribute along + with an initial assignment didn't work correctly has been fixed. +08-12-10 The [[ -t fd ]] test was fixed to handle fd>9. +08-12-10 A bug where function stack misalignment could cause a bus error + has been fixed. +08-12-09 Command completion was changed to use \ to quote special characters + instead of quoting the argument in single quotes. +08-12-07 A bug in typeset -m which occurred when the target node was an + associative array element has been fixed. +08-12-07 A timing bug on some systems (for example darwin), that could + cause the last process of a pipeline entered interactively to fail + with an "Exec format error" has been fixed. +08-12-04 SHOPT_BGX enables background job extensions. Noted by "J" in + the version string when enabled. (1) JOBMAX=n limits the number + of concurrent & jobs to n; the n+1 & job will block until a + running background job completes. (2) SIGCHLD traps are queued + so that each completing background job gets its own trap; $! is + set to the job pid and $? is set to the job exit status at the + beginning of the trap. (3) sleep -s added to sleep until the time + expires or until a signal is delivered. +08-12-04 The sign of floating point zero is preserved across arithmetic + function calls. +08-12-04 A bug that caused print(1) to produce garbled stdout/stderr + output has been fixed. +08-12-04 A bug in which printf "%d\n" "'<euro>'" did not output the + numerical value of the EURO symbol, 8354, has been fixed. +08-11-24 /dev/fd* and /dev/std* redirections are first attempted with + open() to preserve seek semantics; failing that the corresponding + file descriptors are dup()'d. +08-11-20 A bug which could cause a core dump if a function compiled with + shcomp was found has been fixed. +08-11-20 A bug in which jobs were not cleared from the jobs table for + interactive shells when the pipefail option is on has been fixed. +08-11-11 A bug in which a field that was unset in a type definition and later + set for an instance could appear twice when displaying the variable + has been fixed. +08-11-11 A bug in which running a simple command & inside a function would + not return the correct process id has been fixed. +08=11-10 A bug in which the exit status of a command could be lost if the pid + was that of the most recent command substitution that had completed + has been fixed. +08-11-10 The maximum depth for subshells has been increased from 256 to 65536. +08-11-06 A bug which could cause a core dump when the _ reference variable was + used as an embedded type with a compound assignment has been fixed. + 08-10-31 --- Release ksh93t --- 08-10-31 Variable scoping/initialization bugs that could dump core were fixed. 08-10-24 The lexer now accepts all RE characters for patterns prefixed @@ -6,7 +251,7 @@ 08-10-18 A bug in array scoping that could dump core has been fixed. 08-10-10 read -n and -N fixed to count characters in multibyte locales. 08-10-10 A bug that mishandled _.array[] type references has been fixed. -08-10-09 ${.sh.version} now contains a catenation of the following (after +08-10-09 ${.sh.version} now contains a concatenation of the following (after 'Version') denoting compile time features: A SHOPT_AUDIT B SHOPT_BASH @@ -115,7 +360,7 @@ jobs completed has been fixed. 08-06-23 KSH_VERSION added as a name reference to .sh.version. 08-06-20 type now outputs 'special builtin' for special builtins. -08-06-19 A couple of bugs in multi-dimensional arrays have been fxied. +08-06-19 A couple of bugs in multi-dimensional arrays have been fixed. 08-06-19 A bug in which a syntax error in a dot script could generated a syntax error in the next subsequent command has been fixed. 08-06-17 Reduced the maximum function call depth to 2048 to avoid exceptions @@ -865,7 +1110,7 @@ used inside ${...} has been fixed. 03-07-15 An error in which expanding an indexed array inside a compound variable could cause a core dump has been fixed. -03-07-15 A bug in which under on rare occassions a job completion interrupt +03-07-15 A bug in which on rare occasions a job completion interrupt could cause to core dump has been fixed. 03-06-26 A bug in which process substitution embedded within command substitution would generate a syntax error has been fixed. diff --git a/usr/src/lib/libshell/common/bltins/alarm.c b/usr/src/lib/libshell/common/bltins/alarm.c index ff3369d293..17d8442e01 100644 --- a/usr/src/lib/libshell/common/bltins/alarm.c +++ b/usr/src/lib/libshell/common/bltins/alarm.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/bltins/cd_pwd.c b/usr/src/lib/libshell/common/bltins/cd_pwd.c index ac9d3f426f..58a90a42c4 100644 --- a/usr/src/lib/libshell/common/bltins/cd_pwd.c +++ b/usr/src/lib/libshell/common/bltins/cd_pwd.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -37,7 +37,6 @@ #include "name.h" #include "builtins.h" #include <ls.h> -#include <ctype.h> /* * Invalidate path name bindings to relative paths diff --git a/usr/src/lib/libshell/common/bltins/cflow.c b/usr/src/lib/libshell/common/bltins/cflow.c index 6afe9d584f..cc50817e4c 100644 --- a/usr/src/lib/libshell/common/bltins/cflow.c +++ b/usr/src/lib/libshell/common/bltins/cflow.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -33,7 +33,6 @@ #include "defs.h" #include <ast.h> #include <error.h> -#include <ctype.h> #include "shnodes.h" #include "builtins.h" @@ -65,7 +64,7 @@ done: errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); pp->mode = (**argv=='e'?SH_JMPEXIT:SH_JMPFUN); argv += opt_info.index; - n = (((arg= *argv)?(int)strtol(arg, (char**)0, 10):shp->oldexit)&SH_EXITMASK); + n = (((arg= *argv)?(int)strtol(arg, (char**)0, 10)&SH_EXITMASK:shp->oldexit)); /* return outside of function, dotscript and profile is exit */ if(shp->fn_depth==0 && shp->dot_depth==0 && !sh_isstate(SH_PROFILE)) pp->mode = SH_JMPEXIT; diff --git a/usr/src/lib/libshell/common/bltins/enum.c b/usr/src/lib/libshell/common/bltins/enum.c index c4d8bf03e9..487f9cf1c9 100644 --- a/usr/src/lib/libshell/common/bltins/enum.c +++ b/usr/src/lib/libshell/common/bltins/enum.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/bltins/getopts.c b/usr/src/lib/libshell/common/bltins/getopts.c index be48cc8886..5cb81ae4fe 100644 --- a/usr/src/lib/libshell/common/bltins/getopts.c +++ b/usr/src/lib/libshell/common/bltins/getopts.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/bltins/hist.c b/usr/src/lib/libshell/common/bltins/hist.c index b248515a06..d35aec2070 100644 --- a/usr/src/lib/libshell/common/bltins/hist.c +++ b/usr/src/lib/libshell/common/bltins/hist.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -22,7 +22,6 @@ #include <stak.h> #include <ls.h> #include <error.h> -#include <ctype.h> #include "variables.h" #include "io.h" #include "name.h" diff --git a/usr/src/lib/libshell/common/bltins/misc.c b/usr/src/lib/libshell/common/bltins/misc.c index 22a1410fc3..c66dff20bf 100644 --- a/usr/src/lib/libshell/common/bltins/misc.c +++ b/usr/src/lib/libshell/common/bltins/misc.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -116,7 +116,7 @@ int B_login(int argc,char *argv[],void *extra) register struct argnod *arg=shp->envlist; register Namval_t* np; register char *cp; - if(shp->subshell) + if(shp->subshell && !shp->subshare) sh_subfork(); if(logp && logp->clear) { @@ -572,7 +572,7 @@ int b_universe(int argc, char *argv[],void *extra) case 2: if(!shp->lim.fs3d) goto failed; - if(shp->subshell) + if(shp->subshell && !shp->subshare) sh_subfork(); for(n=0;n<argc;n+=2) { diff --git a/usr/src/lib/libshell/common/bltins/mkservice.c b/usr/src/lib/libshell/common/bltins/mkservice.c index be16f45162..8136b4c296 100644 --- a/usr/src/lib/libshell/common/bltins/mkservice.c +++ b/usr/src/lib/libshell/common/bltins/mkservice.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/bltins/poll_solaris.c b/usr/src/lib/libshell/common/bltins/poll_solaris.c new file mode 100644 index 0000000000..1338b5df34 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/poll_solaris.c @@ -0,0 +1,390 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2009 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Roland Mainz <roland.mainz@nrubsig.org> * +* * +***********************************************************************/ +#pragma prototyped + +#include <shell.h> +#include <stdio.h> +#include <stdbool.h> +#include <option.h> +#include <stk.h> +#include <tm.h> +#include "name.h" +#undef nv_isnull +#ifndef SH_DICT +# define SH_DICT "libshell" +#endif +#include <poll.h> +#ifdef __GNUC__ +#include <alloca.h> +#endif /* __GNUC__ */ + +#define sh_contexttoshb(context) ((Shbltin_t*)(context)) +#define sh_contexttoshell(context) ((context)?(sh_contexttoshb(context)->shp):(NULL)) + +static const char sh_optpoll[] = +"[-?\n@(#)$Id: poll (AT&T Labs Research) 2009-05-14 $\n]" +"[-author?Roland Mainz <roland.mainz@nrubsig.org]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? poll - input/output multiplexing]" +"[+DESCRIPTION?The poll command provides applications with a mechanism " + "for multiplexing input/output over a set of file descriptors. " + "For each member of the array variable \bvar\b, " + "poll examines the given file descriptor in the subscript \b.fd\b " + "for the event(s) specified in the subscript \b.events\b." + "The poll command identifies those file descriptors on which an " + "application can read or write data, or on which certain events have " + "occurred.]" +"[+?The \bvar\b argument specifies the file descriptors to be examined " + "and the events of interest for each file descriptor. " + "It is a array of structured variables with one member for each open " + "file descriptor of interest. The array's members contain the following " + "subscripts:]{" + "[+?\b.fd\b # file descriptor]" + "[+?\b.events\b # requested events]" + "[+?\b.revents\b # returned event]" + "}" +"[+?The \bfd\b variable specifies an open file descriptor and the " + "\bevents\b and \brevents\b members are strings constructed from " + "a concaternation of the following event flags, seperated by '|':]" + "{ " + "[+POLLIN?Data other than high priority data may be " + "read without blocking. For STREAMS, this " + "flag is set in revents even if the message " + "is of zero length.]" + "[+POLLRDNORM?Normal data (priority band equals 0) may be " + "read without blocking. For STREAMS, this " + "flag is set in revents even if the message " + "is of zero length.]" + "[+POLLRDBAND?Data from a non-zero priority band may be " + "read without blocking. For STREAMS, this " + "flag is set in revents even if the message " + "is of zero length.]" + "[+POLLPRI?High priority data may be received without " + "blocking. For STREAMS, this flag is set in " + "revents even if the message is of zero " + "length.]" + "[+POLLOUT?Normal data (priority band equals 0) may be " + "written without blocking.]" + "[+POLLWRNORM?The same as POLLOUT.]" + "[+POLLWRBAND?Priority data (priority band > 0) may be " + "written. This event only examines bands " + "that have been written to at least once.]" + "[+POLLERR?An error has occurred on the device or " + "stream. This flag is only valid in the " + "revents bitmask; it is not used in the " + "events member.]" + "[+POLLHUP?A hangup has occurred on the stream. This " + "event and POLLOUT are mutually exclusive; a " + "stream can never be writable if a hangup has " + "occurred. However, this event and POLLIN, " + ", POLLRDBAND, or POLLPRI are not " + "mutually exclusive. This flag is only valid " + "in the revents bitmask; it is not used in " + "the events member.]" + "[+POLLNVAL?The specified fd value does not belong to an " + "open file. This flag is only valid in the " + "revents member; it is not used in the events " + "member.]" + "}" +"]" + +"[+?If the value fd is less than 0, events is ignored and " + "revents is set to 0 in that entry on return from poll.]" + +"[+?The results of the poll query are stored in the revents " + "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b " + "variable to indicate which of the requested events are true. " + "If none are true, the \brevents\b will be an empty string when " + "the poll command returns. The event flags " + "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b " + "if the conditions they indicate are true; this occurs even " + "though these flags were not present in events.]" + +"[+?If none of the defined events have occurred on any selected " + "file descriptor, poll waits at least timeout milliseconds " + "for an event to occur on any of the selected file descriptors. " + "On a computer where millisecond timing accuracy is not " + "available, timeout is rounded up to the nearest legal value " + "available on that system. If the value timeout is 0, poll " + "returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" + +"[+?The poll function supports regular files, terminal and " + "pseudo-terminal devices, STREAMS-based files, FIFOs and " + "pipes. The behavior of poll on elements of fds that refer " + "to other types of file is unspecified.]" + +"[+?The poll function supports sockets.]" + +"[+?A file descriptor for a socket that is listening for connections " + "will indicate that it is ready for reading, once connections " + "are available. A file descriptor for a socket that " + "is connecting asynchronously will indicate that it is ready " + "for writing, once a connection has been established.]" + +"[+?Regular files always poll TRUE for reading and writing.]" + +"[e:eventarray]:[fdcount?Upon successful completion, an indexed array " + "of strings is returned which contains a list of array subscripts " + "in the poll array which received events.]" +"[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, " + "poll returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" +"[T:mtimeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " + "poll returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" +"\n" +"\nvar\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" +; + +/* + * |mystpcpy| - like |strcpy()| but returns the end of the buffer + * + * Copy string s2 to s1. s1 must be large enough. + * return s1-1 (position of string terminator ('\0') in destnation buffer). + */ +static +char *mystpcpy(char *s1, const char *s2) +{ + while (*s1++ = *s2++) + ; + return (s1-1); +} + +static +Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) +{ + char varnamebuff[PATH_MAX]; + va_list ap; + + va_start(ap, namefmt); + vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); + va_end(ap); + + return nv_open(varnamebuff, dict, flags); +} + +static +int poll_strtoevents(const char *str) +{ + int events = 0; + + if (strstr(str, "POLLIN")) events |= POLLIN; + if (strstr(str, "POLLRDNORM")) events |= POLLRDNORM; + if (strstr(str, "POLLRDBAND")) events |= POLLRDBAND; + if (strstr(str, "POLLPRI")) events |= POLLPRI; + if (strstr(str, "POLLOUT")) events |= POLLOUT; + if (strstr(str, "POLLWRNORM")) events |= POLLWRNORM; + if (strstr(str, "POLLWRBAND")) events |= POLLWRBAND; + if (strstr(str, "POLLERR")) events |= POLLERR; + if (strstr(str, "POLLHUP")) events |= POLLHUP; + if (strstr(str, "POLLNVAL")) events |= POLLNVAL; + + return events; +} + + +static +void poll_eventstostr(char *s, int events) +{ + *s='\0'; + if (!events) + return; + + if (events & POLLIN) s=mystpcpy(s, "POLLIN|"); + if (events & POLLRDNORM) s=mystpcpy(s, "POLLRDNORM|"); + if (events & POLLRDBAND) s=mystpcpy(s, "POLLRDBAND|"); + if (events & POLLPRI) s=mystpcpy(s, "POLLPRI|"); + if (events & POLLOUT) s=mystpcpy(s, "POLLOUT|"); + if (events & POLLWRNORM) s=mystpcpy(s, "POLLWRNORM|"); + if (events & POLLWRBAND) s=mystpcpy(s, "POLLWRBAND|"); + if (events & POLLERR) s=mystpcpy(s, "POLLERR|"); + if (events & POLLHUP) s=mystpcpy(s, "POLLHUP|"); + if (events & POLLNVAL) s=mystpcpy(s, "POLLNVAL|"); + + /* Remove trailling '|' */ + s--; + if(*s=='|') + *s='\0'; +} + +#undef getconf +#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) + +extern int b_poll(int argc, char *argv[], void *extra) +{ + Namval_t *np; + Shell_t *shp = sh_contexttoshell(extra); + char *varname; + int n; + int fd; + nfds_t numpollfd = 0; + int i; + char *s; + double timeout = -1.; + char buff[PATH_MAX*2+1]; /* enogth to hold two variable names */ + char *eventarrayname = NULL; + + while (n = optget(argv, sh_optpoll)) switch (n) + { + case 't': + case 'T': + errno = 0; + timeout = strtod(opt_info.arg, (char **)NULL); + if (errno != 0) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); + + /* -t uses seconds, -T milliseconds */ + if (n == 't') + timeout *= 1000.; + break; + case 'e': + eventarrayname = opt_info.arg; + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=1) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + varname = argv[0]; + + Namval_t *array_np, *array_np_sub; + const char *subname; + + array_np = nv_open(varname, shp->var_tree, NV_NOFAIL|NV_NOADD); + if (!array_np) + errormsg(SH_DICT, ERROR_system(1), "cannot find array variable %s", varname); + if(!nv_isattr(array_np, NV_ARRAY)) + errormsg(SH_DICT, ERROR_system(1), "variable %s is not an array", varname); + + /* Count number of array elememts. We need to do it "manually" to + * handle sparse indexed and associative arrays */ + nv_putsub(array_np, NULL, ARRAY_SCAN); + array_np_sub = array_np; + do + { + if (!(subname=nv_getsub(array_np_sub))) + break; + numpollfd++; + } while( array_np_sub && nv_nextsub(array_np_sub) ); + +#ifdef __GNUC__ + /* + * Allocate stack space via |alloca()| for gcc builds since ctfconvert + * is unable to handle VLAs from gcc. We need this until CR #6379193 + * is fixed. + */ + struct pollfd *pollfd = alloca(sizeof(struct pollfd)*(numpollfd+1)); +#else + /* We must allocate one more entry with VLA with zero elements do not work with all compilers */ + struct pollfd pollfd[numpollfd+1]; +#endif /* __GNUC__ */ + + nv_putsub(array_np, NULL, ARRAY_SCAN); + array_np_sub = array_np; + i = 0; + do + { + if (!(subname=nv_getsub(array_np_sub))) + break; + + np = nv_open_fmt(shp->var_tree, NV_NOFAIL|NV_NOADD, "%s[%s].fd", varname, subname); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "missing pollfd %s[%s].fd", varname, subname); + fd = (int)nv_getnum(np); + if (fd < 0 || fd > OPEN_MAX) + errormsg(SH_DICT, ERROR_system(1), "invalid pollfd fd %d", fd); + nv_close(np); + pollfd[i].fd = fd; + + np = nv_open_fmt(shp->var_tree, NV_NOFAIL|NV_NOADD, "%s[%s].events", varname, subname); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "missing pollfd %s[%s].events", varname, subname); + + s = nv_getval(np); + if (!s) + errormsg(SH_DICT, ERROR_system(1), "missing pollfd events value"); + pollfd[i].events = poll_strtoevents(s); + nv_close(np); + + pollfd[i].revents = 0; + + i++; + } while( array_np_sub && nv_nextsub(array_np_sub) ); + + n = poll(pollfd, numpollfd, timeout); + /* FixMe: EGAIN and EINTR may require extra handling */ + if (n < 0) + errormsg(SH_DICT, ERROR_system(1), "failure"); + + if (eventarrayname) + { + np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_ARRAY|NV_NOFAIL, "%s", eventarrayname); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "couldn't create poll count variable %s", eventarrayname); + nv_close(np); + } + + nv_putsub(array_np, NULL, ARRAY_SCAN); + array_np_sub = array_np; + i = 0; + do + { + if (!(subname=nv_getsub(array_np_sub))) + break; + + np = nv_open_fmt(shp->var_tree, NV_NOFAIL, "%s[%s].revents", varname, subname); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "couldn't create pollfd %s[%s].revents", varname, subname); + + poll_eventstostr(buff, pollfd[i].revents); + + nv_putval(np, buff, 0); + nv_close(np); + + if (eventarrayname && pollfd[i].revents) + { + sprintf(buff, "%s+=( '%s' )", eventarrayname, subname); + sh_trap(buff, 0); + } + + i++; + } while( array_np_sub && nv_nextsub(array_np_sub) ); + + nv_close(array_np); + + return(0); +} diff --git a/usr/src/lib/libshell/common/bltins/print.c b/usr/src/lib/libshell/common/bltins/print.c index 513d46fb0a..18b51aab67 100644 --- a/usr/src/lib/libshell/common/bltins/print.c +++ b/usr/src/lib/libshell/common/bltins/print.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -36,7 +36,6 @@ #include "builtins.h" #include "streval.h" #include <tmx.h> -#include <ctype.h> #include <ccode.h> union types_t @@ -203,7 +202,10 @@ int b_print(int argc, char *argv[], void *extra) fd = -1; break; case 'v': - vflag=1; + vflag='v'; + break; + case 'C': + vflag='C'; break; case ':': /* The following is for backward compatibility */ @@ -240,7 +242,7 @@ int b_print(int argc, char *argv[], void *extra) if(error_info.errors || (argc<0 && !(format = *argv++))) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); if(vflag && format) - errormsg(SH_DICT,ERROR_usage(2),"-v and -f are mutually exclusive"); + errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag); skip: if(format) format = genformat(format); @@ -293,13 +295,19 @@ skip2: } while(*pdata.nextarg && pdata.nextarg!=argv); if(pdata.nextarg == nullarg && pdata.argsize>0) sfwrite(outfile,stakptr(staktell()),pdata.argsize); + if(sffileno(outfile)!=sffileno(sfstderr)) + sfsync(outfile); sfpool(sfstderr,pool,SF_WRITE); exitval = pdata.err; } else if(vflag) { while(*argv) - fmtbase64(outfile,*argv++,0); + { + fmtbase64(outfile,*argv++,vflag=='C'); + if(!nflag) + sfputc(outfile,'\n'); + } } else { @@ -519,7 +527,14 @@ static void *fmtbase64(char *string, ssize_t *sz, int alt) else { int n = nv_size(np); - cp = (char*)np->nvalue.cp; + if(nv_isarray(np)) + { + nv_onattr(np,NV_RAW); + cp = nv_getval(np); + nv_offattr(np,NV_RAW); + } + else + cp = (char*)np->nvalue.cp; if((size = n)==0) size = strlen(cp); size = sfwrite(iop, cp, size); @@ -593,6 +608,7 @@ static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) union types_t* value = (union types_t*)v; struct printf* pp = (struct printf*)fe; register char* argp = *pp->nextarg; + char* w; if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1))) { @@ -712,7 +728,13 @@ static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) fe->flags &= ~SFFMT_LONG; break; case 'c': - if(fe->base >=0) + if(mbwide() && (n = mbsize(argp)) > 1) + { + fe->fmt = 's'; + fe->size = n; + value->s = argp; + } + else if(fe->base >=0) value->s = argp; else value->c = *argp; @@ -737,8 +759,12 @@ static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) { case '\'': case '"': - value->ll = ((unsigned char*)argp)[1]; - if(argp[2] && (argp[2] != argp[0] || argp[3])) + w = argp + 1; + if(mbwide() && mbsize(w) > 1) + value->ll = mbchar(w); + else + value->ll = *(unsigned char*)w++; + if(w[0] && (w[0] != argp[0] || w[1])) { errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); pp->err = 1; diff --git a/usr/src/lib/libshell/common/bltins/read.c b/usr/src/lib/libshell/common/bltins/read.c index 874b575986..d5df0ca53d 100644 --- a/usr/src/lib/libshell/common/bltins/read.c +++ b/usr/src/lib/libshell/common/bltins/read.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,6 @@ #include <ast.h> #include <error.h> -#include <ctype.h> #include "defs.h" #include "variables.h" #include "lexstates.h" @@ -68,9 +67,14 @@ int b_read(int argc,char *argv[], void *extra) int save_prompt, fixargs=((Shbltin_t*)extra)->invariant; struct read_save *rp; static char default_prompt[3] = {ESC,ESC}; + rp = (struct read_save*)(((Shbltin_t*)extra)->data); if(argc==0) + { + if(rp) + free((void*)rp); return(0); - if(rp = (struct read_save*)(((Shbltin_t*)extra)->data)) + } + if(rp) { flags = rp->flags; timeout = rp->timeout; @@ -199,7 +203,7 @@ static void timedout(void *handle) int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout) { - register int c; + register ssize_t c; register unsigned char *cp; register Namval_t *np; register char *name, *val; @@ -217,7 +221,7 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo void *timeslot=0; int delim = '\n'; int jmpval=0; - int size = 0; + ssize_t size = 0; int binary; struct checkpt buff; if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd))) @@ -225,9 +229,12 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo sh_stats(STAT_READS); if(names && (name = *names)) { + Namval_t *mp; if(val= strchr(name,'?')) *val = 0; np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); + if(np && nv_isarray(np) && (mp=nv_opensub(np))) + np = mp; if((flags&V_FLAG) && shp->ed_context) ((struct edit*)shp->ed_context)->e_default = np; if(flags&A_FLAG) @@ -311,7 +318,7 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo } if(flags&(N_FLAG|NN_FLAG)) { - char buf[64],*var=buf,*cur,*end,*up,*v; + char buf[256],*var=buf,*cur,*end,*up,*v; /* reserved buffer */ if((c=size)>=sizeof(buf)) { @@ -331,21 +338,24 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo } else { - int f,m; + ssize_t m; + int f; for (;;) { c = (flags&NN_FLAG) ? -size : -1; cp = sfreserve(iop,c,SF_LOCKR); f = 1; - if((m = sfvalue(iop)) > 0) + if(cp) + m = sfvalue(iop); + else { - if(!cp) - { - m = (cp = sfreserve(iop,size,0)) ? sfvalue(iop) : 0; - f = 0; - } - if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) - m = v-(char*)cp; + m = (cp = sfreserve(iop,size,0)) ? sfvalue(iop) : 0; + f = 0; + } + if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) + { + *v++ = 0; + m = v-(char*)cp; } if((c=m)>size) c = size; @@ -353,18 +363,18 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo { if(c > (end-cur)) { - int cx = cur - var, ux = up - var; + ssize_t cx = cur - var, ux = up - var; + m = (end - var) + (c - (end - cur)); if (var == buf) { - m = (end - var) + (c - (end - cur)); v = (char*)malloc(m+1); - memcpy(v, var, cur - var); + var = memcpy(v, var, cur - var); } else - v = newof(var, char, m, 1); - end = v + m; - cur = v + cx; - up = v + ux; + var = newof(var, char, m, 1); + end = var + m; + cur = var + cx; + up = var + ux; } memcpy((void*)cur,cp,c); if(f) @@ -375,7 +385,6 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo { int x; int z; - int y = cur - up; mbinit(); *cur = 0; @@ -402,16 +411,19 @@ int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeo } if(timeslot) timerdel(timeslot); - if(binary) + if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) { - if(c==nv_size(np)) + if((c==size) && np->nvalue.cp && !nv_isarray(np)) memcpy((char*)np->nvalue.cp,var,c); else { + Namval_t *mp; if(var==buf) var = memdup(var,c); nv_putval(np,var,NV_RAW); nv_setsize(np,c); + if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv)) + nv_setsize(mp,c); } } else diff --git a/usr/src/lib/libshell/common/bltins/regress.c b/usr/src/lib/libshell/common/bltins/regress.c new file mode 100644 index 0000000000..b736fd1534 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/regress.c @@ -0,0 +1,343 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2009 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * regression test intercept control + * enable with SHOPT_REGRESS==1 in Makefile + * not for production use + * see --man for details + * all string constants inline here instead of in data/... + * + * David Korn + * at&t research + */ + +#include "defs.h" + +#if SHOPT_REGRESS + +#include <error.h> +#include <ls.h> +#include "io.h" +#include "builtins.h" +#include <tmx.h> + +#define REGRESS_HEADER "ksh:REGRESS:" + +#define TRACE(r,i,f) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__) + +static const char usage[] = +"[-1p0?\n@(#)$Id: __regress__ (AT&T Research) 2009-03-29 $\n]" +USAGE_LICENSE +"[+NAME?__regress__ - shell regression test intercept control]" +"[+DESCRIPTION?\b__regress__\b controls the regression test intercepts " + "for shells compiled with SHOPT_REGRESS==1. Shells compiled this way are " + "for testing only. In addition to \b__regress__\b and the \b--regress\b " + "command line option, these shells may contain system library function " + "intercepts that behave different from the native counterparts.]" +"[+?Each option controls a different test and possibly a different set " + "of intercepts. The options are interpreted \bdd\b(1) style -- '-' or " + "'--' prefix not required. This simplifies the specification of the " + "command line \b--regress\b=\avalue\a option, where \avalue\a is passed " + "as an option to the \b__regress__\b builtin. Typically regression test " + "intercepts are enabled with one or more command line \b--regress\b " + "options, with optional specific calls to \b__regress__\b in test " + "scripts to enable/disable intercepts as the test progresses.]" +"[+?Each enabled intercept may result in trace lines of the form \b" REGRESS_HEADER + "\aoption\a:\aintercept\a:\ainfo\a on the standard error, where " + "\aoption\a is one of the options below, \aintercept\a is the name of " + "the specific intercept for \aoption\a, and \ainfo\a is \aoption\a " + "specific information. Unless noted otherwise, one regression test trace " + "line is produced each time an enabled intercept is called.]" +"[101:egid?The intercept effective gid is set to \aoriginal-egid\a. The " + "effective gid of the underlying system process is not affected. The " + "trace line info is either \begid==rgid\b or \begid!=rgid\b. The " + "intercepts are:]#?[original-egid:=1]" + "{" + "[+getegid()?The intercept effecive gid is returned. The " + "\bsetgid\b() intercept may change this between the real gid and " + "\aoriginal-egid\a.]" + "[+setgid(gid)?Sets the intercept effective gid to \agid\a. " + "Fails if \agid\a is neither the real gid nor " + "\aoriginal-egid\a.]" + "}" +"[102:euid?The intercept effective uid is set to \aoriginal-euid\a. The " + "effective uid of the underlying system process is not affected. The " + "trace line info is either \beuid==ruid\b or \beuid!=ruid\b. The " + "intercepts are:]#?[original-euid:=1]" + "{" + "[+geteuid()?The intercept effecive uid is returned. The " + "\bsetuid\b() intercept may change this between the real uid and " + "\aoriginal-euid\a.]" + "[+setuid(uid)?Sets the intercept effective uid to \auid\a. " + "Fails if \auid\a is neither the real uid nor " + "\aoriginal-euid\a.]" + "}" +"[103:p_suid?Specifies a value for SHOPT_P_SUID. Effective uids greater " + "than the non-privileged-uid disable the priveleged mode. The intercepts " + "are:]#?[non-privileged-uid:=1]" + "{" + "[+SHOPT_P_SUID?The SHOPT_P_SUID macro value is overridden by " + "\bp_suid\b. A trace line is output for each SHOPT_P_SUID " + "access.]" + "}" +"[104:source?The intercepts are:]" + "{" + "[+sh_source()?The trace line info is the path of the script " + "being sourced. Used to trace shell startup scripts.]" + "}" +"[105:etc?Map file paths matching \b/etc/\b* to \aetc-dir\a/*. The " + "intercepts are:]:[etc-dir:=/etc]" + "{" + "[+sh_open()?Paths matching \b/etc/\b* are changed to " + "\aetc-dir\a/*.]" + "}" +"[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]" +; + +static const char* regress_options[] = +{ + "ERROR", + "egid", + "euid", + "p_suid", + "source", + "etc", +}; + +void sh_regress_init(Shell_t* shp) +{ + static Regress_t state; + + shp->regress = &state; +} + +/* + * regress info trace output + */ + +void sh_regress(unsigned int index, const char* intercept, const char* info, unsigned int line, const char* file) +{ + char* name; + char buf[16]; + + if (index >= 1 && index <= elementsof(regress_options)) + name = (char*)regress_options[index]; + else + sfsprintf(name = buf, sizeof(buf), "%u", index); + sfprintf(sfstderr, REGRESS_HEADER "%s:%s:%s\n", name, intercept, fmtesc(info)); +} + +/* + * egid intercepts + */ + +static gid_t intercept_sgid = 0; +static gid_t intercept_egid = -1; +static gid_t intercept_rgid = -1; + +gid_t getegid(void) +{ + if (intercept_rgid == -1) + intercept_rgid = getgid(); + if (sh_isregress(REGRESS_egid)) + { + TRACE(egid, "getegid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid")); + return intercept_egid; + } + return intercept_rgid; +} + +int setgid(gid_t gid) +{ + if (intercept_rgid == -1) + intercept_rgid = getgid(); + if (sh_isregress(REGRESS_egid)) + { + if (gid != intercept_rgid && gid != intercept_sgid) + { + TRACE(egid, "setgid", ("%s", "EPERM")); + errno = EPERM; + return -1; + } + intercept_egid = gid; + TRACE(egid, "setgid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid")); + } + else if (gid != intercept_rgid) + { + errno = EPERM; + return -1; + } + return 0; +} + +/* + * euid intercepts + */ + +static uid_t intercept_suid = 0; +static uid_t intercept_euid = -1; +static uid_t intercept_ruid = -1; + +uid_t geteuid(void) +{ + if (intercept_ruid == -1) + intercept_ruid = getuid(); + if (sh_isregress(REGRESS_euid)) + { + TRACE(euid, "geteuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid")); + return intercept_euid; + } + return intercept_ruid; +} + +int setuid(uid_t uid) +{ + if (intercept_ruid == -1) + intercept_ruid = getuid(); + if (sh_isregress(REGRESS_euid)) + { + if (uid != intercept_ruid && uid != intercept_suid) + { + TRACE(euid, "setuid", ("%s", "EPERM")); + errno = EPERM; + return -1; + } + intercept_euid = uid; + TRACE(euid, "setuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid")); + } + else if (uid != intercept_ruid) + { + errno = EPERM; + return -1; + } + return 0; +} + +/* + * p_suid intercept + */ + +static uid_t intercept_p_suid = 0x7fffffff; + +uid_t sh_regress_p_suid(unsigned int line, const char* file) +{ + REGRESS(p_suid, "SHOPT_P_SUID", ("%d", intercept_p_suid)); + return intercept_p_suid; +} + +/* + * p_suid intercept + */ + +static char* intercept_etc = 0; + +char* sh_regress_etc(const char* path, unsigned int line, const char* file) +{ + REGRESS(etc, "sh_open", ("%s => %s%s", path, intercept_etc, path+4)); + return intercept_etc; +} + +/* + * __regress__ builtin + */ + +int b___regress__(int argc, char** argv, void *extra) +{ + register Shell_t* shp = ((Shbltin_t*)extra)->shp; + int n; + + for (;;) + { + switch (n = optget(argv, usage)) + { + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case 0: + break; + default: + if (n < -100) + { + n = -(n + 100); + if (opt_info.arg || opt_info.number) + sh_onregress(n); + else + sh_offregress(n); + switch (n) + { + case REGRESS_egid: + if (sh_isregress(n)) + { + intercept_egid = intercept_sgid = (gid_t)opt_info.number; + TRACE(egid, argv[0], ("%d", intercept_egid)); + } + else + TRACE(egid, argv[0], ("%s", "off")); + break; + case REGRESS_euid: + if (sh_isregress(n)) + { + intercept_euid = intercept_suid = (uid_t)opt_info.number; + TRACE(euid, argv[0], ("%d", intercept_euid)); + } + else + TRACE(euid, argv[0], ("%s", "off")); + break; + case REGRESS_p_suid: + if (sh_isregress(n)) + { + intercept_p_suid = (uid_t)opt_info.number; + TRACE(p_suid, argv[0], ("%d", intercept_p_suid)); + } + else + TRACE(p_suid, argv[0], ("%s", "off")); + break; + case REGRESS_source: + TRACE(source, argv[0], ("%s", sh_isregress(n) ? "on" : "off")); + break; + case REGRESS_etc: + if (sh_isregress(n)) + { + intercept_etc = opt_info.arg; + TRACE(etc, argv[0], ("%s", intercept_etc)); + } + else + TRACE(etc, argv[0], ("%s", "off")); + break; + } + } + continue; + } + break; + } + if (error_info.errors || *(argv + opt_info.index)) + errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NiL)); + return 0; +} + +#else + +NoN(regress) + +#endif diff --git a/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c b/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c index 0f49eb982f..55e0e0357c 100644 --- a/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c +++ b/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c @@ -857,329 +857,6 @@ extern int b_stat(int argc, char *argv[], void *extra) return(0); } -static const char sh_optpoll[] = -"[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-12-20 $\n]" -"[-author?Roland Mainz <roland.mainz@nrubsig.org]" -"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" -"[+NAME? poll - input/output multiplexing]" -"[+DESCRIPTION?The poll command provides applications with a mechanism " - "for multiplexing input/output over a set of file descriptors. " - "For each member of the array variable \bvar\b, " - "poll examines the given file descriptor in the subscript \b.fd\b " - "for the event(s) specified in the subscript \b.events\b." - "The poll command identifies those file descriptors on which an " - "application can read or write data, or on which certain events have " - "occurred.]" -"[+?The \bvar\b argument specifies the file descriptors to be examined " - "and the events of interest for each file descriptor. " - "It is a array of structured variables with one member for each open " - "file descriptor of interest. The array's members contain the following " - "subscripts:]{" - "[+?\b.fd\b # file descriptor]" - "[+?\b.events\b # requested events]" - "[+?\b.revents\b # returned event]" - "}" -"[+?The \bfd\b variable specifies an open file descriptor and the " - "\bevents\b and \brevents\b members are strings constructed from " - "a concaternation of the following event flags, seperated by '|':]" - "{ " - "[+POLLIN?Data other than high priority data may be " - "read without blocking. For STREAMS, this " - "flag is set in revents even if the message " - "is of zero length.]" - "[+POLLRDNORM?Normal data (priority band equals 0) may be " - "read without blocking. For STREAMS, this " - "flag is set in revents even if the message " - "is of zero length.]" - "[+POLLRDBAND?Data from a non-zero priority band may be " - "read without blocking. For STREAMS, this " - "flag is set in revents even if the message " - "is of zero length.]" - "[+POLLPRI?High priority data may be received without " - "blocking. For STREAMS, this flag is set in " - "revents even if the message is of zero " - "length.]" - "[+POLLOUT?Normal data (priority band equals 0) may be " - "written without blocking.]" - "[+POLLWRNORM?The same as POLLOUT.]" - "[+POLLWRBAND?Priority data (priority band > 0) may be " - "written. This event only examines bands " - "that have been written to at least once.]" - "[+POLLERR?An error has occurred on the device or " - "stream. This flag is only valid in the " - "revents bitmask; it is not used in the " - "events member.]" - "[+POLLHUP?A hangup has occurred on the stream. This " - "event and POLLOUT are mutually exclusive; a " - "stream can never be writable if a hangup has " - "occurred. However, this event and POLLIN, " - ", POLLRDBAND, or POLLPRI are not " - "mutually exclusive. This flag is only valid " - "in the revents bitmask; it is not used in " - "the events member.]" - "[+POLLNVAL?The specified fd value does not belong to an " - "open file. This flag is only valid in the " - "revents member; it is not used in the events " - "member.]" - "}" -"]" - -"[+?If the value fd is less than 0, events is ignored and " - "revents is set to 0 in that entry on return from poll.]" - -"[+?The results of the poll query are stored in the revents " - "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b " - "variable to indicate which of the requested events are true. " - "If none are true, the \brevents\b will be an empty string when " - "the poll command returns. The event flags " - "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b " - "if the conditions they indicate are true; this occurs even " - "though these flags were not present in events.]" - -"[+?If none of the defined events have occurred on any selected " - "file descriptor, poll waits at least timeout milliseconds " - "for an event to occur on any of the selected file descriptors. " - "On a computer where millisecond timing accuracy is not " - "available, timeout is rounded up to the nearest legal value " - "available on that system. If the value timeout is 0, poll " - "returns immediately. If the value of timeout is -1, poll " - "blocks until a requested event occurs or until the call is " - "interrupted.]" - -"[+?The poll function supports regular files, terminal and " - "pseudo-terminal devices, STREAMS-based files, FIFOs and " - "pipes. The behavior of poll on elements of fds that refer " - "to other types of file is unspecified.]" - -"[+?The poll function supports sockets.]" - -"[+?A file descriptor for a socket that is listening for connections " - "will indicate that it is ready for reading, once connections " - "are available. A file descriptor for a socket that " - "is connecting asynchronously will indicate that it is ready " - "for writing, once a connection has been established.]" - -"[+?Regular files always poll TRUE for reading and writing.]" - -"[c:fdcount]:[fdcount?Upon successful completion, a non-negative value is " - "returned. A positive value indicates the total number of " - "file descriptors that has been selected (that is, file " - "descriptors for which the revents member is non-zero). A " - "value of 0 indicates that the call timed out and no file " - "descriptors have been selected. Upon failure, -1 is returned.]" -"[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, " - "poll returns immediately. If the value of timeout is -1, poll " - "blocks until a requested event occurs or until the call is " - "interrupted.]" -"[T:mtimeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " - "poll returns immediately. If the value of timeout is -1, poll " - "blocks until a requested event occurs or until the call is " - "interrupted.]" -"\n" -"\nvar\n" -"\n" -"[+EXIT STATUS?]{" - "[+0?Success.]" - "[+>0?An error occurred.]" -"}" -"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" -; - -/* - * |mystpcpy| - like |strcpy()| but returns the end of the buffer - * - * Copy string s2 to s1. s1 must be large enough. - * return s1-1 (position of string terminator ('\0') in destnation buffer). - */ -static -char *mystpcpy(char *s1, const char *s2) -{ - while (*s1++ = *s2++) - ; - return (s1-1); -} - -static -Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) -{ - char varnamebuff[PATH_MAX]; - va_list ap; - - va_start(ap, namefmt); - vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); - va_end(ap); - - return nv_open(varnamebuff, dict, flags); -} - -static -int poll_strtoevents(const char *str) -{ - int events = 0; - - if (strstr(str, "POLLIN")) events |= POLLIN; - if (strstr(str, "POLLRDNORM")) events |= POLLRDNORM; - if (strstr(str, "POLLRDBAND")) events |= POLLRDBAND; - if (strstr(str, "POLLPRI")) events |= POLLPRI; - if (strstr(str, "POLLOUT")) events |= POLLOUT; - if (strstr(str, "POLLWRNORM")) events |= POLLWRNORM; - if (strstr(str, "POLLWRBAND")) events |= POLLWRBAND; - if (strstr(str, "POLLERR")) events |= POLLERR; - if (strstr(str, "POLLHUP")) events |= POLLHUP; - if (strstr(str, "POLLNVAL")) events |= POLLNVAL; - - return events; -} - - -static -void poll_eventstostr(char *s, int events) -{ - *s='\0'; - if (!events) - return; - - if (events & POLLIN) s=mystpcpy(s, "POLLIN|"); - if (events & POLLRDNORM) s=mystpcpy(s, "POLLRDNORM|"); - if (events & POLLRDBAND) s=mystpcpy(s, "POLLRDBAND|"); - if (events & POLLPRI) s=mystpcpy(s, "POLLPRI|"); - if (events & POLLOUT) s=mystpcpy(s, "POLLOUT|"); - if (events & POLLWRNORM) s=mystpcpy(s, "POLLWRNORM|"); - if (events & POLLWRBAND) s=mystpcpy(s, "POLLWRBAND|"); - if (events & POLLERR) s=mystpcpy(s, "POLLERR|"); - if (events & POLLHUP) s=mystpcpy(s, "POLLHUP|"); - if (events & POLLNVAL) s=mystpcpy(s, "POLLNVAL|"); - - /* Remove trailling '|' */ - s--; - if(*s=='|') - *s='\0'; -} - -#undef getconf -#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) - -extern int b_poll(int argc, char *argv[], void *extra) -{ - register Namval_t *np; - register int n; - Shell_t *shp = sh_contexttoshell(extra); - char *varname; - int fd; - unsigned int numpollfd = 0; - int i; - char *s; - double timeout = -1.; - char buff[256]; - char *pollfdcountvarname = NULL; - long open_max, - bpoll_max; - - if ((open_max = getconf("OPEN_MAX")) <= 0) - open_max = OPEN_MAX; - /* |bpoll_max| needs to be larger than |OPEN_MAX| to make sure we - * can listen to different sets of events per fd. - */ - bpoll_max = open_max*2L; - - while (n = optget(argv, sh_optpoll)) switch (n) - { - case 't': - case 'T': - errno = 0; - timeout = strtod(opt_info.arg, (char **)NULL); - if (errno != 0) - errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); - - /* -t uses seconds, -T milliseconds */ - if (n == 't') - timeout *= 1000.; - break; - case 'c': - pollfdcountvarname = opt_info.arg; - break; - case ':': - errormsg(SH_DICT, 2, "%s", opt_info.arg); - break; - case '?': - errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); - break; - } - argc -= opt_info.index; - argv += opt_info.index; - if(argc!=1) - errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); - - varname = argv[0]; - -#ifdef __GNUC__ - /* - * Allocate one extra array entry to keep ctfconvert+gcc builds - * happy until CR #6379193 is fixed. - */ - struct pollfd pollfd[bpoll_max+1]; -#else - struct pollfd pollfd[bpoll_max]; -#endif - for(i=0 ; i < bpoll_max ; i++) - { - np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); - if (!np) - break; - fd = (int)nv_getnum(np); - if (fd < 0 || fd > OPEN_MAX) - errormsg(SH_DICT, ERROR_system(1), "invalid pollfd fd"); - nv_close(np); - pollfd[i].fd = fd; - - np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); - if (!np) - errormsg(SH_DICT, ERROR_system(1), "missing pollfd events"); - - s = nv_getval(np); - if (!s) - errormsg(SH_DICT, ERROR_system(1), "missing pollfd events value"); - pollfd[i].events = poll_strtoevents(s); - nv_close(np); - - pollfd[i].revents = 0; - - numpollfd++; - } - - if (i == bpoll_max) - errormsg(SH_DICT, ERROR_system(1), "cannot handle more than %d entries.", bpoll_max); - - n = poll(pollfd, numpollfd, timeout); - /* FixMe: EGAIN and EINTR may require extra handling */ - if (n < 0) - errormsg(SH_DICT, ERROR_system(1), "failure"); - - if (pollfdcountvarname) - { - int32_t v = n; - - np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s", pollfdcountvarname); - if (!np) - errormsg(SH_DICT, ERROR_system(1), "couldn't create poll count variable %s", pollfdcountvarname); - nv_putval(np, (char *)&v, NV_INTEGER); - nv_close(np); - } - - for(i=0 ; i < numpollfd ; i++) - { - np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%d].revents", varname, i); - if (!np) - errormsg(SH_DICT, ERROR_system(1), "couldn't create pollfd %s[%d].revents", varname, i); - - poll_eventstostr(buff, pollfd[i].revents); - - nv_putval(np, buff, 0); - nv_close(np); - } - - return(0); -} static const char sh_optrewind[] = "[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]" diff --git a/usr/src/lib/libshell/common/bltins/sleep.c b/usr/src/lib/libshell/common/bltins/sleep.c index 48af7fe807..a0648632dd 100644 --- a/usr/src/lib/libshell/common/bltins/sleep.c +++ b/usr/src/lib/libshell/common/bltins/sleep.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -31,6 +31,7 @@ #undef sleep #include <error.h> #include <errno.h> +#include <tmx.h> #include "builtins.h" #include "FEATURE/time" #include "FEATURE/poll" @@ -44,14 +45,18 @@ int b_sleep(register int argc,char *argv[],void *extra) { register char *cp; - register double d; + register double d=0; register Shell_t *shp = ((Shbltin_t*)extra)->shp; + int sflag=0; time_t tloc = 0; char *last; if(!(shp->sigflag[SIGALRM]&(SH_SIGFAULT|SH_SIGOFF))) sh_sigtrap(SIGALRM); while((argc = optget(argv,sh_optsleep))) switch(argc) { + case 's': + sflag=1; + break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; @@ -60,20 +65,47 @@ int b_sleep(register int argc,char *argv[],void *extra) break; } argv += opt_info.index; - if(error_info.errors || !(cp= *argv) || ((d=strtod(cp, (char**)&last)),*last)) - errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(cp = *argv) + { + d = strtod(cp, &last); + if(*last) + { + Time_t now,ns; + char* pp; + now = TMX_NOW; + if(*cp == 'P' || *cp == 'p') + ns = tmxdate(cp, &last, now); + else + { + if(pp = sfprints("exact %s", cp)) + ns = tmxdate(pp, &last, now); + if(*last && (pp = sfprints("p%s", cp))) + ns = tmxdate(pp, &last, now); + } + if(*last) + errormsg(SH_DICT,ERROR_exit(1),e_number,*argv); + d = ns - now; + d /= TMX_RESOLUTION; + } + if(argv[1]) + errormsg(SH_DICT,ERROR_exit(1),e_oneoperand); + } + else if(!sflag) + errormsg(SH_DICT,ERROR_exit(1),e_oneoperand); if(d > .10) { time(&tloc); tloc += (time_t)(d+.5); } - while(1) + if(sflag && d==0) + pause(); + else while(1) { time_t now; errno = 0; shp->lastsig=0; sh_delay(d); - if(tloc==0 || errno!=EINTR || shp->lastsig) + if(sflag || tloc==0 || errno!=EINTR || shp->lastsig) break; sh_sigcheck(); if(tloc < (now=time(NIL(time_t*)))) diff --git a/usr/src/lib/libshell/common/bltins/test.c b/usr/src/lib/libshell/common/bltins/test.c index 644f54eb1c..ec8095107d 100644 --- a/usr/src/lib/libshell/common/bltins/test.c +++ b/usr/src/lib/libshell/common/bltins/test.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -29,7 +29,6 @@ #include "defs.h" -#include <ctype.h> #include <error.h> #include <ls.h> #include "io.h" @@ -267,8 +266,11 @@ static int e3(struct test *tp) goto skip; if(c2_eq(arg,'-','t')) { - if(cp && isdigit(*cp)) - return(*(cp+1)?0:tty_check(*cp-'0')); + if(cp) + { + op = strtol(cp,&binop, 10); + return(*binop?0:tty_check(op)); + } else { /* test -t with no arguments */ @@ -300,7 +302,7 @@ skip: cp = nxtarg(tp,0); if(!op) errormsg(SH_DICT,ERROR_exit(2),e_badop,binop); - if(op==TEST_AND | op==TEST_OR) + if(op==TEST_AND || op==TEST_OR) tp->ap--; return(test_binop(op,arg,cp)); } @@ -415,9 +417,34 @@ int test_unop(register int op,register const char *arg) op = sh_lookopt(arg,&f); return(op && (f==(sh_isoption(op)!=0))); case 't': - if(isdigit(*arg) && arg[1]==0) - return(tty_check(*arg-'0')); - return(0); + { + char *last; + op = strtol(arg,&last, 10); + return(*last?0:tty_check(op)); + } + case 'v': + case 'R': + { + Namval_t *np; + Namarr_t *ap; + int isref; + if(!(np = nv_open(arg,sh.var_tree,NV_VARNAME|NV_NOFAIL|NV_NOADD|NV_NOREF))) + return(0); + isref = nv_isref(np); + if(op=='R') + return(isref); + if(isref) + { + if(np->nvalue.cp) + np = nv_refnode(np); + else + return(0); + + } + if(ap = nv_arrayptr(np)) + return(nv_arrayisset(np,ap)); + return(!nv_isnull(np) || nv_isattr(np,NV_INTEGER)); + } default: { static char a[3] = "-?"; diff --git a/usr/src/lib/libshell/common/bltins/trap.c b/usr/src/lib/libshell/common/bltins/trap.c index a298a35742..494d5d8431 100644 --- a/usr/src/lib/libshell/common/bltins/trap.c +++ b/usr/src/lib/libshell/common/bltins/trap.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -30,7 +30,6 @@ */ #include "defs.h" -#include <ctype.h> #include "jobs.h" #include "builtins.h" @@ -150,10 +149,11 @@ int b_trap(int argc,char *argv[],void *extra) { if(sig >= shp->st.trapmax) shp->st.trapmax = sig+1; - if(arg=shp->st.trapcom[sig]) - free(arg); - shp->st.trapcom[sig] = strdup(action); + arg = shp->st.trapcom[sig]; sh_sigtrap(sig); + shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action); + if(arg && arg != Empty) + free(arg); } } } @@ -260,6 +260,12 @@ static int sig_number(const char *string) { sig = 1; o += 3; + if(isdigit(*stakptr(o))) + { + n = strtol(stakptr(o),&last,10); + if(!*last) + return(n); + } } tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); n = tp->sh_number; @@ -279,7 +285,7 @@ static int sig_number(const char *string) if(n < SH_TRAP) n--; } - if(n<0 && (name=stakptr(o)) && *name++=='R' && *name++=='T') + if(n<0 && sh.sigruntime[1] && (name=stakptr(o)) && *name++=='R' && *name++=='T') { if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+') { @@ -348,7 +354,7 @@ static char* sig_name(int sig, char* buf, int pfx) static void sig_list(register Shell_t *shp,register int flag) { register const struct shtable2 *tp; - register int sig = shp->sigmax+1; + register int sig; register char *sname; char name[10]; const char *names[SH_TRAP]; @@ -357,16 +363,16 @@ static void sig_list(register Shell_t *shp,register int flag) if(flag<=0) { /* not all signals may be defined, so initialize */ - while(--sig >= 0) + for(sig=shp->sigmax; sig>=0; sig--) names[sig] = 0; for(sig=SH_DEBUGTRAP; sig>=0; sig--) traps[sig] = 0; } - while(*tp->sh_name) + for(; *tp->sh_name; tp++) { sig = tp->sh_number&((1<<SH_SIGBITS)-1); - if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) - sig = sh.sigruntime[sig-1]+1; + if (((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) && (sig = sh.sigruntime[sig-1]+1) == 1) + continue; if(sig==flag) { sfprintf(sfstdout,"%s\n",tp->sh_name); @@ -374,9 +380,8 @@ static void sig_list(register Shell_t *shp,register int flag) } else if(sig&SH_TRAP) traps[sig&~SH_TRAP] = (char*)tp->sh_name; - else if(sig < sizeof(names)/sizeof(char*)) + else if(sig-- && sig < elementsof(names)) names[sig] = (char*)tp->sh_name; - tp++; } if(flag > 0) sfputr(sfstdout, sig_name(flag-1,name,0), '\n'); @@ -391,7 +396,7 @@ static void sig_list(register Shell_t *shp,register int flag) { if(!(trap=trapcom[sig])) continue; - if(!(sname=(char*)names[sig+1])) + if(sig > shp->sigmax || !(sname=(char*)names[sig])) sname = sig_name(sig,name,1); sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname); } @@ -405,9 +410,9 @@ static void sig_list(register Shell_t *shp,register int flag) else { /* print all the signal names */ - for(sig=2; sig <= shp->sigmax; sig++) + for(sig=1; sig <= shp->sigmax; sig++) { - if(!(sname=(char*)names[sig+1])) + if(!(sname=(char*)names[sig])) sname = sig_name(sig,name,1); sfputr(sfstdout,sname,'\n'); } diff --git a/usr/src/lib/libshell/common/bltins/typeset.c b/usr/src/lib/libshell/common/bltins/typeset.c index 734651fd3a..6428248499 100644 --- a/usr/src/lib/libshell/common/bltins/typeset.c +++ b/usr/src/lib/libshell/common/bltins/typeset.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -248,7 +248,7 @@ int b_typeset(int argc,register char *argv[],void *extra) case 'F': case 'X': if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) - tdata.argnum = 10; + tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10); isfloat = 1; if(n=='E') { @@ -389,6 +389,8 @@ endargs: stkseek(stkp,offset); if(!tdata.tp) errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); + else if(nv_isnull(tdata.tp)) + nv_newtype(tdata.tp); tdata.tp->nvenv = tdata.help; flag &= ~NV_TYPE; } @@ -402,10 +404,15 @@ endargs: static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) { char *name; + int aflag=tp->aflag; if(nv_isnull(np)) - return; - sfputr(iop,nv_name(np),tp->aflag=='+'?'\n':'='); - if(tp->aflag=='+') + { + if(!np->nvflag) + return; + aflag = '+'; + } + sfputr(iop,nv_name(np),aflag=='+'?'\n':'='); + if(aflag=='+') return; if(nv_isarray(np) && nv_arrayptr(np)) { @@ -478,7 +485,7 @@ static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata * print_namval(sfstdout,np,tp->aflag=='+',tp); continue; } - if(shp->subshell) + if(shp->subshell && !shp->subshare) sh_subfork(); if(tp->aflag=='-') nv_onattr(np,flag|NV_FUNCTION); @@ -539,12 +546,18 @@ static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata * { if(comvar) { - _nv_unset(np,NV_RDONLY); - nv_onattr(np,NV_NOFREE); + Namarr_t *ap=nv_arrayptr(np); + if(ap) + ap->nelem |= ARRAY_TREE; + else + { + _nv_unset(np,NV_RDONLY); + nv_onattr(np,NV_NOFREE); + } } nv_setarray(np,nv_associative); } - else if(comvar && !nv_rename(np,flag|NV_COMVAR)) + else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR)) nv_setvtree(np); } if(flag&NV_MOVE) @@ -553,7 +566,7 @@ static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata * nv_close(np); continue; } - if(tp->tp) + if(tp->tp && nv_type(np)!=tp->tp) { nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); flag = (np->nvflag&NV_NOCHANGE); @@ -562,9 +575,11 @@ static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata * flag &= ~NV_ASSIGN; if(last=strchr(name,'=')) *last = 0; + if (shp->typeinit) + continue; if (tp->aflag == '-') { - if((flag&NV_EXPORT) && strchr(name,'.')) + if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np))) errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); #if SHOPT_BSH if(flag&NV_EXPORT) @@ -769,6 +784,8 @@ int b_builtin(int argc,char *argv[],void *extra) memset(&tdata,0,sizeof(tdata)); tdata.sh = ((Shbltin_t*)extra)->shp; stkp = tdata.sh->stk; + if(!tdata.sh->pathlist) + path_absolute(argv[0],NIL(Pathcomp_t*)); while (n = optget(argv,sh_optbuiltin)) switch (n) { case 's': @@ -801,7 +818,7 @@ int b_builtin(int argc,char *argv[],void *extra) errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); if(sh_isoption(SH_PFSH)) errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); - if(tdata.sh->subshell) + if(tdata.sh->subshell && !tdata.sh->subshare) sh_subfork(); } #if SHOPT_DYNAMIC @@ -922,7 +939,8 @@ static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) register const char *name; register int r; Dt_t *dp; - int nflag=0,all=0,isfun; + int nflag=0,all=0,isfun,jmpval; + struct checkpt buff; NOT_USED(argc); if(troot==shp->alias_tree) { @@ -963,13 +981,28 @@ static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) else nflag = NV_NOSCOPE; if(all) + { dtclear(troot); - else while(name = *argv++) + return(r); + } + sh_pushcontext(&buff,1); + while(name = *argv++) { - if(np=nv_open(name,troot,NV_NOADD|NV_NOFAIL|nflag)) + jmpval = sigsetjmp(buff.buff,0); + np = 0; + if(jmpval==0) + np=nv_open(name,troot,NV_NOADD|nflag); + else + { + r = 1; + continue; + } + if(np) { - if(is_abuiltin(np)) + if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY)) { + if(nv_isattr(np,NV_RDONLY)) + errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); r = 1; continue; } @@ -985,16 +1018,16 @@ static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) if(shp->subshell) np=sh_assignok(np,0); } - nv_unset(np); + if(!nv_isnull(np)) + nv_unset(np); nv_close(np); if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) nv_delete(np,dp,NV_NOFREE); else if(isfun) nv_delete(np,troot,NV_NOFREE); } - else - r = 1; } + sh_popcontext(&buff); return(r); } diff --git a/usr/src/lib/libshell/common/bltins/ulimit.c b/usr/src/lib/libshell/common/bltins/ulimit.c index 53fd29def5..7c8e9378d3 100644 --- a/usr/src/lib/libshell/common/bltins/ulimit.c +++ b/usr/src/lib/libshell/common/bltins/ulimit.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -29,7 +29,7 @@ #include <ast.h> #include <sfio.h> #include <error.h> -#include <shell.h> +#include "defs.h" #include "builtins.h" #include "name.h" #include "ulimit.h" @@ -132,7 +132,7 @@ int b_ulimit(int argc,char *argv[],void *extra) unit = shtab_units[tp->type]; if(limit) { - if(shp->subshell) + if(shp->subshell && !shp->subshare) sh_subfork(); if(strcmp(limit,e_unlimited)==0) i = INFINITY; diff --git a/usr/src/lib/libshell/common/bltins/umask.c b/usr/src/lib/libshell/common/bltins/umask.c index fc5a684016..d8bc67647a 100644 --- a/usr/src/lib/libshell/common/bltins/umask.c +++ b/usr/src/lib/libshell/common/bltins/umask.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/bltins/whence.c b/usr/src/lib/libshell/common/bltins/whence.c index 39366f0e68..4714c78b10 100644 --- a/usr/src/lib/libshell/common/bltins/whence.c +++ b/usr/src/lib/libshell/common/bltins/whence.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/data/aliases.c b/usr/src/lib/libshell/common/data/aliases.c index 8a76dc7e82..5b7298b299 100644 --- a/usr/src/lib/libshell/common/data/aliases.c +++ b/usr/src/lib/libshell/common/data/aliases.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -36,6 +36,7 @@ const struct shtable2 shtab_aliases[] = #endif /* SHOPT_FS_3D */ "autoload", NV_NOFREE, "typeset -fu", "command", NV_NOFREE, "command ", + "compound", NV_NOFREE, "typeset -C", "fc", NV_NOFREE, "hist", "float", NV_NOFREE, "typeset -lE", "functions", NV_NOFREE, "typeset -f", diff --git a/usr/src/lib/libshell/common/data/bash_pre_rc.sh b/usr/src/lib/libshell/common/data/bash_pre_rc.sh index e8f51f428b..56767363dc 100644 --- a/usr/src/lib/libshell/common/data/bash_pre_rc.sh +++ b/usr/src/lib/libshell/common/data/bash_pre_rc.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/data/builtins.c b/usr/src/lib/libshell/common/data/builtins.c index dad24caf31..94b34c77dd 100644 --- a/usr/src/lib/libshell/common/data/builtins.c +++ b/usr/src/lib/libshell/common/data/builtins.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -139,6 +139,9 @@ const struct shtable3 shtab_builtins[] = CMDLIST(wc) CMDLIST(sync) #endif +#if SHOPT_REGRESS + "__regress__", NV_BLTIN|BLT_ENV, bltin(__regress__), +#endif "", 0, 0 }; @@ -677,6 +680,7 @@ USAGE_LICENSE "\aflags\a with optional \anumber\a values may be specified to control " "option parsing. " "The flags are:]{" + "[++?Arguments beginning with + are considered options.]" "[+c?Cache this \aoptstring\a for multiple passes. Used to optimize " "builtins that may be called many times within the same process.]" "[+i?Ignore this \aoptstring\a when generating help. Used when " @@ -737,9 +741,7 @@ USAGE_LICENSE "[+8.?A group of the form [-\aname\a?\atext\a]] specifies entries " "for the \bIMPLEMENTATION\b section.]" "}" -"[+?If the leading character of \aoptstring\a is +, then arguments " - "beginning with + will also be considered options.]" -"[+?A leading : character or a : following a leading + in \aoptstring\a " +"[+?A leading : character in \aoptstring\a " "affects the way errors are handled. If an option character or longname " "argument not specified in \aoptstring\a is encountered when processing " "options, the shell variable whose name is \aname\a will be set to the ? " @@ -750,6 +752,8 @@ USAGE_LICENSE "Without the leading :, \aname\a will be set to the ? character, \bOPTARG\b " "will be unset, and an error message will be written to standard error " "when errors are encountered.]" +"[+?A leading + character or a + following a leading : in \aoptstring\a " + "specifies that arguments beginning with + will also be considered options.]" "[+?The end of options occurs when:]{" "[+1.?The special argument \b--\b is encountered.]" "[+2.?An argument that does not begin with a \b-\b is encountered.]" @@ -1060,7 +1064,7 @@ USAGE_LICENSE ; const char sh_optprint[] = -"[-1c?\n@(#)$Id: print (AT&T Research) 1999-04-07 $\n]" +"[-1c?\n@(#)$Id: print (AT&T Research) 2008-11-26 $\n]" USAGE_LICENSE "[+NAME?print - write arguments to standard output]" "[+DESCRIPTION?By default, \bprint\b writes each \astring\a operand to " @@ -1102,6 +1106,8 @@ USAGE_LICENSE "[u]:[fd:=1?Write to file descriptor number \afd\a instead of standard output.]" "[v?Treat each \astring\a as a variable name and write the value in \b%B\b " "format. Cannot be used with \b-f\b.]" +"[C?Treat each \astring\a as a variable name and write the value in \b%#B\b " + "format. Cannot be used with \b-f\b.]" "\n" "\n[string ...]\n" "\n" @@ -1113,7 +1119,7 @@ USAGE_LICENSE ; const char sh_optprintf[] = -"[-1c?\n@(#)$Id: printf (AT&T Research) 2006-10-26 $\n]" +"[-1c?\n@(#)$Id: printf (AT&T Research) 2009-02-02 $\n]" USAGE_LICENSE "[+NAME?printf - write formatted output]" "[+DESCRIPTION?\bprintf\b writes each \astring\a operand to " @@ -1161,7 +1167,7 @@ USAGE_LICENSE "in the underlying code set of the character following the " "\b\"\b or \b'\b. Otherwise, \astring\a is treated like a shell " "arithmetic expression and evaluated.]" -"[+?If a \astring\a operand cannot be completed converted into a value " +"[+?If a \astring\a operand cannot be completely converted into a value " "appropriate for that format specifier, an error will occur, " "but remaining \astring\a operands will continue to be processed.]" "[+?In addition to the format specifier extensions, the following " @@ -1174,8 +1180,10 @@ USAGE_LICENSE "[+-?The escape sequence \b\\x{\b\ahex\a\b}\b expands to the " "character corresponding to the hexidecimal value \ahex\a.]" "[+-?The format modifier flag \b=\b can be used to center a field to " - "a specified width. When the output is a terminal, the " - "character width is used rather than the number of bytes.]" + "a specified width.]" + "[+-?The format modifier flag \bL\b can be used with the \bc\b and " + "\bs\b formats to treat precision as character width instead " + "of byte count.]" "[+-?Each of the integral format specifiers can have a third " "modifier after width and precision that specifies the " "base of the conversion from 2 to 64. In this case the " @@ -1388,10 +1396,16 @@ USAGE_LICENSE "in \afile\a that can be used a separate shell script browser. The " "-R option requires a script to be specified as the first operand.]" #endif /* SHOPT_KIA */ +#if SHOPT_REGRESS +"[I:regress]:[intercept?Enable the regression test \aintercept\a. Must be " + "the first command line option(s).]" +#endif #if SHOPT_BASH "\fbash2\f" #endif "\fabc\f" +"?" +"[T?Enable implementation specific test code defined by mask.]#[mask]" "\n" "\n[arg ...]\n" "\n" @@ -1475,23 +1489,37 @@ USAGE_LICENSE ; const char sh_optsleep[] = -"[-1c?\n@(#)$Id: sleep (AT&T Research) 1999-04-07 $\n]" +"[-1c?\n@(#)$Id: sleep (AT&T Research) 2009-03-12 $\n]" USAGE_LICENSE "[+NAME?sleep - suspend execution for an interval]" "[+DESCRIPTION?\bsleep\b suspends execution for at least the time specified " - "by \aseconds\a or until a \bSIGALRM\b signal is received. " - "\aseconds\a can be specified as a floating point number but the " - "actual granularity depends on the underlying system, normally " - "around 1 millisecond.]" + "by \aduration\a or until a \bSIGALRM\b signal is received. " + "\aduration\a may be one of the following:]" +"{" + "[+integer?The number of seconds to sleep.]" + "[+floating point?The number of seconds to sleep. The actual " + "granularity depends on the underlying system, normally " + "around 1 millisecond.]" + "[+P\an\a\bY\b\an\a\bM\b\an\a\bDT\b\an\a\bH\b\an\a\bM\b\an\a\bS?An ISO 8601 duration " + "where at least one of the duration parts must be specified.]" + "[+P\an\a\bW?An ISO 8601 duration specifying \an\a weeks.]" + "[+p\an\a\bY\b\an\a\bM\b\an\a\bDT\b\an\a\bH\b\an\a\bm\b\an\a\bS?A case insensitive " + "ISO 8601 duration except that \bM\b specifies months, \bm\b before \bs\b or \bS\b " + "specifies minutes and after specifies milliseconds, \bu\b or \bU\b specifies " + "microseconds, and \bn\b specifies nanoseconds.]" + "[+date/time?Sleep until the \bdate\b(1) compatible date/time.]" +"}" +"[s?Sleep until a signal or a timeout is received. If \aduration\a is omitted " + "or 0 then no timeout will be used.]" "\n" -"\nseconds\n" +"\n[ duration ]\n" "\n" "[+EXIT STATUS?]{" - "[+0?The execution was successfully suspended for at least \atime\a " - "seconds, or a \bSIGALRM\b signal was received.]" + "[+0?The execution was successfully suspended for at least \aduration\a " + "or a \bSIGALRM\b signal was received.]" "[+>0?An error occurred.]" "}" -"[+SEE ALSO?\btime\b(1), \bwait\b(1)]" +"[+SEE ALSO?\bdate\b(1), \btime\b(1), \bwait\b(1)]" ; const char sh_opttrap[] = @@ -1566,9 +1594,10 @@ USAGE_LICENSE "options \b-i\b, \b-E\b, and \b-F\b cannot be specified with " "the justification options \b-L\b, \b-R\b, and \b-Z\b.]" "[+?Note that the following preset aliases are set by the shell:]{" - "[+float?\b\f?\f -E\b.]" + "[+compound?\b\f?\f -C\b.]" + "[+float?\b\f?\f -lE\b.]" "[+functions?\b\f?\f -f\b.]" - "[+integer?\b\f?\f -i\b.]" + "[+integer?\b\f?\f -li\b.]" "[+nameref?\b\f?\f -n\b.]" "}" "[+?If no \aname\as are specified then variables that have the specified " @@ -1640,8 +1669,8 @@ USAGE_LICENSE "[R]#?[n?Right justify. If \an\a is given it represents the field width. If " "the \b-Z\b attribute is also specified, then zeros will " "be used as the fill character. Otherwise, spaces are used.]" -"[X]#?[n:=10?Floating point number represented in hexadecimal notation. " - "\an\a specifies the number of significant figures when the " +"[X]#?[n:=2*sizeof(long long)?Floating point number represented in hexadecimal " + "notation. \an\a specifies the number of significant figures when the " "value is expanded.]" #ifdef SHOPT_TYPEDEF diff --git a/usr/src/lib/libshell/common/data/keywords.c b/usr/src/lib/libshell/common/data/keywords.c index 95e4bee1f6..ccacdb95ee 100644 --- a/usr/src/lib/libshell/common/data/keywords.c +++ b/usr/src/lib/libshell/common/data/keywords.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/data/lexstates.c b/usr/src/lib/libshell/common/data/lexstates.c index 438d58f568..3decd14dbc 100644 --- a/usr/src/lib/libshell/common/data/lexstates.c +++ b/usr/src/lib/libshell/common/data/lexstates.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -399,6 +399,7 @@ const char e_lexobsolete3[] = "line %d: '=' obsolete, use '=='"; const char e_lexobsolete4[] = "line %d: %s within [[...]] obsolete, use ((...))"; const char e_lexobsolete5[] = "line %d: set %s obsolete"; const char e_lexobsolete6[] = "line %d: `{' instead of `in' is obsolete"; +const char e_lexnonstandard[] = "line %d: `&>file' is nonstandard -- interpreted as `>file 2>&1' for profile input only"; const char e_lexusebrace[] = "line %d: use braces to avoid ambiguities with $id[...]"; const char e_lexusequote[] = "line %d: %c within ${} should be quoted"; const char e_lexescape[] = "line %d: escape %c to avoid ambiguities"; diff --git a/usr/src/lib/libshell/common/data/limits.c b/usr/src/lib/libshell/common/data/limits.c index 4c743f7050..ae13d21df5 100644 --- a/usr/src/lib/libshell/common/data/limits.c +++ b/usr/src/lib/libshell/common/data/limits.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/data/math.tab b/usr/src/lib/libshell/common/data/math.tab index 281389f105..412154c23a 100644 --- a/usr/src/lib/libshell/common/data/math.tab +++ b/usr/src/lib/libshell/common/data/math.tab @@ -1,6 +1,6 @@ # <return type: i:integer f:floating-point> <#floating-point-args> <function-name> [<alias> ...] # <function-name>l variants are handled by features/math.sh -# @(#)math.tab (AT&T Research) 2008-05-22 +# @(#)math.tab (AT&T Research) 2009-08-18 f 1 acos f 1 acosh f 1 asin @@ -33,16 +33,21 @@ i 1 isfinite i 2 isgreater i 2 isgreaterequal i 1 isinf +i 1 isinfinite i 2 isless i 2 islessequal i 2 islessgreater i 1 isnan i 1 isnormal -i 1 issubnormal +i 1 issubnormal fpclassify=FP_SUBNORMAL i 2 isunordered -i 1 iszero +i 1 iszero fpclassify=FP_ZERO +f 1 j0 +f 1 j1 +f 2 jn f 1 lgamma f 1 log +f 1 log10 f 1 log1p f 1 log2 f 1 logb @@ -63,3 +68,6 @@ f 1 tan f 1 tanh f 1 tgamma f 1 trunc +f 1 y0 +f 1 y1 +f 2 yn diff --git a/usr/src/lib/libshell/common/data/msg.c b/usr/src/lib/libshell/common/data/msg.c index 3a06ed3f8d..022aa5390d 100644 --- a/usr/src/lib/libshell/common/data/msg.c +++ b/usr/src/lib/libshell/common/data/msg.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -50,6 +50,7 @@ const char e_histopen[] = "history file cannot open"; const char e_option[] = "%s: bad option(s)"; const char e_toomany[] = "open file limit exceeded"; const char e_argtype[] = "invalid argument of type %c"; +const char e_oneoperand[] = "one operand expected"; const char e_formspec[] = "%c: unknown format specifier"; const char e_badregexp[] = "%s: invalid regular expression"; const char e_number[] = "%s: bad number"; @@ -85,6 +86,7 @@ const char e_access[] = "permission denied"; #endif /* _cmd_universe */ const char e_direct[] = "bad directory"; const char e_file[] = "%s: bad file unit number"; +const char e_redirect[] = "redirection failed"; const char e_trap[] = "%s: bad trap"; const char e_readonly[] = "%s: is read only"; const char e_badfield[] = "%d: negative field size"; @@ -93,12 +95,14 @@ const char e_badname[] = "%s: invalid name"; const char e_varname[] = "%s: invalid variable name"; const char e_badfun[] = "%s: invalid function name"; const char e_aliname[] = "%s: invalid alias name"; -const char e_badexport[] = "%s: invalid export name"; +const char e_badexport[] = "%s: only simple variables can be exported"; const char e_badref[] = "%s: reference variable cannot be an array"; +const char e_badsubscript[] = "%c: invalid subscript in assignment"; const char e_noarray[] = "%s: cannot be an array"; const char e_badappend[] = "%s: invalid append to associative array"; const char e_noref[] = "%s: no reference name"; const char e_selfref[] = "%s: invalid self reference"; +const char e_globalref[] = "%s: global reference cannot refer to local variable"; const char e_noalias[] = "%s: alias not found\n"; const char e_format[] = "%s: bad format"; const char e_redef[] = "%s: type cannot be redefined"; diff --git a/usr/src/lib/libshell/common/data/options.c b/usr/src/lib/libshell/common/data/options.c index cd49f6555c..b2894b90e7 100644 --- a/usr/src/lib/libshell/common/data/options.c +++ b/usr/src/lib/libshell/common/data/options.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -127,6 +127,8 @@ const Shtable_t shtab_attributes[] = {"-xexport", NV_EXPORT}, {"-rreadonly", NV_RDONLY}, {"-ttagged", NV_TAGGED}, + {"-Aassociative array", NV_ARRAY}, + {"-aindexed array", NV_ARRAY}, {"-llong", (NV_DOUBLE|NV_LONG)}, {"-Eexponential",(NV_DOUBLE|NV_EXPNOTE)}, {"-Xhexfloat", (NV_DOUBLE|NV_HEXFLOAT)}, @@ -142,8 +144,6 @@ const Shtable_t shtab_attributes[] = {"-Lleftjust", NV_LJUST}, {"-Rrightjust", NV_RJUST}, {"-uuppercase", NV_LTOU}, - {"-Aassociative array", NV_ARRAY}, - {"-aindexed array", NV_ARRAY}, {"++namespace", NV_TABLE}, {"", 0} }; diff --git a/usr/src/lib/libshell/common/data/signals.c b/usr/src/lib/libshell/common/data/signals.c index 7c3df373f9..371ffa2eac 100644 --- a/usr/src/lib/libshell/common/data/signals.c +++ b/usr/src/lib/libshell/common/data/signals.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -34,180 +34,205 @@ #define S(s) ERROR_dictionary(s) /* - * This is a table that gives numbers and default settings to each signal - * The signal numbers go in the low bits and the attributes go in the high bits + * This is a table that gives numbers and default settings to each signal. + * The signal numbers go in the low bits and the attributes go in the high bits. + * The names must be ASCII sorted lo-hi. */ const struct shtable2 shtab_signals[] = { #ifdef SIGABRT - "ABRT", VAL(SIGABRT,SH_SIGDONE), S("Abort"), + "ABRT", VAL(SIGABRT,SH_SIGDONE), S("Abort"), #endif /*SIGABRT */ #ifdef SIGAIO - "AIO", VAL(SIGAIO,SH_SIGIGNORE), S("Asynchronous I/O"), + "AIO", VAL(SIGAIO,SH_SIGIGNORE), S("Asynchronous I/O"), #endif /*SIGAIO */ #ifdef SIGALRM - "ALRM", VAL(SIGALRM,SH_SIGDONE), S("Alarm call"), + "ALRM", VAL(SIGALRM,SH_SIGDONE), S("Alarm call"), +#endif /* SIGALRM */ +#ifdef SIGALRM1 + "ALRM1", VAL(SIGALRM1,SH_SIGDONE), S("Scheduling - reserved"), #endif /* SIGALRM */ #ifdef SIGAPOLLO - "APOLLO", VAL(SIGAPOLLO,0), "SIGAPOLLO"), + "APOLLO", VAL(SIGAPOLLO,0), S("SIGAPOLLO"), #endif /* SIGAPOLLO */ #ifdef SIGBUS - "BUS", VAL(SIGBUS,SH_SIGDONE), S("Bus error"), + "BUS", VAL(SIGBUS,SH_SIGDONE), S("Bus error"), #endif /* SIGBUS */ #ifdef SIGCANCEL - "CANCEL", VAL(SIGCANCEL,SH_SIGIGNORE), S("Thread cancellation"), + "CANCEL", VAL(SIGCANCEL,SH_SIGIGNORE), S("Thread cancellation"), #endif /*SIGCANCEL */ #ifdef SIGCHLD - "CHLD", VAL(SIGCHLD,SH_SIGFAULT), S("Death of Child"), + "CHLD", VAL(SIGCHLD,SH_SIGFAULT), S("Death of Child"), # ifdef SIGCLD # if SIGCLD!=SIGCHLD - "CLD", VAL(SIGCLD,SH_SIGFAULT), S("Death of Child"), + "CLD", VAL(SIGCLD,SH_SIGFAULT), S("Death of Child"), # endif # endif /* SIGCLD */ #else # ifdef SIGCLD - "CLD", VAL(SIGCLD,SH_SIGFAULT), S("Death of Child"), + "CLD", VAL(SIGCLD,SH_SIGFAULT), S("Death of Child"), # endif /* SIGCLD */ #endif /* SIGCHLD */ #ifdef SIGCONT - "CONT", VAL(SIGCONT,SH_SIGIGNORE), S("Stopped process continued"), + "CONT", VAL(SIGCONT,SH_SIGIGNORE), S("Stopped process continued"), #endif /* SIGCONT */ - "DEBUG", VAL(TRAP(SH_DEBUGTRAP),0), "", +#ifdef SIGCPUFAIL + "CPUFAIL", VAL(SIGCPUFAIL,0), S("Predictive processor deconfiguration"), +#endif /* SIGRETRACT */ + "DEBUG", VAL(TRAP(SH_DEBUGTRAP),0), "", #ifdef SIGDANGER - "DANGER", VAL(SIGDANGER,0), S("System crash soon"), + "DANGER", VAL(SIGDANGER,0), S("System crash soon"), #endif /* SIGDANGER */ #ifdef SIGDIL - "DIL", VAL(SIGDIL,0), S("DIL signal"), + "DIL", VAL(SIGDIL,0), S("DIL signal"), #endif /* SIGDIL */ #ifdef SIGEMT - "EMT", VAL(SIGEMT,SH_SIGDONE), S("EMT trap"), + "EMT", VAL(SIGEMT,SH_SIGDONE), S("EMT trap"), #endif /* SIGEMT */ - "ERR", VAL(TRAP(SH_ERRTRAP),0), "", + "ERR", VAL(TRAP(SH_ERRTRAP),0), "", #ifdef SIGERR - "ERR", VAL(SIGERR,0), "", + "ERR", VAL(SIGERR,0), "", #endif /* SIGERR */ - "EXIT", VAL(0,0), "", - "FPE", VAL(SIGFPE,SH_SIGDONE), S("Floating exception"), + "EXIT", VAL(0,0), "", + "FPE", VAL(SIGFPE,SH_SIGDONE), S("Floating exception"), #ifdef SIGFREEZE - "FREEZE", VAL(SIGFREEZE,SH_SIGIGNORE), S("Special signal used by CPR"), + "FREEZE", VAL(SIGFREEZE,SH_SIGIGNORE), S("Special signal used by CPR"), #endif /* SIGFREEZE */ - "HUP", VAL(SIGHUP,SH_SIGDONE), S("Hangup"), - "ILL", VAL(SIGILL,SH_SIGDONE), S("Illegal instruction"), +#ifdef SIGGRANT + "GRANT", VAL(SIGGRANT,0), S("Grant monitor mode"), +#endif /* SIGGRANT */ + "HUP", VAL(SIGHUP,SH_SIGDONE), S("Hangup"), + "ILL", VAL(SIGILL,SH_SIGDONE), S("Illegal instruction"), #ifdef JOBS - "INT", VAL(SIGINT,SH_SIGINTERACTIVE), S("Interrupt"), + "INT", VAL(SIGINT,SH_SIGINTERACTIVE), S("Interrupt"), #else - "INT", VAL(SIGINT,SH_SIGINTERACTIVE), "", + "INT", VAL(SIGINT,SH_SIGINTERACTIVE), "", #endif /* JOBS */ #ifdef SIGIO - "IO", VAL(SIGIO,SH_SIGIGNORE), S("IO signal"), + "IO", VAL(SIGIO,SH_SIGDONE), S("IO signal"), #endif /* SIGIO */ #ifdef SIGIOT - "IOT", VAL(SIGIOT,SH_SIGDONE), S("Abort"), + "IOT", VAL(SIGIOT,SH_SIGDONE), S("Abort"), #endif /* SIGIOT */ #ifdef SIGJVM1 - "JVM1", VAL(SIGJVM1,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), + "JVM1", VAL(SIGJVM1,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), #endif /*SIGJVM1 */ #ifdef SIGJVM2 - "JVM2", VAL(SIGJVM2,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), + "JVM2", VAL(SIGJVM2,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), #endif /*SIGJVM2 */ - "KEYBD", VAL(TRAP(SH_KEYTRAP),0), "", + "KEYBD", VAL(TRAP(SH_KEYTRAP),0), "", #ifdef SIGKILL - "KILL", VAL(SIGKILL,0), S("Killed"), + "KILL", VAL(SIGKILL,0), S("Killed"), #endif /* SIGKILL */ #ifdef SIGLAB - "LAB", VAL(SIGLAB,0), S("Security label changed"), + "LAB", VAL(SIGLAB,0), S("Security label changed"), #endif /* SIGLAB */ #ifdef SIGLOST - "LOST", VAL(SIGLOST,SH_SIGDONE), S("Resources lost"), + "LOST", VAL(SIGLOST,SH_SIGDONE), S("Resources lost"), #endif /* SIGLOST */ #ifdef SIGLWP - "LWP", VAL(SIGLWP,SH_SIGIGNORE), S("Special signal used by thread library"), + "LWP", VAL(SIGLWP,SH_SIGIGNORE), S("Special signal used by thread library"), #endif /* SIGLWP */ +#ifdef SIGMIGRATE + "MIGRATE", VAL(SIGMIGRATE,0), S("Migrate process"), +#endif /* SIGMIGRATE */ +#ifdef SIGMSG + "MSG", VAL(SIGMSG,0), S("Ring buffer input data"), +#endif /* SIGMSG */ #ifdef SIGPHONE - "PHONE", VAL(SIGPHONE,0), S("Phone interrupt"), + "PHONE", VAL(SIGPHONE,0), S("Phone interrupt"), #endif /* SIGPHONE */ #ifdef SIGPIPE #ifdef JOBS - "PIPE", VAL(SIGPIPE,SH_SIGDONE), S("Broken Pipe"), + "PIPE", VAL(SIGPIPE,SH_SIGDONE), S("Broken Pipe"), #else - "PIPE", VAL(SIGPIPE,SH_SIGDONE), "", + "PIPE", VAL(SIGPIPE,SH_SIGDONE), "", #endif /* JOBS */ #endif /* SIGPIPE */ #ifdef SIGPOLL - "POLL", VAL(SIGPOLL,SH_SIGDONE), S("Polling alarm"), + "POLL", VAL(SIGPOLL,SH_SIGDONE), S("Polling alarm"), #endif /* SIGPOLL */ #ifdef SIGPROF - "PROF", VAL(SIGPROF,SH_SIGDONE), S("Profiling time alarm"), + "PROF", VAL(SIGPROF,SH_SIGDONE), S("Profiling time alarm"), #endif /* SIGPROF */ +#ifdef SIGPRE + "PRE", VAL(SIGPRE,SH_SIGDONE), S("Programming exception"), +#endif /* SIGPRE */ #ifdef SIGPWR # if SIGPWR>0 - "PWR", VAL(SIGPWR,SH_SIGIGNORE), S("Power fail"), + "PWR", VAL(SIGPWR,SH_SIGIGNORE), S("Power fail"), # endif #endif /* SIGPWR */ #ifdef SIGQUIT "QUIT", VAL(SIGQUIT,SH_SIGDONE|SH_SIGINTERACTIVE), S("Quit"), #endif /* SIGQUIT */ +#ifdef SIGRETRACT + "RETRACT", VAL(SIGRETRACT,0), S("Relinquish monitor mode"), +#endif /* SIGRETRACT */ #ifdef SIGRTMIN - "RTMIN", VAL(SH_SIGRTMIN,SH_SIGRUNTIME), S("Lowest priority realtime signal"), + "RTMIN", VAL(SH_SIGRTMIN,SH_SIGRUNTIME), S("Lowest priority realtime signal"), #endif /* SIGRTMIN */ #ifdef SIGRTMAX - "RTMAX", VAL(SH_SIGRTMAX,SH_SIGRUNTIME), S("Highest priority realtime signal"), + "RTMAX", VAL(SH_SIGRTMAX,SH_SIGRUNTIME), S("Highest priority realtime signal"), #endif /* SIGRTMAX */ - "SEGV", VAL(SIGSEGV,0), S("Memory fault"), +#ifdef SIGSAK + "SAK", VAL(SIGSAK,0), S("Secure attention key"), +#endif /* SIGSAK */ + "SEGV", VAL(SIGSEGV,0), S("Memory fault"), +#ifdef SIGSOUND + "SOUND", VAL(SIGSOUND,0), S("Sound completed"), +#endif /* SIGSOUND */ #ifdef SIGSTOP - "STOP", VAL(SIGSTOP,0), S("Stopped (SIGSTOP)"), + "STOP", VAL(SIGSTOP,0), S("Stopped (SIGSTOP)"), #endif /* SIGSTOP */ #ifdef SIGSYS - "SYS", VAL(SIGSYS,SH_SIGDONE), S("Bad system call"), + "SYS", VAL(SIGSYS,SH_SIGDONE), S("Bad system call"), #endif /* SIGSYS */ "TERM", VAL(SIGTERM,SH_SIGDONE|SH_SIGINTERACTIVE), S("Terminated"), +#ifdef SIGTHAW + "THAW", VAL(SIGTHAW,SH_SIGIGNORE), S("Special signal used by CPR"), +#endif /* SIGTHAW */ #ifdef SIGTINT # ifdef JOBS - "TINT", VAL(SIGTINT,0), S("Interrupt"), + "TINT", VAL(SIGTINT,0), S("Interrupt"), # else - "TINT", VAL(SIGTINT,0), "". + "TINT", VAL(SIGTINT,0), "", # endif /* JOBS */ #endif /* SIGTINT */ #ifdef SIGTRAP - "TRAP", VAL(SIGTRAP,SH_SIGDONE), S("Trace/BPT trap"), + "TRAP", VAL(SIGTRAP,SH_SIGDONE), S("Trace/BPT trap"), #endif /* SIGTRAP */ #ifdef SIGTSTP - "TSTP", VAL(SIGTSTP,0), S("Stopped"), + "TSTP", VAL(SIGTSTP,0), S("Stopped"), #endif /* SIGTSTP */ #ifdef SIGTTIN - "TTIN", VAL(SIGTTIN,0), S("Stopped (SIGTTIN)"), + "TTIN", VAL(SIGTTIN,0), S("Stopped (SIGTTIN)"), #endif /* SIGTTIN */ #ifdef SIGTTOU - "TTOU", VAL(SIGTTOU,0), S("Stopped(SIGTTOU)"), + "TTOU", VAL(SIGTTOU,0), S("Stopped(SIGTTOU)"), #endif /* SIGTTOU */ #ifdef SIGURG - "URG", VAL(SIGURG,SH_SIGIGNORE), S("Socket interrupt"), + "URG", VAL(SIGURG,SH_SIGIGNORE), S("Socket interrupt"), #endif /* SIGURG */ #ifdef SIGUSR1 - "USR1", VAL(SIGUSR1,SH_SIGDONE), S("User signal 1"), + "USR1", VAL(SIGUSR1,SH_SIGDONE), S("User signal 1"), #endif /* SIGUSR1 */ #ifdef SIGUSR2 - "USR2", VAL(SIGUSR2,SH_SIGDONE), S("User signal 2"), + "USR2", VAL(SIGUSR2,SH_SIGDONE), S("User signal 2"), #endif /* SIGUSR2 */ +#ifdef SIGVIRT + "VIRT", VAL(SIGVIRT,0), S("Virtual timer alarm"), +#endif /* SIGVIRT */ #ifdef SIGVTALRM - "VTALRM", VAL(SIGVTALRM,SH_SIGDONE), S("Virtual time alarm"), + "VTALRM", VAL(SIGVTALRM,SH_SIGDONE), S("Virtual time alarm"), #endif /* SIGVTALRM */ -#ifdef SIGWINCH - "WINCH", VAL(SIGWINCH,SH_SIGIGNORE), S("Window size change"), -#endif /* SIGWINCH */ -#ifdef SIGMIGRATE - "MIGRATE", VAL(SIGMIGRATE,0), S("Migrate process"), -#endif /* SIGMIGRATE */ -#ifdef SIGSOUND - "SOUND", VAL(SIGSOUND,0), S("Sound completed"), -#endif /* SIGSOUND */ -#ifdef SIGTHAW - "THAW", VAL(SIGTHAW,SH_SIGIGNORE), S("Special signal used by CPR"), -#endif /* SIGTHAW */ #ifdef SIGWAITING - "WAITING", VAL(SIGWAITING,SH_SIGIGNORE), S("All threads blocked"), + "WAITING", VAL(SIGWAITING,SH_SIGIGNORE), S("All threads blocked"), #endif /* SIGWAITING */ +#ifdef SIGWINCH + "WINCH", VAL(SIGWINCH,SH_SIGIGNORE), S("Window size change"), +#endif /* SIGWINCH */ #ifdef SIGXCPU "XCPU", VAL(SIGXCPU,SH_SIGDONE|SH_SIGINTERACTIVE), S("Exceeded CPU time limit"), #endif /* SIGXCPU */ diff --git a/usr/src/lib/libshell/common/data/solaris_cmdlist.h b/usr/src/lib/libshell/common/data/solaris_cmdlist.h index 29c75aaa7d..4cb7672636 100644 --- a/usr/src/lib/libshell/common/data/solaris_cmdlist.h +++ b/usr/src/lib/libshell/common/data/solaris_cmdlist.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -70,6 +70,7 @@ extern "C" { /* undo ast_map.h #defines to avoid collision */ #undef basename #undef dirname +#undef mktemp /* Generated data, do not edit. */ XPG4CMDLIST(basename) @@ -82,36 +83,52 @@ ASTCMDLIST(chmod) XPG4CMDLIST(chown) BINCMDLIST(chown) ASTCMDLIST(chown) +BINCMDLIST(cksum) +ASTCMDLIST(cksum) +BINCMDLIST(cmp) ASTCMDLIST(cmp) +BINCMDLIST(comm) ASTCMDLIST(comm) XPG4CMDLIST(cp) ASTCMDLIST(cp) +BINCMDLIST(cut) ASTCMDLIST(cut) XPG4CMDLIST(date) ASTCMDLIST(date) ASTCMDLIST(dirname) +ASTCMDLIST(egrep) XPG4CMDLIST(expr) ASTCMDLIST(expr) ASTCMDLIST(fds) +ASTCMDLIST(fgrep) ASTCMDLIST(fmt) +BINCMDLIST(fold) ASTCMDLIST(fold) +ASTCMDLIST(grep) BINCMDLIST(head) ASTCMDLIST(head) XPG4CMDLIST(id) ASTCMDLIST(id) +BINCMDLIST(join) ASTCMDLIST(join) XPG4CMDLIST(ln) ASTCMDLIST(ln) BINCMDLIST(logname) ASTCMDLIST(logname) +ASTCMDLIST(md5sum) BINCMDLIST(mkdir) ASTCMDLIST(mkdir) BINCMDLIST(mkfifo) ASTCMDLIST(mkfifo) +BINCMDLIST(mktemp) +ASTCMDLIST(mktemp) XPG4CMDLIST(mv) ASTCMDLIST(mv) +BINCMDLIST(paste) ASTCMDLIST(paste) +BINCMDLIST(pathchk) ASTCMDLIST(pathchk) +ASTCMDLIST(readlink) BINCMDLIST(rev) ASTCMDLIST(rev) XPG4CMDLIST(rm) @@ -127,6 +144,7 @@ SBINCMDLIST(sync) BINCMDLIST(sync) ASTCMDLIST(sync) XPG4CMDLIST(tail) +BINCMDLIST(tail) ASTCMDLIST(tail) BINCMDLIST(tee) ASTCMDLIST(tee) @@ -137,6 +155,7 @@ BINCMDLIST(uniq) ASTCMDLIST(uniq) BINCMDLIST(wc) ASTCMDLIST(wc) +ASTCMDLIST(xgrep) /* Mandatory for ksh93 test suite and AST scripts */ BINCMDLIST(getconf) diff --git a/usr/src/lib/libshell/common/data/strdata.c b/usr/src/lib/libshell/common/data/strdata.c index f980c834f3..4642c2826b 100644 --- a/usr/src/lib/libshell/common/data/strdata.c +++ b/usr/src/lib/libshell/common/data/strdata.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/data/testops.c b/usr/src/lib/libshell/common/data/testops.c index e00e4857c9..230ec4cbf8 100644 --- a/usr/src/lib/libshell/common/data/testops.c +++ b/usr/src/lib/libshell/common/data/testops.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -104,6 +104,7 @@ USAGE_LICENSE "open and is associated with a terminal device.]" "[+-u \afile\a?True if \afile\a exists and has its set-user-id bit " "set.]" + "[+-v \avarname\a?True if \avarname\a is a valid variable name that is set.]" "[+-w \afile\a?True if \afile\a exists and is writable.]" "[+-x \afile\a?True if \afile\a exists and is executable. For a " "directory it means that it can be searched.]" @@ -115,7 +116,12 @@ USAGE_LICENSE "it was last read.]" "[+-O \afile\a?True if \afile\a exists and owner is the effective " "user id of the current process.]" + "[+-R \avarname\a?True if \avarname\a is a name reference.]" "[+-S \afile\a?True if \afile\a exists and is a socket.]" +#if SHOPT_FS_3D + "[+-V \afile\a?True if \afile\a exists and is a version " + "directory.]" +#endif /* SHOPT_FS_3D */ "}" "[+?Binary expressions can be one of the following:]{" "[+\astring1\a = \astring2\a?True if \astring1\a is equal to " @@ -156,7 +162,7 @@ USAGE_LICENSE "[+SEE ALSO?\blet\b(1), \bexpr\b(1)]" ; -const char test_opchars[] = "HLNSVOGCaeohrwxdcbfugk" +const char test_opchars[] = "HLNRSVOGCaeohrwxdcbfugkv" #if SHOPT_TEST_L "l" #endif diff --git a/usr/src/lib/libshell/common/data/variables.c b/usr/src/lib/libshell/common/data/variables.c index 65b1985d29..bb8d7441fe 100644 --- a/usr/src/lib/libshell/common/data/variables.c +++ b/usr/src/lib/libshell/common/data/variables.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -47,7 +47,7 @@ const struct shtable2 shtab_variables[] = "EDITOR", 0, (char*)0, "MAILCHECK", NV_NOFREE|NV_INTEGER, (char*)0, "RANDOM", NV_NOFREE|NV_INTEGER, (char*)0, - "ENV", NV_NOFREE, "$HOME/.kshrc", + "ENV", NV_NOFREE, (char*)0, "HISTFILE", 0, (char*)0, "HISTSIZE", 0, (char*)0, "HISTEDIT", NV_NOFREE, (char*)0, @@ -77,6 +77,7 @@ const struct shtable2 shtab_variables[] = "LC_NUMERIC", 0, (char*)0, "FIGNORE", 0, (char*)0, "KSH_VERSION", 0, (char*)0, + "JOBMAX", NV_NOFREE|NV_INTEGER, (char*)0, ".sh", NV_TABLE|NV_RDONLY|NV_NOFREE|NV_NOPRINT,(char*)0, ".sh.edchar", 0, (char*)0, ".sh.edcol", 0, (char*)0, @@ -108,7 +109,7 @@ const struct shtable2 shtab_variables[] = "", 0, (char*)0 }; -const char *nv_discnames[] = { "get", "set", "append", "unset", 0 }; +const char *nv_discnames[] = { "get", "set", "append", "unset", "getn", 0 }; #ifdef SHOPT_STATS const Shtable_t shtab_stats[] = diff --git a/usr/src/lib/libshell/common/edit/completion.c b/usr/src/lib/libshell/common/edit/completion.c index 54b4212470..f90f7af9c6 100644 --- a/usr/src/lib/libshell/common/edit/completion.c +++ b/usr/src/lib/libshell/common/edit/completion.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -24,7 +24,6 @@ */ #include "defs.h" -#include <ctype.h> #include <ast_wchar.h> #include "lexstates.h" #include "path.h" @@ -32,6 +31,31 @@ #include "edit.h" #include "history.h" +#if !SHOPT_MULTIBYTE +#define mbchar(p) (*(unsigned char*)p++) +#endif + +static char *fmtx(const char *string) +{ + register const char *cp = string; + register int n,c; + unsigned char *state = (unsigned char*)sh_lexstates[2]; + int offset; + while((c=mbchar(cp)),(c>UCHAR_MAX)||(n=state[c])==0); + if(n==S_EOF) + return((char*)string); + offset = staktell(); + stakwrite(string,--cp-string); + while(c=mbchar(cp)) + { + if(state[c]) + stakputc('\\'); + stakputc(c); + } + stakputc(0); + return(stakptr(offset)); +} + static int charcmp(int a, int b, int nocase) { if(nocase) @@ -337,7 +361,7 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) { char **savcom = com; while (*com) - size += strlen(cp=sh_fmtq(*com++)); + size += strlen(cp=fmtx(*com++)); com = savcom; } } @@ -364,7 +388,7 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) var = 0; } else - out = strcopy(begin,sh_fmtq(*com)); + out = strcopy(begin,fmtx(*com)); com++; } else @@ -394,7 +418,7 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) out = strcopy(begin,cp); } /* add quotes if necessary */ - if((cp=sh_fmtq(begin))!=begin) + if((cp=fmtx(begin))!=begin) out = strcopy(begin,cp); if(var=='$' && begin[-1]=='{') *out = '}'; @@ -402,11 +426,11 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) *out = ' '; *++out = 0; } - else if(out[-1]=='/' && (cp=sh_fmtq(begin))!=begin) + else if((cp=fmtx(begin))!=begin) { out = strcopy(begin,cp); if(out[-1] =='"' || out[-1]=='\'') - *--out = 0;; + *--out = 0; } if(*begin==0) ed_ringbell(); @@ -416,7 +440,7 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) while (*com) { *out++ = ' '; - out = strcopy(out,sh_fmtq(*com++)); + out = strcopy(out,fmtx(*com++)); } } if(ep->e_nlist) diff --git a/usr/src/lib/libshell/common/edit/edit.c b/usr/src/lib/libshell/common/edit/edit.c index fbee33ca57..7fe6a99c47 100644 --- a/usr/src/lib/libshell/common/edit/edit.c +++ b/usr/src/lib/libshell/common/edit/edit.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -30,7 +30,6 @@ #include <ast.h> #include <errno.h> #include <ccode.h> -#include <ctype.h> #include "FEATURE/options" #include "FEATURE/time" #include "FEATURE/cmds" @@ -43,6 +42,7 @@ # include "defs.h" # include "variables.h" #else +# include <ctype.h> extern char ed_errbuf[]; char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n"; #endif /* KSHELL */ @@ -818,7 +818,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) { if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; - if(ep->sh->winch) + if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS))) { Edpos_t lastpos; int n, rows, newsize; @@ -857,9 +857,12 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) buff[2] = 'a'; return(3); } - buff[0] = cntl('L'); + if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI)) + buff[0] = cntl('L'); return(1); } + else + ep->sh->winch = 0; /* an interrupt that should be ignored */ errno = 0; if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0) diff --git a/usr/src/lib/libshell/common/edit/emacs.c b/usr/src/lib/libshell/common/edit/emacs.c index 02842994ab..8faf4c7856 100644 --- a/usr/src/lib/libshell/common/edit/emacs.c +++ b/usr/src/lib/libshell/common/edit/emacs.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -62,10 +62,11 @@ One line screen editor for any program */ #include <ast.h> -#include <ctype.h> #include "FEATURE/cmds" #if KSHELL # include "defs.h" +#else +# include <ctype.h> #endif /* KSHELL */ #include "io.h" @@ -207,7 +208,9 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) ed_setup(ep->ed,fd,reedit); out = (genchar*)buff; #if SHOPT_MULTIBYTE - out = (genchar*)roundof((char*)out-(char*)0,sizeof(genchar)); + out = (genchar*)roundof(buff-(char*)0,sizeof(genchar)); + if(reedit) + ed_internal(buff,out); #endif /* SHOPT_MULTIBYTE */ if(!kstack) { @@ -907,13 +910,11 @@ static int escape(register Emacs_t* ep,register genchar *out,int count) char buf[MAXLINE]; char *ptr; ptr = hist_word(buf,MAXLINE,(count?count:-1)); -#if !KSHELL if(ptr==0) { beep(); break; } -#endif /* KSHELL */ if ((eol - cur) >= sizeof(name)) { beep(); @@ -1072,6 +1073,7 @@ static int escape(register Emacs_t* ep,register genchar *out,int count) beep(); return(-1); } + return(-1); } diff --git a/usr/src/lib/libshell/common/edit/hexpand.c b/usr/src/lib/libshell/common/edit/hexpand.c index 49444ca464..497f8170d5 100644 --- a/usr/src/lib/libshell/common/edit/hexpand.c +++ b/usr/src/lib/libshell/common/edit/hexpand.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -41,8 +41,6 @@ NoN(hexpand) #else -#include <ctype.h> - static char *modifiers = "htrepqxs&"; static int mod_flags[] = { 0, 0, 0, 0, HIST_PRINT, HIST_QUOTE, HIST_QUOTE|HIST_QUOTE_BR, 0, 0 }; diff --git a/usr/src/lib/libshell/common/edit/history.c b/usr/src/lib/libshell/common/edit/history.c index da875d70c4..b0a3c8db27 100644 --- a/usr/src/lib/libshell/common/edit/history.c +++ b/usr/src/lib/libshell/common/edit/history.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -74,7 +74,6 @@ #include <sfio.h> #include "FEATURE/time" #include <error.h> -#include <ctype.h> #include <ls.h> #if KSHELL # include "defs.h" @@ -82,6 +81,8 @@ # include "path.h" # include "builtins.h" # include "io.h" +#else +# include <ctype.h> #endif /* KSHELL */ #include "history.h" @@ -1071,14 +1072,7 @@ char *hist_word(char *string,int size,int word) register int flag = 0; History_t *hp = hist_ptr; if(!hp) -#if KSHELL - { - strncpy(string,((Shell_t*)hp->histshell)->lastarg,size); - return(string); - } -#else return(NIL(char*)); -#endif /* KSHELL */ hist_copy(string,size,(int)hp->histind-1,-1); for(;c = *cp;cp++) { diff --git a/usr/src/lib/libshell/common/edit/vi.c b/usr/src/lib/libshell/common/edit/vi.c index 391999b5e9..b374aa4b0d 100644 --- a/usr/src/lib/libshell/common/edit/vi.c +++ b/usr/src/lib/libshell/common/edit/vi.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -34,8 +34,8 @@ #else # include <ast.h> # include "FEATURE/options" +# include <ctype.h> #endif /* KSHELL */ -#include <ctype.h> #include "io.h" #include "history.h" @@ -581,7 +581,11 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit vp->U_saved = 0; if(reedit) + { + cur_phys = vp->first_wind; + vp->ofirst_wind = INVALID; refresh(vp,INPUT); + } if(viraw) getline(vp,APPEND); else if(last_virt>=0 && virtual[last_virt]==term_char) @@ -1566,9 +1570,10 @@ static int mvcursor(register Vi_t* vp,register int motion) if(cur_virt>=0 && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt) { virtual[last_virt + 1] = '\0'; - gencpy(&((genchar*)lsearch)[1], virtual); #if SHOPT_MULTIBYTE - ed_external(&((genchar*)lsearch)[1],lsearch+1); + ed_external(virtual,lsearch+1); +#else + strcpy(lsearch+1,virtual); #endif /* SHOPT_MULTIBYTE */ *lsearch = '^'; vp->direction = -2; @@ -2381,13 +2386,11 @@ addin: if(vp->repeat_set==0) vp->repeat = -1; p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat); -#if !KSHELL if(p==0) { ed_ringbell(); break; } -#endif /* KSHELL */ #if SHOPT_MULTIBYTE ed_internal((char*)p,tmpbuf); p = tmpbuf; diff --git a/usr/src/lib/libshell/common/features/math.sh b/usr/src/lib/libshell/common/features/math.sh index 4db6d7b3e3..5d7a498921 100644 --- a/usr/src/lib/libshell/common/features/math.sh +++ b/usr/src/lib/libshell/common/features/math.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -20,10 +20,10 @@ : generate the ksh math builtin table : include math.tab -# @(#)math.sh (AT&T Research) 2008-08-29 +# @(#)math.sh (AT&T Research) 2009-08-18 command=$0 -iffeflags="-n -v -F ast_standards.h" +iffeflags="-n -v" iffehdrs="math.h ieeefp.h" iffelibs="-lm" table=/dev/null @@ -39,6 +39,13 @@ tests= eval `iffe $iffeflags -c "$cc" - typ long.double 2>&$stderr` +: check ast_standards.h + +eval `iffe $iffeflags -F ast_standards.h -c "$cc" - tst use_ast_standards -lm 'note{' 'math.h needs ast_standards.h' '}end' 'link{' '#include <math.h>' '#ifndef isgreater' '#define isgreater(a,b) 0' '#endif' 'int main() { return isgreater(0.0,1.0); }' '}end'` +case $_use_ast_standards in +1) iffeflags="$iffeflags -F ast_standards.h" ;; +esac + : read the table exec < $table @@ -80,13 +87,14 @@ cat <<! typedef Sfdouble_t (*Math_f)(Sfdouble_t,...); ! -echo "#include <ast_standards.h>" +case $_use_ast_standards in +1) echo "#include <ast_standards.h>" ;; +esac echo "#include <math.h>" case $_hdr_ieeefp in -1) echo "#include <ieeefp.h>" - echo - ;; +1) echo "#include <ieeefp.h>" ;; esac +echo : generate the intercept functions and table entries @@ -105,7 +113,23 @@ do eval x='$'_lib_${name}l y='$'_lib_${name} r='$'TYPE_${name} a='$'ARGS_${name} t=double local=$_typ_long_double ;; - *) continue + *) case $aka in + *=*) f=${aka%%=*} + v=${aka#*=} + eval x='$'_lib_${f}l y='$'_lib_${f} + case $x:$y in + 1:*) f=${f}l + ;; + *:1) ;; + *) continue + ;; + esac + L=local_$name r=int R=1 + echo "#ifdef $v${nl}static $r $L(Sfdouble_t x) { return $f(x) == $v; }${nl}#endif" + tab="$tab$nl#ifdef $v$nl$ht\"\\0${R}${a}${name}\",$ht(Math_f)${L},${nl}#endif" + ;; + esac + continue ;; esac eval n='$'_npt_$f m='$'_mac_$f d='$'_dat_$f diff --git a/usr/src/lib/libshell/common/include/argnod.h b/usr/src/lib/libshell/common/include/argnod.h index 7d59fb41f1..524cc49d61 100644 --- a/usr/src/lib/libshell/common/include/argnod.h +++ b/usr/src/lib/libshell/common/include/argnod.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -61,6 +61,8 @@ struct slnod /* struct for link list of stacks */ struct slnod *slnext; struct slnod *slchild; Stak_t *slptr; + /* slpad aligns struct functnod = struct slnod + 1 on some architectures */ + struct slnod *slpad; }; /* diff --git a/usr/src/lib/libshell/common/include/builtins.h b/usr/src/lib/libshell/common/include/builtins.h index 9fc32de97d..900bc35937 100644 --- a/usr/src/lib/libshell/common/include/builtins.h +++ b/usr/src/lib/libshell/common/include/builtins.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -124,6 +124,7 @@ extern const char e_badbase[]; extern const char e_overlimit[]; extern const char e_eneedsarg[]; +extern const char e_oneoperand[]; extern const char e_toodeep[]; extern const char e_badname[]; extern const char e_badsyntax[]; diff --git a/usr/src/lib/libshell/common/include/defs.h b/usr/src/lib/libshell/common/include/defs.h index f5e03fd98e..57c39b6dec 100644 --- a/usr/src/lib/libshell/common/include/defs.h +++ b/usr/src/lib/libshell/common/include/defs.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -37,6 +37,7 @@ #include "fault.h" #include "argnod.h" #include "name.h" +#include <ctype.h> #define _SH_PRIVATE #include <shcmd.h> #undef _SH_PRIVATE @@ -149,6 +150,7 @@ struct limits pid_t bckpid; /* background process id */ \ pid_t cpid; \ pid_t spid; /* subshell process id */ \ + pid_t pipepid; \ int32_t ppid; /* parent process id of shell */ \ int topfd; \ int sigmax; /* maximum number of signals */ \ @@ -167,6 +169,7 @@ struct limits char indebug; /* set when in debug trap */ \ unsigned char lastsig; /* last signal received */ \ char subshare; /* set when in ${..} comsub */ \ + char toomany; /* set when out of fd's */ \ char *readscript; /* set before reading a script */ \ int *inpipe; /* input pipe pointer */ \ int *outpipe; /* output pipe pointer */ \ @@ -226,10 +229,12 @@ struct limits Shopt_t glob_options; \ Namval_t *typeinit; \ int *stats; \ - Namfun_t nvfun; + Namfun_t nvfun; \ + struct Regress_s*regress; #include <shell.h> +#include "regress.h" /* error exits from various parts of shell */ #define NIL(type) ((type)0) @@ -248,8 +253,7 @@ struct limits /* states */ /* low numbered states are same as options */ -#define SH_NOFORK 0 /* set when fork not necessary, not a state */ -#define SH_COMPLETE 0 /* set for command completion */ +#define SH_NOFORK 0 /* set when fork not necessary */ #define SH_FORKED 7 /* set when process has been forked */ #define SH_PROFILE 8 /* set when processing profiles */ #define SH_NOALIAS 9 /* do not expand non-exported aliases */ @@ -262,6 +266,7 @@ struct limits #define SH_TTYWAIT 16 /* waiting for keyboard input */ #define SH_FCOMPLETE 17 /* set for filename completion */ #define SH_PREINIT 18 /* set with SH_INIT before parsing options */ +#define SH_COMPLETE 19 /* set for command completion */ #define SH_BASH 41 #define SH_BRACEEXPAND 42 @@ -335,6 +340,7 @@ struct limits #define MATCH_MAX 64 #define SH_READEVAL 0x4000 /* for sh_eval */ +#define SH_FUNEVAL 0x10000 /* for sh_eval for function load */ extern Shell_t *nv_shell(Namval_t*); extern int sh_addlib(void*); @@ -343,6 +349,7 @@ extern char **sh_argbuild(Shell_t*,int*,const struct comnod*,int); extern struct dolnod *sh_argfree(Shell_t *, struct dolnod*,int); extern struct dolnod *sh_argnew(Shell_t*,char*[],struct dolnod**); extern void *sh_argopen(Shell_t*); +extern struct argnod *sh_argprocsub(Shell_t*,struct argnod*); extern void sh_argreset(Shell_t*,struct dolnod*,struct dolnod*); extern Namval_t *sh_assignok(Namval_t*,int); extern struct dolnod *sh_arguse(Shell_t*); diff --git a/usr/src/lib/libshell/common/include/edit.h b/usr/src/lib/libshell/common/include/edit.h index c477130ed1..3e8fe73f8d 100644 --- a/usr/src/lib/libshell/common/include/edit.h +++ b/usr/src/lib/libshell/common/include/edit.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/env.h b/usr/src/lib/libshell/common/include/env.h index 93db7f5c27..c8b30a2c68 100644 --- a/usr/src/lib/libshell/common/include/env.h +++ b/usr/src/lib/libshell/common/include/env.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/fault.h b/usr/src/lib/libshell/common/include/fault.h index e754ea56eb..97a4280b0d 100644 --- a/usr/src/lib/libshell/common/include/fault.h +++ b/usr/src/lib/libshell/common/include/fault.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/fcin.h b/usr/src/lib/libshell/common/include/fcin.h index b498efa7f2..310cc6693c 100644 --- a/usr/src/lib/libshell/common/include/fcin.h +++ b/usr/src/lib/libshell/common/include/fcin.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/history.h b/usr/src/lib/libshell/common/include/history.h index 53e2b24964..40351707f9 100644 --- a/usr/src/lib/libshell/common/include/history.h +++ b/usr/src/lib/libshell/common/include/history.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/io.h b/usr/src/lib/libshell/common/include/io.h index 4f3d280262..bd2a8bdb87 100644 --- a/usr/src/lib/libshell/common/include/io.h +++ b/usr/src/lib/libshell/common/include/io.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -92,6 +92,7 @@ extern const char e_create[]; extern const char e_tmpcreate[]; extern const char e_exists[]; extern const char e_file[]; +extern const char e_redirect[]; extern const char e_formspec[]; extern const char e_badregexp[]; extern const char e_open[]; diff --git a/usr/src/lib/libshell/common/include/jobs.h b/usr/src/lib/libshell/common/include/jobs.h index 068f0a1abe..513667e1ab 100644 --- a/usr/src/lib/libshell/common/include/jobs.h +++ b/usr/src/lib/libshell/common/include/jobs.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -84,6 +84,9 @@ struct jobs unsigned int in_critical; /* >0 => in critical region */ int savesig; /* active signal */ int numpost; /* number of posted jobs */ +#ifdef SHOPT_BGX + int numbjob; /* number of background jobs */ +#endif /* SHOPT_BGX */ short fd; /* tty descriptor number */ #ifdef JOBS int suspend; /* suspend character */ @@ -116,9 +119,17 @@ extern struct jobs job; #define vmbusy() 0 #endif - #define job_lock() (job.in_critical++) -#define job_unlock() do{if(!--job.in_critical&&job.savesig&&!vmbusy())job_reap(job.savesig);}while(0) +#define job_unlock() \ + do { \ + int sig; \ + if (!--job.in_critical && (sig = job.savesig)) \ + { \ + if (!job.in_critical++ && !vmbusy()) \ + job_reap(sig); \ + job.in_critical--; \ + } \ + } while(0) extern const char e_jobusage[]; extern const char e_done[]; @@ -153,6 +164,9 @@ extern int job_wait(pid_t); extern int job_post(pid_t,pid_t); extern void *job_subsave(void); extern void job_subrestore(void*); +#ifdef SHOPT_BGX +extern void job_chldtrap(Shell_t*, const char*,int); +#endif /* SHOPT_BGX */ #ifdef JOBS extern void job_init(Shell_t*,int); extern int job_close(Shell_t*); diff --git a/usr/src/lib/libshell/common/include/lexstates.h b/usr/src/lib/libshell/common/include/lexstates.h index 77f351c88d..e3f75446e4 100644 --- a/usr/src/lib/libshell/common/include/lexstates.h +++ b/usr/src/lib/libshell/common/include/lexstates.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -138,6 +138,7 @@ extern const char e_lexobsolete3[]; extern const char e_lexobsolete4[]; extern const char e_lexobsolete5[]; extern const char e_lexobsolete6[]; +extern const char e_lexnonstandard[]; extern const char e_lexusebrace[]; extern const char e_lexusequote[]; extern const char e_lexescape[]; diff --git a/usr/src/lib/libshell/common/include/name.h b/usr/src/lib/libshell/common/include/name.h index 60821ee706..80d970055c 100644 --- a/usr/src/lib/libshell/common/include/name.h +++ b/usr/src/lib/libshell/common/include/name.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -107,7 +107,7 @@ struct Ufunction /* attributes of Namval_t items */ /* The following attributes are for internal use */ -#define NV_NOCHANGE (NV_EXPORT|NV_IMPORT|NV_RDONLY|NV_TAGGED|NV_NOFREE) +#define NV_NOCHANGE (NV_EXPORT|NV_IMPORT|NV_RDONLY|NV_TAGGED|NV_NOFREE|NV_ARRAY) #define NV_ATTRIBUTES (~(NV_NOSCOPE|NV_ARRAY|NV_NOARRAY|NV_IDENT|NV_ASSIGN|NV_REF|NV_VARNAME|NV_STATIC)) #define NV_PARAM NV_NODISC /* expansion use positional params */ @@ -115,6 +115,7 @@ struct Ufunction #define NV_TYPE 0x1000000 #define NV_STATIC 0x2000000 #define NV_COMVAR 0x4000000 +#define NV_UNJUST 0x8000000 /* clear justify attributes */ #define NV_FUNCTION (NV_RJUST|NV_FUNCT) /* value is shell function */ #define NV_FPOSIX NV_LJUST /* posix function semantics */ #define NV_FTMP NV_ZFILL /* function source in tmpfile */ @@ -166,12 +167,13 @@ extern int array_maxindex(Namval_t*); extern char *nv_endsubscript(Namval_t*, char*, int); extern Namfun_t *nv_cover(Namval_t*); extern Namarr_t *nv_arrayptr(Namval_t*); +extern int nv_arrayisset(Namval_t*, Namarr_t*); extern int nv_arraysettype(Namval_t*, Namval_t*,const char*,int); extern int nv_aimax(Namval_t*); extern int nv_atypeindex(Namval_t*, const char*); extern int nv_setnotify(Namval_t*,char **); extern int nv_unsetnotify(Namval_t*,char **); -extern void nv_setlist(struct argnod*, int); +extern void nv_setlist(struct argnod*, int, Namval_t*); extern struct argnod* nv_onlist(struct argnod*, const char*); extern void nv_optimize(Namval_t*); extern void nv_outname(Sfio_t*,char*, int); @@ -197,6 +199,7 @@ extern int nv_compare(Dt_t*, Void_t*, Void_t*, Dtdisc_t*); extern void nv_outnode(Namval_t*,Sfio_t*, int, int); extern int nv_subsaved(Namval_t*); extern void nv_typename(Namval_t*, Sfio_t*); +extern void nv_newtype(Namval_t*); extern const Namdisc_t RESTRICTED_disc; extern const Namdisc_t ENUM_disc; @@ -219,6 +222,7 @@ extern const char e_notenum[]; extern const char e_aliname[]; extern const char e_badexport[]; extern const char e_badref[]; +extern const char e_badsubscript[]; extern const char e_noref[]; extern const char e_selfref[]; extern const char e_envmarker[]; @@ -228,4 +232,5 @@ extern const char e_redef[]; extern const char e_required[]; extern const char e_badappend[]; extern const char e_unknowntype[]; +extern const char e_globalref[]; #endif /* _NV_PRIVATE */ diff --git a/usr/src/lib/libshell/common/include/national.h b/usr/src/lib/libshell/common/include/national.h index 542bb583d6..41fe6e5316 100644 --- a/usr/src/lib/libshell/common/include/national.h +++ b/usr/src/lib/libshell/common/include/national.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/nval.h b/usr/src/lib/libshell/common/include/nval.h index def26ebb18..2a4c61f0ac 100644 --- a/usr/src/lib/libshell/common/include/nval.h +++ b/usr/src/lib/libshell/common/include/nval.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -265,6 +265,7 @@ extern Namfun_t *nv_isvtree(Namval_t*); extern Namval_t *nv_lastdict(void); extern Namval_t *nv_mkinttype(char*, size_t, int, const char*, Namdisc_t*); extern void nv_newattr(Namval_t*,unsigned,int); +extern void nv_newtype(Namval_t*); extern Namval_t *nv_open(const char*,Dt_t*,int); extern void nv_putval(Namval_t*,const char*,int); extern void nv_putv(Namval_t*,const char*,int,Namfun_t*); diff --git a/usr/src/lib/libshell/common/include/path.h b/usr/src/lib/libshell/common/include/path.h index 15c4e9694b..39f45e8883 100644 --- a/usr/src/lib/libshell/common/include/path.h +++ b/usr/src/lib/libshell/common/include/path.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -44,7 +44,7 @@ #define PATH_STD_DIR 0100 /* directory is on $(getconf PATH) */ #define PATH_OFFSET 2 /* path offset for path_join */ -#define MAXDEPTH (sizeof(char*)==2?64:2048) /* maximum recursion depth*/ +#define MAXDEPTH (sizeof(char*)==2?64:1024) /* maximum recursion depth*/ /* * path component structure for path searching diff --git a/usr/src/lib/libshell/common/include/regress.h b/usr/src/lib/libshell/common/include/regress.h new file mode 100644 index 0000000000..e47cc2cf17 --- /dev/null +++ b/usr/src/lib/libshell/common/include/regress.h @@ -0,0 +1,66 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2009 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * David Korn + * AT&T Labs + * + * Shell interface private definitions + * + */ + +#ifndef _REGRESS_H +#define _REGRESS_H 1 + +#if SHOPT_REGRESS + +typedef struct Regress_s +{ + Shopt_t options; +} Regress_t; + +#define sh_isregress(r) is_option(&sh.regress->options,r) +#define sh_onregress(r) on_option(&sh.regress->options,r) +#define sh_offregress(r) off_option(&sh.regress->options,r) + +#define REGRESS(r,i,f) do { if (sh_isregress(REGRESS_##r)) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__); } while (0) + +#define REGRESS_egid 1 +#define REGRESS_euid 2 +#define REGRESS_p_suid 3 +#define REGRESS_source 4 +#define REGRESS_etc 5 + +#undef SHOPT_P_SUID +#define SHOPT_P_SUID sh_regress_p_suid(__LINE__, __FILE__) + +extern int b___regress__(int, char**, void*); +extern void sh_regress_init(Shell_t*); +extern void sh_regress(unsigned int, const char*, const char*, unsigned int, const char*); +extern uid_t sh_regress_p_suid(unsigned int, const char*); +extern char* sh_regress_etc(const char*, unsigned int, const char*); + +#else + +#define REGRESS(r,i,f) + +#endif /* SHOPT_REGRESS */ + +#endif /* _REGRESS_H */ diff --git a/usr/src/lib/libshell/common/include/shell.h b/usr/src/lib/libshell/common/include/shell.h index b82e582cfc..d649dbf271 100644 --- a/usr/src/lib/libshell/common/include/shell.h +++ b/usr/src/lib/libshell/common/include/shell.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -137,8 +137,8 @@ struct Shell_s int inlineno; /* line number of current input file */ int exitval; /* most recent exit value */ unsigned char trapnote; /* set when trap/signal is pending */ - char subshell; /* set for virtual subshell */ char shcomp; /* set when runing shcomp */ + short subshell; /* set for virtual subshell */ #ifdef _SH_PRIVATE _SH_PRIVATE #endif /* _SH_PRIVATE */ diff --git a/usr/src/lib/libshell/common/include/shlex.h b/usr/src/lib/libshell/common/include/shlex.h index 8f5277c246..371e01b001 100644 --- a/usr/src/lib/libshell/common/include/shlex.h +++ b/usr/src/lib/libshell/common/include/shlex.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -41,6 +41,7 @@ typedef struct _shlex_ int lastline; /* last line number */ int lasttok; /* previous token number */ int digits; /* numerical value with word token */ + int nonstandard; /* nonstandard construct in profile */ char aliasok; /* on when alias is legal */ char assignok; /* on when name=value is legal */ char inexec; /* on when processing exec */ @@ -110,6 +111,7 @@ typedef struct _shlex_ #define FALLTHRUSYM (SYMAMP|';') #define COOPSYM (SYMAMP|'|') #define IORDWRSYM (SYMGT|'<') +#define IORDWRSYMT (SYMSEMI|'<') #define IOCLOBSYM (SYMPIPE|'>') #define IPROCSYM (SYMLPAR|'<') #define OPROCSYM (SYMLPAR|'>') diff --git a/usr/src/lib/libshell/common/include/shnodes.h b/usr/src/lib/libshell/common/include/shnodes.h index e55cfc42eb..176a0d9e5f 100644 --- a/usr/src/lib/libshell/common/include/shnodes.h +++ b/usr/src/lib/libshell/common/include/shnodes.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -186,6 +186,7 @@ struct arithnod #define IOARITH 0x40000 /* arithmetic seek <# ((expr)) */ #define IOREWRITE 0x80000 /* arithmetic seek <# ((expr)) */ #define IOCOPY IOCLOB /* copy skipped lines onto standard output */ +#define IOPROCSUB IOARITH /* process substitution redirection */ union Shnode_u { diff --git a/usr/src/lib/libshell/common/include/shtable.h b/usr/src/lib/libshell/common/include/shtable.h index 041372b431..f8953f651d 100644 --- a/usr/src/lib/libshell/common/include/shtable.h +++ b/usr/src/lib/libshell/common/include/shtable.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/streval.h b/usr/src/lib/libshell/common/include/streval.h index 4ec3181f15..001f2d1ea1 100644 --- a/usr/src/lib/libshell/common/include/streval.h +++ b/usr/src/lib/libshell/common/include/streval.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -151,13 +151,14 @@ typedef struct _arith_ #define A_JMPZ 44 #define A_JMPNZ 45 #define A_JMP 46 -#define A_CALL0 47 -#define A_CALL1 48 -#define A_CALL2 49 -#define A_CALL3 50 -#define A_DOT 51 -#define A_LIT 52 -#define A_NOTNOT 53 +#define A_CALL1F 47 +#define A_CALL2F 48 +#define A_CALL3F 49 +#define A_CALL1I 50 +#define A_CALL2I 51 +#define A_DOT 52 +#define A_LIT 53 +#define A_NOTNOT 54 /* define error messages */ diff --git a/usr/src/lib/libshell/common/include/terminal.h b/usr/src/lib/libshell/common/include/terminal.h index a0e813c935..7192039013 100644 --- a/usr/src/lib/libshell/common/include/terminal.h +++ b/usr/src/lib/libshell/common/include/terminal.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/test.h b/usr/src/lib/libshell/common/include/test.h index 593bd5852b..1a38632d44 100644 --- a/usr/src/lib/libshell/common/include/test.h +++ b/usr/src/lib/libshell/common/include/test.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -51,8 +51,8 @@ #define TEST_EF 3 #define TEST_NT 10 #define TEST_OT 12 -#define TEST_SLT 15 -#define TEST_SGT 16 +#define TEST_SLT 16 +#define TEST_SGT 17 #define TEST_END 8 #define TEST_REP 20 diff --git a/usr/src/lib/libshell/common/include/timeout.h b/usr/src/lib/libshell/common/include/timeout.h index 803c6b09d2..276cf131a1 100644 --- a/usr/src/lib/libshell/common/include/timeout.h +++ b/usr/src/lib/libshell/common/include/timeout.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/ulimit.h b/usr/src/lib/libshell/common/include/ulimit.h index d5f3b21391..39fedeed78 100644 --- a/usr/src/lib/libshell/common/include/ulimit.h +++ b/usr/src/lib/libshell/common/include/ulimit.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/include/variables.h b/usr/src/lib/libshell/common/include/variables.h index ac9c5a536b..098e8743aa 100644 --- a/usr/src/lib/libshell/common/include/variables.h +++ b/usr/src/lib/libshell/common/include/variables.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -69,40 +69,41 @@ #define LCNUMNOD (sh.bltin_nodes+39) #define FIGNORENOD (sh.bltin_nodes+40) #define VERSIONNOD (sh.bltin_nodes+41) -#define DOTSHNOD (sh.bltin_nodes+42) -#define ED_CHRNOD (sh.bltin_nodes+43) -#define ED_COLNOD (sh.bltin_nodes+44) -#define ED_TXTNOD (sh.bltin_nodes+45) -#define ED_MODENOD (sh.bltin_nodes+46) -#define SH_NAMENOD (sh.bltin_nodes+47) -#define SH_SUBSCRNOD (sh.bltin_nodes+48) -#define SH_VALNOD (sh.bltin_nodes+49) -#define SH_VERSIONNOD (sh.bltin_nodes+50) -#define SH_DOLLARNOD (sh.bltin_nodes+51) -#define SH_MATCHNOD (sh.bltin_nodes+52) -#define SH_COMMANDNOD (sh.bltin_nodes+53) -#define SH_PATHNAMENOD (sh.bltin_nodes+54) -#define SH_FUNNAMENOD (sh.bltin_nodes+55) -#define SH_SUBSHELLNOD (sh.bltin_nodes+56) -#define SH_LEVELNOD (sh.bltin_nodes+57) -#define SH_LINENO (sh.bltin_nodes+58) -#define SH_STATS (sh.bltin_nodes+59) -#define SHLVL (sh.bltin_nodes+60) +#define JOBMAXNOD (sh.bltin_nodes+42) +#define DOTSHNOD (sh.bltin_nodes+43) +#define ED_CHRNOD (sh.bltin_nodes+44) +#define ED_COLNOD (sh.bltin_nodes+45) +#define ED_TXTNOD (sh.bltin_nodes+46) +#define ED_MODENOD (sh.bltin_nodes+47) +#define SH_NAMENOD (sh.bltin_nodes+48) +#define SH_SUBSCRNOD (sh.bltin_nodes+49) +#define SH_VALNOD (sh.bltin_nodes+50) +#define SH_VERSIONNOD (sh.bltin_nodes+51) +#define SH_DOLLARNOD (sh.bltin_nodes+52) +#define SH_MATCHNOD (sh.bltin_nodes+53) +#define SH_COMMANDNOD (sh.bltin_nodes+54) +#define SH_PATHNAMENOD (sh.bltin_nodes+55) +#define SH_FUNNAMENOD (sh.bltin_nodes+56) +#define SH_SUBSHELLNOD (sh.bltin_nodes+57) +#define SH_LEVELNOD (sh.bltin_nodes+58) +#define SH_LINENO (sh.bltin_nodes+59) +#define SH_STATS (sh.bltin_nodes+60) +#define SHLVL (sh.bltin_nodes+61) #if SHOPT_FS_3D -# define VPATHNOD (sh.bltin_nodes+61) +# define VPATHNOD (sh.bltin_nodes+62) # define NFS_3D 1 #else # define NFS_3D 0 #endif /* SHOPT_FS_3D */ #if SHOPT_VPIX -# define DOSPATHNOD (sh.bltin_nodes+61+NFS_3D) -# define VPIXNOD (sh.bltin_nodes+62+NFS_3D) +# define DOSPATHNOD (sh.bltin_nodes+62+NFS_3D) +# define VPIXNOD (sh.bltin_nodes+63+NFS_3D) # define NVPIX (NFS_3D+2) #else # define NVPIX NFS_3D #endif /* SHOPT_VPIX */ #ifdef apollo -# define SYSTYPENOD (sh.bltin_nodes+61+NVPIX) +# define SYSTYPENOD (sh.bltin_nodes+62+NVPIX) #endif /* apollo */ #endif /* SH_VALNOD */ diff --git a/usr/src/lib/libshell/common/include/version.h b/usr/src/lib/libshell/common/include/version.h index 8f025169ff..b22c513e65 100644 --- a/usr/src/lib/libshell/common/include/version.h +++ b/usr/src/lib/libshell/common/include/version.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -17,4 +17,4 @@ * David Korn <dgk@research.att.com> * * * ***********************************************************************/ -#define SH_RELEASE "93t 2008-11-04" +#define SH_RELEASE "93t+ 2009-10-12" diff --git a/usr/src/lib/libshell/common/scripts/cpvprint.sh b/usr/src/lib/libshell/common/scripts/cpvprint.sh new file mode 100644 index 0000000000..bcf2daa985 --- /dev/null +++ b/usr/src/lib/libshell/common/scripts/cpvprint.sh @@ -0,0 +1,185 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# cpvprint - compound variable pretty printer +# + +# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +function prettyprint_compoundvar +{ + nameref var=$1 + + # print tree + str="${ print -v var ; }" + # do some "pretty-printing" for human users (the output is still a + # valid compound variable value) + # (note: This does not scale well with large files) + str="${str//$'\t'typeset -l -E /$'\t'float }" + str="${str//$'\t'typeset -l -i /$'\t'integer }" + str="${str//$'\t'typeset -C /$'\t'compound }" + print -r -- "${str}" + + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${cpvprint_usage}" OPT '-?' + exit 2 +} + +# HTML constants +compound -r hc=( + compound -r doctype=( + compound -r xhtml=( + typeset -r transitional=$'<!DOCTYPE html\n\tPUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n\t"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' + ) + ) + compound -r namespace=( + typeset -r xhtml=$'http://www.w3.org/1999/xhtml' + ) + typeset -r xml_head=$'<?xml version="1.0" encoding="UTF-8"?>\n' +) + +# main +builtin basename + +set -o noglob +set -o errexit +set -o nounset + +# tree variable +compound tree + +typeset progname="${ basename "${0}" ; }" + +typeset -r cpvprint_usage=$'+ +[-?\n@(#)\$Id: cpvprint (Roland Mainz) 2009-06-15 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?cpvprint - render compound variable trees in various formats] +[+DESCRIPTION?\bcpvprint\b is converter which reads a ksh compound + variable and prints it on a different format. Supported + formats are \'default\', \'altdefault\', + \'tree\', \'alttree\', + \'pretty\', \'pretty.html\', \'list\' and \'fulllist\'] + +format [ arguments ] + +[+SEE ALSO?\bksh93\b(1), \bcpvlint\b(1)] +' + +while getopts -a "${progname}" "${cpvprint_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# prechecks +(( $# > 0 )) || usage + +printformat="$1" +shift + +# read variable +case $# in + 0) + read -C tree || fatal_error $"Read error." + ;; + 1) + integer fd + + redirect {fd}<> "$1" || fatal_error $"Cannot open file." + read -u${fd} -C tree || fatal_error $"Read error." + redirect {fd}<&- || fatal_error $"Close error." + ;; + 2) + print -u2 -f $"%s: Unsupported number of arguments.\n" "$0" + exit 1 + ;; +esac + +# print variable +case ${printformat} in + 'default' | 'tree') + print -v tree + ;; + 'altdefault' | 'alttree') + print -C tree + ;; + 'pretty') + # print variable tree (same as $ print -v filetree # except that it "looks better") + prettyprint_compoundvar tree + ;; + 'pretty.html') + printf '%s%s<html xmlns="%s" xml:lang="en" lang="en">\n<head><meta name="generator" content="%H" /><title>%H</title></head>\n<body><pre>%H\n</pre></body></html>\n' \ + "${hc.xml_head}" \ + "${hc.doctype.xhtml.transitional}" \ + "${hc.namespace.xhtml}" \ + "ksh Compound Variable Pretty Printer (cpvprint)" \ + "" \ + "$(prettyprint_compoundvar tree)" | iconv -f "UTF-8" - - + ;; + 'list') + set | egrep '^tree.' | sed 's/^tree\.//' | egrep -v '^[[:alnum:]]+(\.([[:alnum:]\.]+)(\[.*\])*)*=\(' + ;; + 'fulllist') + set | egrep "^tree." + ;; + *) + fatal_error $"Unsupported format." + ;; +esac + +exit 0 +# EOF. diff --git a/usr/src/lib/libshell/common/scripts/crawlsrccomments.sh b/usr/src/lib/libshell/common/scripts/crawlsrccomments.sh index 520d48f118..bdcecd00cf 100644 --- a/usr/src/lib/libshell/common/scripts/crawlsrccomments.sh +++ b/usr/src/lib/libshell/common/scripts/crawlsrccomments.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -44,7 +44,7 @@ fi export LC_NUMERIC=C # constants values for tokenizer/parser stuff -typeset -r ch=( +compound -r ch=( newline=$'\n' tab=$'\t' formfeed=$'\f' @@ -317,7 +317,7 @@ function enumerate_comments_cpp integer content_length integer file_pos # file position - typeset line_pos=( + compound line_pos=( integer x=0 # X position in line integer y=0 # Y position in line (line number) ) @@ -325,20 +325,20 @@ function enumerate_comments_cpp typeset comment - typeset state=( + compound state=( # C comment state typeset in_c_comment=false # C++ comment state - typeset cxx=( + compound cxx=( typeset in_comment=false typeset comment_continued=false # position of current //-pos - typeset comment_pos=( + compound comment_pos=( integer x=-1 integer y=-1 ) # position of previous //-pos - typeset comment_prev_pos=( + compound comment_prev_pos=( integer x=-1 integer y=-1 ) @@ -708,56 +708,99 @@ function cat_http_body return 0 } -function cat_http +function cat_url { typeset protocol="${1%://*}" typeset path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" - - typeset host="${path1%%/*}" - typeset path="${path1#*/}" - typeset port="${host##*:}" + + if [[ "${protocol}" == "file" ]] ; then + cat "${path1}" + return $? + elif [[ "${protocol}" == ~(Elr)http(|s) ]] ; then + typeset host="${path1%%/*}" + typeset path="${path1#*/}" + typeset port="${host##*:}" - integer netfd - typeset -C httpresponse # http response - - # If URL did not contain a port number in the host part then look at the - # protocol to get the port number - if [[ "${port}" == "${host}" ]] ; then - case "${protocol}" in - "http") port=80 ;; - *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; - esac - else - host="${host%:*}" - fi + integer netfd + compound httpresponse # http response + + # If URL did not contain a port number in the host part then look at the + # protocol to get the port number + if [[ "${port}" == "${host}" ]] ; then + case "${protocol}" in + "http") port=80 ;; + "https") port=443 ;; + *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; + esac + else + host="${host%:*}" + fi - printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" + printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" - # prechecks - [[ "${protocol}" == "" ]] && { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } - [[ "${port}" == "" ]] && { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } - [[ "${host}" == "" ]] && { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } - [[ "${path}" == "" ]] && { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } - - # open TCP channel - redirect {netfd}<>"/dev/tcp/${host}/${port}" - (( $? != 0 )) && { print -u2 -f "%s: Couldn't open %s\n" "$0" "${1}" ; return 1 ; } - - # send HTTP request - request="GET /${path} HTTP/1.1\r\n" - request+="Host: ${host}\r\n" - request+="User-Agent: crawlsrccomments/ksh93 (2008-06-14; $(uname -s -r -p))\r\n" - request+="Connection: close\r\n" - print -n -- "${request}\r\n" >&${netfd} + # prechecks + [[ "${protocol}" != "" ]] || { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } + [[ "${port}" != "" ]] || { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } + [[ "${host}" != "" ]] || { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } + [[ "${path}" != "" ]] || { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } + + # open TCP channel + if [[ "${protocol}" == "https" ]] ; then + compound sslfifo + sslfifo.dir="$(mktemp -d)" + sslfifo.in="${sslfifo.dir}/in" + sslfifo.out="${sslfifo.dir}/out" + + # register an EXIT trap and use "errexit" to leave it at the first error + # (this saves lots of if/fi tests for error checking) + trap "rm -r \"${sslfifo.dir}\"" EXIT + set -o errexit + + mkfifo "${sslfifo.in}" "${sslfifo.out}" + + # create async openssl child to handle https + openssl s_client -quiet -connect "${host}:${port}" <"${sslfifo.in}" >>"${sslfifo.out}" & + + # send HTTP request + request="GET /${path} HTTP/1.1\r\n" + request+="Host: ${host}\r\n" + request+="User-Agent: crawlsrccomments/ksh93(ssl) (2009-05-08; $(uname -s -r -p))\r\n" + request+="Connection: close\r\n" + print -n -- "${request}\r\n" >> "${sslfifo.in}" + + # collect response and send it to stdout + { + parse_http_response httpresponse + cat_http_body "${httpresponse.transfer_encoding}" + } <"${sslfifo.out}" + + wait || { print -u2 -f "%s: openssl failed.\n" ; exit 1 ; } + + return 0 + else + redirect {netfd}<> "/dev/tcp/${host}/${port}" + (( $? != 0 )) && { print -u2 -f "%s: Could not open %s\n" "$0" "${1}" ; return 1 ; } + + # send HTTP request + request="GET /${path} HTTP/1.1\r\n" + request+="Host: ${host}\r\n" + request+="User-Agent: crawlsrccomments/ksh93 (2009-05-08; $(uname -s -r -p))\r\n" + request+="Connection: close\r\n" + print -n -- "${request}\r\n" >&${netfd} - # collect response and send it to stdout - parse_http_response httpresponse <&${netfd} - cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} + # collect response and send it to stdout + parse_http_response httpresponse <&${netfd} + cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} - # close connection - redirect {netfd}<&- - - return 0 + # close connection + redirect {netfd}<&- + + return 0 + fi + else + return 1 + fi + # notreached } function print_stats @@ -765,7 +808,7 @@ function print_stats set -o errexit # gather some statistics - typeset stats=( + compound stats=( integer files_with_comments=0 integer files_without_comments=0 @@ -797,7 +840,7 @@ function print_stats (( stats.total_num_files++ )) done - printf "%B\n" stats + print -v stats return 0 } @@ -951,7 +994,7 @@ function do_crawl { set -o errexit - typeset options=( + compound options=( integer max_filesize_for_scan=$((256*1024)) integer max_num_comments=$((2**62)) # FIXME: This should be "+Inf" (=Infinite) ) @@ -967,7 +1010,7 @@ function do_crawl done shift $((OPTIND-1)) - typeset scan=( + compound scan=( typeset -A records ) @@ -978,8 +1021,7 @@ function do_crawl done # print compound variable array (we strip the "typeset -A records" for now) - printf "%B\n" scan | - sed $'s/^#.*$//;s/^\(//;s/^\)//;s/^\ttypeset -A records=\(//;s/^\t\)//' >"crawlsrccomments_extracted_comments.cpv" + print -v scan >"crawlsrccomments_extracted_comments.cpv" print "# Wrote results to crawlsrccomments_extracted_comments.cpv" @@ -991,22 +1033,20 @@ function do_getcomments set -o errexit # vars - typeset scan=( - typeset -A records - ) + compound scan typeset database typeset tmp - typeset options=( + compound options=( typeset database="crawlsrccomments_extracted_comments.cpv" typeset print_stats=false typeset zapduplicates=false - typeset filepattern=( + compound filepattern=( typeset accept="*" typeset reject="" ) - typeset commentpattern=( + compound commentpattern=( typeset accept="~(Ei)(license|copyright)" typeset reject="" ) @@ -1035,11 +1075,11 @@ function do_getcomments trap 'set -o errexit ; print -u2 "# Cleaning up..." ; ((${#tmpfiles[@]} > 0)) && rm -- "${tmpfiles[@]}" ; print -u2 "# Done."' EXIT # Support for HTTP URLs - if [[ "${options.database}" == ~(El)http://.* ]] ; then - database="/tmp/extract_license_cat_http_${PPID}_$$.tmp" + if [[ "${options.database}" == ~(El)(http|https)://.* ]] ; then + database="/tmp/extract_license_cat_url_${PPID}_$$.tmp" tmpfiles+=( "${database}" ) print -u2 "# Loading URL..." - cat_http "${options.database}" >"${database}" + cat_url "${options.database}" >"${database}" print -u2 "# Loading URL done." else database="${options.database}" @@ -1071,11 +1111,7 @@ function do_getcomments # Read compound variable which contain all recorded comments print -u2 "# reading records..." - { - printf "(" - cat "${database}" - printf ")\n" - } | read -C scan.records || fatal_error 'Error reading data.' + read -C scan <"${database}" || fatal_error 'Error reading data.' print -u2 -f "# reading %d records done.\n" "${#scan.records[@]}" # print comments @@ -1105,7 +1141,7 @@ function usage } typeset -r do_getcomments_usage=$'+ -[-?\n@(#)\$Id: getcomments (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: getcomments (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [+NAME?getcomments - extract license information from source files] [+DESCRIPTION?\bgetcomments\b is a small utilty script which extracts @@ -1117,7 +1153,7 @@ typeset -r do_getcomments_usage=$'+ the comments and stores this information in a "database" file called "crawlsrccomments_extracted_comments.cpv" and then \bextract_license\b allows queries on this database.] -[D:database?Database file for input (either file or http://-URL).]:[database] +[D:database?Database file for input (either file, http:// or https://-URL).]:[database] [l:acceptfilepattern?Process only files which match pattern.]:[pattern] [L:rejectfilepattern?Process only files which do not match pattern.]:[pattern] [c:acceptcommentpattern?Match comments which match pattern. Defaults to ~(Ei)(license|copyright)]:[pattern] @@ -1128,7 +1164,7 @@ typeset -r do_getcomments_usage=$'+ ' typeset -r do_crawl_usage=$'+ -[-?\n@(#)\$Id: crawl (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: crawl (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [+NAME?crawl - crawl comment information from source files] [+DESCRIPTION?\bcrawl\b is a small utilty script which reads @@ -1144,7 +1180,7 @@ typeset -r do_crawl_usage=$'+ ' typeset -r crawlsrccomments_usage=$'+ -[-?\n@(#)\$Id: crawlsrccomments (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: crawlsrccomments (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [+NAME?crawlsrccomments - extract and filter comment information from source files] [+DESCRIPTION?\bcrawlsrccomments\b is a small utilty script which reads diff --git a/usr/src/lib/libshell/common/scripts/filetree1.sh b/usr/src/lib/libshell/common/scripts/filetree1.sh index 6946fca4fb..243c9758cf 100644 --- a/usr/src/lib/libshell/common/scripts/filetree1.sh +++ b/usr/src/lib/libshell/common/scripts/filetree1.sh @@ -60,8 +60,8 @@ function do_directory typeset i typeset dummy - typeset -A tree.files - typeset -A tree.dirs + typeset -C -A tree.files + typeset -C -A tree.dirs find "${basedir}"/* -prune 2>/dev/null | while read i ; do dirname="$(dirname "$i")" @@ -169,7 +169,7 @@ builtin uname typeset progname="${ basename "${0}" ; }" typeset -r filetree1_usage=$'+ -[-?\n@(#)\$Id: filetree1 (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: filetree1 (Roland Mainz) 2009-05-06 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?filetree1 - file tree demo] @@ -177,7 +177,7 @@ typeset -r filetree1_usage=$'+ which accepts a directory name as input, and then builds tree nodes for all files+directories and stores all file attributes in these notes and then outputs the tree in the format - specified by viewmode (either "list", "namelist" or "tree")..] + specified by viewmode (either "list", "namelist", "tree" or "compacttree")..] viewmode dirs @@ -195,7 +195,7 @@ shift $((OPTIND-1)) typeset viewmode="$1" shift -if [[ "${viewmode}" != ~(Elr)(list|namelist|tree) ]] ; then +if [[ "${viewmode}" != ~(Elr)(list|namelist|tree|compacttree) ]] ; then fatal_error $"Invalid view mode \"${viewmode}\"." fi @@ -216,7 +216,10 @@ case "${viewmode}" in typeset + | egrep "^myfiletree\[" ;; tree) - printf "%B\n" myfiletree + print -v myfiletree + ;; + compacttree) + print -C myfiletree ;; *) fatal_error $"Invalid view mode \"${viewmode}\"." diff --git a/usr/src/lib/libshell/common/scripts/gnaw.sh b/usr/src/lib/libshell/common/scripts/gnaw.sh index 880e18118b..878f2899ac 100644 --- a/usr/src/lib/libshell/common/scripts/gnaw.sh +++ b/usr/src/lib/libshell/common/scripts/gnaw.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -926,7 +926,7 @@ builtin wc typeset progname="${ basename "${0}" ; }" # terminal size rect -typeset -C termsize=( +compound termsize=( integer columns=-1 integer lines=-1 ) @@ -942,7 +942,7 @@ integer game_use_colors=0 integer game_use_unicode=0 typeset -r gnaw_usage=$'+ -[-?\n@(#)\$Id: gnaw (Roland Mainz) 2008-11-04 \$\n] +[-?\n@(#)\$Id: gnaw (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?gnaw - maze game written in ksh93] [+DESCRIPTION?\bgnaw\b is a maze game. diff --git a/usr/src/lib/libshell/common/scripts/mandelbrotset1.sh b/usr/src/lib/libshell/common/scripts/mandelbrotset1.sh index 2b01d33f4e..b9ae173df9 100644 --- a/usr/src/lib/libshell/common/scripts/mandelbrotset1.sh +++ b/usr/src/lib/libshell/common/scripts/mandelbrotset1.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -71,12 +71,6 @@ function get_term_size return 0 } -function print_color -{ - print -r -n -- "${symbollist:${1}:1}" - return 0 -} - function mandelbrot { nameref result=$1 @@ -109,16 +103,19 @@ function mandelbrot function loop_serial { integer value + typeset line="" for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen} - print_color ${value} + line+="${symbollist:value:1}" done - print + line+=$'\n' done - + + print -r -- "${line}" + return 0 } @@ -128,6 +125,7 @@ function loop_parallel integer numjobs=0 # the following calculation suffers from rounding errors integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) )) + typeset tmpjobdir printmsg $"# lines_per_job=${lines_per_job}" printmsg $"# numcpus=${numcpus}" @@ -135,16 +133,15 @@ function loop_parallel # "renice" worker jobs set -o bgnice - if [[ "${TMPDIR}" == "" ]] ; then - TMPDIR="/tmp" - fi + tmpjobdir="$(mktemp --default=/tmp --directory "mandelbrotset1${PPID}_$$_XXXXXX")" || fatal_error $"Could not create temporary directory." + trap "rm -r ${tmpjobdir}" EXIT # cleanup # try to generate a job identifer prefix which is unique across multiple hosts jobident="job_host_$(uname -n)pid_$$_ppid${PPID}" printmsg $"## prepare..." for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do - rm -f "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + rm -f "${tmpjobdir}/${jobident}_child_$y.joboutput" (( numjobs++ )) done @@ -153,15 +150,21 @@ function loop_parallel for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do ( integer value + typeset line="" + # save file name since we're going to modify "y" + typeset filename="${tmpjobdir}/${jobident}_child_$y.joboutput" for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen} - print_color ${value} + line+="${symbollist:value:1}" done - print - done >"${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + line+=$'\n' + done + print -r -- "${line}" >"${filename}" + + exit 0 ) & done @@ -170,8 +173,8 @@ function loop_parallel printmsg $"## output:" for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do - print -- "$( < "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput")" - rm "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + print -r -- "$( < "${tmpjobdir}/${jobident}_child_$y.joboutput")" + # EXIT trap will cleanup temporary files done return 0 @@ -189,6 +192,10 @@ builtin basename builtin cat builtin rm builtin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names +builtin mktemp + +set -o noglob +set -o nounset typeset progname="${ basename "${0}" ; }" @@ -203,7 +210,7 @@ float stepwidth integer numcpus # terminal size rect -typeset -C termsize=( +compound termsize=( integer columns=-1 integer lines=-1 ) @@ -221,7 +228,7 @@ numcpus=16 (( m_width=termsize.columns-1 , m_height=termsize.lines-2 )) typeset -r mandelbrotset1_usage=$'+ -[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2008-11-04 \$\n] +[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2009-06-14 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93] [+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator @@ -247,7 +254,9 @@ while getopts -a "${progname}" "${mandelbrotset1_usage}" OPT ; do m) max_mag="${OPTARG}" ;; p) stepwidth="${OPTARG}" ;; S) mode="serial" ;; + +S) mode="parallel" ;; P) mode="parallel" ;; + +P) mode="serial" ;; M) mode="${OPTARG}" ;; C) numcpus="${OPTARG}" ;; *) usage ;; diff --git a/usr/src/lib/libshell/common/scripts/multifollow.sh b/usr/src/lib/libshell/common/scripts/multifollow.sh index d0323ef915..b5d5cb7bb2 100644 --- a/usr/src/lib/libshell/common/scripts/multifollow.sh +++ b/usr/src/lib/libshell/common/scripts/multifollow.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -64,7 +64,7 @@ builtin cat typeset progname="$(basename "${0}")" typeset -r multifollow_usage=$'+ -[-?\n@(#)\$Id: multifollow (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: multifollow (Roland Mainz) 2009-04-08 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?multifollow - use tail -f on multiple files] [+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow" multiple @@ -109,7 +109,7 @@ for (( ; $# > 0 ; numfiles++ )) ; do ) mkfifo "${files[${numfiles}].pipename}" - redirect {files[numfiles].fd}<>"${files[numfiles].pipename}" + redirect {files[numfiles].fd}<> "${files[numfiles].pipename}" tail -f "${files[${numfiles}].name}" >"${files[${numfiles}].pipename}" & files[${numfiles}].childpid=$! diff --git a/usr/src/lib/libshell/common/scripts/numtree1.sh b/usr/src/lib/libshell/common/scripts/numtree1.sh new file mode 100644 index 0000000000..beca4aae76 --- /dev/null +++ b/usr/src/lib/libshell/common/scripts/numtree1.sh @@ -0,0 +1,219 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# numtree1 - basic compound variable tree demo+benchmark +# + +# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +function add_number_to_tree +{ + typeset treename=$1 + integer num=$2 + integer i + typeset nodepath # full name of compound variable + integer -a pe # path elements + + # first built an array containing the names of each path element + # (e.g. "135" results in an array containing "( 1 3 5 )") + for (( i=$(rev <<<$num) ; i > 0 ; i=i/10 )) ; do + pe+=( $((i % 10)) ) + done + + # walk path described via the "pe" array and build nodes if + # there aren't any nodes yet + nodepath="${treename}" + for (( i=0 ; i < ${#pe[@]} ; i++ )) ; do + nameref x="${nodepath}" + [[ ! -v x.node ]] && compound -C -a x.nodes + + nodepath+=".nodes[${pe[i]}]" + done + + # insert element + nameref node="${nodepath}" + [[ ! -v node.elements ]] && integer -a node.elements + node.elements+=( ${num} ) + + return 0 +} + + +# floating-point version of "seq" +function floatseq +{ + float i + float arg1=$1 + float arg2=$2 + float arg3=$3 + + case $# in + 1) + for (( i=1. ; i <= arg1 ; i=i+1. )) ; do + printf "%a\n" i + done + ;; + 2) + for (( i=arg1 ; i <= arg2 ; i=i+1. )) ; do + printf "%a\n" i + done + ;; + 3) + for (( i=arg1 ; i <= arg3 ; i+=arg2 )) ; do + printf "%a\n" i + done + ;; + *) + print -u2 -f "%s: Illegal number of arguments %d\n" "$0" $# + return 1 + ;; + esac + + return 0 +} + + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${numtree1_usage}" OPT '-?' + exit 2 +} + +# main +builtin basename +builtin rev + +set -o noglob +set -o errexit +set -o nounset + +compound base + +compound bench=( + float start + float stop +) + +integer i + +typeset progname="${ basename "${0}" ; }" + +typeset -r numtree1_usage=$'+ +[-?\n@(#)\$Id: numtree1 (Roland Mainz) 2009-08-17 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?numtree1 - generate sorted variable tree containing numbers] +[+DESCRIPTION?\bnumtree1\b is a simple variable tree generator + sorts a given set of numbers into a ksh compound variable tree). + the application supports two different modes: \'seq\' takes + 1-3 arguments to specify the set of numbers via seq(1) and + \'stdin\' reads the numbers from stdin (one per line)] + +method [ arguments ] + +[+SEE ALSO?\bksh93\b(1), \bseq\b(1)] +' + +while getopts -a "${progname}" "${numtree1_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# prechecks +(( $# > 0 )) || usage + +cmd=$1 +shift + +# Read numbers from stdin outside benchmark loop +if [[ ${cmd} == 'stdin' ]] ; then + stdin_numbers="$( cat /dev/stdin )" || fatal_error "stdin read error" +fi + +(( bench.start=SECONDS )) + +case ${cmd} in + "seq") + for i in ${ floatseq "$@" ; } ; do + add_number_to_tree base "${i}" + done + ;; + "stdin") + for i in ${stdin_numbers} ; do + add_number_to_tree base "${i}" + done + ;; + "demo1") + for i in 1 32 33 34 34 38 90 ; do + add_number_to_tree base "${i}" + done + ;; + "demo2") + for (( i=1000000000 ; i < 1000000000+10 ; i++ )) ; do + add_number_to_tree base "$i" + done + ;; + *) + fatal_error "Invalid command ${cmd}." + ;; +esac + +(( bench.stop=SECONDS )) + +print -u2 -f "# time used: %f\n" $((bench.stop - bench.start)) + +# print tree +print -v base + +exit 0 +# EOF. diff --git a/usr/src/lib/libshell/common/scripts/rssread.sh b/usr/src/lib/libshell/common/scripts/rssread.sh index fea8627178..1010a7d873 100644 --- a/usr/src/lib/libshell/common/scripts/rssread.sh +++ b/usr/src/lib/libshell/common/scripts/rssread.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -51,112 +51,223 @@ function fatal_error exit 1 } -# parse HTTP return code, cookies etc. -function parse_http_response -{ - nameref response="$1" - typeset h statuscode statusmsg i - - # we use '\r' as additional IFS to filter the final '\r' - IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> - [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; } - [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n" "$0" ; return 1 ; } - response.statuscode="$statuscode" - response.statusmsg="$statusmsg" - - # skip remaining headers - while IFS='' read -r i ; do - [[ "$i" == $'\r' ]] && break - - # strip '\r' at the end - i="${i/~(Er)$'\r'/}" - - case "$i" in - ~(Eli)Content-Type:.*) - response.content_type="${i/~(El).*:[[:blank:]]*/}" - ;; - ~(Eli)Content-Length:[[:blank:]]*[0-9]*) - integer response.content_length="${i/~(El).*:[[:blank:]]*/}" - ;; - ~(Eli)Transfer-Encoding:.*) - response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" - ;; - esac - done +typeset -T urlconnection_t=( + # public + typeset user_agent="ksh93/urlconnection_t" - return 0 -} + # private variables + typeset protocol + typeset path1 + typeset host + typeset path + typeset port + + compound netfd=( + integer in=-1 # incoming traffic + integer out=-1 # outgoing traffic + ) -function cat_http_body -{ - typeset emode="$1" - typeset hexchunksize="0" - integer chunksize=0 - - if [[ "${emode}" == "chunked" ]] ; then - while IFS=$'\r' read hexchunksize && - [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && - (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do - dd bs=1 count="${chunksize}" 2>/dev/null + # only used for https + compound ssl=( + compound fifo=( + typeset dir="" + typeset in="" + typeset out="" + ) + integer openssl_client_pid=-1 + ) + + # parse HTTP return code, cookies etc. + function parse_http_response + { + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac done - else - cat - fi - - return 0 -} -function cat_http -{ - typeset protocol="${1%://*}" - typeset path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" + return 0 + } + + function cat_http_body + { + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\n' read hexchunksize ; do + hexchunksize="${hexchunksize//$'\r'/}" + [[ "${hexchunksize}" != "" ]] || continue + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]+ ]] || break + (( chunksize=16#${hexchunksize} )) + (( chunksize > 0 )) || break + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi - typeset host="${path1%%/*}" - typeset path="${path1#*/}" - typeset port="${host##*:}" - - integer netfd - typeset -C httpresponse # http response - - # If URL did not contain a port number in the host part then look at the - # protocol to get the port number - if [[ "${port}" == "${host}" ]] ; then - case "${protocol}" in - "http") port=80 ;; - *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; - esac - else - host="${host%:*}" - fi - - printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" - - # prechecks - [[ "${protocol}" == "" ]] && { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } - [[ "${port}" == "" ]] && { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } - [[ "${host}" == "" ]] && { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } - [[ "${path}" == "" ]] && { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } - - # open TCP channel - redirect {netfd}<>"/dev/tcp/${host}/${port}" - (( $? != 0 )) && { print -u2 -f "%s: Couldn't open %s\n" "$0" "${1}" ; return 1 ; } - - # send HTTP request - request="GET /${path} HTTP/1.1\r\n" - request+="Host: ${host}\r\n" - request+="User-Agent: rssread/ksh93 (2008-10-14; $(uname -s -r -p))\r\n" - request+="Connection: close\r\n" - print -n -- "${request}\r\n" >&${netfd} - - # collect response and send it to stdout - parse_http_response httpresponse <&${netfd} - cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} - + return 0 + } + + function init_url + { + _.protocol="${1%://*}" + _.path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" + + if [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then + _.host="${_.path1%%/*}" + _.path="${_.path1#*/}" + _.port="${_.host##*:}" + fi + + return 0 + } + # close connection - redirect {netfd}<&- + function close_connection + { + integer ret + + if (( _.netfd.in != -1 )) ; then + redirect {_.netfd.in}<&- + (( _.netfd.in=-1 )) + fi + + if (( _.netfd.in != _.netfd.out && _.netfd.out != -1 )) ; then + redirect {_.netfd.out}<&- + (( _.netfd.out=-1 )) + fi + + if [[ "${_.protocol}" == "https" ]] ; then + wait ${_.ssl.openssl_client_pid} || { print -u2 -f "%s: openssl failed.\n" ; return 1 ; } + (( _.ssl.openssl_client_pid=-1 )) + + rm -r \"${_.ssl.fifo.dir}\" + _.ssl.fifo.dir="" + fi + + return 0 + } - return 0 -} + function open_connection + { + if [[ "${_.protocol}" == "https" ]] ; then + _.ssl.fifo.dir="$(mktemp -d)" + _.ssl.fifo.in="${_.ssl.fifo.dir}/in" + _.ssl.fifo.out="${_.ssl.fifo.dir}/out" + + # Use "errexit" to leave it at the first error + # (this saves lots of if/fi tests for error checking) + set -o errexit + + mkfifo "${_.ssl.fifo.in}" "${_.ssl.fifo.out}" + + # create async openssl child to handle https + openssl s_client -quiet -connect "${_.host}:${_.port}" <"${_.ssl.fifo.in}" >>"${_.ssl.fifo.out}" & + + _.ssl.openssl_client_pid=$! + else + redirect {_.netfd.in}<> "/dev/tcp/${_.host}/${_.port}" + (( $? != 0 )) && { print -u2 -f "%s: Could not open %s\n" "$0" "${1}" ; return 1 ; } + (( _.netfd.out=_.netfd.in )) + fi + return 0 + } + + function send_request + { + typeset request="$1" + + set -o errexit + + if [[ "${_.protocol}" == "https" ]] ; then + print -n -- "${request}\r\n" >> "${_.ssl.fifo.in}" + + redirect {_.netfd.in}< "${_.ssl.fifo.out}" + else + print -n -- "${request}\r\n" >&${_.netfd.out} + fi + return 0 + } + + function cat_url + { + if [[ "${_.protocol}" == "file" ]] ; then + cat "${_.path1}" + return $? + elif [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then + compound httpresponse # http response + + # If URL did not contain a port number in the host part then look at the + # protocol to get the port number + if [[ "${_.port}" == "${_.host}" ]] ; then + case "${_.protocol}" in + "http") _.port=80 ;; + "https") _.port=443 ;; + *) _.port="$(getent services "${_.protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; + esac + else + _.host="${_.host%:*}" + fi + + printmsg "protocol=${_.protocol} port=${_.port} host=${_.host} path=${_.path}" + + # prechecks + [[ "${_.protocol}" != "" ]] || { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } + [[ "${_.port}" != "" ]] || { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } + [[ "${_.host}" != "" ]] || { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } + [[ "${_.path}" != "" ]] || { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } + + _.open_connection + + # send HTTP request + request="GET /${_.path} HTTP/1.1\r\n" + request+="Host: ${_.host}\r\n" + request+="User-Agent: ${_.user_agent}\r\n" + request+="Connection: close\r\n" + _.send_request "${request}\r\n" + + # collect response and send it to stdout + { + _.parse_http_response httpresponse + _.cat_http_body "${httpresponse.transfer_encoding}" + } <&${_.netfd.in} + + _.close_connection + + return 0 + else + return 1 + fi + # notreached + } +) function html_entity_to_ascii { @@ -448,10 +559,21 @@ function do_rssread LC_TIME="en_US.UTF-8" \ LANG="en_US.UTF-8" - # need extra newline after cat_http to terminate line with $'\n' + # return non-zero exit code for this function if the rss processing below fails + set -o errexit + + urlconnection_t hc + hc.user_agent="rssread/ksh93(ssl) (2009-08-14; $(uname -s -r -p))" + hc.init_url "$1" + + # need extra newline after cat_url to terminate line with $'\n' # to make "xml_tok" happy - { cat_http "$1" ; print ; } | - xml_tok "rsstok_cb" + data="${ hc.cat_url ; print ; }" + + print -u2 -f "# Got %d lines of RSS data, processing...\n" "${ wc -l <<< "${data}" ; }" + + xml_tok "rsstok_cb" <<< "${data}" + return 0 } @@ -465,6 +587,7 @@ function usage # make sure we use the ksh93 builtin versions builtin basename builtin cat +builtin mkfifo typeset -A rsstok_cb # callbacks for xml_tok rsstok_cb["tag_begin"]="handle_rss" @@ -488,11 +611,14 @@ bookmark_urls=( ["google_blogs_ksh"]="http://blogsearch.google.com/blogsearch_feeds?hl=en&scoring=d&q=(%22ksh93%22%7C%22ksh+93%22+%7C+%22korn93%22+%7C+%22korn+93%22)&ie=utf-8&num=100&output=rss" # OpenSolaris.org sites ["ksh93_integration"]="http://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml" + ["ksh93_integration_ssl"]="https://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml" ["shell"]="http://www.opensolaris.org/rss/os/project/shell/announcements/rss2.xml" ["systemz"]="http://www.opensolaris.org/rss/os/project/systemz/announcements/rss2.xml" + ["systemz_ssl"]="https://www.opensolaris.org/rss/os/project/systemz/announcements/rss2.xml" # some Sun staff/sites ["blogs_sun_com"]="http://blogs.sun.com/main/feed/entries/rss" ["bigadmin"]="http://www.sun.com/bigadmin/content/rss/motd.xml" + ["bigadmin_scripts"]="https://www.sun.com/bigadmin/content/rss/scripts.xml" ["jmcp"]="http://www.jmcp.homeunix.com/roller/jmcp/feed/entries/rss" ["katakai"]="http://blogs.sun.com/katakai/feed/entries/rss" ["alanc"]="http://blogs.sun.com/alanc/feed/entries/rss" @@ -502,12 +628,13 @@ bookmark_urls=( ["theregister_uk"]="http://www.theregister.co.uk/headlines.rss" ["heise"]="http://www.heise.de/newsticker/heise.rdf" ["slashdot"]="http://rss.slashdot.org/Slashdot/slashdot" + ["wikipedia_command_shells"]="http://en.wikipedia.org/w/index.php?title=Comparison_of_command_shells&feed=rss&action=history" ) typeset progname="${ basename "${0}" ; }" typeset -r rssread_usage=$'+ -[-?\n@(#)\$Id: rssread (Roland Mainz) 2008-11-10 \$\n] +[-?\n@(#)\$Id: rssread (Roland Mainz) 2009-08-14 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?rssread - fetch RSS messages and convert them to plain text] diff --git a/usr/src/lib/libshell/common/scripts/shircbot.sh b/usr/src/lib/libshell/common/scripts/shircbot.sh index 2ce067ad6c..3c99355222 100644 --- a/usr/src/lib/libshell/common/scripts/shircbot.sh +++ b/usr/src/lib/libshell/common/scripts/shircbot.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -55,7 +55,7 @@ function fatal_error # Definition for a IRC session class typeset -T ircsession_t=( - typeset -C server=( + compound server=( typeset name integer port ) @@ -74,7 +74,7 @@ typeset -T ircsession_t=( _.server.port=$2 _.nick=$3 - redirect {_.fd}<>"/dev/tcp/${_.server.name}/${_.server.port}" + redirect {_.fd}<> "/dev/tcp/${_.server.name}/${_.server.port}" (( $? == 0 )) || { print -n2 $"Could not open server connection." ; return 1 ; } printf "fd=%d\n" _.fd @@ -111,9 +111,7 @@ typeset -T ircsession_t=( linebuf_t serverbuf linebuf_t clientbuf integer fd=${_.fd} - - set -o xtrace - + _.login while ${_.running} ; do @@ -148,13 +146,13 @@ typeset -T ircsession_t=( case "${line}" in ~(El)PING) - typeset -C ping_args=( + compound ping_args=( line="$line" ) _.serverevent_ping "ping_args" ;; ~(El):.*\ PRIVMSG) - typeset -C privmsg_args=( + compound privmsg_args=( typeset line="$line" typeset msguser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" typeset msgchannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" @@ -163,7 +161,7 @@ typeset -T ircsession_t=( _.serverevent_privmsg "privmsg_args" ;; ~(El):.*\ INVITE) - typeset -C invite_args=( + compound invite_args=( typeset line="$line" typeset inviteuser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" typeset invitenick="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" @@ -270,7 +268,7 @@ builtin sum typeset progname="${ basename "${0}" ; }" typeset -r shircbot_usage=$'+ -[-?\n@(#)\$Id: shircbot (Roland Mainz) 2008-10-31 \$\n] +[-?\n@(#)\$Id: shircbot (Roland Mainz) 2009-09-09 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?shircbot - simple IRC bot demo] @@ -282,7 +280,7 @@ typeset -r shircbot_usage=$'+ [+SEE ALSO?\bksh93\b(1)] ' -typeset -C config=( +compound config=( typeset nickname="${LOGNAME}bot" typeset servername="irc.freenode.net" integer port=6667 @@ -306,6 +304,8 @@ if (( ${#config.join_channels[@]} == 0 )) ; then config.join_channels+=( "#opensolaris" ) config.join_channels+=( "#opensolaris-dev" ) config.join_channels+=( "#opensolaris-arc" ) + config.join_channels+=( "#opensolaris-meeting" ) + config.join_channels+=( "#ospkg" ) config.join_channels+=( "#ksh" ) elif [[ "${config.servername}" == ~(E)irc.(sfbay|sweden) ]] ; then config.join_channels+=( "#onnv" ) @@ -344,9 +344,9 @@ function mybot.serverevent_privmsg case "$msg" in ~(Eli)date) - _.send_privmsg "$msgchannel" "$( - ( printf "%(%Y-%m-%d, %Th/%Z)T\n" ) - )" + _.send_privmsg "$msgchannel" "${ + printf "%(%Y-%m-%d, %Th/%Z)T\n" + }" ;; ~(Eli)echo) _.send_privmsg "$msgchannel" "${msg#*echo}" @@ -358,10 +358,10 @@ function mybot.serverevent_privmsg fi ;; ~(Eli)help) - _.send_privmsg "$msgchannel" "$( + _.send_privmsg "$msgchannel" "${ printf "Hello, this is shircbot, written in ksh93 (%s). " "${.sh.version}" printf "Subcommands are 'say hello', 'math <math-expr>', 'stocks', 'uuid', 'date' and 'echo'." - )" + }" ;; ~(Eli)math) if [[ "${msg}" == ~(E)[\`\$] ]] ; then @@ -371,9 +371,9 @@ function mybot.serverevent_privmsg typeset mathexpr="${msg#*math}" printf "Calculating '%s'\n" "${mathexpr}" - _.send_privmsg "$msgchannel" "$( - ( printf 'export PATH=/usr/$RANDOM/foo ; set -o restricted ; printf "%%s = %%.40g\n" "%s" $(( %s ))\n' "${mathexpr}" "${mathexpr}" | source /dev/stdin 2>&1 ) - )" + _.send_privmsg "$msgchannel" "${ + ( printf 'export PATH=/usr/${RANDOM}/$$/${RANDOM}/foo ; set -o restricted ; printf "%%s = %%.40g\n" "%s" $(( %s ))\n' "${mathexpr}" "${mathexpr}" | source /dev/stdin 2>&1 ) + }" fi ;; ~(Eli)say\ hello) @@ -381,15 +381,15 @@ function mybot.serverevent_privmsg ;; ~(Eli)stocks) typeset stockmsg tickersymbol - for tickersymbol in "JAVA" "IBM" "AAPL" "HPQ" ; do + for tickersymbol in "JAVA" "ORCL" "IBM" "AAPL" "HPQ" ; do stockmsg="$( /usr/sfw/bin/wget -q -O /dev/stdout "http://quote.yahoo.com/d/quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=${tickersymbol}" 2>&1 )" _.send_privmsg "$msgchannel" "${tickersymbol}: ${stockmsg//,/ }" done ;; ~(Eli)uuid) - _.send_privmsg "$msgchannel" "$( - ( print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256 ) - )" + _.send_privmsg "$msgchannel" "${ + print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256 + }" ;; esac diff --git a/usr/src/lib/libshell/common/scripts/shlint.sh b/usr/src/lib/libshell/common/scripts/shlint.sh index 640fb14837..aea60a4951 100644 --- a/usr/src/lib/libshell/common/scripts/shlint.sh +++ b/usr/src/lib/libshell/common/scripts/shlint.sh @@ -66,7 +66,7 @@ builtin basename typeset progname="${ basename "${0}" ; }" typeset -r shlint_usage=$'+ -[-?\n@(#)\$Id: shlint (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: shlint (Roland Mainz) 2009-03-15 \$\n] [-author?Roland Mainz <roland.mainz@sun.com>] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?shlint - lint for POSIX shell scripts] @@ -82,13 +82,15 @@ while getopts -a "${progname}" "${shlint_usage}" OPT ; do done shift $((OPTIND-1)) +(( $# > 0 )) || usage + file="$1" [[ ! -f "$file" ]] && fatal_error $"File ${file} not found." [[ ! -r "$file" ]] && fatal_error $"File ${file} not readable." -x="$( /usr/bin/ksh93 -n "${file}" 2>&1 1>/dev/null )" +x="$( /usr/bin/shcomp -n "${file}" /dev/null 2>&1 1>/dev/null )" -printf "%s" "$x" +printf "%s\n" "$x" [[ "$x" != "" ]] && exit 1 || exit 0 # EOF. diff --git a/usr/src/lib/libshell/common/scripts/shman.sh b/usr/src/lib/libshell/common/scripts/shman.sh index 57e57cec23..56c2e42c12 100644 --- a/usr/src/lib/libshell/common/scripts/shman.sh +++ b/usr/src/lib/libshell/common/scripts/shman.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -174,7 +174,7 @@ function browse_manpage # /usr/bin/man <keyword> function show_manpage { - typeset -a -C mandirs + compound -a mandirs integer i integer j @@ -236,7 +236,7 @@ function show_manpage # /usr/bin/man -l <keyword> function list_manpages { - typeset -a -C mandirs + compound -a mandirs enumerate_mandirs mandirs #debug_print -- "${mandirs[@]}" @@ -320,7 +320,7 @@ builtin date typeset progname="$(basename "${0}")" typeset -r man_usage=$'+ -[-?\n@(#)\$Id: shman (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: shman (Roland Mainz) 2009-06-26 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [-author?Roland Mainz <roland.mainz@sun.com>] [+NAME?man - find and display reference manual pages] @@ -372,16 +372,24 @@ shift $((OPTIND-1)) # cd /usr/man; LC_MESSAGES=C /usr/lib/sgml/sgml2roff /usr/man/sman1as/asadmin-list-timers.1as | tbl | eqn | nroff -u0 -Tlp -man - | col -x > /tmp/mpLQaqac -typeset manname="$1" -debug_print -f "# searching for %s ...\n" "${manname}" +# prechecks +(( $# > 0 )) || usage -if ${do_keyword} ; then - list_keywords -elif ${do_list} ; then - list_manpages -else - show_manpage -fi +# process arguments +while (( $# > 0 )) ; do + typeset manname="$1" + shift + + debug_print -f "# searching for %s ...\n" "${manname}" + + if ${do_keyword} ; then + list_keywords + elif ${do_list} ; then + list_manpages + else + show_manpage + fi +done # todo: better exit codes exit 0 diff --git a/usr/src/lib/libshell/common/scripts/shnote.sh b/usr/src/lib/libshell/common/scripts/shnote.sh index 1361feb8a7..b449f257c0 100644 --- a/usr/src/lib/libshell/common/scripts/shnote.sh +++ b/usr/src/lib/libshell/common/scripts/shnote.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -181,11 +181,11 @@ function print_history fi # open history file - redirect {histfd}<>"${history_file}" - (( $? != 0 )) && { print -u2 "Couldn't open history file." ; return 1 ; } + redirect {histfd}<> "${history_file}" + (( $? != 0 )) && { print -u2 "Could not open history file." ; return 1 ; } while read -u${histfd} line ; do - typeset -C rec + compound rec printf "( %s )\n" "${line}" | read -C rec @@ -213,13 +213,13 @@ function put_note_pastebin_ca typeset url_path="/quiet-paste.php?api=${pastebin_ca_key}" typeset url="http://${url_host}${url_path}" integer netfd # http stream number - typeset -C httpresponse + compound httpresponse (( $# != 1 )) && { print -u2 -f $"%s: Wrong number of arguments.\n" "$0" ; return 1 ; } (( ${#1} == 0 )) && { print -u2 -f $"%s: No data.\n" "$0" ; return 1 ; } # argument for "encode_multipart_form_data" - typeset mimeform=( + compound mimeform=( # input typeset boundary typeset -a form @@ -252,8 +252,8 @@ function put_note_pastebin_ca request+="Content-Type: multipart/form-data; boundary=${boundary}\r\n" request+="Content-Length: $(( mimeform.content_length ))\r\n" - redirect {netfd}<>"/dev/tcp/${url_host}/80" - (( $? != 0 )) && { print -u2 -f $"$0: Couldn't open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } + redirect {netfd}<> "/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } # send http post { @@ -274,7 +274,7 @@ function put_note_pastebin_ca printf "SUCCESS: http://opensolaris.pastebin.ca/%s\n" "${response_token}" # write history entry - typeset histrec=( + compound histrec=( title="${mimeform.form[0].data}" description="${mimeform.form[3].data}" providertoken="${response_token}" @@ -321,8 +321,8 @@ function get_note_pastebin_ca # I hereby curse Solaris for not having an entry for "http" in /etc/services # open TCP channel - redirect {netfd}<>"/dev/tcp/${url_host}/80" - (( $? != 0 )) && { print -u2 -f $"%s: Couldn't open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } + redirect {netfd}<> "/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } # send HTTP request request="GET ${url_path} HTTP/1.1\r\n" @@ -359,14 +359,14 @@ builtin uname typeset progname="${ basename "${0}" ; }" # HTTP protocol client identifer -typeset -r http_user_agent="shnote/ksh93 (2008-10-14; $(uname -s -r -p))" +typeset -r http_user_agent="shnote/ksh93 (2009-05-09; $(uname -s -r -p))" # name of history log (the number after "history" is some kind of version # counter to handle incompatible changes to the history file format) typeset -r history_file="${HOME}/.shnote/history0.txt" typeset -r shnote_usage=$'+ -[-?\n@(#)\$Id: shnote (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: shnote (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?shnote - read/write text data to internet clipboards] [+DESCRIPTION?\bshnote\b is a small utilty which can read and write text diff --git a/usr/src/lib/libshell/common/scripts/shpiano.sh b/usr/src/lib/libshell/common/scripts/shpiano.sh index 4690fee5ed..e20813a75a 100644 --- a/usr/src/lib/libshell/common/scripts/shpiano.sh +++ b/usr/src/lib/libshell/common/scripts/shpiano.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -58,7 +58,7 @@ function beep # array which holds frequency and sample data # (the data are created on demand, "sample_set" indicates whether the "sample" variable # needs to be filled or not) -typeset -A tones=( +compound -A tones=( ["C3"]=( float freq=261.63 ; typeset sample_set="false" ; typeset -b sample ) ["C#3"]=( float freq=277.18 ; typeset sample_set="false" ; typeset -b sample ) ["D3"]=( float freq=293.66 ; typeset sample_set="false" ; typeset -b sample ) @@ -91,7 +91,7 @@ typeset -A tones=( # alias table which translates the various names of "notes" to the matching entry # in the "tones" table -typeset -r -A notes=( +compound -r -A notes=( ["C3"]=( val=tones["C3"] ) ["key_d"]=( val=tones["C3"] ) ["C#3"]=( val=tones["C#3"] ) ["key_r"]=( val=tones["C#3"] ) ["D3"]=( val=tones["D3"] ) ["key_f"]=( val=tones["D3"] ) @@ -1278,18 +1278,24 @@ builtin basename typeset progname="${ basename "${0}" ; }" typeset -r shpiano_usage=$'+ -[-?\n@(#)\$Id: shpiano (Roland Mainz) 2008-11-03 \$\n] +[-?\n@(#)\$Id: shpiano (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] +[-author?Valeria Elisabeth Mainz <valeria.mainz@no.such.email.toddler>] [+NAME?shpiano - simple audio demo] [+DESCRIPTION?\bshpiano\b is a small demo application which converts keyboard input into 8bit Mu-law audio samples which are send to /dev/audio.] +[b:babymode?Mode to entertain toddlers. Plays a sound for any key + and ignores SIGINT. Requires ESC to quit the application.] [+SEE ALSO?\bksh93\b(1), \bau\b(4), \baudio\b(7i)] ' +typeset babymode=false while getopts -a "${progname}" "${shpiano_usage}" OPT ; do # printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" case ${OPT} in + b) babymode=true ;; + +b) babymode=false ;; *) usage ;; esac done @@ -1304,19 +1310,30 @@ float w # temporary "wave" value integer i integer audiofd # audio device file descriptor typeset key -typeset audio=( typeset -i currpos=0 ; typeset -a -i data=( [0]=0 ) ) # stack object +compound audio=( integer currpos=0 ; integer -a data=( [0]=0 ) ) # stack object clear print_piano_layout +if ${babymode} ; then + [[ -x /usr/bin/banner ]] || fatal_error "-n requires /usr/bin/banner" + + typeset lastkeys + + nameref curr_note=tones["A#4"] + (( freq=curr_note.freq )) + + trap "" INT +fi + if [[ "${AUDIODEV}" == "" ]] ; then AUDIODEV="/dev/audio" fi -print -u2 -f $"Playing sound to device\n" "${AUDIODEV}" +print -u2 -f $"Playing sound to device %s\n" "${AUDIODEV}" # open channel to audio device -redirect {audiofd}<>"${AUDIODEV}" -(( $? != 0 )) && fatal_error $"Couldn't open audio device." +redirect {audiofd}<> "${AUDIODEV}" +(( $? != 0 )) && fatal_error $"Could not open audio device." # build pause sample stack_init audio @@ -1332,20 +1349,32 @@ typeset -b au_header=${ bytearraytobase64 audio.data ; } # begin playing printf "%B" au_header >&${audiofd} + # warning: the math used here is so wrong that your head may # explode when you continue reading this while read -r -N 1 key?$'\r > ' ; do - if [[ ${key} == ~(E)($'\E'|'q'|'Q') ]] ; then + if [[ ${key} == $'\E' ]] || [[ ${babymode} != "true" && ${key} == ~(E)($'\E'|'q'|'Q') ]] ; then break # quit fi printf "\r" - if [[ -z "${notes[key_${key}]}" ]] ; then - nameref curr_note=tones["p"] - (( freq=1.*(1./duration) )) - else + if [[ -v notes[key_${key}] ]] ; then nameref curr_note="${notes[key_${key}].val}" (( freq=curr_note.freq )) + else + if ${babymode} ; then + nameref curr_note=tones["A#4"] + (( freq=curr_note.freq )) + else + nameref curr_note=tones["p"] + (( freq=1.*(1./duration) )) + fi + fi + + # babymode: print "keys" to screen via /usr/bin/banner + if ${babymode} ; then + lastkeys="${lastkeys/~(Er).*(........)/\1}${key}" + banner "${lastkeys}" fi # printf "note=%s sample_rate=%f, freq=%f\n" "${!curr_note}" sample_rate freq >&2 diff --git a/usr/src/lib/libshell/common/scripts/shtinyurl.sh b/usr/src/lib/libshell/common/scripts/shtinyurl.sh index 1d3e70bf67..fb18627081 100644 --- a/usr/src/lib/libshell/common/scripts/shtinyurl.sh +++ b/usr/src/lib/libshell/common/scripts/shtinyurl.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -112,7 +112,7 @@ function request_tinyurl typeset url="http://${url_host}${url_path}" integer netfd # http stream number typeset inputurl="$1" - typeset -C httpresponse # http response + compound httpresponse # http response typeset request="" # we assume "inputurl" is a correctly encoded URL which doesn't @@ -124,8 +124,8 @@ function request_tinyurl request+="User-Agent: ${http_user_agent}\r\n" request+="Connection: close\r\n" - redirect {netfd}<>"/dev/tcp/${url_host}/80" - (( $? != 0 )) && { print -u2 -f $"%s: Couldn't open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } + redirect {netfd}<> "/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } # send http post { @@ -150,6 +150,53 @@ function request_tinyurl # not reached } +function request_trimurl +{ + # site setup + typeset url_host="api.tr.im" + typeset url_path="/api/trim_url.xml" + typeset url="http://${url_host}${url_path}" + integer netfd # http stream number + typeset inputurl="$1" + compound httpresponse # http response + typeset request="" + + # we assume "inputurl" is a correctly encoded URL which doesn't + # require any further mangling + url_path+="?url=${inputurl}" + + request="GET ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + + redirect {netfd}<> "/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } + + # send http post + { + print -n -- "${request}\r\n" + } >&${netfd} + + # process reply + parse_http_response httpresponse <&${netfd} + response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" + + # close connection + redirect {netfd}<&- + + if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then + # the statement below should really parse the XML... + print -r -- "${response/~(Elr).*(\<url\>)(.*)(\<\/url\>).*/\2}" + return 0 + else + print -u2 -f $"tr.im response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" + return 1 + fi + + # not reached +} + function usage { OPTIND=0 @@ -166,37 +213,54 @@ builtin uname typeset progname="${ basename "${0}" ; }" # HTTP protocol client identifer -typeset -r http_user_agent="shtinyurl/ksh93 (2008-10-14; ${ uname -s -r -p ; })" +typeset -r http_user_agent="shtinyurl/ksh93 (2009-08-12; ${ uname -s -r -p ; })" typeset -r shtinyurl_usage=$'+ -[-?\n@(#)\$Id: shtinyurl (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: shtinyurl (Roland Mainz) 2009-08-12 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] -[+NAME?shtinyurl - create short tinyurl.com alias URL from long URL] +[+NAME?shtinyurl - create short alias URL from long URL] [+DESCRIPTION?\bshtinyurl\b is a small utility which passes a given URL - to the tinyurl.com service which creates short aliases in the - form of http://tinyurl.com/XXXXXXXX to redirect long URLs.] + to internet service which creates short aliases in the + form of http://<servicename>/XXXXXXXX to redirect long URLs.] [+?The first arg \burl\b describes a long URL which is transformed into a tinyurl.com short alias.] +[P:provider?Service provider (either \'tinyurl.com\' or \'tr.im\').]:[mode] url -[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), http://www.tinyurl.com] +[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), http://www.tinyurl.com, http://tr.im] ' +typeset service_provider="tr.im" + while getopts -a "${progname}" "${shtinyurl_usage}" OPT ; do # printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" case ${OPT} in + P) service_provider="${OPTARG}" ;; *) usage ;; esac done shift $((OPTIND-1)) # expecting at least one more argument -(($# >= 1)) || usage +(( $# >= 1 )) || usage typeset url="$1" shift -request_tinyurl "${url}" -exit $? +case "${service_provider}" in + "tinyurl.com") + request_tinyurl "${url}" + exit $? + ;; + "tr.im") + request_trimurl "${url}" + exit $? + ;; + *) + fatal_error "Unsupported service provider." +esac + +# not reached + # EOF. diff --git a/usr/src/lib/libshell/common/scripts/shtwitter.sh b/usr/src/lib/libshell/common/scripts/shtwitter.sh index 9eca33bcbd..c7672dde6c 100644 --- a/usr/src/lib/libshell/common/scripts/shtwitter.sh +++ b/usr/src/lib/libshell/common/scripts/shtwitter.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -192,12 +192,14 @@ function put_twitter_message typeset url="http://${url_host}${url_path}" integer netfd # http stream number typeset msgtext="$1" - typeset -C httpresponse # http response + compound httpresponse # http response # argument for "encode_x_www_form_urlencoded" - typeset urlform=( + compound urlform=( # input - typeset -a form + compound -a form=( + ( name="status" data="${msgtext}" ) + ) # output typeset content integer content_length @@ -206,10 +208,6 @@ function put_twitter_message typeset request="" typeset content="" - urlform.form=( - ( name="status" data="${msgtext}" ) - ) - encode_x_www_form_urlencoded urlform content="${urlform.content}" @@ -222,7 +220,7 @@ function put_twitter_message request+="Content-Type: application/x-www-form-urlencoded\r\n" request+="Content-Length: $(( urlform.content_length ))\r\n" - redirect {netfd}<>"/dev/tcp/${url_host}/80" + redirect {netfd}<> "/dev/tcp/${url_host}/80" (( $? != 0 )) && { print -u2 -f "%s: Could not open connection to %s\n." "$0" "${url_host}" ; return 1 ; } # send http post @@ -261,7 +259,7 @@ function verify_twitter_credentials typeset url_path="/account/verify_credentials.xml" typeset url="http://${url_host}${url_path}" integer netfd # http stream number - typeset -C httpresponse # http response + compound httpresponse # http response typeset request="" @@ -273,7 +271,7 @@ function verify_twitter_credentials request+="Content-Type: application/x-www-form-urlencoded\r\n" request+="Content-Length: 0\r\n" # dummy - redirect {netfd}<>"/dev/tcp/${url_host}/80" + redirect {netfd}<> "/dev/tcp/${url_host}/80" (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } # send http post @@ -315,10 +313,10 @@ builtin uname typeset progname="${ basename "${0}" ; }" # HTTP protocol client identifer -typeset -r http_user_agent="shtwitter/ksh93 (2008-10-14; ${ uname -s -r -p ; })" +typeset -r http_user_agent="shtwitter/ksh93 (2009-06-15; ${ uname -s -r -p ; })" typeset -r shtwitter_usage=$'+ -[-?\n@(#)\$Id: shtwitter (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: shtwitter (Roland Mainz) 2009-06-15 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?shtwitter - read/write text data to internet clipboards] [+DESCRIPTION?\bshtwitter\b is a small utility which can read and write text diff --git a/usr/src/lib/libshell/common/scripts/simplefileattributetree1.sh b/usr/src/lib/libshell/common/scripts/simplefileattributetree1.sh new file mode 100644 index 0000000000..95a36063dc --- /dev/null +++ b/usr/src/lib/libshell/common/scripts/simplefileattributetree1.sh @@ -0,0 +1,273 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# simplefileattributetree1 - build a simple file tree (including file attributes) +# + +# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + + +function add_file_to_tree +{ + typeset treename=$1 + typeset filename=$2 + nameref destnodename=$3 + integer i + typeset nodepath # full name of compound variable + typeset -a pe # path elements + + # first built an array containing the names of each path element + # (e.g. "foo/var/baz"" results in an array containing "( 'foo' 'bar' 'baz' )") + typeset IFS='/' + pe+=( ${filename} ) + + [[ ${pe[0]} == '' ]] && pe[0]='/' + + # walk path described via the "pe" array and build nodes if + # there aren't any nodes yet + nodepath="${treename}" + for (( i=0 ; i < (${#pe[@]}-1) ; i++ )) ; do + nameref x="${nodepath}" + [[ ! -v x.node ]] && compound -A x.nodes + + nodepath+=".nodes[${pe[i]}]" + done + + # insert element + nameref node="${nodepath}" + [[ ! -v node.elements ]] && compound -A node.elements + node.elements[${pe[i]}]=( + filepath="${filename}" + ) + + destnodename="${!node}.elements[${pe[i]}]" + + return 0 +} + +function parse_findls +{ + nameref out=$1 + typeset str="$2" + + # find -ls on Solaris uses the following output format by default: + #604302 3 -rw-r--r-- 1 test001 users 2678 May 9 00:46 ./httpsresdump + + integer out.inodenum="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\1}" + integer out.kbblocks="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\2}" + typeset out.mode="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\3}" + integer out.numlinks="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\4}" + compound out.owner=( + typeset user="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\5}" + typeset group="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\6}" + ) + integer out.filesize="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\7}" + typeset out.date="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\8}" + typeset out.filepath="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\9}" + + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${simplefileattributetree1_usage}" OPT '-?' + exit 2 +} + +# main +builtin basename +builtin dirname + +set -o noglob +set -o nounset + +# tree base +compound filetree + +# benchmark data +compound bench=( + float start + float stop +) + +compound appconfig=( + typeset do_benchmarking=false + compound do_record=( + typeset content=false + typeset filetype=false + ) +) + + +integer i + +typeset progname="${ basename "${0}" ; }" + +typeset -r simplefileattributetree1_usage=$'+ +[-?\n@(#)\$Id: simplefileattributetree1 (Roland Mainz) 2009-06-26 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?simplefileattributetree1 - generate compound variable tree which contains file names and their attributes] +[+DESCRIPTION?\bsimplefileattributetree1\b is a simple variable tree + demo which builds a compound variable tree based on the output + of /usr/xpg4/bin/file which contains the file name, the file attributes + and optionally file type and content] +[b:benchmark?Print time needed to generate the tree.] +[c:includecontent?Include the file\'s content in the tree, split into 1kb blocks.] +[t:includefiletype?Include the file type (output of /usr/xpg4/bin/file).] + +path + +[+SEE ALSO?\bksh93\b(1), \bfile\b(1), \bfind\b(1)] +' + +while getopts -a "${progname}" "${simplefileattributetree1_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + b) appconfig.do_benchmarking="true" ;; + +b) appconfig.do_benchmarking="false" ;; + c) appconfig.do_record.content="true" ;; + +c) appconfig.do_record.content="false" ;; + t) appconfig.do_record.filetype="true" ;; + +t) appconfig.do_record.filetype="false" ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + + +# argument prechecks +if (( $# == 0 )) ; then + print -u2 -f "%s: Missing <path> argument.\n" "${progname}" + exit 1 +fi + + +print -u2 -f "# reading file names...\n" +while (( $# > 0 )) ; do + # "ulimit -c 0" use used to force ksh93 to use a seperate process for subshells, + # this is used to work around a bug with LC_ALL changes bleeding through subshells + IFS=$'\n' ; typeset -a findls_lines=( $(ulimit -c 0 ; LC_ALL=C find "$1" -type f -ls) ) ; IFS=$' \t\n' + shift +done + + +print -u2 -f "# building tree...\n" + +${appconfig.do_benchmarking} && (( bench.start=SECONDS )) + +for (( i=0 ; i < ${#findls_lines[@]} ; i++ )) ; do + compound parseddata + typeset treenodename + + # parse "find -ls" output + parse_findls parseddata "${findls_lines[i]}" + + # add node to tree and return it's absolute name in "treenodename" + add_file_to_tree filetree "${parseddata.filepath}" treenodename + + # merge parsed "find -ls" output into tree node + nameref treenode="${treenodename}" + treenode+=parseddata + + # extras (calculated from the existing values in "parseddata") + typeset treenode.dirname="${ dirname "${treenode.filepath}" ; }" + typeset treenode.basename="${ basename "${treenode.filepath}" ; }" + + if ${appconfig.do_record.filetype} ; then + # Using /usr/(xpg4/)*/bin/file requires a |fork()|+|exec()| which makes the script a few hundred times slower... ;-( + typeset treenode.filetype="$(file "${treenode.filepath}")" + fi + + if ${appconfig.do_record.content} ; then + if [[ -r "${treenode.filepath}" ]] ; then + # We use an array of compound variables here to support + # files with holes (and later alternative streams, too) + compound -a treenode.content + integer cl=0 + while \ + { + treenode.content[${cl}]=( + typeset type="data" # (todo: "add support for "holes" (sparse files)) + typeset -b bin + ) + read -n1024 treenode.content[${cl}].bin + } ; do + (( cl++ )) + done < "${treenode.filepath}" + unset treenode.content[${cl}] + + typeset -A treenode.hashsum=( + [md5]="$(sum -x md5 < "${treenode.filepath}")" + [sha512]="$(sum -x sha512 < "${treenode.filepath}")" + ) + + # we do this for internal debugging only + if [[ "${ { + integer j + for (( j=0 ; j < ${#treenode.content[@]} ; j++ )) ; do + printf "%B" treenode.content[$j].bin + done + } | sum -x sha512 ; }" != "${treenode.hashsum[sha512]}" ]] ; then + # this should never happen... + print -u2 -f "fatal hash mismatch for %s\n" "${treenode.filepath}" + unset treenode.content treenode.hashsum + fi + fi + fi +done + +${appconfig.do_benchmarking} && (( bench.stop=SECONDS )) + + +if ${appconfig.do_benchmarking} ; then + # print benchmark data + print -u2 -f "# time used: %f\n" $((bench.stop - bench.start)) +fi + +# print variable tree +print -v filetree + +exit 0 +# EOF. diff --git a/usr/src/lib/libshell/common/scripts/simplefiletree1.sh b/usr/src/lib/libshell/common/scripts/simplefiletree1.sh new file mode 100644 index 0000000000..5b79aae8f8 --- /dev/null +++ b/usr/src/lib/libshell/common/scripts/simplefiletree1.sh @@ -0,0 +1,126 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# simplefiletree1 - build a simple file tree +# + +# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + + +function add_file_to_tree +{ + typeset treename=$1 + typeset filename=$2 + integer i + typeset nodepath # full name of compound variable + typeset -a pe # path elements + + # first built an array containing the names of each path element + # (e.g. "foo/var/baz"" results in an array containing "( 'foo' 'bar' 'baz' )") + typeset IFS='/' + pe+=( ${filename} ) + + [[ ${pe[0]} == '' ]] && pe[0]='/' + + # walk path described via the "pe" array and build nodes if + # there aren't any nodes yet + nodepath="${treename}" + for (( i=0 ; i < (${#pe[@]}-1) ; i++ )) ; do + nameref x="${nodepath}" + [[ ! -v x.node ]] && compound -A x.nodes + + nodepath+=".nodes[${pe[i]}]" + done + + # insert element + nameref node="${nodepath}" + [[ ! -v node.elements ]] && typeset -a node.elements + node.elements+=( "${pe[i]}" ) + + return 0 +} + +# main +builtin rev + +# tree base +compound filetree + +# benchmark data +compound bench=( + float start + float stop +) + +typeset i + +# argument prechecks +if (( $# == 0 )) ; then + print -u2 -f "%s: Missing <path> argument." "$0" + exit 1 +fi + +print -u2 "# reading file names" +while (( $# > 0 )) ; do + IFS=$'\n' ; typeset -a filenames=( $(find "$1" -type f) ) ; IFS=$' \t\n' + shift +done +print -u2 "# building tree..." + +(( bench.start=SECONDS )) + +for ((i=0 ; i < ${#filenames[@]} ; i++ )) ; do + add_file_to_tree filetree "${filenames[i]}" +done + +(( bench.stop=SECONDS )) + +# print benchmark data +print -u2 -f "# time used: %f\n" $((bench.stop - bench.start)) + +# print tree +print -v filetree + +exit 0 +# EOF. diff --git a/usr/src/lib/libshell/common/scripts/svcproptree1.sh b/usr/src/lib/libshell/common/scripts/svcproptree1.sh index e196fb413a..d3f1ee9742 100644 --- a/usr/src/lib/libshell/common/scripts/svcproptree1.sh +++ b/usr/src/lib/libshell/common/scripts/svcproptree1.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -74,11 +74,11 @@ function svcproptovartree servicename="${servicename/~(El)svc:\//}" # strip "svc:/" propname="${name#~(El).*:properties/}" - if [[ "${tree["${servicename}"].properties[*]}" == "" ]] ; then - typeset -A tree["${servicename}"].properties=( ) + if [[ "$(typeset -p "tree[${servicename}].properties")" == "" ]] ; then + compound -A tree[${servicename}].properties fi - nameref node=tree["${servicename}"].properties["${propname}"] + nameref node=tree[${servicename}].properties[${propname}] node=( typeset datatype="${datatype}" @@ -110,14 +110,14 @@ builtin uname typeset progname="${ basename "${0}" ; }" typeset -r svcproptree1_usage=$'+ -[-?\n@(#)\$Id: svcproptree1 (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: svcproptree1 (Roland Mainz) 2009-06-26 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?svcproptree1 - SMF tree demo] [+DESCRIPTION?\bsvcproptree1\b is a small ksh93 compound variable demo which reads accepts a SMF service pattern name input file, reads the matching service properties and converts them into an internal variable tree representation and outputs it in the format - specified by viewmode (either "list", "namelist" or "tree")..] + specified by viewmode (either "list", "namelist", "tree" or "compacttree")..] pattern viewmode @@ -135,11 +135,11 @@ shift $((OPTIND-1)) typeset svcpattern="$1" typeset viewmode="$2" -if [[ "${viewmode}" != ~(Elr)(list|namelist|tree) ]] ; then +if [[ "${viewmode}" != ~(Elr)(list|namelist|tree|compacttree) ]] ; then fatal_error $"Invalid view mode \"${viewmode}\"." fi -typeset svc=( +compound svc=( typeset -A proptree ) @@ -159,7 +159,10 @@ case "${viewmode}" in typeset + | egrep "^svc.proptree\[" ;; tree) - printf "%B\n" svc + print -v svc + ;; + compacttree) + print -C svc ;; *) fatal_error $"Invalid view mode \"${viewmode}\"." diff --git a/usr/src/lib/libshell/common/scripts/termclock.sh b/usr/src/lib/libshell/common/scripts/termclock.sh index edcadd4e10..582e70ad62 100644 --- a/usr/src/lib/libshell/common/scripts/termclock.sh +++ b/usr/src/lib/libshell/common/scripts/termclock.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -193,7 +193,7 @@ function main_loop 6<#((0)) cat <&6 - redirect 6<&- ; rm -f "${scratchfile}" ; redirect 6<>"${scratchfile}" + redirect 6<&- ; rm -f "${scratchfile}" ; redirect 6<> "${scratchfile}" c="" ; read -r -t ${update_interval} -N 1 c if [[ "$c" != "" ]] ; then @@ -221,6 +221,7 @@ function usage builtin basename builtin cat builtin date +builtin mktemp builtin rm typeset progname="${ basename "${0}" ; }" @@ -228,14 +229,14 @@ typeset progname="${ basename "${0}" ; }" float -r M_PI=3.14159265358979323846 # terminal size rect -typeset -C termsize=( +compound termsize=( integer columns=-1 integer lines=-1 ) typeset init_screen="true" -typeset -C clock=( +compound clock=( float middle_x float middle_y integer len_x @@ -244,17 +245,17 @@ typeset -C clock=( # set clock properties -typeset -C seconds=( +compound seconds=( float val typeset ch float scale integer length ) -typeset -C minutes=( +compound minutes=( float val typeset ch float scale integer length ) -typeset -C hours=( +compound hours=( float val typeset ch float scale @@ -267,7 +268,7 @@ hours.length=50 hours.scale=12 hours.ch=$"h" float update_interval=0.9 typeset -r termclock_usage=$'+ -[-?\n@(#)\$Id: termclock (Roland Mainz) 2008-11-04 \$\n] +[-?\n@(#)\$Id: termclock (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [-author?David Korn <dgk@research.att.com>] [+NAME?termclock - analog clock for terminals] @@ -290,7 +291,6 @@ shift $((OPTIND-1)) # prechecks which tput >/dev/null || fatal_error $"tput not found." -which mktemp >/dev/null || fatal_error $"mktemp not found." (( update_interval >= 0. && update_interval <= 7200. )) || fatal_error $"invalid update_interval value." # create temporary file for double-buffering and register an EXIT trap @@ -298,7 +298,7 @@ which mktemp >/dev/null || fatal_error $"mktemp not found." scratchfile="${ mktemp "/tmp/termclock.ppid${PPID}_pid$$.XXXXXX" ; }" [[ "${scratchfile}" != "" ]] || fatal_error $"Could not create temporary file name." trap 'rm -f "${scratchfile}"' EXIT -rm -f "${scratchfile}" ; redirect 6<>"${scratchfile}" || fatal_error $"Could not create temporary file." +rm -f "${scratchfile}" ; redirect 6<> "${scratchfile}" || fatal_error $"Could not create temporary file." # register trap to handle window size changes trap 'init_screen="true"' WINCH diff --git a/usr/src/lib/libshell/common/scripts/test_net_sctp.sh b/usr/src/lib/libshell/common/scripts/test_net_sctp.sh index a17aaba62f..92b805f2dd 100644 --- a/usr/src/lib/libshell/common/scripts/test_net_sctp.sh +++ b/usr/src/lib/libshell/common/scripts/test_net_sctp.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -44,13 +44,13 @@ print "# testing SCTP support" print "# (via fetching the main page of http://www.sctp.org/ via SCTP)" # open sctp stream and print it's number -redirect {netfd}<>/dev/sctp/www.sctp.org/80 +redirect {netfd}<> /dev/sctp/www.sctp.org/80 print "sctp fd=${netfd}" # send HTTP request request="GET / HTTP/1.1\r\n" request+="Host: www.sctp.org\r\n" -request+="User-Agent: ksh93/test_net_sctp (2008-10-14; $(uname -s -r -p))\r\n" +request+="User-Agent: ksh93/test_net_sctp (2009-04-08; $(uname -s -r -p))\r\n" request+="Connection: close\r\n" print -u${netfd} -n -- "${request}\r\n" diff --git a/usr/src/lib/libshell/common/scripts/xmldocumenttree1.sh b/usr/src/lib/libshell/common/scripts/xmldocumenttree1.sh index ab6517f372..9bb25b855a 100644 --- a/usr/src/lib/libshell/common/scripts/xmldocumenttree1.sh +++ b/usr/src/lib/libshell/common/scripts/xmldocumenttree1.sh @@ -22,7 +22,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -106,8 +106,8 @@ function handle_document nodepath[${nodesnum}]+=( typeset tagtype="element" typeset tagname="${tag_value}" - typeset -A tagattributes=( ) - typeset -A nodes=( ) + compound -A tagattributes + compound -A nodes integer nodesnum=0 ) @@ -268,13 +268,13 @@ builtin uname typeset progname="${ basename "${0}" ; }" typeset -r xmldocumenttree1_usage=$'+ -[-?\n@(#)\$Id: xmldocumenttree1 (Roland Mainz) 2008-10-14 \$\n] +[-?\n@(#)\$Id: xmldocumenttree1 (Roland Mainz) 2009-05-09 \$\n] [-author?Roland Mainz <roland.mainz@nrubsig.org>] [+NAME?xmldocumenttree1 - XML tree demo] [+DESCRIPTION?\bxmldocumenttree\b is a small ksh93 compound variable demo which reads a XML input file, converts it into an internal variable tree representation and outputs it in the format - specified by viewmode (either "list", "namelist" or "tree").] + specified by viewmode (either "list", "namelist", "tree" or "compacttree").] file viewmode @@ -296,15 +296,15 @@ if [[ "${xmlfile}" == "" ]] ; then fatal_error $"No file given." fi -if [[ "${viewmode}" != ~(Elr)(list|namelist|tree) ]] ; then +if [[ "${viewmode}" != ~(Elr)(list|namelist|tree|compacttree) ]] ; then fatal_error $"Invalid view mode \"${viewmode}\"." fi -typeset -C xdoc -typeset -A xdoc.nodes +compound xdoc +compound -A xdoc.nodes integer xdoc.nodesnum=0 -typeset -C stack +compound stack typeset -a stack.items=( [0]="doc.nodes" ) integer stack.pos=0 @@ -343,7 +343,10 @@ case "${viewmode}" in typeset + | egrep "xdoc.*(tagname|tagtype|tagval|tagattributes)" ;; tree) - print -- "${xdoc}" + print -v xdoc + ;; + compacttree) + print -C xdoc ;; *) fatal_error $"Invalid view mode \"${viewmode}\"." diff --git a/usr/src/lib/libshell/common/sh.1 b/usr/src/lib/libshell/common/sh.1 index 4ebbb41a31..365b11fd5c 100644 --- a/usr/src/lib/libshell/common/sh.1 +++ b/usr/src/lib/libshell/common/sh.1 @@ -4,6 +4,7 @@ .\" .\" @(#)sh.1 (dgk@research.att.com) 12/28/93 .\" +.xx labels=5 .nr Z 1 \" set to 1 when command name is ksh, 2 for ksh93 .ds OK [\| .ds CK \|] @@ -20,15 +21,14 @@ .\} .SH NAME .if \nZ=0 \{\ -sh, rsh, pfsh \- shell, the +sh, rsh, pfsh \- shell, the standard/restricted command and programming language .\} .if \nZ=1 \{\ -ksh, rksh, pfksh \- KornShell, a +ksh, rksh, pfksh \- KornShell, a standard/restricted command and programming language .\} .if \nZ=2 \{\ -ksh93, rksh93, pfksh93 \- KornShell, a +ksh93, rksh93, pfksh93 \- KornShell, a standard/restricted command and programming language .\} -standard/restricted command and programming language .SH SYNOPSIS .if \nZ=0 \{\ .B sh @@ -699,7 +699,7 @@ current ones provided that the types are compatible. The right hand side of a variable assignment undergoes all the expansion list below except word splitting, brace expansion, and file name generation. When the left hand side is an assignment is a compound variable and -the right hand is the name of a compound variable, the coumpound variable +the right hand is the name of a compound variable, the compound variable on the right will be copied or appended to the compound variable on the left. .SS Comments. .PD 0 @@ -765,6 +765,8 @@ but can be unset or redefined: .TP .B "command=\(fmcommand \(fm" .TP +.B "compound=\(fmtypeset \-C\(fm" +.TP .B "fc=hist" .TP .B "float=\(fmtypeset \-lE\(fm" @@ -945,6 +947,14 @@ is a UNIX so programs that expect to .IR lseek (2) on the file will not work. +.PP +Process substitution of the form +\f3<(\fP\f2list\^\fP\f3)\fP +can also be used with the +.B < +redirection operator which causes the output of +.I list\^ +to be standard input or the input for whatever file descriptor is specified. .SS Parameter Expansion. A .I parameter\^ @@ -1179,7 +1189,7 @@ elements between .I sub1\^ and .I sub2\^ -inclusive (or all elments for +inclusive (or all elements for .B \(** and .BR @ ) @@ -1916,6 +1926,12 @@ then two adjacent characters delimit a null field. .TP .B +.SM JOBMAX +This variable defines the maximum number running background jobs +that can run at a time. When this limit is reached, the +shell will wait for a job to complete before staring a new job. +.TP +.B .SM LANG This variable determines the locale category for any category not specifically selected with a variable @@ -2856,8 +2872,8 @@ can be used within an arithmetic expression: .PP .if t .RS .B -.if n abs acos acosh asin asinh atan atan2 atanh cbrt copysign cos cosh erf erfc exp exp2 expm1 fabs fdim finite floor fma fmax fmod hypot ilogb int isinf isnan lgamma log log2 logb nearbyint nextafter nexttoward pow remainder rint round sin sinh sqrt tan tanh tgamma trunc -.if t abs acos acosh asin asinh atan atan2 atanh cbrt copysign cos cosh erf erfc exp exp2 expm1 fabs fdim finite floor fma fmax fmod hypot ilogb int isinf isnan lgamma log log2 logb nearbyint nextafter nexttoward pow rint round sin sinh sqrt tan tanh tgamma trunc +.if n abs acos acosh asin asinh atan atan2 atanh cbrt copysign cos cosh erf erfc exp exp2 expm1 fabs fdim finite floor fma fmax fmod hypot ilogb int isinf isnan j0 j1 jn lgamma log log2 logb nearbyint nextafter nexttoward pow remainder rint round sin sinh sqrt tan tanh tgamma trunc y0 y1 yn +.if t abs acos acosh asin asinh atan atan2 atanh cbrt copysign cos cosh erf erfc exp exp2 expm1 fabs fdim finite floor fma fmax fmod j0 j1 jn hypot ilogb int isinf isnan lgamma log log2 logb nearbyint nextafter nexttoward pow rint round sin sinh sqrt tan tanh tgamma trunc y0 y1 yn .if t .RE .PP An internal representation of a @@ -3305,6 +3321,16 @@ except that it overrides the .B noclobber option. .TP +.BI >; word +Write output to a temporary file. If the command completes +successfully rename it to +.IR word , +otherwise, delete the temporary file. +.BI >; word +cannot be used with the +.IR exec (2). +built-in. +.TP .BI >> word Use file .I word\^ @@ -3316,7 +3342,18 @@ otherwise, the file is created. Open file .I word\^ for reading and writing -as standard input. +as standard output. +.TP +.BI <>; word +The same as +.BI <> word +except that if the command completes successfully, +.I word\^ +is truncated to the offset at command completion. +.BI <>; word +cannot be used with the +.IR exec (2). +built-in. .TP \f3<<\fP\*(OK\f3\-\fP\*(CK\f2word\fP The shell input is read up to a line that is the same as @@ -5772,7 +5809,7 @@ The pathname is used for each of the parameters that requires .IR pathname . .TP -\f3getopts\fP \*(OK \f3\ -a\fP \f2name\^\fP \*(CK \f2optstring vname\^\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK +\f3getopts\fP \*(OK \f3\ \-a\fP \f2name\^\fP \*(CK \f2optstring vname\^\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK Checks .I arg for legal options. @@ -6038,7 +6075,7 @@ Equivalent to .BI "exec /bin/newgrp" " arg\^" \&.\|.\|.\^. .TP -\f3print\fP \*(OK \f3\-Renprs\^\fP \*(CK \*(OK \f3\-u\fP \f2unit\^\fP\*(CK \*(OK \f3\-f\fP \f2format\^\fP \*(CK \*(OK \f2arg\^\fP .\|.\|. \*(CK +\f3print\fP \*(OK \f3\-CRenprsv\^\fP \*(CK \*(OK \f3\-u\fP \f2unit\^\fP\*(CK \*(OK \f3\-f\fP \f2format\^\fP \*(CK \*(OK \f2arg\^\fP .\|.\|. \*(CK With no options or with option .B \- or @@ -6060,9 +6097,11 @@ In this case, any options are ignored. Otherwise, unless the -.B \-R -or +.BR \-C , +.BR \-R , .BR \-r , +or +.B \-v are specified, the following escape conventions will be applied: .RS @@ -6133,6 +6172,24 @@ of the process spawned with .B \(bv& instead of standard output. The +.B \-v +option treats each +.I arg\^ +as a variable name and writes the value in +the +.B printf +.B %B +format. +The +.B \-C +option treats each +.I arg\^ +as a variable name and writes the value in +the +.B printf +.B %#B +format. +The .B \-s option causes the arguments to be written onto the history file @@ -6164,8 +6221,10 @@ format specifications, the .B format\^ string is reused to format remaining arguments. The following extensions can also be used: -.BL -.LI +.RS +.PD 0 +.TP +.B %b A .B %b format can be used instead of @@ -6174,16 +6233,21 @@ to cause escape sequences in the corresponding .I arg\^ to be expanded as described in .BR print. -.LI +.TP +.B %B A .B %B option causes each of the arguments to be treated as variable names and the binary value of variable will be printed. -This is most useful for variables whose attribute +The alternate flag +.B # +causes a compound variable to be output on a single line. +This is most useful for compound variables and variables whose attribute is .BR \-b . -.LI +.TP +.B %H A .B %H format can be used instead of @@ -6192,7 +6256,8 @@ to cause characters in .I arg\^ that are special in HTML and XML to be output as their entity name. -.LI +.TP +.B %P A .B %P format can be used instead of @@ -6201,7 +6266,8 @@ to cause .I arg\^ to be interpreted as an extended regular expression and be printed as a shell pattern. -.LI +.TP +.B %R A .B %R format can be used instead of @@ -6210,14 +6276,16 @@ to cause .I arg\^ to be interpreted as a shell pattern and to be printed as an extended regular expression. -.LI +.TP +.B %q A .B %q format can be used instead of .B %s to cause the resulting string to be quoted in a manner than can be reinput to the shell. -.LI +.TP +.BI %( date-format )T A .BI %( date-format )T format can be use to treat an argument as a date/time string @@ -6226,11 +6294,13 @@ and to format the date/time according to the as defined for the .BR date (1) command. -.LI +.TP +.B %Z A .B %Z format will output a byte whose value is 0. -.LI +.TP +.B %d The precision field of the .B %d format can be followed by a @@ -6241,7 +6311,8 @@ In this case, the flag character causes .IB base # to be prepended. -.LI +.TP +.B # The .B # flag when used with the @@ -6250,7 +6321,6 @@ specifier without an output base, causes the output to be displayed in thousands units with one of the suffixes .B "k M G T P E" to indicate the unit. -.LI The .B # flag when used with the @@ -6258,11 +6328,14 @@ flag when used with the specifier causes the output to be displayed in 1024 with one of the suffixes .B "Ki Mi Gi Ti Pi Ei" to indicate the unit. -.LI +.TP +.B = The .B = flag has been added to center the output within the specified field width. -.LE +.PD +.PP +.RE .TP \f3pwd\fP \*(OK \f3\-LP\fP \*(CK Outputs the value of the current working @@ -6881,6 +6954,18 @@ The command with no arguments prints a list of commands associated with each signal number. +.PP +An +.B exit +or +.B return +without an argument in a trap action will +preserve the exit status of the command that invoked the trap. +.TP +\f3true\fP +Does nothing, and exits 0. Used with +.B while +for infinite loops. .TP \f3true\fP Does nothing, and exits 0. Used with @@ -7122,7 +7207,7 @@ This is usually used to reference a variable inside a function whose name has been passed as an argument. .TP .B \-p -The name, attributes and values for the give +The name, attributes and values for the given .IR vname s are written on standard output in a form that can be used as shell input. diff --git a/usr/src/lib/libshell/common/sh/args.c b/usr/src/lib/libshell/common/sh/args.c index 06ae7dbd38..d70e58c048 100644 --- a/usr/src/lib/libshell/common/sh/args.c +++ b/usr/src/lib/libshell/common/sh/args.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -264,8 +264,13 @@ int sh_argopts(int argc,register char *argv[], void *context) ap->kiafile = opt_info.arg; n = 'n'; } - /* FALL THRU */ + /*FALLTHROUGH*/ #endif /* SHOPT_KIA */ +#if SHOPT_REGRESS + goto skip; + case 'I': + continue; +#endif /* SHOPT_REGRESS */ skip: default: if(cp=strchr(optksh,n)) @@ -384,9 +389,9 @@ void sh_applyopts(Shell_t* shp,Shopt_t newflags) off_option(&newflags,SH_NOEXEC); if(is_option(&newflags,SH_PRIVILEGED)) on_option(&newflags,SH_NOUSRPROFILE); - if(is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED)) + if(!sh_isstate(SH_INIT) && is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED) || sh_isstate(SH_INIT) && is_option(&((Arg_t*)shp->arg_context)->sh->offoptions,SH_PRIVILEGED) && shp->userid!=shp->euserid) { - if(sh_isoption(SH_PRIVILEGED)) + if(!is_option(&newflags,SH_PRIVILEGED)) { setuid(shp->userid); setgid(shp->groupid); @@ -789,6 +794,42 @@ static int arg_pipe(register int pv[]) } #endif +struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp) +{ + /* argument of the form <(cmd) or >(cmd) */ + register struct argnod *ap; + int monitor, fd, pv[2]; + int subshell = shp->subshell; + ap = (struct argnod*)stkseek(shp->stk,ARGVAL); + ap->argflag |= ARG_MAKE; + ap->argflag &= ~ARG_RAW; + sfwrite(shp->stk,e_devfdNN,8); + sh_pipe(pv); + fd = argp->argflag&ARG_RAW; + sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); + ap = (struct argnod*)stkfreeze(shp->stk,0); + shp->inpipe = shp->outpipe = 0; + if(monitor = (sh_isstate(SH_MONITOR)!=0)) + sh_offstate(SH_MONITOR); + shp->subshell = 0; + if(fd) + { + shp->inpipe = pv; + sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); + } + else + { + shp->outpipe = pv; + sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); + } + shp->subshell = subshell; + if(monitor) + sh_onstate(SH_MONITOR); + close(pv[1-fd]); + sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); + return(ap); +} + /* Argument expansion */ static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag) { @@ -797,37 +838,11 @@ static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod * #if SHOPT_DEVFD if(*argp->argval==0 && (argp->argflag&ARG_EXP)) { - /* argument of the form (cmd) */ - register struct argnod *ap; - int monitor, fd, pv[2]; - ap = (struct argnod*)stkseek(shp->stk,ARGVAL); - ap->argflag |= ARG_MAKE; - ap->argflag &= ~ARG_RAW; + struct argnod *ap; + ap = sh_argprocsub(shp,argp); ap->argchn.ap = *argchain; *argchain = ap; count++; - sfwrite(shp->stk,e_devfdNN,8); - sh_pipe(pv); - fd = argp->argflag&ARG_RAW; - sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); - ap = (struct argnod*)stkfreeze(shp->stk,0); - shp->inpipe = shp->outpipe = 0; - if(monitor = (sh_isstate(SH_MONITOR)!=0)) - sh_offstate(SH_MONITOR); - if(fd) - { - shp->inpipe = pv; - sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); - } - else - { - shp->outpipe = pv; - sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); - } - if(monitor) - sh_onstate(SH_MONITOR); - close(pv[1-fd]); - sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); } else #endif /* SHOPT_DEVFD */ diff --git a/usr/src/lib/libshell/common/sh/arith.c b/usr/src/lib/libshell/common/sh/arith.c index f21b79ad6f..bb17fc936d 100644 --- a/usr/src/lib/libshell/common/sh/arith.c +++ b/usr/src/lib/libshell/common/sh/arith.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -25,7 +25,6 @@ */ #include "defs.h" -#include <ctype.h> #include "lexstates.h" #include "name.h" #include "streval.h" @@ -65,6 +64,7 @@ static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval * register Namval_t *mp; int flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET; Dt_t *sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0); + Dt_t *root = shp->var_tree; assign = assign?NV_ASSIGN:NV_NOASSIGN; if(cp>=lvalue->expr && cp < lvalue->expr+lvalue->elen) { @@ -79,7 +79,11 @@ static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval * cp[flag] = c; return(&FunNode); } - np = nv_open(cp,shp->var_tree,assign|NV_VARNAME); + if(!np && assign) + np = nv_open(cp,shp->var_tree,assign|NV_VARNAME); + if(!np) + return(0); + root = shp->last_root; cp[flag] = c; if(cp[flag+1]=='[') flag++; @@ -87,7 +91,7 @@ static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval * flag = 0; cp = (char*)np; } - if((lvalue->emode&ARITH_COMP) && dtvnext(shp->var_tree) && ((mp=nv_search(cp,shp->var_tree,flags))||(sdict && (mp=nv_search(cp,sdict,flags))))) + if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((mp=nv_search(cp,root,flags))||(sdict && (mp=nv_search(cp,sdict,flags))))) { while(nv_isref(mp)) { @@ -100,10 +104,7 @@ static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval * { if(!sub) sub = (char*)&lvalue->expr[flag]; - if(((ap=nv_arrayptr(np)) && array_assoc(ap)) || (lvalue->emode&ARITH_COMP)) - nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE); - else - nv_putsub(np, NIL(char*),flag); + nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE); } return(np); } @@ -239,28 +240,18 @@ static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdoubl if(!np && lvalue->value) break; lvalue->value = (char*)np; - if((lvalue->emode&ARITH_COMP) || (nv_isarray(np) && nv_aindex(np)<0)) - { - /* bind subscript later */ - lvalue->flag = 0; - if(c=='[') - { - lvalue->flag = (str-lvalue->expr); - do - str = nv_endsubscript(np,str,0); - while((c= *str)=='['); - } - break; - } + /* bind subscript later */ + if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) + lvalue->isfloat=1; + lvalue->flag = 0; if(c=='[') { + lvalue->flag = (str-lvalue->expr); do - str = nv_endsubscript(np,str,NV_ADD|NV_SUBQUOTE); - while((c=*str)=='['); + str = nv_endsubscript(np,str,0); + while((c= *str)=='['); + break; } - if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) - lvalue->isfloat=1; - lvalue->flag = nv_aindex(np); } else { @@ -317,9 +308,19 @@ static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdoubl if(sh_isoption(SH_NOEXEC)) return(0); np = scope(shp,np,lvalue,0); + if(!np) + { + if(sh_isoption(SH_NOUNSET)) + { + *ptr = lvalue->value; + goto skip; + } + return(0); + } if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER)) { *ptr = nv_name(np); + skip: lvalue->value = (char*)ERROR_dictionary(e_notset); lvalue->emode |= 010; return(0); diff --git a/usr/src/lib/libshell/common/sh/array.c b/usr/src/lib/libshell/common/sh/array.c index ed46e84738..0346b9fb59 100644 --- a/usr/src/lib/libshell/common/sh/array.c +++ b/usr/src/lib/libshell/common/sh/array.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -189,6 +189,18 @@ static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update) return(up); } +int nv_arrayisset(Namval_t *np, Namarr_t *arp) +{ + register struct index_array *ap = (struct index_array*)arp; + union Value *up; + if(is_associative(ap)) + return((np = nv_opensub(np)) && !nv_isnull(np)); + if(ap->cur >= ap->maxi) + return(0); + up = &(ap->val[ap->cur]); + return(up->cp && up->cp!=Empty); +} + /* * Get the Value pointer for an array. * Delete space as necessary if flag is ARRAY_DELETE @@ -487,7 +499,7 @@ static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t * scan = ap->nelem&ARRAY_SCAN; if(mp && mp!=np) { - if(!is_associative(ap) && string && !nv_type(np) && nv_isvtree(mp)) + if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp)) { if(!nv_isattr(np,NV_NOFREE)) _nv_unset(mp,flags&NV_RDONLY); @@ -529,7 +541,7 @@ static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t * ap->nelem--; } } - if(array_elem(ap)==0 && ((ap->nelem&ARRAY_SCAN) || !is_associative(ap))) + if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN)) { if(is_associative(ap)) (*ap->fun)(np, NIL(char*), NV_AFREE); @@ -602,12 +614,13 @@ static const Namdisc_t array_disc = static void array_copytree(Namval_t *np, Namval_t *mp) { - char *val; Namfun_t *fp = nv_disc(np,NULL,NV_POP); nv_offattr(np,NV_ARRAY); nv_clone(np,mp,0); + if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE)) + free((void*)np->nvalue.cp); + np->nvalue.cp = 0; np->nvalue.up = &mp->nvalue; - val = sfstruse(sh.strbuf); fp->nofree &= ~1; nv_disc(np,(Namfun_t*)fp, NV_FIRST); fp->nofree |= 1; @@ -662,22 +675,21 @@ static struct index_array *array_grow(Namval_t *np, register struct index_array if(nv_hasdisc(np,&array_disc) || nv_isvtree(np)) { ap->header.table = dtopen(&_Nvdisc,Dtoset); - mp = nv_search("0", ap->header.table, 0); - + mp = nv_search("0", ap->header.table,NV_ADD); if(mp && nv_isnull(mp)) { Namfun_t *fp; ap->val[0].np = mp; array_setbit(ap->bits,0,ARRAY_CHILD); for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next); - if(fp) + if(fp && fp->disc && fp->disc->readf) (*fp->disc->readf)(mp,(Sfio_t*)0,0,fp); i++; } } else if((ap->val[0].cp=np->nvalue.cp)) i++; - else if(nv_isattr(np,NV_INTEGER)) + else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np)) { Sfdouble_t d= nv_getnum(np); i++; @@ -1077,9 +1089,15 @@ char *nv_endsubscript(Namval_t *np, register char *cp, int mode) } if(mode && np) { + Namarr_t *ap = nv_arrayptr(np); + int scan = 0; + if(ap) + scan = ap->nelem&ARRAY_SCAN; if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+')) mode |= NV_ADD; nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL)); + if(scan) + ap->nelem |= scan; } if(quoted) stakseek(count); @@ -1252,7 +1270,7 @@ void *nv_associative(register Namval_t *np,const char *sp,int mode) else if(ap->header.nelem&ARRAY_NOSCOPE) mode = HASH_NOSCOPE; if(*sp==0 && (mode&NV_ADD)) - sfprintf(sfstderr,"adding empty subscript\n"); + errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript"); if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp)) ap->cur = mp; if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD)) @@ -1280,7 +1298,9 @@ void *nv_associative(register Namval_t *np,const char *sp,int mode) ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp); } np = mp; - if(ap->pos != np && !(ap->header.nelem&ARRAY_SCAN)) + if(ap->pos && ap->pos==np) + ap->header.nelem |= ARRAY_SCAN; + else if(!(ap->header.nelem&ARRAY_SCAN)) ap->pos = 0; ap->cur = np; } diff --git a/usr/src/lib/libshell/common/sh/bash.c b/usr/src/lib/libshell/common/sh/bash.c index 4b2def3b22..41945b4d53 100644 --- a/usr/src/lib/libshell/common/sh/bash.c +++ b/usr/src/lib/libshell/common/sh/bash.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/defs.c b/usr/src/lib/libshell/common/sh/defs.c index 8b8a6aa323..b535ac2bce 100644 --- a/usr/src/lib/libshell/common/sh/defs.c +++ b/usr/src/lib/libshell/common/sh/defs.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/deparse.c b/usr/src/lib/libshell/common/sh/deparse.c index c5704d2cf9..88b135262d 100644 --- a/usr/src/lib/libshell/common/sh/deparse.c +++ b/usr/src/lib/libshell/common/sh/deparse.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/env.c b/usr/src/lib/libshell/common/sh/env.c index d1f9361975..0e007ce796 100644 --- a/usr/src/lib/libshell/common/sh/env.c +++ b/usr/src/lib/libshell/common/sh/env.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/expand.c b/usr/src/lib/libshell/common/sh/expand.c index 15004a09be..49862d75cb 100644 --- a/usr/src/lib/libshell/common/sh/expand.c +++ b/usr/src/lib/libshell/common/sh/expand.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -32,6 +32,7 @@ # include "test.h" #else # include <ast.h> +# include <ctype.h> # include <setjmp.h> #endif /* KSHELL */ #include <glob.h> diff --git a/usr/src/lib/libshell/common/sh/fault.c b/usr/src/lib/libshell/common/sh/fault.c index 60af63972d..fc90ad573e 100644 --- a/usr/src/lib/libshell/common/sh/fault.c +++ b/usr/src/lib/libshell/common/sh/fault.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -98,7 +98,7 @@ void sh_fault(register int sig) } return; } - if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH) + if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT) { shp->exitval = SH_EXITSIG|sig; sh_subfork(); @@ -141,7 +141,7 @@ void sh_fault(register int sig) } /* mark signal and continue */ shp->trapnote |= SH_SIGSET; - if(sig < shp->sigmax) + if(sig <= shp->sigmax) shp->sigflag[sig] |= SH_SIGSET; #if defined(VMFL) && (VMALLOC_VERSION>=20031205L) if(abortsig(sig)) @@ -186,7 +186,6 @@ void sh_fault(register int sig) #endif /* SIGTSTP */ } #ifdef ERROR_NOTIFY - /* This is obsolete */ if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun) action = (*shp->bltinfun)(-sig,(char**)0,(void*)0); if(action>0) @@ -198,7 +197,7 @@ void sh_fault(register int sig) return; } shp->trapnote |= flag; - if(sig < shp->sigmax) + if(sig <= shp->sigmax) shp->sigflag[sig] |= flag; if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK)) { @@ -215,23 +214,28 @@ void sh_fault(register int sig) void sh_siginit(void *ptr) { Shell_t *shp = (Shell_t*)ptr; - register int sig, n=SIGTERM+1; + register int sig, n; register const struct shtable2 *tp = shtab_signals; sig_begin(); /* find the largest signal number in the table */ -#ifdef SIGRTMIN - shp->sigruntime[SH_SIGRTMIN] = SIGRTMIN; -#endif /* SIGRTMIN */ -#ifdef SIGRTMAX - shp->sigruntime[SH_SIGRTMAX] = SIGRTMAX; -#endif /* SIGRTMAX */ +#if defined(SIGRTMIN) && defined(SIGRTMAX) + if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP) + { + shp->sigruntime[SH_SIGRTMIN] = n; + shp->sigruntime[SH_SIGRTMAX] = sig; + } +#endif /* SIGRTMIN && SIGRTMAX */ + n = SIGTERM; while(*tp->sh_name) { - sig = tp->sh_number&((1<<SH_SIGBITS)-1); - if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) - sig = shp->sigruntime[sig-1]; - if(sig>n && sig<SH_TRAP) - n = sig; + sig = (tp->sh_number&((1<<SH_SIGBITS)-1)); + if (!(sig-- & SH_TRAP)) + { + if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) + sig = shp->sigruntime[sig]; + if(sig>n && sig<SH_TRAP) + n = sig; + } tp++; } shp->sigmax = n++; @@ -241,7 +245,7 @@ void sh_siginit(void *ptr) for(tp=shtab_signals; sig=tp->sh_number; tp++) { n = (sig>>SH_SIGBITS); - if((sig &= ((1<<SH_SIGBITS)-1)) > shp->sigmax) + if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->sigmax+1)) continue; sig--; if(n&SH_SIGRUNTIME) @@ -291,7 +295,7 @@ void sh_sigdone(void) { register int flag, sig = sh.sigmax; sh.sigflag[0] |= SH_SIGFAULT; - while(--sig>0) + for(sig=sh.sigmax; sig>0; sig--) { flag = sh.sigflag[sig]; if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF))) @@ -321,7 +325,8 @@ void sh_sigreset(register int mode) } else if(sig && mode>1) { - signal(sig,SIG_IGN); + if(sig!=SIGCHLD) + signal(sig,SIG_IGN); flag &= ~SH_SIGFAULT; flag |= SH_SIGOFF; } @@ -396,13 +401,25 @@ void sh_chktrap(void) } if(sh.sigflag[SIGALRM]&SH_SIGALRM) sh_timetraps(); +#ifdef SHOPT_BGX + if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD]) + job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1); + while(--sig>=0 && sig!=SIGCHLD) +#else while(--sig>=0) +#endif /* SHOPT_BGX */ { if(sh.sigflag[sig]&SH_SIGTRAP) { sh.sigflag[sig] &= ~SH_SIGTRAP; if(trap=sh.st.trapcom[sig]) - sh_trap(trap,0); + { + Sfio_t *fp; + if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp)) + sfclose(fp); + sh.oldexit = SH_EXITSIG|sig; + sh_trap(trap,0); + } } } } @@ -465,7 +482,7 @@ int sh_trap(const char *trap, int mode) if(was_verbose) sh_onstate(SH_VERBOSE); exitset(); - if(jmpval>SH_JMPTRAP) + if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT)) siglongjmp(*shp->jmplist,jmpval); return(shp->exitval); } @@ -568,8 +585,8 @@ void sh_done(void *ptr, register int sig) register int savxit = shp->exitval; shp->trapnote = 0; indone=1; - if(sig==0) - sig = shp->lastsig; + if(sig) + savxit = SH_EXITSIG|sig; if(shp->userinit) (*shp->userinit)(shp, -1); if(t=shp->st.trapcom[0]) @@ -604,6 +621,8 @@ void sh_done(void *ptr, register int sig) sfsync((Sfio_t*)sfstdin); sfsync((Sfio_t*)shp->outpool); sfsync((Sfio_t*)sfstdout); + if(savxit&SH_EXITSIG) + sig = savxit&SH_EXITMASK; if(sig) { /* generate fault termination code */ diff --git a/usr/src/lib/libshell/common/sh/fcin.c b/usr/src/lib/libshell/common/sh/fcin.c index 9618bb9ac0..0fd7e7cd70 100644 --- a/usr/src/lib/libshell/common/sh/fcin.c +++ b/usr/src/lib/libshell/common/sh/fcin.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/init.c b/usr/src/lib/libshell/common/sh/init.c index 0bd2f92b79..7371b8de98 100644 --- a/usr/src/lib/libshell/common/sh/init.c +++ b/usr/src/lib/libshell/common/sh/init.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -29,7 +29,6 @@ #include "defs.h" #include <stak.h> -#include <ctype.h> #include <ccode.h> #include <pwd.h> #include <tmx.h> @@ -44,6 +43,7 @@ #include "builtins.h" #include "FEATURE/time" #include "FEATURE/dynamic" +#include "FEATURE/externs" #include "lexstates.h" #include "version.h" @@ -56,6 +56,10 @@ char e_version[] = "\n@(#)$Id: Version " #define ATTRS 1 "B" #endif +#if SHOPT_BGX +#define ATTRS 1 + "J" +#endif #if SHOPT_ACCT #define ATTRS 1 "L" @@ -68,6 +72,10 @@ char e_version[] = "\n@(#)$Id: Version " #define ATTRS 1 "P" #endif +#if SHOPT_REGRESS +#define ATTRS 1 + "R" +#endif #if ATTRS " " #endif @@ -162,6 +170,7 @@ static int nbltins; static void env_init(Shell_t*); static Init_t *nv_init(Shell_t*); static Dt_t *inittree(Shell_t*,const struct shtable2*); +static int shlvl; #ifdef _WINIX # define EXE "?(.exe)" @@ -195,22 +204,27 @@ static char *nospace(int unused) static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { register const char *cp, *name=nv_name(np); + register int newopt=0; Shell_t *shp = nv_shell(np); if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD))) goto done; - sh_offoption(SH_VI); - sh_offoption(SH_EMACS); - sh_offoption(SH_GMACS); if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD))))) goto done; /* turn on vi or emacs option if editor name is either*/ cp = path_basename(cp); if(strmatch(cp,"*[Vv][Ii]*")) - sh_onoption(SH_VI); + newopt=SH_VI; else if(strmatch(cp,"*gmacs*")) - sh_onoption(SH_GMACS); + newopt=SH_GMACS; else if(strmatch(cp,"*macs*")) - sh_onoption(SH_EMACS); + newopt=SH_EMACS; + if(newopt) + { + sh_offoption(SH_VI); + sh_offoption(SH_EMACS); + sh_offoption(SH_GMACS); + sh_onoption(newopt); + } done: nv_putv(np, val, flags, fp); } @@ -220,11 +234,12 @@ static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t { Shell_t *shp = nv_shell(np); void *histopen = shp->hist_ptr; + char *cp; if(val && histopen) { - if(np==HISTFILE && strcmp(val,nv_getval(HISTFILE))==0) + if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0) return; - if(np==HISTSIZE && sh_arith(val)==nv_getnum(HISTSIZE)) + if(np==HISTSIZE && sh_arith(val)==nv_getnum(HISTSIZE)) return; hist_close(shp->hist_ptr); } @@ -340,13 +355,17 @@ static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t } #endif - /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */ + /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */ static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp) { Shell_t *shp = nv_shell(np); int type; char *lc_all = nv_getval(LCALLNOD); char *name = nv_name(np); + if((shp->test&1) && !val && !nv_getval(np)) + return; + if(shp->test&2) + nv_putv(np, val, flags, fp); if(name==(LCALLNOD)->nvname) type = LC_ALL; else if(name==(LCTYPENOD)->nvname) @@ -357,22 +376,30 @@ static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t type = LC_COLLATE; else if(name==(LCNUMNOD)->nvname) type = LC_NUMERIC; - else if(name==(LANGNOD)->nvname && (!lc_all || *lc_all==0)) - type = LC_ALL; +#ifdef LC_LANG + else if(name==(LANGNOD)->nvname) + type = LC_LANG; +#else +#define LC_LANG LC_ALL + else if(name==(LANGNOD)->nvname && (!lc_all || !*lc_all)) + type = LC_LANG; +#endif else type= -1; if(sh_isstate(SH_INIT) && type>=0 && type!=LC_ALL && lc_all && *lc_all) type= -1; - if(type>=0 || type==LC_ALL) + if(type>=0 || type==LC_ALL || type==LC_LANG) { - if(!setlocale(type,val?val:"")) + if(!setlocale(type,val?val:"-") && val) { if(!sh_isstate(SH_INIT) || shp->login_sh==0) errormsg(SH_DICT,0,e_badlocale,val); return; } } - if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_CTYPE)) + if(!(shp->test&2)) + nv_putv(np, val, flags, fp); + if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE)) { if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN]) free((void*)sh_lexstates[ST_BEGIN]); @@ -423,7 +450,6 @@ static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t if(type==LC_ALL || type==LC_MESSAGES) error_info.translate = msg_translate; #endif - nv_putv(np, val, flags, fp); } #endif /* _hdr_locale */ @@ -431,10 +457,18 @@ static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { register struct ifs *ip = (struct ifs*)fp; + Shell_t *shp; ip->ifsnp = 0; + if(!val) + { + fp = nv_stack(np, NIL(Namfun_t*)); + if(fp && !fp->nofree) + free((void*)fp); + } if(val != np->nvalue.cp) nv_putv(np, val, flags, fp); - + if(!val && !(flags&NV_CLONE) && (fp=np->nvfun) && !fp->disc && (shp=(Shell_t*)(fp->last))) + nv_stack(np,&((Init_t*)shp->init_context)->IFS_init.hdr); } /* @@ -505,8 +539,10 @@ static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t struct tms tp; if(!val) { - nv_stack(np, NIL(Namfun_t*)); - nv_unset(np); + fp = nv_stack(np, NIL(Namfun_t*)); + if(fp && !fp->nofree) + free((void*)fp); + nv_putv(np, val, flags, fp); return; } if(!np->nvalue.dp) @@ -552,7 +588,9 @@ static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *f register long n; if(!val) { - nv_stack(np, NIL(Namfun_t*)); + fp = nv_stack(np, NIL(Namfun_t*)); + if(fp && !fp->nofree) + free((void*)fp); nv_unset(np); return; } @@ -608,7 +646,9 @@ static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp) Shell_t *shp = nv_shell(np); if(!val) { - nv_stack(np, NIL(Namfun_t*)); + fp = nv_stack(np, NIL(Namfun_t*)); + if(fp && !fp->nofree) + free((void*)fp); nv_unset(np); return; } @@ -627,8 +667,11 @@ static char* get_lineno(register Namval_t* np, Namfun_t *fp) static char* get_lastarg(Namval_t* np, Namfun_t *fp) { - Shell_t *shp = nv_shell(np); - NOT_USED(np); + Shell_t *shp = nv_shell(np); + char *cp; + int pid; + if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*') + nv_putval(np,(pid==getppid()?cp+1:0),0); return(shp->lastarg); } @@ -640,14 +683,15 @@ static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp) sfprintf(shp->strbuf,"%.*g",12,*((double*)val)); val = sfstruse(shp->strbuf); } + if(val) + val = strdup(val); if(shp->lastarg && !nv_isattr(np,NV_NOFREE)) free((void*)shp->lastarg); else nv_offattr(np,NV_NOFREE); - if(val) - shp->lastarg = strdup(val); - else - shp->lastarg = 0; + shp->lastarg = (char*)val; + nv_offattr(np,NV_EXPORT); + np->nvenv = 0; } static int hasgetdisc(register Namfun_t *fp) @@ -979,6 +1023,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) register int n; int type; static char *login_files[3]; + memfatal(); n = strlen(e_version); if(e_version[n-1]=='$' && e_version[n-2]==' ') e_version[n-2]=0; @@ -1001,6 +1046,41 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) #if ERROR_VERSION >= 20000102L error_info.catalog = e_dict; #endif +#if SHOPT_REGRESS + { + Opt_t* nopt; + Opt_t* oopt; + char* a; + char** av = argv; + char* regress[3]; + + sh_regress_init(shp); + regress[0] = "__regress__"; + regress[2] = 0; + /* NOTE: only shp is used by __regress__ at this point */ + shp->bltindata.shp = shp; + while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r')) + { + if (a[1] == 'I') + { + if (a[2]) + regress[1] = a + 2; + else if (!(regress[1] = *++av)) + break; + } + else if (strncmp(a+2, "regress", 7)) + break; + else if (a[9] == '=') + regress[1] = a + 10; + else if (!(regress[1] = *++av)) + break; + nopt = optctx(0, 0); + oopt = optctx(nopt, 0); + b___regress__(2, regress, &shp->bltindata); + optctx(oopt, nopt); + } + } +#endif shp->cpipe[0] = -1; shp->coutpipe = -1; shp->userid=getuid(); @@ -1051,6 +1131,11 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) shp->login_sh = 2; } env_init(shp); + if(!ENVNOD->nvalue.cp) + { + sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME)); + nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY); + } *SHLVL->nvalue.ip +=1; #if SHOPT_SPAWN { @@ -1058,15 +1143,20 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) * try to find the pathname for this interpreter * try using environment variable _ or argv[0] */ - char *last, *cp=nv_getval(L_ARGNOD); + char *cp=nv_getval(L_ARGNOD); char buff[PATH_MAX+1]; shp->shpath = 0; +#if _AST_VERSION >= 20090202L + if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff)) + shp->shpath = strdup(buff); +#else sfprintf(shp->strbuf,"/proc/%d/exe",getpid()); if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0) { buff[n] = 0; shp->shpath = strdup(buff); } +#endif else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/'))) { if(*cp=='/') @@ -1168,17 +1258,16 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) /* set[ug]id scripts require the -p flag */ if(shp->userid!=shp->euserid || shp->groupid!=shp->egroupid) { -#if SHOPT_P_SUID +#ifdef SHOPT_P_SUID /* require sh -p to run setuid and/or setgid */ - if(!sh_isoption(SH_PRIVILEGED) && shp->euserid < SHOPT_P_SUID) + if(!sh_isoption(SH_PRIVILEGED) && shp->userid >= SHOPT_P_SUID) { setuid(shp->euserid=shp->userid); setgid(shp->egroupid=shp->groupid); } else -#else - sh_onoption(SH_PRIVILEGED); #endif /* SHOPT_P_SUID */ + sh_onoption(SH_PRIVILEGED); #ifdef SHELLMAGIC /* careful of #! setuid scripts with name beginning with - */ if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0) @@ -1305,7 +1394,14 @@ int sh_reinit(char *argv[]) sh_offstate(SH_FORKED); shp->fn_depth = shp->dot_depth = 0; sh_sigreset(0); + if(!(SHLVL->nvalue.ip)) + { + shlvl = 0; + SHLVL->nvalue.ip = &shlvl; + nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE); + } *SHLVL->nvalue.ip +=1; + shp->st.filename = strdup(shp->lastarg); return(1); } @@ -1314,7 +1410,7 @@ int sh_reinit(char *argv[]) */ Namfun_t *nv_cover(register Namval_t *np) { - if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS) + if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD) return(np->nvfun); #ifdef _hdr_locale if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD) @@ -1433,7 +1529,6 @@ static void stat_init(Shell_t *shp) */ static Init_t *nv_init(Shell_t *shp) { - static int shlvl=0; Namval_t *np; register Init_t *ip; double d=0; diff --git a/usr/src/lib/libshell/common/sh/io.c b/usr/src/lib/libshell/common/sh/io.c index 50fa35561f..547a67aa27 100644 --- a/usr/src/lib/libshell/common/sh/io.c +++ b/usr/src/lib/libshell/common/sh/io.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -31,7 +31,6 @@ #include <fcin.h> #include <ls.h> #include <stdarg.h> -#include <ctype.h> #include <regex.h> #include "variables.h" #include "path.h" @@ -406,7 +405,7 @@ void sh_ioinit(Shell_t *shp) sh_iostream(shp,0); /* all write steams are in the same pool and share outbuff */ shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */ - shp->outbuff = (char*)malloc(IOBSIZE); + shp->outbuff = (char*)malloc(IOBSIZE+4); shp->errbuff = (char*)malloc(IOBSIZE/4); sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4); sfsetbuf(sfstdout,shp->outbuff,IOBSIZE); @@ -548,7 +547,11 @@ static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2) if(f2==shp->infd) shp->infd = fd; if(fd<0) + { + shp->toomany = 1; + ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; errormsg(SH_DICT,ERROR_system(1),e_toomany); + } if(shp->fdptrs[fd]=shp->fdptrs[f2]) { if(f2==job.fd) @@ -717,6 +720,20 @@ int sh_open(register const char *path, int flags, ...) } if (fd >= 0) { + int nfd= -1; + if (flags & O_CREAT) + { + struct stat st; + if (stat(path,&st) >=0) + nfd = open(path,flags,st.st_mode); + } + else + nfd = open(path,flags); + if(nfd>=0) + { + fd = nfd; + goto ok; + } if((mode=sh_iocheckfd(shp,fd))==IOCLOSE) return(-1); flags &= O_ACCMODE; @@ -727,12 +744,21 @@ int sh_open(register const char *path, int flags, ...) if((fd=dup(fd))<0) return(-1); } - else while((fd = open(path, flags, mode)) < 0) - if(errno!=EINTR || sh.trapnote) - return(-1); -#ifdef O_SERVICE - ok: + else + { +#if SHOPT_REGRESS + char buf[PATH_MAX]; + if(strncmp(path,"/etc/",5)==0) + { + sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4); + path = buf; + } #endif + while((fd = open(path, flags, mode)) < 0) + if(errno!=EINTR || sh.trapnote) + return(-1); + } + ok: flags &= O_ACCMODE; if(flags==O_WRONLY) mode = IOWRITE; @@ -939,10 +965,11 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) const char *message = e_open; int o_mode; /* mode flag for open */ static char io_op[7]; /* used for -x trace info */ - int clexec=0, fn, traceon; + int trunc=0, clexec=0, fn, traceon; int r, indx = shp->topfd, perm= -1; char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP]; Namval_t *np=0; + int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0; if(flag==2) clexec = 1; if(iop) @@ -951,7 +978,7 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) { iof=iop->iofile; fn = (iof&IOUFD); - if(fn==1 && shp->subshell && (flag==2 || (sfset(sfstdout,0,0)&SF_STRING))) + if(fn==1 && shp->subshell && !shp->subshare && (flag==2 || isstring)) sh_subfork(); io_op[0] = '0'+(iof&IOUFD); if(iof&IOPUT) @@ -978,6 +1005,16 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) strcpy(ap->argval,iop->ioname); fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP); } + else if(iof&IOPROCSUB) + { + struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname)); + memset(ap, 0, ARGVAL); + if(iof&IOPUT) + ap->argflag = ARG_RAW; + ap->argchn.ap = (struct argnod*)fname; + ap = sh_argprocsub(shp,ap); + fname = ap->argval; + } else fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0); } @@ -1033,7 +1070,7 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) message = e_file; goto fail; } - if(shp->subshell && dupfd==1) + if(shp->subshell && dupfd==1 && (sfset(sfstdout,0,0)&SF_STRING)) { sh_subtmpfile(0); dupfd = sffileno(sfstdout); @@ -1083,6 +1120,8 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname); io_op[2] = '>'; o_mode = O_RDWR|O_CREAT; + if(iof&IOREWRITE) + trunc = io_op[2] = ';'; goto openit; } else if(!(iof&IOPUT)) @@ -1197,7 +1236,10 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) if((off = file_offset(shp,fn,fname))<0) goto fail; if(sp) + { off=sfseek(sp, off, SEEK_SET); + sfsync(sp); + } else off=lseek(fn, off, SEEK_SET); if(off<0) @@ -1245,7 +1287,7 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) sh_close(fn); } } - sh_iosave(shp,fn,indx,tname?fname:0); + sh_iosave(shp,fn,indx,tname?fname:(trunc?Empty:0)); } else if(sh_subsavefd(fn)) sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0); @@ -1422,7 +1464,11 @@ void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name) #endif /* SHOPT_DEVFD */ { if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF) + { + shp->toomany=1; + ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; errormsg(SH_DICT,ERROR_system(1),e_toomany); + } } filemap[shp->topfd].tname = name; filemap[shp->topfd].subshell = flag; @@ -1492,7 +1538,9 @@ void sh_iorestore(Shell_t *shp, int last, int jmpval) continue; } origfd = filemap[fd].orig_fd; - if(filemap[fd].tname) + if(filemap[fd].tname == Empty && shp->exitval==0) + ftruncate(origfd,lseek(origfd,0,SEEK_CUR)); + else if(filemap[fd].tname) io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1); sh_close(origfd); if ((savefd = filemap[fd].save_fd) >= 0) @@ -1638,7 +1686,10 @@ static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *ha int fd = sffileno(iop); NOT_USED(handle); if(job.waitsafe && job.savesig) - job_reap(job.savesig); + { + job_lock(); + job_unlock(); + } if(sh.trapnote) { errno = EINTR; @@ -1942,14 +1993,7 @@ static void sftrack(Sfio_t* sp, int flag, void* data) if(mode&SF_READ) flag |= IOREAD; shp->fdstatus[fd] = flag; -#if 0 - if(flag==IOWRITE) - sfpool(sp,shp->outpool,SF_WRITE); - else -#else - if(flag!=IOWRITE) -#endif - sh_iostream(shp,fd); + sh_iostream(shp,fd); } if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD) { diff --git a/usr/src/lib/libshell/common/sh/jobs.c b/usr/src/lib/libshell/common/sh/jobs.c index 0c9724ce0f..778be37706 100644 --- a/usr/src/lib/libshell/common/sh/jobs.c +++ b/usr/src/lib/libshell/common/sh/jobs.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -30,7 +30,6 @@ */ #include "defs.h" -#include <ctype.h> #include <wait.h> #include "io.h" #include "jobs.h" @@ -77,24 +76,6 @@ static void init_savelist(void) } } -/* - * return next on link list of jobsave free list - */ -static struct jobsave *jobsave_create(pid_t pid) -{ - register struct jobsave *jp = job_savelist; - if(jp) - { - njob_savelist--; - job_savelist = jp->next; - } - else - jp = newof(0,struct jobsave,1,0); - if(jp) - jp->pid = pid; - return(jp); -} - struct back_save { int count; @@ -132,6 +113,9 @@ struct back_save #define P_COREDUMP 0100 #define P_DISOWN 0200 #define P_FG 0400 +#ifdef SHOPT_BGX +#define P_BG 01000 +#endif /* SHOPT_BGX */ static int job_chksave(pid_t); static struct process *job_bypid(pid_t); @@ -151,7 +135,6 @@ static Sfio_t *outfile; static pid_t lastpid; static struct back_save bck; - #ifdef JOBS static void job_set(struct process*); static void job_reset(struct process*); @@ -195,6 +178,62 @@ static struct back_save bck; typedef int (*Waitevent_f)(int,long,int); +#ifdef SHOPT_BGX +void job_chldtrap(Shell_t *shp, const char *trap, int unpost) +{ + register struct process *pw,*pwnext; + pid_t bckpid; + int oldexit; + job_lock(); + shp->sigflag[SIGCHLD] &= ~SH_SIGTRAP; + for(pw=job.pwlist;pw;pw=pwnext) + { + pwnext = pw->p_nxtjob; + if((pw->p_flag&(P_BG|P_DONE)) != (P_BG|P_DONE)) + continue; + pw->p_flag &= ~P_BG; + bckpid = shp->bckpid; + oldexit = shp->savexit; + shp->bckpid = pw->p_pid; + shp->savexit = pw->p_exit; + if(pw->p_flag&P_SIGNALLED) + shp->savexit |= SH_EXITSIG; + sh_trap(trap,0); + shp->savexit = oldexit; + shp->bckpid = bckpid; + if(unpost) + job_unpost(pw,0); + } + job_unlock(); +} +#endif /* SHOPT_BGX */ + +/* + * return next on link list of jobsave free list + */ +static struct jobsave *jobsave_create(pid_t pid) +{ + register struct jobsave *jp = job_savelist; + job_chksave(pid); + if(++bck.count > sh.lim.child_max) + job_chksave(0); + if(jp) + { + njob_savelist--; + job_savelist = jp->next; + } + else + jp = newof(0,struct jobsave,1,0); + if(jp) + { + jp->pid = pid; + jp->next = bck.list; + bck.list = jp; + jp->exitval = 0; + } + return(jp); +} + /* * Reap one job * When called with sig==0, it does a blocking wait @@ -206,7 +245,6 @@ int job_reap(register int sig) struct process *px; register int flags; struct jobsave *jp; - struct back_save *bp; int nochild=0, oerrno, wstat; Waitevent_f waitevent = sh.waitevent; static int wcontinued = WCONTINUED; @@ -268,14 +306,7 @@ int job_reap(register int sig) pw->p_exitmin = 0; if(job.toclear) job_clear(); - if(++bck.count > sh.lim.child_max) - job_chksave(0); - if(jp = jobsave_create(pid)) - { - jp->next = bck.list; - bck.list = jp; - jp->exitval = 0; - } + jp = jobsave_create(pid); pw->p_flag = 0; lastpid = pw->p_pid = pid; px = 0; @@ -344,6 +375,22 @@ int job_reap(register int sig) if(WEXITSTATUS(wstat) > pw->p_exitmin) pw->p_exit = WEXITSTATUS(wstat); } +#ifdef SHOPT_BGX + if((pw->p_flag&P_DONE) && (pw->p_flag&P_BG)) + { + job.numbjob--; + if(sh.st.trapcom[SIGCHLD]) + { + sh.sigflag[SIGCHLD] |= SH_SIGTRAP; + if(sig==0) + job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],0); + else + sh.trapnote |= SH_SIGTRAP; + } + else + pw->p_flag &= ~P_BG; + } +#endif /* SHOPT_BGX */ if(pw->p_pgrp==0) pw->p_flag &= ~P_NOTIFY; } @@ -367,15 +414,20 @@ int job_reap(register int sig) if(!px) tcsetpgrp(JOBTTY,job.mypid); } +#ifndef SHOPT_BGX if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid))) { sh.sigflag[SIGCHLD] |= SH_SIGTRAP; sh.trapnote |= SH_SIGTRAP; } +#endif } if(errno==ECHILD) { errno = oerrno; +#ifdef SHOPT_BGX + job.numbjob = 0; +#endif /* SHOPT_BGX */ nochild = 1; } sh.waitevent = waitevent; @@ -1045,6 +1097,9 @@ void job_clear(void) init_savelist(); job.pwlist = NIL(struct process*); job.numpost=0; +#ifdef SHOPT_BGX + job.numbjob = 0; +#endif /* SHOPT_BGX */ job.waitall = 0; job.curpgid = 0; job.toclear = 0; @@ -1064,16 +1119,28 @@ int job_post(pid_t pid, pid_t join) { register struct process *pw; register History_t *hp = sh.hist_ptr; +#ifdef SHOPT_BGX + int val,bg=0; +#else int val; +#endif sh.jobenv = sh.curenv; - if(njob_savelist < NJOB_SAVELIST) - init_savelist(); if(job.toclear) { job_clear(); return(0); } job_lock(); +#ifdef SHOPT_BGX + if(join==1) + { + join = 0; + bg = P_BG; + job.numbjob++; + } +#endif /* SHOPT_BGX */ + if(njob_savelist < NJOB_SAVELIST) + init_savelist(); if(pw = job_bypid(pid)) job_unpost(pw,0); if(join && (pw=job_bypid(join))) @@ -1090,6 +1157,7 @@ int job_post(pid_t pid, pid_t join) freelist = pw->p_nxtjob; else pw = new_of(struct process,0); + pw->p_flag = 0; job.numpost++; if(join && job.pwlist) { @@ -1109,7 +1177,8 @@ int job_post(pid_t pid, pid_t join) job.pwlist = pw; pw->p_env = sh.curenv; pw->p_pid = pid; - pw->p_flag = P_EXITSAVE; + if(!sh.outpipe || sh_isoption(SH_PIPEFAIL)) + pw->p_flag = P_EXITSAVE; pw->p_exitmin = sh.xargexit; pw->p_exit = 0; if(sh_isstate(SH_MONITOR)) @@ -1140,9 +1209,18 @@ int job_post(pid_t pid, pid_t join) pw->p_flag |= (P_SIGNALLED|P_STOPPED); pw->p_exit = 0; } + else if(pw->p_exit >= SH_EXITSIG) + { + pw->p_flag |= P_DONE|P_SIGNALLED; + pw->p_exit &= SH_EXITMASK; + } else pw->p_flag |= (P_DONE|P_NOTIFY); } +#ifdef SHOPT_BGX + if(bg && !(pw->p_flag&P_DONE)) + pw->p_flag |= P_BG; +#endif /* SHOPT_BGX */ lastpid = 0; job_unlock(); return(pw->p_job); @@ -1334,13 +1412,8 @@ int job_wait(register pid_t pid) px->p_flag &= ~P_EXITSAVE; } } - if(!job.waitall) - { - if(!sh_isoption(SH_PIPEFAIL)) - job_unpost(pw,1); - break; - } - else if(!(px=job_unpost(pw,1))) + px = job_unpost(pw,1); + if(!px || !sh_isoption(SH_PIPEFAIL)) break; pw = px; continue; @@ -1430,6 +1503,9 @@ int job_switch(register struct process *pw,int bgflag) { sfprintf(outfile,"[%d]\t",(int)pw->p_job); sh.bckpid = pw->p_pid; +#ifdef SHOPT_BGX + pw->p_flag |= P_BG; +#endif msg = "&"; } else @@ -1451,6 +1527,9 @@ int job_switch(register struct process *pw,int bgflag) } job.waitall = 1; pw->p_flag |= P_FG; +#ifdef SHOPT_BGX + pw->p_flag &= ~P_BG; +#endif job_wait(pw->p_pid); job.waitall = 0; } @@ -1515,6 +1594,10 @@ static struct process *job_unpost(register struct process *pwtop,int notify) sfsync(sfstderr); #endif /* DEBUG */ pwtop = pw = job_byjid((int)pwtop->p_job); +#ifdef SHOPT_BGX + if(pw->p_flag&P_BG) + return(pw); +#endif /* SHOPT_BGX */ for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc); if(pw) return(pw); @@ -1527,12 +1610,8 @@ static struct process *job_unpost(register struct process *pwtop,int notify) { struct jobsave *jp; /* save status for future wait */ - if(bck.count++ > sh.lim.child_max) - job_chksave(0); if(jp = jobsave_create(pw->p_pid)) { - jp->next = bck.list; - bck.list = jp; jp->exitval = pw->p_exit; if(pw->p_flag&P_SIGNALLED) jp->exitval |= SH_EXITSIG; @@ -1630,7 +1709,7 @@ static char *job_sigmsg(int sig) if ( sig == SIGAPOLLO ) return( apollo_error() ); #endif /* apollo */ - if(sig<sh.sigmax && sh.sigmsg[sig]) + if(sig<=sh.sigmax && sh.sigmsg[sig]) return(sh.sigmsg[sig]); #if defined(SIGRTMIN) && defined(SIGRTMAX) if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX]) @@ -1656,7 +1735,8 @@ static int job_chksave(register pid_t pid) { register struct jobsave *jp = bck.list, *jpold=0; register int r= -1; - while(jp) + register int count=bck.count; + while(jp && count-->0) { if(jp->pid==pid) break; @@ -1712,6 +1792,7 @@ void job_subrestore(void* ptr) { jp->next = bp->list; bp->list = jp; + bp->count++; } else job_chksave(jp->pid); @@ -1719,7 +1800,7 @@ void job_subrestore(void* ptr) for(pw=job.pwlist; pw; pw=pwnext) { pwnext = pw->p_nxtjob; - if(pw->p_env != sh.curenv) + if(pw->p_env != sh.curenv || pw->p_pid==sh.pipepid) continue; for(px=pw; px; px=px->p_nxtproc) px->p_flag |= P_DONE; diff --git a/usr/src/lib/libshell/common/sh/lex.c b/usr/src/lib/libshell/common/sh/lex.c index 9753ea8074..b5a0761dae 100644 --- a/usr/src/lib/libshell/common/sh/lex.c +++ b/usr/src/lib/libshell/common/sh/lex.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -100,6 +100,7 @@ struct lexdata int lex_max; int *lex_match; int lex_state; + int docextra; #if SHOPT_KIA off_t kiaoff; #endif @@ -196,6 +197,12 @@ static void lex_advance(Sfio_t *iop, const char *buff, register int size, void * #endif if(lp->lexd.nocopy) return; + if(lp->lexd.dolparen && lp->lexd.docword) + { + int n = size - (lp->lexd.docend-(char*)buff); + sfwrite(shp->strbuf,lp->lexd.docend,n); + lp->lexd.docextra += n; + } if(lp->lexd.first) { size -= (lp->lexd.first-(char*)buff); @@ -222,12 +229,13 @@ static int lexfill(Lex_t *lp) register int c; Lex_t savelex; struct argnod *ap; - int aok; + int aok,docextra; savelex = *lp; ap = lp->arg; c = fcfill(); if(ap) lp->arg = ap; + docextra = lp->lexd.docextra; lp->lex = savelex.lex; lp->lexd = savelex.lexd; if(fcfile() || c) @@ -237,6 +245,11 @@ static int lexfill(Lex_t *lp) memcpy(lp, &savelex, offsetof(Lex_t,lexd)); lp->arg = ap; lp->aliasok = aok; + if(lp->lexd.docword && docextra) + { + lp->lexd.docextra = docextra; + lp->lexd.docend = fcseek(0)-1; + } return(c); } @@ -533,14 +546,17 @@ int sh_lex(Lex_t* lp) return(lp->token=c); else if(c=='&') { -#if SHOPT_BASH - if(!sh_isoption(SH_POSIX) && n=='>') + if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE))) { + if(!sh_isoption(SH_BASH) && !lp->nonstandard) + { + lp->nonstandard = 1; + errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno); + } lp->digits = -1; c = '>'; } else -#endif n = 0; } else if(n=='&') @@ -556,7 +572,20 @@ int sh_lex(Lex_t* lp) else if(n=='|') c |= SYMPIPE; else if(c=='<' && n=='>') + { + lp->digits = 1; c = IORDWRSYM; + fcgetc(n); + if(fcgetc(n)==';') + { + lp->token = c = IORDWRSYMT; + if(lp->inexec) + sh_syntax(lp); + } + else if(n>0) + fcseek(-1); + n= 0; + } else if(n=='#' && (c=='<'||c=='>')) c |= SYMSHARP; else if(n==';' && c=='>') @@ -577,7 +606,7 @@ int sh_lex(Lex_t* lp) } else { - if((n=fcpeek(0))!=RPAREN && n!=LPAREN && lp->lexd.warn) + if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t') errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n); } } @@ -762,7 +791,7 @@ int sh_lex(Lex_t* lp) lp->lastline = shp->inlineno; pushlevel(lp,c,mode); } - ingrave = (c=='`'); + ingrave ^= (c=='`'); mode = ST_QUOTE; continue; } @@ -985,7 +1014,7 @@ int sh_lex(Lex_t* lp) { if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE)) errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); - else if(c=='"' && mode!=ST_QUOTE) + else if(c=='"' && mode!=ST_QUOTE && !ingrave) wordflags |= ARG_MESSAGE; fcseek(-1); } @@ -1111,6 +1140,16 @@ int sh_lex(Lex_t* lp) (oldmode(lp)==ST_NONE) || (mode==ST_NAME && (lp->assignok||lp->lexd.level))) { + if(mode==ST_NAME) + { + fcgetc(n); + if(n>0) + { + if(n==']') + errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript"); + fcseek(-1); + } + } pushlevel(lp,RBRACT,mode); wordflags |= ARG_QUOTED; mode = ST_NESTED; @@ -1522,6 +1561,7 @@ static int comsub(register Lex_t *lp, int endtok) fcseek(-1); break; case IODOCSYM: + lp->lexd.docextra = 0; sh_lex(lp); break; case 0: @@ -1564,9 +1604,14 @@ static void nested_here(register Lex_t *lp) if(offset=stktell(stkp)) base = stkfreeze(stkp,0); n = fcseek(0)-lp->lexd.docend; - iop = newof(0,struct ionod,1,n+ARGVAL); + iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL); iop->iolst = lp->heredoc; stkseek(stkp,ARGVAL); + if(lp->lexd.docextra) + { + sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET); + sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1); + } sfwrite(stkp,lp->lexd.docend,n); lp->arg = sh_endword(lp->sh,0); iop->ioname = (char*)(iop+1); @@ -1839,9 +1884,9 @@ static int here_copy(Lex_t *lp,register struct ionod *iop) { /* new-line joining */ lp->sh->inlineno++; - if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>0) + if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0) { - if((n=sfwrite(sp,bufp,n))>0) + if(n && (n=sfwrite(sp,bufp,n))>0) iop->iosize += n; bufp = fcseek(0)+1; } @@ -1872,6 +1917,7 @@ done: */ static char *fmttoken(Lex_t *lp, register int sym, char *tok) { + int n=1; if(sym < 0) return((char*)sh_translate(e_lexzerobyte)); if(sym==0) @@ -1891,7 +1937,7 @@ static char *fmttoken(Lex_t *lp, register int sym, char *tok) return((char*)sh_translate(e_newline)); tok[0] = sym; if(sym&SYMREP) - tok[1] = sym; + tok[n++] = sym; else { switch(sym&SYMMASK) @@ -1912,14 +1958,16 @@ static char *fmttoken(Lex_t *lp, register int sym, char *tok) sym = '#'; break; case SYMSEMI: + if(tok[0]=='<') + tok[n++] = '>'; sym = ';'; break; default: sym = 0; } - tok[1] = sym; + tok[n++] = sym; } - tok[2] = 0; + tok[n] = 0; return(tok); } diff --git a/usr/src/lib/libshell/common/sh/macro.c b/usr/src/lib/libshell/common/sh/macro.c index cb938764d6..684e2d0464 100644 --- a/usr/src/lib/libshell/common/sh/macro.c +++ b/usr/src/lib/libshell/common/sh/macro.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -38,6 +38,7 @@ #include "variables.h" #include "shlex.h" #include "io.h" +#include "jobs.h" #include "shnodes.h" #include "path.h" #include "national.h" @@ -529,8 +530,13 @@ static void copyto(register Mac_t *mp,int endch, int newquote) { /* preserve \digit for pattern matching */ /* also \alpha for extended patterns */ - if(!mp->lit && !mp->quote && (n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP))) - break; + if(!mp->lit && !mp->quote) + { + if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP))) + break; + if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp)) + break; + } /* followed by file expansion */ if(!mp->lit && (n==S_ESC || (!mp->quote && (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-')))) @@ -647,8 +653,14 @@ static void copyto(register Mac_t *mp,int endch, int newquote) int offset=0,oldpat = mp->pattern; int oldarith = mp->arith, oldsub=mp->subcopy; sfwrite(stkp,first,++c); - if((mp->assign&1) && first[c-2]=='.') - offset = stktell(stkp); + if(mp->assign&1) + { + if(first[c-2]=='.') + offset = stktell(stkp); + if(isastchar(*cp) && cp[1]==']') + errormsg(SH_DICT,ERROR_exit(1), +e_badsubscript,*cp); + } first = fcseek(c); mp->pattern = 4; mp->arith = 0; @@ -678,7 +690,7 @@ static void copyto(register Mac_t *mp,int endch, int newquote) { char *p = cp; while((c=mbchar(p)) && c!=RPAREN && c!='E'); - ere = c=='E'; + ere = (c=='E'||c=='A'); } } else if(n==RPAREN) @@ -892,7 +904,7 @@ static char *getdolarg(Shell_t *shp, int n, int *size) static char *prefix(Shell_t *shp, char *id) { Namval_t *np; - register char *cp = strchr(id,'.'); + register char *sub=0, *cp = strchr(id,'.'); if(cp) { *cp = 0; @@ -905,11 +917,23 @@ static char *prefix(Shell_t *shp, char *id) int n; char *sp; shp->argaddr = 0; - while(nv_isref(np)) + while(nv_isref(np) && np->nvalue.cp) + { + sub = nv_refsub(np); np = nv_refnode(np); - id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+1); - strcpy(&id[n],cp); + if(sub) + nv_putsub(np,sub,0L); + } + id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1)); memcpy(id,sp,n); + if(sub) + { + id[n++] = '['; + strcpy(&id[n],sub); + n+= strlen(sub)+1; + id[n-1] = ']'; + } + strcpy(&id[n],cp); return(id); } } @@ -961,7 +985,7 @@ int sh_macfun(Shell_t *shp, const char *name, int offset) tp = (Shnode_t*)&node; tp->com.comarg = (struct argnod*)dp; tp->com.comline = shp->inlineno; - dp->dolnum = 2; + dp->dolnum = 1; dp->dolval[0] = strdup(name); stkseek(shp->stk,offset); comsubst((Mac_t*)shp->mac_context,tp,2); @@ -1009,14 +1033,14 @@ static int varsub(Mac_t *mp) Namarr_t *ap=0; int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0; char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0; - int addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d; + int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d; Stk_t *stkp = mp->shp->stk; retry1: mp->zeros = 0; idbuff[0] = 0; idbuff[1] = 0; c = fcget(); - switch(c>0x7f?S_ALP:sh_lexstates[ST_DOL][c]) + switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP) { case S_RBRA: if(type<M_SIZE) @@ -1053,6 +1077,7 @@ retry1: } /* FALL THRU */ case S_SPC2: + var = 0; *id = c; v = special(mp->shp,c); if(isastchar(c)) @@ -1081,6 +1106,7 @@ retry1: comsubst(mp,(Shnode_t*)0,1); return(1); case S_DIG: + var = 0; c -= '0'; mp->shp->argaddr = 0; if(type) @@ -1117,7 +1143,7 @@ retry1: np = 0; do sfputc(stkp,c); - while(((c=fcget()),(c>0x7f||isaname(c)))||type && c=='.'); + while(((c=fcget()),(!isascii(c)||isaname(c)))||type && c=='.'); while(c==LBRACT && (type||mp->arrayok)) { mp->shp->argaddr=0; @@ -1204,10 +1230,14 @@ retry1: } else #endif /* SHOPT_FILESCAN */ - if(mp->shp->argaddr) - flag &= ~NV_NOADD; - np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL); - if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY)) + { + if(mp->shp->argaddr) + flag &= ~NV_NOADD; + np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL); + } + if(isastchar(mode)) + var = 0; + if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.')) { if(sh_macfun(mp->shp,id,offset)) { @@ -1215,6 +1245,13 @@ retry1: return(1); } } + if(np && (flag&NV_NOADD) && nv_isnull(np)) + { + if(nv_isattr(np,NV_NOFREE)) + nv_offattr(np,NV_NOFREE); + else + np = 0; + } ap = np?nv_arrayptr(np):0; if(type) { @@ -1299,7 +1336,15 @@ retry1: v = nv_getvtree(np,(Namfun_t*)0); else { - v = nv_getval(np); + if(type && fcpeek(0)=='+') + { + if(ap) + v = nv_arrayisset(np,ap)?(char*)"x":0; + else + v = nv_isnull(np)?0:(char*)"x"; + } + else + v = nv_getval(np); /* special case --- ignore leading zeros */ if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c))) mp->zeros = 1; @@ -1345,6 +1390,7 @@ retry1: mac_error(np); if(type==M_NAMESCAN || type==M_NAMECOUNT) { + mp->shp->last_root = mp->shp->var_tree; id = prefix(mp->shp,id); stkseek(stkp,offset); if(type==M_NAMECOUNT) @@ -1432,6 +1478,7 @@ retry1: int quoted = mp->quoted; int arith = mp->arith; int zeros = mp->zeros; + int assign = mp->assign; if(newops) { type = fcget(); @@ -1446,6 +1493,7 @@ retry1: mp->pattern = 1+(c=='/'); mp->split = 0; mp->quoted = 0; + mp->assign &= ~1; mp->arith = mp->zeros = 0; newquote = 0; } @@ -1459,6 +1507,7 @@ retry1: mp->quoted = quoted; mp->arith = arith; mp->zeros = zeros; + mp->assign = assign; /* add null byte */ sfputc(stkp,0); stkseek(stkp,stktell(stkp)-1); @@ -1803,7 +1852,7 @@ retry2: mac_error(np); } } - else if(sh_isoption(SH_NOUNSET) && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp))) + else if(var && sh_isoption(SH_NOUNSET) && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp))) { if(np) { @@ -2467,7 +2516,6 @@ static char *sh_tilde(Shell_t *shp,register const char *string) */ static char *special(Shell_t *shp,register int c) { - register Namval_t *np; if(c!='$') shp->argaddr = 0; switch(c) @@ -2497,10 +2545,10 @@ static char *special(Shell_t *shp,register int c) case '?': return(ltos(shp->savexit)); case 0: - if(sh_isstate(SH_PROFILE) || !error_info.id || ((np=nv_search(error_info.id,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))) + if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname) return(shp->shname); else - return(error_info.id); + return(shp->st.cmdname); } return(NIL(char*)); } diff --git a/usr/src/lib/libshell/common/sh/main.c b/usr/src/lib/libshell/common/sh/main.c index 793e978b56..54949b0d85 100644 --- a/usr/src/lib/libshell/common/sh/main.c +++ b/usr/src/lib/libshell/common/sh/main.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -37,6 +37,7 @@ #include "path.h" #include "io.h" #include "jobs.h" +#include "shlex.h" #include "shnodes.h" #include "history.h" #include "timeout.h" @@ -114,10 +115,14 @@ int sh_source(Shell_t *shp, Sfio_t *iop, const char *file) int fd; if (!file || !*file || (fd = path_open(file, PATHCOMP)) < 0) + { + REGRESS(source, "sh_source", ("%s:ENOENT", file)); return 0; + } oid = error_info.id; nid = error_info.id = strdup(file); shp->st.filename = path_fullname(stakptr(PATH_OFFSET)); + REGRESS(source, "sh_source", ("%s", file)); exfile(shp, iop, fd); error_info.id = oid; free(nid); @@ -177,6 +182,7 @@ int sh_main(int ac, char *av[], Shinit_f userinit) if((beenhere++)==0) { sh_onstate(SH_PROFILE); + ((Lex_t*)shp->lex_context)->nonstandard = 0; if(shp->ppid==1) shp->login_sh++; if(shp->login_sh >= 2) @@ -274,8 +280,10 @@ int sh_main(int ac, char *av[], Shinit_f userinit) /* open stream should have been passed into shell */ if(strmatch(name,e_devfdNN)) { +#if !_WINIX char *cp; int type; +#endif fdin = (int)strtol(name+8, (char**)0, 10); if(fstat(fdin,&statb)<0) errormsg(SH_DICT,ERROR_system(1),e_open,name); diff --git a/usr/src/lib/libshell/common/sh/name.c b/usr/src/lib/libshell/common/sh/name.c index bbdeeb83dd..2189a3a42a 100644 --- a/usr/src/lib/libshell/common/sh/name.c +++ b/usr/src/lib/libshell/common/sh/name.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -26,7 +26,6 @@ #define putenv ___putenv #include "defs.h" -#include <ctype.h> #include "variables.h" #include "path.h" #include "lexstates.h" @@ -88,6 +87,7 @@ struct adata struct Cache_entry { Dt_t *root; + Dt_t *last_root; char *name; Namval_t *np; Namval_t *last_table; @@ -283,7 +283,7 @@ struct argnod *nv_onlist(struct argnod *arg, const char *name) * Perform parameter assignment for a linked list of parameters * <flags> contains attributes for the parameters */ -void nv_setlist(register struct argnod *arg,register int flags) +void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) { Shell_t *shp = &sh; register char *cp; @@ -340,6 +340,8 @@ void nv_setlist(register struct argnod *arg,register int flags) else cp = fp->fornam; error_info.line = fp->fortyp-shp->st.firstline; + if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[') + array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY; if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET) flag |= NV_NOSCOPE; if(prefix && tp->com.comset && *cp=='[') @@ -359,13 +361,15 @@ void nv_setlist(register struct argnod *arg,register int flags) } } np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN); + if(typ && !array && (nv_isnull(np) || nv_isarray(np))) + nv_settype(np,typ,0); if((flags&NV_STATIC) && !nv_isnull(np)) #if SHOPT_TYPEDEF goto check_type; #else continue; #endif /* SHOPT_TYPEDEF */ - if(array) + if(array && (!(ap=nv_arrayptr(np)) || !ap->hdr.type)) { if(!(arg->argflag&ARG_APPEND)) nv_unset(np); @@ -377,7 +381,9 @@ void nv_setlist(register struct argnod *arg,register int flags) { nv_onattr(np,NV_ARRAY); } - if(tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg) + } + if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg) + { #if SHOPT_TYPEDEF goto check_type; #else @@ -444,7 +450,7 @@ void nv_setlist(register struct argnod *arg,register int flags) if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE)) nv_setarray(np,nv_associative); } - nv_setlist(tp->com.comset,flags); + nv_setlist(tp->com.comset,flags,0); shp->prefix = prefix; if(tp->com.comset->argval[1]!='[') nv_setvtree(np); @@ -496,17 +502,25 @@ void nv_setlist(register struct argnod *arg,register int flags) else shp->prefix = cp; shp->last_table = 0; - memset(&nr,0,sizeof(nr)); - memcpy(&node,L_ARGNOD,sizeof(node)); - L_ARGNOD->nvalue.nrp = &nr; - nr.np = np; - nr.root = shp->last_root; - nr.table = shp->last_table; - L_ARGNOD->nvflag = NV_REF|NV_NOFREE; - L_ARGNOD->nvfun = 0; + if(shp->prefix) + { + if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD)) + { + sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1); + shp->prefix = stkfreeze(stkstd,1); + } + memset(&nr,0,sizeof(nr)); + memcpy(&node,L_ARGNOD,sizeof(node)); + L_ARGNOD->nvalue.nrp = &nr; + nr.np = np; + nr.root = shp->last_root; + nr.table = shp->last_table; + L_ARGNOD->nvflag = NV_REF|NV_NOFREE; + L_ARGNOD->nvfun = 0; + } sh_exec(tp,sh_isstate(SH_ERREXIT)); #if SHOPT_TYPEDEF - if(!maketype) + if(shp->prefix) #endif { L_ARGNOD->nvalue.nrp = node.nvalue.nrp; @@ -523,7 +537,7 @@ void nv_setlist(register struct argnod *arg,register int flags) tp = tp->lst.lstrit; } - if(!nv_isarray(np) && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='[')) + if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='[')) nv_setvtree(np); #if SHOPT_TYPEDEF goto check_type; @@ -776,7 +790,10 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) if(top) { if(nq==np) + { flags &= ~NV_NOSCOPE; + root = shp->var_base; + } else if(nq) { if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq))) @@ -798,7 +815,7 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) #endif if(c=='.') /* don't optimize */ shp->argaddr = 0; - else if((flags&NV_NOREF) && (c!='[' || *cp!='.')) + else if((flags&NV_NOREF) && (c!='[' && *cp!='.')) { if(c && !(flags&NV_NOADD)) nv_unref(np); @@ -835,6 +852,9 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) flags &= ~NV_NOSCOPE; } flags |= NV_NOREF; + if(nv_isnull(np)) + nv_onattr(np,NV_NOFREE); + } shp->last_root = root; if(cp[1]=='.') @@ -867,8 +887,13 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) { char *sub=0; int n = 0; + mode &= ~HASH_NOSCOPE; if(c=='[') { +#if 0 + Namarr_t *ap = nv_arrayptr(np); + int scan = ap?(ap->nelem&ARRAY_SCAN):0; +#endif n = mode|nv_isarray(np); if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']') { @@ -881,6 +906,10 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) if(flags&NV_ASSIGN) n |= NV_ADD; cp = nv_endsubscript(np,sp,n|(flags&NV_ASSIGN)); +#if 0 + if(scan) + nv_putsub(np,NIL(char*),ARRAY_SCAN); +#endif } else cp = sp; @@ -1000,6 +1029,7 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np) { add = NV_ADD; + shp->last_table = 0; break; } else if(np=nq) @@ -1075,6 +1105,7 @@ void nv_delete(Namval_t* np, Dt_t *root, int flags) * If <flags> & NV_NOREF then don't follow reference * If <flags> & NV_NOFAIL then don't generate an error message on failure * If <flags> & NV_STATIC then unset before an assignment + * If <flags> & NV_UNJUST then unset attributes before assignment * SH_INIT is only set while initializing the environment */ Namval_t *nv_open(const char *name, Dt_t *root, int flags) @@ -1175,6 +1206,7 @@ Namval_t *nv_open(const char *name, Dt_t *root, int flags) if(nv_isarray(np)) nv_putsub(np,NIL(char*),ARRAY_UNDEF); shp->last_table = xp->last_table; + shp->last_root = xp->last_root; goto nocache; } } @@ -1209,6 +1241,7 @@ Namval_t *nv_open(const char *name, Dt_t *root, int flags) xp->root = root; xp->np = np; xp->last_table = shp->last_table; + xp->last_root = shp->last_root; xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE)); nvcache.index = (nvcache.index+1)&(NVCACHE-1); } @@ -1241,7 +1274,6 @@ skip: if(np && shp->mktype) np = nv_addnode(np,0); #endif /* SHOPT_TYPEDEF */ - if(c=='=' && np && (flags&NV_ASSIGN)) { cp++; @@ -1259,7 +1291,10 @@ skip: if((flags&NV_STATIC) && !shp->mktype) { if(!nv_isnull(np)) + { + shp->prefix = prefix; return(np); + } } isref = nv_isref(np); if(sh_isoption(SH_XTRACE) && nv_isarray(np)) @@ -1267,9 +1302,18 @@ skip: c = msg==e_aliname? 0: (append | (flags&NV_EXPORT)); if(isref) nv_offattr(np,NV_REF); + if(!append && (flags&NV_UNJUST)) + { + nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL); + np->nvsize = 0; + } nv_putval(np, cp, c); if(isref) + { + if(nv_search((char*)np,shp->var_base,HASH_BUCKET)) + shp->last_root = shp->var_base; nv_setref(np,(Dt_t*)0,NV_VARNAME); + } savesub = sub; shp->prefix = prefix; } @@ -1325,7 +1369,7 @@ void nv_putval(register Namval_t *np, const char *string, int flags) sh.argaddr = 0; if(sh.subshell && !nv_local) np = sh_assignok(np,1); - if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isattr(np,NV_REF)) + if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np)) { /* This function contains disc */ if(!nv_local) @@ -1387,7 +1431,7 @@ void nv_putval(register Namval_t *np, const char *string, int flags) up->ldp = new_of(Sfdouble_t,0); else if(flags&NV_APPEND) old = *(up->ldp); - *(up->ldp) = ld+old; + *(up->ldp) = old?ld+old:ld; } else { @@ -1407,7 +1451,7 @@ void nv_putval(register Namval_t *np, const char *string, int flags) up->dp = new_of(double,0); else if(flags&NV_APPEND) od = *(up->dp); - *(up->dp) = d+od; + *(up->dp) = od?d+od:d; } } else @@ -1957,7 +2001,7 @@ static int scanfilter(Dt_t *dict, void *arg, void *data) register struct adata *tp = (struct adata*)sp->scandata; NOT_USED(dict); #if SHOPT_TYPEDEF - if(tp && tp->tp && nv_type(np)!=tp->tp) + if(tp && !is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp) return(0); #endif /*SHOPT_TYPEDEF */ if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags))) @@ -2014,7 +2058,7 @@ void sh_scope(Shell_t *shp, struct argnod *envlist, int fun) { dtview(newscope,(Dt_t*)shp->var_tree); shp->var_tree = newscope; - nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN); + nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0); if(!fun) return; shp->var_tree = dtview(newscope,0); @@ -2039,6 +2083,10 @@ void sh_envnolocal (register Namval_t *np, void *data) { char *cp=0; NOT_USED(data); + if(np==VERSIONNOD && nv_isref(np)) + return; + if(np==L_ARGNOD) + return; if(nv_isattr(np,NV_EXPORT) && nv_isarray(np)) { nv_putsub(np,NIL(char*),0); @@ -2047,7 +2095,7 @@ void sh_envnolocal (register Namval_t *np, void *data) } if(nv_isattr(np,NV_EXPORT|NV_NOFREE)) { - if(nv_isref(np)) + if(nv_isref(np) && np!=VERSIONNOD) { nv_offattr(np,NV_NOFREE|NV_REF); free((void*)np->nvalue.nrp); @@ -2082,7 +2130,11 @@ static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroo for(np=(Namval_t*)dtfirst(root);np;np=npnext) { if(nv_isref(np)) - nv_unref(np); + { + free((void*)np->nvalue.nrp); + np->nvalue.cp = 0; + np->nvflag = 0; + } if(nq=dtsearch(oroot,np)) { if(nv_cover(nq)) @@ -2094,6 +2146,8 @@ static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroo Sfdouble_t d = nv_getnum(nq); nv_putval(nq,(char*)&d,NV_LDOUBLE); } + else if(shp->test&4) + nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY); else nv_putval(nq, nv_getval(nq), NV_RDONLY); shp->subshell = subshell; @@ -2200,6 +2254,11 @@ void _nv_unset(register Namval_t *np,int flags) /* called from disc, assign the actual value */ nv_local=0; } + if(nv_isattr(np,NV_INT16P) == NV_INT16) + { + np->nvalue.cp = nv_isarray(np)?Empty:0; + goto done; + } if(nv_isarray(np) && np->nvalue.cp!=Empty && np->nvfun) up = np->nvalue.up; else @@ -2604,6 +2663,7 @@ void nv_newattr (register Namval_t *np, unsigned newatts, int size) Namarr_t *ap = 0; int oldsize,oldatts; Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0; + char *prefix = sh.prefix; newatts &= ~NV_NODISC; /* check for restrictions */ @@ -2623,7 +2683,8 @@ void nv_newattr (register Namval_t *np, unsigned newatts, int size) sh_envput(sh.env,np); } #endif - if((size==0||(n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0) + oldsize = nv_size(np); + if((size==oldsize|| (n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0) { if(size) nv_setsize(np,size); @@ -2684,6 +2745,7 @@ void nv_newattr (register Namval_t *np, unsigned newatts, int size) np->nvfun = fp; if(ap) ap->nelem--; + sh.prefix = prefix; return; } @@ -2800,11 +2862,20 @@ static char *lastdot(register char *cp, int eq) while(c= *cp++) { if(c=='[') - cp = nv_endsubscript((Namval_t*)0,ep=cp,0); + { + if(*cp==']') + cp++; + else + cp = nv_endsubscript((Namval_t*)0,ep=cp,0); + } else if(c=='.') { if(*cp=='[') - cp = nv_endsubscript((Namval_t*)0,cp,0); + { + cp = nv_endsubscript((Namval_t*)0,ep=cp,0); + if((ep=sh_checkid(ep+1,cp)) < cp) + cp=strcpy(ep,cp); + } ep = 0; } else if(eq && c == '=') @@ -2822,6 +2893,7 @@ int nv_rename(register Namval_t *np, int flags) Namval_t *last_table = shp->last_table; Dt_t *last_root = shp->last_root; Dt_t *hp = 0; + char *prefix=shp->prefix,*nvenv = 0; if(nv_isattr(np,NV_PARAM) && shp->st.prevst) { if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) @@ -2837,6 +2909,7 @@ int nv_rename(register Namval_t *np, int flags) errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np)); if(nv_isarray(np) && !(mp=nv_opensub(np))) index=nv_aindex(np); + shp->prefix = 0; if(!hp) hp = shp->var_tree; if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL))) @@ -2845,6 +2918,7 @@ int nv_rename(register Namval_t *np, int flags) hp = shp->last_root; if(!nr) nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL)); + shp->prefix = prefix; if(!nr) { if(!nv_isvtree(np)) @@ -2859,7 +2933,10 @@ int nv_rename(register Namval_t *np, int flags) mp->nvenv = (void*)np; } if(mp) + { + nvenv = (char*)np; np = mp; + } if(nr==np) { if(index<0) @@ -2868,6 +2945,8 @@ int nv_rename(register Namval_t *np, int flags) cp = strdup(cp); } _nv_unset(np,0); + if(!nv_isattr(np,NV_MINIMAL)) + np->nvenv = nvenv; if(nr==np) { nv_putsub(np,(char*)0, index); @@ -2892,7 +2971,9 @@ void nv_setref(register Namval_t *np, Dt_t *hp, int flags) { Shell_t *shp = &sh; register Namval_t *nq, *nr=0; - register char *ep,*cp; + register char *ep,*cp; + Dt_t *root = shp->last_root; + Namarr_t *ap; if(nv_isref(np)) return; if(nv_isarray(np)) @@ -2908,13 +2989,22 @@ void nv_setref(register Namval_t *np, Dt_t *hp, int flags) if(!hp) hp = shp->var_tree; if(!(nr = nq = nv_open(cp, hp, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL))) - hp = shp->var_base; + hp = shp->last_root==shp->var_tree?shp->var_tree:shp->var_base; else if(shp->last_root) hp = shp->last_root; if(nq && ep && nv_isarray(nq) && !nv_getsub(nq)) nv_endsubscript(nq,ep-1,NV_ADD); if(!nr) + { nr= nq = nv_open(cp, hp, flags); + hp = shp->last_root; + } + if(shp->last_root == shp->var_tree && root!=shp->var_tree) + { + _nv_unset(np,NV_RDONLY); + nv_onattr(np,NV_REF); + errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np)); + } if(nr==np) { if(shp->namespace && nv_dict(shp->namespace)==hp) @@ -2923,6 +3013,8 @@ void nv_setref(register Namval_t *np, Dt_t *hp, int flags) if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np) errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np)); } + if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN))) + ep = nv_getsub(nq); if(ep) { /* cause subscript evaluation and return result */ @@ -3017,8 +3109,10 @@ void nv_unref(register Namval_t *np) Namval_t *nq; if(!nv_isref(np)) return; - nq = nv_refnode(np); nv_offattr(np,NV_NOFREE|NV_REF); + if(!np->nvalue.nrp) + return; + nq = nv_refnode(np); free((void*)np->nvalue.nrp); np->nvalue.cp = strdup(nv_name(nq)); #if SHOPT_OPTIMIZE diff --git a/usr/src/lib/libshell/common/sh/nvdisc.c b/usr/src/lib/libshell/common/sh/nvdisc.c index bcf987b9a6..94b2d28ca9 100644 --- a/usr/src/lib/libshell/common/sh/nvdisc.c +++ b/usr/src/lib/libshell/common/sh/nvdisc.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -150,16 +150,17 @@ void nv_putv(Namval_t *np, const char *value, int flags, register Namfun_t *nfp) } } -#define LOOKUP 0 +#define LOOKUPS 0 #define ASSIGN 1 #define APPEND 2 #define UNASSIGN 3 +#define LOOKUPN 4 #define BLOCKED ((Namval_t*)&nv_local) struct vardisc { Namfun_t fun; - Namval_t *disc[4]; + Namval_t *disc[5]; }; struct blocked @@ -281,12 +282,12 @@ static void assign(Namval_t *np,const char* val,int flags,Namfun_t *handle) { int bflag; block(bp,type); - if (type==APPEND && (bflag= !isblocked(bp,LOOKUP))) - block(bp,LOOKUP); + if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS))) + block(bp,LOOKUPS); sh_fun(nq,np,(char**)0); unblock(bp,type); if(bflag) - unblock(bp,LOOKUP); + unblock(bp,LOOKUPS); if(!vp->disc[type]) chktfree(np,vp); } @@ -351,15 +352,15 @@ done: * This function executes a lookup disc and then performs * the lookup on the given node <np> */ -static char* lookup(Namval_t *np, Namfun_t *handle) +static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle) { register struct vardisc *vp = (struct vardisc*)handle; struct blocked block, *bp = block_info(np, &block); - register Namval_t *nq = vp->disc[LOOKUP]; + register Namval_t *nq = vp->disc[type]; register char *cp=0; Namval_t node; union Value *up = np->nvalue.up; - if(nq && !isblocked(bp,LOOKUP)) + if(nq && !isblocked(bp,type)) { node = *SH_VALNOD; if(!nv_isnull(SH_VALNOD)) @@ -367,16 +368,24 @@ static char* lookup(Namval_t *np, Namfun_t *handle) nv_onattr(SH_VALNOD,NV_NOFREE); nv_unset(SH_VALNOD); } - block(bp,LOOKUP); + if(type==LOOKUPN) + { + nv_onattr(SH_VALNOD,NV_DOUBLE|NV_INTEGER); + nv_setsize(SH_VALNOD,10); + } + block(bp,type); sh_fun(nq,np,(char**)0); - unblock(bp,LOOKUP); - if(!vp->disc[LOOKUP]) + unblock(bp,type); + if(!vp->disc[type]) chktfree(np,vp); - if(cp = nv_getval(SH_VALNOD)) + if(type==LOOKUPN) { - cp = stkcopy(stkstd,cp); - _nv_unset(SH_VALNOD,NV_RDONLY); + cp = (char*)(SH_VALNOD->nvalue.cp); + *dp = nv_getnum(SH_VALNOD); } + else if(cp = nv_getval(SH_VALNOD)) + cp = stkcopy(stkstd,cp); + _nv_unset(SH_VALNOD,NV_RDONLY); if(!nv_isnull(&node)) { /* restore everything but the nvlink field */ @@ -386,19 +395,29 @@ static char* lookup(Namval_t *np, Namfun_t *handle) if(nv_isarray(np)) np->nvalue.up = up; if(!cp) - cp = nv_getv(np,handle); + { + if(type==LOOKUPS) + cp = nv_getv(np,handle); + else + *dp = nv_getn(np,handle); + } if(bp== &block) block_done(bp); return(cp); } +static char* lookups(Namval_t *np, Namfun_t *handle) +{ + return(lookup(np,LOOKUPS,(Sfdouble_t*)0,handle)); +} -static const Namdisc_t shdisc = +static Sfdouble_t lookupn(Namval_t *np, Namfun_t *handle) { - sizeof(struct vardisc), - assign, - lookup -}; + Sfdouble_t d; + lookup(np,LOOKUPN, &d ,handle); + return(d); +} + /* * Set disc on given <event> to <action> @@ -465,11 +484,16 @@ char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *acti vp = 0; if(!vp) { + Namdisc_t *dp; if(action==np) return((char*)action); - if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,0))) + if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,sizeof(Namdisc_t)))) return(0); - vp->fun.disc = &shdisc; + dp = (Namdisc_t*)(vp+1); + vp->fun.disc = dp; + memset(dp,0,sizeof(*dp)); + dp->dsize = sizeof(struct vardisc); + dp->putval = assign; nv_stack(np, (Namfun_t*)vp); } if(action==np) @@ -478,7 +502,14 @@ char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *acti empty = 0; } else if(action) + { + Namdisc_t *dp = (Namdisc_t*)vp->fun.disc; + if(type==LOOKUPS) + dp->getval = lookups; + else if(type==LOOKUPN) + dp->getnum = lookupn; vp->disc[type] = action; + } else { struct blocked *bp; @@ -573,13 +604,14 @@ Namfun_t *nv_clone_disc(register Namfun_t *fp, int flags) { register Namfun_t *nfp; register int size; + if(!fp->disc && !fp->next && (fp->nofree&1)) + return(fp); if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize))) size = sizeof(Namfun_t); if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t)))) return(0); memcpy(nfp,fp,size); - if(flags&NV_COMVAR) - nfp->nofree &= ~1; + nfp->nofree &= ~1; nfp->nofree |= (flags&NV_RDONLY)?1:0; return(nfp); } @@ -901,7 +933,10 @@ int nv_clone(Namval_t *np, Namval_t *mp, int flags) return(1); } if(nv_isattr(np,NV_INTEGER) && mp->nvalue.ip!=np->nvalue.ip) + { mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip); + nv_offattr(mp,NV_NOFREE); + } else if(flags&NV_NOFREE) nv_onattr(np,NV_NOFREE); return(1); @@ -972,7 +1007,7 @@ Namval_t *nv_search(const char *name, Dt_t *root, int mode) } else { - if(*name=='.' && root==sh.var_tree) + if(*name=='.' && root==sh.var_tree && !dp) root = sh.var_base; np = dtmatch(root,(void*)name); } diff --git a/usr/src/lib/libshell/common/sh/nvtree.c b/usr/src/lib/libshell/common/sh/nvtree.c index d493b5d602..36d7d933e3 100644 --- a/usr/src/lib/libshell/common/sh/nvtree.c +++ b/usr/src/lib/libshell/common/sh/nvtree.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -193,6 +193,8 @@ void *nv_diropen(Namval_t *np,const char *name) last = 0; } } + else + dp->hp = (Namval_t*)dtfirst(dp->root); } else dp->hp = (Namval_t*)dtfirst(dp->root); @@ -283,7 +285,7 @@ char *nv_dirnext(void *dir) if(nv_isarray(np)) nv_putsub(np,(char*)0, ARRAY_UNDEF); dp->hp = nextnode(dp); - if(nv_isnull(np) && !nv_isarray(np)) + if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER)) continue; last_table = sh.last_table; #if 0 @@ -417,7 +419,7 @@ void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname) { if(nv_isvtree(np)) sfprintf(out,"%s -C ",prefix); - else if(!np->nvalue.cp && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_")) + else if((!np->nvalue.cp||np->nvalue.cp==Empty) && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_")) sfputr(out,prefix,' '); } return; @@ -478,7 +480,7 @@ void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname) } else if(tp->sh_name[1]=='A') continue; - if(ap && (ap->nelem&ARRAY_TREE)) + if((ap && (ap->nelem&ARRAY_TREE)) || (!ap && nv_isattr(np,NV_NOFREE))) { if(prefix && *prefix) sfwrite(out,"-C ",3); @@ -592,6 +594,8 @@ void nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special) if(mp && nv_isvtree(mp)) nv_onattr(mp,NV_EXPORT); ep = nv_getval(mp?mp:np); + if(ep==Empty) + ep = 0; xp = 0; if(!ap && nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST) { @@ -681,7 +685,7 @@ static void outval(char *name, const char *vname, struct Walk *wp) if(!xp) return; } - if((nv_isnull(np) || np->nvalue.cp==Empty) && !nv_isarray(np)) + if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER)) return; if(special || (nv_isarray(np) && nv_arrayptr(np))) { @@ -718,7 +722,7 @@ static void outval(char *name, const char *vname, struct Walk *wp) if(*name!='.') nv_attribute(np,wp->out,"typeset",'='); nv_outname(wp->out,name,-1); - if(np->nvalue.cp || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np)) + if((np->nvalue.cp && np->nvalue.cp!=Empty) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np)) sfputc(wp->out,(isarray==2?'\n':'=')); if(isarray==2) return; @@ -819,15 +823,24 @@ static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp) } else if(outfile && !wp->nofollow && argv[1] && memcmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[') { + int k=1; + Namarr_t *ap=0; Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope); if(!np) continue; - wp->array = nv_isarray(np); + if((wp->array = nv_isarray(np)) && (ap=nv_arrayptr(np))) + k = array_elem(ap); + if(wp->indent>0) sfnputc(outfile,'\t',wp->indent); nv_attribute(np,outfile,"typeset",1); nv_close(np); - sfputr(outfile,arg+m+r+(n?n:0),'='); + sfputr(outfile,arg+m+r+(n?n:0),(k?'=':'\n')); + if(!k) + { + wp->array=0; + continue; + } wp->nofollow=1; argv = genvalue(argv,cp,cp-arg ,wp); sfputc(outfile,wp->indent<0?';':'\n'); @@ -1031,7 +1044,7 @@ static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t Shell_t *shp = sh_getinterp(); Namval_t *last_table = shp->last_table; Dt_t *last_root = shp->last_root; - Namval_t *mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL):0; + Namval_t *mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_ARRAY|NV_NOFAIL):0; if(mp && nv_isvtree(mp)) { shp->prev_table = shp->last_table; diff --git a/usr/src/lib/libshell/common/sh/nvtype.c b/usr/src/lib/libshell/common/sh/nvtype.c index a17bc99fda..82eab00d83 100644 --- a/usr/src/lib/libshell/common/sh/nvtype.c +++ b/usr/src/lib/libshell/common/sh/nvtype.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -248,6 +248,13 @@ static void put_chtype(Namval_t* np, const char* val, int flag, Namfun_t* fp) } } +static Namfun_t *clone_chtype(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) +{ + if(flags&NV_NODISC) + return(0); + return(nv_clone_disc(fp,flags)); +} + static const Namdisc_t chtype_disc = { sizeof(Namchld_t), @@ -256,7 +263,7 @@ static const Namdisc_t chtype_disc = 0, 0, 0, - 0, + clone_chtype, name_chtype }; @@ -394,7 +401,7 @@ static Namfun_t *clone_type(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) nrp++; nq = nq->nvalue.nrp->np; } - if(nq->nvalue.cp || nv_isarray(nq) || nv_isattr(nq,NV_RDONLY)) + if(nq->nvalue.cp || !nv_isvtree(nq) || nv_isattr(nq,NV_RDONLY)) { /* see if default value has been overwritten */ if(!mp->nvname) @@ -796,7 +803,7 @@ void nv_addtype(Namval_t *np, const char *optstr, Optdisc_t *op, size_t optsz) nv_onattr(np, NV_RDONLY); } -static void addtype(Namval_t *mp) +void nv_newtype(Namval_t *mp) { struct { Optdisc_t opt; @@ -1113,8 +1120,10 @@ else sfprintf(sfstderr,"tp==NULL\n"); if(nv_isarray(nq) && !nq->nvfun) { nv_putsub(nq, (char*)0, ARRAY_FILL); - ((Namarr_t*)nq->nvfun)->nelem--; - + if(nv_isattr(nq,NV_INTEGER)) + nv_putval(nq, "0",0); + else + ((Namarr_t*)nq->nvfun)->nelem--; } nv_disc(nq, &pp->childfun.fun, NV_LAST); if(nq->nvfun) @@ -1139,6 +1148,8 @@ else sfprintf(sfstderr,"tp==NULL\n"); if(!j) free((void*)np->nvalue.cp); } + if(!nq->nvalue.cp && nq->nvfun== &pp->childfun.fun) + nq->nvalue.cp = Empty; np->nvalue.cp = 0; #if 0 offset += dsize; @@ -1170,7 +1181,7 @@ else sfprintf(sfstderr,"tp==NULL\n"); } if(mnodes!=nodes) free((void*)mnodes); - addtype(mp); + nv_newtype(mp); return(mp); } @@ -1207,7 +1218,7 @@ Namval_t *nv_mkinttype(char *name, size_t size, int sign, const char *help, Namd if(!sign) nv_onattr(mp,NV_UNSIGN); nv_disc(mp, fp, NV_LAST); - addtype(mp); + nv_newtype(mp); return(mp); } @@ -1230,6 +1241,11 @@ void nv_typename(Namval_t *tp, Sfio_t *out) Namval_t *nv_type(Namval_t *np) { Namfun_t *fp; + if(nv_isattr(np,NV_BLTIN|BLT_DCL)==(NV_BLTIN|BLT_DCL)) + { + Namdecl_t *ntp = (Namdecl_t*)nv_context(np); + return(ntp?ntp->tp:0); + } for(fp=np->nvfun; fp; fp=fp->next) { if(fp->type) @@ -1326,6 +1342,7 @@ int nv_settype(Namval_t* np, Namval_t *tp, int flags) np->nvalue.up = 0; nofree = ap->hdr.nofree; ap->hdr.nofree = 0; + ap->hdr.type = tp; nv_disc(np, &ap->hdr, NV_FIRST); ap->hdr.nofree = nofree; nv_onattr(np,NV_ARRAY); @@ -1492,7 +1509,7 @@ Namval_t *nv_mkstruct(const char *name, int rsize, Fields_t *fields) nv_setsize(mp,rsize); nv_disc(mp, &pp->fun, NV_LAST); mp->nvalue.cp = pp->data; - addtype(mp); + nv_newtype(mp); return(mp); } diff --git a/usr/src/lib/libshell/common/sh/parse.c b/usr/src/lib/libshell/common/sh/parse.c index bccbd49d50..c7290d20e7 100644 --- a/usr/src/lib/libshell/common/sh/parse.c +++ b/usr/src/lib/libshell/common/sh/parse.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -32,8 +32,8 @@ #include "defs.h" #else #include <shell.h> -#endif #include <ctype.h> +#endif #include <fcin.h> #include <error.h> #include "shlex.h" @@ -293,7 +293,7 @@ void *sh_parse(Shell_t *shp, Sfio_t *iop, int flag) Fcin_t sav_input; struct argnod *sav_arg = lexp->arg; int sav_prompt = shp->nextprompt; - if(shp->binscript && sffileno(iop)==shp->infd) + if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))) return((void*)sh_trestore(shp,iop)); fcsave(&sav_input); shp->st.staklist = 0; @@ -323,12 +323,13 @@ void *sh_parse(Shell_t *shp, Sfio_t *iop, int flag) lexp->arg = sav_arg; if(version > 3) errormsg(SH_DICT,ERROR_exit(1),e_lexversion); - if(sffileno(iop)==shp->infd) + if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)) shp->binscript = 1; sfgetc(iop); return((void*)sh_trestore(shp,iop)); } } + flag &= ~SH_FUNEVAL; if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0) shp->inlineno=1; #if KSHELL @@ -718,7 +719,7 @@ static Shnode_t *funct(Lex_t *lexp) { if(fcfill() >= 0) fcseek(-1); - if(sh_isstate(SH_HISTORY)) + if(sh_isstate(SH_HISTORY) && shp->hist_ptr) t->funct.functloc = sfseek(shp->hist_ptr->histfp,(off_t)0,SEEK_CUR); else { @@ -1177,13 +1178,13 @@ static Shnode_t *item(Lex_t *lexp,int flag) case LBRACE: comsub = lexp->comsub; lexp->comsub = 0; - t = sh_cmd(lexp,RBRACE,SH_NL); + t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI); lexp->comsub = comsub; break; case LPAREN: t = getnode(parnod); - t->par.partre=sh_cmd(lexp,RPAREN,SH_NL); + t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI); t->par.partyp=TPAR; break; @@ -1224,6 +1225,20 @@ done: return(t); } +static struct argnod *process_sub(Lex_t *lexp,int tok) +{ + struct argnod *argp; + Shnode_t *t; + int mode = (tok==OPROCSYM); + t = sh_cmd(lexp,RPAREN,SH_NL); + argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod)); + *argp->argval = 0; + argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t); + argp->argflag = (ARG_EXP|mode); + return(argp); +} + + /* * This is for a simple command, for list, or compound assignment */ @@ -1278,7 +1293,7 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io) if(assignment==1) { last = strchr(argp->argval,'='); - if((cp=strchr(argp->argval,'[')) && (cp < last)) + if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last)) last = cp; stkseek(stkp,ARGVAL); sfwrite(stkp,argp->argval,last-argp->argval); @@ -1338,17 +1353,11 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io) #if SHOPT_DEVFD if((tok==IPROCSYM || tok==OPROCSYM)) { - Shnode_t *t; - int mode = (tok==OPROCSYM); - t = sh_cmd(lexp,RPAREN,SH_NL); - argp = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)); - *argp->argval = 0; + argp = process_sub(lexp,tok); argmax = 0; argno = -1; *argtail = argp; argtail = &(argp->argnxt.ap); - argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t); - argp->argflag = (ARG_EXP|mode); goto retry; } #endif /* SHOPT_DEVFD */ @@ -1502,9 +1511,7 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) register struct ionod *iop; Stk_t *stkp = lexp->sh->stk; char *iovname=0; -#if SHOPT_BASH register int errout=0; -#endif if(token==IOVNAME) { iovname=lexp->arg->argval+1; @@ -1518,6 +1525,8 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) iof |= (IODOC|IORAW); else if(token==IOMOV0SYM) iof |= IOMOV; + else if(token==IORDWRSYMT) + iof |= IORDW|IOREWRITE; else if(token==IORDWRSYM) iof |= IORDW; else if((token&SYMSHARP) == SYMSHARP) @@ -1532,13 +1541,11 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) break; case '>': -#if SHOPT_BASH if(iof<0) { errout = 1; iof = 1; } -#endif iof |= IOPUT; if(token==IOAPPSYM) iof |= IOAPP; @@ -1570,10 +1577,18 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) } else if(token==EXPRSYM && (iof&IOLSEEK)) iof |= IOARITH; + else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC))) + { + lexp->arg = process_sub(lexp,token); + iof |= IOPROCSUB; + } else sh_syntax(lexp); } - iop->ioname=lexp->arg->argval; + if( (iof&IOPROCSUB) && !(iof&IOLSEEK)) + iop->ioname= (char*)lexp->arg->argchn.ap; + else + iop->ioname=lexp->arg->argval; iop->iovname = iovname; if(iof&IODOC) { @@ -1622,18 +1637,17 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) { struct ionod *ioq=iop; sh_lex(lexp); -#if SHOPT_BASH if(errout) { /* redirect standard output to standard error */ ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod)); + memset(ioq,0,sizeof(*ioq)); ioq->ioname = "1"; ioq->iolst = 0; ioq->iodelim = 0; ioq->iofile = IORAW|IOPUT|IOMOV|2; iop->ionxt=ioq; } -#endif ioq->ionxt=inout(lexp,lastio,flag); } else diff --git a/usr/src/lib/libshell/common/sh/path.c b/usr/src/lib/libshell/common/sh/path.c index fc91fb34e4..94af2fe682 100644 --- a/usr/src/lib/libshell/common/sh/path.c +++ b/usr/src/lib/libshell/common/sh/path.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -57,6 +57,7 @@ static int canexecute(char*,int); static void funload(Shell_t*,int,const char*); static void exscript(Shell_t*,char*, char*[], char**); static int path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int); +static void path_checkdup(register Pathcomp_t*); static const char *std_path; @@ -352,6 +353,7 @@ static char *path_lib(Pathcomp_t *pp, char *path) char save[8]; for( ;pp; pp=pp->next) { + path_checkdup(pp); if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime) return(pp->lib); } @@ -380,19 +382,63 @@ void path_dump(register Pathcomp_t *pp) #endif /* + * check for duplicate directories on PATH + */ +static void path_checkdup(register Pathcomp_t *pp) +{ + register char *name = pp->name; + register Pathcomp_t *oldpp,*first; + register int flag=0; + struct stat statb; + if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode)) + { + pp->flags |= PATH_SKIP; + pp->dev = *name=='/'; + return; + } + pp->mtime = statb.st_mtime; + pp->ino = statb.st_ino; + pp->dev = statb.st_dev; + if(*name=='/' && onstdpath(name)) + flag = PATH_STD_DIR; + first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get(""); + for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next) + { + if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime) + { + flag |= PATH_SKIP; + break; + } + } + pp->flags |= flag; + if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)) + { + int offset = staktell(); + stakputs(name); + path_chkpaths(first,0,pp,offset); + stakseek(offset); + } +} + +/* * write the next path to search on the current stack * if last is given, all paths that come before <last> are skipped * the next pathcomp is returned. */ Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last) { + Pathcomp_t *ppnext; stakseek(PATH_OFFSET); if(*name=='/') pp = 0; else { - for(;pp && pp!=last;pp=pp->next) + for(;pp && pp!=last;pp=ppnext) { + if(ppnext=pp->next) + ppnext->shp = pp->shp; + if(!pp->dev && !pp->ino) + path_checkdup(pp); if(pp->flags&PATH_SKIP) continue; if(!last || *pp->name!='/') @@ -523,6 +569,13 @@ static int path_opentype(const char *name, register Pathcomp_t *pp, int fun) if(fd>=0 && (fd = sh_iomovefd(fd)) > 0) { fcntl(fd,F_SETFD,FD_CLOEXEC); + if(!shp) + { + shp = sh_getinterp(); +#if _UWIN + close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */ +#endif + } shp->fdstatus[fd] |= IOCLEX; } return(fd); @@ -581,16 +634,17 @@ static void funload(Shell_t *shp,int fno, const char *name) pname = path_fullname(stakptr(PATH_OFFSET)); if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname))) { + Dt_t *funtree = sh_subfuntree(1); do { - if((np = dtsearch(shp->fun_tree,rp->np)) && is_afunction(np)) + if((np = dtsearch(funtree,rp->np)) && is_afunction(np)) { if(np->nvalue.rp) np->nvalue.rp->fdict = 0; - nv_delete(np,shp->fun_tree,NV_NOFREE); + nv_delete(np,funtree,NV_NOFREE); } - dtinsert(shp->fun_tree,rp->np); - rp->fdict = shp->fun_tree; + dtinsert(funtree,rp->np); + rp->fdict = funtree; } while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0); return; @@ -601,7 +655,7 @@ static void funload(Shell_t *shp,int fno, const char *name) shp->st.filename = pname; shp->funload = 1; error_info.line = 0; - sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),0); + sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL); shp->readscript = 0; free((void*)shp->st.filename); shp->funload = oldload; @@ -652,10 +706,17 @@ int path_search(register const char *name,Pathcomp_t **oldpp, int flag) path_init(shp); if(flag) { + if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp)) + { + stakseek(PATH_OFFSET); + path_nextcomp(pp,name,pp); + stakputc(0); + return(0); + } pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*)); if(oldpp) *oldpp = pp; - if(!pp && (np=nv_search(name,sh.fun_tree,HASH_NOSCOPE))&&np->nvalue.ip) + if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip) return(1); if(!pp) *stakptr(PATH_OFFSET) = 0; @@ -685,11 +746,9 @@ int path_search(register const char *name,Pathcomp_t **oldpp, int flag) return(0); } - /* * do a path search and find the full pathname of file name */ - Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) { register int f,isfun; @@ -706,7 +765,18 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) sh_sigcheck(); isfun = (pp->flags&PATH_FPATH); if(oldpp=pp) + { pp = path_nextcomp(pp,name,0); + while(oldpp->flags&PATH_SKIP) + { + if(!(oldpp=oldpp->next)) + { + shp->path_err = ENOENT; + return(0); + } + } + } + if(!isfun && !sh_isoption(SH_RESTRICTED)) { if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) @@ -717,6 +787,7 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) typedef int (*Fptr_t)(int, char*[], void*); Fptr_t addr; int n = staktell(); + int libcmd; char *cp; stakputs("b_"); stakputs(name); @@ -727,7 +798,7 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) cp++; else cp = oldpp->blib; - if(strcmp(cp,LIBCMD)==0 && (addr=(Fptr_t)dlllook((void*)0,stakptr(n)))) + if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n)))) { if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT)) return(oldpp); @@ -737,7 +808,21 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) #else if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) #endif - sh_addlib(oldpp->bltin_lib); + { + /* + * this detects the 2007-05-11 builtin context change and also + * the 2008-03-30 opt_info.num change that hit libcmd::b_head + */ + + if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids")) + { + dlclose(oldpp->bltin_lib); + oldpp->bltin_lib = 0; + oldpp->blib = 0; + } + else + sh_addlib(oldpp->bltin_lib); + } } if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) && (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) && @@ -753,7 +838,8 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) f = canexecute(stakptr(PATH_OFFSET),isfun); if(isfun && f>=0) { - nv_onattr(nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); + nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); + funload(shp,f,name); close(f); f = -1; return(0); @@ -881,7 +967,7 @@ void path_exec(register const char *arg0,register char *argv[],struct argnod *lo Pathcomp_t *libpath, *pp=0; Shell_t *shp = &sh; int slash=0; - nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN); + nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0); envp = sh_envgen(); if(strchr(arg0,'/')) { @@ -896,6 +982,8 @@ void path_exec(register const char *arg0,register char *argv[],struct argnod *lo sfsync(NIL(Sfio_t*)); timerdel(NIL(void*)); /* find first path that has a library component */ + while(pp && (pp->flags&PATH_SKIP)) + pp = pp->next; if(pp || slash) do { sh_sigcheck(); @@ -926,15 +1014,16 @@ pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t char **xp=0, *xval, *libenv = (libpath?libpath->lib:0); Namval_t* np; char *s, *v; - int r, n; + int r, n, pidsize; pid_t pid= -1; /* leave room for inserting _= pathname in environment */ envp--; #if _lib_readlink /* save original pathname */ stakseek(PATH_OFFSET); + pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid()); stakputs(opath); - opath = stakfreeze(1)+PATH_OFFSET; + opath = stakfreeze(1)+PATH_OFFSET+pidsize; np=nv_search(argv[0],shp->track_tree,0); while(libpath && !libpath->lib) libpath=libpath->next; @@ -1012,7 +1101,7 @@ pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t } if(!opath) opath = stakptr(PATH_OFFSET); - envp[0] = (char*)opath-PATH_OFFSET; + envp[0] = (char*)opath-(PATH_OFFSET+pidsize); envp[0][0] = '_'; envp[0][1] = '='; sfsync(sfstderr); @@ -1219,6 +1308,8 @@ static void exscript(Shell_t *shp,register char *path,register char *argv[],char (HISTCUR)->nvalue.lp = 0; } sh_offstate(SH_FORKED); + if(shp->sigflag[SIGCHLD]==SH_SIGOFF) + shp->sigflag[SIGCHLD] = SH_SIGFAULT; siglongjmp(*shp->jmplist,SH_JMPSCRIPT); } @@ -1322,7 +1413,6 @@ static void exscript(Shell_t *shp,register char *path,register char *argv[],char static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag) { register Pathcomp_t *pp, *oldpp; - struct stat statb; int len, offset=staktell(); if(!(flag&PATH_BFPATH)) { @@ -1344,65 +1434,26 @@ static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *n return(first); } } - if(old && (old=path_dirfind(old,name,0))) - { - statb.st_ino = old->ino; - statb.st_dev = old->dev; - statb.st_mtime = old->mtime; - if(old->ino==0 && old->dev==0) - flag |= PATH_SKIP; - } - else if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode)) - { - if(*name=='/') - { - if(strcmp(name,SH_CMDLIB_DIR)) - return(first); - statb.st_dev = 1; - } - else - { - flag |= PATH_SKIP; - statb.st_dev = 0; - } - statb.st_ino = 0; - statb.st_mtime = 0; - } - if(*name=='/' && onstdpath(name)) - flag |= PATH_STD_DIR; - for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next) - { - if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime) - { - /* if both absolute paths, eliminate second */ - pp->flags |= flag; - if(*name=='/' && *pp->name=='/') - return(first); - /* keep the path but mark it as skip */ - flag |= PATH_SKIP; - } - } + for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next); pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1); pp->refcount = 1; memcpy((char*)(pp+1),name,len+1); pp->name = (char*)(pp+1); pp->len = len; - pp->dev = statb.st_dev; - pp->ino = statb.st_ino; - pp->mtime = statb.st_mtime; if(oldpp) oldpp->next = pp; else first = pp; pp->flags = flag; - if(pp->ino==0 && pp->dev==1) + if(strcmp(name,SH_CMDLIB_DIR)==0) { + pp->dev = 1; pp->flags |= PATH_BUILTIN_LIB; pp->blib = malloc(4); strcpy(pp->blib,LIBCMD); return(first); } - if((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH) + if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH)) path_chkpaths(first,old,pp,offset); return(first); } diff --git a/usr/src/lib/libshell/common/sh/pmain.c b/usr/src/lib/libshell/common/sh/pmain.c index 5c61ce4107..8cab334192 100644 --- a/usr/src/lib/libshell/common/sh/pmain.c +++ b/usr/src/lib/libshell/common/sh/pmain.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/shcomp.c b/usr/src/lib/libshell/common/sh/shcomp.c index a1b717f3e7..1cd0383673 100644 --- a/usr/src/lib/libshell/common/sh/shcomp.c +++ b/usr/src/lib/libshell/common/sh/shcomp.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/streval.c b/usr/src/lib/libshell/common/sh/streval.c index f39cc24e9b..92a8256594 100644 --- a/usr/src/lib/libshell/common/sh/streval.c +++ b/usr/src/lib/libshell/common/sh/streval.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -78,11 +78,13 @@ struct vars /* vars stacked per invocation */ Sfdouble_t (*convert)(const char**,struct lval*,int,Sfdouble_t); }; -typedef int (*Math_0_f)(Sfdouble_t); -typedef Sfdouble_t (*Fun_t)(Sfdouble_t,...); -typedef Sfdouble_t (*Math_1_f)(Sfdouble_t); -typedef Sfdouble_t (*Math_2_f)(Sfdouble_t,Sfdouble_t); -typedef Sfdouble_t (*Math_3_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t); +typedef Sfdouble_t (*Math_f)(Sfdouble_t,...); +typedef Sfdouble_t (*Math_1f_f)(Sfdouble_t); +typedef int (*Math_1i_f)(Sfdouble_t); +typedef Sfdouble_t (*Math_2f_f)(Sfdouble_t,Sfdouble_t); +typedef int (*Math_2i_f)(Sfdouble_t,Sfdouble_t); +typedef Sfdouble_t (*Math_3f_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t); +typedef int (*Math_3i_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t); #define getchr(vp) (*(vp)->nextchr++) #define peekchr(vp) (*(vp)->nextchr) @@ -155,7 +157,7 @@ Sfdouble_t arith_exec(Arith_t *ep) register char *tp; Sfdouble_t small_stack[SMALL_STACK+1]; const char *ptr = ""; - Fun_t fun; + Math_f fun; struct lval node; node.emode = ep->emode; node.expr = ep->expr; @@ -257,11 +259,12 @@ Sfdouble_t arith_exec(Arith_t *ep) node.value = (char*)dp; node.flag = c; num = (*ep->fun)(&ptr,&node,ASSIGN,num); + c=0; break; case A_PUSHF: - cp = roundptr(ep,cp,Fun_t); + cp = roundptr(ep,cp,Math_f); *++sp = (Sfdouble_t)(cp-ep->code); - cp += sizeof(Fun_t); + cp += sizeof(Math_f); *++tp = *cp++; continue; case A_PUSHN: @@ -368,29 +371,35 @@ Sfdouble_t arith_exec(Arith_t *ep) num = (sp[-1]<num); type=0; break; - case A_CALL0: + case A_CALL1F: sp--,tp--; - fun = *((Fun_t*)(ep->code+(int)(*sp))); + fun = *((Math_f*)(ep->code+(int)(*sp))); type = 0; - num = (*((Math_0_f)fun))(num); + num = (*((Math_1f_f)fun))(num); break; - case A_CALL1: + case A_CALL1I: sp--,tp--; - fun = *((Fun_t*)(ep->code+(int)(*sp))); + fun = *((Math_f*)(ep->code+(int)(*sp))); type = *tp; - num = (*fun)(num); + num = (*((Math_1i_f)fun))(num); break; - case A_CALL2: + case A_CALL2F: sp-=2,tp-=2; - fun = *((Fun_t*)(ep->code+(int)(*sp))); + fun = *((Math_f*)(ep->code+(int)(*sp))); + type = 0; + num = (*((Math_2f_f)fun))(sp[1],num); + break; + case A_CALL2I: + sp-=2,tp-=2; + fun = *((Math_f*)(ep->code+(int)(*sp))); type = *tp; - num = (*((Math_2_f)fun))(sp[1],num); + num = (*((Math_2i_f)fun))(sp[1],num); break; - case A_CALL3: + case A_CALL3F: sp-=3,tp-=3; - fun = *((Fun_t*)(ep->code+(int)(*sp))); - type = *tp; - num = (*((Math_3_f)fun))(sp[1],sp[2],num); + fun = *((Math_f*)(ep->code+(int)(*sp))); + type = 0; + num = (*((Math_3f_f)fun))(sp[1],sp[2],num); break; } if(c&T_BINARY) @@ -593,7 +602,10 @@ again: vp->staksize--; } if(!expr(vp,c)) + { + stakseek(-1); return(0); + } lvalue.value = 0; break; @@ -610,7 +622,7 @@ again: vp->stakmaxsize = vp->staksize; vp->infun=1; stakputc(A_PUSHF); - stakpush(vp,fun,Fun_t); + stakpush(vp,fun,Math_f); stakputc(1); } else @@ -623,13 +635,13 @@ again: vp->paren--; if(fun) { - int x= (nargs>7); + int x= (nargs>7)?2:-1; nargs &= 7; if(vp->infun != nargs) ERROR(vp,e_argcount); if(vp->staksize+=nargs>=vp->stakmaxsize) vp->stakmaxsize = vp->staksize+nargs; - stakputc(A_CALL0+nargs -x); + stakputc(A_CALL1F+nargs+x); vp->staksize -= nargs; } vp->infun = infun; diff --git a/usr/src/lib/libshell/common/sh/string.c b/usr/src/lib/libshell/common/sh/string.c index b7c9c7d63c..89b34159e5 100644 --- a/usr/src/lib/libshell/common/sh/string.c +++ b/usr/src/lib/libshell/common/sh/string.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,6 @@ #include <ast_wchar.h> #include "defs.h" #include <stak.h> -#include <ctype.h> #include <ccode.h> #include "shtable.h" #include "lexstates.h" diff --git a/usr/src/lib/libshell/common/sh/subshell.c b/usr/src/lib/libshell/common/sh/subshell.c index 4d54449c27..9f6eeafdd9 100644 --- a/usr/src/lib/libshell/common/sh/subshell.c +++ b/usr/src/lib/libshell/common/sh/subshell.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -102,38 +102,48 @@ void sh_subtmpfile(int pflag) Shell_t *shp = &sh; int fds[2]; Sfoff_t off; + register struct checkpt *pp = (struct checkpt*)shp->jmplist; + register struct subshell *sp = subshell_data->pipe; if(sfset(sfstdout,0,0)&SF_STRING) { register int fd; - register struct checkpt *pp = (struct checkpt*)shp->jmplist; - register struct subshell *sp = subshell_data->pipe; /* save file descriptor 1 if open */ if((sp->tmpfd = fd = fcntl(1,F_DUPFD,10)) >= 0) { fcntl(fd,F_SETFD,FD_CLOEXEC); shp->fdstatus[fd] = shp->fdstatus[1]|IOCLEX; close(1); + shp->fdstatus[1] = IOCLOSE; } else if(errno!=EBADF) + { + ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; + shp->toomany = 1; errormsg(SH_DICT,ERROR_system(1),e_toomany); - if(!pflag) + } + if(shp->subshare || !pflag) { sfdisc(sfstdout,SF_POPDISC); if((fd=sffileno(sfstdout))>=0) { - sh.fdstatus[fd] = IOREAD|IOWRITE; + shp->fdstatus[fd] = IOREAD|IOWRITE; sfsync(sfstdout); if(fd==1) fcntl(1,F_SETFD,0); else { sfsetfd(sfstdout,1); - sh.fdstatus[1] = sh.fdstatus[fd]; - sh.fdstatus[fd] = IOCLOSE; + shp->fdstatus[1] = shp->fdstatus[fd]; + shp->fdstatus[fd] = IOCLOSE; } goto skip; } } + } + if(sp && (shp->fdstatus[1]==IOCLOSE || (!shp->subshare && !(shp->fdstatus[1]&IONOSEEK)))) + { + struct stat statb,statx; + int fd; sh_pipe(fds); sp->pipefd = fds[0]; sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC); @@ -143,10 +153,22 @@ void sh_subtmpfile(int pflag) write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off); sfpurge(sfstdout); } + if((sfset(sfstdout,0,0)&SF_STRING) || fstat(1,&statb)<0) + statb.st_ino = 0; sfclose(sfstdout); if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1) - errormsg(SH_DICT,ERROR_system(1),e_file+4); + errormsg(SH_DICT,ERROR_system(1),e_redirect); sh_close(fds[1]); + if(statb.st_ino) for(fd=0; fd < 10; fd++) + { + if(fd==1 || ((shp->fdstatus[fd]&(IONOSEEK|IOSEEK|IOWRITE))!=(IOSEEK|IOWRITE)) || fstat(fd,&statx)<0) + continue; + if(statb.st_ino==statx.st_ino && statb.st_dev==statx.st_dev) + { + sh_close(fd); + fcntl(1,F_DUPFD, fd); + } + } skip: sh_iostream(shp,1); sfset(sfstdout,SF_SHARE|SF_PUBLIC,1); @@ -156,6 +178,7 @@ void sh_subtmpfile(int pflag) } } + /* * This routine creates a temp file if necessary and creates a subshell. * The parent routine longjmps back to sh_subshell() @@ -167,16 +190,21 @@ void sh_subfork(void) Shell_t *shp = sp->shp; int curenv = shp->curenv; pid_t pid; + char *trap = shp->st.trapcom[0]; + if(trap) + trap = strdup(trap); /* see whether inside $(...) */ if(sp->pipe) sh_subtmpfile(1); shp->curenv = 0; - if(pid = sh_fork(0,NIL(int*))) + if(pid = sh_fork(FSHOWME,NIL(int*))) { shp->curenv = curenv; /* this is the parent part of the fork */ if(sp->subpid==0) sp->subpid = pid; + if(trap) + free((void*)trap); siglongjmp(*shp->jmplist,SH_JMPSUB); } else @@ -190,6 +218,7 @@ void sh_subfork(void) shp->subshell = 0; SH_SUBSHELLNOD->nvalue.s = 0; sp->subpid=0; + shp->st.trapcom[0] = trap; } } @@ -225,7 +254,7 @@ Namval_t *sh_assignok(register Namval_t *np,int add) Namarr_t *ap; int save; /* don't bother with this */ - if(!sp->shpwd || (nv_isnull(np) && !add)) + if(!sp->shpwd || (nv_isnull(np) && !add) || np==SH_LEVELNOD) return(np); /* don't bother to save if in newer scope */ if(!(rp=shp->st.real_fun) || !(dp=rp->sdict)) @@ -305,7 +334,7 @@ static void nv_restore(struct subshell *sp) continue; if(nv_isarray(mp)) nv_putsub(mp,NIL(char*),ARRAY_SCAN); - _nv_unset(mp,NV_RDONLY); + _nv_unset(mp,NV_RDONLY|NV_CLONE); if(nv_isarray(np)) { nv_clone(np,mp,NV_MOVE); @@ -317,7 +346,11 @@ static void nv_restore(struct subshell *sp) mp->nvfun = np->nvfun; mp->nvflag = np->nvflag; if(nv_cover(mp)) - nv_putval(mp, np->nvalue.cp,0); + { + nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE); + if(!nv_isattr(np,NV_NOFREE)) + nv_offattr(mp,NV_NOFREE); + } else mp->nvalue.cp = np->nvalue.cp; np->nvfun = 0; @@ -386,7 +419,7 @@ static void table_unset(register Dt_t *root,int fun) { nq = (Namval_t*)dtnext(root,np); flag=0; - if(fun && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') + if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') { np->nvalue.rp->fdict = 0; flag = NV_NOFREE; @@ -437,7 +470,7 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) Shell_t *shp = &sh; struct subshell sub_data; register struct subshell *sp = &sub_data; - int jmpval,nsig=0; + int jmpval,nsig=0,duped=0; int savecurenv = shp->curenv; int savejobpgid = job.curpgid; int16_t subshell; @@ -498,7 +531,6 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) sp->cpid = shp->cpid; sp->coutpipe = shp->coutpipe; sp->cpipe = shp->cpipe[1]; - shp->coutpipe = shp->cpipe[1] = -1; shp->cpid = 0; sh_sigreset(0); } @@ -554,6 +586,7 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) subshell_data = sp->prev; if(jmpval==SH_JMPSCRIPT) siglongjmp(*shp->jmplist,jmpval); + shp->exitval &= SH_EXITMASK; sh_done(shp,0); } if(comsub) @@ -584,7 +617,11 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) { int fd=sfsetfd(iop,3); if(fd<0) + { + shp->toomany = 1; + ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; errormsg(SH_DICT,ERROR_system(1),e_toomany); + } shp->sftable[fd] = iop; fcntl(fd,F_SETFD,FD_CLOEXEC); shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX); @@ -597,7 +634,8 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) if(sp->tmpfd>=0) { close(1); - fcntl(sp->tmpfd,F_DUPFD,1); + if (fcntl(sp->tmpfd,F_DUPFD,1) != 1) + duped++; sh_close(sp->tmpfd); } shp->fdstatus[1] = sp->fdstatus; @@ -609,8 +647,6 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) shp->exitval = 0; if(comsub) shp->spid = sp->subpid; - else - job_wait(sp->subpid); } if(comsub && iop && sp->pipefd<0) sfseek(iop,(off_t)0,SEEK_SET); @@ -671,7 +707,7 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) free((void*)sp->pwd); if(sp->mask!=shp->mask) umask(shp->mask=sp->mask); - if(shp->coutpipe>=0) + if(shp->coutpipe!=sp->coutpipe) { sh_close(shp->coutpipe); sh_close(shp->cpipe[1]); @@ -683,6 +719,11 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) shp->subshare = sp->subshare; if(shp->subshell) SH_SUBSHELLNOD->nvalue.s = --shp->subshell; + subshell = shp->subshell; + subshell_data = sp->prev; + sh_argfree(shp,argsav,0); + if(shp->topfd != buff.topfd) + sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); if(sp->sig) { if(sp->prev) @@ -693,17 +734,23 @@ Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) sh_chktrap(); } } - subshell = shp->subshell; - subshell_data = sp->prev; - sh_argfree(shp,argsav,0); + sh_sigcheck(); shp->trapnote = 0; - if(shp->topfd != buff.topfd) - sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); + if(sp->subpid && !comsub) + job_wait(sp->subpid); if(shp->exitval > SH_EXITSIG) { int sig = shp->exitval&SH_EXITMASK; if(sig==SIGINT || sig== SIGQUIT) sh_fault(sig); } + if(duped) + { + ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; + shp->toomany = 1; + errormsg(SH_DICT,ERROR_system(1),e_redirect); + } + if(jmpval && shp->toomany) + siglongjmp(*shp->jmplist,jmpval); return(iop); } diff --git a/usr/src/lib/libshell/common/sh/suid_exec.c b/usr/src/lib/libshell/common/sh/suid_exec.c index 461dc7879a..04fad8051e 100644 --- a/usr/src/lib/libshell/common/sh/suid_exec.c +++ b/usr/src/lib/libshell/common/sh/suid_exec.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/tdump.c b/usr/src/lib/libshell/common/sh/tdump.c index c5d6b25c99..afdd6336dd 100644 --- a/usr/src/lib/libshell/common/sh/tdump.c +++ b/usr/src/lib/libshell/common/sh/tdump.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/timers.c b/usr/src/lib/libshell/common/sh/timers.c index 796b43cf5a..7508525834 100644 --- a/usr/src/lib/libshell/common/sh/timers.c +++ b/usr/src/lib/libshell/common/sh/timers.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/trestore.c b/usr/src/lib/libshell/common/sh/trestore.c index b9fc63d82f..98ae02a004 100644 --- a/usr/src/lib/libshell/common/sh/trestore.c +++ b/usr/src/lib/libshell/common/sh/trestore.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -134,16 +134,22 @@ static Shnode_t *r_tree(Shell_t *shp) { Stak_t *savstak; struct slnod *slp; + struct functnod *fp; t = getnode(shp->stk,functnod); t->funct.functloc = -1; t->funct.functline = sfgetu(infile); t->funct.functnam = r_string(shp->stk); savstak = stakcreate(STAK_SMALL); savstak = stakinstall(savstak, 0); - slp = (struct slnod*)stkalloc(shp->stk,sizeof(struct slnod)); + slp = (struct slnod*)stkalloc(shp->stk,sizeof(struct slnod)+sizeof(struct functnod)); slp->slchild = 0; slp->slnext = shp->st.staklist; shp->st.staklist = 0; + fp = (struct functnod*)(slp+1); + memset(fp, 0, sizeof(*fp)); + fp->functtyp = TFUN|FAMP; + if(shp->st.filename) + fp->functnam = stkcopy(shp->stk,shp->st.filename); t->funct.functtre = r_tree(shp); t->funct.functstak = slp; slp->slptr = stakinstall(savstak,0); diff --git a/usr/src/lib/libshell/common/sh/waitevent.c b/usr/src/lib/libshell/common/sh/waitevent.c index f187a3085d..d04ea1d809 100644 --- a/usr/src/lib/libshell/common/sh/waitevent.c +++ b/usr/src/lib/libshell/common/sh/waitevent.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libshell/common/sh/xec.c b/usr/src/lib/libshell/common/sh/xec.c index 1c93fa9dab..2e59e8a8f2 100644 --- a/usr/src/lib/libshell/common/sh/xec.c +++ b/usr/src/lib/libshell/common/sh/xec.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2008 AT&T Intellectual Property * +* Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -352,7 +352,12 @@ static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp) int16_t level, oldlevel = (int16_t)nv_getnum(np); nv_putv(np,val,flags,fp); if(!val) + { + fp = nv_stack(np, NIL(Namfun_t*)); + if(fp && !fp->nofree) + free((void*)fp); return; + } level = nv_getnum(np); if(level<0 || level > lp->maxlevel) { @@ -414,7 +419,7 @@ int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subsc n -= 2; sfwrite(iop,cp,n); } - if(!(flags&ARG_RAW)) + if(*argv && !(flags&ARG_RAW)) out_string(iop, *argv++,' ', 0); n = (flags&ARG_ARITH); while(cp = *argv++) @@ -466,7 +471,9 @@ int sh_eval(register Sfio_t *iop, int mode) struct checkpt buff; static Sfio_t *io_save; volatile int traceon=0, lineno=0; + int binscript=shp->binscript; io_save = iop; /* preserve correct value across longjmp */ + shp->binscript = 0; #define SH_TOPFUN 0x8000 /* this is a temporary tksh hack */ if (mode & SH_TOPFUN) { @@ -476,7 +483,7 @@ int sh_eval(register Sfio_t *iop, int mode) sh_pushcontext(&buff,SH_JMPEVAL); buff.olist = pp->olist; jmpval = sigsetjmp(buff.buff,0); - if(jmpval==0) + while(jmpval==0) { if(mode&SH_READEVAL) { @@ -484,22 +491,28 @@ int sh_eval(register Sfio_t *iop, int mode) if(traceon=sh_isoption(SH_XTRACE)) sh_offoption(SH_XTRACE); } - t = (Shnode_t*)sh_parse(shp,iop,(mode&SH_READEVAL)?0:SH_NL); - if(mode&SH_READEVAL) - mode &= SH_READEVAL; - else - sfclose(iop); - io_save = 0; + t = (Shnode_t*)sh_parse(shp,iop,(mode&(SH_READEVAL|SH_FUNEVAL))?mode&SH_FUNEVAL:SH_NL); + if(!(mode&SH_FUNEVAL) || !sfreserve(iop,0,0)) + { + if(!(mode&SH_READEVAL)) + sfclose(iop); + io_save = 0; + mode &= ~SH_FUNEVAL; + } + mode &= ~SH_READEVAL; if(!sh_isoption(SH_VERBOSE)) sh_offstate(SH_VERBOSE); - if(mode && shp->hist_ptr) + if((mode&~SH_FUNEVAL) && shp->hist_ptr) { hist_flush(shp->hist_ptr); mode = sh_state(SH_INTERACTIVE); } - sh_exec(t,sh_isstate(SH_ERREXIT)|mode); + sh_exec(t,sh_isstate(SH_ERREXIT)|sh_isstate(SH_NOFORK)|(mode&~SH_FUNEVAL)); + if(!(mode&SH_FUNEVAL)) + break; } sh_popcontext(&buff); + shp->binscript = binscript; if(traceon) sh_onoption(SH_XTRACE); if(lineno) @@ -597,12 +610,14 @@ static void free_list(struct openlist *olist) */ static int set_instance(Namval_t *nq, Namval_t *node, struct Namref *nr) { - char *cp = nv_name(nq); + char *sp=0,*cp = nv_name(nq); Namarr_t *ap; memset(nr,0,sizeof(*nr)); nr->np = nq; nr->root = sh.var_tree; nr->table = sh.last_table; + if((ap=nv_arrayptr(nq)) && (sp = nv_getsub(nq))) + sp = strdup(sp); if(sh.var_tree!=sh.var_base && !nv_open(cp,nr->root,NV_VARNAME|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)) nr->root = sh.var_base; nv_putval(SH_NAMENOD, cp, NV_NOFREE); @@ -611,9 +626,9 @@ static int set_instance(Namval_t *nq, Namval_t *node, struct Namref *nr) L_ARGNOD->nvflag = NV_REF|NV_NOFREE; L_ARGNOD->nvfun = 0; L_ARGNOD->nvenv = 0; - if((ap=nv_arrayptr(nq)) && (cp = nv_getsub(nq)) && (cp = strdup(cp))) + if(sp) { - nv_putval(SH_SUBSCRNOD,nr->sub=cp,NV_NOFREE); + nv_putval(SH_SUBSCRNOD,nr->sub=sp,NV_NOFREE); return(ap->nelem&ARRAY_SCAN); } return(0); @@ -644,9 +659,12 @@ int sh_exec(register const Shnode_t *t, int flags) register char *com0 = 0; int errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE; int execflg = (type&sh_state(SH_NOFORK)); + int execflg2 = (type&sh_state(SH_FORKED)); int mainloop = (type&sh_state(SH_INTERACTIVE)); #if SHOPT_AMP || SHOPT_SPAWN int ntflag = (type&sh_state(SH_NTFORK)); +#else + int ntflag = 0; #endif int topfd = shp->topfd; char *sav=stkptr(stkp,0); @@ -659,6 +677,8 @@ int sh_exec(register const Shnode_t *t, int flags) int echeck = 0; if(flags&sh_state(SH_INTERACTIVE)) { + if(pipejob==2) + job_unlock(); pipejob = 0; job.curpgid = 0; flags &= ~sh_state(SH_INTERACTIVE); @@ -746,6 +766,7 @@ int sh_exec(register const Shnode_t *t, int flags) { if(argn==0 || (np && nv_isattr(np,BLT_SPC))) { + Namval_t *tp=0; if(argn) { if(checkopt(com,'A')) @@ -771,13 +792,18 @@ int sh_exec(register const Shnode_t *t, int flags) #endif { if(np!=SYSTYPESET) + { shp->typeinit = np; + tp = nv_type(np); + } if(checkopt(com,'C')) flgs |= NV_COMVAR; if(checkopt(com,'S')) flgs |= NV_STATIC; if(checkopt(com,'n')) flgs |= NV_NOREF; + else if(!shp->typeinit && (checkopt(com,'L') || checkopt(com,'R') || checkopt(com,'Z'))) + flgs |= NV_UNJUST; #if SHOPT_TYPEDEF else if(argn>=3 && checkopt(com,'T')) { @@ -799,7 +825,7 @@ int sh_exec(register const Shnode_t *t, int flags) if(OPTIMIZE) flgs |= NV_TAGGED; #endif - nv_setlist(argp,flgs); + nv_setlist(argp,flgs,tp); if(np==shp->typeinit) shp->typeinit = 0; shp->envlist = argp; @@ -875,6 +901,11 @@ int sh_exec(register const Shnode_t *t, int flags) np = 0; } } + if(np && pipejob==2) + { + job_unlock(); + pipejob = 1; + } /* check for builtins */ if(np && is_abuiltin(np)) { @@ -882,6 +913,7 @@ int sh_exec(register const Shnode_t *t, int flags) volatile void *save_ptr; volatile void *save_data; int jmpval, save_prompt; + int was_nofork = execflg?sh_isstate(SH_NOFORK):0; struct checkpt buff; unsigned long was_vi=0, was_emacs=0, was_gmacs=0; struct stat statb; @@ -902,6 +934,8 @@ int sh_exec(register const Shnode_t *t, int flags) sh_offoption(SH_EMACS); sh_offoption(SH_GMACS); } + if(execflg) + sh_onstate(SH_NOFORK); sh_pushcontext(&buff,SH_JMPCMD); jmpval = sigsetjmp(buff.buff,1); if(jmpval == 0) @@ -999,6 +1033,8 @@ int sh_exec(register const Shnode_t *t, int flags) } if(bp && bp->ptr!= nv_context(np)) np->nvfun = (Namfun_t*)bp->ptr; + if(execflg && !was_nofork) + sh_offstate(SH_NOFORK); if(!(nv_isattr(np,BLT_ENV))) { if(bp->nosfio && shp->pwd) @@ -1019,7 +1055,7 @@ int sh_exec(register const Shnode_t *t, int flags) } sh_popcontext(&buff); errorpop(&buff.err); - error_info.flags &= ~ERROR_SILENT; + error_info.flags &= ~(ERROR_SILENT|ERROR_NOTIFY); shp->bltinfun = 0; if(buff.olist) free_list(buff.olist); @@ -1127,15 +1163,19 @@ int sh_exec(register const Shnode_t *t, int flags) register pid_t parent; int no_fork,jobid; int pipes[2]; - no_fork = (execflg && !(type&(FAMP|FPOU)) && -#if SHOPT_AMP || SHOPT_SPAWN - !ntflag && -#endif - !shp->subshell && !shp->st.trapcom[0] && - !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && - !(pipejob && sh_isoption(SH_PIPEFAIL))); if(shp->subshell) - sh_subtmpfile(1); + { + if(shp->subshare) + sh_subtmpfile(1); + else + sh_subfork(); + } + no_fork = !ntflag && !(type&(FAMP|FPOU)) && + !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && + (execflg2 || (execflg && + !shp->subshell && shp->fn_depth==0 && + !(pipejob && sh_isoption(SH_PIPEFAIL)) + )); if(sh_isstate(SH_PROFILE) || shp->dot_depth) { /* disable foreground job monitor */ @@ -1150,6 +1190,18 @@ int sh_exec(register const Shnode_t *t, int flags) job.parent=parent=0; else { +#ifdef SHOPT_BGX + int maxjob; + if(((type&(FAMP|FINT)) == (FAMP|FINT)) && (maxjob=nv_getnum(JOBMAXNOD))>0) + { + while(job.numbjob >= maxjob) + { + job_lock(); + job_reap(0); + job_unlock(); + } + } +#endif /* SHOPT_BGX */ if(type&FCOOP) coproc_init(shp,pipes); nv_getval(RANDNOD); @@ -1183,6 +1235,11 @@ int sh_exec(register const Shnode_t *t, int flags) * It may or may not wait for the child */ { + if(pipejob==2) + { + pipejob = 1; + job_unlock(); + } if(type&FPCL) sh_close(shp->inpipe[0]); if(type&(FCOOP|FAMP)) @@ -1197,11 +1254,13 @@ int sh_exec(register const Shnode_t *t, int flags) sh_sigtrap(SIGINT); shp->trapnote |= SH_SIGIGNORE; } - if(execflg && shp->subshell) + if(execflg && shp->subshell && !shp->subshare) { shp->spid = parent; job.pwlist->p_env--; } + else if(shp->pipepid) + shp->pipepid = parent; else job_wait(parent); if(!sh_isoption(SH_MONITOR)) @@ -1294,7 +1353,7 @@ int sh_exec(register const Shnode_t *t, int flags) */ if(!no_fork && !(type&FPOU)) job_clear(); - sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)); + sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)|sh_state(SH_FORKED)); } else if(com0) { @@ -1317,7 +1376,8 @@ int sh_exec(register const Shnode_t *t, int flags) * save and restore io-streams */ pid_t pid; - int jmpval, waitall; + int jmpval, waitall; + int simple = (t->fork.forktre->tre.tretyp&COMMSK)==TCOM; struct checkpt buff; if(shp->subshell) execflg = 0; @@ -1326,14 +1386,14 @@ int sh_exec(register const Shnode_t *t, int flags) { was_interactive = sh_isstate(SH_INTERACTIVE); sh_offstate(SH_INTERACTIVE); - if(!execflg) - sh_iosave(shp,0,shp->topfd,(char*)0); + sh_iosave(shp,0,shp->topfd,(char*)0); + shp->pipepid = simple; sh_iorenumber(shp,shp->inpipe[0],0); /* * if read end of pipe is a simple command * treat as non-sharable to improve performance */ - if((t->fork.forktre->tre.tretyp&COMMSK)==TCOM) + if(simple) sfset(sfstdin,SF_PUBLIC|SF_SHARE,0); waitall = job.waitall; job.waitall = 0; @@ -1346,7 +1406,7 @@ int sh_exec(register const Shnode_t *t, int flags) { sh_redirect(shp,t->fork.forkio,execflg); (t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME; - sh_exec(t->fork.forktre,flags); + sh_exec(t->fork.forktre,flags&~simple); } else sfsync(shp->outpool); @@ -1361,11 +1421,23 @@ int sh_exec(register const Shnode_t *t, int flags) if(!(type&SH_EXITSIG)) { /* wait for remainder of pipline */ - job_wait(waitall?pid:0); + if(shp->pipepid>1) + { + job_wait(shp->pipepid); + type = shp->exitval; + } + else + job_wait(waitall?pid:0); if(type || !sh_isoption(SH_PIPEFAIL)) shp->exitval = type; } + shp->pipepid = 0; shp->st.ioset = 0; + if(simple && was_errexit) + { + echeck = 1; + sh_onstate(SH_ERREXIT); + } } if(jmpval>SH_JMPIO) siglongjmp(*shp->jmplist,jmpval); @@ -1377,8 +1449,17 @@ int sh_exec(register const Shnode_t *t, int flags) flags &= ~OPTIMIZE_FLAG; if(!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK))) { - int jmpval; + char *savsig; + int nsig,jmpval; struct checkpt buff; + shp->st.otrapcom = 0; + if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) + { + nsig += sizeof(char*); + memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); + shp->st.otrapcom = (char**)savsig; + } + sh_sigreset(0); sh_pushcontext(&buff,SH_JMPEXIT); jmpval = sigsetjmp(buff.buff,0); if(jmpval==0) @@ -1419,6 +1500,7 @@ int sh_exec(register const Shnode_t *t, int flags) job.waitall = 1; else job.waitall |= !pipejob && sh_isstate(SH_MONITOR); + job_lock(); do { #if SHOPT_FASTPIPE @@ -1442,6 +1524,7 @@ int sh_exec(register const Shnode_t *t, int flags) while(!type && t->tre.tretyp==TFIL); shp->inpipe = pvn; shp->outpipe = 0; + pipejob = 2; if(type == 0) { /* @@ -1454,6 +1537,8 @@ int sh_exec(register const Shnode_t *t, int flags) else /* execution failure, close pipe */ sh_pclose(pvn); + if(pipejob==2) + job_unlock(); pipejob = savepipe; #ifdef SIGTSTP if(!pipejob && sh_isstate(SH_MONITOR)) @@ -1651,7 +1736,7 @@ int sh_exec(register const Shnode_t *t, int flags) shp->offsets[0] = -1; shp->offsets[1] = 0; if(tt->com.comset) - nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN); + nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN,0); } #endif /*SHOPT_FILESCAN */ shp->st.loopcnt++; @@ -2336,7 +2421,15 @@ pid_t _sh_fork(register pid_t parent,int flags,int *jobid) job.curpgid = parent; if(flags&FCOOP) shp->cpid = parent; +#ifdef SHOPT_BGX + if(!postid && (flags&(FAMP|FINT)) == (FAMP|FINT)) + postid = 1; myjob = job_post(parent,postid); + if(postid==1) + postid = 0; +#else + myjob = job_post(parent,postid); +#endif /* SHOPT_BGX */ if(flags&FAMP) job.curpgid = curpgid; if(jobid) @@ -2388,7 +2481,8 @@ pid_t _sh_fork(register pid_t parent,int flags,int *jobid) #endif /* SHOPT_ACCT */ /* Reset remaining signals to parent */ /* except for those `lost' by trap */ - sh_sigreset(2); + if(!(flags&FSHOWME)) + sh_sigreset(2); shp->subshell = 0; if((flags&FAMP) && shp->coutpipe>1) sh_close(shp->coutpipe); @@ -2463,6 +2557,8 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) struct funenv *fp; struct checkpt buff; Namval_t *nspace = shp->namespace; + Dt_t *last_root = shp->last_root; + Shopt_t options = shp->options; if(shp->fn_depth==0) shp->glob_options = shp->options; else @@ -2534,7 +2630,10 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) if(jmpval == 0) { if(shp->fn_depth++ > MAXDEPTH) + { + shp->toomany = 1; siglongjmp(*shp->jmplist,SH_JMPERRFN); + } else if(fun) r= (*fun)(arg); else @@ -2567,7 +2666,8 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) shp->trapnote=0; if(nsig) stakset(savstak,0); - shp->options = shp->glob_options; + shp->options = options; + shp->last_root = last_root; if(trap) { sh_trap(trap,0); @@ -2588,7 +2688,8 @@ static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct arg struct funenv fun; char *fname = nv_getval(SH_FUNNAMENOD); struct Level *lp =(struct Level*)(SH_LEVELNOD->nvfun); - int level; + int level, pipepid=shp->pipepid; + shp->pipepid = 0; sh_stats(STAT_FUNCT); if(!lp->hdr.disc) lp = init_level(0); @@ -2632,6 +2733,7 @@ static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct arg nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE); #endif nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); + shp->pipepid = pipepid; } /* @@ -3136,7 +3238,7 @@ static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,in { sh_unscope(shp); if(jmpval==SH_JMPSCRIPT) - nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN); + nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN,0); } if(t->com.comio) sh_iorestore(shp,buff.topfd,jmpval); diff --git a/usr/src/lib/libshell/common/tests/README.tests b/usr/src/lib/libshell/common/tests/README.tests new file mode 100644 index 0000000000..c78d32d9b1 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/README.tests @@ -0,0 +1,53 @@ + +#### ksh93 test suite + +## Intro +The directory /usr/demo/ksh/tests/ contains the ksh93 test suite +which is used to verify the correct behaviour of ksh93. + +The test suite is split into modules with the ending *.sh +and a frontend called "shtests" which is used to run the tests. + + +## Basic description: +/usr/demo/ksh/tests/shtests <options> <varname=value> <testmodule> + +<options> may be: + -a execute test module one time as normal script code + and a 2nd time as compiled shell script. The env + variable SHCOMP defines the version of the shell + compiler being used (default is "${SHELL%/*}/shcomp", + however it is recommended to explicitly set SHCOMP + to /usr/bin/shcomp). + -c execute test module as compiled shell script + -s execute test module as normal shell script + -t do not print timing information + -v use VMDEBUG +<varname=value> + Sets one or more environment variables to value "value". +<testmodule> + file name of test module + + +## Basic usage in Solaris >= 11 and OpenSolaris/Indiana: +The tests can be executed like this: +$ export SHELL=<path-to-ksh93-executable> +$ export SHCOMP=/usr/bin/shcomp +for t in /usr/demo/ksh/tests/*.sh ; do + $SHELL /usr/demo/ksh/tests/shtests -a "$t" +done + +Note that you MUST NOT use "/usr/bin/ksh93" as value for +SHELL since /usr/bin/ksh93 on Solaris is a wrapper which +selects a suitable executable in /usr/bin/<isa>/ksh93 +based on the hardware capabilities defined via /usr/bin/isalist + +Valid values for SHELL are: +- SHELL=/usr/bin/i86/ksh93 # 32bit i386 +- SHELL=/usr/bin/amd64/ksh93 # 64bit AMD64 +- SHELL=/usr/bin/sparcv7/ksh93 # 32bit SPARC +- SHELL=/usr/bin/sparcv9/ksh93 # 64bit SPARC +- SHELL=/usr/bin/s390/ksh93 # 32bit SystemZ +- SHELL=/usr/bin/s390x/ksh93 # 64bit SystemZ + +# EOF. diff --git a/usr/src/lib/libshell/common/tests/alias.sh b/usr/src/lib/libshell/common/tests/alias.sh index e001668ef7..f527faf23e 100644 --- a/usr/src/lib/libshell/common/tests/alias.sh +++ b/usr/src/lib/libshell/common/tests/alias.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + alias foo='print hello' if [[ $(foo) != hello ]] then err_exit 'foo, where foo is alias for "print hello" failed' @@ -66,7 +70,7 @@ alias !!=print if [[ $(!! hello 2>/dev/null) != hello ]] then err_exit 'alias for !!=print not working' fi -alias foo=echo +alias foo=echo if [[ $(print "$(foo bar)" ) != bar ]] then err_exit 'alias in command substitution not working' fi @@ -81,14 +85,12 @@ then [[ ! $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not set' [[ $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not cleared' fi if hash -r 2>/dev/null && [[ ! $(hash) ]] -then mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" - trap "cd /; rm -rf /tmp/ksh$$" EXIT - PATH=/tmp/ksh$$:/bin:/usr/bin +then PATH=$tmp:/bin:/usr/bin for i in foo -foo -- - do print ':' > /tmp/ksh$$/$i - chmod +x /tmp/ksh$$/$i + do print ':' > $tmp/$i + chmod +x $tmp/$i hash -r -- $i 2>/dev/null || err_exit "hash -r -- $i failed" - [[ $(hash) == $i=/tmp/ksh$$/$i ]] || err_exit "hash -r -- $i failed, expected $i=/tmp/ksh$$/$i, got $(hash)" + [[ $(hash) == $i=$tmp/$i ]] || err_exit "hash -r -- $i failed, expected $i=$tmp/$i, got $(hash)" done else err_exit 'hash -r failed' fi diff --git a/usr/src/lib/libshell/common/tests/append.sh b/usr/src/lib/libshell/common/tests/append.sh index 00c432520a..d3e10c9100 100644 --- a/usr/src/lib/libshell/common/tests/append.sh +++ b/usr/src/lib/libshell/common/tests/append.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/arith.sh b/usr/src/lib/libshell/common/tests/arith.sh index c330abce90..47c9619c75 100644 --- a/usr/src/lib/libshell/common/tests/arith.sh +++ b/usr/src/lib/libshell/common/tests/arith.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -26,8 +26,13 @@ function err_exit alias err_exit='err_exit $LINENO' Command=${0##*/} -trap '' FPE # NOTE: osf.alpha requires this (no ieee math) integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +trap '' FPE # NOTE: osf.alpha requires this (no ieee math) + integer x=1 y=2 z=3 if (( 2+2 != 4 )) then err_exit 2+2!=4 @@ -135,7 +140,7 @@ if [[ $? == 0 ]] then err_exit 'floating point allowed with % operator' fi x=.125 -if [[ $(( 4 * x/2 )) != 0.25 ]] +if [[ $(( 4 * x/2 )) != 0.25 ]] then err_exit '(( 4 * x/2 )) is not 0.25, with x=.125' fi if [[ $(( pow(2,3) )) != 8 ]] @@ -190,7 +195,7 @@ then err_exit "&= not working" fi function newscope { - float x=1.5 + float x=1.5 (( x += 1 )) print -r -- $x } @@ -342,7 +347,7 @@ for ((i=0; i < 4; i++)) do (( ipx = ip % 256 )) (( ip /= 256 )) (( ipx != hex[3-i] )) && err_exit "hex digit $((3-i)) not correct" -done +done unset x x=010 (( x == 8 )) || err_exit 'leading zeros not treated as octal arithmetic' @@ -365,8 +370,7 @@ i=2 unset i; typeset -i i=01-2 (( i == -1 )) || err_exit "01-2 is not -1" -trap 'rm -f /tmp/script$$ /tmp/data$$.[12]' EXIT -cat > /tmp/script$$ <<-\! +cat > $tmp/script <<-\! tests=$* typeset -A blop function blop.get @@ -412,14 +416,14 @@ function mkobj } mkobj bla ! -chmod +x /tmp/script$$ -[[ $(/tmp/script$$ 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +chmod +x $tmp/script +[[ $($tmp/script 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' unset foo typeset -F1 foo=123456789.19 [[ $foo == 123456789.2 ]] || err_exit 'typeset -F1 not working correctly' @@ -434,7 +438,7 @@ for expr in '1/(1.0/2)' '1/(1/2.0)' do [[ $( ( $SHELL -c "( print -r -- \$(($expr)) )" ) 2>/dev/null ) == 2 ]] || err_exit "invalid value for: $expr" done [[ $((5||0)) == 1 ]] || err_exit '$((5||0))'" == $((5||0)) should be 1" -$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7 && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working' +$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7 && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working' $SHELL -c 'b=0; [[ $((b?a=1:b=9)) == 9 ]]' 2> /dev/null || err_exit 'b?a=1:b=9 not working' unset x (( x = 4*atan(1.0) )) @@ -483,4 +487,46 @@ $SHELL -c '(( x=));:' 2> /dev/null && err_exit '((x=)) should be an error' $SHELL -c '(( x+=));:' 2> /dev/null && err_exit '((x+=)) should be an error' $SHELL -c '(( x=+));:' 2> /dev/null && err_exit '((x=+)) should be an error' $SHELL -c 'x=();x.arr[0]=(z=3); ((x.arr[0].z=2))' 2> /dev/null || err_exit '(((x.arr[0].z=2)) should not be an error' + +float t +typeset a b r +v="-0.0 0.0 +0.0 -1.0 1.0 +1.0" +for a in $v +do for b in $v + do (( r = copysign(a,b) )) + (( t = copysign(a,b) )) + [[ $r == $t ]] || err_exit $(printf "float t=copysign(%3.1f,%3.1f) => %3.1f -- expected %3.1f\n" a b t r) + done +done + +typeset -l y y_ascii +(( y=sin(90) )) +y_ascii=$y +(( y == y_ascii )) || err_exit "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" y_ascii)" + +( $SHELL <<- \EOF + p=5 + t[p]=6 + while (( t[p] != 0 )) ; do + (( + p+=1 , + t[p]+=2 , + p+=3 , + t[p]+=5 , + p+=1 , + t[p]+=2 , + p+=1 , + t[p]+=1 , + p-=6 , + t[p]-=1 + )) + : + done +EOF) 2> /dev/null || err_exit 'error with comma expression' + +N=(89551 89557) +i=0 j=1 +[[ $(printf "%d" N[j]-N[i]) == 6 ]] || err_exit 'printf %d N[i]-N[j] failed' +[[ $((N[j]-N[i])) == 6 ]] || err_exit '$((N[j]-N[i])) incorrect' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/arrays.sh b/usr/src/lib/libshell/common/tests/arrays.sh index 14504edc00..996101409f 100644 --- a/usr/src/lib/libshell/common/tests/arrays.sh +++ b/usr/src/lib/libshell/common/tests/arrays.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function fun { integer i @@ -34,8 +40,6 @@ function fun done } -Command=${0##*/} -integer Errors=0 set -A x zero one two three four 'five six' if [[ $x != zero ]] then err_exit '$x is not element 0' @@ -268,7 +272,7 @@ fi export foo typeset -i foo [[ $($SHELL -c "print $foo") == 143 ]]' -) 2> /dev/null || +) 2> /dev/null || err_exit 'exporting associative array not exporting 0-th element' unset foo typeset -A foo @@ -283,7 +287,7 @@ for i in one three four five do : ${foo[$i]} done if [[ ${!foo[@]} != two ]] -then err_exit 'Error in subscript names' +then err_exit 'error in subscript names' fi unset x x=( 1 2 3) @@ -329,24 +333,23 @@ bam[foo]=value [[ $bam == value ]] && err_exit 'unset associative array element error' : only first element of an array can be exported unset bam -trap 'rm -f /tmp/sharr$$' EXIT -print 'print ${var[0]} ${var[1]}' > /tmp/sharr$$ -chmod +x /tmp/sharr$$ -[[ $($SHELL -c "var=(foo bar);export var;/tmp/sharr$$") == foo ]] || err_exit 'export array not exporting just first element' +print 'print ${var[0]} ${var[1]}' > $tmp/script +chmod +x $tmp/script +[[ $($SHELL -c "var=(foo bar);export var;$tmp/script") == foo ]] || err_exit 'export array not exporting just first element' unset foo set -o allexport foo=one foo[1]=two foo[0]=three [[ $foo == three ]] || err_exit 'export all not working with arrays' -cat > /tmp/sharr$$ <<- \! +cat > $tmp/script <<- \! typeset -A foo print foo${foo[abc]} ! # 04-05-24 bug fix unset foo -[[ $($SHELL -c "typeset -A foo;/tmp/sharr$$") == foo ]] 2> /dev/null || err_exit 'empty associative arrays not being cleared correctly before scripts' -[[ $($SHELL -c "typeset -A foo;foo[abc]=abc;/tmp/sharr$$") == foo ]] 2> /dev/null || err_exit 'associative arrays not being cleared correctly before scripts' +[[ $($SHELL -c "typeset -A foo;$tmp/script") == foo ]] 2> /dev/null || err_exit 'empty associative arrays not being cleared correctly before scripts' +[[ $($SHELL -c "typeset -A foo;foo[abc]=abc;$tmp/script") == foo ]] 2> /dev/null || err_exit 'associative arrays not being cleared correctly before scripts' unset foo foo=(one two) [[ ${foo[@]:1} == two ]] || err_exit '${foo[@]:1} == two' @@ -406,7 +409,7 @@ x=${bar[$foo[5]]} test_array[3]=4 print "val=${test_array[3]}" ++EOF+++ -) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' +) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' [[ $($SHELL <<- \+++EOF+++ pastebin=( typeset -a form) pastebin.form+=( name="name" data="clueless" ) @@ -464,4 +467,10 @@ a[6]=six [[ ${a[-1]} == six ]] || err_exit 'a[-1] should be six' [[ ${a[-3]} == four ]] || err_exit 'a[-3] should be four' [[ ${a[-3..-1]} == 'four six' ]] || err_exit "a[-3,-1] should be 'four six'" + +FILTER=(typeset scope) +FILTER[0].scope=include +FILTER[1].scope=exclude +[[ ${#FILTER[@]} == 2 ]] || err_exit "FILTER array should have two elements not ${#FILTER[@]}" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/arrays2.sh b/usr/src/lib/libshell/common/tests/arrays2.sh index 56bce796ae..ee8f0ae315 100644 --- a/usr/src/lib/libshell/common/tests/arrays2.sh +++ b/usr/src/lib/libshell/common/tests/arrays2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/attributes.sh b/usr/src/lib/libshell/common/tests/attributes.sh index 2d4f1e3d21..474972c03b 100644 --- a/usr/src/lib/libshell/common/tests/attributes.sh +++ b/usr/src/lib/libshell/common/tests/attributes.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + r=readonly u=Uppercase l=Lowercase i=22 i8=10 L=abc L5=def uL5=abcdef xi=20 x=export t=tagged H=hostname LZ5=026 RZ5=026 Z5=123 lR5=ABcdef R5=def n=l for option in u l i i8 L L5 LZ5 RZ5 Z5 r x H t R5 uL5 lR5 xi n @@ -115,18 +119,18 @@ fi sz=(typeset -E y=2.2) string="$(print $sz)" if [[ "${sz}" == *'typeset -E -F'* ]] -then err_exit 'print of exponential shows both -E and -F attributes' +then err_exit 'print of exponential shows both -E and -F attributes' fi -print 'typeset -i m=48/4+1;print -- $m' > /tmp/ksh$$ -chmod +x /tmp/ksh$$ +print 'typeset -i m=48/4+1;print -- $m' > $tmp/script +chmod +x $tmp/script typeset -Z2 m -if [[ $(/tmp/ksh$$) != 13 ]] +if [[ $($tmp/script) != 13 ]] then err_exit 'attributes not cleared for script execution' fi -print 'print VAR=$VAR' > /tmp/ksh$$ +print 'print VAR=$VAR' > $tmp/script typeset -L70 VAR=var -/tmp/ksh$$ > /tmp/ksh$$.1 -[[ $(< /tmp/ksh$$.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' +$tmp/script > $tmp/script.1 +[[ $(< $tmp/script.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' typeset -Z LAST=00 unset -f foo function foo @@ -145,7 +149,6 @@ if (( ${#LAST} != 2 )) then err_exit 'LAST!=2' fi [[ $(set | grep LAST) == LAST=02 ]] || err_exit "LAST not correct in set list" -rm -rf /tmp/ksh$$* set -a unset foo foo=bar @@ -195,7 +198,9 @@ hello worldhello worldhello world ! [[ $v1 == "$b1" ]] || err_exit "v1=$v1 should be $b1" [[ $v2 == "$x" ]] || err_exit "v1=$v2 should be $x" -[[ $(env - '!=1' $SHELL -c 'echo ok' 2>/dev/null) == ok ]] || err_exit 'malformed environment terminates shell' +if env '!=1' >/dev/null 2>&1 +then [[ $(env '!=1' $SHELL -c 'echo ok' 2>/dev/null) == ok ]] || err_exit 'malformed environment terminates shell' +fi unset var typeset -b var printf '12%Z34' | read -r -N 5 var @@ -211,10 +216,10 @@ unset foo bar unset -f fun function fun { - export foo=hello + export foo=hello typeset -x bar=world [[ $foo == hello ]] || err_exit 'export scoping problem in function' -} +} fun [[ $(export | grep foo) == 'foo=hello' ]] || err_exit 'export not working in functions' [[ $(export | grep bar) ]] && err_exit 'typeset -x not local' @@ -224,9 +229,9 @@ fred[66]=88 unset x y z typeset -LZ3 x=abcd y z=00abcd y=03 -[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' -[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' -[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' +[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' unset x z set +a [[ $(typeset -p z) ]] && err_exit "typeset -p for z undefined failed" @@ -280,4 +285,43 @@ function foo } bar=xxx [[ $(foo) == bar=xxx ]] || err_exit 'typeset -p not working inside a function' +unset foo +typeset -L5 foo +[[ $(typeset -p foo) == 'typeset -L 5 foo' ]] || err_exit 'typeset -p not working for variables with attributes but without a value' +{ $SHELL <<- EOF + typeset -L3 foo=aaa + typeset -L6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} || err_exit 'typeset -L should not preserve old attributes' +{ $SHELL <<- EOF + typeset -R3 foo=aaa + typeset -R6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} 2> /dev/null || err_exit 'typeset -R should not preserve old attributes' + +expected='YWJjZGVmZ2hpag==' +unset foo +typeset -b -Z10 foo +read foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -Z10 foo +read -N10 foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -A foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -A" foo not working' +unset foo +typeset -b -a foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -a" foo not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary associative array element not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary indexed array element not working' +unset foo + +$SHELL 2> /dev/null -c 'export foo=(bar=3)' && err_exit 'compound variables cannot be exported' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/basic.sh b/usr/src/lib/libshell/common/tests/basic.sh index 3911f9c472..597833e74f 100644 --- a/usr/src/lib/libshell/common/tests/basic.sh +++ b/usr/src/lib/libshell/common/tests/basic.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,9 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test basic file operations like redirection, pipes, file expansion Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test basic file operations like redirection, pipes, file expansion set -- \ go+r 0000 \ go-r 0044 \ @@ -53,11 +57,9 @@ umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] then err_exit 'umask -S incorrect' fi -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap "cd /; rm -rf /tmp/ksh$$" EXIT pwd=$PWD [[ $SHELL != /* ]] && SHELL=$pwd/$SHELL -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } um=$(umask -S) ( umask 0777; > foobar ) rm -f foobar @@ -70,11 +72,11 @@ rm -f foobar for i in 1 2 do print foobar* rm -f foobar -done > out$$ -if [[ "$(<out$$)" != "foobar"$'\n'"foobar*" ]] +done > out +if [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] then print -u2 "optimizer bug with file expansion" fi -rm -f out$$ foobar +rm -f out foobar mkdir dir if [[ $(print */) != dir/ ]] then err_exit 'file expansion with trailing / not working' @@ -100,7 +102,7 @@ set -- dat* if (( $# != 5 )) then err_exit "dat* matches only $# files" fi -if (command > foo\\abc) 2> /dev/null +if (command > foo\\abc) 2> /dev/null then set -- foo* if [[ $1 != 'foo\abc' ]] then err_exit 'foo* does not match foo\abc' @@ -113,15 +115,14 @@ then set -- TT* fi fi cd ~- || err_exit "cd back failed" -cat > /tmp/ksh$$/script <<- ! +cat > $tmp/script <<- ! #! $SHELL print -r -- \$0 ! -chmod 755 /tmp/ksh$$/script -if [[ $(/tmp/ksh$$/script) != "/tmp/ksh$$/script" ]] +chmod 755 $tmp/script +if [[ $($tmp/script) != "$tmp/script" ]] then err_exit '$0 not correct for #! script' fi -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" bar=foo eval foo=\$bar if [[ $foo != foo ]] @@ -140,9 +141,9 @@ fi ( sleep 2; cat <<! foobar ! -) | cat > /tmp/foobar$$ & +) | cat > $tmp/foobar & wait $! -foobar=$( < /tmp/foobar$$) +foobar=$( < $tmp/foobar) if [[ $foobar != foobar ]] then err_exit "$foobar is not foobar" fi @@ -150,26 +151,26 @@ fi print foo /bin/echo bar print bam -} > /tmp/foobar$$ -if [[ $( < /tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Output file pointer not shared correctly." +} > $tmp/foobar +if [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" fi -cat > /tmp/foobar$$ <<\! +cat > $tmp/foobar <<\! print foo /bin/echo bar print bam ! -chmod +x /tmp/foobar$$ -if [[ $(/tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Script not working." +chmod +x $tmp/foobar +if [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "script not working" fi -if [[ $(/tmp/foobar$$ | /bin/cat) != $'foo\nbar\nbam' ]] -then err_exit "Script | cat not working." +if [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] +then err_exit "script | cat not working" fi -if [[ $( /tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Output file pointer not shared correctly." +if [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" fi -rm -f /tmp/foobar$$ +rm -f $tmp/foobar x=$( (print foo) ; (print bar) ) if [[ $x != $'foo\nbar' ]] then err_exit " ( (print foo);(print bar ) failed" @@ -182,7 +183,7 @@ x=$( (/bin/echo foo) ; (/bin/echo bar) ) if [[ $x != $'foo\nbar' ]] then err_exit " ( (/bin/echo);(/bin/echo bar ) failed" fi -cat > /tmp/ksh$$ <<\! +cat > $tmp/script <<\! if [[ -p /dev/fd/0 ]] then builtin cat cat - > /dev/null @@ -190,33 +191,30 @@ then builtin cat else print no fi ! -chmod +x /tmp/ksh$$ -case $( (print) | /tmp/ksh$$;:) in +chmod +x $tmp/script +case $( (print) | $tmp/script;:) in ok) ;; no) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; *) err_exit "builtin replaces standard input pipe" ;; esac -print 'print $0' > /tmp/ksh$$ -print ". /tmp/ksh$$" > /tmp/ksh$$x -chmod +x /tmp/ksh$$x -if [[ $(/tmp/ksh$$x) != /tmp/ksh$$x ]] +print 'print $0' > $tmp/script +print ". $tmp/script" > $tmp/scriptx +chmod +x $tmp/scriptx +if [[ $($tmp/scriptx) != $tmp/scriptx ]] then err_exit '$0 not correct for . script' fi -rm -r /tmp/ksh$$ /tmp/ksh$$x -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" -print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } +print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e chmod 755 a b c d e x=$(./a) if [[ $x != "hello there" ]] -then err_exit "nested scripts failed" +then err_exit "nested scripts failed" fi x=$( (./a) | cat) if [[ $x != "hello there" ]] -then err_exit "scripts in subshells fail" +then err_exit "scripts in subshells fail" fi cd ~- || err_exit "cd back failed" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" x=$( (/bin/echo foo) 2> /dev/null ) if [[ $x != foo ]] then err_exit "subshell in command substitution fails" @@ -239,29 +237,29 @@ x=$( (/bin/echo hello) 2> /dev/null ) if [[ $x != hello ]] then err_exit "subshell in command substitution with 1 closed fails" fi -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! read line 2> /dev/null print done ! -if [[ $($SHELL /tmp/ksh$$ <&-) != done ]] +if [[ $($SHELL $tmp/script <&-) != done ]] then err_exit "executing script with 0 closed fails" fi trap '' INT -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! trap 'print bad' INT kill -s INT $$ print good ! -chmod +x /tmp/ksh$$ -if [[ $($SHELL /tmp/ksh$$) != good ]] +chmod +x $tmp/script +if [[ $($SHELL $tmp/script) != good ]] then err_exit "traps ignored by parent not ignored" fi trap - INT -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! read line /bin/cat ! -if [[ $($SHELL /tmp/ksh$$ <<! +if [[ $($SHELL $tmp/script <<! one two ! @@ -305,7 +303,7 @@ wait # not running --pipefail which would interfere with subsequent tests sleep 20 & pids=$! if [[ $(jobs -p) != $! ]] -then err_exit 'jobs -p not reporting a background job' +then err_exit 'jobs -p not reporting a background job' fi sleep 20 & pids="$pids $!" @@ -323,32 +321,31 @@ kill $pids command exec 3<> /dev/null if cat /dev/fd/3 >/dev/null 2>&1 then [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' - [[ $($SHELL -c 'print $(cat <(print foo) )' 2> /dev/null) == foo ]] || err_exit 'process substitution in subshell not working' - [[ $($SHELL -c $'tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null <<- \!!! + [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! line0 line1 line2 !!! wait - cat /tmp/ksh'$$x 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' - > /tmp/ksh$$x + cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' + > $tmp/scriptx [[ $($SHELL -c $' for i in 1 - do tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null <<- \!!! + do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! line0 line1 line2 !!! done wait - cat /tmp/ksh'$$x 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' + cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || err_exit 'process substitution of compound commands not working' fi [[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' -print cat > /tmp/ksh$$x -chmod +x /tmp/ksh$$x -[[ $($SHELL -c "print foo | /tmp/ksh$$x ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' +print cat > $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' [[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' [[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' exec 3<&- @@ -357,19 +354,18 @@ then [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not $SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop" fi exec 3> /dev/null -print 'print foo "$@"' > /tmp/ksh$$x -[[ $( print "(/tmp/ksh$$x bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' -print "#! $SHELL" > /tmp/ksh$$x -print 'print -- $0' >> /tmp/ksh$$x -chmod +x /tmp/ksh$$x -[[ $(/tmp/ksh$$x) == /tmp/ksh$$x ]] || err_exit "\$0 is $0 instead of /tmp/ksh$$x" -cat > /tmp/ksh$$x <<- \EOF +print 'print foo "$@"' > $tmp/scriptx +[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' +print "#! $SHELL" > $tmp/scriptx +print 'print -- $0' >> $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" +cat > $tmp/scriptx <<- \EOF myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} set -o pipefail sleep 3 | myfilter EOF -(( $($SHELL /tmp/ksh$$x) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' -rm -f /tmp/ksh$$x +(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' exec 3<&- ( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' $SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' @@ -406,13 +402,8 @@ $SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' EOF unset foo -function foo -{ - print bar -} -[[ ${foo} == bar ]] || err_exit '${foo} is not command substitution when foo unset' -[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' -[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' +[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' +[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' [[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' [[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' unset foo @@ -421,10 +412,57 @@ expected=foreback got=$(print -n fore;(sleep 2;print back)&) [[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" -for false in false $(whence -p false) +binfalse=$(whence -p false) +for false in false $binfalse do x=$($false) && err_exit "x=\$($false) should fail" $($false) && err_exit "\$($false) should fail" $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" done -[[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' +if env x-a=y >/dev/null 2>&1 +then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' +fi +float s=SECONDS +sleep=$(whence -p sleep) +for i in 1 2 +do print $i +done | while read sec; do ( $sleep $sec; $sleep $sec) done +(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' +s=SECONDS +set -o pipefail +for ((i=0; i < 30; i++)) +do print hello + sleep .1 +done | $sleep 1 +(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' +[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' +var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) +[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' + +exp= +got=$( + function fun + { + $binfalse && echo FAILED + } + : works if this line deleted : | + fun + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" +got=$( + : works if this line deleted : | + { $binfalse && echo FAILED; } + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" + +got=$( + : works if this line deleted : | + ( $binfalse && echo FAILED ) + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" + +( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/bracket.sh b/usr/src/lib/libshell/common/tests/bracket.sh index 0b36806fbf..496fdae5a4 100644 --- a/usr/src/lib/libshell/common/tests/bracket.sh +++ b/usr/src/lib/libshell/common/tests/bracket.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,17 +27,19 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + null='' if [[ ! -z $null ]] then err_exit "-z: null string should be of zero length" fi -file=/tmp/regresso$$ -newer_file=/tmp/regressn$$ +file=$tmp/original +newer_file=$tmp/newer if [[ -z $file ]] then err_exit "-z: $file string should not be of zero length" fi -trap "rm -f $file $newer_file" EXIT -rm -f $file if [[ -a $file ]] then err_exit "-a: $file shouldn't exist" fi @@ -119,11 +121,11 @@ fi if [[ $file -nt $newer_file ]] then err_exit "$newer_file should be newer than $file" fi -if [[ $file != /tmp/* ]] -then err_exit "$file should match /tmp/*" +if [[ $file != $tmp/* ]] +then err_exit "$file should match $tmp/*" fi -if [[ $file = '/tmp/*' ]] -then err_exit "$file should not equal /tmp/*" +if [[ $file = $tmp'/*' ]] +then err_exit "$file should not equal $tmp'/*'" fi [[ ! ( ! -z $null && ! -z x) ]] || err_exit "negation and grouping" [[ -z '' || -z '' || -z '' ]] || err_exit "three ors not working" @@ -211,17 +213,17 @@ done [[ aaaa == {2,5}(a) ]] || err_exit 'aaaa != {2,4}(a)' [[ abcdcdabcd == {3,6}(ab|cd) ]] || err_exit 'abcdcdabcd == {3,4}(ab|cd)' [[ abcdcdabcde == {5}(ab|cd)e ]] || err_exit 'abcdcdabcd == {5}(ab|cd)e' -) || err_exit 'Errors with {..}(...) patterns' +) || err_exit 'errors with {..}(...) patterns' [[ D290.2003.02.16.temp == D290.+(2003.02.16).temp* ]] || err_exit 'pattern match bug with +(...)' rm -rf $file { -[[ -N $file ]] && err_exit 'test -N /tmp/*: st_mtime>st_atime after creat' +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat' sleep 2 print 'hello world' -[[ -N $file ]] || err_exit 'test -N /tmp/*: st_mtime<=st_atime after write' +[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write' sleep 2 read -[[ -N $file ]] && err_exit 'test -N /tmp/*: st_mtime>st_atime after read' +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read' } > $file < $file if rm -rf "$file" && ln -s / "$file" then [[ -L "$file" ]] || err_exit '-L not working' @@ -242,4 +244,80 @@ i=hell test '(' = ')' && err_exit '"test ( = )" should not be true' [[ $($SHELL -c 'case F in ~(Eilr)[a-z0-9#]) print ok;;esac' 2> /dev/null) == ok ]] || err_exit '~(Eilr) not working in case command' [[ $($SHELL -c "case Q in ~(Fi)q | \$'\E') print ok;;esac" 2> /dev/null) == ok ]] || err_exit '~(Fi)q | \E not working in case command' + +for l in C en_US.ISO8859-15 +do [[ $($SHELL -c "LC_COLLATE=$l" 2>&1) ]] && continue + export LC_COLLATE=$l + set -- \ + 'A' 0 1 1 0 1 1 1 0 0 1 0 0 \ + 'Z' 0 1 1 0 1 1 1 0 0 1 0 0 \ + '/' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '.' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '_' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '-' 1 1 1 1 1 1 0 0 0 0 0 0 \ + '%' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '@' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '!' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '^' 0 0 0 0 0 0 1 1 1 1 1 1 \ + # retain this line # + while (( $# >= 13 )) + do c=$1 + shift + for p in \ + '[![.-.]]' \ + '[![.-.][:upper:]]' \ + '[![.-.]A-Z]' \ + '[!-]' \ + '[!-[:upper:]]' \ + '[!-A-Z]' \ + '[[.-.]]' \ + '[[.-.][:upper:]]' \ + '[[.-.]A-Z]' \ + '[-]' \ + '[-[:upper:]]' \ + '[-A-Z]' \ + # retain this line # + do e=$1 + shift + [[ $c == $p ]] + g=$? + [[ $g == $e ]] || err_exit "[[ '$c' == $p ]] for LC_COLLATE=$l failed -- expected $e, got $g" + done + done +done +integer n +if ( : < /dev/tty ) 2>/dev/null && exec {n}< /dev/tty +then [[ -t $n ]] || err_exit "[[ -t n ]] fails when n > 9" +fi +foo=([1]=a [2]=b [3]=c) +[[ -v foo[1] ]] || err_exit 'foo[1] should be set' +[[ ${foo[1]+x} ]] || err_exit '${foo[1]+x} should be x' +[[ ${foo[@]+x} ]] || err_exit '${foo[@]+x} should be x' +unset foo[1] +[[ -v foo[1] ]] && err_exit 'foo[1] should not be set' +[[ ${foo[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +bar=(a b c) +[[ -v bar[1] ]] || err_exit 'bar[1] should be set' +[[ ${bar[1]+x} ]] || err_exit '${foo[1]+x} should be x' +unset bar[1] +[[ ${bar[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +[[ -v bar ]] || err_exit 'bar should be set' +[[ -v bar[1] ]] && err_exit 'bar[1] should not be set' +integer z=( 1 2 4) +[[ -v z[1] ]] || err_exit 'z[1] should be set' +unset z[1] +[[ -v z[1] ]] && err_exit 'z[1] should not be set' +typeset -si y=( 1 2 4) +[[ -v y[6] ]] && err_exit 'y[6] should not be set' +[[ -v y[1] ]] || err_exit 'y[1] should be set' +unset y[1] +[[ -v y[1] ]] && err_exit 'y[1] should not be set' +x=abc +[[ -v x[0] ]] || err_exit 'x[0] should be set' +[[ ${x[0]+x} ]] || err_exit print '${x[0]+x} should be x' +[[ -v x[3] ]] && err_exit 'x[3] should not be set' +[[ ${x[3]+x} ]] && err_exit '${x[0]+x} should be Empty' +unset x +[[ ${x[@]+x} ]] && err_exit '${x[@]+x} should be Empty' +unset x y z foo bar exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/builtins.sh b/usr/src/lib/libshell/common/tests/builtins.sh index 08dac83a4e..cbd78fa98b 100644 --- a/usr/src/lib/libshell/common/tests/builtins.sh +++ b/usr/src/lib/libshell/common/tests/builtins.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,9 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test shell builtin commands Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test shell builtin commands builtin getconf : ${foo=bar} || err_exit ": failed" [[ $foo = bar ]] || err_exit ": side effects failed" @@ -171,30 +175,31 @@ if [[ $(command -v if) != if ]] then err_exit 'command -v not working' fi read -r var <<\! - + ! if [[ $var != "" ]] then err_exit "read -r of blank line not working" fi -mkdir -p /tmp/ksh$$/a/b/c 2>/dev/null || err_exit "mkdir -p failed" -$SHELL -c "cd /tmp/ksh$$/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" -trap 'print HUP' HUP -if [[ $(trap) != "trap -- 'print HUP' HUP" ]] -then err_exit '$(trap) not working' -fi -if [[ $(trap -p HUP) != 'print HUP' ]] -then err_exit '$(trap -p HUP) not working' -fi +mkdir -p $tmp/a/b/c 2>/dev/null || err_exit "mkdir -p failed" +$SHELL -c "cd $tmp/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" + +trap 'print TERM' TERM +exp=$'trap -- \'print TERM\' TERM\ntrap -- \'cd /; rm -rf '$tmp$'\' EXIT' +got=$(trap) +[[ $got == $exp ]] || err_exit "\$(trap) failed -- expected \"$exp\", got \"$got\"" +exp='print TERM' +got=$(trap -p TERM) +[[ $got == $exp ]] || err_exit "\$(trap -p TERM) failed -- expected \"$exp\", got \"$got\"" + [[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' [[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' [[ $($SHELL -c '( trap "" TERM);kill $$;print bad' == bad) ]] 2> /dev/null && err_exit 'trap ignored in subshell causes it to be ignored by parent' ${SHELL} -c 'kill -1 -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' ${SHELL} -c 'kill -1 -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' ${SHELL} -c 'kill -s HUP -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' n=123 typeset -A base base[o]=8# @@ -266,23 +271,23 @@ OPTIND=1 if [[ $(getopts $'[+?X\ffoobar\fX]' v --man 2>&1) != *'Xhello world'X* ]] then err_exit '\f...\f not working in getopts usage strings' fi -if [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] +if [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] then err_exit 'printf %H not working' fi -if [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] +if [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] then err_exit 'printf %R not working' fi if [[ $(printf '%..:c\n' abc) != a:b:c ]] -then err_exit "printf '%..:c' not working" +then err_exit "printf '%..:c' not working" fi if [[ $(printf '%..*c\n' : abc) != a:b:c ]] -then err_exit "printf '%..*c' not working" +then err_exit "printf '%..*c' not working" fi if [[ $(printf '%..:s\n' abc def ) != abc:def ]] -then err_exit "printf '%..:s' not working" +then err_exit "printf '%..:s' not working" fi if [[ $(printf '%..*s\n' : abc def) != abc:def ]] -then err_exit "printf '%..*s' not working" +then err_exit "printf '%..*s' not working" fi [[ $(printf '%q\n') == '' ]] || err_exit 'printf "%q" with missing arguments' # we won't get hit by the one second boundary twice, right? @@ -296,12 +301,18 @@ behead() } print $'line1\nline2' | behead if [[ $left != line2 ]] -then err_exit "read reading ahead on a pipe" +then err_exit "read reading ahead on a pipe" fi -print -n $'{ read -r line;print $line;}\nhello' > /tmp/ksh$$ -chmod 755 /tmp/ksh$$ -trap 'rm -rf /tmp/ksh$$' EXIT -if [[ $($SHELL < /tmp/ksh$$) != hello ]] +read -n1 y <<! +abc +! +exp=a +if [[ $y != $exp ]] +then err_exit "read -n1 failed -- expected '$exp', got '$y'" +fi +print -n $'{ read -r line;print $line;}\nhello' > $tmp/script +chmod 755 $tmp/script +if [[ $($SHELL < $tmp/script) != hello ]] then err_exit 'read of incomplete line not working correctly' fi set -f @@ -321,19 +332,13 @@ wait $pid1 (( $? == 1 )) || err_exit "wait not saving exit value" wait $pid2 (( $? == 127 )) || err_exit "subshell job known to parent" -set --noglob -ifs=$IFS -IFS=, -set -- $(getconf LIBPATH) -IFS=$ifs env= -for v -do IFS=: - set -- $v - IFS=$ifs - eval [[ \$$2 ]] && env="$env $2=\"\$$2\"" +v=$(getconf LIBPATH) +for v in ${v//,/ } +do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && env="$env $v=\"\$$v\"" done -set --glob if [[ $(foo=bar; eval foo=\$foo $env exec -c \$SHELL -c \'print \$foo\') != bar ]] then err_exit '"name=value exec -c ..." not working' fi @@ -364,7 +369,7 @@ do arg=$1 val=$2 code=$3 err=$(printf "$fmt" "$arg" 2>&1 >/dev/null) printf "$fmt" "$arg" >/dev/null 2>&1 ret=$? - [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected $val, got $out" + [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'" if (( $code )) then [[ $err ]] || err_exit "printf $fmt $arg failed, error message expected" else [[ $err ]] && err_exit "$err: printf $fmt $arg failed, error message not expected -- got '$err'" @@ -398,6 +403,50 @@ do case $opt in *) err_exit "getopts $options failed -- got flag $opt" ;; esac done + +unset a +{ read -N3 a; read -N1 b;} <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -N3 here-document failed -- expected '$exp', got '$a'" +exp=d +[[ $b == $exp ]] || err_exit "read -N1 here-document failed -- expected '$exp', got '$b'" +read -n3 a <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -n3 here-document failed -- expected '$exp', got '$a'" +#(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} +#[[ $a == $exp ]] || err_exit "read -N3 from pipe failed -- expected '$exp', got '$a'" +#exp=d +#[[ $b == $exp ]] || err_exit "read -N1 from pipe failed -- expected '$exp', got '$b'" +#(print -n a;sleep 1; print -n bcde) | read -n3 a +#exp=a +#[[ $a == $exp ]] || err_exit "read -n3 from pipe failed -- expected '$exp', got '$a'" +#rm -f $tmp/fifo +#if mkfifo $tmp/fifo 2> /dev/null +#then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' +# read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' +# } 5< $tmp/fifo +# exp=a +# [[ $a == $exp ]] || err_exit "read -n3 from fifo failed -- expected '$exp', got '$a'" +# rm -f $tmp/fifo +# mkfifo $tmp/fifo 2> /dev/null +# (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' +# read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' +# } 5< $tmp/fifo +# exp=abc +# [[ $a == $exp ]] || err_exit "read -N3 from fifo failed -- expected '$exp', got '$a'" +# exp=d +# [[ $b == $exp ]] || err_exit "read -N1 from fifo failed -- expected '$exp', got '$b'" +#fi +#rm -f $tmp/fifo + function longline { integer i @@ -437,33 +486,43 @@ getconf UNIVERSE - ucb [[ $($SHELL -c 'echo -3') == -3 ]] || err_exit "echo -3 not working in ucb universe" typeset -F3 start_x=SECONDS total_t delay=0.02 typeset reps=50 leeway=5 -sleep $(( 2 * leeway * reps * delay )) | -for (( i=0 ; i < reps ; i++ )) -do read -N1 -t $delay -done -(( total_t = SECONDS - start_x )) -if (( total_t > leeway * reps * delay )) -then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" -elif (( total_t < reps * delay )) -then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" -fi -$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" -$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' +#sleep $(( 2 * leeway * reps * delay )) | +#for (( i=0 ; i < reps ; i++ )) +#do read -N1 -t $delay +#done +#(( total_t = SECONDS - start_x )) +#if (( total_t > leeway * reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" +#elif (( total_t < reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" +#fi +#$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" +#$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' [[ $(ulimit) == "$(ulimit -fS)" ]] || err_exit 'ulimit is not the same as ulimit -fS' -tmpfile=${TMP-/tmp}/ksh$$.2 -trap 'rm -f /tmp/ksh$$ "$tmpfile"' EXIT +tmpfile=$tmp/file.2 print $'\nprint -r -- "${.sh.file} ${LINENO} ${.sh.lineno}"' > $tmpfile [[ $( . "$tmpfile") == "$tmpfile 2 1" ]] || err_exit 'dot command not working' print -r -- "'xxx" > $tmpfile [[ $($SHELL -c ". $tmpfile"$'\n print ok' 2> /dev/null) == ok ]] || err_exit 'syntax error in dot command affects next command' -float sec=$SECONDS del=4 -exec 3>&2 2>/dev/null -$SHELL -c "( sleep 1; kill -ALRM \$\$ ) & sleep $del" 2> /dev/null -exitval=$? -(( sec = SECONDS - sec )) -exec 2>&3- -(( exitval )) && err_exit "sleep doesn't exit 0 with ALRM interupt" -(( sec > (del - 1) )) || err_exit "ALRM signal causes sleep to terminate prematurely -- expected 3 sec, got $sec" +#float sec=$SECONDS del=4 +#exec 3>&2 2>/dev/null +#$SHELL -c "( sleep 1; kill -ALRM \$\$ ) & sleep $del" 2> /dev/null +#exitval=$? +#(( sec = SECONDS - sec )) +#exec 2>&3- +#(( exitval )) && err_exit "sleep doesn't exit 0 with ALRM interupt" +#(( sec > (del - 1) )) || err_exit "ALRM signal causes sleep to terminate prematurely -- expected 3 sec, got $sec" +typeset -r z=3 +y=5 +for i in 123 z %x a.b.c +do ( unset $i) 2>/dev/null && err_exit "unset $i should fail" +done +a=() +for i in y y y[8] t[abc] y.d a.b a +do unset $i || print -u2 "err_exit unset $i should not fail" +done +[[ $($SHELL -c 'y=3; unset 123 y;print $?$y') == 1 ]] 2> /dev/null || err_exit 'y is not getting unset with unset 123 y' +[[ $($SHELL -c 'trap foo TERM; (trap;(trap) )') == 'trap -- foo TERM' ]] || err_exit 'traps not getting reset when subshell is last process' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/case.sh b/usr/src/lib/libshell/common/tests/case.sh index cca84686bd..1f04cfd30d 100644 --- a/usr/src/lib/libshell/common/tests/case.sh +++ b/usr/src/lib/libshell/common/tests/case.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/comvar.sh b/usr/src/lib/libshell/common/tests/comvar.sh index dfc9d9acfd..00eac1d188 100644 --- a/usr/src/lib/libshell/common/tests/comvar.sh +++ b/usr/src/lib/libshell/common/tests/comvar.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -85,7 +85,7 @@ foo=(integer x=3) if [[ ${foo} != *x=3* ]] then err_exit "compound variable with integer subvariable not working" fi -$SHELL -c $'x=(foo=bar)\n[[ x == x ]]' 2> /dev/null || +$SHELL -c $'x=(foo=bar)\n[[ x == x ]]' 2> /dev/null || err_exit '[[ ... ]] not working after compound assignment' unset foo [[ ${!foo.@} ]] && err_exit 'unset compound variable leaves subvariables' @@ -194,7 +194,7 @@ localvar [[ $($SHELL -c 'foo=();foo.[x]=(y z); print ${foo.x[@]}') == 'y z' ]] 2> /dev/null || err_exit 'foo=( [x]=(y z) not working' function staticvar { - if [[ $1 ]] + if [[ $1 ]] then print -r -- "$point" return fi @@ -291,7 +291,7 @@ foo=( ) eval foo2="$foo" foo2.hello=notok foo2.yes.yex=no foo2.extra=yes. -typeset -C bar bam +typeset -C bar bam { read -Cu3 bar read -Cu3 bam @@ -422,5 +422,120 @@ data.samples+=( command2="grrrr2" ) -[[ $data == %(()) ]] || err_exit "unbalanced parenthesis with compound variable containing array of compound variables" +[[ $data == %(()) ]] || err_exit "unbalanced parenthesis with compound variable containing array of compound variables" +typeset -C -A hello=( [foo]=bar) +[[ $(typeset -p hello) == 'typeset -C -A hello=([foo]=bar)' ]] || err_exit 'typeset -A -C with intial assignment not working' +# this caused a core dump before ksh93t+ +[[ $($SHELL -c 'foo=(x=3 y=4);function bar { typeset z=4;: $z;};bar;print ${!foo.@}') == 'foo.x foo.y' ]] 2> /dev/null || err_exit '${!foo.@} after function not working' + +function foo +{ + typeset tmp + read -C tmp + read -C tmp +} +foo 2> /dev/null <<- \EOF || err_exit 'deleting compound variable in function failed' + ( + typeset -A myarray3=( + [a]=( foo=bar) + [b]=( foo=bar) + [c d]=( foo=bar) + [e]=( foo=bar) + [f]=( foo=bar) + [g]=( foo=bar) + [h]=( foo=bar) + [i]=( foo=bar) + [j]=( foo=bar) + ) + ) + hello +EOF + +typeset -C -a mica01 +mica01[4]=( a_string="foo bar" ) +typeset -C more_content=( + some_stuff="hello" +) +mica01[4]+=more_content +expected=$'typeset -C -a mica01=([4]=(a_string=\'foo bar\';some_stuff=hello;))' +[[ $(typeset -p mica01) == "$expected" ]] || err_exit 'appened to indexed array compound variable not working' + +unset x +compound x=( integer x ; ) +[[ ! -v x.x ]] && err_exit 'x.x should be set' +expected=$'(\n\ttypeset -l -i x=0\n)' +[[ $(print -v x) == "$expected" ]] || err_exit "'print -v x' should be $expected" + +typeset -C -A hello19=( + [19]=( + one="xone 19" + two="xtwo 19" + ) + [23]=( + one="xone 23" + two="xtwo 23" + ) +) +expected="typeset -C -A hello19=([19]=(one='xone 19';two='xtwo 19';) [23]=(one='xone 23';two='xtwo 23';))" +[[ $(typeset -p hello19) == "$expected" ]] || print -u2 'typeset -p hello19 incorrect' +expected=$'(\n\tone=\'xone 19\'\n\ttwo=\'xtwo 19\'\n) (\n\tone=\'xone 23\'\n\ttwo=\'xtwo 23\'\n)' +[[ ${hello19[@]} == "$expected" ]] || print -u2 '${hello19[@]} incorrect' + +typeset -C -A foo1=( abc="alphabet" ) foo2=( abc="alphabet" ) +function add_one +{ + nameref left_op=$1 + typeset -C info + info.hello="world" + nameref x=info + left_op+=x +} +nameref node1="foo1[1234]" +add_one "node1" +add_one "foo2[1234]" +[[ "${foo1[1234]}" == "${foo2[1234]}" ]] || err_exit "test failed\n$(diff -u <( print -r -- "${foo1[1234]}") <(print -r -- "${foo2[1234]}"))." + +typeset -C tree +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + + # move local note into the array + typeset -m tr.subtree["a_node"]=node +} +f1 tree +expected=$'(\n\ttypeset -A subtree=(\n\t\t[a_node]=(\n\t\t\tone=hello\n\t\t\ttwo=world\n\t\t)\n\t)\n)' +[[ $tree == "$expected" ]] || err_exit 'move of compound local variable to global variable not working' + +typeset -C -A array +float array[12].amount=2.9 +expected='typeset -C -A array=([12]=(typeset -l -E amount=2.9;))' +[[ $(typeset -p array) == "$expected" ]] || err_exit 'typeset with compound variable with compound variable array not working' + +typeset -T foo_t=( + function diff + { + print 1.0 + return 0 + } +) +foo_t sw +compound output=( + integer one=1 + float mydiff=sw.diff + float end=.314 +) +[[ $output == *end=* ]] || err_exit "The field 'name' end is missing" + +compound cpv1=( integer f=2 ) +compound x=( + integer a=1 + compound b=cpv1 +) +[[ $x == *f=2* ]] || err_exit "The field b containg 'f=2' is missing" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/coprocess.sh b/usr/src/lib/libshell/common/tests/coprocess.sh index feff0bace2..dde9a49805 100644 --- a/usr/src/lib/libshell/common/tests/coprocess.sh +++ b/usr/src/lib/libshell/common/tests/coprocess.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -29,6 +29,9 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + if [[ -d /cygdrive ]] then err_exit cygwin detected - coprocess tests disabled - enable at the risk of wedging your system exit $((Errors)) @@ -46,11 +49,11 @@ function ping # id cat |& print -p "hello" read -p line -[[ $line == hello ]] || err_exit 'coprocessing fails' +[[ $line == hello ]] || err_exit 'coprocessing fails' exec 5>&p 6<&p print -u5 'hello again' || err_exit 'write on u5 fails' read -u6 line -[[ $line == 'hello again' ]] || err_exit 'coprocess after moving fds fails' +[[ $line == 'hello again' ]] || err_exit 'coprocess after moving fds fails' exec 5<&- 6<&- wait $! @@ -87,8 +90,7 @@ do (( count-- )) done kill $(jobs -p) 2>/dev/null -file=/tmp/regress$$ -trap "rm -f $file" EXIT +file=$tmp/regress cat > $file <<\! /bin/cat |& ! @@ -100,15 +102,24 @@ exec 5<&- 6>&- kill $(jobs -p) 2>/dev/null ${SHELL-ksh} |& -print -p $'print hello | cat\nprint Done' +cop=$! +exp=Done +print -p $'print hello | cat\nprint '$exp read -t 5 -p read -t 5 -p -if [[ $REPLY != Done ]] -then err_exit "${SHELL-ksh} coprocess not working" +got=$REPLY +if [[ $got != $exp ]] +then err_exit "${SHELL-ksh} coprocess io failed -- got '$got', expected '$exp'" fi exec 5<&p 6>&p exec 5<&- 6>&- -wait $! +{ sleep 4; kill $cop; } 2>/dev/null & +spy=$! +if wait $cop 2>/dev/null +then kill $spy 2>/dev/null +else err_exit "coprocess hung after 'exec 5<&p 6>&p; exec 5<&- 6>&-'" +fi +wait { echo line1 | grep 'line2' @@ -123,7 +134,7 @@ then err_exit "read -p hanging (SECONDS=$SECONDS count=$count)" fi wait $! -( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) || +( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) || err_exit "coprocess cleanup not working correctly" { : |& } 2>/dev/null || err_exit "subshell coprocess lingers in parent" @@ -163,7 +174,7 @@ r= print -u6 ok exec 6>&- sleep 1 - kill $! 2> /dev/null + kill $! 2> /dev/null ) && err_exit 'coprocess with subshell would hang' for sig in IOT ABRT do if ( trap - $sig ) 2> /dev/null @@ -178,7 +189,7 @@ do if ( trap - $sig ) 2> /dev/null kill -$sig $$ kill $pid sleep 2 - kill $$ + kill $$ ) & read -p ++EOF++ @@ -206,7 +217,7 @@ trap - TERM trap 'sleep_pid=; kill $pid; err_exit "coprocess 2 hung"' TERM { sleep 5; kill $$; } & sleep_pid=$! -cat |& +cat |& pid=$! print foo >&p 2> /dev/null || err_exit 'first write of foo to coprocess failed' print foo >&p 2> /dev/null || err_exit 'second write of foo to coprocess failed' @@ -218,7 +229,7 @@ trap - TERM trap 'sleep_pid=; kill $pid; err_exit "coprocess 3 hung"' TERM { sleep 5; kill $$; } & sleep_pid=$! -cat |& +cat |& pid=$! print -p foo print -p bar @@ -231,4 +242,72 @@ wait $pid 2> /dev/null trap - TERM [[ $sleep_pid ]] && kill $sleep_pid +exp=ksh +got=$(print -r $'#00315 +COATTRIBUTES=\'label=make \' +# @(#)$Id: libcoshell (AT&T Research) 2008-04-28 $ +_COSHELL_msgfd=5 +{ { (eval \'function fun { trap \":\" 0; return 1; }; trap \"exit 0\" 0; fun; exit 1\') && PATH= print -u$_COSHELL_msgfd ksh; } || { times && echo bsh >&$_COSHELL_msgfd; } || { echo osh >&$_COSHELL_msgfd; }; } >/dev/null 2>&1' | $SHELL 5>&1) +[[ $got == $exp ]] || err_exit "coshell(3) identification sequence failed -- expected '$exp', got '$got'" + +function cop +{ + read + print ok +} + +exp=ok + +cop |& +pid=$! +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +cop |& +pid=$! +( +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess subshell query failed -- expected $exp, got '$got'" +) +kill $pid 2>/dev/null +wait + +exp='no coprocess' + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +( +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess subshell query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait +) + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/cubetype.sh b/usr/src/lib/libshell/common/tests/cubetype.sh index f3597d258d..4a718d4a38 100644 --- a/usr/src/lib/libshell/common/tests/cubetype.sh +++ b/usr/src/lib/libshell/common/tests/cubetype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -120,7 +120,7 @@ typeset -T Cube_t=( for ((i=0; i < n; i++)) do Box_t b=(name=box2) -[[ ${b.name} == box2 ]] || err_exit "\${b.name} incorrect -- expected box2, got '${b.name}'" +[[ ${b.name} == box2 ]] || err_exit "\${b.name} incorrect -- expected box2, got '${b.name}'" (( b.len == 5 )) || err_exit "b.len incorrect for box2 -- expected 5, got '$(( b.len ))'" (( b.count == 1 )) || err_exit "b.count incorrect -- expected 1, got '$(( b.count ))'" Cube_t c=(name=cube1) @@ -134,7 +134,7 @@ Cube_t c=(name=cube1) (( c.count == 2 )) || err_exit 'c.count != 2' (( c.count == b.count )) || err_exit 'c.count != b.count' c.count=0 -Cube_t d=c +Cube_t d=c [[ $d == "$c" ]] || err_exit '$d != $c' eval "Cube_t zzz=$c" [[ $zzz == "$c" ]] || err_exit '$zzz != $c' @@ -149,6 +149,7 @@ for ((i=0; i < n; i++)) do Cube_t cc cc[2]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +[[ ${cc[0].x} == 8 ]] || err_exit 'cc[0].x !=8' [[ ${cc[2].y} == 3 ]] || err_exit '${cc[2].y} != 3' (( cc[2].y == 3 )) || err_exit '(( cc[2].y != 3))' [[ ${cc[2].colors[table]} == white ]] || err_exit '${cc[2].colors[table]} != white' @@ -162,7 +163,7 @@ unset cc[2].x cc[2].y cc[2].z (( cc[2].len == cc.len )) || err_exit 'cc[2].len != cc.len' (( cc[2].count == 6 )) || err_exit 'cc[2].count != 6' unset cc[2].name cc[2].colors cc[2].items -[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' +[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' cc.count=0 unset cc Cube_t -A cc @@ -181,7 +182,7 @@ unset cc[two].x cc[two].y cc[two].z (( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' (( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' unset cc[two].name unset cc[two].colors cc[two].items -[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' +[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' cc[two].count=0 unset cc Cube_t cc=( diff --git a/usr/src/lib/libshell/common/tests/enum.sh b/usr/src/lib/libshell/common/tests/enum.sh index 35d2a27952..1929472bb5 100644 --- a/usr/src/lib/libshell/common/tests/enum.sh +++ b/usr/src/lib/libshell/common/tests/enum.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -43,8 +43,8 @@ x[2]=green [[ $x == orange ]] || err_exit '$x is no longer orange' Color_t -A y y[foo]=yellow -[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' -(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' +[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' +(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' unset y typeset -a [Color_t] z z[green]=xyz diff --git a/usr/src/lib/libshell/common/tests/exit.sh b/usr/src/lib/libshell/common/tests/exit.sh index 01c407bf18..a14b0dcbec 100644 --- a/usr/src/lib/libshell/common/tests/exit.sh +++ b/usr/src/lib/libshell/common/tests/exit.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function abspath { base=$(basename $SHELL) @@ -34,28 +40,20 @@ function abspath print $newdir/$base } #test for proper exit of shell -Command=${0##*/} -integer Errors=0 builtin getconf ABSHELL=$(abspath) -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } print exit 0 >.profile ${ABSHELL} <<! HOME=$PWD \ PATH=$PATH \ SHELL=$ABSSHELL \ $( - set --noglob - ifs=$IFS - IFS=, - set -- $(getconf LIBPATH) - IFS=$ifs - for v - do IFS=: - set -- $v - IFS=$ifs - eval [[ \$$2 ]] && eval print -n \" \"\$2=\"\$$2\" + v=$(getconf LIBPATH) + for v in ${v//,/ } + do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && eval print -n \" \"\$v=\"\$$v\" done ) \ exec -c -a -ksh ${ABSHELL} -c "exit 1" 1>/dev/null 2>&1 @@ -77,6 +75,6 @@ if [[ $($SHELL ./run.sh) != 123 ]] then err_exit 'subshell trap on exit overwrites parent trap' fi cd ~- || err_exit "cd back failed" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" $SHELL -c 'builtin -f cmd getconf; getconf --"?-version"; exit 0' >/dev/null 2>&1 || err_exit 'ksh plugin exit failed -- was ksh built with CCFLAGS+=$(CC.EXPORT.DYNAMIC)?' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/expand.sh b/usr/src/lib/libshell/common/tests/expand.sh index 5dd46bdd8f..c63e7eb3e2 100644 --- a/usr/src/lib/libshell/common/tests/expand.sh +++ b/usr/src/lib/libshell/common/tests/expand.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/functions.sh b/usr/src/lib/libshell/common/tests/functions.sh index 0eaa17c688..146b537743 100644 --- a/usr/src/lib/libshell/common/tests/functions.sh +++ b/usr/src/lib/libshell/common/tests/functions.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,12 +28,10 @@ alias err_exit='err_exit $LINENO' integer Errors=0 Command=${0##*/} -tmp=/tmp/kshtf$$ -function cleanup -{ - rm -rf $tmp -} -mkdir $tmp || err_exit "mkdir $tmp failed" +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT integer foo=33 bar=bye @@ -89,11 +87,11 @@ function foobar { (return 0) } -> $tmp/shtests$$.1 +> $tmp/test1 { foobar -if [ -r $tmp/shtests$$.1 ] -then rm -r $tmp/shtests$$.1 +if [ -r $tmp/test1 ] +then rm -r $tmp/test1 else err_exit 'return within subshell inside function error' fi } @@ -138,37 +136,36 @@ fun() /bin/echo hello if [[ $(fun) != hello ]] then err_exit one line functions not working fi -trap cleanup EXIT -cat > $tmp/script$$ <<-\! +cat > $tmp/script <<-\! print -r -- "$1" ! -chmod +x $tmp/script$$ +chmod +x $tmp/script function passargs { - $tmp/script$$ "$@" + $tmp/script "$@" } if [[ $(passargs one) != one ]] then err_exit 'passing args from functions to scripts not working' fi -cat > $tmp/script$$ <<-\! +cat > $tmp/script <<-\! trap 'exit 0' EXIT function foo { - /tmp > /dev/null 2>&1 + /tmp > /dev/null 2>&1 } foo ! -if ! $tmp/script$$ -then err_exit 'exit trap incorrectly triggered' +if ! $tmp/script +then err_exit 'exit trap incorrectly triggered' fi -if ! $SHELL -c $tmp/script$$ -then err_exit 'exit trap incorrectly triggered when invoked with -c' +if ! $SHELL -c $tmp/script +then err_exit 'exit trap incorrectly triggered when invoked with -c' fi -$SHELL -c "trap 'rm $tmp/script$$' EXIT" -if [[ -f $tmp/script$$ ]] -then err_exit 'exit trap not triggered when invoked with -c' +$SHELL -c "trap 'rm $tmp/script' EXIT" +if [[ -f $tmp/script ]] +then err_exit 'exit trap not triggered when invoked with -c' fi -cat > $tmp/script$$ <<- \EOF +cat > $tmp/script <<- \EOF foobar() { return @@ -177,8 +174,8 @@ cat > $tmp/script$$ <<- \EOF foobar print -r -- "$1" EOF -chmod +x $tmp/script$$ -if [[ $( $SHELL $tmp/script$$ arg1 arg2) != arg2 ]] +chmod +x $tmp/script +if [[ $( $SHELL $tmp/script arg1 arg2) != arg2 ]] then err_exit 'arguments not restored by posix functions' fi function foo @@ -212,18 +209,17 @@ x=1 if [[ $(foo) != 3 ]] then err_exit 'variable assignment list not using parent scope' fi -unset -f foo$$ -#trap "rm -f $tmp/foo$$" EXIT INT -cat > $tmp/foo$$ <<! -function foo$$ +unset -f foobar +cat > $tmp/foobar <<! +function foobar { print foo } ! -chmod +x $tmp/foo$$ +chmod +x $tmp/foobar FPATH=$tmp -autoload foo$$ -if [[ $(foo$$ 2>/dev/null) != foo ]] +autoload foobar +if [[ $(foobar 2>/dev/null) != foo ]] then err_exit 'autoload not working' fi unset -f foobar @@ -233,14 +229,14 @@ function foobar return 0 } ( foobar ) 2> /dev/null || err_exit "cannot unset readonly variable in function" -if $SHELL -n 2> /dev/null <<-! +if $SHELL -n 2> /dev/null <<-! abc() ! then err_exit 'abc() without a function body is not a syntax error' fi function winpath { - usage='q pathname ...' + usage='q pathname ...' typeset var format=s while getopts "$usage" var do case $var in @@ -296,7 +292,7 @@ then err_exit 'set -e not inherited for posix functions' fi trap - ERR -function myexport +function myexport { nameref var=$1 if (( $# > 1 )) @@ -309,7 +305,6 @@ function myexport typeset val val=$(export | grep "^$1=") print ${val#"$1="} - } export dgk=base val=$(myexport dgk fun) @@ -384,8 +379,26 @@ function closure return $r } closure 0 || err_exit -u2 'for loop function optimization bug2' -mkdir $tmp/ksh$$ || err_exit "mkdir $tmp/ksh$$ failed" -cd $tmp/ksh$$ || err_exit "cd $tmp/ksh$$ failed" +dir=$tmp/dir +mkdir $dir +cd $dir || { err_exit "cd $dir failed"; exit 1; } + +( + function a { + print a + } + function b { + print 1 + a + print 2 + } > /dev/null + typeset -ft a b + PS4=X + b +) > file 2>&1 +[[ $(<file) == *'Xprint 2'* ]] || err_exit 'function trace disabled by function call' +rm -f file + print 'false' > try chmod +x try cat > tst <<- EOF @@ -400,18 +413,19 @@ EOF if [[ $($SHELL < tst) == error ]] then err_exit 'ERR trap not cleared' fi -FPATH=$tmp/ksh$$ -print ': This does nothing' > $tmp/ksh$$/foobar -chmod +x $tmp/ksh$$/foobar -unset -f foobar -{ foobar;} 2> /dev/null -if [[ $? != 126 ]] -then err_exit 'function file without function definition processes wrong error' +FPATH=$dir +print ': This does nothing' > foobar +chmod +x foobar +unset -f foobar +{ foobar; } 2>/dev/null +got=$? +exp=126 +if [[ $got != $exp ]] +then err_exit "function file without function definition processes wrong error -- expected '$exp', got '$got'" fi -print 'set a b c' > dotscript +print 'set a b c' > dotscript [[ $(PATH=$PATH: $SHELL -c '. dotscript;print $#') == 3 ]] || err_exit 'positional parameters not preserved with . script without arguments' cd ~- || err_exit "cd back failed" -cd /; rm -r $tmp/ksh$$ || err_exit "rm -r $tmp/ksh$$ failed" function errcheck { trap 'print ERR; return 1' ERR @@ -439,7 +453,7 @@ a() b() { : ;} [[ $(a) == a ]] || err_exit '.sh.fun not set correctly in a function' print $'a(){\ndate\n}' | $SHELL 2> /dev/null || err_exit 'parser error in a(){;date;}' -cat > $tmp/data$$.1 << '++EOF' +cat > $tmp/data1 << '++EOF' 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -461,7 +475,7 @@ cat > $tmp/data$$.1 << '++EOF' 19 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 20 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ++EOF -cat > $tmp/script$$ << '++EOF' +cat > $tmp/script << '++EOF' # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -727,10 +741,10 @@ f() { cat <<\M ++EOF -cat $tmp/data$$.1 >> $tmp/script$$ -printf 'M\n}\n\nf\n\n' >> $tmp/script$$ -$SHELL -c $tmp/script$$ > $tmp/data$$.2 -cmp -s $tmp/data$$.[12] || err_exit 'error with long functions' +cat $tmp/data1 >> $tmp/script +printf 'M\n}\n\nf\n\n' >> $tmp/script +$SHELL -c $tmp/script > $tmp/data2 +cmp -s $tmp/data[12] || err_exit 'error with long functions' v=1 function f { @@ -776,7 +790,7 @@ x=$( integer count=0 function err_f { - if ((count++==3)) + if ((count++==3)) then print failed else false fi @@ -785,7 +799,6 @@ x=$( false ) [[ $x == failed ]] && err_exit 'ERR trap executed multiple times' -trap cleanup EXIT export environment typeset global function f @@ -819,17 +832,17 @@ function f } f local global environment literal positional $SHELL -c ' - print exit 0 > '$tmp'/script$$ - chmod +x '$tmp'/script$$ + print exit 0 > '$tmp'/script + chmod +x '$tmp'/script unset var var=( ident=1 ) function fun { - PATH='$tmp' script$$ + PATH='$tmp' script } fun ' || err_exit "compound variable cleanup before script exec failed" -( $SHELL << \++EOF++ +( $SHELL << \++EOF++ function main { typeset key @@ -921,10 +934,7 @@ unset -f .sh.fun.set # tests for debug functions basefile=${.sh.file} integer baseline -cleanup -trap 'rm $tmp' EXIT -tmp=${TMPDIR:-/tmp}/ksh$$.1 -cat > $tmp << \+++ +cat > $tmp/debug << \+++ : line 1 : line 3 @@ -943,7 +953,7 @@ function _Dbg_print_frame [[ $arg == DEBUG ]] && ((baseline++)) [[ $line == "$baseline" ]] || err_exit "line number for level 0 is $line not $baseline" elif ((pos==1)) - then [[ $filename == "$tmp" ]] || err_exit "filename for level 1 is $filename not $tmp" + then [[ $filename == "$tmp/debug" ]] || err_exit "filename for level 1 is $filename not $tmp/debug" [[ $* == 'foo bar' ]] || err_exit "args are '$*', not 'foo bar'" [[ $line == $arg ]] || err_exit "line number for level 1 is $line not $arg" else err_exit "level should be 0 or 1 but is $pos" @@ -963,9 +973,9 @@ function _Dbg_debug_trap_handler ((baseline=LINENO+2)) trap '_Dbg_debug_trap_handler' DEBUG -. $tmp foo bar +. $tmp/debug foo bar trap '' DEBUG - + caller() { integer .level=.sh.level .max=.sh.level-1 while((--.level>=0)) @@ -978,4 +988,84 @@ bar() { caller;} set -- $(bar) [[ $1 == $2 ]] && err_exit ".sh.inline optimization bug" ( $SHELL -c ' function foo { typeset x=$1;print $1;};z=();z=($(foo bar)) ') 2> /dev/null || err_exit 'using a function to set an array in a command sub fails' + +{ +got=$( +s=$(ulimit -s) +if [[ $s == +([[:digit:]]) ]] && (( s < 16384 )) +then ulimit -s 16384 2>/dev/null +fi +$SHELL << \+++ +f() +{ + if (($1>1)) + then x=$(f $(($1-1))) || exit 1 + fi + return 0 +} +f 257 && print ok ++++ +) +} 2>/dev/null +[[ $got == ok ]] || err_exit 'cannot handle comsub depth > 256 in function' + +tmp1=$tmp/job.1 +tmp2=$tmp/job.2 +cat > $tmp1 << +++ +#! $SHELL +print \$\$ ++++ +chmod +x $tmp1 +function foo +{ + typeset pid + $tmp1 > $tmp2 & pid=$! + wait $! + [[ $(< $tmp2) == $pid ]] || err_exit 'wrong pid for & job in function' +} +foo +# make sure compiled functions work +[[ $(tmp=$tmp $SHELL <<- \++++ + cat > $tmp/functions <<- \EOF + function bar + { + print foo + } + function foobar + { + bar + } + EOF + ${SHCOMP:-${SHELL%/*}/shcomp} $tmp/functions > $tmp/foobar + rm -f "$tmp/functions" + chmod +x $tmp/foobar + rm $tmp/!(dir|foobar) + FPATH=$tmp + PATH=$FPATH:$PATH + foobar +++++ +) == foo ]] > /dev/null || err_exit 'functions compiled with shcomp not working' +# test for functions in shell having side effects. +unset -f foo foobar bar +cd "$tmp" +FPATH=$PWD +PATH=$FPATH:$PATH +cat > foo <<- \EOF + function bar + { + print foobar + } + function foo + { + bar + } +EOF +chmod +x foo +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effect of function foo' +unset -f foo bar +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effects of function foo after reload' +[[ $(typeset +f) == *bar* ]] && err_exit 'function in subshell leaving side effects of function bar after reload' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/glob.sh b/usr/src/lib/libshell/common/tests/glob.sh index 2c3ccd09d3..fa22291c96 100644 --- a/usr/src/lib/libshell/common/tests/glob.sh +++ b/usr/src/lib/libshell/common/tests/glob.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,7 +24,11 @@ function err_exit } alias err_exit='err_exit $LINENO' -integer aware=0 contrary=0 ignorant=0 +Command=${0##*/} +integer aware=0 contrary=0 errors=0 ignorant=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT function test_glob { @@ -84,17 +88,11 @@ function test_case } alias test_case='test_case $LINENO' -Command=${0##*/} -tmp=/tmp/ksh$$ -integer errors=0 unset undefined export LC_COLLATE=C -mkdir $tmp || err_exit "mkdir $tmp failed" -trap "cd /; rm -rf $tmp" EXIT -cd $tmp || err_exit "cd $tmp failed" -rm -rf * +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } touch B b set -- * diff --git a/usr/src/lib/libshell/common/tests/grep.sh b/usr/src/lib/libshell/common/tests/grep.sh index 82c0e13cac..40a80a07a7 100644 --- a/usr/src/lib/libshell/common/tests/grep.sh +++ b/usr/src/lib/libshell/common/tests/grep.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,6 +28,9 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function grep { # @@ -84,8 +87,7 @@ function grep let tc # set the return value } -trap 'rm -f /tmp/grep$$' EXIT -cat > /tmp/grep$$ <<\! +cat > $tmp/grep <<\! this is a food bar test to see how many lines find both foo and bar. Some line contain foo only, @@ -96,7 +98,7 @@ There should be six lines with foo and bar. There are only two line with out foo but with bar. ! -if (( $(grep -c 'foo*bar' /tmp/grep$$ ) != 6)) +if (( $(grep -c 'foo*bar' $tmp/grep ) != 6)) then err_exit fi exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/heredoc.sh b/usr/src/lib/libshell/common/tests/heredoc.sh index aadc9cdeec..7b3c923bf0 100644 --- a/usr/src/lib/libshell/common/tests/heredoc.sh +++ b/usr/src/lib/libshell/common/tests/heredoc.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,9 +27,12 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -f=/tmp/here1$$ -g=/tmp/here2$$ -trap "rm -f $f $g" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +f=$tmp/here1 +g=$tmp/here2 cat > $f <<! hello world ! @@ -143,7 +146,7 @@ abc EOF) != $'#abc\nabc' ]] then err_exit 'comments not preserved in here-documents' fi -cat > "$f" <<- '!!!!' +cat > "$f" <<- '!!!!' builtin cat : << EOF $PWD @@ -173,7 +176,7 @@ chmod 755 "$f" if [[ $($SHELL "$f") != abc ]] then err_exit 'here document descritor was closed' fi -cat > "$f" <<- '!!!!' +cat > "$f" <<- '!!!!' exec 0<&- foobar() { @@ -207,9 +210,9 @@ if [[ $($SHELL "$f") != foobar ]] then err_exit 'here document with stdin closed failed' fi printf $'cat <<# \\!!!\n\thello\n\t\tworld\n!!!' > $f -[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for quoted here documents" +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for quoted here documents" printf $'w=world;cat <<# !!!\n\thello\n\t\t$w\n!!!' > $f -[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for non-quoted here documents" +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for non-quoted here documents" [[ $( $SHELL <<- \++++ S=( typeset a ) function S.a.get @@ -226,4 +229,27 @@ printf $'w=world;cat <<# !!!\n\thello\n\t\t$w\n!!!' > $f ${ g;} EOF ' 2> /dev/null) == ok ]] || err_exit '${ command;} not working in heredoc' +script=$f +{ +for ((i=0; i < 406; i++)) +do print ': 23456789012345678' +done +print : 123456789123 +cat <<- \EOF +eval "$( + { cat ; } <<MARKER + print hello + MARKER +)" +EOF +} > $script +chmod +x $script +[[ $($SHELL $script) == hello ]] 2> /dev/null || err_exit 'heredoc embeded in command substitution fails at buffer boundary' + +got=$( cat << EOF +\ +abc +EOF) +[[ $got == abc ]] || err_exit 'line continuation at start of buffer not working' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/io.sh b/usr/src/lib/libshell/common/tests/io.sh index a8b1b8a030..3468fe9429 100644 --- a/usr/src/lib/libshell/common/tests/io.sh +++ b/usr/src/lib/libshell/common/tests/io.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,29 +28,29 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + unset HISTFILE function fun { - while command exec 3>&1 - do break + while command exec 3>&1 + do break done 2> /dev/null print -u3 good } -print 'read -r a;print -r -u$1 -- "$a"' > /tmp/mycat$$ -chmod 755 /tmp/mycat$$ +print 'read -r a;print -r -u$1 -- "$a"' > $tmp/mycat +chmod 755 $tmp/mycat for ((i=3; i < 10; i++)) do - eval "a=\$(print foo | /tmp/mycat$$" $i $i'>&1 > /dev/null |cat)' 2> /dev/null + eval "a=\$(print foo | $tmp/mycat" $i $i'>&1 > /dev/null |cat)' 2> /dev/null [[ $a == foo ]] || err_exit "bad file descriptor $i in comsub script" done -rm -f /tmp/mycat$$ exec 3> /dev/null [[ $(fun) == good ]] || err_exit 'file 3 closed before subshell completes' exec 3>&- -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap 'rm -rf /tmp/ksh$$' EXIT -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit ; } print foo > file1 print bar >> file1 if [[ $(<file1) != $'foo\nbar' ]] @@ -59,19 +59,55 @@ fi set -o noclobber exec 3<> file1 read -u3 line -if [[ $line != foo ]] -then err_exit '<> not working right with read' +exp=foo +if [[ $line != $exp ]] +then err_exit "read on <> fd failed -- expected '$exp', got '$line'" fi if ( 4> file1 ) 2> /dev/null then err_exit 'noclobber not causing exclusive open' fi set +o noclobber -if command exec 4< /dev/fd/3 -then read -u4 line - if [[ $line != bar ]] - then '4< /dev/fd/3 not working correctly' - fi + +FDFS=( + ( dir=/proc/self/fd semantics='open' ) + ( dir=/proc/$$/fd semantics='open' ) + ( dir=/dev/fd semantics='open|dup' ) + ( dir=/dev/fd semantics='dup' ) +) +for ((fdfs=0; fdfs<${#FDFS[@]}-1; fdfs++)) +do [[ -e ${FDFS[fdfs].dir} ]] && { command : > ${FDFS[fdfs].dir}/1; } 2>/dev/null && break +done + +exec 3<> file1 +if command exec 4< ${FDFS[fdfs].dir}/3 +then read -u3 got + read -u4 got + exp='foo|bar' + case $got in + foo) semantics='open' ;; + bar) semantics='dup' ;; + *) semantics='failed' ;; + esac + [[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "'4< ${FDFS[fdfs].dir}/3' $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" fi + +# 2004-11-25 ancient /dev/fd/N redirection bug fix +got=$( + { + print -n 1 + print -n 2 > ${FDFS[fdfs].dir}/2 + print -n 3 + print -n 4 > ${FDFS[fdfs].dir}/2 + } 2>&1 +) +exp='1234|4' +case $got in +1234) semantics='dup' ;; +4) semantics='open' ;; +*) semantics='failed' ;; +esac +[[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "${FDFS[fdfs].dir}/N $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" + cat > close0 <<\! exec 0<&- echo $(./close1) @@ -91,15 +127,15 @@ cat > close0 <<\! ! ./close0 2> /dev/null || err_exit "multiple exec 4< /dev/null can fail" $SHELL -c ' - trap "rm -f in$$ out$$" EXIT + trap "rm -f in out" EXIT for ((i = 0; i < 1000; i++)) do print -r -- "This is a test" - done > in$$ - > out$$ - exec 1<> out$$ + done > in + > out + exec 1<> out builtin cat - print -r -- "$(cat in$$)" - cmp -s in$$ out$$' 2> /dev/null + print -r -- "$(<in)" + cmp -s in out' 2> /dev/null [[ $? == 0 ]] || err_exit 'builtin cat truncates files' cat >| script <<-\! print hello @@ -122,7 +158,7 @@ read line if [[ $line != foo ]] then err_exit 'file descriptor not restored after exec in subshell' fi -exec 3>&- 4>&-; cd /; rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" +exec 3>&- 4>&- [[ $( { read -r line;print -r -- "$line" ( @@ -137,37 +173,26 @@ line 2 line 3 !) == $'line 1\nline 2\nline 3' ]] || err_exit 'read error with subshells' # 2004-05-11 bug fix -cat > /tmp/io$$.1 <<- \++EOF++ - script=/tmp/io$$.2 - trap 'rm -f $script' EXIT - exec 9> $script +cat > $tmp/1 <<- ++EOF++ + script=$tmp/2 + trap "rm -f \$script" EXIT + exec 9> \$script for ((i=3; i<9; i++)) - do eval "while read -u$i; do : ;done $i</dev/null" - print -u9 "exec $i< /dev/null" + do eval "while read -u\$i; do : ;done \$i</dev/null" + print -u9 "exec \$i< /dev/null" done for ((i=0; i < 60; i++)) do print -u9 -f "%.80c\n" ' ' done print -u9 'print ok' exec 9<&- - chmod +x $script - $script + chmod +x \$script + \$script ++EOF++ -chmod +x /tmp/io$$.1 -[[ $($SHELL /tmp/io$$.1) == ok ]] || err_exit "parent i/o causes child script to fail" -rm -rf /tmp/io$$.[12] -# 2004-11-25 ancient /dev/fd/NN redirection bug fix -x=$( - { - print -n 1 - print -n 2 > /dev/fd/2 - print -n 3 - print -n 4 > /dev/fd/2 - } 2>&1 -) -[[ $x == "1234" ]] || err_exit "/dev/fd/NN redirection fails to dup" -# 2004-12-20 redirction loss bug fix -cat > /tmp/io$$.1 <<- \++EOF++ +chmod +x $tmp/1 +[[ $($SHELL $tmp/1) == ok ]] || err_exit "parent i/o causes child script to fail" +# 2004-12-20 redirection loss bug fix +cat > $tmp/1 <<- \++EOF++ function a { trap 'print ok' EXIT @@ -175,49 +200,47 @@ cat > /tmp/io$$.1 <<- \++EOF++ } a ++EOF++ -chmod +x /tmp/io$$.1 -[[ $(/tmp/io$$.1) == ok ]] || err_exit "trap on EXIT loses last command redirection" -print > /dev/null {n}> /tmp/io$$.1 -[[ ! -s /tmp/io$$.1 ]] && newio=1 -rm -rf /tmp/io$$.1 -if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] +chmod +x $tmp/1 +[[ $($tmp/1) == ok ]] || err_exit "trap on EXIT loses last command redirection" +print > /dev/null {n}> $tmp/1 +[[ ! -s $tmp/1 ]] && newio=1 +if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] then err_exit "{n}<&0 not working with for loop" fi [[ $({ read -r;read -u3 3<&0; print -- "$REPLY" ;} <<! hello world !) == world ]] || err_exit 'I/O not synchronized with <&' -trap 'rm -f /tmp/seek$$; exit $((Errors+1))' EXIT x="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNSPQRSTUVWXYZ1234567890" for ((i=0; i < 62; i++)) do printf "%.39c\n" ${x:i:1} -done > /tmp/seek$$ -if command exec 3<> /tmp/seek$$ +done > $tmp/seek +if command exec 3<> $tmp/seek then (( $(3<#) == 0 )) || err_exit "not at position 0" (( $(3<# ((EOF))) == 40*62 )) || err_exit "not at end-of-file" - command exec 3<# ((40*8)) || err_exit "absolute seek fails" + command exec 3<# ((40*8)) || err_exit "absolute seek fails" read -u3 - [[ $REPLY == +(i) ]] || err_exit "expecting iiii..." + [[ $REPLY == +(i) ]] || err_exit "expected iiii..., got $REPLY" [[ $(3<#) == $(3<# ((CUR)) ) ]] || err_exit '$(3<#)!=$(3<#((CUR)))' command exec 3<# ((CUR+80)) read -u3 - [[ $REPLY == {39}(l) ]] || err_exit "expecting lll..." + [[ $REPLY == {39}(l) ]] || err_exit "expected lll..., got $REPLY" command exec 3<# ((EOF-80)) read -u3 - [[ $REPLY == +(9) ]] || err_exit "expecting 999...; got $REPLY" + [[ $REPLY == +(9) ]] || err_exit "expected 999..., got $REPLY" command exec 3># ((80)) print -u3 -f "%.39c\n" @ command exec 3># ((80)) read -u3 - [[ $REPLY == +(@) ]] || err_exit "expecting @@@..." + [[ $REPLY == +(@) ]] || err_exit "expected @@@..., got $REPLY" read -u3 - [[ $REPLY == +(d) ]] || err_exit "expecting ddd..." + [[ $REPLY == +(d) ]] || err_exit "expected ddd..., got $REPLY" command exec 3># ((EOF)) print -u3 -f "%.39c\n" ^ (( $(3<# ((CUR-0))) == 40*63 )) || err_exit "not at extended end-of-file" - command exec 3<# ((40*62)) + command exec 3<# ((40*62)) read -u3 - [[ $REPLY == +(^) ]] || err_exit "expecting ddd..." + [[ $REPLY == +(^) ]] || err_exit "expected ddd..., got $REPLY" command exec 3<# ((0)) command exec 3<# *jjjj* read -u3 @@ -227,24 +250,22 @@ then (( $(3<#) == 0 )) || err_exit "not at position 0" [[ $REPLY == {39}(l) ]] || err_exit "<## pattern failed to position" command exec 3<# *abc* read -u3 && err_exit "not found pattern not positioning at eof" - cat /tmp/seek$$ | read -r <# *WWW* + cat $tmp/seek | read -r <# *WWW* [[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes' - { < /tmp/seek$$ <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' -else err_exit "/tmp/seek$$: cannot open for reading" + { < $tmp/seek <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' +else err_exit "$tmp/seek: cannot open for reading" fi command exec 3<&- || 'cannot close 3' for ((i=0; i < 62; i++)) do printf "%.39c\n" ${x:i:1} -done > /tmp/seek$$ -if command exec {n}<> /tmp/seek$$ +done > $tmp/seek +if command exec {n}<> $tmp/seek then { command exec {n}<#((EOF)) ;} 2> /dev/null || err_exit '{n}<# not working' if $SHELL -c '{n}</dev/null' 2> /dev/null then (( $({n}<#) == 40*62)) || err_exit '$({n}<#) not working' else err_exit 'not able to parse {n}</dev/null' fi fi -trap "" EXIT -rm -f /tmp/seek$$ $SHELL -ic ' { print -u2 || exit 2 @@ -258,9 +279,8 @@ $SHELL -ic ' } 3> /dev/null 4> /dev/null 5> /dev/null 6> /dev/null 7> /dev/null 8> /dev/null 9> /dev/null' > /dev/null 2>&1 exitval=$? (( exitval )) && err_exit "print to unit $exitval failed" -trap 'rm -rf /tmp/io.sh$$*' EXIT -$SHELL -c "{ > /tmp/io.sh$$.1 ; date;} >&- 2> /dev/null" > /tmp/io.sh$$.2 -[[ -s /tmp/io.sh$$.1 || -s /tmp/io.sh$$.2 ]] && err_exit 'commands with standard output closed produce output' +$SHELL -c "{ > $tmp/1 ; date;} >&- 2> /dev/null" > $tmp/2 +[[ -s $tmp/1 || -s $tmp/2 ]] && err_exit 'commands with standard output closed produce output' $SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard output not passed to subshell' [[ $(cat <<- \EOF | $SHELL do_it_all() @@ -273,12 +293,26 @@ $SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard out EOF) == 'hello world' ]] || err_exit 'invalid readahead on stdin' $SHELL -c 'exec 3>; /dev/null' 2> /dev/null && err_exit '>; with exec should be an error' $SHELL -c ': 3>; /dev/null' 2> /dev/null || err_exit '>; not working with at all' -print hello > /tmp/io.sh$$.1 -if ! $SHELL -c "false >; /tmp/io.sh$$.1" 2> /dev/null -then [[ $(</tmp/io.sh$$.1) == hello ]] || err_exit '>; not preserving file on failure' +print hello > $tmp/1 +if ! $SHELL -c "false >; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '>; not preserving file on failure' fi -if ! $SHELL -c "sed -e 's/hello/hello world/' /tmp/io.sh$$.1" >; /tmp/io.sh$$.1 2> /dev/null -then [[ $(</tmp/io.sh$$.1) == 'hello world' ]] || err_exit '>; not updating file on success' +if ! $SHELL -c "sed -e 's/hello/hello world/' $tmp/1" >; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == 'hello world' ]] || err_exit '>; not updating file on success' +fi + +$SHELL -c 'exec 3<>; /dev/null' 2> /dev/null && err_exit '<>; with exec should be an error' +$SHELL -c ': 3<>; /dev/null' 2> /dev/null || err_exit '<>; not working with at all' +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c "false <>; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == $'hello\nworld' ]] || err_exit '<>; not preserving file on failure' +fi +if ! $SHELL -c "head -1 $tmp/1" <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '<>; not truncating file on success of head' +fi +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c head < $tmp/1 <#((6)) <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == world ]] || err_exit '<>; not truncating file on success of behead' fi unset y @@ -303,25 +337,41 @@ abcdefg [[ $b == d ]] || err_exit 'read -N1 from pipe not working' (print -n a;sleep 1; print -n bcde) |read -n3 a [[ $a == a ]] || err_exit 'read -n3 from pipe not working' -rm -f /tmp/fifo$$ -if mkfifo /tmp/fifo$$ 2> /dev/null -then (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & +if mkfifo $tmp/fifo 2> /dev/null +then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & { read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' - } 5< /tmp/fifo$$ + } 5< $tmp/fifo [[ $a == a ]] || err_exit 'read -n3 from fifo not working' - rm -f /tmp/fifo$$ - mkfifo /tmp/fifo$$ 2> /dev/null - (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & + rm -f $tmp/fifo + mkfifo $tmp/fifo 2> /dev/null + (print -n a; sleep 1;print -n bcde) > $tmp/fifo & { read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' - } 5< /tmp/fifo$$ + } 5< $tmp/fifo [[ $a == abc ]] || err_exit 'read -N3 from fifo not working' [[ $b == d ]] || err_exit 'read -N1 from fifo not working' fi -rm -f /tmp/fifo$$ +( + print -n 'prompt1: ' + sleep .1 + print line2 + sleep .1 + print -n 'prompt2: ' + sleep .1 +) | { + read -t2 -n 1000 line1 + read -t2 -n 1000 line2 + read -t2 -n 1000 line3 + read -t2 -n 1000 line4 +} +[[ $? == 0 ]] && err_exit 'should have time out' +[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '" +[[ $line2 == line2 ]] || err_exit "line2 should be line2" +[[ $line3 == 'prompt2: ' ]] || err_exit "line3 should be 'prompt2: '" +[[ ! $line4 ]] || err_exit "line4 should be empty" if $SHELL -c "export LC_ALL=en_US.UTF-8; c=$'\342\202\254'; [[ \${#c} == 1 ]]" 2>/dev/null then lc_utf8=en_US.UTF-8 @@ -370,4 +420,32 @@ then export LC_ALL=en_US.UTF-8 fi fi +exec 3<&2 +file=$tmp/file +redirect 5>$file 2>&5 +print -u5 -f 'This is a test\n' +print -u2 OK +exec 2<&3 +exp=$'This is a test\nOK' +got=$(< $file) +[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")" +print 'hello world' > $file +1<>; $file 1># ((5)) +(( $(wc -c < $file) == 5 )) || err_exit "$file was not truncate to 5 bytes" + +$SHELL -c "PS4=':2:' + exec 1> $tmp/21.out 2> $tmp/22.out + set -x + printf ':1:A:' + print \$(:) + print :1:Z:" 1> $tmp/11.out 2> $tmp/12.out +[[ -s $tmp/11.out ]] && err_exit "standard output leaked past redirection" +[[ -s $tmp/12.out ]] && err_exit "standard error leaked past redirection" +exp=$':1:A:\n:1:Z:' +got=$(<$tmp/21.out) +[[ $exp == "$got" ]] || err_exit "standard output garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" +exp=$':2:printf :1:A:\n:2::\n:2:print\n:2:print :1:Z:' +got=$(<$tmp/22.out) +[[ $exp == "$got" ]] || err_exit "standard error garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/locale.sh b/usr/src/lib/libshell/common/tests/locale.sh deleted file mode 100644 index ab94722e2d..0000000000 --- a/usr/src/lib/libshell/common/tests/locale.sh +++ /dev/null @@ -1,104 +0,0 @@ -######################################################################## -# # -# This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # -# and is licensed under the # -# Common Public License, Version 1.0 # -# by AT&T Intellectual Property # -# # -# A copy of the License is available at # -# http://www.opensource.org/licenses/cpl1.0.txt # -# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # -# # -# Information and Software Systems Research # -# AT&T Research # -# Florham Park NJ # -# # -# David Korn <dgk@research.att.com> # -# # -######################################################################## -function err_exit -{ - print -u2 -n "\t" - print -u2 -r ${Command}[$1]: "${@:2}" - let Errors+=1 -} -alias err_exit='err_exit $LINENO' - -Command=${0##*/} -integer Errors=0 - -# LC_ALL=debug is an ast specific debug/test locale - -if [[ "$(LC_ALL=debug $SHELL <<- \+EOF+ - x=a<1z>b<2yx>c - print ${#x} - +EOF+)" != 5 - ]] -then err_exit '${#x} not working with multibyte locales' -fi - -export LC_ALL=C -if (( $($SHELL -c $'export LC_ALL=en_US.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 )) -then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'Multibyte ${var:offset:len} not working correctly' -fi - -export LC_ALL=C -a=$($SHELL -c '/' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -b=$($SHELL -c '(LC_ALL=debug / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" -b=$($SHELL -c '(LC_ALL=debug; / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" - -# test shift-jis \x81\x40 ... \x81\x7E encodings -# (shift char followed by 7 bit ascii) - -typeset -i16 chr -for lc_all in $(PATH=/bin:/usr/bin locale -a 2>/dev/null | grep -i jis) -do export LC_ALL=$lc_all - for ((chr=0x40; chr<=0x7E; chr++)) - do c=${chr#16#} - for s in \\x81\\x$c \\x$c - do b="$(printf "$s")" - eval n=\$\'$s\' - [[ $b == "$n" ]] || err_exit "LC_ALL=$lc_all printf difference for \"$s\" -- expected '$n', got '$b'" - u=$(print -- $b) - q=$(print -- "$b") - [[ $u == "$q" ]] || err_exit "LC_ALL=$lc_all quoted print difference for \"$s\" -- $b => '$u' vs \"$b\" => '$q'" - done - done -done - -# test multibyte value/trace format -- $'\303\274' is UTF-8 u-umlaut - -LC_ALL=C -lc_all=de_DE.UTF-8 -c=$(LC_ALL=C $SHELL -c "printf $':%2s:\n' $'\303\274'") -u=$(LC_ALL=$lc_all $SHELL -c "printf $':%2s:\n' $'\303\274'" 2>/dev/null) -if [[ "$c" != "$u" ]] -then LC_ALL=$lc_all - x=$'+2+ typeset item.text\ -+3+ item.text=\303\274\ -+4+ print -- \303\274\ -\303\274\ -+5+ eval $\'arr[0]=(\\n\\ttext=\\303\\274\\n)\' -+2+ arr[0].text=ü\ -+6+ print -- \303\274\ -ü\ -+7+ eval txt=$\'(\\n\\ttext=\\303\\274\\n)\' -+2+ txt.text=\303\274\ -+8+ print -- \'(\' text=$\'\\303\\274\' \')\'\ -( text=\303\274 )' - u=$(LC_ALL=$lc_all PS4='+$LINENO+ ' $SHELL -x -c " - item=(typeset text) - item.text=$'\303\274' - print -- \"\${item.text}\" - eval \"arr[0]=\$item\" - print -- \"\${arr[0].text}\" - eval \"txt=\${arr[0]}\" - print -- \$txt - " 2>&1) - [[ "$u" == "$x" ]] || err_exit LC_ALL=$lc_all multibyte value/trace format failed -fi - -exit $Errors diff --git a/usr/src/lib/libshell/common/tests/nameref.sh b/usr/src/lib/libshell/common/tests/nameref.sh index 21a672db14..7bb9ec2c91 100644 --- a/usr/src/lib/libshell/common/tests/nameref.sh +++ b/usr/src/lib/libshell/common/tests/nameref.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function checkref { nameref foo=$1 bar=$2 @@ -80,7 +84,7 @@ nameref x=.foo.bar if [[ ${!x} != .foo.bar ]] then err_exit "${!x} not working" fi -typeset +n x $(typeset +n) +typeset +n x $(typeset +n) unset x nameref x=.foo.bar function x.set @@ -96,7 +100,7 @@ fi if [[ $(typeset -n) != x=.foo.bar ]] then err_exit "typeset +n doesn't list values of reference variables" fi -file=/tmp/shtest$$ +file=$tmp/test typeset +n foo bar 2> /dev/null unset foo bar export bar=foo @@ -104,7 +108,6 @@ nameref foo=bar if [[ $foo != foo ]] then err_exit "value of nameref foo != $foo" fi -trap "rm -f $file" EXIT INT cat > $file <<\! print -r -- $foo ! @@ -113,7 +116,7 @@ y=$( $file) if [[ $y != '' ]] then err_exit "reference variable not cleared" fi -{ +{ command nameref xx=yy command nameref yy=xx } 2> /dev/null && err_exit "self reference not detected" @@ -127,7 +130,7 @@ then err_exit 'nameref of positional paramters outside of function not working' fi unset foo bar bar=123 -function foobar +function foobar { typeset -n foo=bar typeset -n foo=bar @@ -216,7 +219,7 @@ function local qs=(integer a=3; integer b=4) } local 2> /dev/null || err_exit 'function local has non-zero exit status' -[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable' +[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable' unset fun i foo=(x=hi) function fun @@ -297,4 +300,66 @@ vars=(data=()) vars.data._1.a=a.1 vars.data._1.b=b.1 [[ $(a) == 'a.1 b.1' ]] || err_exit 'nameref choosing wrong scope -- ' +typeset +n bam zip foo +unset bam zip foo +typeset -A foo +foo[2]=bar +typeset -n bam=foo[2] +typeset -n zip=bam +[[ $zip == bar ]] || err_exit 'nameref to another nameref to array element fails' +[[ -R zip ]] || err_exit '[[ -R zip ]] should detect that zip is a reference' +[[ -R bam ]] || err_exit '[[ -R bam ]] should detect that bam is a reference' +[[ -R zip ]] || err_exit '[[ -v zip ]] should detect that zip is set' +[[ -v bam ]] || err_exit '[[ -v bam ]] should detect that bam is set' +[[ -R 123 ]] && err_exit '[[ -R 123 ]] should detect that 123 is not a reference' +[[ -v 123 ]] && err_exit '[[ -v 123 ]] should detect that 123 is not set' + +unset ref x +typeset -n ref +x=3 +function foobar +{ + typeset xxx=3 + ref=xxx + return 0 +} +foobar 2> /dev/null && err_exit 'invalid reference should cause foobar to fail' +[[ -v ref ]] && err_exit '$ref should be unset' +ref=x +[[ $ref == 3 ]] || err_exit "\$ref is $ref, it should be 3" +function foobar +{ + typeset fvar=() + typeset -n ref=fvar.foo + ref=ok + print -r $ref +} +[[ $(foobar) == ok ]] 2> /dev/null || err_exit 'nameref in function not creating variable in proper scope' +function foobar +{ + nameref doc=docs + nameref bar=doc.num + [[ $bar == 2 ]] || err_exit 'nameref scoping error' +} + +docs=(num=2) +foobar + +typeset +n x y +unset x y +typeset -A x +x[a]=(b=c) +typeset -n y=x[a] +[[ ${!y.@} == 'x[a].b' ]] || err_exit 'reference to array element not expanded with ${!y.@}' + +typeset +n v +v=() +k=a.b.c/d +command typeset -n n=v.${k//['./']/_} 2> /dev/null || err_exit 'patterns with quotes not handled correctly with name reference assignment' + +typeset _n sp +nameref sp=addrsp +sp[14]=( size=1 ) +[[ -v sp[19] ]] && err_exit '[[ -v sp[19] ]] where sp is a nameref should not be set' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/options.sh b/usr/src/lib/libshell/common/tests/options.sh index 07608efa1e..cebb405a27 100644 --- a/usr/src/lib/libshell/common/tests/options.sh +++ b/usr/src/lib/libshell/common/tests/options.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -29,11 +29,17 @@ Command=${0##*/} integer Errors=0 unset HISTFILE +export LC_ALL=C ENV= + +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT if [[ $( ${SHELL-ksh} -s hello<<-\! print $1 ! - ) != hello ]] + ) != hello ]] then err_exit "${SHELL-ksh} -s not working" fi x=$( @@ -42,102 +48,118 @@ x=$( print good ) if [[ $x != good ]] -then err_exit 'sh -e not workuing' +then err_exit 'sh -e not working' fi [[ $($SHELL -D -c 'print hi; print $"hello"') == '"hello"' ]] || err_exit 'ksh -D not working' -tmp=/tmp/ksh$$ -mkdir $tmp +env=$tmp/.env +print $'(print -u1 aha) &>/dev/null\n(print -u2 aha) &>/dev/null' > $env rc=$tmp/.kshrc print $'PS1=""\nfunction env_hit\n{\n\tprint OK\n}' > $rc -export ENV='${nosysrc}'$rc +export ENV=/.$env +if [[ ! -o privileged ]] +then + got=$($SHELL -E -c : 2>/dev/null) + if [[ $g ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got" + fi + got=$($SHELL -E -c : 2>&1 >/dev/null) + if [[ $got != *nonstandard* || $got == *$'\n'* ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stderr -- expected one diagnostic line, got $got" + fi +fi + +export ENV=/.$rc if [[ -o privileged ]] then - [[ $(print env_hit | $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $ENV file' - [[ $(print env_hit | $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E reads $ENV file' - [[ $(print env_hit | $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $ENV file' - [[ $(print env_hit | $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc reads $ENV file' - [[ $(print env_hit | $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $ENV file' else - [[ $(print env_hit | $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $ENV file' - [[ $(print env_hit | $SHELL -E 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] || err_exit '-E ignores $ENV file' - [[ $(print env_hit | $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $ENV file' - [[ $(print env_hit | $SHELL --rc 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] || err_exit '--rc ignores $ENV file' - [[ $(print env_hit | $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $ENV file' - [[ $(print env_hit | $SHELL -i 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL -i 2>&1) == "OK" ]] || err_exit '-i ignores $ENV file' fi export ENV= if [[ -o privileged ]] then - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $HOME/.kshrc file' else - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit '-E ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit '--rc ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $HOME/.kshrc file' fi unset ENV if [[ -o privileged ]] then - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $HOME/.kshrc file' else - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] || err_exit '-E ignores $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] || err_exit '--rc ignores $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $HOME/.kshrc file' fi -rm -rf $tmp +rm -rf $tmp/.kshrc if command set -G 2> /dev/null -then mkdir /tmp/ksh$$ - cd /tmp/ksh$$ +then cd $tmp mkdir bar foo - > bar.c > bam.c + > bar.c > bam.c > bar/foo.c > bar/bam.c > foo/bam.c set -- **.c @@ -157,49 +179,48 @@ then mkdir /tmp/ksh$$ [[ $* == $expected ]] || err_exit "-G **/bam.c failed -- expected '$expected', got '$*'" cd ~- - rm -rf /tmp/ksh$$ fi -mkdir /tmp/ksh$$ -cd /tmp/ksh$$ +cd $tmp t="<$$>.profile.<$$>" echo "echo '$t'" > .profile cp $SHELL ./-ksh if [[ -o privileged ]] then - [[ $(HOME=$PWD $SHELL -l </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] && err_exit 'privileged -l reads .profile' - [[ $(HOME=$PWD $SHELL --login </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login reads .profile' - [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login-shell reads .profile' - [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login_shell reads .profile' - [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] && err_exit 'privileged exec -a -ksh ksh reads .profile' - [[ $(HOME=$PWD ./-ksh -i </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] && err_exit 'privileged ./-ksh reads .profile' - [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && err_exit 'privileged ./-ksh -p reads .profile' else - [[ $(HOME=$PWD $SHELL -l </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] || err_exit '-l ignores .profile' - [[ $(HOME=$PWD $SHELL --login </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] || err_exit '--login ignores .profile' - [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] || err_exit '--login-shell ignores .profile' - [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] || err_exit '--login_shell ignores .profile' - [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] || - err_exit 'exec -a -ksh ksh ignores .profile' - [[ $(HOME=$PWD ./-ksh -i </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>/dev/null ignores .profile' + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>&1 ignores .profile' + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] || err_exit './-ksh ignores .profile' - [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && err_exit './-ksh -p does not ignore .profile' fi cd ~- -rm -rf /tmp/ksh$$ - +rm -rf $tmp/.profile # { exec interactive login_shell restricted xtrace } in the following test @@ -333,44 +354,146 @@ set $restore state=$(set --state) [[ $state == "set $restore" ]] || err_exit "set --state after restore failed: expected 'set $restore', got '$state'" -false | true | true || err_exit 'pipe not exiting exit value of last element' -true | true | false && err_exit 'pipe not exiting false' -set -o pipefail -false | true | true && err_exit 'pipe with first not failing with pipefail' -true | false | true && err_exit 'pipe middle not failing with pipefail' -true | true | false && err_exit 'pipe last not failing with pipefail' -print hi | (sleep 1;/bin/cat) > /dev/null || err_exit 'pipeline fails with pipefail' +typeset -a pipeline +pipeline=( + ( nopipefail=0 pipefail=1 command='false|true|true' ) + ( nopipefail=0 pipefail=1 command='true|false|true' ) + ( nopipefail=1 pipefail=1 command='true|true|false' ) + ( nopipefail=1 pipefail=1 command='false|false|false' ) + ( nopipefail=0 pipefail=0 command='true|true|true' ) + ( nopipefail=0 pipefail=0 command='print hi|(sleep 1;/bin/cat)>/dev/null' ) +) +set --nopipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].nopipefail} + [[ $status == $expected ]] || + err_exit "--nopipefail '${pipeline[i].command}' exit status $status -- expected $expected" +done +ftt=0 +set --pipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].pipefail} + if [[ $status != $expected ]] + then err_exit "--pipefail '${pipeline[i].command}' exit status $status -- expected $expected" + (( i == 0 )) && ftt=1 + fi +done +if (( ! ftt )) +then exp=10 + got=$(for((n=1;n<exp;n++))do $SHELL --pipefail -c '(sleep 0.1;false)|true|true' && break; done; print $n) + [[ $got == $exp ]] || err_exit "--pipefail -c '(sleep 0.1;false)|true|true' fails with exit status 0 (after $got/$exp iterations)" +fi + +echo=$(whence -p echo) +for ((i=0; i < 20; i++)) +do if ! x=$(true | $echo 123) + then err_exit 'command substitution with wrong exit status with pipefai' + break + fi +done ( set -o pipefail false | true (( $? )) || err_exit 'pipe not failing in subshell with pipefail' ) | wc >/dev/null $SHELL -c 'set -o pipefail; false | $(whence -p true);' && err_exit 'pipefail not returning failure with sh -c' -[[ $( set -o pipefail +exp='1212 or 1221' +got=$( + set --pipefail pipe() { date | cat > /dev/null ;} print $'1\n2' | - while read i - do if pipe /tmp - then { print enter $i; sleep 2; print leave $i; } & + while read i + do if pipe $tmp + then { print -n $i; sleep 2; print -n $i; } & fi done - wait) == $'enter 1\nenter 2'* ]] || err_exit '& job delayed by pipefail' -$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' -trap 'rm -f /tmp/.profile' EXIT -> /tmp/.profile -for i in i l r s D E a b e f h k n r t u v x B C G H -do HOME=/tmp ENV= $SHELL -$i 2> /dev/null <<- ++EOF++ || err_exit "option $i not in \$-" - [[ \$- == *$i* ]] || exit 1 + wait +) +[[ $got == @((12|21)(12|21)) ]] || err_exit "& job delayed by --pipefail, expected '$exp', got '$got'" +$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' +> $tmp/.profile +for i in i l r s D E a b e f h k n t u v x B C G H +do HOME=$tmp ENV= $SHELL -$i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not in \$-" + [[ \$- == *$i* ]] || exit 1 ++EOF++ done letters=ilrabefhknuvxBCGE integer j=0 -for i in interactive login restricted allexport notify errexit \ - noglob trackall keyword noexec nounset verbose xtrace braceexpand \ +for i in interactive login restricted allexport notify errexit \ + noglob trackall keyword noexec nounset verbose xtrace braceexpand \ noclobber globstar rc -do HOME=/tmp ENV= $SHELL -o $i 2> /dev/null <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" - [[ \$- == *${letters:j:1}* ]] || exit 1 +do HOME=$tmp ENV= $SHELL -o $i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" + [[ \$- == *${letters:j:1}* ]] || exit 1 ++EOF++ ((j++)) done + +export ENV= +histfile=$tmp/history +exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo') +for var in HISTSIZE HISTFILE +do got=$( ( HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 ) + got=${got##*': '} + [[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'" + got=$( { HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 ) + got=${got##*': '} + [[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'" +done +( unset HISTFILE; $SHELL -ic "HISTFILE=$histfile" 2>/dev/null ) || err_exit "setting HISTFILE when not in environment fails" + +# the next tests loop on all combinations of +# { SUB PAR CMD ADD } + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +PAR=( + ( BEG='( ' END=' )' ) + ( BEG='{ ' END='; }' ) +) +CMD=( command-kill script-kill ) +ADD=( '' '; :' ) + +cd $tmp +print $'#!'$SHELL$'\nkill -KILL $$' > command-kill +print $'kill -KILL $$' > script-kill +chmod +x command-kill script-kill +export PATH=.:$PATH +exp='Killed' +for ((S=0; S<${#SUB[@]}; S++)) +do for ((P=0; P<${#PAR[@]}; P++)) + do for ((C=0; C<${#CMD[@]}; C++)) + do for ((A=0; A<${#ADD[@]}; A++)) + do cmd="${SUB[S].BEG}${PAR[P].BEG}${CMD[C]}${PAR[P].END} 2>&1${ADD[A]}${SUB[S].END}" + eval got="$cmd" + got=${got##*': '} + got=${got%%'('*} + [[ $got == "$exp" ]] || err_exit "$cmd failed -- got '$got', expected '$exp'" + done + done + done +done + +$SHELL 2> /dev/null -c '{; true ;}' || err_exit 'leading ; causes syntax error in brace group' +$SHELL 2> /dev/null -c '(; true ;)' || err_exit 'leading ; causes syntax error in parenthesis group' + +print 'for ((i = 0; i < ${1:-10000}; i++ )); do printf "%.*c\n" 15 x; done' > pipefail +chmod +x pipefail +$SHELL --pipefail -c './pipefail 10000 | sed 1q' >/dev/null 2>&1 & +tst=$! +{ sleep 4; kill $tst; } 2>/dev/null & +spy=$! +wait $tst 2>/dev/null +status=$? +if [[ $status == 0 || $(kill -l $status) == PIPE ]] +then kill $spy 2>/dev/null +else err_exit "pipefail pipeline bypasses SIGPIPE and hangs" +fi +wait + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/path.sh b/usr/src/lib/libshell/common/tests/path.sh index 2e46e2bd48..edf7621663 100644 --- a/usr/src/lib/libshell/common/tests/path.sh +++ b/usr/src/lib/libshell/common/tests/path.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,12 +24,14 @@ function err_exit let Errors+=1 } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ -cd /tmp/ksh$$ -trap "PATH=$PATH; cd /; rm -rf /tmp/ksh$$" EXIT +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || exit type /xxxxxx > out1 2> out2 [[ -s out1 ]] && err_exit 'type should not write on stdout for not found case' [[ -s out2 ]] || err_exit 'type should write on stderr for not found case' @@ -69,37 +71,36 @@ PATH=$FPATH:$p PATH=$p (PATH="/bin") [[ $($SHELL -c 'print -r -- "$PATH"') == "$PATH" ]] || err_exit 'export PATH lost in subshell' -cat > bug1 <<- \EOF - print print ok > /tmp/ok$$ - /bin/chmod 755 /tmp/ok$$ - trap 'cd /; rm -f /tmp/ok$$' EXIT +cat > bug1 <<- EOF + print print ok > $tmp/ok + /bin/chmod 755 $tmp/ok function a { - typeset -x PATH=/tmp - ok$$ + typeset -x PATH=$tmp + ok } - path=$PATH + path=\$PATH unset PATH a - PATH=$path + PATH=\$path } EOF -[[ $($SHELL ./bug1 2> /dev/null) == ok ]] || err_exit "PATH in function not working" +[[ $($SHELL ./bug1 2>/dev/null) == ok ]] || err_exit "PATH in function not working" cat > bug1 <<- \EOF function lock_unlock { typeset PATH=/usr/bin typeset -x PATH='' } - + PATH=/usr/bin : $(PATH=/usr/bin getconf PATH) typeset -ft lock_unlock lock_unlock EOF ($SHELL ./bug1) 2> /dev/null || err_exit "path_delete bug" -mkdir tdir$$ -if $SHELL tdir$$ > /dev/null 2>&1 +mkdir tdir +if $SHELL tdir > /dev/null 2>&1 then err_exit 'not an error to run ksh on a directory' fi @@ -121,7 +122,7 @@ var=$(whence date) dir=$(basename "$var") for i in 1 2 3 4 5 6 7 8 9 0 do if ! whence notfound$i 2> /dev/null - then cmd=notfound$i + then cmd=notfound$i break fi done @@ -132,7 +133,7 @@ chmod +x "$cmd" > foo chmod 755 foo for PATH in $path :$path $path: .:$path $path: $path:. $PWD::$path $PWD:.:$path $path:$PWD $path:.:$PWD -do +do # print path=$PATH $(whence date) # print path=$PATH $(whence "$cmd") date @@ -155,19 +156,60 @@ fi status=$? [[ $status == 126 ]] || err_exit "exit status of non-executable is $status -- 126 expected" builtin -d rm 2> /dev/null +chmod=$(whence chmod) rm=$(whence rm) d=$(dirname "$rm") + +chmod=$(whence chmod) + +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(unset FPATH; PATH=/dev/null; whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence $cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(unset FPATH; PATH=/dev/null; whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done + +exp='' +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence ./notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence $PWD/notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + unset FPATH PATH=/dev/null -if date > /dev/null 2>&1 -then err_exit 'programs in . should not be found' -fi -[[ $(whence ./foo) != "$PWD/"./foo ]] && err_exit 'whence ./foo not working' -[[ $(whence "$PWD/foo") != "$PWD/foo" ]] && err_exit 'whence $PWD/foo not working' -[[ $(whence ./xxxxx) ]] && err_exit 'whence ./xxxx not working' +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($cmd 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($cmd 2>&1; :) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence ./$cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done +exp='' +got=$(whence ./notfound) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$(whence $PWD/notfound) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + PATH=$d: -cp "$rm" kshrm$$ -if [[ $(whence kshrm$$) != $PWD/kshrm$$ ]] +cp "$rm" kshrm +if [[ $(whence kshrm) != $PWD/kshrm ]] then err_exit 'trailing : in pathname not working' fi cp "$rm" rm @@ -196,7 +238,7 @@ then PATH= then err_exit 'unsetting path not working' fi fi -PATH=/dev:/tmp/ksh$$ +PATH=/dev:$tmp x=$(whence rm) typeset foo=$(PATH=/xyz:/abc :) y=$(whence rm) @@ -212,11 +254,11 @@ PATH=$PWD:.:${x%/ls} [[ $(whence ls) == "$x" ]] || err_exit 'PATH search bug when :$PWD:. in path' cd "${x%/ls}" [[ $(whence ls) == /* ]] || err_exit 'whence not generating absolute pathname' -status=$($SHELL -c $'trap \'print $?\' EXIT;/a/b/c/d/e 2> /dev/null') +status=$($SHELL -c $'trap \'print $?\' EXIT;/xxx/a/b/c/d/e 2> /dev/null') [[ $status == 127 ]] || err_exit "not found command exit status $status -- expected 127" status=$($SHELL -c $'trap \'print $?\' EXIT;/dev/null 2> /dev/null') [[ $status == 126 ]] || err_exit "non executable command exit status $status -- expected 126" -status=$($SHELL -c $'trap \'print $?\' ERR;/a/b/c/d/e 2> /dev/null') +status=$($SHELL -c $'trap \'print $?\' ERR;/xxx/a/b/c/d/e 2> /dev/null') [[ $status == 127 ]] || err_exit "not found command with ERR trap exit status $status -- expected 127" status=$($SHELL -c $'trap \'print $?\' ERR;/dev/null 2> /dev/null') [[ $status == 126 ]] || err_exit "non executable command ERR trap exit status $status -- expected 126" @@ -231,7 +273,7 @@ getconf UNIVERSE - att # override sticky default 'UNIVERSE = foo' PATH=$path -scr=/tmp/ksh$$/foo +scr=$tmp/script exp=126 : > $scr diff --git a/usr/src/lib/libshell/common/tests/pointtype.sh b/usr/src/lib/libshell/common/tests/pointtype.sh index 25b9f5fbc5..28b60c499c 100644 --- a/usr/src/lib/libshell/common/tests/pointtype.sh +++ b/usr/src/lib/libshell/common/tests/pointtype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/quoting.sh b/usr/src/lib/libshell/common/tests/quoting.sh index b15739da08..a1df26a230 100644 --- a/usr/src/lib/libshell/common/tests/quoting.sh +++ b/usr/src/lib/libshell/common/tests/quoting.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -212,12 +212,12 @@ fi foo=bar bar=$(print -r -- ${foo+\\n\ }) if [[ $bar != '\n ' ]] -then err_exit '${foo+\\n\ } expansion error' +then err_exit '${foo+\\n\ } expansion error' fi unset bar bar=$(print -r -- ${foo+\\n\ $bar}) if [[ $bar != '\n ' ]] -then err_exit '${foo+\\n\ $bar} expansion error with bar unset' +then err_exit '${foo+\\n\ $bar} expansion error with bar unset' fi x='\\(..\\)|&\|\|\\&\\|' if [[ $(print -r -- $x) != "$x" ]] @@ -326,7 +326,7 @@ string='&foo' { x=x x=${x:-`id | sed 's/^[^(]*(\([^)]*\)).*/\1/'`} -} 2> /dev/null || err_exit 'skipping over `` failed' +} 2> /dev/null || err_exit 'skipping over `` failed' [[ $x == x ]] || err_exit 'assignment ${x:=`...`} failed' [[ $($SHELL -c 'print a[') == 'a[' ]] || err_exit "unbalanced '[' in command arg fails" $SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;:' 2> /dev/null || err_exit 'syntax error with ` in arithmetic expression' @@ -334,4 +334,9 @@ $SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;: varname=foobarx x=`print '"\$'${varname}'"'` [[ $x == '"$foobarx"' ]] || err_exit $'\\$\' not handled correctly inside ``' + +copy1=5 copynum=1 +foo="`eval echo "$"{copy$copynum"-0}"`" +[[ $foo == "$copy1" ]] || err_exit '$"..." not being ignored inside ``' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/quoting2.sh b/usr/src/lib/libshell/common/tests/quoting2.sh index 334ed40e7c..dab0992f6b 100644 --- a/usr/src/lib/libshell/common/tests/quoting2.sh +++ b/usr/src/lib/libshell/common/tests/quoting2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -197,11 +197,13 @@ foo=foo [[ "$" == '$' ]] || err_exit '"$" != $' [[ "${foo}$" == 'foo$' ]] || err_exit 'foo=foo;"${foo}$" != foo$' [[ "${foo}${foo}$" == 'foofoo$' ]] || err_exit 'foo=foo;"${foo}${foo}$" != foofoo$' -foo='$ ' +foo='$ ' [[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'$ \' not matching RE \\\\\\$|#\'' -[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' foo='# ' -[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' [[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'# \' not matching RE \'\\$\'|#\'' [[ '\$' == '\$'* ]] || err_exit $'\'\\$\' not matching \'\\$\'*' +[[ a+a == ~(E)a\+a ]] || err_exit '~(E)a\+a not matching a+a' +[[ a+a =~ a\+a ]] || err_exit 'RE a\+a not matching a+a' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/recttype.sh b/usr/src/lib/libshell/common/tests/recttype.sh index 8fe1f3d4ff..b2bca80f50 100644 --- a/usr/src/lib/libshell/common/tests/recttype.sh +++ b/usr/src/lib/libshell/common/tests/recttype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/restricted.sh b/usr/src/lib/libshell/common/tests/restricted.sh index 9cc28c7303..eca93ce6f2 100644 --- a/usr/src/lib/libshell/common/tests/restricted.sh +++ b/usr/src/lib/libshell/common/tests/restricted.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,11 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test restricted shell Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap "cd /; rm -rf /tmp/ksh$$" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test restricted shell pwd=$PWD case $SHELL in /*) ;; @@ -40,14 +42,14 @@ function check_restricted { rm -f out rksh -c "$@" 2> out > /dev/null - grep restricted out > /dev/null 2>&1 + grep restricted out > /dev/null 2>&1 } [[ $SHELL != /* ]] && SHELL=$pwd/$SHELL -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || err_exit "cd $tmp failed" ln -s $SHELL rksh PATH=$PWD:$PATH -rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' +rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' [[ $(rksh -c 'print hello') == hello ]] || err_exit 'unable to run print' check_restricted /bin/echo || err_exit '/bin/echo not resticted' check_restricted ./echo || err_exit './echo not resticted' @@ -74,4 +76,7 @@ print hello ! ! check_restricted 'script;:' || err_exit 'script with #! pathname should run in restricted mode' ! check_restricted 'script' || err_exit 'script with #! pathname should run in restricted mode even if last command in script' +for i in PATH ENV FPATH +do check_restricted "function foo { typeset $i=foobar;};foo" || err_exit "$i can be changed in function by using typeset" +done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/return.sh b/usr/src/lib/libshell/common/tests/return.sh index ac9d2761c0..c9bbf0f33c 100644 --- a/usr/src/lib/libshell/common/tests/return.sh +++ b/usr/src/lib/libshell/common/tests/return.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -26,14 +26,17 @@ function err_exit let Errors+=1 } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + unset HISTFILE foo=NOVAL bar=NOVAL -file=/tmp/shtest$$ -trap "rm -f $file" EXIT INT +file=$tmp/test function foo { typeset foo=NOEXIT @@ -125,7 +128,7 @@ then err_exit "return in script is $ret should be 3" fi cat > $file <<! : line 1 -# next line should fail and cause an exit +# next line should fail and cause an exit : > / exit 4 ! diff --git a/usr/src/lib/libshell/common/tests/select.sh b/usr/src/lib/libshell/common/tests/select.sh index 578fca2e11..2728f85a40 100644 --- a/usr/src/lib/libshell/common/tests/select.sh +++ b/usr/src/lib/libshell/common/tests/select.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,10 +27,13 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -trap "rm -f /tmp/Sh$$*" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + PS3='ABC ' -cat > /tmp/Sh$$.1 <<\! +cat > $tmp/1 <<\! 1) foo 2) bar 3) bam @@ -57,7 +60,7 @@ do case $i in ( set -u; : $i ) || err_exit "select: i not set to null" 2>&3 break;; esac -done 3>&2 2> /tmp/Sh$$.2 <<! +done 3>&2 2> $tmp/2 <<! foo ! exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/shtests b/usr/src/lib/libshell/common/tests/shtests index 63b8db0462..37a36c29ef 100644 --- a/usr/src/lib/libshell/common/tests/shtests +++ b/usr/src/lib/libshell/common/tests/shtests @@ -1,13 +1,15 @@ # This program runs ksh regression tests # shtests [ name=value ... ] [ --all | --compile ] [ --time ] [ a.sh b.sh ... ] -unset DISPLAY ENV FIGNORE +timesensitive='*@(options|sigchld|subshell).sh' + +unset DISPLAY ENV FIGNORE HISTFILE LANG=C LC_ALL=C compile=1 script=1 time=1 -vmdebug=1 +vmdebug=a while : do case $1 in -a|--a*)compile=2 @@ -38,9 +40,11 @@ do case $1 in done if [[ ! $vmdebug ]] then unset VMDEBUG -elif [[ ! $VMDEBUG ]] -then export VMDEBUG=a +elif [[ $VMDEBUG ]] +then vmdebug=$VMDEBUG +else export VMDEBUG=$vmdebug fi +[[ $VMDEBUG ]] || timesensitive=. export LANG LC_ALL PATH PWD SHELL PWD=`pwd` SHELL=${SHELL-ksh} @@ -65,9 +69,8 @@ fi if [[ $compile ]] then SHCOMP=${SHCOMP:-shcomp} if whence $SHCOMP > /dev/null - then tmp=/tmp/ksh-$$ - trap 'rm -rf $tmp' EXIT - mkdir $tmp || exit + then tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; } + trap "cd /; rm -rf $tmp" EXIT elif [[ $compile != 1 ]] then echo $0: --compile: $SHCOMP not found >&2 exit 1 @@ -88,6 +91,9 @@ do t=$(grep -c err_exit $i) E=error if [[ $script ]] then echo test $i begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + if [[ $i == $timesensitive ]] + then unset VMDEBUG + fi if $SHELL $i then echo test $i passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" else e=$? @@ -100,6 +106,9 @@ do t=$(grep -c err_exit $i) fi echo test $i failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi + if [[ $i == $timesensitive ]] + then export VMDEBUG=$vmdebug + fi fi done if [[ $compile ]] @@ -114,7 +123,10 @@ then for i in ${*-*.sh} echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} E=error if $SHCOMP $i > $tmp/$o - then if $SHELL $tmp/$o + then if [[ $i == $timesensitive ]] + then unset VMDEBUG + fi + if $SHELL $tmp/$o then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" else e=$? if (( e > 256 )) @@ -126,6 +138,9 @@ then for i in ${*-*.sh} fi echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi + if [[ $i == $timesensitive ]] + then export VMDEBUG=$vmdebug + fi else e=$? t=1 T=test diff --git a/usr/src/lib/libshell/common/tests/sigchld.sh b/usr/src/lib/libshell/common/tests/sigchld.sh index 018eb9fbc0..0b2bf8e03f 100644 --- a/usr/src/lib/libshell/common/tests/sigchld.sh +++ b/usr/src/lib/libshell/common/tests/sigchld.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -59,7 +59,55 @@ print foreground=$foreground background=$background eval $s -(( foreground == FOREGROUND )) || err_exit "expected $FOREGROUND foreground -- got $foreground (DELAY=$DELAY)" -(( background == BACKGROUND )) || err_exit "expected $BACKGROUND background -- got $background (DELAY=$DELAY)" +(( foreground == FOREGROUND )) || err_exit "expected '$FOREGROUND foreground' -- got '$foreground' (DELAY=$DELAY)" +(( background == BACKGROUND )) || err_exit "expected '$BACKGROUND background' -- got '$background' (DELAY=$DELAY)" + +set --noerrexit + +if [[ ${.sh.version} == Version?*([[:upper:]])J* ]] +then + + jobmax=4 + got=$($SHELL -c ' + JOBMAX='$jobmax' JOBCOUNT=$(('$jobmax'*2)) + integer running=0 maxrunning=0 + trap "((running--))" CHLD + for ((i=0; i<JOBCOUNT; i++)) + do sleep 1 & + if ((++running > maxrunning)) + then ((maxrunning=running)) + fi + done + wait + print running=$running maxrunning=$maxrunning + ') + exp='running=0 maxrunning='$jobmax + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected '$exp', got '$got'" + + got=$($SHELL -c ' + typeset -A proc + + trap " + print \${proc[\$!].name} \${proc[\$!].status} \$? + unset proc[\$!] + " CHLD + + { sleep 3; print a; exit 1; } & + proc[$!]=( name=a status=1 ) + + { sleep 2; print b; exit 2; } & + proc[$!]=( name=b status=2 ) + + { sleep 1; print c; exit 3; } & + proc[$!]=( name=c status=3 ) + + while (( ${#proc[@]} )) + do sleep -s + done + ') + exp='c\nc 3 3\nb\nb 2 2\na\na 1 1' + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected $(printf %q "$exp"), got $(printf %q "$got")" + +fi exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/signal.sh b/usr/src/lib/libshell/common/tests/signal.sh index 12b06d6fca..bab844fc4d 100644 --- a/usr/src/lib/libshell/common/tests/signal.sh +++ b/usr/src/lib/libshell/common/tests/signal.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,14 +28,39 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap 'cd /; rm -rf /tmp/ksh$$' EXIT -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || err_exit "cd $tmp failed" + +( + set --pipefail + { + $SHELL 2> out2 <<- \EOF + g=false + trap 'print -u2 PIPED; $g && exit 0;g=true' PIPE + while : + do print hello + done + EOF + } | head > /dev/null + (( $? == 0)) || err_exit "SIGPIPE with wrong error code $?" + [[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct' +) & +cop=$! +{ sleep 4; kill $cop; } 2>/dev/null & +spy=$! +if wait $cop 2>/dev/null +then kill $spy 2>/dev/null +else err_exit "pipe with --pipefail PIPE trap hangs" +fi +wait +rm -f out2 [[ $( trap 'print -n got_child' SIGCHLD sleep 2 & for ((i=0; i < 4; i++)) - do sleep .9 + do sleep .75 print -n $i done) == 01got_child23 ]] || err_exit 'SIGCHLD not working' @@ -55,7 +80,8 @@ cat > tst <<'!' # # d call next script directly, otherwise via $SHELL -c # t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x -# x trap, echo on SIGINT, and exit 0, otherwise SIGINT default +# x trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit, otherwise SIGINT default +# z trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit 0, otherwise SIGINT default # # Usage: tst [-v] [-options] shell-to-test ... @@ -71,7 +97,7 @@ set -o monitor function gen { typeset o t x d - for x in - x + for x in - x z do case $x in [$1]) for t in - t do case $t in @@ -153,6 +179,11 @@ sleep 2 ! cat > tst-2 <<'!' case $1 in +*z*) trap ' + echo 2-intr + exit 0 + ' INT + ;; *x*) trap ' echo 2-intr exit @@ -176,7 +207,7 @@ printf '2-%04d\n' $status ! cat > tst-3 <<'!' case $1 in -*x*) trap ' +*[xz]*) trap ' sleep 2 echo 3-intr exit 0 @@ -206,10 +237,14 @@ expected[---]="3-intr" expected[--d]="3-intr" expected[-t-]="3-intr 2-intr 1-intr 1-0258" expected[-td]="3-intr 2-intr 1-intr 1-0258" -expected[x--]="3-intr 2-intr 1-0000" -expected[x-d]="3-intr 2-intr 1-0000" -expected[xt-]="3-intr 2-intr 1-intr 1-0000" -expected[xtd]="3-intr 2-intr 1-intr 1-0000" +expected[x--]="3-intr 2-intr" +expected[x-d]="3-intr 2-intr" +expected[xt-]="3-intr 2-intr 1-intr 1-0258" +expected[xtd]="3-intr 2-intr 1-intr 1-0258" +expected[z--]="3-intr 2-intr 1-0000" +expected[z-d]="3-intr 2-intr 1-0000" +expected[zt-]="3-intr 2-intr 1-intr 1-0000" +expected[ztd]="3-intr 2-intr 1-intr 1-0000" tst $SHELL > tst.got @@ -218,9 +253,71 @@ do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- ex done < tst.got float s=$SECONDS -[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell ignoring signal does not send signal to parent' +[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell ignoring signal does not send signal to parent' (( (SECONDS-s) < 4 )) && err_exit 'parent does not wait for child to complete before handling signal' ((s = SECONDS)) -[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "exit" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell catching signal does not send signal to parent' +[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "exit" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell catching signal does not send signal to parent' (( SECONDS-s < 4 )) && err_exit 'parent completes early' + +unset n s t +for s in $(kill -l) +do if ! n=$(kill -l $s 2>/dev/null) + then err_exit "'kill -l $s' failed" + continue + fi + if ! t=$(kill -l $n 2>/dev/null) + then err_exit "'kill -l $n' failed" + continue + fi + if [[ $s == ?(SIG)$t ]] + then continue + fi + if ! m=$(kill -l $t 2>/dev/null) + then err_exit "'kill -l $t' failed" + continue + fi + if [[ $m == $n ]] + then continue + fi + err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n" +done +yes=$(whence -p yes) +[[ $yes ]] && for exp in TERM VTALRM PIPE +do { $SHELL <<- EOF + foo() { return 0; } + trap foo EXIT + { sleep 2; kill -$exp \$\$; sleep 3; kill -0 \$\$ && kill -KILL \$\$; } & + $yes | while read yes; do + (/bin/date; sleep .1) + done > /dev/null + EOF + } 2>> /dev/null + got=$(kill -l $?) + [[ $exp == $got ]] || err_exit "kill -$exp \$\$ failed, required termination by signal '$got'" +done + +SECONDS=0 +$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished' > $tmp/sig +(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" + +SECONDS=0 +{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit" EXIT; (sleep 5);print finished' > $tmp/sig ;} 2> /dev/null +[[ $(kill -l $?) == TERM ]] || err_exit "wrong exit status expecting TERM got $(kill -l $?)" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" + +SECONDS=0 +x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished') +(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS < 4 )) && err_exit "took $SECONDS seconds, expecting around 5" + +trap '' SIGBUS +[[ $($SHELL -c 'trap date SIGBUS;trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap' +trap -- - SIGBUS + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/statics.sh b/usr/src/lib/libshell/common/tests/statics.sh index d6af9c7c91..21175c08db 100644 --- a/usr/src/lib/libshell/common/tests/statics.sh +++ b/usr/src/lib/libshell/common/tests/statics.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -30,9 +30,9 @@ function testfunc typeset cmd="$2" typeset expected_output="$3" typeset output - + output="$($SHELL -c "${cmd}" 2>&1 )" - + [[ "${output}" != "${expected_output}" ]] && err_exit2 ${line_number} "${output} != ${expected_output}" } alias testfunc='testfunc $LINENO' @@ -60,9 +60,9 @@ testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; function l { typeset -S s=( a=0 b=0 ) - + (( s.a++, s.b++ )) - + $1 && printf 'a=%d, b=%d\n' s.a s.b } l false ; l false ; l true @@ -75,9 +75,9 @@ got=$( function ar { typeset -a -S s=( "hello" ) - + s+=( "an element" ) - + $1 && { printf '%s' "${s[@]}" ; printf '\n' ; } } ar false ; ar false ; ar true diff --git a/usr/src/lib/libshell/common/tests/subshell.sh b/usr/src/lib/libshell/common/tests/subshell.sh index 985aba6eaa..bc63bde995 100644 --- a/usr/src/lib/libshell/common/tests/subshell.sh +++ b/usr/src/lib/libshell/common/tests/subshell.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,9 +24,15 @@ function err_exit (( Errors+=1 )) } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 Error_fd=2 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +bincat=$(PATH=$(getconf PATH) whence -p cat) + z=() z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) z.bar[0]=hello @@ -70,7 +76,7 @@ false [[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working' ) [[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' - + x=( foo=( qqq=abc rrr=def) bar=( zzz=no rst=fed) @@ -97,8 +103,6 @@ while whence $TEST_notfound >/dev/null 2>&1 do TEST_notfound=notfound-$RANDOM done -tmp=/tmp/kshsubsh$$ -trap "rm -f $tmp" EXIT integer BS=1024 nb=64 ss=60 bs no for bs in $BS 1 do $SHELL -c ' @@ -109,8 +113,8 @@ do $SHELL -c ' set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs') print ${#1} kill $! - ' > $tmp 2>/dev/null - no=$(<$tmp) + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}" done # this time with redirection on the trailing command @@ -124,8 +128,8 @@ do $SHELL -c ' set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null) print ${#1} kill $! - ' > $tmp 2>/dev/null - no=$(<$tmp) + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}" done @@ -220,4 +224,230 @@ do for TEST_exec in '' 'exec' done done +$SHELL -c '( autoload xxxxx);print -n' || err_exit 'autoloaded functions in subshells can cause failure' +foo=$($SHELL <<- ++EOF++ + (trap 'print bar' EXIT;print -n foo) + ++EOF++ +) +[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered' + +err=$( + $SHELL 2>&1 <<- \EOF + date=$(whence -p date) + function foo + { + x=$( $date > /dev/null 2>&1 ;:) + } + # consume almost all fds to push the test to the fd limit # + integer max=$(ulimit --nofile) + (( max -= 6 )) + for ((i=20; i < max; i++)) + do exec {i}>&1 + done + for ((i=0; i < 20; i++)) + do y=$(foo) + done + EOF +) || { + err=${err%%$'\n'*} + err=${err#*:} + err=${err##[[:space:]]} + err_exit "nested command substitution with redirections failed -- $err" +} + +exp=0 +$SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + exit '$exp$' +' +got=$? +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" +exp=ok +got=$($SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + print '$exp$' +') +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" + +# command substitution variations # +set -- \ + '$(' ')' \ + '${ ' '; }' \ + '$(ulimit -c 0; ' ')' \ + '$( (' ') )' \ + '${ (' '); }' \ + '`' '`' \ + '`(' ')`' \ + '`ulimit -c 0; ' '`' \ + # end of table # +exp=ok +testcase[1]=' + if %sexpr "NOMATCH" : ".*Z" >/dev/null%s + then print error + else print ok + fi + exit %s +' +testcase[2]=' + function bar + { + pipeout=%1$sprintf Ok | tr O o%2$s + print $pipeout + return 0 + } + foo=%1$sbar%2$s || foo="exit status $?" + print $foo + exit %3$s +' +while (( $# >= 2 )) +do for ((TEST=1; TEST<=${#testcase[@]}; TEST++)) + do body=${testcase[TEST]} + for code in 0 2 + do got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 } + status=$? + if (( status != code )) + then err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code" + elif [[ $got != $exp ]] + then err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'" + fi + done + done + shift 2 +done + +# the next tests loop on all combinations of +# { SUB CAT INS TST APP } X { file-sizes } +# where the file size starts at 1Ki and doubles up to and including 1Mi +# +# the tests and timeouts are done in async subshells to prevent +# the test harness from hanging + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +CAT=( cat $bincat ) +INS=( "" "builtin cat; " "builtin -d cat $bincat; " ": > /dev/null; " ) +APP=( "" "; :" ) +TST=( + ( CMD='print foo | $cat' EXP=3 ) + ( CMD='$cat < $tmp/lin' ) + ( CMD='cat $tmp/lin | $cat' ) + ( CMD='read v < $tmp/buf; print $v' LIM=4*1024 ) + ( CMD='cat $tmp/buf | read v; print $v' LIM=4*1024 ) +) + +command exec 3<> /dev/null +if cat /dev/fd/3 >/dev/null 2>&1 +then T=${#TST[@]} + TST[T].CMD='$cat <(print foo)' + TST[T].EXP=3 +fi + +# prime the two data files to 512 bytes each +# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines +# the outer loop doubles the file size at top + +buf=$'1234567890abcdef' +lin=$'\n1234567890abcde' +for ((i=0; i<5; i++)) +do buf=$buf$buf + lin=$lin$lin +done +print -n "$buf" > $tmp/buf +print -n "$lin" > $tmp/lin + +unset SKIP +for ((n=1024; n<=1024*1024; n*=2)) +do cat $tmp/buf $tmp/buf > $tmp/tmp + mv $tmp/tmp $tmp/buf + cat $tmp/lin $tmp/lin > $tmp/tmp + mv $tmp/tmp $tmp/lin + for ((S=0; S<${#SUB[@]}; S++)) + do for ((C=0; C<${#CAT[@]}; C++)) + do cat=${CAT[C]} + for ((I=0; I<${#INS[@]}; I++)) + do for ((A=0; A<${#APP[@]}; A++)) + do for ((T=0; T<${#TST[@]}; T++)) + do #undent...# + + if [[ ! ${SKIP[S][C][I][A][T]} ]] + then eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &" + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) + if [[ ! $got ]] && (( h )) + then got=HUNG + fi + if [[ ${TST[T].EXP} ]] + then exp=${TST[T].EXP} + else exp=$n + fi + if [[ $got != $exp ]] + then # on failure skip similar tests on larger files sizes # + SKIP[S][C][I][A][T]=1 + siz=$(printf $'%#i' $exp) + cmd=${TST[T].CMD//\$cat/$cat} + cmd=${cmd//\$tmp\/buf/$siz.buf} + cmd=${cmd//\$tmp\/lin/$siz.lin} + err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'" + elif [[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n )) + then SKIP[S][C][I][A][T]=1 + fi + fi + + #...indent# + done + done + done + done + done +done + +# specifics -- there's more? + +{ + cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &' + eval $cmd + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) +} 2>/dev/null +exp='' +if [[ ! $got ]] && (( h )) +then got=HUNG +fi +if [[ $got != $exp ]] +then err_exit "eval '$cmd' failed -- expected '$exp', got '$got'" +fi + +float t1=$SECONDS +sleep=$(whence -p sleep) +if [[ $sleep ]] +then + $SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat + (( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging' + ((t1=SECONDS)) +fi +$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat +(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging' + exit $Errors diff --git a/usr/src/lib/libshell/common/tests/substring.sh b/usr/src/lib/libshell/common/tests/substring.sh index 8d283c6a29..0d7fc384a7 100644 --- a/usr/src/lib/libshell/common/tests/substring.sh +++ b/usr/src/lib/libshell/common/tests/substring.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -192,7 +192,7 @@ fi if [[ ${foo//\//_} != one_two_three ]] then err_exit 'escaping / in replacements failed' fi -function myexport +function myexport { nameref var=$1 if (( $# > 1 )) @@ -205,7 +205,7 @@ function myexport typeset val val=$(export | grep "^$1=") print ${val#"$1="} - + } export dgk=base if [[ $(myexport dgk fun) != fun ]] @@ -280,7 +280,7 @@ b='[abc 123 def]' [[ ${b//$a/\1} == 123 ]] || err_exit "\${var/pattern} not working with \[ in pattern" unset foo foo='(win32.i386) ' -[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" +[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" $SHELL -c $'v=\'$(hello)\'; [[ ${v//\'$(\'/-I\'$(\'} == -I"$v" ]]' 2> /dev/null || err_exit "\${var/pattern} not working with \$( as pattern" unset X $SHELL -c '[[ ! ${X[@]:0:300} ]]' 2> /dev/null || err_exit '${X[@]:0:300} with X undefined fails' @@ -303,7 +303,7 @@ done [[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z' : ${string/$pattern/} (( ${#.sh.match[@]} == 53 )) || err_exit '.sh.match has wrong number of elements' -[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect' +[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect' D=$';' E=$'\\\\' Q=$'"' S=$'\'' M='nested pattern substitution failed' @@ -501,7 +501,7 @@ pattern=00 var=100 [[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embeddded patterns fails" [[ $( print $(( ${var%%$pattern} )) ) == 1 ]] || err_exit "arithmetic with embeddded pattern variables fails" -if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]] +if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]] then err_exit '${.sh.match[1]:1:${#.sh.match[1]}} not expanding correctly' fi @@ -509,10 +509,10 @@ string='foo(d:\nt\box\something)bar' expected='d:\nt\box\something' [[ ${string/*\(+([!\)])\)*/\1} == "$expected" ]] || err_exit "substring expansion failed '${string/*\(+([!\)])\)*/\1}' returned -- '$expected' expected" if [[ $($SHELL -c $'export LC_ALL=en_US.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 ]] -then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'Multibyte ${var:offset:len} not working correctly' +then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'multibyte ${var:offset:len} not working correctly' fi -{ $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' -{ $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' +{ $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' +{ $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' # subject mode pattern result # set -- \ diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh b/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh new file mode 100644 index 0000000000..45b3851f19 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh @@ -0,0 +1,303 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test module checks whether indexed+associative arrays +# set the default datatype correctly if someone uses the "+=" +# operator to add a value to an array element which does not +# exist yet. +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +# the test cannot use "nounset" +Command=${0##*/} +integer Errors=0 + +compound bracketstat=( + integer bopen=0 + integer bclose=0 +) + +function count_brackets +{ + typeset x="$1" + typeset c + + integer i + (( bracketstat.bopen=0 , bracketstat.bclose=0 )) + + for (( i=0 ; i < ${#x} ; i++ )) ; do + c="${x:i:1}" + [[ "$c" == "(" ]] && (( bracketstat.bopen++ )) + [[ "$c" == ")" ]] && (( bracketstat.bclose++ )) + done + + (( bracketstat.bopen != bracketstat.bclose )) && return 1 + + return 0 +} + +# function to add the floating-point value 1.1 to array element "34" +# floating-point datatypes should increment by 1.1, integers by 1 +function add_float +{ + nameref arr=$1 + + arr[34]+=1.1 + + return 0 +} + +# function to add a compound variable called "val" to array element arr[34] +function add_compound +{ + nameref arr=$1 + + arr[34]+=( float val=1.1 ) + + return 0 +} + +# We run the tests in multiple cyles: +# First cycle uses a normal compound variable as basis +# Second cycle uses a nameref to a compound variable as basis +# Third cycle uses a nameref to a nameref to a compound variable as basis +for cycle in \ + c1 c2 c3 c4 \ + c2_sub c3_sub c4_sub \ + c2_indexed_array c3_indexed_array c4_indexed_array \ + c2_associative_array c3_associative_array c4_associative_array; do + case ${cycle} in + c1) + compound mycpv + ;; + c2) + compound rootcpv + nameref mycpv=rootcpv + ;; + c3) + compound rootcpv + nameref namereftoroot=rootcpv + nameref mycpv=namereftoroot + ;; + c4) + compound rootcpv + nameref namereftoroot0=rootcpv + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of rootcpv + c2_sub) + compound rootcpv + compound rootcpv.sub + nameref mycpv=rootcpv.sub + ;; + c3_sub) + compound rootcpv + compound rootcpv.sub + nameref namereftoroot=rootcpv.sub + nameref mycpv=namereftoroot + ;; + c4_sub) + compound rootcpv + compound rootcpv.sub + nameref namereftoroot0=rootcpv.sub + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of an indexed array + c2_indexed_array) + compound -a rootcpv + nameref mycpv=rootcpv[4] + ;; + c3_indexed_array) + compound -a rootcpv + nameref namereftoroot=rootcpv[4] + nameref mycpv=namereftoroot + ;; + c4_indexed_array) + compound -a rootcpv + nameref namereftoroot0=rootcpv[4] + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of an indexed array + c2_associative_array) + compound -A rootcpv + nameref mycpv=rootcpv["hello world"] + ;; + c3_associative_array) + compound -A rootcpv + nameref namereftoroot=rootcpv["hello world"] + nameref mycpv=namereftoroot + ;; + c4_associative_array) + compound -A rootcpv + nameref namereftoroot0=rootcpv["hello world"] + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + *) + err_exit "${cycle}: Should not happen." + ;; + esac + + + # Test 001: Test indexed floating-point array + float -a mycpv.myindexedfloatarray + + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" + unset mycpv.myindexedfloatarray[34] + (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" + unset mycpv.myindexedfloatarray[34] + (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" + + + + # Test 002: Test associative floating-point array + float -A mycpv.myassociativefloatarray + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" + unset mycpv.myassociativefloatarray[34] + (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" + unset mycpv.myassociativefloatarray[34] + (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" + + + + # Test 003: Test indexed integer array + integer -a mycpv.myindexedintegerarray + + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" + unset mycpv.myindexedintegerarray[34] + (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" + unset mycpv.myindexedintegerarray[34] + (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" + + + + # Test 004: Test associative integer array + integer -A mycpv.myassociativeintegerarray + + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" + unset mycpv.myassociativeintegerarray[34] + (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" + unset mycpv.myassociativeintegerarray[34] + (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" + + + + # Test 005: Tested indexed compound variable array + compound -a mycpv.myindexedcompoundarray + add_compound mycpv.myindexedcompoundarray + (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" + # try to add it a 2nd time - since the new element will replace the old + # one the value will _not_ be incremented (or better: The compound + # variable value "val" will be added, not the value of the "val" + # variable) + add_compound mycpv.myindexedcompoundarray + (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" + unset mycpv.myindexedcompoundarray[34] + [[ ! -v mycpv.myindexedcompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myindexedcompoundarray[34].val ]] should return failure, got $?" + (( mycpv.myindexedcompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 0.0" + [[ "${mycpv.myindexedcompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myindexedcompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myindexedcompoundarray[34]}|" + + + + # Test 006: Tested associative compound variable array + compound -A mycpv.myassociativecompoundarray + add_compound mycpv.myassociativecompoundarray + (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" + # try to add it a 2nd time - since the new element will replace the old + # one the value will _not_ be incremented (or better: The compound + # variable value "val" will be added, not the value of the "val" + # variable) + add_compound mycpv.myassociativecompoundarray + (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" + unset mycpv.myassociativecompoundarray[34] + [[ ! -v mycpv.myassociativecompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myassociativecompoundarray[34].val ]] should return failure, got $?" + (( mycpv.myassociativecompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 0.0" + [[ "${mycpv.myassociativecompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myassociativecompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myassociativecompoundarray[34]}|" + + + # check whether the compound variable output is still Ok + count_brackets "${mycpv}" || err_exit "${cycle}: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + count_brackets "$(print -v mycpv)" || err_exit "${cycle}: print -v mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + count_brackets "$(print -C mycpv)" || err_exit "${cycle}: print -C mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + + + # reset + unset mycpv + [[ ! -v mycpv ]] || err_exit "${cycle}: mycpy should not exist" + [[ "${mycpv}" == "" ]] || err_exit "${cycle}: mycpv expected to be empty" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh new file mode 100644 index 0000000000..5dc5f5cce1 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh @@ -0,0 +1,72 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Test whether the ksh93/poll builtin works as expected +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +builtin -f libshell.so.1 poll || err_exit "poll builtin not found." + +compound d1=( + compound -A u=( + [y]=( fd=5 events="POLLIN" revents="" ) + [x]=( fd=5 events="POLLIN" revents="" ) + ) +) + +# test 1: +cat /dev/zero | { redirect 5<&0 ; poll -e d1.res -t 5. d1.u ; } || err_exit "poll returned non-zero exit code $?" +[[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not POLLIN" +[[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not POLLIN" +[[ "${d1.res[*]}" == "x y" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y'" + +# test 2: +unset d1.res + +d1.u[z]=( fd=5 events="POLLOUT" revents="" ) +{ poll -e d1.res -t 5. d1.u ; } 5</dev/null 5>/dev/null || err_exit "poll returned non-zero exit code $?" +[[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not 'POLLIN'" +[[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not 'POLLIN'" +[[ "${d1.u[z].revents}" == "POLLOUT|POLLWRNORM" ]] || err_exit "d1.u[z].revents contains '${d1.u[z].revents}', not 'POLLOUT|POLLWRNORM,'" +[[ "${d1.res[*]}" == "x y z" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y z'" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh index d2dc6db883..e80111a538 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -29,6 +29,7 @@ # Solaris/SystemV /usr/bin/sum # +# test setup function err_exit { print -u2 -n "\t" @@ -37,9 +38,11 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset Command=${0##*/} integer Errors=0 + typeset x builtin sum || err_exit "sum builtin not found" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh new file mode 100644 index 0000000000..69a7f1a6b9 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh @@ -0,0 +1,446 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Test whether the ksh93/libcmd tail builtin is compatible to +# Solaris/SystemV { /usr/bin/tail, /usr/xpg4/bin/tail } and +# POSIX "tail" +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# common functions +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} + +function waitpidtimeout +{ + integer pid=$1 + float timeout=$2 + float i + float -r STEP=0.5 # const + + (( timeout=timeout/STEP )) + + for (( i=0 ; i < timeout ; i+=STEP )) ; do + isvalidpid ${pid} || break + sleep ${STEP} + done + + return 0 +} + +function myintseq +{ + integer i + float arg1=$1 + float arg2=$2 + float arg3=$3 + + case $# in + 1) + for (( i=1 ; i <= arg1 ; i++ )) ; do + printf "%d\n" i + done + ;; + 2) + for (( i=arg1 ; i <= arg2 ; i++ )) ; do + printf "%d\n" i + done + ;; + 3) + for (( i=arg1 ; i <= arg3 ; i+=arg2 )) ; do + printf "%d\n" i + done + ;; + *) + print -u2 -f "%s: Illegal number of arguments %d\n" "$0" $# + return 1 + ;; + esac + + return 0 +} + +# quote input string but use double-backslash that "err_exit" prints +# the strings correctly +function doublebackslashquote +{ + typeset s + s="$(printf "%q\n" "$1")" + s="${s//\\/\\\\}" + print -r "$s" + return 0 +} + + +# main +builtin mktemp || err_exit "mktemp builtin not found" +builtin rm || err_exit "rm builtin not found" +builtin tail || err_exit "tail builtin not found" + +typeset ocwd +typeset tmpdir + +# create temporary test directory +ocwd="$PWD" +tmpdir="$(mktemp -d "test_sun_solaris_builtin_tail.XXXXXXXX")" || err_exit "Cannot create temporary directory" + +cd "${tmpdir}" || err_exit "cd ${tmpdir} failed." + + +# run tests: + +# test1: basic tests +compound -a testcases=( + ( + name="reverse_n" + input=$'hello\nworld' + compound -A tail_args=( + [legacy]=( argv=( "-r" ) ) + ) + expected_output=$'world\nhello' + ) + ( + name="revlist0n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-0" ) ) + [std_like]=( argv=( "-n" "0" ) ) + ) + expected_output=$'' + ) + ( + name="revlist0nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-0r" ) ) + [std_like]=( argv=( "-n" "0" "-r" ) ) + [long_options]=( argv=( "--lines" "0" "--reverse" ) ) + ) + expected_output=$'' ) + ( + name="revlist1n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-1" ) ) + [std_like]=( argv=( "-n" "1" ) ) + [long_options]=( argv=( "--lines" "1" ) ) + ) + expected_output=$'4' ) + ( + name="revlist1nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-1r" ) ) + [std_like]=( argv=( "-n" "1" "-r" ) ) + [long_options]=( argv=( "--lines" "1" "--reverse" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist2n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-2" ) ) + [std_like]=( argv=( "-n" "2" ) ) + ) + expected_output=$'3\n4' + ) + ( + name="revlist2nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-2r" ) ) + [std_like]=( argv=( "-n" "2" "-r" ) ) + ) + expected_output=$'4\n3' + ) + ( + name="revlist3nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-3r" ) ) + [std_like]=( argv=( "-n" "3" "-r" ) ) + ) + expected_output=$'4\n3\n2' + ) + ( + name="revlist2p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+2" ) ) + [std_like]=( argv=( "-n" "+2" ) ) + ) + expected_output=$'2\n3\n4' + ) + ( + name="revlist2pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+2r" ) ) + [std_like]=( argv=( "-n" "+2" "-r" ) ) + ) + expected_output=$'4\n3\n2' + ) + ( + name="revlist3p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+3" ) ) + [std_like]=( argv=( "-n" "+3" ) ) + ) + expected_output=$'3\n4' + ) + ( + name="revlist3pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+3r" ) ) + [std_like]=( argv=( "-n" "+3" "-r" ) ) + ) + expected_output=$'4\n3' + ) + ( + name="revlist4p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+4" ) ) + [std_like]=( argv=( "-n" "+4" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist4pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+4r" ) ) + [std_like]=( argv=( "-n" "+4" "-r" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist5p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+5" ) ) + [std_like]=( argv=( "-n" "+5" ) ) + ) + expected_output=$'' + ) + ( + name="revlist5pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+5r" ) ) + [std_like]=( argv=( "-n" "+5" "-r" ) ) + ) + expected_output=$'' + ) +) + +for testid in "${!testcases[@]}" ; do + nameref tc=testcases[${testid}] + + for argv_variants in "${!tc.tail_args[@]}" ; do + nameref argv=tc.tail_args[${argv_variants}].argv + output=$( + #set -o pipefail + print -r -- "${tc.input}" | tail "${argv[@]}" + ) || err_exit "test ${tc.name}/${argv_variants}: command failed with exit code $?" + + [[ "${output}" == "${tc.expected_output}" ]] || err_exit "test ${tc.name}/${argv_variants}: Expected $(doublebackslashquote "${tc.expected_output}"), got $(doublebackslashquote "${output}")" + done +done + + +# test2: test "tail -r </etc/profile | rev -l" vs. "cat </etc/profile" +[[ "$(tail -r </etc/profile | rev -l)" == "$( cat /etc/profile )" ]] || err_exit "'tail -r </etc/profile | rev -l' output does not match 'cat /etc/profile'" + + +# test 3: ast-ksh.2009-05-05 "tail" builtin may crash if we pass unsupported long options +$SHELL -o errexit -c 'builtin tail ; print "hello" | tail --attack_of_chicken_monsters' >/dev/null 2>&1 +(( $? == 2 )) || err_exit "expected exit code 2 for unsupported long option, got $?" + + +# test 4: FIFO tests + +# FIFO test functions +# (we use functions here to do propper garbage collection) +function test_tail_fifo_1 +{ + typeset tail_cmd="$1" + integer i + integer tail_pid=-1 + + # cleanup trap + trap "rm -f tailtestfifo tailout" EXIT + + # create test FIFO + mkfifo tailtestfifo + + ${tail_cmd} -f <tailtestfifo >tailout & + tail_pid=$! + + myintseq 20 >tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + err_exit "test_tail_fifo_1: # tail hung (not expected)" + kill -KILL ${tail_pid} + fi + + wait || err_exit "tail child returned non-zero exit code=$?" + + [[ "$(cat tailout)" == $'11\n12\n13\n14\n15\n16\n17\n18\n19\n20' ]] || err_exit "test_tail_fifo_1: Expected $(doublebackslashquote '11\n12\n13\n14\n15\n16\n17\n18\n19\n20'), got $(doublebackslashquote "$(cat tailout)")" + + return 0 +} + +function test_tail_fifo_2 +{ + typeset tail_cmd="$1" + integer i + integer tail_pid=-1 + + # cleanup trap + trap "rm -f tailtestfifo tailout" EXIT + + # create test FIFO + mkfifo tailtestfifo + + ${tail_cmd} -f tailtestfifo >tailout & + tail_pid=$! + + myintseq 14 >tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14'), got $(doublebackslashquote "$(cat tailout)")" + + myintseq 15 >>tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + kill -KILL ${tail_pid} + else + err_exit "test_tail_fifo_2: # tail exit with return code $? (not expected)" + fi + fi + + wait || err_exit "tail child returned non-zero exit code=$?" + + [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15'), got $(doublebackslashquote "$(cat tailout)")" + + return 0 +} + +# fixme: This should test /usr/bin/tail and /usr/xpg4/bin/tail in Solaris +test_tail_fifo_1 "tail" +test_tail_fifo_2 "tail" + + +# test 5: "tail -f" tests +function followtest1 +{ + typeset -r FOLLOWFILE="followfile.txt" + typeset -r OUTFILE="outfile.txt" + + typeset title="$1" + typeset testcmd="$2" + typeset usenewline=$3 + typeset followstr="" + typeset newline="" + integer i + integer tailchild=-1 + + if ${usenewline} ; then + newline=$'\n' + fi + + rm -f "${FOLLOWFILE}" "${OUTFILE}" + print -n "${newline}" > "${FOLLOWFILE}" + + ${testcmd} -f "${FOLLOWFILE}" >"${OUTFILE}" & + (( tailchild=$! )) + + for (( i=0 ; i < 10 ; i++)) ; do + followstr+="${newline}${i}" + print -n "${i}${newline}" >>"${FOLLOWFILE}" + sleep 2 + + [[ "$( < "${OUTFILE}")" == "${followstr}" ]] || err_exit "${title}: Expected $(doublebackslashquote "${followstr}"), got "$(doublebackslashquote "$( < "${OUTFILE}")")"" + done + + #kill -TERM ${tailchild} 2>/dev/null + kill -KILL ${tailchild} 2>/dev/null + waitpidtimeout ${tailchild} 5 + + if isvalidpid ${tailchild} ; then + err_exit "${title}: tail pid=${tailchild} hung." + kill -KILL ${tailchild} 2>/dev/null + fi + + wait ${tailchild} 2>/dev/null + + rm -f "${FOLLOWFILE}" "${OUTFILE}" + + return 0 +} + +followtest1 "test5a" "tail" true +# fixme: later we should test this, too: +#followtest1 "test5b" "tail" false +#followtest1 "test5c" "/usr/xpg4/bin/tail" true +#followtest1 "test5d" "/usr/xpg4/bin/tail" false +#followtest1 "test5e" "/usr/bin/tail" true +#followtest1 "test5f" "/usr/bin/tail" false + + +# cleanup +cd "${ocwd}" +rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh b/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh new file mode 100644 index 0000000000..77ab14714e --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh @@ -0,0 +1,291 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Written by Roland Mainz <roland.mainz@nrubsig.org> +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} +integer testfilesize i maxwait +typeset tmpfile +integer testid + + +######################################################################## +#### test set 001: +# run loop and check various temp filesizes +# (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh) + +# test 1: run loop and check various temp filesizes +tmpfile="$(mktemp "/tmp/ksh93_tests_command_substitution.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." + +compound test1=( + compound -a testcases=( + # test 1a: Run test child for $(...) + # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) + ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1b: Same as test1a but uses ${... ; } instead if $(...) + ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1c: Same as test1a but does not use a pipe + ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1d: Same as test1a but does not use a pipe + ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + + # test 1e: Same as test1a but uses an external "cat" command + ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1f: Same as test1a but uses an external "cat" command + ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1g: Same as test1a but uses an external "cat" command + ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1h: Same as test1a but uses an external "cat" command + ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + ) +) + +for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do + # Create temp file + { + for (( i=0 ; i < testfilesize ; i+=64 )) ; do + print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" + done + } >"${tmpfile}" + + # wait up to log2(i) seconds for the child to terminate + # (this is 10 seconds for 1KB and 19 seconds for 512KB) + (( maxwait=log2(testfilesize) )) + + for testid in "${!test1.testcases[@]}" ; do + nameref currtst=test1.testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + # compare input/output + cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." + rm "${tmpfile}.out" + done + + # Cleanup + rm "${tmpfile}" +done + + +######################################################################## +#### test set 002: +# If a command substitution calls a function and that function contains +# a command substitution which contains a piped command, the original +# command substitution calling the function will return 127 instead of 0. +# This is causing problems in several VSC tests. +# If we remove the piped command from the simple +# case in the attached script, it returns 0. + +typeset str +typeset testbody +typeset testout + +testbody=$( +# <CS> means command substitution start, <CE> means command substitution end +cat <<EOF +myfunc () +{ + pipedcmd=<CS> printf "hi" | tr "h" "H" <CE> + echo \$pipedcmd + + return 0 +} + +foo=<CS>myfunc<CE> +retval=\$? + +if [ "\$foo"X != "HiX" ]; then + echo "myfunc returned '\${foo}'; expected 'Hi'" +fi + +if [ \$retval -ne 0 ]; then + echo "command substitution calling myfunc returned \"\${retval}\"; expected 0" +else + echo "command substitution calling myfunc successfully returned 0" +fi +EOF +) + + +# Test 002/a: Plain test +testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/b: Same as test002/a but replaces "$(" with "${" +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0" +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/d: Same as test002/a but uses extra subshell +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/e: Same as test002/b but uses extra subshell after "${ " +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + + + + +######################################################################## +#### test set 003: +# An expression within backticks which should return false, instead +# returns true (0). + +typeset str +typeset testbody +typeset testout + +testbody=$( +# <CS> means command substitution start, <CE> means command substitution end +cat <<EOF +if <CS>expr "NOMATCH" : ".*Z" > /dev/null<CE> ; then + echo "xerror" +else + echo "xok" +fi +EOF +) + + +# Test 003/a: Plain test +testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/b: Same as test003/a but replaces "$(" with "${" +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0" +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/d: Same as test003/a but uses extra subshell +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/e: Same as test003/b but uses extra subshell after "${ " +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + + +######################################################################## +#### test set 004: +# test pipe within ${... ; } command subtitution ending in a +# non-builtin command (therefore we use "/bin/cat" instead of "cat" below +# to force the use of the external "cat" command). ast-ksh.2009-01-20 +# had a bug which caused this test to fail. +testout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' ) +[[ "${testout}" == "hi" ]] || err_exit "test004: Expected 'hi', got '${testout}'" + + +######################################################################## +#### test set 005: +# Test whether the shell may hang in a +# 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)' +# Originally discovered with ast-ksh.2009-05-05 which hung in +# the "configure" script of postgresql-8.3.7.tar.gz (e.g. +# configure --enable-thread-safety --without-readline) +compound test5=( + compound -a testcases=( + # gsf's reduced testcase + ( name="test5_a" cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' ) + # gisburn's reduced testcase + ( name="test5_b" cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' ) + + ## The following tests do not trigger the problem but are included here for completeness + ## and to make sure we don't get other incarnations of the same problem later... + + # same as test5_a but uses ${ ... ; } instead of $(...) + ( name="test5_c" cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' ) + # same as test5_b but uses ${ ... ; } instead of $(...) + ( name="test5_d" cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' ) + # same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) + ( name="test5_e" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' ) + # same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) + ( name="test5_f" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' ) + ) +) + +maxwait=5 +for testid in "${!test5.testcases[@]}" ; do + nameref currtst=test5.testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + testout="$( < "${tmpfile}.out")" + rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed." + [[ "${testout}" == "done" ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh b/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh new file mode 100644 index 0000000000..3714227449 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh @@ -0,0 +1,215 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + + + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# name reference test #001 +# Note we run this test in a seperate shell to make sure the memory +# corruption originally reported can be reproduced (which precisely +# depends on ordering in the testcase) +( +cat <<EOF + function err_exit + { + print -u2 -n "\t" + print -u2 -r \${Command}[\$1]: "\${@:2}" + (( Errors++ )) + } + alias err_exit='err_exit \$LINENO' + + function function2 + { + nameref v=\$1 + + v.x=19 + v.y=20 + } + + function function1 + { + typeset compound_var=() + + function2 compound_var + + printf "x=%d, y=%d\n" compound_var.x compound_var.y + } + + x="\$(function1)" + + [[ "\$x" == 'x=19, y=20' ]] || err_exit "expected 'x=19, y=20', got '\${x}'" + +EOF +) | ${SHELL} +(( Errors+=$? )) + + +# +# name reference test #002 +# Originally derived from the xmldocumenttree1.sh demo which failed +# with ast-ksh.2009-04-15 since the nodepath+nodesnum nameref calls +# were removing the compound variable members nodes+nodesnum (caused +# by a scoping bug) +# +( +cat <<EOF + compound xdoc + compound -A xdoc.nodes + integer xdoc.nodesnum=0 + + function test1 + { + nameref doc=xdoc + nameref nodepath="doc.nodes" + nameref nodesnum="doc.nodesnum" + print -v doc + } + + test1 +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" + +(( ${ wc -l <<<"${out}" ; } == 4 )) || err_exit "Expected four lines of output, got ${out}" +(set -o errexit ; read -C tmp <<<"${out}" ; [[ "$(typeset +p tmp.nodes)" == *-A* ]]) || err_exit "missing variable tmp.nodes" +(set -o errexit ; read -C tmp <<<"${out}" ; [[ -v tmp.nodesnum ]]) || err_exit "missing variable tmp.nodesnum" + + +# +# name reference test #003a +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -A addrsp + + nameref sp=addrsp + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #003b +# (same as test #003a but uses a function) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -A addrsp + + function t1 + { + nameref sp=\$1 + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi + } + + t1 addrsp +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #004a +# (same as #003a but uses an indexed array instead of an associative one) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -a addrsp + + nameref sp=addrsp + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #004b +# (same as test #004a but uses a function) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -a addrsp + + function t1 + { + nameref sp=\$1 + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi + } + + t1 addrsp +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh b/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh index 18aed2aa7a..52bc5dca82 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh @@ -20,20 +20,25 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' -typeset -C bracketstat=( +# "nounset" disabled for now +#set -o nounset +Command=${0##*/} +integer Errors=0 + +compound bracketstat=( integer bopen=0 integer bclose=0 ) @@ -57,7 +62,45 @@ function count_brackets return 0 } -integer Errors=0 +# compound variable "cat" nr.1, using $ print "%B\n" ... # +function cpvcat1 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf "%B\n" tmp ; done + return 0 +} + +# compound variable "cat" nr.2, using $ print "%#B\n" ... # +function cpvcat2 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf "%#B\n" tmp ; done + return 0 +} + +# compound variable "cat" nr.3, using $ print -C ... # +function cpvcat3 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -C tmp ; done + return 0 +} + +# compound variable "cat" nr.4, using $ print -v ... # +function cpvcat4 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -v tmp ; done + return 0 +} typeset s @@ -71,7 +114,7 @@ typeset s # -- snip -- # (additionally we test some extra stuff like bracket count) s=${ - typeset -C x=( + compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) @@ -88,7 +131,7 @@ s=${ integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -96,13 +139,19 @@ s=${ [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) { printf "%B\n" x print "hello" - } | { + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { read -C y read s } @@ -111,6 +160,8 @@ s=${ [[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}" count_brackets "$y" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" # cleanup unset x y || err_exit "unset failed" @@ -128,11 +179,11 @@ unset x y || err_exit "unset failed" # <compound var> # -- snip -- s=${ - typeset -C x=( + compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) - typeset -A myarray3=( + compound -A myarray3=( [a]=( float m1=0.5 float m2=0.6 @@ -145,7 +196,7 @@ s=${ integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -153,6 +204,12 @@ s=${ [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) @@ -160,7 +217,7 @@ s=${ printf "%B\n" x print "hello" printf "%B\n" x - } | { + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { read -C y1 read s read -C y2 @@ -170,10 +227,22 @@ s=${ } || err_exit "test returned exit code $?" [[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}." +[[ "${y1.myarray3[b].foo}" == "bar" ]] || err_exit "y1.myarray3[b].foo != bar" +[[ "${y2.myarray3[b].foo}" == "bar" ]] || err_exit "y2.myarray3[b].foo != bar" [[ "$y1" != "" ]] || err_exit "y1 is empty" [[ "$y2" != "" ]] || err_exit "y2 is empty" +(( ${#y1.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y1.myarray3[e].nested_cpv, got ${#y1.myarray3[e].nested_cpv[@]}" +(( ${#y2.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y2.myarray3[e].nested_cpv, got ${#y2.myarray3[e].nested_cpv[@]}" +(( isnan(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not a NaN" +(( isnan(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not a NaN" +(( signbit(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not negative" +(( signbit(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not negative" count_brackets "$y1" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" count_brackets "$y2" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" [[ "$y1" == "$y2" ]] || err_exit "Expected $(printf "%q\n" "${y1}") == $(printf "%q\n" "${y2}")." [[ "$x" == "$y1" ]] || err_exit "Expected $(printf "%q\n" "${x}") == $(printf "%q\n" "${y}")." @@ -185,11 +254,11 @@ unset x y1 y2 || err_exit "unset failed" # Test 3: Test compound variable copy operator vs. "read -C" -typeset -C x=( +compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) - typeset -A myarray3=( + compound -A myarray3=( [a]=( float m1=0.5 float m2=0.6 @@ -202,7 +271,7 @@ typeset -C x=( integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -210,27 +279,41 @@ typeset -C x=( [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) -typeset -C x_copy=x || err_exit "x_copy copy failed" +compound x_copy=x || err_exit "x_copy copy failed" [[ "${x_copy}" != "" ]] || err_exit "x_copy should not be empty" count_brackets "${x_copy}" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" -typeset -C nested_cpv_copy +compound nested_cpv_copy nested_cpv_copy=x.myarray3[e].nested_cpv || err_exit "x.myarray3[e].nested_cpv copy failed" +(( ${#nested_cpv_copy.myarray[@]} == 10 )) || err_exit "Expected 10 elements in nested_cpv_copy.myarray, got ${#nested_cpv_copy.myarray[@]}" # unset branch "x.myarray3[e].nested_cpv" of the variable tree "x" ... unset x.myarray3[e].nested_cpv || err_exit "unset x.myarray3[e].nested_cpv failed" [[ "${x.myarray3[e].nested_cpv}" == "" ]] || err_exit "x.myarray3[e].nested_cpv still has a value" # ... and restore it from the saved copy -printf "%B\n" nested_cpv_copy | read -C x.myarray3[e].nested_cpv || err_exit "read failed" +printf "%B\n" nested_cpv_copy | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | read -C x.myarray3[e].nested_cpv || err_exit "read failed" # compare copy of the original tree and the modified one [[ "${x}" == "${x_copy}" ]] || err_exit "x != x_copy" count_brackets "${x}" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +(( ${#x.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in x.myarray3[e].nested_cpv, got ${#x.myarray3[e].nested_cpv[@]}" +(( isnan(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not a NaN" +(( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative" # cleanup unset x x_copy nested_cpv_copy || err_exit "unset failed" @@ -238,14 +321,15 @@ unset x x_copy nested_cpv_copy || err_exit "unset failed" # Test 4: Test "read -C" failure for missing bracket at the end typeset s -s=$($SHELL -c 'typeset -C myvar ; print "( unfinished=1" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" +s=$($SHELL -c 'compound myvar ; print "( unfinished=1" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" [[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}" # Test 5: Test "read -C" failure for missing bracket at the beginning typeset s -s=$($SHELL -c 'typeset -C myvar ; print " unfinished=1 )" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" +s=$($SHELL -c 'compound myvar ; print " unfinished=1 )" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" [[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh index 335470aa79..27cac4aa88 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -46,6 +46,7 @@ # -- snip -- # +# test setup function err_exit { print -u2 -n "\t" @@ -54,15 +55,16 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} +integer Errors=0 + function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } -Command=${0##*/} -integer Errors=0 - integer childpid typeset testdir integer childretval @@ -208,5 +210,6 @@ childretval=$? cd /tmp rmdir "${testdir}" || err_exit "Could not remove temporary test directory ${testdir}" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh index 4f03984951..28a84caff1 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -51,17 +51,20 @@ # ... provides the correct output. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset var1 var2 # use unset, l=() compound syntax and print @@ -75,13 +78,13 @@ var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l' [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and print -var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and print -var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # use unset, l=() compound syntax and printf "%B\n" @@ -95,14 +98,15 @@ var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l) ; print [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and printf "%B\n" -var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and printf "%B\n" -var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh index 333f5cc1a0..793d53d20d 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -40,17 +40,20 @@ # -- snip -- # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + ## ## test one: ## @@ -115,5 +118,6 @@ print "done" (( count=$(fgrep "got_child" <<< "$s" | wc -l) )) || err_exit "counting failed." (( count == 3 )) || err_exit "Expected count==3, got count==${count}." + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh index c755f86c87..fa016f4c67 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -40,17 +40,20 @@ # -- snip -- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + # # test set 1: Simple umask in subshell # @@ -93,5 +96,6 @@ x=$(${SHELL} -c 'umask 0; ( umask 20); umask') || err_exit "shell y=$(${SHELL} -c 'umask 0; (ulimit -c 0 ; umask 20); umask') || err_exit "shell failed." [[ "$x" == "$y" ]] || err_exit "$x != $y" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh index d4bd345833..6b0092d5ba 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -45,17 +45,20 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset s # test using "echo" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh index f3ffae5e84..bc3426f063 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -63,17 +63,20 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset testtmpdir=/tmp/ksh93_test_cr_6763594_${PPID}_$$ mkdir "${testtmpdir}" || { err_exit "Could not create temporary directory ${testtmpdir}." ; exit ${Errors} ; } @@ -90,6 +93,7 @@ s=$( < out_stderr ) ; [[ "$s" == ~(Elr)(.*:\ \./myfoo:\ \./myfoo:\ .*\[.*\]) ]] rm "myfoo" "out_stdout" "out_stderr" || err_exit "rm failed." cd .. rmdir "${testtmpdir}" || err_exit "Failed to remove temporary directory ${testtmpdir}." - + + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh index fc83db0e8a..7463baea5a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -70,15 +70,17 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 @@ -168,5 +170,6 @@ while (( $# >= 13 )) ; do done done + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh new file mode 100644 index 0000000000..7f76862bdd --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh @@ -0,0 +1,124 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 supports more than 256 recursive +# function+command substitution calls. +# +# This was reported as CR #6769332 ('Recursive function+command +# substitutions terminate shell after 257 iterations'): +# ------------ snip ------------ +# Recursive function+command substitutions +# (e.g. func1() { x=$( func2 ) ; } ; x=$( func1 ) ) terminate the +# ksh93 shell after 257 iterations with a exit code of "0" (it +# seems the shell just "quits" after the last "return 0" statement +# in the function). +# Running the attached testcase terminates the shell after 257 +# iterations (g=257 in the script) while 256 iterations (replace +# "257" with "256" in the script) just works fine. +# The same testcase works Ok in ksh88 (=/usr/bin/ksh in +# Solaris 10U5) +# +# Expected Result +# The script should output "done" and return the exit code 0. +# +# Actual Result +# No messsge. Exit code "0". +# +# Error Message(s) +# None (exit code is "0"). +# +# Test Case +# f1() +# { +# h=$1 +# (( h=h-1 )) +# (( h <= 0 )) && return 0 +# x=$(f1 "$h" "$l" "$g" d e "$l") || print -u2 "$g/$h: fail" +# return 0 +# } +# l="" +# g=257 +# i=0 +# while (( i < $g )) ; do +# l="${l}x" +# (( i=i+1 )) +# done +# f1 "$g" "$l" "$g" d e "$l" || print -u2 "$g: fail0" +# print "done" +# exit 0 +# +# Workaround +# - +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# test1: Testcase from CR #6769332 +# +( +cat <<EOF +# make sure we have enougth stack (needed for 64bit SPARC and SystemZ) +ulimit -s 65536 + +f1() +{ + h=\$1 + (( h=h-1 )) + (( h <= 0 )) && return 0 + x=\$(f1 "\$h" "\$l" "\$g" d e "\$l") || print -u2 "\$g/\$h: fail" + return 0 +} +l="" +g=257 +i=0 +while (( i < \$g )) ; do + l="\${l}x" + (( i=i+1 )) +done +f1 "\$g" "\$l" "\$g" d e "\$l" || print -u2 "\$g: fail0" +print "done" +EOF +) | out="$( ${SHELL} 2>&1 ; )" || err_exit "Shell returned non-zero exit code $?." + +[[ "${out}" == "done" ]] || err_exit "Output expected to be 'done', got '${out}'." + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh new file mode 100644 index 0000000000..2dd0fc997f --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh @@ -0,0 +1,95 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether the arithmetric function "iszero" is available. +# +# This was reported as CR #6777491 ("*ksh93* lacks arithmetric function +# iszero()"): +# ------------ snip ------------ +# ksh93 lacks arithmetric function "iszero()" which limits the ability +# to classify floating-point values or even correctly match against +# zero (since IEEE754-1985/2008 floating-point math differs between +# positive and negaive zero values). +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# $ ksh93 -c '(( iszero(0) )) && print "0 is a zero"' +# Expected Result +# Output to stdout: +# -- snip -- +# 0 is a zero +# -- snip -- +# Actual Result +# ksh93 exists with: +# -- snip -- +# ksh93: iszero(0) : unknown function +# -- snip -- +# Error Message(s) +# ksh93: iszero(0) : unknown function +# Test Case +# ksh93 -c '(( iszero(0) )) && print "0 is a zero"' +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset str +integer i + +typeset -a tests=( + '(( iszero(0) )) && print "OK"' + '(( iszero(0.) )) && print "OK"' + '(( iszero(-0) )) && print "OK"' + '(( iszero(-0.) )) && print "OK"' + 'float n=0. ; (( iszero(n) )) && print "OK"' + 'float n=+0. ; (( iszero(n) )) && print "OK"' + 'float n=-0. ; (( iszero(n) )) && print "OK"' + 'float n=1. ; (( iszero(n) )) || print "OK"' + 'float n=1. ; (( iszero(n-1.) )) && print "OK"' + 'float n=-1. ; (( iszero(n+1.) )) && print "OK"' +) + +for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + str="$( $SHELL -o errexit -c "${tests[i]}" 2>&1 )" || err_exit "test $i: returned non-zero exit code $?" + [[ "${str}" == "OK" ]] || err_exit "test $i: expected 'OK', got '${str}'" +done + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh new file mode 100644 index 0000000000..24f99cb581 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh @@ -0,0 +1,83 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 supports traps for the SIGTHAW +# signal. +# +# This was reported as CR #6778077 ("*ksh93* does not understand "THAW" +# as a signal for use with trap"): +# -- snip -- +# While ksh93 understand THAW in the list of signals for kill it does +# not understand it for "trap' +# +# : pod5.eu TS 6 $; kill -l | egrep '(THAW|FREEZE)' +# FREEZE +# THAW +# : pod5.eu TS 7 $; trap "echo THAW" THAW +# ksh93: trap: THAW: bad trap +# : pod5.eu TS 8 $; +# +# Using the signal number (35) works around this. +# -- snip -- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +## test one: Check whether the shell supports SIGTHAW as trap +${SHELL} -o errexit -c 'trap "true" SIGTHAW ; true' || err_exit "SIGTHAW not supported." +${SHELL} -o errexit -c 'trap "true" THAW ; true' || err_exit "THAW not supported." +${SHELL} -o errexit -c 'trap "true" 35 ; true' || err_exit "signal 35 not supported." + + +## test two: Check whether the shell supports SIGFREEZE as trap +## (we check this since it is SIGTHAW's counterpart) +${SHELL} -o errexit -c 'trap "true" SIGFREEZE ; true' || err_exit "SIGFREEZE not supported." +${SHELL} -o errexit -c 'trap "true" FREEZE ; true' || err_exit "FREEZE not supported." +${SHELL} -o errexit -c 'trap "true" 34 ; true' || err_exit "signal 34 not supported." + + +## test three: Check all other signals listed by "kill -l" +kill -l | while read i ; do + str="$( ${SHELL} -c "trap true $i ; print 'ok'" 2>&1 )" || err_exit "shell returned code $? for trap $i" + [[ "${str}" == "ok" ]] || err_exit "expected 'ok', got $str" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh new file mode 100644 index 0000000000..69159a9f76 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh @@ -0,0 +1,130 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly supports +# negative zero values +# +# This was reported as CR #6789247 ("libast/ksh93 1-digit hexfloat base conversion rounds incorrectly"): +# ---- snip ---- +# Description +# [The same issue was described in http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2008-December/006737.html] +# This is basically a spin-off of http://bugs.opensolaris.org/view_bug.do?bug_id=6773712 ("1-digit hex fp +# base conversion of long double rounds incorrectly"). +# The bug description for Solaris libc says this: +# > The first line of output from this program is correct. The second line +# > is not. +# > +# > leviathan% cat a.c +# > #include <stdio.h> +# > +# > int main() +# > { +# > printf("%.0a\n", 1.5); +# > printf("%.0La\n", 1.5L); +# > return 0; +# > } +# > leviathan% cc -o a a.c +# > leviathan% a +# > 0x1p+1 +# > 0x1p+0 +# > leviathan% +# If I compile the testcase with libast on Solaris 11/B84 SPARC (which +# matches ast-open.2008-11-04) I get this: +# -- snip -- +# $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && +# ./a +# 0x1p+00 +# 0x1p+00 +# -- snip -- +# ... which seems to be incorrect per the bugs comment above and should +# be: +# -- snip -- +# 0x1p+1 +# 0x1p+1 +# -- snip -- +# ksh93 has the same problem: +# $ ksh93 -c 'float r=1.5 ; printf "%.0a\n" r' +# 0x1p+00 +# Steps to Reproduce +# Compile and run testcase like this: +# -- snip -- +# $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && +# ./a +# -- snip -- +# Expected Result +# 0x1p+1 +# 0x1p+1 +# Actual Result +# 0x1p+00 +# 0x1p+00 +# ---- snip ---- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +float r +float result +typeset str + +# Test #001/a - check whether the result of a rounded 1.5 is 2.0 +r=1.5 +result=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" +(( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" + + +# Test #001/b - same as test #001/a but uses "%.0A\n" instead of "%.0a\n" +r=1.5 +result=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" +(( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" + + +# Test #002/a - check whether the hexfloat string value matches the expected pattern +r=1.5 +str=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" +[[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" + + +# Test #002/b - same as test #002/a but uses "%.0A\n" instead of "%.0a\n" +r=1.5 +str=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" +[[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh index 396095ee63..de745b8a3a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh @@ -35,7 +35,8 @@ # # and here's where it's hung: # ---8<--- -# xxxxx@xxxxx $ pstack 204600 +# Edward Pilatowicz <edward.pilatowicz@sun.com> +# $ pstack 204600 # 204600: /bin/ksh /opt/onbld/bin/Install -o debug -k i86xpv -T domu-219:/tmp # fffffd7fff2e3d1a write (1, 4154c0, 64) # fffffd7ffefdafc8 sfwr () + 2d0 @@ -70,68 +71,142 @@ # # as it turns out, i can easily reproduce this problem as follows: # ---8<--- -# xxxxx@xxxxx $ ksh93 -# xxxxx@xxxxx $ set -- `cat /etc/termcap | sort | uniq` +# $ ksh93 +# $ set -- `cat /etc/termcap | sort | uniq` # <hang> # ---8<--- # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 -integer i j d +# common functions/variables +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} +integer testfilesize i maxwait typeset tmpfile +integer testid + # test 1: run loop and check various temp filesizes tmpfile="$(mktemp "/tmp/sun_solaris_cr_6800929_large_command_substitution_hang.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." -for (( i=1*1024 ; i <= 512*1024 ; i*=2 )) ; do +compound -a testcases=( + # test 1a: Run test child for $(...) + # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) + ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1b: Same as test1a but uses ${... ; } instead if $(...) + ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1c: Same as test1a but does not use a pipe + ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1d: Same as test1a but does not use a pipe + ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + + # test 1e: Same as test1a but uses an external "cat" command + ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1f: Same as test1a but uses an external "cat" command + ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1g: Same as test1a but uses an external "cat" command + ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1h: Same as test1a but uses an external "cat" command + ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) +) + +for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do # Create temp file { - for ((j=0 ; j < i ; j+=16 )) ; do - print "0123456789abcde" + for (( i=0 ; i < testfilesize ; i+=64 )) ; do + print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" done } >"${tmpfile}" - - # Run test child - ${SHELL} -c "builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" >/dev/null & - (( childpid=$! )) # wait up to log2(i) seconds for the child to terminate # (this is 10 seconds for 1KB and 19 seconds for 512KB) - (( d=log2(i) )) - for (( j=0 ; j < d ; j++ )) ; do - kill -0 ${childpid} 2>/dev/null || break - sleep 0.5 + (( maxwait=log2(testfilesize) )) + + for testid in "${!testcases[@]}" ; do + nameref currtst=testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + # compare input/output + cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." + rm "${tmpfile}.out" done - if kill -0 ${childpid} 2>/dev/null ; then - err_exit "test1: child (pid=${childpid}) still busy, filesize=${i}." - kill -KILL ${childpid} 2>/dev/null - fi - wait # wait for child (and/or avoid zombies/slime) + # Cleanup rm "${tmpfile}" done -# test 2: Edward's Solaris-specific testcase -${SHELL} -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & +# test 2a: Edward Pilatowicz <edward.pilatowicz@sun.com>'s Solaris-specific testcase +${SHELL} -o errexit -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & (( childpid=$! )) sleep 5 -if kill -0 ${childpid} 2>/dev/null ; then - err_exit "test2: child (pid=${childpid}) still busy." +if isvalidpid ${childpid} ; then + err_exit "test2a: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi -wait # wait for child (and/or avoid zombies/slime) +wait || err_exit "test2a: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2b: Same as test 2a but uses ${... ; } instead of $(...) +${SHELL} -o errexit -c 'builtin uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2b: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2b: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2c: Same as test 2a but makes sure that "uniq" is not a builtin +${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2c: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2c: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2d: Same as test 2c but uses ${... ; } instead of $(...) +${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2d: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2d: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh new file mode 100644 index 0000000000..4f774b2f8b --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh @@ -0,0 +1,152 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether "typeset -m" correctly moves local variables +# into a global variable tree. +# +# This was reported as CR #6805792 ("XXXX"): +# -------- snip -------- +# The following attempt to move a local node into an associative array +# fails like this: +# -- snip -- +# typeset -C tree +# function f1 +# { +# nameref tr=$1 +# +# typeset -A tr.subtree +# +# typeset -C node +# +# node.one="hello" +# node.two="world" +# +# # move local note into the array +# typeset -m tr.subtree["a_node"]=node +# +# return 0 +# } +# f1 tree +# printf "%B\n" tree +# print "ok" +# exit 0 +# -- snip -- +# The output looks like this: +# -- snip -- +# $ ksh93 +# varmovetest1.sh +# ( +# ( +# ) +# ok +# -- snip -- +# ... but AFAIK it should print: +# -- snip -- +# ( +# typeset -A subtree=( +# [a_node]=( +# one=hello +# two=world +# ) +# ) +# ) +# ok +# -- snip -- +# -------- snip -------- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +## test start +compound tree1 tree2 + +# add node to tree which uses "typeset -m" to move a local variable +# into tree1.subtree["a_node"] +function f1 +{ + nameref tr=$1 + + typeset -A tr.subtree + + compound node + + node.one="dummy1" + node.two="dummy2" + + # We use the nameref's here since ast-ksh,2008-12-12 crashes + # when this function returns because "nodeone" and "nodetwo" + # still reference "node" which was renamed. + # (note that "f1" must be first function and the first being + # called, otherwise the crash will not occur) + nameref nodeone=node.one + nameref nodetwo=node.two + nodeone="hello" + nodetwo="world" + + # move local note into the array + typeset -m tr.subtree["a_node"]=node + + return 0 +} + +# Alternative version which uses "nameref" instead of "typeset -m" +function f2 +{ + nameref tr=$1 + + typeset -A tr.subtree + + nameref node=tr.subtree["a_node"] + + node.one="hello" + node.two="world" + + return 0 +} + +f1 tree1 +f2 tree2 + +[[ "${tree1.subtree["a_node"].one}" == "hello" ]] || err_exit "Expected tree1.subtree[\"a_node\"].one == 'hello', got ${tree1.subtree["a_node"].one}" +[[ "${tree1.subtree["a_node"].two}" == "world" ]] || err_exit "Expected tree1.subtree[\"a_node\"].two == 'world', got ${tree1.subtree["a_node"].two}" +[[ "${tree1}" == "${tree2}" ]] || err_exit "tree1 and tree2 differ:"$'\n'"$(diff -u <( printf '%B\n' tree1 ) <( printf '%B\n' tree2 ) )" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh new file mode 100644 index 0000000000..bbcb9b168d --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh @@ -0,0 +1,106 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric operator '<character> +# is working +# +# This was reported as CR #6805794 ('[ku1] printf returns "invalid character constant" for $ printf "%d\n" "'<euro>"'): +# ------------ snip ------------ +# There seems be a bug in how ast-ksh.2008-11-04's "printf" builtin +# handles multibyte characters. For example if I try this in the +# en_US.UTF-8 locale ("<euro>" needs to be replace with the EURO symbol): +# -- snip -- +# $ printf "%d\n" "'<euro>" +# -ksh93: printf: warning: ': invalid character constant +# 226 +# -- snip -- +# AFAIK the correct behaviour was to return the numeric value of the +# <euro> symbol in this case (hexadecimal "20ac", decimal 8364), e.g. +# -- snip -- +# $ printf "%d\n" +# "'<euro>" +# 8364 +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# Enter this in an interractive shell: +# $ printf "%d\n" "'<euro>" +# Expected Result +# -- snip -- +# $ printf "%d\n" +# "'<euro>" +# 8364 +# -- snip -- +# Actual Result +# -- snip -- +# $ printf "%d\n" "'<euro>" +# -ksh93: printf: warning: ': invalid character constant +# 226 +# -- snip -- +# Error Message(s) +# printf: warning: ': invalid character constant +# Test Case +# printf "%d\n" "'<euro>" +# Workaround +# None. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# declare variables +typeset str + +# test whether the locale uses an UTF-8 (-like) encoding and override it on demand +[[ "$(printf "\u[20ac]")" == $'\342\202\254' ]] || LC_ALL=en_US.UTF-8 +if [[ "$(printf "\u[20ac]")" != $'\342\202\254' ]] ; then + err_exit "Local overrride failed." + exit $((Errors)) +fi + +# run test +str=$(print $'printf "%d\\\\n" "\'\342\202\254"' | source /dev/stdin) +[[ "${str}" == "8364" ]] || err_exit "expected 8364, got ${str}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh new file mode 100644 index 0000000000..1dccc97505 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh @@ -0,0 +1,170 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly supports +# negative zero values +# +# This was reported as CR #6805795 ("[ku1] ksh93 does not differ between -0 and +0"): +# ------------ snip ------------ +# Original bug report was: +# ------ snip ------ +# Is there a reason why ksh93 does not display the negative sign for the +# value zero ? For example if I have use the C99 function "copysign" +# (copies absolute value of operant a and sign of operant b) I get this +# for { a=5, b=-0 }: +# -- snip -- +# $ ksh93 -c 'float x; (( x=copysign(5, -0) )) ; printf "%f\n" +# x' +# -5.000000 +# -- snip -- +# Now if I swap operands a and b I get this result: +# -- snip -- +# $ ksh93 -c 'float x; (( x=copysign(0, -5) )) ; printf "%f\n" x' +# 0.000000 +# -- snip -- +# AFAIK this result should be "-0.000000" ... or not ? +# BTW: Parsing of "-0" doesn't seem to work either, e.g. +# -- snip -- +# $ ksh93 -c 'float x a=-1 b=-0; (( x=copysign(a, b) )) ; printf "%f\n" +# x' +# 1.000000 +# -- snip -- +# ... while AFAIK it should be "-1.000000" since the 2nd operand of +# "copysign" defines the sign of the result. +# ------ snip ------ +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset str + +# test 1: test "copysign()" using constant values +str=$( + set -o errexit + + print -- $(( copysign(0, -5) )) + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected copysign(0, -5) == -0, got ${str}" + + +# test 2: Same as test 1 but using variables for the values +str=$( + set -o errexit + + float a + float b + float c + + a=0. + b=-5. + + (( c=copysign(a, b) )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" + + +# test 3: test "signbit()" +str=$( + set -o errexit + + float a + + a=-0. + + print -- $(( signbit(a) )) + ) || err_exit "test failed." +[[ "${str}" == "1" ]] || err_exit "Expected signbit(a, b) == 1, got ${str}" + + +# test 4: test "signbit()" +str=$( + set -o errexit + + float a + float c + + a=-0. + + (( c=signbit(a) )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "1" ]] || err_exit "Expected c == 1, got ${str}" + + +# test 5: test whether "typeset -X" (C99 "hexfloat") correctly recognizes +# negative zero assigned from a "float" +str=$( + set -o errexit + + float a # float + typeset -X c # hexfloat + + a=-0. + + # copy value from "float" to "hexfloat" + (( c=a )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == -0x* ]] || err_exit "Expected c == -0x*, got ${str}" + + +# test 6: Reverse of test 5: Test whether "float" correctly recognizes +# a C99 "hexfloat" value +str=$( + set -o errexit + + typeset -X a # hexfloat + float c # float + + a=-0x0.0000000000000000000000000000p+00 + + # copy value from "hexfloat" to "float" + (( c=a )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh new file mode 100644 index 0000000000..dc91bbeb82 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh @@ -0,0 +1,139 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93's builtin "cat" command properly +# supports the "-n" option. +# +# This was reported as CR #6835835 ('ksh93 "cat" builtin does not handle "-n" correctly'): +# ------------ snip ------------ +# [Originally reported in +# http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html +# by Casper Dik] +# -- snip -- +# I just noticed this in ksh93: +# ksh93 -c 'yes "" | head -5|cat -n' +# 1 +# 2 +# 3 +# 4 +# (I used this for older shells when I want to a list of all integers from 1 +# to a particular number) +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# Execute $ ksh93 -c 'yes "" | head -5|cat -n' # +# Expected Result +# 1 +# 2 +# 3 +# 4 +# 5 +# Actual Result +# +# +# 1 +# 2 +# +# 3 +# +# 4 +# Error Message(s) +# None. +# Test Case +# See description. +# Workaround +# Disable ksh93's builtin "cat" command either via using an absolute path +# to the "cat" command (POSIX-style workaround) or using ksh93's +# "builtin" command to remove "cat" from the list of builtin +# commands (e.g. $ builtin -d /bin/cat /usr/bin/cat #). +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# test 1: Compare output of various "cat -n" combinations +# +integer i +typeset expected_output +typeset out + +expected_output=$( ${SHELL} -c 'for ((i=1 ; i <= 12 ; i++ )) ; do printf "%6d\t\n" i ; done' ) + +compound -a testcases=( + # note: we have to add an extra /usr/bin/cat at the end of the pipe to make + # sure the "cat" builtin uses the correct buffering mode to trigger + # the error and a "true" to make sure the "cat" command isn't the last command + # of the shell + ( name="test1a" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n | /usr/bin/cat ; true' ) + # same as "test1a" but uses external "cat" command + ( name="test1b" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /usr/bin/cat -n | /usr/bin/cat ; true' ) + + # same as "test1a" but without the last /usr/bin/cat in the pipe + ( name="test1c" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n ; true' ) + # same as "test1b" but without the last /usr/bin/cat in the pipe + ( name="test1d" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /usr/bin/cat -n ; true' ) +) + +for testid in "${!testcases[@]}" ; do + nameref tc=testcases[${testid}] + + out="$( ${SHELL} -o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" + [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" + + out="$( ${SHELL} +o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" + [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" +done + + +# +# test 2: Casper Dik's original testcase +# from http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html +# + +cmp -s \ + <( ${SHELL} -c 'yes "" | head -5 | cat -n' ) \ + <( for ((i=1 ; i <= 5 ; i++ )) ; do printf "%6d\t\n" i ; done ) \ + || err_exit 'yes "" | head -5 | cat -n does not match expected output.' + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh new file mode 100644 index 0000000000..396816960a --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh @@ -0,0 +1,94 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 does not execute builtin command +# "foo" when referencing variable "foo" when the variable is not +# set (this applies to all builtin commands not bound to a +# specific PATH element, e.g. "test", "sleep", "print" etc.). +# +# This was reported as CR #6848486 ('"echo ${test}" with test +# undefined crashes the shell') +# ------------ snip ------------ +# This is an odd one: +# +# $ ksh93 --version +# version sh (AT&T Research) 93t 2008-11-04 +# $ ksh93 +# jl138328@gir:~$ echo $test +# +# jl138328@gir:~$ echo ${test} +# Segmentation Fault (core dumped) +# ------------ snip ------------ +# +# The bug originates from the ksh93 "type system" which allows +# an application to define it's own types in ksh93. In such cases +# the output of function "mytype.len" is used when type "mytype" +# has no member variable "len" (note it requires the use of +# ${foo} since the use of $foo does not allow "foo" to contain +# a dot in the variable name). +# The implementation in ast-ksh.2009-11-04 however does this +# for _all_ types of variables and not only for those which +# are a member of an application-defined type, therefore +# causing this bug. +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# Test 1: Test whether the shell crashes when looking for an empty +# "shell" variable. +# (note: return code 78 was just picked randomly) +$SHELL -c 'unset test ; print ${test} ; exit 78' >/dev/null 2>&1 +(( $? == 78 )) || err_exit "expected return code is 78, got $?" + + +# Test 2: Test whether the shell can reach a point (which prints +# "#mark") after the use of ${test} in the script. +out=$($SHELL -o errexit -c 'unset test ; print ${test} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." +[[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" + + +# Test 3: Check whether the use of ${sleep} returns nothing +# (ast-ksh.2008-11-04 will return the usage string of the sleep +# builtin) +out=$($SHELL -o errexit -c 'print ${sleep} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." +[[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh new file mode 100644 index 0000000000..22de05b56c --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh @@ -0,0 +1,145 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly +# converts a IEEE 754-2008 floating-point value to the C99 hexfloat format +# and back _without_ using digits. +# +# This was reported as CR #6855875 ("typeset -X x ; print $x # does not +# print sufficient digits to restore value"): +# ------------ snip ------------ +# $ typeset -X varname # was added to ksh93 to get a reliable way +# (using the C99 "hexfloat" format (see printf(3c)'s "%a" format)) to +# serialise a IEEE754-2008 floating-point value to a string and later feed +# it back into a application _without_ loosing any precision (normal +# base10 floating-point values (e.g. used by $ typeset -E/-F-G #) cause +# rounding errors since IEEE754-2008 |long double| uses base2). +# However $ typeset -l -X x ; ... ; print $x # currently does not print +# sufficient number of digits to restore the full |long double| value as +# expected, instead some digits are missing, resulting in an unwanted +# rounding. +# Example: +# -- snip -- +# $ ksh93 -c 'typeset -l -X y y_ascii; (( y=sin(90) )) ; y_ascii=$y ; (( y +# == y_ascii )) || print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf +# "%a\n" y_ascii)"' +# no match, +# 0x1.c9b9ee41cb8665c7890a136ace6bp-01 +# != +# 0x1.c9b9ee41cc000000000000000000p-01 +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# [See description] +# Expected Result +# [See description] +# Actual Result +# [See description] +# Error Message(s) +# - +# Test Case +# typeset -l -X y y_ascii +# (( y=sin(90) )) +# y_ascii=$y # convert y to string and store it in "y_ascii" +# if (( y == y_ascii )) ; then +# print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" +# y_ascii)" +# fi +# Workaround +# 1. Manually increase the number of digits via typeset +# -X<numdigits> +# OR +# 2. Use $ printf "%a" varname # +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# declare variables +typeset str +integer i +float x +float -a test_values + +typeset -l -X y # hexfloat +typeset -l -E y_restored1 +typeset -l -F y_restored2 +typeset -l -X y_restored3 + + +# create array of test values +for (( x=-181. ; x < 361. ; x+=.1 )) ; do + test_values+=( x ) +done +test_values+=( 0 -0 +0 ) # (nan -nan inf -inf) are excluded since nan!=nan is always "true" + + +# run the tests +for (( i=0 ; i < ${#test_values[@]} ; i++ )) ; do + (( y=sin(test_values[i]) )) + + # convert floating-point value to string (using the hexfloat format) and store it in "str" + str="${y}" + + # convert it back (via string assignment) + y_restored1="${str}" + y_restored2="${str}" + y_restored3="${str}" + (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" + (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" + (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" + + # convert it back (using arithmetric expression) + (( y_restored1=str )) + (( y_restored2=str )) + (( y_restored3=str )) + (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" + (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" + (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" + + # we exit if we get more than 8 errors (126 would be the maximum) + (( Errors > 8 )) && exit $((Errors)) +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh new file mode 100644 index 0000000000..568b43f35d --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh @@ -0,0 +1,111 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether the Solaris kernel can directly execute compiled +# shell code. +# +# This was reported as CR #6862121 ("shbinexec kernel module defunct"): +# ------------ snip ------------ +# [Originally reported by Sun Japan] +# The new shbinexec kernel module added in B106 is defunct, originally +# caused by my mismerge of the original development tree and later +# because the matching test module didn't test it correctly (April +# quickly discovered the problem but the issue drowned in the cleanup +# putbacks ). +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# $ cat test1.sh +# print hello +# printf "args=%s\n" "$@" +# $ shcomp test1.sh test1 +# # note: this MUST be bash since ksh93 has special support for compiled shell +# # scripts which causes the kernel module to be bypassed (that's why the tes +# # never worked) +# $ bash -c './test1 "a b" "c" "d"' +# Expected Result +# hello +# args=a a1 +# args=b +# args=c +# Actual Result +# ./test1: line 1: a: not found +# Error Message(s) +# ./test1: line 1: a: not found +# Test Case +# See above. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset ocwd +typeset tmpdir +typeset out + +# create temporary test directory +ocwd="$PWD" +tmpdir="$(mktemp -d "test_sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.XXXXXXXX")" || err_exit "Cannot create temporary directory" + +cd "${tmpdir}" || err_exit "cd ${tmpdir} failed." + + +# run tests +{ +cat <<EOF + print hello + printf "args=%s\n" "\$@" +EOF +} >script1.sh + +# Compile script (note we use the platform's /usr/bin/shcomp, _not_ ${SHCOMP}) +/usr/bin/shcomp "script1.sh" "script1" || err_exit "shcomp failed with error=$?" + +[[ -x "./script1" ]] || err_exit "Script script1 not executable" +out="$(/usr/bin/bash -c './script1 a b "c d"' 2>&1 )" || err_exit "Compiled script failed to execute, error=$?" +[[ "${out}" == $'hello\nargs=a\nargs=b\nargs=c d' ]] || err_exit "Expected xxx, got $(printf "%q\n" "$out")" + +# cleanup +rm "script1" "script1.sh" +cd "${ocwd}" +rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh new file mode 100644 index 0000000000..a5aae41ce5 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh @@ -0,0 +1,82 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether a background process called in a subshell can +# cause it to wait for the child process instead of exiting. +# +# This was reported as CR #6881017 ("Subshell doesn't exit, holds pipe +# open preventing callers from exiting"): +# ------------ snip ------------ +# The following scenario hangs with snv_122, 100% reproducible: +# +# Create a script hangit: +# ----- +# #!/bin/ksh +# ( sleep 100000 </dev/null >/dev/null 2>&1 & ) +# exit 0 +# ----- +# +# Run the following command: +# hangit | tee -a /tmp/log +# +# The hang can be eliminated either by removing the "exit 0" line (?!?), or by +# redirecting the subshell output to /dev/null. +# +# This is pretty nasty. I've whittled it down to this simple case but am seeing +# it in a much more subtle and complex environment where there are several +# intermediate calling scripts which have exited and eventually the parent pipes +# the output and hangs on the open pipe. It was hard to track down. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +float tstart tstop tdiff + +# run test with 10 second timeout +(( tstart=SECONDS )) +$SHELL -c '( sleep 10 </dev/null >/dev/null 2>&1 & ) ; exit 0' | cat >/dev/null +(( tstop=SECONDS )) + +# we remove two seconds below to make sure we don't run into issues +# with smaller xntpd adjustments +(( tdiff=tstop-tstart )) +(( tdiff < (10.-2.) )) || err_exit "test run needed ${tdiff} seconds to complete (instead of < 8.)" + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh b/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh index 2089ad184c..8e1e2ab937 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -38,6 +38,7 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset Command=${0##*/} integer Errors=0 @@ -56,6 +57,15 @@ export PATH=/usr/bin:/bin # work in compiled shell scripts) typeset -r getconf_test_functions="$( cat <<EOF +function err_exit +{ + print -u2 -n "\t" + print -u2 -r \${Command}[\$1]: "\${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit \$LINENO' +Command=\${0##*/} +integer Errors=0 # compare builtin getconf output with /usr/bin/getconf function compare_normal { @@ -63,13 +73,13 @@ function compare_normal /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) - t="${i%:*}" + t="\${i%:*}" - a="$(getconf "$t" 2>/dev/null)" - b="$(/usr/bin/getconf "$t" 2>/dev/null)" + a="\$(getconf "\$t" 2>/dev/null)" + b="\$(/usr/bin/getconf "\$t" 2>/dev/null)" - if [[ "$a" != "$b" ]] ; then - print -u2 "getconf/normal built mismatch: |$t|:|$a| != |$b|" + if [[ "\$a" != "\$b" ]] ; then + print -u2 "getconf/normal built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done @@ -82,13 +92,13 @@ function compare_path /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) - t="${i%:*}" + t="\${i%:*}" - a="$(getconf "$t" "/tmp" 2>/dev/null)" - b="$(/usr/bin/getconf "$t" "/tmp" 2>/dev/null)" + a="\$(getconf "\$t" "/tmp" 2>/dev/null)" + b="\$(/usr/bin/getconf "\$t" "/tmp" 2>/dev/null)" - if [[ "$a" != "$b" ]] ; then - print -u2 "getconf/path built mismatch: |$t|:|$a| != |$b|" + if [[ "\$a" != "\$b" ]] ; then + print -u2 "getconf/path built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done @@ -108,7 +118,7 @@ do export PATH="${i}" ## test whether the getconf builtin is available - if [[ "$(builtin | fgrep "/bin/getconf")" = "" ]] ; then + if [[ "$(builtin | fgrep "/bin/getconf")" == "" ]] ; then err_exit '/bin/getconf not found in the list of builtins.' fi @@ -161,5 +171,6 @@ do (( Errors+=$? )) done + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh b/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh index 30a2deb314..e95a502daf 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh @@ -28,17 +28,20 @@ # name reference test #001 # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + function function2 { nameref v=$1 @@ -60,5 +63,6 @@ x="$(function1)" [[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh b/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh index 9230c9925f..9f430d7c1c 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -45,8 +45,11 @@ function testfunc alias testfunc='testfunc $LINENO' alias err_exit='err_exit2 $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + # string testfunc '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh index 74783e6ff7..bf5257a78a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -50,15 +50,17 @@ # [14] main(argc = 2, argv = 0xffffffff7ffffa08), line 46 in "pmain.c" # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh index e233f596e3..c2ca8f5e5e 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -31,22 +31,24 @@ # and "unset" handling. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 # "built_tree1" and "built_tree2" are identical except the way how they test # whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content -# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +# - "built_tree2" uses "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", e.g. "unset" in a subshell. function build_tree1 { #set -o errexit -o xtrace @@ -113,7 +115,7 @@ function build_tree1 # whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content -# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +# - "built_tree2" uses "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", e.g. "unset" in a subshell. function build_tree2 { #set -o errexit -o xtrace @@ -144,12 +146,12 @@ function build_tree2 [[ "$c" == "" ]] && c='-' #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then - if ! (unset dest_tree.l1["$a"]) ; then + if ! ([[ -v dest_tree.l1["$a"] ]] ; res=$? ; unset dest_tree.l1["$a"] ; exit $res) ; then typeset -A dest_tree.l1["$a"].l2 fi #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then - if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + if ! ([[ -v dest_tree.l1["$a"].l2["$b"] ]] ; res=$? ; unset dest_tree.l1["$a"].l2["$b"] ; exit $res) ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3 fi @@ -301,43 +303,47 @@ function main #### test "unset" in a subshell - ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." - ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." # remove parent node (array element) and then check whether the child is gone, too: ( set -o errexit unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' - ! unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Global: Parent node removed (array element), child still exists" ( set -o errexit unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Local: Parent node removed (array element), child still exists" # remove parent node (array variable) and then check whether the child is gone, too: ( set -o errexit unset 'mytree_local1.l1[urw].l2' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Global: Parent node removed (array variable), child still exists" ( set -o errexit unset 'mytree_local1.l1[urw].l2' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Local: Parent node removed (array variable), child still exists" #### test "unset" and compare trees - unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + (( res == 0 )) || err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + (( res == 0 )) || err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." # Compare trees (after "unset") diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh index 89bc9e7541..1bab7006c3 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -31,15 +31,17 @@ # and "unset" handling. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 function example_tree diff --git a/usr/src/lib/libshell/common/tests/tilde.sh b/usr/src/lib/libshell/common/tests/tilde.sh index 60a2de0aa8..e22626f6df 100644 --- a/usr/src/lib/libshell/common/tests/tilde.sh +++ b/usr/src/lib/libshell/common/tests/tilde.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function home # id { typeset IFS=: pwd=/etc/passwd @@ -36,8 +42,6 @@ function home # id fi } -Command=${0##*/} -integer Errors=0 OLDPWD=/bin if [[ ~ != $HOME ]] then err_exit '~' not $HOME @@ -69,24 +73,23 @@ do h=$(home $u) if [[ $h != . ]] then [[ ~$u -ef $h ]] || err_exit "~$u not $h" x=~$u - [[ $x -ef $h ]] || "x=~$u not $h" + [[ $x -ef $h ]] || x="~$u not $h" break fi done -x=~%% -if [[ $x != '~%%' ]] -then err_exit 'x='~%%' not '~%% +x=~g.r.emlin +if [[ $x != '~g.r.emlin' ]] +then err_exit "x=~g.r.emlin failed -- expected '~g.r.emlin', got '$x'" fi x=~:~ if [[ $x != "$HOME:$HOME" ]] -then err_exit x=~:~ not $HOME:$HOME +then err_exit "x=~:~ failed, expected '$HOME:$HOME', got '$x'" fi HOME=/ [[ ~ == / ]] || err_exit '~ should be /' -trap 'rm -rf /tmp/kshtilde$$' EXIT [[ ~/foo == /foo ]] || err_exit '~/foo should be /foo when ~==/' -print $'print ~+\n[[ $1 ]] && $0' > /tmp/kshtilde$$ -chmod +x /tmp/kshtilde$$ +print $'print ~+\n[[ $1 ]] && $0' > $tmp/tilde +chmod +x $tmp/tilde nl=$'\n' -[[ $(/tmp/kshtilde$$ foo) == "$PWD$nl$PWD" ]] 2> /dev/null || err_exit 'tilde fails inside a script run by name' +[[ $($tmp/tilde foo) == "$PWD$nl$PWD" ]] 2> /dev/null || err_exit 'tilde fails inside a script run by name' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/timetype.sh b/usr/src/lib/libshell/common/tests/timetype.sh index c2046d5272..94b27843f1 100644 --- a/usr/src/lib/libshell/common/tests/timetype.sh +++ b/usr/src/lib/libshell/common/tests/timetype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/treemove.sh b/usr/src/lib/libshell/common/tests/treemove.sh new file mode 100644 index 0000000000..9e83e35e50 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/treemove.sh @@ -0,0 +1,85 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether "typeset -m" correctly moves local variables +# into a global variable tree. +# +# This was reported as CR #XXXXXXXX ("XXXX"): +# -- snip -- +#XXXX +# -- snip -- +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +## test start +typeset -C tree1 tree2 + +# add node to tree which uses "typeset -m" to move a local variable +# into tree1.subtree["a_node"] +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + # move local note into the array +false + typeset -m tr.subtree["a_node"]=node + return 0 +} + +# Alternative version which uses "nameref" instead of "typeset -m" +function f2 +{ + nameref tr=$1 + typeset -A tr.subtree + nameref node=tr.subtree["a_node"] + node.one="hello" + node.two="world" + return 0 +} + +f1 tree1 +f2 tree2 + +[[ "${tree1.subtree["a_node"].one}" == "hello" ]] || err_exit "expected tree1.subtree[\"a_node\"].one == 'hello', got ${tree1.subtree["a_node"].one}" +[[ "${tree1.subtree["a_node"].two}" == "world" ]] || err_exit "expected tree1.subtree[\"a_node\"].two == 'world', got ${tree1.subtree["a_node"].two}" +[[ "${tree1}" == "${tree2}" ]] || err_exit "tree1 and tree2 differ:$'\n'" + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/types.sh b/usr/src/lib/libshell/common/tests/types.sh index 24be9e9863..5904640e07 100644 --- a/usr/src/lib/libshell/common/tests/types.sh +++ b/usr/src/lib/libshell/common/tests/types.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + integer n=2 typeset -T Type_t=( @@ -109,14 +113,13 @@ x=(a b c) typeset -m x[1]=x[2] [[ ${x[1]} == c ]] || err_exit 'move an indexed array element fails' [[ ${x[2]} ]] && err_exit 'x[2] should be unset after move' -trap 'rm -f /tmp/kshtype$$' EXIT -cat > /tmp/kshtype$$ <<- \+++ +cat > $tmp/types <<- \+++ typeset -T Pt_t=(float x=1. y=0.) Pt_t p=(y=2) print -r -- ${p.y} +++ expected=2 -got=$(. /tmp/kshtype$$) 2>/dev/null +got=$(. $tmp/types) 2>/dev/null [[ "$got" == "$expected" ]] || err_exit "typedefs in dot script failed -- expected '$expected', got '$got'" typeset -T X_t=( typeset x=foo y=bar @@ -263,6 +266,114 @@ $SHELL > /dev/null <<- '+++++' || err_exit 'passing _ as nameref arg not workin function f { f1 _ ;} ) A_t a - [[ ${ a.f ./t1;} == "$a" ]] + [[ ${ a.f ./t1;} == "$a" ]] +++++ +expected='A_t b.a=(name=one;)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name=aha + ) + typeset -T B_t=( + typeset arr + A_t a + f() + { + _.a=(name=one) + typeset -p _.a + } + ) + B_t b + b.f ++++ +) == "$expected" ]] 2> /dev/null || err_exit '_.a=(name=one) not expanding correctly' +expected='A_t x=(name=xxx;)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name + ) + A_t x=(name="xxx") + typeset -p x ++++ +) == "$expected" ]] || err_exit 'empty field in definition does not expand correctly' + +typeset -T Foo_t=( + integer x=3 + integer y=4 + len() { print -r -- $(( sqrt(_.x**2 + _.y**2))) ;} +) +Foo_t foo +[[ ${foo.len} == 5 ]] || err_exit "discipline function len not working" + +typeset -T benchmark_t=( + integer num_iterations +) +function do_benchmarks +{ + nameref tst=b + integer num_iterations + (( num_iterations= int(tst.num_iterations * 1.0) )) + printf "%d\n" num_iterations +} +benchmark_t b=(num_iterations=5) +[[ $(do_benchmarks) == 5 ]] || err_exit 'scoping of nameref of type variables in arithmetic expressions not working' + +function cat_content +{ + cat <<- EOF + ( + foo_t -a foolist=( + ( val=3 ) + ( val=4 ) + ( val=5 ) + ) + ) + EOF + return 0 +} +typeset -T foo_t=( + integer val=-1 + function print + { + print -- ${_.val} + } +) +function do_something +{ + nameref li=$1 # "li" may be an index or associative array + li[2].print +} +cat_content | read -C x +[[ $(do_something x.foolist) == 5 ]] || err_exit 'subscripts not honored for arrays of type with disciplines' + +typeset -T benchcmd_t=( + float x=1 + float y=2 +) +unset x +compound x=( + float o + benchcmd_t -a m + integer h +) +expected=$'(\n\ttypeset -l -i h=0\n\tbenchcmd_t -a m\n\ttypeset -l -E o=0\n)' +[[ $x == "$expected" ]] || err_exit 'compound variable with array of types with no elements not working' + +expected=$'Std_file_t db.file[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)' +{ + got=$($SHELL <<- \EOF + MAGIC='stdinstall (at&t research) 2009-08-25' + typeset -T Std_file_t=( + typeset action + typeset -A sum + ) + typeset -T Std_t=( + typeset magic=$MAGIC + Std_file_t -A file + ) + Std_t db=(magic='stdinstall (at&t research) 2009-08-25';Std_file_t -A file=( [/./home/gsf/.env.sh]=(action=preserve;typeset -A sum=([9b67ab407d01a52b3e73e3945b9a3ee0]=1);)[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)[/home/gsf/.profile]=(action=preserve;typeset -A sum=([3ce23137335219672bf2865d003a098e]=1);));) + typeset -p db.file[/etc/profile] + EOF) +} 2> /dev/null +[[ $got == "$expected" ]] || err_exit 'types with arrays of types as members fails' + exit $Errors diff --git a/usr/src/lib/libshell/common/tests/variables.sh b/usr/src/lib/libshell/common/tests/variables.sh index 1808d2fbcf..f174a9a2bf 100644 --- a/usr/src/lib/libshell/common/tests/variables.sh +++ b/usr/src/lib/libshell/common/tests/variables.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,11 +28,14 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + [[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION' unset ss -[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' -[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' -[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' +[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' +[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' +[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' # RANDOM if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) then err_exit RANDOM variable not working @@ -57,17 +60,19 @@ fi #fi # PWD if [[ ! $PWD -ef . ]] -then err_exit PWD variable not working +then err_exit PWD variable failed, not equivalent to . fi # PPID -if [[ $($SHELL -c 'print $PPID') != $$ ]] -then err_exit PPID variable not working +exp=$$ +got=${ $SHELL -c 'print $PPID'; } +if [[ ${ $SHELL -c 'print $PPID'; } != $$ ]] +then err_exit "PPID variable failed -- expected '$exp', got '$got'" fi # OLDPWD old=$PWD cd / if [[ $OLDPWD != $old ]] -then err_exit OLDPWD variable not working +then err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'" fi cd $old || err_exit cd failed # REPLY @@ -90,7 +95,7 @@ LINENO=save+10 IFS=: x=a::b::c if [[ $x != a::b::c ]] -then err_exit "Word splitting on constants" +then err_exit "word splitting on constants" fi set -- $x if [[ $# != 5 ]] @@ -171,7 +176,7 @@ unset -n foo foo=junk function foo.get { - .sh.value=stuff + .sh.value=stuff unset -f foo.get } if [[ $foo != stuff ]] @@ -209,22 +214,19 @@ done kill $! unset x CDPATH=/ -x=$(cd tmp) -if [[ $x != /tmp ]] +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] then err_exit 'CDPATH does not display new directory' fi -mkdir /tmp/ksh$$ CDPATH=/: -x=$(cd /tmp;cd ksh$$) +x=$(cd ${tmp%/*}; cd ${tmp##*/}) if [[ $x ]] then err_exit 'CDPATH displays new directory when not used' fi -x=$(cd tmp/ksh$$) -if [[ $x != /tmp/ksh$$ ]] -then err_exit "CDPATH tmp/ksh$$ does not display new directory" +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] +then err_exit "CDPATH ${tmp#/} does not display new directory" fi -cd / -rm -rf /tmp/ksh$$ TMOUT=100 (TMOUT=20) if (( TMOUT !=100 )) @@ -411,15 +413,15 @@ done unset IFS if [[ $( (print ${12345:?}) 2>&1) != *12345* ]] -then err_exit 'Incorrect error message with ${12345?}' +then err_exit 'incorrect error message with ${12345?}' fi unset foobar if [[ $( (print ${foobar:?}) 2>&1) != *foobar* ]] -then err_exit 'Incorrect error message with ${foobar?}' +then err_exit 'incorrect error message with ${foobar?}' fi unset bar if [[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]] -then err_exit 'Incorrect error message with ${foobar?}' +then err_exit 'incorrect error message with ${foobar?}' fi { $SHELL -c ' function foo @@ -427,14 +429,13 @@ function foo typeset SECONDS=0 sleep 1.5 print $SECONDS - + } x=$(foo) -(( x >1 && x < 2 )) +(( x >1 && x < 2 )) ' } 2> /dev/null || err_exit 'SECONDS not working in function' -trap 'rm -f /tmp/script$$ /tmp/out$$' EXIT -cat > /tmp/script$$ <<-\! +cat > $tmp/script <<-\! posixfun() { unset x @@ -451,12 +452,12 @@ cat > /tmp/script$$ <<-\! else print -r -- "${.sh.file}" fi ! -chmod +x /tmp/script$$ -. /tmp/script$$ 1 -[[ $file == /tmp/script$$ ]] || err_exit ".sh.file not working for dot scripts" -[[ $($SHELL /tmp/script$$) == /tmp/script$$ ]] || err_exit ".sh.file not working for scripts" -[[ $(posixfun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for posix functions" -[[ $(fun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for functions" +chmod +x $tmp/script +. $tmp/script 1 +[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts" +[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts" +[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions" +[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions" [[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions" [[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions" [[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions" @@ -483,22 +484,22 @@ function dave.unset unset dave [[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed' -print 'print ${VAR}' > /tmp/script$$ +print 'print ${VAR}' > $tmp/script unset VAR -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'" [[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'" unset VAR VAR=old -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'" [[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'" unset VAR export VAR=old -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'" [[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'" @@ -511,7 +512,7 @@ got=$(</tmp/out$$) } dave=foo; dave+=bar [[ $dave == barfoo ]] || exit 2 -) 2> /dev/null +) 2> /dev/null case $? in 0) ;; 1) err_exit 'append discipline not implemented';; @@ -522,8 +523,8 @@ esac function .sh.foobar.get { .sh.value=world - } -} 2> /dev/null || err_exit "Can't add get discipline to .sh.foobar" + } +} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar" [[ ${.sh.foobar} == world ]] || err_exit 'get discipline for .sh.foobar not working' x='a|b' IFS='|' @@ -557,12 +558,12 @@ function foo.set ;; esac } -foo[barrier_hit]=no +foo[barrier_hit]=no foo[bar]=1 (( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1' [[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no' [[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes' -foo[barrier_hit]=no +foo[barrier_hit]=no foo[bar]=2 (( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5' [[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes' @@ -576,8 +577,10 @@ function x.set } x[0]=0 x[1]=1 x[2]=2 x[3]=3 [[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly' +float seconds ((SECONDS=3*4)) -(( SECONDS < 12 || SECONDS > 12.1 )) && err_exit "SECONDS is $SECONDS and should be close to 12" +seconds=SECONDS +(( seconds < 12 || seconds > 12.1 )) && err_exit "SECONDS is $seconds and should be close to 12" unset a function a.set { @@ -611,15 +614,37 @@ do nameref r=$v else err_exit "unset $v; : \$$v failed" fi done + +x=x for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC do nameref r=$v unset $v [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" d=$($SHELL -c "$v=$x" 2>&1) [[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic" - ( r=$x; [[ ! $r ]] ) 2>/dev/null || err_exit "$v=$x failed -- expected ''" - ( r=C; r=$x; [[ $r == C ]] ) 2>/dev/null || err_exit "$v=C; $v=$x failed -- expected 'C'" + { g=$( r=$x; print -- $r ); } 2>/dev/null + [[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'" + { g=$( r=C; r=$x; print -- $r ); } 2>/dev/null + [[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'" done PATH=$path +cd $tmp + +print print -n zzz > zzz +chmod +x zzz +exp='aaazzz' +got=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1 +[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'" + +mkdir glean +for cmd in date ok +do exp="$cmd ok" + rm -f $cmd + print print $exp > glean/$cmd + chmod +x glean/$cmd + got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1) + [[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'" +done + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/vartree1.sh b/usr/src/lib/libshell/common/tests/vartree1.sh index 88116a24c3..67134086af 100644 --- a/usr/src/lib/libshell/common/tests/vartree1.sh +++ b/usr/src/lib/libshell/common/tests/vartree1.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -41,7 +41,7 @@ function build_tree typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -53,15 +53,15 @@ function build_tree for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then #if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -75,7 +75,7 @@ function build_tree if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + #dest_tree.l1["$a"].l2["$b"].l3["$c"].entries+=( "$index" ) typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then @@ -88,12 +88,12 @@ function build_tree continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } function add_tree_leaf @@ -101,7 +101,7 @@ function add_tree_leaf nameref tree_leafnode="$1" nameref data_node=srcdata.hashnodes["$2"] typeset add_mode="$3" - + case "${add_mode}" in "leaf_name") tree_leafnode="${data_node.name}" @@ -121,7 +121,7 @@ function add_tree_leaf return 1 ;; esac - + # not reached return 1 } @@ -151,7 +151,7 @@ typeset mysrcdata_global=( ) mytree_global=() - + function main { # "mysrcdata_local" and "mysrcdata_global" must be identical @@ -182,32 +182,32 @@ function main build_tree mytree_global mysrcdata_global leaf_compound || \ err_exit 'build_tree mytree_global mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global' too small." + (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global' too small" # build tree using local tree variables mytree_local=() build_tree mytree_local mysrcdata_local leaf_compound || \ err_exit 'build_tree mytree_local mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local' too small." - + (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local' too small" + # Compare trees if [[ "${mytree_global}" != "${mytree_local}" ]] ; then - err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical" + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical" fi - + unset 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + [[ "${mytree_global}" != "${mytree_local}" ]] || err_exit "mytree_global and mytree_local should differ" unset 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + # Compare trees (after "unset") if [[ "${mytree_global}" != "${mytree_local}" ]] ; then - err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical after unset" - fi + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical after unset" + fi } main diff --git a/usr/src/lib/libshell/common/tests/vartree2.sh b/usr/src/lib/libshell/common/tests/vartree2.sh index 38512d5a42..9f478ae140 100644 --- a/usr/src/lib/libshell/common/tests/vartree2.sh +++ b/usr/src/lib/libshell/common/tests/vartree2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -34,7 +34,7 @@ function err_exit alias err_exit='err_exit $LINENO' # "built_tree1" and "built_tree2" are identical except the way how they test -# whether a variable exists: +# whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content # - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell @@ -46,7 +46,7 @@ function build_tree1 typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -58,15 +58,15 @@ function build_tree1 for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then #if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -80,7 +80,7 @@ function build_tree1 if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) @@ -92,16 +92,16 @@ function build_tree1 continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } # "built_tree1" and "built_tree2" are identical except the way how they test -# whether a variable exists: +# whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content # - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell @@ -113,7 +113,7 @@ function build_tree2 typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -125,15 +125,15 @@ function build_tree2 for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -147,7 +147,7 @@ function build_tree2 if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) @@ -159,12 +159,12 @@ function build_tree2 continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } @@ -173,7 +173,7 @@ function add_tree_leaf nameref tree_leafnode="$1" nameref data_node=srcdata.hashnodes["$2"] typeset add_mode="$3" - + case "${add_mode}" in "leaf_name") tree_leafnode="${data_node.name}" @@ -193,7 +193,7 @@ function add_tree_leaf return 1 ;; esac - + # not reached return 1 } @@ -224,7 +224,7 @@ typeset mysrcdata_global=( mytree_global1=() mytree_global2=() - + function main { # "mysrcdata_local" and "mysrcdata_global" must be identical @@ -254,11 +254,11 @@ function main #### Build tree using global tree variables build_tree1 mytree_global1 mysrcdata_global leaf_compound || \ err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global1' too small." + (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global1' too small" build_tree2 mytree_global2 mysrcdata_global leaf_compound || \ err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global2' too small." + (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global2' too small" #### build tree using local tree variables @@ -267,67 +267,67 @@ function main build_tree1 mytree_local1 mysrcdata_local leaf_compound || \ err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local1' too small." + (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local1' too small" build_tree2 mytree_local2 mysrcdata_local leaf_compound || \ err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local2' too small." + (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local2' too small" + - #### Compare treess if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then - err_exit "Compound trees 'mytree_global1' and 'mytree_local1' not identical" + err_exit "compound trees 'mytree_global1' and 'mytree_local1' not identical" fi if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then - err_exit "Compound trees 'mytree_global1' and 'mytree_global2' not identical" + err_exit "compound trees 'mytree_global1' and 'mytree_global2' not identical" fi if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then - err_exit "Compound trees 'mytree_local1' and 'mytree_local2' not identical" + err_exit "compound trees 'mytree_local1' and 'mytree_local2' not identical" fi #### test "unset" in a subshell ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ - err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + err_exit "try 1: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ - err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + err_exit "try 2: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" # remove parent node (array element) and then check whether the child is gone, too: ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' - unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Global: Parent node removed (array element), child still exists" + [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]'} ]] + ) && err_exit "global: parent node removed (array element), child still exists" ( unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Local: Parent node removed (array element), child still exists" - + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array element), child still exists" + # remove parent node (array variable) and then check whether the child is gone, too: ( unset 'mytree_local1.l1[urw].l2' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Global: Parent node removed (array variable), child still exists" + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "global: parent node removed (array variable), child still exists" ( unset 'mytree_local1.l1[urw].l2' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Local: Parent node removed (array variable), child still exists" + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array variable), child still exists" #### test "unset" and compare trees unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + # Compare trees (after "unset") if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then - err_exit "Compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" - fi + err_exit "compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" + fi } main |