Wed Aug 22 20:08:54 2018 UTC ()
Fix (hopefully) the problem reported on current-users by Patrick Welche.
we had incorrect usage of setstackmark()/popstackmark()

There was an ancient idiom (imported from CSRG in 1993) where code
can do:
	setstackmark(&smark); loop until whatever condition {
		/* do lots of code */ popstackmark(&smark);
	} popstackmark(&smark);

The 1st (inner) popstackmark() resets the stack, conserving memory,
The 2nd one is needed just in case the "whatever condition" was never
true, and the first one was never executed.

This is (was) safe as all popstackmark() did was reset the stack.
That could be done over and over again with no harm.

That is, until 2000 when a fix from FreeBSD for another problem was
imported.  That connected all the stack marks as a list (so they can be
located).  That caused the problem, as the idiom was not changed, now
there is this list of marks, and popstackmark() was removing an entry.

It rarely (never?) caused any problems as the idiom was rarely used
(the shell used to do loops like above, mostly, without the inner
popstackmark()).  Further, the stack mark list is only ever used when
a memory block is realloc'd.

That is, until last weekend - with the recent set of changes.

Part of that copied code from FreeBSD introduced the idiom above
into more functions - functions used much more, and with a greater
possibility of stack marks being set on blocks that are realloc'd
and so cause the problem.   In the FreeBSD code, they changed the idiom,
and always do a setstackmark() immediately after the inner popstackmark().
But not for reasons related to a list of stack marks, as in the
intervening period, FreeBSD deleted that, but for another reason.

We do not have their issue, and I did not believe that their
updated idiom was needed (I did some analysis of exactly this issue -
just missed the important part!), and just continued using the old one.
Hence Patrick's core dump....

The solution used here is to split popstackmark() into 2 halves,
popstackmark() continues to do what it has (recently) done,
but is now implemented as a call of (a new func) rststackmark()
which does all the original work of popstackmark - but not removing
the entry from the stack mark list (which remains in popstackmark()).
Then in the idiom above, the inner popstackmark() turns into a call of
rststackmark() so the stack is reset, but the stack mark list is
unchanged.  Tail recursion elimination makes this essentially free.


(kre)
diff -r1.159 -r1.160 src/bin/sh/eval.c
diff -r1.75 -r1.76 src/bin/sh/main.c
diff -r1.31 -r1.32 src/bin/sh/memalloc.c
diff -r1.17 -r1.18 src/bin/sh/memalloc.h

cvs diff -r1.159 -r1.160 src/bin/sh/eval.c (switch to unified diff)

