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 * A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23
24 /*
25 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 #if defined(sun)
33 #pragma ident "@(#)name.c 1.25 06/06/16 SMI"
34 #endif
35
36 #include "defs.h"
37
38 /*
39 * Copyright 2008-2020 J. Schilling
40 *
41 * @(#)name.c 1.80 20/05/17 2008-2020 J. Schilling
42 */
43 #ifndef lint
44 static UConst char sccsid[] =
45 "@(#)name.c 1.80 20/05/17 2008-2020 J. Schilling";
46 #endif
47
48 /*
49 * UNIX shell
50 */
51
52 #ifdef INTERACTIVE
53 #include <schily/shedit.h>
54 #endif
55 #ifdef HAVE_STROPTS_H
56 #include <stropts.h>
57 #endif
58
59 extern int mailchk;
60
61 int syslook __PR((unsigned char *w,
62 const struct sysnod syswds[], int n));
63 const struct sysnod *
64 sysnlook __PR((unsigned char *w,
65 const struct sysnod syswds[], int n));
66 void setlist __PR((struct argnod *arg, int xp));
67 void setname __PR((unsigned char *, int));
68 void replace __PR((unsigned char **a, unsigned char *v));
69 void dfault __PR((struct namnod *n, unsigned char *v));
70 void assign __PR((struct namnod *n, unsigned char *v));
71 static void use __PR((struct namnod *n));
72 static void set_builtins_path __PR((void));
73 static int patheq __PR((unsigned char *component, char *dir));
74 int readvar __PR((int namec, unsigned char **names));
75 void assnum __PR((unsigned char **p, long i));
76 unsigned char *make __PR((unsigned char *v));
77 struct namnod *lookup __PR((unsigned char *nam));
78 static BOOL chkid __PR((unsigned char *nam));
79 void namscan __PR((void (*fn)(struct namnod *n)));
80 static void namwalk __PR((struct namnod *));
81 void printfunc __PR((struct namnod *n));
82 void printnam __PR((struct namnod *n));
83 #ifdef DO_LINENO
84 unsigned char *linenoval __PR((void));
85 #endif
86 void printro __PR((struct namnod *n));
87 void printpro __PR((struct namnod *n));
88 void printexp __PR((struct namnod *n));
89 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
90 void pushval __PR((struct namnod *nm, void *t));
91 #endif
92 #ifdef DO_SYSLOCAL
93 void poplvars __PR((void));
94 static void _poplvars __PR((struct namnod *n));
95 void printlocal __PR((struct namnod *n));
96 #endif
97 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
98 void popvars __PR((void));
99 static void _popvars __PR((struct namnod *n));
100 #endif
101 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
102 void popval __PR((struct namnod *n));
103 #endif
104 void setup_env __PR((void));
105 static void countnam __PR((struct namnod *n));
106 static void pushnam __PR((struct namnod *n));
107 unsigned char **local_setenv __PR((int flg));
108 unsigned char **get_envptr __PR((void));
109 struct namnod *findnam __PR((unsigned char *nam));
110 void unset_name __PR((unsigned char *name, int uflg));
111 static void dolocale __PR((char *nm));
112
113 #ifndef HAVE_ISASTREAM
114 static int isastream __PR((int fd));
115 #endif
116 #ifdef INTERACTIVE
117 char *getcurenv __PR((char *name));
118 void ev_insert __PR((char *name));
119 #endif
120
121 struct namnod ps2nod = /* PS2= */
122 {
123 (struct namnod *)NIL,
124 &acctnod,
125 (struct namnod *)NIL,
126 (unsigned char *)ps2name
127 };
128 struct namnod fcenod = /* FCEDIT= */
129 {
130 (struct namnod *)NIL,
131 (struct namnod *)NIL,
132 (struct namnod *)NIL,
133 (unsigned char *)fcename
134 };
135 struct namnod envnod = /* ENV= */
136 {
137 (struct namnod *)NIL,
138 &fcenod,
139 (struct namnod *)NIL,
140 (unsigned char *)envname
141 };
142 struct namnod cdpnod = /* CDPATH= */
143 {
144 (struct namnod *)NIL,
145 &envnod,
146 (struct namnod *)NIL,
147 (unsigned char *)cdpname
148 };
149 struct namnod ppidnod = /* PPID= */
150 {
151 (struct namnod *)NIL,
152 (struct namnod *)NIL,
153 (struct namnod *)NIL,
154 (unsigned char *)ppidname
155 };
156 struct namnod pathnod = /* PATH= */
157 {
158 &mailpnod,
159 &ppidnod,
160 (struct namnod *)NIL,
161 (unsigned char *)pathname
162 };
163 struct namnod ifsnod = /* IFS= */
164 {
165 &homenod,
166 &mailnod,
167 (struct namnod *)NIL,
168 (unsigned char *)ifsname
169 };
170 struct namnod ps1nod = /* PS1= */
171 {
172 &pathnod,
173 &ps2nod,
174 (struct namnod *)NIL,
175 (unsigned char *)ps1name
176 };
177 struct namnod ps4nod = /* PS4= */
178 {
179 (struct namnod *)NIL,
180 (struct namnod *)NIL,
181 (struct namnod *)NIL,
182 (unsigned char *)ps4name
183 };
184 struct namnod ps3nod = /* PS3= */
185 {
186 (struct namnod *)NIL,
187 &ps4nod,
188 (struct namnod *)NIL,
189 (unsigned char *)ps3name
190 };
191 struct namnod homenod = /* HOME= */
192 {
193 &cdpnod,
194 (struct namnod *)NIL,
195 (struct namnod *)NIL,
196 (unsigned char *)homename
197 };
198 struct namnod linenonod = /* LINENO= */
199 {
200 (struct namnod *)NIL,
201 (struct namnod *)NIL,
202 (struct namnod *)NIL,
203 (unsigned char *)linenoname
204 };
205 struct namnod mailnod = /* MAIL= */
206 {
207 &linenonod,
208 (struct namnod *)NIL,
209 (struct namnod *)NIL,
210 (unsigned char *)mailname
211 };
212 struct namnod mchknod = /* MAILCHECK= */
213 {
214 &ifsnod,
215 &ps1nod,
216 (struct namnod *)NIL,
217 (unsigned char *)mchkname
218 };
219 struct namnod repnod = /* REPLY= */
220 {
221 (struct namnod *)NIL,
222 (struct namnod *)NIL,
223 (struct namnod *)NIL,
224 (unsigned char *)repname,
225 };
226 struct namnod pwdnod = /* PWD= */
227 {
228 &ps3nod,
229 &repnod,
230 (struct namnod *)NIL,
231 (unsigned char *)pwdname,
232 };
233 struct namnod opwdnod = /* OLDPWD= */
234 {
235 (struct namnod *)NIL,
236 (struct namnod *)NIL,
237 (struct namnod *)NIL,
238 (unsigned char *)opwdname,
239 };
240 struct namnod timefmtnod = /* TIMEFORMAT= */
241 {
242 (struct namnod *)NIL,
243 (struct namnod *)NIL,
244 (struct namnod *)NIL,
245 (unsigned char *)timefmtname,
246 };
247 struct namnod acctnod = /* SHACCT= */
248 {
249 &pwdnod,
250 &timefmtnod,
251 (struct namnod *)NIL,
252 (unsigned char *)acctname
253 };
254 struct namnod mailpnod = /* MAILPATH= */
255 {
256 (struct namnod *)NIL,
257 &opwdnod,
258 (struct namnod *)NIL,
259 (unsigned char *)mailpname
260 };
261 #ifdef DO_GETOPT_POSIX
262 struct namnod *optindnodep; /* OPTIND= */
263 #endif
264
265
266 struct namnod *namep = &mchknod;
267
268 /* ======== variable and string handling ======== */
269
270 /*
271 * Return numeric identifier for reserved words and builtin commands.
272 */
273 int
syslook(w,syswds,n)274 syslook(w, syswds, n)
275 unsigned char *w;
276 const struct sysnod syswds[];
277 int n;
278 {
279 const struct sysnod *res = sysnlook(w, syswds, n);
280
281 if (res == NULL)
282 return (0);
283 return (res->sysval);
284 }
285
286 /*
287 * Lookup function for reserved words and builtin commands,
288 * return sysnod structure.
289 */
290 const struct sysnod *
sysnlook(w,syswds,n)291 sysnlook(w, syswds, n)
292 unsigned char *w;
293 const struct sysnod syswds[];
294 int n;
295 {
296 int low;
297 int high;
298 int mid;
299 int cond;
300
301 if (w == 0 || *w == 0)
302 return (0);
303
304 low = 0;
305 high = n - 1;
306
307 while (low <= high) {
308 mid = (low + high) / 2;
309
310 if ((cond = cf(w, (unsigned char *)syswds[mid].sysnam)) < 0)
311 high = mid - 1;
312 else if (cond > 0)
313 low = mid + 1;
314 else
315 return (&syswds[mid]);
316 }
317 return (0);
318 }
319
320 /*
321 * Set up the list of local shell variable definitions to be
322 * exported for the next command.
323 */
324 void
setlist(arg,xp)325 setlist(arg, xp)
326 struct argnod *arg;
327 int xp;
328 {
329 if (flags & exportflg)
330 xp |= N_EXPORT;
331
332 while (arg) {
333 unsigned char *s = mactrim(arg->argval);
334 setname(s, xp);
335 arg = arg->argnxt;
336 if (flags & execpr) {
337 #ifdef DO_PS34
338 prs(ps_macro(ps4nod.namval?ps4nod.namval:UC execpmsg,
339 FALSE));
340 #endif
341 prs(s);
342 if (arg)
343 blank();
344 else
345 newline();
346 }
347 }
348 }
349
350 /*
351 * does parameter assignments for cases when a NAME=value string exists
352 */
353 void
setname(argi,xp)354 setname(argi, xp)
355 unsigned char *argi;
356 int xp;
357 {
358 unsigned char *argscan = argi;
359 struct namnod *n;
360
361 if (letter(*argscan)) {
362 while (alphanum(*argscan))
363 argscan++;
364
365 if (*argscan == '=') {
366 *argscan = 0; /* make name a cohesive string */
367
368 n = lookup(argi);
369 *argscan++ = '=';
370
371 if (xp & N_ENVNAM) {
372 n->namenv = n->namval = argscan;
373 if (n == &pathnod)
374 set_builtins_path();
375 } else {
376 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
377 if (xp & N_PUSHOV)
378 pushval(n, NULL);
379 #endif
380 assign(n, argscan);
381 }
382 attrib(n, xp); /* readonly attrib after assignement */
383
384 dolocale((char *)n->namid);
385 #ifdef DO_GETOPT_POSIX
386 /*
387 * make sure that option parsing starts
388 * at first character
389 */
390 if (n == optindnodep)
391 _sp = 1;
392 #endif
393 return;
394 }
395 }
396 }
397
398 void
replace(a,v)399 replace(a, v)
400 unsigned char **a;
401 unsigned char *v;
402 {
403 free(*a);
404 *a = make(v);
405 }
406
407 /*
408 * Assign a default value to a shell variable that is currently unset.
409 */
410 void
dfault(n,v)411 dfault(n, v)
412 struct namnod *n;
413 unsigned char *v;
414 {
415 if (n->namval == 0)
416 assign(n, v);
417 }
418
419 /*
420 * Unconditionally assign a value to a shell variable.
421 */
422 void
assign(n,v)423 assign(n, v)
424 struct namnod *n;
425 unsigned char *v;
426 {
427 if (n->namflg & N_RDONLY)
428 failed(n->namid, wtfailed);
429
430 #ifndef RES
431
432 else if (flags & rshflg) {
433 if (n == &pathnod || eq(n->namid, "SHELL"))
434 failed(n->namid, restricted);
435 }
436 #endif
437
438 #ifndef DO_POSIX_UNSET
439 else if (n->namflg & N_FUNCTN) {
440 func_unhash(n->namid);
441 freefunc(n);
442
443 n->funcval = 0;
444 n->namflg = N_DEFAULT;
445 }
446 #endif
447 replace(&n->namval, v);
448 attrib(n, N_ENVCHG); /* Mark as changed after env inport */
449 #ifdef DO_ALLEXPORT
450 if (flags & exportflg) /* set -a ? */
451 attrib(n, N_EXPORT); /* Mark for export */
452 #endif
453
454 use(n);
455 }
456
457 /*
458 * Let the shell use the new value.
459 */
460 static void
use(n)461 use(n)
462 struct namnod *n;
463 {
464 if (n == &mchknod) {
465 mailchk = stoi(n->namval);
466
467 } else if (n == &pathnod) {
468 zaphash();
469 set_dotpath();
470 set_builtins_path();
471
472 } if (flags & prompt) {
473 if ((n == &mailpnod) ||
474 (n == &mailnod && mailpnod.namflg == N_DEFAULT)) {
475 setmail(n->namval);
476 }
477 }
478 }
479
480 static void
set_builtins_path()481 set_builtins_path()
482 {
483 unsigned char *path;
484
485 ucb_builtins = 0;
486 path = getpath((unsigned char *)"");
487 while (path && *path) {
488 if (patheq(path, "/usr/ucb")) {
489 ucb_builtins++;
490 break;
491 } else if (patheq(path, "/usr/bin"))
492 break;
493 else if (patheq(path, "/bin"))
494 break;
495 else if (patheq(path, "/usr/5bin"))
496 break;
497 path = nextpath(path);
498 }
499 }
500
501 static int
patheq(component,dir)502 patheq(component, dir)
503 unsigned char *component;
504 char *dir;
505 {
506 unsigned char c;
507
508 for (;;) {
509 c = *component++;
510 if (c == COLON)
511 c = '\0'; /* end of component of path */
512 if (c != *dir++)
513 return (0);
514 if (c == '\0')
515 return (1);
516 }
517 }
518
519 /*
520 * The read(1) builtin.
521 */
522 int
readvar(namec,names)523 readvar(namec, names)
524 int namec;
525 unsigned char **names;
526 {
527 struct fileblk fb;
528 struct fileblk *f = &fb;
529 unsigned char c[MULTI_BYTE_MAX+1];
530 int rc = 0;
531 struct namnod *n;
532 unsigned char *rel;
533 unsigned char *oldstak;
534 unsigned char *pc, *rest;
535 int d;
536 #ifdef DO_POSIX_READ
537 wchar_t wc;
538 unsigned char ifsw[3]; /* Max.: space and tab */
539 #else
540 unsigned char *ifsw;
541 #endif
542 unsigned int (*nextwchar)__PR((void));
543 unsigned char *ifs;
544 BOOL ifswhite = FALSE;
545 #ifdef DO_SELECT
546 unsigned char *a[2];
547 #endif
548
549 nextwchar = nextwc;
550
551 #if defined(DO_READ_R) || defined(DO_SELECT)
552 if (namec > 1) {
553 struct optv optv;
554 int ch;
555
556 optinit(&optv);
557
558 while ((ch = optnext(namec, names, &optv, "r",
559 "read [-r] [name ...]")) != -1) {
560 if (ch == 0) /* Was -help */
561 return (1);
562 else if (ch == 'r')
563 nextwchar = readwc;
564 }
565 namec -= --optv.optind;
566 names += optv.optind;
567 }
568
569 #if defined(DO_SELECT)
570 if (namec <= 1) {
571 a[0] = UC repname; /* REPLY */
572 a[1] = NULL;
573 names = a;
574 } else
575 #endif
576 #endif
577 names++;
578 ifs = ifsnod.namval;
579 if (ifs == NULL)
580 ifs = (unsigned char *)sptbnl;
581
582 #ifdef DO_POSIX_READ
583 ifsw[0] = '\0';
584 ifsw[1] = '\0';
585 pc = ifsw;
586 for (rel = ifs; *rel; rel += d) {
587 if ((d = mbtowc(&wc, C rel, MULTI_BYTE_MAX)) <= 0) {
588 (void) mbtowc(NULL, NULL, 0);
589 wc = *rel;
590 }
591 if (space(wc)) {
592 if (ifsw[0] != wc && ifsw[1] != wc)
593 *pc++ = wc;
594 ifswhite = TRUE;
595 }
596 }
597 *pc = '\0';
598 #else
599 ifswhite = TRUE;
600 ifsw = UC sptbnl;
601 #endif
602
603 n = lookup(*names++); /* done now to avoid storage mess */
604 rel = (unsigned char *)relstak();
605
606 push(f);
607 initf(dup(STDIN_FILENO));
608
609 /*
610 * If stdin is a pipe then this lseek(2) will fail with ESPIPE, so
611 * the read buffer size is set to 1 because we will not be able
612 * lseek(2) back towards the beginning of the file, so we have
613 * to read a byte at a time instead
614 *
615 */
616 if (lseek(STDIN_FILENO, (off_t)0, SEEK_CUR) == -1)
617 f->fsiz = 1;
618
619 /*
620 * If stdin is a socket then this isastream(3C) will return 1, so
621 * the read buffer size is set to 1 because we will not be able
622 * lseek(2) back towards the beginning of the file, so we have
623 * to read a byte at a time instead
624 *
625 */
626 if (isastream(STDIN_FILENO) == 1)
627 f->fsiz = 1;
628
629 /*
630 * Read first character and
631 * strip leading IFS white space characters
632 */
633 c[0] = '\0';
634 do {
635 d = nextwchar();
636 if (eolchar(d))
637 break;
638 rest = readw(d);
639 pc = c;
640 while ((*pc++ = *rest++) != '\0')
641 /* LINTED */
642 ;
643 if (ifswhite && !anys(c, ifsw))
644 break;
645 } while (ifswhite);
646
647 oldstak = curstak();
648 for (;;) {
649 if ((*names && anys(c, ifs)) || eolchar(d)) {
650 GROWSTAKTOP();
651 zerostak();
652 assign(n, absstak(rel));
653 setstak(rel);
654 if (*names)
655 n = lookup(*names++);
656 else
657 n = 0;
658 if (eolchar(d)) {
659 break;
660 } else { /* strip imbedded IFS characters */
661 c[0] = '\0';
662 do {
663 d = nextwchar();
664 if (eolchar(d))
665 break;
666 rest = readw(d);
667 pc = c;
668 while ((*pc++ = *rest++) != '\0')
669 /* LINTED */
670 ;
671 if (ifswhite && !anys(c, ifsw))
672 break;
673 } while (ifswhite);
674 }
675 } else {
676 if (d == '\\' && nextwchar == nextwc) {
677 d = readwc();
678 rest = readw(d);
679 while ((d = *rest++) != '\0') {
680 GROWSTAKTOP();
681 pushstak(d);
682 }
683 oldstak = staktop;
684 } else {
685 pc = c;
686 while ((d = *pc++) != '\0') {
687 GROWSTAKTOP();
688 pushstak(d);
689 }
690 if (!anys(c, ifs))
691 oldstak = staktop;
692 }
693 d = nextwchar();
694
695 if (eolchar(d)) {
696 staktop = oldstak;
697 } else {
698 rest = readw(d);
699 pc = c;
700 while ((*pc++ = *rest++) != '\0')
701 /* LINTED */
702 ;
703 }
704 }
705 }
706 while (n) {
707 #ifdef DO_READ_ALLEXPORT
708 if (flags & exportflg)
709 n->namflg |= N_EXPORT;
710 #endif
711 assign(n, (unsigned char *)nullstr);
712 if (*names)
713 n = lookup(*names++);
714 else
715 n = 0;
716 }
717
718 if (eof)
719 rc = 1;
720
721 if (isastream(STDIN_FILENO) != 1)
722 /*
723 * If we are reading on a stream do not attempt to
724 * lseek(2) back towards the start because this is
725 * logically meaningless, but there is nothing in
726 * the standards to pervent the stream implementation
727 * from attempting it and breaking our code here
728 *
729 */
730 lseek(STDIN_FILENO, (off_t)(f->nxtoff - f->endoff), SEEK_CUR);
731
732 pop();
733 return (rc);
734 }
735
736 void
assnum(p,i)737 assnum(p, i)
738 unsigned char **p;
739 long i;
740 {
741 int j = ltos(i);
742 replace(p, &numbuf[j]);
743 }
744
745 unsigned char *
make(v)746 make(v)
747 unsigned char *v;
748 {
749 unsigned char *p;
750
751 if (v) {
752 movstr(v, p = (unsigned char *)alloc(length(v)));
753 return (p);
754 } else
755 return (0);
756 }
757
758 /*
759 * Lookup a shell variable and allocate a new node if the
760 * variable does not yet exist.
761 */
762 struct namnod *
lookup(nam)763 lookup(nam)
764 register unsigned char *nam;
765 {
766 register struct namnod *nscan = namep;
767 struct namnod **prev = NULL; /* Make stupid GCC happy */
768 int LR;
769
770 if (!chkid(nam))
771 failed(nam, notid);
772
773 while (nscan) {
774 #define INLINE_CMP
775 #ifdef INLINE_CMP
776 {
777 register unsigned char *s1 = nam;
778 register unsigned char *s2 = nscan->namid;
779
780 while (*s1++ == *s2)
781 if (*s2++ == 0)
782 return (nscan);
783 LR = *--s1 - *s2;
784 }
785 if (LR < 0)
786 #else
787 if ((LR = cf(nam, nscan->namid)) == 0)
788 return (nscan);
789 else if (LR < 0)
790 #endif
791 prev = &(nscan->namlft);
792 else
793 prev = &(nscan->namrgt);
794 nscan = *prev;
795 }
796 /*
797 * add name node
798 */
799 nscan = (struct namnod *)alloc(sizeof (*nscan));
800 nscan->namlft = nscan->namrgt = nscan->nampush = (struct namnod *)NIL;
801 nscan->namid = make(nam);
802 nscan->namval = 0;
803 nscan->namflg = N_DEFAULT;
804 nscan->namenv = 0;
805 #ifdef DO_POSIX_UNSET
806 nscan->funcval = 0;
807 #endif
808
809 #ifdef NAME_DEBUG
810 /*
811 * Allow to set up handcrafted pointers in *nod structures.
812 */
813 printf("prev = %p name '%s' ME %p\n", prev, nam, nscan);
814 #endif
815 return (*prev = nscan);
816 }
817
818 /*
819 * A valid shell variable name starts with a letter and
820 * contains only letters or digits.
821 */
822 static BOOL
chkid(nam)823 chkid(nam)
824 unsigned char *nam;
825 {
826 unsigned char *cp = nam;
827
828 if (!letter(*cp))
829 return (FALSE);
830 else {
831 while (*++cp) {
832 if (!alphanum(*cp))
833 return (FALSE);
834 }
835 }
836 return (TRUE);
837 }
838
839 static void (*namfn) __PR((struct namnod *n));
840 static int namflg;
841
842 void
843 namscan(fn)
844 void (*fn) __PR((struct namnod *n));
845 {
846 namfn = fn;
847 namwalk(namep);
848 }
849
850 static void
namwalk(np)851 namwalk(np)
852 struct namnod *np;
853 {
854 if (np) {
855 namwalk(np->namlft);
856 (*namfn)(np);
857 namwalk(np->namrgt);
858 }
859 }
860
861 void
printfunc(n)862 printfunc(n)
863 struct namnod *n;
864 {
865 sigchk();
866
867 if (n->namflg & N_FUNCTN) {
868 struct fndnod *f = fndptr(n->funcval);
869
870 prs_buff(n->namid);
871 prs_buff((unsigned char *)"(){\n");
872 if (f != NULL)
873 prf((struct trenod *)f->fndval);
874 prs_buff((unsigned char *)"\n}\n");
875 }
876 }
877
878 void
printnam(n)879 printnam(n)
880 struct namnod *n;
881 {
882 unsigned char *s;
883
884 sigchk();
885
886 if (!(flags2 & posixflg) &&
887 n->namflg & N_FUNCTN) {
888 printfunc(n);
889 #ifndef DO_POSIX_UNSET
890 return;
891 #endif
892 }
893 #ifdef DO_LINENO
894 if (n == &linenonod) {
895 prs_buff(n->namid);
896 prc_buff('=');
897 prs_buff(linenoval());
898 prc_buff(NL);
899 } else
900 #endif
901 if ((s = n->namval) != NULL) {
902 prs_buff(n->namid);
903 prc_buff('=');
904 #ifdef DO_POSIX_UNSET
905 qprs_buff(s);
906 #else
907 prs_buff(s);
908 #endif
909 prc_buff(NL);
910 }
911 }
912
913 #ifdef DO_LINENO
914 unsigned char *
linenoval()915 linenoval()
916 {
917 struct fileblk *f = standin;
918
919 #ifdef LINENO_DEBUG
920 while (1) {
921 printf("F %p des %d\n", f, f->fdes);
922 if (f->fstak == NULL)
923 break;
924 f = f->fstak;
925 }
926 f = standin;
927 #endif
928 if (f->fstak != NULL)
929 f = f->fstak;
930 /*
931 * Subtract 1 as parsing of the current
932 * was already done.
933 */
934 itos(f->flin - 1);
935 return (numbuf);
936 }
937 #endif
938
939 static int namec;
940
941 void
printro(n)942 printro(n)
943 struct namnod *n;
944 {
945 if (n->namflg & N_RDONLY) {
946 prs_buff(_gettext(readonly));
947 prc_buff(SPACE);
948 prs_buff(n->namid);
949 prc_buff(NL);
950 }
951 }
952
953 #ifdef DO_POSIX_EXPORT
954 void
printpro(n)955 printpro(n)
956 struct namnod *n;
957 {
958 if (n->namflg & N_RDONLY) {
959 unsigned char *s;
960
961 prs_buff(UC readonly);
962 prc_buff(SPACE);
963 prs_buff(n->namid);
964 if ((s = n->namval) != NULL) {
965 prs_buff(UC "='");
966 prs_buff(s);
967 prc_buff('\'');
968 }
969 prc_buff(NL);
970 }
971 }
972 #endif
973
974 void
printexp(n)975 printexp(n)
976 struct namnod *n;
977 {
978 if (n->namflg & N_EXPORT) {
979 prs_buff(_gettext(export));
980 prc_buff(SPACE);
981 prs_buff(n->namid);
982 prc_buff(NL);
983 }
984 }
985
986 #ifdef DO_POSIX_EXPORT
987 void
printpexp(n)988 printpexp(n)
989 struct namnod *n;
990 {
991 if (n->namflg & N_EXPORT) {
992 unsigned char *s;
993
994 prs_buff(UC export);
995 prc_buff(SPACE);
996 prs_buff(n->namid);
997 if ((s = n->namval) != NULL) {
998 prs_buff(UC "='");
999 prs_buff(s);
1000 prc_buff('\'');
1001 }
1002 prc_buff(NL);
1003 }
1004 }
1005 #endif
1006
1007 #ifdef DO_POSIX_EXPORT_ENV
1008 void
exportenv(n)1009 exportenv(n)
1010 struct namnod *n;
1011 {
1012 if (n->namflg & N_ENVNAM)
1013 n->namflg |= N_EXPORT;
1014 }
1015 void
deexportenv(n)1016 deexportenv(n)
1017 struct namnod *n;
1018 {
1019 if ((n->namflg & (N_ENVNAM|N_EXPORT|N_ENVCHG)) == (N_ENVNAM|N_EXPORT))
1020 n->namflg &= ~N_EXPORT;
1021 }
1022 #endif
1023
1024 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
1025 /*
1026 * Push the current value by dulicating the content in
1027 * preparation of a later change of the node value.
1028 */
1029 void
pushval(n,t)1030 pushval(n, t)
1031 struct namnod *n;
1032 void *t;
1033 {
1034 struct namnod *nscan = (struct namnod *)alloc(sizeof (*nscan));
1035
1036 *nscan = *n;
1037 n->namval = make(n->namval);
1038 n->nampush = nscan;
1039 nscan->funcval = t;
1040
1041 attrib(n, t ? N_LOCAL : N_PUSHOV);
1042 }
1043 #endif
1044
1045 #ifdef DO_SYSLOCAL
1046 /*
1047 * pop local vars
1048 */
1049 void
poplvars()1050 poplvars()
1051 {
1052 _poplvars(namep);
1053 }
1054
1055 static void
_poplvars(np)1056 _poplvars(np)
1057 struct namnod *np;
1058 {
1059 if (np) {
1060 _poplvars(np->namlft);
1061 if ((np->namflg & N_LOCAL) != 0) {
1062 if (localp) {
1063 while (np->nampush &&
1064 np->nampush->funcval == localp) {
1065 popval(np);
1066 }
1067 } else {
1068 do {
1069 popval(np);
1070 } while ((np->namflg & N_LOCAL) != 0);
1071 }
1072 }
1073 _poplvars(np->namrgt);
1074 }
1075 }
1076
1077 void
printlocal(n)1078 printlocal(n)
1079 struct namnod *n;
1080 {
1081 if (n->namflg & N_LOCAL) {
1082 unsigned char *s;
1083
1084 prs_buff(UC "local");
1085 prc_buff(SPACE);
1086 prs_buff(n->namid);
1087 if ((s = n->namval) != NULL) {
1088 prs_buff(UC "='");
1089 prs_buff(s);
1090 prc_buff('\'');
1091 }
1092 prc_buff(NL);
1093 }
1094 }
1095 #endif /* DO_SYSLOCAL */
1096
1097 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
1098 void
popvars()1099 popvars()
1100 {
1101 _popvars(namep);
1102 }
1103
1104 static void
_popvars(np)1105 _popvars(np)
1106 struct namnod *np;
1107 {
1108 if (np) {
1109 _popvars(np->namlft);
1110 if ((np->namflg & N_PUSHOV) != 0)
1111 popval(np);
1112 _popvars(np->namrgt);
1113 }
1114 }
1115 #endif
1116
1117 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
1118 /*
1119 * If the node has a pushed value, restore the original value.
1120 */
1121 void
popval(n)1122 popval(n)
1123 struct namnod *n;
1124 {
1125 if (n->nampush) {
1126 struct namnod *p = n->nampush;
1127
1128 if (n->namval)
1129 free(n->namval);
1130 n->namval = p->namval;
1131 n->namflg = p->namflg;
1132 n->nampush = p->nampush;
1133 free(p);
1134 } else {
1135 if (n->namval)
1136 free(n->namval);
1137 n->namval = 0;
1138 n->namflg = N_DEFAULT;
1139 }
1140 use(n);
1141 dolocale((char *)n->namid);
1142 if (n == &pwdnod) {
1143 extern unsigned char cwdname[];
1144
1145 pwdnod.namval = pwdnod.namenv = cwdname;
1146 }
1147 #ifdef DO_POSIX_CD
1148 else if (n == &opwdnod) {
1149 extern unsigned char *ocwdname;
1150
1151 opwdnod.namval = opwdnod.namenv = ocwdname;
1152 }
1153 #endif
1154 }
1155 #endif
1156
1157 void
setup_env()1158 setup_env()
1159 {
1160 unsigned char **e = (unsigned char **)environ;
1161
1162 while (*e)
1163 setname(*e++, N_ENVNAM);
1164 }
1165
1166
1167 static unsigned char **argnam;
1168
1169 static void
countnam(n)1170 countnam(n)
1171 struct namnod *n;
1172 {
1173 if (n->namval)
1174 namec++;
1175 }
1176
1177 /*
1178 * Set up a single environ entry for a new external command, called only
1179 * local_setenv().
1180 */
1181 static void
pushnam(n)1182 pushnam(n)
1183 struct namnod *n;
1184 {
1185 int flg = n->namflg;
1186 unsigned char *p;
1187 unsigned char *namval;
1188
1189 #ifndef DO_POSIX_UNSET
1190 if (((flg & N_ENVCHG) && (flg & N_EXPORT)) || (flg & N_FUNCTN)) {
1191 #else
1192 if ((flg & N_ENVCHG) && (flg & N_EXPORT)) {
1193 #endif
1194 namval = n->namval;
1195 } else {
1196 /* Discard Local variable in child process */
1197 #ifdef SUN_EXPORT_BUG
1198 if (!(flg & ~N_ENVCHG)) {
1199 #else
1200 if (!(flg & (N_EXPORT | N_ENVNAM))) {
1201 #endif
1202 if (!(namflg & ENV_NOFREE)) {
1203 n->namflg = 0;
1204 n->namenv = 0;
1205 if (n->namval) {
1206 /* Release for re-use */
1207 free(n->namval);
1208 n->namval = (unsigned char *)NIL;
1209 }
1210 }
1211 namval = (unsigned char *)NIL;
1212 } else {
1213 namval = n->namenv;
1214 }
1215 }
1216
1217 if (namval) {
1218 p = movstrstak(n->namid, staktop);
1219 p = movstrstak((unsigned char *)"=", p);
1220 p = movstrstak(namval, p);
1221 *argnam++ =
1222 getstak((Intptr_t)(p + 1 - (unsigned char *)(stakbot)));
1223 }
1224 }
1225
1226 /*
1227 * Prepare the environ for a new external command.
1228 * The allocated memory is free()d before starting the next command.
1229 */
1230 unsigned char **
local_setenv(flg)1231 local_setenv(flg)
1232 int flg;
1233 {
1234 unsigned char **er;
1235
1236 namec = 0;
1237 namscan(countnam);
1238
1239 argnam = er = (unsigned char **)getstak((Intptr_t)namec * BYTESPERWORD +
1240 BYTESPERWORD);
1241 namflg = flg;
1242 namscan(pushnam);
1243 namflg = 0;
1244 *argnam++ = 0;
1245 return (er);
1246 }
1247
1248 /*
1249 * Get a temporary environ, e.g. for a builtin command.
1250 */
1251 unsigned char **
get_envptr()1252 get_envptr()
1253 {
1254 return (local_setenv(ENV_NOFREE));
1255 }
1256
1257 struct namnod *
findnam(nam)1258 findnam(nam)
1259 unsigned char *nam;
1260 {
1261 struct namnod *nscan = namep;
1262 int LR;
1263
1264 if (!chkid(nam))
1265 return (0);
1266 while (nscan) {
1267 if ((LR = cf(nam, nscan->namid)) == 0)
1268 return (nscan);
1269 else if (LR < 0)
1270 nscan = nscan->namlft;
1271 else
1272 nscan = nscan->namrgt;
1273 }
1274 return (0);
1275 }
1276
1277 void
unset_name(name,uflg)1278 unset_name(name, uflg)
1279 unsigned char *name;
1280 int uflg;
1281 {
1282 struct namnod *n;
1283 unsigned char call_dolocale = 0;
1284
1285 if ((n = findnam(name)) != NULL) {
1286 if (n->namflg & N_RDONLY) {
1287 #ifdef DO_POSIX_UNSET
1288 if (uflg == 0 || uflg == UNSET_VAR)
1289 #endif
1290 failed(name, wtfailed);
1291 }
1292
1293 #ifndef DO_POSIX_UNSET
1294 if (n == &pathnod ||
1295 n == &ifsnod ||
1296 n == &ps1nod ||
1297 n == &ps2nod ||
1298 n == &mchknod) {
1299 failed(name, badunset);
1300 }
1301 #else
1302 if (n == &mchknod)
1303 mailchk = 0;
1304 #endif
1305
1306 #ifndef RES
1307
1308 if ((flags & rshflg) && eq(name, "SHELL"))
1309 failed(name, restricted);
1310
1311 #endif
1312
1313 #ifndef DO_POSIX_UNSET
1314 if (n->namflg & N_FUNCTN) {
1315 func_unhash(name);
1316 freefunc(n);
1317 } else {
1318 call_dolocale++;
1319 free(n->namval);
1320 free(n->namenv);
1321 }
1322 n->namval = n->namenv = 0;
1323 n->namflg = N_DEFAULT;
1324 #else
1325 if ((n->namflg & N_FUNCTN) && (uflg & UNSET_FUNC)) {
1326 func_unhash(name);
1327 freefunc(n);
1328 n->funcval = 0;
1329 n->namflg &= ~N_FUNCTN;
1330 } else {
1331 call_dolocale++;
1332 free(n->namval);
1333 free(n->namenv);
1334 n->namval = n->namenv = 0;
1335 n->namflg &= (N_FUNCTN|N_LOCAL|N_PUSHOV);
1336 }
1337 #endif
1338
1339 if (call_dolocale)
1340 dolocale((char *)name);
1341
1342 if (flags & prompt) {
1343 if (n == &mailpnod)
1344 setmail(mailnod.namval);
1345 else if (n == &mailnod &&
1346 (mailpnod.namflg & ~N_FUNCTN) == N_DEFAULT)
1347 setmail(0);
1348 }
1349 }
1350 }
1351
1352 /*
1353 * The environment variables which affect locale.
1354 * Note: if all names in this list do not begin with 'L',
1355 * you MUST modify dolocale(). Also, be sure that the
1356 * fake_env has the same number of elements as localevar.
1357 */
1358 static char *localevar[] = {
1359 "LC_ALL",
1360 "LC_CTYPE",
1361 "LC_MESSAGES",
1362 "LC_NUMERIC",
1363 "LANG",
1364 0
1365 };
1366
1367 static char *fake_env[] = {
1368 0,
1369 0,
1370 0,
1371 0,
1372 0,
1373 0
1374 };
1375
1376 /*
1377 * If name is one of several special variables which affect the locale,
1378 * do a setlocale().
1379 */
1380 static void
dolocale(nm)1381 dolocale(nm)
1382 char *nm;
1383 {
1384 char **real_env;
1385 struct namnod *n;
1386 int lv, fe;
1387 int i;
1388
1389 #ifdef INTERACTIVE
1390 /*
1391 * Only set history size in libshedit if we are
1392 * in interactive mode. This allows to avoid to
1393 * load libshedit when interpreting shell scripts.
1394 */
1395 if ((flags & prompt) &&
1396 (*nm == 'H') && eq(nm, "HISTORY")) {
1397 char *hv = getcurenv(nm);
1398
1399 shedit_chghistory(hv ? hv:"0");
1400 }
1401 #endif
1402
1403 /*
1404 * Take advantage of fact that names of these vars all start
1405 * with 'L' to avoid unnecessary work.
1406 * Do locale processing only if /usr is mounted.
1407 */
1408 if ((*nm != 'L') || !localedir_exists ||
1409 (!(eq(nm, "LC_ALL") || eq(nm, "LC_CTYPE") ||
1410 eq(nm, "LANG") || eq(nm, "LC_MESSAGES") || eq(nm, "LC_NUMERIC"))))
1411 return;
1412
1413 /*
1414 * setlocale() has all the smarts built into it, but
1415 * it works by examining the environment. Unfortunately,
1416 * when you set an environment variable, the shell does
1417 * not modify its own environment; it just remembers that the
1418 * variable needs to be exported to any children. We hack around
1419 * this by consing up a fake environment for the use of setlocale()
1420 * and substituting it for the real env before calling setlocale().
1421 */
1422
1423 /*
1424 * Build the fake environment.
1425 * Look up the value of each of the special environment
1426 * variables, and put their value into the fake environment,
1427 * if they are exported.
1428 */
1429 for (lv = 0, fe = 0; localevar[lv]; lv++) {
1430 if ((n = findnam((unsigned char *)localevar[lv]))) {
1431 char *p, *q;
1432
1433 if (!n->namval)
1434 continue;
1435
1436 fake_env[fe++] = p = alloc(length((unsigned char *)
1437 localevar[lv])
1438 + length(n->namval) + 2);
1439 /* copy name */
1440 q = localevar[lv];
1441 while (*q)
1442 *p++ = *q++;
1443
1444 *p++ = '=';
1445
1446 /* copy value */
1447 q = (char *)(n->namval);
1448 while (*q)
1449 *p++ = *q++;
1450 *p++ = '\0';
1451 }
1452 }
1453 fake_env[fe] = (char *)0;
1454
1455 /*
1456 * Switch fake env for real and call setlocale().
1457 */
1458 real_env = (char **)environ;
1459 environ = (char **)fake_env;
1460
1461 if (setlocale(LC_ALL, "") == NULL)
1462 prs(_gettext(badlocale));
1463
1464 /*
1465 * Switch back and tear down the fake env.
1466 */
1467 environ = (char **)real_env;
1468 for (i = 0; i < fe; i++) {
1469 free(fake_env[i]);
1470 fake_env[i] = (char *)0;
1471 }
1472 }
1473
1474 #ifndef HAVE_ISASTREAM
1475 static int
isastream(fd)1476 isastream(fd)
1477 int fd;
1478 {
1479 int ret = 0;
1480
1481 if (isatty(fd))
1482 return (1);
1483
1484 #ifdef I_CANPUT
1485 ret = ioctl(fd, I_CANPUT, 0);
1486 if (ret == -1 && errno == EBADF)
1487 return (-1);
1488
1489 errno = 0;
1490 if (ret == 0 || ret == 1)
1491 ret = 1;
1492 #endif
1493 return (ret);
1494 }
1495 #endif
1496
1497 #ifdef INTERACTIVE
1498 /*
1499 * Functions needed by the history editor.
1500 */
1501 char *
getcurenv(name)1502 getcurenv(name)
1503 char *name;
1504 {
1505 struct namnod *n;
1506
1507 n = findnam((unsigned char *)name);
1508 return (n ? (char *)n->namval:NULL);
1509 }
1510
1511 void
ev_insert(name)1512 ev_insert(name)
1513 char *name;
1514 {
1515 struct namnod *n;
1516 char *p = strchr(name, '=');
1517
1518 if (p == NULL)
1519 return;
1520
1521 *p = '\0';
1522 n = lookup((unsigned char *)name);
1523 *p = '=';
1524 if (n == 0)
1525 return;
1526
1527 assign(n, (unsigned char *)&p[1]);
1528
1529 n->namflg |= N_EXPORT;
1530 }
1531 #endif /* INTERACTIVE */
1532