source: mainline/uspace/app/ash/var.c@ 8ccd2ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8ccd2ea was c28a023, checked in by Josef Cejka <malyzelenyhnus@…>, 17 years ago

Initial commit of ash shell.
It cannot be compiled yet.

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