Commit Graph

82 Commits

Author SHA1 Message Date
kre 9eccf618bb Oops, somehow managed to commit an older version where NBSH_INVOCATION
start char was '@' rather than '!' (which meant not lexically ordered).
This is how it was intended to be (and is documented).
2022-09-18 17:11:33 +00:00
kre e7b0505e69 Add the -l option (aka -o login): be a login shell. Meaningful only on
the command line (with both - and + forms) - overrides the presence (or
otherwise) of a '-' as argv[0][0].

Since this allows any shell to be a login shell (which simply means that
it runs /etc/profile and ~/.profile at shell startup - there are no other
side effects) add a new, always set at startup, variable NBSH_INVOCATION
which has a char string as its value, where each char has a meaning,
more or less related to how the shell was started.   See sh(1).
This is intended to allow those startup scripts to tailor their behaviour
to the nature of this particular login shell (it is possible to detect
whether a shell is a login shell merely because of -l, or whether it would
have been anyway, before the -l option was added - and more).   The
var could also be used to set different values for $ENV for different
uses of the shell.
2022-09-18 06:03:19 +00:00
kre 6a1a2ce2c3 Fix the fix to a typo in one of the comments. 2021-08-09 11:29:30 +00:00
andvar f1229b5389 s/varable/variable s/explictly/explicitly/ s/proerly/properly/ in comments. 2021-08-08 20:50:12 +00:00
kre 727a664bee Add the "specialvar" built-in command. Discussed (well, mentioned
anway) on tech-userlevel with no adverse response.

This allows the magic of vars like HOSTNAME SECONDS, ToD (etc) to be
restored should it be lost - perhaps by having a var of the same name
imported from the environment (which needs to remove the magic in case
a set of scripts are using the env to pass data, and the var name chosen
happens to be one of our magic ones).

