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