00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef lint
00034 #if 0
00035 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
00036 #endif
00037 #endif
00038
00039
00040
00041
00042
00043 #include <unistd.h>
00044 #include <stdlib.h>
00045 #ifndef NO_PATHS_H
00046 #include <paths.h>
00047 #endif
00048
00049
00050
00051
00052
00053 #include <locale.h>
00054
00055 #include "shell.h"
00056 #include "output.h"
00057 #include "expand.h"
00058 #include "nodes.h"
00059 #include "eval.h"
00060 #include "exec.h"
00061 #include "syntax.h"
00062 #include "options.h"
00063 #include "mail.h"
00064 #include "var.h"
00065 #include "memalloc.h"
00066 #include "error.h"
00067 #include "mystring.h"
00068 #include "parser.h"
00069 #if !defined(NO_HISTORY) && !defined(EDITLINE)
00070 #include "myhistedit.h"
00071 #endif
00072
00073 #include "builtins.h"
00074
00075 #ifndef _PATH_DEFPATH
00076 #define _PATH_DEFPATH "/usr/bin:/bin"
00077 #endif
00078
00079 #define VTABSIZE 39
00080
00081
00082 struct varinit {
00083 struct var *var;
00084 int flags;
00085 char *text;
00086 void (*func)(const char *);
00087 };
00088
00089
00090 #ifndef NO_HISTORY
00091 struct var vhistsize;
00092 #endif
00093 struct var vifs;
00094 struct var vmail;
00095 struct var vmpath;
00096 struct var vpath;
00097 struct var vppid;
00098 struct var vps1;
00099 struct var vps2;
00100 struct var vpse;
00101 struct var vvers;
00102 STATIC struct var voptind;
00103
00104 STATIC const struct varinit varinit[] = {
00105 #if !defined(NO_HISTORY) && !defined(EDITLINE)
00106 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
00107 sethistsize },
00108 #endif
00109 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
00110 NULL },
00111 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
00112 NULL },
00113 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
00114 NULL },
00115 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH,
00116 changepath },
00117 { &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=",
00118 NULL },
00119
00120
00121
00122 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
00123 NULL },
00124 { &vpse, VSTRFIXED|VTEXTFIXED|VUNSET, "PSE=",
00125 NULL },
00126 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
00127 getoptsreset },
00128 { NULL, 0, NULL,
00129 NULL }
00130 };
00131
00132 STATIC struct var *vartab[VTABSIZE];
00133
00134 STATIC struct var **hashvar(char *);
00135 STATIC int varequal(char *, char *);
00136 STATIC int localevar(char *);
00137
00138
00139
00140
00141
00142 #ifdef mkinit
00143 INCLUDE "var.h"
00144 INIT {
00145 char **envp;
00146 extern char **environ;
00147
00148 initvar();
00149 for (envp = environ ; *envp ; envp++) {
00150 if (strchr(*envp, '=')) {
00151 setvareq(*envp, VEXPORT|VTEXTFIXED);
00152 }
00153 }
00154 }
00155 #endif
00156
00157
00158
00159
00160
00161
00162
00163 void
00164 initvar(void)
00165 {
00166 char ppid[20];
00167 const struct varinit *ip;
00168 struct var *vp;
00169 struct var **vpp;
00170
00171 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
00172 if ((vp->flags & VEXPORT) == 0) {
00173 vpp = hashvar(ip->text);
00174 vp->next = *vpp;
00175 *vpp = vp;
00176 vp->text = ip->text;
00177 vp->flags = ip->flags;
00178 vp->func = ip->func;
00179 }
00180 }
00181
00182
00183
00184 if ((vps1.flags & VEXPORT) == 0) {
00185 vpp = hashvar("PS1=");
00186 vps1.next = *vpp;
00187 *vpp = &vps1;
00188 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
00189 vps1.flags = VSTRFIXED|VTEXTFIXED;
00190 }
00191 if ((vppid.flags & VEXPORT) == 0) {
00192 fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
00193 setvarsafe("PPID", ppid, 0);
00194 }
00195 }
00196
00197
00198
00199
00200
00201 int
00202 setvarsafe(char *name, char *val, int flags)
00203 {
00204 struct jmploc jmploc;
00205 struct jmploc *volatile savehandler = handler;
00206 int err = 0;
00207 #if __GNUC__
00208
00209 (void) &err;
00210 #endif
00211
00212 if (setjmp(jmploc.loc))
00213 err = 1;
00214 else {
00215 handler = &jmploc;
00216 setvar(name, val, flags);
00217 }
00218 handler = savehandler;
00219 return err;
00220 }
00221
00222
00223
00224
00225
00226
00227 void
00228 setvar(char *name, char *val, int flags)
00229 {
00230 char *p, *q;
00231 int len;
00232 int namelen;
00233 char *nameeq;
00234 int isbad;
00235
00236 isbad = 0;
00237 p = name;
00238 if (! is_name(*p))
00239 isbad = 1;
00240 p++;
00241 for (;;) {
00242 if (! is_in_name(*p)) {
00243 if (*p == '\0' || *p == '=')
00244 break;
00245 isbad = 1;
00246 }
00247 p++;
00248 }
00249 namelen = p - name;
00250 if (isbad)
00251 error("%.*s: bad variable name", namelen, name);
00252 len = namelen + 2;
00253 if (val == NULL) {
00254 flags |= VUNSET;
00255 } else {
00256 len += strlen(val);
00257 }
00258 p = nameeq = ckmalloc(len);
00259 q = name;
00260 while (--namelen >= 0)
00261 *p++ = *q++;
00262 *p++ = '=';
00263 *p = '\0';
00264 if (val)
00265 scopy(val, p);
00266 setvareq(nameeq, flags);
00267 }
00268
00269 STATIC int
00270 localevar(char *s)
00271 {
00272 static char *lnames[7] = {
00273 "ALL", "COLLATE", "CTYPE", "MONETARY",
00274 "NUMERIC", "TIME", NULL
00275 };
00276 char **ss;
00277
00278 if (*s != 'L')
00279 return 0;
00280 if (varequal(s + 1, "ANG"))
00281 return 1;
00282 if (strncmp(s + 1, "C_", 2) != 0)
00283 return 0;
00284 for (ss = lnames; *ss ; ss++)
00285 if (varequal(s + 3, *ss))
00286 return 1;
00287 return 0;
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297 void
00298 setvareq(char *s, int flags)
00299 {
00300 struct var *vp, **vpp;
00301 int len;
00302
00303 if (aflag)
00304 flags |= VEXPORT;
00305 vpp = hashvar(s);
00306 for (vp = *vpp ; vp ; vp = vp->next) {
00307 if (varequal(s, vp->text)) {
00308 if (vp->flags & VREADONLY) {
00309 len = strchr(s, '=') - s;
00310 error("%.*s: is read only", len, s);
00311 }
00312 INTOFF;
00313
00314 if (vp->func && (flags & VNOFUNC) == 0)
00315 (*vp->func)(strchr(s, '=') + 1);
00316
00317 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
00318 ckfree(vp->text);
00319
00320 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
00321 vp->flags |= flags;
00322 vp->text = s;
00323
00324
00325
00326
00327
00328 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
00329 chkmail(1);
00330 if ((vp->flags & VEXPORT) && localevar(s)) {
00331 putenv(s);
00332 (void) setlocale(LC_ALL, "");
00333 }
00334 INTON;
00335 return;
00336 }
00337 }
00338
00339 vp = ckmalloc(sizeof (*vp));
00340 vp->flags = flags;
00341 vp->text = s;
00342 vp->next = *vpp;
00343 vp->func = NULL;
00344 INTOFF;
00345 *vpp = vp;
00346 if ((vp->flags & VEXPORT) && localevar(s)) {
00347 putenv(s);
00348 (void) setlocale(LC_ALL, "");
00349 }
00350 INTON;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 void
00360 listsetvar(struct strlist *list)
00361 {
00362 struct strlist *lp;
00363
00364 INTOFF;
00365 for (lp = list ; lp ; lp = lp->next) {
00366 setvareq(savestr(lp->text), 0);
00367 }
00368 INTON;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377 char *
00378 lookupvar(char *name)
00379 {
00380 struct var *v;
00381
00382 for (v = *hashvar(name) ; v ; v = v->next) {
00383 if (varequal(v->text, name)) {
00384 if (v->flags & VUNSET)
00385 return NULL;
00386 return strchr(v->text, '=') + 1;
00387 }
00388 }
00389 return NULL;
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 char *
00401 bltinlookup(char *name, int doall)
00402 {
00403 struct strlist *sp;
00404 struct var *v;
00405
00406 for (sp = cmdenviron ; sp ; sp = sp->next) {
00407 if (varequal(sp->text, name))
00408 return strchr(sp->text, '=') + 1;
00409 }
00410 for (v = *hashvar(name) ; v ; v = v->next) {
00411 if (varequal(v->text, name)) {
00412 if ((v->flags & VUNSET)
00413 || (!doall && (v->flags & VEXPORT) == 0))
00414 return NULL;
00415 return strchr(v->text, '=') + 1;
00416 }
00417 }
00418 return NULL;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428 char **
00429 environment(void)
00430 {
00431 int nenv;
00432 struct var **vpp;
00433 struct var *vp;
00434 char **env, **ep;
00435
00436 nenv = 0;
00437 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00438 for (vp = *vpp ; vp ; vp = vp->next)
00439 if (vp->flags & VEXPORT)
00440 nenv++;
00441 }
00442 ep = env = stalloc((nenv + 1) * sizeof *env);
00443 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00444 for (vp = *vpp ; vp ; vp = vp->next)
00445 if (vp->flags & VEXPORT)
00446 *ep++ = vp->text;
00447 }
00448 *ep = NULL;
00449 return env;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459 #ifdef mkinit
00460 SHELLPROC {
00461 shprocvar();
00462 }
00463 #endif
00464
00465 void
00466 shprocvar(void)
00467 {
00468 struct var **vpp;
00469 struct var *vp, **prev;
00470
00471 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00472 for (prev = vpp ; (vp = *prev) != NULL ; ) {
00473 if ((vp->flags & VEXPORT) == 0) {
00474 *prev = vp->next;
00475 if ((vp->flags & VTEXTFIXED) == 0)
00476 ckfree(vp->text);
00477 if ((vp->flags & VSTRFIXED) == 0)
00478 ckfree(vp);
00479 } else {
00480 if (vp->flags & VSTACK) {
00481 vp->text = savestr(vp->text);
00482 vp->flags &=~ VSTACK;
00483 }
00484 prev = &vp->next;
00485 }
00486 }
00487 }
00488 initvar();
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 int
00500 showvarscmd(int argc __unused, char **argv __unused)
00501 {
00502 struct var **vpp;
00503 struct var *vp;
00504 const char *s;
00505
00506 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00507 for (vp = *vpp ; vp ; vp = vp->next) {
00508 if (vp->flags & VUNSET)
00509 continue;
00510 for (s = vp->text; *s != '='; s++)
00511 out1c(*s);
00512 out1c('=');
00513 out1qstr(s + 1);
00514 out1c('\n');
00515 }
00516 }
00517 return 0;
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 int
00527 exportcmd(int argc, char **argv)
00528 {
00529 struct var **vpp;
00530 struct var *vp;
00531 char *name;
00532 char *p;
00533 char *cmdname;
00534 int ch, values;
00535 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
00536
00537 cmdname = argv[0];
00538 optreset = optind = 1;
00539 opterr = 0;
00540 values = 0;
00541 while ((ch = getopt(argc, argv, "p")) != -1) {
00542 switch (ch) {
00543 case 'p':
00544 values = 1;
00545 break;
00546 case '?':
00547 default:
00548 error("unknown option: -%c", optopt);
00549 }
00550 }
00551 argc -= optind;
00552 argv += optind;
00553
00554 listsetvar(cmdenviron);
00555 if (argc != 0) {
00556 while ((name = *argptr++) != NULL) {
00557 if ((p = strchr(name, '=')) != NULL) {
00558 p++;
00559 } else {
00560 vpp = hashvar(name);
00561 for (vp = *vpp ; vp ; vp = vp->next) {
00562 if (varequal(vp->text, name)) {
00563
00564 vp->flags |= flag;
00565 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
00566 putenv(vp->text);
00567 (void) setlocale(LC_ALL, "");
00568 }
00569 goto found;
00570 }
00571 }
00572 }
00573 setvar(name, p, flag);
00574 found:;
00575 }
00576 } else {
00577 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00578 for (vp = *vpp ; vp ; vp = vp->next) {
00579 if (vp->flags & flag) {
00580 if (values) {
00581 out1str(cmdname);
00582 out1c(' ');
00583 }
00584 for (p = vp->text ; *p != '=' ; p++)
00585 out1c(*p);
00586 if (values && !(vp->flags & VUNSET)) {
00587 out1c('=');
00588 out1qstr(p + 1);
00589 }
00590 out1c('\n');
00591 }
00592 }
00593 }
00594 }
00595 return 0;
00596 }
00597
00598
00599
00600
00601
00602
00603 int
00604 localcmd(int argc __unused, char **argv __unused)
00605 {
00606 char *name;
00607
00608 if (! in_function())
00609 error("Not in a function");
00610 while ((name = *argptr++) != NULL) {
00611 mklocal(name);
00612 }
00613 return 0;
00614 }
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 void
00625 mklocal(char *name)
00626 {
00627 struct localvar *lvp;
00628 struct var **vpp;
00629 struct var *vp;
00630
00631 INTOFF;
00632 lvp = ckmalloc(sizeof (struct localvar));
00633 if (name[0] == '-' && name[1] == '\0') {
00634 lvp->text = ckmalloc(sizeof optlist);
00635 memcpy(lvp->text, optlist, sizeof optlist);
00636 vp = NULL;
00637 } else {
00638 vpp = hashvar(name);
00639 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
00640 if (vp == NULL) {
00641 if (strchr(name, '='))
00642 setvareq(savestr(name), VSTRFIXED);
00643 else
00644 setvar(name, NULL, VSTRFIXED);
00645 vp = *vpp;
00646 lvp->text = NULL;
00647 lvp->flags = VUNSET;
00648 } else {
00649 lvp->text = vp->text;
00650 lvp->flags = vp->flags;
00651 vp->flags |= VSTRFIXED|VTEXTFIXED;
00652 if (strchr(name, '='))
00653 setvareq(savestr(name), 0);
00654 }
00655 }
00656 lvp->vp = vp;
00657 lvp->next = localvars;
00658 localvars = lvp;
00659 INTON;
00660 }
00661
00662
00663
00664
00665
00666
00667 void
00668 poplocalvars(void)
00669 {
00670 struct localvar *lvp;
00671 struct var *vp;
00672
00673 while ((lvp = localvars) != NULL) {
00674 localvars = lvp->next;
00675 vp = lvp->vp;
00676 if (vp == NULL) {
00677 memcpy(optlist, lvp->text, sizeof optlist);
00678 ckfree(lvp->text);
00679 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
00680 (void)unsetvar(vp->text);
00681 } else {
00682 if ((vp->flags & VTEXTFIXED) == 0)
00683 ckfree(vp->text);
00684 vp->flags = lvp->flags;
00685 vp->text = lvp->text;
00686 }
00687 ckfree(lvp);
00688 }
00689 }
00690
00691
00692 int
00693 setvarcmd(int argc, char **argv)
00694 {
00695 if (argc <= 2)
00696 return unsetcmd(argc, argv);
00697 else if (argc == 3)
00698 setvar(argv[1], argv[2], 0);
00699 else
00700 error("List assignment not implemented");
00701 return 0;
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711 int
00712 unsetcmd(int argc __unused, char **argv __unused)
00713 {
00714 char **ap;
00715 int i;
00716 int flg_func = 0;
00717 int flg_var = 0;
00718 int ret = 0;
00719
00720 while ((i = nextopt("vf")) != '\0') {
00721 if (i == 'f')
00722 flg_func = 1;
00723 else
00724 flg_var = 1;
00725 }
00726 if (flg_func == 0 && flg_var == 0)
00727 flg_var = 1;
00728
00729 for (ap = argptr; *ap ; ap++) {
00730 if (flg_func)
00731 ret |= unsetfunc(*ap);
00732 if (flg_var)
00733 ret |= unsetvar(*ap);
00734 }
00735 return ret;
00736 }
00737
00738
00739
00740
00741
00742
00743 int
00744 unsetvar(char *s)
00745 {
00746 struct var **vpp;
00747 struct var *vp;
00748
00749 vpp = hashvar(s);
00750 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
00751 if (varequal(vp->text, s)) {
00752 if (vp->flags & VREADONLY)
00753 return (1);
00754 INTOFF;
00755 if (*(strchr(vp->text, '=') + 1) != '\0')
00756 setvar(s, nullstr, 0);
00757 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
00758 unsetenv(s);
00759 setlocale(LC_ALL, "");
00760 }
00761 vp->flags &= ~VEXPORT;
00762 vp->flags |= VUNSET;
00763 if ((vp->flags & VSTRFIXED) == 0) {
00764 if ((vp->flags & VTEXTFIXED) == 0)
00765 ckfree(vp->text);
00766 *vpp = vp->next;
00767 ckfree(vp);
00768 }
00769 INTON;
00770 return (0);
00771 }
00772 }
00773
00774 return (0);
00775 }
00776
00777
00778
00779
00780
00781
00782
00783 STATIC struct var **
00784 hashvar(char *p)
00785 {
00786 unsigned int hashval;
00787
00788 hashval = ((unsigned char) *p) << 4;
00789 while (*p && *p != '=')
00790 hashval += (unsigned char) *p++;
00791 return &vartab[hashval % VTABSIZE];
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 STATIC int
00803 varequal(char *p, char *q)
00804 {
00805 while (*p == *q++) {
00806 if (*p++ == '=')
00807 return 1;
00808 }
00809 if (*p == '=' && *(q - 1) == '\0')
00810 return 1;
00811 return 0;
00812 }
00813
00814
00815
00816