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