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