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