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