Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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