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