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