source: MondoRescue/branches/stable/mindi-busybox/shell/hush.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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