aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-22 14:23:34 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-22 14:23:34 +0000
commit424f79b48f8a28da687c11f98927e3bd6ca805cf (patch)
tree64e84105bd7e70ce96e8d576410e5a2d496f9d97
parente1300f6fc7a16e7c91f666192e66798eb40965be (diff)
downloadbusybox-w32-424f79b48f8a28da687c11f98927e3bd6ca805cf.tar.gz
busybox-w32-424f79b48f8a28da687c11f98927e3bd6ca805cf.tar.bz2
busybox-w32-424f79b48f8a28da687c11f98927e3bd6ca805cf.zip
hush: rearrange functions to reduce amount of forward references.
Minimal code changes.
-rw-r--r--shell/hush.c1848
1 files changed, 904 insertions, 944 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 9c0cd7c8e..0e43b63e7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1,9 +1,9 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * sh.c -- a prototype Bourne shell grammar parser 3 * A prototype Bourne shell grammar parser.
4 * Intended to follow the original Thompson and Ritchie 4 * Intended to follow the original Thompson and Ritchie
5 * "small and simple is beautiful" philosophy, which 5 * "small and simple is beautiful" philosophy, which
6 * incidentally is a good match to today's BusyBox. 6 * incidentally is a good match to today's BusyBox.
7 * 7 *
8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org> 8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
9 * 9 *
@@ -22,8 +22,8 @@
22 * Other credits: 22 * Other credits:
23 * o_addchr() derived from similar w_addchar function in glibc-2.2. 23 * o_addchr() derived from similar w_addchar function in glibc-2.2.
24 * setup_redirect(), redirect_opt_num(), and big chunks of main() 24 * setup_redirect(), redirect_opt_num(), and big chunks of main()
25 * and many builtins derived from contributions by Erik Andersen 25 * and many builtins derived from contributions by Erik Andersen.
26 * miscellaneous bugfixes from Matt Kraai. 26 * Miscellaneous bugfixes from Matt Kraai.
27 * 27 *
28 * There are two big (and related) architecture differences between 28 * There are two big (and related) architecture differences between
29 * this parser and the lash parser. One is that this version is 29 * this parser and the lash parser. One is that this version is
@@ -55,19 +55,17 @@
55 * change { and } from special chars to reserved words 55 * change { and } from special chars to reserved words
56 * builtins: return, trap, ulimit 56 * builtins: return, trap, ulimit
57 * test magic exec with redirection only 57 * test magic exec with redirection only
58 * check setting of global_argc and global_argv
59 * follow IFS rules more precisely, including update semantics 58 * follow IFS rules more precisely, including update semantics
60 * figure out what to do with backslash-newline 59 * figure out what to do with backslash-newline
61 * propagate syntax errors, die on resource errors? 60 * propagate syntax errors, die on resource errors?
62 * continuation lines, both explicit and implicit - done? 61 * continuation lines, both explicit and implicit - done?
63 * memory leak finding and plugging - done?
64 * maybe change charmap[] to use 2-bit entries 62 * maybe change charmap[] to use 2-bit entries
65 * 63 *
66 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 64 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
67 */ 65 */
68 66
69#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 67#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
70//TODO: pull in some .h and find out do we have SINGLE_APPLET_MAIN? 68//TODO: pull in some .h and find out whether we have SINGLE_APPLET_MAIN?
71//#include "applet_tables.h" doesn't work 69//#include "applet_tables.h" doesn't work
72#include <glob.h> 70#include <glob.h>
73/* #include <dmalloc.h> */ 71/* #include <dmalloc.h> */
@@ -75,7 +73,7 @@
75#include <fnmatch.h> 73#include <fnmatch.h>
76#endif 74#endif
77 75
78#define HUSH_VER_STR "0.91" 76#define HUSH_VER_STR "0.92"
79 77
80#if defined SINGLE_APPLET_MAIN 78#if defined SINGLE_APPLET_MAIN
81/* STANDALONE does not make sense, and won't compile */ 79/* STANDALONE does not make sense, and won't compile */
@@ -108,6 +106,16 @@
108#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 106#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
109#endif 107#endif
110 108
109/* Do we support ANY keywords? */
110#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
111#define HAS_KEYWORDS 1
112#define IF_HAS_KEYWORDS(...) __VA_ARGS__
113#define IF_HAS_NO_KEYWORDS(...)
114#else
115#define HAS_KEYWORDS 0
116#define IF_HAS_KEYWORDS(...)
117#define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
118#endif
111 119
112/* Keep unconditionally on for now */ 120/* Keep unconditionally on for now */
113#define HUSH_DEBUG 1 121#define HUSH_DEBUG 1
@@ -237,17 +245,9 @@ void xxfree(void *ptr)
237#endif 245#endif
238 246
239 247
240/* Do we support ANY keywords? */ 248static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
241#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
242#define HAS_KEYWORDS 1
243#define IF_HAS_KEYWORDS(...) __VA_ARGS__
244#define IF_HAS_NO_KEYWORDS(...)
245#else
246#define HAS_KEYWORDS 0
247#define IF_HAS_KEYWORDS(...)
248#define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
249#endif
250 249
250#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
251 251
252#define SPECIAL_VAR_SYMBOL 3 252#define SPECIAL_VAR_SYMBOL 3
253#define PARSEFLAG_EXIT_FROM_LOOP 1 253#define PARSEFLAG_EXIT_FROM_LOOP 1
@@ -324,7 +324,7 @@ struct command {
324 pid_t pid; /* 0 if exited */ 324 pid_t pid; /* 0 if exited */
325 int assignment_cnt; /* how many argv[i] are assignments? */ 325 int assignment_cnt; /* how many argv[i] are assignments? */
326 smallint is_stopped; /* is the command currently running? */ 326 smallint is_stopped; /* is the command currently running? */
327 smallint grp_type; 327 smallint grp_type; /* GRP_xxx */
328 struct pipe *group; /* if non-NULL, this "prog" is {} group, 328 struct pipe *group; /* if non-NULL, this "prog" is {} group,
329 * subshell, or a compound statement */ 329 * subshell, or a compound statement */
330 char **argv; /* command name and arguments */ 330 char **argv; /* command name and arguments */
@@ -442,7 +442,6 @@ enum {
442 442
443 443
444/* "Globals" within this file */ 444/* "Globals" within this file */
445
446/* Sorted roughly by size (smaller offsets == smaller code) */ 445/* Sorted roughly by size (smaller offsets == smaller code) */
447struct globals { 446struct globals {
448#if ENABLE_HUSH_INTERACTIVE 447#if ENABLE_HUSH_INTERACTIVE
@@ -503,7 +502,93 @@ struct globals {
503} while (0) 502} while (0)
504 503
505 504
506#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 505/* Function prototypes for builtins */
506static int builtin_cd(char **argv);
507static int builtin_echo(char **argv);
508static int builtin_eval(char **argv);
509static int builtin_exec(char **argv);
510static int builtin_exit(char **argv);
511static int builtin_export(char **argv);
512#if ENABLE_HUSH_JOB
513static int builtin_fg_bg(char **argv);
514static int builtin_jobs(char **argv);
515#endif
516#if ENABLE_HUSH_HELP
517static int builtin_help(char **argv);
518#endif
519static int builtin_pwd(char **argv);
520static int builtin_read(char **argv);
521static int builtin_test(char **argv);
522static int builtin_true(char **argv);
523static int builtin_set(char **argv);
524static int builtin_shift(char **argv);
525static int builtin_source(char **argv);
526static int builtin_umask(char **argv);
527static int builtin_unset(char **argv);
528#if ENABLE_HUSH_LOOPS
529static int builtin_break(char **argv);
530static int builtin_continue(char **argv);
531#endif
532//static int builtin_not_written(char **argv);
533
534/* Table of built-in functions. They can be forked or not, depending on
535 * context: within pipes, they fork. As simple commands, they do not.
536 * When used in non-forking context, they can change global variables
537 * in the parent shell process. If forked, of course they cannot.
538 * For example, 'unset foo | whatever' will parse and run, but foo will
539 * still be set at the end. */
540struct built_in_command {
541 const char *cmd;
542 int (*function)(char **argv);
543#if ENABLE_HUSH_HELP
544 const char *descr;
545#define BLTIN(cmd, func, help) { cmd, func, help }
546#else
547#define BLTIN(cmd, func, help) { cmd, func }
548#endif
549};
550
551/* For now, echo and test are unconditionally enabled.
552 * Maybe make it configurable? */
553static const struct built_in_command bltins[] = {
554 BLTIN("." , builtin_source, "Run commands in a file"),
555 BLTIN(":" , builtin_true, "No-op"),
556 BLTIN("[" , builtin_test, "Test condition"),
557 BLTIN("[[" , builtin_test, "Test condition"),
558#if ENABLE_HUSH_JOB
559 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"),
560#endif
561#if ENABLE_HUSH_LOOPS
562 BLTIN("break" , builtin_break, "Exit from a loop"),
563#endif
564 BLTIN("cd" , builtin_cd, "Change directory"),
565#if ENABLE_HUSH_LOOPS
566 BLTIN("continue", builtin_continue, "Start new loop iteration"),
567#endif
568 BLTIN("echo" , builtin_echo, "Write to stdout"),
569 BLTIN("eval" , builtin_eval, "Construct and run shell command"),
570 BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"),
571 BLTIN("exit" , builtin_exit, "Exit"),
572 BLTIN("export", builtin_export, "Set environment variable"),
573#if ENABLE_HUSH_JOB
574 BLTIN("fg" , builtin_fg_bg, "Bring job into the foreground"),
575 BLTIN("jobs" , builtin_jobs, "List active jobs"),
576#endif
577 BLTIN("pwd" , builtin_pwd, "Print current directory"),
578 BLTIN("read" , builtin_read, "Input environment variable"),
579// BLTIN("return", builtin_not_written, "Return from a function"),
580 BLTIN("set" , builtin_set, "Set/unset shell local variables"),
581 BLTIN("shift" , builtin_shift, "Shift positional parameters"),
582// BLTIN("trap" , builtin_not_written, "Trap signals"),
583 BLTIN("test" , builtin_test, "Test condition"),
584// BLTIN("ulimit", builtin_not_written, "Control resource limits"),
585 BLTIN("umask" , builtin_umask, "Set file creation mask"),
586 BLTIN("unset" , builtin_unset, "Unset environment variable"),
587#if ENABLE_HUSH_HELP
588 BLTIN("help" , builtin_help, "List shell built-in commands"),
589#endif
590};
591
507 592
508#if 1 593#if 1
509/* Normal */ 594/* Normal */
@@ -520,7 +605,6 @@ static void syntax(const char *msg)
520 bb_error_msg_and_die(msg ? "%s: %s" : "syntax error", "syntax error", msg); 605 bb_error_msg_and_die(msg ? "%s: %s" : "syntax error", "syntax error", msg);
521#endif 606#endif
522} 607}
523
524#else 608#else
525/* Debug */ 609/* Debug */
526static void syntax_lineno(int line) 610static void syntax_lineno(int line)
@@ -536,84 +620,6 @@ static void syntax_lineno(int line)
536#define syntax(str) syntax_lineno(__LINE__) 620#define syntax(str) syntax_lineno(__LINE__)
537#endif 621#endif
538 622
539/* Index of subroutines: */
540/* in_str manipulations: */
541static int static_get(struct in_str *i);
542static int static_peek(struct in_str *i);
543static int file_get(struct in_str *i);
544static int file_peek(struct in_str *i);
545static void setup_file_in_str(struct in_str *i, FILE *f);
546static void setup_string_in_str(struct in_str *i, const char *s);
547/* "run" the final data structures: */
548#if !defined(DEBUG_CLEAN)
549#define free_pipe_list(head, indent) free_pipe_list(head)
550#define free_pipe(pi, indent) free_pipe(pi)
551#endif
552static int free_pipe_list(struct pipe *head, int indent);
553static int free_pipe(struct pipe *pi, int indent);
554/* really run the final data structures: */
555typedef struct nommu_save_t {
556 char **new_env;
557 char **old_env;
558 char **argv;
559} nommu_save_t;
560#if BB_MMU
561#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
562 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
563#define pseudo_exec(nommu_save, command, argv_expanded) \
564 pseudo_exec(command, argv_expanded)
565#endif
566static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
567static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN;
568static int setup_redirects(struct command *prog, int squirrel[]);
569static int run_list(struct pipe *pi);
570static int run_pipe(struct pipe *pi);
571/* data structure manipulation: */
572static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input);
573static void initialize_context(struct parse_context *ctx);
574static int done_word(o_string *dest, struct parse_context *ctx);
575static int done_command(struct parse_context *ctx);
576static void done_pipe(struct parse_context *ctx, pipe_style type);
577/* primary string parsing: */
578static int redirect_dup_num(struct in_str *input);
579static int redirect_opt_num(o_string *o);
580#if ENABLE_HUSH_TICK
581static int process_command_subs(o_string *dest,
582 struct in_str *input, const char *subst_end);
583#endif
584static int parse_group(o_string *dest, struct parse_context *ctx, struct in_str *input, int ch);
585static const char *lookup_param(const char *src);
586static int handle_dollar(o_string *dest,
587 struct in_str *input);
588static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input0, const char *end_trigger);
589/* setup: */
590static int parse_and_run_stream(struct in_str *inp, int parse_flag);
591static int parse_and_run_string(const char *s, int parse_flag);
592static int parse_and_run_file(FILE *f);
593/* job management: */
594static int checkjobs(struct pipe* fg_pipe);
595#if ENABLE_HUSH_JOB
596static int checkjobs_and_fg_shell(struct pipe* fg_pipe);
597static void insert_bg_job(struct pipe *pi);
598static void remove_bg_job(struct pipe *pi);
599static void delete_finished_bg_job(struct pipe *pi);
600#else
601int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
602#endif
603/* local variable support */
604static char **expand_strvec_to_strvec(char **argv);
605/* used for eval */
606static char *expand_strvec_to_string(char **argv);
607/* used for expansion of right hand of assignments */
608static char *expand_string_to_string(const char *str);
609static struct variable *get_local_var(const char *name);
610static int set_local_var(char *str, int flg_export);
611static void unset_local_var(const char *name);
612
613
614static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
615
616
617static int glob_needed(const char *s) 623static int glob_needed(const char *s)
618{ 624{
619 while (*s) { 625 while (*s) {
@@ -747,94 +753,6 @@ static void free_strings(char **strings)
747} 753}
748 754
749 755
750/* Function prototypes for builtins */
751static int builtin_cd(char **argv);
752static int builtin_echo(char **argv);
753static int builtin_eval(char **argv);
754static int builtin_exec(char **argv);
755static int builtin_exit(char **argv);
756static int builtin_export(char **argv);
757#if ENABLE_HUSH_JOB
758static int builtin_fg_bg(char **argv);
759static int builtin_jobs(char **argv);
760#endif
761#if ENABLE_HUSH_HELP
762static int builtin_help(char **argv);
763#endif
764static int builtin_pwd(char **argv);
765static int builtin_read(char **argv);
766static int builtin_test(char **argv);
767static int builtin_true(char **argv);
768static int builtin_set(char **argv);
769static int builtin_shift(char **argv);
770static int builtin_source(char **argv);
771static int builtin_umask(char **argv);
772static int builtin_unset(char **argv);
773#if ENABLE_HUSH_LOOPS
774static int builtin_break(char **argv);
775static int builtin_continue(char **argv);
776#endif
777//static int builtin_not_written(char **argv);
778
779/* Table of built-in functions. They can be forked or not, depending on
780 * context: within pipes, they fork. As simple commands, they do not.
781 * When used in non-forking context, they can change global variables
782 * in the parent shell process. If forked, of course they cannot.
783 * For example, 'unset foo | whatever' will parse and run, but foo will
784 * still be set at the end. */
785struct built_in_command {
786 const char *cmd;
787 int (*function)(char **argv);
788#if ENABLE_HUSH_HELP
789 const char *descr;
790#define BLTIN(cmd, func, help) { cmd, func, help }
791#else
792#define BLTIN(cmd, func, help) { cmd, func }
793#endif
794};
795
796/* For now, echo and test are unconditionally enabled.
797 * Maybe make it configurable? */
798static const struct built_in_command bltins[] = {
799 BLTIN("." , builtin_source, "Run commands in a file"),
800 BLTIN(":" , builtin_true, "No-op"),
801 BLTIN("[" , builtin_test, "Test condition"),
802 BLTIN("[[" , builtin_test, "Test condition"),
803#if ENABLE_HUSH_JOB
804 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"),
805#endif
806#if ENABLE_HUSH_LOOPS
807 BLTIN("break" , builtin_break, "Exit from a loop"),
808#endif
809 BLTIN("cd" , builtin_cd, "Change directory"),
810#if ENABLE_HUSH_LOOPS
811 BLTIN("continue", builtin_continue, "Start new loop iteration"),
812#endif
813 BLTIN("echo" , builtin_echo, "Write to stdout"),
814 BLTIN("eval" , builtin_eval, "Construct and run shell command"),
815 BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"),
816 BLTIN("exit" , builtin_exit, "Exit"),
817 BLTIN("export", builtin_export, "Set environment variable"),
818#if ENABLE_HUSH_JOB
819 BLTIN("fg" , builtin_fg_bg, "Bring job into the foreground"),
820 BLTIN("jobs" , builtin_jobs, "List active jobs"),
821#endif
822 BLTIN("pwd" , builtin_pwd, "Print current directory"),
823 BLTIN("read" , builtin_read, "Input environment variable"),
824// BLTIN("return", builtin_not_written, "Return from a function"),
825 BLTIN("set" , builtin_set, "Set/unset shell local variables"),
826 BLTIN("shift" , builtin_shift, "Shift positional parameters"),
827// BLTIN("trap" , builtin_not_written, "Trap signals"),
828 BLTIN("test" , builtin_test, "Test condition"),
829// BLTIN("ulimit", builtin_not_written, "Control resource limits"),
830 BLTIN("umask" , builtin_umask, "Set file creation mask"),
831 BLTIN("unset" , builtin_unset, "Unset environment variable"),
832#if ENABLE_HUSH_HELP
833 BLTIN("help" , builtin_help, "List shell built-in commands"),
834#endif
835};
836
837
838/* Signals are grouped, we handle them in batches */ 756/* Signals are grouped, we handle them in batches */
839static void set_misc_sighandler(void (*handler)(int)) 757static void set_misc_sighandler(void (*handler)(int))
840{ 758{
@@ -961,8 +879,10 @@ static void hush_exit(int exitcode)
961 879
962static const char *set_cwd(void) 880static const char *set_cwd(void)
963{ 881{
882 /* xrealloc_getcwd_or_warn(arg) calls free(arg),
883 * we must not try to free(bb_msg_unknown) */
964 if (G.cwd == bb_msg_unknown) 884 if (G.cwd == bb_msg_unknown)
965 G.cwd = NULL; /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */ 885 G.cwd = NULL;
966 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd); 886 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd);
967 if (!G.cwd) 887 if (!G.cwd)
968 G.cwd = bb_msg_unknown; 888 G.cwd = bb_msg_unknown;
@@ -970,6 +890,295 @@ static const char *set_cwd(void)
970} 890}
971 891
972 892
893/* Get/check local shell variables */
894static struct variable *get_local_var(const char *name)
895{
896 struct variable *cur;
897 int len;
898
899 if (!name)
900 return NULL;
901 len = strlen(name);
902 for (cur = G.top_var; cur; cur = cur->next) {
903 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
904 return cur;
905 }
906 return NULL;
907}
908
909/* Basically useful version until someone wants to get fancier,
910 * see the bash man page under "Parameter Expansion" */
911static const char *lookup_param(const char *src)
912{
913 struct variable *var = get_local_var(src);
914 if (var)
915 return strchr(var->varstr, '=') + 1;
916 return NULL;
917}
918
919/* str holds "NAME=VAL" and is expected to be malloced.
920 * We take ownership of it. */
921static int set_local_var(char *str, int flg_export)
922{
923 struct variable *cur;
924 char *value;
925 int name_len;
926
927 value = strchr(str, '=');
928 if (!value) { /* not expected to ever happen? */
929 free(str);
930 return -1;
931 }
932
933 name_len = value - str + 1; /* including '=' */
934 cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
935 while (1) {
936 if (strncmp(cur->varstr, str, name_len) != 0) {
937 if (!cur->next) {
938 /* Bail out. Note that now cur points
939 * to last var in linked list */
940 break;
941 }
942 cur = cur->next;
943 continue;
944 }
945 /* We found an existing var with this name */
946 *value = '\0';
947 if (cur->flg_read_only) {
948 bb_error_msg("%s: readonly variable", str);
949 free(str);
950 return -1;
951 }
952 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
953 unsetenv(str); /* just in case */
954 *value = '=';
955 if (strcmp(cur->varstr, str) == 0) {
956 free_and_exp:
957 free(str);
958 goto exp;
959 }
960 if (cur->max_len >= strlen(str)) {
961 /* This one is from startup env, reuse space */
962 strcpy(cur->varstr, str);
963 goto free_and_exp;
964 }
965 /* max_len == 0 signifies "malloced" var, which we can
966 * (and has to) free */
967 if (!cur->max_len)
968 free(cur->varstr);
969 cur->max_len = 0;
970 goto set_str_and_exp;
971 }
972
973 /* Not found - create next variable struct */
974 cur->next = xzalloc(sizeof(*cur));
975 cur = cur->next;
976
977 set_str_and_exp:
978 cur->varstr = str;
979 exp:
980 if (flg_export)
981 cur->flg_export = 1;
982 if (cur->flg_export) {
983 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
984 return putenv(cur->varstr);
985 }
986 return 0;
987}
988
989static void unset_local_var(const char *name)
990{
991 struct variable *cur;
992 struct variable *prev = prev; /* for gcc */
993 int name_len;
994
995 if (!name)
996 return;
997 name_len = strlen(name);
998 cur = G.top_var;
999 while (cur) {
1000 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
1001 if (cur->flg_read_only) {
1002 bb_error_msg("%s: readonly variable", name);
1003 return;
1004 }
1005 /* prev is ok to use here because 1st variable, HUSH_VERSION,
1006 * is ro, and we cannot reach this code on the 1st pass */
1007 prev->next = cur->next;
1008 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
1009 bb_unsetenv(cur->varstr);
1010 if (!cur->max_len)
1011 free(cur->varstr);
1012 free(cur);
1013 return;
1014 }
1015 prev = cur;
1016 cur = cur->next;
1017 }
1018}
1019
1020
1021/*
1022 * in_str support
1023 */
1024static int static_get(struct in_str *i)
1025{
1026 int ch = *i->p++;
1027 if (ch == '\0') return EOF;
1028 return ch;
1029}
1030
1031static int static_peek(struct in_str *i)
1032{
1033 return *i->p;
1034}
1035
1036#if ENABLE_HUSH_INTERACTIVE
1037
1038#if ENABLE_FEATURE_EDITING
1039static void cmdedit_set_initial_prompt(void)
1040{
1041#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1042 G.PS1 = NULL;
1043#else
1044 G.PS1 = getenv("PS1");
1045 if (G.PS1 == NULL)
1046 G.PS1 = "\\w \\$ ";
1047#endif
1048}
1049#endif /* EDITING */
1050
1051static const char* setup_prompt_string(int promptmode)
1052{
1053 const char *prompt_str;
1054 debug_printf("setup_prompt_string %d ", promptmode);
1055#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1056 /* Set up the prompt */
1057 if (promptmode == 0) { /* PS1 */
1058 free((char*)G.PS1);
1059 G.PS1 = xasprintf("%s %c ", G.cwd, (geteuid() != 0) ? '$' : '#');
1060 prompt_str = G.PS1;
1061 } else {
1062 prompt_str = G.PS2;
1063 }
1064#else
1065 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2;
1066#endif
1067 debug_printf("result '%s'\n", prompt_str);
1068 return prompt_str;
1069}
1070
1071static void get_user_input(struct in_str *i)
1072{
1073 int r;
1074 const char *prompt_str;
1075
1076 prompt_str = setup_prompt_string(i->promptmode);
1077#if ENABLE_FEATURE_EDITING
1078 /* Enable command line editing only while a command line
1079 * is actually being read */
1080 do {
1081 r = read_line_input(prompt_str, G.user_input_buf, BUFSIZ-1, G.line_input_state);
1082 } while (r == 0); /* repeat if Ctrl-C */
1083 i->eof_flag = (r < 0);
1084 if (i->eof_flag) { /* EOF/error detected */
1085 G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
1086 G.user_input_buf[1] = '\0';
1087 }
1088#else
1089 fputs(prompt_str, stdout);
1090 fflush(stdout);
1091 G.user_input_buf[0] = r = fgetc(i->file);
1092 /*G.user_input_buf[1] = '\0'; - already is and never changed */
1093 i->eof_flag = (r == EOF);
1094#endif
1095 i->p = G.user_input_buf;
1096}
1097
1098#endif /* INTERACTIVE */
1099
1100/* This is the magic location that prints prompts
1101 * and gets data back from the user */
1102static int file_get(struct in_str *i)
1103{
1104 int ch;
1105
1106 /* If there is data waiting, eat it up */
1107 if (i->p && *i->p) {
1108#if ENABLE_HUSH_INTERACTIVE
1109 take_cached:
1110#endif
1111 ch = *i->p++;
1112 if (i->eof_flag && !*i->p)
1113 ch = EOF;
1114 } else {
1115 /* need to double check i->file because we might be doing something
1116 * more complicated by now, like sourcing or substituting. */
1117#if ENABLE_HUSH_INTERACTIVE
1118 if (G.interactive_fd && i->promptme && i->file == stdin) {
1119 do {
1120 get_user_input(i);
1121 } while (!*i->p); /* need non-empty line */
1122 i->promptmode = 1; /* PS2 */
1123 i->promptme = 0;
1124 goto take_cached;
1125 }
1126#endif
1127 ch = fgetc(i->file);
1128 }
1129 debug_printf("file_get: got a '%c' %d\n", ch, ch);
1130#if ENABLE_HUSH_INTERACTIVE
1131 if (ch == '\n')
1132 i->promptme = 1;
1133#endif
1134 return ch;
1135}
1136
1137/* All the callers guarantee this routine will never be
1138 * used right after a newline, so prompting is not needed.
1139 */
1140static int file_peek(struct in_str *i)
1141{
1142 int ch;
1143 if (i->p && *i->p) {
1144 if (i->eof_flag && !i->p[1])
1145 return EOF;
1146 return *i->p;
1147 }
1148 ch = fgetc(i->file);
1149 i->eof_flag = (ch == EOF);
1150 i->peek_buf[0] = ch;
1151 i->peek_buf[1] = '\0';
1152 i->p = i->peek_buf;
1153 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p);
1154 return ch;
1155}
1156
1157static void setup_file_in_str(struct in_str *i, FILE *f)
1158{
1159 i->peek = file_peek;
1160 i->get = file_get;
1161#if ENABLE_HUSH_INTERACTIVE
1162 i->promptme = 1;
1163 i->promptmode = 0; /* PS1 */
1164#endif
1165 i->file = f;
1166 i->p = NULL;
1167}
1168
1169static void setup_string_in_str(struct in_str *i, const char *s)
1170{
1171 i->peek = static_peek;
1172 i->get = static_get;
1173#if ENABLE_HUSH_INTERACTIVE
1174 i->promptme = 1;
1175 i->promptmode = 0; /* PS1 */
1176#endif
1177 i->p = s;
1178 i->eof_flag = 0;
1179}
1180
1181
973/* 1182/*
974 * o_string support 1183 * o_string support
975 */ 1184 */
@@ -1252,164 +1461,300 @@ static char **o_finalize_list(o_string *o, int n)
1252} 1461}
1253 1462
1254 1463
1255/* 1464/* expand_strvec_to_strvec() takes a list of strings, expands
1256 * in_str support 1465 * all variable references within and returns a pointer to
1257 */ 1466 * a list of expanded strings, possibly with larger number
1258static int static_get(struct in_str *i) 1467 * of strings. (Think VAR="a b"; echo $VAR).
1259{ 1468 * This new list is allocated as a single malloc block.
1260 int ch = *i->p++; 1469 * NULL-terminated list of char* pointers is at the beginning of it,
1261 if (ch == '\0') return EOF; 1470 * followed by strings themself.
1262 return ch; 1471 * Caller can deallocate entire list by single free(list). */
1263}
1264 1472
1265static int static_peek(struct in_str *i) 1473/* Store given string, finalizing the word and starting new one whenever
1474 * we encounter IFS char(s). This is used for expanding variable values.
1475 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
1476static int expand_on_ifs(o_string *output, int n, const char *str)
1266{ 1477{
1267 return *i->p; 1478 while (1) {
1479 int word_len = strcspn(str, G.ifs);
1480 if (word_len) {
1481 if (output->o_quote || !output->o_glob)
1482 o_addQstr(output, str, word_len);
1483 else /* protect backslashes against globbing up :) */
1484 o_addstr_duplicate_backslash(output, str, word_len);
1485 str += word_len;
1486 }
1487 if (!*str) /* EOL - do not finalize word */
1488 break;
1489 o_addchr(output, '\0');
1490 debug_print_list("expand_on_ifs", output, n);
1491 n = o_save_ptr(output, n);
1492 str += strspn(str, G.ifs); /* skip ifs chars */
1493 }
1494 debug_print_list("expand_on_ifs[1]", output, n);
1495 return n;
1268} 1496}
1269 1497
1270#if ENABLE_HUSH_INTERACTIVE 1498#if ENABLE_HUSH_TICK
1499static int process_command_subs(o_string *dest,
1500 struct in_str *input, const char *subst_end);
1501#endif
1271 1502
1272#if ENABLE_FEATURE_EDITING 1503/* Expand all variable references in given string, adding words to list[]
1273static void cmdedit_set_initial_prompt(void) 1504 * at n, n+1,... positions. Return updated n (so that list[n] is next one
1505 * to be filled). This routine is extremely tricky: has to deal with
1506 * variables/parameters with whitespace, $* and $@, and constructs like
1507 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
1508static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1274{ 1509{
1275#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1510 /* or_mask is either 0 (normal case) or 0x80
1276 G.PS1 = NULL; 1511 * (expansion of right-hand side of assignment == 1-element expand.
1277#else 1512 * It will also do no globbing, and thus we must not backslash-quote!) */
1278 G.PS1 = getenv("PS1"); 1513
1279 if (G.PS1 == NULL) 1514 char first_ch, ored_ch;
1280 G.PS1 = "\\w \\$ "; 1515 int i;
1516 const char *val;
1517 char *p;
1518
1519 ored_ch = 0;
1520
1521 debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
1522 debug_print_list("expand_vars_to_list", output, n);
1523 n = o_save_ptr(output, n);
1524 debug_print_list("expand_vars_to_list[0]", output, n);
1525
1526 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
1527#if ENABLE_HUSH_TICK
1528 o_string subst_result = NULL_O_STRING;
1281#endif 1529#endif
1282} 1530 o_addstr(output, arg, p - arg);
1283#endif /* EDITING */ 1531 debug_print_list("expand_vars_to_list[1]", output, n);
1532 arg = ++p;
1533 p = strchr(p, SPECIAL_VAR_SYMBOL);
1284 1534
1285static const char* setup_prompt_string(int promptmode) 1535 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
1286{ 1536 /* "$@" is special. Even if quoted, it can still
1287 const char *prompt_str; 1537 * expand to nothing (not even an empty string) */
1288 debug_printf("setup_prompt_string %d ", promptmode); 1538 if ((first_ch & 0x7f) != '@')
1289#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1539 ored_ch |= first_ch;
1290 /* Set up the prompt */ 1540 val = NULL;
1291 if (promptmode == 0) { /* PS1 */ 1541 switch (first_ch & 0x7f) {
1292 free((char*)G.PS1); 1542 /* Highest bit in first_ch indicates that var is double-quoted */
1293 G.PS1 = xasprintf("%s %c ", G.cwd, (geteuid() != 0) ? '$' : '#'); 1543 case '$': /* pid */
1294 prompt_str = G.PS1; 1544 val = utoa(G.root_pid);
1545 break;
1546 case '!': /* bg pid */
1547 val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)"";
1548 break;
1549 case '?': /* exitcode */
1550 val = utoa(G.last_return_code);
1551 break;
1552 case '#': /* argc */
1553 val = utoa(G.global_argc ? G.global_argc-1 : 0);
1554 break;
1555 case '*':
1556 case '@':
1557 i = 1;
1558 if (!G.global_argv[i])
1559 break;
1560 ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
1561 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
1562 smallint sv = output->o_quote;
1563 /* unquoted var's contents should be globbed, so don't quote */
1564 output->o_quote = 0;
1565 while (G.global_argv[i]) {
1566 n = expand_on_ifs(output, n, G.global_argv[i]);
1567 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
1568 if (G.global_argv[i++][0] && G.global_argv[i]) {
1569 /* this argv[] is not empty and not last:
1570 * put terminating NUL, start new word */
1571 o_addchr(output, '\0');
1572 debug_print_list("expand_vars_to_list[2]", output, n);
1573 n = o_save_ptr(output, n);
1574 debug_print_list("expand_vars_to_list[3]", output, n);
1575 }
1576 }
1577 output->o_quote = sv;
1578 } else
1579 /* If or_mask is nonzero, we handle assignment 'a=....$@.....'
1580 * and in this case should treat it like '$*' - see 'else...' below */
1581 if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
1582 while (1) {
1583 o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
1584 if (++i >= G.global_argc)
1585 break;
1586 o_addchr(output, '\0');
1587 debug_print_list("expand_vars_to_list[4]", output, n);
1588 n = o_save_ptr(output, n);
1589 }
1590 } else { /* quoted $*: add as one word */
1591 while (1) {
1592 o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
1593 if (!G.global_argv[++i])
1594 break;
1595 if (G.ifs[0])
1596 o_addchr(output, G.ifs[0]);
1597 }
1598 }
1599 break;
1600 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
1601 /* "Empty variable", used to make "" etc to not disappear */
1602 arg++;
1603 ored_ch = 0x80;
1604 break;
1605#if ENABLE_HUSH_TICK
1606 case '`': { /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
1607 struct in_str input;
1608 *p = '\0';
1609 arg++;
1610//TODO: can we just stuff it into "output" directly?
1611 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
1612 setup_string_in_str(&input, arg);
1613 process_command_subs(&subst_result, &input, NULL);
1614 debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
1615 val = subst_result.data;
1616 goto store_val;
1617 }
1618#endif
1619 default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
1620 *p = '\0';
1621 arg[0] = first_ch & 0x7f;
1622 if (isdigit(arg[0])) {
1623 i = xatoi_u(arg);
1624 if (i < G.global_argc)
1625 val = G.global_argv[i];
1626 /* else val remains NULL: $N with too big N */
1627 } else
1628 val = lookup_param(arg);
1629 arg[0] = first_ch;
1630#if ENABLE_HUSH_TICK
1631 store_val:
1632#endif
1633 *p = SPECIAL_VAR_SYMBOL;
1634 if (!(first_ch & 0x80)) { /* unquoted $VAR */
1635 debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote);
1636 if (val) {
1637 /* unquoted var's contents should be globbed, so don't quote */
1638 smallint sv = output->o_quote;
1639 output->o_quote = 0;
1640 n = expand_on_ifs(output, n, val);
1641 val = NULL;
1642 output->o_quote = sv;
1643 }
1644 } else { /* quoted $VAR, val will be appended below */
1645 debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
1646 }
1647 }
1648 if (val) {
1649 o_addQstr(output, val, strlen(val));
1650 }
1651
1652#if ENABLE_HUSH_TICK
1653 o_free(&subst_result);
1654#endif
1655 arg = ++p;
1656 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */
1657
1658 if (arg[0]) {
1659 debug_print_list("expand_vars_to_list[a]", output, n);
1660 /* this part is literal, and it was already pre-quoted
1661 * if needed (much earlier), do not use o_addQstr here! */
1662 o_addstr(output, arg, strlen(arg) + 1);
1663 debug_print_list("expand_vars_to_list[b]", output, n);
1664 } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
1665 && !(ored_ch & 0x80) /* and all vars were not quoted. */
1666 ) {
1667 n--;
1668 /* allow to reuse list[n] later without re-growth */
1669 output->has_empty_slot = 1;
1295 } else { 1670 } else {
1296 prompt_str = G.PS2; 1671 o_addchr(output, '\0');
1297 } 1672 }
1298#else 1673 return n;
1299 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2;
1300#endif
1301 debug_printf("result '%s'\n", prompt_str);
1302 return prompt_str;
1303} 1674}
1304 1675
1305static void get_user_input(struct in_str *i) 1676static char **expand_variables(char **argv, int or_mask)
1306{ 1677{
1307 int r; 1678 int n;
1308 const char *prompt_str; 1679 char **list;
1680 char **v;
1681 o_string output = NULL_O_STRING;
1309 1682
1310 prompt_str = setup_prompt_string(i->promptmode); 1683 if (or_mask & 0x100) {
1311#if ENABLE_FEATURE_EDITING 1684 output.o_quote = 1; /* protect against globbing for "$var" */
1312 /* Enable command line editing only while a command line 1685 /* (unquoted $var will temporarily switch it off) */
1313 * is actually being read */ 1686 output.o_glob = 1;
1314 do {
1315 r = read_line_input(prompt_str, G.user_input_buf, BUFSIZ-1, G.line_input_state);
1316 } while (r == 0); /* repeat if Ctrl-C */
1317 i->eof_flag = (r < 0);
1318 if (i->eof_flag) { /* EOF/error detected */
1319 G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
1320 G.user_input_buf[1] = '\0';
1321 } 1687 }
1322#else
1323 fputs(prompt_str, stdout);
1324 fflush(stdout);
1325 G.user_input_buf[0] = r = fgetc(i->file);
1326 /*G.user_input_buf[1] = '\0'; - already is and never changed */
1327 i->eof_flag = (r == EOF);
1328#endif
1329 i->p = G.user_input_buf;
1330}
1331 1688
1332#endif /* INTERACTIVE */ 1689 n = 0;
1690 v = argv;
1691 while (*v) {
1692 n = expand_vars_to_list(&output, n, *v, (char)or_mask);
1693 v++;
1694 }
1695 debug_print_list("expand_variables", &output, n);
1333 1696
1334/* This is the magic location that prints prompts 1697 /* output.data (malloced in one block) gets returned in "list" */
1335 * and gets data back from the user */ 1698 list = o_finalize_list(&output, n);
1336static int file_get(struct in_str *i) 1699 debug_print_strings("expand_variables[1]", list);
1337{ 1700 return list;
1338 int ch; 1701}
1339 1702
1340 /* If there is data waiting, eat it up */ 1703static char **expand_strvec_to_strvec(char **argv)
1341 if (i->p && *i->p) { 1704{
1342#if ENABLE_HUSH_INTERACTIVE 1705 return expand_variables(argv, 0x100);
1343 take_cached:
1344#endif
1345 ch = *i->p++;
1346 if (i->eof_flag && !*i->p)
1347 ch = EOF;
1348 } else {
1349 /* need to double check i->file because we might be doing something
1350 * more complicated by now, like sourcing or substituting. */
1351#if ENABLE_HUSH_INTERACTIVE
1352 if (G.interactive_fd && i->promptme && i->file == stdin) {
1353 do {
1354 get_user_input(i);
1355 } while (!*i->p); /* need non-empty line */
1356 i->promptmode = 1; /* PS2 */
1357 i->promptme = 0;
1358 goto take_cached;
1359 }
1360#endif
1361 ch = fgetc(i->file);
1362 }
1363 debug_printf("file_get: got a '%c' %d\n", ch, ch);
1364#if ENABLE_HUSH_INTERACTIVE
1365 if (ch == '\n')
1366 i->promptme = 1;
1367#endif
1368 return ch;
1369} 1706}
1370 1707
1371/* All the callers guarantee this routine will never be 1708/* Used for expansion of right hand of assignments */
1372 * used right after a newline, so prompting is not needed. 1709/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs
1373 */ 1710 * "v=/bin/c*" */
1374static int file_peek(struct in_str *i) 1711static char *expand_string_to_string(const char *str)
1375{ 1712{
1376 int ch; 1713 char *argv[2], **list;
1377 if (i->p && *i->p) { 1714
1378 if (i->eof_flag && !i->p[1]) 1715 argv[0] = (char*)str;
1379 return EOF; 1716 argv[1] = NULL;
1380 return *i->p; 1717 list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
1381 } 1718 if (HUSH_DEBUG)
1382 ch = fgetc(i->file); 1719 if (!list[0] || list[1])
1383 i->eof_flag = (ch == EOF); 1720 bb_error_msg_and_die("BUG in varexp2");
1384 i->peek_buf[0] = ch; 1721 /* actually, just move string 2*sizeof(char*) bytes back */
1385 i->peek_buf[1] = '\0'; 1722 overlapping_strcpy((char*)list, list[0]);
1386 i->p = i->peek_buf; 1723 debug_printf_expand("string_to_string='%s'\n", (char*)list);
1387 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p); 1724 return (char*)list;
1388 return ch;
1389} 1725}
1390 1726
1391static void setup_file_in_str(struct in_str *i, FILE *f) 1727/* Used for "eval" builtin */
1728static char* expand_strvec_to_string(char **argv)
1392{ 1729{
1393 i->peek = file_peek; 1730 char **list;
1394 i->get = file_get; 1731
1395#if ENABLE_HUSH_INTERACTIVE 1732 list = expand_variables(argv, 0x80);
1396 i->promptme = 1; 1733 /* Convert all NULs to spaces */
1397 i->promptmode = 0; /* PS1 */ 1734 if (list[0]) {
1398#endif 1735 int n = 1;
1399 i->file = f; 1736 while (list[n]) {
1400 i->p = NULL; 1737 if (HUSH_DEBUG)
1738 if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
1739 bb_error_msg_and_die("BUG in varexp3");
1740 list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */
1741 n++;
1742 }
1743 }
1744 overlapping_strcpy((char*)list, list[0]);
1745 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
1746 return (char*)list;
1401} 1747}
1402 1748
1403static void setup_string_in_str(struct in_str *i, const char *s) 1749static char **expand_assignments(char **argv, int count)
1404{ 1750{
1405 i->peek = static_peek; 1751 int i;
1406 i->get = static_get; 1752 char **p = NULL;
1407#if ENABLE_HUSH_INTERACTIVE 1753 /* Expand assignments into one string each */
1408 i->promptme = 1; 1754 for (i = 0; i < count; i++) {
1409 i->promptmode = 0; /* PS1 */ 1755 p = add_string_to_strings(p, expand_string_to_string(argv[i]));
1410#endif 1756 }
1411 i->p = s; 1757 return p;
1412 i->eof_flag = 0;
1413} 1758}
1414 1759
1415 1760
@@ -1469,22 +1814,104 @@ static void restore_redirects(int squirrel[])
1469 } 1814 }
1470} 1815}
1471 1816
1472static char **expand_assignments(char **argv, int count) 1817
1818#if !defined(DEBUG_CLEAN)
1819#define free_pipe_list(head, indent) free_pipe_list(head)
1820#define free_pipe(pi, indent) free_pipe(pi)
1821#endif
1822static int free_pipe_list(struct pipe *head, int indent);
1823
1824/* return code is the exit status of the pipe */
1825static int free_pipe(struct pipe *pi, int indent)
1473{ 1826{
1474 int i; 1827 char **p;
1475 char **p = NULL; 1828 struct command *command;
1476 /* Expand assignments into one string each */ 1829 struct redir_struct *r, *rnext;
1477 for (i = 0; i < count; i++) { 1830 int a, i, ret_code = 0;
1478 p = add_string_to_strings(p, expand_string_to_string(argv[i])); 1831
1832 if (pi->stopped_cmds > 0)
1833 return ret_code;
1834 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
1835 for (i = 0; i < pi->num_cmds; i++) {
1836 command = &pi->cmds[i];
1837 debug_printf_clean("%s command %d:\n", indenter(indent), i);
1838 if (command->argv) {
1839 for (a = 0, p = command->argv; *p; a++, p++) {
1840 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p);
1841 }
1842 free_strings(command->argv);
1843 command->argv = NULL;
1844 } else if (command->group) {
1845 debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type);
1846 ret_code = free_pipe_list(command->group, indent+3);
1847 debug_printf_clean("%s end group\n", indenter(indent));
1848 } else {
1849 debug_printf_clean("%s (nil)\n", indenter(indent));
1850 }
1851 for (r = command->redirects; r; r = rnext) {
1852 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
1853 if (r->dup == -1) {
1854 /* guard against the case >$FOO, where foo is unset or blank */
1855 if (r->rd_filename) {
1856 debug_printf_clean(" %s\n", r->rd_filename);
1857 free(r->rd_filename);
1858 r->rd_filename = NULL;
1859 }
1860 } else {
1861 debug_printf_clean("&%d\n", r->dup);
1862 }
1863 rnext = r->next;
1864 free(r);
1865 }
1866 command->redirects = NULL;
1479 } 1867 }
1480 return p; 1868 free(pi->cmds); /* children are an array, they get freed all at once */
1869 pi->cmds = NULL;
1870#if ENABLE_HUSH_JOB
1871 free(pi->cmdtext);
1872 pi->cmdtext = NULL;
1873#endif
1874 return ret_code;
1481} 1875}
1482 1876
1877static int free_pipe_list(struct pipe *head, int indent)
1878{
1879 int rcode = 0; /* if list has no members */
1880 struct pipe *pi, *next;
1881
1882 for (pi = head; pi; pi = next) {
1883#if HAS_KEYWORDS
1884 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
1885#endif
1886 rcode = free_pipe(pi, indent);
1887 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
1888 next = pi->next;
1889 /*pi->next = NULL;*/
1890 free(pi);
1891 }
1892 return rcode;
1893}
1894
1895
1896#if !BB_MMU
1897typedef struct nommu_save_t {
1898 char **new_env;
1899 char **old_env;
1900 char **argv;
1901} nommu_save_t;
1902#else
1903#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
1904 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
1905#define pseudo_exec(nommu_save, command, argv_expanded) \
1906 pseudo_exec(command, argv_expanded)
1907#endif
1908
1483/* Called after [v]fork() in run_pipe(), or from builtin_exec(). 1909/* Called after [v]fork() in run_pipe(), or from builtin_exec().
1484 * Never returns. 1910 * Never returns.
1485 * XXX no exit() here. If you don't exec, use _exit instead. 1911 * XXX no exit() here. If you don't exec, use _exit instead.
1486 * The at_exit handlers apparently confuse the calling process, 1912 * The at_exit handlers apparently confuse the calling process,
1487 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 1913 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */
1914static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
1488static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) 1915static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded)
1489{ 1916{
1490 int rcode; 1917 int rcode;
@@ -1554,8 +1981,11 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignme
1554 _exit(EXIT_FAILURE); 1981 _exit(EXIT_FAILURE);
1555} 1982}
1556 1983
1984static int run_list(struct pipe *pi);
1985
1557/* Called after [v]fork() in run_pipe() 1986/* Called after [v]fork() in run_pipe()
1558 */ 1987 */
1988static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN;
1559static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) 1989static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded)
1560{ 1990{
1561 if (command->argv) 1991 if (command->argv)
@@ -2461,77 +2891,6 @@ static int run_list(struct pipe *pi)
2461 return rcode; 2891 return rcode;
2462} 2892}
2463 2893
2464/* return code is the exit status of the pipe */
2465static int free_pipe(struct pipe *pi, int indent)
2466{
2467 char **p;
2468 struct command *command;
2469 struct redir_struct *r, *rnext;
2470 int a, i, ret_code = 0;
2471
2472 if (pi->stopped_cmds > 0)
2473 return ret_code;
2474 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
2475 for (i = 0; i < pi->num_cmds; i++) {
2476 command = &pi->cmds[i];
2477 debug_printf_clean("%s command %d:\n", indenter(indent), i);
2478 if (command->argv) {
2479 for (a = 0, p = command->argv; *p; a++, p++) {
2480 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p);
2481 }
2482 free_strings(command->argv);
2483 command->argv = NULL;
2484 } else if (command->group) {
2485 debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type);
2486 ret_code = free_pipe_list(command->group, indent+3);
2487 debug_printf_clean("%s end group\n", indenter(indent));
2488 } else {
2489 debug_printf_clean("%s (nil)\n", indenter(indent));
2490 }
2491 for (r = command->redirects; r; r = rnext) {
2492 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
2493 if (r->dup == -1) {
2494 /* guard against the case >$FOO, where foo is unset or blank */
2495 if (r->rd_filename) {
2496 debug_printf_clean(" %s\n", r->rd_filename);
2497 free(r->rd_filename);
2498 r->rd_filename = NULL;
2499 }
2500 } else {
2501 debug_printf_clean("&%d\n", r->dup);
2502 }
2503 rnext = r->next;
2504 free(r);
2505 }
2506 command->redirects = NULL;
2507 }
2508 free(pi->cmds); /* children are an array, they get freed all at once */
2509 pi->cmds = NULL;
2510#if ENABLE_HUSH_JOB
2511 free(pi->cmdtext);
2512 pi->cmdtext = NULL;
2513#endif
2514 return ret_code;
2515}
2516
2517static int free_pipe_list(struct pipe *head, int indent)
2518{
2519 int rcode = 0; /* if list has no members */
2520 struct pipe *pi, *next;
2521
2522 for (pi = head; pi; pi = next) {
2523#if HAS_KEYWORDS
2524 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
2525#endif
2526 rcode = free_pipe(pi, indent);
2527 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
2528 next = pi->next;
2529 /*pi->next = NULL;*/
2530 free(pi);
2531 }
2532 return rcode;
2533}
2534
2535/* Select which version we will use */ 2894/* Select which version we will use */
2536static int run_and_free_list(struct pipe *pi) 2895static int run_and_free_list(struct pipe *pi)
2537{ 2896{
@@ -2550,402 +2909,32 @@ static int run_and_free_list(struct pipe *pi)
2550} 2909}
2551 2910
2552 2911
2553/* expand_strvec_to_strvec() takes a list of strings, expands 2912/* Peek ahead in the in_str to find out if we have a "&n" construct,
2554 * all variable references within and returns a pointer to 2913 * as in "2>&1", that represents duplicating a file descriptor.
2555 * a list of expanded strings, possibly with larger number 2914 * Return either -2 (syntax error), -1 (no &), or the number found.
2556 * of strings. (Think VAR="a b"; echo $VAR). 2915 */
2557 * This new list is allocated as a single malloc block. 2916static int redirect_dup_num(struct in_str *input)
2558 * NULL-terminated list of char* pointers is at the beginning of it,
2559 * followed by strings themself.
2560 * Caller can deallocate entire list by single free(list). */
2561
2562/* Store given string, finalizing the word and starting new one whenever
2563 * we encounter IFS char(s). This is used for expanding variable values.
2564 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
2565static int expand_on_ifs(o_string *output, int n, const char *str)
2566{
2567 while (1) {
2568 int word_len = strcspn(str, G.ifs);
2569 if (word_len) {
2570 if (output->o_quote || !output->o_glob)
2571 o_addQstr(output, str, word_len);
2572 else /* protect backslashes against globbing up :) */
2573 o_addstr_duplicate_backslash(output, str, word_len);
2574 str += word_len;
2575 }
2576 if (!*str) /* EOL - do not finalize word */
2577 break;
2578 o_addchr(output, '\0');
2579 debug_print_list("expand_on_ifs", output, n);
2580 n = o_save_ptr(output, n);
2581 str += strspn(str, G.ifs); /* skip ifs chars */
2582 }
2583 debug_print_list("expand_on_ifs[1]", output, n);
2584 return n;
2585}
2586
2587/* Expand all variable references in given string, adding words to list[]
2588 * at n, n+1,... positions. Return updated n (so that list[n] is next one
2589 * to be filled). This routine is extremely tricky: has to deal with
2590 * variables/parameters with whitespace, $* and $@, and constructs like
2591 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
2592static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2593{
2594 /* or_mask is either 0 (normal case) or 0x80
2595 * (expansion of right-hand side of assignment == 1-element expand.
2596 * It will also do no globbing, and thus we must not backslash-quote!) */
2597
2598 char first_ch, ored_ch;
2599 int i;
2600 const char *val;
2601 char *p;
2602
2603 ored_ch = 0;
2604
2605 debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
2606 debug_print_list("expand_vars_to_list", output, n);
2607 n = o_save_ptr(output, n);
2608 debug_print_list("expand_vars_to_list[0]", output, n);
2609
2610 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
2611#if ENABLE_HUSH_TICK
2612 o_string subst_result = NULL_O_STRING;
2613#endif
2614 o_addstr(output, arg, p - arg);
2615 debug_print_list("expand_vars_to_list[1]", output, n);
2616 arg = ++p;
2617 p = strchr(p, SPECIAL_VAR_SYMBOL);
2618
2619 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
2620 /* "$@" is special. Even if quoted, it can still
2621 * expand to nothing (not even an empty string) */
2622 if ((first_ch & 0x7f) != '@')
2623 ored_ch |= first_ch;
2624 val = NULL;
2625 switch (first_ch & 0x7f) {
2626 /* Highest bit in first_ch indicates that var is double-quoted */
2627 case '$': /* pid */
2628 val = utoa(G.root_pid);
2629 break;
2630 case '!': /* bg pid */
2631 val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)"";
2632 break;
2633 case '?': /* exitcode */
2634 val = utoa(G.last_return_code);
2635 break;
2636 case '#': /* argc */
2637 val = utoa(G.global_argc ? G.global_argc-1 : 0);
2638 break;
2639 case '*':
2640 case '@':
2641 i = 1;
2642 if (!G.global_argv[i])
2643 break;
2644 ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
2645 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
2646 smallint sv = output->o_quote;
2647 /* unquoted var's contents should be globbed, so don't quote */
2648 output->o_quote = 0;
2649 while (G.global_argv[i]) {
2650 n = expand_on_ifs(output, n, G.global_argv[i]);
2651 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
2652 if (G.global_argv[i++][0] && G.global_argv[i]) {
2653 /* this argv[] is not empty and not last:
2654 * put terminating NUL, start new word */
2655 o_addchr(output, '\0');
2656 debug_print_list("expand_vars_to_list[2]", output, n);
2657 n = o_save_ptr(output, n);
2658 debug_print_list("expand_vars_to_list[3]", output, n);
2659 }
2660 }
2661 output->o_quote = sv;
2662 } else
2663 /* If or_mask is nonzero, we handle assignment 'a=....$@.....'
2664 * and in this case should treat it like '$*' - see 'else...' below */
2665 if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
2666 while (1) {
2667 o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
2668 if (++i >= G.global_argc)
2669 break;
2670 o_addchr(output, '\0');
2671 debug_print_list("expand_vars_to_list[4]", output, n);
2672 n = o_save_ptr(output, n);
2673 }
2674 } else { /* quoted $*: add as one word */
2675 while (1) {
2676 o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
2677 if (!G.global_argv[++i])
2678 break;
2679 if (G.ifs[0])
2680 o_addchr(output, G.ifs[0]);
2681 }
2682 }
2683 break;
2684 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
2685 /* "Empty variable", used to make "" etc to not disappear */
2686 arg++;
2687 ored_ch = 0x80;
2688 break;
2689#if ENABLE_HUSH_TICK
2690 case '`': { /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
2691 struct in_str input;
2692 *p = '\0';
2693 arg++;
2694//TODO: can we just stuff it into "output" directly?
2695 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
2696 setup_string_in_str(&input, arg);
2697 process_command_subs(&subst_result, &input, NULL);
2698 debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
2699 val = subst_result.data;
2700 goto store_val;
2701 }
2702#endif
2703 default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
2704 *p = '\0';
2705 arg[0] = first_ch & 0x7f;
2706 if (isdigit(arg[0])) {
2707 i = xatoi_u(arg);
2708 if (i < G.global_argc)
2709 val = G.global_argv[i];
2710 /* else val remains NULL: $N with too big N */
2711 } else
2712 val = lookup_param(arg);
2713 arg[0] = first_ch;
2714#if ENABLE_HUSH_TICK
2715 store_val:
2716#endif
2717 *p = SPECIAL_VAR_SYMBOL;
2718 if (!(first_ch & 0x80)) { /* unquoted $VAR */
2719 debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote);
2720 if (val) {
2721 /* unquoted var's contents should be globbed, so don't quote */
2722 smallint sv = output->o_quote;
2723 output->o_quote = 0;
2724 n = expand_on_ifs(output, n, val);
2725 val = NULL;
2726 output->o_quote = sv;
2727 }
2728 } else { /* quoted $VAR, val will be appended below */
2729 debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
2730 }
2731 }
2732 if (val) {
2733 o_addQstr(output, val, strlen(val));
2734 }
2735
2736#if ENABLE_HUSH_TICK
2737 o_free(&subst_result);
2738#endif
2739 arg = ++p;
2740 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */
2741
2742 if (arg[0]) {
2743 debug_print_list("expand_vars_to_list[a]", output, n);
2744 /* this part is literal, and it was already pre-quoted
2745 * if needed (much earlier), do not use o_addQstr here! */
2746 o_addstr(output, arg, strlen(arg) + 1);
2747 debug_print_list("expand_vars_to_list[b]", output, n);
2748 } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
2749 && !(ored_ch & 0x80) /* and all vars were not quoted. */
2750 ) {
2751 n--;
2752 /* allow to reuse list[n] later without re-growth */
2753 output->has_empty_slot = 1;
2754 } else {
2755 o_addchr(output, '\0');
2756 }
2757 return n;
2758}
2759
2760static char **expand_variables(char **argv, int or_mask)
2761{
2762 int n;
2763 char **list;
2764 char **v;
2765 o_string output = NULL_O_STRING;
2766
2767 if (or_mask & 0x100) {
2768 output.o_quote = 1; /* protect against globbing for "$var" */
2769 /* (unquoted $var will temporarily switch it off) */
2770 output.o_glob = 1;
2771 }
2772
2773 n = 0;
2774 v = argv;
2775 while (*v) {
2776 n = expand_vars_to_list(&output, n, *v, (char)or_mask);
2777 v++;
2778 }
2779 debug_print_list("expand_variables", &output, n);
2780
2781 /* output.data (malloced in one block) gets returned in "list" */
2782 list = o_finalize_list(&output, n);
2783 debug_print_strings("expand_variables[1]", list);
2784 return list;
2785}
2786
2787static char **expand_strvec_to_strvec(char **argv)
2788{
2789 return expand_variables(argv, 0x100);
2790}
2791
2792/* Used for expansion of right hand of assignments */
2793/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs
2794 * "v=/bin/c*" */
2795static char *expand_string_to_string(const char *str)
2796{
2797 char *argv[2], **list;
2798
2799 argv[0] = (char*)str;
2800 argv[1] = NULL;
2801 list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
2802 if (HUSH_DEBUG)
2803 if (!list[0] || list[1])
2804 bb_error_msg_and_die("BUG in varexp2");
2805 /* actually, just move string 2*sizeof(char*) bytes back */
2806 overlapping_strcpy((char*)list, list[0]);
2807 debug_printf_expand("string_to_string='%s'\n", (char*)list);
2808 return (char*)list;
2809}
2810
2811/* Used for "eval" builtin */
2812static char* expand_strvec_to_string(char **argv)
2813{
2814 char **list;
2815
2816 list = expand_variables(argv, 0x80);
2817 /* Convert all NULs to spaces */
2818 if (list[0]) {
2819 int n = 1;
2820 while (list[n]) {
2821 if (HUSH_DEBUG)
2822 if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
2823 bb_error_msg_and_die("BUG in varexp3");
2824 list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */
2825 n++;
2826 }
2827 }
2828 overlapping_strcpy((char*)list, list[0]);
2829 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
2830 return (char*)list;
2831}
2832
2833
2834/* Used to get/check local shell variables */
2835static struct variable *get_local_var(const char *name)
2836{
2837 struct variable *cur;
2838 int len;
2839
2840 if (!name)
2841 return NULL;
2842 len = strlen(name);
2843 for (cur = G.top_var; cur; cur = cur->next) {
2844 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
2845 return cur;
2846 }
2847 return NULL;
2848}
2849
2850/* str holds "NAME=VAL" and is expected to be malloced.
2851 * We take ownership of it. */
2852static int set_local_var(char *str, int flg_export)
2853{ 2917{
2854 struct variable *cur; 2918 int ch, d = 0, ok = 0;
2855 char *value; 2919 ch = i_peek(input);
2856 int name_len; 2920 if (ch != '&') return -1;
2857
2858 value = strchr(str, '=');
2859 if (!value) { /* not expected to ever happen? */
2860 free(str);
2861 return -1;
2862 }
2863 2921
2864 name_len = value - str + 1; /* including '=' */ 2922 i_getch(input); /* get the & */
2865 cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */ 2923 ch = i_peek(input);
2866 while (1) { 2924 if (ch == '-') {
2867 if (strncmp(cur->varstr, str, name_len) != 0) { 2925 i_getch(input);
2868 if (!cur->next) { 2926 return -3; /* "-" represents "close me" */
2869 /* Bail out. Note that now cur points
2870 * to last var in linked list */
2871 break;
2872 }
2873 cur = cur->next;
2874 continue;
2875 }
2876 /* We found an existing var with this name */
2877 *value = '\0';
2878 if (cur->flg_read_only) {
2879 bb_error_msg("%s: readonly variable", str);
2880 free(str);
2881 return -1;
2882 }
2883 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
2884 unsetenv(str); /* just in case */
2885 *value = '=';
2886 if (strcmp(cur->varstr, str) == 0) {
2887 free_and_exp:
2888 free(str);
2889 goto exp;
2890 }
2891 if (cur->max_len >= strlen(str)) {
2892 /* This one is from startup env, reuse space */
2893 strcpy(cur->varstr, str);
2894 goto free_and_exp;
2895 }
2896 /* max_len == 0 signifies "malloced" var, which we can
2897 * (and has to) free */
2898 if (!cur->max_len)
2899 free(cur->varstr);
2900 cur->max_len = 0;
2901 goto set_str_and_exp;
2902 } 2927 }
2903 2928 while (isdigit(ch)) {
2904 /* Not found - create next variable struct */ 2929 d = d*10 + (ch-'0');
2905 cur->next = xzalloc(sizeof(*cur)); 2930 ok = 1;
2906 cur = cur->next; 2931 i_getch(input);
2907 2932 ch = i_peek(input);
2908 set_str_and_exp:
2909 cur->varstr = str;
2910 exp:
2911 if (flg_export)
2912 cur->flg_export = 1;
2913 if (cur->flg_export) {
2914 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
2915 return putenv(cur->varstr);
2916 } 2933 }
2917 return 0; 2934 if (ok) return d;
2918}
2919
2920static void unset_local_var(const char *name)
2921{
2922 struct variable *cur;
2923 struct variable *prev = prev; /* for gcc */
2924 int name_len;
2925 2935
2926 if (!name) 2936 bb_error_msg("ambiguous redirect");
2927 return; 2937 return -2;
2928 name_len = strlen(name);
2929 cur = G.top_var;
2930 while (cur) {
2931 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
2932 if (cur->flg_read_only) {
2933 bb_error_msg("%s: readonly variable", name);
2934 return;
2935 }
2936 /* prev is ok to use here because 1st variable, HUSH_VERSION,
2937 * is ro, and we cannot reach this code on the 1st pass */
2938 prev->next = cur->next;
2939 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
2940 bb_unsetenv(cur->varstr);
2941 if (!cur->max_len)
2942 free(cur->varstr);
2943 free(cur);
2944 return;
2945 }
2946 prev = cur;
2947 cur = cur->next;
2948 }
2949} 2938}
2950 2939
2951/* The src parameter allows us to peek forward to a possible &n syntax 2940/* The src parameter allows us to peek forward to a possible &n syntax
@@ -2997,6 +2986,7 @@ static int setup_redirect(struct parse_context *ctx, int fd, redir_type style,
2997 return 0; 2986 return 0;
2998} 2987}
2999 2988
2989
3000static struct pipe *new_pipe(void) 2990static struct pipe *new_pipe(void)
3001{ 2991{
3002 struct pipe *pi; 2992 struct pipe *pi;
@@ -3006,6 +2996,91 @@ static struct pipe *new_pipe(void)
3006 return pi; 2996 return pi;
3007} 2997}
3008 2998
2999/* Command (member of a pipe) is complete. The only possible error here
3000 * is out of memory, in which case xmalloc exits. */
3001static int done_command(struct parse_context *ctx)
3002{
3003 /* The command is really already in the pipe structure, so
3004 * advance the pipe counter and make a new, null command. */
3005 struct pipe *pi = ctx->pipe;
3006 struct command *command = ctx->command;
3007
3008 if (command) {
3009 if (command->group == NULL
3010 && command->argv == NULL
3011 && command->redirects == NULL
3012 ) {
3013 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
3014 return pi->num_cmds;
3015 }
3016 pi->num_cmds++;
3017 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
3018 } else {
3019 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds);
3020 }
3021
3022 /* Only real trickiness here is that the uncommitted
3023 * command structure is not counted in pi->num_cmds. */
3024 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
3025 command = &pi->cmds[pi->num_cmds];
3026 memset(command, 0, sizeof(*command));
3027
3028 ctx->command = command;
3029 /* but ctx->pipe and ctx->list_head remain unchanged */
3030
3031 return pi->num_cmds; /* used only for 0/nonzero check */
3032}
3033
3034static void done_pipe(struct parse_context *ctx, pipe_style type)
3035{
3036 int not_null;
3037
3038 debug_printf_parse("done_pipe entered, followup %d\n", type);
3039 /* Close previous command */
3040 not_null = done_command(ctx);
3041 ctx->pipe->followup = type;
3042 IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;)
3043 IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;)
3044 IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
3045
3046 /* Without this check, even just <enter> on command line generates
3047 * tree of three NOPs (!). Which is harmless but annoying.
3048 * IOW: it is safe to do it unconditionally.
3049 * RES_NONE case is for "for a in; do ..." (empty IN set)
3050 * to work, possibly other cases too. */
3051 if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) {
3052 struct pipe *new_p;
3053 debug_printf_parse("done_pipe: adding new pipe: "
3054 "not_null:%d ctx->ctx_res_w:%d\n",
3055 not_null, ctx->ctx_res_w);
3056 new_p = new_pipe();
3057 ctx->pipe->next = new_p;
3058 ctx->pipe = new_p;
3059 ctx->command = NULL; /* needed! */
3060 /* RES_THEN, RES_DO etc are "sticky" -
3061 * they remain set for commands inside if/while.
3062 * This is used to control execution.
3063 * RES_FOR and RES_IN are NOT sticky (needed to support
3064 * cases where variable or value happens to match a keyword):
3065 */
3066#if ENABLE_HUSH_LOOPS
3067 if (ctx->ctx_res_w == RES_FOR
3068 || ctx->ctx_res_w == RES_IN)
3069 ctx->ctx_res_w = RES_NONE;
3070#endif
3071#if ENABLE_HUSH_CASE
3072 if (ctx->ctx_res_w == RES_MATCH)
3073 ctx->ctx_res_w = RES_CASEI;
3074#endif
3075 /* Create the memory for command, roughly:
3076 * ctx->pipe->cmds = new struct command;
3077 * ctx->command = &ctx->pipe->cmds[0];
3078 */
3079 done_command(ctx);
3080 }
3081 debug_printf_parse("done_pipe return\n");
3082}
3083
3009static void initialize_context(struct parse_context *ctx) 3084static void initialize_context(struct parse_context *ctx)
3010{ 3085{
3011 memset(ctx, 0, sizeof(*ctx)); 3086 memset(ctx, 0, sizeof(*ctx));
@@ -3017,6 +3092,7 @@ static void initialize_context(struct parse_context *ctx)
3017 done_command(ctx); 3092 done_command(ctx);
3018} 3093}
3019 3094
3095
3020/* If a reserved word is found and processed, parse context is modified 3096/* If a reserved word is found and processed, parse context is modified
3021 * and 1 is returned. 3097 * and 1 is returned.
3022 * Handles if, then, elif, else, fi, for, while, until, do, done. 3098 * Handles if, then, elif, else, fi, for, while, until, do, done.
@@ -3260,119 +3336,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3260 return 0; 3336 return 0;
3261} 3337}
3262 3338
3263/* Command (member of a pipe) is complete. The only possible error here
3264 * is out of memory, in which case xmalloc exits. */
3265static int done_command(struct parse_context *ctx)
3266{
3267 /* The command is really already in the pipe structure, so
3268 * advance the pipe counter and make a new, null command. */
3269 struct pipe *pi = ctx->pipe;
3270 struct command *command = ctx->command;
3271
3272 if (command) {
3273 if (command->group == NULL
3274 && command->argv == NULL
3275 && command->redirects == NULL
3276 ) {
3277 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
3278 return pi->num_cmds;
3279 }
3280 pi->num_cmds++;
3281 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
3282 } else {
3283 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds);
3284 }
3285
3286 /* Only real trickiness here is that the uncommitted
3287 * command structure is not counted in pi->num_cmds. */
3288 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
3289 command = &pi->cmds[pi->num_cmds];
3290 memset(command, 0, sizeof(*command));
3291
3292 ctx->command = command;
3293 /* but ctx->pipe and ctx->list_head remain unchanged */
3294
3295 return pi->num_cmds; /* used only for 0/nonzero check */
3296}
3297
3298static void done_pipe(struct parse_context *ctx, pipe_style type)
3299{
3300 int not_null;
3301
3302 debug_printf_parse("done_pipe entered, followup %d\n", type);
3303 /* Close previous command */
3304 not_null = done_command(ctx);
3305 ctx->pipe->followup = type;
3306 IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;)
3307 IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;)
3308 IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
3309
3310 /* Without this check, even just <enter> on command line generates
3311 * tree of three NOPs (!). Which is harmless but annoying.
3312 * IOW: it is safe to do it unconditionally.
3313 * RES_NONE case is for "for a in; do ..." (empty IN set)
3314 * to work, possibly other cases too. */
3315 if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) {
3316 struct pipe *new_p;
3317 debug_printf_parse("done_pipe: adding new pipe: "
3318 "not_null:%d ctx->ctx_res_w:%d\n",
3319 not_null, ctx->ctx_res_w);
3320 new_p = new_pipe();
3321 ctx->pipe->next = new_p;
3322 ctx->pipe = new_p;
3323 ctx->command = NULL; /* needed! */
3324 /* RES_THEN, RES_DO etc are "sticky" -
3325 * they remain set for commands inside if/while.
3326 * This is used to control execution.
3327 * RES_FOR and RES_IN are NOT sticky (needed to support
3328 * cases where variable or value happens to match a keyword):
3329 */
3330#if ENABLE_HUSH_LOOPS
3331 if (ctx->ctx_res_w == RES_FOR
3332 || ctx->ctx_res_w == RES_IN)
3333 ctx->ctx_res_w = RES_NONE;
3334#endif
3335#if ENABLE_HUSH_CASE
3336 if (ctx->ctx_res_w == RES_MATCH)
3337 ctx->ctx_res_w = RES_CASEI;
3338#endif
3339 /* Create the memory for command, roughly:
3340 * ctx->pipe->cmds = new struct command;
3341 * ctx->command = &ctx->pipe->cmds[0];
3342 */
3343 done_command(ctx);
3344 }
3345 debug_printf_parse("done_pipe return\n");
3346}
3347
3348/* Peek ahead in the in_str to find out if we have a "&n" construct,
3349 * as in "2>&1", that represents duplicating a file descriptor.
3350 * Return either -2 (syntax error), -1 (no &), or the number found.
3351 */
3352static int redirect_dup_num(struct in_str *input)
3353{
3354 int ch, d = 0, ok = 0;
3355 ch = i_peek(input);
3356 if (ch != '&') return -1;
3357
3358 i_getch(input); /* get the & */
3359 ch = i_peek(input);
3360 if (ch == '-') {
3361 i_getch(input);
3362 return -3; /* "-" represents "close me" */
3363 }
3364 while (isdigit(ch)) {
3365 d = d*10 + (ch-'0');
3366 ok = 1;
3367 i_getch(input);
3368 ch = i_peek(input);
3369 }
3370 if (ok) return d;
3371
3372 bb_error_msg("ambiguous redirect");
3373 return -2;
3374}
3375
3376/* If a redirect is immediately preceded by a number, that number is 3339/* If a redirect is immediately preceded by a number, that number is
3377 * supposed to tell which file descriptor to redirect. This routine 3340 * supposed to tell which file descriptor to redirect. This routine
3378 * looks for such preceding numbers. In an ideal world this routine 3341 * looks for such preceding numbers. In an ideal world this routine
@@ -3444,6 +3407,9 @@ static FILE *generate_stream_from_list(struct pipe *head)
3444 /* 'head' is freed by the caller */ 3407 /* 'head' is freed by the caller */
3445} 3408}
3446 3409
3410static int parse_stream(o_string *dest, struct parse_context *ctx,
3411 struct in_str *input0, const char *end_trigger);
3412
3447/* Return code is exit status of the process that is run. */ 3413/* Return code is exit status of the process that is run. */
3448static int process_command_subs(o_string *dest, 3414static int process_command_subs(o_string *dest,
3449 struct in_str *input, 3415 struct in_str *input,
@@ -3544,16 +3510,6 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3544 /* command remains "open", available for possible redirects */ 3510 /* command remains "open", available for possible redirects */
3545} 3511}
3546 3512
3547/* Basically useful version until someone wants to get fancier,
3548 * see the bash man page under "Parameter Expansion" */
3549static const char *lookup_param(const char *src)
3550{
3551 struct variable *var = get_local_var(src);
3552 if (var)
3553 return strchr(var->varstr, '=') + 1;
3554 return NULL;
3555}
3556
3557#if ENABLE_HUSH_TICK 3513#if ENABLE_HUSH_TICK
3558/* Subroutines for copying $(...) and `...` things */ 3514/* Subroutines for copying $(...) and `...` things */
3559static void add_till_backquote(o_string *dest, struct in_str *input); 3515static void add_till_backquote(o_string *dest, struct in_str *input);
@@ -3761,7 +3717,7 @@ static int handle_dollar(o_string *dest, struct in_str *input)
3761 * -1 on EOF (but if end_trigger == NULL then return 0), 3717 * -1 on EOF (but if end_trigger == NULL then return 0),
3762 * 1 for syntax error */ 3718 * 1 for syntax error */
3763static int parse_stream(o_string *dest, struct parse_context *ctx, 3719static int parse_stream(o_string *dest, struct parse_context *ctx,
3764 struct in_str *input, const char *end_trigger) 3720 struct in_str *input, const char *end_trigger)
3765{ 3721{
3766 int ch, m; 3722 int ch, m;
3767 int redir_fd; 3723 int redir_fd;
@@ -4680,45 +4636,49 @@ static int builtin_read(char **argv)
4680 */ 4636 */
4681static int builtin_set(char **argv) 4637static int builtin_set(char **argv)
4682{ 4638{
4683 struct variable *e; 4639 int n;
4684 char **pp; 4640 char **pp, **g_argv;
4685 char *arg = *++argv; 4641 char *arg = *++argv;
4686 4642
4687 if (arg == NULL) { 4643 if (arg == NULL) {
4644 struct variable *e;
4688 for (e = G.top_var; e; e = e->next) 4645 for (e = G.top_var; e; e = e->next)
4689 puts(e->varstr); 4646 puts(e->varstr);
4690 } else { 4647 return EXIT_SUCCESS;
4691 /* NB: G.global_argv[0] ($0) is never freed/changed */ 4648 }
4692 4649
4693 if (G.global_args_malloced) { 4650 do {
4694 pp = G.global_argv; 4651 if (arg[0] == '+')
4695 while (*++pp) 4652 continue;
4696 free(*pp); 4653 if (arg[0] != '-')
4697 G.global_argv[1] = NULL; 4654 break;
4698 } else { 4655 if (arg[1] == '-' && arg[2] == '\0') {
4699 G.global_args_malloced = 1; 4656 argv++;
4700 pp = xzalloc(sizeof(pp[0]) * 2); 4657 break;
4701 pp[0] = G.global_argv[0]; /* retain $0 */
4702 G.global_argv = pp;
4703 } 4658 }
4704 do { 4659 } while ((arg = *++argv) != NULL);
4705 if (arg[0] == '+') 4660 /* Now argv[0] is 1st argument */
4706 continue;
4707 if (arg[0] != '-')
4708 break;
4709 if (arg[1] == '-' && arg[2] == '\0') {
4710 argv++;
4711 break;
4712 }
4713 } while ((arg = *++argv) != NULL);
4714 /* Now argv[0] is 1st argument */
4715 4661
4716 /* This realloc's G.global_argv */ 4662 /* NB: G.global_argv[0] ($0) is never freed/changed */
4717 G.global_argv = pp = add_strings_to_strings(G.global_argv, argv, /*dup:*/ 1); 4663 g_argv = G.global_argv;
4718 G.global_argc = 1; 4664 if (G.global_args_malloced) {
4665 pp = g_argv;
4719 while (*++pp) 4666 while (*++pp)
4720 G.global_argc++; 4667 free(*pp);
4668 g_argv[1] = NULL;
4669 } else {
4670 G.global_args_malloced = 1;
4671 pp = xzalloc(sizeof(pp[0]) * 2);
4672 pp[0] = g_argv[0]; /* retain $0 */
4673 g_argv = pp;
4721 } 4674 }
4675 /* This realloc's G.global_argv */
4676 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
4677
4678 n = 1;
4679 while (*++pp)
4680 n++;
4681 G.global_argc = n;
4722 4682
4723 return EXIT_SUCCESS; 4683 return EXIT_SUCCESS;
4724} 4684}