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