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