No change to SMALL shells (or smaller) - none of the magic vars (except
LINENO, which is exempt from all of this) exist in those, hence such a
shell has no need for this command either.
2019-02-14 11:15:24 +00:00
kre 83735e242c DTRT when dynamically generated variables return "unset" instead of
a value.   There are none which do that at the minute, so this is a NFCI
change, which is just making the code correct even though nothing
currently triggers any bugs.
2019-02-09 09:38:11 +00:00
kre e8999de45c INTON / INTOFF audit and cleanup.
No visible differences expected - there is a remote chance that
some internal lossage may no longer occur in interactive shells
that receive SIGINT (untrapped) at inopportune times, but you would
have had to have been very unlucky to have ever suffered from that.
2019-02-09 03:35:55 +00:00
kre dd761e12dc Fix an off by one buffer length problem. Fortunately, it was off by
one in the "safe" way (it was ensuring the buffer always ended in 2 \0
characters ... one is enough.)   This could affect the expansions of
LINENO RANDOM and SECONDS, though only if they have at least 8 digits
(and then, only sometimes).   RANDOM thus is safe, as it never produces
a number with more than 5 digits, you'd need a script with 10000000
lines before there might be an issue with LINENO (and even autoconf
generated scripts don't generally get that bit) and a shell would need
to be running for almost 4 months for SECONDS to climb that high.

Nevertheless: XXX pullup -8.
2019-01-21 13:27:29 +00:00
kre 150d8297c3 Implement:
readonly -q VAR...
	readonly -p VAR...
	export -q [-x] VAR...
	export -p [-x] VAR...

all available only in !SMALL shells - and while here, limit
"export -x" to full sized shells as well.

Also, do a better job of arg checking and validating of the
export and readonly commands (which is really just one built-in)
and of issuing error messages when something bogus is detected.

Since these commands are special builtin commands, any error
causes shell exit (for non-interactive shells).
2018-12-12 11:51:33 +00:00
kre 64c9a713d8 Fix a botch made in 1.70 (a bit over a week ago) where
var=foo; readonly var=new
now fails.

If var was already set, an attempt to make it readonly, and assign it
a new value at the same time, failed - the readonly flag was set too soon.

Pointed out by Martijn Dekker (thanks).

Also, while here, add a couple of comments.
2018-12-12 07:56:57 +00:00
kre 370f00cafc Alter a design botch when magic (self modifying) variables
were added to sh ... in other shells, setting such a variable
(for most of them) causes it to lose its special properties,
and act the same as any other variable.   I had assumed that
was just implementor laziness...   I was wrong.

From now on the NetBSD shell will act like the others, and if vars
like HOSTNAME (and SECONDS, etc) are used as variables in a script
or whatever, they will act just like normal variables (and unless
this happens when they have been made local, or as a variable-assignment
as a prefix to a command, the special properties they would have had
otherwise are lost for the remainder of the life of the (sub-)shell
in which the variables were set).

Importing a value from the environment counts as setting the
value for this purpose (so if HOSTNAME is set in the environment,
the value there will be the value $HOSTNAME expands to).

The two exceptions to this are LINENO and RANDOM.   RANDOM
needs to be able to be set to (re-)set its seed.  LINENO needs to
be able to be set (at least in the "local" command) to achieve
the desired functionality.   It is unlikely that any (sane) script
is going to want to use those two as normal vars however.

While here, fix a minor bug in popping local vars (fn return) that need
to notify the shell of changes in value (like PATH).

Change sh(1) to reflect this alteration.  Also add doc of the
(forgotten) magic var EUSER (which has been there since the others
were added), and add a few more vars (which are documented
in other places in sh(1) - like ENV) into the defined or used
variable list (as well as wherever else they appear).

XXX pullup -8
2018-12-04 14:03:30 +00:00
kre 522d163154 Fix "export -x" (and its consequences) to behave as originally
intended (and as documented) rather than how it has been behaving
(which was not very rational.)   Since it is unlikely that anyone
is using this, the change should be mostly invisible.

While here, a couple of other minor cleanups:
	. One call of geteuid() is enough in choose_ps1()
	. Fix a typo in a comment
	. Improve appearance (whitspace changes) in find_var()
2018-12-03 06:42:25 +00:00
kre c6c29888c4 Remove atoi()
Mostly use number() (no longer implemented using atoi()) when an
unsigned integer is required, but use strtoXXX() when a conversion
is wanted, without the possibility or error (like setting OPTIND
and RANDOM).   Always init OPTIND to 1 when sh starts (overriding
anything in environ.)
2018-07-13 22:43:44 +00:00
kre ffc64c6374 Implement the -X option - an apparent variant of -x which sends all trace
output to the stderr which existed when the -X option was (last) enabled.
It also enables tracing by enabling -x (and when reset, +X, also resets
the 'x' flag (+x)).  Note that it is still -x/+x which actually
enables/disables the trace output.   Hence "apparent variant" - what -X
actually does (aside from setting -x) is just to lock the trace output,
rather than having it follow wherever stderr is later redirected.
2017-11-19 03:23:01 +00:00
kre 4512d56802 Extract the variable name validity test from setname() into a
function of its own.  It will soon be needed from another source.
2017-10-28 03:59:11 +00:00
kre e7beee7b61 Fix a bug noticed by Soren Jacobsen running the netbsd-6-0 build.sh which
causes a core dump in some exotic circumstances (when restoring local
variables when a function returns).  ("build.sh makewrapper" exposed it.)

This was introduced in 1.63 - not as part of the substance of that
change (addition) but as an unrelated "must be the right thing to do"
cleanup, which wasn't...
2017-08-31 05:09:38 +00:00
kre 59695ae2d7 NFC: DEBUG mode only change - add a little more tracing. 2017-07-24 13:36:15 +00:00
kre cdfea65894 Fix a reference after free (and consequent nonsense diagnostic for
attempts to set readonly variables) I added in 1.60 by incompletely
copying the FreeBSD fix for the lost memory issue.
2017-07-12 19:06:16 +00:00
kre 2eafa75298 DEBUG only changes. Convert the TRACE() calls in the remaining files
that still used it to the new format.   NFC.
2017-07-05 20:00:27 +00:00
kre dc83385122 Implement a bunch of new shell environment variables. many mostly useful
in prompts when expanded at prompt time, but all available for general use.
Many of the new ones are not available in SMALL shells (they work as normal
if assigned, but the shell does not set or use them - and there is no magic
in a SMALL shell (usually for install media.))
2017-06-30 23:05:45 +00:00
kre 4754b1e8f4 Now libedit supports embedded mode switch sequence, improve sh
support for them (adds PSlit variable to set the magic character).
2017-06-28 13:46:06 +00:00
kre 3c2922e71c Properly support EDITRC - use it as (naming) the file when setting
up libedit, and re-do the config whenever EDITRC is set.
2017-06-27 02:22:08 +00:00
kre ad0b72d9e9 Cosmetic changes to variable flags - make their values more suited
to my delicate sensibilities...  (NFC).

Arrange not to barf (ever) if some turkey makes _ readonly.  Do this
by adding a VNOERROR flag that causes errors in var setting to be
ignored (intended use is only for internal shell var setting, like of "_").
(nb: invalid var name errors ignore this flag, but those should never
occur on a var set by the shell itself.)

From FreeBSD: don't simply discard memory if a variable is not set for
any reason (including because it is readonly) if the var's value had
been malloc'd.  Free it instead...
2017-06-17 10:46:34 +00:00
kre 354d46cb96 s/volatile/const/ -- wonderful how opposites attract like this. 2017-06-17 04:12:06 +00:00
kre ce6f66ce50 Unbreak (at least) i386 build .... I have no idea why this built for me on
amd64 (problem was missing prototype for snprintf witout <stdio.h>)

While here, add some (DEBUG mode only) tracing that proved useful in
solving another problem.
2017-06-07 08:06:22 +00:00
kre 727a69dc1d A better LINENO implementation. This version deletes (well, #if 0's out)
the LINENO hack, and uses the LINENO var for both ${LINENO} and $((LINENO)).
(Code to invert the LINENO hack when required, like when de-compiling the
execution tree to provide the "jobs" command strings, is still included,
that can be deleted when the LINENO hack is completely removed - look for
refs to VSLINENO throughout the code.  The var funclinno in parser.c can
also be removed, it is used only for the LINENO hack.)

This version produces accurate results: $((LINENO)) was made as accurate
as the LINENO hack made ${LINENO} which is very good.  That's why the
LINENO hack is not yet completely removed, so it can be easily re-enabled.
If you can tell the difference when it is in use, or not in use, then
something has broken (or I managed to miss a case somewhere.)

The way that LINENO works is documented in its own (new) section in the
man page, so nothing more about that, or the new options, etc, here.

This version introduces the possibility of having a "reference" function
associated with a variable, which gets called whenever the value of the
variable is required (that's what implements LINENO).  There is just
one function pointer however, so any particular variable gets at most
one of the set function (as used for PATH, etc) or the reference function.
The VFUNCREF bit in the var flags indicates which func the variable in
question uses (if any - the func ptr, as before, can be NULL).

I would not call the results of this perfect yet, but it is close.
2017-06-07 05:08:32 +00:00
kre fd38bbe2e4 An initial attempt at implementing LINENO to meet the specs.
Aside from one problem (not too hard to fix if it was ever needed) this version
does about as well as most other shell implementations when expanding
$((LINENO)) and better for ${LINENO} as it retains the "LINENO hack" for the
latter, and that is very accurate.

Unfortunately that means that ${LINENO} and $((LINENO)) do not always produce
the same value when used on the same line (a defect that other shells do not
share - aside from the FreeBSD sh as it is today, where only the LINENO hack
exists and so (like for us before this commit) $((LINENO)) is always either
0, or at least whatever value was last set, perhaps by
	LINENO=${LINENO}
which does actually work ... for that one line...)

This could be corrected by simply removing the LINENO hack (look for the string
LINENO in parser.c) in which case ${LINENO} and $((LINENO)) would give the
same (not perfectly accurate) values, as do most other shells.

POSIX requires that LINENO be set before each command, and this implementation
does that fairly literally - except that we only bother before the commands
which actually expand words (for, case and simple commands).   Unfortunately
this forgot that expansions also occur in redirects, and the other compound
commands can also have redirects, so if a redirect on one of the other compound
commands wants to use the value of $((LINENO)) as a part of a generated file
name, then it will get an incorrect value.  This is the "one problem" above.
(Because the LINENO hack is still enabled, using ${LINENO} works.)

This could be fixed, but as this version of the LINENO implementation is just
for reference purposes (it will be superseded within minutes by a better one)
I won't bother.  However should anyone else decide that this is a better choice
(it is probably a smaller implementation, in terms of code & data space then
the replacement, but also I would expect, slower, and definitely less accurate)
this defect is something to bear in mind, and fix.

This version retains the *BSD historical practice that line numbers in functions
(all functions) count from 1 from the start of the function, and elsewhere,
start from 1 from where the shell started reading the input file/stream in
question.  In an "eval" expression the line number starts at the line of the
"eval" (and then increases if the input is a multi-line string).

Note: this version is not documented (beyond as much as LINENO was before)
hence this slightly longer than usual commit message.
2017-06-07 04:44:17 +00:00
kre 2d8874d9a7 More standard (and saner) implementation of the ! reserved word.
Unless the shell is compiled with the (compilation time) option
BOGUS_NOT_COMMAND (as in CFLAGS+=-DBOGUS_NOT_COMMAND) which it
will not normally be, the ! command (reserved word) will only
be permitted at the start of a pipeline (which includes the
degenerate pipeline with no '|'s in it of course - ie: a simple cmd)
and not in the middle of a pipeline sequence (no "cmd | ! cmd" nonsense.)
If the latter is really required, then "cmd | { ! cmd; }" works as
a standard equivalent.

In POSIX mode, permit only one !  ("! pipeline" is ok. "! ! pipeline" is not).
Again, if needed (and POSIX conformance is wanted) "! { ! pipeline; }"
works as an alternative - and is safer, some shells treat "! ! cmd" as
being identical to "cmd" (this one did until recently.)
2017-05-27 11:19:57 +00:00
kre 8df083c104 It turns out that most shells do not do variable value/attribute
inheritance when a variable is declared local, but instead leave
the local var unset (if not given a value) in the function.
Only ash derived shells do inheritance it seems.

So, to compensate for that, and get one step closer to making
"local" part of POSIX, so we can really rely upon it, a compromise
has been suggested, where "local x" is implementation defined
when it comes to this issue, and we add "local -I x" to specify
inheritance, and "local -N x" to specify "not" (something...)
(not inherited, or not set, or whatever you prefer to imagine!)
The option names took a lot of hunting to find something reasonable
that no shell (we know of) had already used for some other purpose...
The I was easy, but 'u' 'U' 'X' ... all in use somewhere.

This implements that (well, semi-) agreement.

While here, add "local -x" (which many other shells already have)
which causes the local variable to be made exported.  Not a lot
of gain in that (since "export x" can always be done immediately
after "local x") but it is very cheap to add and allows more other
scripts to work with out shell.

Note that while 'local x="${x}"' always works to specify inheritance
(while making the shell work harder), "local x; unset x" does not
always work to specify the alternative, as some shells have
"re-interpreted" unset of a local variable to mean something that
would best be described as "unlocal" instead - ie: after the unset
you might be back with the variable from the outer scope, rather
than with an unset local variable.

Also add "unset -x" to allow unsetting a variable without removing
any exported status it has.

There are gazillions of other options that are not supported here!
2017-05-27 06:32:12 +00:00
kre f52337da20 Make ${NETBSD_SHELL} value include (a human recognisable form of)
MKREPRO_TIMESTAMP (as an additional word in the value, with a "BUILD:" prefix)
if it is set during the build.   (Trailing 00 pairs in the time are removed).

While here, throw in some extra words that list the compilation
options used which alter sh behaviour (mostly by removing stuff.)
Usually that will only be noticed in a SMALL shell compiled for
install media, or similar - none of the others (not that there
are many) are ever changed from the default in a normal build
(default settings are just omitted.)   This also allows scripts
to tell if they are running in a DEBUG shell, which can sometimes
make debugging easier.
2017-05-14 11:23:33 +00:00
kre be0a98abf6 I noticed!
POSIX requires that the output of the "set" command (with no args -- it
gives a list of variables, and their values) be sorted according to
the collating sequence defined by the current locale.

Now I'm not aware of any locale where the collating sequence order of
ascii letters, digits, and '_' are any different than they are in the
C locale (and those are the only characters that can occur in variable
names - unless there is perhaps a locale that defines "dictionary" order
as the sort order) but never mind, that isn't the bug...

What "collating sequence order" does mean however, if not "collating
sequence order, except when we happen to have two variable names, where
one name is a prefix of the other (say X and XY) and the first character
of the 'Y' part of the longer name happens to be a digit..."

"set" is not a frequently used command (particularly in scripts where
it matters - that is, the no args form, nothing here alters anything
about any use of set with args) and is already a bit slow (sluggish...)
because of the sort requirement, so let's make it fractionally even
slower, but correct.
2017-05-10 06:18:43 +00:00
kre 3276f23b14 Make "export VAR" work correctly ... if VAR was unset before this
command it should remain unset afterwards.

Previouly "export VAR" did much the same as:
	export VAR="${VAR}"
(but without the side effects if VAR had previously been VAR='~' or similar)

Also stop unset exported variables from actually making it into the
environment.  Previously this was impossible - variables get exported
in just one of 3 ways, by being imported from the environ (which means
the var is set) when -a is set, and a var is given a value (so the var
is set), or using "export" which previously always set a null string
if the var was otheriwse unset.

The same happens for "readonly"  (readonly and export use the same mechanism)
- except, once marked readonly, it is no longer possible to set the var, so
(assuming VAR is not already readonly)
	unset VAR; readonly VAR
is (now) a way to guarantee that "VAR" can never be set.

This conforms with POISX (though it is not particularly clear on this
point) and with bash and ksh93 (and also with the FreeBSD shell, though
they export unset variables that are marked for export as if set to '')

It s not clear whether
	unset VAR; readonly VAR; unset VAR; echo $?
should print 0, or non-0, so for now just leave this as it is (prints 1).
2017-05-03 00:39:40 +00:00
kre 6f0d4805b2 Fix several problems with the implementation of the "trap" command
(that is, with the command itself, not with the traps that are
executed, if any).

- "trap -- -l" is not rational, permit the (non-std) -l option only
  when given as the sole arg (ie: "trap -l").
- "trap --" is the same as just "trap" (and -- is ignored for below)
- "trap action" generates a usage message (there must be at least one condition)
- "trap N [condition...]" (the old form with a numeric first arg, to reset
  traps to default, instead of "trap - condition...") is properly detected.
  In particular while "trap 1 2 3" resets sighup sigint and siquit handlers
  to default, "trap hup int quit" runs the "hup" command on sigint or sigquit
  and does nothing to sighup at all.
- actions can start with "-" (as can commands in general) - it may be unusual
  or even unwise, but it is not prohibited, and should work
- bad conditions (signal names/numbers) are just a usage error (resulting in
  non-zero "exit status" (and a diagnostic on stderr)) they do not cause
  the script to abort (as a syntax error in a special builtin would.)
  (so says posix, very explicitly.)
- when outputting the trap list ("trap") properly quote null actions
  (ignored conditions).  This has the side effect of also generating an
  explicit null string ('') in other cases where null values are output,
  such as when reporting var values ("set") but that's OK, and might be
  better (VAR= and VAR='' mean the same, but the latter is more obvious.)

We still do not properly handle traps=$(trap) (ie: it does not work at all,
and should) but that's a different problem that needs fixing in another place.
2017-04-29 15:12:21 +00:00
christos 9302f8ef1a Implement the NETBSD_SHELL readonly unexportable unimportable
variable (with its current value set at 20160401) as discussed on
current-users and tech-userlevel. This also includes the necessary
support to implement it properly (particularly the unexportable
part) and adds options to the export command to support unexportable
variables. Also implement the "posix" option (no single letter
equivalent) which gets its default value from whether or not
POSIXLY_CORRECT is set in the environment when the shell starts
(but can be changed just like any other option using -o and +o on
the command line, or the set builtin command.) While there, fix
all uses of options so it is possible to have options that have a
short (one char) name, and no long name, just as it has been possible
to have options with a long name and no short name, though there
are currently none (with no long name).  For now, the only use of
the posix option is to control whether ${ENV} is read at startup
by a non-interactive shell, so changing it with set is not usful
- that might change in the future. (from kre@)
2016-03-31 16:16:35 +00:00
christos ca12a0b88a General KNF and source code cleanups, avoid scattering the
magic string " \t\n" all over the place, slightly improved
syntax error messages, restructured some of the code for
clarity, don't allow IFS to be imported through the environment,
and remove the (never) conditionally compiled ATTY option.
Apart from one or two syntax error messages, and ignoring IFS
if present in the environment, this is intended to have no
user visible changes. (from kre@)
2016-03-27 14:34:46 +00:00
christos 1dd2c2fdec Move the PPID installation to the init() section. 2016-03-08 23:24:51 +00:00
christos 2c7c3a0713 - don't export $PPID (from kre)
- include <stdio.h>
2016-03-08 18:16:11 +00:00
christos ae3fe60ef5 Provide $PPID, kill vvers (unused) 2016-03-08 14:32:34 +00:00
christos ac33f4ea5e Drop privileges when executed set{u,g}id unless -p is specified like other
shells do to avoid system() and popen() abuse.
2015-05-26 21:35:15 +00:00
christos 5c83aa644a PR/48312: Dieter Roelands: According to TOG, unset should not return an error
for functions are variables that were not previously set:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
2013-11-01 16:49:02 +00:00
christos 6814c65d63 PR/47317: Henning Petersen: Replace index() with strchr() 2012-12-13 19:33:23 +00:00
christos a080d61232 include <limits.h> for CHAR_MIN/CHAR_MAX 2012-03-28 20:11:25 +00:00
christos 4fc4fe2edf PR/45069: Henning Petersen: Use prototypes from builtins.h . 2011-06-18 21:18:46 +00:00
dholland 0faa1734e3 Use "extern" properly for referencing globals defined in other modules.
Now builds cleanly with -warn-common.
2008-10-16 14:36:40 +00:00
christos a54fe38a0d fix a volatile variable; from Anon Ymous 2006-12-18 00:37:33 +00:00
snj a640fe8c43 It's "its." 2006-04-24 19:00:29 +00:00
enami 87aaf3d70d Fix a bug introduced by previous commit. It breaks export command
with multiple arguments if one of them are already set.  Fix PR#27155
and probably PR#27143.
2004-10-06 10:23:43 +00:00
dsl 5f9b910124 Save the length of each variable in the name table so that we can
compare the lengths and then use memcmp() in the search code.
Speeds up one of my scripts by a facter of 2.
Increase the size of the variable hash table.
Cuts down time for script to execute from 60 seconds to 10.
Move variable search into a new function to hide the implementation
from most of the code, new version is slightly smaller than old.
2004-10-02 12:16:53 +00:00
jmmv aba1ca99ae Include strings.h, needed for index's prototype. 2003-08-26 18:14:24 +00:00
agc b5b2954259 Move UCB-licensed code from 4-clause to 3-clause licence.
Patches provided by Joel Baker in PR 22249, verified by myself.
2003-08-07 09:05:01 +00:00