1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * sh.c -- a prototype Bourne shell grammar parser
3*4882a593Smuzhiyun * Intended to follow the original Thompson and Ritchie
4*4882a593Smuzhiyun * "small and simple is beautiful" philosophy, which
5*4882a593Smuzhiyun * incidentally is a good match to today's BusyBox.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Credits:
10*4882a593Smuzhiyun * The parser routines proper are all original material, first
11*4882a593Smuzhiyun * written Dec 2000 and Jan 2001 by Larry Doolittle.
12*4882a593Smuzhiyun * The execution engine, the builtins, and much of the underlying
13*4882a593Smuzhiyun * support has been adapted from busybox-0.49pre's lash,
14*4882a593Smuzhiyun * which is Copyright (C) 2000 by Lineo, Inc., and
15*4882a593Smuzhiyun * written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
16*4882a593Smuzhiyun * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
17*4882a593Smuzhiyun * Erik W. Troan, which they placed in the public domain. I don't know
18*4882a593Smuzhiyun * how much of the Johnson/Troan code has survived the repeated rewrites.
19*4882a593Smuzhiyun * Other credits:
20*4882a593Smuzhiyun * b_addchr() derived from similar w_addchar function in glibc-2.2
21*4882a593Smuzhiyun * setup_redirect(), redirect_opt_num(), and big chunks of main()
22*4882a593Smuzhiyun * and many builtins derived from contributions by Erik Andersen
23*4882a593Smuzhiyun * miscellaneous bugfixes from Matt Kraai
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * There are two big (and related) architecture differences between
26*4882a593Smuzhiyun * this parser and the lash parser. One is that this version is
27*4882a593Smuzhiyun * actually designed from the ground up to understand nearly all
28*4882a593Smuzhiyun * of the Bourne grammar. The second, consequential change is that
29*4882a593Smuzhiyun * the parser and input reader have been turned inside out. Now,
30*4882a593Smuzhiyun * the parser is in control, and asks for input as needed. The old
31*4882a593Smuzhiyun * way had the input reader in control, and it asked for parsing to
32*4882a593Smuzhiyun * take place as needed. The new way makes it much easier to properly
33*4882a593Smuzhiyun * handle the recursion implicit in the various substitutions, especially
34*4882a593Smuzhiyun * across continuation lines.
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * Bash grammar not implemented: (how many of these were in original sh?)
37*4882a593Smuzhiyun * $@ (those sure look like weird quoting rules)
38*4882a593Smuzhiyun * $_
39*4882a593Smuzhiyun * ! negation operator for pipes
40*4882a593Smuzhiyun * &> and >& redirection of stdout+stderr
41*4882a593Smuzhiyun * Brace Expansion
42*4882a593Smuzhiyun * Tilde Expansion
43*4882a593Smuzhiyun * fancy forms of Parameter Expansion
44*4882a593Smuzhiyun * aliases
45*4882a593Smuzhiyun * Arithmetic Expansion
46*4882a593Smuzhiyun * <(list) and >(list) Process Substitution
47*4882a593Smuzhiyun * reserved words: case, esac, select, function
48*4882a593Smuzhiyun * Here Documents ( << word )
49*4882a593Smuzhiyun * Functions
50*4882a593Smuzhiyun * Major bugs:
51*4882a593Smuzhiyun * job handling woefully incomplete and buggy
52*4882a593Smuzhiyun * reserved word execution woefully incomplete and buggy
53*4882a593Smuzhiyun * to-do:
54*4882a593Smuzhiyun * port selected bugfixes from post-0.49 busybox lash - done?
55*4882a593Smuzhiyun * finish implementing reserved words: for, while, until, do, done
56*4882a593Smuzhiyun * change { and } from special chars to reserved words
57*4882a593Smuzhiyun * builtins: break, continue, eval, return, set, trap, ulimit
58*4882a593Smuzhiyun * test magic exec
59*4882a593Smuzhiyun * handle children going into background
60*4882a593Smuzhiyun * clean up recognition of null pipes
61*4882a593Smuzhiyun * check setting of global_argc and global_argv
62*4882a593Smuzhiyun * control-C handling, probably with longjmp
63*4882a593Smuzhiyun * follow IFS rules more precisely, including update semantics
64*4882a593Smuzhiyun * figure out what to do with backslash-newline
65*4882a593Smuzhiyun * explain why we use signal instead of sigaction
66*4882a593Smuzhiyun * propagate syntax errors, die on resource errors?
67*4882a593Smuzhiyun * continuation lines, both explicit and implicit - done?
68*4882a593Smuzhiyun * memory leak finding and plugging - done?
69*4882a593Smuzhiyun * more testing, especially quoting rules and redirection
70*4882a593Smuzhiyun * document how quoting rules not precisely followed for variable assignments
71*4882a593Smuzhiyun * maybe change map[] to use 2-bit entries
72*4882a593Smuzhiyun * (eventually) remove all the printf's
73*4882a593Smuzhiyun *
74*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define __U_BOOT__
78*4882a593Smuzhiyun #ifdef __U_BOOT__
79*4882a593Smuzhiyun #include <malloc.h> /* malloc, free, realloc*/
80*4882a593Smuzhiyun #include <linux/ctype.h> /* isalpha, isdigit */
81*4882a593Smuzhiyun #include <common.h> /* readline */
82*4882a593Smuzhiyun #include <console.h>
83*4882a593Smuzhiyun #include <bootretry.h>
84*4882a593Smuzhiyun #include <cli.h>
85*4882a593Smuzhiyun #include <cli_hush.h>
86*4882a593Smuzhiyun #include <command.h> /* find_cmd */
87*4882a593Smuzhiyun #ifndef CONFIG_SYS_PROMPT_HUSH_PS2
88*4882a593Smuzhiyun #define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun #endif
91*4882a593Smuzhiyun #ifndef __U_BOOT__
92*4882a593Smuzhiyun #include <ctype.h> /* isalpha, isdigit */
93*4882a593Smuzhiyun #include <unistd.h> /* getpid */
94*4882a593Smuzhiyun #include <stdlib.h> /* getenv, atoi */
95*4882a593Smuzhiyun #include <string.h> /* strchr */
96*4882a593Smuzhiyun #include <stdio.h> /* popen etc. */
97*4882a593Smuzhiyun #include <glob.h> /* glob, of course */
98*4882a593Smuzhiyun #include <stdarg.h> /* va_list */
99*4882a593Smuzhiyun #include <errno.h>
100*4882a593Smuzhiyun #include <fcntl.h>
101*4882a593Smuzhiyun #include <getopt.h> /* should be pretty obvious */
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #include <sys/stat.h> /* ulimit */
104*4882a593Smuzhiyun #include <sys/types.h>
105*4882a593Smuzhiyun #include <sys/wait.h>
106*4882a593Smuzhiyun #include <signal.h>
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* #include <dmalloc.h> */
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun #if 1
111*4882a593Smuzhiyun #include "busybox.h"
112*4882a593Smuzhiyun #include "cmdedit.h"
113*4882a593Smuzhiyun #else
114*4882a593Smuzhiyun #define applet_name "hush"
115*4882a593Smuzhiyun #include "standalone.h"
116*4882a593Smuzhiyun #define hush_main main
117*4882a593Smuzhiyun #undef CONFIG_FEATURE_SH_FANCY_PROMPT
118*4882a593Smuzhiyun #define BB_BANNER
119*4882a593Smuzhiyun #endif
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun #define SPECIAL_VAR_SYMBOL 03
122*4882a593Smuzhiyun #define SUBSTED_VAR_SYMBOL 04
123*4882a593Smuzhiyun #ifndef __U_BOOT__
124*4882a593Smuzhiyun #define FLAG_EXIT_FROM_LOOP 1
125*4882a593Smuzhiyun #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
126*4882a593Smuzhiyun #define FLAG_REPARSING (1 << 2) /* >= 2nd pass */
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #ifdef __U_BOOT__
131*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #define EXIT_SUCCESS 0
134*4882a593Smuzhiyun #define EOF -1
135*4882a593Smuzhiyun #define syntax() syntax_err()
136*4882a593Smuzhiyun #define xstrdup strdup
137*4882a593Smuzhiyun #define error_msg printf
138*4882a593Smuzhiyun #else
139*4882a593Smuzhiyun typedef enum {
140*4882a593Smuzhiyun REDIRECT_INPUT = 1,
141*4882a593Smuzhiyun REDIRECT_OVERWRITE = 2,
142*4882a593Smuzhiyun REDIRECT_APPEND = 3,
143*4882a593Smuzhiyun REDIRECT_HEREIS = 4,
144*4882a593Smuzhiyun REDIRECT_IO = 5
145*4882a593Smuzhiyun } redir_type;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* The descrip member of this structure is only used to make debugging
148*4882a593Smuzhiyun * output pretty */
149*4882a593Smuzhiyun struct {int mode; int default_fd; char *descrip;} redir_table[] = {
150*4882a593Smuzhiyun { 0, 0, "()" },
151*4882a593Smuzhiyun { O_RDONLY, 0, "<" },
152*4882a593Smuzhiyun { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
153*4882a593Smuzhiyun { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
154*4882a593Smuzhiyun { O_RDONLY, -1, "<<" },
155*4882a593Smuzhiyun { O_RDWR, 1, "<>" }
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun #endif
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun typedef enum {
160*4882a593Smuzhiyun PIPE_SEQ = 1,
161*4882a593Smuzhiyun PIPE_AND = 2,
162*4882a593Smuzhiyun PIPE_OR = 3,
163*4882a593Smuzhiyun PIPE_BG = 4,
164*4882a593Smuzhiyun } pipe_style;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* might eventually control execution */
167*4882a593Smuzhiyun typedef enum {
168*4882a593Smuzhiyun RES_NONE = 0,
169*4882a593Smuzhiyun RES_IF = 1,
170*4882a593Smuzhiyun RES_THEN = 2,
171*4882a593Smuzhiyun RES_ELIF = 3,
172*4882a593Smuzhiyun RES_ELSE = 4,
173*4882a593Smuzhiyun RES_FI = 5,
174*4882a593Smuzhiyun RES_FOR = 6,
175*4882a593Smuzhiyun RES_WHILE = 7,
176*4882a593Smuzhiyun RES_UNTIL = 8,
177*4882a593Smuzhiyun RES_DO = 9,
178*4882a593Smuzhiyun RES_DONE = 10,
179*4882a593Smuzhiyun RES_XXXX = 11,
180*4882a593Smuzhiyun RES_IN = 12,
181*4882a593Smuzhiyun RES_SNTX = 13
182*4882a593Smuzhiyun } reserved_style;
183*4882a593Smuzhiyun #define FLAG_END (1<<RES_NONE)
184*4882a593Smuzhiyun #define FLAG_IF (1<<RES_IF)
185*4882a593Smuzhiyun #define FLAG_THEN (1<<RES_THEN)
186*4882a593Smuzhiyun #define FLAG_ELIF (1<<RES_ELIF)
187*4882a593Smuzhiyun #define FLAG_ELSE (1<<RES_ELSE)
188*4882a593Smuzhiyun #define FLAG_FI (1<<RES_FI)
189*4882a593Smuzhiyun #define FLAG_FOR (1<<RES_FOR)
190*4882a593Smuzhiyun #define FLAG_WHILE (1<<RES_WHILE)
191*4882a593Smuzhiyun #define FLAG_UNTIL (1<<RES_UNTIL)
192*4882a593Smuzhiyun #define FLAG_DO (1<<RES_DO)
193*4882a593Smuzhiyun #define FLAG_DONE (1<<RES_DONE)
194*4882a593Smuzhiyun #define FLAG_IN (1<<RES_IN)
195*4882a593Smuzhiyun #define FLAG_START (1<<RES_XXXX)
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* This holds pointers to the various results of parsing */
198*4882a593Smuzhiyun struct p_context {
199*4882a593Smuzhiyun struct child_prog *child;
200*4882a593Smuzhiyun struct pipe *list_head;
201*4882a593Smuzhiyun struct pipe *pipe;
202*4882a593Smuzhiyun #ifndef __U_BOOT__
203*4882a593Smuzhiyun struct redir_struct *pending_redirect;
204*4882a593Smuzhiyun #endif
205*4882a593Smuzhiyun reserved_style w;
206*4882a593Smuzhiyun int old_flag; /* for figuring out valid reserved words */
207*4882a593Smuzhiyun struct p_context *stack;
208*4882a593Smuzhiyun int type; /* define type of parser : ";$" common or special symbol */
209*4882a593Smuzhiyun /* How about quoting status? */
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun #ifndef __U_BOOT__
213*4882a593Smuzhiyun struct redir_struct {
214*4882a593Smuzhiyun redir_type type; /* type of redirection */
215*4882a593Smuzhiyun int fd; /* file descriptor being redirected */
216*4882a593Smuzhiyun int dup; /* -1, or file descriptor being duplicated */
217*4882a593Smuzhiyun struct redir_struct *next; /* pointer to the next redirect in the list */
218*4882a593Smuzhiyun glob_t word; /* *word.gl_pathv is the filename */
219*4882a593Smuzhiyun };
220*4882a593Smuzhiyun #endif
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun struct child_prog {
223*4882a593Smuzhiyun #ifndef __U_BOOT__
224*4882a593Smuzhiyun pid_t pid; /* 0 if exited */
225*4882a593Smuzhiyun #endif
226*4882a593Smuzhiyun char **argv; /* program name and arguments */
227*4882a593Smuzhiyun /* was quoted when parsed; copy of struct o_string.nonnull field */
228*4882a593Smuzhiyun int *argv_nonnull;
229*4882a593Smuzhiyun #ifdef __U_BOOT__
230*4882a593Smuzhiyun int argc; /* number of program arguments */
231*4882a593Smuzhiyun #endif
232*4882a593Smuzhiyun struct pipe *group; /* if non-NULL, first in group or subshell */
233*4882a593Smuzhiyun #ifndef __U_BOOT__
234*4882a593Smuzhiyun int subshell; /* flag, non-zero if group must be forked */
235*4882a593Smuzhiyun struct redir_struct *redirects; /* I/O redirections */
236*4882a593Smuzhiyun glob_t glob_result; /* result of parameter globbing */
237*4882a593Smuzhiyun int is_stopped; /* is the program currently running? */
238*4882a593Smuzhiyun struct pipe *family; /* pointer back to the child's parent pipe */
239*4882a593Smuzhiyun #endif
240*4882a593Smuzhiyun int sp; /* number of SPECIAL_VAR_SYMBOL */
241*4882a593Smuzhiyun int type;
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun struct pipe {
245*4882a593Smuzhiyun #ifndef __U_BOOT__
246*4882a593Smuzhiyun int jobid; /* job number */
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun int num_progs; /* total number of programs in job */
249*4882a593Smuzhiyun #ifndef __U_BOOT__
250*4882a593Smuzhiyun int running_progs; /* number of programs running */
251*4882a593Smuzhiyun char *text; /* name of job */
252*4882a593Smuzhiyun char *cmdbuf; /* buffer various argv's point into */
253*4882a593Smuzhiyun pid_t pgrp; /* process group ID for the job */
254*4882a593Smuzhiyun #endif
255*4882a593Smuzhiyun struct child_prog *progs; /* array of commands in pipe */
256*4882a593Smuzhiyun struct pipe *next; /* to track background commands */
257*4882a593Smuzhiyun #ifndef __U_BOOT__
258*4882a593Smuzhiyun int stopped_progs; /* number of programs alive, but stopped */
259*4882a593Smuzhiyun int job_context; /* bitmask defining current context */
260*4882a593Smuzhiyun #endif
261*4882a593Smuzhiyun pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
262*4882a593Smuzhiyun reserved_style r_mode; /* supports if, for, while, until */
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun #ifndef __U_BOOT__
266*4882a593Smuzhiyun struct close_me {
267*4882a593Smuzhiyun int fd;
268*4882a593Smuzhiyun struct close_me *next;
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun #endif
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun struct variables {
273*4882a593Smuzhiyun char *name;
274*4882a593Smuzhiyun char *value;
275*4882a593Smuzhiyun int flg_export;
276*4882a593Smuzhiyun int flg_read_only;
277*4882a593Smuzhiyun struct variables *next;
278*4882a593Smuzhiyun };
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* globals, connect us to the outside world
281*4882a593Smuzhiyun * the first three support $?, $#, and $1 */
282*4882a593Smuzhiyun #ifndef __U_BOOT__
283*4882a593Smuzhiyun char **global_argv;
284*4882a593Smuzhiyun unsigned int global_argc;
285*4882a593Smuzhiyun #endif
286*4882a593Smuzhiyun static unsigned int last_return_code;
287*4882a593Smuzhiyun #ifndef __U_BOOT__
288*4882a593Smuzhiyun extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
289*4882a593Smuzhiyun #endif
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* "globals" within this file */
292*4882a593Smuzhiyun static uchar *ifs;
293*4882a593Smuzhiyun static char map[256];
294*4882a593Smuzhiyun #ifndef __U_BOOT__
295*4882a593Smuzhiyun static int fake_mode;
296*4882a593Smuzhiyun static int interactive;
297*4882a593Smuzhiyun static struct close_me *close_me_head;
298*4882a593Smuzhiyun static const char *cwd;
299*4882a593Smuzhiyun static struct pipe *job_list;
300*4882a593Smuzhiyun static unsigned int last_bg_pid;
301*4882a593Smuzhiyun static unsigned int last_jobid;
302*4882a593Smuzhiyun static unsigned int shell_terminal;
303*4882a593Smuzhiyun static char *PS1;
304*4882a593Smuzhiyun static char *PS2;
305*4882a593Smuzhiyun struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
306*4882a593Smuzhiyun struct variables *top_vars = &shell_ver;
307*4882a593Smuzhiyun #else
308*4882a593Smuzhiyun static int flag_repeat = 0;
309*4882a593Smuzhiyun static int do_repeat = 0;
310*4882a593Smuzhiyun static struct variables *top_vars = NULL ;
311*4882a593Smuzhiyun #endif /*__U_BOOT__ */
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun #define B_CHUNK (100)
314*4882a593Smuzhiyun #define B_NOSPAC 1
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun typedef struct {
317*4882a593Smuzhiyun char *data;
318*4882a593Smuzhiyun int length;
319*4882a593Smuzhiyun int maxlen;
320*4882a593Smuzhiyun int quote;
321*4882a593Smuzhiyun int nonnull;
322*4882a593Smuzhiyun } o_string;
323*4882a593Smuzhiyun #define NULL_O_STRING {NULL,0,0,0,0}
324*4882a593Smuzhiyun /* used for initialization:
325*4882a593Smuzhiyun o_string foo = NULL_O_STRING; */
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* I can almost use ordinary FILE *. Is open_memstream() universally
328*4882a593Smuzhiyun * available? Where is it documented? */
329*4882a593Smuzhiyun struct in_str {
330*4882a593Smuzhiyun const char *p;
331*4882a593Smuzhiyun #ifndef __U_BOOT__
332*4882a593Smuzhiyun char peek_buf[2];
333*4882a593Smuzhiyun #endif
334*4882a593Smuzhiyun int __promptme;
335*4882a593Smuzhiyun int promptmode;
336*4882a593Smuzhiyun #ifndef __U_BOOT__
337*4882a593Smuzhiyun FILE *file;
338*4882a593Smuzhiyun #endif
339*4882a593Smuzhiyun int (*get) (struct in_str *);
340*4882a593Smuzhiyun int (*peek) (struct in_str *);
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun #define b_getch(input) ((input)->get(input))
343*4882a593Smuzhiyun #define b_peek(input) ((input)->peek(input))
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun #ifndef __U_BOOT__
346*4882a593Smuzhiyun #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun struct built_in_command {
349*4882a593Smuzhiyun char *cmd; /* name */
350*4882a593Smuzhiyun char *descr; /* description */
351*4882a593Smuzhiyun int (*function) (struct child_prog *); /* function ptr */
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* define DEBUG_SHELL for debugging output (obviously ;-)) */
356*4882a593Smuzhiyun #if 0
357*4882a593Smuzhiyun #define DEBUG_SHELL
358*4882a593Smuzhiyun #endif
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* This should be in utility.c */
361*4882a593Smuzhiyun #ifdef DEBUG_SHELL
362*4882a593Smuzhiyun #ifndef __U_BOOT__
debug_printf(const char * format,...)363*4882a593Smuzhiyun static void debug_printf(const char *format, ...)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun va_list args;
366*4882a593Smuzhiyun va_start(args, format);
367*4882a593Smuzhiyun vfprintf(stderr, format, args);
368*4882a593Smuzhiyun va_end(args);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun #else
371*4882a593Smuzhiyun #define debug_printf(fmt,args...) printf (fmt ,##args)
372*4882a593Smuzhiyun #endif
373*4882a593Smuzhiyun #else
debug_printf(const char * format,...)374*4882a593Smuzhiyun static inline void debug_printf(const char *format, ...) { }
375*4882a593Smuzhiyun #endif
376*4882a593Smuzhiyun #define final_printf debug_printf
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun #ifdef __U_BOOT__
syntax_err(void)379*4882a593Smuzhiyun static void syntax_err(void) {
380*4882a593Smuzhiyun printf("syntax error\n");
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun #else
__syntax(char * file,int line)383*4882a593Smuzhiyun static void __syntax(char *file, int line) {
384*4882a593Smuzhiyun error_msg("syntax error %s:%d", file, line);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun #define syntax() __syntax(__FILE__, __LINE__)
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun #ifdef __U_BOOT__
390*4882a593Smuzhiyun static void *xmalloc(size_t size);
391*4882a593Smuzhiyun static void *xrealloc(void *ptr, size_t size);
392*4882a593Smuzhiyun #else
393*4882a593Smuzhiyun /* Index of subroutines: */
394*4882a593Smuzhiyun /* function prototypes for builtins */
395*4882a593Smuzhiyun static int builtin_cd(struct child_prog *child);
396*4882a593Smuzhiyun static int builtin_env(struct child_prog *child);
397*4882a593Smuzhiyun static int builtin_eval(struct child_prog *child);
398*4882a593Smuzhiyun static int builtin_exec(struct child_prog *child);
399*4882a593Smuzhiyun static int builtin_exit(struct child_prog *child);
400*4882a593Smuzhiyun static int builtin_export(struct child_prog *child);
401*4882a593Smuzhiyun static int builtin_fg_bg(struct child_prog *child);
402*4882a593Smuzhiyun static int builtin_help(struct child_prog *child);
403*4882a593Smuzhiyun static int builtin_jobs(struct child_prog *child);
404*4882a593Smuzhiyun static int builtin_pwd(struct child_prog *child);
405*4882a593Smuzhiyun static int builtin_read(struct child_prog *child);
406*4882a593Smuzhiyun static int builtin_set(struct child_prog *child);
407*4882a593Smuzhiyun static int builtin_shift(struct child_prog *child);
408*4882a593Smuzhiyun static int builtin_source(struct child_prog *child);
409*4882a593Smuzhiyun static int builtin_umask(struct child_prog *child);
410*4882a593Smuzhiyun static int builtin_unset(struct child_prog *child);
411*4882a593Smuzhiyun static int builtin_not_written(struct child_prog *child);
412*4882a593Smuzhiyun #endif
413*4882a593Smuzhiyun /* o_string manipulation: */
414*4882a593Smuzhiyun static int b_check_space(o_string *o, int len);
415*4882a593Smuzhiyun static int b_addchr(o_string *o, int ch);
416*4882a593Smuzhiyun static void b_reset(o_string *o);
417*4882a593Smuzhiyun static int b_addqchr(o_string *o, int ch, int quote);
418*4882a593Smuzhiyun #ifndef __U_BOOT__
419*4882a593Smuzhiyun static int b_adduint(o_string *o, unsigned int i);
420*4882a593Smuzhiyun #endif
421*4882a593Smuzhiyun /* in_str manipulations: */
422*4882a593Smuzhiyun static int static_get(struct in_str *i);
423*4882a593Smuzhiyun static int static_peek(struct in_str *i);
424*4882a593Smuzhiyun static int file_get(struct in_str *i);
425*4882a593Smuzhiyun static int file_peek(struct in_str *i);
426*4882a593Smuzhiyun #ifndef __U_BOOT__
427*4882a593Smuzhiyun static void setup_file_in_str(struct in_str *i, FILE *f);
428*4882a593Smuzhiyun #else
429*4882a593Smuzhiyun static void setup_file_in_str(struct in_str *i);
430*4882a593Smuzhiyun #endif
431*4882a593Smuzhiyun static void setup_string_in_str(struct in_str *i, const char *s);
432*4882a593Smuzhiyun #ifndef __U_BOOT__
433*4882a593Smuzhiyun /* close_me manipulations: */
434*4882a593Smuzhiyun static void mark_open(int fd);
435*4882a593Smuzhiyun static void mark_closed(int fd);
436*4882a593Smuzhiyun static void close_all(void);
437*4882a593Smuzhiyun #endif
438*4882a593Smuzhiyun /* "run" the final data structures: */
439*4882a593Smuzhiyun static char *indenter(int i);
440*4882a593Smuzhiyun static int free_pipe_list(struct pipe *head, int indent);
441*4882a593Smuzhiyun static int free_pipe(struct pipe *pi, int indent);
442*4882a593Smuzhiyun /* really run the final data structures: */
443*4882a593Smuzhiyun #ifndef __U_BOOT__
444*4882a593Smuzhiyun static int setup_redirects(struct child_prog *prog, int squirrel[]);
445*4882a593Smuzhiyun #endif
446*4882a593Smuzhiyun static int run_list_real(struct pipe *pi);
447*4882a593Smuzhiyun #ifndef __U_BOOT__
448*4882a593Smuzhiyun static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
449*4882a593Smuzhiyun #endif
450*4882a593Smuzhiyun static int run_pipe_real(struct pipe *pi);
451*4882a593Smuzhiyun /* extended glob support: */
452*4882a593Smuzhiyun #ifndef __U_BOOT__
453*4882a593Smuzhiyun static int globhack(const char *src, int flags, glob_t *pglob);
454*4882a593Smuzhiyun static int glob_needed(const char *s);
455*4882a593Smuzhiyun static int xglob(o_string *dest, int flags, glob_t *pglob);
456*4882a593Smuzhiyun #endif
457*4882a593Smuzhiyun /* variable assignment: */
458*4882a593Smuzhiyun static int is_assignment(const char *s);
459*4882a593Smuzhiyun /* data structure manipulation: */
460*4882a593Smuzhiyun #ifndef __U_BOOT__
461*4882a593Smuzhiyun static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
462*4882a593Smuzhiyun #endif
463*4882a593Smuzhiyun static void initialize_context(struct p_context *ctx);
464*4882a593Smuzhiyun static int done_word(o_string *dest, struct p_context *ctx);
465*4882a593Smuzhiyun static int done_command(struct p_context *ctx);
466*4882a593Smuzhiyun static int done_pipe(struct p_context *ctx, pipe_style type);
467*4882a593Smuzhiyun /* primary string parsing: */
468*4882a593Smuzhiyun #ifndef __U_BOOT__
469*4882a593Smuzhiyun static int redirect_dup_num(struct in_str *input);
470*4882a593Smuzhiyun static int redirect_opt_num(o_string *o);
471*4882a593Smuzhiyun static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
472*4882a593Smuzhiyun static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
473*4882a593Smuzhiyun #endif
474*4882a593Smuzhiyun static char *lookup_param(char *src);
475*4882a593Smuzhiyun static char *make_string(char **inp, int *nonnull);
476*4882a593Smuzhiyun static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
477*4882a593Smuzhiyun #ifndef __U_BOOT__
478*4882a593Smuzhiyun static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
479*4882a593Smuzhiyun #endif
480*4882a593Smuzhiyun static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
481*4882a593Smuzhiyun /* setup: */
482*4882a593Smuzhiyun static int parse_stream_outer(struct in_str *inp, int flag);
483*4882a593Smuzhiyun #ifndef __U_BOOT__
484*4882a593Smuzhiyun static int parse_string_outer(const char *s, int flag);
485*4882a593Smuzhiyun static int parse_file_outer(FILE *f);
486*4882a593Smuzhiyun #endif
487*4882a593Smuzhiyun #ifndef __U_BOOT__
488*4882a593Smuzhiyun /* job management: */
489*4882a593Smuzhiyun static int checkjobs(struct pipe* fg_pipe);
490*4882a593Smuzhiyun static void insert_bg_job(struct pipe *pi);
491*4882a593Smuzhiyun static void remove_bg_job(struct pipe *pi);
492*4882a593Smuzhiyun #endif
493*4882a593Smuzhiyun /* local variable support */
494*4882a593Smuzhiyun static char **make_list_in(char **inp, char *name);
495*4882a593Smuzhiyun static char *insert_var_value(char *inp);
496*4882a593Smuzhiyun static char *insert_var_value_sub(char *inp, int tag_subst);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun #ifndef __U_BOOT__
499*4882a593Smuzhiyun /* Table of built-in functions. They can be forked or not, depending on
500*4882a593Smuzhiyun * context: within pipes, they fork. As simple commands, they do not.
501*4882a593Smuzhiyun * When used in non-forking context, they can change global variables
502*4882a593Smuzhiyun * in the parent shell process. If forked, of course they can not.
503*4882a593Smuzhiyun * For example, 'unset foo | whatever' will parse and run, but foo will
504*4882a593Smuzhiyun * still be set at the end. */
505*4882a593Smuzhiyun static struct built_in_command bltins[] = {
506*4882a593Smuzhiyun {"bg", "Resume a job in the background", builtin_fg_bg},
507*4882a593Smuzhiyun {"break", "Exit for, while or until loop", builtin_not_written},
508*4882a593Smuzhiyun {"cd", "Change working directory", builtin_cd},
509*4882a593Smuzhiyun {"continue", "Continue for, while or until loop", builtin_not_written},
510*4882a593Smuzhiyun {"env", "Print all environment variables", builtin_env},
511*4882a593Smuzhiyun {"eval", "Construct and run shell command", builtin_eval},
512*4882a593Smuzhiyun {"exec", "Exec command, replacing this shell with the exec'd process",
513*4882a593Smuzhiyun builtin_exec},
514*4882a593Smuzhiyun {"exit", "Exit from shell()", builtin_exit},
515*4882a593Smuzhiyun {"export", "Set environment variable", builtin_export},
516*4882a593Smuzhiyun {"fg", "Bring job into the foreground", builtin_fg_bg},
517*4882a593Smuzhiyun {"jobs", "Lists the active jobs", builtin_jobs},
518*4882a593Smuzhiyun {"pwd", "Print current directory", builtin_pwd},
519*4882a593Smuzhiyun {"read", "Input environment variable", builtin_read},
520*4882a593Smuzhiyun {"return", "Return from a function", builtin_not_written},
521*4882a593Smuzhiyun {"set", "Set/unset shell local variables", builtin_set},
522*4882a593Smuzhiyun {"shift", "Shift positional parameters", builtin_shift},
523*4882a593Smuzhiyun {"trap", "Trap signals", builtin_not_written},
524*4882a593Smuzhiyun {"ulimit","Controls resource limits", builtin_not_written},
525*4882a593Smuzhiyun {"umask","Sets file creation mask", builtin_umask},
526*4882a593Smuzhiyun {"unset", "Unset environment variable", builtin_unset},
527*4882a593Smuzhiyun {".", "Source-in and run commands in a file", builtin_source},
528*4882a593Smuzhiyun {"help", "List shell built-in commands", builtin_help},
529*4882a593Smuzhiyun {NULL, NULL, NULL}
530*4882a593Smuzhiyun };
531*4882a593Smuzhiyun
set_cwd(void)532*4882a593Smuzhiyun static const char *set_cwd(void)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun if(cwd==unknown)
535*4882a593Smuzhiyun cwd = NULL; /* xgetcwd(arg) called free(arg) */
536*4882a593Smuzhiyun cwd = xgetcwd((char *)cwd);
537*4882a593Smuzhiyun if (!cwd)
538*4882a593Smuzhiyun cwd = unknown;
539*4882a593Smuzhiyun return cwd;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /* built-in 'eval' handler */
builtin_eval(struct child_prog * child)543*4882a593Smuzhiyun static int builtin_eval(struct child_prog *child)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun char *str = NULL;
546*4882a593Smuzhiyun int rcode = EXIT_SUCCESS;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun if (child->argv[1]) {
549*4882a593Smuzhiyun str = make_string(child->argv + 1);
550*4882a593Smuzhiyun parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
551*4882a593Smuzhiyun FLAG_PARSE_SEMICOLON);
552*4882a593Smuzhiyun free(str);
553*4882a593Smuzhiyun rcode = last_return_code;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun return rcode;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /* built-in 'cd <path>' handler */
builtin_cd(struct child_prog * child)559*4882a593Smuzhiyun static int builtin_cd(struct child_prog *child)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun char *newdir;
562*4882a593Smuzhiyun if (child->argv[1] == NULL)
563*4882a593Smuzhiyun newdir = env_get("HOME");
564*4882a593Smuzhiyun else
565*4882a593Smuzhiyun newdir = child->argv[1];
566*4882a593Smuzhiyun if (chdir(newdir)) {
567*4882a593Smuzhiyun printf("cd: %s: %s\n", newdir, strerror(errno));
568*4882a593Smuzhiyun return EXIT_FAILURE;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun set_cwd();
571*4882a593Smuzhiyun return EXIT_SUCCESS;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /* built-in 'env' handler */
builtin_env(struct child_prog * dummy)575*4882a593Smuzhiyun static int builtin_env(struct child_prog *dummy)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun char **e = environ;
578*4882a593Smuzhiyun if (e == NULL) return EXIT_FAILURE;
579*4882a593Smuzhiyun for (; *e; e++) {
580*4882a593Smuzhiyun puts(*e);
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun return EXIT_SUCCESS;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun /* built-in 'exec' handler */
builtin_exec(struct child_prog * child)586*4882a593Smuzhiyun static int builtin_exec(struct child_prog *child)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun if (child->argv[1] == NULL)
589*4882a593Smuzhiyun return EXIT_SUCCESS; /* Really? */
590*4882a593Smuzhiyun child->argv++;
591*4882a593Smuzhiyun pseudo_exec(child);
592*4882a593Smuzhiyun /* never returns */
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun /* built-in 'exit' handler */
builtin_exit(struct child_prog * child)596*4882a593Smuzhiyun static int builtin_exit(struct child_prog *child)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun if (child->argv[1] == NULL)
599*4882a593Smuzhiyun exit(last_return_code);
600*4882a593Smuzhiyun exit (atoi(child->argv[1]));
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun /* built-in 'export VAR=value' handler */
builtin_export(struct child_prog * child)604*4882a593Smuzhiyun static int builtin_export(struct child_prog *child)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun int res = 0;
607*4882a593Smuzhiyun char *name = child->argv[1];
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun if (name == NULL) {
610*4882a593Smuzhiyun return (builtin_env(child));
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun name = strdup(name);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun if(name) {
616*4882a593Smuzhiyun char *value = strchr(name, '=');
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun if (!value) {
619*4882a593Smuzhiyun char *tmp;
620*4882a593Smuzhiyun /* They are exporting something without an =VALUE */
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun value = get_local_var(name);
623*4882a593Smuzhiyun if (value) {
624*4882a593Smuzhiyun size_t ln = strlen(name);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun tmp = realloc(name, ln+strlen(value)+2);
627*4882a593Smuzhiyun if(tmp==NULL)
628*4882a593Smuzhiyun res = -1;
629*4882a593Smuzhiyun else {
630*4882a593Smuzhiyun sprintf(tmp+ln, "=%s", value);
631*4882a593Smuzhiyun name = tmp;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun } else {
634*4882a593Smuzhiyun /* bash does not return an error when trying to export
635*4882a593Smuzhiyun * an undefined variable. Do likewise. */
636*4882a593Smuzhiyun res = 1;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun if (res<0)
641*4882a593Smuzhiyun perror_msg("export");
642*4882a593Smuzhiyun else if(res==0)
643*4882a593Smuzhiyun res = set_local_var(name, 1);
644*4882a593Smuzhiyun else
645*4882a593Smuzhiyun res = 0;
646*4882a593Smuzhiyun free(name);
647*4882a593Smuzhiyun return res;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun /* built-in 'fg' and 'bg' handler */
builtin_fg_bg(struct child_prog * child)651*4882a593Smuzhiyun static int builtin_fg_bg(struct child_prog *child)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun int i, jobnum;
654*4882a593Smuzhiyun struct pipe *pi=NULL;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun if (!interactive)
657*4882a593Smuzhiyun return EXIT_FAILURE;
658*4882a593Smuzhiyun /* If they gave us no args, assume they want the last backgrounded task */
659*4882a593Smuzhiyun if (!child->argv[1]) {
660*4882a593Smuzhiyun for (pi = job_list; pi; pi = pi->next) {
661*4882a593Smuzhiyun if (pi->jobid == last_jobid) {
662*4882a593Smuzhiyun break;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun if (!pi) {
666*4882a593Smuzhiyun error_msg("%s: no current job", child->argv[0]);
667*4882a593Smuzhiyun return EXIT_FAILURE;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun } else {
670*4882a593Smuzhiyun if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
671*4882a593Smuzhiyun error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
672*4882a593Smuzhiyun return EXIT_FAILURE;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun for (pi = job_list; pi; pi = pi->next) {
675*4882a593Smuzhiyun if (pi->jobid == jobnum) {
676*4882a593Smuzhiyun break;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun if (!pi) {
680*4882a593Smuzhiyun error_msg("%s: %d: no such job", child->argv[0], jobnum);
681*4882a593Smuzhiyun return EXIT_FAILURE;
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun if (*child->argv[0] == 'f') {
686*4882a593Smuzhiyun /* Put the job into the foreground. */
687*4882a593Smuzhiyun tcsetpgrp(shell_terminal, pi->pgrp);
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun /* Restart the processes in the job */
691*4882a593Smuzhiyun for (i = 0; i < pi->num_progs; i++)
692*4882a593Smuzhiyun pi->progs[i].is_stopped = 0;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
695*4882a593Smuzhiyun if (i == ESRCH) {
696*4882a593Smuzhiyun remove_bg_job(pi);
697*4882a593Smuzhiyun } else {
698*4882a593Smuzhiyun perror_msg("kill (SIGCONT)");
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun pi->stopped_progs = 0;
703*4882a593Smuzhiyun return EXIT_SUCCESS;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun /* built-in 'help' handler */
builtin_help(struct child_prog * dummy)707*4882a593Smuzhiyun static int builtin_help(struct child_prog *dummy)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun struct built_in_command *x;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun printf("\nBuilt-in commands:\n");
712*4882a593Smuzhiyun printf("-------------------\n");
713*4882a593Smuzhiyun for (x = bltins; x->cmd; x++) {
714*4882a593Smuzhiyun if (x->descr==NULL)
715*4882a593Smuzhiyun continue;
716*4882a593Smuzhiyun printf("%s\t%s\n", x->cmd, x->descr);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun printf("\n\n");
719*4882a593Smuzhiyun return EXIT_SUCCESS;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun /* built-in 'jobs' handler */
builtin_jobs(struct child_prog * child)723*4882a593Smuzhiyun static int builtin_jobs(struct child_prog *child)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun struct pipe *job;
726*4882a593Smuzhiyun char *status_string;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun for (job = job_list; job; job = job->next) {
729*4882a593Smuzhiyun if (job->running_progs == job->stopped_progs)
730*4882a593Smuzhiyun status_string = "Stopped";
731*4882a593Smuzhiyun else
732*4882a593Smuzhiyun status_string = "Running";
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun return EXIT_SUCCESS;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun /* built-in 'pwd' handler */
builtin_pwd(struct child_prog * dummy)741*4882a593Smuzhiyun static int builtin_pwd(struct child_prog *dummy)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun puts(set_cwd());
744*4882a593Smuzhiyun return EXIT_SUCCESS;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun /* built-in 'read VAR' handler */
builtin_read(struct child_prog * child)748*4882a593Smuzhiyun static int builtin_read(struct child_prog *child)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun int res;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun if (child->argv[1]) {
753*4882a593Smuzhiyun char string[BUFSIZ];
754*4882a593Smuzhiyun char *var = 0;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun string[0] = 0; /* In case stdin has only EOF */
757*4882a593Smuzhiyun /* read string */
758*4882a593Smuzhiyun fgets(string, sizeof(string), stdin);
759*4882a593Smuzhiyun chomp(string);
760*4882a593Smuzhiyun var = malloc(strlen(child->argv[1])+strlen(string)+2);
761*4882a593Smuzhiyun if(var) {
762*4882a593Smuzhiyun sprintf(var, "%s=%s", child->argv[1], string);
763*4882a593Smuzhiyun res = set_local_var(var, 0);
764*4882a593Smuzhiyun } else
765*4882a593Smuzhiyun res = -1;
766*4882a593Smuzhiyun if (res)
767*4882a593Smuzhiyun fprintf(stderr, "read: %m\n");
768*4882a593Smuzhiyun free(var); /* So not move up to avoid breaking errno */
769*4882a593Smuzhiyun return res;
770*4882a593Smuzhiyun } else {
771*4882a593Smuzhiyun do res=getchar(); while(res!='\n' && res!=EOF);
772*4882a593Smuzhiyun return 0;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /* built-in 'set VAR=value' handler */
builtin_set(struct child_prog * child)777*4882a593Smuzhiyun static int builtin_set(struct child_prog *child)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun char *temp = child->argv[1];
780*4882a593Smuzhiyun struct variables *e;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (temp == NULL)
783*4882a593Smuzhiyun for(e = top_vars; e; e=e->next)
784*4882a593Smuzhiyun printf("%s=%s\n", e->name, e->value);
785*4882a593Smuzhiyun else
786*4882a593Smuzhiyun set_local_var(temp, 0);
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun return EXIT_SUCCESS;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun /* Built-in 'shift' handler */
builtin_shift(struct child_prog * child)793*4882a593Smuzhiyun static int builtin_shift(struct child_prog *child)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun int n=1;
796*4882a593Smuzhiyun if (child->argv[1]) {
797*4882a593Smuzhiyun n=atoi(child->argv[1]);
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun if (n>=0 && n<global_argc) {
800*4882a593Smuzhiyun /* XXX This probably breaks $0 */
801*4882a593Smuzhiyun global_argc -= n;
802*4882a593Smuzhiyun global_argv += n;
803*4882a593Smuzhiyun return EXIT_SUCCESS;
804*4882a593Smuzhiyun } else {
805*4882a593Smuzhiyun return EXIT_FAILURE;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /* Built-in '.' handler (read-in and execute commands from file) */
builtin_source(struct child_prog * child)810*4882a593Smuzhiyun static int builtin_source(struct child_prog *child)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun FILE *input;
813*4882a593Smuzhiyun int status;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (child->argv[1] == NULL)
816*4882a593Smuzhiyun return EXIT_FAILURE;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun /* XXX search through $PATH is missing */
819*4882a593Smuzhiyun input = fopen(child->argv[1], "r");
820*4882a593Smuzhiyun if (!input) {
821*4882a593Smuzhiyun error_msg("Couldn't open file '%s'", child->argv[1]);
822*4882a593Smuzhiyun return EXIT_FAILURE;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun /* Now run the file */
826*4882a593Smuzhiyun /* XXX argv and argc are broken; need to save old global_argv
827*4882a593Smuzhiyun * (pointer only is OK!) on this stack frame,
828*4882a593Smuzhiyun * set global_argv=child->argv+1, recurse, and restore. */
829*4882a593Smuzhiyun mark_open(fileno(input));
830*4882a593Smuzhiyun status = parse_file_outer(input);
831*4882a593Smuzhiyun mark_closed(fileno(input));
832*4882a593Smuzhiyun fclose(input);
833*4882a593Smuzhiyun return (status);
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
builtin_umask(struct child_prog * child)836*4882a593Smuzhiyun static int builtin_umask(struct child_prog *child)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun mode_t new_umask;
839*4882a593Smuzhiyun const char *arg = child->argv[1];
840*4882a593Smuzhiyun char *end;
841*4882a593Smuzhiyun if (arg) {
842*4882a593Smuzhiyun new_umask=strtoul(arg, &end, 8);
843*4882a593Smuzhiyun if (*end!='\0' || end == arg) {
844*4882a593Smuzhiyun return EXIT_FAILURE;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun } else {
847*4882a593Smuzhiyun printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun umask(new_umask);
850*4882a593Smuzhiyun return EXIT_SUCCESS;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun /* built-in 'unset VAR' handler */
builtin_unset(struct child_prog * child)854*4882a593Smuzhiyun static int builtin_unset(struct child_prog *child)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun /* bash returned already true */
857*4882a593Smuzhiyun unset_local_var(child->argv[1]);
858*4882a593Smuzhiyun return EXIT_SUCCESS;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun
builtin_not_written(struct child_prog * child)861*4882a593Smuzhiyun static int builtin_not_written(struct child_prog *child)
862*4882a593Smuzhiyun {
863*4882a593Smuzhiyun printf("builtin_%s not written\n",child->argv[0]);
864*4882a593Smuzhiyun return EXIT_FAILURE;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun #endif
867*4882a593Smuzhiyun
b_check_space(o_string * o,int len)868*4882a593Smuzhiyun static int b_check_space(o_string *o, int len)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun /* It would be easy to drop a more restrictive policy
871*4882a593Smuzhiyun * in here, such as setting a maximum string length */
872*4882a593Smuzhiyun if (o->length + len > o->maxlen) {
873*4882a593Smuzhiyun char *old_data = o->data;
874*4882a593Smuzhiyun /* assert (data == NULL || o->maxlen != 0); */
875*4882a593Smuzhiyun o->maxlen += max(2*len, B_CHUNK);
876*4882a593Smuzhiyun o->data = realloc(o->data, 1 + o->maxlen);
877*4882a593Smuzhiyun if (o->data == NULL) {
878*4882a593Smuzhiyun free(old_data);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun return o->data == NULL;
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun
b_addchr(o_string * o,int ch)884*4882a593Smuzhiyun static int b_addchr(o_string *o, int ch)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
887*4882a593Smuzhiyun if (b_check_space(o, 1)) return B_NOSPAC;
888*4882a593Smuzhiyun o->data[o->length] = ch;
889*4882a593Smuzhiyun o->length++;
890*4882a593Smuzhiyun o->data[o->length] = '\0';
891*4882a593Smuzhiyun return 0;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
b_reset(o_string * o)894*4882a593Smuzhiyun static void b_reset(o_string *o)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun o->length = 0;
897*4882a593Smuzhiyun o->nonnull = 0;
898*4882a593Smuzhiyun if (o->data != NULL) *o->data = '\0';
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun
b_free(o_string * o)901*4882a593Smuzhiyun static void b_free(o_string *o)
902*4882a593Smuzhiyun {
903*4882a593Smuzhiyun b_reset(o);
904*4882a593Smuzhiyun free(o->data);
905*4882a593Smuzhiyun o->data = NULL;
906*4882a593Smuzhiyun o->maxlen = 0;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun /* My analysis of quoting semantics tells me that state information
910*4882a593Smuzhiyun * is associated with a destination, not a source.
911*4882a593Smuzhiyun */
b_addqchr(o_string * o,int ch,int quote)912*4882a593Smuzhiyun static int b_addqchr(o_string *o, int ch, int quote)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun if (quote && strchr("*?[\\",ch)) {
915*4882a593Smuzhiyun int rc;
916*4882a593Smuzhiyun rc = b_addchr(o, '\\');
917*4882a593Smuzhiyun if (rc) return rc;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun return b_addchr(o, ch);
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun #ifndef __U_BOOT__
b_adduint(o_string * o,unsigned int i)923*4882a593Smuzhiyun static int b_adduint(o_string *o, unsigned int i)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun int r;
926*4882a593Smuzhiyun char *p = simple_itoa(i);
927*4882a593Smuzhiyun /* no escape checking necessary */
928*4882a593Smuzhiyun do r=b_addchr(o, *p++); while (r==0 && *p);
929*4882a593Smuzhiyun return r;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun #endif
932*4882a593Smuzhiyun
static_get(struct in_str * i)933*4882a593Smuzhiyun static int static_get(struct in_str *i)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun int ch = *i->p++;
936*4882a593Smuzhiyun if (ch=='\0') return EOF;
937*4882a593Smuzhiyun return ch;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun
static_peek(struct in_str * i)940*4882a593Smuzhiyun static int static_peek(struct in_str *i)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun return *i->p;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun #ifndef __U_BOOT__
cmdedit_set_initial_prompt(void)946*4882a593Smuzhiyun static inline void cmdedit_set_initial_prompt(void)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
949*4882a593Smuzhiyun PS1 = NULL;
950*4882a593Smuzhiyun #else
951*4882a593Smuzhiyun PS1 = env_get("PS1");
952*4882a593Smuzhiyun if(PS1==0)
953*4882a593Smuzhiyun PS1 = "\\w \\$ ";
954*4882a593Smuzhiyun #endif
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
setup_prompt_string(int promptmode,char ** prompt_str)957*4882a593Smuzhiyun static inline void setup_prompt_string(int promptmode, char **prompt_str)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun debug_printf("setup_prompt_string %d ",promptmode);
960*4882a593Smuzhiyun #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
961*4882a593Smuzhiyun /* Set up the prompt */
962*4882a593Smuzhiyun if (promptmode == 1) {
963*4882a593Smuzhiyun free(PS1);
964*4882a593Smuzhiyun PS1=xmalloc(strlen(cwd)+4);
965*4882a593Smuzhiyun sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
966*4882a593Smuzhiyun *prompt_str = PS1;
967*4882a593Smuzhiyun } else {
968*4882a593Smuzhiyun *prompt_str = PS2;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun #else
971*4882a593Smuzhiyun *prompt_str = (promptmode==1)? PS1 : PS2;
972*4882a593Smuzhiyun #endif
973*4882a593Smuzhiyun debug_printf("result %s\n",*prompt_str);
974*4882a593Smuzhiyun }
975*4882a593Smuzhiyun #endif
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun #ifdef __U_BOOT__
uboot_cli_readline(struct in_str * i)978*4882a593Smuzhiyun static int uboot_cli_readline(struct in_str *i)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun char *prompt;
981*4882a593Smuzhiyun char __maybe_unused *ps_prompt = NULL;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun if (i->promptmode == 1)
984*4882a593Smuzhiyun prompt = CONFIG_SYS_PROMPT;
985*4882a593Smuzhiyun else
986*4882a593Smuzhiyun prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun #ifdef CONFIG_CMDLINE_PS_SUPPORT
989*4882a593Smuzhiyun if (i->promptmode == 1)
990*4882a593Smuzhiyun ps_prompt = env_get("PS1");
991*4882a593Smuzhiyun else
992*4882a593Smuzhiyun ps_prompt = env_get("PS2");
993*4882a593Smuzhiyun if (ps_prompt)
994*4882a593Smuzhiyun prompt = ps_prompt;
995*4882a593Smuzhiyun #endif
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun return cli_readline(prompt);
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun #endif
1000*4882a593Smuzhiyun
get_user_input(struct in_str * i)1001*4882a593Smuzhiyun static void get_user_input(struct in_str *i)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun #ifndef __U_BOOT__
1004*4882a593Smuzhiyun char *prompt_str;
1005*4882a593Smuzhiyun static char the_command[BUFSIZ];
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun setup_prompt_string(i->promptmode, &prompt_str);
1008*4882a593Smuzhiyun #ifdef CONFIG_FEATURE_COMMAND_EDITING
1009*4882a593Smuzhiyun /*
1010*4882a593Smuzhiyun ** enable command line editing only while a command line
1011*4882a593Smuzhiyun ** is actually being read; otherwise, we'll end up bequeathing
1012*4882a593Smuzhiyun ** atexit() handlers and other unwanted stuff to our
1013*4882a593Smuzhiyun ** child processes (rob@sysgo.de)
1014*4882a593Smuzhiyun */
1015*4882a593Smuzhiyun cmdedit_read_input(prompt_str, the_command);
1016*4882a593Smuzhiyun #else
1017*4882a593Smuzhiyun fputs(prompt_str, stdout);
1018*4882a593Smuzhiyun fflush(stdout);
1019*4882a593Smuzhiyun the_command[0]=fgetc(i->file);
1020*4882a593Smuzhiyun the_command[1]='\0';
1021*4882a593Smuzhiyun #endif
1022*4882a593Smuzhiyun fflush(stdout);
1023*4882a593Smuzhiyun i->p = the_command;
1024*4882a593Smuzhiyun #else
1025*4882a593Smuzhiyun int n;
1026*4882a593Smuzhiyun static char the_command[CONFIG_SYS_CBSIZE + 1];
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun bootretry_reset_cmd_timeout();
1029*4882a593Smuzhiyun i->__promptme = 1;
1030*4882a593Smuzhiyun n = uboot_cli_readline(i);
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun #ifdef CONFIG_BOOT_RETRY_TIME
1033*4882a593Smuzhiyun if (n == -2) {
1034*4882a593Smuzhiyun puts("\nTimeout waiting for command\n");
1035*4882a593Smuzhiyun # ifdef CONFIG_RESET_TO_RETRY
1036*4882a593Smuzhiyun do_reset(NULL, 0, 0, NULL);
1037*4882a593Smuzhiyun # else
1038*4882a593Smuzhiyun # error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
1039*4882a593Smuzhiyun # endif
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun #endif
1042*4882a593Smuzhiyun if (n == -1 ) {
1043*4882a593Smuzhiyun flag_repeat = 0;
1044*4882a593Smuzhiyun i->__promptme = 0;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun n = strlen(console_buffer);
1047*4882a593Smuzhiyun console_buffer[n] = '\n';
1048*4882a593Smuzhiyun console_buffer[n+1]= '\0';
1049*4882a593Smuzhiyun if (had_ctrlc()) flag_repeat = 0;
1050*4882a593Smuzhiyun clear_ctrlc();
1051*4882a593Smuzhiyun do_repeat = 0;
1052*4882a593Smuzhiyun if (i->promptmode == 1) {
1053*4882a593Smuzhiyun if (console_buffer[0] == '\n'&& flag_repeat == 0) {
1054*4882a593Smuzhiyun strcpy(the_command,console_buffer);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun else {
1057*4882a593Smuzhiyun if (console_buffer[0] != '\n') {
1058*4882a593Smuzhiyun strcpy(the_command,console_buffer);
1059*4882a593Smuzhiyun flag_repeat = 1;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun else {
1062*4882a593Smuzhiyun do_repeat = 1;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun i->p = the_command;
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun else {
1068*4882a593Smuzhiyun if (console_buffer[0] != '\n') {
1069*4882a593Smuzhiyun if (strlen(the_command) + strlen(console_buffer)
1070*4882a593Smuzhiyun < CONFIG_SYS_CBSIZE) {
1071*4882a593Smuzhiyun n = strlen(the_command);
1072*4882a593Smuzhiyun the_command[n-1] = ' ';
1073*4882a593Smuzhiyun strcpy(&the_command[n],console_buffer);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun else {
1076*4882a593Smuzhiyun the_command[0] = '\n';
1077*4882a593Smuzhiyun the_command[1] = '\0';
1078*4882a593Smuzhiyun flag_repeat = 0;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun if (i->__promptme == 0) {
1082*4882a593Smuzhiyun the_command[0] = '\n';
1083*4882a593Smuzhiyun the_command[1] = '\0';
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun i->p = console_buffer;
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun #endif
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun /* This is the magic location that prints prompts
1091*4882a593Smuzhiyun * and gets data back from the user */
file_get(struct in_str * i)1092*4882a593Smuzhiyun static int file_get(struct in_str *i)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun int ch;
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun ch = 0;
1097*4882a593Smuzhiyun /* If there is data waiting, eat it up */
1098*4882a593Smuzhiyun if (i->p && *i->p) {
1099*4882a593Smuzhiyun ch = *i->p++;
1100*4882a593Smuzhiyun } else {
1101*4882a593Smuzhiyun /* need to double check i->file because we might be doing something
1102*4882a593Smuzhiyun * more complicated by now, like sourcing or substituting. */
1103*4882a593Smuzhiyun #ifndef __U_BOOT__
1104*4882a593Smuzhiyun if (i->__promptme && interactive && i->file == stdin) {
1105*4882a593Smuzhiyun while(! i->p || (interactive && strlen(i->p)==0) ) {
1106*4882a593Smuzhiyun #else
1107*4882a593Smuzhiyun while(! i->p || strlen(i->p)==0 ) {
1108*4882a593Smuzhiyun #endif
1109*4882a593Smuzhiyun get_user_input(i);
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun i->promptmode=2;
1112*4882a593Smuzhiyun #ifndef __U_BOOT__
1113*4882a593Smuzhiyun i->__promptme = 0;
1114*4882a593Smuzhiyun #endif
1115*4882a593Smuzhiyun if (i->p && *i->p) {
1116*4882a593Smuzhiyun ch = *i->p++;
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun #ifndef __U_BOOT__
1119*4882a593Smuzhiyun } else {
1120*4882a593Smuzhiyun ch = fgetc(i->file);
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun #endif
1124*4882a593Smuzhiyun debug_printf("b_getch: got a %d\n", ch);
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun #ifndef __U_BOOT__
1127*4882a593Smuzhiyun if (ch == '\n') i->__promptme=1;
1128*4882a593Smuzhiyun #endif
1129*4882a593Smuzhiyun return ch;
1130*4882a593Smuzhiyun }
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun /* All the callers guarantee this routine will never be
1133*4882a593Smuzhiyun * used right after a newline, so prompting is not needed.
1134*4882a593Smuzhiyun */
1135*4882a593Smuzhiyun static int file_peek(struct in_str *i)
1136*4882a593Smuzhiyun {
1137*4882a593Smuzhiyun #ifndef __U_BOOT__
1138*4882a593Smuzhiyun if (i->p && *i->p) {
1139*4882a593Smuzhiyun #endif
1140*4882a593Smuzhiyun return *i->p;
1141*4882a593Smuzhiyun #ifndef __U_BOOT__
1142*4882a593Smuzhiyun } else {
1143*4882a593Smuzhiyun i->peek_buf[0] = fgetc(i->file);
1144*4882a593Smuzhiyun i->peek_buf[1] = '\0';
1145*4882a593Smuzhiyun i->p = i->peek_buf;
1146*4882a593Smuzhiyun debug_printf("b_peek: got a %d\n", *i->p);
1147*4882a593Smuzhiyun return *i->p;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun #endif
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun #ifndef __U_BOOT__
1153*4882a593Smuzhiyun static void setup_file_in_str(struct in_str *i, FILE *f)
1154*4882a593Smuzhiyun #else
1155*4882a593Smuzhiyun static void setup_file_in_str(struct in_str *i)
1156*4882a593Smuzhiyun #endif
1157*4882a593Smuzhiyun {
1158*4882a593Smuzhiyun i->peek = file_peek;
1159*4882a593Smuzhiyun i->get = file_get;
1160*4882a593Smuzhiyun i->__promptme=1;
1161*4882a593Smuzhiyun i->promptmode=1;
1162*4882a593Smuzhiyun #ifndef __U_BOOT__
1163*4882a593Smuzhiyun i->file = f;
1164*4882a593Smuzhiyun #endif
1165*4882a593Smuzhiyun i->p = NULL;
1166*4882a593Smuzhiyun }
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun static void setup_string_in_str(struct in_str *i, const char *s)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun i->peek = static_peek;
1171*4882a593Smuzhiyun i->get = static_get;
1172*4882a593Smuzhiyun i->__promptme=1;
1173*4882a593Smuzhiyun i->promptmode=1;
1174*4882a593Smuzhiyun i->p = s;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun #ifndef __U_BOOT__
1178*4882a593Smuzhiyun static void mark_open(int fd)
1179*4882a593Smuzhiyun {
1180*4882a593Smuzhiyun struct close_me *new = xmalloc(sizeof(struct close_me));
1181*4882a593Smuzhiyun new->fd = fd;
1182*4882a593Smuzhiyun new->next = close_me_head;
1183*4882a593Smuzhiyun close_me_head = new;
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun static void mark_closed(int fd)
1187*4882a593Smuzhiyun {
1188*4882a593Smuzhiyun struct close_me *tmp;
1189*4882a593Smuzhiyun if (close_me_head == NULL || close_me_head->fd != fd)
1190*4882a593Smuzhiyun error_msg_and_die("corrupt close_me");
1191*4882a593Smuzhiyun tmp = close_me_head;
1192*4882a593Smuzhiyun close_me_head = close_me_head->next;
1193*4882a593Smuzhiyun free(tmp);
1194*4882a593Smuzhiyun }
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun static void close_all(void)
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun struct close_me *c;
1199*4882a593Smuzhiyun for (c=close_me_head; c; c=c->next) {
1200*4882a593Smuzhiyun close(c->fd);
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun close_me_head = NULL;
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun /* squirrel != NULL means we squirrel away copies of stdin, stdout,
1206*4882a593Smuzhiyun * and stderr if they are redirected. */
1207*4882a593Smuzhiyun static int setup_redirects(struct child_prog *prog, int squirrel[])
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun int openfd, mode;
1210*4882a593Smuzhiyun struct redir_struct *redir;
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun for (redir=prog->redirects; redir; redir=redir->next) {
1213*4882a593Smuzhiyun if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
1214*4882a593Smuzhiyun /* something went wrong in the parse. Pretend it didn't happen */
1215*4882a593Smuzhiyun continue;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun if (redir->dup == -1) {
1218*4882a593Smuzhiyun mode=redir_table[redir->type].mode;
1219*4882a593Smuzhiyun openfd = open(redir->word.gl_pathv[0], mode, 0666);
1220*4882a593Smuzhiyun if (openfd < 0) {
1221*4882a593Smuzhiyun /* this could get lost if stderr has been redirected, but
1222*4882a593Smuzhiyun bash and ash both lose it as well (though zsh doesn't!) */
1223*4882a593Smuzhiyun perror_msg("error opening %s", redir->word.gl_pathv[0]);
1224*4882a593Smuzhiyun return 1;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun } else {
1227*4882a593Smuzhiyun openfd = redir->dup;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun if (openfd != redir->fd) {
1231*4882a593Smuzhiyun if (squirrel && redir->fd < 3) {
1232*4882a593Smuzhiyun squirrel[redir->fd] = dup(redir->fd);
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun if (openfd == -3) {
1235*4882a593Smuzhiyun close(openfd);
1236*4882a593Smuzhiyun } else {
1237*4882a593Smuzhiyun dup2(openfd, redir->fd);
1238*4882a593Smuzhiyun if (redir->dup == -1)
1239*4882a593Smuzhiyun close (openfd);
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun return 0;
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun static void restore_redirects(int squirrel[])
1247*4882a593Smuzhiyun {
1248*4882a593Smuzhiyun int i, fd;
1249*4882a593Smuzhiyun for (i=0; i<3; i++) {
1250*4882a593Smuzhiyun fd = squirrel[i];
1251*4882a593Smuzhiyun if (fd != -1) {
1252*4882a593Smuzhiyun /* No error checking. I sure wouldn't know what
1253*4882a593Smuzhiyun * to do with an error if I found one! */
1254*4882a593Smuzhiyun dup2(fd, i);
1255*4882a593Smuzhiyun close(fd);
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun /* never returns */
1261*4882a593Smuzhiyun /* XXX no exit() here. If you don't exec, use _exit instead.
1262*4882a593Smuzhiyun * The at_exit handlers apparently confuse the calling process,
1263*4882a593Smuzhiyun * in particular stdin handling. Not sure why? */
1264*4882a593Smuzhiyun static void pseudo_exec(struct child_prog *child)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun int i, rcode;
1267*4882a593Smuzhiyun char *p;
1268*4882a593Smuzhiyun struct built_in_command *x;
1269*4882a593Smuzhiyun if (child->argv) {
1270*4882a593Smuzhiyun for (i=0; is_assignment(child->argv[i]); i++) {
1271*4882a593Smuzhiyun debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
1272*4882a593Smuzhiyun p = insert_var_value(child->argv[i]);
1273*4882a593Smuzhiyun putenv(strdup(p));
1274*4882a593Smuzhiyun if (p != child->argv[i]) free(p);
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun child->argv+=i; /* XXX this hack isn't so horrible, since we are about
1277*4882a593Smuzhiyun to exit, and therefore don't need to keep data
1278*4882a593Smuzhiyun structures consistent for free() use. */
1279*4882a593Smuzhiyun /* If a variable is assigned in a forest, and nobody listens,
1280*4882a593Smuzhiyun * was it ever really set?
1281*4882a593Smuzhiyun */
1282*4882a593Smuzhiyun if (child->argv[0] == NULL) {
1283*4882a593Smuzhiyun _exit(EXIT_SUCCESS);
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun /*
1287*4882a593Smuzhiyun * Check if the command matches any of the builtins.
1288*4882a593Smuzhiyun * Depending on context, this might be redundant. But it's
1289*4882a593Smuzhiyun * easier to waste a few CPU cycles than it is to figure out
1290*4882a593Smuzhiyun * if this is one of those cases.
1291*4882a593Smuzhiyun */
1292*4882a593Smuzhiyun for (x = bltins; x->cmd; x++) {
1293*4882a593Smuzhiyun if (strcmp(child->argv[0], x->cmd) == 0 ) {
1294*4882a593Smuzhiyun debug_printf("builtin exec %s\n", child->argv[0]);
1295*4882a593Smuzhiyun rcode = x->function(child);
1296*4882a593Smuzhiyun fflush(stdout);
1297*4882a593Smuzhiyun _exit(rcode);
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun }
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun /* Check if the command matches any busybox internal commands
1302*4882a593Smuzhiyun * ("applets") here.
1303*4882a593Smuzhiyun * FIXME: This feature is not 100% safe, since
1304*4882a593Smuzhiyun * BusyBox is not fully reentrant, so we have no guarantee the things
1305*4882a593Smuzhiyun * from the .bss are still zeroed, or that things from .data are still
1306*4882a593Smuzhiyun * at their defaults. We could exec ourself from /proc/self/exe, but I
1307*4882a593Smuzhiyun * really dislike relying on /proc for things. We could exec ourself
1308*4882a593Smuzhiyun * from global_argv[0], but if we are in a chroot, we may not be able
1309*4882a593Smuzhiyun * to find ourself... */
1310*4882a593Smuzhiyun #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
1311*4882a593Smuzhiyun {
1312*4882a593Smuzhiyun int argc_l;
1313*4882a593Smuzhiyun char** argv_l=child->argv;
1314*4882a593Smuzhiyun char *name = child->argv[0];
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
1317*4882a593Smuzhiyun /* Following discussions from November 2000 on the busybox mailing
1318*4882a593Smuzhiyun * list, the default configuration, (without
1319*4882a593Smuzhiyun * get_last_path_component()) lets the user force use of an
1320*4882a593Smuzhiyun * external command by specifying the full (with slashes) filename.
1321*4882a593Smuzhiyun * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN then applets
1322*4882a593Smuzhiyun * _aways_ override external commands, so if you want to run
1323*4882a593Smuzhiyun * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
1324*4882a593Smuzhiyun * filesystem and is _not_ busybox. Some systems may want this,
1325*4882a593Smuzhiyun * most do not. */
1326*4882a593Smuzhiyun name = get_last_path_component(name);
1327*4882a593Smuzhiyun #endif
1328*4882a593Smuzhiyun /* Count argc for use in a second... */
1329*4882a593Smuzhiyun for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
1330*4882a593Smuzhiyun optind = 1;
1331*4882a593Smuzhiyun debug_printf("running applet %s\n", name);
1332*4882a593Smuzhiyun run_applet_by_name(name, argc_l, child->argv);
1333*4882a593Smuzhiyun }
1334*4882a593Smuzhiyun #endif
1335*4882a593Smuzhiyun debug_printf("exec of %s\n",child->argv[0]);
1336*4882a593Smuzhiyun execvp(child->argv[0],child->argv);
1337*4882a593Smuzhiyun perror_msg("couldn't exec: %s",child->argv[0]);
1338*4882a593Smuzhiyun _exit(1);
1339*4882a593Smuzhiyun } else if (child->group) {
1340*4882a593Smuzhiyun debug_printf("runtime nesting to group\n");
1341*4882a593Smuzhiyun interactive=0; /* crucial!!!! */
1342*4882a593Smuzhiyun rcode = run_list_real(child->group);
1343*4882a593Smuzhiyun /* OK to leak memory by not calling free_pipe_list,
1344*4882a593Smuzhiyun * since this process is about to exit */
1345*4882a593Smuzhiyun _exit(rcode);
1346*4882a593Smuzhiyun } else {
1347*4882a593Smuzhiyun /* Can happen. See what bash does with ">foo" by itself. */
1348*4882a593Smuzhiyun debug_printf("trying to pseudo_exec null command\n");
1349*4882a593Smuzhiyun _exit(EXIT_SUCCESS);
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun static void insert_bg_job(struct pipe *pi)
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun struct pipe *thejob;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun /* Linear search for the ID of the job to use */
1358*4882a593Smuzhiyun pi->jobid = 1;
1359*4882a593Smuzhiyun for (thejob = job_list; thejob; thejob = thejob->next)
1360*4882a593Smuzhiyun if (thejob->jobid >= pi->jobid)
1361*4882a593Smuzhiyun pi->jobid = thejob->jobid + 1;
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun /* add thejob to the list of running jobs */
1364*4882a593Smuzhiyun if (!job_list) {
1365*4882a593Smuzhiyun thejob = job_list = xmalloc(sizeof(*thejob));
1366*4882a593Smuzhiyun } else {
1367*4882a593Smuzhiyun for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
1368*4882a593Smuzhiyun thejob->next = xmalloc(sizeof(*thejob));
1369*4882a593Smuzhiyun thejob = thejob->next;
1370*4882a593Smuzhiyun }
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun /* physically copy the struct job */
1373*4882a593Smuzhiyun memcpy(thejob, pi, sizeof(struct pipe));
1374*4882a593Smuzhiyun thejob->next = NULL;
1375*4882a593Smuzhiyun thejob->running_progs = thejob->num_progs;
1376*4882a593Smuzhiyun thejob->stopped_progs = 0;
1377*4882a593Smuzhiyun thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun /*if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) */
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun char *bar=thejob->text;
1382*4882a593Smuzhiyun char **foo=pi->progs[0].argv;
1383*4882a593Smuzhiyun while(foo && *foo) {
1384*4882a593Smuzhiyun bar += sprintf(bar, "%s ", *foo++);
1385*4882a593Smuzhiyun }
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun /* we don't wait for background thejobs to return -- append it
1389*4882a593Smuzhiyun to the list of backgrounded thejobs and leave it alone */
1390*4882a593Smuzhiyun printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
1391*4882a593Smuzhiyun last_bg_pid = thejob->progs[0].pid;
1392*4882a593Smuzhiyun last_jobid = thejob->jobid;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun /* remove a backgrounded job */
1396*4882a593Smuzhiyun static void remove_bg_job(struct pipe *pi)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun struct pipe *prev_pipe;
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun if (pi == job_list) {
1401*4882a593Smuzhiyun job_list = pi->next;
1402*4882a593Smuzhiyun } else {
1403*4882a593Smuzhiyun prev_pipe = job_list;
1404*4882a593Smuzhiyun while (prev_pipe->next != pi)
1405*4882a593Smuzhiyun prev_pipe = prev_pipe->next;
1406*4882a593Smuzhiyun prev_pipe->next = pi->next;
1407*4882a593Smuzhiyun }
1408*4882a593Smuzhiyun if (job_list)
1409*4882a593Smuzhiyun last_jobid = job_list->jobid;
1410*4882a593Smuzhiyun else
1411*4882a593Smuzhiyun last_jobid = 0;
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun pi->stopped_progs = 0;
1414*4882a593Smuzhiyun free_pipe(pi, 0);
1415*4882a593Smuzhiyun free(pi);
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun /* Checks to see if any processes have exited -- if they
1419*4882a593Smuzhiyun have, figure out why and see if a job has completed */
1420*4882a593Smuzhiyun static int checkjobs(struct pipe* fg_pipe)
1421*4882a593Smuzhiyun {
1422*4882a593Smuzhiyun int attributes;
1423*4882a593Smuzhiyun int status;
1424*4882a593Smuzhiyun int prognum = 0;
1425*4882a593Smuzhiyun struct pipe *pi;
1426*4882a593Smuzhiyun pid_t childpid;
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun attributes = WUNTRACED;
1429*4882a593Smuzhiyun if (fg_pipe==NULL) {
1430*4882a593Smuzhiyun attributes |= WNOHANG;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1434*4882a593Smuzhiyun if (fg_pipe) {
1435*4882a593Smuzhiyun int i, rcode = 0;
1436*4882a593Smuzhiyun for (i=0; i < fg_pipe->num_progs; i++) {
1437*4882a593Smuzhiyun if (fg_pipe->progs[i].pid == childpid) {
1438*4882a593Smuzhiyun if (i==fg_pipe->num_progs-1)
1439*4882a593Smuzhiyun rcode=WEXITSTATUS(status);
1440*4882a593Smuzhiyun (fg_pipe->num_progs)--;
1441*4882a593Smuzhiyun return(rcode);
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun for (pi = job_list; pi; pi = pi->next) {
1447*4882a593Smuzhiyun prognum = 0;
1448*4882a593Smuzhiyun while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
1449*4882a593Smuzhiyun prognum++;
1450*4882a593Smuzhiyun }
1451*4882a593Smuzhiyun if (prognum < pi->num_progs)
1452*4882a593Smuzhiyun break;
1453*4882a593Smuzhiyun }
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun if(pi==NULL) {
1456*4882a593Smuzhiyun debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
1457*4882a593Smuzhiyun continue;
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun if (WIFEXITED(status) || WIFSIGNALED(status)) {
1461*4882a593Smuzhiyun /* child exited */
1462*4882a593Smuzhiyun pi->running_progs--;
1463*4882a593Smuzhiyun pi->progs[prognum].pid = 0;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun if (!pi->running_progs) {
1466*4882a593Smuzhiyun printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
1467*4882a593Smuzhiyun remove_bg_job(pi);
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun } else {
1470*4882a593Smuzhiyun /* child stopped */
1471*4882a593Smuzhiyun pi->stopped_progs++;
1472*4882a593Smuzhiyun pi->progs[prognum].is_stopped = 1;
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun #if 0
1475*4882a593Smuzhiyun /* Printing this stuff is a pain, since it tends to
1476*4882a593Smuzhiyun * overwrite the prompt an inconveinient moments. So
1477*4882a593Smuzhiyun * don't do that. */
1478*4882a593Smuzhiyun if (pi->stopped_progs == pi->num_progs) {
1479*4882a593Smuzhiyun printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun #endif
1482*4882a593Smuzhiyun }
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun if (childpid == -1 && errno != ECHILD)
1486*4882a593Smuzhiyun perror_msg("waitpid");
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun /* move the shell to the foreground */
1489*4882a593Smuzhiyun /*if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) */
1490*4882a593Smuzhiyun /* perror_msg("tcsetpgrp-2"); */
1491*4882a593Smuzhiyun return -1;
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun /* Figure out our controlling tty, checking in order stderr,
1495*4882a593Smuzhiyun * stdin, and stdout. If check_pgrp is set, also check that
1496*4882a593Smuzhiyun * we belong to the foreground process group associated with
1497*4882a593Smuzhiyun * that tty. The value of shell_terminal is needed in order to call
1498*4882a593Smuzhiyun * tcsetpgrp(shell_terminal, ...); */
1499*4882a593Smuzhiyun void controlling_tty(int check_pgrp)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun pid_t curpgrp;
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
1504*4882a593Smuzhiyun && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
1505*4882a593Smuzhiyun && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
1506*4882a593Smuzhiyun goto shell_terminal_error;
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if (check_pgrp && curpgrp != getpgid(0))
1509*4882a593Smuzhiyun goto shell_terminal_error;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun return;
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun shell_terminal_error:
1514*4882a593Smuzhiyun shell_terminal = -1;
1515*4882a593Smuzhiyun return;
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun #endif
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun /* run_pipe_real() starts all the jobs, but doesn't wait for anything
1520*4882a593Smuzhiyun * to finish. See checkjobs().
1521*4882a593Smuzhiyun *
1522*4882a593Smuzhiyun * return code is normally -1, when the caller has to wait for children
1523*4882a593Smuzhiyun * to finish to determine the exit status of the pipe. If the pipe
1524*4882a593Smuzhiyun * is a simple builtin command, however, the action is done by the
1525*4882a593Smuzhiyun * time run_pipe_real returns, and the exit code is provided as the
1526*4882a593Smuzhiyun * return value.
1527*4882a593Smuzhiyun *
1528*4882a593Smuzhiyun * The input of the pipe is always stdin, the output is always
1529*4882a593Smuzhiyun * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
1530*4882a593Smuzhiyun * because it tries to avoid running the command substitution in
1531*4882a593Smuzhiyun * subshell, when that is in fact necessary. The subshell process
1532*4882a593Smuzhiyun * now has its stdout directed to the input of the appropriate pipe,
1533*4882a593Smuzhiyun * so this routine is noticeably simpler.
1534*4882a593Smuzhiyun */
1535*4882a593Smuzhiyun static int run_pipe_real(struct pipe *pi)
1536*4882a593Smuzhiyun {
1537*4882a593Smuzhiyun int i;
1538*4882a593Smuzhiyun #ifndef __U_BOOT__
1539*4882a593Smuzhiyun int nextin, nextout;
1540*4882a593Smuzhiyun int pipefds[2]; /* pipefds[0] is for reading */
1541*4882a593Smuzhiyun struct child_prog *child;
1542*4882a593Smuzhiyun struct built_in_command *x;
1543*4882a593Smuzhiyun char *p;
1544*4882a593Smuzhiyun # if __GNUC__
1545*4882a593Smuzhiyun /* Avoid longjmp clobbering */
1546*4882a593Smuzhiyun (void) &i;
1547*4882a593Smuzhiyun (void) &nextin;
1548*4882a593Smuzhiyun (void) &nextout;
1549*4882a593Smuzhiyun (void) &child;
1550*4882a593Smuzhiyun # endif
1551*4882a593Smuzhiyun #else
1552*4882a593Smuzhiyun int nextin;
1553*4882a593Smuzhiyun int flag = do_repeat ? CMD_FLAG_REPEAT : 0;
1554*4882a593Smuzhiyun struct child_prog *child;
1555*4882a593Smuzhiyun char *p;
1556*4882a593Smuzhiyun # if __GNUC__
1557*4882a593Smuzhiyun /* Avoid longjmp clobbering */
1558*4882a593Smuzhiyun (void) &i;
1559*4882a593Smuzhiyun (void) &nextin;
1560*4882a593Smuzhiyun (void) &child;
1561*4882a593Smuzhiyun # endif
1562*4882a593Smuzhiyun #endif /* __U_BOOT__ */
1563*4882a593Smuzhiyun
1564*4882a593Smuzhiyun nextin = 0;
1565*4882a593Smuzhiyun #ifndef __U_BOOT__
1566*4882a593Smuzhiyun pi->pgrp = -1;
1567*4882a593Smuzhiyun #endif
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun /* Check if this is a simple builtin (not part of a pipe).
1570*4882a593Smuzhiyun * Builtins within pipes have to fork anyway, and are handled in
1571*4882a593Smuzhiyun * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
1572*4882a593Smuzhiyun */
1573*4882a593Smuzhiyun if (pi->num_progs == 1) child = & (pi->progs[0]);
1574*4882a593Smuzhiyun #ifndef __U_BOOT__
1575*4882a593Smuzhiyun if (pi->num_progs == 1 && child->group && child->subshell == 0) {
1576*4882a593Smuzhiyun int squirrel[] = {-1, -1, -1};
1577*4882a593Smuzhiyun int rcode;
1578*4882a593Smuzhiyun debug_printf("non-subshell grouping\n");
1579*4882a593Smuzhiyun setup_redirects(child, squirrel);
1580*4882a593Smuzhiyun /* XXX could we merge code with following builtin case,
1581*4882a593Smuzhiyun * by creating a pseudo builtin that calls run_list_real? */
1582*4882a593Smuzhiyun rcode = run_list_real(child->group);
1583*4882a593Smuzhiyun restore_redirects(squirrel);
1584*4882a593Smuzhiyun #else
1585*4882a593Smuzhiyun if (pi->num_progs == 1 && child->group) {
1586*4882a593Smuzhiyun int rcode;
1587*4882a593Smuzhiyun debug_printf("non-subshell grouping\n");
1588*4882a593Smuzhiyun rcode = run_list_real(child->group);
1589*4882a593Smuzhiyun #endif
1590*4882a593Smuzhiyun return rcode;
1591*4882a593Smuzhiyun } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
1592*4882a593Smuzhiyun for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
1593*4882a593Smuzhiyun if (i!=0 && child->argv[i]==NULL) {
1594*4882a593Smuzhiyun /* assignments, but no command: set the local environment */
1595*4882a593Smuzhiyun for (i=0; child->argv[i]!=NULL; i++) {
1596*4882a593Smuzhiyun
1597*4882a593Smuzhiyun /* Ok, this case is tricky. We have to decide if this is a
1598*4882a593Smuzhiyun * local variable, or an already exported variable. If it is
1599*4882a593Smuzhiyun * already exported, we have to export the new value. If it is
1600*4882a593Smuzhiyun * not exported, we need only set this as a local variable.
1601*4882a593Smuzhiyun * This junk is all to decide whether or not to export this
1602*4882a593Smuzhiyun * variable. */
1603*4882a593Smuzhiyun int export_me=0;
1604*4882a593Smuzhiyun char *name, *value;
1605*4882a593Smuzhiyun name = xstrdup(child->argv[i]);
1606*4882a593Smuzhiyun debug_printf("Local environment set: %s\n", name);
1607*4882a593Smuzhiyun value = strchr(name, '=');
1608*4882a593Smuzhiyun if (value)
1609*4882a593Smuzhiyun *value=0;
1610*4882a593Smuzhiyun #ifndef __U_BOOT__
1611*4882a593Smuzhiyun if ( get_local_var(name)) {
1612*4882a593Smuzhiyun export_me=1;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun #endif
1615*4882a593Smuzhiyun free(name);
1616*4882a593Smuzhiyun p = insert_var_value(child->argv[i]);
1617*4882a593Smuzhiyun set_local_var(p, export_me);
1618*4882a593Smuzhiyun if (p != child->argv[i]) free(p);
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun for (i = 0; is_assignment(child->argv[i]); i++) {
1623*4882a593Smuzhiyun p = insert_var_value(child->argv[i]);
1624*4882a593Smuzhiyun #ifndef __U_BOOT__
1625*4882a593Smuzhiyun putenv(strdup(p));
1626*4882a593Smuzhiyun #else
1627*4882a593Smuzhiyun set_local_var(p, 0);
1628*4882a593Smuzhiyun #endif
1629*4882a593Smuzhiyun if (p != child->argv[i]) {
1630*4882a593Smuzhiyun child->sp--;
1631*4882a593Smuzhiyun free(p);
1632*4882a593Smuzhiyun }
1633*4882a593Smuzhiyun }
1634*4882a593Smuzhiyun if (child->sp) {
1635*4882a593Smuzhiyun char * str = NULL;
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun str = make_string(child->argv + i,
1638*4882a593Smuzhiyun child->argv_nonnull + i);
1639*4882a593Smuzhiyun parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
1640*4882a593Smuzhiyun free(str);
1641*4882a593Smuzhiyun return last_return_code;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun #ifndef __U_BOOT__
1644*4882a593Smuzhiyun for (x = bltins; x->cmd; x++) {
1645*4882a593Smuzhiyun if (strcmp(child->argv[i], x->cmd) == 0 ) {
1646*4882a593Smuzhiyun int squirrel[] = {-1, -1, -1};
1647*4882a593Smuzhiyun int rcode;
1648*4882a593Smuzhiyun if (x->function == builtin_exec && child->argv[i+1]==NULL) {
1649*4882a593Smuzhiyun debug_printf("magic exec\n");
1650*4882a593Smuzhiyun setup_redirects(child,NULL);
1651*4882a593Smuzhiyun return EXIT_SUCCESS;
1652*4882a593Smuzhiyun }
1653*4882a593Smuzhiyun debug_printf("builtin inline %s\n", child->argv[0]);
1654*4882a593Smuzhiyun /* XXX setup_redirects acts on file descriptors, not FILEs.
1655*4882a593Smuzhiyun * This is perfect for work that comes after exec().
1656*4882a593Smuzhiyun * Is it really safe for inline use? Experimentally,
1657*4882a593Smuzhiyun * things seem to work with glibc. */
1658*4882a593Smuzhiyun setup_redirects(child, squirrel);
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun child->argv += i; /* XXX horrible hack */
1661*4882a593Smuzhiyun rcode = x->function(child);
1662*4882a593Smuzhiyun /* XXX restore hack so free() can work right */
1663*4882a593Smuzhiyun child->argv -= i;
1664*4882a593Smuzhiyun restore_redirects(squirrel);
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun return rcode;
1667*4882a593Smuzhiyun }
1668*4882a593Smuzhiyun #else
1669*4882a593Smuzhiyun /* check ";", because ,example , argv consist from
1670*4882a593Smuzhiyun * "help;flinfo" must not execute
1671*4882a593Smuzhiyun */
1672*4882a593Smuzhiyun if (strchr(child->argv[i], ';')) {
1673*4882a593Smuzhiyun printf("Unknown command '%s' - try 'help' or use "
1674*4882a593Smuzhiyun "'run' command\n", child->argv[i]);
1675*4882a593Smuzhiyun return -1;
1676*4882a593Smuzhiyun }
1677*4882a593Smuzhiyun /* Process the command */
1678*4882a593Smuzhiyun return cmd_process(flag, child->argc, child->argv,
1679*4882a593Smuzhiyun &flag_repeat, NULL);
1680*4882a593Smuzhiyun #endif
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun #ifndef __U_BOOT__
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun for (i = 0; i < pi->num_progs; i++) {
1685*4882a593Smuzhiyun child = & (pi->progs[i]);
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun /* pipes are inserted between pairs of commands */
1688*4882a593Smuzhiyun if ((i + 1) < pi->num_progs) {
1689*4882a593Smuzhiyun if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1690*4882a593Smuzhiyun nextout = pipefds[1];
1691*4882a593Smuzhiyun } else {
1692*4882a593Smuzhiyun nextout=1;
1693*4882a593Smuzhiyun pipefds[0] = -1;
1694*4882a593Smuzhiyun }
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun /* XXX test for failed fork()? */
1697*4882a593Smuzhiyun if (!(child->pid = fork())) {
1698*4882a593Smuzhiyun /* Set the handling for job control signals back to the default. */
1699*4882a593Smuzhiyun signal(SIGINT, SIG_DFL);
1700*4882a593Smuzhiyun signal(SIGQUIT, SIG_DFL);
1701*4882a593Smuzhiyun signal(SIGTERM, SIG_DFL);
1702*4882a593Smuzhiyun signal(SIGTSTP, SIG_DFL);
1703*4882a593Smuzhiyun signal(SIGTTIN, SIG_DFL);
1704*4882a593Smuzhiyun signal(SIGTTOU, SIG_DFL);
1705*4882a593Smuzhiyun signal(SIGCHLD, SIG_DFL);
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun close_all();
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun if (nextin != 0) {
1710*4882a593Smuzhiyun dup2(nextin, 0);
1711*4882a593Smuzhiyun close(nextin);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun if (nextout != 1) {
1714*4882a593Smuzhiyun dup2(nextout, 1);
1715*4882a593Smuzhiyun close(nextout);
1716*4882a593Smuzhiyun }
1717*4882a593Smuzhiyun if (pipefds[0]!=-1) {
1718*4882a593Smuzhiyun close(pipefds[0]); /* opposite end of our output pipe */
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun /* Like bash, explicit redirects override pipes,
1722*4882a593Smuzhiyun * and the pipe fd is available for dup'ing. */
1723*4882a593Smuzhiyun setup_redirects(child,NULL);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun if (interactive && pi->followup!=PIPE_BG) {
1726*4882a593Smuzhiyun /* If we (the child) win the race, put ourselves in the process
1727*4882a593Smuzhiyun * group whose leader is the first process in this pipe. */
1728*4882a593Smuzhiyun if (pi->pgrp < 0) {
1729*4882a593Smuzhiyun pi->pgrp = getpid();
1730*4882a593Smuzhiyun }
1731*4882a593Smuzhiyun if (setpgid(0, pi->pgrp) == 0) {
1732*4882a593Smuzhiyun tcsetpgrp(2, pi->pgrp);
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun }
1735*4882a593Smuzhiyun
1736*4882a593Smuzhiyun pseudo_exec(child);
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun /* put our child in the process group whose leader is the
1741*4882a593Smuzhiyun first process in this pipe */
1742*4882a593Smuzhiyun if (pi->pgrp < 0) {
1743*4882a593Smuzhiyun pi->pgrp = child->pid;
1744*4882a593Smuzhiyun }
1745*4882a593Smuzhiyun /* Don't check for errors. The child may be dead already,
1746*4882a593Smuzhiyun * in which case setpgid returns error code EACCES. */
1747*4882a593Smuzhiyun setpgid(child->pid, pi->pgrp);
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun if (nextin != 0)
1750*4882a593Smuzhiyun close(nextin);
1751*4882a593Smuzhiyun if (nextout != 1)
1752*4882a593Smuzhiyun close(nextout);
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun /* If there isn't another process, nextin is garbage
1755*4882a593Smuzhiyun but it doesn't matter */
1756*4882a593Smuzhiyun nextin = pipefds[0];
1757*4882a593Smuzhiyun }
1758*4882a593Smuzhiyun #endif
1759*4882a593Smuzhiyun return -1;
1760*4882a593Smuzhiyun }
1761*4882a593Smuzhiyun
1762*4882a593Smuzhiyun static int run_list_real(struct pipe *pi)
1763*4882a593Smuzhiyun {
1764*4882a593Smuzhiyun char *save_name = NULL;
1765*4882a593Smuzhiyun char **list = NULL;
1766*4882a593Smuzhiyun char **save_list = NULL;
1767*4882a593Smuzhiyun struct pipe *rpipe;
1768*4882a593Smuzhiyun int flag_rep = 0;
1769*4882a593Smuzhiyun #ifndef __U_BOOT__
1770*4882a593Smuzhiyun int save_num_progs;
1771*4882a593Smuzhiyun #endif
1772*4882a593Smuzhiyun int rcode=0, flag_skip=1;
1773*4882a593Smuzhiyun int flag_restore = 0;
1774*4882a593Smuzhiyun int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
1775*4882a593Smuzhiyun reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
1776*4882a593Smuzhiyun /* check syntax for "for" */
1777*4882a593Smuzhiyun for (rpipe = pi; rpipe; rpipe = rpipe->next) {
1778*4882a593Smuzhiyun if ((rpipe->r_mode == RES_IN ||
1779*4882a593Smuzhiyun rpipe->r_mode == RES_FOR) &&
1780*4882a593Smuzhiyun (rpipe->next == NULL)) {
1781*4882a593Smuzhiyun syntax();
1782*4882a593Smuzhiyun #ifdef __U_BOOT__
1783*4882a593Smuzhiyun flag_repeat = 0;
1784*4882a593Smuzhiyun #endif
1785*4882a593Smuzhiyun return 1;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun if ((rpipe->r_mode == RES_IN &&
1788*4882a593Smuzhiyun (rpipe->next->r_mode == RES_IN &&
1789*4882a593Smuzhiyun rpipe->next->progs->argv != NULL))||
1790*4882a593Smuzhiyun (rpipe->r_mode == RES_FOR &&
1791*4882a593Smuzhiyun rpipe->next->r_mode != RES_IN)) {
1792*4882a593Smuzhiyun syntax();
1793*4882a593Smuzhiyun #ifdef __U_BOOT__
1794*4882a593Smuzhiyun flag_repeat = 0;
1795*4882a593Smuzhiyun #endif
1796*4882a593Smuzhiyun return 1;
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun }
1799*4882a593Smuzhiyun for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
1800*4882a593Smuzhiyun if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
1801*4882a593Smuzhiyun pi->r_mode == RES_FOR) {
1802*4882a593Smuzhiyun #ifdef __U_BOOT__
1803*4882a593Smuzhiyun /* check Ctrl-C */
1804*4882a593Smuzhiyun ctrlc();
1805*4882a593Smuzhiyun if ((had_ctrlc())) {
1806*4882a593Smuzhiyun return 1;
1807*4882a593Smuzhiyun }
1808*4882a593Smuzhiyun #endif
1809*4882a593Smuzhiyun flag_restore = 0;
1810*4882a593Smuzhiyun if (!rpipe) {
1811*4882a593Smuzhiyun flag_rep = 0;
1812*4882a593Smuzhiyun rpipe = pi;
1813*4882a593Smuzhiyun }
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun rmode = pi->r_mode;
1816*4882a593Smuzhiyun debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
1817*4882a593Smuzhiyun if (rmode == skip_more_in_this_rmode && flag_skip) {
1818*4882a593Smuzhiyun if (pi->followup == PIPE_SEQ) flag_skip=0;
1819*4882a593Smuzhiyun continue;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun flag_skip = 1;
1822*4882a593Smuzhiyun skip_more_in_this_rmode = RES_XXXX;
1823*4882a593Smuzhiyun if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
1824*4882a593Smuzhiyun if (rmode == RES_THEN && if_code) continue;
1825*4882a593Smuzhiyun if (rmode == RES_ELSE && !if_code) continue;
1826*4882a593Smuzhiyun if (rmode == RES_ELIF && !if_code) break;
1827*4882a593Smuzhiyun if (rmode == RES_FOR && pi->num_progs) {
1828*4882a593Smuzhiyun if (!list) {
1829*4882a593Smuzhiyun /* if no variable values after "in" we skip "for" */
1830*4882a593Smuzhiyun if (!pi->next->progs->argv) continue;
1831*4882a593Smuzhiyun /* create list of variable values */
1832*4882a593Smuzhiyun list = make_list_in(pi->next->progs->argv,
1833*4882a593Smuzhiyun pi->progs->argv[0]);
1834*4882a593Smuzhiyun save_list = list;
1835*4882a593Smuzhiyun save_name = pi->progs->argv[0];
1836*4882a593Smuzhiyun pi->progs->argv[0] = NULL;
1837*4882a593Smuzhiyun flag_rep = 1;
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun if (!(*list)) {
1840*4882a593Smuzhiyun free(pi->progs->argv[0]);
1841*4882a593Smuzhiyun free(save_list);
1842*4882a593Smuzhiyun list = NULL;
1843*4882a593Smuzhiyun flag_rep = 0;
1844*4882a593Smuzhiyun pi->progs->argv[0] = save_name;
1845*4882a593Smuzhiyun #ifndef __U_BOOT__
1846*4882a593Smuzhiyun pi->progs->glob_result.gl_pathv[0] =
1847*4882a593Smuzhiyun pi->progs->argv[0];
1848*4882a593Smuzhiyun #endif
1849*4882a593Smuzhiyun continue;
1850*4882a593Smuzhiyun } else {
1851*4882a593Smuzhiyun /* insert new value from list for variable */
1852*4882a593Smuzhiyun if (pi->progs->argv[0])
1853*4882a593Smuzhiyun free(pi->progs->argv[0]);
1854*4882a593Smuzhiyun pi->progs->argv[0] = *list++;
1855*4882a593Smuzhiyun #ifndef __U_BOOT__
1856*4882a593Smuzhiyun pi->progs->glob_result.gl_pathv[0] =
1857*4882a593Smuzhiyun pi->progs->argv[0];
1858*4882a593Smuzhiyun #endif
1859*4882a593Smuzhiyun }
1860*4882a593Smuzhiyun }
1861*4882a593Smuzhiyun if (rmode == RES_IN) continue;
1862*4882a593Smuzhiyun if (rmode == RES_DO) {
1863*4882a593Smuzhiyun if (!flag_rep) continue;
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun if (rmode == RES_DONE) {
1866*4882a593Smuzhiyun if (flag_rep) {
1867*4882a593Smuzhiyun flag_restore = 1;
1868*4882a593Smuzhiyun } else {
1869*4882a593Smuzhiyun rpipe = NULL;
1870*4882a593Smuzhiyun }
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun if (pi->num_progs == 0) continue;
1873*4882a593Smuzhiyun #ifndef __U_BOOT__
1874*4882a593Smuzhiyun save_num_progs = pi->num_progs; /* save number of programs */
1875*4882a593Smuzhiyun #endif
1876*4882a593Smuzhiyun rcode = run_pipe_real(pi);
1877*4882a593Smuzhiyun debug_printf("run_pipe_real returned %d\n",rcode);
1878*4882a593Smuzhiyun #ifndef __U_BOOT__
1879*4882a593Smuzhiyun if (rcode!=-1) {
1880*4882a593Smuzhiyun /* We only ran a builtin: rcode was set by the return value
1881*4882a593Smuzhiyun * of run_pipe_real(), and we don't need to wait for anything. */
1882*4882a593Smuzhiyun } else if (pi->followup==PIPE_BG) {
1883*4882a593Smuzhiyun /* XXX check bash's behavior with nontrivial pipes */
1884*4882a593Smuzhiyun /* XXX compute jobid */
1885*4882a593Smuzhiyun /* XXX what does bash do with attempts to background builtins? */
1886*4882a593Smuzhiyun insert_bg_job(pi);
1887*4882a593Smuzhiyun rcode = EXIT_SUCCESS;
1888*4882a593Smuzhiyun } else {
1889*4882a593Smuzhiyun if (interactive) {
1890*4882a593Smuzhiyun /* move the new process group into the foreground */
1891*4882a593Smuzhiyun if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
1892*4882a593Smuzhiyun perror_msg("tcsetpgrp-3");
1893*4882a593Smuzhiyun rcode = checkjobs(pi);
1894*4882a593Smuzhiyun /* move the shell to the foreground */
1895*4882a593Smuzhiyun if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
1896*4882a593Smuzhiyun perror_msg("tcsetpgrp-4");
1897*4882a593Smuzhiyun } else {
1898*4882a593Smuzhiyun rcode = checkjobs(pi);
1899*4882a593Smuzhiyun }
1900*4882a593Smuzhiyun debug_printf("checkjobs returned %d\n",rcode);
1901*4882a593Smuzhiyun }
1902*4882a593Smuzhiyun last_return_code=rcode;
1903*4882a593Smuzhiyun #else
1904*4882a593Smuzhiyun if (rcode < -1) {
1905*4882a593Smuzhiyun last_return_code = -rcode - 2;
1906*4882a593Smuzhiyun return -2; /* exit */
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun last_return_code=(rcode == 0) ? 0 : 1;
1909*4882a593Smuzhiyun #endif
1910*4882a593Smuzhiyun #ifndef __U_BOOT__
1911*4882a593Smuzhiyun pi->num_progs = save_num_progs; /* restore number of programs */
1912*4882a593Smuzhiyun #endif
1913*4882a593Smuzhiyun if ( rmode == RES_IF || rmode == RES_ELIF )
1914*4882a593Smuzhiyun next_if_code=rcode; /* can be overwritten a number of times */
1915*4882a593Smuzhiyun if (rmode == RES_WHILE)
1916*4882a593Smuzhiyun flag_rep = !last_return_code;
1917*4882a593Smuzhiyun if (rmode == RES_UNTIL)
1918*4882a593Smuzhiyun flag_rep = last_return_code;
1919*4882a593Smuzhiyun if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
1920*4882a593Smuzhiyun (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
1921*4882a593Smuzhiyun skip_more_in_this_rmode=rmode;
1922*4882a593Smuzhiyun #ifndef __U_BOOT__
1923*4882a593Smuzhiyun checkjobs(NULL);
1924*4882a593Smuzhiyun #endif
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun return rcode;
1927*4882a593Smuzhiyun }
1928*4882a593Smuzhiyun
1929*4882a593Smuzhiyun /* broken, of course, but OK for testing */
1930*4882a593Smuzhiyun static char *indenter(int i)
1931*4882a593Smuzhiyun {
1932*4882a593Smuzhiyun static char blanks[]=" ";
1933*4882a593Smuzhiyun return &blanks[sizeof(blanks)-i-1];
1934*4882a593Smuzhiyun }
1935*4882a593Smuzhiyun
1936*4882a593Smuzhiyun /* return code is the exit status of the pipe */
1937*4882a593Smuzhiyun static int free_pipe(struct pipe *pi, int indent)
1938*4882a593Smuzhiyun {
1939*4882a593Smuzhiyun char **p;
1940*4882a593Smuzhiyun struct child_prog *child;
1941*4882a593Smuzhiyun #ifndef __U_BOOT__
1942*4882a593Smuzhiyun struct redir_struct *r, *rnext;
1943*4882a593Smuzhiyun #endif
1944*4882a593Smuzhiyun int a, i, ret_code=0;
1945*4882a593Smuzhiyun char *ind = indenter(indent);
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun #ifndef __U_BOOT__
1948*4882a593Smuzhiyun if (pi->stopped_progs > 0)
1949*4882a593Smuzhiyun return ret_code;
1950*4882a593Smuzhiyun final_printf("%s run pipe: (pid %d)\n",ind,getpid());
1951*4882a593Smuzhiyun #endif
1952*4882a593Smuzhiyun for (i=0; i<pi->num_progs; i++) {
1953*4882a593Smuzhiyun child = &pi->progs[i];
1954*4882a593Smuzhiyun final_printf("%s command %d:\n",ind,i);
1955*4882a593Smuzhiyun if (child->argv) {
1956*4882a593Smuzhiyun for (a=0,p=child->argv; *p; a++,p++) {
1957*4882a593Smuzhiyun final_printf("%s argv[%d] = %s\n",ind,a,*p);
1958*4882a593Smuzhiyun }
1959*4882a593Smuzhiyun #ifndef __U_BOOT__
1960*4882a593Smuzhiyun globfree(&child->glob_result);
1961*4882a593Smuzhiyun #else
1962*4882a593Smuzhiyun for (a = 0; a < child->argc; a++) {
1963*4882a593Smuzhiyun free(child->argv[a]);
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun free(child->argv);
1966*4882a593Smuzhiyun free(child->argv_nonnull);
1967*4882a593Smuzhiyun child->argc = 0;
1968*4882a593Smuzhiyun #endif
1969*4882a593Smuzhiyun child->argv=NULL;
1970*4882a593Smuzhiyun } else if (child->group) {
1971*4882a593Smuzhiyun #ifndef __U_BOOT__
1972*4882a593Smuzhiyun final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
1973*4882a593Smuzhiyun #endif
1974*4882a593Smuzhiyun ret_code = free_pipe_list(child->group,indent+3);
1975*4882a593Smuzhiyun final_printf("%s end group\n",ind);
1976*4882a593Smuzhiyun } else {
1977*4882a593Smuzhiyun final_printf("%s (nil)\n",ind);
1978*4882a593Smuzhiyun }
1979*4882a593Smuzhiyun #ifndef __U_BOOT__
1980*4882a593Smuzhiyun for (r=child->redirects; r; r=rnext) {
1981*4882a593Smuzhiyun final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
1982*4882a593Smuzhiyun if (r->dup == -1) {
1983*4882a593Smuzhiyun /* guard against the case >$FOO, where foo is unset or blank */
1984*4882a593Smuzhiyun if (r->word.gl_pathv) {
1985*4882a593Smuzhiyun final_printf(" %s\n", *r->word.gl_pathv);
1986*4882a593Smuzhiyun globfree(&r->word);
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun } else {
1989*4882a593Smuzhiyun final_printf("&%d\n", r->dup);
1990*4882a593Smuzhiyun }
1991*4882a593Smuzhiyun rnext=r->next;
1992*4882a593Smuzhiyun free(r);
1993*4882a593Smuzhiyun }
1994*4882a593Smuzhiyun child->redirects=NULL;
1995*4882a593Smuzhiyun #endif
1996*4882a593Smuzhiyun }
1997*4882a593Smuzhiyun free(pi->progs); /* children are an array, they get freed all at once */
1998*4882a593Smuzhiyun pi->progs=NULL;
1999*4882a593Smuzhiyun return ret_code;
2000*4882a593Smuzhiyun }
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun static int free_pipe_list(struct pipe *head, int indent)
2003*4882a593Smuzhiyun {
2004*4882a593Smuzhiyun int rcode=0; /* if list has no members */
2005*4882a593Smuzhiyun struct pipe *pi, *next;
2006*4882a593Smuzhiyun char *ind = indenter(indent);
2007*4882a593Smuzhiyun for (pi=head; pi; pi=next) {
2008*4882a593Smuzhiyun final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
2009*4882a593Smuzhiyun rcode = free_pipe(pi, indent);
2010*4882a593Smuzhiyun final_printf("%s pipe followup code %d\n", ind, pi->followup);
2011*4882a593Smuzhiyun next=pi->next;
2012*4882a593Smuzhiyun pi->next=NULL;
2013*4882a593Smuzhiyun free(pi);
2014*4882a593Smuzhiyun }
2015*4882a593Smuzhiyun return rcode;
2016*4882a593Smuzhiyun }
2017*4882a593Smuzhiyun
2018*4882a593Smuzhiyun /* Select which version we will use */
2019*4882a593Smuzhiyun static int run_list(struct pipe *pi)
2020*4882a593Smuzhiyun {
2021*4882a593Smuzhiyun int rcode=0;
2022*4882a593Smuzhiyun #ifndef __U_BOOT__
2023*4882a593Smuzhiyun if (fake_mode==0) {
2024*4882a593Smuzhiyun #endif
2025*4882a593Smuzhiyun rcode = run_list_real(pi);
2026*4882a593Smuzhiyun #ifndef __U_BOOT__
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun #endif
2029*4882a593Smuzhiyun /* free_pipe_list has the side effect of clearing memory
2030*4882a593Smuzhiyun * In the long run that function can be merged with run_list_real,
2031*4882a593Smuzhiyun * but doing that now would hobble the debugging effort. */
2032*4882a593Smuzhiyun free_pipe_list(pi,0);
2033*4882a593Smuzhiyun return rcode;
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun
2036*4882a593Smuzhiyun /* The API for glob is arguably broken. This routine pushes a non-matching
2037*4882a593Smuzhiyun * string into the output structure, removing non-backslashed backslashes.
2038*4882a593Smuzhiyun * If someone can prove me wrong, by performing this function within the
2039*4882a593Smuzhiyun * original glob(3) api, feel free to rewrite this routine into oblivion.
2040*4882a593Smuzhiyun * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
2041*4882a593Smuzhiyun * XXX broken if the last character is '\\', check that before calling.
2042*4882a593Smuzhiyun */
2043*4882a593Smuzhiyun #ifndef __U_BOOT__
2044*4882a593Smuzhiyun static int globhack(const char *src, int flags, glob_t *pglob)
2045*4882a593Smuzhiyun {
2046*4882a593Smuzhiyun int cnt=0, pathc;
2047*4882a593Smuzhiyun const char *s;
2048*4882a593Smuzhiyun char *dest;
2049*4882a593Smuzhiyun for (cnt=1, s=src; s && *s; s++) {
2050*4882a593Smuzhiyun if (*s == '\\') s++;
2051*4882a593Smuzhiyun cnt++;
2052*4882a593Smuzhiyun }
2053*4882a593Smuzhiyun dest = malloc(cnt);
2054*4882a593Smuzhiyun if (!dest) return GLOB_NOSPACE;
2055*4882a593Smuzhiyun if (!(flags & GLOB_APPEND)) {
2056*4882a593Smuzhiyun pglob->gl_pathv=NULL;
2057*4882a593Smuzhiyun pglob->gl_pathc=0;
2058*4882a593Smuzhiyun pglob->gl_offs=0;
2059*4882a593Smuzhiyun pglob->gl_offs=0;
2060*4882a593Smuzhiyun }
2061*4882a593Smuzhiyun pathc = ++pglob->gl_pathc;
2062*4882a593Smuzhiyun pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
2063*4882a593Smuzhiyun if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
2064*4882a593Smuzhiyun pglob->gl_pathv[pathc-1]=dest;
2065*4882a593Smuzhiyun pglob->gl_pathv[pathc]=NULL;
2066*4882a593Smuzhiyun for (s=src; s && *s; s++, dest++) {
2067*4882a593Smuzhiyun if (*s == '\\') s++;
2068*4882a593Smuzhiyun *dest = *s;
2069*4882a593Smuzhiyun }
2070*4882a593Smuzhiyun *dest='\0';
2071*4882a593Smuzhiyun return 0;
2072*4882a593Smuzhiyun }
2073*4882a593Smuzhiyun
2074*4882a593Smuzhiyun /* XXX broken if the last character is '\\', check that before calling */
2075*4882a593Smuzhiyun static int glob_needed(const char *s)
2076*4882a593Smuzhiyun {
2077*4882a593Smuzhiyun for (; *s; s++) {
2078*4882a593Smuzhiyun if (*s == '\\') s++;
2079*4882a593Smuzhiyun if (strchr("*[?",*s)) return 1;
2080*4882a593Smuzhiyun }
2081*4882a593Smuzhiyun return 0;
2082*4882a593Smuzhiyun }
2083*4882a593Smuzhiyun
2084*4882a593Smuzhiyun #if 0
2085*4882a593Smuzhiyun static void globprint(glob_t *pglob)
2086*4882a593Smuzhiyun {
2087*4882a593Smuzhiyun int i;
2088*4882a593Smuzhiyun debug_printf("glob_t at %p:\n", pglob);
2089*4882a593Smuzhiyun debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",
2090*4882a593Smuzhiyun pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
2091*4882a593Smuzhiyun for (i=0; i<pglob->gl_pathc; i++)
2092*4882a593Smuzhiyun debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
2093*4882a593Smuzhiyun pglob->gl_pathv[i], pglob->gl_pathv[i]);
2094*4882a593Smuzhiyun }
2095*4882a593Smuzhiyun #endif
2096*4882a593Smuzhiyun
2097*4882a593Smuzhiyun static int xglob(o_string *dest, int flags, glob_t *pglob)
2098*4882a593Smuzhiyun {
2099*4882a593Smuzhiyun int gr;
2100*4882a593Smuzhiyun
2101*4882a593Smuzhiyun /* short-circuit for null word */
2102*4882a593Smuzhiyun /* we can code this better when the debug_printf's are gone */
2103*4882a593Smuzhiyun if (dest->length == 0) {
2104*4882a593Smuzhiyun if (dest->nonnull) {
2105*4882a593Smuzhiyun /* bash man page calls this an "explicit" null */
2106*4882a593Smuzhiyun gr = globhack(dest->data, flags, pglob);
2107*4882a593Smuzhiyun debug_printf("globhack returned %d\n",gr);
2108*4882a593Smuzhiyun } else {
2109*4882a593Smuzhiyun return 0;
2110*4882a593Smuzhiyun }
2111*4882a593Smuzhiyun } else if (glob_needed(dest->data)) {
2112*4882a593Smuzhiyun gr = glob(dest->data, flags, NULL, pglob);
2113*4882a593Smuzhiyun debug_printf("glob returned %d\n",gr);
2114*4882a593Smuzhiyun if (gr == GLOB_NOMATCH) {
2115*4882a593Smuzhiyun /* quote removal, or more accurately, backslash removal */
2116*4882a593Smuzhiyun gr = globhack(dest->data, flags, pglob);
2117*4882a593Smuzhiyun debug_printf("globhack returned %d\n",gr);
2118*4882a593Smuzhiyun }
2119*4882a593Smuzhiyun } else {
2120*4882a593Smuzhiyun gr = globhack(dest->data, flags, pglob);
2121*4882a593Smuzhiyun debug_printf("globhack returned %d\n",gr);
2122*4882a593Smuzhiyun }
2123*4882a593Smuzhiyun if (gr == GLOB_NOSPACE)
2124*4882a593Smuzhiyun error_msg_and_die("out of memory during glob");
2125*4882a593Smuzhiyun if (gr != 0) { /* GLOB_ABORTED ? */
2126*4882a593Smuzhiyun error_msg("glob(3) error %d",gr);
2127*4882a593Smuzhiyun }
2128*4882a593Smuzhiyun /* globprint(glob_target); */
2129*4882a593Smuzhiyun return gr;
2130*4882a593Smuzhiyun }
2131*4882a593Smuzhiyun #endif
2132*4882a593Smuzhiyun
2133*4882a593Smuzhiyun #ifdef __U_BOOT__
2134*4882a593Smuzhiyun static char *get_dollar_var(char ch);
2135*4882a593Smuzhiyun #endif
2136*4882a593Smuzhiyun
2137*4882a593Smuzhiyun /* This is used to get/check local shell variables */
2138*4882a593Smuzhiyun char *get_local_var(const char *s)
2139*4882a593Smuzhiyun {
2140*4882a593Smuzhiyun struct variables *cur;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun if (!s)
2143*4882a593Smuzhiyun return NULL;
2144*4882a593Smuzhiyun
2145*4882a593Smuzhiyun #ifdef __U_BOOT__
2146*4882a593Smuzhiyun if (*s == '$')
2147*4882a593Smuzhiyun return get_dollar_var(s[1]);
2148*4882a593Smuzhiyun #endif
2149*4882a593Smuzhiyun
2150*4882a593Smuzhiyun for (cur = top_vars; cur; cur=cur->next)
2151*4882a593Smuzhiyun if(strcmp(cur->name, s)==0)
2152*4882a593Smuzhiyun return cur->value;
2153*4882a593Smuzhiyun return NULL;
2154*4882a593Smuzhiyun }
2155*4882a593Smuzhiyun
2156*4882a593Smuzhiyun /* This is used to set local shell variables
2157*4882a593Smuzhiyun flg_export==0 if only local (not exporting) variable
2158*4882a593Smuzhiyun flg_export==1 if "new" exporting environ
2159*4882a593Smuzhiyun flg_export>1 if current startup environ (not call putenv()) */
2160*4882a593Smuzhiyun int set_local_var(const char *s, int flg_export)
2161*4882a593Smuzhiyun {
2162*4882a593Smuzhiyun char *name, *value;
2163*4882a593Smuzhiyun int result=0;
2164*4882a593Smuzhiyun struct variables *cur;
2165*4882a593Smuzhiyun
2166*4882a593Smuzhiyun #ifdef __U_BOOT__
2167*4882a593Smuzhiyun /* might be possible! */
2168*4882a593Smuzhiyun if (!isalpha(*s))
2169*4882a593Smuzhiyun return -1;
2170*4882a593Smuzhiyun #endif
2171*4882a593Smuzhiyun
2172*4882a593Smuzhiyun name=strdup(s);
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun #ifdef __U_BOOT__
2175*4882a593Smuzhiyun if (env_get(name) != NULL) {
2176*4882a593Smuzhiyun printf ("ERROR: "
2177*4882a593Smuzhiyun "There is a global environment variable with the same name.\n");
2178*4882a593Smuzhiyun free(name);
2179*4882a593Smuzhiyun return -1;
2180*4882a593Smuzhiyun }
2181*4882a593Smuzhiyun #endif
2182*4882a593Smuzhiyun /* Assume when we enter this function that we are already in
2183*4882a593Smuzhiyun * NAME=VALUE format. So the first order of business is to
2184*4882a593Smuzhiyun * split 's' on the '=' into 'name' and 'value' */
2185*4882a593Smuzhiyun value = strchr(name, '=');
2186*4882a593Smuzhiyun if (value == NULL || *(value + 1) == 0) {
2187*4882a593Smuzhiyun free(name);
2188*4882a593Smuzhiyun return -1;
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun *value++ = 0;
2191*4882a593Smuzhiyun
2192*4882a593Smuzhiyun for(cur = top_vars; cur; cur = cur->next) {
2193*4882a593Smuzhiyun if(strcmp(cur->name, name)==0)
2194*4882a593Smuzhiyun break;
2195*4882a593Smuzhiyun }
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun if(cur) {
2198*4882a593Smuzhiyun if(strcmp(cur->value, value)==0) {
2199*4882a593Smuzhiyun if(flg_export>0 && cur->flg_export==0)
2200*4882a593Smuzhiyun cur->flg_export=flg_export;
2201*4882a593Smuzhiyun else
2202*4882a593Smuzhiyun result++;
2203*4882a593Smuzhiyun } else {
2204*4882a593Smuzhiyun if(cur->flg_read_only) {
2205*4882a593Smuzhiyun error_msg("%s: readonly variable", name);
2206*4882a593Smuzhiyun result = -1;
2207*4882a593Smuzhiyun } else {
2208*4882a593Smuzhiyun if(flg_export>0 || cur->flg_export>1)
2209*4882a593Smuzhiyun cur->flg_export=1;
2210*4882a593Smuzhiyun free(cur->value);
2211*4882a593Smuzhiyun
2212*4882a593Smuzhiyun cur->value = strdup(value);
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun }
2215*4882a593Smuzhiyun } else {
2216*4882a593Smuzhiyun cur = malloc(sizeof(struct variables));
2217*4882a593Smuzhiyun if(!cur) {
2218*4882a593Smuzhiyun result = -1;
2219*4882a593Smuzhiyun } else {
2220*4882a593Smuzhiyun cur->name = strdup(name);
2221*4882a593Smuzhiyun if (cur->name == NULL) {
2222*4882a593Smuzhiyun free(cur);
2223*4882a593Smuzhiyun result = -1;
2224*4882a593Smuzhiyun } else {
2225*4882a593Smuzhiyun struct variables *bottom = top_vars;
2226*4882a593Smuzhiyun cur->value = strdup(value);
2227*4882a593Smuzhiyun cur->next = NULL;
2228*4882a593Smuzhiyun cur->flg_export = flg_export;
2229*4882a593Smuzhiyun cur->flg_read_only = 0;
2230*4882a593Smuzhiyun while(bottom->next) bottom=bottom->next;
2231*4882a593Smuzhiyun bottom->next = cur;
2232*4882a593Smuzhiyun }
2233*4882a593Smuzhiyun }
2234*4882a593Smuzhiyun }
2235*4882a593Smuzhiyun
2236*4882a593Smuzhiyun #ifndef __U_BOOT__
2237*4882a593Smuzhiyun if(result==0 && cur->flg_export==1) {
2238*4882a593Smuzhiyun *(value-1) = '=';
2239*4882a593Smuzhiyun result = putenv(name);
2240*4882a593Smuzhiyun } else {
2241*4882a593Smuzhiyun #endif
2242*4882a593Smuzhiyun free(name);
2243*4882a593Smuzhiyun #ifndef __U_BOOT__
2244*4882a593Smuzhiyun if(result>0) /* equivalent to previous set */
2245*4882a593Smuzhiyun result = 0;
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun #endif
2248*4882a593Smuzhiyun return result;
2249*4882a593Smuzhiyun }
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun void unset_local_var(const char *name)
2252*4882a593Smuzhiyun {
2253*4882a593Smuzhiyun struct variables *cur;
2254*4882a593Smuzhiyun
2255*4882a593Smuzhiyun if (name) {
2256*4882a593Smuzhiyun for (cur = top_vars; cur; cur=cur->next) {
2257*4882a593Smuzhiyun if(strcmp(cur->name, name)==0)
2258*4882a593Smuzhiyun break;
2259*4882a593Smuzhiyun }
2260*4882a593Smuzhiyun if (cur != NULL) {
2261*4882a593Smuzhiyun struct variables *next = top_vars;
2262*4882a593Smuzhiyun if(cur->flg_read_only) {
2263*4882a593Smuzhiyun error_msg("%s: readonly variable", name);
2264*4882a593Smuzhiyun return;
2265*4882a593Smuzhiyun } else {
2266*4882a593Smuzhiyun #ifndef __U_BOOT__
2267*4882a593Smuzhiyun if(cur->flg_export)
2268*4882a593Smuzhiyun unenv_set(cur->name);
2269*4882a593Smuzhiyun #endif
2270*4882a593Smuzhiyun free(cur->name);
2271*4882a593Smuzhiyun free(cur->value);
2272*4882a593Smuzhiyun while (next->next != cur)
2273*4882a593Smuzhiyun next = next->next;
2274*4882a593Smuzhiyun next->next = cur->next;
2275*4882a593Smuzhiyun }
2276*4882a593Smuzhiyun free(cur);
2277*4882a593Smuzhiyun }
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun }
2280*4882a593Smuzhiyun
2281*4882a593Smuzhiyun static int is_assignment(const char *s)
2282*4882a593Smuzhiyun {
2283*4882a593Smuzhiyun if (s == NULL)
2284*4882a593Smuzhiyun return 0;
2285*4882a593Smuzhiyun
2286*4882a593Smuzhiyun if (!isalpha(*s)) return 0;
2287*4882a593Smuzhiyun ++s;
2288*4882a593Smuzhiyun while(isalnum(*s) || *s=='_') ++s;
2289*4882a593Smuzhiyun return *s=='=';
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun #ifndef __U_BOOT__
2293*4882a593Smuzhiyun /* the src parameter allows us to peek forward to a possible &n syntax
2294*4882a593Smuzhiyun * for file descriptor duplication, e.g., "2>&1".
2295*4882a593Smuzhiyun * Return code is 0 normally, 1 if a syntax error is detected in src.
2296*4882a593Smuzhiyun * Resource errors (in xmalloc) cause the process to exit */
2297*4882a593Smuzhiyun static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
2298*4882a593Smuzhiyun struct in_str *input)
2299*4882a593Smuzhiyun {
2300*4882a593Smuzhiyun struct child_prog *child=ctx->child;
2301*4882a593Smuzhiyun struct redir_struct *redir = child->redirects;
2302*4882a593Smuzhiyun struct redir_struct *last_redir=NULL;
2303*4882a593Smuzhiyun
2304*4882a593Smuzhiyun /* Create a new redir_struct and drop it onto the end of the linked list */
2305*4882a593Smuzhiyun while(redir) {
2306*4882a593Smuzhiyun last_redir=redir;
2307*4882a593Smuzhiyun redir=redir->next;
2308*4882a593Smuzhiyun }
2309*4882a593Smuzhiyun redir = xmalloc(sizeof(struct redir_struct));
2310*4882a593Smuzhiyun redir->next=NULL;
2311*4882a593Smuzhiyun redir->word.gl_pathv=NULL;
2312*4882a593Smuzhiyun if (last_redir) {
2313*4882a593Smuzhiyun last_redir->next=redir;
2314*4882a593Smuzhiyun } else {
2315*4882a593Smuzhiyun child->redirects=redir;
2316*4882a593Smuzhiyun }
2317*4882a593Smuzhiyun
2318*4882a593Smuzhiyun redir->type=style;
2319*4882a593Smuzhiyun redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
2320*4882a593Smuzhiyun
2321*4882a593Smuzhiyun debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun /* Check for a '2>&1' type redirect */
2324*4882a593Smuzhiyun redir->dup = redirect_dup_num(input);
2325*4882a593Smuzhiyun if (redir->dup == -2) return 1; /* syntax error */
2326*4882a593Smuzhiyun if (redir->dup != -1) {
2327*4882a593Smuzhiyun /* Erik had a check here that the file descriptor in question
2328*4882a593Smuzhiyun * is legit; I postpone that to "run time"
2329*4882a593Smuzhiyun * A "-" representation of "close me" shows up as a -3 here */
2330*4882a593Smuzhiyun debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
2331*4882a593Smuzhiyun } else {
2332*4882a593Smuzhiyun /* We do _not_ try to open the file that src points to,
2333*4882a593Smuzhiyun * since we need to return and let src be expanded first.
2334*4882a593Smuzhiyun * Set ctx->pending_redirect, so we know what to do at the
2335*4882a593Smuzhiyun * end of the next parsed word.
2336*4882a593Smuzhiyun */
2337*4882a593Smuzhiyun ctx->pending_redirect = redir;
2338*4882a593Smuzhiyun }
2339*4882a593Smuzhiyun return 0;
2340*4882a593Smuzhiyun }
2341*4882a593Smuzhiyun #endif
2342*4882a593Smuzhiyun
2343*4882a593Smuzhiyun static struct pipe *new_pipe(void)
2344*4882a593Smuzhiyun {
2345*4882a593Smuzhiyun struct pipe *pi;
2346*4882a593Smuzhiyun pi = xmalloc(sizeof(struct pipe));
2347*4882a593Smuzhiyun pi->num_progs = 0;
2348*4882a593Smuzhiyun pi->progs = NULL;
2349*4882a593Smuzhiyun pi->next = NULL;
2350*4882a593Smuzhiyun pi->followup = 0; /* invalid */
2351*4882a593Smuzhiyun pi->r_mode = RES_NONE;
2352*4882a593Smuzhiyun return pi;
2353*4882a593Smuzhiyun }
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun static void initialize_context(struct p_context *ctx)
2356*4882a593Smuzhiyun {
2357*4882a593Smuzhiyun ctx->pipe=NULL;
2358*4882a593Smuzhiyun #ifndef __U_BOOT__
2359*4882a593Smuzhiyun ctx->pending_redirect=NULL;
2360*4882a593Smuzhiyun #endif
2361*4882a593Smuzhiyun ctx->child=NULL;
2362*4882a593Smuzhiyun ctx->list_head=new_pipe();
2363*4882a593Smuzhiyun ctx->pipe=ctx->list_head;
2364*4882a593Smuzhiyun ctx->w=RES_NONE;
2365*4882a593Smuzhiyun ctx->stack=NULL;
2366*4882a593Smuzhiyun #ifdef __U_BOOT__
2367*4882a593Smuzhiyun ctx->old_flag=0;
2368*4882a593Smuzhiyun #endif
2369*4882a593Smuzhiyun done_command(ctx); /* creates the memory for working child */
2370*4882a593Smuzhiyun }
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun /* normal return is 0
2373*4882a593Smuzhiyun * if a reserved word is found, and processed, return 1
2374*4882a593Smuzhiyun * should handle if, then, elif, else, fi, for, while, until, do, done.
2375*4882a593Smuzhiyun * case, function, and select are obnoxious, save those for later.
2376*4882a593Smuzhiyun */
2377*4882a593Smuzhiyun struct reserved_combo {
2378*4882a593Smuzhiyun char *literal;
2379*4882a593Smuzhiyun int code;
2380*4882a593Smuzhiyun long flag;
2381*4882a593Smuzhiyun };
2382*4882a593Smuzhiyun /* Mostly a list of accepted follow-up reserved words.
2383*4882a593Smuzhiyun * FLAG_END means we are done with the sequence, and are ready
2384*4882a593Smuzhiyun * to turn the compound list into a command.
2385*4882a593Smuzhiyun * FLAG_START means the word must start a new compound list.
2386*4882a593Smuzhiyun */
2387*4882a593Smuzhiyun static struct reserved_combo reserved_list[] = {
2388*4882a593Smuzhiyun { "if", RES_IF, FLAG_THEN | FLAG_START },
2389*4882a593Smuzhiyun { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
2390*4882a593Smuzhiyun { "elif", RES_ELIF, FLAG_THEN },
2391*4882a593Smuzhiyun { "else", RES_ELSE, FLAG_FI },
2392*4882a593Smuzhiyun { "fi", RES_FI, FLAG_END },
2393*4882a593Smuzhiyun { "for", RES_FOR, FLAG_IN | FLAG_START },
2394*4882a593Smuzhiyun { "while", RES_WHILE, FLAG_DO | FLAG_START },
2395*4882a593Smuzhiyun { "until", RES_UNTIL, FLAG_DO | FLAG_START },
2396*4882a593Smuzhiyun { "in", RES_IN, FLAG_DO },
2397*4882a593Smuzhiyun { "do", RES_DO, FLAG_DONE },
2398*4882a593Smuzhiyun { "done", RES_DONE, FLAG_END }
2399*4882a593Smuzhiyun };
2400*4882a593Smuzhiyun #define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo))
2401*4882a593Smuzhiyun
2402*4882a593Smuzhiyun static int reserved_word(o_string *dest, struct p_context *ctx)
2403*4882a593Smuzhiyun {
2404*4882a593Smuzhiyun struct reserved_combo *r;
2405*4882a593Smuzhiyun for (r=reserved_list;
2406*4882a593Smuzhiyun r<reserved_list+NRES; r++) {
2407*4882a593Smuzhiyun if (strcmp(dest->data, r->literal) == 0) {
2408*4882a593Smuzhiyun debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
2409*4882a593Smuzhiyun if (r->flag & FLAG_START) {
2410*4882a593Smuzhiyun struct p_context *new = xmalloc(sizeof(struct p_context));
2411*4882a593Smuzhiyun debug_printf("push stack\n");
2412*4882a593Smuzhiyun if (ctx->w == RES_IN || ctx->w == RES_FOR) {
2413*4882a593Smuzhiyun syntax();
2414*4882a593Smuzhiyun free(new);
2415*4882a593Smuzhiyun ctx->w = RES_SNTX;
2416*4882a593Smuzhiyun b_reset(dest);
2417*4882a593Smuzhiyun return 1;
2418*4882a593Smuzhiyun }
2419*4882a593Smuzhiyun *new = *ctx; /* physical copy */
2420*4882a593Smuzhiyun initialize_context(ctx);
2421*4882a593Smuzhiyun ctx->stack=new;
2422*4882a593Smuzhiyun } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
2423*4882a593Smuzhiyun syntax();
2424*4882a593Smuzhiyun ctx->w = RES_SNTX;
2425*4882a593Smuzhiyun b_reset(dest);
2426*4882a593Smuzhiyun return 1;
2427*4882a593Smuzhiyun }
2428*4882a593Smuzhiyun ctx->w=r->code;
2429*4882a593Smuzhiyun ctx->old_flag = r->flag;
2430*4882a593Smuzhiyun if (ctx->old_flag & FLAG_END) {
2431*4882a593Smuzhiyun struct p_context *old;
2432*4882a593Smuzhiyun debug_printf("pop stack\n");
2433*4882a593Smuzhiyun done_pipe(ctx,PIPE_SEQ);
2434*4882a593Smuzhiyun old = ctx->stack;
2435*4882a593Smuzhiyun old->child->group = ctx->list_head;
2436*4882a593Smuzhiyun #ifndef __U_BOOT__
2437*4882a593Smuzhiyun old->child->subshell = 0;
2438*4882a593Smuzhiyun #endif
2439*4882a593Smuzhiyun *ctx = *old; /* physical copy */
2440*4882a593Smuzhiyun free(old);
2441*4882a593Smuzhiyun }
2442*4882a593Smuzhiyun b_reset (dest);
2443*4882a593Smuzhiyun return 1;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun }
2446*4882a593Smuzhiyun return 0;
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun
2449*4882a593Smuzhiyun /* normal return is 0.
2450*4882a593Smuzhiyun * Syntax or xglob errors return 1. */
2451*4882a593Smuzhiyun static int done_word(o_string *dest, struct p_context *ctx)
2452*4882a593Smuzhiyun {
2453*4882a593Smuzhiyun struct child_prog *child=ctx->child;
2454*4882a593Smuzhiyun #ifndef __U_BOOT__
2455*4882a593Smuzhiyun glob_t *glob_target;
2456*4882a593Smuzhiyun int gr, flags = 0;
2457*4882a593Smuzhiyun #else
2458*4882a593Smuzhiyun char *str, *s;
2459*4882a593Smuzhiyun int argc, cnt;
2460*4882a593Smuzhiyun #endif
2461*4882a593Smuzhiyun
2462*4882a593Smuzhiyun debug_printf("done_word: %s %p\n", dest->data, child);
2463*4882a593Smuzhiyun if (dest->length == 0 && !dest->nonnull) {
2464*4882a593Smuzhiyun debug_printf(" true null, ignored\n");
2465*4882a593Smuzhiyun return 0;
2466*4882a593Smuzhiyun }
2467*4882a593Smuzhiyun #ifndef __U_BOOT__
2468*4882a593Smuzhiyun if (ctx->pending_redirect) {
2469*4882a593Smuzhiyun glob_target = &ctx->pending_redirect->word;
2470*4882a593Smuzhiyun } else {
2471*4882a593Smuzhiyun #endif
2472*4882a593Smuzhiyun if (child->group) {
2473*4882a593Smuzhiyun syntax();
2474*4882a593Smuzhiyun return 1; /* syntax error, groups and arglists don't mix */
2475*4882a593Smuzhiyun }
2476*4882a593Smuzhiyun if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
2477*4882a593Smuzhiyun debug_printf("checking %s for reserved-ness\n",dest->data);
2478*4882a593Smuzhiyun if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
2479*4882a593Smuzhiyun }
2480*4882a593Smuzhiyun #ifndef __U_BOOT__
2481*4882a593Smuzhiyun glob_target = &child->glob_result;
2482*4882a593Smuzhiyun if (child->argv) flags |= GLOB_APPEND;
2483*4882a593Smuzhiyun #else
2484*4882a593Smuzhiyun for (cnt = 1, s = dest->data; s && *s; s++) {
2485*4882a593Smuzhiyun if (*s == '\\') s++;
2486*4882a593Smuzhiyun cnt++;
2487*4882a593Smuzhiyun }
2488*4882a593Smuzhiyun str = malloc(cnt);
2489*4882a593Smuzhiyun if (!str) return 1;
2490*4882a593Smuzhiyun if ( child->argv == NULL) {
2491*4882a593Smuzhiyun child->argc=0;
2492*4882a593Smuzhiyun }
2493*4882a593Smuzhiyun argc = ++child->argc;
2494*4882a593Smuzhiyun child->argv = realloc(child->argv, (argc+1)*sizeof(*child->argv));
2495*4882a593Smuzhiyun if (child->argv == NULL) {
2496*4882a593Smuzhiyun free(str);
2497*4882a593Smuzhiyun return 1;
2498*4882a593Smuzhiyun }
2499*4882a593Smuzhiyun child->argv_nonnull = realloc(child->argv_nonnull,
2500*4882a593Smuzhiyun (argc+1)*sizeof(*child->argv_nonnull));
2501*4882a593Smuzhiyun if (child->argv_nonnull == NULL) {
2502*4882a593Smuzhiyun free(str);
2503*4882a593Smuzhiyun return 1;
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun child->argv[argc-1]=str;
2506*4882a593Smuzhiyun child->argv_nonnull[argc-1] = dest->nonnull;
2507*4882a593Smuzhiyun child->argv[argc]=NULL;
2508*4882a593Smuzhiyun child->argv_nonnull[argc] = 0;
2509*4882a593Smuzhiyun for (s = dest->data; s && *s; s++,str++) {
2510*4882a593Smuzhiyun if (*s == '\\') s++;
2511*4882a593Smuzhiyun *str = *s;
2512*4882a593Smuzhiyun }
2513*4882a593Smuzhiyun *str = '\0';
2514*4882a593Smuzhiyun #endif
2515*4882a593Smuzhiyun #ifndef __U_BOOT__
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun gr = xglob(dest, flags, glob_target);
2518*4882a593Smuzhiyun if (gr != 0) return 1;
2519*4882a593Smuzhiyun #endif
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun b_reset(dest);
2522*4882a593Smuzhiyun #ifndef __U_BOOT__
2523*4882a593Smuzhiyun if (ctx->pending_redirect) {
2524*4882a593Smuzhiyun ctx->pending_redirect=NULL;
2525*4882a593Smuzhiyun if (glob_target->gl_pathc != 1) {
2526*4882a593Smuzhiyun error_msg("ambiguous redirect");
2527*4882a593Smuzhiyun return 1;
2528*4882a593Smuzhiyun }
2529*4882a593Smuzhiyun } else {
2530*4882a593Smuzhiyun child->argv = glob_target->gl_pathv;
2531*4882a593Smuzhiyun }
2532*4882a593Smuzhiyun #endif
2533*4882a593Smuzhiyun if (ctx->w == RES_FOR) {
2534*4882a593Smuzhiyun done_word(dest,ctx);
2535*4882a593Smuzhiyun done_pipe(ctx,PIPE_SEQ);
2536*4882a593Smuzhiyun }
2537*4882a593Smuzhiyun return 0;
2538*4882a593Smuzhiyun }
2539*4882a593Smuzhiyun
2540*4882a593Smuzhiyun /* The only possible error here is out of memory, in which case
2541*4882a593Smuzhiyun * xmalloc exits. */
2542*4882a593Smuzhiyun static int done_command(struct p_context *ctx)
2543*4882a593Smuzhiyun {
2544*4882a593Smuzhiyun /* The child is really already in the pipe structure, so
2545*4882a593Smuzhiyun * advance the pipe counter and make a new, null child.
2546*4882a593Smuzhiyun * Only real trickiness here is that the uncommitted
2547*4882a593Smuzhiyun * child structure, to which ctx->child points, is not
2548*4882a593Smuzhiyun * counted in pi->num_progs. */
2549*4882a593Smuzhiyun struct pipe *pi=ctx->pipe;
2550*4882a593Smuzhiyun struct child_prog *prog=ctx->child;
2551*4882a593Smuzhiyun
2552*4882a593Smuzhiyun if (prog && prog->group == NULL
2553*4882a593Smuzhiyun && prog->argv == NULL
2554*4882a593Smuzhiyun #ifndef __U_BOOT__
2555*4882a593Smuzhiyun && prog->redirects == NULL) {
2556*4882a593Smuzhiyun #else
2557*4882a593Smuzhiyun ) {
2558*4882a593Smuzhiyun #endif
2559*4882a593Smuzhiyun debug_printf("done_command: skipping null command\n");
2560*4882a593Smuzhiyun return 0;
2561*4882a593Smuzhiyun } else if (prog) {
2562*4882a593Smuzhiyun pi->num_progs++;
2563*4882a593Smuzhiyun debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
2564*4882a593Smuzhiyun } else {
2565*4882a593Smuzhiyun debug_printf("done_command: initializing\n");
2566*4882a593Smuzhiyun }
2567*4882a593Smuzhiyun pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun prog = pi->progs + pi->num_progs;
2570*4882a593Smuzhiyun #ifndef __U_BOOT__
2571*4882a593Smuzhiyun prog->redirects = NULL;
2572*4882a593Smuzhiyun #endif
2573*4882a593Smuzhiyun prog->argv = NULL;
2574*4882a593Smuzhiyun prog->argv_nonnull = NULL;
2575*4882a593Smuzhiyun #ifndef __U_BOOT__
2576*4882a593Smuzhiyun prog->is_stopped = 0;
2577*4882a593Smuzhiyun #endif
2578*4882a593Smuzhiyun prog->group = NULL;
2579*4882a593Smuzhiyun #ifndef __U_BOOT__
2580*4882a593Smuzhiyun prog->glob_result.gl_pathv = NULL;
2581*4882a593Smuzhiyun prog->family = pi;
2582*4882a593Smuzhiyun #endif
2583*4882a593Smuzhiyun prog->sp = 0;
2584*4882a593Smuzhiyun ctx->child = prog;
2585*4882a593Smuzhiyun prog->type = ctx->type;
2586*4882a593Smuzhiyun
2587*4882a593Smuzhiyun /* but ctx->pipe and ctx->list_head remain unchanged */
2588*4882a593Smuzhiyun return 0;
2589*4882a593Smuzhiyun }
2590*4882a593Smuzhiyun
2591*4882a593Smuzhiyun static int done_pipe(struct p_context *ctx, pipe_style type)
2592*4882a593Smuzhiyun {
2593*4882a593Smuzhiyun struct pipe *new_p;
2594*4882a593Smuzhiyun done_command(ctx); /* implicit closure of previous command */
2595*4882a593Smuzhiyun debug_printf("done_pipe, type %d\n", type);
2596*4882a593Smuzhiyun ctx->pipe->followup = type;
2597*4882a593Smuzhiyun ctx->pipe->r_mode = ctx->w;
2598*4882a593Smuzhiyun new_p=new_pipe();
2599*4882a593Smuzhiyun ctx->pipe->next = new_p;
2600*4882a593Smuzhiyun ctx->pipe = new_p;
2601*4882a593Smuzhiyun ctx->child = NULL;
2602*4882a593Smuzhiyun done_command(ctx); /* set up new pipe to accept commands */
2603*4882a593Smuzhiyun return 0;
2604*4882a593Smuzhiyun }
2605*4882a593Smuzhiyun
2606*4882a593Smuzhiyun #ifndef __U_BOOT__
2607*4882a593Smuzhiyun /* peek ahead in the in_str to find out if we have a "&n" construct,
2608*4882a593Smuzhiyun * as in "2>&1", that represents duplicating a file descriptor.
2609*4882a593Smuzhiyun * returns either -2 (syntax error), -1 (no &), or the number found.
2610*4882a593Smuzhiyun */
2611*4882a593Smuzhiyun static int redirect_dup_num(struct in_str *input)
2612*4882a593Smuzhiyun {
2613*4882a593Smuzhiyun int ch, d=0, ok=0;
2614*4882a593Smuzhiyun ch = b_peek(input);
2615*4882a593Smuzhiyun if (ch != '&') return -1;
2616*4882a593Smuzhiyun
2617*4882a593Smuzhiyun b_getch(input); /* get the & */
2618*4882a593Smuzhiyun ch=b_peek(input);
2619*4882a593Smuzhiyun if (ch == '-') {
2620*4882a593Smuzhiyun b_getch(input);
2621*4882a593Smuzhiyun return -3; /* "-" represents "close me" */
2622*4882a593Smuzhiyun }
2623*4882a593Smuzhiyun while (isdigit(ch)) {
2624*4882a593Smuzhiyun d = d*10+(ch-'0');
2625*4882a593Smuzhiyun ok=1;
2626*4882a593Smuzhiyun b_getch(input);
2627*4882a593Smuzhiyun ch = b_peek(input);
2628*4882a593Smuzhiyun }
2629*4882a593Smuzhiyun if (ok) return d;
2630*4882a593Smuzhiyun
2631*4882a593Smuzhiyun error_msg("ambiguous redirect");
2632*4882a593Smuzhiyun return -2;
2633*4882a593Smuzhiyun }
2634*4882a593Smuzhiyun
2635*4882a593Smuzhiyun /* If a redirect is immediately preceded by a number, that number is
2636*4882a593Smuzhiyun * supposed to tell which file descriptor to redirect. This routine
2637*4882a593Smuzhiyun * looks for such preceding numbers. In an ideal world this routine
2638*4882a593Smuzhiyun * needs to handle all the following classes of redirects...
2639*4882a593Smuzhiyun * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
2640*4882a593Smuzhiyun * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
2641*4882a593Smuzhiyun * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
2642*4882a593Smuzhiyun * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
2643*4882a593Smuzhiyun * A -1 output from this program means no valid number was found, so the
2644*4882a593Smuzhiyun * caller should use the appropriate default for this redirection.
2645*4882a593Smuzhiyun */
2646*4882a593Smuzhiyun static int redirect_opt_num(o_string *o)
2647*4882a593Smuzhiyun {
2648*4882a593Smuzhiyun int num;
2649*4882a593Smuzhiyun
2650*4882a593Smuzhiyun if (o->length==0) return -1;
2651*4882a593Smuzhiyun for(num=0; num<o->length; num++) {
2652*4882a593Smuzhiyun if (!isdigit(*(o->data+num))) {
2653*4882a593Smuzhiyun return -1;
2654*4882a593Smuzhiyun }
2655*4882a593Smuzhiyun }
2656*4882a593Smuzhiyun /* reuse num (and save an int) */
2657*4882a593Smuzhiyun num=atoi(o->data);
2658*4882a593Smuzhiyun b_reset(o);
2659*4882a593Smuzhiyun return num;
2660*4882a593Smuzhiyun }
2661*4882a593Smuzhiyun
2662*4882a593Smuzhiyun FILE *generate_stream_from_list(struct pipe *head)
2663*4882a593Smuzhiyun {
2664*4882a593Smuzhiyun FILE *pf;
2665*4882a593Smuzhiyun #if 1
2666*4882a593Smuzhiyun int pid, channel[2];
2667*4882a593Smuzhiyun if (pipe(channel)<0) perror_msg_and_die("pipe");
2668*4882a593Smuzhiyun pid=fork();
2669*4882a593Smuzhiyun if (pid<0) {
2670*4882a593Smuzhiyun perror_msg_and_die("fork");
2671*4882a593Smuzhiyun } else if (pid==0) {
2672*4882a593Smuzhiyun close(channel[0]);
2673*4882a593Smuzhiyun if (channel[1] != 1) {
2674*4882a593Smuzhiyun dup2(channel[1],1);
2675*4882a593Smuzhiyun close(channel[1]);
2676*4882a593Smuzhiyun }
2677*4882a593Smuzhiyun #if 0
2678*4882a593Smuzhiyun #define SURROGATE "surrogate response"
2679*4882a593Smuzhiyun write(1,SURROGATE,sizeof(SURROGATE));
2680*4882a593Smuzhiyun _exit(run_list(head));
2681*4882a593Smuzhiyun #else
2682*4882a593Smuzhiyun _exit(run_list_real(head)); /* leaks memory */
2683*4882a593Smuzhiyun #endif
2684*4882a593Smuzhiyun }
2685*4882a593Smuzhiyun debug_printf("forked child %d\n",pid);
2686*4882a593Smuzhiyun close(channel[1]);
2687*4882a593Smuzhiyun pf = fdopen(channel[0],"r");
2688*4882a593Smuzhiyun debug_printf("pipe on FILE *%p\n",pf);
2689*4882a593Smuzhiyun #else
2690*4882a593Smuzhiyun free_pipe_list(head,0);
2691*4882a593Smuzhiyun pf=popen("echo surrogate response","r");
2692*4882a593Smuzhiyun debug_printf("started fake pipe on FILE *%p\n",pf);
2693*4882a593Smuzhiyun #endif
2694*4882a593Smuzhiyun return pf;
2695*4882a593Smuzhiyun }
2696*4882a593Smuzhiyun
2697*4882a593Smuzhiyun /* this version hacked for testing purposes */
2698*4882a593Smuzhiyun /* return code is exit status of the process that is run. */
2699*4882a593Smuzhiyun static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
2700*4882a593Smuzhiyun {
2701*4882a593Smuzhiyun int retcode;
2702*4882a593Smuzhiyun o_string result=NULL_O_STRING;
2703*4882a593Smuzhiyun struct p_context inner;
2704*4882a593Smuzhiyun FILE *p;
2705*4882a593Smuzhiyun struct in_str pipe_str;
2706*4882a593Smuzhiyun initialize_context(&inner);
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun /* recursion to generate command */
2709*4882a593Smuzhiyun retcode = parse_stream(&result, &inner, input, subst_end);
2710*4882a593Smuzhiyun if (retcode != 0) return retcode; /* syntax error or EOF */
2711*4882a593Smuzhiyun done_word(&result, &inner);
2712*4882a593Smuzhiyun done_pipe(&inner, PIPE_SEQ);
2713*4882a593Smuzhiyun b_free(&result);
2714*4882a593Smuzhiyun
2715*4882a593Smuzhiyun p=generate_stream_from_list(inner.list_head);
2716*4882a593Smuzhiyun if (p==NULL) return 1;
2717*4882a593Smuzhiyun mark_open(fileno(p));
2718*4882a593Smuzhiyun setup_file_in_str(&pipe_str, p);
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun /* now send results of command back into original context */
2721*4882a593Smuzhiyun retcode = parse_stream(dest, ctx, &pipe_str, '\0');
2722*4882a593Smuzhiyun /* XXX In case of a syntax error, should we try to kill the child?
2723*4882a593Smuzhiyun * That would be tough to do right, so just read until EOF. */
2724*4882a593Smuzhiyun if (retcode == 1) {
2725*4882a593Smuzhiyun while (b_getch(&pipe_str)!=EOF) { /* discard */ };
2726*4882a593Smuzhiyun }
2727*4882a593Smuzhiyun
2728*4882a593Smuzhiyun debug_printf("done reading from pipe, pclose()ing\n");
2729*4882a593Smuzhiyun /* This is the step that wait()s for the child. Should be pretty
2730*4882a593Smuzhiyun * safe, since we just read an EOF from its stdout. We could try
2731*4882a593Smuzhiyun * to better, by using wait(), and keeping track of background jobs
2732*4882a593Smuzhiyun * at the same time. That would be a lot of work, and contrary
2733*4882a593Smuzhiyun * to the KISS philosophy of this program. */
2734*4882a593Smuzhiyun mark_closed(fileno(p));
2735*4882a593Smuzhiyun retcode=pclose(p);
2736*4882a593Smuzhiyun free_pipe_list(inner.list_head,0);
2737*4882a593Smuzhiyun debug_printf("pclosed, retcode=%d\n",retcode);
2738*4882a593Smuzhiyun /* XXX this process fails to trim a single trailing newline */
2739*4882a593Smuzhiyun return retcode;
2740*4882a593Smuzhiyun }
2741*4882a593Smuzhiyun
2742*4882a593Smuzhiyun static int parse_group(o_string *dest, struct p_context *ctx,
2743*4882a593Smuzhiyun struct in_str *input, int ch)
2744*4882a593Smuzhiyun {
2745*4882a593Smuzhiyun int rcode, endch=0;
2746*4882a593Smuzhiyun struct p_context sub;
2747*4882a593Smuzhiyun struct child_prog *child = ctx->child;
2748*4882a593Smuzhiyun if (child->argv) {
2749*4882a593Smuzhiyun syntax();
2750*4882a593Smuzhiyun return 1; /* syntax error, groups and arglists don't mix */
2751*4882a593Smuzhiyun }
2752*4882a593Smuzhiyun initialize_context(&sub);
2753*4882a593Smuzhiyun switch(ch) {
2754*4882a593Smuzhiyun case '(': endch=')'; child->subshell=1; break;
2755*4882a593Smuzhiyun case '{': endch='}'; break;
2756*4882a593Smuzhiyun default: syntax(); /* really logic error */
2757*4882a593Smuzhiyun }
2758*4882a593Smuzhiyun rcode=parse_stream(dest,&sub,input,endch);
2759*4882a593Smuzhiyun done_word(dest,&sub); /* finish off the final word in the subcontext */
2760*4882a593Smuzhiyun done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
2761*4882a593Smuzhiyun child->group = sub.list_head;
2762*4882a593Smuzhiyun return rcode;
2763*4882a593Smuzhiyun /* child remains "open", available for possible redirects */
2764*4882a593Smuzhiyun }
2765*4882a593Smuzhiyun #endif
2766*4882a593Smuzhiyun
2767*4882a593Smuzhiyun /* basically useful version until someone wants to get fancier,
2768*4882a593Smuzhiyun * see the bash man page under "Parameter Expansion" */
2769*4882a593Smuzhiyun static char *lookup_param(char *src)
2770*4882a593Smuzhiyun {
2771*4882a593Smuzhiyun char *p;
2772*4882a593Smuzhiyun char *sep;
2773*4882a593Smuzhiyun char *default_val = NULL;
2774*4882a593Smuzhiyun int assign = 0;
2775*4882a593Smuzhiyun int expand_empty = 0;
2776*4882a593Smuzhiyun
2777*4882a593Smuzhiyun if (!src)
2778*4882a593Smuzhiyun return NULL;
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun sep = strchr(src, ':');
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun if (sep) {
2783*4882a593Smuzhiyun *sep = '\0';
2784*4882a593Smuzhiyun if (*(sep + 1) == '-')
2785*4882a593Smuzhiyun default_val = sep+2;
2786*4882a593Smuzhiyun if (*(sep + 1) == '=') {
2787*4882a593Smuzhiyun default_val = sep+2;
2788*4882a593Smuzhiyun assign = 1;
2789*4882a593Smuzhiyun }
2790*4882a593Smuzhiyun if (*(sep + 1) == '+') {
2791*4882a593Smuzhiyun default_val = sep+2;
2792*4882a593Smuzhiyun expand_empty = 1;
2793*4882a593Smuzhiyun }
2794*4882a593Smuzhiyun }
2795*4882a593Smuzhiyun
2796*4882a593Smuzhiyun p = env_get(src);
2797*4882a593Smuzhiyun if (!p)
2798*4882a593Smuzhiyun p = get_local_var(src);
2799*4882a593Smuzhiyun
2800*4882a593Smuzhiyun if (!p || strlen(p) == 0) {
2801*4882a593Smuzhiyun p = default_val;
2802*4882a593Smuzhiyun if (assign) {
2803*4882a593Smuzhiyun char *var = malloc(strlen(src)+strlen(default_val)+2);
2804*4882a593Smuzhiyun if (var) {
2805*4882a593Smuzhiyun sprintf(var, "%s=%s", src, default_val);
2806*4882a593Smuzhiyun set_local_var(var, 0);
2807*4882a593Smuzhiyun }
2808*4882a593Smuzhiyun free(var);
2809*4882a593Smuzhiyun }
2810*4882a593Smuzhiyun } else if (expand_empty) {
2811*4882a593Smuzhiyun p += strlen(p);
2812*4882a593Smuzhiyun }
2813*4882a593Smuzhiyun
2814*4882a593Smuzhiyun if (sep)
2815*4882a593Smuzhiyun *sep = ':';
2816*4882a593Smuzhiyun
2817*4882a593Smuzhiyun return p;
2818*4882a593Smuzhiyun }
2819*4882a593Smuzhiyun
2820*4882a593Smuzhiyun #ifdef __U_BOOT__
2821*4882a593Smuzhiyun static char *get_dollar_var(char ch)
2822*4882a593Smuzhiyun {
2823*4882a593Smuzhiyun static char buf[40];
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun buf[0] = '\0';
2826*4882a593Smuzhiyun switch (ch) {
2827*4882a593Smuzhiyun case '?':
2828*4882a593Smuzhiyun sprintf(buf, "%u", (unsigned int)last_return_code);
2829*4882a593Smuzhiyun break;
2830*4882a593Smuzhiyun default:
2831*4882a593Smuzhiyun return NULL;
2832*4882a593Smuzhiyun }
2833*4882a593Smuzhiyun return buf;
2834*4882a593Smuzhiyun }
2835*4882a593Smuzhiyun #endif
2836*4882a593Smuzhiyun
2837*4882a593Smuzhiyun /* return code: 0 for OK, 1 for syntax error */
2838*4882a593Smuzhiyun static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
2839*4882a593Smuzhiyun {
2840*4882a593Smuzhiyun #ifndef __U_BOOT__
2841*4882a593Smuzhiyun int i, advance=0;
2842*4882a593Smuzhiyun #else
2843*4882a593Smuzhiyun int advance=0;
2844*4882a593Smuzhiyun #endif
2845*4882a593Smuzhiyun #ifndef __U_BOOT__
2846*4882a593Smuzhiyun char sep[]=" ";
2847*4882a593Smuzhiyun #endif
2848*4882a593Smuzhiyun int ch = input->peek(input); /* first character after the $ */
2849*4882a593Smuzhiyun debug_printf("handle_dollar: ch=%c\n",ch);
2850*4882a593Smuzhiyun if (isalpha(ch)) {
2851*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2852*4882a593Smuzhiyun ctx->child->sp++;
2853*4882a593Smuzhiyun while(ch=b_peek(input),isalnum(ch) || ch=='_') {
2854*4882a593Smuzhiyun b_getch(input);
2855*4882a593Smuzhiyun b_addchr(dest,ch);
2856*4882a593Smuzhiyun }
2857*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2858*4882a593Smuzhiyun #ifndef __U_BOOT__
2859*4882a593Smuzhiyun } else if (isdigit(ch)) {
2860*4882a593Smuzhiyun i = ch-'0'; /* XXX is $0 special? */
2861*4882a593Smuzhiyun if (i<global_argc) {
2862*4882a593Smuzhiyun parse_string(dest, ctx, global_argv[i]); /* recursion */
2863*4882a593Smuzhiyun }
2864*4882a593Smuzhiyun advance = 1;
2865*4882a593Smuzhiyun #endif
2866*4882a593Smuzhiyun } else switch (ch) {
2867*4882a593Smuzhiyun #ifndef __U_BOOT__
2868*4882a593Smuzhiyun case '$':
2869*4882a593Smuzhiyun b_adduint(dest,getpid());
2870*4882a593Smuzhiyun advance = 1;
2871*4882a593Smuzhiyun break;
2872*4882a593Smuzhiyun case '!':
2873*4882a593Smuzhiyun if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
2874*4882a593Smuzhiyun advance = 1;
2875*4882a593Smuzhiyun break;
2876*4882a593Smuzhiyun #endif
2877*4882a593Smuzhiyun case '?':
2878*4882a593Smuzhiyun #ifndef __U_BOOT__
2879*4882a593Smuzhiyun b_adduint(dest,last_return_code);
2880*4882a593Smuzhiyun #else
2881*4882a593Smuzhiyun ctx->child->sp++;
2882*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2883*4882a593Smuzhiyun b_addchr(dest, '$');
2884*4882a593Smuzhiyun b_addchr(dest, '?');
2885*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2886*4882a593Smuzhiyun #endif
2887*4882a593Smuzhiyun advance = 1;
2888*4882a593Smuzhiyun break;
2889*4882a593Smuzhiyun #ifndef __U_BOOT__
2890*4882a593Smuzhiyun case '#':
2891*4882a593Smuzhiyun b_adduint(dest,global_argc ? global_argc-1 : 0);
2892*4882a593Smuzhiyun advance = 1;
2893*4882a593Smuzhiyun break;
2894*4882a593Smuzhiyun #endif
2895*4882a593Smuzhiyun case '{':
2896*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2897*4882a593Smuzhiyun ctx->child->sp++;
2898*4882a593Smuzhiyun b_getch(input);
2899*4882a593Smuzhiyun /* XXX maybe someone will try to escape the '}' */
2900*4882a593Smuzhiyun while(ch=b_getch(input),ch!=EOF && ch!='}') {
2901*4882a593Smuzhiyun b_addchr(dest,ch);
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun if (ch != '}') {
2904*4882a593Smuzhiyun syntax();
2905*4882a593Smuzhiyun return 1;
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun b_addchr(dest, SPECIAL_VAR_SYMBOL);
2908*4882a593Smuzhiyun break;
2909*4882a593Smuzhiyun #ifndef __U_BOOT__
2910*4882a593Smuzhiyun case '(':
2911*4882a593Smuzhiyun b_getch(input);
2912*4882a593Smuzhiyun process_command_subs(dest, ctx, input, ')');
2913*4882a593Smuzhiyun break;
2914*4882a593Smuzhiyun case '*':
2915*4882a593Smuzhiyun sep[0]=ifs[0];
2916*4882a593Smuzhiyun for (i=1; i<global_argc; i++) {
2917*4882a593Smuzhiyun parse_string(dest, ctx, global_argv[i]);
2918*4882a593Smuzhiyun if (i+1 < global_argc) parse_string(dest, ctx, sep);
2919*4882a593Smuzhiyun }
2920*4882a593Smuzhiyun break;
2921*4882a593Smuzhiyun case '@':
2922*4882a593Smuzhiyun case '-':
2923*4882a593Smuzhiyun case '_':
2924*4882a593Smuzhiyun /* still unhandled, but should be eventually */
2925*4882a593Smuzhiyun error_msg("unhandled syntax: $%c",ch);
2926*4882a593Smuzhiyun return 1;
2927*4882a593Smuzhiyun break;
2928*4882a593Smuzhiyun #endif
2929*4882a593Smuzhiyun default:
2930*4882a593Smuzhiyun b_addqchr(dest,'$',dest->quote);
2931*4882a593Smuzhiyun }
2932*4882a593Smuzhiyun /* Eat the character if the flag was set. If the compiler
2933*4882a593Smuzhiyun * is smart enough, we could substitute "b_getch(input);"
2934*4882a593Smuzhiyun * for all the "advance = 1;" above, and also end up with
2935*4882a593Smuzhiyun * a nice size-optimized program. Hah! That'll be the day.
2936*4882a593Smuzhiyun */
2937*4882a593Smuzhiyun if (advance) b_getch(input);
2938*4882a593Smuzhiyun return 0;
2939*4882a593Smuzhiyun }
2940*4882a593Smuzhiyun
2941*4882a593Smuzhiyun #ifndef __U_BOOT__
2942*4882a593Smuzhiyun int parse_string(o_string *dest, struct p_context *ctx, const char *src)
2943*4882a593Smuzhiyun {
2944*4882a593Smuzhiyun struct in_str foo;
2945*4882a593Smuzhiyun setup_string_in_str(&foo, src);
2946*4882a593Smuzhiyun return parse_stream(dest, ctx, &foo, '\0');
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun #endif
2949*4882a593Smuzhiyun
2950*4882a593Smuzhiyun /* return code is 0 for normal exit, 1 for syntax error */
2951*4882a593Smuzhiyun static int parse_stream(o_string *dest, struct p_context *ctx,
2952*4882a593Smuzhiyun struct in_str *input, int end_trigger)
2953*4882a593Smuzhiyun {
2954*4882a593Smuzhiyun unsigned int ch, m;
2955*4882a593Smuzhiyun #ifndef __U_BOOT__
2956*4882a593Smuzhiyun int redir_fd;
2957*4882a593Smuzhiyun redir_type redir_style;
2958*4882a593Smuzhiyun #endif
2959*4882a593Smuzhiyun int next;
2960*4882a593Smuzhiyun
2961*4882a593Smuzhiyun /* Only double-quote state is handled in the state variable dest->quote.
2962*4882a593Smuzhiyun * A single-quote triggers a bypass of the main loop until its mate is
2963*4882a593Smuzhiyun * found. When recursing, quote state is passed in via dest->quote. */
2964*4882a593Smuzhiyun
2965*4882a593Smuzhiyun debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
2966*4882a593Smuzhiyun while ((ch=b_getch(input))!=EOF) {
2967*4882a593Smuzhiyun m = map[ch];
2968*4882a593Smuzhiyun #ifdef __U_BOOT__
2969*4882a593Smuzhiyun if (input->__promptme == 0) return 1;
2970*4882a593Smuzhiyun #endif
2971*4882a593Smuzhiyun next = (ch == '\n') ? 0 : b_peek(input);
2972*4882a593Smuzhiyun
2973*4882a593Smuzhiyun debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
2974*4882a593Smuzhiyun ch >= ' ' ? ch : '.', ch, m,
2975*4882a593Smuzhiyun dest->quote, ctx->stack == NULL ? '*' : '.');
2976*4882a593Smuzhiyun
2977*4882a593Smuzhiyun if (m==0 || ((m==1 || m==2) && dest->quote)) {
2978*4882a593Smuzhiyun b_addqchr(dest, ch, dest->quote);
2979*4882a593Smuzhiyun } else {
2980*4882a593Smuzhiyun if (m==2) { /* unquoted IFS */
2981*4882a593Smuzhiyun if (done_word(dest, ctx)) {
2982*4882a593Smuzhiyun return 1;
2983*4882a593Smuzhiyun }
2984*4882a593Smuzhiyun /* If we aren't performing a substitution, treat a newline as a
2985*4882a593Smuzhiyun * command separator. */
2986*4882a593Smuzhiyun if (end_trigger != '\0' && ch=='\n')
2987*4882a593Smuzhiyun done_pipe(ctx,PIPE_SEQ);
2988*4882a593Smuzhiyun }
2989*4882a593Smuzhiyun if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
2990*4882a593Smuzhiyun debug_printf("leaving parse_stream (triggered)\n");
2991*4882a593Smuzhiyun return 0;
2992*4882a593Smuzhiyun }
2993*4882a593Smuzhiyun #if 0
2994*4882a593Smuzhiyun if (ch=='\n') {
2995*4882a593Smuzhiyun /* Yahoo! Time to run with it! */
2996*4882a593Smuzhiyun done_pipe(ctx,PIPE_SEQ);
2997*4882a593Smuzhiyun run_list(ctx->list_head);
2998*4882a593Smuzhiyun initialize_context(ctx);
2999*4882a593Smuzhiyun }
3000*4882a593Smuzhiyun #endif
3001*4882a593Smuzhiyun if (m!=2) switch (ch) {
3002*4882a593Smuzhiyun case '#':
3003*4882a593Smuzhiyun if (dest->length == 0 && !dest->quote) {
3004*4882a593Smuzhiyun while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
3005*4882a593Smuzhiyun } else {
3006*4882a593Smuzhiyun b_addqchr(dest, ch, dest->quote);
3007*4882a593Smuzhiyun }
3008*4882a593Smuzhiyun break;
3009*4882a593Smuzhiyun case '\\':
3010*4882a593Smuzhiyun if (next == EOF) {
3011*4882a593Smuzhiyun syntax();
3012*4882a593Smuzhiyun return 1;
3013*4882a593Smuzhiyun }
3014*4882a593Smuzhiyun b_addqchr(dest, '\\', dest->quote);
3015*4882a593Smuzhiyun b_addqchr(dest, b_getch(input), dest->quote);
3016*4882a593Smuzhiyun break;
3017*4882a593Smuzhiyun case '$':
3018*4882a593Smuzhiyun if (handle_dollar(dest, ctx, input)!=0) return 1;
3019*4882a593Smuzhiyun break;
3020*4882a593Smuzhiyun case '\'':
3021*4882a593Smuzhiyun dest->nonnull = 1;
3022*4882a593Smuzhiyun while(ch=b_getch(input),ch!=EOF && ch!='\'') {
3023*4882a593Smuzhiyun #ifdef __U_BOOT__
3024*4882a593Smuzhiyun if(input->__promptme == 0) return 1;
3025*4882a593Smuzhiyun #endif
3026*4882a593Smuzhiyun b_addchr(dest,ch);
3027*4882a593Smuzhiyun }
3028*4882a593Smuzhiyun if (ch==EOF) {
3029*4882a593Smuzhiyun syntax();
3030*4882a593Smuzhiyun return 1;
3031*4882a593Smuzhiyun }
3032*4882a593Smuzhiyun break;
3033*4882a593Smuzhiyun case '"':
3034*4882a593Smuzhiyun dest->nonnull = 1;
3035*4882a593Smuzhiyun dest->quote = !dest->quote;
3036*4882a593Smuzhiyun break;
3037*4882a593Smuzhiyun #ifndef __U_BOOT__
3038*4882a593Smuzhiyun case '`':
3039*4882a593Smuzhiyun process_command_subs(dest, ctx, input, '`');
3040*4882a593Smuzhiyun break;
3041*4882a593Smuzhiyun case '>':
3042*4882a593Smuzhiyun redir_fd = redirect_opt_num(dest);
3043*4882a593Smuzhiyun done_word(dest, ctx);
3044*4882a593Smuzhiyun redir_style=REDIRECT_OVERWRITE;
3045*4882a593Smuzhiyun if (next == '>') {
3046*4882a593Smuzhiyun redir_style=REDIRECT_APPEND;
3047*4882a593Smuzhiyun b_getch(input);
3048*4882a593Smuzhiyun } else if (next == '(') {
3049*4882a593Smuzhiyun syntax(); /* until we support >(list) Process Substitution */
3050*4882a593Smuzhiyun return 1;
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun setup_redirect(ctx, redir_fd, redir_style, input);
3053*4882a593Smuzhiyun break;
3054*4882a593Smuzhiyun case '<':
3055*4882a593Smuzhiyun redir_fd = redirect_opt_num(dest);
3056*4882a593Smuzhiyun done_word(dest, ctx);
3057*4882a593Smuzhiyun redir_style=REDIRECT_INPUT;
3058*4882a593Smuzhiyun if (next == '<') {
3059*4882a593Smuzhiyun redir_style=REDIRECT_HEREIS;
3060*4882a593Smuzhiyun b_getch(input);
3061*4882a593Smuzhiyun } else if (next == '>') {
3062*4882a593Smuzhiyun redir_style=REDIRECT_IO;
3063*4882a593Smuzhiyun b_getch(input);
3064*4882a593Smuzhiyun } else if (next == '(') {
3065*4882a593Smuzhiyun syntax(); /* until we support <(list) Process Substitution */
3066*4882a593Smuzhiyun return 1;
3067*4882a593Smuzhiyun }
3068*4882a593Smuzhiyun setup_redirect(ctx, redir_fd, redir_style, input);
3069*4882a593Smuzhiyun break;
3070*4882a593Smuzhiyun #endif
3071*4882a593Smuzhiyun case ';':
3072*4882a593Smuzhiyun done_word(dest, ctx);
3073*4882a593Smuzhiyun done_pipe(ctx,PIPE_SEQ);
3074*4882a593Smuzhiyun break;
3075*4882a593Smuzhiyun case '&':
3076*4882a593Smuzhiyun done_word(dest, ctx);
3077*4882a593Smuzhiyun if (next=='&') {
3078*4882a593Smuzhiyun b_getch(input);
3079*4882a593Smuzhiyun done_pipe(ctx,PIPE_AND);
3080*4882a593Smuzhiyun } else {
3081*4882a593Smuzhiyun #ifndef __U_BOOT__
3082*4882a593Smuzhiyun done_pipe(ctx,PIPE_BG);
3083*4882a593Smuzhiyun #else
3084*4882a593Smuzhiyun syntax_err();
3085*4882a593Smuzhiyun return 1;
3086*4882a593Smuzhiyun #endif
3087*4882a593Smuzhiyun }
3088*4882a593Smuzhiyun break;
3089*4882a593Smuzhiyun case '|':
3090*4882a593Smuzhiyun done_word(dest, ctx);
3091*4882a593Smuzhiyun if (next=='|') {
3092*4882a593Smuzhiyun b_getch(input);
3093*4882a593Smuzhiyun done_pipe(ctx,PIPE_OR);
3094*4882a593Smuzhiyun } else {
3095*4882a593Smuzhiyun /* we could pick up a file descriptor choice here
3096*4882a593Smuzhiyun * with redirect_opt_num(), but bash doesn't do it.
3097*4882a593Smuzhiyun * "echo foo 2| cat" yields "foo 2". */
3098*4882a593Smuzhiyun #ifndef __U_BOOT__
3099*4882a593Smuzhiyun done_command(ctx);
3100*4882a593Smuzhiyun #else
3101*4882a593Smuzhiyun syntax_err();
3102*4882a593Smuzhiyun return 1;
3103*4882a593Smuzhiyun #endif
3104*4882a593Smuzhiyun }
3105*4882a593Smuzhiyun break;
3106*4882a593Smuzhiyun #ifndef __U_BOOT__
3107*4882a593Smuzhiyun case '(':
3108*4882a593Smuzhiyun case '{':
3109*4882a593Smuzhiyun if (parse_group(dest, ctx, input, ch)!=0) return 1;
3110*4882a593Smuzhiyun break;
3111*4882a593Smuzhiyun case ')':
3112*4882a593Smuzhiyun case '}':
3113*4882a593Smuzhiyun syntax(); /* Proper use of this character caught by end_trigger */
3114*4882a593Smuzhiyun return 1;
3115*4882a593Smuzhiyun break;
3116*4882a593Smuzhiyun #endif
3117*4882a593Smuzhiyun case SUBSTED_VAR_SYMBOL:
3118*4882a593Smuzhiyun dest->nonnull = 1;
3119*4882a593Smuzhiyun while (ch = b_getch(input), ch != EOF &&
3120*4882a593Smuzhiyun ch != SUBSTED_VAR_SYMBOL) {
3121*4882a593Smuzhiyun debug_printf("subst, pass=%d\n", ch);
3122*4882a593Smuzhiyun if (input->__promptme == 0)
3123*4882a593Smuzhiyun return 1;
3124*4882a593Smuzhiyun b_addchr(dest, ch);
3125*4882a593Smuzhiyun }
3126*4882a593Smuzhiyun debug_printf("subst, term=%d\n", ch);
3127*4882a593Smuzhiyun if (ch == EOF) {
3128*4882a593Smuzhiyun syntax();
3129*4882a593Smuzhiyun return 1;
3130*4882a593Smuzhiyun }
3131*4882a593Smuzhiyun break;
3132*4882a593Smuzhiyun default:
3133*4882a593Smuzhiyun syntax(); /* this is really an internal logic error */
3134*4882a593Smuzhiyun return 1;
3135*4882a593Smuzhiyun }
3136*4882a593Smuzhiyun }
3137*4882a593Smuzhiyun }
3138*4882a593Smuzhiyun /* complain if quote? No, maybe we just finished a command substitution
3139*4882a593Smuzhiyun * that was quoted. Example:
3140*4882a593Smuzhiyun * $ echo "`cat foo` plus more"
3141*4882a593Smuzhiyun * and we just got the EOF generated by the subshell that ran "cat foo"
3142*4882a593Smuzhiyun * The only real complaint is if we got an EOF when end_trigger != '\0',
3143*4882a593Smuzhiyun * that is, we were really supposed to get end_trigger, and never got
3144*4882a593Smuzhiyun * one before the EOF. Can't use the standard "syntax error" return code,
3145*4882a593Smuzhiyun * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
3146*4882a593Smuzhiyun debug_printf("leaving parse_stream (EOF)\n");
3147*4882a593Smuzhiyun if (end_trigger != '\0') return -1;
3148*4882a593Smuzhiyun return 0;
3149*4882a593Smuzhiyun }
3150*4882a593Smuzhiyun
3151*4882a593Smuzhiyun static void mapset(const unsigned char *set, int code)
3152*4882a593Smuzhiyun {
3153*4882a593Smuzhiyun const unsigned char *s;
3154*4882a593Smuzhiyun for (s=set; *s; s++) map[*s] = code;
3155*4882a593Smuzhiyun }
3156*4882a593Smuzhiyun
3157*4882a593Smuzhiyun static void update_ifs_map(void)
3158*4882a593Smuzhiyun {
3159*4882a593Smuzhiyun /* char *ifs and char map[256] are both globals. */
3160*4882a593Smuzhiyun ifs = (uchar *)env_get("IFS");
3161*4882a593Smuzhiyun if (ifs == NULL) ifs=(uchar *)" \t\n";
3162*4882a593Smuzhiyun /* Precompute a list of 'flow through' behavior so it can be treated
3163*4882a593Smuzhiyun * quickly up front. Computation is necessary because of IFS.
3164*4882a593Smuzhiyun * Special case handling of IFS == " \t\n" is not implemented.
3165*4882a593Smuzhiyun * The map[] array only really needs two bits each, and on most machines
3166*4882a593Smuzhiyun * that would be faster because of the reduced L1 cache footprint.
3167*4882a593Smuzhiyun */
3168*4882a593Smuzhiyun memset(map,0,sizeof(map)); /* most characters flow through always */
3169*4882a593Smuzhiyun #ifndef __U_BOOT__
3170*4882a593Smuzhiyun mapset((uchar *)"\\$'\"`", 3); /* never flow through */
3171*4882a593Smuzhiyun mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */
3172*4882a593Smuzhiyun #else
3173*4882a593Smuzhiyun {
3174*4882a593Smuzhiyun uchar subst[2] = {SUBSTED_VAR_SYMBOL, 0};
3175*4882a593Smuzhiyun mapset(subst, 3); /* never flow through */
3176*4882a593Smuzhiyun }
3177*4882a593Smuzhiyun mapset((uchar *)"\\$'\"", 3); /* never flow through */
3178*4882a593Smuzhiyun mapset((uchar *)";&|#", 1); /* flow through if quoted */
3179*4882a593Smuzhiyun #endif
3180*4882a593Smuzhiyun mapset(ifs, 2); /* also flow through if quoted */
3181*4882a593Smuzhiyun }
3182*4882a593Smuzhiyun
3183*4882a593Smuzhiyun /* most recursion does not come through here, the exeception is
3184*4882a593Smuzhiyun * from builtin_source() */
3185*4882a593Smuzhiyun static int parse_stream_outer(struct in_str *inp, int flag)
3186*4882a593Smuzhiyun {
3187*4882a593Smuzhiyun
3188*4882a593Smuzhiyun struct p_context ctx;
3189*4882a593Smuzhiyun o_string temp=NULL_O_STRING;
3190*4882a593Smuzhiyun int rcode;
3191*4882a593Smuzhiyun #ifdef __U_BOOT__
3192*4882a593Smuzhiyun int code = 1;
3193*4882a593Smuzhiyun #endif
3194*4882a593Smuzhiyun do {
3195*4882a593Smuzhiyun ctx.type = flag;
3196*4882a593Smuzhiyun initialize_context(&ctx);
3197*4882a593Smuzhiyun update_ifs_map();
3198*4882a593Smuzhiyun if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", 0);
3199*4882a593Smuzhiyun inp->promptmode=1;
3200*4882a593Smuzhiyun rcode = parse_stream(&temp, &ctx, inp,
3201*4882a593Smuzhiyun flag & FLAG_CONT_ON_NEWLINE ? -1 : '\n');
3202*4882a593Smuzhiyun #ifdef __U_BOOT__
3203*4882a593Smuzhiyun if (rcode == 1) flag_repeat = 0;
3204*4882a593Smuzhiyun #endif
3205*4882a593Smuzhiyun if (rcode != 1 && ctx.old_flag != 0) {
3206*4882a593Smuzhiyun syntax();
3207*4882a593Smuzhiyun #ifdef __U_BOOT__
3208*4882a593Smuzhiyun flag_repeat = 0;
3209*4882a593Smuzhiyun #endif
3210*4882a593Smuzhiyun }
3211*4882a593Smuzhiyun if (rcode != 1 && ctx.old_flag == 0) {
3212*4882a593Smuzhiyun done_word(&temp, &ctx);
3213*4882a593Smuzhiyun done_pipe(&ctx,PIPE_SEQ);
3214*4882a593Smuzhiyun #ifndef __U_BOOT__
3215*4882a593Smuzhiyun run_list(ctx.list_head);
3216*4882a593Smuzhiyun #else
3217*4882a593Smuzhiyun code = run_list(ctx.list_head);
3218*4882a593Smuzhiyun if (code == -2) { /* exit */
3219*4882a593Smuzhiyun b_free(&temp);
3220*4882a593Smuzhiyun code = 0;
3221*4882a593Smuzhiyun /* XXX hackish way to not allow exit from main loop */
3222*4882a593Smuzhiyun if (inp->peek == file_peek) {
3223*4882a593Smuzhiyun printf("exit not allowed from main input shell.\n");
3224*4882a593Smuzhiyun continue;
3225*4882a593Smuzhiyun }
3226*4882a593Smuzhiyun break;
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun if (code == -1)
3229*4882a593Smuzhiyun flag_repeat = 0;
3230*4882a593Smuzhiyun #endif
3231*4882a593Smuzhiyun } else {
3232*4882a593Smuzhiyun if (ctx.old_flag != 0) {
3233*4882a593Smuzhiyun free(ctx.stack);
3234*4882a593Smuzhiyun b_reset(&temp);
3235*4882a593Smuzhiyun }
3236*4882a593Smuzhiyun #ifdef __U_BOOT__
3237*4882a593Smuzhiyun if (inp->__promptme == 0) printf("<INTERRUPT>\n");
3238*4882a593Smuzhiyun inp->__promptme = 1;
3239*4882a593Smuzhiyun #endif
3240*4882a593Smuzhiyun temp.nonnull = 0;
3241*4882a593Smuzhiyun temp.quote = 0;
3242*4882a593Smuzhiyun inp->p = NULL;
3243*4882a593Smuzhiyun free_pipe_list(ctx.list_head,0);
3244*4882a593Smuzhiyun }
3245*4882a593Smuzhiyun b_free(&temp);
3246*4882a593Smuzhiyun /* loop on syntax errors, return on EOF */
3247*4882a593Smuzhiyun } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
3248*4882a593Smuzhiyun (inp->peek != static_peek || b_peek(inp)));
3249*4882a593Smuzhiyun #ifndef __U_BOOT__
3250*4882a593Smuzhiyun return 0;
3251*4882a593Smuzhiyun #else
3252*4882a593Smuzhiyun return (code != 0) ? 1 : 0;
3253*4882a593Smuzhiyun #endif /* __U_BOOT__ */
3254*4882a593Smuzhiyun }
3255*4882a593Smuzhiyun
3256*4882a593Smuzhiyun #ifndef __U_BOOT__
3257*4882a593Smuzhiyun static int parse_string_outer(const char *s, int flag)
3258*4882a593Smuzhiyun #else
3259*4882a593Smuzhiyun int parse_string_outer(const char *s, int flag)
3260*4882a593Smuzhiyun #endif /* __U_BOOT__ */
3261*4882a593Smuzhiyun {
3262*4882a593Smuzhiyun struct in_str input;
3263*4882a593Smuzhiyun #ifdef __U_BOOT__
3264*4882a593Smuzhiyun char *p = NULL;
3265*4882a593Smuzhiyun int rcode;
3266*4882a593Smuzhiyun if (!s)
3267*4882a593Smuzhiyun return 1;
3268*4882a593Smuzhiyun if (!*s)
3269*4882a593Smuzhiyun return 0;
3270*4882a593Smuzhiyun if (!(p = strchr(s, '\n')) || *++p) {
3271*4882a593Smuzhiyun p = xmalloc(strlen(s) + 2);
3272*4882a593Smuzhiyun strcpy(p, s);
3273*4882a593Smuzhiyun strcat(p, "\n");
3274*4882a593Smuzhiyun setup_string_in_str(&input, p);
3275*4882a593Smuzhiyun rcode = parse_stream_outer(&input, flag);
3276*4882a593Smuzhiyun free(p);
3277*4882a593Smuzhiyun return rcode;
3278*4882a593Smuzhiyun } else {
3279*4882a593Smuzhiyun #endif
3280*4882a593Smuzhiyun setup_string_in_str(&input, s);
3281*4882a593Smuzhiyun return parse_stream_outer(&input, flag);
3282*4882a593Smuzhiyun #ifdef __U_BOOT__
3283*4882a593Smuzhiyun }
3284*4882a593Smuzhiyun #endif
3285*4882a593Smuzhiyun }
3286*4882a593Smuzhiyun
3287*4882a593Smuzhiyun #ifndef __U_BOOT__
3288*4882a593Smuzhiyun static int parse_file_outer(FILE *f)
3289*4882a593Smuzhiyun #else
3290*4882a593Smuzhiyun int parse_file_outer(void)
3291*4882a593Smuzhiyun #endif
3292*4882a593Smuzhiyun {
3293*4882a593Smuzhiyun int rcode;
3294*4882a593Smuzhiyun struct in_str input;
3295*4882a593Smuzhiyun #ifndef __U_BOOT__
3296*4882a593Smuzhiyun setup_file_in_str(&input, f);
3297*4882a593Smuzhiyun #else
3298*4882a593Smuzhiyun setup_file_in_str(&input);
3299*4882a593Smuzhiyun #endif
3300*4882a593Smuzhiyun rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
3301*4882a593Smuzhiyun return rcode;
3302*4882a593Smuzhiyun }
3303*4882a593Smuzhiyun
3304*4882a593Smuzhiyun #ifdef __U_BOOT__
3305*4882a593Smuzhiyun #ifdef CONFIG_NEEDS_MANUAL_RELOC
3306*4882a593Smuzhiyun static void u_boot_hush_reloc(void)
3307*4882a593Smuzhiyun {
3308*4882a593Smuzhiyun unsigned long addr;
3309*4882a593Smuzhiyun struct reserved_combo *r;
3310*4882a593Smuzhiyun
3311*4882a593Smuzhiyun for (r=reserved_list; r<reserved_list+NRES; r++) {
3312*4882a593Smuzhiyun addr = (ulong) (r->literal) + gd->reloc_off;
3313*4882a593Smuzhiyun r->literal = (char *)addr;
3314*4882a593Smuzhiyun }
3315*4882a593Smuzhiyun }
3316*4882a593Smuzhiyun #endif
3317*4882a593Smuzhiyun
3318*4882a593Smuzhiyun int u_boot_hush_start(void)
3319*4882a593Smuzhiyun {
3320*4882a593Smuzhiyun if (top_vars == NULL) {
3321*4882a593Smuzhiyun top_vars = malloc(sizeof(struct variables));
3322*4882a593Smuzhiyun top_vars->name = "HUSH_VERSION";
3323*4882a593Smuzhiyun top_vars->value = "0.01";
3324*4882a593Smuzhiyun top_vars->next = NULL;
3325*4882a593Smuzhiyun top_vars->flg_export = 0;
3326*4882a593Smuzhiyun top_vars->flg_read_only = 1;
3327*4882a593Smuzhiyun #ifdef CONFIG_NEEDS_MANUAL_RELOC
3328*4882a593Smuzhiyun u_boot_hush_reloc();
3329*4882a593Smuzhiyun #endif
3330*4882a593Smuzhiyun }
3331*4882a593Smuzhiyun return 0;
3332*4882a593Smuzhiyun }
3333*4882a593Smuzhiyun
3334*4882a593Smuzhiyun static void *xmalloc(size_t size)
3335*4882a593Smuzhiyun {
3336*4882a593Smuzhiyun void *p = NULL;
3337*4882a593Smuzhiyun
3338*4882a593Smuzhiyun if (!(p = malloc(size))) {
3339*4882a593Smuzhiyun printf("ERROR : memory not allocated\n");
3340*4882a593Smuzhiyun for(;;);
3341*4882a593Smuzhiyun }
3342*4882a593Smuzhiyun return p;
3343*4882a593Smuzhiyun }
3344*4882a593Smuzhiyun
3345*4882a593Smuzhiyun static void *xrealloc(void *ptr, size_t size)
3346*4882a593Smuzhiyun {
3347*4882a593Smuzhiyun void *p = NULL;
3348*4882a593Smuzhiyun
3349*4882a593Smuzhiyun if (!(p = realloc(ptr, size))) {
3350*4882a593Smuzhiyun printf("ERROR : memory not allocated\n");
3351*4882a593Smuzhiyun for(;;);
3352*4882a593Smuzhiyun }
3353*4882a593Smuzhiyun return p;
3354*4882a593Smuzhiyun }
3355*4882a593Smuzhiyun #endif /* __U_BOOT__ */
3356*4882a593Smuzhiyun
3357*4882a593Smuzhiyun #ifndef __U_BOOT__
3358*4882a593Smuzhiyun /* Make sure we have a controlling tty. If we get started under a job
3359*4882a593Smuzhiyun * aware app (like bash for example), make sure we are now in charge so
3360*4882a593Smuzhiyun * we don't fight over who gets the foreground */
3361*4882a593Smuzhiyun static void setup_job_control(void)
3362*4882a593Smuzhiyun {
3363*4882a593Smuzhiyun static pid_t shell_pgrp;
3364*4882a593Smuzhiyun /* Loop until we are in the foreground. */
3365*4882a593Smuzhiyun while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
3366*4882a593Smuzhiyun kill (- shell_pgrp, SIGTTIN);
3367*4882a593Smuzhiyun
3368*4882a593Smuzhiyun /* Ignore interactive and job-control signals. */
3369*4882a593Smuzhiyun signal(SIGINT, SIG_IGN);
3370*4882a593Smuzhiyun signal(SIGQUIT, SIG_IGN);
3371*4882a593Smuzhiyun signal(SIGTERM, SIG_IGN);
3372*4882a593Smuzhiyun signal(SIGTSTP, SIG_IGN);
3373*4882a593Smuzhiyun signal(SIGTTIN, SIG_IGN);
3374*4882a593Smuzhiyun signal(SIGTTOU, SIG_IGN);
3375*4882a593Smuzhiyun signal(SIGCHLD, SIG_IGN);
3376*4882a593Smuzhiyun
3377*4882a593Smuzhiyun /* Put ourselves in our own process group. */
3378*4882a593Smuzhiyun setsid();
3379*4882a593Smuzhiyun shell_pgrp = getpid ();
3380*4882a593Smuzhiyun setpgid (shell_pgrp, shell_pgrp);
3381*4882a593Smuzhiyun
3382*4882a593Smuzhiyun /* Grab control of the terminal. */
3383*4882a593Smuzhiyun tcsetpgrp(shell_terminal, shell_pgrp);
3384*4882a593Smuzhiyun }
3385*4882a593Smuzhiyun
3386*4882a593Smuzhiyun int hush_main(int argc, char * const *argv)
3387*4882a593Smuzhiyun {
3388*4882a593Smuzhiyun int opt;
3389*4882a593Smuzhiyun FILE *input;
3390*4882a593Smuzhiyun char **e = environ;
3391*4882a593Smuzhiyun
3392*4882a593Smuzhiyun /* XXX what should these be while sourcing /etc/profile? */
3393*4882a593Smuzhiyun global_argc = argc;
3394*4882a593Smuzhiyun global_argv = argv;
3395*4882a593Smuzhiyun
3396*4882a593Smuzhiyun /* (re?) initialize globals. Sometimes hush_main() ends up calling
3397*4882a593Smuzhiyun * hush_main(), therefore we cannot rely on the BSS to zero out this
3398*4882a593Smuzhiyun * stuff. Reset these to 0 every time. */
3399*4882a593Smuzhiyun ifs = NULL;
3400*4882a593Smuzhiyun /* map[] is taken care of with call to update_ifs_map() */
3401*4882a593Smuzhiyun fake_mode = 0;
3402*4882a593Smuzhiyun interactive = 0;
3403*4882a593Smuzhiyun close_me_head = NULL;
3404*4882a593Smuzhiyun last_bg_pid = 0;
3405*4882a593Smuzhiyun job_list = NULL;
3406*4882a593Smuzhiyun last_jobid = 0;
3407*4882a593Smuzhiyun
3408*4882a593Smuzhiyun /* Initialize some more globals to non-zero values */
3409*4882a593Smuzhiyun set_cwd();
3410*4882a593Smuzhiyun #ifdef CONFIG_FEATURE_COMMAND_EDITING
3411*4882a593Smuzhiyun cmdedit_set_initial_prompt();
3412*4882a593Smuzhiyun #else
3413*4882a593Smuzhiyun PS1 = NULL;
3414*4882a593Smuzhiyun #endif
3415*4882a593Smuzhiyun PS2 = "> ";
3416*4882a593Smuzhiyun
3417*4882a593Smuzhiyun /* initialize our shell local variables with the values
3418*4882a593Smuzhiyun * currently living in the environment */
3419*4882a593Smuzhiyun if (e) {
3420*4882a593Smuzhiyun for (; *e; e++)
3421*4882a593Smuzhiyun set_local_var(*e, 2); /* without call putenv() */
3422*4882a593Smuzhiyun }
3423*4882a593Smuzhiyun
3424*4882a593Smuzhiyun last_return_code=EXIT_SUCCESS;
3425*4882a593Smuzhiyun
3426*4882a593Smuzhiyun
3427*4882a593Smuzhiyun if (argv[0] && argv[0][0] == '-') {
3428*4882a593Smuzhiyun debug_printf("\nsourcing /etc/profile\n");
3429*4882a593Smuzhiyun if ((input = fopen("/etc/profile", "r")) != NULL) {
3430*4882a593Smuzhiyun mark_open(fileno(input));
3431*4882a593Smuzhiyun parse_file_outer(input);
3432*4882a593Smuzhiyun mark_closed(fileno(input));
3433*4882a593Smuzhiyun fclose(input);
3434*4882a593Smuzhiyun }
3435*4882a593Smuzhiyun }
3436*4882a593Smuzhiyun input=stdin;
3437*4882a593Smuzhiyun
3438*4882a593Smuzhiyun while ((opt = getopt(argc, argv, "c:xif")) > 0) {
3439*4882a593Smuzhiyun switch (opt) {
3440*4882a593Smuzhiyun case 'c':
3441*4882a593Smuzhiyun {
3442*4882a593Smuzhiyun global_argv = argv+optind;
3443*4882a593Smuzhiyun global_argc = argc-optind;
3444*4882a593Smuzhiyun opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
3445*4882a593Smuzhiyun goto final_return;
3446*4882a593Smuzhiyun }
3447*4882a593Smuzhiyun break;
3448*4882a593Smuzhiyun case 'i':
3449*4882a593Smuzhiyun interactive++;
3450*4882a593Smuzhiyun break;
3451*4882a593Smuzhiyun case 'f':
3452*4882a593Smuzhiyun fake_mode++;
3453*4882a593Smuzhiyun break;
3454*4882a593Smuzhiyun default:
3455*4882a593Smuzhiyun #ifndef BB_VER
3456*4882a593Smuzhiyun fprintf(stderr, "Usage: sh [FILE]...\n"
3457*4882a593Smuzhiyun " or: sh -c command [args]...\n\n");
3458*4882a593Smuzhiyun exit(EXIT_FAILURE);
3459*4882a593Smuzhiyun #else
3460*4882a593Smuzhiyun show_usage();
3461*4882a593Smuzhiyun #endif
3462*4882a593Smuzhiyun }
3463*4882a593Smuzhiyun }
3464*4882a593Smuzhiyun /* A shell is interactive if the `-i' flag was given, or if all of
3465*4882a593Smuzhiyun * the following conditions are met:
3466*4882a593Smuzhiyun * no -c command
3467*4882a593Smuzhiyun * no arguments remaining or the -s flag given
3468*4882a593Smuzhiyun * standard input is a terminal
3469*4882a593Smuzhiyun * standard output is a terminal
3470*4882a593Smuzhiyun * Refer to Posix.2, the description of the `sh' utility. */
3471*4882a593Smuzhiyun if (argv[optind]==NULL && input==stdin &&
3472*4882a593Smuzhiyun isatty(fileno(stdin)) && isatty(fileno(stdout))) {
3473*4882a593Smuzhiyun interactive++;
3474*4882a593Smuzhiyun }
3475*4882a593Smuzhiyun
3476*4882a593Smuzhiyun debug_printf("\ninteractive=%d\n", interactive);
3477*4882a593Smuzhiyun if (interactive) {
3478*4882a593Smuzhiyun /* Looks like they want an interactive shell */
3479*4882a593Smuzhiyun #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3480*4882a593Smuzhiyun printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
3481*4882a593Smuzhiyun printf( "Enter 'help' for a list of built-in commands.\n\n");
3482*4882a593Smuzhiyun #endif
3483*4882a593Smuzhiyun setup_job_control();
3484*4882a593Smuzhiyun }
3485*4882a593Smuzhiyun
3486*4882a593Smuzhiyun if (argv[optind]==NULL) {
3487*4882a593Smuzhiyun opt=parse_file_outer(stdin);
3488*4882a593Smuzhiyun goto final_return;
3489*4882a593Smuzhiyun }
3490*4882a593Smuzhiyun
3491*4882a593Smuzhiyun debug_printf("\nrunning script '%s'\n", argv[optind]);
3492*4882a593Smuzhiyun global_argv = argv+optind;
3493*4882a593Smuzhiyun global_argc = argc-optind;
3494*4882a593Smuzhiyun input = xfopen(argv[optind], "r");
3495*4882a593Smuzhiyun opt = parse_file_outer(input);
3496*4882a593Smuzhiyun
3497*4882a593Smuzhiyun #ifdef CONFIG_FEATURE_CLEAN_UP
3498*4882a593Smuzhiyun fclose(input);
3499*4882a593Smuzhiyun if (cwd && cwd != unknown)
3500*4882a593Smuzhiyun free((char*)cwd);
3501*4882a593Smuzhiyun {
3502*4882a593Smuzhiyun struct variables *cur, *tmp;
3503*4882a593Smuzhiyun for(cur = top_vars; cur; cur = tmp) {
3504*4882a593Smuzhiyun tmp = cur->next;
3505*4882a593Smuzhiyun if (!cur->flg_read_only) {
3506*4882a593Smuzhiyun free(cur->name);
3507*4882a593Smuzhiyun free(cur->value);
3508*4882a593Smuzhiyun free(cur);
3509*4882a593Smuzhiyun }
3510*4882a593Smuzhiyun }
3511*4882a593Smuzhiyun }
3512*4882a593Smuzhiyun #endif
3513*4882a593Smuzhiyun
3514*4882a593Smuzhiyun final_return:
3515*4882a593Smuzhiyun return(opt?opt:last_return_code);
3516*4882a593Smuzhiyun }
3517*4882a593Smuzhiyun #endif
3518*4882a593Smuzhiyun
3519*4882a593Smuzhiyun static char *insert_var_value(char *inp)
3520*4882a593Smuzhiyun {
3521*4882a593Smuzhiyun return insert_var_value_sub(inp, 0);
3522*4882a593Smuzhiyun }
3523*4882a593Smuzhiyun
3524*4882a593Smuzhiyun static char *insert_var_value_sub(char *inp, int tag_subst)
3525*4882a593Smuzhiyun {
3526*4882a593Smuzhiyun int res_str_len = 0;
3527*4882a593Smuzhiyun int len;
3528*4882a593Smuzhiyun int done = 0;
3529*4882a593Smuzhiyun char *p, *p1, *res_str = NULL;
3530*4882a593Smuzhiyun
3531*4882a593Smuzhiyun while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
3532*4882a593Smuzhiyun /* check the beginning of the string for normal characters */
3533*4882a593Smuzhiyun if (p != inp) {
3534*4882a593Smuzhiyun /* copy any characters to the result string */
3535*4882a593Smuzhiyun len = p - inp;
3536*4882a593Smuzhiyun res_str = xrealloc(res_str, (res_str_len + len));
3537*4882a593Smuzhiyun strncpy((res_str + res_str_len), inp, len);
3538*4882a593Smuzhiyun res_str_len += len;
3539*4882a593Smuzhiyun }
3540*4882a593Smuzhiyun inp = ++p;
3541*4882a593Smuzhiyun /* find the ending marker */
3542*4882a593Smuzhiyun p = strchr(inp, SPECIAL_VAR_SYMBOL);
3543*4882a593Smuzhiyun *p = '\0';
3544*4882a593Smuzhiyun /* look up the value to substitute */
3545*4882a593Smuzhiyun if ((p1 = lookup_param(inp))) {
3546*4882a593Smuzhiyun if (tag_subst)
3547*4882a593Smuzhiyun len = res_str_len + strlen(p1) + 2;
3548*4882a593Smuzhiyun else
3549*4882a593Smuzhiyun len = res_str_len + strlen(p1);
3550*4882a593Smuzhiyun res_str = xrealloc(res_str, (1 + len));
3551*4882a593Smuzhiyun if (tag_subst) {
3552*4882a593Smuzhiyun /*
3553*4882a593Smuzhiyun * copy the variable value to the result
3554*4882a593Smuzhiyun * string
3555*4882a593Smuzhiyun */
3556*4882a593Smuzhiyun strcpy((res_str + res_str_len + 1), p1);
3557*4882a593Smuzhiyun
3558*4882a593Smuzhiyun /*
3559*4882a593Smuzhiyun * mark the replaced text to be accepted as
3560*4882a593Smuzhiyun * is
3561*4882a593Smuzhiyun */
3562*4882a593Smuzhiyun res_str[res_str_len] = SUBSTED_VAR_SYMBOL;
3563*4882a593Smuzhiyun res_str[res_str_len + 1 + strlen(p1)] =
3564*4882a593Smuzhiyun SUBSTED_VAR_SYMBOL;
3565*4882a593Smuzhiyun } else
3566*4882a593Smuzhiyun /*
3567*4882a593Smuzhiyun * copy the variable value to the result
3568*4882a593Smuzhiyun * string
3569*4882a593Smuzhiyun */
3570*4882a593Smuzhiyun strcpy((res_str + res_str_len), p1);
3571*4882a593Smuzhiyun
3572*4882a593Smuzhiyun res_str_len = len;
3573*4882a593Smuzhiyun }
3574*4882a593Smuzhiyun *p = SPECIAL_VAR_SYMBOL;
3575*4882a593Smuzhiyun inp = ++p;
3576*4882a593Smuzhiyun done = 1;
3577*4882a593Smuzhiyun }
3578*4882a593Smuzhiyun if (done) {
3579*4882a593Smuzhiyun res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
3580*4882a593Smuzhiyun strcpy((res_str + res_str_len), inp);
3581*4882a593Smuzhiyun while ((p = strchr(res_str, '\n'))) {
3582*4882a593Smuzhiyun *p = ' ';
3583*4882a593Smuzhiyun }
3584*4882a593Smuzhiyun }
3585*4882a593Smuzhiyun return (res_str == NULL) ? inp : res_str;
3586*4882a593Smuzhiyun }
3587*4882a593Smuzhiyun
3588*4882a593Smuzhiyun static char **make_list_in(char **inp, char *name)
3589*4882a593Smuzhiyun {
3590*4882a593Smuzhiyun int len, i;
3591*4882a593Smuzhiyun int name_len = strlen(name);
3592*4882a593Smuzhiyun int n = 0;
3593*4882a593Smuzhiyun char **list;
3594*4882a593Smuzhiyun char *p1, *p2, *p3;
3595*4882a593Smuzhiyun
3596*4882a593Smuzhiyun /* create list of variable values */
3597*4882a593Smuzhiyun list = xmalloc(sizeof(*list));
3598*4882a593Smuzhiyun for (i = 0; inp[i]; i++) {
3599*4882a593Smuzhiyun p3 = insert_var_value(inp[i]);
3600*4882a593Smuzhiyun p1 = p3;
3601*4882a593Smuzhiyun while (*p1) {
3602*4882a593Smuzhiyun if (*p1 == ' ') {
3603*4882a593Smuzhiyun p1++;
3604*4882a593Smuzhiyun continue;
3605*4882a593Smuzhiyun }
3606*4882a593Smuzhiyun if ((p2 = strchr(p1, ' '))) {
3607*4882a593Smuzhiyun len = p2 - p1;
3608*4882a593Smuzhiyun } else {
3609*4882a593Smuzhiyun len = strlen(p1);
3610*4882a593Smuzhiyun p2 = p1 + len;
3611*4882a593Smuzhiyun }
3612*4882a593Smuzhiyun /* we use n + 2 in realloc for list,because we add
3613*4882a593Smuzhiyun * new element and then we will add NULL element */
3614*4882a593Smuzhiyun list = xrealloc(list, sizeof(*list) * (n + 2));
3615*4882a593Smuzhiyun list[n] = xmalloc(2 + name_len + len);
3616*4882a593Smuzhiyun strcpy(list[n], name);
3617*4882a593Smuzhiyun strcat(list[n], "=");
3618*4882a593Smuzhiyun strncat(list[n], p1, len);
3619*4882a593Smuzhiyun list[n++][name_len + len + 1] = '\0';
3620*4882a593Smuzhiyun p1 = p2;
3621*4882a593Smuzhiyun }
3622*4882a593Smuzhiyun if (p3 != inp[i]) free(p3);
3623*4882a593Smuzhiyun }
3624*4882a593Smuzhiyun list[n] = NULL;
3625*4882a593Smuzhiyun return list;
3626*4882a593Smuzhiyun }
3627*4882a593Smuzhiyun
3628*4882a593Smuzhiyun /*
3629*4882a593Smuzhiyun * Make new string for parser
3630*4882a593Smuzhiyun * inp - array of argument strings to flatten
3631*4882a593Smuzhiyun * nonnull - indicates argument was quoted when originally parsed
3632*4882a593Smuzhiyun */
3633*4882a593Smuzhiyun static char *make_string(char **inp, int *nonnull)
3634*4882a593Smuzhiyun {
3635*4882a593Smuzhiyun char *p;
3636*4882a593Smuzhiyun char *str = NULL;
3637*4882a593Smuzhiyun int n;
3638*4882a593Smuzhiyun int len = 2;
3639*4882a593Smuzhiyun char *noeval_str;
3640*4882a593Smuzhiyun int noeval = 0;
3641*4882a593Smuzhiyun
3642*4882a593Smuzhiyun noeval_str = get_local_var("HUSH_NO_EVAL");
3643*4882a593Smuzhiyun if (noeval_str != NULL && *noeval_str != '0' && *noeval_str != '\0')
3644*4882a593Smuzhiyun noeval = 1;
3645*4882a593Smuzhiyun for (n = 0; inp[n]; n++) {
3646*4882a593Smuzhiyun p = insert_var_value_sub(inp[n], noeval);
3647*4882a593Smuzhiyun str = xrealloc(str, (len + strlen(p) + (2 * nonnull[n])));
3648*4882a593Smuzhiyun if (n) {
3649*4882a593Smuzhiyun strcat(str, " ");
3650*4882a593Smuzhiyun } else {
3651*4882a593Smuzhiyun *str = '\0';
3652*4882a593Smuzhiyun }
3653*4882a593Smuzhiyun if (nonnull[n])
3654*4882a593Smuzhiyun strcat(str, "'");
3655*4882a593Smuzhiyun strcat(str, p);
3656*4882a593Smuzhiyun if (nonnull[n])
3657*4882a593Smuzhiyun strcat(str, "'");
3658*4882a593Smuzhiyun len = strlen(str) + 3;
3659*4882a593Smuzhiyun if (p != inp[n]) free(p);
3660*4882a593Smuzhiyun }
3661*4882a593Smuzhiyun len = strlen(str);
3662*4882a593Smuzhiyun *(str + len) = '\n';
3663*4882a593Smuzhiyun *(str + len + 1) = '\0';
3664*4882a593Smuzhiyun return str;
3665*4882a593Smuzhiyun }
3666*4882a593Smuzhiyun
3667*4882a593Smuzhiyun #ifdef __U_BOOT__
3668*4882a593Smuzhiyun static int do_showvar(cmd_tbl_t *cmdtp, int flag, int argc,
3669*4882a593Smuzhiyun char * const argv[])
3670*4882a593Smuzhiyun {
3671*4882a593Smuzhiyun int i, k;
3672*4882a593Smuzhiyun int rcode = 0;
3673*4882a593Smuzhiyun struct variables *cur;
3674*4882a593Smuzhiyun
3675*4882a593Smuzhiyun if (argc == 1) { /* Print all env variables */
3676*4882a593Smuzhiyun for (cur = top_vars; cur; cur = cur->next) {
3677*4882a593Smuzhiyun printf ("%s=%s\n", cur->name, cur->value);
3678*4882a593Smuzhiyun if (ctrlc ()) {
3679*4882a593Smuzhiyun puts ("\n ** Abort\n");
3680*4882a593Smuzhiyun return 1;
3681*4882a593Smuzhiyun }
3682*4882a593Smuzhiyun }
3683*4882a593Smuzhiyun return 0;
3684*4882a593Smuzhiyun }
3685*4882a593Smuzhiyun for (i = 1; i < argc; ++i) { /* print single env variables */
3686*4882a593Smuzhiyun char *name = argv[i];
3687*4882a593Smuzhiyun
3688*4882a593Smuzhiyun k = -1;
3689*4882a593Smuzhiyun for (cur = top_vars; cur; cur = cur->next) {
3690*4882a593Smuzhiyun if(strcmp (cur->name, name) == 0) {
3691*4882a593Smuzhiyun k = 0;
3692*4882a593Smuzhiyun printf ("%s=%s\n", cur->name, cur->value);
3693*4882a593Smuzhiyun }
3694*4882a593Smuzhiyun if (ctrlc ()) {
3695*4882a593Smuzhiyun puts ("\n ** Abort\n");
3696*4882a593Smuzhiyun return 1;
3697*4882a593Smuzhiyun }
3698*4882a593Smuzhiyun }
3699*4882a593Smuzhiyun if (k < 0) {
3700*4882a593Smuzhiyun printf ("## Error: \"%s\" not defined\n", name);
3701*4882a593Smuzhiyun rcode ++;
3702*4882a593Smuzhiyun }
3703*4882a593Smuzhiyun }
3704*4882a593Smuzhiyun return rcode;
3705*4882a593Smuzhiyun }
3706*4882a593Smuzhiyun
3707*4882a593Smuzhiyun U_BOOT_CMD(
3708*4882a593Smuzhiyun showvar, CONFIG_SYS_MAXARGS, 1, do_showvar,
3709*4882a593Smuzhiyun "print local hushshell variables",
3710*4882a593Smuzhiyun "\n - print values of all hushshell variables\n"
3711*4882a593Smuzhiyun "showvar name ...\n"
3712*4882a593Smuzhiyun " - print value of hushshell variable 'name'"
3713*4882a593Smuzhiyun );
3714*4882a593Smuzhiyun
3715*4882a593Smuzhiyun #endif
3716*4882a593Smuzhiyun /****************************************************************************/
3717