xref: /original-bsd/bin/csh/func.c (revision 6219b5e8)
1 #ifndef lint
2 static	char *sccsid = "@(#)func.c	4.15 (Berkeley) 03/28/85";
3 #endif
4 
5 #include "sh.h"
6 #include <sys/ioctl.h>
7 
8 /*
9  * C shell
10  */
11 
12 struct biltins *
13 isbfunc(t)
14 	struct command *t;
15 {
16 	register char *cp = t->t_dcom[0];
17 	register struct biltins *bp, *bp1, *bp2;
18 	int dolabel(), dofg1(), dobg1();
19 	static struct biltins label = { "", dolabel, 0, 0 };
20 	static struct biltins foregnd = { "%job", dofg1, 0, 0 };
21 	static struct biltins backgnd = { "%job &", dobg1, 0, 0 };
22 
23 	if (lastchr(cp) == ':') {
24 		label.bname = cp;
25 		return (&label);
26 	}
27 	if (*cp == '%') {
28 		if (t->t_dflg & FAND) {
29 			t->t_dflg &= ~FAND;
30 			backgnd.bname = cp;
31 			return (&backgnd);
32 		}
33 		foregnd.bname = cp;
34 		return (&foregnd);
35 	}
36 	/*
37 	 * Binary search
38 	 * Bp1 is the beginning of the current search range.
39 	 * Bp2 is one past the end.
40 	 */
41 	for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
42 		register i;
43 
44 		bp = bp1 + (bp2 - bp1 >> 1);
45 		if ((i = *cp - *bp->bname) == 0 &&
46 		    (i = strcmp(cp, bp->bname)) == 0)
47 			return bp;
48 		if (i < 0)
49 			bp2 = bp;
50 		else
51 			bp1 = bp + 1;
52 	}
53 	return (0);
54 }
55 
56 func(t, bp)
57 	register struct command *t;
58 	register struct biltins *bp;
59 {
60 	int i;
61 
62 	xechoit(t->t_dcom);
63 	setname(bp->bname);
64 	i = blklen(t->t_dcom) - 1;
65 	if (i < bp->minargs)
66 		bferr("Too few arguments");
67 	if (i > bp->maxargs)
68 		bferr("Too many arguments");
69 	(*bp->bfunct)(t->t_dcom, t);
70 }
71 
72 dolabel()
73 {
74 
75 }
76 
77 doonintr(v)
78 	char **v;
79 {
80 	register char *cp;
81 	register char *vv = v[1];
82 
83 	if (parintr == SIG_IGN)
84 		return;
85 	if (setintr && intty)
86 		bferr("Can't from terminal");
87 	cp = gointr, gointr = 0, xfree(cp);
88 	if (vv == 0) {
89 		if (setintr)
90 			(void) sigblock(sigmask(SIGINT));
91 		else
92 			(void) signal(SIGINT, SIG_DFL);
93 		gointr = 0;
94 	} else if (eq((vv = strip(vv)), "-")) {
95 		(void) signal(SIGINT, SIG_IGN);
96 		gointr = "-";
97 	} else {
98 		gointr = savestr(vv);
99 		(void) signal(SIGINT, pintr);
100 	}
101 }
102 
103 donohup()
104 {
105 
106 	if (intty)
107 		bferr("Can't from terminal");
108 	if (setintr == 0) {
109 		(void) signal(SIGHUP, SIG_IGN);
110 #ifdef CC
111 		submit(getpid());
112 #endif
113 	}
114 }
115 
116 dozip()
117 {
118 
119 	;
120 }
121 
122 prvars()
123 {
124 
125 	plist(&shvhed);
126 }
127 
128 doalias(v)
129 	register char **v;
130 {
131 	register struct varent *vp;
132 	register char *p;
133 
134 	v++;
135 	p = *v++;
136 	if (p == 0)
137 		plist(&aliases);
138 	else if (*v == 0) {
139 		vp = adrof1(strip(p), &aliases);
140 		if (vp)
141 			blkpr(vp->vec), printf("\n");
142 	} else {
143 		if (eq(p, "alias") || eq(p, "unalias")) {
144 			setname(p);
145 			bferr("Too dangerous to alias that");
146 		}
147 		set1(strip(p), saveblk(v), &aliases);
148 	}
149 }
150 
151 unalias(v)
152 	char **v;
153 {
154 
155 	unset1(v, &aliases);
156 }
157 
158 dologout()
159 {
160 
161 	islogin();
162 	goodbye();
163 }
164 
165 dologin(v)
166 	char **v;
167 {
168 
169 	islogin();
170 	rechist();
171 	(void) signal(SIGTERM, parterm);
172 	execl("/bin/login", "login", v[1], 0);
173 	untty();
174 	exit(1);
175 }
176 
177 #ifdef NEWGRP
178 donewgrp(v)
179 	char **v;
180 {
181 
182 	if (chkstop == 0 && setintr)
183 		panystop(0);
184 	(void) signal(SIGTERM, parterm);
185 	execl("/bin/newgrp", "newgrp", v[1], 0);
186 	execl("/usr/bin/newgrp", "newgrp", v[1], 0);
187 	untty();
188 	exit(1);
189 }
190 #endif
191 
192 islogin()
193 {
194 
195 	if (chkstop == 0 && setintr)
196 		panystop(0);
197 	if (loginsh)
198 		return;
199 	error("Not login shell");
200 }
201 
202 doif(v, kp)
203 	char **v;
204 	struct command *kp;
205 {
206 	register int i;
207 	register char **vv;
208 
209 	v++;
210 	i = exp(&v);
211 	vv = v;
212 	if (*vv == NOSTR)
213 		bferr("Empty if");
214 	if (eq(*vv, "then")) {
215 		if (*++vv)
216 			bferr("Improper then");
217 		setname("then");
218 		/*
219 		 * If expression was zero, then scan to else,
220 		 * otherwise just fall into following code.
221 		 */
222 		if (!i)
223 			search(ZIF, 0);
224 		return;
225 	}
226 	/*
227 	 * Simple command attached to this if.
228 	 * Left shift the node in this tree, munging it
229 	 * so we can reexecute it.
230 	 */
231 	if (i) {
232 		lshift(kp->t_dcom, vv - kp->t_dcom);
233 		reexecute(kp);
234 		donefds();
235 	}
236 }
237 
238 /*
239  * Reexecute a command, being careful not
240  * to redo i/o redirection, which is already set up.
241  */
242 reexecute(kp)
243 	register struct command *kp;
244 {
245 
246 	kp->t_dflg &= FSAVE;
247 	kp->t_dflg |= FREDO;
248 	/*
249 	 * If tty is still ours to arbitrate, arbitrate it;
250 	 * otherwise dont even set pgrp's as the jobs would
251 	 * then have no way to get the tty (we can't give it
252 	 * to them, and our parent wouldn't know their pgrp, etc.
253 	 */
254 	execute(kp, tpgrp > 0 ? tpgrp : -1);
255 }
256 
257 doelse()
258 {
259 
260 	search(ZELSE, 0);
261 }
262 
263 dogoto(v)
264 	char **v;
265 {
266 	register struct whyle *wp;
267 	char *lp;
268 
269 	/*
270 	 * While we still can, locate any unknown ends of existing loops.
271 	 * This obscure code is the WORST result of the fact that we
272 	 * don't really parse.
273 	 */
274 	for (wp = whyles; wp; wp = wp->w_next)
275 		if (wp->w_end == 0) {
276 			search(ZBREAK, 0);
277 			wp->w_end = btell();
278 		} else
279 			bseek(wp->w_end);
280 	search(ZGOTO, 0, lp = globone(v[1]));
281 	xfree(lp);
282 	/*
283 	 * Eliminate loops which were exited.
284 	 */
285 	wfree();
286 }
287 
288 doswitch(v)
289 	register char **v;
290 {
291 	register char *cp, *lp;
292 
293 	v++;
294 	if (!*v || *(*v++) != '(')
295 		goto syntax;
296 	cp = **v == ')' ? "" : *v++;
297 	if (*(*v++) != ')')
298 		v--;
299 	if (*v)
300 syntax:
301 		error("Syntax error");
302 	search(ZSWITCH, 0, lp = globone(cp));
303 	xfree(lp);
304 }
305 
306 dobreak()
307 {
308 
309 	if (whyles)
310 		toend();
311 	else
312 		bferr("Not in while/foreach");
313 }
314 
315 doexit(v)
316 	char **v;
317 {
318 
319 	if (chkstop == 0)
320 		panystop(0);
321 	/*
322 	 * Don't DEMAND parentheses here either.
323 	 */
324 	v++;
325 	if (*v) {
326 		set("status", putn(exp(&v)));
327 		if (*v)
328 			bferr("Expression syntax");
329 	}
330 	btoeof();
331 	if (intty)
332 		(void) close(SHIN);
333 }
334 
335 doforeach(v)
336 	register char **v;
337 {
338 	register char *cp;
339 	register struct whyle *nwp;
340 
341 	v++;
342 	cp = strip(*v);
343 	while (*cp && letter(*cp))
344 		cp++;
345 	if (*cp || strlen(*v) >= 20)
346 		bferr("Invalid variable");
347 	cp = *v++;
348 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
349 		bferr("Words not ()'ed");
350 	v++;
351 	gflag = 0, tglob(v);
352 	v = glob(v);
353 	if (v == 0)
354 		bferr("No match");
355 	nwp = (struct whyle *) calloc(1, sizeof *nwp);
356 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
357 	nwp->w_start = btell();
358 	nwp->w_fename = savestr(cp);
359 	nwp->w_next = whyles;
360 	whyles = nwp;
361 	/*
362 	 * Pre-read the loop so as to be more
363 	 * comprehensible to a terminal user.
364 	 */
365 	if (intty)
366 		preread();
367 	doagain();
368 }
369 
370 dowhile(v)
371 	char **v;
372 {
373 	register int status;
374 	register bool again = whyles != 0 && whyles->w_start == lineloc &&
375 	    whyles->w_fename == 0;
376 
377 	v++;
378 	/*
379 	 * Implement prereading here also, taking care not to
380 	 * evaluate the expression before the loop has been read up
381 	 * from a terminal.
382 	 */
383 	if (intty && !again)
384 		status = !exp0(&v, 1);
385 	else
386 		status = !exp(&v);
387 	if (*v)
388 		bferr("Expression syntax");
389 	if (!again) {
390 		register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp));
391 
392 		nwp->w_start = lineloc;
393 		nwp->w_end = 0;
394 		nwp->w_next = whyles;
395 		whyles = nwp;
396 		if (intty) {
397 			/*
398 			 * The tty preread
399 			 */
400 			preread();
401 			doagain();
402 			return;
403 		}
404 	}
405 	if (status)
406 		/* We ain't gonna loop no more, no more! */
407 		toend();
408 }
409 
410 preread()
411 {
412 
413 	whyles->w_end = -1;
414 	if (setintr)
415 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
416 	search(ZBREAK, 0);
417 	if (setintr)
418 		(void) sigblock(sigmask(SIGINT));
419 	whyles->w_end = btell();
420 }
421 
422 doend()
423 {
424 
425 	if (!whyles)
426 		bferr("Not in while/foreach");
427 	whyles->w_end = btell();
428 	doagain();
429 }
430 
431 docontin()
432 {
433 
434 	if (!whyles)
435 		bferr("Not in while/foreach");
436 	doagain();
437 }
438 
439 doagain()
440 {
441 
442 	/* Repeating a while is simple */
443 	if (whyles->w_fename == 0) {
444 		bseek(whyles->w_start);
445 		return;
446 	}
447 	/*
448 	 * The foreach variable list actually has a spurious word
449 	 * ")" at the end of the w_fe list.  Thus we are at the
450 	 * of the list if one word beyond this is 0.
451 	 */
452 	if (!whyles->w_fe[1]) {
453 		dobreak();
454 		return;
455 	}
456 	set(whyles->w_fename, savestr(*whyles->w_fe++));
457 	bseek(whyles->w_start);
458 }
459 
460 dorepeat(v, kp)
461 	char **v;
462 	struct command *kp;
463 {
464 	register int i, omask;
465 
466 	i = getn(v[1]);
467 	if (setintr)
468 		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
469 	lshift(v, 2);
470 	while (i > 0) {
471 		if (setintr)
472 			(void) sigsetmask(omask);
473 		reexecute(kp);
474 		--i;
475 	}
476 	donefds();
477 	if (setintr)
478 		(void) sigsetmask(omask);
479 }
480 
481 doswbrk()
482 {
483 
484 	search(ZBRKSW, 0);
485 }
486 
487 srchx(cp)
488 	register char *cp;
489 {
490 	register struct srch *sp, *sp1, *sp2;
491 	register i;
492 
493 	/*
494 	 * Binary search
495 	 * Sp1 is the beginning of the current search range.
496 	 * Sp2 is one past the end.
497 	 */
498 	for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
499 		sp = sp1 + (sp2 - sp1 >> 1);
500 		if ((i = *cp - *sp->s_name) == 0 &&
501 		    (i = strcmp(cp, sp->s_name)) == 0)
502 			return sp->s_value;
503 		if (i < 0)
504 			sp2 = sp;
505 		else
506 			sp1 = sp + 1;
507 	}
508 	return (-1);
509 }
510 
511 char	Stype;
512 char	*Sgoal;
513 
514 /*VARARGS2*/
515 search(type, level, goal)
516 	int type;
517 	register int level;
518 	char *goal;
519 {
520 	char wordbuf[BUFSIZ];
521 	register char *aword = wordbuf;
522 	register char *cp;
523 
524 	Stype = type; Sgoal = goal;
525 	if (type == ZGOTO)
526 		bseek((off_t)0);
527 	do {
528 		if (intty && fseekp == feobp)
529 			printf("? "), flush();
530 		aword[0] = 0;
531 		(void) getword(aword);
532 		switch (srchx(aword)) {
533 
534 		case ZELSE:
535 			if (level == 0 && type == ZIF)
536 				return;
537 			break;
538 
539 		case ZIF:
540 			while (getword(aword))
541 				continue;
542 			if ((type == ZIF || type == ZELSE) && eq(aword, "then"))
543 				level++;
544 			break;
545 
546 		case ZENDIF:
547 			if (type == ZIF || type == ZELSE)
548 				level--;
549 			break;
550 
551 		case ZFOREACH:
552 		case ZWHILE:
553 			if (type == ZBREAK)
554 				level++;
555 			break;
556 
557 		case ZEND:
558 			if (type == ZBREAK)
559 				level--;
560 			break;
561 
562 		case ZSWITCH:
563 			if (type == ZSWITCH || type == ZBRKSW)
564 				level++;
565 			break;
566 
567 		case ZENDSW:
568 			if (type == ZSWITCH || type == ZBRKSW)
569 				level--;
570 			break;
571 
572 		case ZLABEL:
573 			if (type == ZGOTO && getword(aword) && eq(aword, goal))
574 				level = -1;
575 			break;
576 
577 		default:
578 			if (type != ZGOTO && (type != ZSWITCH || level != 0))
579 				break;
580 			if (lastchr(aword) != ':')
581 				break;
582 			aword[strlen(aword) - 1] = 0;
583 			if (type == ZGOTO && eq(aword, goal) || type == ZSWITCH && eq(aword, "default"))
584 				level = -1;
585 			break;
586 
587 		case ZCASE:
588 			if (type != ZSWITCH || level != 0)
589 				break;
590 			(void) getword(aword);
591 			if (lastchr(aword) == ':')
592 				aword[strlen(aword) - 1] = 0;
593 			cp = strip(Dfix1(aword));
594 			if (Gmatch(goal, cp))
595 				level = -1;
596 			xfree(cp);
597 			break;
598 
599 		case ZDEFAULT:
600 			if (type == ZSWITCH && level == 0)
601 				level = -1;
602 			break;
603 		}
604 		(void) getword(NOSTR);
605 	} while (level >= 0);
606 }
607 
608 getword(wp)
609 	register char *wp;
610 {
611 	register int found = 0;
612 	register int c, d;
613 
614 	c = readc(1);
615 	d = 0;
616 	do {
617 		while (c == ' ' || c == '\t')
618 			c = readc(1);
619 		if (c == '#')
620 			do
621 				c = readc(1);
622 			while (c >= 0 && c != '\n');
623 		if (c < 0)
624 			goto past;
625 		if (c == '\n') {
626 			if (wp)
627 				break;
628 			return (0);
629 		}
630 		unreadc(c);
631 		found = 1;
632 		do {
633 			c = readc(1);
634 			if (c == '\\' && (c = readc(1)) == '\n')
635 				c = ' ';
636 			if (c == '\'' || c == '"')
637 				if (d == 0)
638 					d = c;
639 				else if (d == c)
640 					d = 0;
641 			if (c < 0)
642 				goto past;
643 			if (wp)
644 				*wp++ = c;
645 		} while ((d || c != ' ' && c != '\t') && c != '\n');
646 	} while (wp == 0);
647 	unreadc(c);
648 	if (found)
649 		*--wp = 0;
650 	return (found);
651 
652 past:
653 	switch (Stype) {
654 
655 	case ZIF:
656 		bferr("then/endif not found");
657 
658 	case ZELSE:
659 		bferr("endif not found");
660 
661 	case ZBRKSW:
662 	case ZSWITCH:
663 		bferr("endsw not found");
664 
665 	case ZBREAK:
666 		bferr("end not found");
667 
668 	case ZGOTO:
669 		setname(Sgoal);
670 		bferr("label not found");
671 	}
672 	/*NOTREACHED*/
673 }
674 
675 toend()
676 {
677 
678 	if (whyles->w_end == 0) {
679 		search(ZBREAK, 0);
680 		whyles->w_end = btell() - 1;
681 	} else
682 		bseek(whyles->w_end);
683 	wfree();
684 }
685 
686 wfree()
687 {
688 	long o = btell();
689 
690 	while (whyles) {
691 		register struct whyle *wp = whyles;
692 		register struct whyle *nwp = wp->w_next;
693 
694 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
695 			break;
696 		if (wp->w_fe0)
697 			blkfree(wp->w_fe0);
698 		if (wp->w_fename)
699 			xfree(wp->w_fename);
700 		xfree((char *)wp);
701 		whyles = nwp;
702 	}
703 }
704 
705 doecho(v)
706 	char **v;
707 {
708 
709 	echo(' ', v);
710 }
711 
712 doglob(v)
713 	char **v;
714 {
715 
716 	echo(0, v);
717 	flush();
718 }
719 
720 echo(sep, v)
721 	char sep;
722 	register char **v;
723 {
724 	register char *cp;
725 	int nonl = 0;
726 
727 	if (setintr)
728 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
729 	v++;
730 	if (*v == 0)
731 		return;
732 	gflag = 0, tglob(v);
733 	if (gflag) {
734 		v = glob(v);
735 		if (v == 0)
736 			bferr("No match");
737 	} else
738 		trim(v);
739 	if (sep == ' ' && *v && !strcmp(*v, "-n"))
740 		nonl++, v++;
741 	while (cp = *v++) {
742 		register int c;
743 
744 		while (c = *cp++)
745 			putchar(c | QUOTE);
746 		if (*v)
747 			putchar(sep | QUOTE);
748 	}
749 	if (sep && nonl == 0)
750 		putchar('\n');
751 	else
752 		flush();
753 	if (setintr)
754 		(void) sigblock(sigmask(SIGINT));
755 	if (gargv)
756 		blkfree(gargv), gargv = 0;
757 }
758 
759 char	**environ;
760 
761 dosetenv(v)
762 	register char **v;
763 {
764 	char *lp = globone(v[2]);
765 
766 	setenv(v[1], lp);
767 	if (eq(v[1], "PATH")) {
768 		importpath(lp);
769 		dohash();
770 	}
771 	xfree(lp);
772 }
773 
774 dounsetenv(v)
775 	register char **v;
776 {
777 
778 	v++;
779 	do
780 		unsetenv(*v++);
781 	while (*v);
782 }
783 
784 setenv(name, val)
785 	char *name, *val;
786 {
787 	register char **ep = environ;
788 	register char *cp, *dp;
789 	char *blk[2], **oep = ep;
790 
791 	for (; *ep; ep++) {
792 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
793 			continue;
794 		if (*cp != 0 || *dp != '=')
795 			continue;
796 		cp = strspl("=", val);
797 		xfree(*ep);
798 		*ep = strspl(name, cp);
799 		xfree(cp);
800 		trim(ep);
801 		return;
802 	}
803 	blk[0] = strspl(name, "="); blk[1] = 0;
804 	environ = blkspl(environ, blk);
805 	xfree((char *)oep);
806 	setenv(name, val);
807 }
808 
809 unsetenv(name)
810 	char *name;
811 {
812 	register char **ep = environ;
813 	register char *cp, *dp;
814 	char **oep = ep;
815 
816 	for (; *ep; ep++) {
817 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
818 			continue;
819 		if (*cp != 0 || *dp != '=')
820 			continue;
821 		cp = *ep;
822 		*ep = 0;
823 		environ = blkspl(environ, ep+1);
824 		*ep = cp;
825 		xfree(cp);
826 		xfree((char *)oep);
827 		return;
828 	}
829 }
830 
831 doumask(v)
832 	register char **v;
833 {
834 	register char *cp = v[1];
835 	register int i;
836 
837 	if (cp == 0) {
838 		i = umask(0);
839 		(void) umask(i);
840 		printf("%o\n", i);
841 		return;
842 	}
843 	i = 0;
844 	while (digit(*cp) && *cp != '8' && *cp != '9')
845 		i = i * 8 + *cp++ - '0';
846 	if (*cp || i < 0 || i > 0777)
847 		bferr("Improper mask");
848 	(void) umask(i);
849 }
850 
851 
852 struct limits {
853 	int	limconst;
854 	char	*limname;
855 	int	limdiv;
856 	char	*limscale;
857 } limits[] = {
858 	RLIMIT_CPU,	"cputime",	1,	"seconds",
859 	RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
860 	RLIMIT_DATA,	"datasize",	1024,	"kbytes",
861 	RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
862 	RLIMIT_CORE,	"coredumpsize",	1024,	"kbytes",
863 	RLIMIT_RSS,	"memoryuse",	1024,	"kbytes",
864 	-1,		0,
865 };
866 
867 struct limits *
868 findlim(cp)
869 	char *cp;
870 {
871 	register struct limits *lp, *res;
872 
873 	res = 0;
874 	for (lp = limits; lp->limconst >= 0; lp++)
875 		if (prefix(cp, lp->limname)) {
876 			if (res)
877 				bferr("Ambiguous");
878 			res = lp;
879 		}
880 	if (res)
881 		return (res);
882 	bferr("No such limit");
883 	/*NOTREACHED*/
884 }
885 
886 dolimit(v)
887 	register char **v;
888 {
889 	register struct limits *lp;
890 	register int limit;
891 	char hard = 0;
892 
893 	v++;
894 	if (eq(*v, "-h")) {
895 		hard = 1;
896 		v++;
897 	}
898 	if (*v == 0) {
899 		for (lp = limits; lp->limconst >= 0; lp++)
900 			plim(lp, hard);
901 		return;
902 	}
903 	lp = findlim(v[0]);
904 	if (v[1] == 0) {
905 		plim(lp,  hard);
906 		return;
907 	}
908 	limit = getval(lp, v+1);
909 	if (setlim(lp, hard, limit) < 0)
910 		error(NOSTR);
911 }
912 
913 getval(lp, v)
914 	register struct limits *lp;
915 	char **v;
916 {
917 	register float f;
918 	double atof();
919 	char *cp = *v++;
920 
921 	f = atof(cp);
922 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
923 		cp++;
924 	if (*cp == 0) {
925 		if (*v == 0)
926 			return ((int)(f+0.5) * lp->limdiv);
927 		cp = *v;
928 	}
929 	switch (*cp) {
930 
931 	case ':':
932 		if (lp->limconst != RLIMIT_CPU)
933 			goto badscal;
934 		return ((int)(f * 60.0 + atof(cp+1)));
935 
936 	case 'h':
937 		if (lp->limconst != RLIMIT_CPU)
938 			goto badscal;
939 		limtail(cp, "hours");
940 		f *= 3600.;
941 		break;
942 
943 	case 'm':
944 		if (lp->limconst == RLIMIT_CPU) {
945 			limtail(cp, "minutes");
946 			f *= 60.;
947 			break;
948 		}
949 	case 'M':
950 		if (lp->limconst == RLIMIT_CPU)
951 			goto badscal;
952 		*cp = 'm';
953 		limtail(cp, "megabytes");
954 		f *= 1024.*1024.;
955 		break;
956 
957 	case 's':
958 		if (lp->limconst != RLIMIT_CPU)
959 			goto badscal;
960 		limtail(cp, "seconds");
961 		break;
962 
963 	case 'k':
964 		if (lp->limconst == RLIMIT_CPU)
965 			goto badscal;
966 		limtail(cp, "kbytes");
967 		f *= 1024;
968 		break;
969 
970 	case 'u':
971 		limtail(cp, "unlimited");
972 		return (RLIM_INFINITY);
973 
974 	default:
975 badscal:
976 		bferr("Improper or unknown scale factor");
977 	}
978 	return ((int)(f+0.5));
979 }
980 
981 limtail(cp, str0)
982 	char *cp, *str0;
983 {
984 	register char *str = str0;
985 
986 	while (*cp && *cp == *str)
987 		cp++, str++;
988 	if (*cp)
989 		error("Bad scaling; did you mean ``%s''?", str0);
990 }
991 
992 plim(lp, hard)
993 	register struct limits *lp;
994 	char hard;
995 {
996 	struct rlimit rlim;
997 	int limit;
998 
999 	printf("%s \t", lp->limname);
1000 	(void) getrlimit(lp->limconst, &rlim);
1001 	limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1002 	if (limit == RLIM_INFINITY)
1003 		printf("unlimited");
1004 	else if (lp->limconst == RLIMIT_CPU)
1005 		psecs((long)limit);
1006 	else
1007 		printf("%d %s", limit / lp->limdiv, lp->limscale);
1008 	printf("\n");
1009 }
1010 
1011 dounlimit(v)
1012 	register char **v;
1013 {
1014 	register struct limits *lp;
1015 	int err = 0;
1016 	char hard = 0;
1017 
1018 	v++;
1019 	if (eq(*v, "-h")) {
1020 		hard = 1;
1021 		v++;
1022 	}
1023 	if (*v == 0) {
1024 		for (lp = limits; lp->limconst >= 0; lp++)
1025 			if (setlim(lp, hard, (int)RLIM_INFINITY) < 0)
1026 				err++;
1027 		if (err)
1028 			error(NOSTR);
1029 		return;
1030 	}
1031 	while (*v) {
1032 		lp = findlim(*v++);
1033 		if (setlim(lp, hard, (int)RLIM_INFINITY) < 0)
1034 			error(NOSTR);
1035 	}
1036 }
1037 
1038 setlim(lp, hard, limit)
1039 	register struct limits *lp;
1040 	char hard;
1041 {
1042 	struct rlimit rlim;
1043 
1044 	(void) getrlimit(lp->limconst, &rlim);
1045 	if (hard)
1046 		rlim.rlim_max = limit;
1047   	else if (limit == RLIM_INFINITY && geteuid() != 0)
1048  		rlim.rlim_cur = rlim.rlim_max;
1049  	else
1050  		rlim.rlim_cur = limit;
1051 	if (setrlimit(lp->limconst, &rlim) < 0) {
1052 		printf("%s: %s: Can't %s%s limit\n", bname, lp->limname,
1053 		    limit == RLIM_INFINITY ? "remove" : "set",
1054 		    hard ? " hard" : "");
1055 		return (-1);
1056 	}
1057 	return (0);
1058 }
1059 
1060 dosuspend()
1061 {
1062 	int ldisc, ctpgrp;
1063 	int (*old)();
1064 
1065 	if (loginsh)
1066 		error("Can't suspend a login shell (yet)");
1067 	untty();
1068 	old = signal(SIGTSTP, SIG_DFL);
1069 	(void) kill(0, SIGTSTP);
1070 	/* the shell stops here */
1071 	(void) signal(SIGTSTP, old);
1072 	if (tpgrp != -1) {
1073 retry:
1074 		(void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp);
1075 		if (ctpgrp != opgrp) {
1076 			old = signal(SIGTTIN, SIG_DFL);
1077 			(void) kill(0, SIGTTIN);
1078 			(void) signal(SIGTTIN, old);
1079 			goto retry;
1080 		}
1081 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
1082 		(void) setpgrp(0, shpgrp);
1083 	}
1084 	(void) ioctl(FSHTTY, TIOCGETD, (char *)&oldisc);
1085 	if (oldisc != NTTYDISC) {
1086 		printf("Switching to new tty driver...\n");
1087 		ldisc = NTTYDISC;
1088 		(void) ioctl(FSHTTY, TIOCSETD, (char *)&ldisc);
1089 	}
1090 }
1091 
1092 doeval(v)
1093 	char **v;
1094 {
1095 	char **oevalvec = evalvec;
1096 	char *oevalp = evalp;
1097 	jmp_buf osetexit;
1098 	int reenter;
1099 	char **gv = 0;
1100 
1101 	v++;
1102 	if (*v == 0)
1103 		return;
1104 	gflag = 0, tglob(v);
1105 	if (gflag) {
1106 		gv = v = glob(v);
1107 		gargv = 0;
1108 		if (v == 0)
1109 			error("No match");
1110 		v = copyblk(v);
1111 	} else
1112 		trim(v);
1113 	getexit(osetexit);
1114 	reenter = 0;
1115 	setexit();
1116 	reenter++;
1117 	if (reenter == 1) {
1118 		evalvec = v;
1119 		evalp = 0;
1120 		process(0);
1121 	}
1122 	evalvec = oevalvec;
1123 	evalp = oevalp;
1124 	doneinp = 0;
1125 	if (gv)
1126 		blkfree(gv);
1127 	resexit(osetexit);
1128 	if (reenter >= 2)
1129 		error(NOSTR);
1130 }
1131