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