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