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