Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/var.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 13344 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /*-
2     * Copyright (c) 1991, 1993
3     * The Regents of the University of California. All rights reserved.
4     * Copyright (c) 1997-2005
5     * Herbert Xu <herbert@gondor.apana.org.au>. 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. Neither the name of the University nor the names of its contributors
19     * may be used to endorse or promote products derived from this software
20     * without specific prior written permission.
21     *
22     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25     * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32     * SUCH DAMAGE.
33     */
34    
35     #include <unistd.h>
36     #include <stdlib.h>
37     #include <paths.h>
38    
39     /*
40     * Shell variables.
41     */
42    
43     #include "shell.h"
44     #include "output.h"
45     #include "expand.h"
46     #include "nodes.h" /* for other headers */
47     #include "eval.h" /* defines cmdenviron */
48     #include "exec.h"
49     #include "syntax.h"
50     #include "options.h"
51     #include "mail.h"
52     #include "var.h"
53     #include "memalloc.h"
54     #include "error.h"
55     #include "mystring.h"
56     #include "parser.h"
57     #include "show.h"
58     #ifndef SMALL
59     #include "myhistedit.h"
60     #endif
61     #include "system.h"
62    
63    
64     #define VTABSIZE 39
65    
66    
67     struct localvar *localvars;
68    
69     const char defpathvar[] =
70     "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
71     #ifdef IFS_BROKEN
72     const char defifsvar[] = "IFS= \t\n";
73     #else
74     const char defifs[] = " \t\n";
75     #endif
76    
77     struct var varinit[] = {
78     #if ATTY
79     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY\0", 0 },
80     #endif
81     #ifdef IFS_BROKEN
82     { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
83     #else
84     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
85     #endif
86     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
87     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
88     { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
89     { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
90     { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
91     { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
92     { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
93     #ifndef SMALL
94     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM\0", 0 },
95     { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE\0", sethistsize },
96     #endif
97     };
98    
99     STATIC struct var *vartab[VTABSIZE];
100    
101     STATIC void mklocal(char *);
102     STATIC struct var **hashvar(const char *);
103     STATIC int vpcmp(const void *, const void *);
104     STATIC struct var **findvar(struct var **, const char *);
105    
106     /*
107     * Initialize the varable symbol tables and import the environment
108     */
109    
110     #ifdef mkinit
111     INCLUDE <unistd.h>
112     INCLUDE <sys/types.h>
113     INCLUDE <sys/stat.h>
114     INCLUDE "cd.h"
115     INCLUDE "output.h"
116     INCLUDE "var.h"
117     MKINIT char **environ;
118     INIT {
119     char **envp;
120     static char ppid[32] = "PPID=";
121     const char *p;
122     struct stat st1, st2;
123    
124     initvar();
125     for (envp = environ ; *envp ; envp++) {
126     if (strchr(*envp, '=')) {
127     setvareq(*envp, VEXPORT|VTEXTFIXED);
128     }
129     }
130    
131     fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
132     setvareq(ppid, VTEXTFIXED);
133    
134     p = lookupvar("PWD");
135     if (p)
136     if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
137     st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
138     p = 0;
139     setpwd(p, 0);
140     }
141     #endif
142    
143    
144     /*
145     * This routine initializes the builtin variables. It is called when the
146     * shell is initialized.
147     */
148    
149     void
150     initvar(void)
151     {
152     struct var *vp;
153     struct var *end;
154     struct var **vpp;
155    
156     vp = varinit;
157     end = vp + sizeof(varinit) / sizeof(varinit[0]);
158     do {
159     vpp = hashvar(vp->text);
160     vp->next = *vpp;
161     *vpp = vp;
162     } while (++vp < end);
163     /*
164     * PS1 depends on uid
165     */
166     if (!geteuid())
167     vps1.text = "PS1=# ";
168     }
169    
170     /*
171     * Safe version of setvar, returns 1 on success 0 on failure.
172     */
173    
174     int
175     setvarsafe(const char *name, const char *val, int flags)
176     {
177     int err;
178     volatile int saveint;
179     struct jmploc *volatile savehandler = handler;
180     struct jmploc jmploc;
181    
182     SAVEINT(saveint);
183     if (setjmp(jmploc.loc))
184     err = 1;
185     else {
186     handler = &jmploc;
187     setvar(name, val, flags);
188     err = 0;
189     }
190     handler = savehandler;
191     RESTOREINT(saveint);
192     return err;
193     }
194    
195     /*
196     * Set the value of a variable. The flags argument is ored with the
197     * flags of the variable. If val is NULL, the variable is unset.
198     */
199    
200     void
201     setvar(const char *name, const char *val, int flags)
202     {
203     char *p, *q;
204     size_t namelen;
205     char *nameeq;
206     size_t vallen;
207    
208     q = endofname(name);
209     p = strchrnul(q, '=');
210     namelen = p - name;
211     if (!namelen || p != q)
212     sh_error("%.*s: bad variable name", namelen, name);
213     vallen = 0;
214     if (val == NULL) {
215     flags |= VUNSET;
216     } else {
217     vallen = strlen(val);
218     }
219     INTOFF;
220     p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
221     if (val) {
222     *p++ = '=';
223     p = mempcpy(p, val, vallen);
224     }
225     *p = '\0';
226     setvareq(nameeq, flags | VNOSAVE);
227     INTON;
228     }
229    
230    
231    
232     /*
233     * Same as setvar except that the variable and value are passed in
234     * the first argument as name=value. Since the first argument will
235     * be actually stored in the table, it should not be a string that
236     * will go away.
237     * Called with interrupts off.
238     */
239    
240     void
241     setvareq(char *s, int flags)
242     {
243     struct var *vp, **vpp;
244    
245     vpp = hashvar(s);
246     flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
247     vp = *findvar(vpp, s);
248     if (vp) {
249     if (vp->flags & VREADONLY) {
250     const char *n;
251    
252     if (flags & VNOSAVE)
253     free(s);
254     n = vp->text;
255     sh_error("%.*s: is read only", strchrnul(n, '=') - n,
256     n);
257     }
258    
259     if (flags & VNOSET)
260     return;
261    
262     if (vp->func && (flags & VNOFUNC) == 0)
263     (*vp->func)(strchrnul(s, '=') + 1);
264    
265     if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
266     ckfree(vp->text);
267    
268     flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
269     } else {
270     if (flags & VNOSET)
271     return;
272     /* not found */
273     vp = ckmalloc(sizeof (*vp));
274     vp->next = *vpp;
275     vp->func = NULL;
276     *vpp = vp;
277     }
278     if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
279     s = savestr(s);
280     vp->text = s;
281     vp->flags = flags;
282     }
283    
284    
285    
286     /*
287     * Process a linked list of variable assignments.
288     */
289    
290     void
291     listsetvar(struct strlist *list, int flags)
292     {
293     struct strlist *lp;
294    
295     lp = list;
296     if (!lp)
297     return;
298     INTOFF;
299     do {
300     setvareq(lp->text, flags);
301     } while ((lp = lp->next));
302     INTON;
303     }
304    
305    
306     /*
307     * Find the value of a variable. Returns NULL if not set.
308     */
309    
310     char *
311     lookupvar(const char *name)
312     {
313     struct var *v;
314    
315     if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
316     return strchrnul(v->text, '=') + 1;
317     }
318     return NULL;
319     }
320    
321    
322    
323     /*
324     * Search the environment of a builtin command.
325     */
326    
327     char *
328     bltinlookup(const char *name)
329     {
330     struct strlist *sp;
331    
332     for (sp = cmdenviron ; sp ; sp = sp->next) {
333     if (varequal(sp->text, name))
334     return strchrnul(sp->text, '=') + 1;
335     }
336     return lookupvar(name);
337     }
338    
339    
340    
341     /*
342     * Generate a list of variables satisfying the given conditions.
343     */
344    
345     char **
346     listvars(int on, int off, char ***end)
347     {
348     struct var **vpp;
349     struct var *vp;
350     char **ep;
351     int mask;
352    
353     STARTSTACKSTR(ep);
354     vpp = vartab;
355     mask = on | off;
356     do {
357     for (vp = *vpp ; vp ; vp = vp->next)
358     if ((vp->flags & mask) == on) {
359     if (ep == stackstrend())
360     ep = growstackstr();
361     *ep++ = (char *) vp->text;
362     }
363     } while (++vpp < vartab + VTABSIZE);
364     if (ep == stackstrend())
365     ep = growstackstr();
366     if (end)
367     *end = ep;
368     *ep++ = NULL;
369     return grabstackstr(ep);
370     }
371    
372    
373    
374     /*
375     * POSIX requires that 'set' (but not export or readonly) output the
376     * variables in lexicographic order - by the locale's collating order (sigh).
377     * Maybe we could keep them in an ordered balanced binary tree
378     * instead of hashed lists.
379     * For now just roll 'em through qsort for printing...
380     */
381    
382     int
383     showvars(const char *prefix, int on, int off)
384     {
385     const char *sep;
386     char **ep, **epend;
387    
388     ep = listvars(on, off, &epend);
389     qsort(ep, epend - ep, sizeof(char *), vpcmp);
390    
391     sep = *prefix ? spcstr : prefix;
392    
393     for (; ep < epend; ep++) {
394     const char *p;
395     const char *q;
396    
397     p = strchrnul(*ep, '=');
398     q = nullstr;
399     if (*p)
400     q = single_quote(++p);
401    
402     out1fmt("%s%s%.*s%s\n", prefix, sep, (int)(p - *ep), *ep, q);
403     }
404    
405     return 0;
406     }
407    
408    
409    
410     /*
411     * The export and readonly commands.
412     */
413    
414     int
415     exportcmd(int argc, char **argv)
416     {
417     struct var *vp;
418     char *name;
419     const char *p;
420     char **aptr;
421     int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
422     int notp;
423    
424     notp = nextopt("p") - 'p';
425     if (notp && ((name = *(aptr = argptr)))) {
426     do {
427     if ((p = strchr(name, '=')) != NULL) {
428     p++;
429     } else {
430     if ((vp = *findvar(hashvar(name), name))) {
431     vp->flags |= flag;
432     continue;
433     }
434     }
435     setvar(name, p, flag);
436     } while ((name = *++aptr) != NULL);
437     } else {
438     showvars(argv[0], flag, 0);
439     }
440     return 0;
441     }
442    
443    
444     /*
445     * The "local" command.
446     */
447    
448     int
449     localcmd(int argc, char **argv)
450     {
451     char *name;
452    
453     argv = argptr;
454     while ((name = *argv++) != NULL) {
455     mklocal(name);
456     }
457     return 0;
458     }
459    
460    
461     /*
462     * Make a variable a local variable. When a variable is made local, it's
463     * value and flags are saved in a localvar structure. The saved values
464     * will be restored when the shell function returns. We handle the name
465     * "-" as a special case.
466     */
467    
468     STATIC void
469     mklocal(char *name)
470     {
471     struct localvar *lvp;
472     struct var **vpp;
473     struct var *vp;
474    
475     INTOFF;
476     lvp = ckmalloc(sizeof (struct localvar));
477     if (name[0] == '-' && name[1] == '\0') {
478     char *p;
479     p = ckmalloc(sizeof(optlist));
480     lvp->text = memcpy(p, optlist, sizeof(optlist));
481     vp = NULL;
482     } else {
483     char *eq;
484    
485     vpp = hashvar(name);
486     vp = *findvar(vpp, name);
487     eq = strchr(name, '=');
488     if (vp == NULL) {
489     if (eq)
490     setvareq(name, VSTRFIXED);
491     else
492     setvar(name, NULL, VSTRFIXED);
493     vp = *vpp; /* the new variable */
494     lvp->flags = VUNSET;
495     } else {
496     lvp->text = vp->text;
497     lvp->flags = vp->flags;
498     vp->flags |= VSTRFIXED|VTEXTFIXED;
499     if (eq)
500     setvareq(name, 0);
501     }
502     }
503     lvp->vp = vp;
504     lvp->next = localvars;
505     localvars = lvp;
506     INTON;
507     }
508    
509    
510     /*
511     * Called after a function returns.
512     * Interrupts must be off.
513     */
514    
515     void
516     poplocalvars(void)
517     {
518     struct localvar *lvp;
519     struct var *vp;
520    
521     while ((lvp = localvars) != NULL) {
522     localvars = lvp->next;
523     vp = lvp->vp;
524     TRACE(("poplocalvar %s", vp ? vp->text : "-"));
525     if (vp == NULL) { /* $- saved */
526     memcpy(optlist, lvp->text, sizeof(optlist));
527     ckfree(lvp->text);
528     optschanged();
529     } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
530     unsetvar(vp->text);
531     } else {
532     if (vp->func)
533     (*vp->func)(strchrnul(lvp->text, '=') + 1);
534     if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
535     ckfree(vp->text);
536     vp->flags = lvp->flags;
537     vp->text = lvp->text;
538     }
539     ckfree(lvp);
540     }
541     }
542    
543    
544     /*
545     * The unset builtin command. We unset the function before we unset the
546     * variable to allow a function to be unset when there is a readonly variable
547     * with the same name.
548     */
549    
550     int
551     unsetcmd(int argc, char **argv)
552     {
553     char **ap;
554     int i;
555     int flag = 0;
556     int ret = 0;
557    
558     while ((i = nextopt("vf")) != '\0') {
559     flag = i;
560     }
561    
562     for (ap = argptr; *ap ; ap++) {
563     if (flag != 'f') {
564     i = unsetvar(*ap);
565     ret |= i;
566     if (!(i & 2))
567     continue;
568     }
569     if (flag != 'v')
570     unsetfunc(*ap);
571     }
572     return ret & 1;
573     }
574    
575    
576     /*
577     * Unset the specified variable.
578     */
579    
580     int
581     unsetvar(const char *s)
582     {
583     struct var **vpp;
584     struct var *vp;
585     int retval;
586    
587     vpp = findvar(hashvar(s), s);
588     vp = *vpp;
589     retval = 2;
590     if (vp) {
591     int flags = vp->flags;
592    
593     retval = 1;
594     if (flags & VREADONLY)
595     goto out;
596     if (flags & VUNSET)
597     goto ok;
598     if ((flags & VSTRFIXED) == 0) {
599     INTOFF;
600     if ((flags & (VTEXTFIXED|VSTACK)) == 0)
601     ckfree(vp->text);
602     *vpp = vp->next;
603     ckfree(vp);
604     INTON;
605     } else {
606     setvar(s, 0, 0);
607     vp->flags &= ~VEXPORT;
608     }
609     ok:
610     retval = 0;
611     }
612    
613     out:
614     return retval;
615     }
616    
617    
618    
619     /*
620     * Find the appropriate entry in the hash table from the name.
621     */
622    
623     STATIC struct var **
624     hashvar(const char *p)
625     {
626     unsigned int hashval;
627    
628     hashval = ((unsigned char) *p) << 4;
629     while (*p && *p != '=')
630     hashval += (unsigned char) *p++;
631     return &vartab[hashval % VTABSIZE];
632     }
633    
634    
635    
636     /*
637     * Compares two strings up to the first = or '\0'. The first
638     * string must be terminated by '='; the second may be terminated by
639     * either '=' or '\0'.
640     */
641    
642     int
643     varcmp(const char *p, const char *q)
644     {
645     int c, d;
646    
647     while ((c = *p) == (d = *q)) {
648     if (!c || c == '=')
649     goto out;
650     p++;
651     q++;
652     }
653     if (c == '=')
654     c = 0;
655     if (d == '=')
656     d = 0;
657     out:
658     return c - d;
659     }
660    
661     STATIC int
662     vpcmp(const void *a, const void *b)
663     {
664     return varcmp(*(const char **)a, *(const char **)b);
665     }
666    
667     STATIC struct var **
668     findvar(struct var **vpp, const char *name)
669     {
670     for (; *vpp; vpp = &(*vpp)->next) {
671     if (varequal((*vpp)->text, name)) {
672     break;
673     }
674     }
675     return vpp;
676     }