var.c revision 1.9 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
37 #ifndef lint
38 /*static char sccsid[] = "from: @(#)var.c 8.1 (Berkeley) 5/31/93";*/
39 static char *rcsid = "$Id: var.c,v 1.9 1994/09/23 11:28:46 mycroft Exp $";
40 #endif /* not lint */
41
42 /*
43 * Shell variables.
44 */
45
46 #include "shell.h"
47 #include "output.h"
48 #include "expand.h"
49 #include "nodes.h" /* for other headers */
50 #include "eval.h" /* defines cmdenviron */
51 #include "exec.h"
52 #include "syntax.h"
53 #include "options.h"
54 #include "mail.h"
55 #include "var.h"
56 #include "memalloc.h"
57 #include "error.h"
58 #include "mystring.h"
59 #include <unistd.h>
60
61
62 #define VTABSIZE 39
63
64
65 struct varinit {
66 struct var *var;
67 int flags;
68 char *text;
69 };
70
71
72 #if ATTY
73 struct var vatty;
74 #endif
75 #ifndef NO_HISTORY
76 struct var vhistsize;
77 #endif
78 struct var vifs;
79 struct var vmail;
80 struct var vmpath;
81 struct var vpath;
82 struct var vps1;
83 struct var vps2;
84 struct var vvers;
85 #if ATTY
86 struct var vterm;
87 #endif
88
89 const struct varinit varinit[] = {
90 #if ATTY
91 {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="},
92 #endif
93 #ifndef NO_HISTORY
94 {&vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE="},
95 #endif
96 {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"},
97 {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="},
98 {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="},
99 {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=:/bin:/usr/bin"},
100 /*
101 * vps1 depends on uid
102 */
103 {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "},
104 #if ATTY
105 {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="},
106 #endif
107 {NULL, 0, NULL}
108 };
109
110 struct var *vartab[VTABSIZE];
111
112 STATIC int unsetvar __P((char *));
113 STATIC struct var **hashvar __P((char *));
114 STATIC int varequal __P((char *, char *));
115
116 /*
117 * Initialize the varable symbol tables and import the environment
118 */
119
120 #ifdef mkinit
121 INCLUDE "var.h"
122 INIT {
123 char **envp;
124 extern char **environ;
125
126 initvar();
127 for (envp = environ ; *envp ; envp++) {
128 if (strchr(*envp, '=')) {
129 setvareq(*envp, VEXPORT|VTEXTFIXED);
130 }
131 }
132 }
133 #endif
134
135
136 /*
137 * This routine initializes the builtin variables. It is called when the
138 * shell is initialized and again when a shell procedure is spawned.
139 */
140
141 void
142 initvar() {
143 const struct varinit *ip;
144 struct var *vp;
145 struct var **vpp;
146
147 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
148 if ((vp->flags & VEXPORT) == 0) {
149 vpp = hashvar(ip->text);
150 vp->next = *vpp;
151 *vpp = vp;
152 vp->text = ip->text;
153 vp->flags = ip->flags;
154 }
155 }
156 /*
157 * PS1 depends on uid
158 */
159 if ((vps1.flags & VEXPORT) == 0) {
160 vpp = hashvar("PS1=");
161 vps1.next = *vpp;
162 *vpp = &vps1;
163 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
164 vps1.flags = VSTRFIXED|VTEXTFIXED;
165 }
166 }
167
168 /*
169 * Set the value of a variable. The flags argument is ored with the
170 * flags of the variable. If val is NULL, the variable is unset.
171 */
172
173 void
174 setvar(name, val, flags)
175 char *name, *val;
176 {
177 char *p, *q;
178 int len;
179 int namelen;
180 char *nameeq;
181 int isbad;
182
183 isbad = 0;
184 p = name;
185 if (! is_name(*p++))
186 isbad = 1;
187 for (;;) {
188 if (! is_in_name(*p)) {
189 if (*p == '\0' || *p == '=')
190 break;
191 isbad = 1;
192 }
193 p++;
194 }
195 namelen = p - name;
196 if (isbad)
197 error("%.*s: bad variable name", namelen, name);
198 len = namelen + 2; /* 2 is space for '=' and '\0' */
199 if (val == NULL) {
200 flags |= VUNSET;
201 } else {
202 len += strlen(val);
203 }
204 p = nameeq = ckmalloc(len);
205 q = name;
206 while (--namelen >= 0)
207 *p++ = *q++;
208 *p++ = '=';
209 *p = '\0';
210 if (val)
211 scopy(val, p);
212 setvareq(nameeq, flags);
213 }
214
215
216
217 /*
218 * Same as setvar except that the variable and value are passed in
219 * the first argument as name=value. Since the first argument will
220 * be actually stored in the table, it should not be a string that
221 * will go away.
222 */
223
224 void
225 setvareq(s, flags)
226 char *s;
227 {
228 struct var *vp, **vpp;
229
230 vpp = hashvar(s);
231 for (vp = *vpp ; vp ; vp = vp->next) {
232 if (varequal(s, vp->text)) {
233 if (vp->flags & VREADONLY) {
234 int len = strchr(s, '=') - s;
235 error("%.*s: is read only", len, s);
236 }
237 INTOFF;
238 if (vp == &vpath)
239 changepath(s + 5); /* 5 = strlen("PATH=") */
240 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
241 ckfree(vp->text);
242 vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
243 vp->flags |= flags;
244 vp->text = s;
245 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
246 chkmail(1);
247 #ifndef NO_HISTORY
248 if (vp == &vhistsize)
249 sethistsize();
250 #endif
251 INTON;
252 return;
253 }
254 }
255 /* not found */
256 vp = ckmalloc(sizeof (*vp));
257 vp->flags = flags;
258 vp->text = s;
259 vp->next = *vpp;
260 *vpp = vp;
261 }
262
263
264
265 /*
266 * Process a linked list of variable assignments.
267 */
268
269 void
270 listsetvar(list)
271 struct strlist *list;
272 {
273 struct strlist *lp;
274
275 INTOFF;
276 for (lp = list ; lp ; lp = lp->next) {
277 setvareq(savestr(lp->text), 0);
278 }
279 INTON;
280 }
281
282
283
284 /*
285 * Find the value of a variable. Returns NULL if not set.
286 */
287
288 char *
289 lookupvar(name)
290 char *name;
291 {
292 struct var *v;
293
294 for (v = *hashvar(name) ; v ; v = v->next) {
295 if (varequal(v->text, name)) {
296 if (v->flags & VUNSET)
297 return NULL;
298 return strchr(v->text, '=') + 1;
299 }
300 }
301 return NULL;
302 }
303
304
305
306 /*
307 * Search the environment of a builtin command. If the second argument
308 * is nonzero, return the value of a variable even if it hasn't been
309 * exported.
310 */
311
312 char *
313 bltinlookup(name, doall)
314 char *name;
315 {
316 struct strlist *sp;
317 struct var *v;
318
319 for (sp = cmdenviron ; sp ; sp = sp->next) {
320 if (varequal(sp->text, name))
321 return strchr(sp->text, '=') + 1;
322 }
323 for (v = *hashvar(name) ; v ; v = v->next) {
324 if (varequal(v->text, name)) {
325 if (v->flags & VUNSET
326 || ! doall && (v->flags & VEXPORT) == 0)
327 return NULL;
328 return strchr(v->text, '=') + 1;
329 }
330 }
331 return NULL;
332 }
333
334
335
336 /*
337 * Generate a list of exported variables. This routine is used to construct
338 * the third argument to execve when executing a program.
339 */
340
341 char **
342 environment() {
343 int nenv;
344 struct var **vpp;
345 struct var *vp;
346 char **env, **ep;
347
348 nenv = 0;
349 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
350 for (vp = *vpp ; vp ; vp = vp->next)
351 if (vp->flags & VEXPORT)
352 nenv++;
353 }
354 ep = env = stalloc((nenv + 1) * sizeof *env);
355 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
356 for (vp = *vpp ; vp ; vp = vp->next)
357 if (vp->flags & VEXPORT)
358 *ep++ = vp->text;
359 }
360 *ep = NULL;
361 return env;
362 }
363
364
365 /*
366 * Called when a shell procedure is invoked to clear out nonexported
367 * variables. It is also necessary to reallocate variables of with
368 * VSTACK set since these are currently allocated on the stack.
369 */
370
371 #ifdef mkinit
372 MKINIT void shprocvar();
373
374 SHELLPROC {
375 shprocvar();
376 }
377 #endif
378
379 void
380 shprocvar() {
381 struct var **vpp;
382 struct var *vp, **prev;
383
384 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
385 for (prev = vpp ; (vp = *prev) != NULL ; ) {
386 if ((vp->flags & VEXPORT) == 0) {
387 *prev = vp->next;
388 if ((vp->flags & VTEXTFIXED) == 0)
389 ckfree(vp->text);
390 if ((vp->flags & VSTRFIXED) == 0)
391 ckfree(vp);
392 } else {
393 if (vp->flags & VSTACK) {
394 vp->text = savestr(vp->text);
395 vp->flags &=~ VSTACK;
396 }
397 prev = &vp->next;
398 }
399 }
400 }
401 initvar();
402 }
403
404
405
406 /*
407 * Command to list all variables which are set. Currently this command
408 * is invoked from the set command when the set command is called without
409 * any variables.
410 */
411
412 int
413 showvarscmd(argc, argv) char **argv; {
414 struct var **vpp;
415 struct var *vp;
416
417 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
418 for (vp = *vpp ; vp ; vp = vp->next) {
419 if ((vp->flags & VUNSET) == 0)
420 out1fmt("%s\n", vp->text);
421 }
422 }
423 return 0;
424 }
425
426
427
428 /*
429 * The export and readonly commands.
430 */
431
432 int
433 exportcmd(argc, argv) char **argv; {
434 struct var **vpp;
435 struct var *vp;
436 char *name;
437 char *p;
438 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
439
440 listsetvar(cmdenviron);
441 if (argc > 1) {
442 while ((name = *argptr++) != NULL) {
443 if ((p = strchr(name, '=')) != NULL) {
444 p++;
445 } else {
446 vpp = hashvar(name);
447 for (vp = *vpp ; vp ; vp = vp->next) {
448 if (varequal(vp->text, name)) {
449 vp->flags |= flag;
450 goto found;
451 }
452 }
453 }
454 setvar(name, p, flag);
455 found:;
456 }
457 } else {
458 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
459 for (vp = *vpp ; vp ; vp = vp->next) {
460 if (vp->flags & flag) {
461 for (p = vp->text ; *p != '=' ; p++)
462 out1c(*p);
463 out1c('\n');
464 }
465 }
466 }
467 }
468 return 0;
469 }
470
471
472 /*
473 * The "local" command.
474 */
475
476 localcmd(argc, argv) char **argv; {
477 char *name;
478
479 if (! in_function())
480 error("Not in a function");
481 while ((name = *argptr++) != NULL) {
482 mklocal(name);
483 }
484 return 0;
485 }
486
487
488 /*
489 * Make a variable a local variable. When a variable is made local, it's
490 * value and flags are saved in a localvar structure. The saved values
491 * will be restored when the shell function returns. We handle the name
492 * "-" as a special case.
493 */
494
495 void
496 mklocal(name)
497 char *name;
498 {
499 struct localvar *lvp;
500 struct var **vpp;
501 struct var *vp;
502
503 INTOFF;
504 lvp = ckmalloc(sizeof (struct localvar));
505 if (name[0] == '-' && name[1] == '\0') {
506 lvp->text = ckmalloc(sizeof optlist);
507 memcpy(lvp->text, optlist, sizeof optlist);
508 vp = NULL;
509 } else {
510 vpp = hashvar(name);
511 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
512 if (vp == NULL) {
513 if (strchr(name, '='))
514 setvareq(savestr(name), VSTRFIXED);
515 else
516 setvar(name, NULL, VSTRFIXED);
517 vp = *vpp; /* the new variable */
518 lvp->text = NULL;
519 lvp->flags = VUNSET;
520 } else {
521 lvp->text = vp->text;
522 lvp->flags = vp->flags;
523 vp->flags |= VSTRFIXED|VTEXTFIXED;
524 if (strchr(name, '='))
525 setvareq(savestr(name), 0);
526 }
527 }
528 lvp->vp = vp;
529 lvp->next = localvars;
530 localvars = lvp;
531 INTON;
532 }
533
534
535 /*
536 * Called after a function returns.
537 */
538
539 void
540 poplocalvars() {
541 struct localvar *lvp;
542 struct var *vp;
543
544 while ((lvp = localvars) != NULL) {
545 localvars = lvp->next;
546 vp = lvp->vp;
547 if (vp == NULL) { /* $- saved */
548 memcpy(optlist, lvp->text, sizeof optlist);
549 ckfree(lvp->text);
550 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
551 (void)unsetvar(vp->text);
552 } else {
553 if ((vp->flags & VTEXTFIXED) == 0)
554 ckfree(vp->text);
555 vp->flags = lvp->flags;
556 vp->text = lvp->text;
557 }
558 ckfree(lvp);
559 }
560 }
561
562
563 setvarcmd(argc, argv) char **argv; {
564 if (argc <= 2)
565 return unsetcmd(argc, argv);
566 else if (argc == 3)
567 setvar(argv[1], argv[2], 0);
568 else
569 error("List assignment not implemented");
570 return 0;
571 }
572
573
574 /*
575 * The unset builtin command. We unset the function before we unset the
576 * variable to allow a function to be unset when there is a readonly variable
577 * with the same name.
578 */
579
580 unsetcmd(argc, argv) char **argv; {
581 char **ap;
582 int i;
583 int flg_func = 0;
584 int flg_var = 0;
585 int ret = 0;
586
587 while ((i = nextopt("vf")) != '\0') {
588 if (i == 'f')
589 flg_func = 1;
590 else
591 flg_var = 1;
592 }
593 if (flg_func == 0 && flg_var == 0)
594 flg_var = 1;
595
596 for (ap = argptr; *ap ; ap++) {
597 if (flg_func)
598 ret |= unsetfunc(*ap);
599 if (flg_var)
600 ret |= unsetvar(*ap);
601 }
602 return ret;
603 }
604
605
606 /*
607 * Unset the specified variable.
608 */
609
610 STATIC int
611 unsetvar(s)
612 char *s;
613 {
614 struct var **vpp;
615 struct var *vp;
616
617 vpp = hashvar(s);
618 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
619 if (varequal(vp->text, s)) {
620 if (vp->flags & VREADONLY)
621 return (1);
622 INTOFF;
623 if (*(strchr(vp->text, '=') + 1) != '\0')
624 setvar(s, nullstr, 0);
625 vp->flags &=~ VEXPORT;
626 vp->flags |= VUNSET;
627 if ((vp->flags & VSTRFIXED) == 0) {
628 if ((vp->flags & VTEXTFIXED) == 0)
629 ckfree(vp->text);
630 *vpp = vp->next;
631 ckfree(vp);
632 }
633 INTON;
634 return (0);
635 }
636 }
637
638 return (1);
639 }
640
641
642
643 /*
644 * Find the appropriate entry in the hash table from the name.
645 */
646
647 STATIC struct var **
648 hashvar(p)
649 register char *p;
650 {
651 unsigned int hashval;
652
653 hashval = *p << 4;
654 while (*p && *p != '=')
655 hashval += *p++;
656 return &vartab[hashval % VTABSIZE];
657 }
658
659
660
661 /*
662 * Returns true if the two strings specify the same varable. The first
663 * variable name is terminated by '='; the second may be terminated by
664 * either '=' or '\0'.
665 */
666
667 STATIC int
668 varequal(p, q)
669 register char *p, *q;
670 {
671 while (*p == *q++) {
672 if (*p++ == '=')
673 return 1;
674 }
675 if (*p == '=' && *(q - 1) == '\0')
676 return 1;
677 return 0;
678 }
679