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