1 /* $NetBSD: var.c,v 1.82 2022/09/18 17:11:33 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.82 2022/09/18 17:11:33 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 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 void 531 setvar_invocation(int argc, char **argv) 532 { 533 char value[32]; /* if we ever get 30, HELP */ 534 char *v; 535 536 /* 537 * Keep the following in ascii lexical order ( ie: Z before a ) 538 */ 539 540 v = value; 541 *v++ = '!'; /* never empty, and the '-' is not first */ 542 543 if (argc > 0 && argv[0] != NULL && argv[0][0] == '-') 544 *v++ = '-'; 545 if (shellparam.nparam == 0) 546 *v++ = '0'; 547 if (minusc) 548 *v++ = 'c'; 549 if (commandname) 550 *v++ = 'f'; 551 if (iflag) 552 *v++ = 'i'; 553 if (loginsh) 554 *v++ = 'l'; 555 if (privileged) 556 *v++ = 'p'; 557 if (sflag) 558 *v++ = 's'; 559 560 *v++ = '\0'; 561 562 /* 563 * this cannot fail, the var name is OK, 564 * there cannot be any (non special) read only 565 * variables at this point, ... 566 */ 567 setvar("NBSH_INVOCATION", value, VNOEXPORT); 568 } 569 570 /* 571 * Process a linked list of variable assignments. 572 */ 573 574 void 575 listsetvar(struct strlist *list, int flags) 576 { 577 struct strlist *lp; 578 579 INTOFF; 580 for (lp = list ; lp ; lp = lp->next) { 581 setvareq(savestr(lp->text), flags); 582 } 583 INTON; 584 } 585 586 void 587 listmklocal(struct strlist *list, int flags) 588 { 589 struct strlist *lp; 590 591 for (lp = list ; lp ; lp = lp->next) 592 mklocal(lp->text, flags); 593 } 594 595 596 /* 597 * Find the value of a variable. Returns NULL if not set. 598 */ 599 600 char * 601 lookupvar(const char *name) 602 { 603 struct var *v; 604 char *p; 605 606 v = find_var(name, NULL, NULL); 607 if (v == NULL || v->flags & VUNSET) 608 return NULL; 609 if (v->rfunc && (v->flags & VFUNCREF) != 0) { 610 p = (*v->rfunc)(v); 611 if (p == NULL) 612 return NULL; 613 } else 614 p = v->text; 615 616 return p + v->name_len + 1; 617 } 618 619 620 621 /* 622 * Search the environment of a builtin command. If the second argument 623 * is nonzero, return the value of a variable even if it hasn't been 624 * exported. 625 */ 626 627 char * 628 bltinlookup(const char *name, int doall) 629 { 630 struct strlist *sp; 631 struct var *v; 632 char *p; 633 634 for (sp = cmdenviron ; sp ; sp = sp->next) { 635 if (strequal(sp->text, name)) 636 return strchr(sp->text, '=') + 1; 637 } 638 639 v = find_var(name, NULL, NULL); 640 641 if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT))) 642 return NULL; 643 644 if (v->rfunc && (v->flags & VFUNCREF) != 0) { 645 p = (*v->rfunc)(v); 646 if (p == NULL) 647 return NULL; 648 } else 649 p = v->text; 650 651 return p + v->name_len + 1; 652 } 653 654 655 656 /* 657 * Generate a list of exported variables. This routine is used to construct 658 * the third argument to execve when executing a program. 659 */ 660 661 char ** 662 environment(void) 663 { 664 int nenv; 665 struct var **vpp; 666 struct var *vp; 667 char **env; 668 char **ep; 669 670 nenv = 0; 671 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 672 for (vp = *vpp ; vp ; vp = vp->next) 673 if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) 674 nenv++; 675 } 676 CTRACE(DBG_VARS, ("environment: %d vars to export\n", nenv)); 677 ep = env = stalloc((nenv + 1) * sizeof *env); 678 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 679 for (vp = *vpp ; vp ; vp = vp->next) 680 if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) { 681 if (vp->rfunc && (vp->flags & VFUNCREF)) { 682 *ep = (*vp->rfunc)(vp); 683 if (*ep != NULL) 684 ep++; 685 } else 686 *ep++ = vp->text; 687 VTRACE(DBG_VARS, ("environment: %s\n", ep[-1])); 688 } 689 } 690 *ep = NULL; 691 return env; 692 } 693 694 695 /* 696 * Called when a shell procedure is invoked to clear out nonexported 697 * variables. It is also necessary to reallocate variables of with 698 * VSTACK set since these are currently allocated on the stack. 699 */ 700 701 #ifdef mkinit 702 void shprocvar(void); 703 704 SHELLPROC { 705 shprocvar(); 706 } 707 #endif 708 709 void 710 shprocvar(void) 711 { 712 struct var **vpp; 713 struct var *vp, **prev; 714 715 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 716 for (prev = vpp ; (vp = *prev) != NULL ; ) { 717 if ((vp->flags & VEXPORT) == 0) { 718 *prev = vp->next; 719 if ((vp->flags & VTEXTFIXED) == 0) 720 ckfree(vp->text); 721 if ((vp->flags & VSTRFIXED) == 0) 722 ckfree(vp); 723 } else { 724 if (vp->flags & VSTACK) { 725 vp->text = savestr(vp->text); 726 vp->flags &=~ VSTACK; 727 } 728 prev = &vp->next; 729 } 730 } 731 } 732 initvar(); 733 } 734 735 736 737 /* 738 * Command to list all variables which are set. Currently this command 739 * is invoked from the set command when the set command is called without 740 * any variables. 741 */ 742 743 void 744 print_quoted(const char *p) 745 { 746 const char *q; 747 748 if (p[0] == '\0') { 749 out1fmt("''"); 750 return; 751 } 752 if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) { 753 out1fmt("%s", p); 754 return; 755 } 756 while (*p) { 757 if (*p == '\'') { 758 out1fmt("\\'"); 759 p++; 760 continue; 761 } 762 q = strchr(p, '\''); 763 if (!q) { 764 out1fmt("'%s'", p ); 765 return; 766 } 767 out1fmt("'%.*s'", (int)(q - p), p ); 768 p = q; 769 } 770 } 771 772 static int 773 sort_var(const void *v_v1, const void *v_v2) 774 { 775 const struct var * const *v1 = v_v1; 776 const struct var * const *v2 = v_v2; 777 char *t1 = (*v1)->text, *t2 = (*v2)->text; 778 779 if (*t1 == *t2) { 780 char *p, *s; 781 782 STARTSTACKSTR(p); 783 784 /* 785 * note: if lengths are equal, strings must be different 786 * so we don't care which string we pick for the \0 in 787 * that case. 788 */ 789 if ((strchr(t1, '=') - t1) <= (strchr(t2, '=') - t2)) { 790 s = t1; 791 t1 = p; 792 } else { 793 s = t2; 794 t2 = p; 795 } 796 797 while (*s && *s != '=') { 798 STPUTC(*s, p); 799 s++; 800 } 801 STPUTC('\0', p); 802 } 803 804 return strcoll(t1, t2); 805 } 806 807 /* 808 * POSIX requires that 'set' (but not export or readonly) output the 809 * variables in lexicographic order - by the locale's collating order (sigh). 810 * Maybe we could keep them in an ordered balanced binary tree 811 * instead of hashed lists. 812 * For now just roll 'em through qsort for printing... 813 */ 814 815 STATIC void 816 showvar(struct var *vp, const char *cmd, const char *xtra, int show_value) 817 { 818 const char *p; 819 820 p = vp->text; 821 if (vp->rfunc && (vp->flags & VFUNCREF) != 0) { 822 p = (*vp->rfunc)(vp); 823 if (p == NULL) { 824 if (!(show_value & 2)) 825 return; 826 p = vp->text; 827 show_value = 0; 828 } 829 } 830 if (cmd) 831 out1fmt("%s ", cmd); 832 if (xtra) 833 out1fmt("%s ", xtra); 834 for ( ; *p != '=' ; p++) 835 out1c(*p); 836 if (!(vp->flags & VUNSET) && show_value) { 837 out1fmt("="); 838 print_quoted(++p); 839 } 840 out1c('\n'); 841 } 842 843 int 844 showvars(const char *cmd, int flag, int show_value, const char *xtra) 845 { 846 struct var **vpp; 847 struct var *vp; 848 849 static struct var **list; /* static in case we are interrupted */ 850 static int list_len; 851 int count = 0; 852 853 if (!list) { 854 list_len = 32; 855 list = ckmalloc(list_len * sizeof *list); 856 } 857 858 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 859 for (vp = *vpp ; vp ; vp = vp->next) { 860 if (flag && !(vp->flags & flag)) 861 continue; 862 if (vp->flags & VUNSET && !(show_value & 2)) 863 continue; 864 if (count >= list_len) { 865 list = ckrealloc(list, 866 (list_len << 1) * sizeof *list); 867 list_len <<= 1; 868 } 869 list[count++] = vp; 870 } 871 } 872 873 qsort(list, count, sizeof *list, sort_var); 874 875 for (vpp = list; count--; vpp++) 876 showvar(*vpp, cmd, xtra, show_value); 877 878 /* no free(list), will be used again next time ... */ 879 880 return 0; 881 } 882 883 884 885 /* 886 * The export and readonly commands. 887 */ 888 889 static void __dead 890 export_usage(const char *cmd) 891 { 892 #ifdef SMALL 893 if (*cmd == 'r') 894 error("Usage: %s [ -p | var[=val]... ]", cmd); 895 else 896 error("Usage: %s [ -p | [-n] var[=val]... ]", cmd); 897 #else 898 if (*cmd == 'r') 899 error("Usage: %s [-p [var...] | -q var... | var[=val]... ]", cmd); 900 else 901 error( 902 "Usage: %s [ -px [var...] | -q[x] var... | [-n|x] var[=val]... ]", 903 cmd); 904 #endif 905 } 906 907 int 908 exportcmd(int argc, char **argv) 909 { 910 struct var *vp; 911 char *name; 912 const char *p = argv[0]; 913 int flag = p[0] == 'r'? VREADONLY : VEXPORT; 914 int pflg = 0; 915 int nflg = 0; 916 #ifndef SMALL 917 int xflg = 0; 918 int qflg = 0; 919 #endif 920 int res; 921 int c; 922 int f; 923 924 #ifdef SMALL 925 #define EXPORT_OPTS "np" 926 #else 927 #define EXPORT_OPTS "npqx" 928 #endif 929 930 while ((c = nextopt(EXPORT_OPTS)) != '\0') { 931 932 #undef EXPORT_OPTS 933 934 switch (c) { 935 case 'n': 936 if (pflg || flag == VREADONLY 937 #ifndef SMALL 938 || qflg || xflg 939 #endif 940 ) 941 export_usage(p); 942 nflg = 1; 943 break; 944 case 'p': 945 if (nflg 946 #ifndef SMALL 947 || qflg 948 #endif 949 ) 950 export_usage(p); 951 pflg = 3; 952 break; 953 #ifndef SMALL 954 case 'q': 955 if (nflg || pflg) 956 export_usage(p); 957 qflg = 1; 958 break; 959 case 'x': 960 if (nflg || flag == VREADONLY) 961 export_usage(p); 962 flag = VNOEXPORT; 963 xflg = 1; 964 break; 965 #endif 966 } 967 } 968 969 if ((nflg 970 #ifndef SMALL 971 || qflg 972 #endif 973 ) && *argptr == NULL) 974 export_usage(p); 975 976 #ifndef SMALL 977 if (pflg && *argptr != NULL) { 978 while ((name = *argptr++) != NULL) { 979 int len; 980 981 vp = find_var(name, NULL, &len); 982 if (name[len] == '=') 983 export_usage(p); 984 if (!goodname(name)) 985 error("%s: bad variable name", name); 986 987 if (vp && vp->flags & flag) 988 showvar(vp, p, xflg ? "-x" : NULL, 1); 989 } 990 return 0; 991 } 992 #endif 993 994 if (pflg || *argptr == NULL) 995 return showvars( pflg ? p : 0, flag, pflg, 996 #ifndef SMALL 997 pflg && xflg ? "-x" : 998 #endif 999 NULL ); 1000 1001 res = 0; 1002 #ifndef SMALL 1003 if (qflg) { 1004 while ((name = *argptr++) != NULL) { 1005 int len; 1006 1007 vp = find_var(name, NULL, &len); 1008 if (name[len] == '=') 1009 export_usage(p); 1010 if (!goodname(name)) 1011 error("%s: bad variable name", name); 1012 1013 if (vp == NULL || !(vp->flags & flag)) 1014 res = 1; 1015 } 1016 return res; 1017 } 1018 #endif 1019 1020 while ((name = *argptr++) != NULL) { 1021 int len; 1022 1023 f = flag; 1024 1025 vp = find_var(name, NULL, &len); 1026 p = name + len; 1027 if (*p++ != '=') 1028 p = NULL; 1029 1030 if (vp != NULL) { 1031 if (nflg) 1032 vp->flags &= ~flag; 1033 else if (flag&VEXPORT && vp->flags&VNOEXPORT) { 1034 /* note we go ahead and do any assignment */ 1035 sh_warnx("%.*s: not available for export", 1036 len, name); 1037 res = 1; 1038 } else { 1039 if (flag == VNOEXPORT) 1040 vp->flags &= ~VEXPORT; 1041 1042 /* if not NULL will be done in setvar below */ 1043 if (p == NULL) 1044 vp->flags |= flag; 1045 } 1046 if (p == NULL) 1047 continue; 1048 } else if (nflg && p == NULL && !goodname(name)) 1049 error("%s: bad variable name", name); 1050 1051 if (!nflg || p != NULL) 1052 setvar(name, p, f); 1053 } 1054 return res; 1055 } 1056 1057 1058 /* 1059 * The "local" command. 1060 */ 1061 1062 int 1063 localcmd(int argc, char **argv) 1064 { 1065 char *name; 1066 int c; 1067 int flags = 0; /*XXX perhaps VUNSET from a -o option value */ 1068 1069 if (! in_function()) 1070 error("Not in a function"); 1071 1072 /* upper case options, as bash stole all the good ones ... */ 1073 while ((c = nextopt("INx")) != '\0') 1074 switch (c) { 1075 case 'I': flags &= ~VUNSET; break; 1076 case 'N': flags |= VUNSET; break; 1077 case 'x': flags |= VEXPORT; break; 1078 } 1079 1080 while ((name = *argptr++) != NULL) { 1081 mklocal(name, flags); 1082 } 1083 return 0; 1084 } 1085 1086 1087 /* 1088 * Make a variable a local variable. When a variable is made local, its 1089 * value and flags are saved in a localvar structure. The saved values 1090 * will be restored when the shell function returns. We handle the name 1091 * "-" as a special case. 1092 */ 1093 1094 void 1095 mklocal(const char *name, int flags) 1096 { 1097 struct localvar *lvp; 1098 struct var **vpp; 1099 struct var *vp; 1100 1101 INTOFF; 1102 lvp = ckmalloc(sizeof (struct localvar)); 1103 if (name[0] == '-' && name[1] == '\0') { 1104 char *p; 1105 p = ckmalloc(sizeof_optlist); 1106 lvp->text = memcpy(p, optlist, sizeof_optlist); 1107 lvp->rfunc = NULL; 1108 vp = NULL; 1109 xtrace_clone(0); 1110 } else { 1111 vp = find_var(name, &vpp, NULL); 1112 if (vp == NULL) { 1113 flags &= ~VNOEXPORT; 1114 if (strchr(name, '=')) 1115 setvareq(savestr(name), 1116 VSTRFIXED | (flags & ~VUNSET)); 1117 else 1118 setvar(name, NULL, VSTRFIXED|flags); 1119 vp = *vpp; /* the new variable */ 1120 lvp->text = NULL; 1121 lvp->flags = VUNSET; 1122 lvp->rfunc = NULL; 1123 } else { 1124 lvp->text = vp->text; 1125 lvp->flags = vp->flags; 1126 lvp->v_u = vp->v_u; 1127 vp->flags |= VSTRFIXED|VTEXTFIXED; 1128 if (flags & (VDOEXPORT | VUNSET)) 1129 vp->flags &= ~VNOEXPORT; 1130 if (vp->flags & VNOEXPORT && 1131 (flags & (VEXPORT|VDOEXPORT|VUNSET)) == VEXPORT) 1132 flags &= ~VEXPORT; 1133 if (flags & (VNOEXPORT | VUNSET)) 1134 vp->flags &= ~VEXPORT; 1135 flags &= ~VNOEXPORT; 1136 if (name[vp->name_len] == '=') 1137 setvareq(savestr(name), flags & ~VUNSET); 1138 else if (flags & VUNSET) 1139 unsetvar(name, 0); 1140 else 1141 vp->flags |= flags & (VUNSET|VEXPORT); 1142 1143 if (vp == &line_num) { 1144 if (name[vp->name_len] == '=') 1145 funclinebase = funclineabs -1; 1146 else 1147 funclinebase = 0; 1148 } 1149 } 1150 } 1151 lvp->vp = vp; 1152 lvp->next = localvars; 1153 localvars = lvp; 1154 INTON; 1155 } 1156 1157 1158 /* 1159 * Called after a function returns. 1160 */ 1161 1162 void 1163 poplocalvars(void) 1164 { 1165 struct localvar *lvp; 1166 struct var *vp; 1167 1168 while ((lvp = localvars) != NULL) { 1169 localvars = lvp->next; 1170 vp = lvp->vp; 1171 VTRACE(DBG_VARS, ("poplocalvar %s\n", vp ? vp->text : "-")); 1172 if (vp == NULL) { /* $- saved */ 1173 memcpy(optlist, lvp->text, sizeof_optlist); 1174 ckfree(lvp->text); 1175 xtrace_pop(); 1176 optschanged(); 1177 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 1178 (void)unsetvar(vp->text, 0); 1179 } else { 1180 if (lvp->func && (lvp->flags & (VNOFUNC|VFUNCREF)) == 0) 1181 (*lvp->func)(lvp->text + vp->name_len + 1); 1182 if ((vp->flags & VTEXTFIXED) == 0) 1183 ckfree(vp->text); 1184 vp->flags = lvp->flags; 1185 vp->text = lvp->text; 1186 vp->v_u = lvp->v_u; 1187 } 1188 ckfree(lvp); 1189 } 1190 } 1191 1192 1193 int 1194 setvarcmd(int argc, char **argv) 1195 { 1196 if (argc <= 2) 1197 return unsetcmd(argc, argv); 1198 else if (argc == 3) 1199 setvar(argv[1], argv[2], 0); 1200 else 1201 error("List assignment not implemented"); 1202 return 0; 1203 } 1204 1205 1206 /* 1207 * The unset builtin command. We unset the function before we unset the 1208 * variable to allow a function to be unset when there is a readonly variable 1209 * with the same name. 1210 */ 1211 1212 int 1213 unsetcmd(int argc, char **argv) 1214 { 1215 char **ap; 1216 int i; 1217 int flg_func = 0; 1218 int flg_var = 0; 1219 int flg_x = 0; 1220 int ret = 0; 1221 1222 while ((i = nextopt("efvx")) != '\0') { 1223 switch (i) { 1224 case 'f': 1225 flg_func = 1; 1226 break; 1227 case 'e': 1228 case 'x': 1229 flg_x = (2 >> (i == 'e')); 1230 /* FALLTHROUGH */ 1231 case 'v': 1232 flg_var = 1; 1233 break; 1234 } 1235 } 1236 1237 if (flg_func == 0 && flg_var == 0) 1238 flg_var = 1; 1239 1240 for (ap = argptr; *ap ; ap++) { 1241 if (flg_func) 1242 ret |= unsetfunc(*ap); 1243 if (flg_var) 1244 ret |= unsetvar(*ap, flg_x); 1245 } 1246 return ret; 1247 } 1248 1249 1250 /* 1251 * Unset the specified variable. 1252 */ 1253 1254 int 1255 unsetvar(const char *s, int unexport) 1256 { 1257 struct var **vpp; 1258 struct var *vp; 1259 1260 vp = find_var(s, &vpp, NULL); 1261 if (vp == NULL) 1262 return 0; 1263 1264 if (vp->flags & VREADONLY && !(unexport & 1)) 1265 return 1; 1266 1267 INTOFF; 1268 if (unexport & 1) { 1269 vp->flags &= ~VEXPORT; 1270 } else { 1271 if (vp->text[vp->name_len + 1] != '\0') 1272 setvar(s, nullstr, 0); 1273 if (!(unexport & 2)) 1274 vp->flags &= ~VEXPORT; 1275 vp->flags |= VUNSET; 1276 if ((vp->flags&(VEXPORT|VSTRFIXED|VREADONLY|VNOEXPORT)) == 0) { 1277 if ((vp->flags & VTEXTFIXED) == 0) 1278 ckfree(vp->text); 1279 *vpp = vp->next; 1280 ckfree(vp); 1281 } 1282 } 1283 INTON; 1284 return 0; 1285 } 1286 1287 1288 /* 1289 * Returns true if the two strings specify the same variable. The first 1290 * variable name is terminated by '='; the second may be terminated by 1291 * either '=' or '\0'. 1292 */ 1293 1294 STATIC int 1295 strequal(const char *p, const char *q) 1296 { 1297 while (*p == *q++) { 1298 if (*p++ == '=') 1299 return 1; 1300 } 1301 if (*p == '=' && *(q - 1) == '\0') 1302 return 1; 1303 return 0; 1304 } 1305 1306 /* 1307 * Search for a variable. 1308 * 'name' may be terminated by '=' or a NUL. 1309 * vppp is set to the pointer to vp, or the list head if vp isn't found 1310 * lenp is set to the number of characters in 'name' 1311 */ 1312 1313 STATIC struct var * 1314 find_var(const char *name, struct var ***vppp, int *lenp) 1315 { 1316 unsigned int hashval; 1317 int len; 1318 struct var *vp, **vpp; 1319 const char *p = name; 1320 1321 hashval = 0; 1322 while (*p && *p != '=') 1323 hashval = 2 * hashval + (unsigned char)*p++; 1324 1325 len = p - name; 1326 if (lenp) 1327 *lenp = len; 1328 1329 vpp = &vartab[hashval % VTABSIZE]; 1330 if (vppp) 1331 *vppp = vpp; 1332 1333 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 1334 if (vp->name_len != len) 1335 continue; 1336 if (memcmp(vp->text, name, len) != 0) 1337 continue; 1338 if (vppp) 1339 *vppp = vpp; 1340 return vp; 1341 } 1342 return NULL; 1343 } 1344 1345 /* 1346 * The following are the functions that create the values for 1347 * shell variables that are dynamically produced when needed. 1348 * 1349 * The output strings cannot be malloc'd as there is nothing to 1350 * free them - callers assume these are ordinary variables where 1351 * the value returned is vp->text 1352 * 1353 * Each function needs its own storage space, as the results are 1354 * used to create processes' environment, and (if exported) all 1355 * the values will (might) be needed simultaneously. 1356 * 1357 * It is not a problem if a var is updated while nominally in use 1358 * somewhere, all these are intended to be dynamic, the value they 1359 * return is not guaranteed, an updated vaue is just as good. 1360 * 1361 * So, malloc a single buffer for the result of each function, 1362 * grow, and even shrink, it as needed, but once we have one that 1363 * is a suitable size for the actual usage, simply hold it forever. 1364 * 1365 * For a SMALL shell we implement only LINENO, none of the others, 1366 * and give it just a fixed length static buffer for its result. 1367 */ 1368 1369 #ifndef SMALL 1370 1371 struct space_reserved { /* record of space allocated for results */ 1372 char *b; 1373 int len; 1374 }; 1375 1376 /* rough (over-)estimate of the number of bytes needed to hold a number */ 1377 static int 1378 digits_in(intmax_t number) 1379 { 1380 int res = 0; 1381 1382 if (number & ~((1LL << 62) - 1)) 1383 res = 64; /* enough for 2^200 and a bit more */ 1384 else if (number & ~((1LL << 32) - 1)) 1385 res = 20; /* enough for 2^64 */ 1386 else if (number & ~((1 << 23) - 1)) 1387 res = 10; /* enough for 2^32 */ 1388 else 1389 res = 8; /* enough for 2^23 or smaller */ 1390 1391 return res; 1392 } 1393 1394 static int 1395 make_space(struct space_reserved *m, int bytes) 1396 { 1397 void *p; 1398 1399 if (m->len >= bytes && m->len <= (bytes<<2)) 1400 return 1; 1401 1402 bytes = SHELL_ALIGN(bytes); 1403 INTOFF; 1404 /* not ckrealloc() - we want failure, not error() here */ 1405 p = realloc(m->b, bytes); 1406 if (p != NULL) { 1407 m->b = p; 1408 m->len = bytes; 1409 m->b[bytes - 1] = '\0'; 1410 } 1411 INTON; 1412 1413 return p != NULL; 1414 } 1415 #endif 1416 1417 char * 1418 get_lineno(struct var *vp) 1419 { 1420 #ifdef SMALL 1421 #define length (8 + 10) /* 10 digits is enough for a 32 bit line num */ 1422 static char result[length]; 1423 #else 1424 static struct space_reserved buf; 1425 #define result buf.b 1426 #define length buf.len 1427 #endif 1428 int ln = line_number; 1429 1430 if (vp->flags & VUNSET) 1431 return NULL; 1432 1433 ln -= funclinebase; 1434 1435 #ifndef SMALL 1436 if (!make_space(&buf, vp->name_len + 2 + digits_in(ln))) 1437 return vp->text; 1438 #endif 1439 1440 snprintf(result, length, "%.*s=%d", vp->name_len, vp->text, ln); 1441 return result; 1442 } 1443 #undef result 1444 #undef length 1445 1446 #ifndef SMALL 1447 1448 char * 1449 get_hostname(struct var *vp) 1450 { 1451 static struct space_reserved buf; 1452 1453 if (vp->flags & VUNSET) 1454 return NULL; 1455 1456 if (!make_space(&buf, vp->name_len + 2 + 256)) 1457 return vp->text; 1458 1459 memcpy(buf.b, vp->text, vp->name_len + 1); /* include '=' */ 1460 (void)gethostname(buf.b + vp->name_len + 1, 1461 buf.len - vp->name_len - 3); 1462 return buf.b; 1463 } 1464 1465 char * 1466 get_tod(struct var *vp) 1467 { 1468 static struct space_reserved buf; /* space for answers */ 1469 static struct space_reserved tzs; /* remember TZ last used */ 1470 static timezone_t last_zone; /* timezone data for tzs zone */ 1471 const char *fmt; 1472 char *tz; 1473 time_t now; 1474 struct tm tm_now, *tmp; 1475 timezone_t zone = NULL; 1476 static char t_err[] = "time error"; 1477 int len; 1478 1479 if (vp->flags & VUNSET) 1480 return NULL; 1481 1482 fmt = lookupvar("ToD_FORMAT"); 1483 if (fmt == NULL) 1484 fmt="%T"; 1485 tz = lookupvar("TZ"); 1486 (void)time(&now); 1487 1488 if (tz != NULL) { 1489 if (tzs.b == NULL || strcmp(tzs.b, tz) != 0) { 1490 INTOFF; 1491 if (make_space(&tzs, strlen(tz) + 1)) { 1492 strcpy(tzs.b, tz); 1493 if (last_zone) 1494 tzfree(last_zone); 1495 last_zone = zone = tzalloc(tz); 1496 INTON; 1497 } else 1498 zone = tzalloc(tz); 1499 } else 1500 zone = last_zone; 1501 1502 tmp = localtime_rz(zone, &now, &tm_now); 1503 } else 1504 tmp = localtime_r(&now, &tm_now); 1505 1506 len = (strlen(fmt) * 4) + vp->name_len + 2; 1507 while (make_space(&buf, len)) { 1508 memcpy(buf.b, vp->text, vp->name_len+1); 1509 if (tmp == NULL) { 1510 if (buf.len >= vp->name_len+2+(int)(sizeof t_err - 1)) { 1511 strcpy(buf.b + vp->name_len + 1, t_err); 1512 if (zone && zone != last_zone) { 1513 tzfree(zone); 1514 INTON; 1515 } 1516 return buf.b; 1517 } 1518 len = vp->name_len + 4 + sizeof t_err - 1; 1519 continue; 1520 } 1521 if (strftime_z(zone, buf.b + vp->name_len + 1, 1522 buf.len - vp->name_len - 2, fmt, tmp)) { 1523 if (zone && zone != last_zone) { 1524 tzfree(zone); 1525 INTON; 1526 } 1527 return buf.b; 1528 } 1529 if (len >= 4096) /* Let's be reasonable */ 1530 break; 1531 len <<= 1; 1532 } 1533 if (zone && zone != last_zone) { 1534 tzfree(zone); 1535 INTON; 1536 } 1537 return vp->text; 1538 } 1539 1540 char * 1541 get_seconds(struct var *vp) 1542 { 1543 static struct space_reserved buf; 1544 intmax_t secs; 1545 1546 if (vp->flags & VUNSET) 1547 return NULL; 1548 1549 secs = (intmax_t)time((time_t *)0) - sh_start_time; 1550 if (!make_space(&buf, vp->name_len + 2 + digits_in(secs))) 1551 return vp->text; 1552 1553 snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs); 1554 return buf.b; 1555 } 1556 1557 char * 1558 get_euser(struct var *vp) 1559 { 1560 static struct space_reserved buf; 1561 static uid_t lastuid = 0; 1562 uid_t euid; 1563 struct passwd *pw; 1564 1565 if (vp->flags & VUNSET) 1566 return NULL; 1567 1568 euid = geteuid(); 1569 if (buf.b != NULL && lastuid == euid) 1570 return buf.b; 1571 1572 pw = getpwuid(euid); 1573 if (pw == NULL) 1574 return vp->text; 1575 1576 if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) { 1577 INTOFF; 1578 lastuid = euid; 1579 snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text, 1580 pw->pw_name); 1581 INTON; 1582 return buf.b; 1583 } 1584 1585 return vp->text; 1586 } 1587 1588 char * 1589 get_random(struct var *vp) 1590 { 1591 static struct space_reserved buf; 1592 static intmax_t random_val = 0; 1593 1594 #ifdef USE_LRAND48 1595 #define random lrand48 1596 #define srandom srand48 1597 #endif 1598 1599 if (vp->flags & VUNSET) 1600 return NULL; 1601 1602 if (vp->text != buf.b) { 1603 /* 1604 * Either initialisation, or a new seed has been set 1605 */ 1606 if (vp->text[vp->name_len + 1] == '\0') { 1607 int fd; 1608 1609 /* 1610 * initialisation (without pre-seeding), 1611 * or explicitly requesting a truly random seed. 1612 */ 1613 INTOFF; 1614 fd = open("/dev/urandom", 0); 1615 if (fd == -1) { 1616 out2str("RANDOM initialisation failed\n"); 1617 random_val = (getpid()<<3) ^ time((time_t *)0); 1618 } else { 1619 int n; 1620 1621 do { 1622 n = read(fd,&random_val,sizeof random_val); 1623 } while (n != sizeof random_val); 1624 close(fd); 1625 } 1626 INTON; 1627 } else 1628 /* good enough for today */ 1629 random_val = strtoimax(vp->text+vp->name_len+1,NULL,0); 1630 1631 srandom((long)random_val); 1632 } 1633 1634 #if 0 1635 random_val = (random_val + 1) & 0x7FFF; /* 15 bit "random" numbers */ 1636 #else 1637 random_val = (random() >> 5) & 0x7FFF; 1638 #endif 1639 1640 if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val))) 1641 return vp->text; 1642 1643 snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, 1644 random_val); 1645 1646 INTOFF; 1647 if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0) 1648 free(vp->text); 1649 vp->flags |= VTEXTFIXED; 1650 vp->text = buf.b; 1651 INTON; 1652 1653 return vp->text; 1654 #undef random 1655 #undef srandom 1656 } 1657 1658 STATIC int 1659 makespecial(const char *name) 1660 { 1661 const struct varinit *ip; 1662 struct var *vp; 1663 1664 CTRACE(DBG_VARS, ("makespecial('%s') -> ", name)); 1665 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 1666 if (strequal(ip->text, name)) { 1667 if (!(ip->flags & VFUNCREF)) { 1668 CTRACE(DBG_VARS, ("+1\n")); 1669 return 1; 1670 } 1671 INTOFF; 1672 vp->flags &= ~VUNSET; 1673 vp->v_u = ip->v_u; 1674 INTON; 1675 CTRACE(DBG_VARS, ("0\n")); 1676 return 0; 1677 } 1678 } 1679 CTRACE(DBG_VARS, ("1\n")); 1680 return 1; 1681 } 1682 1683 int 1684 specialvarcmd(int argc, char **argv) 1685 { 1686 int res = 0; 1687 char **ap; 1688 1689 (void) nextopt(""); 1690 1691 if (!*argptr) 1692 error("Usage: specialvar var..."); 1693 1694 for (ap = argptr; *ap ; ap++) 1695 res |= makespecial(*ap); 1696 1697 return res; 1698 } 1699 1700 #endif /* SMALL */ 1701