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