--- src/bin/sh/eval.c 2018/08/19 23:50:27 1.159
+++ src/bin/sh/eval.c 2018/08/22 20:08:54 1.160
@@ -1,1364 +1,1364 @@ @@ -1,1364 +1,1364 @@
1/* $NetBSD: eval.c,v 1.159 2018/08/19 23:50:27 kre Exp $ */ 1/* $NetBSD: eval.c,v 1.160 2018/08/22 20:08:54 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1993 4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 38static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
39#else 39#else
40__RCSID("$NetBSD: eval.c,v 1.159 2018/08/19 23:50:27 kre Exp $"); 40__RCSID("$NetBSD: eval.c,v 1.160 2018/08/22 20:08:54 kre Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <stdbool.h> 44#include <stdbool.h>
45#include <stdlib.h> 45#include <stdlib.h>
46#include <signal.h> 46#include <signal.h>
47#include <stdio.h> 47#include <stdio.h>
48#include <string.h> 48#include <string.h>
49#include <errno.h> 49#include <errno.h>
50#include <limits.h> 50#include <limits.h>
51#include <unistd.h> 51#include <unistd.h>
52#include <sys/fcntl.h> 52#include <sys/fcntl.h>
53#include <sys/stat.h> 53#include <sys/stat.h>
54#include <sys/times.h> 54#include <sys/times.h>
55#include <sys/param.h> 55#include <sys/param.h>
56#include <sys/types.h> 56#include <sys/types.h>
57#include <sys/wait.h> 57#include <sys/wait.h>
58#include <sys/sysctl.h> 58#include <sys/sysctl.h>
59 59
60/* 60/*
61 * Evaluate a command. 61 * Evaluate a command.
62 */ 62 */
63 63
64#include "shell.h" 64#include "shell.h"
65#include "nodes.h" 65#include "nodes.h"
66#include "syntax.h" 66#include "syntax.h"
67#include "expand.h" 67#include "expand.h"
68#include "parser.h" 68#include "parser.h"
69#include "jobs.h" 69#include "jobs.h"
70#include "eval.h" 70#include "eval.h"
71#include "builtins.h" 71#include "builtins.h"
72#include "options.h" 72#include "options.h"
73#include "exec.h" 73#include "exec.h"
74#include "redir.h" 74#include "redir.h"
75#include "input.h" 75#include "input.h"
76#include "output.h" 76#include "output.h"
77#include "trap.h" 77#include "trap.h"
78#include "var.h" 78#include "var.h"
79#include "memalloc.h" 79#include "memalloc.h"
80#include "error.h" 80#include "error.h"
81#include "show.h" 81#include "show.h"
82#include "mystring.h" 82#include "mystring.h"
83#include "main.h" 83#include "main.h"
84#ifndef SMALL 84#ifndef SMALL
85#include "nodenames.h" 85#include "nodenames.h"
86#include "myhistedit.h" 86#include "myhistedit.h"
87#endif 87#endif
88 88
89 89
90STATIC enum skipstate evalskip; /* != SKIPNONE if we are skipping commands */ 90STATIC enum skipstate evalskip; /* != SKIPNONE if we are skipping commands */
91STATIC int skipcount; /* number of levels to skip */ 91STATIC int skipcount; /* number of levels to skip */
92STATIC int loopnest; /* current loop nesting level */ 92STATIC int loopnest; /* current loop nesting level */
93STATIC int funcnest; /* depth of function calls */ 93STATIC int funcnest; /* depth of function calls */
94STATIC int builtin_flags; /* evalcommand flags for builtins */ 94STATIC int builtin_flags; /* evalcommand flags for builtins */
95/* 95/*
96 * Base function nesting level inside a dot command. Set to 0 initially 96 * Base function nesting level inside a dot command. Set to 0 initially
97 * and to (funcnest + 1) before every dot command to enable  97 * and to (funcnest + 1) before every dot command to enable
98 * 1) detection of being in a file sourced by a dot command and 98 * 1) detection of being in a file sourced by a dot command and
99 * 2) counting of function nesting in that file for the implementation 99 * 2) counting of function nesting in that file for the implementation
100 * of the return command. 100 * of the return command.
101 * The value is reset to its previous value after the dot command. 101 * The value is reset to its previous value after the dot command.
102 */ 102 */
103STATIC int dot_funcnest; 103STATIC int dot_funcnest;
104 104
105 105
106const char *commandname; 106const char *commandname;
107struct strlist *cmdenviron; 107struct strlist *cmdenviron;
108int exitstatus; /* exit status of last command */ 108int exitstatus; /* exit status of last command */
109int back_exitstatus; /* exit status of backquoted command */ 109int back_exitstatus; /* exit status of backquoted command */
110 110
111 111
112STATIC void evalloop(union node *, int); 112STATIC void evalloop(union node *, int);
113STATIC void evalfor(union node *, int); 113STATIC void evalfor(union node *, int);
114STATIC void evalcase(union node *, int); 114STATIC void evalcase(union node *, int);
115STATIC void evalsubshell(union node *, int); 115STATIC void evalsubshell(union node *, int);
116STATIC void expredir(union node *); 116STATIC void expredir(union node *);
117STATIC void evalredir(union node *, int); 117STATIC void evalredir(union node *, int);
118STATIC void evalpipe(union node *); 118STATIC void evalpipe(union node *);
119STATIC void evalcommand(union node *, int, struct backcmd *); 119STATIC void evalcommand(union node *, int, struct backcmd *);
120STATIC void prehash(union node *); 120STATIC void prehash(union node *);
121 121
122STATIC char *find_dot_file(char *); 122STATIC char *find_dot_file(char *);
123 123
124/* 124/*
125 * Called to reset things after an exception. 125 * Called to reset things after an exception.
126 */ 126 */
127 127
128#ifdef mkinit 128#ifdef mkinit
129INCLUDE "eval.h" 129INCLUDE "eval.h"
130 130
131RESET { 131RESET {
132 reset_eval(); 132 reset_eval();
133} 133}
134 134
135SHELLPROC { 135SHELLPROC {
136 exitstatus = 0; 136 exitstatus = 0;
137} 137}
138#endif 138#endif
139 139
140void 140void
141reset_eval(void) 141reset_eval(void)
142{ 142{
143 evalskip = SKIPNONE; 143 evalskip = SKIPNONE;
144 dot_funcnest = 0; 144 dot_funcnest = 0;
145 loopnest = 0; 145 loopnest = 0;
146 funcnest = 0; 146 funcnest = 0;
147} 147}
148 148
149static int 149static int
150sh_pipe(int fds[2]) 150sh_pipe(int fds[2])
151{ 151{
152 int nfd; 152 int nfd;
153 153
154 if (pipe(fds)) 154 if (pipe(fds))
155 return -1; 155 return -1;
156 156
157 if (fds[0] < 3) { 157 if (fds[0] < 3) {
158 nfd = fcntl(fds[0], F_DUPFD, 3); 158 nfd = fcntl(fds[0], F_DUPFD, 3);
159 if (nfd != -1) { 159 if (nfd != -1) {
160 close(fds[0]); 160 close(fds[0]);
161 fds[0] = nfd; 161 fds[0] = nfd;
162 } 162 }
163 } 163 }
164 164
165 if (fds[1] < 3) { 165 if (fds[1] < 3) {
166 nfd = fcntl(fds[1], F_DUPFD, 3); 166 nfd = fcntl(fds[1], F_DUPFD, 3);
167 if (nfd != -1) { 167 if (nfd != -1) {
168 close(fds[1]); 168 close(fds[1]);
169 fds[1] = nfd; 169 fds[1] = nfd;
170 } 170 }
171 } 171 }
172 return 0; 172 return 0;
173} 173}
174 174
175 175
176/* 176/*
177 * The eval commmand. 177 * The eval commmand.
178 */ 178 */
179 179
180int 180int
181evalcmd(int argc, char **argv) 181evalcmd(int argc, char **argv)
182{ 182{
183 char *p; 183 char *p;
184 char *concat; 184 char *concat;
185 char **ap; 185 char **ap;
186 186
187 if (argc > 1) { 187 if (argc > 1) {
188 p = argv[1]; 188 p = argv[1];
189 if (argc > 2) { 189 if (argc > 2) {
190 STARTSTACKSTR(concat); 190 STARTSTACKSTR(concat);
191 ap = argv + 2; 191 ap = argv + 2;
192 for (;;) { 192 for (;;) {
193 while (*p) 193 while (*p)
194 STPUTC(*p++, concat); 194 STPUTC(*p++, concat);
195 if ((p = *ap++) == NULL) 195 if ((p = *ap++) == NULL)
196 break; 196 break;
197 STPUTC(' ', concat); 197 STPUTC(' ', concat);
198 } 198 }
199 STPUTC('\0', concat); 199 STPUTC('\0', concat);
200 p = grabstackstr(concat); 200 p = grabstackstr(concat);
201 } 201 }
202 evalstring(p, builtin_flags & EV_TESTED); 202 evalstring(p, builtin_flags & EV_TESTED);
203 } else 203 } else
204 exitstatus = 0; 204 exitstatus = 0;
205 return exitstatus; 205 return exitstatus;
206} 206}
207 207
208 208
209/* 209/*
210 * Execute a command or commands contained in a string. 210 * Execute a command or commands contained in a string.
211 */ 211 */
212 212
213void 213void
214evalstring(char *s, int flag) 214evalstring(char *s, int flag)
215{ 215{
216 union node *n; 216 union node *n;
217 struct stackmark smark; 217 struct stackmark smark;
218 int last; 218 int last;
219 int any; 219 int any;
220 220
221 last = flag & EV_EXIT; 221 last = flag & EV_EXIT;
222 flag &= ~EV_EXIT; 222 flag &= ~EV_EXIT;
223 223
224 setstackmark(&smark); 224 setstackmark(&smark);
225 setinputstring(s, 1, line_number); 225 setinputstring(s, 1, line_number);
226 226
227 any = 0; /* to determine if exitstatus will have been set */ 227 any = 0; /* to determine if exitstatus will have been set */
228 while ((n = parsecmd(0)) != NEOF) { 228 while ((n = parsecmd(0)) != NEOF) {
229 XTRACE(DBG_EVAL, ("evalstring: "), showtree(n)); 229 XTRACE(DBG_EVAL, ("evalstring: "), showtree(n));
230 if (n && nflag == 0) { 230 if (n && nflag == 0) {
231 if (last && at_eof()) 231 if (last && at_eof())
232 evaltree(n, flag | EV_EXIT); 232 evaltree(n, flag | EV_EXIT);
233 else 233 else
234 evaltree(n, flag); 234 evaltree(n, flag);
235 any = 1; 235 any = 1;
236 } 236 }
237 popstackmark(&smark); 237 rststackmark(&smark);
238 } 238 }
239 popfile(); 239 popfile();
240 popstackmark(&smark); 240 popstackmark(&smark);
241 if (!any) 241 if (!any)
242 exitstatus = 0; 242 exitstatus = 0;
243 if (last) 243 if (last)
244 exraise(EXEXIT); 244 exraise(EXEXIT);
245} 245}
246 246
247 247
248 248
249/* 249/*
250 * Evaluate a parse tree. The value is left in the global variable 250 * Evaluate a parse tree. The value is left in the global variable
251 * exitstatus. 251 * exitstatus.
252 */ 252 */
253 253
254void 254void
255evaltree(union node *n, int flags) 255evaltree(union node *n, int flags)
256{ 256{
257 bool do_etest; 257 bool do_etest;
258 int sflags = flags & ~EV_EXIT; 258 int sflags = flags & ~EV_EXIT;
259 union node *next; 259 union node *next;
260 struct stackmark smark; 260 struct stackmark smark;
261 261
262 do_etest = false; 262 do_etest = false;
263 if (n == NULL || nflag) { 263 if (n == NULL || nflag) {
264 VTRACE(DBG_EVAL, ("evaltree(%s) called\n", 264 VTRACE(DBG_EVAL, ("evaltree(%s) called\n",
265 n == NULL ? "NULL" : "-n")); 265 n == NULL ? "NULL" : "-n"));
266 if (nflag == 0) 266 if (nflag == 0)
267 exitstatus = 0; 267 exitstatus = 0;
268 goto out2; 268 goto out2;
269 } 269 }
270 270
271 setstackmark(&smark); 271 setstackmark(&smark);
272 do { 272 do {
273#ifndef SMALL 273#ifndef SMALL
274 displayhist = 1; /* show history substitutions done with fc */ 274 displayhist = 1; /* show history substitutions done with fc */
275#endif 275#endif
276 next = NULL; 276 next = NULL;
277 CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n", 277 CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n",
278 getpid(), n, NODETYPENAME(n->type), n->type, flags)); 278 getpid(), n, NODETYPENAME(n->type), n->type, flags));
279 switch (n->type) { 279 switch (n->type) {
280 case NSEMI: 280 case NSEMI:
281 evaltree(n->nbinary.ch1, sflags); 281 evaltree(n->nbinary.ch1, sflags);
282 if (nflag || evalskip) 282 if (nflag || evalskip)
283 goto out1; 283 goto out1;
284 next = n->nbinary.ch2; 284 next = n->nbinary.ch2;
285 break; 285 break;
286 case NAND: 286 case NAND:
287 evaltree(n->nbinary.ch1, EV_TESTED); 287 evaltree(n->nbinary.ch1, EV_TESTED);
288 if (nflag || evalskip || exitstatus != 0) 288 if (nflag || evalskip || exitstatus != 0)
289 goto out1; 289 goto out1;
290 next = n->nbinary.ch2; 290 next = n->nbinary.ch2;
291 break; 291 break;
292 case NOR: 292 case NOR:
293 evaltree(n->nbinary.ch1, EV_TESTED); 293 evaltree(n->nbinary.ch1, EV_TESTED);
294 if (nflag || evalskip || exitstatus == 0) 294 if (nflag || evalskip || exitstatus == 0)
295 goto out1; 295 goto out1;
296 next = n->nbinary.ch2; 296 next = n->nbinary.ch2;
297 break; 297 break;
298 case NREDIR: 298 case NREDIR:
299 evalredir(n, flags); 299 evalredir(n, flags);
300 break; 300 break;
301 case NSUBSHELL: 301 case NSUBSHELL:
302 evalsubshell(n, flags); 302 evalsubshell(n, flags);
303 do_etest = !(flags & EV_TESTED); 303 do_etest = !(flags & EV_TESTED);
304 break; 304 break;
305 case NBACKGND: 305 case NBACKGND:
306 evalsubshell(n, flags); 306 evalsubshell(n, flags);
307 break; 307 break;
308 case NIF: { 308 case NIF: {
309 evaltree(n->nif.test, EV_TESTED); 309 evaltree(n->nif.test, EV_TESTED);
310 if (nflag || evalskip) 310 if (nflag || evalskip)
311 goto out1; 311 goto out1;
312 if (exitstatus == 0) 312 if (exitstatus == 0)
313 next = n->nif.ifpart; 313 next = n->nif.ifpart;
314 else if (n->nif.elsepart) 314 else if (n->nif.elsepart)
315 next = n->nif.elsepart; 315 next = n->nif.elsepart;
316 else 316 else
317 exitstatus = 0; 317 exitstatus = 0;
318 break; 318 break;
319 } 319 }
320 case NWHILE: 320 case NWHILE:
321 case NUNTIL: 321 case NUNTIL:
322 evalloop(n, sflags); 322 evalloop(n, sflags);
323 break; 323 break;
324 case NFOR: 324 case NFOR:
325 evalfor(n, sflags); 325 evalfor(n, sflags);
326 break; 326 break;
327 case NCASE: 327 case NCASE:
328 evalcase(n, sflags); 328 evalcase(n, sflags);
329 break; 329 break;
330 case NDEFUN: 330 case NDEFUN:
331 CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n", 331 CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n",
332 n->narg.text, n->narg.lineno, 332 n->narg.text, n->narg.lineno,
333 fnline1 ? " LINENO=1" : "")); 333 fnline1 ? " LINENO=1" : ""));
334 defun(n->narg.text, n->narg.next, n->narg.lineno); 334 defun(n->narg.text, n->narg.next, n->narg.lineno);
335 exitstatus = 0; 335 exitstatus = 0;
336 break; 336 break;
337 case NNOT: 337 case NNOT:
338 evaltree(n->nnot.com, EV_TESTED); 338 evaltree(n->nnot.com, EV_TESTED);
339 exitstatus = !exitstatus; 339 exitstatus = !exitstatus;
340 break; 340 break;
341 case NDNOT: 341 case NDNOT:
342 evaltree(n->nnot.com, EV_TESTED); 342 evaltree(n->nnot.com, EV_TESTED);
343 if (exitstatus != 0) 343 if (exitstatus != 0)
344 exitstatus = 1; 344 exitstatus = 1;
345 break; 345 break;
346 case NPIPE: 346 case NPIPE:
347 evalpipe(n); 347 evalpipe(n);
348 do_etest = !(flags & EV_TESTED); 348 do_etest = !(flags & EV_TESTED);
349 break; 349 break;
350 case NCMD: 350 case NCMD:
351 evalcommand(n, flags, NULL); 351 evalcommand(n, flags, NULL);
352 do_etest = !(flags & EV_TESTED); 352 do_etest = !(flags & EV_TESTED);
353 break; 353 break;
354 default: 354 default:
355#ifdef NODETYPENAME 355#ifdef NODETYPENAME
356 out1fmt("Node type = %d(%s)\n", 356 out1fmt("Node type = %d(%s)\n",
357 n->type, NODETYPENAME(n->type)); 357 n->type, NODETYPENAME(n->type));
358#else 358#else
359 out1fmt("Node type = %d\n", n->type); 359 out1fmt("Node type = %d\n", n->type);
360#endif 360#endif
361 flushout(&output); 361 flushout(&output);
362 break; 362 break;
363 } 363 }
364 n = next; 364 n = next;
365 popstackmark(&smark); 365 rststackmark(&smark);
366 } while(n != NULL); 366 } while(n != NULL);
367 out1: 367 out1:
368 popstackmark(&smark); 368 popstackmark(&smark);
369 out2: 369 out2:
370 if (pendingsigs) 370 if (pendingsigs)
371 dotrap(); 371 dotrap();
372 if (eflag && exitstatus != 0 && do_etest) 372 if (eflag && exitstatus != 0 && do_etest)
373 exitshell(exitstatus); 373 exitshell(exitstatus);
374 if (flags & EV_EXIT) 374 if (flags & EV_EXIT)
375 exraise(EXEXIT); 375 exraise(EXEXIT);
376} 376}
377 377
378 378
379STATIC void 379STATIC void
380evalloop(union node *n, int flags) 380evalloop(union node *n, int flags)
381{ 381{
382 int status; 382 int status;
383 383
384 loopnest++; 384 loopnest++;
385 status = 0; 385 status = 0;
386 386
387 CTRACE(DBG_EVAL, ("evalloop %s:", NODETYPENAME(n->type))); 387 CTRACE(DBG_EVAL, ("evalloop %s:", NODETYPENAME(n->type)));
388 VXTRACE(DBG_EVAL, (" "), showtree(n->nbinary.ch1)); 388 VXTRACE(DBG_EVAL, (" "), showtree(n->nbinary.ch1));
389 VXTRACE(DBG_EVAL, ("evalloop do: "), showtree(n->nbinary.ch2)); 389 VXTRACE(DBG_EVAL, ("evalloop do: "), showtree(n->nbinary.ch2));
390 VTRACE(DBG_EVAL, ("evalloop done\n")); 390 VTRACE(DBG_EVAL, ("evalloop done\n"));
391 CTRACE(DBG_EVAL, ("\n")); 391 CTRACE(DBG_EVAL, ("\n"));
392 392
393 for (;;) { 393 for (;;) {
394 evaltree(n->nbinary.ch1, EV_TESTED); 394 evaltree(n->nbinary.ch1, EV_TESTED);
395 if (nflag) 395 if (nflag)
396 break; 396 break;
397 if (evalskip) { 397 if (evalskip) {
398 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 398 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
399 evalskip = SKIPNONE; 399 evalskip = SKIPNONE;
400 continue; 400 continue;
401 } 401 }
402 if (evalskip == SKIPBREAK && --skipcount <= 0) 402 if (evalskip == SKIPBREAK && --skipcount <= 0)
403 evalskip = SKIPNONE; 403 evalskip = SKIPNONE;
404 break; 404 break;
405 } 405 }
406 if (n->type == NWHILE) { 406 if (n->type == NWHILE) {
407 if (exitstatus != 0) 407 if (exitstatus != 0)
408 break; 408 break;
409 } else { 409 } else {
410 if (exitstatus == 0) 410 if (exitstatus == 0)
411 break; 411 break;
412 } 412 }
413 evaltree(n->nbinary.ch2, flags & EV_TESTED); 413 evaltree(n->nbinary.ch2, flags & EV_TESTED);
414 status = exitstatus; 414 status = exitstatus;
415 if (evalskip) 415 if (evalskip)
416 goto skipping; 416 goto skipping;
417 } 417 }
418 loopnest--; 418 loopnest--;
419 exitstatus = status; 419 exitstatus = status;
420} 420}
421 421
422 422
423 423
424STATIC void 424STATIC void
425evalfor(union node *n, int flags) 425evalfor(union node *n, int flags)
426{ 426{
427 struct arglist arglist; 427 struct arglist arglist;
428 union node *argp; 428 union node *argp;
429 struct strlist *sp; 429 struct strlist *sp;
430 struct stackmark smark; 430 struct stackmark smark;
431 int status; 431 int status;
432 432
433 status = nflag ? exitstatus : 0; 433 status = nflag ? exitstatus : 0;
434 434
435 setstackmark(&smark); 435 setstackmark(&smark);
436 arglist.lastp = &arglist.list; 436 arglist.lastp = &arglist.list;
437 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 437 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
438 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 438 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
439 if (evalskip) 439 if (evalskip)
440 goto out; 440 goto out;
441 } 441 }
442 *arglist.lastp = NULL; 442 *arglist.lastp = NULL;
443 443
444 loopnest++; 444 loopnest++;
445 for (sp = arglist.list ; sp ; sp = sp->next) { 445 for (sp = arglist.list ; sp ; sp = sp->next) {
446 if (xflag) { 446 if (xflag) {
447 outxstr(expandstr(ps4val(), line_number)); 447 outxstr(expandstr(ps4val(), line_number));
448 outxstr("for "); 448 outxstr("for ");
449 outxstr(n->nfor.var); 449 outxstr(n->nfor.var);
450 outxc('='); 450 outxc('=');
451 outxshstr(sp->text); 451 outxshstr(sp->text);
452 outxc('\n'); 452 outxc('\n');
453 flushout(outx); 453 flushout(outx);
454 } 454 }
455 455
456 setvar(n->nfor.var, sp->text, 0); 456 setvar(n->nfor.var, sp->text, 0);
457 evaltree(n->nfor.body, flags & EV_TESTED); 457 evaltree(n->nfor.body, flags & EV_TESTED);
458 status = exitstatus; 458 status = exitstatus;
459 if (nflag) 459 if (nflag)
460 break; 460 break;
461 if (evalskip) { 461 if (evalskip) {
462 if (evalskip == SKIPCONT && --skipcount <= 0) { 462 if (evalskip == SKIPCONT && --skipcount <= 0) {
463 evalskip = SKIPNONE; 463 evalskip = SKIPNONE;
464 continue; 464 continue;
465 } 465 }
466 if (evalskip == SKIPBREAK && --skipcount <= 0) 466 if (evalskip == SKIPBREAK && --skipcount <= 0)
467 evalskip = SKIPNONE; 467 evalskip = SKIPNONE;
468 break; 468 break;
469 } 469 }
470 } 470 }
471 loopnest--; 471 loopnest--;
472 exitstatus = status; 472 exitstatus = status;
473 out: 473 out:
474 popstackmark(&smark); 474 popstackmark(&smark);
475} 475}
476 476
477 477
478 478
479STATIC void 479STATIC void
480evalcase(union node *n, int flags) 480evalcase(union node *n, int flags)
481{ 481{
482 union node *cp, *ncp; 482 union node *cp, *ncp;
483 union node *patp; 483 union node *patp;
484 struct arglist arglist; 484 struct arglist arglist;
485 struct stackmark smark; 485 struct stackmark smark;
486 int status = 0; 486 int status = 0;
487 487
488 setstackmark(&smark); 488 setstackmark(&smark);
489 arglist.lastp = &arglist.list; 489 arglist.lastp = &arglist.list;
490 line_number = n->ncase.lineno; 490 line_number = n->ncase.lineno;
491 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 491 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
492 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 492 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
493 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 493 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
494 line_number = patp->narg.lineno; 494 line_number = patp->narg.lineno;
495 if (casematch(patp, arglist.list->text)) { 495 if (casematch(patp, arglist.list->text)) {
496 while (cp != NULL && evalskip == 0 && 496 while (cp != NULL && evalskip == 0 &&
497 nflag == 0) { 497 nflag == 0) {
498 if (cp->type == NCLISTCONT) 498 if (cp->type == NCLISTCONT)
499 ncp = cp->nclist.next; 499 ncp = cp->nclist.next;
500 else 500 else
501 ncp = NULL; 501 ncp = NULL;
502 line_number = cp->nclist.lineno; 502 line_number = cp->nclist.lineno;
503 evaltree(cp->nclist.body, flags); 503 evaltree(cp->nclist.body, flags);
504 status = exitstatus; 504 status = exitstatus;
505 cp = ncp; 505 cp = ncp;
506 } 506 }
507 goto out; 507 goto out;
508 } 508 }
509 } 509 }
510 } 510 }
511 out: 511 out:
512 exitstatus = status; 512 exitstatus = status;
513 popstackmark(&smark); 513 popstackmark(&smark);
514} 514}
515 515
516 516
517 517
518/* 518/*
519 * Kick off a subshell to evaluate a tree. 519 * Kick off a subshell to evaluate a tree.
520 */ 520 */
521 521
522STATIC void 522STATIC void
523evalsubshell(union node *n, int flags) 523evalsubshell(union node *n, int flags)
524{ 524{
525 struct job *jp= NULL; 525 struct job *jp= NULL;
526 int backgnd = (n->type == NBACKGND); 526 int backgnd = (n->type == NBACKGND);
527 527
528 expredir(n->nredir.redirect); 528 expredir(n->nredir.redirect);
529 if (xflag && n->nredir.redirect) { 529 if (xflag && n->nredir.redirect) {
530 union node *rn; 530 union node *rn;
531 531
532 outxstr(expandstr(ps4val(), line_number)); 532 outxstr(expandstr(ps4val(), line_number));
533 outxstr("using redirections:"); 533 outxstr("using redirections:");
534 for (rn = n->nredir.redirect; rn; rn = rn->nfile.next) 534 for (rn = n->nredir.redirect; rn; rn = rn->nfile.next)
535 (void) outredir(outx, rn, ' '); 535 (void) outredir(outx, rn, ' ');
536 outxstr(" do subshell ("/*)*/); 536 outxstr(" do subshell ("/*)*/);
537 if (backgnd) 537 if (backgnd)
538 outxstr(/*(*/") &"); 538 outxstr(/*(*/") &");
539 outxc('\n'); 539 outxc('\n');
540 flushout(outx); 540 flushout(outx);
541 } 541 }
542 if ((!backgnd && flags & EV_EXIT && !have_traps()) || 542 if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
543 forkshell(jp = makejob(n, 1), n, backgnd?FORK_BG:FORK_FG) == 0) { 543 forkshell(jp = makejob(n, 1), n, backgnd?FORK_BG:FORK_FG) == 0) {
544 INTON; 544 INTON;
545 if (backgnd) 545 if (backgnd)
546 flags &=~ EV_TESTED; 546 flags &=~ EV_TESTED;
547 redirect(n->nredir.redirect, REDIR_KEEP); 547 redirect(n->nredir.redirect, REDIR_KEEP);
548 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 548 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
549 } else if (!backgnd) { 549 } else if (!backgnd) {
550 INTOFF; 550 INTOFF;
551 exitstatus = waitforjob(jp); 551 exitstatus = waitforjob(jp);
552 INTON; 552 INTON;
553 } else 553 } else
554 exitstatus = 0; 554 exitstatus = 0;
555 555
556 if (!backgnd && xflag && n->nredir.redirect) { 556 if (!backgnd && xflag && n->nredir.redirect) {
557 outxstr(expandstr(ps4val(), line_number)); 557 outxstr(expandstr(ps4val(), line_number));
558 outxstr(/*(*/") done subshell\n"); 558 outxstr(/*(*/") done subshell\n");
559 flushout(outx); 559 flushout(outx);
560 } 560 }
561} 561}
562 562
563 563
564 564
565/* 565/*
566 * Compute the names of the files in a redirection list. 566 * Compute the names of the files in a redirection list.
567 */ 567 */
568 568
569STATIC void 569STATIC void
570expredir(union node *n) 570expredir(union node *n)
571{ 571{
572 union node *redir; 572 union node *redir;
573 573
574 for (redir = n ; redir ; redir = redir->nfile.next) { 574 for (redir = n ; redir ; redir = redir->nfile.next) {
575 struct arglist fn; 575 struct arglist fn;
576 576
577 fn.lastp = &fn.list; 577 fn.lastp = &fn.list;
578 switch (redir->type) { 578 switch (redir->type) {
579 case NFROMTO: 579 case NFROMTO:
580 case NFROM: 580 case NFROM:
581 case NTO: 581 case NTO:
582 case NCLOBBER: 582 case NCLOBBER:
583 case NAPPEND: 583 case NAPPEND:
584 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 584 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
585 redir->nfile.expfname = fn.list->text; 585 redir->nfile.expfname = fn.list->text;
586 break; 586 break;
587 case NFROMFD: 587 case NFROMFD:
588 case NTOFD: 588 case NTOFD:
589 if (redir->ndup.vname) { 589 if (redir->ndup.vname) {
590 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 590 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
591 fixredir(redir, fn.list->text, 1); 591 fixredir(redir, fn.list->text, 1);
592 } 592 }
593 break; 593 break;
594 } 594 }
595 } 595 }
596} 596}
597 597
598/* 598/*
599 * Perform redirections for a compound command, and then do it (and restore) 599 * Perform redirections for a compound command, and then do it (and restore)
600 */ 600 */
601STATIC void 601STATIC void
602evalredir(union node *n, int flags) 602evalredir(union node *n, int flags)
603{ 603{
604 struct jmploc jmploc; 604 struct jmploc jmploc;
605 struct jmploc * const savehandler = handler; 605 struct jmploc * const savehandler = handler;
606 volatile int in_redirect = 1; 606 volatile int in_redirect = 1;
607 const char * volatile PS4 = NULL; 607 const char * volatile PS4 = NULL;
608 608
609 expredir(n->nredir.redirect); 609 expredir(n->nredir.redirect);
610 610
611 if (xflag && n->nredir.redirect) { 611 if (xflag && n->nredir.redirect) {
612 union node *rn; 612 union node *rn;
613 613
614 outxstr(PS4 = expandstr(ps4val(), line_number)); 614 outxstr(PS4 = expandstr(ps4val(), line_number));
615 outxstr("using redirections:"); 615 outxstr("using redirections:");
616 for (rn = n->nredir.redirect; rn != NULL; rn = rn->nfile.next) 616 for (rn = n->nredir.redirect; rn != NULL; rn = rn->nfile.next)
617 (void) outredir(outx, rn, ' '); 617 (void) outredir(outx, rn, ' ');
618 outxstr(" do {\n"); /* } */ 618 outxstr(" do {\n"); /* } */
619 flushout(outx); 619 flushout(outx);
620 } 620 }
621 621
622 if (setjmp(jmploc.loc)) { 622 if (setjmp(jmploc.loc)) {
623 int e; 623 int e;
624 624
625 handler = savehandler; 625 handler = savehandler;
626 e = exception; 626 e = exception;
627 popredir(); 627 popredir();
628 if (xflag && n->nredir.redirect) { 628 if (xflag && n->nredir.redirect) {
629 outxstr(PS4); 629 outxstr(PS4);
630 /* { */ outxstr("} failed\n"); 630 /* { */ outxstr("} failed\n");
631 flushout(outx); 631 flushout(outx);
632 } 632 }
633 if (e == EXERROR || e == EXEXEC) { 633 if (e == EXERROR || e == EXEXEC) {
634 if (in_redirect) { 634 if (in_redirect) {
635 exitstatus = 2; 635 exitstatus = 2;
636 return; 636 return;
637 } 637 }
638 } 638 }
639 longjmp(handler->loc, 1); 639 longjmp(handler->loc, 1);
640 } else { 640 } else {
641 INTOFF; 641 INTOFF;
642 handler = &jmploc; 642 handler = &jmploc;
643 redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP); 643 redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP);
644 in_redirect = 0; 644 in_redirect = 0;
645 INTON; 645 INTON;
646 evaltree(n->nredir.n, flags); 646 evaltree(n->nredir.n, flags);
647 } 647 }
648 INTOFF; 648 INTOFF;
649 handler = savehandler; 649 handler = savehandler;
650 popredir(); 650 popredir();
651 INTON; 651 INTON;
652 652
653 if (xflag && n->nredir.redirect) { 653 if (xflag && n->nredir.redirect) {
654 outxstr(PS4); 654 outxstr(PS4);
655 /* { */ outxstr("} done\n"); 655 /* { */ outxstr("} done\n");
656 flushout(outx); 656 flushout(outx);
657 } 657 }
658} 658}
659 659
660 660
661/* 661/*
662 * Evaluate a pipeline. All the processes in the pipeline are children 662 * Evaluate a pipeline. All the processes in the pipeline are children
663 * of the process creating the pipeline. (This differs from some versions 663 * of the process creating the pipeline. (This differs from some versions
664 * of the shell, which make the last process in a pipeline the parent 664 * of the shell, which make the last process in a pipeline the parent
665 * of all the rest.) 665 * of all the rest.)
666 */ 666 */
667 667
668STATIC void 668STATIC void
669evalpipe(union node *n) 669evalpipe(union node *n)
670{ 670{
671 struct job *jp; 671 struct job *jp;
672 struct nodelist *lp; 672 struct nodelist *lp;
673 int pipelen; 673 int pipelen;
674 int prevfd; 674 int prevfd;
675 int pip[2]; 675 int pip[2];
676 676
677 CTRACE(DBG_EVAL, ("evalpipe(%p) called\n", n)); 677 CTRACE(DBG_EVAL, ("evalpipe(%p) called\n", n));
678 pipelen = 0; 678 pipelen = 0;
679 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 679 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
680 pipelen++; 680 pipelen++;
681 INTOFF; 681 INTOFF;
682 jp = makejob(n, pipelen); 682 jp = makejob(n, pipelen);
683 prevfd = -1; 683 prevfd = -1;
684 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 684 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
685 prehash(lp->n); 685 prehash(lp->n);
686 pip[1] = -1; 686 pip[1] = -1;
687 if (lp->next) { 687 if (lp->next) {
688 if (sh_pipe(pip) < 0) { 688 if (sh_pipe(pip) < 0) {
689 if (prevfd >= 0) 689 if (prevfd >= 0)
690 close(prevfd); 690 close(prevfd);
691 error("Pipe call failed: %s", strerror(errno)); 691 error("Pipe call failed: %s", strerror(errno));
692 } 692 }
693 } 693 }
694 if (forkshell(jp, lp->n, 694 if (forkshell(jp, lp->n,
695 n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) { 695 n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
696 INTON; 696 INTON;
697 if (prevfd > 0) 697 if (prevfd > 0)
698 movefd(prevfd, 0); 698 movefd(prevfd, 0);
699 if (pip[1] >= 0) { 699 if (pip[1] >= 0) {
700 close(pip[0]); 700 close(pip[0]);
701 movefd(pip[1], 1); 701 movefd(pip[1], 1);
702 } 702 }
703 evaltree(lp->n, EV_EXIT); 703 evaltree(lp->n, EV_EXIT);
704 } 704 }
705 if (prevfd >= 0) 705 if (prevfd >= 0)
706 close(prevfd); 706 close(prevfd);
707 prevfd = pip[0]; 707 prevfd = pip[0];
708 close(pip[1]); 708 close(pip[1]);
709 } 709 }
710 if (n->npipe.backgnd == 0) { 710 if (n->npipe.backgnd == 0) {
711 INTOFF; 711 INTOFF;
712 exitstatus = waitforjob(jp); 712 exitstatus = waitforjob(jp);
713 CTRACE(DBG_EVAL, ("evalpipe: job done exit status %d\n", 713 CTRACE(DBG_EVAL, ("evalpipe: job done exit status %d\n",
714 exitstatus)); 714 exitstatus));
715 INTON; 715 INTON;
716 } else 716 } else
717 exitstatus = 0; 717 exitstatus = 0;
718 INTON; 718 INTON;
719} 719}
720 720
721 721
722 722
723/* 723/*
724 * Execute a command inside back quotes. If it's a builtin command, we 724 * Execute a command inside back quotes. If it's a builtin command, we
725 * want to save its output in a block obtained from malloc. Otherwise 725 * want to save its output in a block obtained from malloc. Otherwise
726 * we fork off a subprocess and get the output of the command via a pipe. 726 * we fork off a subprocess and get the output of the command via a pipe.
727 * Should be called with interrupts off. 727 * Should be called with interrupts off.
728 */ 728 */
729 729
730void 730void
731evalbackcmd(union node *n, struct backcmd *result) 731evalbackcmd(union node *n, struct backcmd *result)
732{ 732{
733 int pip[2]; 733 int pip[2];
734 struct job *jp; 734 struct job *jp;
735 struct stackmark smark; /* unnecessary (because we fork) */ 735 struct stackmark smark; /* unnecessary (because we fork) */
736 736
737 result->fd = -1; 737 result->fd = -1;
738 result->buf = NULL; 738 result->buf = NULL;
739 result->nleft = 0; 739 result->nleft = 0;
740 result->jp = NULL; 740 result->jp = NULL;
741 741
742 if (nflag || n == NULL) 742 if (nflag || n == NULL)
743 goto out; 743 goto out;
744 744
745 setstackmark(&smark); 745 setstackmark(&smark);
746 746
747#ifdef notyet 747#ifdef notyet
748 /* 748 /*
749 * For now we disable executing builtins in the same 749 * For now we disable executing builtins in the same
750 * context as the shell, because we are not keeping 750 * context as the shell, because we are not keeping
751 * enough state to recover from changes that are 751 * enough state to recover from changes that are
752 * supposed only to affect subshells. eg. echo "`cd /`" 752 * supposed only to affect subshells. eg. echo "`cd /`"
753 */ 753 */
754 if (n->type == NCMD) { 754 if (n->type == NCMD) {
755 exitstatus = oexitstatus; /* XXX o... no longer exists */ 755 exitstatus = oexitstatus; /* XXX o... no longer exists */
756 evalcommand(n, EV_BACKCMD, result); 756 evalcommand(n, EV_BACKCMD, result);
757 } else 757 } else
758#endif 758#endif
759 { 759 {
760 INTOFF; 760 INTOFF;
761 if (sh_pipe(pip) < 0) 761 if (sh_pipe(pip) < 0)
762 error("Pipe call failed"); 762 error("Pipe call failed");
763 jp = makejob(n, 1); 763 jp = makejob(n, 1);
764 if (forkshell(jp, n, FORK_NOJOB) == 0) { 764 if (forkshell(jp, n, FORK_NOJOB) == 0) {
765 FORCEINTON; 765 FORCEINTON;
766 close(pip[0]); 766 close(pip[0]);
767 movefd(pip[1], 1); 767 movefd(pip[1], 1);
768 eflag = 0; 768 eflag = 0;
769 evaltree(n, EV_EXIT); 769 evaltree(n, EV_EXIT);
770 /* NOTREACHED */ 770 /* NOTREACHED */
771 } 771 }
772 close(pip[1]); 772 close(pip[1]);
773 result->fd = pip[0]; 773 result->fd = pip[0];
774 result->jp = jp; 774 result->jp = jp;
775 INTON; 775 INTON;
776 } 776 }
777 popstackmark(&smark); 777 popstackmark(&smark);
778 out: 778 out:
779 CTRACE(DBG_EVAL, ("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 779 CTRACE(DBG_EVAL, ("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
780 result->fd, result->buf, result->nleft, result->jp)); 780 result->fd, result->buf, result->nleft, result->jp));
781} 781}
782 782
783const char * 783const char *
784syspath(void) 784syspath(void)
785{ 785{
786 static char *sys_path = NULL; 786 static char *sys_path = NULL;
787 static int mib[] = {CTL_USER, USER_CS_PATH}; 787 static int mib[] = {CTL_USER, USER_CS_PATH};
788 static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin"; 788 static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
789 size_t len; 789 size_t len;
790 790
791 if (sys_path == NULL) { 791 if (sys_path == NULL) {
792 if (sysctl(mib, 2, 0, &len, 0, 0) != -1 && 792 if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
793 (sys_path = ckmalloc(len + 5)) != NULL && 793 (sys_path = ckmalloc(len + 5)) != NULL &&
794 sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) { 794 sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
795 memcpy(sys_path, "PATH=", 5); 795 memcpy(sys_path, "PATH=", 5);
796 } else { 796 } else {
797 ckfree(sys_path); 797 ckfree(sys_path);
798 /* something to keep things happy */ 798 /* something to keep things happy */
799 sys_path = def_path; 799 sys_path = def_path;
800 } 800 }
801 } 801 }
802 return sys_path; 802 return sys_path;
803} 803}
804 804
805static int 805static int
806parse_command_args(int argc, char **argv, int *use_syspath) 806parse_command_args(int argc, char **argv, int *use_syspath)
807{ 807{
808 int sv_argc = argc; 808 int sv_argc = argc;
809 char *cp, c; 809 char *cp, c;
810 810
811 *use_syspath = 0; 811 *use_syspath = 0;
812 812
813 for (;;) { 813 for (;;) {
814 argv++; 814 argv++;
815 if (--argc == 0) 815 if (--argc == 0)
816 break; 816 break;
817 cp = *argv; 817 cp = *argv;
818 if (*cp++ != '-') 818 if (*cp++ != '-')
819 break; 819 break;
820 if (*cp == '-' && cp[1] == 0) { 820 if (*cp == '-' && cp[1] == 0) {
821 argv++; 821 argv++;
822 argc--; 822 argc--;
823 break; 823 break;
824 } 824 }
825 while ((c = *cp++)) { 825 while ((c = *cp++)) {
826 switch (c) { 826 switch (c) {
827 case 'p': 827 case 'p':
828 *use_syspath = 1; 828 *use_syspath = 1;
829 break; 829 break;
830 default: 830 default:
831 /* run 'typecmd' for other options */ 831 /* run 'typecmd' for other options */
832 return 0; 832 return 0;
833 } 833 }
834 } 834 }
835 } 835 }
836 return sv_argc - argc; 836 return sv_argc - argc;
837} 837}
838 838
839int vforked = 0; 839int vforked = 0;
840extern char *trap[]; 840extern char *trap[];
841 841
842/* 842/*
843 * Execute a simple command. 843 * Execute a simple command.
844 */ 844 */
845 845
846STATIC void 846STATIC void
847evalcommand(union node *cmd, int flgs, struct backcmd *backcmd) 847evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
848{ 848{
849 struct stackmark smark; 849 struct stackmark smark;
850 union node *argp; 850 union node *argp;
851 struct arglist arglist; 851 struct arglist arglist;
852 struct arglist varlist; 852 struct arglist varlist;
853 volatile int flags = flgs; 853 volatile int flags = flgs;
854 char ** volatile argv; 854 char ** volatile argv;
855 volatile int argc; 855 volatile int argc;
856 char **envp; 856 char **envp;
857 int varflag; 857 int varflag;
858 struct strlist *sp; 858 struct strlist *sp;
859 volatile int mode; 859 volatile int mode;
860 int pip[2]; 860 int pip[2];
861 struct cmdentry cmdentry; 861 struct cmdentry cmdentry;
862 struct job * volatile jp; 862 struct job * volatile jp;
863 struct jmploc jmploc; 863 struct jmploc jmploc;
864 struct jmploc *volatile savehandler = NULL; 864 struct jmploc *volatile savehandler = NULL;
865 const char *volatile savecmdname; 865 const char *volatile savecmdname;
866 volatile struct shparam saveparam; 866 volatile struct shparam saveparam;
867 struct localvar *volatile savelocalvars; 867 struct localvar *volatile savelocalvars;
868 volatile int e; 868 volatile int e;
869 char * volatile lastarg; 869 char * volatile lastarg;
870 const char * volatile path = pathval(); 870 const char * volatile path = pathval();
871 volatile int temp_path; 871 volatile int temp_path;
872 const int savefuncline = funclinebase; 872 const int savefuncline = funclinebase;
873 const int savefuncabs = funclineabs; 873 const int savefuncabs = funclineabs;
874 874
875 vforked = 0; 875 vforked = 0;
876 /* First expand the arguments. */ 876 /* First expand the arguments. */
877 CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called [%s]\n", cmd, flags, 877 CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called [%s]\n", cmd, flags,
878 cmd->ncmd.args ? cmd->ncmd.args->narg.text : "")); 878 cmd->ncmd.args ? cmd->ncmd.args->narg.text : ""));
879 setstackmark(&smark); 879 setstackmark(&smark);
880 back_exitstatus = 0; 880 back_exitstatus = 0;
881 881
882 line_number = cmd->ncmd.lineno; 882 line_number = cmd->ncmd.lineno;
883 883
884 arglist.lastp = &arglist.list; 884 arglist.lastp = &arglist.list;
885 varflag = 1; 885 varflag = 1;
886 /* Expand arguments, ignoring the initial 'name=value' ones */ 886 /* Expand arguments, ignoring the initial 'name=value' ones */
887 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 887 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
888 char *p = argp->narg.text; 888 char *p = argp->narg.text;
889 889
890 line_number = argp->narg.lineno; 890 line_number = argp->narg.lineno;
891 if (varflag && is_name(*p)) { 891 if (varflag && is_name(*p)) {
892 do { 892 do {
893 p++; 893 p++;
894 } while (is_in_name(*p)); 894 } while (is_in_name(*p));
895 if (*p == '=') 895 if (*p == '=')
896 continue; 896 continue;
897 } 897 }
898 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 898 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
899 varflag = 0; 899 varflag = 0;
900 } 900 }
901 *arglist.lastp = NULL; 901 *arglist.lastp = NULL;
902 902
903 expredir(cmd->ncmd.redirect); 903 expredir(cmd->ncmd.redirect);
904 904
905 /* Now do the initial 'name=value' ones we skipped above */ 905 /* Now do the initial 'name=value' ones we skipped above */
906 varlist.lastp = &varlist.list; 906 varlist.lastp = &varlist.list;
907 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 907 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
908 char *p = argp->narg.text; 908 char *p = argp->narg.text;
909 909
910 line_number = argp->narg.lineno; 910 line_number = argp->narg.lineno;
911 if (!is_name(*p)) 911 if (!is_name(*p))
912 break; 912 break;
913 do 913 do
914 p++; 914 p++;
915 while (is_in_name(*p)); 915 while (is_in_name(*p));
916 if (*p != '=') 916 if (*p != '=')
917 break; 917 break;
918 expandarg(argp, &varlist, EXP_VARTILDE); 918 expandarg(argp, &varlist, EXP_VARTILDE);
919 } 919 }
920 *varlist.lastp = NULL; 920 *varlist.lastp = NULL;
921 921
922 argc = 0; 922 argc = 0;
923 for (sp = arglist.list ; sp ; sp = sp->next) 923 for (sp = arglist.list ; sp ; sp = sp->next)
924 argc++; 924 argc++;
925 argv = stalloc(sizeof (char *) * (argc + 1)); 925 argv = stalloc(sizeof (char *) * (argc + 1));
926 926
927 for (sp = arglist.list ; sp ; sp = sp->next) { 927 for (sp = arglist.list ; sp ; sp = sp->next) {
928 VTRACE(DBG_EVAL, ("evalcommand arg: %s\n", sp->text)); 928 VTRACE(DBG_EVAL, ("evalcommand arg: %s\n", sp->text));
929 *argv++ = sp->text; 929 *argv++ = sp->text;
930 } 930 }
931 *argv = NULL; 931 *argv = NULL;
932 lastarg = NULL; 932 lastarg = NULL;
933 if (iflag && funcnest == 0 && argc > 0) 933 if (iflag && funcnest == 0 && argc > 0)
934 lastarg = argv[-1]; 934 lastarg = argv[-1];
935 argv -= argc; 935 argv -= argc;
936 936
937 /* Print the command if xflag is set. */ 937 /* Print the command if xflag is set. */
938 if (xflag) { 938 if (xflag) {
939 char sep = 0; 939 char sep = 0;
940 union node *rn; 940 union node *rn;
941 941
942 outxstr(expandstr(ps4val(), line_number)); 942 outxstr(expandstr(ps4val(), line_number));
943 for (sp = varlist.list ; sp ; sp = sp->next) { 943 for (sp = varlist.list ; sp ; sp = sp->next) {
944 char *p; 944 char *p;
945 945
946 if (sep != 0) 946 if (sep != 0)
947 outxc(sep); 947 outxc(sep);
948 948
949 /* 949 /*
950 * The "var=" part should not be quoted, regardless 950 * The "var=" part should not be quoted, regardless
951 * of the value, or it would not represent an 951 * of the value, or it would not represent an
952 * assignment, but rather a command 952 * assignment, but rather a command
953 */ 953 */
954 p = strchr(sp->text, '='); 954 p = strchr(sp->text, '=');
955 if (p != NULL) { 955 if (p != NULL) {
956 *p = '\0'; /*XXX*/ 956 *p = '\0'; /*XXX*/
957 outxshstr(sp->text); 957 outxshstr(sp->text);
958 outxc('='); 958 outxc('=');
959 *p++ = '='; /*XXX*/ 959 *p++ = '='; /*XXX*/
960 } else 960 } else
961 p = sp->text; 961 p = sp->text;
962 outxshstr(p); 962 outxshstr(p);
963 sep = ' '; 963 sep = ' ';
964 } 964 }
965 for (sp = arglist.list ; sp ; sp = sp->next) { 965 for (sp = arglist.list ; sp ; sp = sp->next) {
966 if (sep != 0) 966 if (sep != 0)
967 outxc(sep); 967 outxc(sep);
968 outxshstr(sp->text); 968 outxshstr(sp->text);
969 sep = ' '; 969 sep = ' ';
970 } 970 }
971 for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next) 971 for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next)
972 if (outredir(outx, rn, sep)) 972 if (outredir(outx, rn, sep))
973 sep = ' '; 973 sep = ' ';
974 outxc('\n'); 974 outxc('\n');
975 flushout(outx); 975 flushout(outx);
976 } 976 }
977 977
978 /* Now locate the command. */ 978 /* Now locate the command. */
979 if (argc == 0) { 979 if (argc == 0) {
980 cmdentry.cmdtype = CMDSPLBLTIN; 980 cmdentry.cmdtype = CMDSPLBLTIN;
981 cmdentry.u.bltin = bltincmd; 981 cmdentry.u.bltin = bltincmd;
982 } else { 982 } else {
983 static const char PATH[] = "PATH="; 983 static const char PATH[] = "PATH=";
984 int cmd_flags = 0; 984 int cmd_flags = 0;
985 985
986 /* 986 /*
987 * Modify the command lookup path, if a PATH= assignment 987 * Modify the command lookup path, if a PATH= assignment
988 * is present 988 * is present
989 */ 989 */
990 for (sp = varlist.list; sp; sp = sp->next) 990 for (sp = varlist.list; sp; sp = sp->next)
991 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 991 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
992 path = sp->text + sizeof(PATH) - 1; 992 path = sp->text + sizeof(PATH) - 1;
993 993
994 do { 994 do {
995 int argsused, use_syspath; 995 int argsused, use_syspath;
996 996
997 find_command(argv[0], &cmdentry, cmd_flags, path); 997 find_command(argv[0], &cmdentry, cmd_flags, path);
998#if 0 998#if 0
999 /* 999 /*
1000 * This short circuits all of the processing that 1000 * This short circuits all of the processing that
1001 * should be done (including processing the 1001 * should be done (including processing the
1002 * redirects), so just don't ... 1002 * redirects), so just don't ...
1003 * 1003 *
1004 * (eventually this whole #if'd block will vanish) 1004 * (eventually this whole #if'd block will vanish)
1005 */ 1005 */
1006 if (cmdentry.cmdtype == CMDUNKNOWN) { 1006 if (cmdentry.cmdtype == CMDUNKNOWN) {
1007 exitstatus = 127; 1007 exitstatus = 127;
1008 flushout(&errout); 1008 flushout(&errout);
1009 goto out; 1009 goto out;
1010 } 1010 }
1011#endif 1011#endif
1012 1012
1013 /* implement the 'command' builtin here */ 1013 /* implement the 'command' builtin here */
1014 if (cmdentry.cmdtype != CMDBUILTIN || 1014 if (cmdentry.cmdtype != CMDBUILTIN ||
1015 cmdentry.u.bltin != bltincmd) 1015 cmdentry.u.bltin != bltincmd)
1016 break; 1016 break;
1017 cmd_flags |= DO_NOFUNC; 1017 cmd_flags |= DO_NOFUNC;
1018 argsused = parse_command_args(argc, argv, &use_syspath); 1018 argsused = parse_command_args(argc, argv, &use_syspath);
1019 if (argsused == 0) { 1019 if (argsused == 0) {
1020 /* use 'type' builtin to display info */ 1020 /* use 'type' builtin to display info */
1021 cmdentry.u.bltin = typecmd; 1021 cmdentry.u.bltin = typecmd;
1022 break; 1022 break;
1023 } 1023 }
1024 argc -= argsused; 1024 argc -= argsused;
1025 argv += argsused; 1025 argv += argsused;
1026 if (use_syspath) 1026 if (use_syspath)
1027 path = syspath() + 5; 1027 path = syspath() + 5;
1028 } while (argc != 0); 1028 } while (argc != 0);
1029 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) 1029 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
1030 /* posix mandates that 'command <splbltin>' act as if 1030 /* posix mandates that 'command <splbltin>' act as if
1031 <splbltin> was a normal builtin */ 1031 <splbltin> was a normal builtin */
1032 cmdentry.cmdtype = CMDBUILTIN; 1032 cmdentry.cmdtype = CMDBUILTIN;
1033 } 1033 }
1034 1034
1035 /* Fork off a child process if necessary. */ 1035 /* Fork off a child process if necessary. */
1036 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0) 1036 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0)
1037 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 1037 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
1038 && (flags & EV_EXIT) == 0) 1038 && (flags & EV_EXIT) == 0)
1039 || ((flags & EV_BACKCMD) != 0 && 1039 || ((flags & EV_BACKCMD) != 0 &&
1040 ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) 1040 ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
1041 || cmdentry.u.bltin == dotcmd 1041 || cmdentry.u.bltin == dotcmd
1042 || cmdentry.u.bltin == evalcmd))) { 1042 || cmdentry.u.bltin == evalcmd))) {
1043 INTOFF; 1043 INTOFF;
1044 jp = makejob(cmd, 1); 1044 jp = makejob(cmd, 1);
1045 mode = cmd->ncmd.backgnd; 1045 mode = cmd->ncmd.backgnd;
1046 if (flags & EV_BACKCMD) { 1046 if (flags & EV_BACKCMD) {
1047 mode = FORK_NOJOB; 1047 mode = FORK_NOJOB;
1048 if (sh_pipe(pip) < 0) 1048 if (sh_pipe(pip) < 0)
1049 error("Pipe call failed"); 1049 error("Pipe call failed");
1050 } 1050 }
1051#ifdef DO_SHAREDVFORK 1051#ifdef DO_SHAREDVFORK
1052 /* It is essential that if DO_SHAREDVFORK is defined that the 1052 /* It is essential that if DO_SHAREDVFORK is defined that the
1053 * child's address space is actually shared with the parent as 1053 * child's address space is actually shared with the parent as
1054 * we rely on this. 1054 * we rely on this.
1055 */ 1055 */
1056 if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL) { 1056 if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL) {
1057 pid_t pid; 1057 pid_t pid;
1058 int serrno; 1058 int serrno;
1059 1059
1060 savelocalvars = localvars; 1060 savelocalvars = localvars;
1061 localvars = NULL; 1061 localvars = NULL;
1062 vforked = 1; 1062 vforked = 1;
1063 VFORK_BLOCK 1063 VFORK_BLOCK
1064 switch (pid = vfork()) { 1064 switch (pid = vfork()) {
1065 case -1: 1065 case -1:
1066 serrno = errno; 1066 serrno = errno;
1067 VTRACE(DBG_EVAL, ("vfork() failed, errno=%d\n", 1067 VTRACE(DBG_EVAL, ("vfork() failed, errno=%d\n",
1068 serrno)); 1068 serrno));
1069 INTON; 1069 INTON;
1070 error("Cannot vfork (%s)", strerror(serrno)); 1070 error("Cannot vfork (%s)", strerror(serrno));
1071 break; 1071 break;
1072 case 0: 1072 case 0:
1073 /* Make sure that exceptions only unwind to 1073 /* Make sure that exceptions only unwind to
1074 * after the vfork(2) 1074 * after the vfork(2)
1075 */ 1075 */
1076 SHELL_FORKED(); 1076 SHELL_FORKED();
1077 if (setjmp(jmploc.loc)) { 1077 if (setjmp(jmploc.loc)) {
1078 if (exception == EXSHELLPROC) { 1078 if (exception == EXSHELLPROC) {
1079 /* 1079 /*
1080 * We can't progress with the 1080 * We can't progress with the
1081 * vfork, so, set vforked = 2 1081 * vfork, so, set vforked = 2
1082 * so the parent knows, 1082 * so the parent knows,
1083 * and _exit(); 1083 * and _exit();
1084 */ 1084 */
1085 vforked = 2; 1085 vforked = 2;
1086 _exit(0); 1086 _exit(0);
1087 } else { 1087 } else {
1088 _exit(exerrno); 1088 _exit(exerrno);
1089 } 1089 }
1090 } 1090 }
1091 savehandler = handler; 1091 savehandler = handler;
1092 handler = &jmploc; 1092 handler = &jmploc;
1093 listmklocal(varlist.list, VEXPORT | VNOFUNC); 1093 listmklocal(varlist.list, VEXPORT | VNOFUNC);
1094 forkchild(jp, cmd, mode, vforked); 1094 forkchild(jp, cmd, mode, vforked);
1095 break; 1095 break;
1096 default: 1096 default:
1097 VFORK_UNDO(); 1097 VFORK_UNDO();
1098 /* restore from vfork(2) */ 1098 /* restore from vfork(2) */
1099 handler = savehandler; 1099 handler = savehandler;
1100 poplocalvars(); 1100 poplocalvars();
1101 localvars = savelocalvars; 1101 localvars = savelocalvars;
1102 if (vforked == 2) { 1102 if (vforked == 2) {
1103 vforked = 0; 1103 vforked = 0;
1104 1104
1105 (void)waitpid(pid, NULL, 0); 1105 (void)waitpid(pid, NULL, 0);
1106 /* 1106 /*
1107 * We need to progress in a 1107 * We need to progress in a
1108 * normal fork fashion 1108 * normal fork fashion
1109 */ 1109 */
1110 goto normal_fork; 1110 goto normal_fork;
1111 } 1111 }
1112 /* 1112 /*
1113 * Here the child has left home, 1113 * Here the child has left home,
1114 * getting on with its life, so 1114 * getting on with its life, so
1115 * so must we... 1115 * so must we...
1116 */ 1116 */
1117 vforked = 0; 1117 vforked = 0;
1118 forkparent(jp, cmd, mode, pid); 1118 forkparent(jp, cmd, mode, pid);
1119 goto parent; 1119 goto parent;
1120 } 1120 }
1121 VFORK_END 1121 VFORK_END
1122 } else { 1122 } else {
1123 normal_fork: 1123 normal_fork:
1124#endif 1124#endif
1125 if (forkshell(jp, cmd, mode) != 0) 1125 if (forkshell(jp, cmd, mode) != 0)
1126 goto parent; /* at end of routine */ 1126 goto parent; /* at end of routine */
1127 flags |= EV_EXIT; 1127 flags |= EV_EXIT;
1128 FORCEINTON; 1128 FORCEINTON;
1129#ifdef DO_SHAREDVFORK 1129#ifdef DO_SHAREDVFORK
1130 } 1130 }
1131#endif 1131#endif
1132 if (flags & EV_BACKCMD) { 1132 if (flags & EV_BACKCMD) {
1133 if (!vforked) { 1133 if (!vforked) {
1134 FORCEINTON; 1134 FORCEINTON;
1135 } 1135 }
1136 close(pip[0]); 1136 close(pip[0]);
1137 movefd(pip[1], 1); 1137 movefd(pip[1], 1);
1138 } 1138 }
1139 flags |= EV_EXIT; 1139 flags |= EV_EXIT;
1140 } 1140 }
1141 1141
1142 /* This is the child process if a fork occurred. */ 1142 /* This is the child process if a fork occurred. */
1143 /* Execute the command. */ 1143 /* Execute the command. */
1144 switch (cmdentry.cmdtype) { 1144 switch (cmdentry.cmdtype) {
1145 volatile int saved; 1145 volatile int saved;
1146 1146
1147 case CMDFUNCTION: 1147 case CMDFUNCTION:
1148 VXTRACE(DBG_EVAL, ("Shell function%s: ",vforked?" VF":""), 1148 VXTRACE(DBG_EVAL, ("Shell function%s: ",vforked?" VF":""),
1149 trargs(argv)); 1149 trargs(argv));
1150 redirect(cmd->ncmd.redirect, saved = 1150 redirect(cmd->ncmd.redirect, saved =
1151 !(flags & EV_EXIT) || have_traps() ? REDIR_PUSH : 0); 1151 !(flags & EV_EXIT) || have_traps() ? REDIR_PUSH : 0);
1152 saveparam = shellparam; 1152 saveparam = shellparam;
1153 shellparam.malloc = 0; 1153 shellparam.malloc = 0;
1154 shellparam.reset = 1; 1154 shellparam.reset = 1;
1155 shellparam.nparam = argc - 1; 1155 shellparam.nparam = argc - 1;
1156 shellparam.p = argv + 1; 1156 shellparam.p = argv + 1;
1157 shellparam.optnext = NULL; 1157 shellparam.optnext = NULL;
1158 INTOFF; 1158 INTOFF;
1159 savelocalvars = localvars; 1159 savelocalvars = localvars;
1160 localvars = NULL; 1160 localvars = NULL;
1161 reffunc(cmdentry.u.func); 1161 reffunc(cmdentry.u.func);
1162 INTON; 1162 INTON;
1163 if (setjmp(jmploc.loc)) { 1163 if (setjmp(jmploc.loc)) {
1164 if (exception == EXSHELLPROC) { 1164 if (exception == EXSHELLPROC) {
1165 freeparam((volatile struct shparam *) 1165 freeparam((volatile struct shparam *)
1166 &saveparam); 1166 &saveparam);
1167 } else { 1167 } else {
1168 freeparam(&shellparam); 1168 freeparam(&shellparam);
1169 shellparam = saveparam; 1169 shellparam = saveparam;
1170 } 1170 }
1171 if (saved) 1171 if (saved)
1172 popredir();; 1172 popredir();;
1173 unreffunc(cmdentry.u.func); 1173 unreffunc(cmdentry.u.func);
1174 poplocalvars(); 1174 poplocalvars();
1175 localvars = savelocalvars; 1175 localvars = savelocalvars;
1176 funclinebase = savefuncline; 1176 funclinebase = savefuncline;
1177 funclineabs = savefuncabs; 1177 funclineabs = savefuncabs;
1178 handler = savehandler; 1178 handler = savehandler;
1179 longjmp(handler->loc, 1); 1179 longjmp(handler->loc, 1);
1180 } 1180 }
1181 savehandler = handler; 1181 savehandler = handler;
1182 handler = &jmploc; 1182 handler = &jmploc;
1183 if (cmdentry.u.func) { 1183 if (cmdentry.u.func) {
1184 if (cmdentry.lno_frel) 1184 if (cmdentry.lno_frel)
1185 funclinebase = cmdentry.lineno - 1; 1185 funclinebase = cmdentry.lineno - 1;
1186 else 1186 else
1187 funclinebase = 0; 1187 funclinebase = 0;
1188 funclineabs = cmdentry.lineno; 1188 funclineabs = cmdentry.lineno;
1189 1189
1190 VTRACE(DBG_EVAL, 1190 VTRACE(DBG_EVAL,
1191 ("function: node: %d '%s' # %d%s; funclinebase=%d\n", 1191 ("function: node: %d '%s' # %d%s; funclinebase=%d\n",
1192 getfuncnode(cmdentry.u.func)->type, 1192 getfuncnode(cmdentry.u.func)->type,
1193 NODETYPENAME(getfuncnode(cmdentry.u.func)->type), 1193 NODETYPENAME(getfuncnode(cmdentry.u.func)->type),
1194 cmdentry.lineno, cmdentry.lno_frel?" (=1)":"", 1194 cmdentry.lineno, cmdentry.lno_frel?" (=1)":"",
1195 funclinebase)); 1195 funclinebase));
1196 } 1196 }
1197 listmklocal(varlist.list, VEXPORT); 1197 listmklocal(varlist.list, VEXPORT);
1198 /* stop shell blowing its stack */ 1198 /* stop shell blowing its stack */
1199 if (++funcnest > 1000) 1199 if (++funcnest > 1000)
1200 error("too many nested function calls"); 1200 error("too many nested function calls");
1201 evaltree(getfuncnode(cmdentry.u.func), 1201 evaltree(getfuncnode(cmdentry.u.func),
1202 flags & (EV_TESTED|EV_EXIT)); 1202 flags & (EV_TESTED|EV_EXIT));
1203 funcnest--; 1203 funcnest--;
1204 INTOFF; 1204 INTOFF;
1205 unreffunc(cmdentry.u.func); 1205 unreffunc(cmdentry.u.func);
1206 poplocalvars(); 1206 poplocalvars();
1207 localvars = savelocalvars; 1207 localvars = savelocalvars;
1208 funclinebase = savefuncline; 1208 funclinebase = savefuncline;
1209 funclineabs = savefuncabs; 1209 funclineabs = savefuncabs;
1210 freeparam(&shellparam); 1210 freeparam(&shellparam);
1211 shellparam = saveparam; 1211 shellparam = saveparam;
1212 handler = savehandler; 1212 handler = savehandler;
1213 if (saved) 1213 if (saved)
1214 popredir(); 1214 popredir();
1215 INTON; 1215 INTON;
1216 if (evalskip == SKIPFUNC) { 1216 if (evalskip == SKIPFUNC) {
1217 evalskip = SKIPNONE; 1217 evalskip = SKIPNONE;
1218 skipcount = 0; 1218 skipcount = 0;
1219 } 1219 }
1220 if (flags & EV_EXIT) 1220 if (flags & EV_EXIT)
1221 exitshell(exitstatus); 1221 exitshell(exitstatus);
1222 break; 1222 break;
1223 1223
1224 case CMDBUILTIN: 1224 case CMDBUILTIN:
1225 case CMDSPLBLTIN: 1225 case CMDSPLBLTIN:
1226 VXTRACE(DBG_EVAL, ("builtin command%s: ",vforked?" VF":""), trargs(argv)); 1226 VXTRACE(DBG_EVAL, ("builtin command%s: ",vforked?" VF":""), trargs(argv));
1227 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; 1227 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
1228 if (flags == EV_BACKCMD) { 1228 if (flags == EV_BACKCMD) {
1229 memout.nleft = 0; 1229 memout.nleft = 0;
1230 memout.nextc = memout.buf; 1230 memout.nextc = memout.buf;
1231 memout.bufsize = 64; 1231 memout.bufsize = 64;
1232 mode |= REDIR_BACKQ; 1232 mode |= REDIR_BACKQ;
1233 } 1233 }
1234 e = -1; 1234 e = -1;
1235 savehandler = handler; 1235 savehandler = handler;
1236 savecmdname = commandname; 1236 savecmdname = commandname;
1237 handler = &jmploc; 1237 handler = &jmploc;
1238 temp_path = 0; 1238 temp_path = 0;
1239 if (!setjmp(jmploc.loc)) { 1239 if (!setjmp(jmploc.loc)) {
1240 /* 1240 /*
1241 * We need to ensure the command hash table isn't 1241 * We need to ensure the command hash table isn't
1242 * corrupted by temporary PATH assignments. 1242 * corrupted by temporary PATH assignments.
1243 * However we must ensure the 'local' command works! 1243 * However we must ensure the 'local' command works!
1244 */ 1244 */
1245 if (path != pathval() && (cmdentry.u.bltin == hashcmd || 1245 if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
1246 cmdentry.u.bltin == typecmd)) { 1246 cmdentry.u.bltin == typecmd)) {
1247 savelocalvars = localvars; 1247 savelocalvars = localvars;
1248 localvars = 0; 1248 localvars = 0;
1249 temp_path = 1; 1249 temp_path = 1;
1250 mklocal(path - 5 /* PATH= */, 0); 1250 mklocal(path - 5 /* PATH= */, 0);
1251 } 1251 }
1252 redirect(cmd->ncmd.redirect, mode); 1252 redirect(cmd->ncmd.redirect, mode);
1253 1253
1254 /* exec is a special builtin, but needs this list... */ 1254 /* exec is a special builtin, but needs this list... */
1255 cmdenviron = varlist.list; 1255 cmdenviron = varlist.list;
1256 /* we must check 'readonly' flag for all builtins */ 1256 /* we must check 'readonly' flag for all builtins */
1257 listsetvar(varlist.list, 1257 listsetvar(varlist.list,
1258 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); 1258 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
1259 commandname = argv[0]; 1259 commandname = argv[0];
1260 /* initialize nextopt */ 1260 /* initialize nextopt */
1261 argptr = argv + 1; 1261 argptr = argv + 1;
1262 optptr = NULL; 1262 optptr = NULL;
1263 /* and getopt */ 1263 /* and getopt */
1264 optreset = 1; 1264 optreset = 1;
1265 optind = 1; 1265 optind = 1;
1266 builtin_flags = flags; 1266 builtin_flags = flags;
1267 exitstatus = cmdentry.u.bltin(argc, argv); 1267 exitstatus = cmdentry.u.bltin(argc, argv);
1268 } else { 1268 } else {
1269 e = exception; 1269 e = exception;
1270 if (e == EXINT) 1270 if (e == EXINT)
1271 exitstatus = SIGINT + 128; 1271 exitstatus = SIGINT + 128;
1272 else if (e == EXEXEC) 1272 else if (e == EXEXEC)
1273 exitstatus = exerrno; 1273 exitstatus = exerrno;
1274 else if (e != EXEXIT) 1274 else if (e != EXEXIT)
1275 exitstatus = 2; 1275 exitstatus = 2;
1276 } 1276 }
1277 handler = savehandler; 1277 handler = savehandler;
1278 flushall(); 1278 flushall();
1279 out1 = &output; 1279 out1 = &output;
1280 out2 = &errout; 1280 out2 = &errout;
1281 freestdout(); 1281 freestdout();
1282 if (temp_path) { 1282 if (temp_path) {
1283 poplocalvars(); 1283 poplocalvars();
1284 localvars = savelocalvars; 1284 localvars = savelocalvars;
1285 } 1285 }
1286 cmdenviron = NULL; 1286 cmdenviron = NULL;
1287 if (e != EXSHELLPROC) { 1287 if (e != EXSHELLPROC) {
1288 commandname = savecmdname; 1288 commandname = savecmdname;
1289 if (flags & EV_EXIT) 1289 if (flags & EV_EXIT)
1290 exitshell(exitstatus); 1290 exitshell(exitstatus);
1291 } 1291 }
1292 if (e != -1) { 1292 if (e != -1) {
1293 if ((e != EXERROR && e != EXEXEC) 1293 if ((e != EXERROR && e != EXEXEC)
1294 || cmdentry.cmdtype == CMDSPLBLTIN) 1294 || cmdentry.cmdtype == CMDSPLBLTIN)
1295 exraise(e); 1295 exraise(e);
1296 FORCEINTON; 1296 FORCEINTON;
1297 } 1297 }
1298 if (cmdentry.u.bltin != execcmd) 1298 if (cmdentry.u.bltin != execcmd)
1299 popredir(); 1299 popredir();
1300 if (flags == EV_BACKCMD) { 1300 if (flags == EV_BACKCMD) {
1301 backcmd->buf = memout.buf; 1301 backcmd->buf = memout.buf;
1302 backcmd->nleft = memout.nextc - memout.buf; 1302 backcmd->nleft = memout.nextc - memout.buf;
1303 memout.buf = NULL; 1303 memout.buf = NULL;
1304 } 1304 }
1305 break; 1305 break;
1306 1306
1307 default: 1307 default:
1308 VXTRACE(DBG_EVAL, ("normal command%s: ", vforked?" VF":""), 1308 VXTRACE(DBG_EVAL, ("normal command%s: ", vforked?" VF":""),
1309 trargs(argv)); 1309 trargs(argv));
1310 redirect(cmd->ncmd.redirect,  1310 redirect(cmd->ncmd.redirect,
1311 (vforked ? REDIR_VFORK : 0) | REDIR_KEEP); 1311 (vforked ? REDIR_VFORK : 0) | REDIR_KEEP);
1312 if (!vforked) 1312 if (!vforked)
1313 for (sp = varlist.list ; sp ; sp = sp->next) 1313 for (sp = varlist.list ; sp ; sp = sp->next)
1314 setvareq(sp->text, VEXPORT|VSTACK); 1314 setvareq(sp->text, VEXPORT|VSTACK);
1315 envp = environment(); 1315 envp = environment();
1316 shellexec(argv, envp, path, cmdentry.u.index, vforked); 1316 shellexec(argv, envp, path, cmdentry.u.index, vforked);
1317 break; 1317 break;
1318 } 1318 }
1319 goto out; 1319 goto out;
1320 1320
1321 parent: /* parent process gets here (if we forked) */ 1321 parent: /* parent process gets here (if we forked) */
1322 1322
1323 exitstatus = 0; /* if not altered just below */ 1323 exitstatus = 0; /* if not altered just below */
1324 if (mode == FORK_FG) { /* argument to fork */ 1324 if (mode == FORK_FG) { /* argument to fork */
1325 exitstatus = waitforjob(jp); 1325 exitstatus = waitforjob(jp);
1326 } else if (mode == FORK_NOJOB) { 1326 } else if (mode == FORK_NOJOB) {
1327 backcmd->fd = pip[0]; 1327 backcmd->fd = pip[0];
1328 close(pip[1]); 1328 close(pip[1]);
1329 backcmd->jp = jp; 1329 backcmd->jp = jp;
1330 } 1330 }
1331 FORCEINTON; 1331 FORCEINTON;
1332 1332
1333 out: 1333 out:
1334 if (lastarg) 1334 if (lastarg)
1335 /* implement $_ for whatever use that really is */ 1335 /* implement $_ for whatever use that really is */
1336 (void) setvarsafe("_", lastarg, VNOERROR); 1336 (void) setvarsafe("_", lastarg, VNOERROR);
1337 popstackmark(&smark); 1337 popstackmark(&smark);
1338} 1338}
1339 1339
1340 1340
1341/* 1341/*
1342 * Search for a command. This is called before we fork so that the 1342 * Search for a command. This is called before we fork so that the
1343 * location of the command will be available in the parent as well as 1343 * location of the command will be available in the parent as well as
1344 * the child. The check for "goodname" is an overly conservative 1344 * the child. The check for "goodname" is an overly conservative
1345 * check that the name will not be subject to expansion. 1345 * check that the name will not be subject to expansion.
1346 */ 1346 */
1347 1347
1348STATIC void 1348STATIC void
1349prehash(union node *n) 1349prehash(union node *n)
1350{ 1350{
1351 struct cmdentry entry; 1351 struct cmdentry entry;
1352 1352
1353 if (n && n->type == NCMD && n->ncmd.args) 1353 if (n && n->type == NCMD && n->ncmd.args)
1354 if (goodname(n->ncmd.args->narg.text)) 1354 if (goodname(n->ncmd.args->narg.text))
1355 find_command(n->ncmd.args->narg.text, &entry, 0, 1355 find_command(n->ncmd.args->narg.text, &entry, 0,
1356 pathval()); 1356 pathval());
1357} 1357}
1358 1358
1359int 1359int
1360in_function(void) 1360in_function(void)
1361{ 1361{
1362 return funcnest; 1362 return funcnest;
1363} 1363}
1364 1364

