Deleted Added
sdiff udiff text old ( 25905 ) new ( 36150 )
full compact
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $Id: var.c,v 1.10 1997/04/28 03:06:39 steve Exp $
37 */
38
39#ifndef lint
40static char const sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
41#endif /* not lint */
42
43#include <unistd.h>
44#include <stdlib.h>
45
46/*
47 * Shell variables.
48 */
49
50#include <locale.h>
51
52#include "shell.h"
53#include "output.h"
54#include "expand.h"
55#include "nodes.h" /* for other headers */
56#include "eval.h" /* defines cmdenviron */
57#include "exec.h"
58#include "syntax.h"
59#include "options.h"
60#include "mail.h"
61#include "var.h"
62#include "memalloc.h"
63#include "error.h"
64#include "mystring.h"
65#include "parser.h"
66#ifndef NO_HISTORY
67#include "myhistedit.h"
68#endif
69
70
71#define VTABSIZE 39
72
73
74struct varinit {
75 struct var *var;
76 int flags;
77 char *text;
78 void (*func) __P((const char *));
79};
80
81
82#if ATTY
83struct var vatty;
84#endif
85#ifndef NO_HISTORY
86struct var vhistsize;
87#endif
88struct var vifs;
89struct var vmail;
90struct var vmpath;
91struct var vpath;
92struct var vps1;
93struct var vps2;
94struct var vvers;
95#if ATTY
96struct var vterm;
97#endif
98struct var voptind;
99
100const struct varinit varinit[] = {
101#if ATTY
102 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
103 NULL },
104#endif
105#ifndef NO_HISTORY
106 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
107 sethistsize },
108#endif
109 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
110 NULL },
111 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
112 NULL },
113 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
114 NULL },
115 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin",
116 changepath },
117 /*
118 * vps1 depends on uid
119 */
120 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
121 NULL },
122#if ATTY
123 { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
124 NULL },
125#endif
126 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
127 getoptsreset },
128 { NULL, 0, NULL,
129 NULL }
130};
131
132struct var *vartab[VTABSIZE];
133
134STATIC struct var **hashvar __P((char *));
135STATIC int varequal __P((char *, char *));
136STATIC int localevar __P((char *));
137
138/*
139 * Initialize the varable symbol tables and import the environment
140 */
141
142#ifdef mkinit
143INCLUDE "var.h"
144INIT {
145 char **envp;
146 extern char **environ;
147
148 initvar();
149 for (envp = environ ; *envp ; envp++) {
150 if (strchr(*envp, '=')) {
151 setvareq(*envp, VEXPORT|VTEXTFIXED);
152 }
153 }
154}
155#endif
156
157
158/*
159 * This routine initializes the builtin variables. It is called when the
160 * shell is initialized and again when a shell procedure is spawned.
161 */
162
163void
164initvar() {
165 const struct varinit *ip;
166 struct var *vp;
167 struct var **vpp;
168
169 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
170 if ((vp->flags & VEXPORT) == 0) {
171 vpp = hashvar(ip->text);
172 vp->next = *vpp;
173 *vpp = vp;
174 vp->text = ip->text;
175 vp->flags = ip->flags;
176 vp->func = ip->func;
177 }
178 }
179 /*
180 * PS1 depends on uid
181 */
182 if ((vps1.flags & VEXPORT) == 0) {
183 vpp = hashvar("PS1=");
184 vps1.next = *vpp;
185 *vpp = &vps1;
186 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
187 vps1.flags = VSTRFIXED|VTEXTFIXED;
188 }
189}
190
191/*
192 * Safe version of setvar, returns 1 on success 0 on failure.
193 */
194
195int
196setvarsafe(name, val, flags)
197 char *name, *val;
198 int flags;
199{
200 struct jmploc jmploc;
201 struct jmploc *volatile savehandler = handler;
202 int err = 0;
203#if __GNUC__
204 /* Avoid longjmp clobbering */
205 (void) &err;
206#endif
207
208 if (setjmp(jmploc.loc))
209 err = 1;
210 else {
211 handler = &jmploc;
212 setvar(name, val, flags);
213 }
214 handler = savehandler;
215 return err;
216}
217
218/*
219 * Set the value of a variable. The flags argument is ored with the
220 * flags of the variable. If val is NULL, the variable is unset.
221 */
222
223void
224setvar(name, val, flags)
225 char *name, *val;
226 int flags;
227{
228 char *p, *q;
229 int len;
230 int namelen;
231 char *nameeq;
232 int isbad;
233
234 isbad = 0;
235 p = name;
236 if (! is_name(*p))
237 isbad = 1;
238 p++;
239 for (;;) {
240 if (! is_in_name(*p)) {
241 if (*p == '\0' || *p == '=')
242 break;
243 isbad = 1;
244 }
245 p++;
246 }
247 namelen = p - name;
248 if (isbad)
249 error("%.*s: bad variable name", namelen, name);
250 len = namelen + 2; /* 2 is space for '=' and '\0' */
251 if (val == NULL) {
252 flags |= VUNSET;
253 } else {
254 len += strlen(val);
255 }
256 p = nameeq = ckmalloc(len);
257 q = name;
258 while (--namelen >= 0)
259 *p++ = *q++;
260 *p++ = '=';
261 *p = '\0';
262 if (val)
263 scopy(val, p);
264 setvareq(nameeq, flags);
265}
266
267STATIC int
268localevar(s)
269 char *s;
270 {
271 static char *lnames[7] = {
272 "ALL", "COLLATE", "CTYPE", "MONETARY",
273 "NUMERIC", "TIME", NULL
274 };
275 char **ss;
276
277 if (*s != 'L')
278 return 0;
279 if (varequal(s + 1, "ANG"))
280 return 1;
281 if (strncmp(s + 1, "C_", 2) != 0)
282 return 0;
283 for (ss = lnames; *ss ; ss++)
284 if (varequal(s + 3, *ss))
285 return 1;
286 return 0;
287}
288
289/*
290 * Same as setvar except that the variable and value are passed in
291 * the first argument as name=value. Since the first argument will
292 * be actually stored in the table, it should not be a string that
293 * will go away.
294 */
295
296void
297setvareq(s, flags)
298 char *s;
299 int flags;
300{
301 struct var *vp, **vpp;
302
303 vpp = hashvar(s);
304 for (vp = *vpp ; vp ; vp = vp->next) {
305 if (varequal(s, vp->text)) {
306 if (vp->flags & VREADONLY) {
307 size_t len = strchr(s, '=') - s;
308 error("%.*s: is read only", len, s);
309 }
310 INTOFF;
311
312 if (vp->func && (flags & VNOFUNC) == 0)
313 (*vp->func)(strchr(s, '=') + 1);
314
315 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
316 ckfree(vp->text);
317
318 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
319 vp->flags |= flags;
320 vp->text = s;
321
322 /*
323 * We could roll this to a function, to handle it as
324 * a regular variable function callback, but why bother?
325 */
326 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
327 chkmail(1);
328 if ((vp->flags & VEXPORT) && localevar(s)) {
329 putenv(s);
330 (void) setlocale(LC_ALL, "");
331 }
332 INTON;
333 return;
334 }
335 }
336 /* not found */
337 vp = ckmalloc(sizeof (*vp));
338 vp->flags = flags;
339 vp->text = s;
340 vp->next = *vpp;
341 vp->func = NULL;
342 INTOFF;
343 *vpp = vp;
344 if ((vp->flags & VEXPORT) && localevar(s)) {
345 putenv(s);
346 (void) setlocale(LC_ALL, "");
347 }
348 INTON;
349}
350
351
352
353/*
354 * Process a linked list of variable assignments.
355 */
356
357void
358listsetvar(list)
359 struct strlist *list;
360 {
361 struct strlist *lp;
362
363 INTOFF;
364 for (lp = list ; lp ; lp = lp->next) {
365 setvareq(savestr(lp->text), 0);
366 }
367 INTON;
368}
369
370
371
372/*
373 * Find the value of a variable. Returns NULL if not set.
374 */
375
376char *
377lookupvar(name)
378 char *name;
379 {
380 struct var *v;
381
382 for (v = *hashvar(name) ; v ; v = v->next) {
383 if (varequal(v->text, name)) {
384 if (v->flags & VUNSET)
385 return NULL;
386 return strchr(v->text, '=') + 1;
387 }
388 }
389 return NULL;
390}
391
392
393
394/*
395 * Search the environment of a builtin command. If the second argument
396 * is nonzero, return the value of a variable even if it hasn't been
397 * exported.
398 */
399
400char *
401bltinlookup(name, doall)
402 char *name;
403 int doall;
404{
405 struct strlist *sp;
406 struct var *v;
407
408 for (sp = cmdenviron ; sp ; sp = sp->next) {
409 if (varequal(sp->text, name))
410 return strchr(sp->text, '=') + 1;
411 }
412 for (v = *hashvar(name) ; v ; v = v->next) {
413 if (varequal(v->text, name)) {
414 if ((v->flags & VUNSET)
415 || (!doall && (v->flags & VEXPORT) == 0))
416 return NULL;
417 return strchr(v->text, '=') + 1;
418 }
419 }
420 return NULL;
421}
422
423
424
425/*
426 * Generate a list of exported variables. This routine is used to construct
427 * the third argument to execve when executing a program.
428 */
429
430char **
431environment() {
432 int nenv;
433 struct var **vpp;
434 struct var *vp;
435 char **env, **ep;
436
437 nenv = 0;
438 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
439 for (vp = *vpp ; vp ; vp = vp->next)
440 if (vp->flags & VEXPORT)
441 nenv++;
442 }
443 ep = env = stalloc((nenv + 1) * sizeof *env);
444 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
445 for (vp = *vpp ; vp ; vp = vp->next)
446 if (vp->flags & VEXPORT)
447 *ep++ = vp->text;
448 }
449 *ep = NULL;
450 return env;
451}
452
453
454/*
455 * Called when a shell procedure is invoked to clear out nonexported
456 * variables. It is also necessary to reallocate variables of with
457 * VSTACK set since these are currently allocated on the stack.
458 */
459
460#ifdef mkinit
461MKINIT void shprocvar();
462
463SHELLPROC {
464 shprocvar();
465}
466#endif
467
468void
469shprocvar() {
470 struct var **vpp;
471 struct var *vp, **prev;
472
473 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
474 for (prev = vpp ; (vp = *prev) != NULL ; ) {
475 if ((vp->flags & VEXPORT) == 0) {
476 *prev = vp->next;
477 if ((vp->flags & VTEXTFIXED) == 0)
478 ckfree(vp->text);
479 if ((vp->flags & VSTRFIXED) == 0)
480 ckfree(vp);
481 } else {
482 if (vp->flags & VSTACK) {
483 vp->text = savestr(vp->text);
484 vp->flags &=~ VSTACK;
485 }
486 prev = &vp->next;
487 }
488 }
489 }
490 initvar();
491}
492
493
494
495/*
496 * Command to list all variables which are set. Currently this command
497 * is invoked from the set command when the set command is called without
498 * any variables.
499 */
500
501int
502showvarscmd(argc, argv)
503 int argc __unused;
504 char **argv __unused;
505{
506 struct var **vpp;
507 struct var *vp;
508
509 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
510 for (vp = *vpp ; vp ; vp = vp->next) {
511 if ((vp->flags & VUNSET) == 0)
512 out1fmt("%s\n", vp->text);
513 }
514 }
515 return 0;
516}
517
518
519
520/*
521 * The export and readonly commands.
522 */
523
524int
525exportcmd(argc, argv)
526 int argc;
527 char **argv;
528{
529 struct var **vpp;
530 struct var *vp;
531 char *name;
532 char *p;
533 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
534
535 listsetvar(cmdenviron);
536 if (argc > 1) {
537 while ((name = *argptr++) != NULL) {
538 if ((p = strchr(name, '=')) != NULL) {
539 p++;
540 } else {
541 vpp = hashvar(name);
542 for (vp = *vpp ; vp ; vp = vp->next) {
543 if (varequal(vp->text, name)) {
544 vp->flags |= flag;
545 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
546 putenv(vp->text);
547 (void) setlocale(LC_ALL, "");
548 }
549 goto found;
550 }
551 }
552 }
553 setvar(name, p, flag);
554found:;
555 }
556 } else {
557 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
558 for (vp = *vpp ; vp ; vp = vp->next) {
559 if (vp->flags & flag) {
560 for (p = vp->text ; *p != '=' ; p++)
561 out1c(*p);
562 out1c('\n');
563 }
564 }
565 }
566 }
567 return 0;
568}
569
570
571/*
572 * The "local" command.
573 */
574
575int
576localcmd(argc, argv)
577 int argc __unused;
578 char **argv __unused;
579{
580 char *name;
581
582 if (! in_function())
583 error("Not in a function");
584 while ((name = *argptr++) != NULL) {
585 mklocal(name);
586 }
587 return 0;
588}
589
590
591/*
592 * Make a variable a local variable. When a variable is made local, it's
593 * value and flags are saved in a localvar structure. The saved values
594 * will be restored when the shell function returns. We handle the name
595 * "-" as a special case.
596 */
597
598void
599mklocal(name)
600 char *name;
601 {
602 struct localvar *lvp;
603 struct var **vpp;
604 struct var *vp;
605
606 INTOFF;
607 lvp = ckmalloc(sizeof (struct localvar));
608 if (name[0] == '-' && name[1] == '\0') {
609 lvp->text = ckmalloc(sizeof optlist);
610 memcpy(lvp->text, optlist, sizeof optlist);
611 vp = NULL;
612 } else {
613 vpp = hashvar(name);
614 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
615 if (vp == NULL) {
616 if (strchr(name, '='))
617 setvareq(savestr(name), VSTRFIXED);
618 else
619 setvar(name, NULL, VSTRFIXED);
620 vp = *vpp; /* the new variable */
621 lvp->text = NULL;
622 lvp->flags = VUNSET;
623 } else {
624 lvp->text = vp->text;
625 lvp->flags = vp->flags;
626 vp->flags |= VSTRFIXED|VTEXTFIXED;
627 if (strchr(name, '='))
628 setvareq(savestr(name), 0);
629 }
630 }
631 lvp->vp = vp;
632 lvp->next = localvars;
633 localvars = lvp;
634 INTON;
635}
636
637
638/*
639 * Called after a function returns.
640 */
641
642void
643poplocalvars() {
644 struct localvar *lvp;
645 struct var *vp;
646
647 while ((lvp = localvars) != NULL) {
648 localvars = lvp->next;
649 vp = lvp->vp;
650 if (vp == NULL) { /* $- saved */
651 memcpy(optlist, lvp->text, sizeof optlist);
652 ckfree(lvp->text);
653 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
654 (void)unsetvar(vp->text);
655 } else {
656 if ((vp->flags & VTEXTFIXED) == 0)
657 ckfree(vp->text);
658 vp->flags = lvp->flags;
659 vp->text = lvp->text;
660 }
661 ckfree(lvp);
662 }
663}
664
665
666int
667setvarcmd(argc, argv)
668 int argc;
669 char **argv;
670{
671 if (argc <= 2)
672 return unsetcmd(argc, argv);
673 else if (argc == 3)
674 setvar(argv[1], argv[2], 0);
675 else
676 error("List assignment not implemented");
677 return 0;
678}
679
680
681/*
682 * The unset builtin command. We unset the function before we unset the
683 * variable to allow a function to be unset when there is a readonly variable
684 * with the same name.
685 */
686
687int
688unsetcmd(argc, argv)
689 int argc __unused;
690 char **argv __unused;
691{
692 char **ap;
693 int i;
694 int flg_func = 0;
695 int flg_var = 0;
696 int ret = 0;
697
698 while ((i = nextopt("vf")) != '\0') {
699 if (i == 'f')
700 flg_func = 1;
701 else
702 flg_var = 1;
703 }
704 if (flg_func == 0 && flg_var == 0)
705 flg_var = 1;
706
707 for (ap = argptr; *ap ; ap++) {
708 if (flg_func)
709 ret |= unsetfunc(*ap);
710 if (flg_var)
711 ret |= unsetvar(*ap);
712 }
713 return ret;
714}
715
716
717/*
718 * Unset the specified variable.
719 */
720
721int
722unsetvar(s)
723 char *s;
724 {
725 struct var **vpp;
726 struct var *vp;
727
728 vpp = hashvar(s);
729 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
730 if (varequal(vp->text, s)) {
731 if (vp->flags & VREADONLY)
732 return (1);
733 INTOFF;
734 if (*(strchr(vp->text, '=') + 1) != '\0')
735 setvar(s, nullstr, 0);
736 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
737 unsetenv(s);
738 setlocale(LC_ALL, "");
739 }
740 vp->flags &= ~VEXPORT;
741 vp->flags |= VUNSET;
742 if ((vp->flags & VSTRFIXED) == 0) {
743 if ((vp->flags & VTEXTFIXED) == 0)
744 ckfree(vp->text);
745 *vpp = vp->next;
746 ckfree(vp);
747 }
748 INTON;
749 return (0);
750 }
751 }
752
753 return (1);
754}
755
756
757
758/*
759 * Find the appropriate entry in the hash table from the name.
760 */
761
762STATIC struct var **
763hashvar(p)
764 char *p;
765 {
766 unsigned int hashval;
767
768 hashval = ((unsigned char) *p) << 4;
769 while (*p && *p != '=')
770 hashval += (unsigned char) *p++;
771 return &vartab[hashval % VTABSIZE];
772}
773
774
775
776/*
777 * Returns true if the two strings specify the same varable. The first
778 * variable name is terminated by '='; the second may be terminated by
779 * either '=' or '\0'.
780 */
781
782STATIC int
783varequal(p, q)
784 char *p, *q;
785 {
786 while (*p == *q++) {
787 if (*p++ == '=')
788 return 1;
789 }
790 if (*p == '=' && *(q - 1) == '\0')
791 return 1;
792 return 0;
793}