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