Subversion Repositories HelenOS

Rev

Rev 2714 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 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
42
static 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
 
78
struct varinit {
79
    struct var *var;
80
    int flags;
81
    const char *text;
82
    void (*func) (const char *);
83
};
84
 
85
 
86
#if ATTY
87
struct var vatty;
88
#endif
89
#ifndef SMALL
90
struct var vhistsize;
91
struct var vterm;
92
#endif
93
struct var vifs;
94
struct var vmail;
95
struct var vmpath;
96
struct var vpath;
97
struct var vps1;
98
struct var vps2;
99
struct var vvers;
100
struct var voptind;
101
 
102
const 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
 
134
struct var *vartab[VTABSIZE];
135
 
136
STATIC struct var **hashvar (const char *);
137
STATIC 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
145
INCLUDE "cd.h"
146
INCLUDE "var.h"
147
INIT {
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
 
170
void
171
initvar() {
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
 
206
int
207
setvarsafe(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
 
233
void
234
setvar(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
 
288
void
289
setvareq(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
 
341
void
342
listsetvar(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
 
360
char *
361
lookupvar(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
 
384
char *
385
bltinlookup(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
 
414
char **
415
environment() {
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
446
MKINIT void shprocvar (void);
447
 
448
SHELLPROC {
449
    shprocvar();
450
}
451
#endif
452
 
453
void
454
shprocvar() {
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
 
486
int
487
showvarscmd(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
 
509
int
510
exportcmd(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);
537
found:;
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
 
562
int
563
localcmd(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
 
585
void
586
mklocal(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
 
630
void
631
poplocalvars() {
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
 
654
int
655
setvarcmd(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
 
675
int
676
unsetcmd(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
 
709
int
710
unsetvar(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
 
746
STATIC struct var **
747
hashvar(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
 
766
STATIC int
767
varequal(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
}