1 /* $OpenBSD: var.c,v 1.38 2013/12/20 17:53:09 zhuk Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 5 * 2011, 2012, 2013, 2014 6 * Thorsten Glaser <tg (at) mirbsd.org> 7 * 8 * Provided that these terms and disclaimer and all copyright notices 9 * are retained or reproduced in an accompanying document, permission 10 * is granted to deal in this work without restriction, including un- 11 * limited rights to use, publicly perform, distribute, sell, modify, 12 * merge, give away, or sublicence. 13 * 14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 15 * the utmost extent permitted by applicable law, neither express nor 16 * implied; without malicious intent or gross negligence. In no event 17 * may a licensor, author or contributor be held liable for indirect, 18 * direct, other damage, loss, or other issues arising in any way out 19 * of dealing in the work, even if advised of the possibility of such 20 * damage or existence of a defect, except proven that it results out 21 * of said person's immediate fault when using the work as intended. 22 */ 23 24 #include "sh.h" 25 #include "mirhash.h" 26 27 #if defined(__OpenBSD__) 28 #include <sys/sysctl.h> 29 #endif 30 31 __RCSID("$MirOS: src/bin/mksh/var.c,v 1.183 2014/10/04 11:47:19 tg Exp $"); 32 33 /*- 34 * Variables 35 * 36 * WARNING: unreadable code, needs a rewrite 37 * 38 * if (flag&INTEGER), val.i contains integer value, and type contains base. 39 * otherwise, (val.s + type) contains string value. 40 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. 41 */ 42 43 static struct table specials; 44 static uint32_t lcg_state = 5381, qh_state = 4711; 45 /* may only be set by typeset() just before call to array_index_calc() */ 46 static enum namerefflag innermost_refflag = SRF_NOP; 47 48 static char *formatstr(struct tbl *, const char *); 49 static void exportprep(struct tbl *, const char *); 50 static int special(const char *); 51 static void unspecial(const char *); 52 static void getspec(struct tbl *); 53 static void setspec(struct tbl *); 54 static void unsetspec(struct tbl *); 55 static int getint(struct tbl *, mksh_ari_u *, bool); 56 static const char *array_index_calc(const char *, bool *, uint32_t *); 57 58 /* 59 * create a new block for function calls and simple commands 60 * assume caller has allocated and set up e->loc 61 */ 62 void 63 newblock(void) 64 { 65 struct block *l; 66 static const char *empty[] = { null }; 67 68 l = alloc(sizeof(struct block), ATEMP); 69 l->flags = 0; 70 /* TODO: could use e->area (l->area => l->areap) */ 71 ainit(&l->area); 72 if (!e->loc) { 73 l->argc = 0; 74 l->argv = empty; 75 } else { 76 l->argc = e->loc->argc; 77 l->argv = e->loc->argv; 78 } 79 l->exit = l->error = NULL; 80 ktinit(&l->area, &l->vars, 0); 81 ktinit(&l->area, &l->funs, 0); 82 l->next = e->loc; 83 e->loc = l; 84 } 85 86 /* 87 * pop a block handling special variables 88 */ 89 void 90 popblock(void) 91 { 92 ssize_t i; 93 struct block *l = e->loc; 94 struct tbl *vp, **vpp = l->vars.tbls, *vq; 95 96 /* pop block */ 97 e->loc = l->next; 98 99 i = 1 << (l->vars.tshift); 100 while (--i >= 0) 101 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) { 102 if ((vq = global(vp->name))->flag & ISSET) 103 setspec(vq); 104 else 105 unsetspec(vq); 106 } 107 if (l->flags & BF_DOGETOPTS) 108 user_opt = l->getopts_state; 109 afreeall(&l->area); 110 afree(l, ATEMP); 111 } 112 113 /* called by main() to initialise variable data structures */ 114 #define VARSPEC_DEFNS 115 #include "var_spec.h" 116 117 enum var_specs { 118 #define VARSPEC_ENUMS 119 #include "var_spec.h" 120 V_MAX 121 }; 122 123 /* this is biased with -1 relative to VARSPEC_ENUMS */ 124 static const char * const initvar_names[] = { 125 #define VARSPEC_ITEMS 126 #include "var_spec.h" 127 }; 128 129 void 130 initvar(void) 131 { 132 int i = 0; 133 struct tbl *tp; 134 135 ktinit(APERM, &specials, 136 /* currently 14 specials: 75% of 32 = 2^5 */ 137 5); 138 while (i < V_MAX - 1) { 139 tp = ktenter(&specials, initvar_names[i], 140 hash(initvar_names[i])); 141 tp->flag = DEFINED|ISSET; 142 tp->type = ++i; 143 } 144 } 145 146 /* common code for several functions below and c_typeset() */ 147 struct block * 148 varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) 149 { 150 register struct tbl *vp; 151 152 if (l) { 153 varsearch_loop: 154 if ((vp = ktsearch(&l->vars, vn, h)) != NULL) 155 goto varsearch_out; 156 if (l->next != NULL) { 157 l = l->next; 158 goto varsearch_loop; 159 } 160 } 161 vp = NULL; 162 varsearch_out: 163 *vpp = vp; 164 return (l); 165 } 166 167 /* 168 * Used to calculate an array index for global()/local(). Sets *arrayp 169 * to true if this is an array, sets *valp to the array index, returns 170 * the basename of the array. May only be called from global()/local() 171 * and must be their first callee. 172 */ 173 static const char * 174 array_index_calc(const char *n, bool *arrayp, uint32_t *valp) 175 { 176 const char *p; 177 size_t len; 178 char *ap = NULL; 179 180 *arrayp = false; 181 redo_from_ref: 182 p = skip_varname(n, false); 183 if (innermost_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { 184 struct tbl *vp; 185 char *vn; 186 187 strndupx(vn, n, p - n, ATEMP); 188 /* check if this is a reference */ 189 varsearch(e->loc, &vp, vn, hash(vn)); 190 afree(vn, ATEMP); 191 if (vp && (vp->flag & (DEFINED | ASSOC | ARRAY)) == 192 (DEFINED | ASSOC)) { 193 char *cp; 194 195 /* gotcha! */ 196 cp = shf_smprintf("%s%s", str_val(vp), p); 197 afree(ap, ATEMP); 198 n = ap = cp; 199 goto redo_from_ref; 200 } 201 } 202 innermost_refflag = SRF_NOP; 203 204 if (p != n && *p == '[' && (len = array_ref_len(p))) { 205 char *sub, *tmp; 206 mksh_ari_t rval; 207 208 /* calculate the value of the subscript */ 209 *arrayp = true; 210 strndupx(tmp, p + 1, len - 2, ATEMP); 211 sub = substitute(tmp, 0); 212 afree(tmp, ATEMP); 213 strndupx(n, n, p - n, ATEMP); 214 evaluate(sub, &rval, KSH_UNWIND_ERROR, true); 215 *valp = (uint32_t)rval; 216 afree(sub, ATEMP); 217 } 218 return (n); 219 } 220 221 /* 222 * Search for variable, if not found create globally. 223 */ 224 struct tbl * 225 global(const char *n) 226 { 227 struct block *l = e->loc; 228 struct tbl *vp; 229 int c; 230 bool array; 231 uint32_t h, val; 232 233 /* 234 * check to see if this is an array; 235 * dereference namerefs; must come first 236 */ 237 n = array_index_calc(n, &array, &val); 238 h = hash(n); 239 c = (unsigned char)n[0]; 240 if (!ksh_isalphx(c)) { 241 if (array) 242 errorf("bad substitution"); 243 vp = &vtemp; 244 vp->flag = DEFINED; 245 vp->type = 0; 246 vp->areap = ATEMP; 247 *vp->name = c; 248 if (ksh_isdigit(c)) { 249 if (getn(n, &c) && (c <= l->argc)) 250 /* setstr can't fail here */ 251 setstr(vp, l->argv[c], KSH_RETURN_ERROR); 252 vp->flag |= RDONLY; 253 return (vp); 254 } 255 vp->flag |= RDONLY; 256 if (n[1] != '\0') 257 return (vp); 258 vp->flag |= ISSET|INTEGER; 259 switch (c) { 260 case '$': 261 vp->val.i = kshpid; 262 break; 263 case '!': 264 /* if no job, expand to nothing */ 265 if ((vp->val.i = j_async()) == 0) 266 vp->flag &= ~(ISSET|INTEGER); 267 break; 268 case '?': 269 vp->val.i = exstat & 0xFF; 270 break; 271 case '#': 272 vp->val.i = l->argc; 273 break; 274 case '-': 275 vp->flag &= ~INTEGER; 276 vp->val.s = getoptions(); 277 break; 278 default: 279 vp->flag &= ~(ISSET|INTEGER); 280 } 281 return (vp); 282 } 283 l = varsearch(e->loc, &vp, n, h); 284 if (vp != NULL) 285 return (array ? arraysearch(vp, val) : vp); 286 vp = ktenter(&l->vars, n, h); 287 if (array) 288 vp = arraysearch(vp, val); 289 vp->flag |= DEFINED; 290 if (special(n)) 291 vp->flag |= SPECIAL; 292 return (vp); 293 } 294 295 /* 296 * Search for local variable, if not found create locally. 297 */ 298 struct tbl * 299 local(const char *n, bool copy) 300 { 301 struct block *l = e->loc; 302 struct tbl *vp; 303 bool array; 304 uint32_t h, val; 305 306 /* 307 * check to see if this is an array; 308 * dereference namerefs; must come first 309 */ 310 n = array_index_calc(n, &array, &val); 311 mkssert(n != NULL); 312 h = hash(n); 313 if (!ksh_isalphx(*n)) { 314 vp = &vtemp; 315 vp->flag = DEFINED|RDONLY; 316 vp->type = 0; 317 vp->areap = ATEMP; 318 return (vp); 319 } 320 vp = ktenter(&l->vars, n, h); 321 if (copy && !(vp->flag & DEFINED)) { 322 struct tbl *vq; 323 324 varsearch(l->next, &vq, n, h); 325 if (vq != NULL) { 326 vp->flag |= vq->flag & 327 (EXPORT | INTEGER | RDONLY | LJUST | RJUST | 328 ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); 329 if (vq->flag & INTEGER) 330 vp->type = vq->type; 331 vp->u2.field = vq->u2.field; 332 } 333 } 334 if (array) 335 vp = arraysearch(vp, val); 336 vp->flag |= DEFINED; 337 if (special(n)) 338 vp->flag |= SPECIAL; 339 return (vp); 340 } 341 342 /* get variable string value */ 343 char * 344 str_val(struct tbl *vp) 345 { 346 char *s; 347 348 if ((vp->flag&SPECIAL)) 349 getspec(vp); 350 if (!(vp->flag&ISSET)) 351 /* special to dollar() */ 352 s = null; 353 else if (!(vp->flag&INTEGER)) 354 /* string source */ 355 s = vp->val.s + vp->type; 356 else { 357 /* integer source */ 358 mksh_uari_t n; 359 unsigned int base; 360 /** 361 * worst case number length is when base == 2: 362 * 1 (minus) + 2 (base, up to 36) + 1 ('#') + 363 * number of bits in the mksh_uari_t + 1 (NUL) 364 */ 365 char strbuf[1 + 2 + 1 + 8 * sizeof(mksh_uari_t) + 1]; 366 const char *digits = (vp->flag & UCASEV_AL) ? 367 digits_uc : digits_lc; 368 369 s = strbuf + sizeof(strbuf); 370 if (vp->flag & INT_U) 371 n = vp->val.u; 372 else 373 n = (vp->val.i < 0) ? -vp->val.u : vp->val.u; 374 base = (vp->type == 0) ? 10U : (unsigned int)vp->type; 375 376 if (base == 1 && n == 0) 377 base = 2; 378 if (base == 1) { 379 size_t sz = 1; 380 381 *(s = strbuf) = '1'; 382 s[1] = '#'; 383 if (!UTFMODE || ((n & 0xFF80) == 0xEF80)) 384 /* OPTU-16 -> raw octet */ 385 s[2] = n & 0xFF; 386 else 387 sz = utf_wctomb(s + 2, n); 388 s[2 + sz] = '\0'; 389 } else { 390 *--s = '\0'; 391 do { 392 *--s = digits[n % base]; 393 n /= base; 394 } while (n != 0); 395 if (base != 10) { 396 *--s = '#'; 397 *--s = digits[base % 10]; 398 if (base >= 10) 399 *--s = digits[base / 10]; 400 } 401 if (!(vp->flag & INT_U) && vp->val.i < 0) 402 *--s = '-'; 403 } 404 if (vp->flag & (RJUST|LJUST)) 405 /* case already dealt with */ 406 s = formatstr(vp, s); 407 else 408 strdupx(s, s, ATEMP); 409 } 410 return (s); 411 } 412 413 /* set variable to string value */ 414 int 415 setstr(struct tbl *vq, const char *s, int error_ok) 416 { 417 char *salloc = NULL; 418 bool no_ro_check = tobool(error_ok & 0x4); 419 420 error_ok &= ~0x4; 421 if ((vq->flag & RDONLY) && !no_ro_check) { 422 warningf(true, "read-only: %s", vq->name); 423 if (!error_ok) 424 errorfxz(2); 425 return (0); 426 } 427 if (!(vq->flag&INTEGER)) { 428 /* string dest */ 429 if ((vq->flag&ALLOC)) { 430 #ifndef MKSH_SMALL 431 /* debugging */ 432 if (s >= vq->val.s && 433 s <= vq->val.s + strlen(vq->val.s)) { 434 internal_errorf( 435 "setstr: %s=%s: assigning to self", 436 vq->name, s); 437 } 438 #endif 439 afree(vq->val.s, vq->areap); 440 } 441 vq->flag &= ~(ISSET|ALLOC); 442 vq->type = 0; 443 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) 444 s = salloc = formatstr(vq, s); 445 if ((vq->flag&EXPORT)) 446 exportprep(vq, s); 447 else { 448 strdupx(vq->val.s, s, vq->areap); 449 vq->flag |= ALLOC; 450 } 451 } else { 452 /* integer dest */ 453 if (!v_evaluate(vq, s, error_ok, true)) 454 return (0); 455 } 456 vq->flag |= ISSET; 457 if ((vq->flag&SPECIAL)) 458 setspec(vq); 459 afree(salloc, ATEMP); 460 return (1); 461 } 462 463 /* set variable to integer */ 464 void 465 setint(struct tbl *vq, mksh_ari_t n) 466 { 467 if (!(vq->flag&INTEGER)) { 468 struct tbl *vp = &vtemp; 469 vp->flag = (ISSET|INTEGER); 470 vp->type = 0; 471 vp->areap = ATEMP; 472 vp->val.i = n; 473 /* setstr can't fail here */ 474 setstr(vq, str_val(vp), KSH_RETURN_ERROR); 475 } else 476 vq->val.i = n; 477 vq->flag |= ISSET; 478 if ((vq->flag&SPECIAL)) 479 setspec(vq); 480 } 481 482 static int 483 getint(struct tbl *vp, mksh_ari_u *nump, bool arith) 484 { 485 mksh_uari_t c, num, base; 486 const char *s; 487 bool have_base = false, neg = false; 488 489 if (vp->flag&SPECIAL) 490 getspec(vp); 491 /* XXX is it possible for ISSET to be set and val.s to be NULL? */ 492 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 493 return (-1); 494 if (vp->flag&INTEGER) { 495 nump->i = vp->val.i; 496 return (vp->type); 497 } 498 s = vp->val.s + vp->type; 499 base = 10; 500 num = 0; 501 if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') { 502 s += 2; 503 base = 16; 504 have_base = true; 505 } 506 if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) && 507 !(vp->flag & ZEROFIL)) { 508 /* interpret as octal (deprecated) */ 509 base = 8; 510 have_base = true; 511 } 512 while ((c = (unsigned char)*s++)) { 513 if (c == '-') { 514 neg = true; 515 continue; 516 } else if (c == '#') { 517 if (have_base || num < 1 || num > 36) 518 return (-1); 519 if ((base = num) == 1) { 520 unsigned int wc; 521 522 if (!UTFMODE) 523 wc = *(const unsigned char *)s; 524 else if (utf_mbtowc(&wc, s) == (size_t)-1) 525 /* OPTU-8 -> OPTU-16 */ 526 /* 527 * (with a twist: 1#\uEF80 converts 528 * the same as 1#\x80 does, thus is 529 * not round-tripping correctly XXX) 530 */ 531 wc = 0xEF00 + *(const unsigned char *)s; 532 nump->u = (mksh_uari_t)wc; 533 return (1); 534 } 535 num = 0; 536 have_base = true; 537 continue; 538 } else if (ksh_isdigit(c)) 539 c -= '0'; 540 else if (ksh_islower(c)) 541 c -= 'a' - 10; 542 else if (ksh_isupper(c)) 543 c -= 'A' - 10; 544 else 545 return (-1); 546 if (c >= base) 547 return (-1); 548 num = num * base + c; 549 } 550 if (neg) 551 num = -num; 552 nump->u = num; 553 return (base); 554 } 555 556 /* 557 * convert variable vq to integer variable, setting its value from vp 558 * (vq and vp may be the same) 559 */ 560 struct tbl * 561 setint_v(struct tbl *vq, struct tbl *vp, bool arith) 562 { 563 int base; 564 mksh_ari_u num; 565 566 if ((base = getint(vp, &num, arith)) == -1) 567 return (NULL); 568 setint_n(vq, num.i, 0); 569 if (vq->type == 0) 570 /* default base */ 571 vq->type = base; 572 return (vq); 573 } 574 575 /* convert variable vq to integer variable, setting its value to num */ 576 void 577 setint_n(struct tbl *vq, mksh_ari_t num, int newbase) 578 { 579 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 580 vq->flag &= ~ALLOC; 581 vq->type = 0; 582 afree(vq->val.s, vq->areap); 583 } 584 vq->val.i = num; 585 if (newbase != 0) 586 vq->type = newbase; 587 vq->flag |= ISSET|INTEGER; 588 if (vq->flag&SPECIAL) 589 setspec(vq); 590 } 591 592 static char * 593 formatstr(struct tbl *vp, const char *s) 594 { 595 int olen, nlen; 596 char *p, *q; 597 size_t psiz; 598 599 olen = (int)utf_mbswidth(s); 600 601 if (vp->flag & (RJUST|LJUST)) { 602 if (!vp->u2.field) 603 /* default field width */ 604 vp->u2.field = olen; 605 nlen = vp->u2.field; 606 } else 607 nlen = olen; 608 609 p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); 610 if (vp->flag & (RJUST|LJUST)) { 611 int slen = olen, i = 0; 612 613 if (vp->flag & RJUST) { 614 const char *qq = s; 615 int n = 0; 616 617 while (i < slen) 618 i += utf_widthadj(qq, &qq); 619 /* strip trailing spaces (AT&T uses qq[-1] == ' ') */ 620 while (qq > s && ksh_isspace(qq[-1])) { 621 --qq; 622 --slen; 623 } 624 if (vp->flag & ZEROFIL && vp->flag & INTEGER) { 625 if (!s[0] || !s[1]) 626 goto uhm_no; 627 if (s[1] == '#') 628 n = 2; 629 else if (s[2] == '#') 630 n = 3; 631 uhm_no: 632 if (vp->u2.field <= n) 633 n = 0; 634 } 635 if (n) { 636 memcpy(p, s, n); 637 s += n; 638 } 639 while (slen > vp->u2.field) 640 slen -= utf_widthadj(s, &s); 641 if (vp->u2.field - slen) 642 memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ', 643 vp->u2.field - slen); 644 slen -= n; 645 shf_snprintf(p + vp->u2.field - slen, 646 psiz - (vp->u2.field - slen), 647 "%.*s", slen, s); 648 } else { 649 /* strip leading spaces/zeros */ 650 while (ksh_isspace(*s)) 651 s++; 652 if (vp->flag & ZEROFIL) 653 while (*s == '0') 654 s++; 655 shf_snprintf(p, nlen + 1, "%-*.*s", 656 vp->u2.field, vp->u2.field, s); 657 } 658 } else 659 memcpy(p, s, strlen(s) + 1); 660 661 if (vp->flag & UCASEV_AL) { 662 for (q = p; *q; q++) 663 *q = ksh_toupper(*q); 664 } else if (vp->flag & LCASEV) { 665 for (q = p; *q; q++) 666 *q = ksh_tolower(*q); 667 } 668 669 return (p); 670 } 671 672 /* 673 * make vp->val.s be "name=value" for quick exporting. 674 */ 675 static void 676 exportprep(struct tbl *vp, const char *val) 677 { 678 char *xp; 679 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 680 size_t namelen, vallen; 681 682 mkssert(val != NULL); 683 684 namelen = strlen(vp->name); 685 vallen = strlen(val) + 1; 686 687 vp->flag |= ALLOC; 688 /* since name+val are both in memory this can go unchecked */ 689 xp = alloc(namelen + 1 + vallen, vp->areap); 690 memcpy(vp->val.s = xp, vp->name, namelen); 691 xp += namelen; 692 *xp++ = '='; 693 /* offset to value */ 694 vp->type = xp - vp->val.s; 695 memcpy(xp, val, vallen); 696 if (op != NULL) 697 afree(op, vp->areap); 698 } 699 700 /* 701 * lookup variable (according to (set&LOCAL)), set its attributes 702 * (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, LCASEV, 703 * UCASEV_AL), and optionally set its value if an assignment. 704 */ 705 struct tbl * 706 typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) 707 { 708 struct tbl *vp; 709 struct tbl *vpbase, *t; 710 char *tvar; 711 const char *val; 712 size_t len; 713 bool vappend = false; 714 enum namerefflag new_refflag = SRF_NOP; 715 716 if ((set & (ARRAY | ASSOC)) == ASSOC) { 717 new_refflag = SRF_ENABLE; 718 set &= ~(ARRAY | ASSOC); 719 } 720 if ((clr & (ARRAY | ASSOC)) == ASSOC) { 721 new_refflag = SRF_DISABLE; 722 clr &= ~(ARRAY | ASSOC); 723 } 724 725 /* check for valid variable name, search for value */ 726 val = skip_varname(var, false); 727 if (val == var) { 728 /* no variable name given */ 729 return (NULL); 730 } 731 if (*val == '[') { 732 if (new_refflag != SRF_NOP) 733 errorf("%s: %s", var, 734 "reference variable can't be an array"); 735 len = array_ref_len(val); 736 if (len == 0) 737 return (NULL); 738 /* 739 * IMPORT is only used when the shell starts up and is 740 * setting up its environment. Allow only simple array 741 * references at this time since parameter/command 742 * substitution is performed on the [expression] which 743 * would be a major security hole. 744 */ 745 if (set & IMPORT) { 746 size_t i; 747 748 for (i = 1; i < len - 1; i++) 749 if (!ksh_isdigit(val[i])) 750 return (NULL); 751 } 752 val += len; 753 } 754 if (val[0] == '=') { 755 strndupx(tvar, var, val - var, ATEMP); 756 ++val; 757 } else if (set & IMPORT) { 758 /* environment invalid variable name or no assignment */ 759 return (NULL); 760 } else if (val[0] == '+' && val[1] == '=') { 761 strndupx(tvar, var, val - var, ATEMP); 762 val += 2; 763 vappend = true; 764 } else if (val[0] != '\0') { 765 /* other invalid variable names (not from environment) */ 766 return (NULL); 767 } else { 768 /* just varname with no value part nor equals sign */ 769 strdupx(tvar, var, ATEMP); 770 val = NULL; 771 /* handle foo[*] => foo (whole array) mapping for R39b */ 772 len = strlen(tvar); 773 if (len > 3 && tvar[len - 3] == '[' && tvar[len - 2] == '*' && 774 tvar[len - 1] == ']') 775 tvar[len - 3] = '\0'; 776 } 777 778 if (new_refflag == SRF_ENABLE) { 779 const char *qval, *ccp; 780 781 /* bail out on 'nameref foo+=bar' */ 782 if (vappend) 783 errorf("appending not allowed for nameref"); 784 /* find value if variable already exists */ 785 if ((qval = val) == NULL) { 786 varsearch(e->loc, &vp, tvar, hash(tvar)); 787 if (vp == NULL) 788 goto nameref_empty; 789 qval = str_val(vp); 790 } 791 /* check target value for being a valid variable name */ 792 ccp = skip_varname(qval, false); 793 if (ccp == qval) { 794 if (ksh_isdigit(qval[0])) { 795 int c; 796 797 if (getn(qval, &c)) 798 goto nameref_rhs_checked; 799 } else if (qval[1] == '\0') switch (qval[0]) { 800 case '$': 801 case '!': 802 case '?': 803 case '#': 804 case '-': 805 goto nameref_rhs_checked; 806 } 807 nameref_empty: 808 errorf("%s: %s", var, "empty nameref target"); 809 } 810 len = (*ccp == '[') ? array_ref_len(ccp) : 0; 811 if (ccp[len]) { 812 /* 813 * works for cases "no array", "valid array with 814 * junk after it" and "invalid array"; in the 815 * latter case, len is also 0 and points to '[' 816 */ 817 errorf("%s: %s", qval, 818 "nameref target not a valid parameter name"); 819 } 820 nameref_rhs_checked: 821 /* prevent nameref loops */ 822 while (qval) { 823 if (!strcmp(qval, tvar)) 824 errorf("%s: %s", qval, 825 "expression recurses on parameter"); 826 varsearch(e->loc, &vp, qval, hash(qval)); 827 qval = NULL; 828 if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC)) 829 qval = str_val(vp); 830 } 831 } 832 833 /* prevent typeset from creating a local PATH/ENV/SHELL */ 834 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 || 835 strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) 836 errorf("%s: %s", tvar, "restricted"); 837 838 innermost_refflag = new_refflag; 839 vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : 840 global(tvar); 841 if (new_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) 842 vp->flag &= ~ASSOC; 843 else if (new_refflag == SRF_ENABLE) { 844 if (vp->flag & ARRAY) { 845 struct tbl *a, *tmp; 846 847 /* free up entire array */ 848 for (a = vp->u.array; a; ) { 849 tmp = a; 850 a = a->u.array; 851 if (tmp->flag & ALLOC) 852 afree(tmp->val.s, tmp->areap); 853 afree(tmp, tmp->areap); 854 } 855 vp->u.array = NULL; 856 vp->flag &= ~ARRAY; 857 } 858 vp->flag |= ASSOC; 859 } 860 861 set &= ~(LOCAL|LOCAL_COPY); 862 863 vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp; 864 865 /* 866 * only allow export flag to be set; AT&T ksh allows any 867 * attribute to be changed which means it can be truncated or 868 * modified (-L/-R/-Z/-i) 869 */ 870 if ((vpbase->flag & RDONLY) && 871 (val || clr || (set & ~EXPORT))) 872 /* XXX check calls - is error here ok by POSIX? */ 873 errorfx(2, "read-only: %s", tvar); 874 afree(tvar, ATEMP); 875 876 /* most calls are with set/clr == 0 */ 877 if (set | clr) { 878 bool ok = true; 879 880 /* 881 * XXX if x[0] isn't set, there will be problems: need 882 * to have one copy of attributes for arrays... 883 */ 884 for (t = vpbase; t; t = t->u.array) { 885 bool fake_assign; 886 char *s = NULL; 887 char *free_me = NULL; 888 889 fake_assign = (t->flag & ISSET) && (!val || t != vp) && 890 ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) || 891 ((t->flag & INTEGER) && (clr & INTEGER)) || 892 (!(t->flag & INTEGER) && (set & INTEGER))); 893 if (fake_assign) { 894 if (t->flag & INTEGER) { 895 s = str_val(t); 896 free_me = NULL; 897 } else { 898 s = t->val.s + t->type; 899 free_me = (t->flag & ALLOC) ? t->val.s : 900 NULL; 901 } 902 t->flag &= ~ALLOC; 903 } 904 if (!(t->flag & INTEGER) && (set & INTEGER)) { 905 t->type = 0; 906 t->flag &= ~ALLOC; 907 } 908 t->flag = (t->flag | set) & ~clr; 909 /* 910 * Don't change base if assignment is to be 911 * done, in case assignment fails. 912 */ 913 if ((set & INTEGER) && base > 0 && (!val || t != vp)) 914 t->type = base; 915 if (set & (LJUST|RJUST|ZEROFIL)) 916 t->u2.field = field; 917 if (fake_assign) { 918 if (!setstr(t, s, KSH_RETURN_ERROR)) { 919 /* 920 * Somewhat arbitrary action 921 * here: zap contents of 922 * variable, but keep the flag 923 * settings. 924 */ 925 ok = false; 926 if (t->flag & INTEGER) 927 t->flag &= ~ISSET; 928 else { 929 if (t->flag & ALLOC) 930 afree(t->val.s, t->areap); 931 t->flag &= ~(ISSET|ALLOC); 932 t->type = 0; 933 } 934 } 935 if (free_me) 936 afree(free_me, t->areap); 937 } 938 } 939 if (!ok) 940 errorfz(); 941 } 942 943 if (val != NULL) { 944 char *tval; 945 946 if (vappend) { 947 tval = shf_smprintf("%s%s", str_val(vp), val); 948 val = tval; 949 } else 950 tval = NULL; 951 952 if (vp->flag&INTEGER) { 953 /* do not zero base before assignment */ 954 setstr(vp, val, KSH_UNWIND_ERROR | 0x4); 955 /* done after assignment to override default */ 956 if (base > 0) 957 vp->type = base; 958 } else 959 /* setstr can't fail (readonly check already done) */ 960 setstr(vp, val, KSH_RETURN_ERROR | 0x4); 961 962 if (tval != NULL) 963 afree(tval, ATEMP); 964 } 965 966 /* only x[0] is ever exported, so use vpbase */ 967 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) && 968 vpbase->type == 0) 969 exportprep(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 970 971 return (vp); 972 } 973 974 /** 975 * Unset a variable. The flags can be: 976 * |1 = tear down entire array 977 * |2 = keep attributes, only unset content 978 */ 979 void 980 unset(struct tbl *vp, int flags) 981 { 982 if (vp->flag & ALLOC) 983 afree(vp->val.s, vp->areap); 984 if ((vp->flag & ARRAY) && (flags & 1)) { 985 struct tbl *a, *tmp; 986 987 /* free up entire array */ 988 for (a = vp->u.array; a; ) { 989 tmp = a; 990 a = a->u.array; 991 if (tmp->flag & ALLOC) 992 afree(tmp->val.s, tmp->areap); 993 afree(tmp, tmp->areap); 994 } 995 vp->u.array = NULL; 996 } 997 if (flags & 2) { 998 vp->flag &= ~(ALLOC|ISSET); 999 return; 1000 } 1001 /* if foo[0] is being unset, the remainder of the array is kept... */ 1002 vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED); 1003 if (vp->flag & SPECIAL) 1004 /* responsible for 'unspecial'ing var */ 1005 unsetspec(vp); 1006 } 1007 1008 /* 1009 * Return a pointer to the first char past a legal variable name 1010 * (returns the argument if there is no legal name, returns a pointer to 1011 * the terminating NUL if whole string is legal). 1012 */ 1013 const char * 1014 skip_varname(const char *s, bool aok) 1015 { 1016 size_t alen; 1017 1018 if (s && ksh_isalphx(*s)) { 1019 while (*++s && ksh_isalnux(*s)) 1020 ; 1021 if (aok && *s == '[' && (alen = array_ref_len(s))) 1022 s += alen; 1023 } 1024 return (s); 1025 } 1026 1027 /* Return a pointer to the first character past any legal variable name */ 1028 const char * 1029 skip_wdvarname(const char *s, 1030 /* skip array de-reference? */ 1031 bool aok) 1032 { 1033 if (s[0] == CHAR && ksh_isalphx(s[1])) { 1034 do { 1035 s += 2; 1036 } while (s[0] == CHAR && ksh_isalnux(s[1])); 1037 if (aok && s[0] == CHAR && s[1] == '[') { 1038 /* skip possible array de-reference */ 1039 const char *p = s; 1040 char c; 1041 int depth = 0; 1042 1043 while (/* CONSTCOND */ 1) { 1044 if (p[0] != CHAR) 1045 break; 1046 c = p[1]; 1047 p += 2; 1048 if (c == '[') 1049 depth++; 1050 else if (c == ']' && --depth == 0) { 1051 s = p; 1052 break; 1053 } 1054 } 1055 } 1056 } 1057 return (s); 1058 } 1059 1060 /* Check if coded string s is a variable name */ 1061 int 1062 is_wdvarname(const char *s, bool aok) 1063 { 1064 const char *p = skip_wdvarname(s, aok); 1065 1066 return (p != s && p[0] == EOS); 1067 } 1068 1069 /* Check if coded string s is a variable assignment */ 1070 int 1071 is_wdvarassign(const char *s) 1072 { 1073 const char *p = skip_wdvarname(s, true); 1074 1075 return (p != s && p[0] == CHAR && 1076 (p[1] == '=' || (p[1] == '+' && p[2] == CHAR && p[3] == '='))); 1077 } 1078 1079 /* 1080 * Make the exported environment from the exported names in the dictionary. 1081 */ 1082 char ** 1083 makenv(void) 1084 { 1085 ssize_t i; 1086 struct block *l; 1087 XPtrV denv; 1088 struct tbl *vp, **vpp; 1089 1090 XPinit(denv, 64); 1091 for (l = e->loc; l != NULL; l = l->next) { 1092 vpp = l->vars.tbls; 1093 i = 1 << (l->vars.tshift); 1094 while (--i >= 0) 1095 if ((vp = *vpp++) != NULL && 1096 (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 1097 struct block *l2; 1098 struct tbl *vp2; 1099 uint32_t h = hash(vp->name); 1100 1101 /* unexport any redefined instances */ 1102 for (l2 = l->next; l2 != NULL; l2 = l2->next) { 1103 vp2 = ktsearch(&l2->vars, vp->name, h); 1104 if (vp2 != NULL) 1105 vp2->flag &= ~EXPORT; 1106 } 1107 if ((vp->flag&INTEGER)) { 1108 /* integer to string */ 1109 char *val; 1110 val = str_val(vp); 1111 vp->flag &= ~(INTEGER|RDONLY|SPECIAL); 1112 /* setstr can't fail here */ 1113 setstr(vp, val, KSH_RETURN_ERROR); 1114 } 1115 XPput(denv, vp->val.s); 1116 } 1117 } 1118 XPput(denv, NULL); 1119 return ((char **)XPclose(denv)); 1120 } 1121 1122 /* 1123 * handle special variables with side effects - PATH, SECONDS. 1124 */ 1125 1126 /* Test if name is a special parameter */ 1127 static int 1128 special(const char *name) 1129 { 1130 struct tbl *tp; 1131 1132 tp = ktsearch(&specials, name, hash(name)); 1133 return (tp && (tp->flag & ISSET) ? tp->type : V_NONE); 1134 } 1135 1136 /* Make a variable non-special */ 1137 static void 1138 unspecial(const char *name) 1139 { 1140 struct tbl *tp; 1141 1142 tp = ktsearch(&specials, name, hash(name)); 1143 if (tp) 1144 ktdelete(tp); 1145 } 1146 1147 static time_t seconds; /* time SECONDS last set */ 1148 static int user_lineno; /* what user set $LINENO to */ 1149 1150 static void 1151 getspec(struct tbl *vp) 1152 { 1153 mksh_ari_u num; 1154 int st; 1155 struct timeval tv; 1156 1157 switch ((st = special(vp->name))) { 1158 case V_COLUMNS: 1159 case V_LINES: 1160 /* 1161 * Do NOT export COLUMNS/LINES. Many applications 1162 * check COLUMNS/LINES before checking ws.ws_col/row, 1163 * so if the app is started with C/L in the environ 1164 * and the window is then resized, the app won't 1165 * see the change cause the environ doesn't change. 1166 */ 1167 if (got_winch) 1168 change_winsz(); 1169 break; 1170 } 1171 switch (st) { 1172 case V_BASHPID: 1173 num.u = (mksh_uari_t)procpid; 1174 break; 1175 case V_COLUMNS: 1176 num.i = x_cols; 1177 break; 1178 case V_HISTSIZE: 1179 num.i = histsize; 1180 break; 1181 case V_LINENO: 1182 num.i = current_lineno + user_lineno; 1183 break; 1184 case V_LINES: 1185 num.i = x_lins; 1186 break; 1187 case V_EPOCHREALTIME: { 1188 /* 10(%u) + 1(.) + 6 + NUL */ 1189 char buf[18]; 1190 1191 vp->flag &= ~SPECIAL; 1192 mksh_TIME(tv); 1193 shf_snprintf(buf, sizeof(buf), "%u.%06u", 1194 (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); 1195 setstr(vp, buf, KSH_RETURN_ERROR | 0x4); 1196 vp->flag |= SPECIAL; 1197 return; 1198 } 1199 case V_OPTIND: 1200 num.i = user_opt.uoptind; 1201 break; 1202 case V_RANDOM: 1203 num.i = rndget(); 1204 break; 1205 case V_SECONDS: 1206 /* 1207 * On start up the value of SECONDS is used before 1208 * it has been set - don't do anything in this case 1209 * (see initcoms[] in main.c). 1210 */ 1211 if (vp->flag & ISSET) { 1212 mksh_TIME(tv); 1213 num.i = tv.tv_sec - seconds; 1214 } else 1215 return; 1216 break; 1217 default: 1218 /* do nothing, do not touch vp at all */ 1219 return; 1220 } 1221 vp->flag &= ~SPECIAL; 1222 setint_n(vp, num.i, 0); 1223 vp->flag |= SPECIAL; 1224 } 1225 1226 static void 1227 setspec(struct tbl *vp) 1228 { 1229 mksh_ari_u num; 1230 char *s; 1231 int st; 1232 1233 switch ((st = special(vp->name))) { 1234 #if HAVE_PERSISTENT_HISTORY 1235 case V_HISTFILE: 1236 sethistfile(str_val(vp)); 1237 return; 1238 #endif 1239 case V_IFS: 1240 setctypes(s = str_val(vp), C_IFS); 1241 ifs0 = *s; 1242 return; 1243 case V_PATH: 1244 if (path) 1245 afree(path, APERM); 1246 s = str_val(vp); 1247 strdupx(path, s, APERM); 1248 /* clear tracked aliases */ 1249 flushcom(true); 1250 return; 1251 case V_TMPDIR: 1252 if (tmpdir) { 1253 afree(tmpdir, APERM); 1254 tmpdir = NULL; 1255 } 1256 /* 1257 * Use tmpdir iff it is an absolute path, is writable 1258 * and searchable and is a directory... 1259 */ 1260 { 1261 struct stat statb; 1262 1263 s = str_val(vp); 1264 /* LINTED use of access */ 1265 if (s[0] == '/' && access(s, W_OK|X_OK) == 0 && 1266 stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 1267 strdupx(tmpdir, s, APERM); 1268 } 1269 return; 1270 /* common sub-cases */ 1271 case V_COLUMNS: 1272 case V_LINES: 1273 if (vp->flag & IMPORT) { 1274 /* do not touch */ 1275 unspecial(vp->name); 1276 vp->flag &= ~SPECIAL; 1277 return; 1278 } 1279 /* FALLTHROUGH */ 1280 case V_HISTSIZE: 1281 case V_LINENO: 1282 case V_OPTIND: 1283 case V_RANDOM: 1284 case V_SECONDS: 1285 case V_TMOUT: 1286 vp->flag &= ~SPECIAL; 1287 if (getint(vp, &num, false) == -1) { 1288 s = str_val(vp); 1289 if (st != V_RANDOM) 1290 errorf("%s: %s: %s", vp->name, "bad number", s); 1291 num.u = hash(s); 1292 } 1293 vp->flag |= SPECIAL; 1294 break; 1295 default: 1296 /* do nothing, do not touch vp at all */ 1297 return; 1298 } 1299 1300 /* process the singular parts of the common cases */ 1301 1302 switch (st) { 1303 case V_COLUMNS: 1304 if (num.i >= MIN_COLS) 1305 x_cols = num.i; 1306 break; 1307 case V_HISTSIZE: 1308 sethistsize(num.i); 1309 break; 1310 case V_LINENO: 1311 /* The -1 is because line numbering starts at 1. */ 1312 user_lineno = num.u - current_lineno - 1; 1313 break; 1314 case V_LINES: 1315 if (num.i >= MIN_LINS) 1316 x_lins = num.i; 1317 break; 1318 case V_OPTIND: 1319 getopts_reset((int)num.i); 1320 break; 1321 case V_RANDOM: 1322 /* 1323 * mksh R39d+ no longer has the traditional repeatability 1324 * of $RANDOM sequences, but always retains state 1325 */ 1326 rndset((unsigned long)num.u); 1327 break; 1328 case V_SECONDS: 1329 { 1330 struct timeval tv; 1331 1332 mksh_TIME(tv); 1333 seconds = tv.tv_sec - num.i; 1334 } 1335 break; 1336 case V_TMOUT: 1337 ksh_tmout = num.i >= 0 ? num.i : 0; 1338 break; 1339 } 1340 } 1341 1342 static void 1343 unsetspec(struct tbl *vp) 1344 { 1345 /* 1346 * AT&T ksh man page says OPTIND, OPTARG and _ lose special 1347 * meaning, but OPTARG does not (still set by getopts) and _ is 1348 * also still set in various places. Don't know what AT&T does 1349 * for HISTSIZE, HISTFILE. Unsetting these in AT&T ksh does not 1350 * loose the 'specialness': IFS, COLUMNS, PATH, TMPDIR 1351 */ 1352 1353 switch (special(vp->name)) { 1354 case V_IFS: 1355 setctypes(TC_IFSWS, C_IFS); 1356 ifs0 = ' '; 1357 break; 1358 case V_PATH: 1359 if (path) 1360 afree(path, APERM); 1361 strdupx(path, def_path, APERM); 1362 /* clear tracked aliases */ 1363 flushcom(true); 1364 break; 1365 case V_TMPDIR: 1366 /* should not become unspecial */ 1367 if (tmpdir) { 1368 afree(tmpdir, APERM); 1369 tmpdir = NULL; 1370 } 1371 break; 1372 case V_LINENO: 1373 case V_RANDOM: 1374 case V_SECONDS: 1375 case V_TMOUT: 1376 /* AT&T ksh leaves previous value in place */ 1377 unspecial(vp->name); 1378 break; 1379 } 1380 } 1381 1382 /* 1383 * Search for (and possibly create) a table entry starting with 1384 * vp, indexed by val. 1385 */ 1386 struct tbl * 1387 arraysearch(struct tbl *vp, uint32_t val) 1388 { 1389 struct tbl *prev, *curr, *news; 1390 size_t len; 1391 1392 vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC; 1393 /* the table entry is always [0] */ 1394 if (val == 0) 1395 return (vp); 1396 prev = vp; 1397 curr = vp->u.array; 1398 while (curr && curr->ua.index < val) { 1399 prev = curr; 1400 curr = curr->u.array; 1401 } 1402 if (curr && curr->ua.index == val) { 1403 if (curr->flag&ISSET) 1404 return (curr); 1405 news = curr; 1406 } else 1407 news = NULL; 1408 if (!news) { 1409 len = strlen(vp->name); 1410 checkoktoadd(len, 1 + offsetof(struct tbl, name[0])); 1411 news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap); 1412 memcpy(news->name, vp->name, len); 1413 } 1414 news->flag = (vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL)) | AINDEX; 1415 news->type = vp->type; 1416 news->areap = vp->areap; 1417 news->u2.field = vp->u2.field; 1418 news->ua.index = val; 1419 1420 if (curr != news) { 1421 /* not reusing old array entry */ 1422 prev->u.array = news; 1423 news->u.array = curr; 1424 } 1425 return (news); 1426 } 1427 1428 /* 1429 * Return the length of an array reference (eg, [1+2]) - cp is assumed 1430 * to point to the open bracket. Returns 0 if there is no matching 1431 * closing bracket. 1432 * 1433 * XXX this should parse the actual arithmetic syntax 1434 */ 1435 size_t 1436 array_ref_len(const char *cp) 1437 { 1438 const char *s = cp; 1439 char c; 1440 int depth = 0; 1441 1442 while ((c = *s++) && (c != ']' || --depth)) 1443 if (c == '[') 1444 depth++; 1445 if (!c) 1446 return (0); 1447 return (s - cp); 1448 } 1449 1450 /* 1451 * Make a copy of the base of an array name 1452 */ 1453 char * 1454 arrayname(const char *str) 1455 { 1456 const char *p; 1457 char *rv; 1458 1459 if ((p = cstrchr(str, '[')) == 0) 1460 /* Shouldn't happen, but why worry? */ 1461 strdupx(rv, str, ATEMP); 1462 else 1463 strndupx(rv, str, p - str, ATEMP); 1464 1465 return (rv); 1466 } 1467 1468 /* set (or overwrite, if reset) the array variable var to the values in vals */ 1469 mksh_uari_t 1470 set_array(const char *var, bool reset, const char **vals) 1471 { 1472 struct tbl *vp, *vq; 1473 mksh_uari_t i = 0, j = 0; 1474 const char *ccp = var; 1475 char *cp = NULL; 1476 size_t n; 1477 1478 /* to get local array, use "local foo; set -A foo" */ 1479 n = strlen(var); 1480 if (n > 0 && var[n - 1] == '+') { 1481 /* append mode */ 1482 reset = false; 1483 strndupx(cp, var, n - 1, ATEMP); 1484 ccp = cp; 1485 } 1486 vp = global(ccp); 1487 1488 /* Note: AT&T ksh allows set -A but not set +A of a read-only var */ 1489 if ((vp->flag&RDONLY)) 1490 errorfx(2, "read-only: %s", ccp); 1491 /* This code is quite non-optimal */ 1492 if (reset) { 1493 /* trash existing values and attributes */ 1494 unset(vp, 1); 1495 /* allocate-by-access the [0] element to keep in scope */ 1496 arraysearch(vp, 0); 1497 } 1498 /* 1499 * TODO: would be nice for assignment to completely succeed or 1500 * completely fail. Only really effects integer arrays: 1501 * evaluation of some of vals[] may fail... 1502 */ 1503 if (cp != NULL) { 1504 /* find out where to set when appending */ 1505 for (vq = vp; vq; vq = vq->u.array) { 1506 if (!(vq->flag & ISSET)) 1507 continue; 1508 if (arrayindex(vq) >= j) 1509 j = arrayindex(vq) + 1; 1510 } 1511 afree(cp, ATEMP); 1512 } 1513 while ((ccp = vals[i])) { 1514 #if 0 /* temporarily taken out due to regression */ 1515 if (*ccp == '[') { 1516 int level = 0; 1517 1518 while (*ccp) { 1519 if (*ccp == ']' && --level == 0) 1520 break; 1521 if (*ccp == '[') 1522 ++level; 1523 ++ccp; 1524 } 1525 if (*ccp == ']' && level == 0 && ccp[1] == '=') { 1526 strndupx(cp, vals[i] + 1, ccp - (vals[i] + 1), 1527 ATEMP); 1528 evaluate(substitute(cp, 0), (mksh_ari_t *)&j, 1529 KSH_UNWIND_ERROR, true); 1530 afree(cp, ATEMP); 1531 ccp += 2; 1532 } else 1533 ccp = vals[i]; 1534 } 1535 #endif 1536 1537 vq = arraysearch(vp, j); 1538 /* would be nice to deal with errors here... (see above) */ 1539 setstr(vq, ccp, KSH_RETURN_ERROR); 1540 i++; 1541 j++; 1542 } 1543 1544 return (i); 1545 } 1546 1547 void 1548 change_winsz(void) 1549 { 1550 struct timeval tv; 1551 1552 mksh_TIME(tv); 1553 BAFHUpdateMem_mem(qh_state, &tv, sizeof(tv)); 1554 1555 #ifdef TIOCGWINSZ 1556 /* check if window size has changed */ 1557 if (tty_init_fd() < 2) { 1558 struct winsize ws; 1559 1560 if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) { 1561 if (ws.ws_col) 1562 x_cols = ws.ws_col; 1563 if (ws.ws_row) 1564 x_lins = ws.ws_row; 1565 } 1566 } 1567 #endif 1568 1569 /* bounds check for sane values, use defaults otherwise */ 1570 if (x_cols < MIN_COLS) 1571 x_cols = 80; 1572 if (x_lins < MIN_LINS) 1573 x_lins = 24; 1574 1575 #ifdef SIGWINCH 1576 got_winch = 0; 1577 #endif 1578 } 1579 1580 uint32_t 1581 hash(const void *s) 1582 { 1583 register uint32_t h; 1584 1585 BAFHInit(h); 1586 BAFHUpdateStr_reg(h, s); 1587 BAFHFinish_reg(h); 1588 return (h); 1589 } 1590 1591 uint32_t 1592 chvt_rndsetup(const void *bp, size_t sz) 1593 { 1594 register uint32_t h; 1595 1596 /* use LCG as seed but try to get them to deviate immediately */ 1597 h = lcg_state; 1598 (void)rndget(); 1599 BAFHFinish_reg(h); 1600 /* variation through pid, ppid, and the works */ 1601 BAFHUpdateMem_reg(h, &rndsetupstate, sizeof(rndsetupstate)); 1602 /* some variation, some possibly entropy, depending on OE */ 1603 BAFHUpdateMem_reg(h, bp, sz); 1604 /* mix them all up */ 1605 BAFHFinish_reg(h); 1606 1607 return (h); 1608 } 1609 1610 mksh_ari_t 1611 rndget(void) 1612 { 1613 /* 1614 * this is the same Linear Congruential PRNG as Borland 1615 * C/C++ allegedly uses in its built-in rand() function 1616 */ 1617 return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF); 1618 } 1619 1620 void 1621 rndset(unsigned long v) 1622 { 1623 register uint32_t h; 1624 #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) 1625 register uint32_t t; 1626 #endif 1627 struct { 1628 struct timeval tv; 1629 void *sp; 1630 uint32_t qh; 1631 pid_t pp; 1632 short r; 1633 } z; 1634 1635 #ifdef DEBUG 1636 /* clear the allocated space, for valgrind */ 1637 memset(&z, 0, sizeof(z)); 1638 #endif 1639 1640 h = lcg_state; 1641 BAFHFinish_reg(h); 1642 BAFHUpdateMem_reg(h, &v, sizeof(v)); 1643 1644 mksh_TIME(z.tv); 1645 z.sp = &lcg_state; 1646 z.pp = procpid; 1647 z.r = (short)rndget(); 1648 1649 #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) 1650 t = qh_state; 1651 BAFHFinish_reg(t); 1652 z.qh = (t & 0xFFFF8000) | rndget(); 1653 lcg_state = (t << 15) | rndget(); 1654 /* 1655 * either we have very chap entropy get and push available, 1656 * with malloc() pulling in this code already anyway, or the 1657 * user requested us to use the old functions 1658 */ 1659 t = h; 1660 BAFHUpdateMem_reg(t, &lcg_state, sizeof(lcg_state)); 1661 BAFHFinish_reg(t); 1662 lcg_state = t; 1663 #if defined(arc4random_pushb_fast) 1664 arc4random_pushb_fast(&lcg_state, sizeof(lcg_state)); 1665 lcg_state = arc4random(); 1666 #else 1667 lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state)); 1668 #endif 1669 BAFHUpdateMem_reg(h, &lcg_state, sizeof(lcg_state)); 1670 #else 1671 z.qh = qh_state; 1672 #endif 1673 1674 BAFHUpdateMem_reg(h, &z, sizeof(z)); 1675 BAFHFinish_reg(h); 1676 lcg_state = h; 1677 } 1678 1679 void 1680 rndpush(const void *s) 1681 { 1682 register uint32_t h = qh_state; 1683 1684 BAFHUpdateStr_reg(h, s); 1685 BAFHUpdateOctet_reg(h, 0); 1686 qh_state = h; 1687 } 1688