cvs diff -r1.75 -r1.76 src/bin/sh/main.c (switch to unified diff)

--- src/bin/sh/main.c 2018/08/19 23:50:27 1.75
+++ src/bin/sh/main.c 2018/08/22 20:08:54 1.76
@@ -1,385 +1,384 @@ @@ -1,385 +1,384 @@
1/* $NetBSD: main.c,v 1.75 2018/08/19 23:50:27 kre Exp $ */ 1/* $NetBSD: main.c,v 1.76 2018/08/22 20:08:54 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1991, 1993 4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37__COPYRIGHT("@(#) Copyright (c) 1991, 1993\ 37__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
38 The Regents of the University of California. All rights reserved."); 38 The Regents of the University of California. All rights reserved.");
39#endif /* not lint */ 39#endif /* not lint */
40 40
41#ifndef lint 41#ifndef lint
42#if 0 42#if 0
43static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95"; 43static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
44#else 44#else
45__RCSID("$NetBSD: main.c,v 1.75 2018/08/19 23:50:27 kre Exp $"); 45__RCSID("$NetBSD: main.c,v 1.76 2018/08/22 20:08:54 kre Exp $");
46#endif 46#endif
47#endif /* not lint */ 47#endif /* not lint */
48 48
49#include <errno.h> 49#include <errno.h>
50#include <stdio.h> 50#include <stdio.h>
51#include <signal.h> 51#include <signal.h>
52#include <sys/stat.h> 52#include <sys/stat.h>
53#include <unistd.h> 53#include <unistd.h>
54#include <stdlib.h> 54#include <stdlib.h>
55#include <locale.h> 55#include <locale.h>
56#include <fcntl.h> 56#include <fcntl.h>
57 57
58 58
59#include "shell.h" 59#include "shell.h"
60#include "main.h" 60#include "main.h"
61#include "mail.h" 61#include "mail.h"
62#include "options.h" 62#include "options.h"
63#include "builtins.h" 63#include "builtins.h"
64#include "output.h" 64#include "output.h"
65#include "parser.h" 65#include "parser.h"
66#include "nodes.h" 66#include "nodes.h"
67#include "expand.h" 67#include "expand.h"
68#include "eval.h" 68#include "eval.h"
69#include "jobs.h" 69#include "jobs.h"
70#include "input.h" 70#include "input.h"
71#include "trap.h" 71#include "trap.h"
72#include "var.h" 72#include "var.h"
73#include "show.h" 73#include "show.h"
74#include "memalloc.h" 74#include "memalloc.h"
75#include "error.h" 75#include "error.h"
76#include "init.h" 76#include "init.h"
77#include "mystring.h" 77#include "mystring.h"
78#include "exec.h" 78#include "exec.h"
79#include "cd.h" 79#include "cd.h"
80#include "redir.h" 80#include "redir.h"
81 81
82#define PROFILE 0 82#define PROFILE 0
83 83
84int rootpid; 84int rootpid;
85int rootshell; 85int rootshell;
86int max_user_fd; 86int max_user_fd;
87#if PROFILE 87#if PROFILE
88short profile_buf[16384]; 88short profile_buf[16384];
89extern int etext(); 89extern int etext();
90#endif 90#endif
91 91
92STATIC void read_profile(const char *); 92STATIC void read_profile(const char *);
93 93
94/* 94/*
95 * Main routine. We initialize things, parse the arguments, execute 95 * Main routine. We initialize things, parse the arguments, execute
96 * profiles if we're a login shell, and then call cmdloop to execute 96 * profiles if we're a login shell, and then call cmdloop to execute
97 * commands. The setjmp call sets up the location to jump to when an 97 * commands. The setjmp call sets up the location to jump to when an
98 * exception occurs. When an exception occurs the variable "state" 98 * exception occurs. When an exception occurs the variable "state"
99 * is used to figure out how far we had gotten. 99 * is used to figure out how far we had gotten.
100 */ 100 */
101 101
102int 102int
103main(int argc, char **argv) 103main(int argc, char **argv)
104{ 104{
105 struct jmploc jmploc; 105 struct jmploc jmploc;
106 struct stackmark smark; 106 struct stackmark smark;
107 volatile int state; 107 volatile int state;
108 char *shinit; 108 char *shinit;
109 uid_t uid; 109 uid_t uid;
110 gid_t gid; 110 gid_t gid;
111 111
112 uid = getuid(); 112 uid = getuid();
113 gid = getgid(); 113 gid = getgid();
114 114
115 max_user_fd = fcntl(0, F_MAXFD); 115 max_user_fd = fcntl(0, F_MAXFD);
116 if (max_user_fd < 2) 116 if (max_user_fd < 2)
117 max_user_fd = 2; 117 max_user_fd = 2;
118 118
119 setlocale(LC_ALL, ""); 119 setlocale(LC_ALL, "");
120 120
121 posix = getenv("POSIXLY_CORRECT") != NULL; 121 posix = getenv("POSIXLY_CORRECT") != NULL;
122#if PROFILE 122#if PROFILE
123 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 123 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
124#endif 124#endif
125 state = 0; 125 state = 0;
126 if (setjmp(jmploc.loc)) { 126 if (setjmp(jmploc.loc)) {
127 /* 127 /*
128 * When a shell procedure is executed, we raise the 128 * When a shell procedure is executed, we raise the
129 * exception EXSHELLPROC to clean up before executing 129 * exception EXSHELLPROC to clean up before executing
130 * the shell procedure. 130 * the shell procedure.
131 */ 131 */
132 switch (exception) { 132 switch (exception) {
133 case EXSHELLPROC: 133 case EXSHELLPROC:
134 rootpid = getpid(); 134 rootpid = getpid();
135 rootshell = 1; 135 rootshell = 1;
136 minusc = NULL; 136 minusc = NULL;
137 state = 3; 137 state = 3;
138 break; 138 break;
139 139
140 case EXEXEC: 140 case EXEXEC:
141 exitstatus = exerrno; 141 exitstatus = exerrno;
142 break; 142 break;
143 143
144 case EXERROR: 144 case EXERROR:
145 exitstatus = 2; 145 exitstatus = 2;
146 break; 146 break;
147 147
148 default: 148 default:
149 break; 149 break;
150 } 150 }
151 151
152 if (exception != EXSHELLPROC) { 152 if (exception != EXSHELLPROC) {
153 if (state == 0 || iflag == 0 || ! rootshell || 153 if (state == 0 || iflag == 0 || ! rootshell ||
154 exception == EXEXIT) 154 exception == EXEXIT)
155 exitshell(exitstatus); 155 exitshell(exitstatus);
156 } 156 }
157 reset(); 157 reset();
158 if (exception == EXINT) { 158 if (exception == EXINT) {
159 out2c('\n'); 159 out2c('\n');
160 flushout(&errout); 160 flushout(&errout);
161 } 161 }
162 popstackmark(&smark); 162 popstackmark(&smark);
163 FORCEINTON; /* enable interrupts */ 163 FORCEINTON; /* enable interrupts */
164 if (state == 1) 164 if (state == 1)
165 goto state1; 165 goto state1;
166 else if (state == 2) 166 else if (state == 2)
167 goto state2; 167 goto state2;
168 else if (state == 3) 168 else if (state == 3)
169 goto state3; 169 goto state3;
170 else 170 else
171 goto state4; 171 goto state4;
172 } 172 }
173 handler = &jmploc; 173 handler = &jmploc;
174#ifdef DEBUG 174#ifdef DEBUG
175#if DEBUG >= 2 175#if DEBUG >= 2
176 debug = 1; /* this may be reset by procargs() later */ 176 debug = 1; /* this may be reset by procargs() later */
177#endif 177#endif
178 opentrace(); 178 opentrace();
179 trputs("Shell args: "); trargs(argv); 179 trputs("Shell args: "); trargs(argv);
180#if DEBUG >= 3 180#if DEBUG >= 3
181 set_debug(((DEBUG)==3 ? "_@" : "++"), 1); 181 set_debug(((DEBUG)==3 ? "_@" : "++"), 1);
182#endif 182#endif
183#endif 183#endif
184 rootpid = getpid(); 184 rootpid = getpid();
185 rootshell = 1; 185 rootshell = 1;
186 init(); 186 init();
187 initpwd(); 187 initpwd();
188 setstackmark(&smark); 188 setstackmark(&smark);
189 procargs(argc, argv); 189 procargs(argc, argv);
190 190
191 /* 191 /*
192 * Limit bogus system(3) or popen(3) calls in setuid binaries, 192 * Limit bogus system(3) or popen(3) calls in setuid binaries,
193 * by requiring the -p flag 193 * by requiring the -p flag
194 */ 194 */
195 if (!pflag && (uid != geteuid() || gid != getegid())) { 195 if (!pflag && (uid != geteuid() || gid != getegid())) {
196 setuid(uid); 196 setuid(uid);
197 setgid(gid); 197 setgid(gid);
198 /* PS1 might need to be changed accordingly. */ 198 /* PS1 might need to be changed accordingly. */
199 choose_ps1(); 199 choose_ps1();
200 } 200 }
201 201
202 if (argv[0] && argv[0][0] == '-') { 202 if (argv[0] && argv[0][0] == '-') {
203 state = 1; 203 state = 1;
204 read_profile("/etc/profile"); 204 read_profile("/etc/profile");
205state1: 205state1:
206 state = 2; 206 state = 2;
207 read_profile(".profile"); 207 read_profile(".profile");
208 } 208 }
209state2: 209state2:
210 state = 3; 210 state = 3;
211 if ((iflag || !posix) && 211 if ((iflag || !posix) &&
212 getuid() == geteuid() && getgid() == getegid()) { 212 getuid() == geteuid() && getgid() == getegid()) {
213 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 213 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
214 state = 3; 214 state = 3;
215 read_profile(shinit); 215 read_profile(shinit);
216 } 216 }
217 } 217 }
218state3: 218state3:
219 state = 4; 219 state = 4;
220 line_number = 1; /* undo anything from profile files */ 220 line_number = 1; /* undo anything from profile files */
221 221
222 if (sflag == 0 || minusc) { 222 if (sflag == 0 || minusc) {
223 static int sigs[] = { 223 static int sigs[] = {
224 SIGINT, SIGQUIT, SIGHUP,  224 SIGINT, SIGQUIT, SIGHUP,
225#ifdef SIGTSTP 225#ifdef SIGTSTP
226 SIGTSTP, 226 SIGTSTP,
227#endif 227#endif
228 SIGPIPE 228 SIGPIPE
229 }; 229 };
230#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) 230#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
231 size_t i; 231 size_t i;
232 232
233 for (i = 0; i < SIGSSIZE; i++) 233 for (i = 0; i < SIGSSIZE; i++)
234 setsignal(sigs[i], 0); 234 setsignal(sigs[i], 0);
235 } 235 }
236 236
237 if (minusc) 237 if (minusc)
238 evalstring(minusc, sflag ? 0 : EV_EXIT); 238 evalstring(minusc, sflag ? 0 : EV_EXIT);
239 239
240 if (sflag || minusc == NULL) { 240 if (sflag || minusc == NULL) {
241state4: /* XXX ??? - why isn't this before the "if" statement */ 241state4: /* XXX ??? - why isn't this before the "if" statement */
242 cmdloop(1); 242 cmdloop(1);
243 } 243 }
244#if PROFILE 244#if PROFILE
245 monitor(0); 245 monitor(0);
246#endif 246#endif
247 exitshell(exitstatus); 247 exitshell(exitstatus);
248 /* NOTREACHED */ 248 /* NOTREACHED */
249} 249}
250 250
251 251
252/* 252/*
253 * Read and execute commands. "Top" is nonzero for the top level command 253 * Read and execute commands. "Top" is nonzero for the top level command
254 * loop; it turns on prompting if the shell is interactive. 254 * loop; it turns on prompting if the shell is interactive.
255 */ 255 */
256 256
257void 257void
258cmdloop(int top) 258cmdloop(int top)
259{ 259{
260 union node *n; 260 union node *n;
261 struct stackmark smark; 261 struct stackmark smark;
262 int inter; 262 int inter;
263 int numeof = 0; 263 int numeof = 0;
264 enum skipstate skip; 264 enum skipstate skip;
265 265
266 CTRACE(DBG_ALWAYS, ("cmdloop(%d) called\n", top)); 266 CTRACE(DBG_ALWAYS, ("cmdloop(%d) called\n", top));
267 setstackmark(&smark); 267 setstackmark(&smark);
268 for (;;) { 268 for (;;) {
269 if (pendingsigs) 269 if (pendingsigs)
270 dotrap(); 270 dotrap();
271 inter = 0; 271 inter = 0;
272 if (iflag == 1 && top) { 272 if (iflag == 1 && top) {
273 inter = 1; 273 inter = 1;
274 showjobs(out2, SHOW_CHANGED); 274 showjobs(out2, SHOW_CHANGED);
275 chkmail(0); 275 chkmail(0);
276 flushout(&errout); 276 flushout(&errout);
277 nflag = 0; 277 nflag = 0;
278 } 278 }
279 n = parsecmd(inter); 279 n = parsecmd(inter);
280 VXTRACE(DBG_PARSE|DBG_EVAL|DBG_CMDS,("cmdloop: "),showtree(n)); 280 VXTRACE(DBG_PARSE|DBG_EVAL|DBG_CMDS,("cmdloop: "),showtree(n));
281 if (n == NEOF) { 281 if (n == NEOF) {
282 if (!top || numeof >= 50) 282 if (!top || numeof >= 50)
283 break; 283 break;
284 if (nflag) 284 if (nflag)
285 break; 285 break;
286 if (!stoppedjobs()) { 286 if (!stoppedjobs()) {
287 if (!iflag || !Iflag) 287 if (!iflag || !Iflag)
288 break; 288 break;
289 out2str("\nUse \"exit\" to leave shell.\n"); 289 out2str("\nUse \"exit\" to leave shell.\n");
290 } 290 }
291 numeof++; 291 numeof++;
292 } else if (n != NULL && nflag == 0) { 292 } else if (n != NULL && nflag == 0) {
293 job_warning = (job_warning == 2) ? 1 : 0; 293 job_warning = (job_warning == 2) ? 1 : 0;
294 numeof = 0; 294 numeof = 0;
295 evaltree(n, 0); 295 evaltree(n, 0);
296 } 296 }
297 popstackmark(&smark); 297 rststackmark(&smark);
298 setstackmark(&smark); 
299 298
300 /* 299 /*
301 * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when 300 * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when
302 * a dotcmd is in a loop or a function body and appropriate 301 * a dotcmd is in a loop or a function body and appropriate
303 * built-ins occurs in file scope in the sourced file. Values 302 * built-ins occurs in file scope in the sourced file. Values
304 * other than SKIPFILE are reset by the appropriate eval*() 303 * other than SKIPFILE are reset by the appropriate eval*()
305 * that contained the dotcmd() call. 304 * that contained the dotcmd() call.
306 */ 305 */
307 skip = current_skipstate(); 306 skip = current_skipstate();
308 if (skip != SKIPNONE) { 307 if (skip != SKIPNONE) {
309 if (skip == SKIPFILE) 308 if (skip == SKIPFILE)
310 stop_skipping(); 309 stop_skipping();
311 break; 310 break;
312 } 311 }
313 } 312 }
314 popstackmark(&smark); 313 popstackmark(&smark);
315} 314}
316 315
317 316
318 317
319/* 318/*
320 * Read /etc/profile or .profile. Return on error. 319 * Read /etc/profile or .profile. Return on error.
321 */ 320 */
322 321
323STATIC void 322STATIC void
324read_profile(const char *name) 323read_profile(const char *name)
325{ 324{
326 int fd; 325 int fd;
327 int xflag_set = 0; 326 int xflag_set = 0;
328 int vflag_set = 0; 327 int vflag_set = 0;
329 328
330 INTOFF; 329 INTOFF;
331 if ((fd = open(name, O_RDONLY)) >= 0) 330 if ((fd = open(name, O_RDONLY)) >= 0)
332 setinputfd(fd, 1); 331 setinputfd(fd, 1);
333 INTON; 332 INTON;
334 if (fd < 0) 333 if (fd < 0)
335 return; 334 return;
336 /* -q turns off -x and -v just when executing init files */ 335 /* -q turns off -x and -v just when executing init files */
337 if (qflag) { 336 if (qflag) {
338 if (xflag) 337 if (xflag)
339 xflag = 0, xflag_set = 1; 338 xflag = 0, xflag_set = 1;
340 if (vflag) 339 if (vflag)
341 vflag = 0, vflag_set = 1; 340 vflag = 0, vflag_set = 1;
342 } 341 }
343 cmdloop(0); 342 cmdloop(0);
344 if (qflag) { 343 if (qflag) {
345 if (xflag_set) 344 if (xflag_set)
346 xflag = 1; 345 xflag = 1;
347 if (vflag_set) 346 if (vflag_set)
348 vflag = 1; 347 vflag = 1;
349 } 348 }
350 popfile(); 349 popfile();
351} 350}
352 351
353 352
354 353
355/* 354/*
356 * Read a file containing shell functions. 355 * Read a file containing shell functions.
357 */ 356 */
358 357
359void 358void
360readcmdfile(char *name) 359readcmdfile(char *name)
361{ 360{
362 int fd; 361 int fd;
363 362
364 INTOFF; 363 INTOFF;
365 if ((fd = open(name, O_RDONLY)) >= 0) 364 if ((fd = open(name, O_RDONLY)) >= 0)
366 setinputfd(fd, 1); 365 setinputfd(fd, 1);
367 else 366 else
368 error("Can't open %s", name); 367 error("Can't open %s", name);
369 INTON; 368 INTON;
370 cmdloop(0); 369 cmdloop(0);
371 popfile(); 370 popfile();
372} 371}
373 372
374 373
375 374
376int 375int
377exitcmd(int argc, char **argv) 376exitcmd(int argc, char **argv)
378{ 377{
379 if (stoppedjobs()) 378 if (stoppedjobs())
380 return 0; 379 return 0;
381 if (argc > 1) 380 if (argc > 1)
382 exitstatus = number(argv[1]); 381 exitstatus = number(argv[1]);
383 exitshell(exitstatus); 382 exitshell(exitstatus);
384 /* NOTREACHED */ 383 /* NOTREACHED */
385} 384}

