1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
347 || defined(__APPLE__) \
348 )
349# include <malloc.h>
350#endif
351#include <glob.h>
352
353#if ENABLE_HUSH_CASE
354# include <fnmatch.h>
355#endif
356#include <sys/times.h>
357#include <sys/utsname.h>
358
359#include "busybox.h"
360#include "unicode.h"
361#include "shell_common.h"
362#include "math.h"
363#include "match.h"
364#if ENABLE_HUSH_RANDOM_SUPPORT
365# include "random.h"
366#else
367# define CLEAR_RANDOM_T(rnd) ((void)0)
368#endif
369#ifndef O_CLOEXEC
370# define O_CLOEXEC 0
371#endif
372#ifndef F_DUPFD_CLOEXEC
373# define F_DUPFD_CLOEXEC F_DUPFD
374#endif
375
376#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !ENABLE_SHELL_ASH
377# include "embedded_scripts.h"
378#else
379# define NUM_SCRIPTS 0
380#endif
381
382
383
384#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
385#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
386#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
387#define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT
388#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
389#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
390#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
391#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
392
393
394
395#define LEAK_HUNTING 0
396#define BUILD_AS_NOMMU 0
397
398
399
400
401#define HUSH_DEBUG 1
402
403
404
405
406
407
408#define ENABLE_HUSH_FAST 0
409
410
411
412#define ENABLE_HUSH_DOLLAR_OPS 1
413
414
415#if BUILD_AS_NOMMU
416# undef BB_MMU
417# undef USE_FOR_NOMMU
418# undef USE_FOR_MMU
419# define BB_MMU 0
420# define USE_FOR_NOMMU(...) __VA_ARGS__
421# define USE_FOR_MMU(...)
422#endif
423
424#include "NUM_APPLETS.h"
425#if NUM_APPLETS == 1
426
427# undef CONFIG_FEATURE_SH_STANDALONE
428# undef ENABLE_FEATURE_SH_STANDALONE
429# undef IF_FEATURE_SH_STANDALONE
430# undef IF_NOT_FEATURE_SH_STANDALONE
431# define ENABLE_FEATURE_SH_STANDALONE 0
432# define IF_FEATURE_SH_STANDALONE(...)
433# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
434#endif
435
436#if !ENABLE_HUSH_INTERACTIVE
437# undef ENABLE_FEATURE_EDITING
438# define ENABLE_FEATURE_EDITING 0
439# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
440# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
441# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
442# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0
443#endif
444
445
446#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
447# define HAS_KEYWORDS 1
448# define IF_HAS_KEYWORDS(...) __VA_ARGS__
449# define IF_HAS_NO_KEYWORDS(...)
450#else
451# define HAS_KEYWORDS 0
452# define IF_HAS_KEYWORDS(...)
453# define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
454#endif
455
456
457
458#define debug_printf(...) do {} while (0)
459
460#define debug_printf_parse(...) do {} while (0)
461#define debug_printf_heredoc(...) do {} while (0)
462#define debug_print_tree(a, b) do {} while (0)
463#define debug_printf_exec(...) do {} while (0)
464#define debug_printf_env(...) do {} while (0)
465#define debug_printf_jobs(...) do {} while (0)
466#define debug_printf_expand(...) do {} while (0)
467#define debug_printf_varexp(...) do {} while (0)
468#define debug_printf_glob(...) do {} while (0)
469#define debug_printf_redir(...) do {} while (0)
470#define debug_printf_list(...) do {} while (0)
471#define debug_printf_subst(...) do {} while (0)
472#define debug_printf_prompt(...) do {} while (0)
473#define debug_printf_clean(...) do {} while (0)
474
475#define ERR_PTR ((void*)(long)1)
476
477#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n"
478
479#define _SPECIAL_VARS_STR "_*@$!?#-"
480#define SPECIAL_VARS_STR ("_*@$!?#-" + 1)
481#define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3)
482#if BASH_PATTERN_SUBST
483
484
485# define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?"
486# define VAR_SUBST_OPS ("\\/%#:-=+?" + 1)
487# define MINUS_PLUS_EQUAL_QUESTION ("\\/%#:-=+?" + 5)
488#else
489# define VAR_ENCODED_SUBST_OPS "%#:-=+?"
490# define VAR_SUBST_OPS "%#:-=+?"
491# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3)
492#endif
493
494#define SPECIAL_VAR_SYMBOL_STR "\3"
495#define SPECIAL_VAR_SYMBOL 3
496
497#define SPECIAL_VAR_QUOTED_SVS 1
498
499struct variable;
500
501static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
502
503
504
505
506#if !BB_MMU
507typedef struct nommu_save_t {
508 struct variable *old_vars;
509 char **argv;
510 char **argv_from_re_execing;
511} nommu_save_t;
512#endif
513
514enum {
515 RES_NONE = 0,
516#if ENABLE_HUSH_IF
517 RES_IF ,
518 RES_THEN ,
519 RES_ELIF ,
520 RES_ELSE ,
521 RES_FI ,
522#endif
523#if ENABLE_HUSH_LOOPS
524 RES_FOR ,
525 RES_WHILE ,
526 RES_UNTIL ,
527 RES_DO ,
528 RES_DONE ,
529#endif
530#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
531 RES_IN ,
532#endif
533#if ENABLE_HUSH_CASE
534 RES_CASE ,
535
536 RES_CASE_IN,
537 RES_MATCH ,
538 RES_CASE_BODY,
539 RES_ESAC ,
540#endif
541 RES_XXXX ,
542 RES_SNTX
543};
544
545typedef struct o_string {
546 char *data;
547 int length;
548 int maxlen;
549 int o_expflags;
550
551
552 smallint has_quoted_part;
553 smallint has_empty_slot;
554 smallint ended_in_ifs;
555} o_string;
556enum {
557 EXP_FLAG_SINGLEWORD = 0x80,
558 EXP_FLAG_GLOB = 0x2,
559
560
561 EXP_FLAG_ESC_GLOB_CHARS = 0x1,
562};
563
564#define NULL_O_STRING { NULL }
565
566#ifndef debug_printf_parse
567static const char *const assignment_flag[] = {
568 "MAYBE_ASSIGNMENT",
569 "DEFINITELY_ASSIGNMENT",
570 "NOT_ASSIGNMENT",
571 "WORD_IS_KEYWORD",
572};
573#endif
574
575
576
577
578
579
580
581
582typedef struct HFILE {
583 char *cur;
584 char *end;
585 struct HFILE *next_hfile;
586 int fd;
587 char buf[1024];
588} HFILE;
589
590typedef struct in_str {
591 const char *p;
592 int peek_buf[2];
593 int last_char;
594 HFILE *file;
595} in_str;
596
597
598
599static const struct {
600 int32_t mode;
601 signed char default_fd;
602 char descrip[3];
603} redir_table[] ALIGN4 = {
604 { O_RDONLY, 0, "<" },
605 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
606 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
607 { O_CREAT|O_RDWR, 1, "<>" },
608 { O_RDONLY, 0, "<<" },
609
610
611};
612
613struct redir_struct {
614 struct redir_struct *next;
615 char *rd_filename;
616 int rd_fd;
617
618 int rd_dup;
619 smallint rd_type;
620
621
622
623
624
625};
626typedef enum redir_type {
627 REDIRECT_INPUT = 0,
628 REDIRECT_OVERWRITE = 1,
629 REDIRECT_APPEND = 2,
630 REDIRECT_IO = 3,
631 REDIRECT_HEREDOC = 4,
632 REDIRECT_HEREDOC2 = 5,
633
634 REDIRFD_CLOSE = -3,
635 REDIRFD_SYNTAX_ERR = -2,
636 REDIRFD_TO_FILE = -1,
637
638
639 HEREDOC_SKIPTABS = 1,
640 HEREDOC_QUOTED = 2,
641} redir_type;
642
643
644struct command {
645 pid_t pid;
646 unsigned assignment_cnt;
647#if ENABLE_HUSH_LINENO_VAR
648 unsigned lineno;
649#endif
650 smallint cmd_type;
651#define CMD_NORMAL 0
652#define CMD_SUBSHELL 1
653#if BASH_TEST2
654
655# define CMD_TEST2_SINGLEWORD_NOGLOB 2
656#endif
657#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
658
659# define CMD_SINGLEWORD_NOGLOB 3
660#endif
661#if ENABLE_HUSH_FUNCTIONS
662# define CMD_FUNCDEF 4
663#endif
664
665 smalluint cmd_exitcode;
666
667 struct pipe *group;
668#if !BB_MMU
669 char *group_as_string;
670#endif
671#if ENABLE_HUSH_FUNCTIONS
672 struct function *child_func;
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687#endif
688 char **argv;
689
690
691
692
693
694
695 struct redir_struct *redirects;
696};
697
698#define IS_NULL_CMD(cmd) \
699 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
700
701struct pipe {
702 struct pipe *next;
703 int num_cmds;
704 int alive_cmds;
705 int stopped_cmds;
706#if ENABLE_HUSH_JOB
707 unsigned jobid;
708 pid_t pgrp;
709 char *cmdtext;
710#endif
711 struct command *cmds;
712 smallint followup;
713 IF_HAS_KEYWORDS(smallint pi_inverted;)
714 IF_HAS_KEYWORDS(smallint res_word;)
715};
716typedef enum pipe_style {
717 PIPE_SEQ = 0,
718 PIPE_AND = 1,
719 PIPE_OR = 2,
720 PIPE_BG = 3,
721} pipe_style;
722
723#define IS_NULL_PIPE(pi) \
724 ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE))
725
726
727struct parse_context {
728
729 struct pipe *list_head;
730
731 struct pipe *pipe;
732
733 struct command *command;
734
735 struct redir_struct *pending_redirect;
736 o_string word;
737#if !BB_MMU
738 o_string as_string;
739#endif
740 smallint is_assignment;
741#if HAS_KEYWORDS
742 smallint ctx_res_w;
743 smallint ctx_inverted;
744#if ENABLE_HUSH_CASE
745 smallint ctx_dsemicolon;
746#endif
747
748 int old_flag;
749
750
751
752
753
754
755
756
757
758 struct parse_context *stack;
759#endif
760};
761enum {
762 MAYBE_ASSIGNMENT = 0,
763 DEFINITELY_ASSIGNMENT = 1,
764 NOT_ASSIGNMENT = 2,
765
766 WORD_IS_KEYWORD = 3,
767};
768
769
770
771
772
773
774#define setenv(...) setenv_is_leaky_dont_use()
775struct variable {
776 struct variable *next;
777 char *varstr;
778 int max_len;
779 uint16_t var_nest_level;
780 smallint flg_export;
781 smallint flg_read_only;
782};
783
784enum {
785 BC_BREAK = 1,
786 BC_CONTINUE = 2,
787};
788
789#if ENABLE_HUSH_FUNCTIONS
790struct function {
791 struct function *next;
792 char *name;
793 struct command *parent_cmd;
794 struct pipe *body;
795# if !BB_MMU
796 char *body_as_string;
797# endif
798};
799#endif
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832static const char o_opt_strings[] ALIGN1 =
833 "pipefail\0"
834 "noexec\0"
835 "errexit\0"
836#if ENABLE_HUSH_MODE_X
837 "xtrace\0"
838#endif
839 ;
840enum {
841 OPT_O_PIPEFAIL,
842 OPT_O_NOEXEC,
843 OPT_O_ERREXIT,
844#if ENABLE_HUSH_MODE_X
845 OPT_O_XTRACE,
846#endif
847 NUM_OPT_O
848};
849
850
851
852struct globals {
853
854
855
856
857
858
859
860
861
862
863
864#if ENABLE_HUSH_INTERACTIVE
865
866
867 int interactive_fd;
868 IF_NOT_FEATURE_EDITING_FANCY_PROMPT(char *PS1;)
869# define G_interactive_fd (G.interactive_fd)
870#else
871# define G_interactive_fd 0
872#endif
873#if ENABLE_FEATURE_EDITING
874 line_input_t *line_input_state;
875#endif
876 pid_t root_pid;
877 pid_t root_ppid;
878 pid_t last_bg_pid;
879#if ENABLE_HUSH_RANDOM_SUPPORT
880 random_t random_gen;
881#endif
882#if ENABLE_HUSH_JOB
883 int run_list_level;
884 unsigned last_jobid;
885 pid_t saved_tty_pgrp;
886 struct pipe *job_list;
887# define G_saved_tty_pgrp (G.saved_tty_pgrp)
888#else
889# define G_saved_tty_pgrp 0
890#endif
891
892 int errexit_depth;
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910 char o_opt[NUM_OPT_O];
911#if ENABLE_HUSH_MODE_X
912# define G_x_mode (G.o_opt[OPT_O_XTRACE])
913#else
914# define G_x_mode 0
915#endif
916 char opt_s;
917 char opt_c;
918#if ENABLE_HUSH_INTERACTIVE
919 smallint promptmode;
920#endif
921 smallint flag_SIGINT;
922#if ENABLE_HUSH_LOOPS
923 smallint flag_break_continue;
924#endif
925#if ENABLE_HUSH_FUNCTIONS
926
927
928
929
930 smallint flag_return_in_progress;
931# define G_flag_return_in_progress (G.flag_return_in_progress)
932#else
933# define G_flag_return_in_progress 0
934#endif
935 smallint exiting;
936
937 smalluint last_exitcode;
938 smalluint expand_exitcode;
939 smalluint last_bg_pid_exitcode;
940#if ENABLE_HUSH_SET
941
942 smalluint global_args_malloced;
943# define G_global_args_malloced (G.global_args_malloced)
944#else
945# define G_global_args_malloced 0
946#endif
947#if ENABLE_HUSH_BASH_COMPAT
948 int dead_job_exitcode;
949#endif
950
951 int global_argc;
952 char **global_argv;
953#if !BB_MMU
954 char *argv0_for_re_execing;
955#endif
956#if ENABLE_HUSH_LOOPS
957 unsigned depth_break_continue;
958 unsigned depth_of_loop;
959#endif
960#if ENABLE_HUSH_GETOPTS
961 unsigned getopt_count;
962#endif
963 const char *ifs;
964 char *ifs_whitespace;
965 const char *cwd;
966 struct variable *top_var;
967 char **expanded_assignments;
968 struct variable **shadowed_vars_pp;
969 unsigned var_nest_level;
970#if ENABLE_HUSH_FUNCTIONS
971# if ENABLE_HUSH_LOCAL
972 unsigned func_nest_level;
973# endif
974 struct function *top_func;
975#endif
976
977#if ENABLE_HUSH_FAST
978 unsigned count_SIGCHLD;
979 unsigned handled_SIGCHLD;
980 smallint we_have_children;
981#endif
982#if ENABLE_HUSH_LINENO_VAR
983 unsigned parse_lineno;
984 unsigned execute_lineno;
985#endif
986 HFILE *HFILE_list;
987 HFILE *HFILE_stdin;
988
989
990
991
992
993
994
995 unsigned special_sig_mask;
996#if ENABLE_HUSH_JOB
997 unsigned fatal_sig_mask;
998# define G_fatal_sig_mask (G.fatal_sig_mask)
999#else
1000# define G_fatal_sig_mask 0
1001#endif
1002#if ENABLE_HUSH_TRAP
1003 int pre_trap_exitcode;
1004# if ENABLE_HUSH_FUNCTIONS
1005 int return_exitcode;
1006# endif
1007 char **traps;
1008# define G_traps G.traps
1009#else
1010# define G_traps ((char**)NULL)
1011#endif
1012 sigset_t pending_set;
1013#if ENABLE_HUSH_MEMLEAK
1014 unsigned long memleak_value;
1015#endif
1016#if ENABLE_HUSH_MODE_X
1017 unsigned x_mode_depth;
1018
1019
1020
1021
1022 int x_mode_fd;
1023 o_string x_mode_buf;
1024#endif
1025#if HUSH_DEBUG >= 2
1026 int debug_indent;
1027#endif
1028 struct sigaction sa;
1029 char optstring_buf[sizeof("eixcs")];
1030#if BASH_EPOCH_VARS
1031 char epoch_buf[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
1032#endif
1033#if ENABLE_FEATURE_EDITING
1034 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
1035#endif
1036};
1037#define G (*ptr_to_globals)
1038
1039
1040
1041#define INIT_G() do { \
1042 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
1043 \
1044 sigfillset(&G.sa.sa_mask); \
1045 G.sa.sa_flags = SA_RESTART; \
1046} while (0)
1047
1048
1049
1050static int builtin_cd(char **argv) FAST_FUNC;
1051#if ENABLE_HUSH_ECHO
1052static int builtin_echo(char **argv) FAST_FUNC;
1053#endif
1054static int builtin_eval(char **argv) FAST_FUNC;
1055static int builtin_exec(char **argv) FAST_FUNC;
1056static int builtin_exit(char **argv) FAST_FUNC;
1057#if ENABLE_HUSH_EXPORT
1058static int builtin_export(char **argv) FAST_FUNC;
1059#endif
1060#if ENABLE_HUSH_READONLY
1061static int builtin_readonly(char **argv) FAST_FUNC;
1062#endif
1063#if ENABLE_HUSH_JOB
1064static int builtin_fg_bg(char **argv) FAST_FUNC;
1065static int builtin_jobs(char **argv) FAST_FUNC;
1066#endif
1067#if ENABLE_HUSH_GETOPTS
1068static int builtin_getopts(char **argv) FAST_FUNC;
1069#endif
1070#if ENABLE_HUSH_HELP
1071static int builtin_help(char **argv) FAST_FUNC;
1072#endif
1073#if MAX_HISTORY && ENABLE_FEATURE_EDITING
1074static int builtin_history(char **argv) FAST_FUNC;
1075#endif
1076#if ENABLE_HUSH_LOCAL
1077static int builtin_local(char **argv) FAST_FUNC;
1078#endif
1079#if ENABLE_HUSH_MEMLEAK
1080static int builtin_memleak(char **argv) FAST_FUNC;
1081#endif
1082#if ENABLE_HUSH_PRINTF
1083static int builtin_printf(char **argv) FAST_FUNC;
1084#endif
1085static int builtin_pwd(char **argv) FAST_FUNC;
1086#if ENABLE_HUSH_READ
1087static int builtin_read(char **argv) FAST_FUNC;
1088#endif
1089#if ENABLE_HUSH_SET
1090static int builtin_set(char **argv) FAST_FUNC;
1091#endif
1092static int builtin_shift(char **argv) FAST_FUNC;
1093static int builtin_source(char **argv) FAST_FUNC;
1094#if ENABLE_HUSH_TEST || BASH_TEST2
1095static int builtin_test(char **argv) FAST_FUNC;
1096#endif
1097#if ENABLE_HUSH_TRAP
1098static int builtin_trap(char **argv) FAST_FUNC;
1099#endif
1100#if ENABLE_HUSH_TYPE
1101static int builtin_type(char **argv) FAST_FUNC;
1102#endif
1103#if ENABLE_HUSH_TIMES
1104static int builtin_times(char **argv) FAST_FUNC;
1105#endif
1106static int builtin_true(char **argv) FAST_FUNC;
1107#if ENABLE_HUSH_UMASK
1108static int builtin_umask(char **argv) FAST_FUNC;
1109#endif
1110#if ENABLE_HUSH_UNSET
1111static int builtin_unset(char **argv) FAST_FUNC;
1112#endif
1113#if ENABLE_HUSH_KILL
1114static int builtin_kill(char **argv) FAST_FUNC;
1115#endif
1116#if ENABLE_HUSH_WAIT
1117static int builtin_wait(char **argv) FAST_FUNC;
1118#endif
1119#if ENABLE_HUSH_LOOPS
1120static int builtin_break(char **argv) FAST_FUNC;
1121static int builtin_continue(char **argv) FAST_FUNC;
1122#endif
1123#if ENABLE_HUSH_FUNCTIONS
1124static int builtin_return(char **argv) FAST_FUNC;
1125#endif
1126
1127
1128
1129
1130
1131
1132
1133struct built_in_command {
1134 const char *b_cmd;
1135 int (*b_function)(char **argv) FAST_FUNC;
1136#if ENABLE_HUSH_HELP
1137 const char *b_descr;
1138# define BLTIN(cmd, func, help) { cmd, func, help }
1139#else
1140# define BLTIN(cmd, func, help) { cmd, func }
1141#endif
1142};
1143
1144static const struct built_in_command bltins1[] ALIGN_PTR = {
1145 BLTIN("." , builtin_source , "Run commands in file"),
1146 BLTIN(":" , builtin_true , NULL),
1147#if ENABLE_HUSH_JOB
1148 BLTIN("bg" , builtin_fg_bg , "Resume job in background"),
1149#endif
1150#if ENABLE_HUSH_LOOPS
1151 BLTIN("break" , builtin_break , "Exit loop"),
1152#endif
1153 BLTIN("cd" , builtin_cd , "Change directory"),
1154#if ENABLE_HUSH_LOOPS
1155 BLTIN("continue" , builtin_continue, "Start new loop iteration"),
1156#endif
1157 BLTIN("eval" , builtin_eval , "Construct and run shell command"),
1158 BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"),
1159 BLTIN("exit" , builtin_exit , NULL),
1160#if ENABLE_HUSH_EXPORT
1161 BLTIN("export" , builtin_export , "Set environment variables"),
1162#endif
1163#if ENABLE_HUSH_JOB
1164 BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"),
1165#endif
1166#if ENABLE_HUSH_GETOPTS
1167 BLTIN("getopts" , builtin_getopts , NULL),
1168#endif
1169#if ENABLE_HUSH_HELP
1170 BLTIN("help" , builtin_help , NULL),
1171#endif
1172#if MAX_HISTORY && ENABLE_FEATURE_EDITING
1173 BLTIN("history" , builtin_history , "Show history"),
1174#endif
1175#if ENABLE_HUSH_JOB
1176 BLTIN("jobs" , builtin_jobs , "List jobs"),
1177#endif
1178#if ENABLE_HUSH_KILL
1179 BLTIN("kill" , builtin_kill , "Send signals to processes"),
1180#endif
1181#if ENABLE_HUSH_LOCAL
1182 BLTIN("local" , builtin_local , "Set local variables"),
1183#endif
1184#if ENABLE_HUSH_MEMLEAK
1185 BLTIN("memleak" , builtin_memleak , NULL),
1186#endif
1187#if ENABLE_HUSH_READ
1188 BLTIN("read" , builtin_read , "Input into variable"),
1189#endif
1190#if ENABLE_HUSH_READONLY
1191 BLTIN("readonly" , builtin_readonly, "Make variables read-only"),
1192#endif
1193#if ENABLE_HUSH_FUNCTIONS
1194 BLTIN("return" , builtin_return , "Return from function"),
1195#endif
1196#if ENABLE_HUSH_SET
1197 BLTIN("set" , builtin_set , "Set positional parameters"),
1198#endif
1199 BLTIN("shift" , builtin_shift , "Shift positional parameters"),
1200#if BASH_SOURCE
1201 BLTIN("source" , builtin_source , NULL),
1202#endif
1203#if ENABLE_HUSH_TIMES
1204 BLTIN("times" , builtin_times , NULL),
1205#endif
1206#if ENABLE_HUSH_TRAP
1207 BLTIN("trap" , builtin_trap , "Trap signals"),
1208#endif
1209 BLTIN("true" , builtin_true , NULL),
1210#if ENABLE_HUSH_TYPE
1211 BLTIN("type" , builtin_type , "Show command type"),
1212#endif
1213#if ENABLE_HUSH_ULIMIT
1214 BLTIN("ulimit" , shell_builtin_ulimit, "Control resource limits"),
1215#endif
1216#if ENABLE_HUSH_UMASK
1217 BLTIN("umask" , builtin_umask , "Set file creation mask"),
1218#endif
1219#if ENABLE_HUSH_UNSET
1220 BLTIN("unset" , builtin_unset , "Unset variables"),
1221#endif
1222#if ENABLE_HUSH_WAIT
1223 BLTIN("wait" , builtin_wait , "Wait for process to finish"),
1224#endif
1225};
1226
1227
1228
1229static const struct built_in_command bltins2[] ALIGN_PTR = {
1230#if ENABLE_HUSH_TEST
1231 BLTIN("[" , builtin_test , NULL),
1232#endif
1233#if BASH_TEST2
1234 BLTIN("[[" , builtin_test , NULL),
1235#endif
1236#if ENABLE_HUSH_ECHO
1237 BLTIN("echo" , builtin_echo , NULL),
1238#endif
1239#if ENABLE_HUSH_PRINTF
1240 BLTIN("printf" , builtin_printf , NULL),
1241#endif
1242 BLTIN("pwd" , builtin_pwd , NULL),
1243#if ENABLE_HUSH_TEST
1244 BLTIN("test" , builtin_test , NULL),
1245#endif
1246};
1247
1248
1249
1250
1251#if HUSH_DEBUG >= 2
1252
1253# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "")
1254# define debug_enter() (G.debug_indent++)
1255# define debug_leave() (G.debug_indent--)
1256#else
1257# define indent() ((void)0)
1258# define debug_enter() ((void)0)
1259# define debug_leave() ((void)0)
1260#endif
1261
1262#ifndef debug_printf
1263# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__))
1264#endif
1265
1266#ifndef debug_printf_parse
1267# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__))
1268#endif
1269
1270#ifndef debug_printf_heredoc
1271# define debug_printf_heredoc(...) (indent(), fdprintf(2, __VA_ARGS__))
1272#endif
1273
1274#ifndef debug_printf_exec
1275#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__))
1276#endif
1277
1278#ifndef debug_printf_env
1279# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__))
1280#endif
1281
1282#ifndef debug_printf_jobs
1283# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__))
1284# define DEBUG_JOBS 1
1285#else
1286# define DEBUG_JOBS 0
1287#endif
1288
1289#ifndef debug_printf_expand
1290# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__))
1291# define DEBUG_EXPAND 1
1292#else
1293# define DEBUG_EXPAND 0
1294#endif
1295
1296#ifndef debug_printf_varexp
1297# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__))
1298#endif
1299
1300#ifndef debug_printf_glob
1301# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__))
1302# define DEBUG_GLOB 1
1303#else
1304# define DEBUG_GLOB 0
1305#endif
1306
1307#ifndef debug_printf_redir
1308# define debug_printf_redir(...) (indent(), fdprintf(2, __VA_ARGS__))
1309#endif
1310
1311#ifndef debug_printf_list
1312# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__))
1313#endif
1314
1315#ifndef debug_printf_subst
1316# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__))
1317#endif
1318
1319#ifndef debug_printf_prompt
1320# define debug_printf_prompt(...) (indent(), fdprintf(2, __VA_ARGS__))
1321#endif
1322
1323#ifndef debug_printf_clean
1324# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__))
1325# define DEBUG_CLEAN 1
1326#else
1327# define DEBUG_CLEAN 0
1328#endif
1329
1330#if DEBUG_EXPAND
1331static void debug_print_strings(const char *prefix, char **vv)
1332{
1333 indent();
1334 fdprintf(2, "%s:\n", prefix);
1335 while (*vv)
1336 fdprintf(2, " '%s'\n", *vv++);
1337}
1338#else
1339# define debug_print_strings(prefix, vv) ((void)0)
1340#endif
1341
1342
1343
1344
1345#if LEAK_HUNTING
1346static void *xxmalloc(int lineno, size_t size)
1347{
1348 void *ptr = xmalloc((size + 0xff) & ~0xff);
1349 fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
1350 return ptr;
1351}
1352static void *xxrealloc(int lineno, void *ptr, size_t size)
1353{
1354 ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
1355 fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
1356 return ptr;
1357}
1358static char *xxstrdup(int lineno, const char *str)
1359{
1360 char *ptr = xstrdup(str);
1361 fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
1362 return ptr;
1363}
1364static void xxfree(void *ptr)
1365{
1366 fdprintf(2, "free %p\n", ptr);
1367 free(ptr);
1368}
1369# define xmalloc(s) xxmalloc(__LINE__, s)
1370# define xrealloc(p, s) xxrealloc(__LINE__, p, s)
1371# define xstrdup(s) xxstrdup(__LINE__, s)
1372# define free(p) xxfree(p)
1373#endif
1374
1375
1376
1377
1378
1379
1380
1381#if HUSH_DEBUG < 2
1382# define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__)
1383# define syntax_error(lineno, msg) syntax_error(msg)
1384# define syntax_error_at(lineno, msg) syntax_error_at(msg)
1385# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch)
1386# define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s)
1387# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
1388#endif
1389
1390static void die_if_script(void)
1391{
1392 if (!G_interactive_fd) {
1393 if (G.last_exitcode)
1394 xfunc_error_retval = G.last_exitcode;
1395 xfunc_die();
1396 }
1397}
1398
1399static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
1400{
1401 va_list p;
1402
1403#if HUSH_DEBUG >= 2
1404 bb_error_msg("hush.c:%u", lineno);
1405#endif
1406 va_start(p, fmt);
1407 bb_verror_msg(fmt, p, NULL);
1408 va_end(p);
1409 die_if_script();
1410}
1411
1412static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
1413{
1414 if (msg)
1415 bb_error_msg("syntax error: %s", msg);
1416 else
1417 bb_simple_error_msg("syntax error");
1418 die_if_script();
1419}
1420
1421static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
1422{
1423 bb_error_msg("syntax error at '%s'", msg);
1424 die_if_script();
1425}
1426
1427static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
1428{
1429 bb_error_msg("syntax error: unterminated %s", s);
1430
1431
1432}
1433
1434static void syntax_error_unterm_ch(unsigned lineno, char ch)
1435{
1436 char msg[2] = { ch, '\0' };
1437 syntax_error_unterm_str(lineno, msg);
1438}
1439
1440static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
1441{
1442 char msg[2];
1443 msg[0] = ch;
1444 msg[1] = '\0';
1445#if HUSH_DEBUG >= 2
1446 bb_error_msg("hush.c:%u", lineno);
1447#endif
1448 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
1449 die_if_script();
1450}
1451
1452#if HUSH_DEBUG < 2
1453# undef msg_and_die_if_script
1454# undef syntax_error
1455# undef syntax_error_at
1456# undef syntax_error_unterm_ch
1457# undef syntax_error_unterm_str
1458# undef syntax_error_unexpected_ch
1459#else
1460# define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__)
1461# define syntax_error(msg) syntax_error(__LINE__, msg)
1462# define syntax_error_at(msg) syntax_error_at(__LINE__, msg)
1463# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch)
1464# define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s)
1465# define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch)
1466#endif
1467
1468
1469
1470
1471
1472static char *unbackslash(char *src)
1473{
1474 char *dst = src = strchrnul(src, '\\');
1475 while (1) {
1476 if (*src == '\\') {
1477 src++;
1478 if (*src != '\0') {
1479
1480 *dst++ = *src++;
1481 continue;
1482 }
1483
1484
1485
1486 *dst++ = '\\';
1487
1488 }
1489 if ((*dst++ = *src++) == '\0')
1490 break;
1491 }
1492 return dst;
1493}
1494
1495static char **add_strings_to_strings(char **strings, char **add, int need_to_dup)
1496{
1497 int i;
1498 unsigned count1;
1499 unsigned count2;
1500 char **v;
1501
1502 v = strings;
1503 count1 = 0;
1504 if (v) {
1505 while (*v) {
1506 count1++;
1507 v++;
1508 }
1509 }
1510 count2 = 0;
1511 v = add;
1512 while (*v) {
1513 count2++;
1514 v++;
1515 }
1516 v = xrealloc(strings, (count1 + count2 + 1) * sizeof(char*));
1517 v[count1 + count2] = NULL;
1518 i = count2;
1519 while (--i >= 0)
1520 v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]);
1521 return v;
1522}
1523#if LEAK_HUNTING
1524static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup)
1525{
1526 char **ptr = add_strings_to_strings(strings, add, need_to_dup);
1527 fdprintf(2, "line %d: add_strings_to_strings %p\n", lineno, ptr);
1528 return ptr;
1529}
1530#define add_strings_to_strings(strings, add, need_to_dup) \
1531 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup)
1532#endif
1533
1534
1535static char **add_string_to_strings(char **strings, char *add)
1536{
1537 char *v[2];
1538 v[0] = add;
1539 v[1] = NULL;
1540 return add_strings_to_strings(strings, v, 0);
1541}
1542#if LEAK_HUNTING
1543static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
1544{
1545 char **ptr = add_string_to_strings(strings, add);
1546 fdprintf(2, "line %d: add_string_to_strings %p\n", lineno, ptr);
1547 return ptr;
1548}
1549#define add_string_to_strings(strings, add) \
1550 xx_add_string_to_strings(__LINE__, strings, add)
1551#endif
1552
1553static void free_strings(char **strings)
1554{
1555 char **v;
1556
1557 if (!strings)
1558 return;
1559 v = strings;
1560 while (*v) {
1561 free(*v);
1562 v++;
1563 }
1564 free(strings);
1565}
1566
1567static int dup_CLOEXEC(int fd, int avoid_fd)
1568{
1569 int newfd;
1570 repeat:
1571 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1572 if (newfd >= 0) {
1573 if (F_DUPFD_CLOEXEC == F_DUPFD)
1574 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1575 } else {
1576 if (errno == EBUSY)
1577 goto repeat;
1578 if (errno == EINTR)
1579 goto repeat;
1580 }
1581 return newfd;
1582}
1583
1584static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1585{
1586 int newfd;
1587 repeat:
1588 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1589 if (newfd < 0) {
1590 if (errno == EBUSY)
1591 goto repeat;
1592 if (errno == EINTR)
1593 goto repeat;
1594
1595 if (errno == EBADF)
1596 return fd;
1597 xfunc_die();
1598 }
1599 if (F_DUPFD_CLOEXEC == F_DUPFD)
1600 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1601 close(fd);
1602 return newfd;
1603}
1604
1605
1606
1607static HFILE *hfopen(const char *name)
1608{
1609 HFILE *fp;
1610 int fd;
1611
1612 fd = STDIN_FILENO;
1613 if (name) {
1614 fd = open(name, O_RDONLY | O_CLOEXEC);
1615 if (fd < 0)
1616 return NULL;
1617 if (O_CLOEXEC == 0)
1618 close_on_exec_on(fd);
1619 }
1620
1621 fp = xmalloc(sizeof(*fp));
1622 if (name == NULL)
1623 G.HFILE_stdin = fp;
1624 fp->fd = fd;
1625 fp->cur = fp->end = fp->buf;
1626 fp->next_hfile = G.HFILE_list;
1627 G.HFILE_list = fp;
1628 return fp;
1629}
1630static void hfclose(HFILE *fp)
1631{
1632 HFILE **pp = &G.HFILE_list;
1633 while (*pp) {
1634 HFILE *cur = *pp;
1635 if (cur == fp) {
1636 *pp = cur->next_hfile;
1637 break;
1638 }
1639 pp = &cur->next_hfile;
1640 }
1641 if (fp->fd >= 0)
1642 close(fp->fd);
1643 free(fp);
1644}
1645static int refill_HFILE_and_getc(HFILE *fp)
1646{
1647 int n;
1648
1649 if (fp->fd < 0) {
1650
1651 return EOF;
1652 }
1653#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING
1654
1655
1656
1657
1658 if (fp == G.HFILE_stdin) {
1659 struct pollfd pfd[1];
1660 pfd[0].fd = fp->fd;
1661 pfd[0].events = POLLIN;
1662 n = poll(pfd, 1, -1);
1663 if (n < 0
1664
1665 && sigismember(&G.pending_set, SIGINT)
1666 ) {
1667 return '\0';
1668 }
1669 }
1670#else
1671
1672#endif
1673
1674 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1675 if (n < 0) {
1676 bb_simple_perror_msg("read error");
1677 n = 0;
1678 }
1679 fp->cur = fp->buf;
1680 fp->end = fp->buf + n;
1681 if (n == 0) {
1682
1683 close(fp->fd);
1684 fp->fd = -1;
1685 return EOF;
1686 }
1687 return (unsigned char)(*fp->cur++);
1688}
1689
1690
1691static ALWAYS_INLINE int hfgetc(HFILE *fp)
1692{
1693 if (fp->cur < fp->end)
1694 return (unsigned char)(*fp->cur++);
1695
1696 return refill_HFILE_and_getc(fp);
1697}
1698static int move_HFILEs_on_redirect(int fd, int avoid_fd)
1699{
1700 HFILE *fl = G.HFILE_list;
1701 while (fl) {
1702 if (fd == fl->fd) {
1703
1704 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1705 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1706 return 1;
1707 }
1708 fl = fl->next_hfile;
1709 }
1710#if ENABLE_HUSH_MODE_X
1711 if (G.x_mode_fd > 0 && fd == G.x_mode_fd) {
1712 G.x_mode_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1713 return 1;
1714 }
1715#endif
1716 return 0;
1717}
1718#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
1719static void close_all_HFILE_list(void)
1720{
1721 HFILE *fl = G.HFILE_list;
1722 while (fl) {
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734 if (fl->fd > 0)
1735
1736 close(fl->fd);
1737 fl = fl->next_hfile;
1738 }
1739}
1740#endif
1741static int fd_in_HFILEs(int fd)
1742{
1743 HFILE *fl = G.HFILE_list;
1744 while (fl) {
1745 if (fl->fd == fd)
1746 return 1;
1747 fl = fl->next_hfile;
1748 }
1749 return 0;
1750}
1751
1752
1753
1754
1755typedef struct save_arg_t {
1756 char *sv_argv0;
1757 char **sv_g_argv;
1758 int sv_g_argc;
1759 IF_HUSH_SET(smallint sv_g_malloced;)
1760} save_arg_t;
1761
1762static void save_and_replace_G_args(save_arg_t *sv, char **argv)
1763{
1764 sv->sv_argv0 = argv[0];
1765 sv->sv_g_argv = G.global_argv;
1766 sv->sv_g_argc = G.global_argc;
1767 IF_HUSH_SET(sv->sv_g_malloced = G.global_args_malloced;)
1768
1769 argv[0] = G.global_argv[0];
1770 G.global_argv = argv;
1771 IF_HUSH_SET(G.global_args_malloced = 0;)
1772
1773 G.global_argc = 1 + string_array_len(argv + 1);
1774}
1775
1776static void restore_G_args(save_arg_t *sv, char **argv)
1777{
1778#if ENABLE_HUSH_SET
1779 if (G.global_args_malloced) {
1780
1781 char **pp = G.global_argv;
1782 while (*++pp)
1783 free(*pp);
1784 free(G.global_argv);
1785 }
1786#endif
1787 argv[0] = sv->sv_argv0;
1788 G.global_argv = sv->sv_g_argv;
1789 G.global_argc = sv->sv_g_argc;
1790 IF_HUSH_SET(G.global_args_malloced = sv->sv_g_malloced;)
1791}
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929enum {
1930 SPECIAL_INTERACTIVE_SIGS = 0
1931 | (1 << SIGTERM)
1932 | (1 << SIGINT)
1933 | (1 << SIGHUP)
1934 ,
1935 SPECIAL_JOBSTOP_SIGS = 0
1936#if ENABLE_HUSH_JOB
1937 | (1 << SIGTTIN)
1938 | (1 << SIGTTOU)
1939 | (1 << SIGTSTP)
1940#endif
1941 ,
1942};
1943
1944static void record_pending_signo(int sig)
1945{
1946 sigaddset(&G.pending_set, sig);
1947#if ENABLE_HUSH_FAST
1948 if (sig == SIGCHLD) {
1949 G.count_SIGCHLD++;
1950
1951 }
1952#endif
1953}
1954
1955static sighandler_t install_sighandler(int sig, sighandler_t handler)
1956{
1957 struct sigaction old_sa;
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968 G.sa.sa_handler = handler;
1969 sigaction(sig, &G.sa, &old_sa);
1970 return old_sa.sa_handler;
1971}
1972
1973static void hush_exit(int exitcode) NORETURN;
1974
1975static void restore_ttypgrp_and__exit(void) NORETURN;
1976static void restore_ttypgrp_and__exit(void)
1977{
1978
1979
1980 G.exiting = 1;
1981 hush_exit(xfunc_error_retval);
1982}
1983
1984#if ENABLE_HUSH_JOB
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999static void fflush_and__exit(void) NORETURN;
2000static void fflush_and__exit(void)
2001{
2002 fflush_all();
2003 _exit(xfunc_error_retval);
2004}
2005
2006
2007# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
2008
2009# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit)
2010
2011
2012
2013
2014
2015
2016
2017static void sigexit(int sig) NORETURN;
2018static void sigexit(int sig)
2019{
2020
2021
2022 if (G_saved_tty_pgrp && getpid() == G.root_pid) {
2023
2024
2025
2026 sigprocmask_allsigs(SIG_BLOCK);
2027 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
2028 }
2029
2030
2031 if (sig <= 0)
2032 _exit(- sig);
2033
2034 kill_myself_with_sig(sig);
2035}
2036#else
2037
2038# define disable_restore_tty_pgrp_on_exit() ((void)0)
2039# define enable_restore_tty_pgrp_on_exit() ((void)0)
2040
2041#endif
2042
2043static sighandler_t pick_sighandler(unsigned sig)
2044{
2045 sighandler_t handler = SIG_DFL;
2046 if (sig < sizeof(unsigned)*8) {
2047 unsigned sigmask = (1 << sig);
2048
2049#if ENABLE_HUSH_JOB
2050
2051 if (G_fatal_sig_mask & sigmask)
2052 handler = sigexit;
2053 else
2054#endif
2055
2056 if (G.special_sig_mask & sigmask) {
2057 handler = record_pending_signo;
2058
2059
2060
2061
2062
2063 if (SPECIAL_JOBSTOP_SIGS & sigmask)
2064 handler = SIG_IGN;
2065 }
2066 }
2067 return handler;
2068}
2069
2070
2071static void hush_exit(int exitcode)
2072{
2073#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2074 save_history(G.line_input_state);
2075#endif
2076
2077 fflush_all();
2078 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
2079 char *argv[3];
2080
2081 argv[1] = xstrdup(G_traps[0]);
2082 argv[2] = NULL;
2083 G.exiting = 1;
2084
2085
2086
2087 builtin_eval(argv);
2088 }
2089
2090#if ENABLE_FEATURE_CLEAN_UP
2091 {
2092 struct variable *cur_var;
2093 if (G.cwd != bb_msg_unknown)
2094 free((char*)G.cwd);
2095 cur_var = G.top_var;
2096 while (cur_var) {
2097 struct variable *tmp = cur_var;
2098 if (!cur_var->max_len)
2099 free(cur_var->varstr);
2100 cur_var = cur_var->next;
2101 free(tmp);
2102 }
2103 }
2104#endif
2105
2106 fflush_all();
2107#if ENABLE_HUSH_JOB
2108 sigexit(- (exitcode & 0xff));
2109#else
2110 _exit(exitcode);
2111#endif
2112}
2113
2114
2115static int check_and_run_traps(void)
2116{
2117 int last_sig = 0;
2118
2119 while (1) {
2120 int sig;
2121
2122 if (sigisemptyset(&G.pending_set))
2123 break;
2124 sig = 0;
2125 do {
2126 sig++;
2127 if (sigismember(&G.pending_set, sig)) {
2128 sigdelset(&G.pending_set, sig);
2129 goto got_sig;
2130 }
2131 } while (sig < NSIG);
2132 break;
2133 got_sig:
2134#if ENABLE_HUSH_TRAP
2135 if (G_traps && G_traps[sig]) {
2136 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
2137 if (G_traps[sig][0]) {
2138
2139 smalluint save_rcode;
2140 int save_pre;
2141 char *argv[3];
2142
2143 argv[1] = xstrdup(G_traps[sig]);
2144
2145 argv[2] = NULL;
2146 save_pre = G.pre_trap_exitcode;
2147 G.pre_trap_exitcode = save_rcode = G.last_exitcode;
2148 builtin_eval(argv);
2149 free(argv[1]);
2150 G.pre_trap_exitcode = save_pre;
2151 G.last_exitcode = save_rcode;
2152# if ENABLE_HUSH_FUNCTIONS
2153 if (G.return_exitcode >= 0) {
2154 debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
2155 G.last_exitcode = G.return_exitcode;
2156 }
2157# endif
2158 last_sig = sig;
2159 }
2160 continue;
2161 }
2162#endif
2163
2164 switch (sig) {
2165 case SIGINT:
2166 debug_printf_exec("%s: sig:%d default SIGINT handler\n", __func__, sig);
2167 G.flag_SIGINT = 1;
2168 last_sig = sig;
2169 break;
2170#if ENABLE_HUSH_JOB
2171 case SIGHUP: {
2172
2173
2174
2175 struct pipe *job;
2176 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
2177
2178
2179 for (job = G.job_list; job; job = job->next) {
2180 if (job->pgrp <= 0)
2181 continue;
2182 debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
2183 if (kill(- job->pgrp, SIGHUP) == 0)
2184 kill(- job->pgrp, SIGCONT);
2185 }
2186 sigexit(SIGHUP);
2187 }
2188#endif
2189#if ENABLE_HUSH_FAST
2190 case SIGCHLD:
2191 debug_printf_exec("%s: sig:%d default SIGCHLD handler\n", __func__, sig);
2192 G.count_SIGCHLD++;
2193
2194
2195
2196
2197
2198 break;
2199#endif
2200 default:
2201 debug_printf_exec("%s: sig:%d default handling is to ignore\n", __func__, sig);
2202
2203
2204
2205
2206
2207
2208 break;
2209 }
2210 }
2211 return last_sig;
2212}
2213
2214
2215static const char *get_cwd(int force)
2216{
2217 if (force || G.cwd == NULL) {
2218
2219
2220 if (G.cwd == bb_msg_unknown)
2221 G.cwd = NULL;
2222 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd);
2223 if (!G.cwd)
2224 G.cwd = bb_msg_unknown;
2225 }
2226 return G.cwd;
2227}
2228
2229
2230
2231
2232
2233static struct variable **get_ptr_to_local_var(const char *name, unsigned len)
2234{
2235 struct variable **pp;
2236 struct variable *cur;
2237
2238 pp = &G.top_var;
2239 while ((cur = *pp) != NULL) {
2240 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
2241 return pp;
2242 pp = &cur->next;
2243 }
2244 return NULL;
2245}
2246
2247static const char* FAST_FUNC get_local_var_value(const char *name)
2248{
2249 struct variable **vpp;
2250 unsigned len = strlen(name);
2251
2252 if (G.expanded_assignments) {
2253 char **cpp = G.expanded_assignments;
2254 while (*cpp) {
2255 char *cp = *cpp;
2256 if (strncmp(cp, name, len) == 0 && cp[len] == '=')
2257 return cp + len + 1;
2258 cpp++;
2259 }
2260 }
2261
2262 vpp = get_ptr_to_local_var(name, len);
2263 if (vpp)
2264 return (*vpp)->varstr + len + 1;
2265
2266 if (strcmp(name, "PPID") == 0)
2267 return utoa(G.root_ppid);
2268
2269#if ENABLE_HUSH_RANDOM_SUPPORT
2270 if (strcmp(name, "RANDOM") == 0)
2271 return utoa(next_random(&G.random_gen));
2272#endif
2273#if ENABLE_HUSH_LINENO_VAR
2274 if (strcmp(name, "LINENO") == 0)
2275 return utoa(G.execute_lineno);
2276#endif
2277#if BASH_EPOCH_VARS
2278 {
2279 const char *fmt = NULL;
2280 if (strcmp(name, "EPOCHSECONDS") == 0)
2281 fmt = "%llu";
2282 else if (strcmp(name, "EPOCHREALTIME") == 0)
2283 fmt = "%llu.%06u";
2284 if (fmt) {
2285 struct timeval tv;
2286 xgettimeofday(&tv);
2287 sprintf(G.epoch_buf, fmt, (unsigned long long)tv.tv_sec,
2288 (unsigned)tv.tv_usec);
2289 return G.epoch_buf;
2290 }
2291 }
2292#endif
2293 return NULL;
2294}
2295
2296#if ENABLE_HUSH_GETOPTS
2297static void handle_changed_special_names(const char *name, unsigned name_len)
2298{
2299 if (name_len == 6) {
2300 if (strncmp(name, "OPTIND", 6) == 0) {
2301 G.getopt_count = 0;
2302 return;
2303 }
2304 }
2305}
2306#else
2307
2308# define handle_changed_special_names(...) ((void)0)
2309#endif
2310
2311
2312
2313
2314#define SETFLAG_EXPORT (1 << 0)
2315#define SETFLAG_UNEXPORT (1 << 1)
2316#define SETFLAG_MAKE_RO (1 << 2)
2317#define SETFLAG_VARLVL_SHIFT 3
2318static int set_local_var(char *str, unsigned flags)
2319{
2320 struct variable **cur_pp;
2321 struct variable *cur;
2322 char *free_me = NULL;
2323 char *eq_sign;
2324 int name_len;
2325 int retval;
2326 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
2327
2328 eq_sign = strchr(str, '=');
2329 if (HUSH_DEBUG && !eq_sign)
2330 bb_simple_error_msg_and_die("BUG in setvar");
2331
2332 name_len = eq_sign - str + 1;
2333 cur_pp = &G.top_var;
2334 while ((cur = *cur_pp) != NULL) {
2335 if (strncmp(cur->varstr, str, name_len) != 0) {
2336 cur_pp = &cur->next;
2337 continue;
2338 }
2339
2340
2341 if (cur->flg_read_only) {
2342 bb_error_msg("%s: readonly variable", str);
2343 free(str);
2344
2345
2346 return -1;
2347 }
2348 if (flags & SETFLAG_UNEXPORT) {
2349 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
2350 *eq_sign = '\0';
2351 unsetenv(str);
2352 *eq_sign = '=';
2353 }
2354 if (cur->var_nest_level < local_lvl) {
2355
2356
2357
2358
2359
2360
2361
2362
2363 if (cur->flg_export)
2364 flags |= SETFLAG_EXPORT;
2365
2366
2367
2368
2369
2370
2371 *cur_pp = cur->next;
2372 if (G.shadowed_vars_pp) {
2373
2374 debug_printf_env("shadowing %s'%s'/%u by '%s'/%u\n",
2375 cur->flg_export ? "exported " : "",
2376 cur->varstr, cur->var_nest_level, str, local_lvl
2377 );
2378 cur->next = *G.shadowed_vars_pp;
2379 *G.shadowed_vars_pp = cur;
2380 } else {
2381
2382 debug_printf_env("shadow-deleting %s'%s'/%u by '%s'/%u\n",
2383 cur->flg_export ? "exported " : "",
2384 cur->varstr, cur->var_nest_level, str, local_lvl
2385 );
2386 if (cur->max_len == 0)
2387 free_me = cur->varstr;
2388 free(cur);
2389 }
2390 break;
2391 }
2392
2393 if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
2394 debug_printf_env("assignement '%s' does not change anything\n", str);
2395 free_and_exp:
2396 free(str);
2397 goto exp;
2398 }
2399
2400
2401 if (cur->max_len != 0) {
2402 if (cur->max_len >= strnlen(str, cur->max_len + 1)) {
2403
2404 debug_printf_env("reusing startup env for '%s'\n", str);
2405 strcpy(cur->varstr, str);
2406 goto free_and_exp;
2407 }
2408
2409 cur->max_len = 0;
2410 goto set_str_and_exp;
2411 }
2412
2413
2414
2415
2416
2417
2418 free_me = cur->varstr;
2419 goto set_str_and_exp;
2420 }
2421
2422
2423 debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl);
2424 cur = xzalloc(sizeof(*cur));
2425 cur->var_nest_level = local_lvl;
2426 cur->next = *cur_pp;
2427 *cur_pp = cur;
2428
2429 set_str_and_exp:
2430 cur->varstr = str;
2431 exp:
2432#if !BB_MMU || ENABLE_HUSH_READONLY
2433 if (flags & SETFLAG_MAKE_RO) {
2434 cur->flg_read_only = 1;
2435 }
2436#endif
2437 if (flags & SETFLAG_EXPORT)
2438 cur->flg_export = 1;
2439 retval = 0;
2440 if (cur->flg_export) {
2441 if (flags & SETFLAG_UNEXPORT) {
2442 cur->flg_export = 0;
2443
2444 } else {
2445 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level);
2446 retval = putenv(cur->varstr);
2447
2448
2449
2450 }
2451 }
2452 free(free_me);
2453
2454 handle_changed_special_names(cur->varstr, name_len - 1);
2455
2456 return retval;
2457}
2458
2459static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2460{
2461 char *var = xasprintf("%s=%s", name, val);
2462 set_local_var(var, 0);
2463}
2464
2465
2466static void set_pwd_var(unsigned flag)
2467{
2468 set_local_var(xasprintf("PWD=%s", get_cwd( 1)), flag);
2469}
2470
2471#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2472static int unset_local_var_len(const char *name, int name_len)
2473{
2474 struct variable *cur;
2475 struct variable **cur_pp;
2476
2477 cur_pp = &G.top_var;
2478 while ((cur = *cur_pp) != NULL) {
2479 if (strncmp(cur->varstr, name, name_len) == 0
2480 && cur->varstr[name_len] == '='
2481 ) {
2482 if (cur->flg_read_only) {
2483 bb_error_msg("%s: readonly variable", name);
2484 return EXIT_FAILURE;
2485 }
2486
2487 *cur_pp = cur->next;
2488 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
2489 bb_unsetenv(cur->varstr);
2490 if (!cur->max_len)
2491 free(cur->varstr);
2492 free(cur);
2493
2494 break;
2495 }
2496 cur_pp = &cur->next;
2497 }
2498
2499
2500 handle_changed_special_names(name, name_len);
2501
2502 return EXIT_SUCCESS;
2503}
2504
2505static int unset_local_var(const char *name)
2506{
2507 return unset_local_var_len(name, strlen(name));
2508}
2509#endif
2510
2511
2512
2513
2514
2515static void add_vars(struct variable *var)
2516{
2517 struct variable *next;
2518
2519 while (var) {
2520 next = var->next;
2521 var->next = G.top_var;
2522 G.top_var = var;
2523 if (var->flg_export) {
2524 debug_printf_env("%s: restoring exported '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
2525 putenv(var->varstr);
2526 } else {
2527 debug_printf_env("%s: restoring variable '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
2528 }
2529 var = next;
2530 }
2531}
2532
2533
2534
2535
2536
2537
2538static void set_vars_and_save_old(char **strings)
2539{
2540 char **s;
2541
2542 if (!strings)
2543 return;
2544
2545 s = strings;
2546 while (*s) {
2547 struct variable *var_p;
2548 struct variable **var_pp;
2549 char *eq;
2550
2551 eq = strchr(*s, '=');
2552 if (HUSH_DEBUG && !eq)
2553 bb_simple_error_msg_and_die("BUG in varexp4");
2554 var_pp = get_ptr_to_local_var(*s, eq - *s);
2555 if (var_pp) {
2556 var_p = *var_pp;
2557 if (var_p->flg_read_only) {
2558 char **p;
2559 bb_error_msg("%s: readonly variable", *s);
2560
2561
2562
2563
2564
2565
2566 debug_printf_env("removing/freeing '%s' element\n", *s);
2567 free(*s);
2568 p = s;
2569 do { *p = p[1]; p++; } while (*p);
2570 goto next;
2571 }
2572
2573
2574
2575
2576 }
2577 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2578 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
2579 s++;
2580 next: ;
2581 }
2582 free(strings);
2583}
2584
2585
2586
2587
2588
2589static void reinit_unicode_for_hush(void)
2590{
2591
2592
2593
2594
2595 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2596 || ENABLE_UNICODE_USING_LOCALE
2597 ) {
2598 const char *s = get_local_var_value("LC_ALL");
2599 if (!s) s = get_local_var_value("LC_CTYPE");
2600 if (!s) s = get_local_var_value("LANG");
2601 reinit_unicode(s);
2602 }
2603}
2604
2605
2606
2607
2608
2609#if ENABLE_HUSH_INTERACTIVE
2610
2611
2612
2613
2614
2615
2616
2617
2618static const char *setup_prompt_string(void)
2619{
2620 const char *prompt_str;
2621
2622 debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode);
2623
2624# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2625 prompt_str = get_local_var_value(G.promptmode == 0 ? "PS1" : "PS2");
2626 if (!prompt_str)
2627 prompt_str = "";
2628# else
2629 prompt_str = "> ";
2630 if (G.promptmode == 0) {
2631
2632 free(G.PS1);
2633
2634
2635
2636 prompt_str = G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
2637 }
2638# endif
2639 debug_printf("prompt_str '%s'\n", prompt_str);
2640 return prompt_str;
2641}
2642static int get_user_input(struct in_str *i)
2643{
2644# if ENABLE_FEATURE_EDITING
2645
2646
2647
2648 int r;
2649 const char *prompt_str;
2650
2651 prompt_str = setup_prompt_string();
2652 for (;;) {
2653 reinit_unicode_for_hush();
2654 G.flag_SIGINT = 0;
2655
2656
2657 r = read_line_input(G.line_input_state, prompt_str,
2658 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
2659 );
2660
2661 if (r == 0) {
2662 raise(SIGINT);
2663 }
2664 check_and_run_traps();
2665 if (r != 0 && !G.flag_SIGINT)
2666 break;
2667
2668
2669 write(STDOUT_FILENO, "^C\n", 3);
2670 G.last_exitcode = 128 | SIGINT;
2671 }
2672 if (r < 0) {
2673
2674
2675 write(STDOUT_FILENO, "\n", 1);
2676 i->p = NULL;
2677 i->peek_buf[0] = r = EOF;
2678 return r;
2679 }
2680 i->p = G.user_input_buf;
2681 return (unsigned char)*i->p++;
2682# else
2683
2684
2685
2686 int r;
2687
2688 for (;;) {
2689 G.flag_SIGINT = 0;
2690 if (i->last_char == '\0' || i->last_char == '\n') {
2691 const char *prompt_str = setup_prompt_string();
2692
2693
2694
2695
2696
2697 check_and_run_traps();
2698 fputs_stdout(prompt_str);
2699 fflush_all();
2700 }
2701 r = hfgetc(i->file);
2702
2703
2704
2705
2706 check_and_run_traps();
2707 if (r != '\0' && !G.flag_SIGINT)
2708 break;
2709 if (G.flag_SIGINT) {
2710
2711
2712
2713 write(STDOUT_FILENO, "\n", 1);
2714 G.last_exitcode = 128 | SIGINT;
2715 }
2716 }
2717 return r;
2718# endif
2719}
2720
2721
2722static int fgetc_interactive(struct in_str *i)
2723{
2724 int ch;
2725
2726 if (G_interactive_fd && i->file == G.HFILE_stdin) {
2727
2728 ch = get_user_input(i);
2729 G.promptmode = 1;
2730 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
2731 } else {
2732
2733 do ch = hfgetc(i->file); while (ch == '\0');
2734 }
2735 return ch;
2736}
2737#else
2738static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
2739{
2740 int ch;
2741 do ch = hfgetc(i->file); while (ch == '\0');
2742 return ch;
2743}
2744#endif
2745
2746static int i_getch(struct in_str *i)
2747{
2748 int ch;
2749
2750 if (!i->file) {
2751
2752 ch = (unsigned char)*i->p;
2753 if (ch != '\0') {
2754 i->p++;
2755 i->last_char = ch;
2756#if ENABLE_HUSH_LINENO_VAR
2757 if (ch == '\n') {
2758 G.parse_lineno++;
2759 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
2760 }
2761#endif
2762 return ch;
2763 }
2764 return EOF;
2765 }
2766
2767
2768
2769#if ENABLE_FEATURE_EDITING
2770
2771 if (i->p && *i->p != '\0') {
2772 ch = (unsigned char)*i->p++;
2773 goto out;
2774 }
2775#endif
2776
2777 ch = i->peek_buf[0];
2778 if (ch != 0) {
2779 int ch2 = i->peek_buf[1];
2780 i->peek_buf[0] = ch2;
2781 if (ch2 == 0)
2782 goto out;
2783 i->peek_buf[1] = 0;
2784 goto out;
2785 }
2786
2787 ch = fgetc_interactive(i);
2788 out:
2789 debug_printf("file_get: got '%c' %d\n", ch, ch);
2790 i->last_char = ch;
2791#if ENABLE_HUSH_LINENO_VAR
2792 if (ch == '\n') {
2793 G.parse_lineno++;
2794 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
2795 }
2796#endif
2797 return ch;
2798}
2799
2800static int i_peek(struct in_str *i)
2801{
2802 int ch;
2803
2804 if (!i->file) {
2805
2806
2807 return (unsigned char)*i->p;
2808 }
2809
2810
2811
2812#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2813
2814 if (i->p && *i->p != '\0')
2815 return (unsigned char)*i->p;
2816#endif
2817
2818 ch = i->peek_buf[0];
2819 if (ch != 0)
2820 return ch;
2821
2822
2823 ch = fgetc_interactive(i);
2824 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2825
2826
2827#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2828 if (i->p) {
2829 i->p -= 1;
2830 return ch;
2831 }
2832#endif
2833 i->peek_buf[0] = ch;
2834
2835 return ch;
2836}
2837
2838
2839
2840
2841
2842static int i_peek2(struct in_str *i)
2843{
2844 int ch;
2845
2846
2847
2848
2849
2850
2851
2852 if (i->p)
2853 return (unsigned char)i->p[1];
2854
2855
2856
2857
2858
2859 ch = i->peek_buf[1];
2860 if (ch == 0) {
2861
2862 do ch = hfgetc(i->file); while (ch == '\0');
2863 i->peek_buf[1] = ch;
2864 }
2865
2866 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2867 return ch;
2868}
2869
2870static int i_getch_and_eat_bkslash_nl(struct in_str *input)
2871{
2872 for (;;) {
2873 int ch, ch2;
2874
2875 ch = i_getch(input);
2876 if (ch != '\\')
2877 return ch;
2878 ch2 = i_peek(input);
2879 if (ch2 != '\n')
2880 return ch;
2881
2882 i_getch(input);
2883 }
2884}
2885
2886
2887
2888
2889static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2890{
2891 for (;;) {
2892 int ch, ch2;
2893
2894 ch = i_peek(input);
2895 if (ch != '\\')
2896 return ch;
2897 ch2 = i_peek2(input);
2898 if (ch2 != '\n')
2899 return ch;
2900
2901 i_getch(input);
2902 i_getch(input);
2903 }
2904}
2905
2906static void setup_file_in_str(struct in_str *i, HFILE *fp)
2907{
2908 memset(i, 0, sizeof(*i));
2909 i->file = fp;
2910
2911}
2912
2913static void setup_string_in_str(struct in_str *i, const char *s)
2914{
2915 memset(i, 0, sizeof(*i));
2916 ;
2917 i->p = s;
2918}
2919
2920
2921
2922
2923
2924#define B_CHUNK (32 * sizeof(char*))
2925
2926static void o_reset_to_empty_unquoted(o_string *o)
2927{
2928 o->length = 0;
2929 o->has_quoted_part = 0;
2930 if (o->data)
2931 o->data[0] = '\0';
2932}
2933
2934static void o_free_and_set_NULL(o_string *o)
2935{
2936 free(o->data);
2937 memset(o, 0, sizeof(*o));
2938}
2939
2940static ALWAYS_INLINE void o_free(o_string *o)
2941{
2942 free(o->data);
2943}
2944
2945static void o_grow_by(o_string *o, int len)
2946{
2947 if (o->length + len > o->maxlen) {
2948 o->maxlen += (2 * len) | (B_CHUNK-1);
2949 o->data = xrealloc(o->data, 1 + o->maxlen);
2950 }
2951}
2952
2953static void o_addchr(o_string *o, int ch)
2954{
2955 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o);
2956 if (o->length < o->maxlen) {
2957
2958 add:
2959 o->data[o->length] = ch;
2960 o->length++;
2961 o->data[o->length] = '\0';
2962 return;
2963 }
2964 o_grow_by(o, 1);
2965 goto add;
2966}
2967
2968#if 0
2969
2970static void o_delchr(o_string *o)
2971{
2972 o->length--;
2973 o->data[o->length] = '\0';
2974}
2975#endif
2976
2977static void o_addblock(o_string *o, const char *str, int len)
2978{
2979 o_grow_by(o, len);
2980 ((char*)mempcpy(&o->data[o->length], str, len))[0] = '\0';
2981 o->length += len;
2982}
2983
2984static void o_addstr(o_string *o, const char *str)
2985{
2986 o_addblock(o, str, strlen(str));
2987}
2988
2989static void o_addstr_with_NUL(o_string *o, const char *str)
2990{
2991 o_addblock(o, str, strlen(str) + 1);
2992}
2993
2994#if !BB_MMU
2995static void nommu_addchr(o_string *o, int ch)
2996{
2997 if (o)
2998 o_addchr(o, ch);
2999}
3000#else
3001# define nommu_addchr(o, str) ((void)0)
3002#endif
3003
3004#if ENABLE_HUSH_MODE_X
3005static void x_mode_addchr(int ch)
3006{
3007 o_addchr(&G.x_mode_buf, ch);
3008}
3009static void x_mode_addstr(const char *str)
3010{
3011 o_addstr(&G.x_mode_buf, str);
3012}
3013static void x_mode_addblock(const char *str, int len)
3014{
3015 o_addblock(&G.x_mode_buf, str, len);
3016}
3017static void x_mode_prefix(void)
3018{
3019 int n = G.x_mode_depth;
3020 do x_mode_addchr('+'); while (--n >= 0);
3021}
3022static void x_mode_flush(void)
3023{
3024 int len = G.x_mode_buf.length;
3025 if (len <= 0)
3026 return;
3027 if (G.x_mode_fd > 0) {
3028 G.x_mode_buf.data[len] = '\n';
3029 full_write(G.x_mode_fd, G.x_mode_buf.data, len + 1);
3030 }
3031 G.x_mode_buf.length = 0;
3032}
3033#endif
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046#if ENABLE_HUSH_BRACE_EXPANSION
3047# define MAYBE_BRACES "{}"
3048#else
3049# define MAYBE_BRACES ""
3050#endif
3051
3052
3053
3054
3055static void o_addqchr(o_string *o, int ch)
3056{
3057 int sz = 1;
3058
3059
3060
3061 char *found = strchr("*?[-\\" MAYBE_BRACES, ch);
3062 if (found)
3063 sz++;
3064 o_grow_by(o, sz);
3065 if (found) {
3066 o->data[o->length] = '\\';
3067 o->length++;
3068 }
3069 o->data[o->length] = ch;
3070 o->length++;
3071 o->data[o->length] = '\0';
3072}
3073
3074static void o_addQchr(o_string *o, int ch)
3075{
3076 int sz = 1;
3077 if ((o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)
3078 && strchr("*?[-\\" MAYBE_BRACES, ch)
3079 ) {
3080 sz++;
3081 o->data[o->length] = '\\';
3082 o->length++;
3083 }
3084 o_grow_by(o, sz);
3085 o->data[o->length] = ch;
3086 o->length++;
3087 o->data[o->length] = '\0';
3088}
3089
3090static void o_addqblock(o_string *o, const char *str, int len)
3091{
3092 while (len) {
3093 char ch;
3094 int sz;
3095 int ordinary_cnt = strcspn(str, "*?[-\\" MAYBE_BRACES);
3096 if (ordinary_cnt > len)
3097 ordinary_cnt = len;
3098 o_addblock(o, str, ordinary_cnt);
3099 if (ordinary_cnt == len)
3100 return;
3101 str += ordinary_cnt;
3102 len -= ordinary_cnt + 1;
3103
3104 ch = *str++;
3105 sz = 1;
3106 if (ch) {
3107 sz++;
3108 o->data[o->length] = '\\';
3109 o->length++;
3110 }
3111 o_grow_by(o, sz);
3112 o->data[o->length] = ch;
3113 o->length++;
3114 }
3115 o->data[o->length] = '\0';
3116}
3117
3118static void o_addQblock(o_string *o, const char *str, int len)
3119{
3120 if (!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)) {
3121 o_addblock(o, str, len);
3122 return;
3123 }
3124 o_addqblock(o, str, len);
3125}
3126
3127static void o_addQstr(o_string *o, const char *str)
3128{
3129 o_addQblock(o, str, strlen(str));
3130}
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142#if DEBUG_EXPAND || DEBUG_GLOB
3143static void debug_print_list(const char *prefix, o_string *o, int n)
3144{
3145 char **list = (char**)o->data;
3146 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3147 int i = 0;
3148
3149 indent();
3150 fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n",
3151 prefix, list, n, string_start, o->length, o->maxlen,
3152 !!(o->o_expflags & EXP_FLAG_GLOB),
3153 o->has_quoted_part,
3154 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
3155 while (i < n) {
3156 indent();
3157 fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i],
3158 o->data + (int)(uintptr_t)list[i] + string_start,
3159 o->data + (int)(uintptr_t)list[i] + string_start);
3160 i++;
3161 }
3162 if (n) {
3163 const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start;
3164 indent();
3165 fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
3166 }
3167}
3168#else
3169# define debug_print_list(prefix, o, n) ((void)0)
3170#endif
3171
3172
3173
3174
3175static int o_save_ptr_helper(o_string *o, int n)
3176{
3177 char **list = (char**)o->data;
3178 int string_start;
3179 int string_len;
3180
3181 if (!o->has_empty_slot) {
3182 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3183 string_len = o->length - string_start;
3184 if (!(n & 0xf)) {
3185 debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start);
3186
3187 o->maxlen += 0x10 * sizeof(list[0]);
3188 o->data = xrealloc(o->data, o->maxlen + 1);
3189 list = (char**)o->data;
3190 memmove(list + n + 0x10, list + n, string_len);
3191
3192
3193
3194
3195
3196
3197 list[n + 0x10 - 1] = 0;
3198 o->length += 0x10 * sizeof(list[0]);
3199 } else {
3200 debug_printf_list("list[%d]=%d string_start=%d\n",
3201 n, string_len, string_start);
3202 }
3203 } else {
3204
3205 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]);
3206 string_len = o->length - string_start;
3207 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n",
3208 n, string_len, string_start);
3209 o->has_empty_slot = 0;
3210 }
3211 o->has_quoted_part = 0;
3212 list[n] = (char*)(uintptr_t)string_len;
3213 return n + 1;
3214}
3215
3216
3217static int o_get_last_ptr(o_string *o, int n)
3218{
3219 char **list = (char**)o->data;
3220 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3221
3222 return ((int)(uintptr_t)list[n-1]) + string_start;
3223}
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260#if ENABLE_HUSH_BRACE_EXPANSION
3261
3262
3263
3264
3265
3266
3267
3268static int glob_needed(const char *s)
3269{
3270 while (*s) {
3271 if (*s == '\\') {
3272 if (!s[1])
3273 return 0;
3274 s += 2;
3275 continue;
3276 }
3277 if (*s == '*' || *s == '[' || *s == '?' || *s == '{')
3278 return 1;
3279 s++;
3280 }
3281 return 0;
3282}
3283
3284static const char *next_brace_sub(const char *cp)
3285{
3286 unsigned depth = 0;
3287 cp++;
3288 while (*cp != '\0') {
3289 if (*cp == '\\') {
3290 if (*++cp == '\0')
3291 break;
3292 cp++;
3293 continue;
3294 }
3295 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
3296 break;
3297 if (*cp++ == '{')
3298 depth++;
3299 }
3300
3301 return *cp != '\0' ? cp : NULL;
3302}
3303
3304static int glob_brace(char *pattern, o_string *o, int n)
3305{
3306 char *new_pattern_buf;
3307 const char *begin;
3308 const char *next;
3309 const char *rest;
3310 const char *p;
3311 size_t rest_len;
3312
3313 debug_printf_glob("glob_brace('%s')\n", pattern);
3314
3315 begin = pattern;
3316 while (1) {
3317 if (*begin == '\0')
3318 goto simple_glob;
3319 if (*begin == '{') {
3320
3321
3322 next = next_brace_sub(begin);
3323 if (next == NULL) {
3324
3325 goto simple_glob;
3326 }
3327 if (*next == '}') {
3328
3329
3330 begin = next + 1;
3331 continue;
3332 }
3333 break;
3334 }
3335 if (*begin == '\\' && begin[1] != '\0')
3336 begin++;
3337 begin++;
3338 }
3339 debug_printf_glob("begin:%s\n", begin);
3340 debug_printf_glob("next:%s\n", next);
3341
3342
3343 rest = next;
3344 while (*rest != '}') {
3345 rest = next_brace_sub(rest);
3346 if (rest == NULL) {
3347
3348 goto simple_glob;
3349 }
3350 debug_printf_glob("rest:%s\n", rest);
3351 }
3352 rest_len = strlen(++rest) + 1;
3353
3354
3355
3356
3357 new_pattern_buf = xmalloc(strlen(pattern));
3358
3359
3360
3361
3362
3363
3364
3365 p = begin + 1;
3366 while (1) {
3367
3368 memcpy(
3369 mempcpy(
3370 mempcpy(new_pattern_buf,
3371
3372 pattern, begin - pattern),
3373 p, next - p),
3374 rest, rest_len);
3375
3376
3377
3378
3379 n = glob_brace(new_pattern_buf, o, n);
3380 if (*next == '}') {
3381
3382 break;
3383 }
3384 p = next + 1;
3385 next = next_brace_sub(next);
3386 }
3387 free(new_pattern_buf);
3388 return n;
3389
3390 simple_glob:
3391 {
3392 int gr;
3393 glob_t globdata;
3394
3395 memset(&globdata, 0, sizeof(globdata));
3396 gr = glob(pattern, 0, NULL, &globdata);
3397 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
3398 if (gr != 0) {
3399 if (gr == GLOB_NOMATCH) {
3400 globfree(&globdata);
3401
3402 unbackslash(pattern);
3403 o_addstr_with_NUL(o, pattern);
3404 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3405 return o_save_ptr_helper(o, n);
3406 }
3407 if (gr == GLOB_NOSPACE)
3408 bb_die_memory_exhausted();
3409
3410
3411 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
3412 }
3413 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3414 char **argv = globdata.gl_pathv;
3415 while (1) {
3416 o_addstr_with_NUL(o, *argv);
3417 n = o_save_ptr_helper(o, n);
3418 argv++;
3419 if (!*argv)
3420 break;
3421 }
3422 }
3423 globfree(&globdata);
3424 }
3425 return n;
3426}
3427
3428
3429
3430static int perform_glob(o_string *o, int n)
3431{
3432 char *pattern, *copy;
3433
3434 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
3435 if (!o->data)
3436 return o_save_ptr_helper(o, n);
3437 pattern = o->data + o_get_last_ptr(o, n);
3438 debug_printf_glob("glob pattern '%s'\n", pattern);
3439 if (!glob_needed(pattern)) {
3440
3441 o->length = unbackslash(pattern) - o->data;
3442 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3443 return o_save_ptr_helper(o, n);
3444 }
3445
3446 copy = xstrdup(pattern);
3447
3448 o->length = pattern - o->data;
3449 n = glob_brace(copy, o, n);
3450 free(copy);
3451 if (DEBUG_GLOB)
3452 debug_print_list("perform_glob returning", o, n);
3453 return n;
3454}
3455
3456#else
3457
3458
3459static int glob_needed(const char *s)
3460{
3461 while (*s) {
3462 if (*s == '\\') {
3463 if (!s[1])
3464 return 0;
3465 s += 2;
3466 continue;
3467 }
3468 if (*s == '*' || *s == '[' || *s == '?')
3469 return 1;
3470 s++;
3471 }
3472 return 0;
3473}
3474
3475
3476
3477static int perform_glob(o_string *o, int n)
3478{
3479 glob_t globdata;
3480 int gr;
3481 char *pattern;
3482
3483 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
3484 if (!o->data)
3485 return o_save_ptr_helper(o, n);
3486 pattern = o->data + o_get_last_ptr(o, n);
3487 debug_printf_glob("glob pattern '%s'\n", pattern);
3488 if (!glob_needed(pattern)) {
3489 literal:
3490
3491 o->length = unbackslash(pattern) - o->data;
3492 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3493 return o_save_ptr_helper(o, n);
3494 }
3495
3496 memset(&globdata, 0, sizeof(globdata));
3497
3498
3499
3500
3501
3502 gr = glob(pattern, 0, NULL, &globdata);
3503 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
3504 if (gr != 0) {
3505 if (gr == GLOB_NOMATCH) {
3506 globfree(&globdata);
3507 goto literal;
3508 }
3509 if (gr == GLOB_NOSPACE)
3510 bb_die_memory_exhausted();
3511
3512
3513 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
3514 }
3515 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3516 char **argv = globdata.gl_pathv;
3517
3518 o->length = pattern - o->data;
3519 while (1) {
3520 o_addstr_with_NUL(o, *argv);
3521 n = o_save_ptr_helper(o, n);
3522 argv++;
3523 if (!*argv)
3524 break;
3525 }
3526 }
3527 globfree(&globdata);
3528 if (DEBUG_GLOB)
3529 debug_print_list("perform_glob returning", o, n);
3530 return n;
3531}
3532
3533#endif
3534
3535
3536
3537static int o_save_ptr(o_string *o, int n)
3538{
3539 if (o->o_expflags & EXP_FLAG_GLOB) {
3540
3541
3542
3543 if (!o->has_empty_slot)
3544 return perform_glob(o, n);
3545 }
3546 return o_save_ptr_helper(o, n);
3547}
3548
3549
3550static char **o_finalize_list(o_string *o, int n)
3551{
3552 char **list;
3553 int string_start;
3554
3555 if (DEBUG_EXPAND)
3556 debug_print_list("finalized", o, n);
3557 debug_printf_expand("finalized n:%d\n", n);
3558 list = (char**)o->data;
3559 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3560 list[--n] = NULL;
3561 while (n) {
3562 n--;
3563 list[n] = o->data + (int)(uintptr_t)list[n] + string_start;
3564 }
3565 return list;
3566}
3567
3568static void free_pipe_list(struct pipe *pi);
3569
3570
3571static struct pipe *free_pipe(struct pipe *pi)
3572{
3573 struct pipe *next;
3574 int i;
3575
3576 debug_printf_clean("free_pipe (pid %d)\n", getpid());
3577 for (i = 0; i < pi->num_cmds; i++) {
3578 struct command *command;
3579 struct redir_struct *r, *rnext;
3580
3581 command = &pi->cmds[i];
3582 debug_printf_clean(" command %d:\n", i);
3583 if (command->argv) {
3584 if (DEBUG_CLEAN) {
3585 int a;
3586 char **p;
3587 for (a = 0, p = command->argv; *p; a++, p++) {
3588 debug_printf_clean(" argv[%d] = %s\n", a, *p);
3589 }
3590 }
3591 free_strings(command->argv);
3592
3593 }
3594
3595 if (command->group) {
3596 debug_printf_clean(" begin group (cmd_type:%d)\n",
3597 command->cmd_type);
3598 free_pipe_list(command->group);
3599 debug_printf_clean(" end group\n");
3600
3601 }
3602
3603
3604#if ENABLE_HUSH_FUNCTIONS
3605 else if (command->child_func) {
3606 debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func);
3607 command->child_func->parent_cmd = NULL;
3608 }
3609#endif
3610#if !BB_MMU
3611 free(command->group_as_string);
3612
3613#endif
3614 for (r = command->redirects; r; r = rnext) {
3615 debug_printf_clean(" redirect %d%s",
3616 r->rd_fd, redir_table[r->rd_type].descrip);
3617
3618 if (r->rd_filename) {
3619 debug_printf_clean(" fname:'%s'\n", r->rd_filename);
3620 free(r->rd_filename);
3621
3622 }
3623 debug_printf_clean(" rd_dup:%d\n", r->rd_dup);
3624 rnext = r->next;
3625 free(r);
3626 }
3627
3628 }
3629 free(pi->cmds);
3630
3631#if ENABLE_HUSH_JOB
3632 free(pi->cmdtext);
3633
3634#endif
3635
3636 next = pi->next;
3637 free(pi);
3638 return next;
3639}
3640
3641static void free_pipe_list(struct pipe *pi)
3642{
3643 while (pi) {
3644#if HAS_KEYWORDS
3645 debug_printf_clean("pipe reserved word %d\n", pi->res_word);
3646#endif
3647 debug_printf_clean("pipe followup code %d\n", pi->followup);
3648 pi = free_pipe(pi);
3649 }
3650}
3651
3652
3653
3654
3655#ifndef debug_print_tree
3656static void debug_print_tree(struct pipe *pi, int lvl)
3657{
3658 static const char *const PIPE[] = {
3659 [PIPE_SEQ] = "SEQ",
3660 [PIPE_AND] = "AND",
3661 [PIPE_OR ] = "OR" ,
3662 [PIPE_BG ] = "BG" ,
3663 };
3664 static const char *RES[] = {
3665 [RES_NONE ] = "NONE" ,
3666# if ENABLE_HUSH_IF
3667 [RES_IF ] = "IF" ,
3668 [RES_THEN ] = "THEN" ,
3669 [RES_ELIF ] = "ELIF" ,
3670 [RES_ELSE ] = "ELSE" ,
3671 [RES_FI ] = "FI" ,
3672# endif
3673# if ENABLE_HUSH_LOOPS
3674 [RES_FOR ] = "FOR" ,
3675 [RES_WHILE] = "WHILE",
3676 [RES_UNTIL] = "UNTIL",
3677 [RES_DO ] = "DO" ,
3678 [RES_DONE ] = "DONE" ,
3679# endif
3680# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
3681 [RES_IN ] = "IN" ,
3682# endif
3683# if ENABLE_HUSH_CASE
3684 [RES_CASE ] = "CASE" ,
3685 [RES_CASE_IN ] = "CASE_IN" ,
3686 [RES_MATCH] = "MATCH",
3687 [RES_CASE_BODY] = "CASE_BODY",
3688 [RES_ESAC ] = "ESAC" ,
3689# endif
3690 [RES_XXXX ] = "XXXX" ,
3691 [RES_SNTX ] = "SNTX" ,
3692 };
3693 static const char *const CMDTYPE[] = {
3694 "{}",
3695 "()",
3696 "[noglob]",
3697# if ENABLE_HUSH_FUNCTIONS
3698 "func()",
3699# endif
3700 };
3701
3702 int pin, prn;
3703
3704 pin = 0;
3705 while (pi) {
3706 fdprintf(2, "%*spipe %d #cmds:%d %sres_word=%s followup=%d %s\n",
3707 lvl*2, "",
3708 pin,
3709 pi->num_cmds,
3710 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3711 RES[pi->res_word],
3712 pi->followup, PIPE[pi->followup]
3713 );
3714 prn = 0;
3715 while (prn < pi->num_cmds) {
3716 struct command *command = &pi->cmds[prn];
3717 char **argv = command->argv;
3718
3719 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3720 lvl*2, "", prn,
3721 command->assignment_cnt);
3722# if ENABLE_HUSH_LINENO_VAR
3723 fdprintf(2, " LINENO:%u", command->lineno);
3724# endif
3725 if (command->group) {
3726 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3727 CMDTYPE[command->cmd_type],
3728 argv
3729# if !BB_MMU
3730 , " group_as_string:", command->group_as_string
3731# else
3732 , "", ""
3733# endif
3734 );
3735 debug_print_tree(command->group, lvl+1);
3736 prn++;
3737 continue;
3738 }
3739 if (argv) while (*argv) {
3740 fdprintf(2, " '%s'", *argv);
3741 argv++;
3742 }
3743 if (command->redirects)
3744 fdprintf(2, " {redir}");
3745 fdprintf(2, "\n");
3746 prn++;
3747 }
3748 pi = pi->next;
3749 pin++;
3750 }
3751}
3752#endif
3753
3754static struct pipe *new_pipe(void)
3755{
3756 struct pipe *pi;
3757 pi = xzalloc(sizeof(struct pipe));
3758
3759 return pi;
3760}
3761
3762
3763
3764
3765
3766static int done_command(struct parse_context *ctx)
3767{
3768
3769
3770 struct pipe *pi = ctx->pipe;
3771 struct command *command = ctx->command;
3772
3773#if 0
3774 if (ctx->pending_redirect) {
3775
3776 syntax_error("invalid redirect");
3777 ctx->pending_redirect = NULL;
3778 }
3779#endif
3780
3781 if (command) {
3782 if (IS_NULL_CMD(command)) {
3783 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
3784 goto clear_and_ret;
3785 }
3786 pi->num_cmds++;
3787 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
3788
3789 } else {
3790 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds);
3791 }
3792
3793
3794
3795 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
3796 ctx->command = command = &pi->cmds[pi->num_cmds];
3797 clear_and_ret:
3798 memset(command, 0, sizeof(*command));
3799#if ENABLE_HUSH_LINENO_VAR
3800 command->lineno = G.parse_lineno;
3801 debug_printf_parse("command->lineno = G.parse_lineno (%u)\n", G.parse_lineno);
3802#endif
3803 return pi->num_cmds;
3804}
3805
3806static void done_pipe(struct parse_context *ctx, pipe_style type)
3807{
3808 int not_null;
3809
3810 debug_printf_parse("done_pipe entered, followup %d\n", type);
3811
3812 not_null = done_command(ctx);
3813#if HAS_KEYWORDS
3814 ctx->pipe->pi_inverted = ctx->ctx_inverted;
3815 ctx->ctx_inverted = 0;
3816 ctx->pipe->res_word = ctx->ctx_res_w;
3817#endif
3818 if (type == PIPE_BG && ctx->list_head != ctx->pipe) {
3819
3820
3821
3822
3823 struct pipe *pi;
3824 struct command *command;
3825
3826
3827 pi = ctx->list_head;
3828 while (pi != ctx->pipe) {
3829 if (pi->followup != PIPE_AND && pi->followup != PIPE_OR)
3830 goto no_conv;
3831 pi = pi->next;
3832 }
3833
3834 debug_printf_parse("BG with more than one pipe, converting to { p1 &&...pN; } &\n");
3835 pi->followup = PIPE_SEQ;
3836 pi = xzalloc(sizeof(*pi));
3837 pi->followup = PIPE_BG;
3838 pi->num_cmds = 1;
3839 pi->cmds = xzalloc(sizeof(pi->cmds[0]));
3840 command = &pi->cmds[0];
3841 if (CMD_NORMAL != 0)
3842 command->cmd_type = CMD_NORMAL;
3843 command->group = ctx->list_head;
3844#if !BB_MMU
3845 command->group_as_string = xstrndup(
3846 ctx->as_string.data,
3847 ctx->as_string.length - 1
3848 );
3849#endif
3850
3851 ctx->list_head = ctx->pipe = pi;
3852
3853
3854 not_null = 1;
3855 } else {
3856 no_conv:
3857 ctx->pipe->followup = type;
3858 }
3859
3860
3861
3862
3863 if (not_null
3864#if ENABLE_HUSH_IF
3865 || ctx->ctx_res_w == RES_FI
3866#endif
3867#if ENABLE_HUSH_LOOPS
3868 || ctx->ctx_res_w == RES_DONE
3869 || ctx->ctx_res_w == RES_FOR
3870 || ctx->ctx_res_w == RES_IN
3871#endif
3872#if ENABLE_HUSH_CASE
3873 || ctx->ctx_res_w == RES_ESAC
3874#endif
3875 ) {
3876 struct pipe *new_p;
3877 debug_printf_parse("done_pipe: adding new pipe: "
3878 "not_null:%d ctx->ctx_res_w:%d\n",
3879 not_null, ctx->ctx_res_w);
3880 new_p = new_pipe();
3881 ctx->pipe->next = new_p;
3882 ctx->pipe = new_p;
3883
3884
3885
3886
3887
3888
3889#if ENABLE_HUSH_LOOPS
3890 if (ctx->ctx_res_w == RES_FOR
3891 || ctx->ctx_res_w == RES_IN)
3892 ctx->ctx_res_w = RES_NONE;
3893#endif
3894#if ENABLE_HUSH_CASE
3895 if (ctx->ctx_res_w == RES_MATCH)
3896 ctx->ctx_res_w = RES_CASE_BODY;
3897 if (ctx->ctx_res_w == RES_CASE)
3898 ctx->ctx_res_w = RES_CASE_IN;
3899#endif
3900 ctx->command = NULL;
3901
3902
3903
3904
3905 done_command(ctx);
3906
3907 }
3908 debug_printf_parse("done_pipe return\n");
3909}
3910
3911static void initialize_context(struct parse_context *ctx)
3912{
3913 memset(ctx, 0, sizeof(*ctx));
3914 if (MAYBE_ASSIGNMENT != 0)
3915 ctx->is_assignment = MAYBE_ASSIGNMENT;
3916 ctx->pipe = ctx->list_head = new_pipe();
3917
3918
3919
3920
3921 done_command(ctx);
3922}
3923
3924
3925
3926
3927#if HAS_KEYWORDS
3928struct reserved_combo {
3929 char literal[6];
3930 unsigned char res;
3931 unsigned char assignment_flag;
3932 uint32_t flag;
3933};
3934enum {
3935 FLAG_END = (1 << RES_NONE ),
3936# if ENABLE_HUSH_IF
3937 FLAG_IF = (1 << RES_IF ),
3938 FLAG_THEN = (1 << RES_THEN ),
3939 FLAG_ELIF = (1 << RES_ELIF ),
3940 FLAG_ELSE = (1 << RES_ELSE ),
3941 FLAG_FI = (1 << RES_FI ),
3942# endif
3943# if ENABLE_HUSH_LOOPS
3944 FLAG_FOR = (1 << RES_FOR ),
3945 FLAG_WHILE = (1 << RES_WHILE),
3946 FLAG_UNTIL = (1 << RES_UNTIL),
3947 FLAG_DO = (1 << RES_DO ),
3948 FLAG_DONE = (1 << RES_DONE ),
3949 FLAG_IN = (1 << RES_IN ),
3950# endif
3951# if ENABLE_HUSH_CASE
3952 FLAG_MATCH = (1 << RES_MATCH),
3953 FLAG_ESAC = (1 << RES_ESAC ),
3954# endif
3955 FLAG_START = (1 << RES_XXXX ),
3956};
3957
3958static const struct reserved_combo* match_reserved_word(o_string *word)
3959{
3960
3961
3962
3963
3964
3965 static const struct reserved_combo reserved_list[] ALIGN4 = {
3966# if ENABLE_HUSH_IF
3967 { "!", RES_NONE, NOT_ASSIGNMENT , 0 },
3968 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START },
3969 { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
3970 { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN },
3971 { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI },
3972 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END },
3973# endif
3974# if ENABLE_HUSH_LOOPS
3975 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START },
3976 { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3977 { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3978 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO },
3979 { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE },
3980 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END },
3981# endif
3982# if ENABLE_HUSH_CASE
3983 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START },
3984 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
3985# endif
3986 };
3987 const struct reserved_combo *r;
3988
3989 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
3990 if (strcmp(word->data, r->literal) == 0)
3991 return r;
3992 }
3993 return NULL;
3994}
3995
3996
3997static const struct reserved_combo* reserved_word(struct parse_context *ctx)
3998{
3999# if ENABLE_HUSH_CASE
4000 static const struct reserved_combo reserved_match = {
4001 "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
4002 };
4003# endif
4004 const struct reserved_combo *r;
4005
4006 if (ctx->word.has_quoted_part)
4007 return 0;
4008 r = match_reserved_word(&ctx->word);
4009 if (!r)
4010 return r;
4011
4012 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
4013# if ENABLE_HUSH_CASE
4014 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) {
4015
4016 r = &reserved_match;
4017 } else
4018# endif
4019 if (r->flag == 0) {
4020 if (ctx->ctx_inverted) {
4021 syntax_error("! ! command");
4022 ctx->ctx_res_w = RES_SNTX;
4023 }
4024 ctx->ctx_inverted = 1;
4025 return r;
4026 }
4027 if (r->flag & FLAG_START) {
4028 struct parse_context *old;
4029
4030 old = xmemdup(ctx, sizeof(*ctx));
4031 debug_printf_parse("push stack %p\n", old);
4032 initialize_context(ctx);
4033 ctx->stack = old;
4034 } else if ( !(ctx->old_flag & (1 << r->res))) {
4035 syntax_error_at(ctx->word.data);
4036 ctx->ctx_res_w = RES_SNTX;
4037 return r;
4038 } else {
4039
4040
4041
4042 if (ctx->command->group)
4043 done_pipe(ctx, PIPE_SEQ);
4044 }
4045
4046 ctx->ctx_res_w = r->res;
4047 ctx->old_flag = r->flag;
4048 ctx->is_assignment = r->assignment_flag;
4049 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
4050
4051 if (ctx->old_flag & FLAG_END) {
4052 struct parse_context *old;
4053
4054 done_pipe(ctx, PIPE_SEQ);
4055 debug_printf_parse("pop stack %p\n", ctx->stack);
4056 old = ctx->stack;
4057 old->command->group = ctx->list_head;
4058 old->command->cmd_type = CMD_NORMAL;
4059# if !BB_MMU
4060
4061
4062
4063
4064
4065
4066 {
4067 char *str;
4068 int len = old->as_string.length;
4069
4070 o_addstr(&old->as_string, ctx->as_string.data);
4071 o_free(&ctx->as_string);
4072
4073 str = old->as_string.data + len;
4074 if (str > old->as_string.data)
4075 str--;
4076 while (str > old->as_string.data && isalpha(str[-1]))
4077 str--;
4078
4079 old->command->group_as_string = xstrdup(str);
4080 debug_printf_parse("pop, remembering as:'%s'\n",
4081 old->command->group_as_string);
4082 }
4083# endif
4084 *ctx = *old;
4085 free(old);
4086 }
4087 return r;
4088}
4089#endif
4090
4091
4092
4093
4094
4095static int done_word(struct parse_context *ctx)
4096{
4097 struct command *command = ctx->command;
4098
4099 debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command);
4100 if (ctx->word.length == 0 && !ctx->word.has_quoted_part) {
4101 debug_printf_parse("done_word return 0: true null, ignored\n");
4102 return 0;
4103 }
4104
4105 if (ctx->pending_redirect) {
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130 ctx->pending_redirect->rd_filename = xstrdup(ctx->word.data);
4131
4132
4133
4134
4135
4136 if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) {
4137 unbackslash(ctx->pending_redirect->rd_filename);
4138
4139 if (ctx->word.has_quoted_part) {
4140 ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED;
4141 }
4142 }
4143 debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data);
4144 ctx->pending_redirect = NULL;
4145 } else {
4146#if HAS_KEYWORDS
4147# if ENABLE_HUSH_CASE
4148 if (ctx->ctx_dsemicolon
4149 && strcmp(ctx->word.data, "esac") != 0
4150 ) {
4151
4152
4153 ctx->ctx_dsemicolon = 0;
4154 } else
4155# endif
4156# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4157 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
4158 && strcmp(ctx->word.data, "]]") == 0
4159 ) {
4160
4161 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4162 } else
4163# endif
4164 if (!command->argv
4165# if ENABLE_HUSH_LOOPS
4166 && ctx->ctx_res_w != RES_FOR
4167 && ctx->ctx_res_w != RES_IN
4168# endif
4169# if ENABLE_HUSH_CASE
4170 && ctx->ctx_res_w != RES_CASE
4171# endif
4172 ) {
4173 const struct reserved_combo *reserved;
4174 reserved = reserved_word(ctx);
4175 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
4176 if (reserved) {
4177# if ENABLE_HUSH_LINENO_VAR
4178
4179
4180
4181
4182
4183
4184 if (0
4185 IF_HUSH_IF(|| reserved->res == RES_THEN)
4186 IF_HUSH_IF(|| reserved->res == RES_ELIF)
4187 IF_HUSH_IF(|| reserved->res == RES_ELSE)
4188 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
4189 ) {
4190 done_pipe(ctx, PIPE_SEQ);
4191 }
4192# endif
4193 o_reset_to_empty_unquoted(&ctx->word);
4194 debug_printf_parse("done_word return %d\n",
4195 (ctx->ctx_res_w == RES_SNTX));
4196 return (ctx->ctx_res_w == RES_SNTX);
4197 }
4198# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4199 if (strcmp(ctx->word.data, "[[") == 0) {
4200 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
4201 } else
4202# endif
4203# if defined(CMD_SINGLEWORD_NOGLOB)
4204 if (0
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220 IF_HUSH_LOCAL( || strcmp(ctx->word.data, "local") == 0)
4221 IF_HUSH_EXPORT( || strcmp(ctx->word.data, "export") == 0)
4222 IF_HUSH_READONLY(|| strcmp(ctx->word.data, "readonly") == 0)
4223 ) {
4224 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4225 }
4226# else
4227 { }
4228# endif
4229 }
4230#endif
4231
4232 if (command->group) {
4233
4234 syntax_error_at(ctx->word.data);
4235 debug_printf_parse("done_word return 1: syntax error, "
4236 "groups and arglists don't mix\n");
4237 return 1;
4238 }
4239
4240
4241
4242 if (ctx->is_assignment != DEFINITELY_ASSIGNMENT
4243 && ctx->is_assignment != WORD_IS_KEYWORD
4244 ) {
4245 ctx->is_assignment = NOT_ASSIGNMENT;
4246 } else {
4247 if (ctx->is_assignment == DEFINITELY_ASSIGNMENT) {
4248 command->assignment_cnt++;
4249 debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt);
4250 }
4251 debug_printf_parse("ctx->is_assignment was:'%s'\n", assignment_flag[ctx->is_assignment]);
4252 ctx->is_assignment = MAYBE_ASSIGNMENT;
4253 }
4254 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
4255 command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data));
4256 debug_print_strings("word appended to argv", command->argv);
4257 }
4258
4259#if ENABLE_HUSH_LOOPS
4260 if (ctx->ctx_res_w == RES_FOR) {
4261 if (ctx->word.has_quoted_part
4262 || endofname(command->argv[0])[0] != '\0'
4263 ) {
4264
4265 syntax_error("bad variable name in for");
4266 return 1;
4267 }
4268
4269
4270
4271
4272 done_pipe(ctx, PIPE_SEQ);
4273 }
4274#endif
4275#if ENABLE_HUSH_CASE
4276
4277 if (ctx->ctx_res_w == RES_CASE) {
4278 done_pipe(ctx, PIPE_SEQ);
4279 }
4280#endif
4281
4282 o_reset_to_empty_unquoted(&ctx->word);
4283
4284 debug_printf_parse("done_word return 0\n");
4285 return 0;
4286}
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297#if BB_MMU
4298#define parse_redir_right_fd(as_string, input) \
4299 parse_redir_right_fd(input)
4300#endif
4301static int parse_redir_right_fd(o_string *as_string, struct in_str *input)
4302{
4303 int ch, d, ok;
4304
4305 ch = i_peek(input);
4306 if (ch != '&')
4307 return REDIRFD_TO_FILE;
4308
4309 ch = i_getch(input);
4310 nommu_addchr(as_string, ch);
4311 ch = i_peek(input);
4312 if (ch == '-') {
4313 ch = i_getch(input);
4314 nommu_addchr(as_string, ch);
4315 return REDIRFD_CLOSE;
4316 }
4317 d = 0;
4318 ok = 0;
4319 while (ch != EOF && isdigit(ch)) {
4320 d = d*10 + (ch-'0');
4321 ok = 1;
4322 ch = i_getch(input);
4323 nommu_addchr(as_string, ch);
4324 ch = i_peek(input);
4325 }
4326 if (ok) return d;
4327
4328
4329
4330 bb_simple_error_msg("ambiguous redirect");
4331 return REDIRFD_SYNTAX_ERR;
4332}
4333
4334
4335
4336static int parse_redirect(struct parse_context *ctx,
4337 int fd,
4338 redir_type style,
4339 struct in_str *input)
4340{
4341 struct command *command = ctx->command;
4342 struct redir_struct *redir;
4343 struct redir_struct **redirp;
4344 int dup_num;
4345
4346 dup_num = REDIRFD_TO_FILE;
4347 if (style != REDIRECT_HEREDOC) {
4348
4349 dup_num = parse_redir_right_fd(&ctx->as_string, input);
4350 if (dup_num == REDIRFD_SYNTAX_ERR)
4351 return 1;
4352 } else {
4353 int ch = i_peek_and_eat_bkslash_nl(input);
4354 dup_num = (ch == '-');
4355 if (dup_num) {
4356 ch = i_getch(input);
4357 nommu_addchr(&ctx->as_string, ch);
4358 ch = i_peek(input);
4359 }
4360 }
4361
4362 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) {
4363 int ch = i_peek_and_eat_bkslash_nl(input);
4364 if (ch == '|') {
4365
4366
4367
4368
4369 ch = i_getch(input);
4370 nommu_addchr(&ctx->as_string, ch);
4371 }
4372 }
4373
4374
4375 redirp = &command->redirects;
4376 while ((redir = *redirp) != NULL) {
4377 redirp = &(redir->next);
4378 }
4379 *redirp = redir = xzalloc(sizeof(*redir));
4380
4381
4382 redir->rd_type = style;
4383 redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd;
4384
4385 debug_printf_parse("redirect type %d %s\n", redir->rd_fd,
4386 redir_table[style].descrip);
4387
4388 redir->rd_dup = dup_num;
4389 if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) {
4390
4391
4392
4393 debug_printf_parse("duplicating redirect '%d>&%d'\n",
4394 redir->rd_fd, redir->rd_dup);
4395 } else {
4396#if 0
4397 if (ctx->pending_redirect) {
4398
4399 syntax_error("invalid redirect");
4400 }
4401#endif
4402
4403
4404 ctx->pending_redirect = redir;
4405 }
4406 return 0;
4407}
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429static int redirect_opt_num(o_string *o)
4430{
4431 int num;
4432
4433 if (o->data == NULL)
4434 return -1;
4435 num = bb_strtou(o->data, NULL, 10);
4436 if (errno || num < 0)
4437 return -1;
4438 o_reset_to_empty_unquoted(o);
4439 return num;
4440}
4441
4442#if BB_MMU
4443#define fetch_till_str(as_string, input, word, skip_tabs) \
4444 fetch_till_str(input, word, skip_tabs)
4445#endif
4446static char *fetch_till_str(o_string *as_string,
4447 struct in_str *input,
4448 const char *word,
4449 int heredoc_flags)
4450{
4451 o_string heredoc = NULL_O_STRING;
4452 unsigned past_EOL;
4453 int prev = 0;
4454 int ch;
4455
4456
4457
4458
4459
4460
4461
4462 heredoc.data = xzalloc(1);
4463
4464 goto jump_in;
4465
4466 while (1) {
4467 ch = i_getch(input);
4468 if (ch != EOF)
4469 nommu_addchr(as_string, ch);
4470 if (ch == '\n' || ch == EOF) {
4471 check_heredoc_end:
4472 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
4473
4474 if (strcmp(heredoc.data + past_EOL, word) == 0) {
4475 heredoc.data[past_EOL] = '\0';
4476 debug_printf_heredoc("parsed '%s' heredoc '%s'\n", word, heredoc.data);
4477 return heredoc.data;
4478 }
4479 if (ch == '\n') {
4480
4481
4482
4483 o_addchr(&heredoc, ch);
4484 prev = ch;
4485 jump_in:
4486 past_EOL = heredoc.length;
4487
4488 do {
4489 ch = i_getch(input);
4490 if (ch != EOF)
4491 nommu_addchr(as_string, ch);
4492 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
4493
4494
4495
4496 if (ch == '\n')
4497 goto check_heredoc_end;
4498 }
4499 } else {
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511 heredoc.data[--heredoc.length] = '\0';
4512 prev = 0;
4513 continue;
4514 }
4515 }
4516 if (ch == EOF) {
4517 o_free(&heredoc);
4518 return NULL;
4519 }
4520 o_addchr(&heredoc, ch);
4521 nommu_addchr(as_string, ch);
4522 if (prev == '\\' && ch == '\\')
4523
4524 prev = 0;
4525 else
4526 prev = ch;
4527 }
4528}
4529
4530
4531
4532
4533#if BB_MMU
4534#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
4535 fetch_heredocs(pi, heredoc_cnt, input)
4536#endif
4537static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
4538{
4539 while (pi && heredoc_cnt) {
4540 int i;
4541 struct command *cmd = pi->cmds;
4542
4543 debug_printf_heredoc("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n",
4544 pi->num_cmds,
4545 cmd->argv ? cmd->argv[0] : "NONE"
4546 );
4547 for (i = 0; i < pi->num_cmds; i++) {
4548 struct redir_struct *redir = cmd->redirects;
4549
4550 debug_printf_heredoc("fetch_heredocs: %d cmd argv0:'%s'\n",
4551 i, cmd->argv ? cmd->argv[0] : "NONE");
4552 while (redir) {
4553 if (redir->rd_type == REDIRECT_HEREDOC) {
4554 char *p;
4555
4556 redir->rd_type = REDIRECT_HEREDOC2;
4557
4558 p = fetch_till_str(as_string, input,
4559 redir->rd_filename, redir->rd_dup);
4560 if (!p) {
4561 syntax_error("unexpected EOF in here document");
4562 return -1;
4563 }
4564 free(redir->rd_filename);
4565 redir->rd_filename = p;
4566 heredoc_cnt--;
4567 }
4568 redir = redir->next;
4569 }
4570 if (cmd->group) {
4571
4572 heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
4573
4574 if (heredoc_cnt < 0)
4575 return heredoc_cnt;
4576 }
4577 cmd++;
4578 }
4579 pi = pi->next;
4580 }
4581 return heredoc_cnt;
4582}
4583
4584
4585static int run_list(struct pipe *pi);
4586#if BB_MMU
4587#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
4588 parse_stream(heredoc_cnt_ptr, input, end_trigger)
4589#endif
4590static struct pipe *parse_stream(char **pstring,
4591 int *heredoc_cnt_ptr,
4592 struct in_str *input,
4593 int end_trigger);
4594
4595
4596
4597
4598static int parse_group(struct parse_context *ctx,
4599 struct in_str *input, int ch)
4600{
4601
4602
4603
4604#if BB_MMU
4605# define as_string NULL
4606#else
4607 char *as_string = NULL;
4608#endif
4609 struct pipe *pipe_list;
4610 int heredoc_cnt = 0;
4611 int endch;
4612 struct command *command = ctx->command;
4613
4614 debug_printf_parse("parse_group entered\n");
4615#if ENABLE_HUSH_FUNCTIONS
4616 if (ch == '(' && !ctx->word.has_quoted_part) {
4617 if (ctx->word.length)
4618 if (done_word(ctx))
4619 return -1;
4620 if (!command->argv)
4621 goto skip;
4622 if (command->argv[1]) {
4623 syntax_error_unexpected_ch('(');
4624 return -1;
4625 }
4626
4627 do
4628 ch = i_getch(input);
4629 while (ch == ' ' || ch == '\t');
4630 if (ch != ')') {
4631 syntax_error_unexpected_ch(ch);
4632 return -1;
4633 }
4634 nommu_addchr(&ctx->as_string, ch);
4635 do
4636 ch = i_getch(input);
4637 while (ch == ' ' || ch == '\t' || ch == '\n');
4638 if (ch != '{' && ch != '(') {
4639 syntax_error_unexpected_ch(ch);
4640 return -1;
4641 }
4642 nommu_addchr(&ctx->as_string, ch);
4643 command->cmd_type = CMD_FUNCDEF;
4644 goto skip;
4645 }
4646#endif
4647
4648#if 0
4649 if (command->argv
4650 || ctx->word.length
4651 || ctx->word.has_quoted_part
4652 ) {
4653 syntax_error(NULL);
4654 debug_printf_parse("parse_group return -1: "
4655 "syntax error, groups and arglists don't mix\n");
4656 return -1;
4657 }
4658#endif
4659
4660 IF_HUSH_FUNCTIONS(skip:)
4661
4662 endch = '}';
4663 if (ch == '(') {
4664 endch = ')';
4665 IF_HUSH_FUNCTIONS(if (command->cmd_type != CMD_FUNCDEF))
4666 command->cmd_type = CMD_SUBSHELL;
4667 } else {
4668
4669 ch = i_peek(input);
4670 if (ch != ' ' && ch != '\t' && ch != '\n'
4671 && ch != '('
4672 ) {
4673 syntax_error_unexpected_ch(ch);
4674 return -1;
4675 }
4676 if (ch != '(') {
4677 ch = i_getch(input);
4678 nommu_addchr(&ctx->as_string, ch);
4679 }
4680 }
4681
4682 debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
4683 pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
4684 debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
4685#if !BB_MMU
4686 if (as_string)
4687 o_addstr(&ctx->as_string, as_string);
4688#endif
4689
4690
4691 if (!pipe_list || pipe_list == ERR_PTR) {
4692
4693 if (!BB_MMU)
4694 free(as_string);
4695 debug_printf_parse("parse_group return -1: "
4696 "parse_stream returned %p\n", pipe_list);
4697 return -1;
4698 }
4699#if !BB_MMU
4700 as_string[strlen(as_string) - 1] = '\0';
4701 command->group_as_string = as_string;
4702 debug_printf_parse("end of group, remembering as:'%s'\n",
4703 command->group_as_string);
4704#endif
4705
4706#if ENABLE_HUSH_FUNCTIONS
4707
4708 if (command->cmd_type == CMD_FUNCDEF && endch == ')') {
4709 struct command *cmd2;
4710
4711 cmd2 = xzalloc(sizeof(*cmd2));
4712 cmd2->cmd_type = CMD_SUBSHELL;
4713 cmd2->group = pipe_list;
4714# if !BB_MMU
4715
4716 cmd2->group_as_string = command->group_as_string;
4717 command->group_as_string = xasprintf("(%s)", command->group_as_string);
4718# endif
4719
4720 pipe_list = new_pipe();
4721 pipe_list->cmds = cmd2;
4722 pipe_list->num_cmds = 1;
4723 }
4724#endif
4725
4726 command->group = pipe_list;
4727
4728 debug_printf_parse("parse_group return %d\n", heredoc_cnt);
4729 return heredoc_cnt;
4730
4731#undef as_string
4732}
4733
4734#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4735
4736
4737static int add_till_single_quote(o_string *dest, struct in_str *input)
4738{
4739 while (1) {
4740 int ch = i_getch(input);
4741 if (ch == EOF) {
4742 syntax_error_unterm_ch('\'');
4743 return 0;
4744 }
4745 if (ch == '\'')
4746 return 1;
4747 o_addchr(dest, ch);
4748 }
4749}
4750static int add_till_single_quote_dquoted(o_string *dest, struct in_str *input)
4751{
4752 while (1) {
4753 int ch = i_getch(input);
4754 if (ch == EOF) {
4755 syntax_error_unterm_ch('\'');
4756 return 0;
4757 }
4758 if (ch == '\'')
4759 return 1;
4760 o_addqchr(dest, ch);
4761 }
4762}
4763
4764static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
4765static int add_till_double_quote(o_string *dest, struct in_str *input)
4766{
4767 while (1) {
4768 int ch = i_getch(input);
4769 if (ch == EOF) {
4770 syntax_error_unterm_ch('"');
4771 return 0;
4772 }
4773 if (ch == '"')
4774 return 1;
4775 if (ch == '\\') {
4776 o_addchr(dest, ch);
4777 ch = i_getch(input);
4778 }
4779 o_addchr(dest, ch);
4780 if (ch == '`') {
4781 if (!add_till_backquote(dest, input, 1))
4782 return 0;
4783 o_addchr(dest, ch);
4784 continue;
4785 }
4786
4787 }
4788}
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
4804{
4805 while (1) {
4806 int ch = i_getch(input);
4807 if (ch == '`')
4808 return 1;
4809 if (ch == '\\') {
4810
4811 ch = i_getch(input);
4812 if (ch != '`'
4813 && ch != '$'
4814 && ch != '\\'
4815 && (!in_dquote || ch != '"')
4816 ) {
4817 o_addchr(dest, '\\');
4818 }
4819 }
4820 if (ch == EOF) {
4821 syntax_error_unterm_ch('`');
4822 return 0;
4823 }
4824 o_addchr(dest, ch);
4825 }
4826}
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844#define DOUBLE_CLOSE_CHAR_FLAG 0x80
4845static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch)
4846{
4847 int ch;
4848 char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG;
4849# if BASH_SUBSTR || BASH_PATTERN_SUBST
4850 char end_char2 = end_ch >> 8;
4851# endif
4852 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1);
4853
4854# if ENABLE_HUSH_INTERACTIVE
4855 G.promptmode = 1;
4856# endif
4857 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
4858
4859 while (1) {
4860 ch = i_getch(input);
4861 if (ch == EOF) {
4862 syntax_error_unterm_ch(end_ch);
4863 return 0;
4864 }
4865 if (ch == end_ch
4866# if BASH_SUBSTR || BASH_PATTERN_SUBST
4867 || ch == end_char2
4868# endif
4869 ) {
4870 if (!dbl)
4871 break;
4872
4873 if (i_peek_and_eat_bkslash_nl(input) == end_ch) {
4874 i_getch(input);
4875 break;
4876 }
4877 }
4878 o_addchr(dest, ch);
4879
4880 if (ch == '(' || ch == '{') {
4881 ch = (ch == '(' ? ')' : '}');
4882 if (!add_till_closing_bracket(dest, input, ch))
4883 return 0;
4884 o_addchr(dest, ch);
4885 continue;
4886 }
4887 if (ch == '\'') {
4888 if (!add_till_single_quote(dest, input))
4889 return 0;
4890 o_addchr(dest, ch);
4891 continue;
4892 }
4893 if (ch == '"') {
4894 if (!add_till_double_quote(dest, input))
4895 return 0;
4896 o_addchr(dest, ch);
4897 continue;
4898 }
4899 if (ch == '`') {
4900 if (!add_till_backquote(dest, input, 0))
4901 return 0;
4902 o_addchr(dest, ch);
4903 continue;
4904 }
4905 if (ch == '\\') {
4906
4907 ch = i_getch(input);
4908 if (ch == EOF) {
4909 syntax_error_unterm_ch(end_ch);
4910 return 0;
4911 }
4912# if 0
4913 if (ch == '\n') {
4914
4915 o_delchr(dest);
4916 continue;
4917 }
4918# endif
4919 o_addchr(dest, ch);
4920
4921 continue;
4922 }
4923 }
4924 debug_printf_parse("%s return '%s' ch:'%c'\n", __func__, dest->data, ch);
4925 return ch;
4926}
4927#endif
4928
4929#if BASH_DOLLAR_SQUOTE
4930
4931# if BB_MMU
4932#define parse_dollar_squote(as_string, dest, input) \
4933 parse_dollar_squote(dest, input)
4934#define as_string NULL
4935# endif
4936static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input)
4937{
4938 int start;
4939 int ch = i_peek_and_eat_bkslash_nl(input);
4940 debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch);
4941 if (ch != '\'')
4942 return 0;
4943
4944 dest->has_quoted_part = 1;
4945 start = dest->length;
4946
4947 ch = i_getch(input);
4948 nommu_addchr(as_string, ch);
4949 while (1) {
4950 ch = i_getch(input);
4951 nommu_addchr(as_string, ch);
4952 if (ch == EOF) {
4953 syntax_error_unterm_ch('\'');
4954 return 0;
4955 }
4956 if (ch == '\'')
4957 break;
4958 if (ch == SPECIAL_VAR_SYMBOL) {
4959
4960 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4961 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
4962
4963 } else if (ch == '\\') {
4964 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
4965
4966 ch = i_getch(input);
4967 nommu_addchr(as_string, ch);
4968 if (strchr(C_escapes, ch)) {
4969 char buf[4];
4970 char *p = buf;
4971 int cnt = 2;
4972
4973 buf[0] = ch;
4974 if ((unsigned char)(ch - '0') <= 7) {
4975 do {
4976 ch = i_peek(input);
4977 if ((unsigned char)(ch - '0') > 7)
4978 break;
4979 *++p = ch = i_getch(input);
4980 nommu_addchr(as_string, ch);
4981 } while (--cnt != 0);
4982 } else if (ch == 'x') {
4983 do {
4984 ch = i_peek(input);
4985 if (!isxdigit(ch))
4986 break;
4987 *++p = ch = i_getch(input);
4988 nommu_addchr(as_string, ch);
4989 } while (--cnt != 0);
4990 if (cnt == 2) {
4991 ch = 'x';
4992 goto unrecognized;
4993 }
4994 }
4995 *++p = '\0';
4996 p = buf;
4997 ch = bb_process_escape_sequence((void*)&p);
4998
4999 if (ch == '\0')
5000 continue;
5001 } else {
5002 if (ch != '\'' && ch != '"') {
5003 unrecognized:
5004 o_addqchr(dest, '\\');
5005 }
5006 }
5007 }
5008 o_addqchr(dest, ch);
5009 }
5010
5011 if (dest->length == start) {
5012
5013 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5014 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5015 }
5016
5017 return 1;
5018# undef as_string
5019}
5020#else
5021# define parse_dollar_squote(as_string, dest, input) 0
5022#endif
5023
5024
5025#if BB_MMU
5026#define parse_dollar(as_string, dest, input, quote_mask) \
5027 parse_dollar(dest, input, quote_mask)
5028#define as_string NULL
5029#endif
5030static int parse_dollar(o_string *as_string,
5031 o_string *dest,
5032 struct in_str *input, unsigned char quote_mask)
5033{
5034 int ch = i_peek_and_eat_bkslash_nl(input);
5035
5036 debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask);
5037 if (isalpha(ch)) {
5038 make_var:
5039 ch = i_getch(input);
5040 nommu_addchr(as_string, ch);
5041
5042 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5043 while (1) {
5044 debug_printf_parse(": '%c'\n", ch);
5045 o_addchr(dest, ch | quote_mask);
5046 quote_mask = 0;
5047 ch = i_peek_and_eat_bkslash_nl(input);
5048 if (!isalnum(ch) && ch != '_') {
5049
5050 break;
5051 }
5052 ch = i_getch(input);
5053 nommu_addchr(as_string, ch);
5054 }
5055 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5056 } else if (isdigit(ch)) {
5057 make_one_char_var:
5058 ch = i_getch(input);
5059 nommu_addchr(as_string, ch);
5060 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5061 debug_printf_parse(": '%c'\n", ch);
5062 o_addchr(dest, ch | quote_mask);
5063 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5064 } else switch (ch) {
5065 case '$':
5066 case '!':
5067 case '?':
5068 case '#':
5069 case '*':
5070 case '@':
5071 case '-':
5072 goto make_one_char_var;
5073 case '{': {
5074 char len_single_ch;
5075
5076 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5077
5078 ch = i_getch(input);
5079 nommu_addchr(as_string, ch);
5080
5081 ch = i_getch_and_eat_bkslash_nl(input);
5082
5083
5084
5085
5086 if (ch == EOF
5087 || (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch))
5088 ) {
5089 bad_dollar_syntax:
5090 syntax_error_unterm_str("${name}");
5091 debug_printf_parse("parse_dollar return 0: unterminated ${name}\n");
5092 return 0;
5093 }
5094 nommu_addchr(as_string, ch);
5095 len_single_ch = ch;
5096 ch |= quote_mask;
5097
5098
5099
5100
5101
5102
5103 if (isdigit(len_single_ch)
5104 || (len_single_ch == '#' && isdigit(i_peek_and_eat_bkslash_nl(input)))
5105 ) {
5106
5107
5108
5109
5110
5111
5112 unsigned cnt = 9;
5113 while (1) {
5114 o_addchr(dest, ch);
5115 debug_printf_parse(": '%c'\n", ch);
5116 ch = i_getch_and_eat_bkslash_nl(input);
5117 nommu_addchr(as_string, ch);
5118 if (ch == '}')
5119 break;
5120 if (--cnt == 0)
5121 goto bad_dollar_syntax;
5122 if (len_single_ch != '#' && strchr(VAR_SUBST_OPS, ch))
5123
5124 goto eat_until_closing;
5125 if (!isdigit(ch))
5126 goto bad_dollar_syntax;
5127 }
5128 } else
5129 while (1) {
5130 unsigned pos;
5131
5132 o_addchr(dest, ch);
5133 debug_printf_parse(": '%c'\n", ch);
5134
5135 ch = i_getch(input);
5136 nommu_addchr(as_string, ch);
5137 if (ch == '}')
5138 break;
5139 if (!isalnum(ch) && ch != '_') {
5140 unsigned end_ch;
5141 unsigned char last_ch;
5142
5143
5144
5145 if (!strchr(VAR_SUBST_OPS, ch)) {
5146 if (len_single_ch != '#'
5147
5148 || i_peek(input) != '}'
5149 ) {
5150 goto bad_dollar_syntax;
5151 }
5152
5153
5154
5155
5156 }
5157 eat_until_closing:
5158
5159 end_ch = '}';
5160 if (BASH_SUBSTR
5161 && ch == ':'
5162 && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input))
5163 ) {
5164
5165 end_ch = '}' * 0x100 + ':';
5166 }
5167 if (BASH_PATTERN_SUBST
5168 && ch == '/'
5169 ) {
5170
5171 if (i_peek(input) == '/') {
5172 i_getch(input);
5173 nommu_addchr(as_string, '/');
5174 ch = '\\';
5175 }
5176 end_ch = '}' * 0x100 + '/';
5177 }
5178 o_addchr(dest, ch);
5179
5180
5181
5182
5183
5184
5185 if (i_peek(input) == '/') {
5186 o_addchr(dest, i_getch(input));
5187 }
5188 again:
5189 if (!BB_MMU)
5190 pos = dest->length;
5191#if ENABLE_HUSH_DOLLAR_OPS
5192 last_ch = add_till_closing_bracket(dest, input, end_ch);
5193 if (last_ch == 0)
5194 return 0;
5195#else
5196# error Simple code to only allow ${var} is not implemented
5197#endif
5198 if (as_string) {
5199 o_addstr(as_string, dest->data + pos);
5200 o_addchr(as_string, last_ch);
5201 }
5202
5203 if ((BASH_SUBSTR || BASH_PATTERN_SUBST)
5204 && (end_ch & 0xff00)
5205 ) {
5206
5207 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5208
5209
5210 if ((end_ch & 0xff) == last_ch) {
5211
5212 end_ch = '}';
5213 goto again;
5214 }
5215
5216 if (BASH_SUBSTR && end_ch == '}' * 0x100 + ':') {
5217
5218 o_addstr(dest, "999999999");
5219 }
5220 }
5221 break;
5222 }
5223 len_single_ch = 0;
5224 }
5225 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5226 break;
5227 }
5228#if ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_TICK
5229 case '(': {
5230 unsigned pos;
5231
5232 ch = i_getch(input);
5233 nommu_addchr(as_string, ch);
5234# if ENABLE_FEATURE_SH_MATH
5235 if (i_peek_and_eat_bkslash_nl(input) == '(') {
5236 ch = i_getch(input);
5237 nommu_addchr(as_string, ch);
5238 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5239 o_addchr(dest, quote_mask | '+');
5240 if (!BB_MMU)
5241 pos = dest->length;
5242 if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG))
5243 return 0;
5244 if (as_string) {
5245 o_addstr(as_string, dest->data + pos);
5246 o_addchr(as_string, ')');
5247 o_addchr(as_string, ')');
5248 }
5249 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5250 break;
5251 }
5252# endif
5253# if ENABLE_HUSH_TICK
5254 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5255 o_addchr(dest, quote_mask | '`');
5256 if (!BB_MMU)
5257 pos = dest->length;
5258 if (!add_till_closing_bracket(dest, input, ')'))
5259 return 0;
5260 if (as_string) {
5261 o_addstr(as_string, dest->data + pos);
5262 o_addchr(as_string, ')');
5263 }
5264 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5265# endif
5266 break;
5267 }
5268#endif
5269 case '_':
5270 goto make_var;
5271#if 0
5272
5273
5274
5275
5276 ch = i_getch(input);
5277 nommu_addchr(as_string, ch);
5278 ch = i_peek_and_eat_bkslash_nl(input);
5279 if (isalnum(ch)) {
5280 ch = '_';
5281 goto make_var1;
5282 }
5283
5284#endif
5285 default:
5286 o_addQchr(dest, '$');
5287 }
5288 debug_printf_parse("parse_dollar return 1 (ok)\n");
5289 return 1;
5290#undef as_string
5291}
5292
5293#if BB_MMU
5294#define encode_string(as_string, dest, input, dquote_end) \
5295 encode_string(dest, input, dquote_end)
5296#define as_string NULL
5297#endif
5298static int encode_string(o_string *as_string,
5299 o_string *dest,
5300 struct in_str *input,
5301 int dquote_end)
5302{
5303 int ch;
5304 int next;
5305
5306 again:
5307 ch = i_getch(input);
5308 if (ch != EOF)
5309 nommu_addchr(as_string, ch);
5310 if (ch == dquote_end) {
5311 debug_printf_parse("encode_string return 1 (ok)\n");
5312 return 1;
5313 }
5314
5315 if (ch == EOF) {
5316 syntax_error_unterm_ch('"');
5317 return 0;
5318 }
5319 next = '\0';
5320 if (ch != '\n') {
5321 next = i_peek(input);
5322 }
5323 debug_printf_parse("\" ch=%c (%d) escape=%d\n",
5324 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5325 if (ch == '\\') {
5326 if (next == EOF) {
5327
5328
5329
5330
5331 syntax_error_unterm_ch('"');
5332 return 0;
5333 }
5334
5335
5336
5337
5338
5339
5340
5341
5342 if (next == dquote_end || strchr("$`\\\n", next)) {
5343 ch = i_getch(input);
5344 if (ch == '\n')
5345 goto again;
5346 }
5347 o_addqchr(dest, ch);
5348 nommu_addchr(as_string, ch);
5349 goto again;
5350 }
5351 if (ch == '$') {
5352
5353
5354 if (!parse_dollar(as_string, dest, input, 0x80)) {
5355 debug_printf_parse("encode_string return 0: "
5356 "parse_dollar returned 0 (error)\n");
5357 return 0;
5358 }
5359 goto again;
5360 }
5361#if ENABLE_HUSH_TICK
5362 if (ch == '`') {
5363
5364 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5365 o_addchr(dest, 0x80 | '`');
5366 if (!add_till_backquote(dest, input, dquote_end == '"'))
5367 return 0;
5368 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5369
5370 goto again;
5371 }
5372#endif
5373 o_addQchr(dest, ch);
5374 if (ch == SPECIAL_VAR_SYMBOL) {
5375
5376 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
5377 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5378 }
5379 goto again;
5380#undef as_string
5381}
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391static struct pipe *parse_stream(char **pstring,
5392 int *heredoc_cnt_ptr,
5393 struct in_str *input,
5394 int end_trigger)
5395{
5396 struct parse_context ctx;
5397 int heredoc_cnt;
5398
5399
5400
5401
5402 debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
5403 end_trigger ? end_trigger : 'X');
5404 debug_enter();
5405
5406 initialize_context(&ctx);
5407
5408
5409
5410
5411 ctx.word.data = xzalloc(1);
5412
5413
5414
5415
5416
5417
5418 heredoc_cnt = 0;
5419 while (1) {
5420 const char *is_blank;
5421 const char *is_special;
5422 int ch;
5423 int next;
5424 int redir_fd;
5425 redir_type redir_style;
5426
5427 ch = i_getch(input);
5428 debug_printf_parse(": ch=%c (%d) escape=%d\n",
5429 ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5430 if (ch == EOF) {
5431 struct pipe *pi;
5432
5433 if (heredoc_cnt) {
5434 syntax_error_unterm_str("here document");
5435 goto parse_error_exitcode1;
5436 }
5437 if (end_trigger == ')') {
5438 syntax_error_unterm_ch('(');
5439 goto parse_error_exitcode1;
5440 }
5441 if (end_trigger == '}') {
5442 syntax_error_unterm_ch('{');
5443 goto parse_error_exitcode1;
5444 }
5445
5446 if (done_word(&ctx)) {
5447 goto parse_error_exitcode1;
5448 }
5449 o_free_and_set_NULL(&ctx.word);
5450 done_pipe(&ctx, PIPE_SEQ);
5451 pi = ctx.list_head;
5452
5453
5454
5455 if (pi->num_cmds == 0
5456 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)
5457 ) {
5458 free_pipe_list(pi);
5459 pi = NULL;
5460 }
5461#if !BB_MMU
5462 debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
5463 if (pstring)
5464 *pstring = ctx.as_string.data;
5465 else
5466 o_free(&ctx.as_string);
5467#endif
5468
5469
5470
5471 debug_leave();
5472 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5473 debug_printf_parse("parse_stream return %p\n", pi);
5474 return pi;
5475 }
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485 if (ch == '\\') {
5486 ch = i_getch(input);
5487 if (ch == '\n')
5488 continue;
5489 nommu_addchr(&ctx.as_string, '\\');
5490 if (ch == SPECIAL_VAR_SYMBOL) {
5491 nommu_addchr(&ctx.as_string, ch);
5492
5493 goto case_SPECIAL_VAR_SYMBOL;
5494 }
5495 o_addchr(&ctx.word, '\\');
5496 if (ch == EOF) {
5497
5498
5499
5500
5501 continue;
5502 }
5503
5504
5505
5506 ctx.word.has_quoted_part = 1;
5507 nommu_addchr(&ctx.as_string, ch);
5508 o_addchr(&ctx.word, ch);
5509 continue;
5510 }
5511 nommu_addchr(&ctx.as_string, ch);
5512 if (ch == '\'') {
5513 ctx.word.has_quoted_part = 1;
5514 next = i_getch(input);
5515 if (next == '\'' && !ctx.pending_redirect)
5516 goto insert_empty_quoted_str_marker;
5517
5518 ch = next;
5519 while (1) {
5520 if (ch == EOF) {
5521 syntax_error_unterm_ch('\'');
5522 goto parse_error_exitcode1;
5523 }
5524 nommu_addchr(&ctx.as_string, ch);
5525 if (ch == '\'')
5526 break;
5527 if (ch == SPECIAL_VAR_SYMBOL) {
5528
5529 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5530 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
5531 }
5532 o_addqchr(&ctx.word, ch);
5533 ch = i_getch(input);
5534 }
5535 continue;
5536 }
5537
5538 next = '\0';
5539 if (ch != '\n')
5540 next = i_peek_and_eat_bkslash_nl(input);
5541
5542 is_special = "{}<>&|();#"
5543 "$\"" IF_HUSH_TICK("`")
5544 SPECIAL_VAR_SYMBOL_STR;
5545#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
5546 if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
5547
5548 is_special += 8;
5549 } else
5550#endif
5551
5552 if (ctx.command->argv
5553 || ctx.word.length
5554 || ctx.word.has_quoted_part
5555 || (next != ';'
5556 && next != ')'
5557 && next != '('
5558 && next != '&'
5559 && next != '|'
5560 && !strchr(defifs, next)
5561 )
5562 ) {
5563
5564 is_special += 2;
5565 }
5566 is_special = strchr(is_special, ch);
5567 is_blank = strchr(defifs, ch);
5568
5569 if (!is_special && !is_blank) {
5570 ordinary_char:
5571 o_addQchr(&ctx.word, ch);
5572 if ((ctx.is_assignment == MAYBE_ASSIGNMENT
5573 || ctx.is_assignment == WORD_IS_KEYWORD)
5574 && ch == '='
5575 && endofname(ctx.word.data)[0] == '='
5576 ) {
5577 ctx.is_assignment = DEFINITELY_ASSIGNMENT;
5578 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5579 }
5580 continue;
5581 }
5582
5583 if (is_blank) {
5584#if ENABLE_HUSH_LINENO_VAR
5585
5586
5587
5588
5589
5590
5591
5592 while (ch != '\n') {
5593 next = i_peek(input);
5594 if (next != ' ' && next != '\t' && next != '\n')
5595 break;
5596 ch = i_getch(input);
5597 }
5598
5599#endif
5600 if (done_word(&ctx)) {
5601 goto parse_error_exitcode1;
5602 }
5603 if (ch == '\n') {
5604
5605
5606
5607
5608
5609 if (IS_NULL_CMD(ctx.command)
5610 && ctx.word.length == 0
5611 && !ctx.word.has_quoted_part
5612 && heredoc_cnt == 0
5613 ) {
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631 struct pipe *pi = ctx.list_head;
5632 if (pi->num_cmds != 0
5633 && pi->followup != PIPE_BG
5634 ) {
5635 continue;
5636 }
5637 }
5638
5639 done_pipe(&ctx, PIPE_SEQ);
5640 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
5641 if (heredoc_cnt) {
5642 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5643 if (heredoc_cnt != 0)
5644 goto parse_error_exitcode1;
5645 }
5646 ctx.is_assignment = MAYBE_ASSIGNMENT;
5647 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5648 ch = ';';
5649
5650
5651 }
5652 }
5653
5654
5655
5656
5657
5658 if (ch == '}') {
5659 if (ctx.word.length != 0
5660 || ctx.word.has_quoted_part
5661 ) {
5662 goto ordinary_char;
5663 }
5664 if (!IS_NULL_CMD(ctx.command)) {
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674 if (ctx.command->group)
5675 goto term_group;
5676 goto ordinary_char;
5677 }
5678 if (!IS_NULL_PIPE(ctx.pipe))
5679
5680 goto skip_end_trigger;
5681
5682 }
5683 term_group:
5684 if (end_trigger && end_trigger == ch
5685 && (ch != ';' || heredoc_cnt == 0)
5686#if ENABLE_HUSH_CASE
5687 && (ch != ')'
5688 || ctx.ctx_res_w != RES_MATCH
5689 || (!ctx.word.has_quoted_part && strcmp(ctx.word.data, "esac") == 0)
5690 )
5691#endif
5692 ) {
5693 if (done_word(&ctx)) {
5694 goto parse_error_exitcode1;
5695 }
5696 done_pipe(&ctx, PIPE_SEQ);
5697 ctx.is_assignment = MAYBE_ASSIGNMENT;
5698 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5699
5700 if (!HAS_KEYWORDS
5701 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
5702 ) {
5703 o_free_and_set_NULL(&ctx.word);
5704#if !BB_MMU
5705 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
5706 if (pstring)
5707 *pstring = ctx.as_string.data;
5708 else
5709 o_free(&ctx.as_string);
5710#endif
5711 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
5712
5713 G.last_exitcode = 2;
5714 syntax_error_unexpected_ch(ch);
5715 goto parse_error;
5716 }
5717 if (heredoc_cnt_ptr)
5718 *heredoc_cnt_ptr = heredoc_cnt;
5719 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5720 debug_printf_parse("parse_stream return %p: "
5721 "end_trigger char found\n",
5722 ctx.list_head);
5723 debug_leave();
5724 return ctx.list_head;
5725 }
5726 }
5727
5728 if (is_blank)
5729 continue;
5730
5731
5732
5733 switch (ch) {
5734 case '>':
5735 redir_fd = redirect_opt_num(&ctx.word);
5736 if (done_word(&ctx)) {
5737 goto parse_error_exitcode1;
5738 }
5739 redir_style = REDIRECT_OVERWRITE;
5740 if (next == '>') {
5741 redir_style = REDIRECT_APPEND;
5742 ch = i_getch(input);
5743 nommu_addchr(&ctx.as_string, ch);
5744 }
5745#if 0
5746 else if (next == '(') {
5747 syntax_error(">(process) not supported");
5748 goto parse_error_exitcode1;
5749 }
5750#endif
5751 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5752 goto parse_error_exitcode1;
5753 continue;
5754 case '<':
5755 redir_fd = redirect_opt_num(&ctx.word);
5756 if (done_word(&ctx)) {
5757 goto parse_error_exitcode1;
5758 }
5759 redir_style = REDIRECT_INPUT;
5760 if (next == '<') {
5761 redir_style = REDIRECT_HEREDOC;
5762 heredoc_cnt++;
5763 debug_printf_heredoc("++heredoc_cnt=%d\n", heredoc_cnt);
5764 ch = i_getch(input);
5765 nommu_addchr(&ctx.as_string, ch);
5766 } else if (next == '>') {
5767 redir_style = REDIRECT_IO;
5768 ch = i_getch(input);
5769 nommu_addchr(&ctx.as_string, ch);
5770 }
5771#if 0
5772 else if (next == '(') {
5773 syntax_error("<(process) not supported");
5774 goto parse_error_exitcode1;
5775 }
5776#endif
5777 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5778 goto parse_error_exitcode1;
5779 continue;
5780 case '#':
5781 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
5782
5783
5784
5785
5786
5787
5788
5789
5790 while (1) {
5791 ch = i_peek(input);
5792 if (ch == '\n') {
5793 nommu_addchr(&ctx.as_string, '\n');
5794 break;
5795 }
5796 ch = i_getch(input);
5797 if (ch == EOF)
5798 break;
5799 }
5800 continue;
5801 }
5802 break;
5803 }
5804 skip_end_trigger:
5805
5806 if (ctx.is_assignment == MAYBE_ASSIGNMENT
5807
5808 && !ctx.pending_redirect
5809 ) {
5810
5811
5812 ctx.is_assignment = NOT_ASSIGNMENT;
5813 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5814 }
5815
5816
5817
5818 switch (ch) {
5819 case_SPECIAL_VAR_SYMBOL:
5820 case SPECIAL_VAR_SYMBOL:
5821
5822 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5823 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
5824
5825 case '#':
5826
5827 o_addchr(&ctx.word, ch);
5828 continue;
5829 case '$':
5830 if (parse_dollar_squote(&ctx.as_string, &ctx.word, input))
5831 continue;
5832 if (!parse_dollar(&ctx.as_string, &ctx.word, input, 0)) {
5833 debug_printf_parse("parse_stream parse error: "
5834 "parse_dollar returned 0 (error)\n");
5835 goto parse_error_exitcode1;
5836 }
5837 continue;
5838 case '"':
5839 ctx.word.has_quoted_part = 1;
5840 if (next == '"' && !ctx.pending_redirect) {
5841 i_getch(input);
5842 insert_empty_quoted_str_marker:
5843 nommu_addchr(&ctx.as_string, next);
5844 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5845 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5846 continue;
5847 }
5848 if (ctx.is_assignment == NOT_ASSIGNMENT)
5849 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
5850 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
5851 goto parse_error_exitcode1;
5852 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
5853 continue;
5854#if ENABLE_HUSH_TICK
5855 case '`': {
5856 USE_FOR_NOMMU(unsigned pos;)
5857
5858 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5859 o_addchr(&ctx.word, '`');
5860 USE_FOR_NOMMU(pos = ctx.word.length;)
5861 if (!add_till_backquote(&ctx.word, input, 0))
5862 goto parse_error_exitcode1;
5863# if !BB_MMU
5864 o_addstr(&ctx.as_string, ctx.word.data + pos);
5865 o_addchr(&ctx.as_string, '`');
5866# endif
5867 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5868
5869 continue;
5870 }
5871#endif
5872 case ';':
5873#if ENABLE_HUSH_CASE
5874 case_semi:
5875#endif
5876 if (done_word(&ctx)) {
5877 goto parse_error_exitcode1;
5878 }
5879 done_pipe(&ctx, PIPE_SEQ);
5880#if ENABLE_HUSH_CASE
5881
5882
5883 while (1) {
5884 ch = i_peek_and_eat_bkslash_nl(input);
5885 if (ch != ';')
5886 break;
5887 ch = i_getch(input);
5888 nommu_addchr(&ctx.as_string, ch);
5889 if (ctx.ctx_res_w == RES_CASE_BODY) {
5890 ctx.ctx_dsemicolon = 1;
5891 ctx.ctx_res_w = RES_MATCH;
5892 break;
5893 }
5894 }
5895#endif
5896 new_cmd:
5897
5898
5899 ctx.is_assignment = MAYBE_ASSIGNMENT;
5900 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5901 continue;
5902 case '&':
5903 if (done_word(&ctx)) {
5904 goto parse_error_exitcode1;
5905 }
5906 if (next == '&') {
5907 ch = i_getch(input);
5908 nommu_addchr(&ctx.as_string, ch);
5909 done_pipe(&ctx, PIPE_AND);
5910 } else {
5911 done_pipe(&ctx, PIPE_BG);
5912 }
5913 goto new_cmd;
5914 case '|':
5915 if (done_word(&ctx)) {
5916 goto parse_error_exitcode1;
5917 }
5918#if ENABLE_HUSH_CASE
5919 if (ctx.ctx_res_w == RES_MATCH)
5920 break;
5921#endif
5922 if (next == '|') {
5923 ch = i_getch(input);
5924 nommu_addchr(&ctx.as_string, ch);
5925 done_pipe(&ctx, PIPE_OR);
5926 } else {
5927
5928
5929
5930 done_command(&ctx);
5931 }
5932 goto new_cmd;
5933 case '(':
5934#if ENABLE_HUSH_CASE
5935
5936 if (ctx.ctx_res_w == RES_MATCH
5937 && ctx.command->argv == NULL
5938 && ctx.word.length == 0
5939 && ctx.word.has_quoted_part == 0
5940 ) {
5941 continue;
5942 }
5943#endif
5944
5945 case '{': {
5946 int n = parse_group(&ctx, input, ch);
5947 if (n < 0) {
5948 goto parse_error_exitcode1;
5949 }
5950 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5951 heredoc_cnt += n;
5952 goto new_cmd;
5953 }
5954 case ')':
5955#if ENABLE_HUSH_CASE
5956 if (ctx.ctx_res_w == RES_MATCH)
5957 goto case_semi;
5958#endif
5959 case '}':
5960
5961
5962
5963 G.last_exitcode = 2;
5964 syntax_error_unexpected_ch(ch);
5965 goto parse_error;
5966 default:
5967 if (HUSH_DEBUG)
5968 bb_error_msg_and_die("BUG: unexpected %c", ch);
5969 }
5970 }
5971
5972 parse_error_exitcode1:
5973 G.last_exitcode = 1;
5974 parse_error:
5975 {
5976 struct parse_context *pctx;
5977 IF_HAS_KEYWORDS(struct parse_context *p2;)
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987 pctx = &ctx;
5988 do {
5989
5990
5991 done_pipe(pctx, PIPE_SEQ);
5992 debug_printf_clean("freeing list %p from ctx %p\n",
5993 pctx->list_head, pctx);
5994 debug_print_tree(pctx->list_head, 0);
5995 free_pipe_list(pctx->list_head);
5996 debug_printf_clean("freed list %p\n", pctx->list_head);
5997#if !BB_MMU
5998 o_free(&pctx->as_string);
5999#endif
6000 IF_HAS_KEYWORDS(p2 = pctx->stack;)
6001 if (pctx != &ctx) {
6002 free(pctx);
6003 }
6004 IF_HAS_KEYWORDS(pctx = p2;)
6005 } while (HAS_KEYWORDS && pctx);
6006
6007 o_free(&ctx.word);
6008#if !BB_MMU
6009 if (pstring)
6010 *pstring = NULL;
6011#endif
6012 debug_leave();
6013 return ERR_PTR;
6014 }
6015}
6016
6017
6018
6019
6020
6021#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
6022#define expand_string_to_string(str, EXP_flags, do_unbackslash) \
6023 expand_string_to_string(str)
6024#endif
6025static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash);
6026#if ENABLE_HUSH_TICK
6027static int process_command_subs(o_string *dest, const char *s);
6028#endif
6029static int expand_vars_to_list(o_string *output, int n, char *arg);
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
6043{
6044 while (--len >= 0) {
6045 char c = *str++;
6046
6047#if ENABLE_HUSH_BRACE_EXPANSION
6048 if (c == '{' || c == '}