Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*
* sh.c -- a prototype Bourne shell grammar parser
* Intended to follow the original Thompson and Ritchie
* "small and simple is beautiful" philosophy, which
* incidentally is a good match to today's BusyBox.
*
* Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
*
* Credits:
* The parser routines proper are all original material, first
* written Dec 2000 and Jan 2001 by Larry Doolittle.
* The execution engine, the builtins, and much of the underlying
* support has been adapted from busybox-0.49pre's lash,
* which is Copyright (C) 2000 by Lineo, Inc., and
* written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
* That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
* Erik W. Troan, which they placed in the public domain. I don't know
* how much of the Johnson/Troan code has survived the repeated rewrites.
* Other credits:
* b_addchr() derived from similar w_addchar function in glibc-2.2
* setup_redirect(), redirect_opt_num(), and big chunks of main()
* and many builtins derived from contributions by Erik Andersen
* miscellaneous bugfixes from Matt Kraai
*
* There are two big (and related) architecture differences between
* this parser and the lash parser. One is that this version is
* actually designed from the ground up to understand nearly all
* of the Bourne grammar. The second, consequential change is that
* the parser and input reader have been turned inside out. Now,
* the parser is in control, and asks for input as needed. The old
* way had the input reader in control, and it asked for parsing to
* take place as needed. The new way makes it much easier to properly
* handle the recursion implicit in the various substitutions, especially
* across continuation lines.
*
* Bash grammar not implemented: (how many of these were in original sh?)
* $@ (those sure look like weird quoting rules)
* $_
* ! negation operator for pipes
* &> and >& redirection of stdout+stderr
* Brace Expansion
* Tilde Expansion
* fancy forms of Parameter Expansion
* aliases
* Arithmetic Expansion
* <(list) and >(list) Process Substitution
* reserved words: case, esac, select, function
* Here Documents ( << word )
* Functions
* Major bugs:
* job handling woefully incomplete and buggy
* reserved word execution woefully incomplete and buggy
* to-do:
* port selected bugfixes from post-0.49 busybox lash - done?
* finish implementing reserved words: for, while, until, do, done
* change { and } from special chars to reserved words
* builtins: break, continue, eval, return, set, trap, ulimit
* test magic exec
* handle children going into background
* clean up recognition of null pipes
* check setting of global_argc and global_argv
* control-C handling, probably with longjmp
* follow IFS rules more precisely, including update semantics
* figure out what to do with backslash-newline
* explain why we use signal instead of sigaction
* propagate syntax errors, die on resource errors?
* continuation lines, both explicit and implicit - done?
* memory leak finding and plugging - done?
* more testing, especially quoting rules and redirection
* document how quoting rules not precisely followed for variable assignments
* maybe change map[] to use 2-bit entries
* (eventually) remove all the printf's
*
* SPDX-License-Identifier: GPL-2.0+
#define __U_BOOT__
#ifdef __U_BOOT__
#include <malloc.h> /* malloc, free, realloc*/
#include <linux/ctype.h> /* isalpha, isdigit */
#include <common.h> /* readline */
#ifndef CONFIG_SYS_PROMPT_HUSH_PS2
#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
#endif
#endif
#ifndef __U_BOOT__
#include <ctype.h> /* isalpha, isdigit */
#include <unistd.h> /* getpid */
#include <stdlib.h> /* getenv, atoi */
#include <string.h> /* strchr */
#include <stdio.h> /* popen etc. */
#include <glob.h> /* glob, of course */
#include <stdarg.h> /* va_list */
#include <errno.h>
#include <fcntl.h>
#include <getopt.h> /* should be pretty obvious */
#include <sys/stat.h> /* ulimit */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/* #include <dmalloc.h> */
#include "busybox.h"
#include "cmdedit.h"
#else
#define applet_name "hush"
#include "standalone.h"
#define hush_main main
#undef CONFIG_FEATURE_SH_FANCY_PROMPT
#define BB_BANNER
#define SUBSTED_VAR_SYMBOL 04
#ifndef __U_BOOT__
#define FLAG_EXIT_FROM_LOOP 1
#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
#define FLAG_REPARSING (1 << 2) /* >= 2nd pass */
#endif
#ifdef __U_BOOT__
DECLARE_GLOBAL_DATA_PTR;
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#define EXIT_SUCCESS 0
#define EOF -1
#define syntax() syntax_err()
#define xstrdup strdup
#define error_msg printf
#else
typedef enum {
REDIRECT_INPUT = 1,
REDIRECT_OVERWRITE = 2,
REDIRECT_APPEND = 3,
REDIRECT_HEREIS = 4,
REDIRECT_IO = 5
} redir_type;
/* The descrip member of this structure is only used to make debugging
* output pretty */
struct {int mode; int default_fd; char *descrip;} redir_table[] = {
{ 0, 0, "()" },
{ O_RDONLY, 0, "<" },
{ O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
{ O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
{ O_RDONLY, -1, "<<" },
{ O_RDWR, 1, "<>" }
};
#endif
typedef enum {
PIPE_SEQ = 1,
PIPE_AND = 2,
PIPE_OR = 3,
PIPE_BG = 4,
} pipe_style;
/* might eventually control execution */
typedef enum {
RES_NONE = 0,
RES_IF = 1,
RES_THEN = 2,
RES_ELIF = 3,
RES_ELSE = 4,
RES_FI = 5,
RES_FOR = 6,
RES_WHILE = 7,
RES_UNTIL = 8,
RES_DO = 9,
RES_DONE = 10,
RES_XXXX = 11,
RES_IN = 12,
RES_SNTX = 13
} reserved_style;
#define FLAG_END (1<<RES_NONE)
#define FLAG_IF (1<<RES_IF)
#define FLAG_THEN (1<<RES_THEN)
#define FLAG_ELIF (1<<RES_ELIF)
#define FLAG_ELSE (1<<RES_ELSE)
#define FLAG_FI (1<<RES_FI)
#define FLAG_FOR (1<<RES_FOR)
#define FLAG_WHILE (1<<RES_WHILE)
#define FLAG_UNTIL (1<<RES_UNTIL)
#define FLAG_DO (1<<RES_DO)
#define FLAG_DONE (1<<RES_DONE)
#define FLAG_IN (1<<RES_IN)
#define FLAG_START (1<<RES_XXXX)
/* This holds pointers to the various results of parsing */
struct p_context {
struct child_prog *child;
struct pipe *list_head;
struct pipe *pipe;
Loading
Loading full blame…