cal: make it NOEXEC
[oweals/busybox.git] / shell / ash_LINENO.patch
1 This patch is a backport from dash of the combination of:
2         [SHELL] Add preliminary LINENO support
3         [VAR] Fix varinit ordering that broke fc
4         [SHELL] Improve LINENO support
5
6 Applies cleanly on top of:
7         commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe
8         Date: Tue Aug 15 15:44:41 2017 +0200
9
10 Testsuite needs some tweaks (line numbers in some messages change).
11
12 Unfortunately, it is somewhat big:
13
14 function                                             old     new   delta
15 parse_command                                       1581    1658     +77
16 calcsize                                             203     272     +69
17 copynode                                             195     257     +62
18 lookupvar                                             59     108     +49
19 evaltree                                             494     534     +40
20 evalfor                                              152     187     +35
21 evalcase                                             278     313     +35
22 evalcommand                                         1547    1581     +34
23 evalsubshell                                         169     199     +30
24 linenovar                                              -      22     +22
25 raise_error_syntax                                    11      29     +18
26 evalfun                                              266     280     +14
27 varinit_data                                          96     108     +12
28 cmdtxt                                               626     631      +5
29 lineno                                                 -       4      +4
30 funcline                                               -       4      +4
31 ash_vmsg                                             144     141      -3
32 startlinno                                             4       -      -4
33 funcnest                                               4       -      -4
34 xxreadtoken                                          272     259     -13
35 readtoken1                                          2635    2594     -41
36 ------------------------------------------------------------------------------
37 (add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65)          Total: 445 bytes
38    text    data     bss     dec     hex filename
39  912030     563    5844  918437   e03a5 busybox_old
40  912473     587    5844  918904   e0578 busybox_unstripped
41
42 diff --git a/shell/ash.c b/shell/ash.c
43 index 703802f..93a3814 100644
44 --- a/shell/ash.c
45 +++ b/shell/ash.c
46 @@ -312,6 +312,8 @@ struct globals_misc {
47         /* shell level: 0 for the main shell, 1 for its children, and so on */
48         int shlvl;
49  #define rootshell (!shlvl)
50 +       int errlinno;
51 +
52         char *minusc;  /* argument to -c option */
53  
54         char *curdir; // = nullstr;     /* current working directory */
55 @@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
56  #define job_warning       (G_misc.job_warning)
57  #define rootpid     (G_misc.rootpid    )
58  #define shlvl       (G_misc.shlvl      )
59 +#define errlinno    (G_misc.errlinno   )
60  #define minusc      (G_misc.minusc     )
61  #define curdir      (G_misc.curdir     )
62  #define physdir     (G_misc.physdir    )
63 @@ -723,6 +726,7 @@ union node;
64  
65  struct ncmd {
66         smallint type; /* Nxxxx */
67 +       int linno;
68         union node *assign;
69         union node *args;
70         union node *redirect;
71 @@ -736,6 +740,7 @@ struct npipe {
72  
73  struct nredir {
74         smallint type;
75 +       int linno;
76         union node *n;
77         union node *redirect;
78  };
79 @@ -755,6 +760,7 @@ struct nif {
80  
81  struct nfor {
82         smallint type;
83 +       int linno;
84         union node *args;
85         union node *body;
86         char *var;
87 @@ -762,6 +768,7 @@ struct nfor {
88  
89  struct ncase {
90         smallint type;
91 +       int linno;
92         union node *expr;
93         union node *cases;
94  };
95 @@ -773,6 +780,13 @@ struct nclist {
96         union node *body;
97  };
98  
99 +struct ndefun {
100 +       smallint type;
101 +       int linno;
102 +       char *text;
103 +       union node *body;
104 +};
105 +
106  struct narg {
107         smallint type;
108         union node *next;
109 @@ -824,6 +838,7 @@ union node {
110         struct nfor nfor;
111         struct ncase ncase;
112         struct nclist nclist;
113 +       struct ndefun ndefun;
114         struct narg narg;
115         struct nfile nfile;
116         struct ndup ndup;
117 @@ -1253,7 +1268,6 @@ struct parsefile {
118  
119  static struct parsefile basepf;        /* top level input file */
120  static struct parsefile *g_parsefile = &basepf;  /* current input file */
121 -static int startlinno;                 /* line # where last token started */
122  static char *commandname;              /* currently executing command */
123  
124  
125 @@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap)
126                 if (strcmp(arg0, commandname))
127                         fprintf(stderr, "%s: ", commandname);
128                 if (!iflag || g_parsefile->pf_fd > 0)
129 -                       fprintf(stderr, "line %d: ", startlinno);
130 +                       fprintf(stderr, "line %d: ", errlinno);
131         }
132         vfprintf(stderr, msg, ap);
133         newline_and_flush(stderr);
134 @@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN;
135  static void
136  raise_error_syntax(const char *msg)
137  {
138 +       errlinno = g_parsefile->linno;
139         ash_msg_and_raise_error("syntax error: %s", msg);
140         /* NOTREACHED */
141  }
142 @@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC;
143  static void change_random(const char *) FAST_FUNC;
144  #endif
145  
146 +static int lineno;
147 +static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO=";
148 +
149  static const struct {
150         int flags;
151         const char *var_text;
152 @@ -2014,6 +2032,7 @@ static const struct {
153  #if ENABLE_ASH_GETOPTS
154         { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
155  #endif
156 +       { VSTRFIXED|VTEXTFIXED       , linenovar   , NULL            },
157  #if ENABLE_ASH_RANDOM_SUPPORT
158         { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
159  #endif
160 @@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var;
161  #define vps4      (&vps2)[1]
162  #if ENABLE_ASH_GETOPTS
163  # define voptind  (&vps4)[1]
164 +# define vlineno  (&voptind)[1]
165  # if ENABLE_ASH_RANDOM_SUPPORT
166 -#  define vrandom (&voptind)[1]
167 +#  define vrandom (&vlineno)[1]
168  # endif
169  #else
170 +# define vlineno  (&vps4)[1]
171  # if ENABLE_ASH_RANDOM_SUPPORT
172 -#  define vrandom (&vps4)[1]
173 +#  define vrandom (&vlineno)[1]
174  # endif
175  #endif
176  
177 @@ -2209,8 +2230,12 @@ lookupvar(const char *name)
178                 if (v->flags & VDYNAMIC)
179                         v->var_func(NULL);
180  #endif
181 -               if (!(v->flags & VUNSET))
182 +               if (!(v->flags & VUNSET)) {
183 +                       if (v == &vlineno && v->var_text == linenovar) {
184 +                               fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
185 +                       }
186                         return var_end(v->var_text);
187 +               }
188         }
189         return NULL;
190  }
191 @@ -4783,7 +4808,7 @@ cmdtxt(union node *n)
192                 p = "; done";
193                 goto dodo;
194         case NDEFUN:
195 -               cmdputs(n->narg.text);
196 +               cmdputs(n->ndefun.text);
197                 p = "() { ... }";
198                 goto dotail2;
199         case NCMD:
200 @@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n)
201                 funcblocksize = calcsize(funcblocksize, n->nclist.next);
202                 break;
203         case NDEFUN:
204 +               funcblocksize = calcsize(funcblocksize, n->ndefun.body);
205 +               funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
206 +               break;
207         case NARG:
208                 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
209                 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
210 @@ -8626,6 +8654,7 @@ copynode(union node *n)
211                 new->ncmd.redirect = copynode(n->ncmd.redirect);
212                 new->ncmd.args = copynode(n->ncmd.args);
213                 new->ncmd.assign = copynode(n->ncmd.assign);
214 +               new->ncmd.linno = n->ncmd.linno;
215                 break;
216         case NPIPE:
217                 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
218 @@ -8636,6 +8665,7 @@ copynode(union node *n)
219         case NSUBSHELL:
220                 new->nredir.redirect = copynode(n->nredir.redirect);
221                 new->nredir.n = copynode(n->nredir.n);
222 +               new->nredir.linno = n->nredir.linno;
223                 break;
224         case NAND:
225         case NOR:
226 @@ -8654,10 +8684,12 @@ copynode(union node *n)
227                 new->nfor.var = nodeckstrdup(n->nfor.var);
228                 new->nfor.body = copynode(n->nfor.body);
229                 new->nfor.args = copynode(n->nfor.args);
230 +               new->nfor.linno = n->nfor.linno;
231                 break;
232         case NCASE:
233                 new->ncase.cases = copynode(n->ncase.cases);
234                 new->ncase.expr = copynode(n->ncase.expr);
235 +               new->ncase.linno = n->ncase.linno;
236                 break;
237         case NCLIST:
238                 new->nclist.body = copynode(n->nclist.body);
239 @@ -8665,6 +8697,10 @@ copynode(union node *n)
240                 new->nclist.next = copynode(n->nclist.next);
241                 break;
242         case NDEFUN:
243 +               new->ndefun.body = copynode(n->ndefun.body);
244 +               new->ndefun.text = nodeckstrdup(n->ndefun.text);
245 +               new->ndefun.linno = n->ndefun.linno;
246 +               break;
247         case NARG:
248                 new->narg.backquote = copynodelist(n->narg.backquote);
249                 new->narg.text = nodeckstrdup(n->narg.text);
250 @@ -8733,7 +8769,7 @@ defun(union node *func)
251         INT_OFF;
252         entry.cmdtype = CMDFUNCTION;
253         entry.u.func = copyfunc(func);
254 -       addcmdentry(func->narg.text, &entry);
255 +       addcmdentry(func->ndefun.text, &entry);
256         INT_ON;
257  }
258  
259 @@ -8743,8 +8779,8 @@ defun(union node *func)
260  #define SKIPFUNC       (1 << 2)
261  static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
262  static int skipcount;           /* number of levels to skip */
263 -static int funcnest;            /* depth of function calls */
264  static int loopnest;            /* current loop nesting level */
265 +static int funcline;            /* starting line number of current function, or 0 if not in a function */
266  
267  /* Forward decl way out to parsing code - dotrap needs it */
268  static int evalstring(char *s, int flags);
269 @@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags)
270                 status = !evaltree(n->nnot.com, EV_TESTED);
271                 goto setstatus;
272         case NREDIR:
273 +               errlinno = lineno = n->nredir.linno;
274 +               if (funcline)
275 +                       lineno -= funcline - 1;
276                 expredir(n->nredir.redirect);
277                 pushredir(n->nredir.redirect);
278                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
279 @@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags)
280         struct stackmark smark;
281         int status = 0;
282  
283 +       errlinno = lineno = n->ncase.linno;
284 +       if (funcline)
285 +               lineno -= funcline - 1;
286 +
287         setstackmark(&smark);
288         arglist.list = NULL;
289         arglist.lastp = &arglist.list;
290 @@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags)
291         struct stackmark smark;
292         int status = 0;
293  
294 +       errlinno = lineno = n->ncase.linno;
295 +       if (funcline)
296 +               lineno -= funcline - 1;
297 +
298         setstackmark(&smark);
299         arglist.list = NULL;
300         arglist.lastp = &arglist.list;
301 @@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags)
302         int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
303         int status;
304  
305 +       errlinno = lineno = n->nredir.linno;
306 +       if (funcline)
307 +               lineno -= funcline - 1;
308 +
309         expredir(n->nredir.redirect);
310         if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
311                 goto nofork;
312 @@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
313         struct jmploc *volatile savehandler;
314         struct jmploc jmploc;
315         int e;
316 +       int savefuncline;
317  
318         saveparam = shellparam;
319 +       savefuncline = funcline;
320         savehandler = exception_handler;
321         e = setjmp(jmploc.loc);
322         if (e) {
323 @@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
324         exception_handler = &jmploc;
325         shellparam.malloced = 0;
326         func->count++;
327 -       funcnest++;
328 +       funcline = func->n.ndefun.linno;
329         INT_ON;
330         shellparam.nparam = argc - 1;
331         shellparam.p = argv + 1;
332 @@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
333         shellparam.optoff = -1;
334  #endif
335         pushlocalvars();
336 -       evaltree(func->n.narg.next, flags & EV_TESTED);
337 +       evaltree(func->n.ndefun.body, flags & EV_TESTED);
338         poplocalvars(0);
339   funcdone:
340         INT_OFF;
341 -       funcnest--;
342 +       funcline = savefuncline;
343         freefunc(func);
344         freeparam(&shellparam);
345         shellparam = saveparam;
346 @@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags)
347         char **nargv;
348         smallint cmd_is_exec;
349  
350 +       errlinno = lineno = cmd->ncmd.linno;
351 +       if (funcline)
352 +               lineno -= funcline - 1;
353 +
354         /* First expand the arguments. */
355         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
356         setstackmark(&smark);
357 @@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags)
358         *nargv = NULL;
359  
360         lastarg = NULL;
361 -       if (iflag && funcnest == 0 && argc > 0)
362 +       if (iflag && funcline == 0 && argc > 0)
363                 lastarg = nargv[-1];
364  
365         expredir(cmd->ncmd.redirect);
366 @@ -11317,6 +11374,7 @@ simplecmd(void)
367         union node *vars, **vpp;
368         union node **rpp, *redir;
369         int savecheckkwd;
370 +       int savelinno;
371  #if BASH_TEST2
372         smallint double_brackets_flag = 0;
373  #endif
374 @@ -11330,6 +11388,7 @@ simplecmd(void)
375         rpp = &redir;
376  
377         savecheckkwd = CHKALIAS;
378 +       savelinno = g_parsefile->linno;
379         for (;;) {
380                 int t;
381                 checkkwd = savecheckkwd;
382 @@ -11419,7 +11478,9 @@ simplecmd(void)
383                                 }
384                                 n->type = NDEFUN;
385                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
386 -                               n->narg.next = parse_command();
387 +                               n->ndefun.text = n->narg.text;
388 +                               n->ndefun.linno = g_parsefile->linno;
389 +                               n->ndefun.body = parse_command();
390                                 return n;
391                         }
392                         IF_BASH_FUNCTION(function_flag = 0;)
393 @@ -11435,6 +11496,7 @@ simplecmd(void)
394         *rpp = NULL;
395         n = stzalloc(sizeof(struct ncmd));
396         n->type = NCMD;
397 +       n->ncmd.linno = savelinno;
398         n->ncmd.args = args;
399         n->ncmd.assign = vars;
400         n->ncmd.redirect = redir;
401 @@ -11450,10 +11512,13 @@ parse_command(void)
402         union node *redir, **rpp;
403         union node **rpp2;
404         int t;
405 +       int savelinno;
406  
407         redir = NULL;
408         rpp2 = &redir;
409  
410 +       savelinno = g_parsefile->linno;
411 +
412         switch (readtoken()) {
413         default:
414                 raise_error_unexpected_syntax(-1);
415 @@ -11504,6 +11569,7 @@ parse_command(void)
416                         raise_error_syntax("bad for loop variable");
417                 n1 = stzalloc(sizeof(struct nfor));
418                 n1->type = NFOR;
419 +               n1->nfor.linno = savelinno;
420                 n1->nfor.var = wordtext;
421                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
422                 if (readtoken() == TIN) {
423 @@ -11544,6 +11610,7 @@ parse_command(void)
424         case TCASE:
425                 n1 = stzalloc(sizeof(struct ncase));
426                 n1->type = NCASE;
427 +               n1->ncase.linno = savelinno;
428                 if (readtoken() != TWORD)
429                         raise_error_unexpected_syntax(TWORD);
430                 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
431 @@ -11595,6 +11662,7 @@ parse_command(void)
432         case TLP:
433                 n1 = stzalloc(sizeof(struct nredir));
434                 n1->type = NSUBSHELL;
435 +               n1->nredir.linno = savelinno;
436                 n1->nredir.n = list(0);
437                 /*n1->nredir.redirect = NULL; - stzalloc did it */
438                 t = TRP;
439 @@ -11628,6 +11696,7 @@ parse_command(void)
440                 if (n1->type != NSUBSHELL) {
441                         n2 = stzalloc(sizeof(struct nredir));
442                         n2->type = NREDIR;
443 +                       n2->nredir.linno = savelinno;
444                         n2->nredir.n = n1;
445                         n1 = n2;
446                 }
447 @@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
448         IF_FEATURE_SH_MATH(int arinest;)    /* levels of arithmetic expansion */
449         IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
450         int dqvarnest;       /* levels of variables expansion within double quotes */
451 -
452         IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
453  
454 -       startlinno = g_parsefile->linno;
455         bqlist = NULL;
456         quotef = 0;
457         IF_FEATURE_SH_MATH(prevsyntax = 0;)
458 @@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
459         if (syntax != BASESYNTAX && eofmark == NULL)
460                 raise_error_syntax("unterminated quoted string");
461         if (varnest != 0) {
462 -               startlinno = g_parsefile->linno;
463                 /* { */
464                 raise_error_syntax("missing '}'");
465         }
466 @@ -12298,7 +12364,6 @@ parsebackq: {
467  
468                         case PEOF:
469                         IF_ASH_ALIAS(case PEOA:)
470 -                               startlinno = g_parsefile->linno;
471                                 raise_error_syntax("EOF in backquote substitution");
472  
473                         case '\n':
474 @@ -12380,8 +12445,6 @@ parsearith: {
475   *      quoted.
476   * If the token is TREDIR, then we set redirnode to a structure containing
477   *      the redirection.
478 - * In all cases, the variable startlinno is set to the number of the line
479 - *      on which the token starts.
480   *
481   * [Change comment:  here documents and internal procedures]
482   * [Readtoken shouldn't have any arguments.  Perhaps we should make the
483 @@ -12419,7 +12482,6 @@ xxreadtoken(void)
484                 return lasttoken;
485         }
486         setprompt_if(needprompt, 2);
487 -       startlinno = g_parsefile->linno;
488         for (;;) {                      /* until token or start of word found */
489                 c = pgetc();
490                 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
491 @@ -12480,7 +12542,6 @@ xxreadtoken(void)
492                 return lasttoken;
493         }
494         setprompt_if(needprompt, 2);
495 -       startlinno = g_parsefile->linno;
496         for (;;) {      /* until token or start of word found */
497                 c = pgetc();
498                 switch (c) {