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