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