cvs diff -r1.31 -r1.32 src/bin/sh/memalloc.c (switch to unified diff)

--- src/bin/sh/memalloc.c 2018/07/22 20:37:57 1.31
+++ src/bin/sh/memalloc.c 2018/08/22 20:08:54 1.32
@@ -1,326 +1,334 @@ @@ -1,326 +1,334 @@
1/* $NetBSD: memalloc.c,v 1.31 2018/07/22 20:37:57 kre Exp $ */ 1/* $NetBSD: memalloc.c,v 1.32 2018/08/22 20:08:54 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1991, 1993 4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; 38static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
39#else 39#else
40__RCSID("$NetBSD: memalloc.c,v 1.31 2018/07/22 20:37:57 kre Exp $"); 40__RCSID("$NetBSD: memalloc.c,v 1.32 2018/08/22 20:08:54 kre Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <stdlib.h> 44#include <stdlib.h>
45#include <unistd.h> 45#include <unistd.h>
46 46
47#include "shell.h" 47#include "shell.h"
48#include "output.h" 48#include "output.h"
49#include "memalloc.h" 49#include "memalloc.h"
50#include "error.h" 50#include "error.h"
51#include "machdep.h" 51#include "machdep.h"
52#include "mystring.h" 52#include "mystring.h"
53 53
54/* 54/*
55 * Like malloc, but returns an error when out of space. 55 * Like malloc, but returns an error when out of space.
56 */ 56 */
57 57
58pointer 58pointer
59ckmalloc(size_t nbytes) 59ckmalloc(size_t nbytes)
60{ 60{
61 pointer p; 61 pointer p;
62 62
63 p = malloc(nbytes); 63 p = malloc(nbytes);
64 if (p == NULL) 64 if (p == NULL)
65 error("Out of space"); 65 error("Out of space");
66 return p; 66 return p;
67} 67}
68 68
69 69
70/* 70/*
71 * Same for realloc. 71 * Same for realloc.
72 */ 72 */
73 73
74pointer 74pointer
75ckrealloc(pointer p, int nbytes) 75ckrealloc(pointer p, int nbytes)
76{ 76{
77 p = realloc(p, nbytes); 77 p = realloc(p, nbytes);
78 if (p == NULL) 78 if (p == NULL)
79 error("Out of space"); 79 error("Out of space");
80 return p; 80 return p;
81} 81}
82 82
83 83
84/* 84/*
85 * Make a copy of a string in safe storage. 85 * Make a copy of a string in safe storage.
86 */ 86 */
87 87
88char * 88char *
89savestr(const char *s) 89savestr(const char *s)
90{ 90{
91 char *p; 91 char *p;
92 92
93 p = ckmalloc(strlen(s) + 1); 93 p = ckmalloc(strlen(s) + 1);
94 scopy(s, p); 94 scopy(s, p);
95 return p; 95 return p;
96} 96}
97 97
98 98
99/* 99/*
100 * Parse trees for commands are allocated in lifo order, so we use a stack 100 * Parse trees for commands are allocated in lifo order, so we use a stack
101 * to make this more efficient, and also to avoid all sorts of exception 101 * to make this more efficient, and also to avoid all sorts of exception
102 * handling code to handle interrupts in the middle of a parse. 102 * handling code to handle interrupts in the middle of a parse.
103 * 103 *
104 * The size 504 was chosen because the Ultrix malloc handles that size 104 * The size 504 was chosen because the Ultrix malloc handles that size
105 * well. 105 * well.
106 */ 106 */
107 107
108#define MINSIZE 504 /* minimum size of a block */ 108#define MINSIZE 504 /* minimum size of a block */
109 109
110struct stack_block { 110struct stack_block {
111 struct stack_block *prev; 111 struct stack_block *prev;
112 char space[MINSIZE]; 112 char space[MINSIZE];
113}; 113};
114 114
115struct stack_block stackbase; 115struct stack_block stackbase;
116struct stack_block *stackp = &stackbase; 116struct stack_block *stackp = &stackbase;
117struct stackmark *markp; 117struct stackmark *markp;
118char *stacknxt = stackbase.space; 118char *stacknxt = stackbase.space;
119int stacknleft = MINSIZE; 119int stacknleft = MINSIZE;
120int sstrnleft; 120int sstrnleft;
121int herefd = -1; 121int herefd = -1;
122 122
123pointer 123pointer
124stalloc(int nbytes) 124stalloc(int nbytes)
125{ 125{
126 char *p; 126 char *p;
127 127
128 nbytes = SHELL_ALIGN(nbytes); 128 nbytes = SHELL_ALIGN(nbytes);
129 if (nbytes > stacknleft) { 129 if (nbytes > stacknleft) {
130 int blocksize; 130 int blocksize;
131 struct stack_block *sp; 131 struct stack_block *sp;
132 132
133 blocksize = nbytes; 133 blocksize = nbytes;
134 if (blocksize < MINSIZE) 134 if (blocksize < MINSIZE)
135 blocksize = MINSIZE; 135 blocksize = MINSIZE;
136 INTOFF; 136 INTOFF;
137 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); 137 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
138 sp->prev = stackp; 138 sp->prev = stackp;
139 stacknxt = sp->space; 139 stacknxt = sp->space;
140 stacknleft = blocksize; 140 stacknleft = blocksize;
141 stackp = sp; 141 stackp = sp;
142 INTON; 142 INTON;
143 } 143 }
144 p = stacknxt; 144 p = stacknxt;
145 stacknxt += nbytes; 145 stacknxt += nbytes;
146 stacknleft -= nbytes; 146 stacknleft -= nbytes;
147 return p; 147 return p;
148} 148}
149 149
150 150
151void 151void
152stunalloc(pointer p) 152stunalloc(pointer p)
153{ 153{
154 if (p == NULL) { /*DEBUG */ 154 if (p == NULL) { /*DEBUG */
155 write(2, "stunalloc\n", 10); 155 write(2, "stunalloc\n", 10);
156 abort(); 156 abort();
157 } 157 }
158 stacknleft += stacknxt - (char *)p; 158 stacknleft += stacknxt - (char *)p;
159 stacknxt = p; 159 stacknxt = p;
160} 160}
161 161
162 162
163 163/* save the current status of the sh stack */
164void 164void
165setstackmark(struct stackmark *mark) 165setstackmark(struct stackmark *mark)
166{ 166{
167 mark->stackp = stackp; 167 mark->stackp = stackp;
168 mark->stacknxt = stacknxt; 168 mark->stacknxt = stacknxt;
169 mark->stacknleft = stacknleft; 169 mark->stacknleft = stacknleft;
170 mark->sstrnleft = sstrnleft; 170 mark->sstrnleft = sstrnleft;
171 mark->marknext = markp; 171 mark->marknext = markp;
172 markp = mark; 172 markp = mark;
173} 173}
174 174
175 175/* reset the stack mark, and remove it from the list of marks */
176void 176void
177popstackmark(struct stackmark *mark) 177popstackmark(struct stackmark *mark)
178{ 178{
 179 markp = mark->marknext; /* delete mark from the list */
 180 rststackmark(mark); /* and reset stack */
 181}
 182
 183/* reset the shell stack to its state recorded in the stack mark */
 184void
 185rststackmark(struct stackmark *mark)
 186{
179 struct stack_block *sp; 187 struct stack_block *sp;
180 188
181 INTOFF; 189 INTOFF;
182 markp = mark->marknext; 
183 while (stackp != mark->stackp) { 190 while (stackp != mark->stackp) {
 191 /* delete any recently allocated mem blocks */
184 sp = stackp; 192 sp = stackp;
185 stackp = sp->prev; 193 stackp = sp->prev;
186 ckfree(sp); 194 ckfree(sp);
187 } 195 }
188 stacknxt = mark->stacknxt; 196 stacknxt = mark->stacknxt;
189 stacknleft = mark->stacknleft; 197 stacknleft = mark->stacknleft;
190 sstrnleft = mark->sstrnleft; 198 sstrnleft = mark->sstrnleft;
191 INTON; 199 INTON;
192} 200}
193 201
194 202
195/* 203/*
196 * When the parser reads in a string, it wants to stick the string on the 204 * When the parser reads in a string, it wants to stick the string on the
197 * stack and only adjust the stack pointer when it knows how big the 205 * stack and only adjust the stack pointer when it knows how big the
198 * string is. Stackblock (defined in stack.h) returns a pointer to a block 206 * string is. Stackblock (defined in stack.h) returns a pointer to a block
199 * of space on top of the stack and stackblocklen returns the length of 207 * of space on top of the stack and stackblocklen returns the length of
200 * this block. Growstackblock will grow this space by at least one byte, 208 * this block. Growstackblock will grow this space by at least one byte,
201 * possibly moving it (like realloc). Grabstackblock actually allocates the 209 * possibly moving it (like realloc). Grabstackblock actually allocates the
202 * part of the block that has been used. 210 * part of the block that has been used.
203 */ 211 */
204 212
205void 213void
206growstackblock(void) 214growstackblock(void)
207{ 215{
208 int newlen = SHELL_ALIGN(stacknleft * 2 + 100); 216 int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
209 217
210 INTOFF; 218 INTOFF;
211 if (stacknxt == stackp->space && stackp != &stackbase) { 219 if (stacknxt == stackp->space && stackp != &stackbase) {
212 struct stack_block *oldstackp; 220 struct stack_block *oldstackp;
213 struct stackmark *xmark; 221 struct stackmark *xmark;
214 struct stack_block *sp; 222 struct stack_block *sp;
215 223
216 oldstackp = stackp; 224 oldstackp = stackp;
217 sp = stackp; 225 sp = stackp;
218 stackp = sp->prev; 226 stackp = sp->prev;
219 sp = ckrealloc((pointer)sp, 227 sp = ckrealloc((pointer)sp,
220 sizeof(struct stack_block) - MINSIZE + newlen); 228 sizeof(struct stack_block) - MINSIZE + newlen);
221 sp->prev = stackp; 229 sp->prev = stackp;
222 stackp = sp; 230 stackp = sp;
223 stacknxt = sp->space; 231 stacknxt = sp->space;
224 sstrnleft += newlen - stacknleft; 232 sstrnleft += newlen - stacknleft;
225 stacknleft = newlen; 233 stacknleft = newlen;
226 234
227 /* 235 /*
228 * Stack marks pointing to the start of the old block 236 * Stack marks pointing to the start of the old block
229 * must be relocated to point to the new block  237 * must be relocated to point to the new block
230 */ 238 */
231 xmark = markp; 239 xmark = markp;
232 while (xmark != NULL && xmark->stackp == oldstackp) { 240 while (xmark != NULL && xmark->stackp == oldstackp) {
233 xmark->stackp = stackp; 241 xmark->stackp = stackp;
234 xmark->stacknxt = stacknxt; 242 xmark->stacknxt = stacknxt;
235 xmark->sstrnleft += stacknleft - xmark->stacknleft; 243 xmark->sstrnleft += stacknleft - xmark->stacknleft;
236 xmark->stacknleft = stacknleft; 244 xmark->stacknleft = stacknleft;
237 xmark = xmark->marknext; 245 xmark = xmark->marknext;
238 } 246 }
239 } else { 247 } else {
240 char *oldspace = stacknxt; 248 char *oldspace = stacknxt;
241 int oldlen = stacknleft; 249 int oldlen = stacknleft;
242 char *p = stalloc(newlen); 250 char *p = stalloc(newlen);
243 251
244 (void)memcpy(p, oldspace, oldlen); 252 (void)memcpy(p, oldspace, oldlen);
245 stacknxt = p; /* free the space */ 253 stacknxt = p; /* free the space */
246 stacknleft += newlen; /* we just allocated */ 254 stacknleft += newlen; /* we just allocated */
247 } 255 }
248 INTON; 256 INTON;
249} 257}
250 258
251void 259void
252grabstackblock(int len) 260grabstackblock(int len)
253{ 261{
254 len = SHELL_ALIGN(len); 262 len = SHELL_ALIGN(len);
255 stacknxt += len; 263 stacknxt += len;
256 stacknleft -= len; 264 stacknleft -= len;
257} 265}
258 266
259/* 267/*
260 * The following routines are somewhat easier to use than the above. 268 * The following routines are somewhat easier to use than the above.
261 * The user declares a variable of type STACKSTR, which may be declared 269 * The user declares a variable of type STACKSTR, which may be declared
262 * to be a register. The macro STARTSTACKSTR initializes things. Then 270 * to be a register. The macro STARTSTACKSTR initializes things. Then
263 * the user uses the macro STPUTC to add characters to the string. In 271 * the user uses the macro STPUTC to add characters to the string. In
264 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 272 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
265 * grown as necessary. When the user is done, she can just leave the 273 * grown as necessary. When the user is done, she can just leave the
266 * string there and refer to it using stackblock(). Or she can allocate 274 * string there and refer to it using stackblock(). Or she can allocate
267 * the space for it using grabstackstr(). If it is necessary to allow 275 * the space for it using grabstackstr(). If it is necessary to allow
268 * someone else to use the stack temporarily and then continue to grow 276 * someone else to use the stack temporarily and then continue to grow
269 * the string, the user should use grabstack to allocate the space, and 277 * the string, the user should use grabstack to allocate the space, and
270 * then call ungrabstr(p) to return to the previous mode of operation. 278 * then call ungrabstr(p) to return to the previous mode of operation.
271 * 279 *
272 * USTPUTC is like STPUTC except that it doesn't check for overflow. 280 * USTPUTC is like STPUTC except that it doesn't check for overflow.
273 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 281 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
274 * is space for at least one character. 282 * is space for at least one character.
275 */ 283 */
276 284
277char * 285char *
278growstackstr(void) 286growstackstr(void)
279{ 287{
280 int len = stackblocksize(); 288 int len = stackblocksize();
281 if (herefd >= 0 && len >= 1024) { 289 if (herefd >= 0 && len >= 1024) {
282 xwrite(herefd, stackblock(), len); 290 xwrite(herefd, stackblock(), len);
283 sstrnleft = len - 1; 291 sstrnleft = len - 1;
284 return stackblock(); 292 return stackblock();
285 } 293 }
286 growstackblock(); 294 growstackblock();
287 sstrnleft = stackblocksize() - len - 1; 295 sstrnleft = stackblocksize() - len - 1;
288 return stackblock() + len; 296 return stackblock() + len;
289} 297}
290 298
291/* 299/*
292 * Called from CHECKSTRSPACE. 300 * Called from CHECKSTRSPACE.
293 */ 301 */
294 302
295char * 303char *
296makestrspace(void) 304makestrspace(void)
297{ 305{
298 int len = stackblocksize() - sstrnleft; 306 int len = stackblocksize() - sstrnleft;
299 growstackblock(); 307 growstackblock();
300 sstrnleft = stackblocksize() - len; 308 sstrnleft = stackblocksize() - len;
301 return stackblock() + len; 309 return stackblock() + len;
302} 310}
303 311
304/* 312/*
305 * Note that this only works to release stack space for reuse 313 * Note that this only works to release stack space for reuse
306 * if nothing else has allocated space on the stack since the grabstackstr() 314 * if nothing else has allocated space on the stack since the grabstackstr()
307 * 315 *
308 * "s" is the start of the area to be released, and "p" represents the end 316 * "s" is the start of the area to be released, and "p" represents the end
309 * of the string we have stored beyond there and are now releasing. 317 * of the string we have stored beyond there and are now releasing.
310 * (ie: "p" should be the same as in the call to grabstackstr()). 318 * (ie: "p" should be the same as in the call to grabstackstr()).
311 * 319 *
312 * stunalloc(s) and ungrabstackstr(s, p) are almost interchangable after 320 * stunalloc(s) and ungrabstackstr(s, p) are almost interchangable after
313 * a grabstackstr(), however the latter also returns string space so we 321 * a grabstackstr(), however the latter also returns string space so we
314 * can just continue with STPUTC() etc without needing a new STARTSTACKSTR(s) 322 * can just continue with STPUTC() etc without needing a new STARTSTACKSTR(s)
315 */ 323 */
316void 324void
317ungrabstackstr(char *s, char *p) 325ungrabstackstr(char *s, char *p)
318{ 326{
319#ifdef DEBUG 327#ifdef DEBUG
320 if (s < stacknxt || stacknxt + stacknleft < s) 328 if (s < stacknxt || stacknxt + stacknleft < s)
321 abort(); 329 abort();
322#endif 330#endif
323 stacknleft += stacknxt - s; 331 stacknleft += stacknxt - s;
324 stacknxt = s; 332 stacknxt = s;
325 sstrnleft = stacknleft - (p - s); 333 sstrnleft = stacknleft - (p - s);
326} 334}

