Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / csh / sh.func.c
blob79350599dfea442195d5c47042dc4e4d4a187037
1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include "sh.h"
18 #include <locale.h> /* For LC_ALL */
19 #include "sh.tconst.h"
20 #include <sys/types.h>
21 #include <stdlib.h>
24 * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0. In
25 * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new. Beware of consusing
26 * the keywords that the command prints for these two. The old one was
27 * "memoryuse" and the new one is "memorysize". Note also that a given limit
28 * doesn't necessarily appear in the same position in the two releases.
30 struct limits {
31 int limconst;
32 tchar *limname;
33 int limdiv;
34 tchar *limscale;
35 } limits[] = {
36 RLIMIT_CPU, S_cputime, /* "cputime" */
37 1, S_seconds, /* "seconds" */
38 RLIMIT_FSIZE, S_filesize, /* "filesize" */
39 1024, S_kbytes, /* "kbytes" */
40 RLIMIT_DATA, S_datasize, /* "datasize" */
41 1024, S_kbytes, /* "kbytes" */
42 RLIMIT_STACK, S_stacksize, /* "stacksize" */
43 1024, S_kbytes, /* "kbytes" */
44 RLIMIT_CORE, S_coredumpsize, /* "coredumpsize" */
45 1024, S_kbytes, /* "kbytes" */
46 RLIMIT_NOFILE, S_descriptors, /* "descriptors" */
47 1, S_, /* "" */
48 RLIMIT_VMEM, S_memorysize, /* "memorysize" */
49 1024, S_kbytes, /* "kbytes" */
50 -1, 0,
54 static int getval(struct limits *lp, tchar **v, rlim_t *);
55 void islogin(void);
56 int dolabel(void);
57 void reexecute(struct command *kp);
58 void preread_(void);
59 void doagain(void);
60 void toend(void);
61 void wfree(void);
62 void echo(tchar sep, tchar **v);
63 void local_setenv(tchar *name, tchar *val);
64 void local_unsetenv(tchar *name);
65 void limtail(tchar *cp, tchar *str0);
66 void plim(struct limits *lp, tchar hard);
67 void search();
69 #define BUFSZ 1028
72 * C shell
75 struct biltins *
76 isbfunc(struct command *t)
78 tchar *cp = t->t_dcom[0];
79 struct biltins *bp, *bp1, *bp2;
80 int dofg1(), dobg1();
82 static struct biltins label = { S_, dolabel, 0, 0 };
83 static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 };
84 static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 };
85 #ifdef TRACE
86 tprintf("TRACE- isbfunc()\n");
87 #endif
88 if (lastchr(cp) == ':') {
89 label.bname = cp;
90 return (&label);
92 if (*cp == '%') {
93 if (t->t_dflg & FAND) {
94 t->t_dflg &= ~FAND;
95 backgnd.bname = cp;
96 return (&backgnd);
98 foregnd.bname = cp;
99 return (&foregnd);
102 * Binary search
103 * Bp1 is the beginning of the current search range.
104 * Bp2 is one past the end.
106 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) {
107 int i;
109 bp = bp1 + (bp2 - bp1 >> 1);
110 if ((i = *cp - *bp->bname) == 0 &&
111 (i = strcmp_(cp, bp->bname)) == 0) {
112 return (bp);
114 if (i < 0) {
115 bp2 = bp;
116 } else {
117 bp1 = bp + 1;
120 return (0);
123 void
124 func(struct command *t, struct biltins *bp)
126 int i;
128 #ifdef TRACE
129 tprintf("TRACE- func()\n");
130 #endif
131 xechoit(t->t_dcom);
132 setname(bp->bname);
133 i = blklen(t->t_dcom) - 1;
134 if (i < bp->minargs) {
135 bferr("Too few arguments");
137 if (i > bp->maxargs) {
138 bferr("Too many arguments");
140 (*bp->bfunct)(t->t_dcom, t);
144 dolabel(void)
146 #ifdef TRACE
147 tprintf("TRACE- dolabel()\n");
148 #endif
149 return (0);
152 void
153 doonintr(tchar **v)
155 tchar *cp;
156 tchar *vv = v[1];
158 #ifdef TRACE
159 tprintf("TRACE- doonintr()\n");
160 #endif
161 if (parintr == SIG_IGN) {
162 return;
164 if (setintr && intty) {
165 bferr("Can't from terminal");
167 cp = gointr, gointr = 0, xfree(cp);
168 if (vv == 0) {
169 if (setintr) {
170 (void) sigblock(sigmask(SIGINT));
171 } else {
172 (void) signal(SIGINT, SIG_DFL);
174 gointr = 0;
175 } else if (eq((vv = strip(vv)), S_MINUS)) {
176 (void) signal(SIGINT, SIG_IGN);
177 gointr = S_MINUS;
178 } else {
179 gointr = savestr(vv);
180 (void) signal(SIGINT, pintr);
184 void
185 donohup(void)
188 #ifdef TRACE
189 tprintf("TRACE- donohup()\n");
190 #endif
191 if (intty) {
192 bferr("Can't from terminal");
194 if (setintr == 0) {
195 (void) signal(SIGHUP, SIG_IGN);
196 #ifdef CC
197 submit(getpid());
198 #endif
202 void
203 dozip(void)
208 void
209 prvars(void)
211 #ifdef TRACE
212 tprintf("TRACE- prvars()\n");
213 #endif
215 plist(&shvhed);
218 void
219 doalias(tchar **v)
221 struct varent *vp;
222 tchar *p;
224 #ifdef TRACE
225 tprintf("TRACE- doalias()\n");
226 #endif
227 v++;
228 p = *v++;
229 if (p == 0) {
230 plist(&aliases);
231 } else if (*v == 0) {
232 vp = adrof1(strip(p), &aliases);
233 if (vp) {
234 blkpr(vp->vec), printf("\n");
236 } else {
237 if (eq(p, S_alias) ||
238 eq(p, S_unalias)) {
239 setname(p);
240 bferr("Too dangerous to alias that");
242 set1(strip(p), saveblk(v), &aliases);
246 void
247 unalias(tchar **v)
250 #ifdef TRACE
251 tprintf("TRACE- unalias()\n");
252 #endif
253 unset1(v, &aliases);
256 void
257 dologout(void)
260 #ifdef TRACE
261 tprintf("TRACE- dologout()\n");
262 #endif
263 islogin();
264 goodbye();
267 void
268 dologin(tchar **v)
271 char *v_; /* work */
272 #ifdef TRACE
273 tprintf("TRACE- dologin()\n");
274 #endif
275 islogin();
276 rechist();
277 (void) signal(SIGTERM, parterm);
278 if (v[1] != NULL) {
279 v_ = tstostr(NULL, v[1]); /* No need to free */
280 } else {
281 v_ = 0;
283 execl("/bin/login", "login", v_, 0);
284 untty();
285 exit(1);
288 #ifdef NEWGRP
289 void
290 donewgrp(tchar **v)
293 char *v_; /* work */
294 #ifdef TRACE
295 tprintf("TRACE- donewgrp()\n");
296 #endif
297 if (chkstop == 0 && setintr) {
298 panystop(0);
300 (void) signal(SIGTERM, parterm);
302 if (v[1] != NULL) {
303 v_ = tstostr(NOSTR, v[1]); /* No need to free */
304 } else {
305 v_ = 0;
307 execl("/bin/newgrp", "newgrp", v_, 0);
308 execl("/usr/bin/newgrp", "newgrp", v_, 0);
309 untty();
310 exit(1);
312 #endif
314 void
315 islogin(void)
318 #ifdef TRACE
319 tprintf("TRACE- islogin()\n");
320 #endif
321 if (chkstop == 0 && setintr) {
322 panystop(0);
324 if (loginsh) {
325 return;
327 error("Not login shell");
330 void
331 doif(tchar **v, struct command *kp)
333 int i;
334 tchar **vv;
336 #ifdef TRACE
337 tprintf("TRACE- doif()\n");
338 #endif
339 v++;
340 i = exp(&v);
341 vv = v;
342 if (*vv == NOSTR) {
343 bferr("Empty if");
345 if (eq(*vv, S_then)) {
346 if (*++vv) {
347 bferr("Improper then");
349 setname(S_then);
351 * If expression was zero, then scan to else,
352 * otherwise just fall into following code.
354 if (!i) {
355 search(ZIF, 0);
357 return;
360 * Simple command attached to this if.
361 * Left shift the node in this tree, munging it
362 * so we can reexecute it.
364 if (i) {
365 lshift(kp->t_dcom, vv - kp->t_dcom);
366 reexecute(kp);
367 donefds();
372 * Reexecute a command, being careful not
373 * to redo i/o redirection, which is already set up.
375 void
376 reexecute(struct command *kp)
379 #ifdef TRACE
380 tprintf("TRACE- reexecute()\n");
381 #endif
382 kp->t_dflg &= FSAVE;
383 kp->t_dflg |= FREDO;
385 * If tty is still ours to arbitrate, arbitrate it;
386 * otherwise dont even set pgrp's as the jobs would
387 * then have no way to get the tty (we can't give it
388 * to them, and our parent wouldn't know their pgrp, etc.
390 execute(kp, tpgrp > 0 ? tpgrp : -1);
393 void
394 doelse(void)
397 #ifdef TRACE
398 tprintf("TRACE- doelse()\n");
399 #endif
400 search(ZELSE, 0);
403 void
404 dogoto(tchar **v)
406 struct whyle *wp;
407 tchar *lp;
408 #ifdef TRACE
409 tprintf("TRACE- dogoto()\n");
410 #endif
413 * While we still can, locate any unknown ends of existing loops.
414 * This obscure code is the WORST result of the fact that we
415 * don't really parse.
417 for (wp = whyles; wp; wp = wp->w_next) {
418 if (wp->w_end == 0) {
419 search(ZBREAK, 0);
420 wp->w_end = btell();
421 } else {
422 bseek(wp->w_end);
425 search(ZGOTO, 0, lp = globone(v[1]));
426 xfree(lp);
428 * Eliminate loops which were exited.
430 wfree();
433 void
434 doswitch(tchar **v)
436 tchar *cp, *lp;
438 #ifdef TRACE
439 tprintf("TRACE- doswitch()\n");
440 #endif
441 v++;
442 if (!*v || *(*v++) != '(') {
443 goto syntax;
445 cp = **v == ')' ? S_ : *v++;
446 if (*(*v++) != ')') {
447 v--;
449 if (*v) {
450 syntax:
451 error("Syntax error");
453 search(ZSWITCH, 0, lp = globone(cp));
454 xfree(lp);
457 void
458 dobreak(void)
461 #ifdef TRACE
462 tprintf("TRACE- dobreak()\n");
463 #endif
464 if (whyles) {
465 toend();
466 } else {
467 bferr("Not in while/foreach");
471 void
472 doexit(tchar **v)
475 #ifdef TRACE
476 tprintf("TRACE- doexit()\n");
477 #endif
478 if (chkstop == 0) {
479 panystop(0);
482 * Don't DEMAND parentheses here either.
484 v++;
485 if (*v) {
486 set(S_status, putn(exp(&v)));
487 if (*v) {
488 bferr("Expression syntax");
491 btoeof();
492 if (intty) {
493 (void) close(SHIN);
494 unsetfd(SHIN);
498 void
499 doforeach(tchar **v)
501 tchar *cp;
502 struct whyle *nwp;
504 #ifdef TRACE
505 tprintf("TRACE- doforeach()\n");
506 #endif
507 v++;
508 cp = strip(*v);
509 while (*cp && alnum(*cp)) {
510 cp++;
512 if (*cp || strlen_(*v) >= MAX_VAR_LEN || !letter(**v)) {
513 bferr("Invalid variable");
515 cp = *v++;
516 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') {
517 bferr("Words not ()'ed");
519 v++;
520 gflag = 0, tglob(v);
521 v = glob(v);
522 if (v == 0) {
523 bferr("No match");
525 nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
526 nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
527 nwp->w_start = btell();
528 nwp->w_fename = savestr(cp);
529 nwp->w_next = whyles;
530 whyles = nwp;
532 * Pre-read the loop so as to be more
533 * comprehensible to a terminal user.
535 if (intty) {
536 preread_();
538 doagain();
541 void
542 dowhile(tchar **v)
544 int status;
545 bool again = whyles != 0 && whyles->w_start == lineloc &&
546 whyles->w_fename == 0;
548 #ifdef TRACE
549 tprintf("TRACE- dowhile()\n");
550 #endif
551 v++;
553 * Implement prereading here also, taking care not to
554 * evaluate the expression before the loop has been read up
555 * from a terminal.
557 if (intty && !again) {
558 status = !exp0(&v, 1);
559 } else {
560 status = !exp(&v);
562 if (*v) {
563 bferr("Expression syntax");
565 if (!again) {
566 struct whyle *nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
568 nwp->w_start = lineloc;
569 nwp->w_end = 0;
570 nwp->w_next = whyles;
571 whyles = nwp;
572 if (intty) {
574 * The tty preread
576 preread_();
577 doagain();
578 return;
581 if (status) {
582 /* We ain't gonna loop no more, no more! */
583 toend();
587 void
588 preread_(void)
590 #ifdef TRACE
591 tprintf("TRACE- preread()\n");
592 #endif
594 whyles->w_end = -1;
595 if (setintr) {
596 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
598 search(ZBREAK, 0);
599 if (setintr) {
600 (void) sigblock(sigmask(SIGINT));
602 whyles->w_end = btell();
605 void
606 doend(void)
609 #ifdef TRACE
610 tprintf("TRACE- doend()\n");
611 #endif
612 if (!whyles) {
613 bferr("Not in while/foreach");
615 whyles->w_end = btell();
616 doagain();
619 void
620 docontin(void)
622 #ifdef TRACE
623 tprintf("TRACE- docontin()\n");
624 #endif
626 if (!whyles) {
627 bferr("Not in while/foreach");
629 doagain();
632 void
633 doagain(void)
636 #ifdef TRACE
637 tprintf("TRACE- doagain()\n");
638 #endif
639 /* Repeating a while is simple */
640 if (whyles->w_fename == 0) {
641 bseek(whyles->w_start);
642 return;
645 * The foreach variable list actually has a spurious word
646 * ")" at the end of the w_fe list. Thus we are at the
647 * of the list if one word beyond this is 0.
649 if (!whyles->w_fe[1]) {
650 dobreak();
651 return;
653 set(whyles->w_fename, savestr(*whyles->w_fe++));
654 bseek(whyles->w_start);
657 void
658 dorepeat(tchar **v, struct command *kp)
660 int i, omask;
662 #ifdef TRACE
663 tprintf("TRACE- dorepeat()\n");
664 #endif
665 i = getn(v[1]);
666 if (setintr) {
667 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
669 lshift(v, 2);
670 while (i > 0) {
671 if (setintr) {
672 (void) sigsetmask(omask);
674 reexecute(kp);
675 --i;
677 donefds();
678 if (setintr) {
679 (void) sigsetmask(omask);
683 void
684 doswbrk(void)
687 #ifdef TRACE
688 tprintf("TRACE- doswbrk()\n");
689 #endif
690 search(ZBRKSW, 0);
694 srchx(tchar *cp)
696 struct srch *sp, *sp1, *sp2;
697 int i;
699 #ifdef TRACE
700 tprintf("TRACE- srchx()\n");
701 #endif
703 * Binary search
704 * Sp1 is the beginning of the current search range.
705 * Sp2 is one past the end.
707 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) {
708 sp = sp1 + (sp2 - sp1 >> 1);
709 if ((i = *cp - *sp->s_name) == 0 &&
710 (i = strcmp_(cp, sp->s_name)) == 0) {
711 return (sp->s_value);
713 if (i < 0) {
714 sp2 = sp;
715 } else {
716 sp1 = sp + 1;
719 return (-1);
722 tchar Stype;
723 tchar *Sgoal;
725 /*VARARGS2*/
726 void
727 search(type, level, goal)
728 int type; int level; tchar *goal;
730 tchar wordbuf[BUFSIZ];
731 tchar *aword = wordbuf;
732 tchar *cp;
734 #ifdef TRACE
735 tprintf("TRACE- search()\n");
736 #endif
737 Stype = type; Sgoal = goal;
738 if (type == ZGOTO) {
739 bseek((off_t)0);
741 do {
742 if (intty && fseekp == feobp) {
743 printf("? "), flush();
745 aword[0] = 0;
746 (void) getword(aword);
748 switch (srchx(aword)) {
750 case ZELSE:
751 if (level == 0 && type == ZIF) {
752 return;
754 break;
756 case ZIF:
757 while (getword(aword)) {
758 continue;
760 if ((type == ZIF || type == ZELSE) &&
761 eq(aword, S_then)) {
762 level++;
764 break;
766 case ZENDIF:
767 if (type == ZIF || type == ZELSE) {
768 level--;
770 break;
772 case ZFOREACH:
773 case ZWHILE:
774 if (type == ZBREAK) {
775 level++;
777 break;
779 case ZEND:
780 if (type == ZBREAK) {
781 level--;
783 break;
785 case ZSWITCH:
786 if (type == ZSWITCH || type == ZBRKSW) {
787 level++;
789 break;
791 case ZENDSW:
792 if (type == ZSWITCH || type == ZBRKSW) {
793 level--;
795 break;
797 case ZLABEL:
798 if (type == ZGOTO && getword(aword) &&
799 eq(aword, goal)) {
800 level = -1;
802 break;
804 default:
805 if (type != ZGOTO && (type != ZSWITCH || level != 0)) {
806 break;
808 if (lastchr(aword) != ':') {
809 break;
811 aword[strlen_(aword) - 1] = 0;
812 if (type == ZGOTO && eq(aword, goal) ||
813 type == ZSWITCH && eq(aword, S_default)) {
814 level = -1;
816 break;
818 case ZCASE:
819 if (type != ZSWITCH || level != 0) {
820 break;
822 (void) getword(aword);
823 if (lastchr(aword) == ':') {
824 aword[strlen_(aword) - 1] = 0;
826 cp = strip(Dfix1(aword));
827 if (Gmatch(goal, cp)) {
828 level = -1;
830 xfree(cp);
831 break;
833 case ZDEFAULT:
834 if (type == ZSWITCH && level == 0) {
835 level = -1;
837 break;
839 (void) getword(NOSTR);
840 } while (level >= 0);
844 getword(tchar *wp)
846 int found = 0;
847 int c, d;
848 #ifdef TRACE
849 tprintf("TRACE- getword()\n");
850 #endif
852 c = readc(1);
853 d = 0;
854 do {
855 while (issp(c)) {
856 c = readc(1);
858 if (c == '#') {
859 do {
860 c = readc(1);
861 } while (c >= 0 && c != '\n');
863 if (c < 0) {
864 goto past;
866 if (c == '\n') {
867 if (wp) {
868 break;
870 return (0);
873 /* ( and ) form separate words */
874 if (c == '(' || c == ')') {
875 return (1);
878 unreadc(c);
879 found = 1;
880 do {
881 c = readc(1);
882 if (c == '\\' && (c = readc(1)) == '\n') {
883 c = ' ';
885 if (c == '\'' || c == '"') {
886 if (d == 0) {
887 d = c;
888 } else if (d == c) {
889 d = 0;
892 if (c < 0) {
893 goto past;
895 if (wp) {
896 *wp++ = c;
898 } while ((d || !issp(c) && c != '(' && c != ')') && c != '\n');
899 } while (wp == 0);
900 unreadc(c);
901 if (found) {
902 *--wp = 0;
904 return (found);
906 past:
907 switch (Stype) {
909 case ZIF:
910 bferr("then/endif not found");
912 case ZELSE:
913 bferr("endif not found");
915 case ZBRKSW:
916 case ZSWITCH:
917 bferr("endsw not found");
919 case ZBREAK:
920 bferr("end not found");
922 case ZGOTO:
923 setname(Sgoal);
924 bferr("label not found");
926 /*NOTREACHED*/
928 return (0);
931 void
932 toend(void)
935 #ifdef TRACE
936 tprintf("TRACE- toend()\n");
937 #endif
938 if (whyles->w_end == 0) {
939 search(ZBREAK, 0);
940 whyles->w_end = btell() - 1;
941 } else {
942 bseek(whyles->w_end);
944 wfree();
947 void
948 wfree(void)
950 long o = btell();
952 #ifdef TRACE
953 tprintf("TRACE- wfree()\n");
954 #endif
955 while (whyles) {
956 struct whyle *wp = whyles;
957 struct whyle *nwp = wp->w_next;
959 if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) {
960 break;
962 if (wp->w_fe0) {
963 blkfree(wp->w_fe0);
965 if (wp->w_fename) {
966 xfree(wp->w_fename);
968 xfree((char *)wp);
969 whyles = nwp;
973 void
974 doecho(tchar **v)
977 #ifdef TRACE
978 tprintf("TRACE- doecho()\n");
979 #endif
980 echo(' ', v);
983 void
984 doglob(tchar **v)
987 #ifdef TRACE
988 tprintf("TRACE- doglob()\n");
989 #endif
990 echo(0, v);
991 flush();
994 void
995 echo(tchar sep, tchar **v)
997 tchar *cp;
998 int nonl = 0;
1000 #ifdef TRACE
1001 tprintf("TRACE- echo()\n");
1002 #endif
1003 if (setintr) {
1004 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
1006 v++;
1007 if (*v == 0) {
1009 * echo command needs to have newline when there are no
1010 * flags or arguments. glob should have no newline. If
1011 * the separator is a blank, we are doing an echo. If the
1012 * separator is zero, we are globbing.
1014 if (sep == (tchar)' ')
1015 Putchar('\n');
1016 return;
1018 gflag = 0, tglob(v);
1019 if (gflag) {
1020 v = glob(v);
1021 if (v == 0) {
1022 bferr("No match");
1025 /* check for -n arg, NOTE: it might be quoted */
1026 if (sep == ' ' && *v && strlen_(*v) == 2 &&
1027 ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' &&
1028 (*(*v+2)&TRIM) == 0)) {
1029 nonl++, v++;
1031 while (cp = *v++) {
1032 int c;
1034 while (c = *cp++) {
1035 Putchar(c | QUOTE);
1037 if (*v) {
1038 Putchar(sep | QUOTE);
1041 if (sep && nonl == 0) {
1042 Putchar('\n');
1043 } else {
1044 flush();
1046 if (setintr) {
1047 (void) sigblock(sigmask(SIGINT));
1049 if (gargv) {
1050 blkfree(gargv), gargv = 0;
1054 extern char **environ;
1057 * Check if the environment variable vp affects this csh's behavior
1058 * and therefore we should call setlocale() or not.
1059 * This function has two side effects when it returns 1:
1060 * variable islocalevar_catnum is set to the LC_xxx value.
1061 * variable islocalevar_catname is set to the string "LC_xxx"
1063 static int islocalevar_catnum;
1064 static char *islocalevar_catname;
1066 static
1067 bool
1068 islocalevar(tchar *vp)
1070 static struct lcinfo {
1071 tchar * evname; /* The name of the env. var. */
1072 } categories_we_care[] = {
1073 S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES,
1074 NOSTR /* assumption: LC_xxx >= 0 */
1076 struct lcinfo *p = categories_we_care;
1078 do {
1079 if (strcmp_(vp, p->evname) == 0) {
1080 return (1);
1082 } while (((++p)->evname) != NOSTR);
1083 return (0);
1086 void
1087 dosetenv(tchar **v)
1089 tchar *vp, *lp;
1091 #ifdef TRACE
1092 tprintf("TRACE- dosetenv()\n");
1093 #endif
1094 v++;
1095 if ((vp = *v++) == 0) {
1096 char **ep;
1098 if (setintr) {
1099 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
1101 for (ep = environ; *ep; ep++) {
1102 printf("%s\n", *ep);
1104 return;
1107 if ((lp = *v++) == 0) {
1108 lp = S_; /* "" */
1110 local_setenv(vp, lp = globone(lp));
1111 if (eq(vp, S_PATH)) {
1112 importpath(lp);
1113 dohash(xhash);
1114 } else if (islocalevar(vp)) {
1115 if (!setlocale(LC_ALL, "")) {
1116 error("Locale could not be set properly");
1120 xfree(lp);
1123 void
1124 dounsetenv(tchar **v)
1126 #ifdef TRACE
1127 tprintf("TRACE- dounsetenv()\n");
1128 #endif
1129 v++;
1130 do {
1131 local_unsetenv(*v);
1132 if (islocalevar(*v++)) {
1133 setlocale(LC_ALL, ""); /* Hope no error! */
1135 } while (*v);
1138 void
1139 local_setenv(tchar *name, tchar *val)
1141 char **ep = environ;
1142 tchar *cp;
1143 char *dp;
1144 tchar *ep_; /* temporary */
1145 char *blk[2], **oep = ep;
1147 #ifdef TRACE
1148 /* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */
1149 /* printf("IN local_setenv args = (%t)\n", val); */
1150 #endif
1151 for (; *ep; ep++) {
1152 #ifdef MBCHAR
1153 for (cp = name, dp = *ep; *cp && *dp; cp++) {
1155 * This loop compares two chars in different
1156 * representations, EUC (as char *) and wchar_t
1157 * (in tchar), and ends when they are different.
1159 wchar_t dwc;
1160 int n;
1162 n = mbtowc(&dwc, dp, MB_CUR_MAX);
1163 if (n <= 0) {
1164 break; /* Illegal multibyte. */
1166 dp += n; /* Advance to next multibyte char. */
1167 if (dwc == (wchar_t)(*cp & TRIM)) {
1168 continue;
1169 } else {
1170 break;
1173 #else /* !MBCHAR */
1174 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
1175 continue;
1177 #endif /* !MBCHAR */
1178 if (*cp != 0 || *dp != '=') {
1179 continue;
1181 cp = strspl(S_EQ, val);
1182 xfree(*ep);
1183 ep_ = strspl(name, cp); /* ep_ is xalloc'ed */
1184 xfree(cp);
1186 * Trimming is not needed here.
1187 * trim();
1189 *ep = tstostr(NULL, ep_);
1190 xfree(ep_); /* because temp. use */
1191 return;
1193 ep_ = strspl(name, S_EQ); /* ep_ is xalloc'ed */
1194 blk[0] = tstostr(NULL, ep_);
1195 blk[1] = 0;
1196 xfree(ep_);
1197 environ = (char **)blkspl_((char **)environ, blk);
1198 xfree((void *)oep);
1199 local_setenv(name, val);
1202 void
1203 local_unsetenv(tchar *name)
1205 char **ep = environ;
1206 tchar *cp;
1207 char *dp;
1208 char **oep = ep;
1209 char *cp_; /* tmp use */
1210 static int cnt = 0; /* delete counter */
1212 #ifdef TRACE
1213 tprintf("TRACE- local_unsetenv()\n");
1214 #endif
1215 for (; *ep; ep++) {
1216 #ifdef MBCHAR
1217 for (cp = name, dp = *ep; *cp && *dp; cp++) {
1219 * This loop compares two chars in different
1220 * representations, EUC (as char *) and wchar_t
1221 * (in tchar), and ends when they are different.
1223 wchar_t dwc;
1224 int n;
1226 n = mbtowc(&dwc, dp, MB_CUR_MAX);
1227 if (n <= 0) {
1228 break; /* Illegal multibyte. */
1230 dp += n; /* Advance to next multibyte char. */
1231 if (dwc == (wchar_t)(*cp & TRIM)) {
1232 continue;
1233 } else {
1234 break;
1237 #else /* !MBCHAR */
1238 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
1239 continue;
1241 #endif /* !MBCHAR */
1242 if (*cp != 0 || *dp != '=') {
1243 continue;
1245 cp_ = *ep;
1246 *ep = 0;
1247 environ = (char **)blkspl_((char **)environ, ep+1);
1248 *ep = cp_;
1249 xfree(cp_);
1250 xfree((void *)oep);
1251 return;
1255 void
1256 doumask(tchar **v)
1258 tchar *cp = v[1];
1259 int i;
1261 #ifdef TRACE
1262 tprintf("TRACE- dounmask()\n");
1263 #endif
1264 if (cp == 0) {
1265 i = umask(0);
1266 (void) umask(i);
1267 printf("%o\n", i);
1268 return;
1270 i = 0;
1271 while (digit(*cp) && *cp != '8' && *cp != '9') {
1272 i = i * 8 + *cp++ - '0';
1274 if (*cp || i < 0 || i > 0777) {
1275 bferr("Improper mask");
1277 (void) umask(i);
1281 struct limits *
1282 findlim(tchar *cp)
1284 struct limits *lp, *res;
1286 #ifdef TRACE
1287 tprintf("TRACE- findlim()\n");
1288 #endif
1289 res = 0;
1290 for (lp = limits; lp->limconst >= 0; lp++) {
1291 if (prefix(cp, lp->limname)) {
1292 if (res) {
1293 bferr("Ambiguous");
1295 res = lp;
1298 if (res) {
1299 return (res);
1301 bferr("No such limit");
1302 /*NOTREACHED*/
1305 void
1306 dolimit(tchar **v)
1308 struct limits *lp;
1309 rlim_t limit;
1310 tchar hard = 0;
1312 #ifdef TRACE
1313 tprintf("TRACE- dolimit()\n");
1314 #endif
1315 v++;
1316 if (*v && eq(*v, S_h)) {
1317 hard = 1;
1318 v++;
1320 if (*v == 0) {
1321 for (lp = limits; lp->limconst >= 0; lp++) {
1322 plim(lp, hard);
1324 return;
1326 lp = findlim(v[0]);
1327 if (v[1] == 0) {
1328 plim(lp, hard);
1329 return;
1331 switch (getval(lp, v+1, &limit)) {
1332 case 0:
1333 error("Value specified for limit is too large");
1334 return;
1335 case (-1):
1336 error("Numeric conversion failed");
1337 return;
1338 default:
1339 if (setlim(lp, hard, limit) < 0) {
1340 error(NOSTR);
1345 static int
1346 getval(struct limits *lp, tchar **v, rlim_t *retval)
1348 rlim_t value, tmp, tmp2;
1349 tchar *cp = *v++;
1350 char chbuf[BUFSIZ * MB_LEN_MAX];
1352 #ifdef TRACE
1353 tprintf("TRACE- getval()\n");
1354 #endif
1356 tstostr(chbuf, cp);
1357 errno = 0;
1358 value = strtoull(chbuf, NULL, 0);
1360 * we must accept zero, but the conversion can fail and give us
1361 * zero as well...try to deal with it as gracefully as possible
1362 * by checking for EINVAL
1364 if (value == 0 && errno == EINVAL)
1365 return (-1);
1367 while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') {
1368 cp++;
1370 if (*cp == 0) {
1371 if (*v == 0) {
1372 tmp = value * (rlim_t)lp->limdiv;
1373 /* Check for overflow */
1374 if (tmp >= value) {
1375 *retval = tmp;
1376 return (1);
1377 } else {
1378 return (0);
1381 cp = *v;
1383 switch (*cp) {
1385 case ':':
1386 if (lp->limconst != RLIMIT_CPU) {
1387 goto badscal;
1389 tstostr(chbuf, cp + 1);
1390 tmp = strtoull(chbuf, NULL, 0);
1391 tmp2 = value * 60 + tmp;
1392 if (tmp2 >= value) {
1393 *retval = tmp2;
1394 return (1);
1395 } else {
1396 return (0);
1399 case 'h':
1400 if (lp->limconst != RLIMIT_CPU) {
1401 goto badscal;
1403 limtail(cp, S_hours);
1404 tmp = value * 3600;
1405 if (tmp < value) {
1406 return (0);
1408 value = tmp;
1409 break;
1411 case 'm':
1412 if (lp->limconst == RLIMIT_CPU) {
1413 limtail(cp, S_minutes);
1414 tmp = value * 60;
1415 if (tmp < value) {
1416 return (0);
1418 value = tmp;
1419 break;
1421 case 'M':
1422 if (lp->limconst == RLIMIT_CPU) {
1423 goto badscal;
1425 *cp = 'm';
1426 limtail(cp, S_megabytes);
1427 tmp = value * 1024 * 1024;
1428 if (tmp < value) {
1429 return (0);
1431 value = tmp;
1432 break;
1434 case 's':
1435 if (lp->limconst != RLIMIT_CPU) {
1436 goto badscal;
1438 limtail(cp, S_seconds);
1439 break;
1441 case 'k':
1442 if (lp->limconst == RLIMIT_CPU) {
1443 goto badscal;
1445 limtail(cp, S_kbytes);
1446 tmp = value * 1024;
1447 if (tmp < value) {
1448 return (0);
1450 value = tmp;
1451 break;
1453 case 'u':
1454 limtail(cp, S_unlimited);
1455 *retval = RLIM_INFINITY;
1456 return (1);
1458 default:
1459 badscal:
1460 bferr("Improper or unknown scale factor");
1462 *retval = value;
1463 return (1);
1466 void
1467 limtail(tchar *cp, tchar *str0)
1469 tchar *str = str0;
1470 #ifdef TRACE
1471 tprintf("TRACE- limtail()\n");
1472 #endif
1474 while (*cp && *cp == *str) {
1475 cp++, str++;
1477 if (*cp) {
1478 error("Bad scaling; did you mean ``%t''?", str0);
1482 void
1483 plim(struct limits *lp, tchar hard)
1485 struct rlimit rlim;
1486 char buf[BUFSZ];
1487 char *pbuf;
1488 rlim_t limit;
1490 #ifdef TRACE
1491 tprintf("TRACE- plim()\n");
1492 #endif
1493 printf("%t \t", lp->limname);
1494 (void) getrlimit(lp->limconst, &rlim);
1495 limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1496 if (limit == RLIM_INFINITY) {
1497 printf("unlimited");
1498 } else if (lp->limconst == RLIMIT_CPU) {
1499 psecs_ull(limit);
1500 } else {
1501 buf[BUFSZ - 1] = '\0';
1502 pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]);
1503 printf("%s %t", pbuf, lp->limscale);
1505 printf("\n");
1508 void
1509 dounlimit(tchar **v)
1511 struct limits *lp;
1512 int err = 0;
1513 tchar hard = 0;
1514 #ifdef TRACE
1515 tprintf("TRACE- dounlimit()\n");
1516 #endif
1518 v++;
1519 if (*v && eq(*v, S_h)) {
1520 hard = 1;
1521 v++;
1523 if (*v == 0) {
1524 for (lp = limits; lp->limconst >= 0; lp++) {
1525 if (setlim(lp, hard, RLIM_INFINITY) < 0) {
1526 err++;
1529 if (err) {
1530 error(NULL);
1532 return;
1534 while (*v) {
1535 lp = findlim(*v++);
1536 if (setlim(lp, hard, RLIM_INFINITY) < 0) {
1537 error(NULL);
1543 setlim(struct limits *lp, tchar hard, rlim_t limit)
1545 struct rlimit rlim;
1547 #ifdef TRACE
1548 tprintf("TRACE- setlim()\n");
1549 #endif
1550 (void) getrlimit(lp->limconst, &rlim);
1551 if (hard) {
1552 rlim.rlim_max = limit;
1553 } else if (limit == RLIM_INFINITY && geteuid() != 0) {
1554 rlim.rlim_cur = rlim.rlim_max;
1555 } else {
1556 rlim.rlim_cur = limit;
1558 if (setrlimit(lp->limconst, &rlim) < 0) {
1559 printf("%t: %t: Can't %s%s limit\n", bname, lp->limname,
1560 limit == RLIM_INFINITY ? "remove" : "set",
1561 hard ? " hard" : "");
1562 return (-1);
1564 return (0);
1567 void
1568 dosuspend()
1570 int ctpgrp;
1571 void (*old)();
1573 #ifdef TRACE
1574 tprintf("TRACE- dosuspend()\n");
1575 #endif
1576 if (loginsh) {
1577 error("Can't suspend a login shell (yet)");
1579 if (getpid() == getsid(0)) {
1580 error("Can't suspend this shell");
1582 untty();
1583 old = (void (*)())signal(SIGTSTP, SIG_DFL);
1584 (void) kill(0, SIGTSTP);
1585 /* the shell stops here */
1586 (void) signal(SIGTSTP, old);
1587 if (tpgrp != -1) {
1588 retry:
1589 (void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp);
1590 if (ctpgrp != opgrp) {
1591 old = (void (*)())signal(SIGTTIN, SIG_DFL);
1592 (void) kill(0, SIGTTIN);
1593 (void) signal(SIGTTIN, old);
1594 goto retry;
1596 (void) setpgid(0, shpgrp);
1597 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
1601 void
1602 doeval(tchar **v)
1604 tchar **oevalvec = evalvec;
1605 tchar *oevalp = evalp;
1606 jmp_buf osetexit;
1607 int reenter;
1608 tchar **gv = 0;
1610 #ifdef TRACE
1611 tprintf("TRACE- doeval()\n");
1612 #endif
1613 v++;
1614 if (*v == 0) {
1615 return;
1617 gflag = 0, tglob(v);
1618 if (gflag) {
1619 gv = v = glob(v);
1620 gargv = 0;
1621 if (v == 0) {
1622 error("No match");
1624 v = copyblk(v);
1625 } else {
1626 trim(v);
1628 getexit(osetexit);
1629 reenter = 0;
1630 setexit();
1631 reenter++;
1632 if (reenter == 1) {
1633 evalvec = v;
1634 evalp = 0;
1635 process(0);
1637 evalvec = oevalvec;
1638 evalp = oevalp;
1639 doneinp = 0;
1640 if (gv) {
1641 blkfree(gv);
1643 resexit(osetexit);
1644 if (reenter >= 2) {
1645 error(NULL);