1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)func.c	8.1 (Berkeley) 5/31/93";
37 #else
38 static const char rcsid[] =
39   "$FreeBSD: src/bin/csh/func.c,v 1.14 1999/08/27 23:13:47 peter Exp $";
40 #endif
41 #endif /* not lint */
42 
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <signal.h>
46 #include <locale.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #if __STDC__
51 # include <stdarg.h>
52 #else
53 # include <varargs.h>
54 #endif
55 
56 #include "csh.h"
57 #include "extern.h"
58 #include "pathnames.h"
59 
60 extern char **environ;
61 
62 static int zlast = -1;
63 static void	islogin __P((void));
64 static void	reexecute __P((struct command *));
65 static void	preread __P((void));
66 static void	doagain __P((void));
67 static void	search __P((int, int, Char *));
68 static int	getword __P((Char *));
69 static int	keyword __P((Char *));
70 static void	toend __P((void));
71 static void	xecho __P((int, Char **));
72 static void	Unsetenv __P((Char *));
73 
74 struct biltins *
isbfunc(t)75 isbfunc(t)
76     struct command *t;
77 {
78     Char *cp = t->t_dcom[0];
79     struct biltins *bp, *bp1, *bp2;
80     static struct biltins label = {"", dozip, 0, 0};
81     static struct biltins foregnd = {"%job", dofg1, 0, 0};
82     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
83 
84     if (lastchr(cp) == ':') {
85 	label.bname = short2str(cp);
86 	return (&label);
87     }
88     if (*cp == '%') {
89 	if (t->t_dflg & F_AMPERSAND) {
90 	    t->t_dflg &= ~F_AMPERSAND;
91 	    backgnd.bname = short2str(cp);
92 	    return (&backgnd);
93 	}
94 	foregnd.bname = short2str(cp);
95 	return (&foregnd);
96     }
97     /*
98      * Binary search Bp1 is the beginning of the current search range. Bp2 is
99      * one past the end.
100      */
101     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
102 	int i;
103 
104 	bp = bp1 + ((bp2 - bp1) >> 1);
105 	if ((i = *cp - *bp->bname) == 0 &&
106 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
107 	    return bp;
108 	if (i < 0)
109 	    bp2 = bp;
110 	else
111 	    bp1 = bp + 1;
112     }
113     return (0);
114 }
115 
116 void
func(t,bp)117 func(t, bp)
118     struct command *t;
119     struct biltins *bp;
120 {
121     int     i;
122 
123     xechoit(t->t_dcom);
124     setname(bp->bname);
125     i = blklen(t->t_dcom) - 1;
126     if (i < bp->minargs)
127 	stderror(ERR_NAME | ERR_TOOFEW);
128     if (i > bp->maxargs)
129 	stderror(ERR_NAME | ERR_TOOMANY);
130     (*bp->bfunct) (t->t_dcom, t);
131 }
132 
133 void
134 /*ARGSUSED*/
doonintr(v,t)135 doonintr(v, t)
136     Char **v;
137     struct command *t;
138 {
139     Char *cp;
140     Char *vv = v[1];
141 
142     if (parintr == SIG_IGN)
143 	return;
144     if (setintr && intty)
145 	stderror(ERR_NAME | ERR_TERMINAL);
146     cp = gointr;
147     gointr = 0;
148     xfree((ptr_t) cp);
149     if (vv == 0) {
150 	if (setintr)
151 	    (void) sigblock(sigmask(SIGINT));
152 	else
153 	    (void) signal(SIGINT, SIG_DFL);
154 	gointr = 0;
155     }
156     else if (eq((vv = strip(vv)), STRminus)) {
157 	(void) signal(SIGINT, SIG_IGN);
158 	gointr = Strsave(STRminus);
159     }
160     else {
161 	gointr = Strsave(vv);
162 	(void) signal(SIGINT, pintr);
163     }
164 }
165 
166 void
167 /*ARGSUSED*/
donohup(v,t)168 donohup(v, t)
169     Char **v;
170     struct command *t;
171 {
172     if (intty)
173 	stderror(ERR_NAME | ERR_TERMINAL);
174     if (setintr == 0) {
175 	(void) signal(SIGHUP, SIG_IGN);
176     }
177 }
178 
179 void
180 /*ARGSUSED*/
dozip(v,t)181 dozip(v, t)
182     Char **v;
183     struct command *t;
184 {
185     ;
186 }
187 
188 void
prvars()189 prvars()
190 {
191     plist(&shvhed);
192 }
193 
194 void
195 /*ARGSUSED*/
doalias(v,t)196 doalias(v, t)
197     Char **v;
198     struct command *t;
199 {
200     struct varent *vp;
201     Char *p;
202 
203     v++;
204     p = *v++;
205     if (p == 0)
206 	plist(&aliases);
207     else if (*v == 0) {
208 	vp = adrof1(strip(p), &aliases);
209 	if (vp) {
210 	    blkpr(cshout, vp->vec);
211 	    fputc('\n', cshout);
212 	}
213     }
214     else {
215 	if (eq(p, STRalias) || eq(p, STRunalias)) {
216 	    setname(vis_str(p));
217 	    stderror(ERR_NAME | ERR_DANGER);
218 	}
219 	set1(strip(p), saveblk(v), &aliases);
220     }
221 }
222 
223 void
224 /*ARGSUSED*/
unalias(v,t)225 unalias(v, t)
226     Char **v;
227     struct command *t;
228 {
229     unset1(v, &aliases);
230 }
231 
232 void
233 /*ARGSUSED*/
dologout(v,t)234 dologout(v, t)
235     Char **v;
236     struct command *t;
237 {
238     islogin();
239     goodbye();
240 }
241 
242 void
243 /*ARGSUSED*/
dologin(v,t)244 dologin(v, t)
245     Char **v;
246     struct command *t;
247 {
248     islogin();
249     rechist();
250     (void) signal(SIGTERM, parterm);
251     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
252     untty();
253     xexit(1);
254 }
255 
256 static void
islogin()257 islogin()
258 {
259     if (chkstop == 0 && setintr)
260 	panystop(0);
261     if (loginsh)
262 	return;
263     stderror(ERR_NOTLOGIN);
264 }
265 
266 void
doif(v,kp)267 doif(v, kp)
268     Char  **v;
269     struct command *kp;
270 {
271     int i;
272     Char **vv;
273 
274     v++;
275     i = expr(&v);
276     vv = v;
277     if (*vv == NULL)
278 	stderror(ERR_NAME | ERR_EMPTYIF);
279     if (eq(*vv, STRthen)) {
280 	if (*++vv)
281 	    stderror(ERR_NAME | ERR_IMPRTHEN);
282 	setname(vis_str(STRthen));
283 	/*
284 	 * If expression was zero, then scan to else, otherwise just fall into
285 	 * following code.
286 	 */
287 	if (!i)
288 	    search(T_IF, 0, NULL);
289 	return;
290     }
291     /*
292      * Simple command attached to this if. Left shift the node in this tree,
293      * munging it so we can reexecute it.
294      */
295     if (i) {
296 	lshift(kp->t_dcom, vv - kp->t_dcom);
297 	reexecute(kp);
298 	donefds();
299     }
300 }
301 
302 /*
303  * Reexecute a command, being careful not
304  * to redo i/o redirection, which is already set up.
305  */
306 static void
reexecute(kp)307 reexecute(kp)
308     struct command *kp;
309 {
310     kp->t_dflg &= F_SAVE;
311     kp->t_dflg |= F_REPEAT;
312     /*
313      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
314      * pgrp's as the jobs would then have no way to get the tty (we can't give
315      * it to them, and our parent wouldn't know their pgrp, etc.
316      */
317     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
318 }
319 
320 void
321 /*ARGSUSED*/
doelse(v,t)322 doelse(v, t)
323     Char **v;
324     struct command *t;
325 {
326     search(T_ELSE, 0, NULL);
327 }
328 
329 void
330 /*ARGSUSED*/
dogoto(v,t)331 dogoto(v, t)
332     Char **v;
333     struct command *t;
334 {
335     Char   *lp;
336 
337     gotolab(lp = globone(v[1], G_ERROR));
338     xfree((ptr_t) lp);
339 }
340 
341 void
gotolab(lab)342 gotolab(lab)
343     Char *lab;
344 {
345     struct whyle *wp;
346     /*
347      * While we still can, locate any unknown ends of existing loops. This
348      * obscure code is the WORST result of the fact that we don't really parse.
349      */
350     zlast = T_GOTO;
351     for (wp = whyles; wp; wp = wp->w_next)
352 	if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
353 	    search(T_BREAK, 0, NULL);
354 	    btell(&wp->w_end);
355 	}
356 	else
357 	    bseek(&wp->w_end);
358     search(T_GOTO, 0, lab);
359     /*
360      * Eliminate loops which were exited.
361      */
362     wfree();
363 }
364 
365 void
366 /*ARGSUSED*/
doswitch(v,t)367 doswitch(v, t)
368     Char **v;
369     struct command *t;
370 {
371     Char *cp, *lp;
372 
373     v++;
374     if (!*v || *(*v++) != '(')
375 	stderror(ERR_SYNTAX);
376     cp = **v == ')' ? STRNULL : *v++;
377     if (*(*v++) != ')')
378 	v--;
379     if (*v)
380 	stderror(ERR_SYNTAX);
381     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
382     xfree((ptr_t) lp);
383 }
384 
385 void
386 /*ARGSUSED*/
dobreak(v,t)387 dobreak(v, t)
388     Char **v;
389     struct command *t;
390 {
391     if (whyles)
392 	toend();
393     else
394 	stderror(ERR_NAME | ERR_NOTWHILE);
395 }
396 
397 void
398 /*ARGSUSED*/
doexit(v,t)399 doexit(v, t)
400     Char **v;
401     struct command *t;
402 {
403     if (chkstop == 0 && (intty || intact) && evalvec == 0)
404 	panystop(0);
405     /*
406      * Don't DEMAND parentheses here either.
407      */
408     v++;
409     if (*v) {
410 	set(STRstatus, putn(expr(&v)));
411 	if (*v)
412 	    stderror(ERR_NAME | ERR_EXPRESSION);
413     }
414     btoeof();
415     if (intty)
416 	(void) close(SHIN);
417 }
418 
419 void
420 /*ARGSUSED*/
doforeach(v,t)421 doforeach(v, t)
422     Char **v;
423     struct command *t;
424 {
425     Char *cp, *sp;
426     struct whyle *nwp;
427 
428     v++;
429     sp = cp = strip(*v);
430     if (!letter(*sp))
431 	stderror(ERR_NAME | ERR_VARBEGIN);
432     while (*cp && alnum(*cp))
433 	cp++;
434     if (*cp)
435 	stderror(ERR_NAME | ERR_VARALNUM);
436     if ((cp - sp) > MAXVARLEN)
437 	stderror(ERR_NAME | ERR_VARTOOLONG);
438     cp = *v++;
439     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
440 	stderror(ERR_NAME | ERR_NOPAREN);
441     v++;
442     gflag = 0, tglob(v);
443     v = globall(v);
444     if (v == 0)
445 	stderror(ERR_NAME | ERR_NOMATCH);
446     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
447     nwp->w_fe = nwp->w_fe0 = v;
448     gargv = 0;
449     btell(&nwp->w_start);
450     nwp->w_fename = Strsave(cp);
451     nwp->w_next = whyles;
452     nwp->w_end.type = F_SEEK;
453     whyles = nwp;
454     /*
455      * Pre-read the loop so as to be more comprehensible to a terminal user.
456      */
457     zlast = T_FOREACH;
458     if (intty)
459 	preread();
460     doagain();
461 }
462 
463 void
464 /*ARGSUSED*/
dowhile(v,t)465 dowhile(v, t)
466     Char **v;
467     struct command *t;
468 {
469     int status;
470     bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
471     whyles->w_fename == 0;
472 
473     v++;
474     /*
475      * Implement prereading here also, taking care not to evaluate the
476      * expression before the loop has been read up from a terminal.
477      */
478     if (intty && !again)
479 	status = !exp0(&v, 1);
480     else
481 	status = !expr(&v);
482     if (*v)
483 	stderror(ERR_NAME | ERR_EXPRESSION);
484     if (!again) {
485 	struct whyle *nwp =
486 	(struct whyle *) xcalloc(1, sizeof(*nwp));
487 
488 	nwp->w_start = lineloc;
489 	nwp->w_end.type = F_SEEK;
490 	nwp->w_end.f_seek = 0;
491 	nwp->w_next = whyles;
492 	whyles = nwp;
493 	zlast = T_WHILE;
494 	if (intty) {
495 	    /*
496 	     * The tty preread
497 	     */
498 	    preread();
499 	    doagain();
500 	    return;
501 	}
502     }
503     if (status)
504 	/* We ain't gonna loop no more, no more! */
505 	toend();
506 }
507 
508 static void
preread()509 preread()
510 {
511     whyles->w_end.type = I_SEEK;
512     if (setintr)
513 	(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
514 
515     search(T_BREAK, 0, NULL);		/* read the expression in */
516     if (setintr)
517 	(void) sigblock(sigmask(SIGINT));
518     btell(&whyles->w_end);
519 }
520 
521 void
522 /*ARGSUSED*/
doend(v,t)523 doend(v, t)
524     Char **v;
525     struct command *t;
526 {
527     if (!whyles)
528 	stderror(ERR_NAME | ERR_NOTWHILE);
529     btell(&whyles->w_end);
530     doagain();
531 }
532 
533 void
534 /*ARGSUSED*/
docontin(v,t)535 docontin(v, t)
536     Char **v;
537     struct command *t;
538 {
539     if (!whyles)
540 	stderror(ERR_NAME | ERR_NOTWHILE);
541     doagain();
542 }
543 
544 static void
doagain()545 doagain()
546 {
547     /* Repeating a while is simple */
548     if (whyles->w_fename == 0) {
549 	bseek(&whyles->w_start);
550 	return;
551     }
552     /*
553      * The foreach variable list actually has a spurious word ")" at the end of
554      * the w_fe list.  Thus we are at the of the list if one word beyond this
555      * is 0.
556      */
557     if (!whyles->w_fe[1]) {
558 	dobreak(NULL, NULL);
559 	return;
560     }
561     set(whyles->w_fename, Strsave(*whyles->w_fe++));
562     bseek(&whyles->w_start);
563 }
564 
565 void
dorepeat(v,kp)566 dorepeat(v, kp)
567     Char  **v;
568     struct command *kp;
569 {
570     int i;
571     int omask = 0;
572 
573     i = getn(v[1]);
574     if (setintr)
575 	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
576     lshift(v, 2);
577     while (i > 0) {
578 	if (setintr)
579 	    (void) sigsetmask(omask);
580 	reexecute(kp);
581 	--i;
582     }
583     donefds();
584     if (setintr)
585 	(void) sigsetmask(omask);
586 }
587 
588 void
589 /*ARGSUSED*/
doswbrk(v,t)590 doswbrk(v, t)
591     Char **v;
592     struct command *t;
593 {
594     search(T_BRKSW, 0, NULL);
595 }
596 
597 int
srchx(cp)598 srchx(cp)
599     Char *cp;
600 {
601     struct srch *sp, *sp1, *sp2;
602     int i;
603 
604     /*
605      * Binary search Sp1 is the beginning of the current search range. Sp2 is
606      * one past the end.
607      */
608     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
609 	sp = sp1 + ((sp2 - sp1) >> 1);
610 	if ((i = *cp - *sp->s_name) == 0 &&
611 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
612 	    return sp->s_value;
613 	if (i < 0)
614 	    sp2 = sp;
615 	else
616 	    sp1 = sp + 1;
617     }
618     return (-1);
619 }
620 
621 static Char Stype;
622 static Char *Sgoal;
623 
624 /*VARARGS2*/
625 static void
search(type,level,goal)626 search(type, level, goal)
627     int     type;
628     int level;
629     Char   *goal;
630 {
631     Char    wordbuf[BUFSIZ];
632     Char *aword = wordbuf;
633     Char *cp;
634 
635     Stype = type;
636     Sgoal = goal;
637     if (type == T_GOTO) {
638 	struct Ain a;
639 	a.type = F_SEEK;
640 	a.f_seek = 0;
641 	bseek(&a);
642     }
643     do {
644 	if (intty && fseekp == feobp && aret == F_SEEK)
645 	    (void) fprintf(cshout, "? "), (void) fflush(cshout);
646 	aword[0] = 0;
647 	(void) getword(aword);
648 	switch (srchx(aword)) {
649 
650 	case T_ELSE:
651 	    if (level == 0 && type == T_IF)
652 		return;
653 	    break;
654 
655 	case T_IF:
656 	    while (getword(aword))
657 		continue;
658 	    if ((type == T_IF || type == T_ELSE) &&
659 		eq(aword, STRthen))
660 		level++;
661 	    break;
662 
663 	case T_ENDIF:
664 	    if (type == T_IF || type == T_ELSE)
665 		level--;
666 	    break;
667 
668 	case T_FOREACH:
669 	case T_WHILE:
670 	    if (type == T_BREAK)
671 		level++;
672 	    break;
673 
674 	case T_END:
675 	    if (type == T_BREAK)
676 		level--;
677 	    break;
678 
679 	case T_SWITCH:
680 	    if (type == T_SWITCH || type == T_BRKSW)
681 		level++;
682 	    break;
683 
684 	case T_ENDSW:
685 	    if (type == T_SWITCH || type == T_BRKSW)
686 		level--;
687 	    break;
688 
689 	case T_LABEL:
690 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
691 		level = -1;
692 	    break;
693 
694 	default:
695 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
696 		break;
697 	    if (lastchr(aword) != ':')
698 		break;
699 	    aword[Strlen(aword) - 1] = 0;
700 	    if ((type == T_GOTO && eq(aword, goal)) ||
701 		(type == T_SWITCH && eq(aword, STRdefault)))
702 		level = -1;
703 	    break;
704 
705 	case T_CASE:
706 	    if (type != T_SWITCH || level != 0)
707 		break;
708 	    (void) getword(aword);
709 	    if (lastchr(aword) == ':')
710 		aword[Strlen(aword) - 1] = 0;
711 	    cp = strip(Dfix1(aword));
712 	    if (Gmatch(goal, cp))
713 		level = -1;
714 	    xfree((ptr_t) cp);
715 	    break;
716 
717 	case T_DEFAULT:
718 	    if (type == T_SWITCH && level == 0)
719 		level = -1;
720 	    break;
721 	}
722 	(void) getword(NULL);
723     } while (level >= 0);
724 }
725 
726 static int
getword(wp)727 getword(wp)
728     Char *wp;
729 {
730     int found = 0;
731     int c, d;
732     int     kwd = 0;
733     Char   *owp = wp;
734 
735     c = readc(1);
736     d = 0;
737     do {
738 	while (c == ' ' || c == '\t')
739 	    c = readc(1);
740 	if (c == '#')
741 	    do
742 		c = readc(1);
743 	    while (c >= 0 && c != '\n');
744 	if (c < 0)
745 	    goto past;
746 	if (c == '\n') {
747 	    if (wp)
748 		break;
749 	    return (0);
750 	}
751 	unreadc(c);
752 	found = 1;
753 	do {
754 	    c = readc(1);
755 	    if (c == '\\' && (c = readc(1)) == '\n')
756 		c = ' ';
757 	    if (c == '\'' || c == '"') {
758 		if (d == 0)
759 		    d = c;
760 		else if (d == c)
761 		    d = 0;
762 	    }
763 	    if (c < 0)
764 		goto past;
765 	    if (wp) {
766 		*wp++ = c;
767 		*wp = 0;	/* end the string b4 test */
768 	    }
769 	} while ((d || (!(kwd = keyword(owp)) && c != ' '
770 		  && c != '\t')) && c != '\n');
771     } while (wp == 0);
772 
773     /*
774      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
775      * need to unreadc the look-ahead char
776      */
777     if (!kwd) {
778 	unreadc(c);
779 	if (found)
780 	    *--wp = 0;
781     }
782 
783     return (found);
784 
785 past:
786     switch (Stype) {
787 
788     case T_IF:
789 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
790 
791     case T_ELSE:
792 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
793 
794     case T_BRKSW:
795     case T_SWITCH:
796 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
797 
798     case T_BREAK:
799 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
800 
801     case T_GOTO:
802 	setname(vis_str(Sgoal));
803 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
804     }
805     /* NOTREACHED */
806     return (0);
807 }
808 
809 /*
810  * keyword(wp) determines if wp is one of the built-n functions if,
811  * switch or while. It seems that when an if statement looks like
812  * "if(" then getword above sucks in the '(' and so the search routine
813  * never finds what it is scanning for. Rather than rewrite doword, I hack
814  * in a test to see if the string forms a keyword. Then doword stops
815  * and returns the word "if" -strike
816  */
817 
818 static int
keyword(wp)819 keyword(wp)
820     Char   *wp;
821 {
822     static Char STRif[] = {'i', 'f', '\0'};
823     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
824     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
825 
826     if (!wp)
827 	return (0);
828 
829     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
830 	|| (Strcmp(wp, STRswitch) == 0))
831 	return (1);
832 
833     return (0);
834 }
835 
836 static void
toend()837 toend()
838 {
839     if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
840 	search(T_BREAK, 0, NULL);
841 	btell(&whyles->w_end);
842 	whyles->w_end.f_seek--;
843     }
844     else
845 	bseek(&whyles->w_end);
846     wfree();
847 }
848 
849 void
wfree()850 wfree()
851 {
852     struct Ain    o;
853     struct whyle *nwp;
854 
855     btell(&o);
856 
857     for (; whyles; whyles = nwp) {
858 	struct whyle *wp = whyles;
859 	nwp = wp->w_next;
860 
861 	/*
862 	 * We free loops that have different seek types.
863 	 */
864 	if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
865 	    wp->w_start.type == o.type) {
866 	    if (wp->w_end.type == F_SEEK) {
867 		if (o.f_seek >= wp->w_start.f_seek &&
868 		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
869 		    break;
870 	    }
871 	    else {
872 		if (o.a_seek >= wp->w_start.a_seek &&
873 		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
874 		    break;
875 	    }
876 	}
877 
878 	if (wp->w_fe0)
879 	    blkfree(wp->w_fe0);
880 	if (wp->w_fename)
881 	    xfree((ptr_t) wp->w_fename);
882 	xfree((ptr_t) wp);
883     }
884 }
885 
886 void
887 /*ARGSUSED*/
doecho(v,t)888 doecho(v, t)
889     Char **v;
890     struct command *t;
891 {
892     xecho(' ', v);
893 }
894 
895 void
896 /*ARGSUSED*/
doglob(v,t)897 doglob(v, t)
898     Char **v;
899     struct command *t;
900 {
901     xecho(0, v);
902     (void) fflush(cshout);
903 }
904 
905 static void
xecho(sep,v)906 xecho(sep, v)
907     int    sep;
908     Char **v;
909 {
910     Char *cp;
911     int     nonl = 0;
912 
913     if (setintr)
914 	(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
915     v++;
916     if (*v == 0)
917 	return;
918     gflag = 0, tglob(v);
919     if (gflag) {
920 	v = globall(v);
921 	if (v == 0)
922 	    stderror(ERR_NAME | ERR_NOMATCH);
923     }
924     else {
925 	v = gargv = saveblk(v);
926 	trim(v);
927     }
928     if (sep == ' ' && *v && eq(*v, STRmn))
929 	nonl++, v++;
930     while ((cp = *v++) != NULL) {
931 	int c;
932 
933 	while ((c = *cp++) != '\0')
934 	    (void) vis_fputc(c | QUOTE, cshout);
935 
936 	if (*v)
937 	    (void) vis_fputc(sep | QUOTE, cshout);
938     }
939     if (sep && nonl == 0)
940 	(void) fputc('\n', cshout);
941     else
942 	(void) fflush(cshout);
943     if (setintr)
944 	(void) sigblock(sigmask(SIGINT));
945     if (gargv)
946 	blkfree(gargv), gargv = 0;
947 }
948 
949 void
950 /*ARGSUSED*/
dosetenv(v,t)951 dosetenv(v, t)
952     Char **v;
953     struct command *t;
954 {
955     Char   *vp, *lp;
956 
957     v++;
958     if ((vp = *v++) == 0) {
959 	Char **ep;
960 
961 	if (setintr)
962 	    (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
963 	for (ep = STR_environ; *ep; ep++)
964 	    (void) fprintf(cshout, "%s\n", vis_str(*ep));
965 	return;
966     }
967     if ((lp = *v++) == 0)
968 	lp = STRNULL;
969     Setenv(vp, lp = globone(lp, G_APPEND));
970     if (eq(vp, STRPATH)) {
971 	importpath(lp);
972 	dohash(NULL, NULL);
973     }
974     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE) ||
975 	     eq(vp, STRLC_ALL) || eq(vp, STRLC_COLLATE)) {
976 #ifdef NLS
977 	int     k;
978 
979 	(void) setlocale(LC_ALL, "");
980 	for (k = 0200; k <= 0377 && !Isprint(k); k++)
981 		continue;
982 	AsciiOnly = k > 0377;
983 #else
984 	AsciiOnly = 0;
985 #endif				/* NLS */
986     }
987     xfree((ptr_t) lp);
988 }
989 
990 void
991 /*ARGSUSED*/
dounsetenv(v,t)992 dounsetenv(v, t)
993     Char **v;
994     struct command *t;
995 {
996     Char  **ep, *p, *n;
997     int     i, maxi;
998     static Char *name = NULL;
999 
1000     if (name)
1001 	xfree((ptr_t) name);
1002     /*
1003      * Find the longest environment variable
1004      */
1005     for (maxi = 0, ep = STR_environ; *ep; ep++) {
1006 	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
1007 	    continue;
1008 	if (i > maxi)
1009 	    maxi = i;
1010     }
1011 
1012     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
1013 
1014     while (++v && *v)
1015 	for (maxi = 1; maxi;)
1016 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
1017 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1018 		    continue;
1019 		*n = '\0';
1020 		if (!Gmatch(name, *v))
1021 		    continue;
1022 		maxi = 1;
1023 		/*
1024 		 * Delete name, and start again cause the environment changes
1025 		 */
1026 		Unsetenv(name);
1027 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE) ||
1028 		    eq(name, STRLC_ALL) || eq(name, STRLC_COLLATE)) {
1029 #ifdef NLS
1030 		    int     k;
1031 
1032 		    (void) setlocale(LC_ALL, "");
1033 		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
1034 			continue;
1035 		    AsciiOnly = k > 0377;
1036 #else
1037 		    AsciiOnly = getenv("LANG") == NULL &&
1038 			getenv("LC_ALL") == NULL &&
1039 			getenv("LC_CTYPE") == NULL;
1040 #endif				/* NLS */
1041 		}
1042 		break;
1043 	    }
1044     xfree((ptr_t) name);
1045     name = NULL;
1046 }
1047 
1048 void
Setenv(name,val)1049 Setenv(name, val)
1050     Char   *name, *val;
1051 {
1052     Char **ep = STR_environ;
1053     Char *cp, *dp;
1054     Char   *blk[2];
1055     Char  **oep = ep;
1056 
1057 
1058     for (; *ep; ep++) {
1059 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1060 	    continue;
1061 	if (*cp != 0 || *dp != '=')
1062 	    continue;
1063 	cp = Strspl(STRequal, val);
1064 	xfree((ptr_t) * ep);
1065 	*ep = strip(Strspl(name, cp));
1066 	xfree((ptr_t) cp);
1067 	blkfree((Char **) environ);
1068 	environ = short2blk(STR_environ);
1069 	return;
1070     }
1071     cp = Strspl(name, STRequal);
1072     blk[0] = strip(Strspl(cp, val));
1073     xfree((ptr_t) cp);
1074     blk[1] = 0;
1075     STR_environ = blkspl(STR_environ, blk);
1076     blkfree((Char **) environ);
1077     environ = short2blk(STR_environ);
1078     xfree((ptr_t) oep);
1079 }
1080 
1081 static void
Unsetenv(name)1082 Unsetenv(name)
1083     Char   *name;
1084 {
1085     Char **ep = STR_environ;
1086     Char *cp, *dp;
1087     Char  **oep = ep;
1088 
1089     for (; *ep; ep++) {
1090 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1091 	    continue;
1092 	if (*cp != 0 || *dp != '=')
1093 	    continue;
1094 	cp = *ep;
1095 	*ep = 0;
1096 	STR_environ = blkspl(STR_environ, ep + 1);
1097 	environ = short2blk(STR_environ);
1098 	*ep = cp;
1099 	xfree((ptr_t) cp);
1100 	xfree((ptr_t) oep);
1101 	return;
1102     }
1103 }
1104 
1105 void
1106 /*ARGSUSED*/
doumask(v,t)1107 doumask(v, t)
1108     Char **v;
1109     struct command *t;
1110 {
1111     Char *cp = v[1];
1112     int i;
1113 
1114     if (cp == 0) {
1115 	i = umask(0);
1116 	(void) umask(i);
1117 	(void) fprintf(cshout, "%o\n", i);
1118 	return;
1119     }
1120     i = 0;
1121     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1122 	i = i * 8 + *cp++ - '0';
1123     if (*cp || i < 0 || i > 0777)
1124 	stderror(ERR_NAME | ERR_MASK);
1125     (void) umask(i);
1126 }
1127 
1128 typedef quad_t RLIM_TYPE;
1129 
1130 static struct limits {
1131     int     limconst;
1132     char   *limname;
1133     int     limdiv;
1134     char   *limscale;
1135 }       limits[] = {
1136     { RLIMIT_CPU,	"cputime",	1,	"seconds" },
1137     { RLIMIT_FSIZE,	"filesize",	1024,	"kbytes" },
1138     { RLIMIT_DATA,	"datasize",	1024,	"kbytes" },
1139     { RLIMIT_STACK,	"stacksize",	1024,	"kbytes" },
1140     { RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes" },
1141     { RLIMIT_RSS,	"memoryuse",	1024,	"kbytes" },
1142     { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes" },
1143     { RLIMIT_NPROC,	"maxproc",	1,	"" },
1144     { RLIMIT_NOFILE,	"openfiles",	1,	"" },
1145     { RLIMIT_SBSIZE,	"sbsize ",	1,	"bytes" },
1146     { -1,		NULL,		0,	NULL }
1147 };
1148 
1149 static struct limits *findlim();
1150 static RLIM_TYPE getval();
1151 static void limtail();
1152 static void plim();
1153 static int setlim();
1154 
1155 static struct limits *
findlim(cp)1156 findlim(cp)
1157     Char   *cp;
1158 {
1159     struct limits *lp, *res;
1160 
1161     res = (struct limits *) NULL;
1162     for (lp = limits; lp->limconst >= 0; lp++)
1163 	if (prefix(cp, str2short(lp->limname))) {
1164 	    if (res)
1165 		stderror(ERR_NAME | ERR_AMBIG);
1166 	    res = lp;
1167 	}
1168     if (res)
1169 	return (res);
1170     stderror(ERR_NAME | ERR_LIMIT);
1171     /* NOTREACHED */
1172     return (0);
1173 }
1174 
1175 void
1176 /*ARGSUSED*/
dolimit(v,t)1177 dolimit(v, t)
1178     Char **v;
1179     struct command *t;
1180 {
1181     struct limits *lp;
1182     RLIM_TYPE limit;
1183     char    hard = 0;
1184 
1185     v++;
1186     if (*v && eq(*v, STRmh)) {
1187 	hard = 1;
1188 	v++;
1189     }
1190     if (*v == 0) {
1191 	for (lp = limits; lp->limconst >= 0; lp++)
1192 	    plim(lp, hard);
1193 	return;
1194     }
1195     lp = findlim(v[0]);
1196     if (v[1] == 0) {
1197 	plim(lp, hard);
1198 	return;
1199     }
1200     limit = getval(lp, v + 1);
1201     if (setlim(lp, hard, limit) < 0)
1202 	stderror(ERR_SILENT);
1203 }
1204 
1205 static  RLIM_TYPE
getval(lp,v)1206 getval(lp, v)
1207     struct limits *lp;
1208     Char  **v;
1209 {
1210     float f;
1211     Char   *cp = *v++;
1212 
1213     f = atof(short2str(cp));
1214 
1215     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1216 	cp++;
1217     if (*cp == 0) {
1218 	if (*v == 0)
1219 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
1220 	cp = *v;
1221     }
1222     switch (*cp) {
1223     case ':':
1224 	if (lp->limconst != RLIMIT_CPU)
1225 	    goto badscal;
1226 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
1227     case 'h':
1228 	if (lp->limconst != RLIMIT_CPU)
1229 	    goto badscal;
1230 	limtail(cp, "hours");
1231 	f *= 3600.0;
1232 	break;
1233     case 'm':
1234 	if (lp->limconst == RLIMIT_CPU) {
1235 	    limtail(cp, "minutes");
1236 	    f *= 60.0;
1237 	    break;
1238 	}
1239 	*cp = 'm';
1240 	limtail(cp, "megabytes");
1241 	f *= 1024.0 * 1024.0;
1242 	break;
1243     case 's':
1244 	if (lp->limconst != RLIMIT_CPU)
1245 	    goto badscal;
1246 	limtail(cp, "seconds");
1247 	break;
1248     case 'M':
1249 	if (lp->limconst == RLIMIT_CPU)
1250 	    goto badscal;
1251 	*cp = 'm';
1252 	limtail(cp, "megabytes");
1253 	f *= 1024.0 * 1024.0;
1254 	break;
1255     case 'k':
1256 	if (lp->limconst == RLIMIT_CPU)
1257 	    goto badscal;
1258 	limtail(cp, "kbytes");
1259 	f *= 1024.0;
1260 	break;
1261     case 'u':
1262 	limtail(cp, "unlimited");
1263 	return (RLIM_INFINITY);
1264     default:
1265 badscal:
1266 	stderror(ERR_NAME | ERR_SCALEF);
1267     }
1268     f += 0.5;
1269     if (f > (float) RLIM_INFINITY)
1270 	return RLIM_INFINITY;
1271     else
1272 	return ((RLIM_TYPE) f);
1273 }
1274 
1275 static void
limtail(cp,str)1276 limtail(cp, str)
1277     Char   *cp;
1278     char   *str;
1279 {
1280     while (*cp && *cp == *str)
1281 	cp++, str++;
1282     if (*cp)
1283 	stderror(ERR_BADSCALE, str);
1284 }
1285 
1286 
1287 /*ARGSUSED*/
1288 static void
plim(lp,hard)1289 plim(lp, hard)
1290     struct limits *lp;
1291     Char    hard;
1292 {
1293     struct rlimit rlim;
1294     RLIM_TYPE limit;
1295 
1296     (void) fprintf(cshout, "%s \t", lp->limname);
1297 
1298     (void) getrlimit(lp->limconst, &rlim);
1299     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1300 
1301     if (limit == RLIM_INFINITY)
1302 	(void) fprintf(cshout, "unlimited");
1303     else if (lp->limconst == RLIMIT_CPU)
1304 	psecs((long) limit);
1305     else
1306 	(void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
1307 		       lp->limscale);
1308     (void) fputc('\n', cshout);
1309 }
1310 
1311 void
1312 /*ARGSUSED*/
dounlimit(v,t)1313 dounlimit(v, t)
1314     Char **v;
1315     struct command *t;
1316 {
1317     struct limits *lp;
1318     int     lerr = 0;
1319     Char    hard = 0;
1320 
1321     v++;
1322     if (*v && eq(*v, STRmh)) {
1323 	hard = 1;
1324 	v++;
1325     }
1326     if (*v == 0) {
1327 	for (lp = limits; lp->limconst >= 0; lp++)
1328 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1329 		lerr++;
1330 	if (lerr)
1331 	    stderror(ERR_SILENT);
1332 	return;
1333     }
1334     while (*v) {
1335 	lp = findlim(*v++);
1336 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1337 	    stderror(ERR_SILENT);
1338     }
1339 }
1340 
1341 static int
setlim(lp,hard,limit)1342 setlim(lp, hard, limit)
1343     struct limits *lp;
1344     Char    hard;
1345     RLIM_TYPE limit;
1346 {
1347     struct rlimit rlim;
1348 
1349     (void) getrlimit(lp->limconst, &rlim);
1350 
1351     if (hard)
1352 	rlim.rlim_max = limit;
1353     else if (limit == RLIM_INFINITY && geteuid() != 0)
1354 	rlim.rlim_cur = rlim.rlim_max;
1355     else
1356 	rlim.rlim_cur = limit;
1357 
1358     if (setrlimit(lp->limconst, &rlim) < 0) {
1359 	(void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
1360 		       limit == RLIM_INFINITY ? "remove" : "set",
1361 		       hard ? " hard" : "");
1362 	return (-1);
1363     }
1364     return (0);
1365 }
1366 
1367 void
1368 /*ARGSUSED*/
dosuspend(v,t)1369 dosuspend(v, t)
1370     Char **v;
1371     struct command *t;
1372 {
1373     int     ctpgrp;
1374 
1375     void    (*old) __P((int));
1376 
1377     if (loginsh)
1378 	stderror(ERR_SUSPLOG);
1379     untty();
1380 
1381     old = signal(SIGTSTP, SIG_DFL);
1382     (void) kill(0, SIGTSTP);
1383     /* the shell stops here */
1384     (void) signal(SIGTSTP, old);
1385 
1386     if (tpgrp != -1) {
1387 	ctpgrp = tcgetpgrp(FSHTTY);
1388 	while  (ctpgrp != opgrp) {
1389 	    old = signal(SIGTTIN, SIG_DFL);
1390 	    (void) kill(0, SIGTTIN);
1391 	    (void) signal(SIGTTIN, old);
1392 	}
1393 	(void) setpgid(0, shpgrp);
1394 	(void) tcsetpgrp(FSHTTY, shpgrp);
1395     }
1396 }
1397 
1398 /* This is the dreaded EVAL built-in.
1399  *   If you don't fiddle with file descriptors, and reset didfds,
1400  *   this command will either ignore redirection inside or outside
1401  *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
1402  *   The stuff here seems to work, but I did it by trial and error rather
1403  *   than really knowing what was going on.  If tpgrp is zero, we are
1404  *   probably a background eval, e.g. "eval date &", and we want to
1405  *   make sure that any processes we start stay in our pgrp.
1406  *   This is also the case for "time eval date" -- stay in same pgrp.
1407  *   Otherwise, under stty tostop, processes will stop in the wrong
1408  *   pgrp, with no way for the shell to get them going again.  -IAN!
1409  */
1410 static Char **gv = NULL;
1411 void
1412 /*ARGSUSED*/
doeval(v,t)1413 doeval(v, t)
1414     Char **v;
1415     struct command *t;
1416 {
1417     Char  **oevalvec;
1418     Char   *oevalp;
1419     int     odidfds;
1420     jmp_buf osetexit;
1421     int     my_reenter;
1422     Char  **savegv = gv;
1423     int     saveIN;
1424     int     saveOUT;
1425     int     saveERR;
1426     int     oSHIN;
1427     int     oSHOUT;
1428     int     oSHERR;
1429 
1430     UNREGISTER(v);
1431 
1432     oevalvec = evalvec;
1433     oevalp = evalp;
1434     odidfds = didfds;
1435     oSHIN = SHIN;
1436     oSHOUT = SHOUT;
1437     oSHERR = SHERR;
1438 
1439     v++;
1440     if (*v == 0)
1441 	return;
1442     gflag = 0, tglob(v);
1443     if (gflag) {
1444 	gv = v = globall(v);
1445 	gargv = 0;
1446 	if (v == 0)
1447 	    stderror(ERR_NOMATCH);
1448 	v = copyblk(v);
1449     }
1450     else {
1451 	gv = NULL;
1452 	v = copyblk(v);
1453 	trim(v);
1454     }
1455 
1456     saveIN = dcopy(SHIN, -1);
1457     saveOUT = dcopy(SHOUT, -1);
1458     saveERR = dcopy(SHERR, -1);
1459 
1460     getexit(osetexit);
1461 
1462     if ((my_reenter = setexit()) == 0) {
1463 	evalvec = v;
1464 	evalp = 0;
1465 	SHIN = dcopy(0, -1);
1466 	SHOUT = dcopy(1, -1);
1467 	SHERR = dcopy(2, -1);
1468 	didfds = 0;
1469 	process(0);
1470     }
1471 
1472     evalvec = oevalvec;
1473     evalp = oevalp;
1474     doneinp = 0;
1475     didfds = odidfds;
1476     (void) close(SHIN);
1477     (void) close(SHOUT);
1478     (void) close(SHERR);
1479     SHIN = dmove(saveIN, oSHIN);
1480     SHOUT = dmove(saveOUT, oSHOUT);
1481     SHERR = dmove(saveERR, oSHERR);
1482     if (gv)
1483 	blkfree(gv), gv = NULL;
1484     resexit(osetexit);
1485     gv = savegv;
1486     if (my_reenter)
1487 	stderror(ERR_SILENT);
1488 }
1489 
1490 void
1491 /*ARGSUSED*/
doprintf(v,t)1492 doprintf(v, t)
1493     Char **v;
1494     struct command *t;
1495 {
1496     Char **newv;
1497     char **c;
1498     extern int progprintf __P((int, char **));
1499     int ret;
1500 
1501     gflag = 0;
1502     tglob(v);
1503     if (gflag) {
1504         newv = globall(v);
1505         if (newv == 0) {
1506             stderror(ERR_NAME | ERR_NOMATCH);
1507             return;
1508         }
1509         v = newv;
1510         gargv=0;
1511     }
1512 
1513     ret = progprintf(blklen(v), c = short2blk(v));
1514     (void) fflush(cshout);
1515     (void) fflush(csherr);
1516 
1517     blkfree((Char **) c);
1518     if (ret)
1519 	stderror(ERR_SILENT);
1520 }
1521