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