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