cvs diff -r1.17 -r1.18 src/bin/sh/memalloc.h (switch to unified diff)

--- src/bin/sh/memalloc.h 2017/06/17 07:22:12 1.17
+++ src/bin/sh/memalloc.h 2018/08/22 20:08:54 1.18
@@ -1,78 +1,79 @@ @@ -1,78 +1,79 @@
1/* $NetBSD: memalloc.h,v 1.17 2017/06/17 07:22:12 kre Exp $ */ 1/* $NetBSD: memalloc.h,v 1.18 2018/08/22 20:08:54 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1991, 1993 4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 * 33 *
34 * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 34 * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
35 */ 35 */
36 36
37struct stackmark { 37struct stackmark {
38 struct stack_block *stackp; 38 struct stack_block *stackp;
39 char *stacknxt; 39 char *stacknxt;
40 int stacknleft; 40 int stacknleft;
41 int sstrnleft; 41 int sstrnleft;
42 struct stackmark *marknext; 42 struct stackmark *marknext;
43}; 43};
44 44
45 45
46extern char *stacknxt; 46extern char *stacknxt;
47extern int stacknleft; 47extern int stacknleft;
48extern int sstrnleft; 48extern int sstrnleft;
49extern int herefd; 49extern int herefd;
50 50
51pointer ckmalloc(size_t); 51pointer ckmalloc(size_t);
52pointer ckrealloc(pointer, int); 52pointer ckrealloc(pointer, int);
53char *savestr(const char *); 53char *savestr(const char *);
54pointer stalloc(int); 54pointer stalloc(int);
55void stunalloc(pointer); 55void stunalloc(pointer);
56void setstackmark(struct stackmark *); 56void setstackmark(struct stackmark *);
57void popstackmark(struct stackmark *); 57void popstackmark(struct stackmark *);
 58void rststackmark(struct stackmark *);
58void growstackblock(void); 59void growstackblock(void);
59void grabstackblock(int); 60void grabstackblock(int);
60char *growstackstr(void); 61char *growstackstr(void);
61char *makestrspace(void); 62char *makestrspace(void);
62void ungrabstackstr(char *, char *); 63void ungrabstackstr(char *, char *);
63 64
64 65
65 66
66#define stackblock() stacknxt 67#define stackblock() stacknxt
67#define stackblocksize() stacknleft 68#define stackblocksize() stacknleft
68#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() 69#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
69#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) 70#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
70#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } 71#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); }
71#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) 72#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
72#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), sstrnleft++, *p = '\0') : (*p = '\0')) 73#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), sstrnleft++, *p = '\0') : (*p = '\0'))
73#define STUNPUTC(p) (++sstrnleft, --p) 74#define STUNPUTC(p) (++sstrnleft, --p)
74#define STTOPC(p) p[-1] 75#define STTOPC(p) p[-1]
75#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) 76#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
76#define grabstackstr(p) stalloc((p) - stackblock()) 77#define grabstackstr(p) stalloc((p) - stackblock())
77 78
78#define ckfree(p) free((pointer)(p)) 79#define ckfree(p) free((pointer)(p))