Bug Summary

File:src/bin/csh/func.c
Warning:line 328, column 10
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

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