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