1 /* $NetBSD: var.c,v 1.78 2019/02/14 11:15:24 kre 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. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; 39 #else 40 __RCSID("$NetBSD: var.c,v 1.78 2019/02/14 11:15:24 kre Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <stdio.h> 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <paths.h> 49 #include <limits.h> 50 #include <time.h> 51 #include <pwd.h> 52 #include <fcntl.h> 53 #include <inttypes.h> 54 55 /* 56 * Shell variables. 57 */ 58 59 #include "shell.h" 60 #include "output.h" 61 #include "expand.h" 62 #include "nodes.h" /* for other headers */ 63 #include "eval.h" /* defines cmdenviron */ 64 #include "exec.h" 65 #include "syntax.h" 66 #include "options.h" 67 #include "builtins.h" 68 #include "mail.h" 69 #include "var.h" 70 #include "memalloc.h" 71 #include "error.h" 72 #include "mystring.h" 73 #include "parser.h" 74 #include "show.h" 75 #include "machdep.h" 76 #ifndef SMALL 77 #include "myhistedit.h" 78 #endif 79 80 #ifdef SMALL 81 #define VTABSIZE 39 82 #else 83 #define VTABSIZE 517 84 #endif 85 86 87 struct varinit { 88 struct var *var; 89 int flags; 90 const char *text; 91 union var_func_union v_u; 92 }; 93 #define func v_u.set_func 94 #define rfunc v_u.ref_func 95 96 char *get_lineno(struct var *); 97 98 #ifndef SMALL 99 char *get_tod(struct var *); 100 char *get_hostname(struct var *); 101 char *get_seconds(struct var *); 102 char *get_euser(struct var *); 103 char *get_random(struct var *); 104 #endif 105 106 struct localvar *localvars; 107 108 #ifndef SMALL 109 struct var vhistsize; 110 struct var vterm; 111 struct var editrc; 112 struct var ps_lit; 113 #endif 114 struct var vifs; 115 struct var vmail; 116 struct var vmpath; 117 struct var vpath; 118 struct var vps1; 119 struct var vps2; 120 struct var vps4; 121 struct var vvers; 122 struct var voptind; 123 struct var line_num; 124 #ifndef SMALL 125 struct var tod; 126 struct var host_name; 127 struct var seconds; 128 struct var euname; 129 struct var random_num; 130 131 intmax_t sh_start_time; 132 #endif 133 134 struct var line_num; 135 int line_number; 136 int funclinebase = 0; 137 int funclineabs = 0; 138 139 char ifs_default[] = " \t\n"; 140 141 const struct varinit varinit[] = { 142 #ifndef SMALL 143 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", 144 { .set_func= sethistsize } }, 145 #endif 146 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", 147 { NULL } }, 148 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", 149 { NULL } }, 150 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", 151 { NULL } }, 152 { &vvers, VSTRFIXED|VTEXTFIXED|VNOEXPORT, "NETBSD_SHELL=", 153 { NULL } }, 154 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, 155 { .set_func= changepath } }, 156 /* 157 * vps1 depends on uid 158 */ 159 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", 160 { NULL } }, 161 { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 162 { NULL } }, 163 #ifndef SMALL 164 { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", 165 { .set_func= setterm } }, 166 { &editrc, VSTRFIXED|VTEXTFIXED|VUNSET, "EDITRC=", 167 { .set_func= set_editrc } }, 168 { &ps_lit, VSTRFIXED|VTEXTFIXED|VUNSET, "PSlit=", 169 { .set_func= set_prompt_lit } }, 170 #endif 171 { &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1", 172 { .set_func= getoptsreset } }, 173 { &line_num, VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL, "LINENO=1", 174 { .ref_func= get_lineno } }, 175 #ifndef SMALL 176 { &tod, VSTRFIXED|VTEXTFIXED|VFUNCREF, "ToD=", 177 { .ref_func= get_tod } }, 178 { &host_name, VSTRFIXED|VTEXTFIXED|VFUNCREF, "HOSTNAME=", 179 { .ref_func= get_hostname } }, 180 { &seconds, VSTRFIXED|VTEXTFIXED|VFUNCREF, "SECONDS=", 181 { .ref_func= get_seconds } }, 182 { &euname, VSTRFIXED|VTEXTFIXED|VFUNCREF, "EUSER=", 183 { .ref_func= get_euser } }, 184 { &random_num, VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL, "RANDOM=", 185 { .ref_func= get_random } }, 186 #endif 187 { NULL, 0, NULL, 188 { NULL } } 189 }; 190 191 struct var *vartab[VTABSIZE]; 192 193 STATIC int strequal(const char *, const char *); 194 STATIC struct var *find_var(const char *, struct var ***, int *); 195 STATIC void showvar(struct var *, const char *, const char *, int); 196 static void export_usage(const char *) __dead; 197 STATIC int makespecial(const char *); 198 199 /* 200 * Initialize the varable symbol tables and import the environment 201 */ 202 203 #ifdef mkinit 204 INCLUDE <stdio.h> 205 INCLUDE <unistd.h> 206 INCLUDE <time.h> 207 INCLUDE "var.h" 208 INCLUDE "version.h" 209 MKINIT char **environ; 210 INIT { 211 char **envp; 212 char buf[64]; 213 214 #ifndef SMALL 215 sh_start_time = (intmax_t)time((time_t *)0); 216 #endif 217 /* 218 * Set up our default variables and their values. 219 */ 220 initvar(); 221 222 /* 223 * Import variables from the environment, which will 224 * override anything initialised just previously. 225 */ 226 for (envp = environ ; *envp ; envp++) { 227 if (strchr(*envp, '=')) { 228 setvareq(*envp, VEXPORT|VTEXTFIXED); 229 } 230 } 231 232 /* 233 * Set variables which override anything read from environment. 234 * 235 * PPID is readonly 236 * Always default IFS 237 * POSIX: "Whenever the shell is invoked, OPTIND shall 238 * be initialized to 1." 239 * PSc indicates the root/non-root status of this shell. 240 * START_TIME belongs only to this shell. 241 * NETBSD_SHELL is a constant (readonly), and is never exported 242 * LINENO is simply magic... 243 */ 244 snprintf(buf, sizeof(buf), "%d", (int)getppid()); 245 setvar("PPID", buf, VREADONLY); 246 setvar("IFS", ifs_default, VTEXTFIXED); 247 setvar("OPTIND", "1", VTEXTFIXED); 248 setvar("PSc", (geteuid() == 0 ? "#" : "$"), VTEXTFIXED); 249 250 #ifndef SMALL 251 snprintf(buf, sizeof(buf), "%jd", sh_start_time); 252 setvar("START_TIME", buf, VTEXTFIXED); 253 #endif 254 255 setvar("NETBSD_SHELL", NETBSD_SHELL 256 #ifdef BUILD_DATE 257 " BUILD:" BUILD_DATE 258 #endif 259 #ifdef DEBUG 260 " DEBUG" 261 #endif 262 #if !defined(JOBS) || JOBS == 0 263 " -JOBS" 264 #endif 265 #ifndef DO_SHAREDVFORK 266 " -VFORK" 267 #endif 268 #ifdef SMALL 269 " SMALL" 270 #endif 271 #ifdef TINY 272 " TINY" 273 #endif 274 #ifdef OLD_TTY_DRIVER 275 " OLD_TTY" 276 #endif 277 #ifdef SYSV 278 " SYSV" 279 #endif 280 #ifndef BSD 281 " -BSD" 282 #endif 283 #ifdef BOGUS_NOT_COMMAND 284 " BOGUS_NOT" 285 #endif 286 , VTEXTFIXED|VREADONLY|VNOEXPORT); 287 288 setvar("LINENO", "1", VTEXTFIXED); 289 } 290 #endif 291 292 293 /* 294 * This routine initializes the builtin variables. It is called when the 295 * shell is initialized and again when a shell procedure is spawned. 296 */ 297 298 void 299 initvar(void) 300 { 301 const struct varinit *ip; 302 struct var *vp; 303 struct var **vpp; 304 305 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 306 if (find_var(ip->text, &vpp, &vp->name_len) != NULL) 307 continue; 308 vp->next = *vpp; 309 *vpp = vp; 310 vp->text = strdup(ip->text); 311 vp->flags = (ip->flags & ~VTEXTFIXED) | VSTRFIXED; 312 vp->v_u = ip->v_u; 313 } 314 /* 315 * PS1 depends on uid 316 */ 317 if (find_var("PS1", &vpp, &vps1.name_len) == NULL) { 318 vps1.next = *vpp; 319 *vpp = &vps1; 320 vps1.flags = VSTRFIXED; 321 vps1.text = NULL; 322 choose_ps1(); 323 } 324 } 325 326 void 327 choose_ps1(void) 328 { 329 uid_t u = geteuid(); 330 331 if ((vps1.flags & (VTEXTFIXED|VSTACK)) == 0) 332 free(vps1.text); 333 vps1.text = strdup(u != 0 ? "PS1=$ " : "PS1=# "); 334 vps1.flags &= ~(VTEXTFIXED|VSTACK); 335 336 /* 337 * Update PSc whenever we feel the need to update PS1 338 */ 339 setvarsafe("PSc", (u == 0 ? "#" : "$"), 0); 340 } 341 342 /* 343 * Validate a string as a valid variable name 344 * nb: not parameter - special params and such are "invalid" here. 345 * Name terminated by either \0 or the term param (usually '=' or '\0'). 346 * 347 * If not NULL, the length of the (intended) name is returned via len 348 */ 349 350 int 351 validname(const char *name, int term, int *len) 352 { 353 const char *p = name; 354 int ok = 1; 355 356 if (p == NULL || *p == '\0' || *p == term) { 357 if (len != NULL) 358 *len = 0; 359 return 0; 360 } 361 362 if (!is_name(*p)) 363 ok = 0; 364 p++; 365 for (;;) { 366 if (*p == '\0' || *p == term) 367 break; 368 if (!is_in_name(*p)) 369 ok = 0; 370 p++; 371 } 372 if (len != NULL) 373 *len = p - name; 374 375 return ok; 376 } 377 378 /* 379 * Safe version of setvar, returns 1 on success 0 on failure. 380 */ 381 382 int 383 setvarsafe(const char *name, const char *val, int flags) 384 { 385 struct jmploc jmploc; 386 struct jmploc * const savehandler = handler; 387 int volatile err = 0; 388 389 if (setjmp(jmploc.loc)) 390 err = 1; 391 else { 392 handler = &jmploc; 393 setvar(name, val, flags); 394 } 395 handler = savehandler; 396 return err; 397 } 398 399 /* 400 * Set the value of a variable. The flags argument is ored with the 401 * flags of the variable. If val is NULL, the variable is unset. 402 * 403 * This always copies name and val when setting a variable, so 404 * the source strings can be from anywhere, and are no longer needed 405 * after this function returns. The VTEXTFIXED and VSTACK flags should 406 * not be used (but just in case they were, clear them.) 407 */ 408 409 void 410 setvar(const char *name, const char *val, int flags) 411 { 412 const char *p; 413 const char *q; 414 char *d; 415 int len; 416 int namelen; 417 char *nameeq; 418 419 p = name; 420 421 if (!validname(p, '=', &namelen)) 422 error("%.*s: bad variable name", namelen, name); 423 len = namelen + 2; /* 2 is space for '=' and '\0' */ 424 if (val == NULL) { 425 flags |= VUNSET; 426 } else { 427 len += strlen(val); 428 } 429 d = nameeq = ckmalloc(len); 430 q = name; 431 while (--namelen >= 0) 432 *d++ = *q++; 433 *d++ = '='; 434 *d = '\0'; 435 if (val) 436 scopy(val, d); 437 setvareq(nameeq, flags & ~(VTEXTFIXED | VSTACK)); 438 } 439 440 441 442 /* 443 * Same as setvar except that the variable and value are passed in 444 * the first argument as name=value. Since the first argument will 445 * be actually stored in the table, it should not be a string that 446 * will go away. The flags (VTEXTFIXED or VSTACK) can be used to 447 * indicate the source of the string (if neither is set, the string will 448 * eventually be free()d when a replacement value is assigned.) 449 */ 450 451 void 452 setvareq(char *s, int flags) 453 { 454 struct var *vp, **vpp; 455 int nlen; 456 457 VTRACE(DBG_VARS, ("setvareq([%s],%#x) aflag=%d ", s, flags, aflag)); 458 if (aflag && !(flags & VNOEXPORT)) 459 flags |= VEXPORT; 460 vp = find_var(s, &vpp, &nlen); 461 if (vp != NULL) { 462 VTRACE(DBG_VARS, ("was [%s] fl:%#x\n", vp->text, 463 vp->flags)); 464 if (vp->flags & VREADONLY) { 465 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 466 ckfree(s); 467 if (flags & VNOERROR) 468 return; 469 error("%.*s: is read only", vp->name_len, vp->text); 470 } 471 if (flags & VNOSET) { 472 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 473 ckfree(s); 474 return; 475 } 476 477 INTOFF; 478 479 if (vp->func && !(vp->flags & VFUNCREF) && !(flags & VNOFUNC)) 480 (*vp->func)(s + vp->name_len + 1); 481 482 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 483 ckfree(vp->text); 484 485 /* 486 * if we set a magic var, the magic dissipates, 487 * unless it is very special indeed. 488 */ 489 if (vp->rfunc && (vp->flags & (VFUNCREF|VSPECIAL)) == VFUNCREF) 490 vp->rfunc = NULL; 491 492 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); 493 if (flags & VNOEXPORT) 494 vp->flags &= ~VEXPORT; 495 if (flags & VDOEXPORT) 496 vp->flags &= ~VNOEXPORT; 497 if (vp->flags & VNOEXPORT) 498 flags &= ~VEXPORT; 499 vp->flags |= flags & ~(VNOFUNC | VDOEXPORT); 500 vp->text = s; 501 502 /* 503 * We could roll this to a function, to handle it as 504 * a regular variable function callback, but why bother? 505 */ 506 if (vp == &vmpath || (vp == &vmail && ! mpathset())) 507 chkmail(1); 508 509 INTON; 510 return; 511 } 512 /* not found */ 513 if (flags & VNOSET) { 514 VTRACE(DBG_VARS, ("new noset\n")); 515 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 516 ckfree(s); 517 return; 518 } 519 vp = ckmalloc(sizeof (*vp)); 520 vp->flags = flags & ~(VNOFUNC|VFUNCREF|VDOEXPORT); 521 vp->text = s; 522 vp->name_len = nlen; 523 vp->func = NULL; 524 vp->next = *vpp; 525 *vpp = vp; 526 527 VTRACE(DBG_VARS, ("new [%s] (%d) %#x\n", s, nlen, vp->flags)); 528 } 529 530 531 532 /* 533 * Process a linked list of variable assignments. 534 */ 535 536 void 537 listsetvar(struct strlist *list, int flags) 538 { 539 struct strlist *lp; 540 541 INTOFF; 542 for (lp = list ; lp ; lp = lp->next) { 543 setvareq(savestr(lp->text), flags); 544 } 545 INTON; 546 } 547 548 void 549 listmklocal(struct strlist *list, int flags) 550 { 551 struct strlist *lp; 552 553 for (lp = list ; lp ; lp = lp->next) 554 mklocal(lp->text, flags); 555 } 556 557 558 /* 559 * Find the value of a variable. Returns NULL if not set. 560 */ 561 562 char * 563 lookupvar(const char *name) 564 { 565 struct var *v; 566 char *p; 567 568 v = find_var(name, NULL, NULL); 569 if (v == NULL || v->flags & VUNSET) 570 return NULL; 571 if (v->rfunc && (v->flags & VFUNCREF) != 0) { 572 p = (*v->rfunc)(v); 573 if (p == NULL) 574 return NULL; 575 } else 576 p = v->text; 577 578 return p + v->name_len + 1; 579 } 580 581 582 583 /* 584 * Search the environment of a builtin command. If the second argument 585 * is nonzero, return the value of a variable even if it hasn't been 586 * exported. 587 */ 588 589 char * 590 bltinlookup(const char *name, int doall) 591 { 592 struct strlist *sp; 593 struct var *v; 594 char *p; 595 596 for (sp = cmdenviron ; sp ; sp = sp->next) { 597 if (strequal(sp->text, name)) 598 return strchr(sp->text, '=') + 1; 599 } 600 601 v = find_var(name, NULL, NULL); 602 603 if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT))) 604 return NULL; 605 606 if (v->rfunc && (v->flags & VFUNCREF) != 0) { 607 p = (*v->rfunc)(v); 608 if (p == NULL) 609 return NULL; 610 } else 611 p = v->text; 612 613 return p + v->name_len + 1; 614 } 615 616 617 618 /* 619 * Generate a list of exported variables. This routine is used to construct 620 * the third argument to execve when executing a program. 621 */ 622 623 char ** 624 environment(void) 625 { 626 int nenv; 627 struct var **vpp; 628 struct var *vp; 629 char **env; 630 char **ep; 631 632 nenv = 0; 633 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 634 for (vp = *vpp ; vp ; vp = vp->next) 635 if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) 636 nenv++; 637 } 638 CTRACE(DBG_VARS, ("environment: %d vars to export\n", nenv)); 639 ep = env = stalloc((nenv + 1) * sizeof *env); 640 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 641 for (vp = *vpp ; vp ; vp = vp->next) 642 if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) { 643 if (vp->rfunc && (vp->flags & VFUNCREF)) { 644 *ep = (*vp->rfunc)(vp); 645 if (*ep != NULL) 646 ep++; 647 } else 648 *ep++ = vp->text; 649 VTRACE(DBG_VARS, ("environment: %s\n", ep[-1])); 650 } 651 } 652 *ep = NULL; 653 return env; 654 } 655 656 657 /* 658 * Called when a shell procedure is invoked to clear out nonexported 659 * variables. It is also necessary to reallocate variables of with 660 * VSTACK set since these are currently allocated on the stack. 661 */ 662 663 #ifdef mkinit 664 void shprocvar(void); 665 666 SHELLPROC { 667 shprocvar(); 668 } 669 #endif 670 671 void 672 shprocvar(void) 673 { 674 struct var **vpp; 675 struct var *vp, **prev; 676 677 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 678 for (prev = vpp ; (vp = *prev) != NULL ; ) { 679 if ((vp->flags & VEXPORT) == 0) { 680 *prev = vp->next; 681 if ((vp->flags & VTEXTFIXED) == 0) 682 ckfree(vp->text); 683 if ((vp->flags & VSTRFIXED) == 0) 684 ckfree(vp); 685 } else { 686 if (vp->flags & VSTACK) { 687 vp->text = savestr(vp->text); 688 vp->flags &=~ VSTACK; 689 } 690 prev = &vp->next; 691 } 692 } 693 } 694 initvar(); 695 } 696 697 698 699 /* 700 * Command to list all variables which are set. Currently this command 701 * is invoked from the set command when the set command is called without 702 * any variables. 703 */ 704 705 void 706 print_quoted(const char *p) 707 { 708 const char *q; 709 710 if (p[0] == '\0') { 711 out1fmt("''"); 712 return; 713 } 714 if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) { 715 out1fmt("%s", p); 716 return; 717 } 718 while (*p) { 719 if (*p == '\'') { 720 out1fmt("\\'"); 721 p++; 722 continue; 723 } 724 q = strchr(p, '\''); 725 if (!q) { 726 out1fmt("'%s'", p ); 727 return; 728 } 729 out1fmt("'%.*s'", (int)(q - p), p ); 730 p = q; 731 } 732 } 733 734 static int 735 sort_var(const void *v_v1, const void *v_v2) 736 { 737 const struct var * const *v1 = v_v1; 738 const struct var * const *v2 = v_v2; 739 char *t1 = (*v1)->text, *t2 = (*v2)->text; 740 741 if (*t1 == *t2) { 742 char *p, *s; 743 744 STARTSTACKSTR(p); 745 746 /* 747 * note: if lengths are equal, strings must be different 748 * so we don't care which string we pick for the \0 in 749 * that case. 750 */ 751 if ((strchr(t1, '=') - t1) <= (strchr(t2, '=') - t2)) { 752 s = t1; 753 t1 = p; 754 } else { 755 s = t2; 756 t2 = p; 757 } 758 759 while (*s && *s != '=') { 760 STPUTC(*s, p); 761 s++; 762 } 763 STPUTC('\0', p); 764 } 765 766 return strcoll(t1, t2); 767 } 768 769 /* 770 * POSIX requires that 'set' (but not export or readonly) output the 771 * variables in lexicographic order - by the locale's collating order (sigh). 772 * Maybe we could keep them in an ordered balanced binary tree 773 * instead of hashed lists. 774 * For now just roll 'em through qsort for printing... 775 */ 776 777 STATIC void 778 showvar(struct var *vp, const char *cmd, const char *xtra, int show_value) 779 { 780 const char *p; 781 782 p = vp->text; 783 if (vp->rfunc && (vp->flags & VFUNCREF) != 0) { 784 p = (*vp->rfunc)(vp); 785 if (p == NULL) { 786 if (!(show_value & 2)) 787 return; 788 p = vp->text; 789 show_value = 0; 790 } 791 } 792 if (cmd) 793 out1fmt("%s ", cmd); 794 if (xtra) 795 out1fmt("%s ", xtra); 796 for ( ; *p != '=' ; p++) 797 out1c(*p); 798 if (!(vp->flags & VUNSET) && show_value) { 799 out1fmt("="); 800 print_quoted(++p); 801 } 802 out1c('\n'); 803 } 804 805 int 806 showvars(const char *cmd, int flag, int show_value, const char *xtra) 807 { 808 struct var **vpp; 809 struct var *vp; 810 811 static struct var **list; /* static in case we are interrupted */ 812 static int list_len; 813 int count = 0; 814 815 if (!list) { 816 list_len = 32; 817 list = ckmalloc(list_len * sizeof *list); 818 } 819 820 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 821 for (vp = *vpp ; vp ; vp = vp->next) { 822 if (flag && !(vp->flags & flag)) 823 continue; 824 if (vp->flags & VUNSET && !(show_value & 2)) 825 continue; 826 if (count >= list_len) { 827 list = ckrealloc(list, 828 (list_len << 1) * sizeof *list); 829 list_len <<= 1; 830 } 831 list[count++] = vp; 832 } 833 } 834 835 qsort(list, count, sizeof *list, sort_var); 836 837 for (vpp = list; count--; vpp++) 838 showvar(*vpp, cmd, xtra, show_value); 839 840 /* no free(list), will be used again next time ... */ 841 842 return 0; 843 } 844 845 846 847 /* 848 * The export and readonly commands. 849 */ 850 851 static void __dead 852 export_usage(const char *cmd) 853 { 854 #ifdef SMALL 855 if (*cmd == 'r') 856 error("Usage: %s [ -p | var[=val]... ]", cmd); 857 else 858 error("Usage: %s [ -p | [-n] var[=val]... ]", cmd); 859 #else 860 if (*cmd == 'r') 861 error("Usage: %s [-p [var...] | -q var... | var[=val]... ]", cmd); 862 else 863 error( 864 "Usage: %s [ -px [var...] | -q[x] var... | [-n|x] var[=val]... ]", 865 cmd); 866 #endif 867 } 868 869 int 870 exportcmd(int argc, char **argv) 871 { 872 struct var *vp; 873 char *name; 874 const char *p = argv[0]; 875 int flag = p[0] == 'r'? VREADONLY : VEXPORT; 876 int pflg = 0; 877 int nflg = 0; 878 #ifndef SMALL 879 int xflg = 0; 880 int qflg = 0; 881 #endif 882 int res; 883 int c; 884 int f; 885 886 #ifdef SMALL 887 #define EXPORT_OPTS "np" 888 #else 889 #define EXPORT_OPTS "npqx" 890 #endif 891 892 while ((c = nextopt(EXPORT_OPTS)) != '\0') { 893 894 #undef EXPORT_OPTS 895 896 switch (c) { 897 case 'n': 898 if (pflg || flag == VREADONLY 899 #ifndef SMALL 900 || qflg || xflg 901 #endif 902 ) 903 export_usage(p); 904 nflg = 1; 905 break; 906 case 'p': 907 if (nflg 908 #ifndef SMALL 909 || qflg 910 #endif 911 ) 912 export_usage(p); 913 pflg = 3; 914 break; 915 #ifndef SMALL 916 case 'q': 917 if (nflg || pflg) 918 export_usage(p); 919 qflg = 1; 920 break; 921 case 'x': 922 if (nflg || flag == VREADONLY) 923 export_usage(p); 924 flag = VNOEXPORT; 925 xflg = 1; 926 break; 927 #endif 928 } 929 } 930 931 if ((nflg 932 #ifndef SMALL 933 || qflg 934 #endif 935 ) && *argptr == NULL) 936 export_usage(p); 937 938 #ifndef SMALL 939 if (pflg && *argptr != NULL) { 940 while ((name = *argptr++) != NULL) { 941 int len; 942 943 vp = find_var(name, NULL, &len); 944 if (name[len] == '=') 945 export_usage(p); 946 if (!goodname(name)) 947 error("%s: bad variable name", name); 948 949 if (vp && vp->flags & flag) 950 showvar(vp, p, xflg ? "-x" : NULL, 1); 951 } 952 return 0; 953 } 954 #endif 955 956 if (pflg || *argptr == NULL) 957 return showvars( pflg ? p : 0, flag, pflg, 958 #ifndef SMALL 959 pflg && xflg ? "-x" : 960 #endif 961 NULL ); 962 963 res = 0; 964 #ifndef SMALL 965 if (qflg) { 966 while ((name = *argptr++) != NULL) { 967 int len; 968 969 vp = find_var(name, NULL, &len); 970 if (name[len] == '=') 971 export_usage(p); 972 if (!goodname(name)) 973 error("%s: bad variable name", name); 974 975 if (vp == NULL || !(vp->flags & flag)) 976 res = 1; 977 } 978 return res; 979 } 980 #endif 981 982 while ((name = *argptr++) != NULL) { 983 int len; 984 985 f = flag; 986 987 vp = find_var(name, NULL, &len); 988 p = name + len; 989 if (*p++ != '=') 990 p = NULL; 991 992 if (vp != NULL) { 993 if (nflg) 994 vp->flags &= ~flag; 995 else if (flag&VEXPORT && vp->flags&VNOEXPORT) { 996 /* note we go ahead and do any assignment */ 997 sh_warnx("%.*s: not available for export", 998 len, name); 999 res = 1; 1000 } else { 1001 if (flag == VNOEXPORT) 1002 vp->flags &= ~VEXPORT; 1003 1004 /* if not NULL will be done in setvar below */ 1005 if (p == NULL) 1006 vp->flags |= flag; 1007 } 1008 if (p == NULL) 1009 continue; 1010 } else if (nflg && p == NULL && !goodname(name)) 1011 error("%s: bad variable name", name); 1012 1013 if (!nflg || p != NULL) 1014 setvar(name, p, f); 1015 } 1016 return res; 1017 } 1018 1019 1020 /* 1021 * The "local" command. 1022 */ 1023 1024 int 1025 localcmd(int argc, char **argv) 1026 { 1027 char *name; 1028 int c; 1029 int flags = 0; /*XXX perhaps VUNSET from a -o option value */ 1030 1031 if (! in_function()) 1032 error("Not in a function"); 1033 1034 /* upper case options, as bash stole all the good ones ... */ 1035 while ((c = nextopt("INx")) != '\0') 1036 switch (c) { 1037 case 'I': flags &= ~VUNSET; break; 1038 case 'N': flags |= VUNSET; break; 1039 case 'x': flags |= VEXPORT; break; 1040 } 1041 1042 while ((name = *argptr++) != NULL) { 1043 mklocal(name, flags); 1044 } 1045 return 0; 1046 } 1047 1048 1049 /* 1050 * Make a variable a local variable. When a variable is made local, its 1051 * value and flags are saved in a localvar structure. The saved values 1052 * will be restored when the shell function returns. We handle the name 1053 * "-" as a special case. 1054 */ 1055 1056 void 1057 mklocal(const char *name, int flags) 1058 { 1059 struct localvar *lvp; 1060 struct var **vpp; 1061 struct var *vp; 1062 1063 INTOFF; 1064 lvp = ckmalloc(sizeof (struct localvar)); 1065 if (name[0] == '-' && name[1] == '\0') { 1066 char *p; 1067 p = ckmalloc(sizeof_optlist); 1068 lvp->text = memcpy(p, optlist, sizeof_optlist); 1069 lvp->rfunc = NULL; 1070 vp = NULL; 1071 xtrace_clone(0); 1072 } else { 1073 vp = find_var(name, &vpp, NULL); 1074 if (vp == NULL) { 1075 flags &= ~VNOEXPORT; 1076 if (strchr(name, '=')) 1077 setvareq(savestr(name), 1078 VSTRFIXED | (flags & ~VUNSET)); 1079 else 1080 setvar(name, NULL, VSTRFIXED|flags); 1081 vp = *vpp; /* the new variable */ 1082 lvp->text = NULL; 1083 lvp->flags = VUNSET; 1084 lvp->rfunc = NULL; 1085 } else { 1086 lvp->text = vp->text; 1087 lvp->flags = vp->flags; 1088 lvp->v_u = vp->v_u; 1089 vp->flags |= VSTRFIXED|VTEXTFIXED; 1090 if (flags & (VDOEXPORT | VUNSET)) 1091 vp->flags &= ~VNOEXPORT; 1092 if (vp->flags & VNOEXPORT && 1093 (flags & (VEXPORT|VDOEXPORT|VUNSET)) == VEXPORT) 1094 flags &= ~VEXPORT; 1095 if (flags & (VNOEXPORT | VUNSET)) 1096 vp->flags &= ~VEXPORT; 1097 flags &= ~VNOEXPORT; 1098 if (name[vp->name_len] == '=') 1099 setvareq(savestr(name), flags & ~VUNSET); 1100 else if (flags & VUNSET) 1101 unsetvar(name, 0); 1102 else 1103 vp->flags |= flags & (VUNSET|VEXPORT); 1104 1105 if (vp == &line_num) { 1106 if (name[vp->name_len] == '=') 1107 funclinebase = funclineabs -1; 1108 else 1109 funclinebase = 0; 1110 } 1111 } 1112 } 1113 lvp->vp = vp; 1114 lvp->next = localvars; 1115 localvars = lvp; 1116 INTON; 1117 } 1118 1119 1120 /* 1121 * Called after a function returns. 1122 */ 1123 1124 void 1125 poplocalvars(void) 1126 { 1127 struct localvar *lvp; 1128 struct var *vp; 1129 1130 while ((lvp = localvars) != NULL) { 1131 localvars = lvp->next; 1132 vp = lvp->vp; 1133 VTRACE(DBG_VARS, ("poplocalvar %s\n", vp ? vp->text : "-")); 1134 if (vp == NULL) { /* $- saved */ 1135 memcpy(optlist, lvp->text, sizeof_optlist); 1136 ckfree(lvp->text); 1137 xtrace_pop(); 1138 optschanged(); 1139 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 1140 (void)unsetvar(vp->text, 0); 1141 } else { 1142 if (lvp->func && (lvp->flags & (VNOFUNC|VFUNCREF)) == 0) 1143 (*lvp->func)(lvp->text + vp->name_len + 1); 1144 if ((vp->flags & VTEXTFIXED) == 0) 1145 ckfree(vp->text); 1146 vp->flags = lvp->flags; 1147 vp->text = lvp->text; 1148 vp->v_u = lvp->v_u; 1149 } 1150 ckfree(lvp); 1151 } 1152 } 1153 1154 1155 int 1156 setvarcmd(int argc, char **argv) 1157 { 1158 if (argc <= 2) 1159 return unsetcmd(argc, argv); 1160 else if (argc == 3) 1161 setvar(argv[1], argv[2], 0); 1162 else 1163 error("List assignment not implemented"); 1164 return 0; 1165 } 1166 1167 1168 /* 1169 * The unset builtin command. We unset the function before we unset the 1170 * variable to allow a function to be unset when there is a readonly variable 1171 * with the same name. 1172 */ 1173 1174 int 1175 unsetcmd(int argc, char **argv) 1176 { 1177 char **ap; 1178 int i; 1179 int flg_func = 0; 1180 int flg_var = 0; 1181 int flg_x = 0; 1182 int ret = 0; 1183 1184 while ((i = nextopt("efvx")) != '\0') { 1185 switch (i) { 1186 case 'f': 1187 flg_func = 1; 1188 break; 1189 case 'e': 1190 case 'x': 1191 flg_x = (2 >> (i == 'e')); 1192 /* FALLTHROUGH */ 1193 case 'v': 1194 flg_var = 1; 1195 break; 1196 } 1197 } 1198 1199 if (flg_func == 0 && flg_var == 0) 1200 flg_var = 1; 1201 1202 for (ap = argptr; *ap ; ap++) { 1203 if (flg_func) 1204 ret |= unsetfunc(*ap); 1205 if (flg_var) 1206 ret |= unsetvar(*ap, flg_x); 1207 } 1208 return ret; 1209 } 1210 1211 1212 /* 1213 * Unset the specified variable. 1214 */ 1215 1216 int 1217 unsetvar(const char *s, int unexport) 1218 { 1219 struct var **vpp; 1220 struct var *vp; 1221 1222 vp = find_var(s, &vpp, NULL); 1223 if (vp == NULL) 1224 return 0; 1225 1226 if (vp->flags & VREADONLY && !(unexport & 1)) 1227 return 1; 1228 1229 INTOFF; 1230 if (unexport & 1) { 1231 vp->flags &= ~VEXPORT; 1232 } else { 1233 if (vp->text[vp->name_len + 1] != '\0') 1234 setvar(s, nullstr, 0); 1235 if (!(unexport & 2)) 1236 vp->flags &= ~VEXPORT; 1237 vp->flags |= VUNSET; 1238 if ((vp->flags&(VEXPORT|VSTRFIXED|VREADONLY|VNOEXPORT)) == 0) { 1239 if ((vp->flags & VTEXTFIXED) == 0) 1240 ckfree(vp->text); 1241 *vpp = vp->next; 1242 ckfree(vp); 1243 } 1244 } 1245 INTON; 1246 return 0; 1247 } 1248 1249 1250 /* 1251 * Returns true if the two strings specify the same varable. The first 1252 * variable name is terminated by '='; the second may be terminated by 1253 * either '=' or '\0'. 1254 */ 1255 1256 STATIC int 1257 strequal(const char *p, const char *q) 1258 { 1259 while (*p == *q++) { 1260 if (*p++ == '=') 1261 return 1; 1262 } 1263 if (*p == '=' && *(q - 1) == '\0') 1264 return 1; 1265 return 0; 1266 } 1267 1268 /* 1269 * Search for a variable. 1270 * 'name' may be terminated by '=' or a NUL. 1271 * vppp is set to the pointer to vp, or the list head if vp isn't found 1272 * lenp is set to the number of characters in 'name' 1273 */ 1274 1275 STATIC struct var * 1276 find_var(const char *name, struct var ***vppp, int *lenp) 1277 { 1278 unsigned int hashval; 1279 int len; 1280 struct var *vp, **vpp; 1281 const char *p = name; 1282 1283 hashval = 0; 1284 while (*p && *p != '=') 1285 hashval = 2 * hashval + (unsigned char)*p++; 1286 1287 len = p - name; 1288 if (lenp) 1289 *lenp = len; 1290 1291 vpp = &vartab[hashval % VTABSIZE]; 1292 if (vppp) 1293 *vppp = vpp; 1294 1295 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 1296 if (vp->name_len != len) 1297 continue; 1298 if (memcmp(vp->text, name, len) != 0) 1299 continue; 1300 if (vppp) 1301 *vppp = vpp; 1302 return vp; 1303 } 1304 return NULL; 1305 } 1306 1307 /* 1308 * The following are the functions that create the values for 1309 * shell variables that are dynamically produced when needed. 1310 * 1311 * The output strings cannot be malloc'd as there is nothing to 1312 * free them - callers assume these are ordinary variables where 1313 * the value returned is vp->text 1314 * 1315 * Each function needs its own storage space, as the results are 1316 * used to create processes' environment, and (if exported) all 1317 * the values will (might) be needed simultaneously. 1318 * 1319 * It is not a problem if a var is updated while nominally in use 1320 * somewhere, all these are intended to be dynamic, the value they 1321 * return is not guaranteed, an updated vaue is just as good. 1322 * 1323 * So, malloc a single buffer for the result of each function, 1324 * grow, and even shrink, it as needed, but once we have one that 1325 * is a suitable size for the actual usage, simply hold it forever. 1326 * 1327 * For a SMALL shell we implement only LINENO, none of the others, 1328 * and give it just a fixed length static buffer for its result. 1329 */ 1330 1331 #ifndef SMALL 1332 1333 struct space_reserved { /* record of space allocated for results */ 1334 char *b; 1335 int len; 1336 }; 1337 1338 /* rough (over-)estimate of the number of bytes needed to hold a number */ 1339 static int 1340 digits_in(intmax_t number) 1341 { 1342 int res = 0; 1343 1344 if (number & ~((1LL << 62) - 1)) 1345 res = 64; /* enough for 2^200 and a bit more */ 1346 else if (number & ~((1LL << 32) - 1)) 1347 res = 20; /* enough for 2^64 */ 1348 else if (number & ~((1 << 23) - 1)) 1349 res = 10; /* enough for 2^32 */ 1350 else 1351 res = 8; /* enough for 2^23 or smaller */ 1352 1353 return res; 1354 } 1355 1356 static int 1357 make_space(struct space_reserved *m, int bytes) 1358 { 1359 void *p; 1360 1361 if (m->len >= bytes && m->len <= (bytes<<2)) 1362 return 1; 1363 1364 bytes = SHELL_ALIGN(bytes); 1365 INTOFF; 1366 /* not ckrealloc() - we want failure, not error() here */ 1367 p = realloc(m->b, bytes); 1368 if (p != NULL) { 1369 m->b = p; 1370 m->len = bytes; 1371 m->b[bytes - 1] = '\0'; 1372 } 1373 INTON; 1374 1375 return p != NULL; 1376 } 1377 #endif 1378 1379 char * 1380 get_lineno(struct var *vp) 1381 { 1382 #ifdef SMALL 1383 #define length (8 + 10) /* 10 digits is enough for a 32 bit line num */ 1384 static char result[length]; 1385 #else 1386 static struct space_reserved buf; 1387 #define result buf.b 1388 #define length buf.len 1389 #endif 1390 int ln = line_number; 1391 1392 if (vp->flags & VUNSET) 1393 return NULL; 1394 1395 ln -= funclinebase; 1396 1397 #ifndef SMALL 1398 if (!make_space(&buf, vp->name_len + 2 + digits_in(ln))) 1399 return vp->text; 1400 #endif 1401 1402 snprintf(result, length, "%.*s=%d", vp->name_len, vp->text, ln); 1403 return result; 1404 } 1405 #undef result 1406 #undef length 1407 1408 #ifndef SMALL 1409 1410 char * 1411 get_hostname(struct var *vp) 1412 { 1413 static struct space_reserved buf; 1414 1415 if (vp->flags & VUNSET) 1416 return NULL; 1417 1418 if (!make_space(&buf, vp->name_len + 2 + 256)) 1419 return vp->text; 1420 1421 memcpy(buf.b, vp->text, vp->name_len + 1); /* include '=' */ 1422 (void)gethostname(buf.b + vp->name_len + 1, 1423 buf.len - vp->name_len - 3); 1424 return buf.b; 1425 } 1426 1427 char * 1428 get_tod(struct var *vp) 1429 { 1430 static struct space_reserved buf; /* space for answers */ 1431 static struct space_reserved tzs; /* remember TZ last used */ 1432 static timezone_t last_zone; /* timezone data for tzs zone */ 1433 const char *fmt; 1434 char *tz; 1435 time_t now; 1436 struct tm tm_now, *tmp; 1437 timezone_t zone = NULL; 1438 static char t_err[] = "time error"; 1439 int len; 1440 1441 if (vp->flags & VUNSET) 1442 return NULL; 1443 1444 fmt = lookupvar("ToD_FORMAT"); 1445 if (fmt == NULL) 1446 fmt="%T"; 1447 tz = lookupvar("TZ"); 1448 (void)time(&now); 1449 1450 if (tz != NULL) { 1451 if (tzs.b == NULL || strcmp(tzs.b, tz) != 0) { 1452 INTOFF; 1453 if (make_space(&tzs, strlen(tz) + 1)) { 1454 strcpy(tzs.b, tz); 1455 if (last_zone) 1456 tzfree(last_zone); 1457 last_zone = zone = tzalloc(tz); 1458 INTON; 1459 } else 1460 zone = tzalloc(tz); 1461 } else 1462 zone = last_zone; 1463 1464 tmp = localtime_rz(zone, &now, &tm_now); 1465 } else 1466 tmp = localtime_r(&now, &tm_now); 1467 1468 len = (strlen(fmt) * 4) + vp->name_len + 2; 1469 while (make_space(&buf, len)) { 1470 memcpy(buf.b, vp->text, vp->name_len+1); 1471 if (tmp == NULL) { 1472 if (buf.len >= vp->name_len+2+(int)(sizeof t_err - 1)) { 1473 strcpy(buf.b + vp->name_len + 1, t_err); 1474 if (zone && zone != last_zone) { 1475 tzfree(zone); 1476 INTON; 1477 } 1478 return buf.b; 1479 } 1480 len = vp->name_len + 4 + sizeof t_err - 1; 1481 continue; 1482 } 1483 if (strftime_z(zone, buf.b + vp->name_len + 1, 1484 buf.len - vp->name_len - 2, fmt, tmp)) { 1485 if (zone && zone != last_zone) { 1486 tzfree(zone); 1487 INTON; 1488 } 1489 return buf.b; 1490 } 1491 if (len >= 4096) /* Let's be reasonable */ 1492 break; 1493 len <<= 1; 1494 } 1495 if (zone && zone != last_zone) { 1496 tzfree(zone); 1497 INTON; 1498 } 1499 return vp->text; 1500 } 1501 1502 char * 1503 get_seconds(struct var *vp) 1504 { 1505 static struct space_reserved buf; 1506 intmax_t secs; 1507 1508 if (vp->flags & VUNSET) 1509 return NULL; 1510 1511 secs = (intmax_t)time((time_t *)0) - sh_start_time; 1512 if (!make_space(&buf, vp->name_len + 2 + digits_in(secs))) 1513 return vp->text; 1514 1515 snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs); 1516 return buf.b; 1517 } 1518 1519 char * 1520 get_euser(struct var *vp) 1521 { 1522 static struct space_reserved buf; 1523 static uid_t lastuid = 0; 1524 uid_t euid; 1525 struct passwd *pw; 1526 1527 if (vp->flags & VUNSET) 1528 return NULL; 1529 1530 euid = geteuid(); 1531 if (buf.b != NULL && lastuid == euid) 1532 return buf.b; 1533 1534 pw = getpwuid(euid); 1535 if (pw == NULL) 1536 return vp->text; 1537 1538 if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) { 1539 INTOFF; 1540 lastuid = euid; 1541 snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text, 1542 pw->pw_name); 1543 INTON; 1544 return buf.b; 1545 } 1546 1547 return vp->text; 1548 } 1549 1550 char * 1551 get_random(struct var *vp) 1552 { 1553 static struct space_reserved buf; 1554 static intmax_t random_val = 0; 1555 1556 #ifdef USE_LRAND48 1557 #define random lrand48 1558 #define srandom srand48 1559 #endif 1560 1561 if (vp->flags & VUNSET) 1562 return NULL; 1563 1564 if (vp->text != buf.b) { 1565 /* 1566 * Either initialisation, or a new seed has been set 1567 */ 1568 if (vp->text[vp->name_len + 1] == '\0') { 1569 int fd; 1570 1571 /* 1572 * initialisation (without pre-seeding), 1573 * or explictly requesting a truly random seed. 1574 */ 1575 INTOFF; 1576 fd = open("/dev/urandom", 0); 1577 if (fd == -1) { 1578 out2str("RANDOM initialisation failed\n"); 1579 random_val = (getpid()<<3) ^ time((time_t *)0); 1580 } else { 1581 int n; 1582 1583 do { 1584 n = read(fd,&random_val,sizeof random_val); 1585 } while (n != sizeof random_val); 1586 close(fd); 1587 } 1588 INTON; 1589 } else 1590 /* good enough for today */ 1591 random_val = strtoimax(vp->text+vp->name_len+1,NULL,0); 1592 1593 srandom((long)random_val); 1594 } 1595 1596 #if 0 1597 random_val = (random_val + 1) & 0x7FFF; /* 15 bit "random" numbers */ 1598 #else 1599 random_val = (random() >> 5) & 0x7FFF; 1600 #endif 1601 1602 if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val))) 1603 return vp->text; 1604 1605 snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, 1606 random_val); 1607 1608 INTOFF; 1609 if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0) 1610 free(vp->text); 1611 vp->flags |= VTEXTFIXED; 1612 vp->text = buf.b; 1613 INTON; 1614 1615 return vp->text; 1616 #undef random 1617 #undef srandom 1618 } 1619 1620 STATIC int 1621 makespecial(const char *name) 1622 { 1623 const struct varinit *ip; 1624 struct var *vp; 1625 1626 CTRACE(DBG_VARS, ("makespecial('%s') -> ", name)); 1627 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 1628 if (strequal(ip->text, name)) { 1629 if (!(ip->flags & VFUNCREF)) { 1630 CTRACE(DBG_VARS, ("+1\n")); 1631 return 1; 1632 } 1633 INTOFF; 1634 vp->flags &= ~VUNSET; 1635 vp->v_u = ip->v_u; 1636 INTON; 1637 CTRACE(DBG_VARS, ("0\n")); 1638 return 0; 1639 } 1640 } 1641 CTRACE(DBG_VARS, ("1\n")); 1642 return 1; 1643 } 1644 1645 int 1646 specialvarcmd(int argc, char **argv) 1647 { 1648 int res = 0; 1649 char **ap; 1650 1651 (void) nextopt(""); 1652 1653 if (!*argptr) 1654 error("Usage: specialvar var..."); 1655 1656 for (ap = argptr; *ap ; ap++) 1657 res |= makespecial(*ap); 1658 1659 return res; 1660 } 1661 1662 #endif /* SMALL */ 1663