Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/shell/bbsh.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 984 - (hide annotations) (download)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 5150 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 niro 532 /* vi: set ts=4 :
2     *
3     * bbsh - busybox shell
4     *
5     * Copyright 2006 Rob Landley <rob@landley.net>
6     *
7     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8     */
9    
10     // A section of code that gets repeatedly or conditionally executed is stored
11     // as a string and parsed each time it's run.
12    
13    
14    
15     // Wheee, debugging.
16    
17     // Terminal control
18     #define ENABLE_BBSH_TTY 0
19    
20     // &, fg, bg, jobs. (ctrl-z with tty.)
21     #define ENABLE_BBSH_JOBCTL 0
22    
23     // Flow control (if, while, for, functions { })
24     #define ENABLE_BBSH_FLOWCTL 0
25    
26     #define ENABLE_BBSH_ENVVARS 0 // Environment variable support
27    
28     // Local and synthetic variables, fancy prompts, set, $?, etc.
29     #define ENABLE_BBSH_LOCALVARS 0
30    
31     // Pipes and redirects: | > < >> << && || & () ;
32     #define ENABLE_BBSH_PIPES 0
33    
34     /* Fun:
35    
36     echo `echo hello#comment " woot` and more
37     */
38    
39 niro 816 #include "libbb.h"
40 niro 532
41     // A single executable, its arguments, and other information we know about it.
42     #define BBSH_FLAG_EXIT 1
43     #define BBSH_FLAG_SUSPEND 2
44     #define BBSH_FLAG_PIPE 4
45     #define BBSH_FLAG_AND 8
46     #define BBSH_FLAG_OR 16
47     #define BBSH_FLAG_AMP 32
48     #define BBSH_FLAG_SEMI 64
49     #define BBSH_FLAG_PAREN 128
50    
51     // What we know about a single process.
52     struct command {
53     struct command *next;
54     int flags; // exit, suspend, && ||
55     int pid; // pid (or exit code)
56     int argc;
57 niro 984 char *argv[];
58 niro 532 };
59    
60     // A collection of processes piped into/waiting on each other.
61     struct pipeline {
62     struct pipeline *next;
63     int job_id;
64     struct command *cmd;
65     char *cmdline;
66     int cmdlinelen;
67     };
68    
69     static void free_list(void *list, void (*freeit)(void *data))
70     {
71 niro 816 while (list) {
72 niro 532 void **next = (void **)list;
73     void *list_next = *next;
74     freeit(list);
75     free(list);
76     list = list_next;
77     }
78     }
79    
80     // Parse one word from the command line, appending one or more argv[] entries
81     // to struct command. Handles environment variable substitution and
82     // substrings. Returns pointer to next used byte, or NULL if it
83     // hit an ending token.
84     static char *parse_word(char *start, struct command **cmd)
85     {
86     char *end;
87    
88     // Detect end of line (and truncate line at comment)
89     if (ENABLE_BBSH_PIPES && strchr("><&|(;", *start)) return 0;
90    
91     // Grab next word. (Add dequote and envvar logic here)
92     end = start;
93 niro 816 end = skip_non_whitespace(end);
94 niro 532 (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start);
95    
96     // Allocate more space if there's no room for NULL terminator.
97    
98     if (!((*cmd)->argc & 7))
99     *cmd = xrealloc(*cmd,
100     sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *));
101     (*cmd)->argv[(*cmd)->argc] = 0;
102     return end;
103     }
104    
105     // Parse a line of text into a pipeline.
106     // Returns a pointer to the next line.
107    
108     static char *parse_pipeline(char *cmdline, struct pipeline *line)
109     {
110     struct command **cmd = &(line->cmd);
111     char *start = line->cmdline = cmdline;
112    
113     if (!cmdline) return 0;
114    
115     if (ENABLE_BBSH_JOBCTL) line->cmdline = cmdline;
116    
117     // Parse command into argv[]
118     for (;;) {
119     char *end;
120    
121     // Skip leading whitespace and detect end of line.
122     start = skip_whitespace(start);
123     if (!*start || *start=='#') {
124     if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline;
125     return 0;
126     }
127    
128     // Allocate next command structure if necessary
129     if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *));
130    
131     // Parse next argument and add the results to argv[]
132     end = parse_word(start, cmd);
133    
134     // If we hit the end of this command, how did it end?
135     if (!end) {
136     if (ENABLE_BBSH_PIPES && *start) {
137     if (*start==';') {
138     start++;
139     break;
140     }
141     // handle | & < > >> << || &&
142     }
143     break;
144     }
145     start = end;
146     }
147    
148     if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline;
149    
150     return start;
151     }
152    
153     // Execute the commands in a pipeline
154     static int run_pipeline(struct pipeline *line)
155     {
156     struct command *cmd = line->cmd;
157     if (!cmd || !cmd->argc) return 0;
158    
159     // Handle local commands. This is totally fake and plastic.
160     if (cmd->argc==2 && !strcmp(cmd->argv[0],"cd"))
161     chdir(cmd->argv[1]);
162 niro 816 else if (!strcmp(cmd->argv[0],"exit"))
163 niro 532 exit(cmd->argc>1 ? atoi(cmd->argv[1]) : 0);
164     else {
165     int status;
166     pid_t pid=fork();
167 niro 816 if (!pid) {
168     run_applet_and_exit(cmd->argv[0],cmd->argc,cmd->argv);
169 niro 532 execvp(cmd->argv[0],cmd->argv);
170 niro 816 printf("No %s", cmd->argv[0]);
171     exit(EXIT_FAILURE);
172 niro 532 } else waitpid(pid, &status, 0);
173     }
174    
175     return 0;
176     }
177    
178     static void free_cmd(void *data)
179     {
180     struct command *cmd=(struct command *)data;
181    
182 niro 816 while (cmd->argc) free(cmd->argv[--cmd->argc]);
183 niro 532 }
184    
185    
186     static void handle(char *command)
187     {
188     struct pipeline line;
189     char *start = command;
190    
191     for (;;) {
192     memset(&line,0,sizeof(struct pipeline));
193     start = parse_pipeline(start, &line);
194     if (!line.cmd) break;
195    
196     run_pipeline(&line);
197     free_list(line.cmd, free_cmd);
198     }
199     }
200    
201 niro 816 int bbsh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
202 niro 984 int bbsh_main(int argc UNUSED_PARAM, char **argv)
203 niro 532 {
204     char *command=NULL;
205     FILE *f;
206    
207 niro 816 getopt32(argv, "c:", &command);
208 niro 532
209 niro 816 f = argv[optind] ? xfopen_for_read(argv[optind]) : NULL;
210 niro 532 if (command) handle(command);
211     else {
212     unsigned cmdlen=0;
213     for (;;) {
214 niro 816 if (!f) putchar('$');
215 niro 984 if (1 > getline(&command, &cmdlen, f ? f : stdin)) break;
216 niro 532
217     handle(command);
218     }
219     if (ENABLE_FEATURE_CLEAN_UP) free(command);
220     }
221    
222     return 1;
223     }