1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * UNIX shell 32 */ 33 34 #include "defs.h" 35 #include <stropts.h> 36 37 extern BOOL chkid(); 38 extern unsigned char *simple(); 39 extern int mailchk; 40 41 static void setname(unsigned char *, int); 42 static void set_builtins_path(); 43 static int patheq(); 44 static void namwalk(struct namnod *); 45 static void dolocale(); 46 47 struct namnod ps2nod = 48 { 49 (struct namnod *)NIL, 50 &acctnod, 51 (unsigned char *)ps2name 52 }; 53 struct namnod cdpnod = 54 { 55 (struct namnod *)NIL, 56 (struct namnod *)NIL, 57 (unsigned char *)cdpname 58 }; 59 struct namnod pathnod = 60 { 61 &mailpnod, 62 (struct namnod *)NIL, 63 (unsigned char *)pathname 64 }; 65 struct namnod ifsnod = 66 { 67 &homenod, 68 &mailnod, 69 (unsigned char *)ifsname 70 }; 71 struct namnod ps1nod = 72 { 73 &pathnod, 74 &ps2nod, 75 (unsigned char *)ps1name 76 }; 77 struct namnod homenod = 78 { 79 &cdpnod, 80 (struct namnod *)NIL, 81 (unsigned char *)homename 82 }; 83 struct namnod mailnod = 84 { 85 (struct namnod *)NIL, 86 (struct namnod *)NIL, 87 (unsigned char *)mailname 88 }; 89 struct namnod mchknod = 90 { 91 &ifsnod, 92 &ps1nod, 93 (unsigned char *)mchkname 94 }; 95 struct namnod acctnod = 96 { 97 (struct namnod *)NIL, 98 (struct namnod *)NIL, 99 (unsigned char *)acctname 100 }; 101 struct namnod mailpnod = 102 { 103 (struct namnod *)NIL, 104 (struct namnod *)NIL, 105 (unsigned char *)mailpname 106 }; 107 108 109 struct namnod *namep = &mchknod; 110 111 /* ======== variable and string handling ======== */ 112 113 int 114 syslook(unsigned char *w, struct sysnod syswds[], int n) 115 { 116 int low; 117 int high; 118 int mid; 119 int cond; 120 121 if (w == 0 || *w == 0) 122 return(0); 123 124 low = 0; 125 high = n - 1; 126 127 while (low <= high) 128 { 129 mid = (low + high) / 2; 130 131 if ((cond = cf(w, syswds[mid].sysnam)) < 0) 132 high = mid - 1; 133 else if (cond > 0) 134 low = mid + 1; 135 else 136 return(syswds[mid].sysval); 137 } 138 return(0); 139 } 140 141 void 142 setlist(struct argnod *arg, int xp) 143 { 144 if (flags & exportflg) 145 xp |= N_EXPORT; 146 147 while (arg) 148 { 149 unsigned char *s = mactrim(arg->argval); 150 setname(s, xp); 151 arg = arg->argnxt; 152 if (flags & execpr) 153 { 154 prs(s); 155 if (arg) 156 blank(); 157 else 158 newline(); 159 } 160 } 161 } 162 163 static void 164 setname(unsigned char *argi, int xp) /* does parameter assignments */ 165 { 166 unsigned char *argscan = argi; 167 struct namnod *n; 168 169 if (letter(*argscan)) 170 { 171 while (alphanum(*argscan)) 172 argscan++; 173 174 if (*argscan == '=') 175 { 176 *argscan = 0; /* make name a cohesive string */ 177 178 n = lookup(argi); 179 *argscan++ = '='; 180 attrib(n, xp); 181 if (xp & N_ENVNAM) 182 { 183 n->namenv = n->namval = argscan; 184 if (n == &pathnod) 185 set_builtins_path(); 186 } 187 else 188 assign(n, argscan); 189 190 dolocale(n->namid); 191 return; 192 } 193 } 194 } 195 196 void 197 replace(unsigned char **a, unsigned char *v) 198 { 199 free(*a); 200 *a = make(v); 201 } 202 203 void 204 dfault(struct namnod *n, unsigned char *v) 205 { 206 if (n->namval == 0) 207 assign(n, v); 208 } 209 210 void 211 assign(struct namnod *n, unsigned char *v) 212 { 213 if (n->namflg & N_RDONLY) 214 failed(n->namid, wtfailed); 215 216 #ifndef RES 217 218 else if (flags & rshflg) 219 { 220 if (n == &pathnod || eq(n->namid,"SHELL")) 221 failed(n->namid, restricted); 222 } 223 #endif 224 225 else if (n->namflg & N_FUNCTN) 226 { 227 func_unhash(n->namid); 228 freefunc(n); 229 230 n->namenv = 0; 231 n->namflg = N_DEFAULT; 232 } 233 234 if (n == &mchknod) 235 { 236 mailchk = stoi(v); 237 } 238 239 replace(&n->namval, v); 240 attrib(n, N_ENVCHG); 241 242 if (n == &pathnod) 243 { 244 zaphash(); 245 set_dotpath(); 246 set_builtins_path(); 247 return; 248 } 249 250 if (flags & prompt) 251 { 252 if ((n == &mailpnod) || (n == &mailnod && mailpnod.namflg == N_DEFAULT)) 253 setmail(n->namval); 254 } 255 } 256 257 static void 258 set_builtins_path() 259 { 260 unsigned char *path; 261 262 ucb_builtins = 0; 263 path = getpath(""); 264 while (path && *path) 265 { 266 if (patheq(path, "/usr/ucb")) 267 { 268 ucb_builtins++; 269 break; 270 } 271 else if (patheq(path, "/usr/bin")) 272 break; 273 else if (patheq(path, "/bin")) 274 break; 275 else if (patheq(path, "/usr/5bin")) 276 break; 277 path = nextpath(path); 278 } 279 } 280 281 static int 282 patheq(unsigned char *component, char *dir) 283 { 284 unsigned char c; 285 286 for (;;) 287 { 288 c = *component++; 289 if (c == COLON) 290 c = '\0'; /* end of component of path */ 291 if (c != *dir++) 292 return (0); 293 if (c == '\0') 294 return(1); 295 } 296 } 297 298 int 299 readvar(unsigned char **names) 300 { 301 struct fileblk fb; 302 struct fileblk *f = &fb; 303 unsigned char c[MULTI_BYTE_MAX+1]; 304 int rc = 0; 305 struct namnod *n = lookup(*names++); /* done now to avoid storage mess */ 306 unsigned char *rel = (unsigned char *)relstak(); 307 unsigned char *oldstak; 308 unsigned char *pc, *rest; 309 int d; 310 311 push(f); 312 initf(dup(0)); 313 314 /* 315 * If stdin is a pipe then this lseek(2) will fail with ESPIPE, so 316 * the read buffer size is set to 1 because we will not be able 317 * lseek(2) back towards the beginning of the file, so we have 318 * to read a byte at a time instead 319 * 320 */ 321 if (lseek(0, (off_t)0, SEEK_CUR) == -1) 322 f->fsiz = 1; 323 324 /* 325 * If stdin is a socket then this isastream(3C) will return 1, so 326 * the read buffer size is set to 1 because we will not be able 327 * lseek(2) back towards the beginning of the file, so we have 328 * to read a byte at a time instead 329 * 330 */ 331 if (isastream(0) == 1) 332 f->fsiz = 1; 333 334 /* 335 * strip leading IFS characters 336 */ 337 for (;;) 338 { 339 d = nextwc(); 340 if(eolchar(d)) 341 break; 342 rest = readw(d); 343 pc = c; 344 while(*pc++ = *rest++); 345 if(!anys(c, ifsnod.namval)) 346 break; 347 } 348 349 oldstak = curstak(); 350 for (;;) 351 { 352 if ((*names && anys(c, ifsnod.namval)) || eolchar(d)) 353 { 354 if (staktop >= brkend) 355 growstak(staktop); 356 zerostak(); 357 assign(n, absstak(rel)); 358 setstak(rel); 359 if (*names) 360 n = lookup(*names++); 361 else 362 n = 0; 363 if (eolchar(d)) 364 { 365 break; 366 } 367 else /* strip imbedded IFS characters */ 368 while(1) { 369 d = nextwc(); 370 if(eolchar(d)) 371 break; 372 rest = readw(d); 373 pc = c; 374 while(*pc++ = *rest++); 375 if(!anys(c, ifsnod.namval)) 376 break; 377 } 378 } 379 else 380 { 381 if(d == '\\') { 382 d = readwc(); 383 rest = readw(d); 384 while(d = *rest++) { 385 if (staktop >= brkend) 386 growstak(staktop); 387 pushstak(d); 388 } 389 oldstak = staktop; 390 } 391 else 392 { 393 pc = c; 394 while(d = *pc++) { 395 if (staktop >= brkend) 396 growstak(staktop); 397 pushstak(d); 398 } 399 if(!anys(c, ifsnod.namval)) 400 oldstak = staktop; 401 } 402 d = nextwc(); 403 404 if (eolchar(d)) 405 staktop = oldstak; 406 else 407 { 408 rest = readw(d); 409 pc = c; 410 while(*pc++ = *rest++); 411 } 412 } 413 } 414 while (n) 415 { 416 assign(n, (unsigned char *)nullstr); 417 if (*names) 418 n = lookup(*names++); 419 else 420 n = 0; 421 } 422 423 if (eof) 424 rc = 1; 425 426 if (isastream(0) != 1) 427 /* 428 * If we are reading on a stream do not attempt to 429 * lseek(2) back towards the start because this is 430 * logically meaningless, but there is nothing in 431 * the standards to pervent the stream implementation 432 * from attempting it and breaking our code here 433 * 434 */ 435 lseek(0, (off_t)(f->nxtoff - f->endoff), SEEK_CUR); 436 437 pop(); 438 return(rc); 439 } 440 441 void 442 assnum(unsigned char **p, long i) 443 { 444 int j = ltos(i); 445 replace(p, &numbuf[j]); 446 } 447 448 unsigned char * 449 make(v) 450 unsigned char *v; 451 { 452 unsigned char *p; 453 454 if (v) 455 { 456 movstr(v, p = (unsigned char *)alloc(length(v))); 457 return(p); 458 } 459 else 460 return(0); 461 } 462 463 464 struct namnod * 465 lookup(unsigned char *nam) 466 { 467 struct namnod *nscan = namep; 468 struct namnod **prev; 469 int LR; 470 471 if (!chkid(nam)) 472 failed(nam, notid); 473 474 while (nscan) 475 { 476 if ((LR = cf(nam, nscan->namid)) == 0) 477 return(nscan); 478 479 else if (LR < 0) 480 prev = &(nscan->namlft); 481 else 482 prev = &(nscan->namrgt); 483 nscan = *prev; 484 } 485 /* 486 * add name node 487 */ 488 nscan = (struct namnod *)alloc(sizeof *nscan); 489 nscan->namlft = nscan->namrgt = (struct namnod *)NIL; 490 nscan->namid = make(nam); 491 nscan->namval = 0; 492 nscan->namflg = N_DEFAULT; 493 nscan->namenv = 0; 494 495 return(*prev = nscan); 496 } 497 498 BOOL 499 chkid(nam) 500 unsigned char *nam; 501 { 502 unsigned char *cp = nam; 503 504 if (!letter(*cp)) 505 return(FALSE); 506 else 507 { 508 while (*++cp) 509 { 510 if (!alphanum(*cp)) 511 return(FALSE); 512 } 513 } 514 return(TRUE); 515 } 516 517 static void (*namfn)(); 518 519 void 520 namscan(void (*fn)()) 521 { 522 namfn = fn; 523 namwalk(namep); 524 } 525 526 static void 527 namwalk(struct namnod *np) 528 { 529 if (np) 530 { 531 namwalk(np->namlft); 532 (*namfn)(np); 533 namwalk(np->namrgt); 534 } 535 } 536 537 void 538 printnam(struct namnod *n) 539 { 540 unsigned char *s; 541 542 sigchk(); 543 544 if (n->namflg & N_FUNCTN) 545 { 546 struct fndnod *f = fndptr(n->namenv); 547 548 prs_buff(n->namid); 549 prs_buff("(){\n"); 550 if (f != NULL) 551 prf(f->fndval); 552 prs_buff("\n}\n"); 553 } 554 else if (s = n->namval) 555 { 556 prs_buff(n->namid); 557 prc_buff('='); 558 prs_buff(s); 559 prc_buff(NL); 560 } 561 } 562 563 static int namec; 564 565 void 566 printro(struct namnod *n) 567 { 568 if (n->namflg & N_RDONLY) 569 { 570 prs_buff(_gettext(readonly)); 571 prc_buff(SPACE); 572 prs_buff(n->namid); 573 prc_buff(NL); 574 } 575 } 576 577 void 578 printexp(struct namnod *n) 579 { 580 if (n->namflg & N_EXPORT) 581 { 582 prs_buff(_gettext(export)); 583 prc_buff(SPACE); 584 prs_buff(n->namid); 585 prc_buff(NL); 586 } 587 } 588 589 void 590 setup_env(void) 591 { 592 unsigned char **e = environ; 593 594 while (*e) 595 setname(*e++, N_ENVNAM); 596 } 597 598 599 static unsigned char **argnam; 600 601 static void 602 countnam(struct namnod *n) 603 { 604 if (n->namval) 605 namec++; 606 } 607 608 static void 609 pushnam(struct namnod *n) 610 { 611 int flg = n->namflg; 612 unsigned char *p; 613 unsigned char *namval; 614 615 if (((flg & N_ENVCHG) && (flg & N_EXPORT)) || (flg & N_FUNCTN)) 616 namval = n->namval; 617 else { 618 /* Discard Local variable in child process */ 619 if (!(flg & ~N_ENVCHG)) { 620 n->namflg = 0; 621 n->namenv = 0; 622 if (n->namval) { 623 /* Release for re-use */ 624 free(n->namval); 625 n->namval = (unsigned char *)NIL; 626 } 627 } 628 namval = n->namenv; 629 } 630 631 if (namval) 632 { 633 p = movstrstak(n->namid, staktop); 634 p = movstrstak("=", p); 635 p = movstrstak(namval, p); 636 *argnam++ = getstak(p + 1 - (unsigned char *)(stakbot)); 637 } 638 } 639 640 unsigned char ** 641 local_setenv() 642 { 643 unsigned char **er; 644 645 namec = 0; 646 namscan(countnam); 647 648 argnam = er = (unsigned char **)getstak(namec * BYTESPERWORD + BYTESPERWORD); 649 namscan(pushnam); 650 *argnam++ = 0; 651 return(er); 652 } 653 654 struct namnod * 655 findnam(nam) 656 unsigned char *nam; 657 { 658 struct namnod *nscan = namep; 659 int LR; 660 661 if (!chkid(nam)) 662 return(0); 663 while (nscan) 664 { 665 if ((LR = cf(nam, nscan->namid)) == 0) 666 return(nscan); 667 else if (LR < 0) 668 nscan = nscan->namlft; 669 else 670 nscan = nscan->namrgt; 671 } 672 return(0); 673 } 674 675 void 676 unset_name(unsigned char *name) 677 { 678 struct namnod *n; 679 unsigned char call_dolocale = 0; 680 681 if (n = findnam(name)) 682 { 683 if (n->namflg & N_RDONLY) 684 failed(name, wtfailed); 685 686 if (n == &pathnod || 687 n == &ifsnod || 688 n == &ps1nod || 689 n == &ps2nod || 690 n == &mchknod) 691 { 692 failed(name, badunset); 693 } 694 695 #ifndef RES 696 697 if ((flags & rshflg) && eq(name, "SHELL")) 698 failed(name, restricted); 699 700 #endif 701 702 if (n->namflg & N_FUNCTN) 703 { 704 func_unhash(name); 705 freefunc(n); 706 } 707 else 708 { 709 call_dolocale++; 710 free(n->namval); 711 free(n->namenv); 712 } 713 714 n->namval = n->namenv = 0; 715 n->namflg = N_DEFAULT; 716 717 if (call_dolocale) 718 dolocale(name); 719 720 if (flags & prompt) 721 { 722 if (n == &mailpnod) 723 setmail(mailnod.namval); 724 else if (n == &mailnod && mailpnod.namflg == N_DEFAULT) 725 setmail(0); 726 } 727 } 728 } 729 730 /* 731 * The environment variables which affect locale. 732 * Note: if all names in this list do not begin with 'L', 733 * you MUST modify dolocale(). Also, be sure that the 734 * fake_env has the same number of elements as localevar. 735 */ 736 static char *localevar[] = { 737 "LC_ALL", 738 "LC_CTYPE", 739 "LC_MESSAGES", 740 "LANG", 741 0 742 }; 743 744 static char *fake_env[] = { 745 0, 746 0, 747 0, 748 0, 749 0 750 }; 751 752 /* 753 * If name is one of several special variables which affect the locale, 754 * do a setlocale(). 755 */ 756 static void 757 dolocale(nm) 758 char *nm; 759 { 760 char **real_env; 761 struct namnod *n; 762 int lv, fe; 763 int i; 764 765 /* 766 * Take advantage of fact that names of these vars all start 767 * with 'L' to avoid unnecessary work. 768 * Do locale processing only if /usr is mounted. 769 */ 770 if ((*nm != 'L') || !localedir_exists || 771 (!(eq(nm, "LC_ALL") || eq(nm, "LC_CTYPE") || 772 eq(nm, "LANG") || eq(nm, "LC_MESSAGES")))) 773 return; 774 775 /* 776 * setlocale() has all the smarts built into it, but 777 * it works by examining the environment. Unfortunately, 778 * when you set an environment variable, the shell does 779 * not modify its own environment; it just remembers that the 780 * variable needs to be exported to any children. We hack around 781 * this by consing up a fake environment for the use of setlocale() 782 * and substituting it for the real env before calling setlocale(). 783 */ 784 785 /* 786 * Build the fake environment. 787 * Look up the value of each of the special environment 788 * variables, and put their value into the fake environment, 789 * if they are exported. 790 */ 791 for (lv = 0, fe = 0; localevar[lv]; lv++) { 792 if ((n = findnam(localevar[lv]))) { 793 char *p, *q; 794 795 if (!n->namval) 796 continue; 797 798 fake_env[fe++] = p = alloc(length(localevar[lv]) 799 + length(n->namval) + 2); 800 /* copy name */ 801 q = localevar[lv]; 802 while (*q) 803 *p++ = *q++; 804 805 *p++ = '='; 806 807 /* copy value */ 808 q = (char*)(n->namval); 809 while (*q) 810 *p++ = *q++; 811 *p++ = '\0'; 812 } 813 } 814 fake_env[fe] = (char *)0; 815 816 /* 817 * Switch fake env for real and call setlocale(). 818 */ 819 real_env = (char **)environ; 820 environ = (unsigned char **)fake_env; 821 822 if (setlocale(LC_ALL, "") == NULL) 823 prs(_gettext(badlocale)); 824 825 /* 826 * Switch back and tear down the fake env. 827 */ 828 environ = (unsigned char **)real_env; 829 for (i = 0; i < fe; i++) { 830 free(fake_env[i]); 831 fake_env[i] = (char *)0; 832 } 833 } 834