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
syslook(unsigned char * w,struct sysnod syswds[],int n)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
setlist(struct argnod * arg,int xp)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
setname(unsigned char * argi,int xp)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
replace(unsigned char ** a,unsigned char * v)197 replace(unsigned char **a, unsigned char *v)
198 {
199 free(*a);
200 *a = make(v);
201 }
202
203 void
dfault(struct namnod * n,unsigned char * v)204 dfault(struct namnod *n, unsigned char *v)
205 {
206 if (n->namval == 0)
207 assign(n, v);
208 }
209
210 void
assign(struct namnod * n,unsigned char * v)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
set_builtins_path()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
patheq(unsigned char * component,char * dir)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
readvar(unsigned char ** names)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
assnum(unsigned char ** p,long i)442 assnum(unsigned char **p, long i)
443 {
444 int j = ltos(i);
445 replace(p, &numbuf[j]);
446 }
447
448 unsigned char *
make(v)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 *
lookup(unsigned char * nam)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
chkid(nam)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
namscan(void (* fn)())520 namscan(void (*fn)())
521 {
522 namfn = fn;
523 namwalk(namep);
524 }
525
526 static void
namwalk(struct namnod * np)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
printnam(struct namnod * n)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
printro(struct namnod * n)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
printexp(struct namnod * n)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
setup_env(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
countnam(struct namnod * n)602 countnam(struct namnod *n)
603 {
604 if (n->namval)
605 namec++;
606 }
607
608 static void
pushnam(struct namnod * n)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 **
local_setenv()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 *
findnam(nam)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
unset_name(unsigned char * name)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
dolocale(nm)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