Home | History | Annotate | Line # | Download | only in sh
      1 /*	$NetBSD: var.c,v 1.91 2026/05/28 10:07:58 kre Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Kenneth Almquist.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
     39 #else
     40 __RCSID("$NetBSD: var.c,v 1.91 2026/05/28 10:07:58 kre Exp $");
     41 #endif
     42 #endif /* not lint */
     43 
     44 #include <stdio.h>
     45 #include <unistd.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include <paths.h>
     49 #include <limits.h>
     50 #include <time.h>
     51 #include <pwd.h>
     52 #include <fcntl.h>
     53 #include <inttypes.h>
     54 #ifndef SMALL
     55 #include <locale.h>
     56 #endif
     57 
     58 /*
     59  * Shell variables.
     60  */
     61 
     62 #include "shell.h"
     63 #include "output.h"
     64 #include "expand.h"
     65 #include "nodes.h"	/* for other headers */
     66 #include "eval.h"	/* defines cmdenviron */
     67 #include "exec.h"
     68 #include "syntax.h"
     69 #include "options.h"
     70 #include "builtins.h"
     71 #include "mail.h"
     72 #include "var.h"
     73 #include "memalloc.h"
     74 #include "error.h"
     75 #include "mystring.h"
     76 #include "parser.h"
     77 #include "show.h"
     78 #include "machdep.h"
     79 #ifndef SMALL
     80 #include "myhistedit.h"
     81 #endif
     82 
     83 #ifdef SMALL
     84 #define VTABSIZE 39
     85 #else
     86 #define VTABSIZE 517
     87 #endif
     88 
     89 
     90 struct varinit {
     91 	struct var *var;
     92 	int flags;
     93 	const char *text;
     94 	union var_func_union v_u;
     95 };
     96 #define	func v_u.set_func
     97 #define	rfunc v_u.ref_func
     98 
     99 char *get_lineno(struct var *);
    100 
    101 #ifndef SMALL
    102 char *get_tod(struct var *);
    103 char *get_hostname(struct var *);
    104 char *get_seconds(struct var *);
    105 char *get_euser(struct var *);
    106 char *get_random(struct var *);
    107 
    108 STATIC void set_locale_var(const char *, int, struct var *);
    109 void init_locale_vars(void);
    110 #endif
    111 
    112 struct localvar *localvars;
    113 
    114 #ifndef SMALL
    115 struct var vhistsize;
    116 struct var vhistfile;
    117 struct var vhistappend;
    118 struct var vterm;
    119 struct var editrc;
    120 struct var ps_lit;
    121 #endif
    122 struct var vifs;
    123 struct var vmail;
    124 struct var vmpath;
    125 struct var vpath;
    126 struct var vps1;
    127 struct var vps2;
    128 struct var vps4;
    129 struct var vvers;
    130 struct var voptind;
    131 struct var line_num;
    132 #ifndef SMALL
    133 struct var tod;
    134 struct var host_name;
    135 struct var seconds;
    136 struct var euname;
    137 struct var random_num;
    138 
    139 intmax_t sh_start_time;
    140 
    141 struct var lc_all;
    142 struct var lc_collate;
    143 struct var lc_ctype;
    144 struct var lc_messages;
    145 struct var lc_monetary;
    146 struct var lc_numeric;
    147 struct var lc_time;
    148 struct var lc_lang;
    149 #endif
    150 
    151 struct var line_num;
    152 int line_number;
    153 int funclinebase = 0;
    154 int funclineabs = 0;
    155 
    156 char ifs_default[] = " \t\n";
    157 
    158 const struct varinit varinit[] = {
    159 #ifndef SMALL
    160 	{ &vhistsize,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE=",
    161 	   { .set_func= sethistsize } },
    162 	{ &vhistfile,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTFILE=",
    163 	   { .set_func= sethistfile } },
    164 	{ &vhistappend,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTAPPEND=",
    165 	   { .set_func= sethistappend } },
    166 #endif
    167 	{ &vifs,	VSTRFIXED|VTEXTFIXED,		"IFS= \t\n",
    168 	   { NULL } },
    169 	{ &vmail,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL=",
    170 	   { NULL } },
    171 	{ &vmpath,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH=",
    172 	   { NULL } },
    173 	{ &vvers,	VSTRFIXED|VTEXTFIXED|VNOEXPORT, "NETBSD_SHELL=",
    174 	   { NULL } },
    175 	{ &vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=" _PATH_DEFPATH,
    176 	   { .set_func= changepath } },
    177 	/*
    178 	 * vps1 depends on uid
    179 	 */
    180 	{ &vps2,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",
    181 	   { NULL } },
    182 	{ &vps4,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",
    183 	   { NULL } },
    184 #ifndef SMALL
    185 	{ &vterm,	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM=",
    186 	   { .set_func= setterm } },
    187 	{ &editrc, 	VSTRFIXED|VTEXTFIXED|VUNSET,	"EDITRC=",
    188 	   { .set_func= set_editrc } },
    189 	{ &ps_lit, 	VSTRFIXED|VTEXTFIXED|VUNSET,	"PSlit=",
    190 	   { .set_func= set_prompt_lit } },
    191 	{ &lc_all,	VSTRFIXED|VTEXTFIXED|VUNSET|VFUNCPOST,	"LC_ALL=",
    192 	   { .set_func= set_locale_var } },
    193 	{ &lc_collate,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_COLLATE=",
    194 	   { .set_func= set_locale_var } },
    195 	{ &lc_ctype,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_CTYPE=",
    196 	   { .set_func= set_locale_var } },
    197 	{ &lc_messages,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_MESSAGES=",
    198 	   { .set_func= set_locale_var } },
    199 	{ &lc_monetary,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_MONETARY=",
    200 	   { .set_func= set_locale_var } },
    201 	{ &lc_numeric,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_NUMERIC=",
    202 	   { .set_func= set_locale_var } },
    203 	{ &lc_time,	VSTRFIXED|VTEXTFIXED|VUNSET,	"LC_TIME=",
    204 	   { .set_func= set_locale_var } },
    205 	{ &lc_lang,	VSTRFIXED|VTEXTFIXED|VUNSET|VFUNCPOST,	"LANG=",
    206 	   { .set_func= set_locale_var } },
    207 #endif
    208 	{ &voptind,	VSTRFIXED|VTEXTFIXED|VNOFUNC,	"OPTIND=1",
    209 	   { .set_func= getoptsreset } },
    210 	{ &line_num,	VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL,	"LINENO=1",
    211 	   { .ref_func= get_lineno } },
    212 #ifndef SMALL
    213 	{ &tod,		VSTRFIXED|VTEXTFIXED|VFUNCREF,	"ToD=",
    214 	   { .ref_func= get_tod } },
    215 	{ &host_name,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"HOSTNAME=",
    216 	   { .ref_func= get_hostname } },
    217 	{ &seconds,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"SECONDS=",
    218 	   { .ref_func= get_seconds } },
    219 	{ &euname,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"EUSER=",
    220 	   { .ref_func= get_euser } },
    221 	{ &random_num,	VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL,	"RANDOM=",
    222 	   { .ref_func= get_random } },
    223 #endif
    224 	{ NULL,	0,				NULL,
    225 	   { NULL } }
    226 };
    227 
    228 struct var *vartab[VTABSIZE];
    229 
    230 STATIC int strequal(const char *, const char *);
    231 STATIC struct var *find_var(const char *, struct var ***, int *);
    232 STATIC void showvar(struct var *, const char *, const char *, int);
    233 static void export_usage(const char *) __dead;
    234 STATIC int makespecial(const char *);
    235 
    236 /*
    237  * Initialize the variable symbol tables and import the environment
    238  */
    239 
    240 #ifdef mkinit
    241 INCLUDE <stdio.h>
    242 INCLUDE <unistd.h>
    243 INCLUDE <time.h>
    244 INCLUDE "var.h"
    245 INCLUDE "version.h"
    246 MKINIT char **environ;
    247 MKINIT void setvareqsafe(char *, int);
    248 MKINIT void init_locale_vars(void);
    249 INIT {
    250 	char **envp;
    251 	char buf[64];
    252 
    253 #ifndef SMALL
    254 	sh_start_time = (intmax_t)time((time_t *)0);
    255 #endif
    256 	/*
    257 	 * Set up our default variables and their values.
    258 	 */
    259 	initvar();
    260 
    261 	/*
    262 	 * Import variables from the environment, which will
    263 	 * if permitted, override anything initialised just previously.
    264 	 */
    265 	for (envp = environ ; *envp ; envp++) {
    266 		if (strchr(*envp, '=')) {
    267 			setvareqsafe(*envp, VEXPORT|VTEXTFIXED|VUNSAFE);
    268 		}
    269 	}
    270 
    271 	/*
    272 	 * Set variables which override anything read from environment.
    273 	 *
    274 	 * PPID is readonly
    275 	 * Always default IFS
    276 	 * POSIX: "Whenever the shell is invoked, OPTIND shall
    277 	 *         be initialized to 1."
    278 	 * PSc indicates the root/non-root status of this shell.
    279 	 * START_TIME belongs only to this shell.
    280 	 * NETBSD_SHELL is a constant (readonly), and is never exported
    281 	 * LINENO is simply magic...
    282 	 */
    283 	snprintf(buf, sizeof(buf), "%d", (int)getppid());
    284 	setvar("PPID", buf, VREADONLY);
    285 	setvar("IFS", ifs_default, VTEXTFIXED);
    286 	setvar("OPTIND", "1", VTEXTFIXED);
    287 	setvar("PSc", (geteuid() == 0 ? "#" : "$"), VTEXTFIXED);
    288 
    289 #ifndef SMALL
    290 	snprintf(buf, sizeof(buf), "%jd", sh_start_time);
    291 	setvar("START_TIME", buf, VTEXTFIXED);
    292 
    293 	init_locale_vars();
    294 #endif
    295 
    296 	setvar("NETBSD_SHELL", NETBSD_SHELL
    297 #ifdef BUILD_DATE
    298 		" BUILD:" BUILD_DATE
    299 #endif
    300 #ifdef DEBUG
    301 		" DEBUG"
    302 #endif
    303 #if !defined(JOBS) || JOBS == 0
    304 		" -JOBS"
    305 #endif
    306 #ifndef DO_SHAREDVFORK
    307 		" -VFORK"
    308 #endif
    309 #ifdef SMALL
    310 		" SMALL"
    311 #endif
    312 #ifdef TINY
    313 		" TINY"
    314 #endif
    315 #ifdef OLD_TTY_DRIVER
    316 		" OLD_TTY"
    317 #endif
    318 #ifdef SYSV
    319 		" SYSV"
    320 #endif
    321 #ifndef BSD
    322 		" -BSD"
    323 #endif
    324 #ifdef BOGUS_NOT_COMMAND
    325 		" BOGUS_NOT"
    326 #endif
    327 #ifdef REJECT_NULS
    328 		" REJECT_NULS"
    329 #endif
    330 #ifdef RESCUEDIR
    331 		" RESCUE"
    332 #endif
    333 		    , VTEXTFIXED|VREADONLY|VNOEXPORT);
    334 
    335 	setvar("LINENO", "1", VTEXTFIXED);
    336 }
    337 #endif
    338 
    339 
    340 /*
    341  * This routine initializes the builtin variables.  It is called when the
    342  * shell is initialized and again when a shell procedure is spawned.
    343  */
    344 
    345 void
    346 initvar(void)
    347 {
    348 	const struct varinit *ip;
    349 	struct var *vp;
    350 	struct var **vpp;
    351 
    352 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
    353 		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
    354 			continue;
    355 		vp->next = *vpp;
    356 		*vpp = vp;
    357 		vp->text = strdup(ip->text);
    358 		vp->flags = (ip->flags & ~VTEXTFIXED) | VSTRFIXED;
    359 		vp->v_u = ip->v_u;
    360 	}
    361 	/*
    362 	 * PS1 depends on uid
    363 	 */
    364 	if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
    365 		vps1.next = *vpp;
    366 		*vpp = &vps1;
    367 		vps1.flags = VSTRFIXED;
    368 		vps1.text = NULL;
    369 		choose_ps1();
    370 	}
    371 }
    372 
    373 void
    374 choose_ps1(void)
    375 {
    376 	uid_t u = geteuid();
    377 
    378 	if ((vps1.flags & (VTEXTFIXED|VSTACK)) == 0)
    379 		free(vps1.text);
    380 	vps1.text = strdup(u != 0 ? "PS1=$ " : "PS1=# ");
    381 	vps1.flags &= ~(VTEXTFIXED|VSTACK);
    382 
    383 	/*
    384 	 * Update PSc whenever we feel the need to update PS1
    385 	 */
    386 	setvarsafe("PSc", (u == 0 ? "#" : "$"), 0);
    387 }
    388 
    389 /*
    390  * Validate a string as a valid variable name
    391  * nb: not parameter - special params and such are "invalid" here.
    392  * Name terminated by either \0 or the term param (usually '=' or '\0').
    393  *
    394  * If not NULL, the length of the (intended) name is returned via len
    395  */
    396 
    397 int
    398 validname(const char *name, int term, int *len)
    399 {
    400 	const char *p = name;
    401 	int ok = 1;
    402 
    403 	if (p == NULL || *p == '\0' || *p == term) {
    404 		if (len != NULL)
    405 			*len = 0;
    406 		return 0;
    407 	}
    408 
    409 	if (!is_name(*p))
    410 		ok = 0;
    411 	p++;
    412 	for (;;) {
    413 		if (*p == '\0' || *p == term)
    414 			break;
    415 		if (!is_in_name(*p))
    416 			ok = 0;
    417 		p++;
    418 	}
    419 	if (len != NULL)
    420 		*len = p - name;
    421 
    422 	return ok;
    423 }
    424 
    425 /*
    426  * Safe version of setvar, returns 1 on success 0 on failure.
    427  */
    428 
    429 int
    430 setvarsafe(const char *name, const char *val, int flags)
    431 {
    432 	struct jmploc jmploc;
    433 	struct jmploc * const savehandler = handler;
    434 	int volatile err = 0;
    435 
    436 	if (setjmp(jmploc.loc))
    437 		err = 1;
    438 	else {
    439 		handler = &jmploc;
    440 		setvar(name, val, flags);
    441 	}
    442 	handler = savehandler;
    443 	return err;
    444 }
    445 
    446 void
    447 setvareqsafe(char *s, int flags)
    448 {
    449 	struct jmploc jmploc;
    450 	struct jmploc * const savehandler = handler;
    451 	volatile int e_s = errors_suppressed;
    452 
    453 	if (!setjmp(jmploc.loc)) {
    454 		handler = &jmploc;
    455 		errors_suppressed = 1;
    456 		setvareq(s, flags);
    457 	}
    458 	handler = savehandler;
    459 	errors_suppressed = e_s;
    460 }
    461 
    462 /*
    463  * Set the value of a variable.  The flags argument is ored with the
    464  * flags of the variable.  If val is NULL, the variable is unset.
    465  *
    466  * This always copies name and val when setting a variable, so
    467  * the source strings can be from anywhere, and are no longer needed
    468  * after this function returns.  The VTEXTFIXED and VSTACK flags should
    469  * not be used (but just in case they were, clear them.)
    470  */
    471 
    472 void
    473 setvar(const char *name, const char *val, int flags)
    474 {
    475 	const char *p;
    476 	const char *q;
    477 	char *d;
    478 	int len;
    479 	int namelen;
    480 	char *nameeq;
    481 
    482 	p = name;
    483 
    484 	if (!validname(p, '=', &namelen))
    485 		error("%.*s: bad variable name", namelen, name);
    486 	len = namelen + 2;		/* 2 is space for '=' and '\0' */
    487 	if (val == NULL) {
    488 		flags |= VUNSET;
    489 	} else {
    490 		len += strlen(val);
    491 	}
    492 	d = nameeq = ckmalloc(len);
    493 	q = name;
    494 	while (--namelen >= 0)
    495 		*d++ = *q++;
    496 	*d++ = '=';
    497 	*d = '\0';
    498 	if (val)
    499 		scopy(val, d);
    500 	setvareq(nameeq, flags & ~(VTEXTFIXED | VSTACK));
    501 }
    502 
    503 
    504 
    505 /*
    506  * Same as setvar except that the variable and value are passed in
    507  * the first argument as name=value.  Since the first argument will
    508  * be actually stored in the table, it should not be a string that
    509  * will go away.   The flags (VTEXTFIXED or VSTACK) can be used to
    510  * indicate the source of the string (if neither is set, the string will
    511  * eventually be free()d when a replacement value is assigned.)
    512  */
    513 
    514 void
    515 setvareq(char *s, int flags)
    516 {
    517 	struct var *vp, **vpp;
    518 	int nlen;
    519 
    520 	VTRACE(DBG_VARS, ("setvareq([%s],%#x) aflag=%d ", s, flags, aflag));
    521 	if (aflag && !(flags & VNOEXPORT))
    522 		flags |= VEXPORT;
    523 	vp = find_var(s, &vpp, &nlen);
    524 	if (vp != NULL) {
    525 		VTRACE(DBG_VARS, ("was [%s] fl:%#x\n", vp->text,
    526 		    vp->flags));
    527 		if (vp->flags & VREADONLY) {
    528 			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    529 				ckfree(s);
    530 			if (flags & VNOERROR)
    531 				return;
    532 			error("%.*s: is read only", vp->name_len, vp->text);
    533 		}
    534 		if (flags & VNOSET) {
    535 			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    536 				ckfree(s);
    537 			return;
    538 		}
    539 
    540 		INTOFF;
    541 
    542 		if (vp->func && !(vp->flags & (VFUNCREF|VFUNCPOST)) &&
    543 		    !(flags & VNOFUNC))
    544 			(*vp->func)(s + vp->name_len + 1, flags, vp);
    545 
    546 		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    547 			ckfree(vp->text);
    548 
    549 		/*
    550 		 * if we set a magic var, the magic dissipates,
    551 		 * unless it is very special indeed.
    552 		 */
    553 		if (vp->rfunc && (vp->flags & (VFUNCREF|VSPECIAL)) == VFUNCREF)
    554 			vp->rfunc = NULL;
    555 
    556 		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET|VUNSAFE);
    557 		if (flags & VNOEXPORT)
    558 			vp->flags &= ~VEXPORT;
    559 		if (flags & VDOEXPORT)
    560 			vp->flags &= ~VNOEXPORT;
    561 		if (vp->flags & VNOEXPORT)
    562 			flags &= ~VEXPORT;
    563 		vp->flags |= flags & ~(VNOFUNC | VDOEXPORT);
    564 		vp->text = s;
    565 
    566 		if (vp->func &&
    567 		    (vp->flags & (VFUNCREF|VFUNCPOST)) == VFUNCPOST &&
    568 		    !(flags & VNOFUNC))
    569 			(*vp->func)(s + vp->name_len + 1, flags, vp);
    570 
    571 		/*
    572 		 * We could roll this to a function, to handle it as
    573 		 * a regular variable function callback, but why bother?
    574 		 */
    575 		if (vp == &vmpath || (vp == &vmail && ! mpathset()))
    576 			chkmail(1);
    577 
    578 		INTON;
    579 		return;
    580 	}
    581 	/* not found */
    582 	if (flags & VNOSET) {
    583 		VTRACE(DBG_VARS, ("new noset\n"));
    584 		if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    585 			ckfree(s);
    586 		return;
    587 	}
    588 	vp = ckmalloc(sizeof (*vp));
    589 	vp->flags = flags & ~(VNOFUNC|VFUNCREF|VDOEXPORT);
    590 	vp->text = s;
    591 	vp->name_len = nlen;
    592 	vp->func = NULL;
    593 	vp->next = *vpp;
    594 	*vpp = vp;
    595 
    596 	VTRACE(DBG_VARS, ("new [%s] (%d) %#x\n", s, nlen, vp->flags));
    597 }
    598 
    599 void
    600 setvar_invocation(int argc, char **argv)
    601 {
    602 	char value[32];		/* if we ever get 30, HELP */
    603 	char *v;
    604 
    605 	/*
    606 	 * Keep the following in ascii lexical order ( ie: Z before a )
    607 	 */
    608 
    609 	v = value;
    610 	*v++ = '!';		/* never empty, and the '-' is not first */
    611 
    612 	if (argc > 0 && argv[0] != NULL && argv[0][0] == '-')
    613 		*v++ = '-';
    614 	if (shellparam.nparam == 0)
    615 		*v++ = '0';
    616 	if (minusc)
    617 		*v++ = 'c';
    618 	if (commandname)
    619 		*v++ = 'f';
    620 	if (iflag)
    621 		*v++ = 'i';
    622 	if (loginsh)
    623 		*v++ = 'l';
    624 	if (privileged)
    625 		*v++ = 'p';
    626 	if (sflag)
    627 		*v++ = 's';
    628 
    629 	*v++ = '\0';
    630 
    631 		/*
    632 		 * this cannot fail, the var name is OK,
    633 		 * there cannot be any (non special) read only
    634 		 * variables at this point, ...
    635 		 */
    636 	setvar("NBSH_INVOCATION", value, VNOEXPORT);
    637 }
    638 
    639 /*
    640  * Process a linked list of variable assignments.
    641  */
    642 
    643 void
    644 listsetvar(struct strlist *list, int flags)
    645 {
    646 	struct strlist *lp;
    647 
    648 	INTOFF;
    649 	for (lp = list ; lp ; lp = lp->next) {
    650 		setvareq(savestr(lp->text), flags);
    651 	}
    652 	INTON;
    653 }
    654 
    655 void
    656 listmklocal(struct strlist *list, int flags)
    657 {
    658 	struct strlist *lp;
    659 
    660 	for (lp = list ; lp ; lp = lp->next)
    661 		mklocal(lp->text, flags);
    662 }
    663 
    664 
    665 /*
    666  * Find the value of a variable.  Returns NULL if not set.
    667  */
    668 
    669 char *
    670 lookupvar(const char *name)
    671 {
    672 	struct var *v;
    673 	char *p;
    674 
    675 	v = find_var(name, NULL, NULL);
    676 	if (v == NULL || v->flags & VUNSET)
    677 		return NULL;
    678 	if (v->rfunc && (v->flags & VFUNCREF) != 0) {
    679 		p = (*v->rfunc)(v);
    680 		if (p == NULL)
    681 			return NULL;
    682 	} else
    683 		p = v->text;
    684 
    685 	return p + v->name_len + 1;
    686 }
    687 
    688 
    689 
    690 /*
    691  * Search the environment of a builtin command.  If the second argument
    692  * is nonzero, return the value of a variable even if it hasn't been
    693  * exported.
    694  */
    695 
    696 char *
    697 bltinlookup(const char *name, int doall)
    698 {
    699 	struct strlist *sp;
    700 	struct var *v;
    701 	char *p;
    702 
    703 	for (sp = cmdenviron ; sp ; sp = sp->next) {
    704 		if (strequal(sp->text, name))
    705 			return strchr(sp->text, '=') + 1;
    706 	}
    707 
    708 	v = find_var(name, NULL, NULL);
    709 
    710 	if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
    711 		return NULL;
    712 
    713 	if (v->rfunc && (v->flags & VFUNCREF) != 0) {
    714 		p = (*v->rfunc)(v);
    715 		if (p == NULL)
    716 			return NULL;
    717 	} else
    718 		p = v->text;
    719 
    720 	return p + v->name_len + 1;
    721 }
    722 
    723 
    724 
    725 /*
    726  * Generate a list of exported variables.  This routine is used to construct
    727  * the third argument to execve when executing a program.
    728  */
    729 
    730 char **
    731 environment(void)
    732 {
    733 	int nenv;
    734 	struct var **vpp;
    735 	struct var *vp;
    736 	char **env;
    737 	char **ep;
    738 
    739 	nenv = 0;
    740 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    741 		for (vp = *vpp ; vp ; vp = vp->next)
    742 			if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT)
    743 				nenv++;
    744 	}
    745 	CTRACE(DBG_VARS, ("environment: %d vars to export\n", nenv));
    746 	ep = env = stalloc((nenv + 1) * sizeof *env);
    747 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    748 		for (vp = *vpp ; vp ; vp = vp->next)
    749 			if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) {
    750 				if (vp->rfunc && (vp->flags & VFUNCREF)) {
    751 					*ep = (*vp->rfunc)(vp);
    752 					if (*ep != NULL)
    753 						ep++;
    754 				} else
    755 					*ep++ = vp->text;
    756 				VTRACE(DBG_VARS, ("environment: %s\n", ep[-1]));
    757 			}
    758 	}
    759 	*ep = NULL;
    760 	return env;
    761 }
    762 
    763 
    764 /*
    765  * Called when a shell procedure is invoked to clear out nonexported
    766  * variables.  It is also necessary to reallocate variables of with
    767  * VSTACK set since these are currently allocated on the stack.
    768  */
    769 
    770 #ifdef mkinit
    771 void shprocvar(void);
    772 
    773 SHELLPROC {
    774 	shprocvar();
    775 }
    776 #endif
    777 
    778 void
    779 shprocvar(void)
    780 {
    781 	struct var **vpp;
    782 	struct var *vp, **prev;
    783 
    784 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    785 		for (prev = vpp ; (vp = *prev) != NULL ; ) {
    786 			if ((vp->flags & VEXPORT) == 0) {
    787 				*prev = vp->next;
    788 				if ((vp->flags & VTEXTFIXED) == 0)
    789 					ckfree(vp->text);
    790 				if ((vp->flags & VSTRFIXED) == 0)
    791 					ckfree(vp);
    792 			} else {
    793 				if (vp->flags & VSTACK) {
    794 					vp->text = savestr(vp->text);
    795 					vp->flags &=~ VSTACK;
    796 				}
    797 				prev = &vp->next;
    798 			}
    799 		}
    800 	}
    801 	initvar();
    802 }
    803 
    804 
    805 
    806 /*
    807  * Command to list all variables which are set.  Currently this command
    808  * is invoked from the set command when the set command is called without
    809  * any variables.
    810  */
    811 
    812 void
    813 print_quoted(const char *p)
    814 {
    815 	const char *q;
    816 
    817 	if (p[0] == '\0') {
    818 		out1fmt("''");
    819 		return;
    820 	}
    821 	if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
    822 		out1fmt("%s", p);
    823 		return;
    824 	}
    825 	while (*p) {
    826 		if (*p == '\'') {
    827 			out1fmt("\\'");
    828 			p++;
    829 			continue;
    830 		}
    831 		q = strchr(p, '\'');
    832 		if (!q) {
    833 			out1fmt("'%s'", p );
    834 			return;
    835 		}
    836 		out1fmt("'%.*s'", (int)(q - p), p );
    837 		p = q;
    838 	}
    839 }
    840 
    841 static int
    842 sort_var(const void *v_v1, const void *v_v2)
    843 {
    844 	const struct var * const *v1 = v_v1;
    845 	const struct var * const *v2 = v_v2;
    846 	char *t1 = (*v1)->text, *t2 = (*v2)->text;
    847 
    848 	/*
    849 	 * Note that we really just want return strcoll(t1, t2) here
    850 	 * but we can't do that, as the strings are '=' terminated,
    851 	 * not \0 terminated (there is a \0 later) - and we must not
    852 	 * alter them.   This causes problems if v1 is "x0" and v2 "x"
    853 	 * as those are actually "x0=" and "x=", and since '0' < '='
    854 	 * that causes x0 to sort ahead of x which is backwards.
    855 	 *
    856 	 * So we need to fix that - but it only matters when the
    857 	 * one string is a substring of the other (if they differ
    858 	 * before either ends, that difference will correctly order
    859 	 * the strings).   To avoid too much extra work, we use the
    860 	 * fact that we know the strings are variable names.  This
    861 	 * means that they must contain at least 1 character, and
    862 	 * the names can only be equal if the var structs are the
    863 	 * same thing.
    864 	 */
    865 
    866 	 if (__predict_false(*v1 == *v2))	/* same pointers */
    867 		return 0;			/* must be the same name */
    868 
    869 	/*
    870 	 * But only 1 name char is guaranteed, so we see if the two
    871 	 * names have the same first char, if not, then strcoll()
    872 	 * will work, and we just use it (makes sure the locale collating
    873 	 * sequence is used, rather than simply comparing the bytes.)
    874 	 * (nb: that strcoll() doesn't actually use locales on NetBSD
    875 	 * is irrelevant.)
    876 	 *
    877 	 * If the first char is the same, then we must make sure that the
    878 	 * shorter name is \0 terminated, so if the names happen to be
    879 	 * equal to that point (the shorter is a substring of the longer)
    880 	 * then then shorter will always compare less.
    881 	 *
    882 	 * We do that by copying the shorter to the stack, null terminating
    883 	 * it, and comparing that copy to the longer name
    884 	 */
    885 
    886 	if (__predict_false(*t1 == *t2)) {
    887 		char *p, *s;
    888 
    889 		STARTSTACKSTR(p);
    890 
    891 		/*
    892 		 * note: if lengths are equal, strings must be different
    893 		 * so we don't care which string we pick for the \0 in
    894 		 * that case (the comparison won't reach that far).
    895 		 */
    896 		if ((*v1)->name_len <= (*v2)->name_len) {
    897 			CHECKSTRSPACE((*v1)->name_len + 1, p);
    898 			s = t1;
    899 			t1 = p;
    900 		} else {
    901 			CHECKSTRSPACE((*v2)->name_len + 1, p);
    902 			s = t2;
    903 			t2 = p;
    904 		}
    905 
    906 		/*
    907 		 * MUST use CHECKSTRSPACE() (above) and USTPUTC() here
    908 		 * as STPUTC() may reallocate the buffer (p) which we
    909 		 * already saved in t1 (or t2) above - leading to the
    910 		 * strcoll() below looking at garbage.  USTPUTC() is safe.
    911 		 */
    912 		while (*s && *s != '=') {
    913 			USTPUTC(*s, p);
    914 			s++;
    915 		}
    916 		USTPUTC('\0', p);
    917 	}
    918 
    919 	return strcoll(t1, t2);
    920 }
    921 
    922 /*
    923  * POSIX requires that 'set' (but not export or readonly) output the
    924  * variables in lexicographic order - by the locale's collating order (sigh).
    925  * Maybe we could keep them in an ordered balanced binary tree
    926  * instead of hashed lists.
    927  * For now just roll 'em through qsort for printing...
    928  */
    929 
    930 STATIC void
    931 showvar(struct var *vp, const char *cmd, const char *xtra, int show_value)
    932 {
    933 	const char *p;
    934 
    935 	p = vp->text;
    936 	if (vp->rfunc && (vp->flags & VFUNCREF) != 0) {
    937 		p = (*vp->rfunc)(vp);
    938 		if (p == NULL) {
    939 			if (!(show_value & 2))
    940 				return;
    941 			p = vp->text;
    942 			show_value = 0;
    943 		}
    944 	}
    945 	if (cmd)
    946 		out1fmt("%s ", cmd);
    947 	if (xtra)
    948 		out1fmt("%s ", xtra);
    949 	for ( ; *p != '=' ; p++)
    950 		out1c(*p);
    951 	if (!(vp->flags & VUNSET) && show_value) {
    952 		out1fmt("=");
    953 		print_quoted(++p);
    954 	}
    955 	out1c('\n');
    956 }
    957 
    958 int
    959 showvars(const char *cmd, int flag, int show_value, const char *xtra)
    960 {
    961 	struct var **vpp;
    962 	struct var *vp;
    963 
    964 	static struct var **list;	/* static in case we are interrupted */
    965 	static int list_len;
    966 	int count = 0;
    967 
    968 	if (!list) {
    969 		list_len = 32;
    970 		list = ckmalloc(list_len * sizeof *list);
    971 	}
    972 
    973 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    974 		for (vp = *vpp ; vp ; vp = vp->next) {
    975 			if (flag && !(vp->flags & flag))
    976 				continue;
    977 			if (vp->flags & VUNSET && !(show_value & 2))
    978 				continue;
    979 			if (count >= list_len) {
    980 				list = ckrealloc(list,
    981 					(list_len << 1) * sizeof *list);
    982 				list_len <<= 1;
    983 			}
    984 			list[count++] = vp;
    985 		}
    986 	}
    987 
    988 	qsort(list, count, sizeof *list, sort_var);
    989 
    990 	for (vpp = list; count--; vpp++)
    991 		showvar(*vpp, cmd, xtra, show_value);
    992 
    993 	/* no free(list), will be used again next time ... */
    994 
    995 	return 0;
    996 }
    997 
    998 
    999 
   1000 /*
   1001  * The export and readonly commands.
   1002  */
   1003 
   1004 static void __dead
   1005 export_usage(const char *cmd)
   1006 {
   1007 #ifdef SMALL
   1008 	if (*cmd == 'r')
   1009 	    error("Usage: %s [ -p | var[=val]... ]", cmd);
   1010 	else
   1011 	    error("Usage: %s [ -p | [-n] var[=val]... ]", cmd);
   1012 #else
   1013 	if (*cmd == 'r')
   1014 	    error("Usage: %s [-p [var...] | -q var... | var[=val]... ]", cmd);
   1015 	else
   1016 	    error(
   1017 	     "Usage: %s [ -px [var...] | -q[x] var... | [-n|x] var[=val]... ]",
   1018 		cmd);
   1019 #endif
   1020 }
   1021 
   1022 int
   1023 exportcmd(int argc, char **argv)
   1024 {
   1025 	struct var *vp;
   1026 	char *name;
   1027 	const char *p = argv[0];
   1028 	int flag = p[0] == 'r'? VREADONLY : VEXPORT;
   1029 	int pflg = 0;
   1030 	int nflg = 0;
   1031 #ifndef SMALL
   1032 	int xflg = 0;
   1033 	int qflg = 0;
   1034 #endif
   1035 	int res;
   1036 	int c;
   1037 	int f;
   1038 
   1039 #ifdef SMALL
   1040 #define EXPORT_OPTS "np"
   1041 #else
   1042 #define	EXPORT_OPTS "npqx"
   1043 #endif
   1044 
   1045 	while ((c = nextopt(EXPORT_OPTS)) != '\0') {
   1046 
   1047 #undef EXPORT_OPTS
   1048 
   1049 		switch (c) {
   1050 		case 'n':
   1051 			if (pflg || flag == VREADONLY
   1052 #ifndef SMALL
   1053 				|| qflg || xflg
   1054 #endif
   1055 						)
   1056 				export_usage(p);
   1057 			nflg = 1;
   1058 			break;
   1059 		case 'p':
   1060 			if (nflg
   1061 #ifndef SMALL
   1062 				|| qflg
   1063 #endif
   1064 					)
   1065 				export_usage(p);
   1066 			pflg = 3;
   1067 			break;
   1068 #ifndef SMALL
   1069 		case 'q':
   1070 			if (nflg || pflg)
   1071 				export_usage(p);
   1072 			qflg = 1;
   1073 			break;
   1074 		case 'x':
   1075 			if (nflg || flag == VREADONLY)
   1076 				export_usage(p);
   1077 			flag = VNOEXPORT;
   1078 			xflg = 1;
   1079 			break;
   1080 #endif
   1081 		}
   1082 	}
   1083 
   1084 	if ((nflg
   1085 #ifndef SMALL
   1086 		|| qflg
   1087 #endif
   1088 		 ) && *argptr == NULL)
   1089 		export_usage(p);
   1090 
   1091 #ifndef SMALL
   1092 	if (pflg && *argptr != NULL) {
   1093 		while ((name = *argptr++) != NULL) {
   1094 			int len;
   1095 
   1096 			vp = find_var(name, NULL, &len);
   1097 			if (name[len] == '=')
   1098 				export_usage(p);
   1099 			if (!goodname(name))
   1100 				error("%s: bad variable name", name);
   1101 
   1102 			if (vp && vp->flags & flag)
   1103 				showvar(vp, p, xflg ? "-x" : NULL, 1);
   1104 		}
   1105 		return 0;
   1106 	}
   1107 #endif
   1108 
   1109 	if (pflg || *argptr == NULL)
   1110 		return showvars( pflg ? p : 0, flag, pflg,
   1111 #ifndef SMALL
   1112 		    pflg && xflg ? "-x" :
   1113 #endif
   1114 					    NULL );
   1115 
   1116 	res = 0;
   1117 #ifndef SMALL
   1118 	if (qflg) {
   1119 		while ((name = *argptr++) != NULL) {
   1120 			int len;
   1121 
   1122 			vp = find_var(name, NULL, &len);
   1123 			if (name[len] == '=')
   1124 				export_usage(p);
   1125 			if (!goodname(name))
   1126 				error("%s: bad variable name", name);
   1127 
   1128 			if (vp == NULL || !(vp->flags & flag))
   1129 				res = 1;
   1130 		}
   1131 		return res;
   1132 	}
   1133 #endif
   1134 
   1135 	while ((name = *argptr++) != NULL) {
   1136 		int len;
   1137 
   1138 		f = flag;
   1139 
   1140 		vp = find_var(name, NULL, &len);
   1141 		p = name + len;
   1142 		if (*p++ != '=')
   1143 			p = NULL;
   1144 
   1145 		if (vp != NULL) {
   1146 			if (nflg)
   1147 				vp->flags &= ~flag;
   1148 			else if (flag&VEXPORT && vp->flags&VNOEXPORT) {
   1149 				/* note we go ahead and do any assignment */
   1150 				sh_warnx("%.*s: not available for export",
   1151 				    len, name);
   1152 				res = 1;
   1153 			} else {
   1154 				if (flag == VNOEXPORT)
   1155 					vp->flags &= ~VEXPORT;
   1156 
   1157 				/* if not NULL will be done in setvar below */
   1158 				if (p == NULL)
   1159 					vp->flags |= flag;
   1160 			}
   1161 			if (p == NULL)
   1162 				continue;
   1163 		} else if (nflg && p == NULL && !goodname(name))
   1164 			error("%s: bad variable name", name);
   1165 
   1166 		if (!nflg || p != NULL)
   1167 			setvar(name, p, f);
   1168 	}
   1169 	return res;
   1170 }
   1171 
   1172 
   1173 /*
   1174  * The "local" command.
   1175  */
   1176 
   1177 int
   1178 localcmd(int argc, char **argv)
   1179 {
   1180 	char *name;
   1181 	int c;
   1182 	int flags = 0;		/*XXX perhaps VUNSET from a -o option value */
   1183 
   1184 	if (! in_function())
   1185 		error("Not in a function");
   1186 
   1187 	/* upper case options, as bash stole all the good ones ... */
   1188 	while ((c = nextopt("INx")) != '\0')
   1189 		switch (c) {
   1190 		case 'I':	flags &= ~VUNSET;	break;
   1191 		case 'N':	flags |= VUNSET;	break;
   1192 		case 'x':	flags |= VEXPORT;	break;
   1193 		}
   1194 
   1195 	while ((name = *argptr++) != NULL) {
   1196 		mklocal(name, flags);
   1197 	}
   1198 	return 0;
   1199 }
   1200 
   1201 
   1202 /*
   1203  * Make a variable a local variable.  When a variable is made local, its
   1204  * value and flags are saved in a localvar structure.  The saved values
   1205  * will be restored when the shell function returns.  We handle the name
   1206  * "-" as a special case.
   1207  */
   1208 
   1209 void
   1210 mklocal(const char *name, int flags)
   1211 {
   1212 	struct localvar *lvp;
   1213 	struct var **vpp;
   1214 	struct var *vp;
   1215 
   1216 	INTOFF;
   1217 	lvp = ckmalloc(sizeof (struct localvar));
   1218 	if (name[0] == '-' && name[1] == '\0') {
   1219 		char *p;
   1220 		p = ckmalloc(sizeof_optlist);
   1221 		lvp->text = memcpy(p, optlist, sizeof_optlist);
   1222 		lvp->rfunc = NULL;
   1223 		vp = NULL;
   1224 		xtrace_clone(0);
   1225 	} else {
   1226 		vp = find_var(name, &vpp, NULL);
   1227 		if (vp == NULL) {
   1228 			flags &= ~VNOEXPORT;
   1229 			if (strchr(name, '='))
   1230 				setvareq(savestr(name),
   1231 				    VSTRFIXED | (flags & ~VUNSET));
   1232 			else
   1233 				setvar(name, NULL, VSTRFIXED|flags);
   1234 			vp = *vpp;	/* the new variable */
   1235 			lvp->text = NULL;
   1236 			lvp->flags = VUNSET;
   1237 			lvp->rfunc = NULL;
   1238 		} else {
   1239 			lvp->text = vp->text;
   1240 			lvp->flags = vp->flags;
   1241 			lvp->v_u = vp->v_u;
   1242 			vp->flags |= VSTRFIXED|VTEXTFIXED;
   1243 			if (flags & (VDOEXPORT | VUNSET))
   1244 				vp->flags &= ~VNOEXPORT;
   1245 			if (vp->flags & VNOEXPORT &&
   1246 			    (flags & (VEXPORT|VDOEXPORT|VUNSET)) == VEXPORT)
   1247 				flags &= ~VEXPORT;
   1248 			if (flags & (VNOEXPORT | VUNSET))
   1249 				vp->flags &= ~VEXPORT;
   1250 			flags &= ~VNOEXPORT;
   1251 			if (name[vp->name_len] == '=')
   1252 				setvareq(savestr(name), flags & ~VUNSET);
   1253 			else if (flags & VUNSET)
   1254 				unsetvar(name, 0);
   1255 			else
   1256 				vp->flags |= flags & (VUNSET|VEXPORT);
   1257 
   1258 			if (vp == &line_num) {
   1259 				if (name[vp->name_len] == '=')
   1260 					funclinebase = funclineabs -1;
   1261 				else
   1262 					funclinebase = 0;
   1263 			}
   1264 		}
   1265 	}
   1266 	lvp->vp = vp;
   1267 	lvp->next = localvars;
   1268 	localvars = lvp;
   1269 	INTON;
   1270 }
   1271 
   1272 
   1273 /*
   1274  * Called after a function returns.
   1275  */
   1276 
   1277 void
   1278 poplocalvars(void)
   1279 {
   1280 	struct localvar *lvp;
   1281 	struct var *vp;
   1282 
   1283 	while ((lvp = localvars) != NULL) {
   1284 		localvars = lvp->next;
   1285 		vp = lvp->vp;
   1286 		VTRACE(DBG_VARS, ("poplocalvar %s\n", vp ? vp->text : "-"));
   1287 		if (vp == NULL) {	/* $- saved */
   1288 			memcpy(optlist, lvp->text, sizeof_optlist);
   1289 			ckfree(lvp->text);
   1290 			xtrace_pop();
   1291 			optschanged();
   1292 		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
   1293 			(void)unsetvar(vp->text, 0);
   1294 		} else {
   1295 			if (lvp->func && (lvp->flags & (VNOFUNC|VFUNCREF)) == 0)
   1296 				(*lvp->func)(lvp->text + vp->name_len + 1,
   1297 				    lvp->flags, lvp->vp);
   1298 			if ((vp->flags & VTEXTFIXED) == 0)
   1299 				ckfree(vp->text);
   1300 			vp->flags = lvp->flags;
   1301 			vp->text = lvp->text;
   1302 			vp->v_u = lvp->v_u;
   1303 		}
   1304 		ckfree(lvp);
   1305 	}
   1306 }
   1307 
   1308 
   1309 int
   1310 setvarcmd(int argc, char **argv)
   1311 {
   1312 	if (argc <= 2)
   1313 		return unsetcmd(argc, argv);
   1314 	else if (argc == 3)
   1315 		setvar(argv[1], argv[2], 0);
   1316 	else
   1317 		error("List assignment not implemented");
   1318 	return 0;
   1319 }
   1320 
   1321 
   1322 /*
   1323  * The unset builtin command.  We unset the function before we unset the
   1324  * variable to allow a function to be unset when there is a readonly variable
   1325  * with the same name.
   1326  */
   1327 
   1328 int
   1329 unsetcmd(int argc, char **argv)
   1330 {
   1331 	char **ap;
   1332 	int i;
   1333 	int flg_func = 0;
   1334 	int flg_var = 0;
   1335 	int flg_x = 0;
   1336 	int ret = 0;
   1337 
   1338 	while ((i = nextopt("efvx")) != '\0') {
   1339 		switch (i) {
   1340 		case 'f':
   1341 			flg_func = 1;
   1342 			break;
   1343 		case 'e':
   1344 		case 'x':
   1345 			flg_x = (2 >> (i == 'e'));
   1346 			/* FALLTHROUGH */
   1347 		case 'v':
   1348 			flg_var = 1;
   1349 			break;
   1350 		}
   1351 	}
   1352 
   1353 	if (flg_func == 0 && flg_var == 0)
   1354 		flg_var = 1;
   1355 
   1356 	for (ap = argptr; *ap ; ap++) {
   1357 		if (flg_func)
   1358 			ret |= unsetfunc(*ap);
   1359 		if (flg_var)
   1360 			ret |= unsetvar(*ap, flg_x);
   1361 	}
   1362 	return ret;
   1363 }
   1364 
   1365 
   1366 /*
   1367  * Unset the specified variable.
   1368  */
   1369 
   1370 int
   1371 unsetvar(const char *s, int unexport)
   1372 {
   1373 	struct var **vpp;
   1374 	struct var *vp;
   1375 
   1376 	vp = find_var(s, &vpp, NULL);
   1377 	if (vp == NULL)
   1378 		return 0;
   1379 
   1380 	if (vp->flags & VREADONLY && !(unexport & 1))
   1381 		return 1;
   1382 
   1383 	INTOFF;
   1384 	if (unexport & 1) {
   1385 		vp->flags &= ~VEXPORT;
   1386 	} else {
   1387 		if (vp->text[vp->name_len + 1] != '\0' || !(vp->flags & VUNSET))
   1388 			setvar(s, nullstr, VUNSET);
   1389 		if (!(unexport & 2))
   1390 			vp->flags &= ~VEXPORT;
   1391 		vp->flags |= VUNSET;
   1392 		if ((vp->flags&(VEXPORT|VSTRFIXED|VREADONLY|VNOEXPORT)) == 0) {
   1393 			if ((vp->flags & VTEXTFIXED) == 0)
   1394 				ckfree(vp->text);
   1395 			*vpp = vp->next;
   1396 			ckfree(vp);
   1397 		}
   1398 	}
   1399 	INTON;
   1400 	return 0;
   1401 }
   1402 
   1403 
   1404 /*
   1405  * Returns true if the two strings specify the same variable.  The first
   1406  * variable name is terminated by '='; the second may be terminated by
   1407  * either '=' or '\0'.
   1408  */
   1409 
   1410 STATIC int
   1411 strequal(const char *p, const char *q)
   1412 {
   1413 	while (*p == *q++) {
   1414 		if (*p++ == '=')
   1415 			return 1;
   1416 	}
   1417 	if (*p == '=' && *(q - 1) == '\0')
   1418 		return 1;
   1419 	return 0;
   1420 }
   1421 
   1422 /*
   1423  * Search for a variable.
   1424  * 'name' may be terminated by '=' or a NUL.
   1425  * vppp is set to the pointer to vp, or the list head if vp isn't found
   1426  * lenp is set to the number of characters in 'name'
   1427  */
   1428 
   1429 STATIC struct var *
   1430 find_var(const char *name, struct var ***vppp, int *lenp)
   1431 {
   1432 	unsigned int hashval;
   1433 	int len;
   1434 	struct var *vp, **vpp;
   1435 	const char *p = name;
   1436 
   1437 	hashval = 0;
   1438 	while (*p && *p != '=')
   1439 		hashval = 2 * hashval + (unsigned char)*p++;
   1440 
   1441 	len = p - name;
   1442 	if (lenp)
   1443 		*lenp = len;
   1444 
   1445 	if (len == 0)
   1446 		return NULL;
   1447 
   1448 	vpp = &vartab[hashval % VTABSIZE];
   1449 	if (vppp)
   1450 		*vppp = vpp;
   1451 
   1452 	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
   1453 		if (vp->name_len != len)
   1454 			continue;
   1455 		if (memcmp(vp->text, name, len) != 0)
   1456 			continue;
   1457 		if (vppp)
   1458 			*vppp = vpp;
   1459 		return vp;
   1460 	}
   1461 	return NULL;
   1462 }
   1463 
   1464 /*
   1465  * The following are the functions that create the values for
   1466  * shell variables that are dynamically produced when needed.
   1467  *
   1468  * The output strings cannot be malloc'd as there is nothing to
   1469  * free them - callers assume these are ordinary variables where
   1470  * the value returned is vp->text
   1471  *
   1472  * Each function needs its own storage space, as the results are
   1473  * used to create processes' environment, and (if exported) all
   1474  * the values will (might) be needed simultaneously.
   1475  *
   1476  * It is not a problem if a var is updated while nominally in use
   1477  * somewhere, all these are intended to be dynamic, the value they
   1478  * return is not guaranteed, an updated value is just as good.
   1479  *
   1480  * So, malloc a single buffer for the result of each function,
   1481  * grow, and even shrink, it as needed, but once we have one that
   1482  * is a suitable size for the actual usage, simply hold it forever.
   1483  *
   1484  * For a SMALL shell we implement only LINENO, none of the others,
   1485  * and give it just a fixed length static buffer for its result.
   1486  */
   1487 
   1488 #ifndef SMALL
   1489 
   1490 struct space_reserved {		/* record of space allocated for results */
   1491 	char *b;
   1492 	int len;
   1493 };
   1494 
   1495 /* rough (over-)estimate of the number of bytes needed to hold a number */
   1496 static int
   1497 digits_in(intmax_t number)
   1498 {
   1499 	int res = 0;
   1500 
   1501 	if (number & ~((1LL << 62) - 1))
   1502 		res = 64;	/* enough for 2^200 and a bit more */
   1503 	else if (number & ~((1LL << 32) - 1))
   1504 		res = 20;	/* enough for 2^64 */
   1505 	else if (number & ~((1 << 23) - 1))
   1506 		res = 10;	/* enough for 2^32 */
   1507 	else
   1508 		res = 8;	/* enough for 2^23 or smaller */
   1509 
   1510 	return res;
   1511 }
   1512 
   1513 static int
   1514 make_space(struct space_reserved *m, int bytes)
   1515 {
   1516 	void *p;
   1517 
   1518 	if (m->len >= bytes && m->len <= (bytes<<2))
   1519 		return 1;
   1520 
   1521 	bytes = SHELL_ALIGN(bytes);
   1522 	INTOFF;
   1523 	/* not ckrealloc() - we want failure, not error() here */
   1524 	p = realloc(m->b, bytes);
   1525 	if (p != NULL) {
   1526 		m->b = p;
   1527 		m->len = bytes;
   1528 		m->b[bytes - 1] = '\0';
   1529 	}
   1530 	INTON;
   1531 
   1532 	return p != NULL;
   1533 }
   1534 #endif
   1535 
   1536 char *
   1537 get_lineno(struct var *vp)
   1538 {
   1539 #ifdef SMALL
   1540 #define length (8 + 10)		/* 10 digits is enough for a 32 bit line num */
   1541 	static char result[length];
   1542 #else
   1543 	static struct space_reserved buf;
   1544 #define result buf.b
   1545 #define length buf.len
   1546 #endif
   1547 	int ln = line_number;
   1548 
   1549 	if (vp->flags & VUNSET)
   1550 		return NULL;
   1551 
   1552 	ln -= funclinebase;
   1553 
   1554 #ifndef SMALL
   1555 	if (!make_space(&buf, vp->name_len + 2 + digits_in(ln)))
   1556 		return vp->text;
   1557 #endif
   1558 
   1559 	snprintf(result, length, "%.*s=%d", vp->name_len, vp->text, ln);
   1560 	return result;
   1561 }
   1562 #undef result
   1563 #undef length
   1564 
   1565 #ifndef SMALL
   1566 
   1567 char *
   1568 get_hostname(struct var *vp)
   1569 {
   1570 	static struct space_reserved buf;
   1571 
   1572 	if (vp->flags & VUNSET)
   1573 		return NULL;
   1574 
   1575 	if (!make_space(&buf, vp->name_len + 2 + 256))
   1576 		return vp->text;
   1577 
   1578 	memcpy(buf.b, vp->text, vp->name_len + 1);	/* include '=' */
   1579 	(void)gethostname(buf.b + vp->name_len + 1,
   1580 	    buf.len - vp->name_len - 3);
   1581 	return buf.b;
   1582 }
   1583 
   1584 char *
   1585 get_tod(struct var *vp)
   1586 {
   1587 	static struct space_reserved buf;	/* space for answers */
   1588 	static struct space_reserved tzs;	/* remember TZ last used */
   1589 	static timezone_t last_zone;		/* timezone data for tzs zone */
   1590 	const char *fmt;
   1591 	char *tz;
   1592 	time_t now;
   1593 	struct tm tm_now, *tmp;
   1594 	timezone_t zone = NULL;
   1595 	static char t_err[] = "time error";
   1596 	int len;
   1597 
   1598 	if (vp->flags & VUNSET)
   1599 		return NULL;
   1600 
   1601 	fmt = lookupvar("ToD_FORMAT");
   1602 	if (fmt == NULL)
   1603 		fmt="%T";
   1604 	tz = lookupvar("TZ");
   1605 	(void)time(&now);
   1606 
   1607 	if (tz != NULL) {
   1608 		if (tzs.b == NULL || strcmp(tzs.b, tz) != 0) {
   1609 			INTOFF;
   1610 			if (make_space(&tzs, strlen(tz) + 1)) {
   1611 				strcpy(tzs.b, tz);
   1612 				if (last_zone)
   1613 					tzfree(last_zone);
   1614 				last_zone = zone = tzalloc(tz);
   1615 				INTON;
   1616 			} else
   1617 				zone = tzalloc(tz);
   1618 		} else
   1619 			zone = last_zone;
   1620 
   1621 		tmp = localtime_rz(zone, &now, &tm_now);
   1622 	} else
   1623 		tmp = localtime_r(&now, &tm_now);
   1624 
   1625 	len = (strlen(fmt) * 4) + vp->name_len + 2;
   1626 	while (make_space(&buf, len)) {
   1627 		memcpy(buf.b, vp->text, vp->name_len+1);
   1628 		if (tmp == NULL) {
   1629 			if (buf.len >= vp->name_len+2+(int)(sizeof t_err - 1)) {
   1630 				strcpy(buf.b + vp->name_len + 1, t_err);
   1631 				if (zone && zone != last_zone) {
   1632 					tzfree(zone);
   1633 					INTON;
   1634 				}
   1635 				return buf.b;
   1636 			}
   1637 			len = vp->name_len + 4 + sizeof t_err - 1;
   1638 			continue;
   1639 		}
   1640 		if (zone != NULL) {
   1641 			if (strftime_z(zone, buf.b + vp->name_len + 1,
   1642 			     buf.len - vp->name_len - 2, fmt, tmp)) {
   1643 				if (zone != last_zone) {
   1644 					tzfree(zone);
   1645 					INTON;
   1646 				}
   1647 				return buf.b;
   1648 			}
   1649 		} else if (strftime(buf.b + vp->name_len + 1,
   1650 			    buf.len - vp->name_len - 2, fmt, tmp))
   1651 				return buf.b;
   1652 
   1653 		if (len >= 4096)	/* Let's be reasonable */
   1654 			break;
   1655 		len <<= 1;
   1656 	}
   1657 	if (zone && zone != last_zone) {
   1658 		tzfree(zone);
   1659 		INTON;
   1660 	}
   1661 	return vp->text;
   1662 }
   1663 
   1664 char *
   1665 get_seconds(struct var *vp)
   1666 {
   1667 	static struct space_reserved buf;
   1668 	intmax_t secs;
   1669 
   1670 	if (vp->flags & VUNSET)
   1671 		return NULL;
   1672 
   1673 	secs = (intmax_t)time((time_t *)0) - sh_start_time;
   1674 	if (!make_space(&buf, vp->name_len + 2 + digits_in(secs)))
   1675 		return vp->text;
   1676 
   1677 	snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs);
   1678 	return buf.b;
   1679 }
   1680 
   1681 char *
   1682 get_euser(struct var *vp)
   1683 {
   1684 	static struct space_reserved buf;
   1685 	static uid_t lastuid = 0;
   1686 	uid_t euid;
   1687 	struct passwd *pw;
   1688 
   1689 	if (vp->flags & VUNSET)
   1690 		return NULL;
   1691 
   1692 	euid = geteuid();
   1693 	if (buf.b != NULL && lastuid == euid)
   1694 		return buf.b;
   1695 
   1696 	pw = getpwuid(euid);
   1697 	if (pw == NULL)
   1698 		return vp->text;
   1699 
   1700 	if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) {
   1701 		INTOFF;
   1702 		lastuid = euid;
   1703 		snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text,
   1704 		    pw->pw_name);
   1705 		INTON;
   1706 		return buf.b;
   1707 	}
   1708 
   1709 	return vp->text;
   1710 }
   1711 
   1712 char *
   1713 get_random(struct var *vp)
   1714 {
   1715 	static struct space_reserved buf;
   1716 	static intmax_t random_val = 0;
   1717 
   1718 #ifdef USE_LRAND48
   1719 #define random lrand48
   1720 #define srandom srand48
   1721 #endif
   1722 
   1723 	if (vp->flags & VUNSET)
   1724 		return NULL;
   1725 
   1726 	if (vp->text != buf.b) {
   1727 		/*
   1728 		 * Either initialisation, or a new seed has been set
   1729 		 */
   1730 		if (vp->text[vp->name_len + 1] == '\0') {
   1731 			int fd;
   1732 
   1733 			/*
   1734 			 * initialisation (without pre-seeding),
   1735 			 * or explicitly requesting a truly random seed.
   1736 			 */
   1737 			INTOFF;
   1738 			fd = open("/dev/urandom", 0);
   1739 			if (fd == -1) {
   1740 				out2str("RANDOM initialisation failed\n");
   1741 				random_val = (getpid()<<3) ^ time((time_t *)0);
   1742 			} else {
   1743 				int n;
   1744 
   1745 				do {
   1746 				    n = read(fd,&random_val,sizeof random_val);
   1747 				} while (n != sizeof random_val);
   1748 				close(fd);
   1749 			}
   1750 			INTON;
   1751 		} else
   1752 			/* good enough for today */
   1753 			random_val = strtoimax(vp->text+vp->name_len+1,NULL,0);
   1754 
   1755 		srandom((long)random_val);
   1756 	}
   1757 
   1758 #if 0
   1759 	random_val = (random_val + 1) & 0x7FFF;	/* 15 bit "random" numbers */
   1760 #else
   1761 	random_val = (random() >> 5) & 0x7FFF;
   1762 #endif
   1763 
   1764 	if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val)))
   1765 		return vp->text;
   1766 
   1767 	snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text,
   1768 	    random_val);
   1769 
   1770 	INTOFF;
   1771 	if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0)
   1772 		free(vp->text);
   1773 	vp->flags |= VTEXTFIXED;
   1774 	vp->text = buf.b;
   1775 	INTON;
   1776 
   1777 	return vp->text;
   1778 #undef random
   1779 #undef srandom
   1780 }
   1781 
   1782 STATIC int
   1783 makespecial(const char *name)
   1784 {
   1785 	const struct varinit *ip;
   1786 	struct var *vp;
   1787 
   1788 	CTRACE(DBG_VARS, ("makespecial('%s') -> ", name));
   1789 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
   1790 		if (strequal(ip->text, name)) {
   1791 			if (!(ip->flags & VFUNCREF)) {
   1792 				CTRACE(DBG_VARS, ("+1\n"));
   1793 				return 1;
   1794 			}
   1795 			INTOFF;
   1796 			vp->flags &= ~VUNSET;
   1797 			vp->v_u = ip->v_u;
   1798 			INTON;
   1799 			CTRACE(DBG_VARS, ("0\n"));
   1800 			return 0;
   1801 		}
   1802 	}
   1803 	CTRACE(DBG_VARS, ("1\n"));
   1804 	return 1;
   1805 }
   1806 
   1807 int
   1808 specialvarcmd(int argc, char **argv)
   1809 {
   1810 	int res = 0;
   1811 	char **ap;
   1812 
   1813 	(void) nextopt("");
   1814 
   1815 	if (!*argptr)
   1816 		error("Usage: specialvar var...");
   1817 
   1818 	for (ap = argptr; *ap ; ap++)
   1819 		res |= makespecial(*ap);
   1820 
   1821 	return res;
   1822 }
   1823 
   1824 struct lc_vars {
   1825 	const char *name;
   1826 	int  category;
   1827 	struct var *vp;
   1828 };
   1829 
   1830 const struct lc_vars lc_vars[] = {
   1831 	{ .name= "LC_ALL",	.category= LC_ALL,	.vp= &lc_all	  },
   1832 
   1833 	{ .name= "LC_COLLATE",	.category= LC_COLLATE,	.vp= &lc_collate  },
   1834 	{ .name= "LC_CTYPE",	.category= LC_CTYPE,	.vp= &lc_ctype    },
   1835 	{ .name= "LC_MESSAGES",	.category= LC_MESSAGES,	.vp= &lc_messages },
   1836 	{ .name= "LC_MONETARY",	.category= LC_MONETARY,	.vp= &lc_monetary },
   1837 	{ .name= "LC_NUMERIC",	.category= LC_NUMERIC,	.vp= &lc_numeric  },
   1838 	{ .name= "LC_TIME",	.category= LC_TIME,	.vp= &lc_time     },
   1839 
   1840 	{ .name= "LANG",	.category= LC_ALL,	.vp= &lc_lang     },
   1841 
   1842 	{ .name= NULL,		.category= 0,		.vp= NULL	  }
   1843 };
   1844 
   1845 STATIC void
   1846 set_locale_var(const char *val, int flags, struct var *vp)
   1847 {
   1848 	const struct lc_vars *lv;
   1849 
   1850 	if (flags & VUNSAFE)	/* parsing the environment */
   1851 		return;		/* do nothing until later */
   1852 
   1853 	for (lv = lc_vars; lv->name != NULL;  lv++) {
   1854 		/* Find the var being altered */
   1855 		if (lv->vp != vp)
   1856 			continue;
   1857 
   1858 		if (flags & VUNSET) {
   1859 			/*
   1860 			 * If we are unsetting one of these, then
   1861 			 * we need to set the locale for the category
   1862 			 * back to a default value
   1863 			 */
   1864 
   1865 			if (lv->category == LC_ALL) {
   1866 				/*
   1867 				 * nb: the LC_ALL vars call this func
   1868 				 * after their value has changed, ie:
   1869 				 * since this is an unset,  the var already
   1870 				 * is unset.   This simplifies things.
   1871 				 */
   1872 
   1873 				/*
   1874 				 * LANG is just the default to use when
   1875 				 * nothing more specific is set, if it is
   1876 				 * unset, there is nothing to do.
   1877 				 */
   1878 				if (lv->vp == &lc_lang)
   1879 					return;
   1880 
   1881 				/*
   1882 				 * Otherwise LC_ALL must be being unset,
   1883 				 * in that case, simply set everything to
   1884 				 * the values obtained from the other
   1885 				 * LC_xxx  vars (with LANG as default)
   1886 				 */
   1887 				init_locale_vars();
   1888 				return;
   1889 			}
   1890 
   1891 			/*
   1892 			 * For the category vars, this func is called before
   1893 			 * the sh var is updated
   1894 			 */
   1895 
   1896 			/* If a category var previously was unset - easy case */
   1897 			if (lv->vp->flags & VUNSET)
   1898 				return;
   1899 
   1900 			/*
   1901 			 * One of the specific categories is being
   1902 			 * unset, in that case we fall back upon
   1903 			 * the value of LC_ALL if that is set, or
   1904 			 * otherwise the value of LANG, if that is set,
   1905 			 * or just set the "C" locale for this category
   1906 			 */
   1907 			vp = NULL;
   1908 			if (!(lc_all.flags & VUNSET))
   1909 				vp = &lc_all;
   1910 			else if (!(lc_lang.flags & VUNSET))
   1911 				vp = &lc_lang;
   1912 
   1913 			if (vp != NULL)
   1914 				val = vp->text + vp->name_len + 1;
   1915 			else
   1916 				val = "C";
   1917 
   1918 			set_locale_var(val, 0, lv->vp);
   1919 		} else {
   1920 			char *old;
   1921 
   1922 			if (lv->category == LC_ALL) {
   1923 				/*
   1924 				 * post call, so this var's value is
   1925 				 * already established, just go use
   1926 				 * it (and the others) to set all the
   1927 				 * categories
   1928 				 */
   1929 				init_locale_vars();
   1930 				return;
   1931 			}
   1932 
   1933 			/*
   1934 			 * Potentially changing the value of a specific
   1935 			 * category.
   1936 			 *
   1937 			 * If the value isn't actually changing, do nothing
   1938 			 */
   1939 			old = setlocale(lv->category, NULL);
   1940 			if (old != NULL && strcmp(old, val) != 0) {
   1941 				/*
   1942 				 * Otherwise update the shell's locale
   1943 				 * to match the new setting
   1944 				 */
   1945 				if (setlocale(lv->category, val) == NULL) {
   1946 		/*XXX NetBSD! */    if (lv->category != LC_COLLATE)
   1947 					outfmt(out2,
   1948 					    "Setting %s to '%s' failed"
   1949 					    " setlocale(3)\n", lv->name, val);
   1950 				} else if (lv->category == LC_CTYPE) {
   1951 					/*
   1952 					 * and if that worked,  and we're
   1953 					 * changing the char encodings,
   1954 					 * go re-init libedit (if in use)
   1955 					 */
   1956 					if (iflag && (Eflag || Vflag)) {
   1957 						int oE = Eflag, oV = Vflag;
   1958 
   1959 						/*
   1960 						  * re-init editing if
   1961 						  * LC_CTYPE changes
   1962 						  *
   1963 						  * easy way: disable, then
   1964 						  * enable again
   1965 						  */
   1966 						Eflag = Vflag = 0;
   1967 						histedit();
   1968 						Eflag = oE, Vflag=oV;
   1969 						histedit();
   1970 					}
   1971 				}
   1972 			}
   1973 
   1974 		}
   1975 		return;
   1976 	}
   1977 }
   1978 
   1979 void
   1980 init_locale_vars(void)
   1981 {
   1982 	const struct lc_vars *lv;
   1983 	const char *defval;
   1984 
   1985 	if (!(lc_all.flags & VUNSET)) {
   1986 		/*
   1987 		 * If LC_ALL is set, just use it, ignore others
   1988 		 * Simply set all categories to the value of LC_ALL
   1989 		 *
   1990 		 * nb: strlen("LC_ALL") + 1 == 7
   1991 		 */
   1992 		for (lv = lc_vars; lv->name != NULL; lv++) {
   1993 			if (lv->category == LC_ALL)
   1994 				continue;
   1995 			set_locale_var(lc_all.text + 7, 0, lv->vp);
   1996 		}
   1997 		return;
   1998 	}
   1999 
   2000 	/*
   2001 	 * Otherwise, for each specific category, set the value
   2002 	 * of its variable for that category, if that variable is
   2003 	 * set, otherwise we need a default for that category.
   2004 	 * If LANG is set, that gives the default, otherwise it is "C"
   2005 	 */
   2006 	if (lc_lang.flags & VUNSET)
   2007 		defval = "C";
   2008 	else
   2009 		defval = lc_lang.text + 5;   /* strlen("LANG") + 1 == 5 */
   2010 
   2011 	for (lv = lc_vars; lv->name != NULL; lv++) {
   2012 		/* ignore LC_ALL and LANG */
   2013 		if (lv->category == LC_ALL)
   2014 			continue;
   2015 		/* otherwise set the category to the appropriate value */
   2016 		set_locale_var( (lv->vp->flags & VUNSET ? defval :
   2017 			             lv->vp->text + lv->vp->name_len + 1),
   2018 			        0, lv->vp);
   2019 	}
   2020 }
   2021 
   2022 #endif /* SMALL */
   2023