1 /*        $NetBSD: var.c,v 1.88 2024/12/26 03:23:28 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.88 2024/12/26 03:23:28 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
initvar(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
choose_ps1(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
validname(const char * name,int term,int * len)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
setvarsafe(const char * name,const char * val,int flags)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
setvareqsafe(char * s,int flags)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
setvar(const char * name,const char * val,int flags)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
setvareq(char * s,int flags)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
setvar_invocation(int argc,char ** argv)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
listsetvar(struct strlist * list,int flags)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
listmklocal(struct strlist * list,int flags)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 *
lookupvar(const char * name)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 *
bltinlookup(const char * name,int doall)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 **
environment(void)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
shprocvar(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
print_quoted(const char * p)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
sort_var(const void * v_v1,const void * v_v2)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
showvar(struct var * vp,const char * cmd,const char * xtra,int show_value)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
showvars(const char * cmd,int flag,int show_value,const char * xtra)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
export_usage(const char * cmd)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
exportcmd(int argc,char ** argv)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
localcmd(int argc,char ** argv)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
mklocal(const char * name,int flags)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
poplocalvars(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
setvarcmd(int argc,char ** argv)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
unsetcmd(int argc,char ** argv)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
unsetvar(const char * s,int unexport)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
strequal(const char * p,const char * q)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 *
find_var(const char * name,struct var *** vppp,int * lenp)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
digits_in(intmax_t number)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
make_space(struct space_reserved * m,int bytes)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 *
get_lineno(struct var * vp)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 *
get_hostname(struct var * vp)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 *
get_tod(struct var * vp)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 (zone != NULL) {
1555                               if (strftime_z(zone, buf.b + vp->name_len + 1,
1556                                    buf.len - vp->name_len - 2, fmt, tmp)) {
1557                                         if (zone != last_zone) {
1558                                                   tzfree(zone);
1559                                                   INTON;
1560                                         }
1561                                         return buf.b;
1562                               }
1563                     } else if (strftime(buf.b + vp->name_len + 1,
1564                                   buf.len - vp->name_len - 2, fmt, tmp))
1565                                         return buf.b;
1566 
1567                     if (len >= 4096)    /* Let's be reasonable */
1568                               break;
1569                     len <<= 1;
1570           }
1571           if (zone && zone != last_zone) {
1572                     tzfree(zone);
1573                     INTON;
1574           }
1575           return vp->text;
1576 }
1577 
1578 char *
get_seconds(struct var * vp)1579 get_seconds(struct var *vp)
1580 {
1581           static struct space_reserved buf;
1582           intmax_t secs;
1583 
1584           if (vp->flags & VUNSET)
1585                     return NULL;
1586 
1587           secs = (intmax_t)time((time_t *)0) - sh_start_time;
1588           if (!make_space(&buf, vp->name_len + 2 + digits_in(secs)))
1589                     return vp->text;
1590 
1591           snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs);
1592           return buf.b;
1593 }
1594 
1595 char *
get_euser(struct var * vp)1596 get_euser(struct var *vp)
1597 {
1598           static struct space_reserved buf;
1599           static uid_t lastuid = 0;
1600           uid_t euid;
1601           struct passwd *pw;
1602 
1603           if (vp->flags & VUNSET)
1604                     return NULL;
1605 
1606           euid = geteuid();
1607           if (buf.b != NULL && lastuid == euid)
1608                     return buf.b;
1609 
1610           pw = getpwuid(euid);
1611           if (pw == NULL)
1612                     return vp->text;
1613 
1614           if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) {
1615                     INTOFF;
1616                     lastuid = euid;
1617                     snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text,
1618                         pw->pw_name);
1619                     INTON;
1620                     return buf.b;
1621           }
1622 
1623           return vp->text;
1624 }
1625 
1626 char *
get_random(struct var * vp)1627 get_random(struct var *vp)
1628 {
1629           static struct space_reserved buf;
1630           static intmax_t random_val = 0;
1631 
1632 #ifdef USE_LRAND48
1633 #define random lrand48
1634 #define srandom srand48
1635 #endif
1636 
1637           if (vp->flags & VUNSET)
1638                     return NULL;
1639 
1640           if (vp->text != buf.b) {
1641                     /*
1642                      * Either initialisation, or a new seed has been set
1643                      */
1644                     if (vp->text[vp->name_len + 1] == '\0') {
1645                               int fd;
1646 
1647                               /*
1648                                * initialisation (without pre-seeding),
1649                                * or explicitly requesting a truly random seed.
1650                                */
1651                               INTOFF;
1652                               fd = open("/dev/urandom", 0);
1653                               if (fd == -1) {
1654                                         out2str("RANDOM initialisation failed\n");
1655                                         random_val = (getpid()<<3) ^ time((time_t *)0);
1656                               } else {
1657                                         int n;
1658 
1659                                         do {
1660                                             n = read(fd,&random_val,sizeof random_val);
1661                                         } while (n != sizeof random_val);
1662                                         close(fd);
1663                               }
1664                               INTON;
1665                     } else
1666                               /* good enough for today */
1667                               random_val = strtoimax(vp->text+vp->name_len+1,NULL,0);
1668 
1669                     srandom((long)random_val);
1670           }
1671 
1672 #if 0
1673           random_val = (random_val + 1) & 0x7FFF; /* 15 bit "random" numbers */
1674 #else
1675           random_val = (random() >> 5) & 0x7FFF;
1676 #endif
1677 
1678           if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val)))
1679                     return vp->text;
1680 
1681           snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text,
1682               random_val);
1683 
1684           INTOFF;
1685           if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0)
1686                     free(vp->text);
1687           vp->flags |= VTEXTFIXED;
1688           vp->text = buf.b;
1689           INTON;
1690 
1691           return vp->text;
1692 #undef random
1693 #undef srandom
1694 }
1695 
1696 STATIC int
makespecial(const char * name)1697 makespecial(const char *name)
1698 {
1699           const struct varinit *ip;
1700           struct var *vp;
1701 
1702           CTRACE(DBG_VARS, ("makespecial('%s') -> ", name));
1703           for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
1704                     if (strequal(ip->text, name)) {
1705                               if (!(ip->flags & VFUNCREF)) {
1706                                         CTRACE(DBG_VARS, ("+1\n"));
1707                                         return 1;
1708                               }
1709                               INTOFF;
1710                               vp->flags &= ~VUNSET;
1711                               vp->v_u = ip->v_u;
1712                               INTON;
1713                               CTRACE(DBG_VARS, ("0\n"));
1714                               return 0;
1715                     }
1716           }
1717           CTRACE(DBG_VARS, ("1\n"));
1718           return 1;
1719 }
1720 
1721 int
specialvarcmd(int argc,char ** argv)1722 specialvarcmd(int argc, char **argv)
1723 {
1724           int res = 0;
1725           char **ap;
1726 
1727           (void) nextopt("");
1728 
1729           if (!*argptr)
1730                     error("Usage: specialvar var...");
1731 
1732           for (ap = argptr; *ap ; ap++)
1733                     res |= makespecial(*ap);
1734 
1735           return res;
1736 }
1737 
1738 #endif /* SMALL */
1739