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