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