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