1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
8
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.
13 */
14
15 #pragma ident "%Z%%M% %I% %E% SMI"
16
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>
22
23 /*
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.
29 */
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,
51 };
52
53
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();
68
69 #define BUFSZ 1028
70
71 /*
72 * C shell
73 */
74
75 struct biltins *
isbfunc(struct command * t)76 isbfunc(struct command *t)
77 {
78 tchar *cp = t->t_dcom[0];
79 struct biltins *bp, *bp1, *bp2;
80 int dofg1(), dobg1();
81
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);
91 }
92 if (*cp == '%') {
93 if (t->t_dflg & FAND) {
94 t->t_dflg &= ~FAND;
95 backgnd.bname = cp;
96 return (&backgnd);
97 }
98 foregnd.bname = cp;
99 return (&foregnd);
100 }
101 /*
102 * Binary search
103 * Bp1 is the beginning of the current search range.
104 * Bp2 is one past the end.
105 */
106 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) {
107 int i;
108
109 bp = bp1 + (bp2 - bp1 >> 1);
110 if ((i = *cp - *bp->bname) == 0 &&
111 (i = strcmp_(cp, bp->bname)) == 0) {
112 return (bp);
113 }
114 if (i < 0) {
115 bp2 = bp;
116 } else {
117 bp1 = bp + 1;
118 }
119 }
120 return (0);
121 }
122
123 void
func(struct command * t,struct biltins * bp)124 func(struct command *t, struct biltins *bp)
125 {
126 int i;
127
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");
136 }
137 if (i > bp->maxargs) {
138 bferr("Too many arguments");
139 }
140 (*bp->bfunct)(t->t_dcom, t);
141 }
142
143 int
dolabel(void)144 dolabel(void)
145 {
146 #ifdef TRACE
147 tprintf("TRACE- dolabel()\n");
148 #endif
149 return (0);
150 }
151
152 void
doonintr(tchar ** v)153 doonintr(tchar **v)
154 {
155 tchar *cp;
156 tchar *vv = v[1];
157
158 #ifdef TRACE
159 tprintf("TRACE- doonintr()\n");
160 #endif
161 if (parintr == SIG_IGN) {
162 return;
163 }
164 if (setintr && intty) {
165 bferr("Can't from terminal");
166 }
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);
173 }
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);
181 }
182 }
183
184 void
donohup(void)185 donohup(void)
186 {
187
188 #ifdef TRACE
189 tprintf("TRACE- donohup()\n");
190 #endif
191 if (intty) {
192 bferr("Can't from terminal");
193 }
194 if (setintr == 0) {
195 (void) signal(SIGHUP, SIG_IGN);
196 #ifdef CC
197 submit(getpid());
198 #endif
199 }
200 }
201
202 void
dozip(void)203 dozip(void)
204 {
205 ;
206 }
207
208 void
prvars(void)209 prvars(void)
210 {
211 #ifdef TRACE
212 tprintf("TRACE- prvars()\n");
213 #endif
214
215 plist(&shvhed);
216 }
217
218 void
doalias(tchar ** v)219 doalias(tchar **v)
220 {
221 struct varent *vp;
222 tchar *p;
223
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");
235 }
236 } else {
237 if (eq(p, S_alias) ||
238 eq(p, S_unalias)) {
239 setname(p);
240 bferr("Too dangerous to alias that");
241 }
242 set1(strip(p), saveblk(v), &aliases);
243 }
244 }
245
246 void
unalias(tchar ** v)247 unalias(tchar **v)
248 {
249
250 #ifdef TRACE
251 tprintf("TRACE- unalias()\n");
252 #endif
253 unset1(v, &aliases);
254 }
255
256 void
dologout(void)257 dologout(void)
258 {
259
260 #ifdef TRACE
261 tprintf("TRACE- dologout()\n");
262 #endif
263 islogin();
264 goodbye();
265 }
266
267 void
dologin(tchar ** v)268 dologin(tchar **v)
269 {
270
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;
282 }
283 execl("/bin/login", "login", v_, 0);
284 untty();
285 exit(1);
286 }
287
288 #ifdef NEWGRP
289 void
donewgrp(tchar ** v)290 donewgrp(tchar **v)
291 {
292
293 char *v_; /* work */
294 #ifdef TRACE
295 tprintf("TRACE- donewgrp()\n");
296 #endif
297 if (chkstop == 0 && setintr) {
298 panystop(0);
299 }
300 (void) signal(SIGTERM, parterm);
301
302 if (v[1] != NULL) {
303 v_ = tstostr(NOSTR, v[1]); /* No need to free */
304 } else {
305 v_ = 0;
306 }
307 execl("/bin/newgrp", "newgrp", v_, 0);
308 execl("/usr/bin/newgrp", "newgrp", v_, 0);
309 untty();
310 exit(1);
311 }
312 #endif
313
314 void
islogin(void)315 islogin(void)
316 {
317
318 #ifdef TRACE
319 tprintf("TRACE- islogin()\n");
320 #endif
321 if (chkstop == 0 && setintr) {
322 panystop(0);
323 }
324 if (loginsh) {
325 return;
326 }
327 error("Not login shell");
328 }
329
330 void
doif(tchar ** v,struct command * kp)331 doif(tchar **v, struct command *kp)
332 {
333 int i;
334 tchar **vv;
335
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");
344 }
345 if (eq(*vv, S_then)) {
346 if (*++vv) {
347 bferr("Improper then");
348 }
349 setname(S_then);
350 /*
351 * If expression was zero, then scan to else,
352 * otherwise just fall into following code.
353 */
354 if (!i) {
355 search(ZIF, 0);
356 }
357 return;
358 }
359 /*
360 * Simple command attached to this if.
361 * Left shift the node in this tree, munging it
362 * so we can reexecute it.
363 */
364 if (i) {
365 lshift(kp->t_dcom, vv - kp->t_dcom);
366 reexecute(kp);
367 donefds();
368 }
369 }
370
371 /*
372 * Reexecute a command, being careful not
373 * to redo i/o redirection, which is already set up.
374 */
375 void
reexecute(struct command * kp)376 reexecute(struct command *kp)
377 {
378
379 #ifdef TRACE
380 tprintf("TRACE- reexecute()\n");
381 #endif
382 kp->t_dflg &= FSAVE;
383 kp->t_dflg |= FREDO;
384 /*
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.
389 */
390 execute(kp, tpgrp > 0 ? tpgrp : -1);
391 }
392
393 void
doelse(void)394 doelse(void)
395 {
396
397 #ifdef TRACE
398 tprintf("TRACE- doelse()\n");
399 #endif
400 search(ZELSE, 0);
401 }
402
403 void
dogoto(tchar ** v)404 dogoto(tchar **v)
405 {
406 struct whyle *wp;
407 tchar *lp;
408 #ifdef TRACE
409 tprintf("TRACE- dogoto()\n");
410 #endif
411
412 /*
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.
416 */
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);
423 }
424 }
425 search(ZGOTO, 0, lp = globone(v[1]));
426 xfree(lp);
427 /*
428 * Eliminate loops which were exited.
429 */
430 wfree();
431 }
432
433 void
doswitch(tchar ** v)434 doswitch(tchar **v)
435 {
436 tchar *cp, *lp;
437
438 #ifdef TRACE
439 tprintf("TRACE- doswitch()\n");
440 #endif
441 v++;
442 if (!*v || *(*v++) != '(') {
443 goto syntax;
444 }
445 cp = **v == ')' ? S_ : *v++;
446 if (*(*v++) != ')') {
447 v--;
448 }
449 if (*v) {
450 syntax:
451 error("Syntax error");
452 }
453 search(ZSWITCH, 0, lp = globone(cp));
454 xfree(lp);
455 }
456
457 void
dobreak(void)458 dobreak(void)
459 {
460
461 #ifdef TRACE
462 tprintf("TRACE- dobreak()\n");
463 #endif
464 if (whyles) {
465 toend();
466 } else {
467 bferr("Not in while/foreach");
468 }
469 }
470
471 void
doexit(tchar ** v)472 doexit(tchar **v)
473 {
474
475 #ifdef TRACE
476 tprintf("TRACE- doexit()\n");
477 #endif
478 if (chkstop == 0) {
479 panystop(0);
480 }
481 /*
482 * Don't DEMAND parentheses here either.
483 */
484 v++;
485 if (*v) {
486 set(S_status, putn(exp(&v)));
487 if (*v) {
488 bferr("Expression syntax");
489 }
490 }
491 btoeof();
492 if (intty) {
493 (void) close(SHIN);
494 unsetfd(SHIN);
495 }
496 }
497
498 void
doforeach(tchar ** v)499 doforeach(tchar **v)
500 {
501 tchar *cp;
502 struct whyle *nwp;
503
504 #ifdef TRACE
505 tprintf("TRACE- doforeach()\n");
506 #endif
507 v++;
508 cp = strip(*v);
509 while (*cp && alnum(*cp)) {
510 cp++;
511 }
512 if (*cp || strlen_(*v) >= MAX_VAR_LEN || !letter(**v)) {
513 bferr("Invalid variable");
514 }
515 cp = *v++;
516 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') {
517 bferr("Words not ()'ed");
518 }
519 v++;
520 gflag = 0, tglob(v);
521 v = glob(v);
522 if (v == 0) {
523 bferr("No match");
524 }
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;
531 /*
532 * Pre-read the loop so as to be more
533 * comprehensible to a terminal user.
534 */
535 if (intty) {
536 preread_();
537 }
538 doagain();
539 }
540
541 void
dowhile(tchar ** v)542 dowhile(tchar **v)
543 {
544 int status;
545 bool again = whyles != 0 && whyles->w_start == lineloc &&
546 whyles->w_fename == 0;
547
548 #ifdef TRACE
549 tprintf("TRACE- dowhile()\n");
550 #endif
551 v++;
552 /*
553 * Implement prereading here also, taking care not to
554 * evaluate the expression before the loop has been read up
555 * from a terminal.
556 */
557 if (intty && !again) {
558 status = !exp0(&v, 1);
559 } else {
560 status = !exp(&v);
561 }
562 if (*v) {
563 bferr("Expression syntax");
564 }
565 if (!again) {
566 struct whyle *nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
567
568 nwp->w_start = lineloc;
569 nwp->w_end = 0;
570 nwp->w_next = whyles;
571 whyles = nwp;
572 if (intty) {
573 /*
574 * The tty preread
575 */
576 preread_();
577 doagain();
578 return;
579 }
580 }
581 if (status) {
582 /* We ain't gonna loop no more, no more! */
583 toend();
584 }
585 }
586
587 void
preread_(void)588 preread_(void)
589 {
590 #ifdef TRACE
591 tprintf("TRACE- preread()\n");
592 #endif
593
594 whyles->w_end = -1;
595 if (setintr) {
596 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
597 }
598 search(ZBREAK, 0);
599 if (setintr) {
600 (void) sigblock(sigmask(SIGINT));
601 }
602 whyles->w_end = btell();
603 }
604
605 void
doend(void)606 doend(void)
607 {
608
609 #ifdef TRACE
610 tprintf("TRACE- doend()\n");
611 #endif
612 if (!whyles) {
613 bferr("Not in while/foreach");
614 }
615 whyles->w_end = btell();
616 doagain();
617 }
618
619 void
docontin(void)620 docontin(void)
621 {
622 #ifdef TRACE
623 tprintf("TRACE- docontin()\n");
624 #endif
625
626 if (!whyles) {
627 bferr("Not in while/foreach");
628 }
629 doagain();
630 }
631
632 void
doagain(void)633 doagain(void)
634 {
635
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;
643 }
644 /*
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.
648 */
649 if (!whyles->w_fe[1]) {
650 dobreak();
651 return;
652 }
653 set(whyles->w_fename, savestr(*whyles->w_fe++));
654 bseek(whyles->w_start);
655 }
656
657 void
dorepeat(tchar ** v,struct command * kp)658 dorepeat(tchar **v, struct command *kp)
659 {
660 int i, omask;
661
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);
668 }
669 lshift(v, 2);
670 while (i > 0) {
671 if (setintr) {
672 (void) sigsetmask(omask);
673 }
674 reexecute(kp);
675 --i;
676 }
677 donefds();
678 if (setintr) {
679 (void) sigsetmask(omask);
680 }
681 }
682
683 void
doswbrk(void)684 doswbrk(void)
685 {
686
687 #ifdef TRACE
688 tprintf("TRACE- doswbrk()\n");
689 #endif
690 search(ZBRKSW, 0);
691 }
692
693 int
srchx(tchar * cp)694 srchx(tchar *cp)
695 {
696 struct srch *sp, *sp1, *sp2;
697 int i;
698
699 #ifdef TRACE
700 tprintf("TRACE- srchx()\n");
701 #endif
702 /*
703 * Binary search
704 * Sp1 is the beginning of the current search range.
705 * Sp2 is one past the end.
706 */
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);
712 }
713 if (i < 0) {
714 sp2 = sp;
715 } else {
716 sp1 = sp + 1;
717 }
718 }
719 return (-1);
720 }
721
722 tchar Stype;
723 tchar *Sgoal;
724
725 /*VARARGS2*/
726 void
search(type,level,goal)727 search(type, level, goal)
728 int type; int level; tchar *goal;
729 {
730 tchar wordbuf[BUFSIZ];
731 tchar *aword = wordbuf;
732 tchar *cp;
733
734 #ifdef TRACE
735 tprintf("TRACE- search()\n");
736 #endif
737 Stype = type; Sgoal = goal;
738 if (type == ZGOTO) {
739 bseek((off_t)0);
740 }
741 do {
742 if (intty && fseekp == feobp) {
743 printf("? "), flush();
744 }
745 aword[0] = 0;
746 (void) getword(aword);
747
748 switch (srchx(aword)) {
749
750 case ZELSE:
751 if (level == 0 && type == ZIF) {
752 return;
753 }
754 break;
755
756 case ZIF:
757 while (getword(aword)) {
758 continue;
759 }
760 if ((type == ZIF || type == ZELSE) &&
761 eq(aword, S_then)) {
762 level++;
763 }
764 break;
765
766 case ZENDIF:
767 if (type == ZIF || type == ZELSE) {
768 level--;
769 }
770 break;
771
772 case ZFOREACH:
773 case ZWHILE:
774 if (type == ZBREAK) {
775 level++;
776 }
777 break;
778
779 case ZEND:
780 if (type == ZBREAK) {
781 level--;
782 }
783 break;
784
785 case ZSWITCH:
786 if (type == ZSWITCH || type == ZBRKSW) {
787 level++;
788 }
789 break;
790
791 case ZENDSW:
792 if (type == ZSWITCH || type == ZBRKSW) {
793 level--;
794 }
795 break;
796
797 case ZLABEL:
798 if (type == ZGOTO && getword(aword) &&
799 eq(aword, goal)) {
800 level = -1;
801 }
802 break;
803
804 default:
805 if (type != ZGOTO && (type != ZSWITCH || level != 0)) {
806 break;
807 }
808 if (lastchr(aword) != ':') {
809 break;
810 }
811 aword[strlen_(aword) - 1] = 0;
812 if (type == ZGOTO && eq(aword, goal) ||
813 type == ZSWITCH && eq(aword, S_default)) {
814 level = -1;
815 }
816 break;
817
818 case ZCASE:
819 if (type != ZSWITCH || level != 0) {
820 break;
821 }
822 (void) getword(aword);
823 if (lastchr(aword) == ':') {
824 aword[strlen_(aword) - 1] = 0;
825 }
826 cp = strip(Dfix1(aword));
827 if (Gmatch(goal, cp)) {
828 level = -1;
829 }
830 xfree(cp);
831 break;
832
833 case ZDEFAULT:
834 if (type == ZSWITCH && level == 0) {
835 level = -1;
836 }
837 break;
838 }
839 (void) getword(NOSTR);
840 } while (level >= 0);
841 }
842
843 int
getword(tchar * wp)844 getword(tchar *wp)
845 {
846 int found = 0;
847 int c, d;
848 #ifdef TRACE
849 tprintf("TRACE- getword()\n");
850 #endif
851
852 c = readc(1);
853 d = 0;
854 do {
855 while (issp(c)) {
856 c = readc(1);
857 }
858 if (c == '#') {
859 do {
860 c = readc(1);
861 } while (c >= 0 && c != '\n');
862 }
863 if (c < 0) {
864 goto past;
865 }
866 if (c == '\n') {
867 if (wp) {
868 break;
869 }
870 return (0);
871 }
872
873 /* ( and ) form separate words */
874 if (c == '(' || c == ')') {
875 return (1);
876 }
877
878 unreadc(c);
879 found = 1;
880 do {
881 c = readc(1);
882 if (c == '\\' && (c = readc(1)) == '\n') {
883 c = ' ';
884 }
885 if (c == '\'' || c == '"') {
886 if (d == 0) {
887 d = c;
888 } else if (d == c) {
889 d = 0;
890 }
891 }
892 if (c < 0) {
893 goto past;
894 }
895 if (wp) {
896 *wp++ = c;
897 }
898 } while ((d || !issp(c) && c != '(' && c != ')') && c != '\n');
899 } while (wp == 0);
900 unreadc(c);
901 if (found) {
902 *--wp = 0;
903 }
904 return (found);
905
906 past:
907 switch (Stype) {
908
909 case ZIF:
910 bferr("then/endif not found");
911
912 case ZELSE:
913 bferr("endif not found");
914
915 case ZBRKSW:
916 case ZSWITCH:
917 bferr("endsw not found");
918
919 case ZBREAK:
920 bferr("end not found");
921
922 case ZGOTO:
923 setname(Sgoal);
924 bferr("label not found");
925 }
926 /*NOTREACHED*/
927
928 return (0);
929 }
930
931 void
toend(void)932 toend(void)
933 {
934
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);
943 }
944 wfree();
945 }
946
947 void
wfree(void)948 wfree(void)
949 {
950 long o = btell();
951
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;
958
959 if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) {
960 break;
961 }
962 if (wp->w_fe0) {
963 blkfree(wp->w_fe0);
964 }
965 if (wp->w_fename) {
966 xfree(wp->w_fename);
967 }
968 xfree((char *)wp);
969 whyles = nwp;
970 }
971 }
972
973 void
doecho(tchar ** v)974 doecho(tchar **v)
975 {
976
977 #ifdef TRACE
978 tprintf("TRACE- doecho()\n");
979 #endif
980 echo(' ', v);
981 }
982
983 void
doglob(tchar ** v)984 doglob(tchar **v)
985 {
986
987 #ifdef TRACE
988 tprintf("TRACE- doglob()\n");
989 #endif
990 echo(0, v);
991 flush();
992 }
993
994 void
echo(tchar sep,tchar ** v)995 echo(tchar sep, tchar **v)
996 {
997 tchar *cp;
998 int nonl = 0;
999
1000 #ifdef TRACE
1001 tprintf("TRACE- echo()\n");
1002 #endif
1003 if (setintr) {
1004 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
1005 }
1006 v++;
1007 if (*v == 0) {
1008 /*
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.
1013 */
1014 if (sep == (tchar)' ')
1015 Putchar('\n');
1016 return;
1017 }
1018 gflag = 0, tglob(v);
1019 if (gflag) {
1020 v = glob(v);
1021 if (v == 0) {
1022 bferr("No match");
1023 }
1024 }
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++;
1030 }
1031 while (cp = *v++) {
1032 int c;
1033
1034 while (c = *cp++) {
1035 Putchar(c | QUOTE);
1036 }
1037 if (*v) {
1038 Putchar(sep | QUOTE);
1039 }
1040 }
1041 if (sep && nonl == 0) {
1042 Putchar('\n');
1043 } else {
1044 flush();
1045 }
1046 if (setintr) {
1047 (void) sigblock(sigmask(SIGINT));
1048 }
1049 if (gargv) {
1050 blkfree(gargv), gargv = 0;
1051 }
1052 }
1053
1054 extern char **environ;
1055
1056 /*
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"
1062 */
1063 static int islocalevar_catnum;
1064 static char *islocalevar_catname;
1065
1066 static
1067 bool
islocalevar(tchar * vp)1068 islocalevar(tchar *vp)
1069 {
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 */
1075 };
1076 struct lcinfo *p = categories_we_care;
1077
1078 do {
1079 if (strcmp_(vp, p->evname) == 0) {
1080 return (1);
1081 }
1082 } while (((++p)->evname) != NOSTR);
1083 return (0);
1084 }
1085
1086 void
dosetenv(tchar ** v)1087 dosetenv(tchar **v)
1088 {
1089 tchar *vp, *lp;
1090
1091 #ifdef TRACE
1092 tprintf("TRACE- dosetenv()\n");
1093 #endif
1094 v++;
1095 if ((vp = *v++) == 0) {
1096 char **ep;
1097
1098 if (setintr) {
1099 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
1100 }
1101 for (ep = environ; *ep; ep++) {
1102 printf("%s\n", *ep);
1103 }
1104 return;
1105 }
1106
1107 if ((lp = *v++) == 0) {
1108 lp = S_; /* "" */
1109 }
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");
1117 }
1118 }
1119
1120 xfree(lp);
1121 }
1122
1123 void
dounsetenv(tchar ** v)1124 dounsetenv(tchar **v)
1125 {
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! */
1134 }
1135 } while (*v);
1136 }
1137
1138 void
local_setenv(tchar * name,tchar * val)1139 local_setenv(tchar *name, tchar *val)
1140 {
1141 char **ep = environ;
1142 tchar *cp;
1143 char *dp;
1144 tchar *ep_; /* temporary */
1145 char *blk[2], **oep = ep;
1146
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++) {
1154 /*
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.
1158 */
1159 wchar_t dwc;
1160 int n;
1161
1162 n = mbtowc(&dwc, dp, MB_CUR_MAX);
1163 if (n <= 0) {
1164 break; /* Illegal multibyte. */
1165 }
1166 dp += n; /* Advance to next multibyte char. */
1167 if (dwc == (wchar_t)(*cp & TRIM)) {
1168 continue;
1169 } else {
1170 break;
1171 }
1172 }
1173 #else /* !MBCHAR */
1174 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
1175 continue;
1176 }
1177 #endif /* !MBCHAR */
1178 if (*cp != 0 || *dp != '=') {
1179 continue;
1180 }
1181 cp = strspl(S_EQ, val);
1182 xfree(*ep);
1183 ep_ = strspl(name, cp); /* ep_ is xalloc'ed */
1184 xfree(cp);
1185 /*
1186 * Trimming is not needed here.
1187 * trim();
1188 */
1189 *ep = tstostr(NULL, ep_);
1190 xfree(ep_); /* because temp. use */
1191 return;
1192 }
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);
1200 }
1201
1202 void
local_unsetenv(tchar * name)1203 local_unsetenv(tchar *name)
1204 {
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 */
1211
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++) {
1218 /*
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.
1222 */
1223 wchar_t dwc;
1224 int n;
1225
1226 n = mbtowc(&dwc, dp, MB_CUR_MAX);
1227 if (n <= 0) {
1228 break; /* Illegal multibyte. */
1229 }
1230 dp += n; /* Advance to next multibyte char. */
1231 if (dwc == (wchar_t)(*cp & TRIM)) {
1232 continue;
1233 } else {
1234 break;
1235 }
1236 }
1237 #else /* !MBCHAR */
1238 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
1239 continue;
1240 }
1241 #endif /* !MBCHAR */
1242 if (*cp != 0 || *dp != '=') {
1243 continue;
1244 }
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;
1252 }
1253 }
1254
1255 void
doumask(tchar ** v)1256 doumask(tchar **v)
1257 {
1258 tchar *cp = v[1];
1259 int i;
1260
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;
1269 }
1270 i = 0;
1271 while (digit(*cp) && *cp != '8' && *cp != '9') {
1272 i = i * 8 + *cp++ - '0';
1273 }
1274 if (*cp || i < 0 || i > 0777) {
1275 bferr("Improper mask");
1276 }
1277 (void) umask(i);
1278 }
1279
1280
1281 struct limits *
findlim(tchar * cp)1282 findlim(tchar *cp)
1283 {
1284 struct limits *lp, *res;
1285
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");
1294 }
1295 res = lp;
1296 }
1297 }
1298 if (res) {
1299 return (res);
1300 }
1301 bferr("No such limit");
1302 /*NOTREACHED*/
1303 }
1304
1305 void
dolimit(tchar ** v)1306 dolimit(tchar **v)
1307 {
1308 struct limits *lp;
1309 rlim_t limit;
1310 tchar hard = 0;
1311
1312 #ifdef TRACE
1313 tprintf("TRACE- dolimit()\n");
1314 #endif
1315 v++;
1316 if (*v && eq(*v, S_h)) {
1317 hard = 1;
1318 v++;
1319 }
1320 if (*v == 0) {
1321 for (lp = limits; lp->limconst >= 0; lp++) {
1322 plim(lp, hard);
1323 }
1324 return;
1325 }
1326 lp = findlim(v[0]);
1327 if (v[1] == 0) {
1328 plim(lp, hard);
1329 return;
1330 }
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);
1341 }
1342 }
1343 }
1344
1345 static int
getval(struct limits * lp,tchar ** v,rlim_t * retval)1346 getval(struct limits *lp, tchar **v, rlim_t *retval)
1347 {
1348 rlim_t value, tmp, tmp2;
1349 tchar *cp = *v++;
1350 char chbuf[BUFSIZ * MB_LEN_MAX];
1351
1352 #ifdef TRACE
1353 tprintf("TRACE- getval()\n");
1354 #endif
1355
1356 tstostr(chbuf, cp);
1357 errno = 0;
1358 value = strtoull(chbuf, NULL, 0);
1359 /*
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
1363 */
1364 if (value == 0 && errno == EINVAL)
1365 return (-1);
1366
1367 while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') {
1368 cp++;
1369 }
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);
1379 }
1380 }
1381 cp = *v;
1382 }
1383 switch (*cp) {
1384
1385 case ':':
1386 if (lp->limconst != RLIMIT_CPU) {
1387 goto badscal;
1388 }
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);
1397 }
1398
1399 case 'h':
1400 if (lp->limconst != RLIMIT_CPU) {
1401 goto badscal;
1402 }
1403 limtail(cp, S_hours);
1404 tmp = value * 3600;
1405 if (tmp < value) {
1406 return (0);
1407 }
1408 value = tmp;
1409 break;
1410
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);
1417 }
1418 value = tmp;
1419 break;
1420 }
1421 case 'M':
1422 if (lp->limconst == RLIMIT_CPU) {
1423 goto badscal;
1424 }
1425 *cp = 'm';
1426 limtail(cp, S_megabytes);
1427 tmp = value * 1024 * 1024;
1428 if (tmp < value) {
1429 return (0);
1430 }
1431 value = tmp;
1432 break;
1433
1434 case 's':
1435 if (lp->limconst != RLIMIT_CPU) {
1436 goto badscal;
1437 }
1438 limtail(cp, S_seconds);
1439 break;
1440
1441 case 'k':
1442 if (lp->limconst == RLIMIT_CPU) {
1443 goto badscal;
1444 }
1445 limtail(cp, S_kbytes);
1446 tmp = value * 1024;
1447 if (tmp < value) {
1448 return (0);
1449 }
1450 value = tmp;
1451 break;
1452
1453 case 'u':
1454 limtail(cp, S_unlimited);
1455 *retval = RLIM_INFINITY;
1456 return (1);
1457
1458 default:
1459 badscal:
1460 bferr("Improper or unknown scale factor");
1461 }
1462 *retval = value;
1463 return (1);
1464 }
1465
1466 void
limtail(tchar * cp,tchar * str0)1467 limtail(tchar *cp, tchar *str0)
1468 {
1469 tchar *str = str0;
1470 #ifdef TRACE
1471 tprintf("TRACE- limtail()\n");
1472 #endif
1473
1474 while (*cp && *cp == *str) {
1475 cp++, str++;
1476 }
1477 if (*cp) {
1478 error("Bad scaling; did you mean ``%t''?", str0);
1479 }
1480 }
1481
1482 void
plim(struct limits * lp,tchar hard)1483 plim(struct limits *lp, tchar hard)
1484 {
1485 struct rlimit rlim;
1486 char buf[BUFSZ];
1487 char *pbuf;
1488 rlim_t limit;
1489
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);
1504 }
1505 printf("\n");
1506 }
1507
1508 void
dounlimit(tchar ** v)1509 dounlimit(tchar **v)
1510 {
1511 struct limits *lp;
1512 int err = 0;
1513 tchar hard = 0;
1514 #ifdef TRACE
1515 tprintf("TRACE- dounlimit()\n");
1516 #endif
1517
1518 v++;
1519 if (*v && eq(*v, S_h)) {
1520 hard = 1;
1521 v++;
1522 }
1523 if (*v == 0) {
1524 for (lp = limits; lp->limconst >= 0; lp++) {
1525 if (setlim(lp, hard, RLIM_INFINITY) < 0) {
1526 err++;
1527 }
1528 }
1529 if (err) {
1530 error(NULL);
1531 }
1532 return;
1533 }
1534 while (*v) {
1535 lp = findlim(*v++);
1536 if (setlim(lp, hard, RLIM_INFINITY) < 0) {
1537 error(NULL);
1538 }
1539 }
1540 }
1541
1542 int
setlim(struct limits * lp,tchar hard,rlim_t limit)1543 setlim(struct limits *lp, tchar hard, rlim_t limit)
1544 {
1545 struct rlimit rlim;
1546
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;
1557 }
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);
1563 }
1564 return (0);
1565 }
1566
1567 void
dosuspend()1568 dosuspend()
1569 {
1570 int ctpgrp;
1571 void (*old)();
1572
1573 #ifdef TRACE
1574 tprintf("TRACE- dosuspend()\n");
1575 #endif
1576 if (loginsh) {
1577 error("Can't suspend a login shell (yet)");
1578 }
1579 if (getpid() == getsid(0)) {
1580 error("Can't suspend this shell");
1581 }
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;
1595 }
1596 (void) setpgid(0, shpgrp);
1597 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
1598 }
1599 }
1600
1601 void
doeval(tchar ** v)1602 doeval(tchar **v)
1603 {
1604 tchar **oevalvec = evalvec;
1605 tchar *oevalp = evalp;
1606 jmp_buf osetexit;
1607 int reenter;
1608 tchar **gv = 0;
1609
1610 #ifdef TRACE
1611 tprintf("TRACE- doeval()\n");
1612 #endif
1613 v++;
1614 if (*v == 0) {
1615 return;
1616 }
1617 gflag = 0, tglob(v);
1618 if (gflag) {
1619 gv = v = glob(v);
1620 gargv = 0;
1621 if (v == 0) {
1622 error("No match");
1623 }
1624 v = copyblk(v);
1625 } else {
1626 trim(v);
1627 }
1628 getexit(osetexit);
1629 reenter = 0;
1630 setexit();
1631 reenter++;
1632 if (reenter == 1) {
1633 evalvec = v;
1634 evalp = 0;
1635 process(0);
1636 }
1637 evalvec = oevalvec;
1638 evalp = oevalp;
1639 doneinp = 0;
1640 if (gv) {
1641 blkfree(gv);
1642 }
1643 resexit(osetexit);
1644 if (reenter >= 2) {
1645 error(NULL);
1646 }
1647 }
1648