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