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