1 /* $OpenBSD: var.c,v 1.73 2023/07/23 23:42:03 kn Exp $ */ 2 3 #include <sys/stat.h> 4 #include <sys/time.h> 5 6 #include <ctype.h> 7 #include <errno.h> 8 #include <inttypes.h> 9 #include <limits.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <time.h> 13 #include <unistd.h> 14 #ifndef SMALL 15 # include <term.h> 16 # include <curses.h> 17 #endif 18 19 #include "sh.h" 20 21 /* 22 * Variables 23 * 24 * WARNING: unreadable code, needs a rewrite 25 * 26 * if (flag&INTEGER), val.i contains integer value, and type contains base. 27 * otherwise, (val.s + type) contains string value. 28 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. 29 */ 30 static struct tbl vtemp; 31 static struct table specials; 32 static char *formatstr(struct tbl *, const char *); 33 static void export(struct tbl *, const char *); 34 static int special(const char *); 35 static void unspecial(const char *); 36 static void getspec(struct tbl *); 37 static void setspec(struct tbl *); 38 static void unsetspec(struct tbl *); 39 static struct tbl *arraysearch(struct tbl *, int); 40 41 /* 42 * create a new block for function calls and simple commands 43 * assume caller has allocated and set up genv->loc 44 */ 45 void 46 newblock(void) 47 { 48 struct block *l; 49 static char *const empty[] = {null}; 50 51 l = alloc(sizeof(struct block), ATEMP); 52 l->flags = 0; 53 ainit(&l->area); /* todo: could use genv->area (l->area => l->areap) */ 54 if (!genv->loc) { 55 l->argc = 0; 56 l->argv = (char **) empty; 57 } else { 58 l->argc = genv->loc->argc; 59 l->argv = genv->loc->argv; 60 } 61 l->exit = l->error = NULL; 62 ktinit(&l->vars, &l->area, 0); 63 ktinit(&l->funs, &l->area, 0); 64 l->next = genv->loc; 65 genv->loc = l; 66 } 67 68 /* 69 * pop a block handling special variables 70 */ 71 void 72 popblock(void) 73 { 74 struct block *l = genv->loc; 75 struct tbl *vp, **vpp = l->vars.tbls, *vq; 76 int i; 77 78 genv->loc = l->next; /* pop block */ 79 for (i = l->vars.size; --i >= 0; ) 80 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) { 81 if ((vq = global(vp->name))->flag & ISSET) 82 setspec(vq); 83 else 84 unsetspec(vq); 85 } 86 if (l->flags & BF_DOGETOPTS) 87 user_opt = l->getopts_state; 88 afreeall(&l->area); 89 afree(l, ATEMP); 90 } 91 92 /* called by main() to initialize variable data structures */ 93 void 94 initvar(void) 95 { 96 static const struct { 97 const char *name; 98 int v; 99 } names[] = { 100 { "COLUMNS", V_COLUMNS }, 101 { "IFS", V_IFS }, 102 { "OPTIND", V_OPTIND }, 103 { "PATH", V_PATH }, 104 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT }, 105 { "TMPDIR", V_TMPDIR }, 106 { "HISTCONTROL", V_HISTCONTROL }, 107 { "HISTFILE", V_HISTFILE }, 108 { "HISTSIZE", V_HISTSIZE }, 109 { "EDITOR", V_EDITOR }, 110 { "VISUAL", V_VISUAL }, 111 #ifndef SMALL 112 { "MAIL", V_MAIL }, 113 { "MAILCHECK", V_MAILCHECK }, 114 { "MAILPATH", V_MAILPATH }, 115 #endif /* SMALL */ 116 { "RANDOM", V_RANDOM }, 117 { "SECONDS", V_SECONDS }, 118 { "TMOUT", V_TMOUT }, 119 { "LINENO", V_LINENO }, 120 { "TERM", V_TERM }, 121 { NULL, 0 } 122 }; 123 int i; 124 struct tbl *tp; 125 126 ktinit(&specials, APERM, 32); /* must be 2^n (currently 19 specials) */ 127 for (i = 0; names[i].name; i++) { 128 tp = ktenter(&specials, names[i].name, hash(names[i].name)); 129 tp->flag = DEFINED|ISSET; 130 tp->type = names[i].v; 131 } 132 } 133 134 /* Used to calculate an array index for global()/local(). Sets *arrayp to 135 * non-zero if this is an array, sets *valp to the array index, returns 136 * the basename of the array. 137 */ 138 static const char * 139 array_index_calc(const char *n, bool *arrayp, int *valp) 140 { 141 const char *p; 142 int len; 143 144 *arrayp = false; 145 p = skip_varname(n, false); 146 if (p != n && *p == '[' && (len = array_ref_len(p))) { 147 char *sub, *tmp; 148 int64_t rval; 149 150 /* Calculate the value of the subscript */ 151 *arrayp = true; 152 tmp = str_nsave(p+1, len-2, ATEMP); 153 sub = substitute(tmp, 0); 154 afree(tmp, ATEMP); 155 n = str_nsave(n, p - n, ATEMP); 156 evaluate(sub, &rval, KSH_UNWIND_ERROR, true); 157 if (rval < 0 || rval > INT_MAX) 158 errorf("%s: subscript %" PRIi64 " out of range", 159 n, rval); 160 *valp = rval; 161 afree(sub, ATEMP); 162 } 163 return n; 164 } 165 166 /* 167 * Search for variable, if not found create globally. 168 */ 169 struct tbl * 170 global(const char *n) 171 { 172 struct block *l = genv->loc; 173 struct tbl *vp; 174 long num; 175 int c; 176 unsigned int h; 177 bool array; 178 int val; 179 180 /* Check to see if this is an array */ 181 n = array_index_calc(n, &array, &val); 182 h = hash(n); 183 c = (unsigned char)n[0]; 184 if (!letter(c)) { 185 if (array) 186 errorf("bad substitution"); 187 vp = &vtemp; 188 vp->flag = DEFINED; 189 vp->type = 0; 190 vp->areap = ATEMP; 191 *vp->name = c; 192 if (digit(c)) { 193 errno = 0; 194 num = strtol(n, NULL, 10); 195 if (errno == 0 && num <= l->argc) 196 /* setstr can't fail here */ 197 setstr(vp, l->argv[num], KSH_RETURN_ERROR); 198 vp->flag |= RDONLY; 199 return vp; 200 } 201 vp->flag |= RDONLY; 202 if (n[1] != '\0') 203 return vp; 204 vp->flag |= ISSET|INTEGER; 205 switch (c) { 206 case '$': 207 vp->val.i = kshpid; 208 break; 209 case '!': 210 /* If no job, expand to nothing */ 211 if ((vp->val.i = j_async()) == 0) 212 vp->flag &= ~(ISSET|INTEGER); 213 break; 214 case '?': 215 vp->val.i = exstat; 216 break; 217 case '#': 218 vp->val.i = l->argc; 219 break; 220 case '-': 221 vp->flag &= ~INTEGER; 222 vp->val.s = getoptions(); 223 break; 224 default: 225 vp->flag &= ~(ISSET|INTEGER); 226 } 227 return vp; 228 } 229 for (l = genv->loc; ; l = l->next) { 230 vp = ktsearch(&l->vars, n, h); 231 if (vp != NULL) { 232 if (array) 233 return arraysearch(vp, val); 234 else 235 return vp; 236 } 237 if (l->next == NULL) 238 break; 239 } 240 vp = ktenter(&l->vars, n, h); 241 if (array) 242 vp = arraysearch(vp, val); 243 vp->flag |= DEFINED; 244 if (special(n)) 245 vp->flag |= SPECIAL; 246 return vp; 247 } 248 249 /* 250 * Search for local variable, if not found create locally. 251 */ 252 struct tbl * 253 local(const char *n, bool copy) 254 { 255 struct block *l = genv->loc; 256 struct tbl *vp; 257 unsigned int h; 258 bool array; 259 int val; 260 261 /* Check to see if this is an array */ 262 n = array_index_calc(n, &array, &val); 263 h = hash(n); 264 if (!letter(*n)) { 265 vp = &vtemp; 266 vp->flag = DEFINED|RDONLY; 267 vp->type = 0; 268 vp->areap = ATEMP; 269 return vp; 270 } 271 vp = ktenter(&l->vars, n, h); 272 if (copy && !(vp->flag & DEFINED)) { 273 struct block *ll = l; 274 struct tbl *vq = NULL; 275 276 while ((ll = ll->next) && !(vq = ktsearch(&ll->vars, n, h))) 277 ; 278 if (vq) { 279 vp->flag |= vq->flag & 280 (EXPORT | INTEGER | RDONLY | LJUST | RJUST | 281 ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); 282 if (vq->flag & INTEGER) 283 vp->type = vq->type; 284 vp->u2.field = vq->u2.field; 285 } 286 } 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 /* get variable string value */ 296 char * 297 str_val(struct tbl *vp) 298 { 299 char *s; 300 301 if ((vp->flag&SPECIAL)) 302 getspec(vp); 303 if (!(vp->flag&ISSET)) 304 s = null; /* special to dollar() */ 305 else if (!(vp->flag&INTEGER)) /* string source */ 306 s = vp->val.s + vp->type; 307 else { /* integer source */ 308 /* worst case number length is when base=2, so use 309 * minus base # number BITS(int64_t) NUL */ 310 char strbuf[1 + 2 + 1 + BITS(int64_t) + 1]; 311 const char *digits = (vp->flag & UCASEV_AL) ? 312 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : 313 "0123456789abcdefghijklmnopqrstuvwxyz"; 314 uint64_t n; 315 unsigned int base; 316 317 s = strbuf + sizeof(strbuf); 318 if (vp->flag & INT_U) 319 n = (uint64_t) vp->val.i; 320 else 321 n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; 322 base = (vp->type == 0) ? 10 : vp->type; 323 if (base < 2 || base > strlen(digits)) 324 base = 10; 325 326 *--s = '\0'; 327 do { 328 *--s = digits[n % base]; 329 n /= base; 330 } while (n != 0); 331 if (base != 10) { 332 *--s = '#'; 333 *--s = digits[base % 10]; 334 if (base >= 10) 335 *--s = digits[base / 10]; 336 } 337 if (!(vp->flag & INT_U) && vp->val.i < 0) 338 *--s = '-'; 339 if (vp->flag & (RJUST|LJUST)) /* case already dealt with */ 340 s = formatstr(vp, s); 341 else 342 s = str_save(s, ATEMP); 343 } 344 return s; 345 } 346 347 /* get variable integer value, with error checking */ 348 int64_t 349 intval(struct tbl *vp) 350 { 351 int64_t num; 352 int base; 353 354 base = getint(vp, &num, false); 355 if (base == -1) 356 /* XXX check calls - is error here ok by POSIX? */ 357 errorf("%s: bad number", str_val(vp)); 358 return num; 359 } 360 361 /* set variable to string value */ 362 int 363 setstr(struct tbl *vq, const char *s, int error_ok) 364 { 365 const char *fs = NULL; 366 int no_ro_check = error_ok & KSH_IGNORE_RDONLY; 367 error_ok &= ~KSH_IGNORE_RDONLY; 368 if ((vq->flag & RDONLY) && !no_ro_check) { 369 warningf(true, "%s: is read only", vq->name); 370 if (!error_ok) 371 errorf(NULL); 372 return 0; 373 } 374 if (!(vq->flag&INTEGER)) { /* string dest */ 375 if ((vq->flag&ALLOC)) { 376 /* debugging */ 377 if (s >= vq->val.s && 378 s <= vq->val.s + strlen(vq->val.s)) 379 internal_errorf("%s: %s=%s: assigning to self", 380 __func__, vq->name, s); 381 afree(vq->val.s, vq->areap); 382 } 383 vq->flag &= ~(ISSET|ALLOC); 384 vq->type = 0; 385 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) 386 fs = s = formatstr(vq, s); 387 if ((vq->flag&EXPORT)) 388 export(vq, s); 389 else { 390 vq->val.s = str_save(s, vq->areap); 391 vq->flag |= ALLOC; 392 } 393 } else { /* integer dest */ 394 if (!v_evaluate(vq, s, error_ok, true)) 395 return 0; 396 } 397 vq->flag |= ISSET; 398 if ((vq->flag&SPECIAL)) 399 setspec(vq); 400 afree((void *)fs, ATEMP); 401 return 1; 402 } 403 404 /* set variable to integer */ 405 void 406 setint(struct tbl *vq, int64_t n) 407 { 408 if (!(vq->flag&INTEGER)) { 409 struct tbl *vp = &vtemp; 410 vp->flag = (ISSET|INTEGER); 411 vp->type = 0; 412 vp->areap = ATEMP; 413 vp->val.i = n; 414 /* setstr can't fail here */ 415 setstr(vq, str_val(vp), KSH_RETURN_ERROR); 416 } else 417 vq->val.i = n; 418 vq->flag |= ISSET; 419 if ((vq->flag&SPECIAL)) 420 setspec(vq); 421 } 422 423 int 424 getint(struct tbl *vp, int64_t *nump, bool arith) 425 { 426 char *s; 427 int c; 428 int base, neg; 429 int have_base = 0; 430 int64_t num; 431 432 if (vp->flag&SPECIAL) 433 getspec(vp); 434 /* XXX is it possible for ISSET to be set and val.s to be 0? */ 435 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 436 return -1; 437 if (vp->flag&INTEGER) { 438 *nump = vp->val.i; 439 return vp->type; 440 } 441 s = vp->val.s + vp->type; 442 if (s == NULL) /* redundant given initial test */ 443 s = null; 444 base = 10; 445 num = 0; 446 neg = 0; 447 if (arith && *s == '0' && *(s+1)) { 448 s++; 449 if (*s == 'x' || *s == 'X') { 450 s++; 451 base = 16; 452 } else if (vp->flag & ZEROFIL) { 453 while (*s == '0') 454 s++; 455 } else 456 base = 8; 457 have_base++; 458 } 459 for (c = (unsigned char)*s++; c ; c = (unsigned char)*s++) { 460 if (c == '-') { 461 neg++; 462 } else if (c == '#') { 463 base = (int) num; 464 if (have_base || base < 2 || base > 36) 465 return -1; 466 num = 0; 467 have_base = 1; 468 } else if (letnum(c)) { 469 if (isdigit(c)) 470 c -= '0'; 471 else if (islower(c)) 472 c -= 'a' - 10; /* todo: assumes ascii */ 473 else if (isupper(c)) 474 c -= 'A' - 10; /* todo: assumes ascii */ 475 else 476 c = -1; /* _: force error */ 477 if (c < 0 || c >= base) 478 return -1; 479 num = num * base + c; 480 } else 481 return -1; 482 } 483 if (neg) 484 num = -num; 485 *nump = num; 486 return base; 487 } 488 489 /* convert variable vq to integer variable, setting its value from vp 490 * (vq and vp may be the same) 491 */ 492 struct tbl * 493 setint_v(struct tbl *vq, struct tbl *vp, bool arith) 494 { 495 int base; 496 int64_t num; 497 498 if ((base = getint(vp, &num, arith)) == -1) 499 return NULL; 500 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 501 vq->flag &= ~ALLOC; 502 afree(vq->val.s, vq->areap); 503 } 504 vq->val.i = num; 505 if (vq->type == 0) /* default base */ 506 vq->type = base; 507 vq->flag |= ISSET|INTEGER; 508 if (vq->flag&SPECIAL) 509 setspec(vq); 510 return vq; 511 } 512 513 static char * 514 formatstr(struct tbl *vp, const char *s) 515 { 516 int olen, nlen; 517 char *p, *q; 518 519 olen = strlen(s); 520 521 if (vp->flag & (RJUST|LJUST)) { 522 if (!vp->u2.field) /* default field width */ 523 vp->u2.field = olen; 524 nlen = vp->u2.field; 525 } else 526 nlen = olen; 527 528 p = alloc(nlen + 1, ATEMP); 529 if (vp->flag & (RJUST|LJUST)) { 530 int slen; 531 532 if (vp->flag & RJUST) { 533 const char *r = s + olen; 534 /* strip trailing spaces (at&t ksh uses r[-1] == ' ') */ 535 while (r > s && isspace((unsigned char)r[-1])) 536 --r; 537 slen = r - s; 538 if (slen > vp->u2.field) { 539 s += slen - vp->u2.field; 540 slen = vp->u2.field; 541 } 542 shf_snprintf(p, nlen + 1, 543 ((vp->flag & ZEROFIL) && digit(*s)) ? 544 "%0*s%.*s" : "%*s%.*s", 545 vp->u2.field - slen, null, slen, s); 546 } else { 547 /* strip leading spaces/zeros */ 548 while (isspace((unsigned char)*s)) 549 s++; 550 if (vp->flag & ZEROFIL) 551 while (*s == '0') 552 s++; 553 shf_snprintf(p, nlen + 1, "%-*.*s", 554 vp->u2.field, vp->u2.field, s); 555 } 556 } else 557 memcpy(p, s, olen + 1); 558 559 if (vp->flag & UCASEV_AL) { 560 for (q = p; *q; q++) 561 if (islower((unsigned char)*q)) 562 *q = toupper((unsigned char)*q); 563 } else if (vp->flag & LCASEV) { 564 for (q = p; *q; q++) 565 if (isupper((unsigned char)*q)) 566 *q = tolower((unsigned char)*q); 567 } 568 569 return p; 570 } 571 572 /* 573 * make vp->val.s be "name=value" for quick exporting. 574 */ 575 static void 576 export(struct tbl *vp, const char *val) 577 { 578 char *xp; 579 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 580 int namelen = strlen(vp->name); 581 int vallen = strlen(val) + 1; 582 583 vp->flag |= ALLOC; 584 xp = alloc(namelen + 1 + vallen, vp->areap); 585 memcpy(vp->val.s = xp, vp->name, namelen); 586 xp += namelen; 587 *xp++ = '='; 588 vp->type = xp - vp->val.s; /* offset to value */ 589 memcpy(xp, val, vallen); 590 afree(op, vp->areap); 591 } 592 593 /* 594 * lookup variable (according to (set&LOCAL)), 595 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, 596 * LCASEV, UCASEV_AL), and optionally set its value if an assignment. 597 */ 598 struct tbl * 599 typeset(const char *var, int set, int clr, int field, int base) 600 { 601 struct tbl *vp; 602 struct tbl *vpbase, *t; 603 char *tvar; 604 const char *val; 605 606 /* check for valid variable name, search for value */ 607 val = skip_varname(var, false); 608 if (val == var) 609 return NULL; 610 if (*val == '[') { 611 int len; 612 613 len = array_ref_len(val); 614 if (len == 0) 615 return NULL; 616 /* IMPORT is only used when the shell starts up and is 617 * setting up its environment. Allow only simple array 618 * references at this time since parameter/command substitution 619 * is preformed on the [expression], which would be a major 620 * security hole. 621 */ 622 if (set & IMPORT) { 623 int i; 624 for (i = 1; i < len - 1; i++) 625 if (!digit(val[i])) 626 return NULL; 627 } 628 val += len; 629 } 630 if (*val == '=') 631 tvar = str_nsave(var, val++ - var, ATEMP); 632 else { 633 /* Importing from original environment: must have an = */ 634 if (set & IMPORT) 635 return NULL; 636 tvar = (char *) var; 637 val = NULL; 638 } 639 640 /* Prevent typeset from creating a local PATH/ENV/SHELL */ 641 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 || 642 strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) 643 errorf("%s: restricted", tvar); 644 645 vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? true : false) : 646 global(tvar); 647 set &= ~(LOCAL|LOCAL_COPY); 648 649 vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp; 650 651 /* only allow export flag to be set. at&t ksh allows any attribute to 652 * be changed, which means it can be truncated or modified 653 * (-L/-R/-Z/-i). 654 */ 655 if ((vpbase->flag&RDONLY) && 656 (val || clr || (set & ~EXPORT))) 657 /* XXX check calls - is error here ok by POSIX? */ 658 errorf("%s: is read only", tvar); 659 if (val) 660 afree(tvar, ATEMP); 661 662 /* most calls are with set/clr == 0 */ 663 if (set | clr) { 664 int ok = 1; 665 /* XXX if x[0] isn't set, there will be problems: need to have 666 * one copy of attributes for arrays... 667 */ 668 for (t = vpbase; t; t = t->u.array) { 669 int fake_assign; 670 int error_ok = KSH_RETURN_ERROR; 671 char *s = NULL; 672 char *free_me = NULL; 673 674 fake_assign = (t->flag & ISSET) && (!val || t != vp) && 675 ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) || 676 ((t->flag & INTEGER) && (clr & INTEGER)) || 677 (!(t->flag & INTEGER) && (set & INTEGER))); 678 if (fake_assign) { 679 if (t->flag & INTEGER) { 680 s = str_val(t); 681 free_me = NULL; 682 } else { 683 s = t->val.s + t->type; 684 free_me = (t->flag & ALLOC) ? t->val.s : 685 NULL; 686 } 687 t->flag &= ~ALLOC; 688 } 689 if (!(t->flag & INTEGER) && (set & INTEGER)) { 690 t->type = 0; 691 t->flag &= ~ALLOC; 692 } 693 if (!(t->flag & RDONLY) && (set & RDONLY)) { 694 /* allow var to be initialized read-only */ 695 error_ok |= KSH_IGNORE_RDONLY; 696 } 697 t->flag = (t->flag | set) & ~clr; 698 /* Don't change base if assignment is to be done, 699 * in case assignment fails. 700 */ 701 if ((set & INTEGER) && base > 0 && (!val || t != vp)) 702 t->type = base; 703 if (set & (LJUST|RJUST|ZEROFIL)) 704 t->u2.field = field; 705 if (fake_assign) { 706 if (!setstr(t, s, error_ok)) { 707 /* Somewhat arbitrary action here: 708 * zap contents of variable, but keep 709 * the flag settings. 710 */ 711 ok = 0; 712 if (t->flag & INTEGER) 713 t->flag &= ~ISSET; 714 else { 715 if (t->flag & ALLOC) 716 afree(t->val.s, t->areap); 717 t->flag &= ~(ISSET|ALLOC); 718 t->type = 0; 719 } 720 } 721 afree(free_me, t->areap); 722 } 723 } 724 if (!ok) 725 errorf(NULL); 726 } 727 728 if (val != NULL) { 729 if (vp->flag&INTEGER) { 730 /* do not zero base before assignment */ 731 setstr(vp, val, KSH_UNWIND_ERROR | KSH_IGNORE_RDONLY); 732 /* Done after assignment to override default */ 733 if (base > 0) 734 vp->type = base; 735 } else 736 /* setstr can't fail (readonly check already done) */ 737 setstr(vp, val, KSH_RETURN_ERROR | KSH_IGNORE_RDONLY); 738 } 739 740 /* only x[0] is ever exported, so use vpbase */ 741 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) && 742 vpbase->type == 0) 743 export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 744 745 return vp; 746 } 747 748 /* Unset a variable. array_ref is set if there was an array reference in 749 * the name lookup (eg, x[2]). 750 */ 751 void 752 unset(struct tbl *vp, int array_ref) 753 { 754 if (vp->flag & ALLOC) 755 afree(vp->val.s, vp->areap); 756 if ((vp->flag & ARRAY) && !array_ref) { 757 struct tbl *a, *tmp; 758 759 /* Free up entire array */ 760 for (a = vp->u.array; a; ) { 761 tmp = a; 762 a = a->u.array; 763 if (tmp->flag & ALLOC) 764 afree(tmp->val.s, tmp->areap); 765 afree(tmp, tmp->areap); 766 } 767 vp->u.array = NULL; 768 } 769 /* If foo[0] is being unset, the remainder of the array is kept... */ 770 vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0); 771 if (vp->flag & SPECIAL) 772 unsetspec(vp); /* responsible for `unspecial'ing var */ 773 } 774 775 /* return a pointer to the first char past a legal variable name (returns the 776 * argument if there is no legal name, returns * a pointer to the terminating 777 * null if whole string is legal). 778 */ 779 char * 780 skip_varname(const char *s, int aok) 781 { 782 int alen; 783 784 if (s && letter(*s)) { 785 while (*++s && letnum(*s)) 786 ; 787 if (aok && *s == '[' && (alen = array_ref_len(s))) 788 s += alen; 789 } 790 return (char *) s; 791 } 792 793 /* Return a pointer to the first character past any legal variable name. */ 794 char * 795 skip_wdvarname(const char *s, 796 int aok) /* skip array de-reference? */ 797 { 798 if (s[0] == CHAR && letter(s[1])) { 799 do { 800 s += 2; 801 } while (s[0] == CHAR && letnum(s[1])); 802 if (aok && s[0] == CHAR && s[1] == '[') { 803 /* skip possible array de-reference */ 804 const char *p = s; 805 char c; 806 int depth = 0; 807 808 while (1) { 809 if (p[0] != CHAR) 810 break; 811 c = p[1]; 812 p += 2; 813 if (c == '[') 814 depth++; 815 else if (c == ']' && --depth == 0) { 816 s = p; 817 break; 818 } 819 } 820 } 821 } 822 return (char *) s; 823 } 824 825 /* Check if coded string s is a variable name */ 826 int 827 is_wdvarname(const char *s, int aok) 828 { 829 char *p = skip_wdvarname(s, aok); 830 831 return p != s && p[0] == EOS; 832 } 833 834 /* Check if coded string s is a variable assignment */ 835 int 836 is_wdvarassign(const char *s) 837 { 838 char *p = skip_wdvarname(s, true); 839 840 return p != s && p[0] == CHAR && p[1] == '='; 841 } 842 843 /* 844 * Make the exported environment from the exported names in the dictionary. 845 */ 846 char ** 847 makenv(void) 848 { 849 struct block *l; 850 XPtrV env; 851 struct tbl *vp, **vpp; 852 int i; 853 854 XPinit(env, 64); 855 for (l = genv->loc; l != NULL; l = l->next) 856 for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) 857 if ((vp = *vpp++) != NULL && 858 (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 859 struct block *l2; 860 struct tbl *vp2; 861 unsigned int h = hash(vp->name); 862 863 /* unexport any redefined instances */ 864 for (l2 = l->next; l2 != NULL; l2 = l2->next) { 865 vp2 = ktsearch(&l2->vars, vp->name, h); 866 if (vp2 != NULL) 867 vp2->flag &= ~EXPORT; 868 } 869 if ((vp->flag&INTEGER)) { 870 /* integer to string */ 871 char *val; 872 val = str_val(vp); 873 vp->flag &= ~(INTEGER|RDONLY); 874 /* setstr can't fail here */ 875 setstr(vp, val, KSH_RETURN_ERROR); 876 } 877 XPput(env, vp->val.s); 878 } 879 XPput(env, NULL); 880 return (char **) XPclose(env); 881 } 882 883 /* 884 * Called after a fork in parent to bump the random number generator. 885 * Done to ensure children will not get the same random number sequence 886 * if the parent doesn't use $RANDOM. 887 */ 888 void 889 change_random(void) 890 { 891 rand(); 892 } 893 894 /* 895 * handle special variables with side effects - PATH, SECONDS. 896 */ 897 898 /* Test if name is a special parameter */ 899 static int 900 special(const char *name) 901 { 902 struct tbl *tp; 903 904 tp = ktsearch(&specials, name, hash(name)); 905 return tp && (tp->flag & ISSET) ? tp->type : V_NONE; 906 } 907 908 /* Make a variable non-special */ 909 static void 910 unspecial(const char *name) 911 { 912 struct tbl *tp; 913 914 tp = ktsearch(&specials, name, hash(name)); 915 if (tp) 916 ktdelete(tp); 917 } 918 919 static struct timespec seconds; /* time SECONDS last set */ 920 static int user_lineno; /* what user set $LINENO to */ 921 922 static void 923 getspec(struct tbl *vp) 924 { 925 switch (special(vp->name)) { 926 case V_SECONDS: 927 vp->flag &= ~SPECIAL; 928 /* On start up the value of SECONDS is used before seconds 929 * has been set - don't do anything in this case 930 * (see initcoms[] in main.c). 931 */ 932 if (vp->flag & ISSET) { 933 struct timespec difference, now; 934 935 clock_gettime(CLOCK_MONOTONIC, &now); 936 timespecsub(&now, &seconds, &difference); 937 setint(vp, (int64_t)difference.tv_sec); 938 } 939 vp->flag |= SPECIAL; 940 break; 941 case V_RANDOM: 942 vp->flag &= ~SPECIAL; 943 setint(vp, (int64_t) (rand() & 0x7fff)); 944 vp->flag |= SPECIAL; 945 break; 946 case V_HISTSIZE: 947 vp->flag &= ~SPECIAL; 948 setint(vp, (int64_t) histsize); 949 vp->flag |= SPECIAL; 950 break; 951 case V_OPTIND: 952 vp->flag &= ~SPECIAL; 953 setint(vp, (int64_t) user_opt.uoptind); 954 vp->flag |= SPECIAL; 955 break; 956 case V_LINENO: 957 vp->flag &= ~SPECIAL; 958 setint(vp, (int64_t) current_lineno + user_lineno); 959 vp->flag |= SPECIAL; 960 break; 961 } 962 } 963 964 static void 965 setspec(struct tbl *vp) 966 { 967 char *s; 968 969 switch (special(vp->name)) { 970 case V_PATH: 971 afree(search_path, APERM); 972 search_path = str_save(str_val(vp), APERM); 973 flushcom(1); /* clear tracked aliases */ 974 break; 975 case V_IFS: 976 setctypes(s = str_val(vp), C_IFS); 977 ifs0 = *s; 978 break; 979 case V_OPTIND: 980 vp->flag &= ~SPECIAL; 981 getopts_reset((int) intval(vp)); 982 vp->flag |= SPECIAL; 983 break; 984 case V_POSIXLY_CORRECT: 985 change_flag(FPOSIX, OF_SPECIAL, 1); 986 break; 987 case V_TMPDIR: 988 afree(tmpdir, APERM); 989 tmpdir = NULL; 990 /* Use tmpdir iff it is an absolute path, is writable and 991 * searchable and is a directory... 992 */ 993 { 994 struct stat statb; 995 996 s = str_val(vp); 997 if (s[0] == '/' && access(s, W_OK|X_OK) == 0 && 998 stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 999 tmpdir = str_save(s, APERM); 1000 } 1001 break; 1002 case V_HISTCONTROL: 1003 sethistcontrol(str_val(vp)); 1004 break; 1005 case V_HISTSIZE: 1006 vp->flag &= ~SPECIAL; 1007 sethistsize((int) intval(vp)); 1008 vp->flag |= SPECIAL; 1009 break; 1010 case V_HISTFILE: 1011 sethistfile(str_val(vp)); 1012 break; 1013 case V_VISUAL: 1014 set_editmode(str_val(vp)); 1015 break; 1016 case V_EDITOR: 1017 if (!(global("VISUAL")->flag & ISSET)) 1018 set_editmode(str_val(vp)); 1019 break; 1020 case V_COLUMNS: 1021 { 1022 int64_t l; 1023 1024 if (getint(vp, &l, false) == -1) { 1025 x_cols = MIN_COLS; 1026 break; 1027 } 1028 if (l <= MIN_COLS || l > INT_MAX) 1029 x_cols = MIN_COLS; 1030 else 1031 x_cols = l; 1032 } 1033 break; 1034 #ifndef SMALL 1035 case V_MAIL: 1036 mbset(str_val(vp)); 1037 break; 1038 case V_MAILPATH: 1039 mpset(str_val(vp)); 1040 break; 1041 case V_MAILCHECK: 1042 vp->flag &= ~SPECIAL; 1043 mcset(intval(vp)); 1044 vp->flag |= SPECIAL; 1045 break; 1046 #endif /* SMALL */ 1047 case V_RANDOM: 1048 vp->flag &= ~SPECIAL; 1049 srand_deterministic((unsigned int)intval(vp)); 1050 vp->flag |= SPECIAL; 1051 break; 1052 case V_SECONDS: 1053 vp->flag &= ~SPECIAL; 1054 clock_gettime(CLOCK_MONOTONIC, &seconds); 1055 seconds.tv_sec -= intval(vp); 1056 vp->flag |= SPECIAL; 1057 break; 1058 case V_TMOUT: 1059 /* Enforce integer to avoid command execution from initcoms[] */ 1060 vp->flag &= ~SPECIAL; 1061 intval(vp); 1062 vp->flag |= SPECIAL; 1063 /* at&t ksh seems to do this (only listen if integer) */ 1064 if (vp->flag & INTEGER) 1065 ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; 1066 break; 1067 case V_LINENO: 1068 vp->flag &= ~SPECIAL; 1069 /* The -1 is because line numbering starts at 1. */ 1070 user_lineno = (unsigned int) intval(vp) - current_lineno - 1; 1071 vp->flag |= SPECIAL; 1072 break; 1073 case V_TERM: 1074 #ifndef SMALL 1075 { 1076 int ret; 1077 1078 vp->flag &= ~SPECIAL; 1079 if (setupterm(str_val(vp), shl_out->fd, &ret) == ERR) 1080 del_curterm(cur_term); 1081 vp->flag |= SPECIAL; 1082 } 1083 #endif 1084 break; 1085 } 1086 } 1087 1088 static void 1089 unsetspec(struct tbl *vp) 1090 { 1091 switch (special(vp->name)) { 1092 case V_PATH: 1093 afree(search_path, APERM); 1094 search_path = str_save(def_path, APERM); 1095 flushcom(1); /* clear tracked aliases */ 1096 break; 1097 case V_IFS: 1098 setctypes(" \t\n", C_IFS); 1099 ifs0 = ' '; 1100 break; 1101 case V_TMPDIR: 1102 /* should not become unspecial */ 1103 afree(tmpdir, APERM); 1104 tmpdir = NULL; 1105 break; 1106 #ifndef SMALL 1107 case V_MAIL: 1108 mbset(NULL); 1109 break; 1110 case V_MAILPATH: 1111 mpset(NULL); 1112 break; 1113 #endif /* SMALL */ 1114 case V_HISTCONTROL: 1115 sethistcontrol(NULL); 1116 break; 1117 case V_LINENO: 1118 #ifndef SMALL 1119 case V_MAILCHECK: /* at&t ksh leaves previous value in place */ 1120 #endif /* SMALL */ 1121 case V_RANDOM: 1122 case V_SECONDS: 1123 case V_TMOUT: /* at&t ksh leaves previous value in place */ 1124 unspecial(vp->name); 1125 break; 1126 1127 /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning, 1128 * but OPTARG does not (still set by getopts) and _ is also still 1129 * set in various places. 1130 * Don't know what at&t does for: 1131 * MAIL, MAILPATH, HISTSIZE, HISTFILE, 1132 * Unsetting these in at&t ksh does not loose the `specialness': 1133 * no effect: IFS, COLUMNS, PATH, TMPDIR, 1134 * VISUAL, EDITOR, 1135 * pdkshisms: no effect: 1136 * POSIXLY_CORRECT (use set +o posix instead) 1137 */ 1138 } 1139 } 1140 1141 /* 1142 * Search for (and possibly create) a table entry starting with 1143 * vp, indexed by val. 1144 */ 1145 static struct tbl * 1146 arraysearch(struct tbl *vp, int val) 1147 { 1148 struct tbl *prev, *curr, *new; 1149 size_t namelen = strlen(vp->name) + 1; 1150 1151 vp->flag |= ARRAY|DEFINED; 1152 vp->index = 0; 1153 /* The table entry is always [0] */ 1154 if (val == 0) 1155 return vp; 1156 prev = vp; 1157 curr = vp->u.array; 1158 while (curr && curr->index < val) { 1159 prev = curr; 1160 curr = curr->u.array; 1161 } 1162 if (curr && curr->index == val) { 1163 if (curr->flag&ISSET) 1164 return curr; 1165 else 1166 new = curr; 1167 } else 1168 new = alloc(sizeof(struct tbl) + namelen, 1169 vp->areap); 1170 strlcpy(new->name, vp->name, namelen); 1171 new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL); 1172 new->type = vp->type; 1173 new->areap = vp->areap; 1174 new->u2.field = vp->u2.field; 1175 new->index = val; 1176 if (curr != new) { /* not reusing old array entry */ 1177 prev->u.array = new; 1178 new->u.array = curr; 1179 } 1180 return new; 1181 } 1182 1183 /* Return the length of an array reference (eg, [1+2]) - cp is assumed 1184 * to point to the open bracket. Returns 0 if there is no matching closing 1185 * bracket. 1186 */ 1187 int 1188 array_ref_len(const char *cp) 1189 { 1190 const char *s = cp; 1191 int c; 1192 int depth = 0; 1193 1194 while ((c = *s++) && (c != ']' || --depth)) 1195 if (c == '[') 1196 depth++; 1197 if (!c) 1198 return 0; 1199 return s - cp; 1200 } 1201 1202 /* 1203 * Make a copy of the base of an array name 1204 */ 1205 char * 1206 arrayname(const char *str) 1207 { 1208 const char *p; 1209 1210 if ((p = strchr(str, '[')) == 0) 1211 /* Shouldn't happen, but why worry? */ 1212 return (char *) str; 1213 1214 return str_nsave(str, p - str, ATEMP); 1215 } 1216 1217 /* Set (or overwrite, if !reset) the array variable var to the values in vals. 1218 */ 1219 void 1220 set_array(const char *var, int reset, char **vals) 1221 { 1222 struct tbl *vp, *vq; 1223 int i; 1224 1225 /* to get local array, use "typeset foo; set -A foo" */ 1226 vp = global(var); 1227 1228 /* Note: at&t ksh allows set -A but not set +A of a read-only var */ 1229 if ((vp->flag&RDONLY)) 1230 errorf("%s: is read only", var); 1231 /* This code is quite non-optimal */ 1232 if (reset > 0) 1233 /* trash existing values and attributes */ 1234 unset(vp, 0); 1235 /* todo: would be nice for assignment to completely succeed or 1236 * completely fail. Only really effects integer arrays: 1237 * evaluation of some of vals[] may fail... 1238 */ 1239 for (i = 0; vals[i]; i++) { 1240 vq = arraysearch(vp, i); 1241 /* would be nice to deal with errors here... (see above) */ 1242 setstr(vq, vals[i], KSH_RETURN_ERROR); 1243 } 1244 } 1245