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