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