Home | History | Annotate | Line # | Download | only in sh
var.c revision 1.83
      1 /*	$NetBSD: var.c,v 1.83 2024/07/12 07:30:30 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.83 2024/07/12 07:30:30 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 
     55 /*
     56  * Shell variables.
     57  */
     58 
     59 #include "shell.h"
     60 #include "output.h"
     61 #include "expand.h"
     62 #include "nodes.h"	/* for other headers */
     63 #include "eval.h"	/* defines cmdenviron */
     64 #include "exec.h"
     65 #include "syntax.h"
     66 #include "options.h"
     67 #include "builtins.h"
     68 #include "mail.h"
     69 #include "var.h"
     70 #include "memalloc.h"
     71 #include "error.h"
     72 #include "mystring.h"
     73 #include "parser.h"
     74 #include "show.h"
     75 #include "machdep.h"
     76 #ifndef SMALL
     77 #include "myhistedit.h"
     78 #endif
     79 
     80 #ifdef SMALL
     81 #define VTABSIZE 39
     82 #else
     83 #define VTABSIZE 517
     84 #endif
     85 
     86 
     87 struct varinit {
     88 	struct var *var;
     89 	int flags;
     90 	const char *text;
     91 	union var_func_union v_u;
     92 };
     93 #define	func v_u.set_func
     94 #define	rfunc v_u.ref_func
     95 
     96 char *get_lineno(struct var *);
     97 
     98 #ifndef SMALL
     99 char *get_tod(struct var *);
    100 char *get_hostname(struct var *);
    101 char *get_seconds(struct var *);
    102 char *get_euser(struct var *);
    103 char *get_random(struct var *);
    104 #endif
    105 
    106 struct localvar *localvars;
    107 
    108 #ifndef SMALL
    109 struct var vhistsize;
    110 struct var vterm;
    111 struct var editrc;
    112 struct var ps_lit;
    113 #endif
    114 struct var vifs;
    115 struct var vmail;
    116 struct var vmpath;
    117 struct var vpath;
    118 struct var vps1;
    119 struct var vps2;
    120 struct var vps4;
    121 struct var vvers;
    122 struct var voptind;
    123 struct var line_num;
    124 #ifndef SMALL
    125 struct var tod;
    126 struct var host_name;
    127 struct var seconds;
    128 struct var euname;
    129 struct var random_num;
    130 
    131 intmax_t sh_start_time;
    132 #endif
    133 
    134 struct var line_num;
    135 int line_number;
    136 int funclinebase = 0;
    137 int funclineabs = 0;
    138 
    139 char ifs_default[] = " \t\n";
    140 
    141 const struct varinit varinit[] = {
    142 #ifndef SMALL
    143 	{ &vhistsize,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE=",
    144 	   { .set_func= sethistsize } },
    145 #endif
    146 	{ &vifs,	VSTRFIXED|VTEXTFIXED,		"IFS= \t\n",
    147 	   { NULL } },
    148 	{ &vmail,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL=",
    149 	   { NULL } },
    150 	{ &vmpath,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH=",
    151 	   { NULL } },
    152 	{ &vvers,	VSTRFIXED|VTEXTFIXED|VNOEXPORT, "NETBSD_SHELL=",
    153 	   { NULL } },
    154 	{ &vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=" _PATH_DEFPATH,
    155 	   { .set_func= changepath } },
    156 	/*
    157 	 * vps1 depends on uid
    158 	 */
    159 	{ &vps2,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",
    160 	   { NULL } },
    161 	{ &vps4,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",
    162 	   { NULL } },
    163 #ifndef SMALL
    164 	{ &vterm,	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM=",
    165 	   { .set_func= setterm } },
    166 	{ &editrc, 	VSTRFIXED|VTEXTFIXED|VUNSET,	"EDITRC=",
    167 	   { .set_func= set_editrc } },
    168 	{ &ps_lit, 	VSTRFIXED|VTEXTFIXED|VUNSET,	"PSlit=",
    169 	   { .set_func= set_prompt_lit } },
    170 #endif
    171 	{ &voptind,	VSTRFIXED|VTEXTFIXED|VNOFUNC,	"OPTIND=1",
    172 	   { .set_func= getoptsreset } },
    173 	{ &line_num,	VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL,	"LINENO=1",
    174 	   { .ref_func= get_lineno } },
    175 #ifndef SMALL
    176 	{ &tod,		VSTRFIXED|VTEXTFIXED|VFUNCREF,	"ToD=",
    177 	   { .ref_func= get_tod } },
    178 	{ &host_name,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"HOSTNAME=",
    179 	   { .ref_func= get_hostname } },
    180 	{ &seconds,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"SECONDS=",
    181 	   { .ref_func= get_seconds } },
    182 	{ &euname,	VSTRFIXED|VTEXTFIXED|VFUNCREF,	"EUSER=",
    183 	   { .ref_func= get_euser } },
    184 	{ &random_num,	VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL,	"RANDOM=",
    185 	   { .ref_func= get_random } },
    186 #endif
    187 	{ NULL,	0,				NULL,
    188 	   { NULL } }
    189 };
    190 
    191 struct var *vartab[VTABSIZE];
    192 
    193 STATIC int strequal(const char *, const char *);
    194 STATIC struct var *find_var(const char *, struct var ***, int *);
    195 STATIC void showvar(struct var *, const char *, const char *, int);
    196 static void export_usage(const char *) __dead;
    197 STATIC int makespecial(const char *);
    198 
    199 /*
    200  * Initialize the variable symbol tables and import the environment
    201  */
    202 
    203 #ifdef mkinit
    204 INCLUDE <stdio.h>
    205 INCLUDE <unistd.h>
    206 INCLUDE <time.h>
    207 INCLUDE "var.h"
    208 INCLUDE "version.h"
    209 MKINIT char **environ;
    210 MKINIT void setvareqsafe(char *, int);
    211 INIT {
    212 	char **envp;
    213 	char buf[64];
    214 
    215 #ifndef SMALL
    216 	sh_start_time = (intmax_t)time((time_t *)0);
    217 #endif
    218 	/*
    219 	 * Set up our default variables and their values.
    220 	 */
    221 	initvar();
    222 
    223 	/*
    224 	 * Import variables from the environment, which will
    225 	 * if permitted, override anything initialised just previously.
    226 	 */
    227 	for (envp = environ ; *envp ; envp++) {
    228 		if (strchr(*envp, '=')) {
    229 			setvareqsafe(*envp, VEXPORT|VTEXTFIXED|VUNSAFE);
    230 		}
    231 	}
    232 
    233 	/*
    234 	 * Set variables which override anything read from environment.
    235 	 *
    236 	 * PPID is readonly
    237 	 * Always default IFS
    238 	 * POSIX: "Whenever the shell is invoked, OPTIND shall
    239 	 *         be initialized to 1."
    240 	 * PSc indicates the root/non-root status of this shell.
    241 	 * START_TIME belongs only to this shell.
    242 	 * NETBSD_SHELL is a constant (readonly), and is never exported
    243 	 * LINENO is simply magic...
    244 	 */
    245 	snprintf(buf, sizeof(buf), "%d", (int)getppid());
    246 	setvar("PPID", buf, VREADONLY);
    247 	setvar("IFS", ifs_default, VTEXTFIXED);
    248 	setvar("OPTIND", "1", VTEXTFIXED);
    249 	setvar("PSc", (geteuid() == 0 ? "#" : "$"), VTEXTFIXED);
    250 
    251 #ifndef SMALL
    252 	snprintf(buf, sizeof(buf), "%jd", sh_start_time);
    253 	setvar("START_TIME", buf, VTEXTFIXED);
    254 #endif
    255 
    256 	setvar("NETBSD_SHELL", NETBSD_SHELL
    257 #ifdef BUILD_DATE
    258 		" BUILD:" BUILD_DATE
    259 #endif
    260 #ifdef DEBUG
    261 		" DEBUG"
    262 #endif
    263 #if !defined(JOBS) || JOBS == 0
    264 		" -JOBS"
    265 #endif
    266 #ifndef DO_SHAREDVFORK
    267 		" -VFORK"
    268 #endif
    269 #ifdef SMALL
    270 		" SMALL"
    271 #endif
    272 #ifdef TINY
    273 		" TINY"
    274 #endif
    275 #ifdef OLD_TTY_DRIVER
    276 		" OLD_TTY"
    277 #endif
    278 #ifdef SYSV
    279 		" SYSV"
    280 #endif
    281 #ifndef BSD
    282 		" -BSD"
    283 #endif
    284 #ifdef BOGUS_NOT_COMMAND
    285 		" BOGUS_NOT"
    286 #endif
    287 		    , VTEXTFIXED|VREADONLY|VNOEXPORT);
    288 
    289 	setvar("LINENO", "1", VTEXTFIXED);
    290 }
    291 #endif
    292 
    293 
    294 /*
    295  * This routine initializes the builtin variables.  It is called when the
    296  * shell is initialized and again when a shell procedure is spawned.
    297  */
    298 
    299 void
    300 initvar(void)
    301 {
    302 	const struct varinit *ip;
    303 	struct var *vp;
    304 	struct var **vpp;
    305 
    306 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
    307 		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
    308 			continue;
    309 		vp->next = *vpp;
    310 		*vpp = vp;
    311 		vp->text = strdup(ip->text);
    312 		vp->flags = (ip->flags & ~VTEXTFIXED) | VSTRFIXED;
    313 		vp->v_u = ip->v_u;
    314 	}
    315 	/*
    316 	 * PS1 depends on uid
    317 	 */
    318 	if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
    319 		vps1.next = *vpp;
    320 		*vpp = &vps1;
    321 		vps1.flags = VSTRFIXED;
    322 		vps1.text = NULL;
    323 		choose_ps1();
    324 	}
    325 }
    326 
    327 void
    328 choose_ps1(void)
    329 {
    330 	uid_t u = geteuid();
    331 
    332 	if ((vps1.flags & (VTEXTFIXED|VSTACK)) == 0)
    333 		free(vps1.text);
    334 	vps1.text = strdup(u != 0 ? "PS1=$ " : "PS1=# ");
    335 	vps1.flags &= ~(VTEXTFIXED|VSTACK);
    336 
    337 	/*
    338 	 * Update PSc whenever we feel the need to update PS1
    339 	 */
    340 	setvarsafe("PSc", (u == 0 ? "#" : "$"), 0);
    341 }
    342 
    343 /*
    344  * Validate a string as a valid variable name
    345  * nb: not parameter - special params and such are "invalid" here.
    346  * Name terminated by either \0 or the term param (usually '=' or '\0').
    347  *
    348  * If not NULL, the length of the (intended) name is returned via len
    349  */
    350 
    351 int
    352 validname(const char *name, int term, int *len)
    353 {
    354 	const char *p = name;
    355 	int ok = 1;
    356 
    357 	if (p == NULL || *p == '\0' || *p == term) {
    358 		if (len != NULL)
    359 			*len = 0;
    360 		return 0;
    361 	}
    362 
    363 	if (!is_name(*p))
    364 		ok = 0;
    365 	p++;
    366 	for (;;) {
    367 		if (*p == '\0' || *p == term)
    368 			break;
    369 		if (!is_in_name(*p))
    370 			ok = 0;
    371 		p++;
    372 	}
    373 	if (len != NULL)
    374 		*len = p - name;
    375 
    376 	return ok;
    377 }
    378 
    379 /*
    380  * Safe version of setvar, returns 1 on success 0 on failure.
    381  */
    382 
    383 int
    384 setvarsafe(const char *name, const char *val, int flags)
    385 {
    386 	struct jmploc jmploc;
    387 	struct jmploc * const savehandler = handler;
    388 	int volatile err = 0;
    389 
    390 	if (setjmp(jmploc.loc))
    391 		err = 1;
    392 	else {
    393 		handler = &jmploc;
    394 		setvar(name, val, flags);
    395 	}
    396 	handler = savehandler;
    397 	return err;
    398 }
    399 
    400 void
    401 setvareqsafe(char *s, int flags)
    402 {
    403 	struct jmploc jmploc;
    404 	struct jmploc * const savehandler = handler;
    405 	volatile int e_s = errors_suppressed;
    406 
    407 	if (!setjmp(jmploc.loc)) {
    408 		handler = &jmploc;
    409 		errors_suppressed = 1;
    410 		setvareq(s, flags);
    411 	}
    412 	handler = savehandler;
    413 	errors_suppressed = e_s;
    414 }
    415 
    416 /*
    417  * Set the value of a variable.  The flags argument is ored with the
    418  * flags of the variable.  If val is NULL, the variable is unset.
    419  *
    420  * This always copies name and val when setting a variable, so
    421  * the source strings can be from anywhere, and are no longer needed
    422  * after this function returns.  The VTEXTFIXED and VSTACK flags should
    423  * not be used (but just in case they were, clear them.)
    424  */
    425 
    426 void
    427 setvar(const char *name, const char *val, int flags)
    428 {
    429 	const char *p;
    430 	const char *q;
    431 	char *d;
    432 	int len;
    433 	int namelen;
    434 	char *nameeq;
    435 
    436 	p = name;
    437 
    438 	if (!validname(p, '=', &namelen))
    439 		error("%.*s: bad variable name", namelen, name);
    440 	len = namelen + 2;		/* 2 is space for '=' and '\0' */
    441 	if (val == NULL) {
    442 		flags |= VUNSET;
    443 	} else {
    444 		len += strlen(val);
    445 	}
    446 	d = nameeq = ckmalloc(len);
    447 	q = name;
    448 	while (--namelen >= 0)
    449 		*d++ = *q++;
    450 	*d++ = '=';
    451 	*d = '\0';
    452 	if (val)
    453 		scopy(val, d);
    454 	setvareq(nameeq, flags & ~(VTEXTFIXED | VSTACK));
    455 }
    456 
    457 
    458 
    459 /*
    460  * Same as setvar except that the variable and value are passed in
    461  * the first argument as name=value.  Since the first argument will
    462  * be actually stored in the table, it should not be a string that
    463  * will go away.   The flags (VTEXTFIXED or VSTACK) can be used to
    464  * indicate the source of the string (if neither is set, the string will
    465  * eventually be free()d when a replacement value is assigned.)
    466  */
    467 
    468 void
    469 setvareq(char *s, int flags)
    470 {
    471 	struct var *vp, **vpp;
    472 	int nlen;
    473 
    474 	VTRACE(DBG_VARS, ("setvareq([%s],%#x) aflag=%d ", s, flags, aflag));
    475 	if (aflag && !(flags & VNOEXPORT))
    476 		flags |= VEXPORT;
    477 	vp = find_var(s, &vpp, &nlen);
    478 	if (vp != NULL) {
    479 		VTRACE(DBG_VARS, ("was [%s] fl:%#x\n", vp->text,
    480 		    vp->flags));
    481 		if (vp->flags & VREADONLY) {
    482 			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    483 				ckfree(s);
    484 			if (flags & VNOERROR)
    485 				return;
    486 			error("%.*s: is read only", vp->name_len, vp->text);
    487 		}
    488 		if (flags & VNOSET) {
    489 			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    490 				ckfree(s);
    491 			return;
    492 		}
    493 
    494 		INTOFF;
    495 
    496 		if (vp->func && !(vp->flags & VFUNCREF) && !(flags & VNOFUNC))
    497 			(*vp->func)(s + vp->name_len + 1, flags);
    498 
    499 		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    500 			ckfree(vp->text);
    501 
    502 		/*
    503 		 * if we set a magic var, the magic dissipates,
    504 		 * unless it is very special indeed.
    505 		 */
    506 		if (vp->rfunc && (vp->flags & (VFUNCREF|VSPECIAL)) == VFUNCREF)
    507 			vp->rfunc = NULL;
    508 
    509 		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET|VUNSAFE);
    510 		if (flags & VNOEXPORT)
    511 			vp->flags &= ~VEXPORT;
    512 		if (flags & VDOEXPORT)
    513 			vp->flags &= ~VNOEXPORT;
    514 		if (vp->flags & VNOEXPORT)
    515 			flags &= ~VEXPORT;
    516 		vp->flags |= flags & ~(VNOFUNC | VDOEXPORT);
    517 		vp->text = s;
    518 
    519 		/*
    520 		 * We could roll this to a function, to handle it as
    521 		 * a regular variable function callback, but why bother?
    522 		 */
    523 		if (vp == &vmpath || (vp == &vmail && ! mpathset()))
    524 			chkmail(1);
    525 
    526 		INTON;
    527 		return;
    528 	}
    529 	/* not found */
    530 	if (flags & VNOSET) {
    531 		VTRACE(DBG_VARS, ("new noset\n"));
    532 		if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    533 			ckfree(s);
    534 		return;
    535 	}
    536 	vp = ckmalloc(sizeof (*vp));
    537 	vp->flags = flags & ~(VNOFUNC|VFUNCREF|VDOEXPORT);
    538 	vp->text = s;
    539 	vp->name_len = nlen;
    540 	vp->func = NULL;
    541 	vp->next = *vpp;
    542 	*vpp = vp;
    543 
    544 	VTRACE(DBG_VARS, ("new [%s] (%d) %#x\n", s, nlen, vp->flags));
    545 }
    546 
    547 void
    548 setvar_invocation(int argc, char **argv)
    549 {
    550 	char value[32];		/* if we ever get 30, HELP */
    551 	char *v;
    552 
    553 	/*
    554 	 * Keep the following in ascii lexical order ( ie: Z before a )
    555 	 */
    556 
    557 	v = value;
    558 	*v++ = '!';		/* never empty, and the '-' is not first */
    559 
    560 	if (argc > 0 && argv[0] != NULL && argv[0][0] == '-')
    561 		*v++ = '-';
    562 	if (shellparam.nparam == 0)
    563 		*v++ = '0';
    564 	if (minusc)
    565 		*v++ = 'c';
    566 	if (commandname)
    567 		*v++ = 'f';
    568 	if (iflag)
    569 		*v++ = 'i';
    570 	if (loginsh)
    571 		*v++ = 'l';
    572 	if (privileged)
    573 		*v++ = 'p';
    574 	if (sflag)
    575 		*v++ = 's';
    576 
    577 	*v++ = '\0';
    578 
    579 		/*
    580 		 * this cannot fail, the var name is OK,
    581 		 * there cannot be any (non special) read only
    582 		 * variables at this point, ...
    583 		 */
    584 	setvar("NBSH_INVOCATION", value, VNOEXPORT);
    585 }
    586 
    587 /*
    588  * Process a linked list of variable assignments.
    589  */
    590 
    591 void
    592 listsetvar(struct strlist *list, int flags)
    593 {
    594 	struct strlist *lp;
    595 
    596 	INTOFF;
    597 	for (lp = list ; lp ; lp = lp->next) {
    598 		setvareq(savestr(lp->text), flags);
    599 	}
    600 	INTON;
    601 }
    602 
    603 void
    604 listmklocal(struct strlist *list, int flags)
    605 {
    606 	struct strlist *lp;
    607 
    608 	for (lp = list ; lp ; lp = lp->next)
    609 		mklocal(lp->text, flags);
    610 }
    611 
    612 
    613 /*
    614  * Find the value of a variable.  Returns NULL if not set.
    615  */
    616 
    617 char *
    618 lookupvar(const char *name)
    619 {
    620 	struct var *v;
    621 	char *p;
    622 
    623 	v = find_var(name, NULL, NULL);
    624 	if (v == NULL || v->flags & VUNSET)
    625 		return NULL;
    626 	if (v->rfunc && (v->flags & VFUNCREF) != 0) {
    627 		p = (*v->rfunc)(v);
    628 		if (p == NULL)
    629 			return NULL;
    630 	} else
    631 		p = v->text;
    632 
    633 	return p + v->name_len + 1;
    634 }
    635 
    636 
    637 
    638 /*
    639  * Search the environment of a builtin command.  If the second argument
    640  * is nonzero, return the value of a variable even if it hasn't been
    641  * exported.
    642  */
    643 
    644 char *
    645 bltinlookup(const char *name, int doall)
    646 {
    647 	struct strlist *sp;
    648 	struct var *v;
    649 	char *p;
    650 
    651 	for (sp = cmdenviron ; sp ; sp = sp->next) {
    652 		if (strequal(sp->text, name))
    653 			return strchr(sp->text, '=') + 1;
    654 	}
    655 
    656 	v = find_var(name, NULL, NULL);
    657 
    658 	if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
    659 		return NULL;
    660 
    661 	if (v->rfunc && (v->flags & VFUNCREF) != 0) {
    662 		p = (*v->rfunc)(v);
    663 		if (p == NULL)
    664 			return NULL;
    665 	} else
    666 		p = v->text;
    667 
    668 	return p + v->name_len + 1;
    669 }
    670 
    671 
    672 
    673 /*
    674  * Generate a list of exported variables.  This routine is used to construct
    675  * the third argument to execve when executing a program.
    676  */
    677 
    678 char **
    679 environment(void)
    680 {
    681 	int nenv;
    682 	struct var **vpp;
    683 	struct var *vp;
    684 	char **env;
    685 	char **ep;
    686 
    687 	nenv = 0;
    688 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    689 		for (vp = *vpp ; vp ; vp = vp->next)
    690 			if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT)
    691 				nenv++;
    692 	}
    693 	CTRACE(DBG_VARS, ("environment: %d vars to export\n", nenv));
    694 	ep = env = stalloc((nenv + 1) * sizeof *env);
    695 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    696 		for (vp = *vpp ; vp ; vp = vp->next)
    697 			if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) {
    698 				if (vp->rfunc && (vp->flags & VFUNCREF)) {
    699 					*ep = (*vp->rfunc)(vp);
    700 					if (*ep != NULL)
    701 						ep++;
    702 				} else
    703 					*ep++ = vp->text;
    704 				VTRACE(DBG_VARS, ("environment: %s\n", ep[-1]));
    705 			}
    706 	}
    707 	*ep = NULL;
    708 	return env;
    709 }
    710 
    711 
    712 /*
    713  * Called when a shell procedure is invoked to clear out nonexported
    714  * variables.  It is also necessary to reallocate variables of with
    715  * VSTACK set since these are currently allocated on the stack.
    716  */
    717 
    718 #ifdef mkinit
    719 void shprocvar(void);
    720 
    721 SHELLPROC {
    722 	shprocvar();
    723 }
    724 #endif
    725 
    726 void
    727 shprocvar(void)
    728 {
    729 	struct var **vpp;
    730 	struct var *vp, **prev;
    731 
    732 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    733 		for (prev = vpp ; (vp = *prev) != NULL ; ) {
    734 			if ((vp->flags & VEXPORT) == 0) {
    735 				*prev = vp->next;
    736 				if ((vp->flags & VTEXTFIXED) == 0)
    737 					ckfree(vp->text);
    738 				if ((vp->flags & VSTRFIXED) == 0)
    739 					ckfree(vp);
    740 			} else {
    741 				if (vp->flags & VSTACK) {
    742 					vp->text = savestr(vp->text);
    743 					vp->flags &=~ VSTACK;
    744 				}
    745 				prev = &vp->next;
    746 			}
    747 		}
    748 	}
    749 	initvar();
    750 }
    751 
    752 
    753 
    754 /*
    755  * Command to list all variables which are set.  Currently this command
    756  * is invoked from the set command when the set command is called without
    757  * any variables.
    758  */
    759 
    760 void
    761 print_quoted(const char *p)
    762 {
    763 	const char *q;
    764 
    765 	if (p[0] == '\0') {
    766 		out1fmt("''");
    767 		return;
    768 	}
    769 	if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
    770 		out1fmt("%s", p);
    771 		return;
    772 	}
    773 	while (*p) {
    774 		if (*p == '\'') {
    775 			out1fmt("\\'");
    776 			p++;
    777 			continue;
    778 		}
    779 		q = strchr(p, '\'');
    780 		if (!q) {
    781 			out1fmt("'%s'", p );
    782 			return;
    783 		}
    784 		out1fmt("'%.*s'", (int)(q - p), p );
    785 		p = q;
    786 	}
    787 }
    788 
    789 static int
    790 sort_var(const void *v_v1, const void *v_v2)
    791 {
    792 	const struct var * const *v1 = v_v1;
    793 	const struct var * const *v2 = v_v2;
    794 	char *t1 = (*v1)->text, *t2 = (*v2)->text;
    795 
    796 	if (*t1 == *t2) {
    797 		char *p, *s;
    798 
    799 		STARTSTACKSTR(p);
    800 
    801 		/*
    802 		 * note: if lengths are equal, strings must be different
    803 		 * so we don't care which string we pick for the \0 in
    804 		 * that case.
    805 		 */
    806 		if ((strchr(t1, '=') - t1) <= (strchr(t2, '=') - t2)) {
    807 			s = t1;
    808 			t1 = p;
    809 		} else {
    810 			s = t2;
    811 			t2 = p;
    812 		}
    813 
    814 		while (*s && *s != '=') {
    815 			STPUTC(*s, p);
    816 			s++;
    817 		}
    818 		STPUTC('\0', p);
    819 	}
    820 
    821 	return strcoll(t1, t2);
    822 }
    823 
    824 /*
    825  * POSIX requires that 'set' (but not export or readonly) output the
    826  * variables in lexicographic order - by the locale's collating order (sigh).
    827  * Maybe we could keep them in an ordered balanced binary tree
    828  * instead of hashed lists.
    829  * For now just roll 'em through qsort for printing...
    830  */
    831 
    832 STATIC void
    833 showvar(struct var *vp, const char *cmd, const char *xtra, int show_value)
    834 {
    835 	const char *p;
    836 
    837 	p = vp->text;
    838 	if (vp->rfunc && (vp->flags & VFUNCREF) != 0) {
    839 		p = (*vp->rfunc)(vp);
    840 		if (p == NULL) {
    841 			if (!(show_value & 2))
    842 				return;
    843 			p = vp->text;
    844 			show_value = 0;
    845 		}
    846 	}
    847 	if (cmd)
    848 		out1fmt("%s ", cmd);
    849 	if (xtra)
    850 		out1fmt("%s ", xtra);
    851 	for ( ; *p != '=' ; p++)
    852 		out1c(*p);
    853 	if (!(vp->flags & VUNSET) && show_value) {
    854 		out1fmt("=");
    855 		print_quoted(++p);
    856 	}
    857 	out1c('\n');
    858 }
    859 
    860 int
    861 showvars(const char *cmd, int flag, int show_value, const char *xtra)
    862 {
    863 	struct var **vpp;
    864 	struct var *vp;
    865 
    866 	static struct var **list;	/* static in case we are interrupted */
    867 	static int list_len;
    868 	int count = 0;
    869 
    870 	if (!list) {
    871 		list_len = 32;
    872 		list = ckmalloc(list_len * sizeof *list);
    873 	}
    874 
    875 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
    876 		for (vp = *vpp ; vp ; vp = vp->next) {
    877 			if (flag && !(vp->flags & flag))
    878 				continue;
    879 			if (vp->flags & VUNSET && !(show_value & 2))
    880 				continue;
    881 			if (count >= list_len) {
    882 				list = ckrealloc(list,
    883 					(list_len << 1) * sizeof *list);
    884 				list_len <<= 1;
    885 			}
    886 			list[count++] = vp;
    887 		}
    888 	}
    889 
    890 	qsort(list, count, sizeof *list, sort_var);
    891 
    892 	for (vpp = list; count--; vpp++)
    893 		showvar(*vpp, cmd, xtra, show_value);
    894 
    895 	/* no free(list), will be used again next time ... */
    896 
    897 	return 0;
    898 }
    899 
    900 
    901 
    902 /*
    903  * The export and readonly commands.
    904  */
    905 
    906 static void __dead
    907 export_usage(const char *cmd)
    908 {
    909 #ifdef SMALL
    910 	if (*cmd == 'r')
    911 	    error("Usage: %s [ -p | var[=val]... ]", cmd);
    912 	else
    913 	    error("Usage: %s [ -p | [-n] var[=val]... ]", cmd);
    914 #else
    915 	if (*cmd == 'r')
    916 	    error("Usage: %s [-p [var...] | -q var... | var[=val]... ]", cmd);
    917 	else
    918 	    error(
    919 	     "Usage: %s [ -px [var...] | -q[x] var... | [-n|x] var[=val]... ]",
    920 		cmd);
    921 #endif
    922 }
    923 
    924 int
    925 exportcmd(int argc, char **argv)
    926 {
    927 	struct var *vp;
    928 	char *name;
    929 	const char *p = argv[0];
    930 	int flag = p[0] == 'r'? VREADONLY : VEXPORT;
    931 	int pflg = 0;
    932 	int nflg = 0;
    933 #ifndef SMALL
    934 	int xflg = 0;
    935 	int qflg = 0;
    936 #endif
    937 	int res;
    938 	int c;
    939 	int f;
    940 
    941 #ifdef SMALL
    942 #define EXPORT_OPTS "np"
    943 #else
    944 #define	EXPORT_OPTS "npqx"
    945 #endif
    946 
    947 	while ((c = nextopt(EXPORT_OPTS)) != '\0') {
    948 
    949 #undef EXPORT_OPTS
    950 
    951 		switch (c) {
    952 		case 'n':
    953 			if (pflg || flag == VREADONLY
    954 #ifndef SMALL
    955 				|| qflg || xflg
    956 #endif
    957 						)
    958 				export_usage(p);
    959 			nflg = 1;
    960 			break;
    961 		case 'p':
    962 			if (nflg
    963 #ifndef SMALL
    964 				|| qflg
    965 #endif
    966 					)
    967 				export_usage(p);
    968 			pflg = 3;
    969 			break;
    970 #ifndef SMALL
    971 		case 'q':
    972 			if (nflg || pflg)
    973 				export_usage(p);
    974 			qflg = 1;
    975 			break;
    976 		case 'x':
    977 			if (nflg || flag == VREADONLY)
    978 				export_usage(p);
    979 			flag = VNOEXPORT;
    980 			xflg = 1;
    981 			break;
    982 #endif
    983 		}
    984 	}
    985 
    986 	if ((nflg
    987 #ifndef SMALL
    988 		|| qflg
    989 #endif
    990 		 ) && *argptr == NULL)
    991 		export_usage(p);
    992 
    993 #ifndef SMALL
    994 	if (pflg && *argptr != NULL) {
    995 		while ((name = *argptr++) != NULL) {
    996 			int len;
    997 
    998 			vp = find_var(name, NULL, &len);
    999 			if (name[len] == '=')
   1000 				export_usage(p);
   1001 			if (!goodname(name))
   1002 				error("%s: bad variable name", name);
   1003 
   1004 			if (vp && vp->flags & flag)
   1005 				showvar(vp, p, xflg ? "-x" : NULL, 1);
   1006 		}
   1007 		return 0;
   1008 	}
   1009 #endif
   1010 
   1011 	if (pflg || *argptr == NULL)
   1012 		return showvars( pflg ? p : 0, flag, pflg,
   1013 #ifndef SMALL
   1014 		    pflg && xflg ? "-x" :
   1015 #endif
   1016 					    NULL );
   1017 
   1018 	res = 0;
   1019 #ifndef SMALL
   1020 	if (qflg) {
   1021 		while ((name = *argptr++) != NULL) {
   1022 			int len;
   1023 
   1024 			vp = find_var(name, NULL, &len);
   1025 			if (name[len] == '=')
   1026 				export_usage(p);
   1027 			if (!goodname(name))
   1028 				error("%s: bad variable name", name);
   1029 
   1030 			if (vp == NULL || !(vp->flags & flag))
   1031 				res = 1;
   1032 		}
   1033 		return res;
   1034 	}
   1035 #endif
   1036 
   1037 	while ((name = *argptr++) != NULL) {
   1038 		int len;
   1039 
   1040 		f = flag;
   1041 
   1042 		vp = find_var(name, NULL, &len);
   1043 		p = name + len;
   1044 		if (*p++ != '=')
   1045 			p = NULL;
   1046 
   1047 		if (vp != NULL) {
   1048 			if (nflg)
   1049 				vp->flags &= ~flag;
   1050 			else if (flag&VEXPORT && vp->flags&VNOEXPORT) {
   1051 				/* note we go ahead and do any assignment */
   1052 				sh_warnx("%.*s: not available for export",
   1053 				    len, name);
   1054 				res = 1;
   1055 			} else {
   1056 				if (flag == VNOEXPORT)
   1057 					vp->flags &= ~VEXPORT;
   1058 
   1059 				/* if not NULL will be done in setvar below */
   1060 				if (p == NULL)
   1061 					vp->flags |= flag;
   1062 			}
   1063 			if (p == NULL)
   1064 				continue;
   1065 		} else if (nflg && p == NULL && !goodname(name))
   1066 			error("%s: bad variable name", name);
   1067 
   1068 		if (!nflg || p != NULL)
   1069 			setvar(name, p, f);
   1070 	}
   1071 	return res;
   1072 }
   1073 
   1074 
   1075 /*
   1076  * The "local" command.
   1077  */
   1078 
   1079 int
   1080 localcmd(int argc, char **argv)
   1081 {
   1082 	char *name;
   1083 	int c;
   1084 	int flags = 0;		/*XXX perhaps VUNSET from a -o option value */
   1085 
   1086 	if (! in_function())
   1087 		error("Not in a function");
   1088 
   1089 	/* upper case options, as bash stole all the good ones ... */
   1090 	while ((c = nextopt("INx")) != '\0')
   1091 		switch (c) {
   1092 		case 'I':	flags &= ~VUNSET;	break;
   1093 		case 'N':	flags |= VUNSET;	break;
   1094 		case 'x':	flags |= VEXPORT;	break;
   1095 		}
   1096 
   1097 	while ((name = *argptr++) != NULL) {
   1098 		mklocal(name, flags);
   1099 	}
   1100 	return 0;
   1101 }
   1102 
   1103 
   1104 /*
   1105  * Make a variable a local variable.  When a variable is made local, its
   1106  * value and flags are saved in a localvar structure.  The saved values
   1107  * will be restored when the shell function returns.  We handle the name
   1108  * "-" as a special case.
   1109  */
   1110 
   1111 void
   1112 mklocal(const char *name, int flags)
   1113 {
   1114 	struct localvar *lvp;
   1115 	struct var **vpp;
   1116 	struct var *vp;
   1117 
   1118 	INTOFF;
   1119 	lvp = ckmalloc(sizeof (struct localvar));
   1120 	if (name[0] == '-' && name[1] == '\0') {
   1121 		char *p;
   1122 		p = ckmalloc(sizeof_optlist);
   1123 		lvp->text = memcpy(p, optlist, sizeof_optlist);
   1124 		lvp->rfunc = NULL;
   1125 		vp = NULL;
   1126 		xtrace_clone(0);
   1127 	} else {
   1128 		vp = find_var(name, &vpp, NULL);
   1129 		if (vp == NULL) {
   1130 			flags &= ~VNOEXPORT;
   1131 			if (strchr(name, '='))
   1132 				setvareq(savestr(name),
   1133 				    VSTRFIXED | (flags & ~VUNSET));
   1134 			else
   1135 				setvar(name, NULL, VSTRFIXED|flags);
   1136 			vp = *vpp;	/* the new variable */
   1137 			lvp->text = NULL;
   1138 			lvp->flags = VUNSET;
   1139 			lvp->rfunc = NULL;
   1140 		} else {
   1141 			lvp->text = vp->text;
   1142 			lvp->flags = vp->flags;
   1143 			lvp->v_u = vp->v_u;
   1144 			vp->flags |= VSTRFIXED|VTEXTFIXED;
   1145 			if (flags & (VDOEXPORT | VUNSET))
   1146 				vp->flags &= ~VNOEXPORT;
   1147 			if (vp->flags & VNOEXPORT &&
   1148 			    (flags & (VEXPORT|VDOEXPORT|VUNSET)) == VEXPORT)
   1149 				flags &= ~VEXPORT;
   1150 			if (flags & (VNOEXPORT | VUNSET))
   1151 				vp->flags &= ~VEXPORT;
   1152 			flags &= ~VNOEXPORT;
   1153 			if (name[vp->name_len] == '=')
   1154 				setvareq(savestr(name), flags & ~VUNSET);
   1155 			else if (flags & VUNSET)
   1156 				unsetvar(name, 0);
   1157 			else
   1158 				vp->flags |= flags & (VUNSET|VEXPORT);
   1159 
   1160 			if (vp == &line_num) {
   1161 				if (name[vp->name_len] == '=')
   1162 					funclinebase = funclineabs -1;
   1163 				else
   1164 					funclinebase = 0;
   1165 			}
   1166 		}
   1167 	}
   1168 	lvp->vp = vp;
   1169 	lvp->next = localvars;
   1170 	localvars = lvp;
   1171 	INTON;
   1172 }
   1173 
   1174 
   1175 /*
   1176  * Called after a function returns.
   1177  */
   1178 
   1179 void
   1180 poplocalvars(void)
   1181 {
   1182 	struct localvar *lvp;
   1183 	struct var *vp;
   1184 
   1185 	while ((lvp = localvars) != NULL) {
   1186 		localvars = lvp->next;
   1187 		vp = lvp->vp;
   1188 		VTRACE(DBG_VARS, ("poplocalvar %s\n", vp ? vp->text : "-"));
   1189 		if (vp == NULL) {	/* $- saved */
   1190 			memcpy(optlist, lvp->text, sizeof_optlist);
   1191 			ckfree(lvp->text);
   1192 			xtrace_pop();
   1193 			optschanged();
   1194 		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
   1195 			(void)unsetvar(vp->text, 0);
   1196 		} else {
   1197 			if (lvp->func && (lvp->flags & (VNOFUNC|VFUNCREF)) == 0)
   1198 				(*lvp->func)(lvp->text + vp->name_len + 1,
   1199 				    lvp->flags);
   1200 			if ((vp->flags & VTEXTFIXED) == 0)
   1201 				ckfree(vp->text);
   1202 			vp->flags = lvp->flags;
   1203 			vp->text = lvp->text;
   1204 			vp->v_u = lvp->v_u;
   1205 		}
   1206 		ckfree(lvp);
   1207 	}
   1208 }
   1209 
   1210 
   1211 int
   1212 setvarcmd(int argc, char **argv)
   1213 {
   1214 	if (argc <= 2)
   1215 		return unsetcmd(argc, argv);
   1216 	else if (argc == 3)
   1217 		setvar(argv[1], argv[2], 0);
   1218 	else
   1219 		error("List assignment not implemented");
   1220 	return 0;
   1221 }
   1222 
   1223 
   1224 /*
   1225  * The unset builtin command.  We unset the function before we unset the
   1226  * variable to allow a function to be unset when there is a readonly variable
   1227  * with the same name.
   1228  */
   1229 
   1230 int
   1231 unsetcmd(int argc, char **argv)
   1232 {
   1233 	char **ap;
   1234 	int i;
   1235 	int flg_func = 0;
   1236 	int flg_var = 0;
   1237 	int flg_x = 0;
   1238 	int ret = 0;
   1239 
   1240 	while ((i = nextopt("efvx")) != '\0') {
   1241 		switch (i) {
   1242 		case 'f':
   1243 			flg_func = 1;
   1244 			break;
   1245 		case 'e':
   1246 		case 'x':
   1247 			flg_x = (2 >> (i == 'e'));
   1248 			/* FALLTHROUGH */
   1249 		case 'v':
   1250 			flg_var = 1;
   1251 			break;
   1252 		}
   1253 	}
   1254 
   1255 	if (flg_func == 0 && flg_var == 0)
   1256 		flg_var = 1;
   1257 
   1258 	for (ap = argptr; *ap ; ap++) {
   1259 		if (flg_func)
   1260 			ret |= unsetfunc(*ap);
   1261 		if (flg_var)
   1262 			ret |= unsetvar(*ap, flg_x);
   1263 	}
   1264 	return ret;
   1265 }
   1266 
   1267 
   1268 /*
   1269  * Unset the specified variable.
   1270  */
   1271 
   1272 int
   1273 unsetvar(const char *s, int unexport)
   1274 {
   1275 	struct var **vpp;
   1276 	struct var *vp;
   1277 
   1278 	vp = find_var(s, &vpp, NULL);
   1279 	if (vp == NULL)
   1280 		return 0;
   1281 
   1282 	if (vp->flags & VREADONLY && !(unexport & 1))
   1283 		return 1;
   1284 
   1285 	INTOFF;
   1286 	if (unexport & 1) {
   1287 		vp->flags &= ~VEXPORT;
   1288 	} else {
   1289 		if (vp->text[vp->name_len + 1] != '\0' || !(vp->flags & VUNSET))
   1290 			setvar(s, nullstr, VUNSET);
   1291 		if (!(unexport & 2))
   1292 			vp->flags &= ~VEXPORT;
   1293 		vp->flags |= VUNSET;
   1294 		if ((vp->flags&(VEXPORT|VSTRFIXED|VREADONLY|VNOEXPORT)) == 0) {
   1295 			if ((vp->flags & VTEXTFIXED) == 0)
   1296 				ckfree(vp->text);
   1297 			*vpp = vp->next;
   1298 			ckfree(vp);
   1299 		}
   1300 	}
   1301 	INTON;
   1302 	return 0;
   1303 }
   1304 
   1305 
   1306 /*
   1307  * Returns true if the two strings specify the same variable.  The first
   1308  * variable name is terminated by '='; the second may be terminated by
   1309  * either '=' or '\0'.
   1310  */
   1311 
   1312 STATIC int
   1313 strequal(const char *p, const char *q)
   1314 {
   1315 	while (*p == *q++) {
   1316 		if (*p++ == '=')
   1317 			return 1;
   1318 	}
   1319 	if (*p == '=' && *(q - 1) == '\0')
   1320 		return 1;
   1321 	return 0;
   1322 }
   1323 
   1324 /*
   1325  * Search for a variable.
   1326  * 'name' may be terminated by '=' or a NUL.
   1327  * vppp is set to the pointer to vp, or the list head if vp isn't found
   1328  * lenp is set to the number of characters in 'name'
   1329  */
   1330 
   1331 STATIC struct var *
   1332 find_var(const char *name, struct var ***vppp, int *lenp)
   1333 {
   1334 	unsigned int hashval;
   1335 	int len;
   1336 	struct var *vp, **vpp;
   1337 	const char *p = name;
   1338 
   1339 	hashval = 0;
   1340 	while (*p && *p != '=')
   1341 		hashval = 2 * hashval + (unsigned char)*p++;
   1342 
   1343 	len = p - name;
   1344 	if (lenp)
   1345 		*lenp = len;
   1346 
   1347 	vpp = &vartab[hashval % VTABSIZE];
   1348 	if (vppp)
   1349 		*vppp = vpp;
   1350 
   1351 	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
   1352 		if (vp->name_len != len)
   1353 			continue;
   1354 		if (memcmp(vp->text, name, len) != 0)
   1355 			continue;
   1356 		if (vppp)
   1357 			*vppp = vpp;
   1358 		return vp;
   1359 	}
   1360 	return NULL;
   1361 }
   1362 
   1363 /*
   1364  * The following are the functions that create the values for
   1365  * shell variables that are dynamically produced when needed.
   1366  *
   1367  * The output strings cannot be malloc'd as there is nothing to
   1368  * free them - callers assume these are ordinary variables where
   1369  * the value returned is vp->text
   1370  *
   1371  * Each function needs its own storage space, as the results are
   1372  * used to create processes' environment, and (if exported) all
   1373  * the values will (might) be needed simultaneously.
   1374  *
   1375  * It is not a problem if a var is updated while nominally in use
   1376  * somewhere, all these are intended to be dynamic, the value they
   1377  * return is not guaranteed, an updated vaue is just as good.
   1378  *
   1379  * So, malloc a single buffer for the result of each function,
   1380  * grow, and even shrink, it as needed, but once we have one that
   1381  * is a suitable size for the actual usage, simply hold it forever.
   1382  *
   1383  * For a SMALL shell we implement only LINENO, none of the others,
   1384  * and give it just a fixed length static buffer for its result.
   1385  */
   1386 
   1387 #ifndef SMALL
   1388 
   1389 struct space_reserved {		/* record of space allocated for results */
   1390 	char *b;
   1391 	int len;
   1392 };
   1393 
   1394 /* rough (over-)estimate of the number of bytes needed to hold a number */
   1395 static int
   1396 digits_in(intmax_t number)
   1397 {
   1398 	int res = 0;
   1399 
   1400 	if (number & ~((1LL << 62) - 1))
   1401 		res = 64;	/* enough for 2^200 and a bit more */
   1402 	else if (number & ~((1LL << 32) - 1))
   1403 		res = 20;	/* enough for 2^64 */
   1404 	else if (number & ~((1 << 23) - 1))
   1405 		res = 10;	/* enough for 2^32 */
   1406 	else
   1407 		res = 8;	/* enough for 2^23 or smaller */
   1408 
   1409 	return res;
   1410 }
   1411 
   1412 static int
   1413 make_space(struct space_reserved *m, int bytes)
   1414 {
   1415 	void *p;
   1416 
   1417 	if (m->len >= bytes && m->len <= (bytes<<2))
   1418 		return 1;
   1419 
   1420 	bytes = SHELL_ALIGN(bytes);
   1421 	INTOFF;
   1422 	/* not ckrealloc() - we want failure, not error() here */
   1423 	p = realloc(m->b, bytes);
   1424 	if (p != NULL) {
   1425 		m->b = p;
   1426 		m->len = bytes;
   1427 		m->b[bytes - 1] = '\0';
   1428 	}
   1429 	INTON;
   1430 
   1431 	return p != NULL;
   1432 }
   1433 #endif
   1434 
   1435 char *
   1436 get_lineno(struct var *vp)
   1437 {
   1438 #ifdef SMALL
   1439 #define length (8 + 10)		/* 10 digits is enough for a 32 bit line num */
   1440 	static char result[length];
   1441 #else
   1442 	static struct space_reserved buf;
   1443 #define result buf.b
   1444 #define length buf.len
   1445 #endif
   1446 	int ln = line_number;
   1447 
   1448 	if (vp->flags & VUNSET)
   1449 		return NULL;
   1450 
   1451 	ln -= funclinebase;
   1452 
   1453 #ifndef SMALL
   1454 	if (!make_space(&buf, vp->name_len + 2 + digits_in(ln)))
   1455 		return vp->text;
   1456 #endif
   1457 
   1458 	snprintf(result, length, "%.*s=%d", vp->name_len, vp->text, ln);
   1459 	return result;
   1460 }
   1461 #undef result
   1462 #undef length
   1463 
   1464 #ifndef SMALL
   1465 
   1466 char *
   1467 get_hostname(struct var *vp)
   1468 {
   1469 	static struct space_reserved buf;
   1470 
   1471 	if (vp->flags & VUNSET)
   1472 		return NULL;
   1473 
   1474 	if (!make_space(&buf, vp->name_len + 2 + 256))
   1475 		return vp->text;
   1476 
   1477 	memcpy(buf.b, vp->text, vp->name_len + 1);	/* include '=' */
   1478 	(void)gethostname(buf.b + vp->name_len + 1,
   1479 	    buf.len - vp->name_len - 3);
   1480 	return buf.b;
   1481 }
   1482 
   1483 char *
   1484 get_tod(struct var *vp)
   1485 {
   1486 	static struct space_reserved buf;	/* space for answers */
   1487 	static struct space_reserved tzs;	/* remember TZ last used */
   1488 	static timezone_t last_zone;		/* timezone data for tzs zone */
   1489 	const char *fmt;
   1490 	char *tz;
   1491 	time_t now;
   1492 	struct tm tm_now, *tmp;
   1493 	timezone_t zone = NULL;
   1494 	static char t_err[] = "time error";
   1495 	int len;
   1496 
   1497 	if (vp->flags & VUNSET)
   1498 		return NULL;
   1499 
   1500 	fmt = lookupvar("ToD_FORMAT");
   1501 	if (fmt == NULL)
   1502 		fmt="%T";
   1503 	tz = lookupvar("TZ");
   1504 	(void)time(&now);
   1505 
   1506 	if (tz != NULL) {
   1507 		if (tzs.b == NULL || strcmp(tzs.b, tz) != 0) {
   1508 			INTOFF;
   1509 			if (make_space(&tzs, strlen(tz) + 1)) {
   1510 				strcpy(tzs.b, tz);
   1511 				if (last_zone)
   1512 					tzfree(last_zone);
   1513 				last_zone = zone = tzalloc(tz);
   1514 				INTON;
   1515 			} else
   1516 				zone = tzalloc(tz);
   1517 		} else
   1518 			zone = last_zone;
   1519 
   1520 		tmp = localtime_rz(zone, &now, &tm_now);
   1521 	} else
   1522 		tmp = localtime_r(&now, &tm_now);
   1523 
   1524 	len = (strlen(fmt) * 4) + vp->name_len + 2;
   1525 	while (make_space(&buf, len)) {
   1526 		memcpy(buf.b, vp->text, vp->name_len+1);
   1527 		if (tmp == NULL) {
   1528 			if (buf.len >= vp->name_len+2+(int)(sizeof t_err - 1)) {
   1529 				strcpy(buf.b + vp->name_len + 1, t_err);
   1530 				if (zone && zone != last_zone) {
   1531 					tzfree(zone);
   1532 					INTON;
   1533 				}
   1534 				return buf.b;
   1535 			}
   1536 			len = vp->name_len + 4 + sizeof t_err - 1;
   1537 			continue;
   1538 		}
   1539 		if (strftime_z(zone, buf.b + vp->name_len + 1,
   1540 		     buf.len - vp->name_len - 2, fmt, tmp)) {
   1541 			if (zone && zone != last_zone) {
   1542 				tzfree(zone);
   1543 				INTON;
   1544 			}
   1545 			return buf.b;
   1546 		}
   1547 		if (len >= 4096)	/* Let's be reasonable */
   1548 			break;
   1549 		len <<= 1;
   1550 	}
   1551 	if (zone && zone != last_zone) {
   1552 		tzfree(zone);
   1553 		INTON;
   1554 	}
   1555 	return vp->text;
   1556 }
   1557 
   1558 char *
   1559 get_seconds(struct var *vp)
   1560 {
   1561 	static struct space_reserved buf;
   1562 	intmax_t secs;
   1563 
   1564 	if (vp->flags & VUNSET)
   1565 		return NULL;
   1566 
   1567 	secs = (intmax_t)time((time_t *)0) - sh_start_time;
   1568 	if (!make_space(&buf, vp->name_len + 2 + digits_in(secs)))
   1569 		return vp->text;
   1570 
   1571 	snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs);
   1572 	return buf.b;
   1573 }
   1574 
   1575 char *
   1576 get_euser(struct var *vp)
   1577 {
   1578 	static struct space_reserved buf;
   1579 	static uid_t lastuid = 0;
   1580 	uid_t euid;
   1581 	struct passwd *pw;
   1582 
   1583 	if (vp->flags & VUNSET)
   1584 		return NULL;
   1585 
   1586 	euid = geteuid();
   1587 	if (buf.b != NULL && lastuid == euid)
   1588 		return buf.b;
   1589 
   1590 	pw = getpwuid(euid);
   1591 	if (pw == NULL)
   1592 		return vp->text;
   1593 
   1594 	if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) {
   1595 		INTOFF;
   1596 		lastuid = euid;
   1597 		snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text,
   1598 		    pw->pw_name);
   1599 		INTON;
   1600 		return buf.b;
   1601 	}
   1602 
   1603 	return vp->text;
   1604 }
   1605 
   1606 char *
   1607 get_random(struct var *vp)
   1608 {
   1609 	static struct space_reserved buf;
   1610 	static intmax_t random_val = 0;
   1611 
   1612 #ifdef USE_LRAND48
   1613 #define random lrand48
   1614 #define srandom srand48
   1615 #endif
   1616 
   1617 	if (vp->flags & VUNSET)
   1618 		return NULL;
   1619 
   1620 	if (vp->text != buf.b) {
   1621 		/*
   1622 		 * Either initialisation, or a new seed has been set
   1623 		 */
   1624 		if (vp->text[vp->name_len + 1] == '\0') {
   1625 			int fd;
   1626 
   1627 			/*
   1628 			 * initialisation (without pre-seeding),
   1629 			 * or explicitly requesting a truly random seed.
   1630 			 */
   1631 			INTOFF;
   1632 			fd = open("/dev/urandom", 0);
   1633 			if (fd == -1) {
   1634 				out2str("RANDOM initialisation failed\n");
   1635 				random_val = (getpid()<<3) ^ time((time_t *)0);
   1636 			} else {
   1637 				int n;
   1638 
   1639 				do {
   1640 				    n = read(fd,&random_val,sizeof random_val);
   1641 				} while (n != sizeof random_val);
   1642 				close(fd);
   1643 			}
   1644 			INTON;
   1645 		} else
   1646 			/* good enough for today */
   1647 			random_val = strtoimax(vp->text+vp->name_len+1,NULL,0);
   1648 
   1649 		srandom((long)random_val);
   1650 	}
   1651 
   1652 #if 0
   1653 	random_val = (random_val + 1) & 0x7FFF;	/* 15 bit "random" numbers */
   1654 #else
   1655 	random_val = (random() >> 5) & 0x7FFF;
   1656 #endif
   1657 
   1658 	if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val)))
   1659 		return vp->text;
   1660 
   1661 	snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text,
   1662 	    random_val);
   1663 
   1664 	INTOFF;
   1665 	if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0)
   1666 		free(vp->text);
   1667 	vp->flags |= VTEXTFIXED;
   1668 	vp->text = buf.b;
   1669 	INTON;
   1670 
   1671 	return vp->text;
   1672 #undef random
   1673 #undef srandom
   1674 }
   1675 
   1676 STATIC int
   1677 makespecial(const char *name)
   1678 {
   1679 	const struct varinit *ip;
   1680 	struct var *vp;
   1681 
   1682 	CTRACE(DBG_VARS, ("makespecial('%s') -> ", name));
   1683 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
   1684 		if (strequal(ip->text, name)) {
   1685 			if (!(ip->flags & VFUNCREF)) {
   1686 				CTRACE(DBG_VARS, ("+1\n"));
   1687 				return 1;
   1688 			}
   1689 			INTOFF;
   1690 			vp->flags &= ~VUNSET;
   1691 			vp->v_u = ip->v_u;
   1692 			INTON;
   1693 			CTRACE(DBG_VARS, ("0\n"));
   1694 			return 0;
   1695 		}
   1696 	}
   1697 	CTRACE(DBG_VARS, ("1\n"));
   1698 	return 1;
   1699 }
   1700 
   1701 int
   1702 specialvarcmd(int argc, char **argv)
   1703 {
   1704 	int res = 0;
   1705 	char **ap;
   1706 
   1707 	(void) nextopt("");
   1708 
   1709 	if (!*argptr)
   1710 		error("Usage: specialvar var...");
   1711 
   1712 	for (ap = argptr; *ap ; ap++)
   1713 		res |= makespecial(*ap);
   1714 
   1715 	return res;
   1716 }
   1717 
   1718 #endif /* SMALL */
   1719