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