1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
347 || defined(__APPLE__) \
348 )
349# include <malloc.h>
350#endif
351#include <glob.h>
352
353#if ENABLE_HUSH_CASE
354# include <fnmatch.h>
355#endif
356#include <sys/times.h>
357#include <sys/utsname.h>
358
359#include "busybox.h"
360#include "unicode.h"
361#include "shell_common.h"
362#include "math.h"
363#include "match.h"
364#if ENABLE_HUSH_RANDOM_SUPPORT
365# include "random.h"
366#else
367# define CLEAR_RANDOM_T(rnd) ((void)0)
368#endif
369#ifndef O_CLOEXEC
370# define O_CLOEXEC 0
371#endif
372#ifndef F_DUPFD_CLOEXEC
373# define F_DUPFD_CLOEXEC F_DUPFD
374#endif
375
376#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH)
377# include "embedded_scripts.h"
378#else
379# define NUM_SCRIPTS 0
380#endif
381
382
383
384#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
385#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
386#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
387#define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT
388#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
389#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
390#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
391#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
392
393
394
395#define LEAK_HUNTING 0
396#define BUILD_AS_NOMMU 0
397
398
399
400
401#define HUSH_DEBUG 1
402
403
404
405
406
407
408#define ENABLE_HUSH_FAST 0
409
410
411
412#define ENABLE_HUSH_DOLLAR_OPS 1
413
414
415#if BUILD_AS_NOMMU
416# undef BB_MMU
417# undef USE_FOR_NOMMU
418# undef USE_FOR_MMU
419# define BB_MMU 0
420# define USE_FOR_NOMMU(...) __VA_ARGS__
421# define USE_FOR_MMU(...)
422#endif
423
424#include "NUM_APPLETS.h"
425#if NUM_APPLETS == 1
426
427# undef CONFIG_FEATURE_SH_STANDALONE
428# undef ENABLE_FEATURE_SH_STANDALONE
429# undef IF_FEATURE_SH_STANDALONE
430# undef IF_NOT_FEATURE_SH_STANDALONE
431# define ENABLE_FEATURE_SH_STANDALONE 0
432# define IF_FEATURE_SH_STANDALONE(...)
433# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
434#endif
435
436#if !ENABLE_HUSH_INTERACTIVE
437# undef ENABLE_FEATURE_EDITING
438# define ENABLE_FEATURE_EDITING 0
439# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
440# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
441# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
442# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0
443#endif
444
445
446#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
447# define HAS_KEYWORDS 1
448# define IF_HAS_KEYWORDS(...) __VA_ARGS__
449# define IF_HAS_NO_KEYWORDS(...)
450#else
451# define HAS_KEYWORDS 0
452# define IF_HAS_KEYWORDS(...)
453# define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
454#endif
455
456
457
458#define debug_printf(...) do {} while (0)
459
460#define debug_printf_parse(...) do {} while (0)
461#define debug_printf_heredoc(...) do {} while (0)
462#define debug_print_tree(a, b) do {} while (0)
463#define debug_printf_exec(...) do {} while (0)
464#define debug_printf_env(...) do {} while (0)
465#define debug_printf_jobs(...) do {} while (0)
466#define debug_printf_expand(...) do {} while (0)
467#define debug_printf_varexp(...) do {} while (0)
468#define debug_printf_glob(...) do {} while (0)
469#define debug_printf_redir(...) do {} while (0)
470#define debug_printf_list(...) do {} while (0)
471#define debug_printf_subst(...) do {} while (0)
472#define debug_printf_prompt(...) do {} while (0)
473#define debug_printf_clean(...) do {} while (0)
474
475#define ERR_PTR ((void*)(long)1)
476
477#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n"
478
479#define _SPECIAL_VARS_STR "_*@$!?#-"
480#define SPECIAL_VARS_STR ("_*@$!?#-" + 1)
481#define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3)
482#if BASH_PATTERN_SUBST
483
484
485# define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?"
486# define VAR_SUBST_OPS ("\\/%#:-=+?" + 1)
487# define MINUS_PLUS_EQUAL_QUESTION ("\\/%#:-=+?" + 5)
488#else
489# define VAR_ENCODED_SUBST_OPS "%#:-=+?"
490# define VAR_SUBST_OPS "%#:-=+?"
491# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3)
492#endif
493
494#define SPECIAL_VAR_SYMBOL_STR "\3"
495#define SPECIAL_VAR_SYMBOL 3
496
497#define SPECIAL_VAR_QUOTED_SVS 1
498
499struct variable;
500
501static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
502
503
504
505
506#if !BB_MMU
507typedef struct nommu_save_t {
508 struct variable *old_vars;
509 char **argv;
510 char **argv_from_re_execing;
511} nommu_save_t;
512#endif
513
514enum {
515 RES_NONE = 0,
516#if ENABLE_HUSH_IF
517 RES_IF ,
518 RES_THEN ,
519 RES_ELIF ,
520 RES_ELSE ,
521 RES_FI ,
522#endif
523#if ENABLE_HUSH_LOOPS
524 RES_FOR ,
525 RES_WHILE ,
526 RES_UNTIL ,
527 RES_DO ,
528 RES_DONE ,
529#endif
530#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
531 RES_IN ,
532#endif
533#if ENABLE_HUSH_CASE
534 RES_CASE ,
535
536 RES_CASE_IN,
537 RES_MATCH ,
538 RES_CASE_BODY,
539 RES_ESAC ,
540#endif
541 RES_XXXX ,
542 RES_SNTX
543};
544
545typedef struct o_string {
546 char *data;
547 int length;
548 int maxlen;
549 int o_expflags;
550
551
552 smallint has_quoted_part;
553 smallint has_empty_slot;
554 smallint ended_in_ifs;
555} o_string;
556enum {
557 EXP_FLAG_SINGLEWORD = 0x80,
558 EXP_FLAG_GLOB = 0x2,
559
560
561 EXP_FLAG_ESC_GLOB_CHARS = 0x1,
562};
563
564#define NULL_O_STRING { NULL }
565
566#ifndef debug_printf_parse
567static const char *const assignment_flag[] = {
568 "MAYBE_ASSIGNMENT",
569 "DEFINITELY_ASSIGNMENT",
570 "NOT_ASSIGNMENT",
571 "WORD_IS_KEYWORD",
572};
573#endif
574
575
576
577
578
579
580
581
582typedef struct HFILE {
583 char *cur;
584 char *end;
585 struct HFILE *next_hfile;
586 int fd;
587 char buf[1024];
588} HFILE;
589
590typedef struct in_str {
591 const char *p;
592 int peek_buf[2];
593 int last_char;
594 HFILE *file;
595} in_str;
596
597
598
599static const struct {
600 int32_t mode;
601 signed char default_fd;
602 char descrip[3];
603} redir_table[] ALIGN4 = {
604 { O_RDONLY, 0, "<" },
605 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
606 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
607 { O_CREAT|O_RDWR, 1, "<>" },
608 { O_RDONLY, 0, "<<" },
609
610
611};
612
613struct redir_struct {
614 struct redir_struct *next;
615 char *rd_filename;
616 int rd_fd;
617
618 int rd_dup;
619 smallint rd_type;
620
621
622
623
624
625};
626typedef enum redir_type {
627 REDIRECT_INPUT = 0,
628 REDIRECT_OVERWRITE = 1,
629 REDIRECT_APPEND = 2,
630 REDIRECT_IO = 3,
631 REDIRECT_HEREDOC = 4,
632 REDIRECT_HEREDOC2 = 5,
633
634 REDIRFD_CLOSE = -3,
635 REDIRFD_SYNTAX_ERR = -2,
636 REDIRFD_TO_FILE = -1,
637
638
639 HEREDOC_SKIPTABS = 1,
640 HEREDOC_QUOTED = 2,
641} redir_type;
642
643
644struct command {
645 pid_t pid;
646 unsigned assignment_cnt;
647#if ENABLE_HUSH_LINENO_VAR
648 unsigned lineno;
649#endif
650 smallint cmd_type;
651#define CMD_NORMAL 0
652#define CMD_SUBSHELL 1
653#if BASH_TEST2
654
655# define CMD_TEST2_SINGLEWORD_NOGLOB 2
656#endif
657#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
658
659# define CMD_SINGLEWORD_NOGLOB 3
660#endif
661#if ENABLE_HUSH_FUNCTIONS
662# define CMD_FUNCDEF 4
663#endif
664
665 smalluint cmd_exitcode;
666
667 struct pipe *group;
668#if !BB_MMU
669 char *group_as_string;
670#endif
671#if ENABLE_HUSH_FUNCTIONS
672 struct function *child_func;
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687#endif
688 char **argv;
689
690
691
692
693
694
695 struct redir_struct *redirects;
696};
697
698#define IS_NULL_CMD(cmd) \
699 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
700
701struct pipe {
702 struct pipe *next;
703 int num_cmds;
704 int alive_cmds;
705 int stopped_cmds;
706#if ENABLE_HUSH_JOB
707 unsigned jobid;
708 pid_t pgrp;
709 char *cmdtext;
710#endif
711 struct command *cmds;
712 smallint followup;
713 IF_HAS_KEYWORDS(smallint pi_inverted;)
714 IF_HAS_KEYWORDS(smallint res_word;)
715};
716typedef enum pipe_style {
717 PIPE_SEQ = 0,
718 PIPE_AND = 1,
719 PIPE_OR = 2,
720 PIPE_BG = 3,
721} pipe_style;
722
723#define IS_NULL_PIPE(pi) \
724 ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE))
725
726
727struct parse_context {
728
729 struct pipe *list_head;
730
731 struct pipe *pipe;
732
733 struct command *command;
734
735 struct redir_struct *pending_redirect;
736 o_string word;
737#if !BB_MMU
738 o_string as_string;
739#endif
740 smallint is_assignment;
741#if HAS_KEYWORDS
742 smallint ctx_res_w;
743 smallint ctx_inverted;
744#if ENABLE_HUSH_CASE
745 smallint ctx_dsemicolon;
746#endif
747
748 int old_flag;
749
750
751
752
753
754
755
756
757
758 struct parse_context *stack;
759#endif
760};
761enum {
762 MAYBE_ASSIGNMENT = 0,
763 DEFINITELY_ASSIGNMENT = 1,
764 NOT_ASSIGNMENT = 2,
765
766 WORD_IS_KEYWORD = 3,
767};
768
769
770
771
772
773
774#define setenv(...) setenv_is_leaky_dont_use()
775struct variable {
776 struct variable *next;
777 char *varstr;
778 int max_len;
779 uint16_t var_nest_level;
780 smallint flg_export;
781 smallint flg_read_only;
782};
783
784enum {
785 BC_BREAK = 1,
786 BC_CONTINUE = 2,
787};
788
789#if ENABLE_HUSH_FUNCTIONS
790struct function {
791 struct function *next;
792 char *name;
793 struct command *parent_cmd;
794 struct pipe *body;
795# if !BB_MMU
796 char *body_as_string;
797# endif
798};
799#endif
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832static const char o_opt_strings[] ALIGN1 =
833 "pipefail\0"
834 "noexec\0"
835 "errexit\0"
836#if ENABLE_HUSH_MODE_X
837 "xtrace\0"
838#endif
839 ;
840enum {
841 OPT_O_PIPEFAIL,
842 OPT_O_NOEXEC,
843 OPT_O_ERREXIT,
844#if ENABLE_HUSH_MODE_X
845 OPT_O_XTRACE,
846#endif
847 NUM_OPT_O
848};
849
850
851
852struct globals {
853
854
855
856
857
858
859
860
861
862
863
864#if ENABLE_HUSH_INTERACTIVE
865
866
867 int interactive_fd;
868 IF_NOT_FEATURE_EDITING_FANCY_PROMPT(char *PS1;)
869# define G_interactive_fd (G.interactive_fd)
870#else
871# define G_interactive_fd 0
872#endif
873#if ENABLE_FEATURE_EDITING
874 line_input_t *line_input_state;
875#endif
876 pid_t root_pid;
877 pid_t root_ppid;
878 pid_t last_bg_pid;
879#if ENABLE_HUSH_RANDOM_SUPPORT
880 random_t random_gen;
881#endif
882#if ENABLE_HUSH_JOB
883 int run_list_level;
884 unsigned last_jobid;
885 pid_t saved_tty_pgrp;
886 struct pipe *job_list;
887# define G_saved_tty_pgrp (G.saved_tty_pgrp)
888#else
889# define G_saved_tty_pgrp 0
890#endif
891
892 int errexit_depth;
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910 char o_opt[NUM_OPT_O];
911#if ENABLE_HUSH_MODE_X
912# define G_x_mode (G.o_opt[OPT_O_XTRACE])
913#else
914# define G_x_mode 0
915#endif
916 char opt_s;
917 char opt_c;
918#if ENABLE_HUSH_INTERACTIVE
919 smallint promptmode;
920#endif
921 smallint flag_SIGINT;
922#if ENABLE_HUSH_LOOPS
923 smallint flag_break_continue;
924#endif
925#if ENABLE_HUSH_FUNCTIONS
926
927
928
929
930 smallint flag_return_in_progress;
931# define G_flag_return_in_progress (G.flag_return_in_progress)
932#else
933# define G_flag_return_in_progress 0
934#endif
935 smallint exiting;
936
937 smalluint last_exitcode;
938 smalluint expand_exitcode;
939 smalluint last_bg_pid_exitcode;
940#if ENABLE_HUSH_SET
941
942 smalluint global_args_malloced;
943# define G_global_args_malloced (G.global_args_malloced)
944#else
945# define G_global_args_malloced 0
946#endif
947#if ENABLE_HUSH_BASH_COMPAT
948 int dead_job_exitcode;
949#endif
950
951 int global_argc;
952 char **global_argv;
953#if !BB_MMU
954 char *argv0_for_re_execing;
955#endif
956#if ENABLE_HUSH_LOOPS
957 unsigned depth_break_continue;
958 unsigned depth_of_loop;
959#endif
960#if ENABLE_HUSH_GETOPTS
961 unsigned getopt_count;
962#endif
963 const char *ifs;
964 char *ifs_whitespace;
965 const char *cwd;
966 struct variable *top_var;
967 char **expanded_assignments;
968 struct variable **shadowed_vars_pp;
969 unsigned var_nest_level;
970#if ENABLE_HUSH_FUNCTIONS
971# if ENABLE_HUSH_LOCAL
972 unsigned func_nest_level;
973# endif
974 struct function *top_func;
975#endif
976
977#if ENABLE_HUSH_FAST
978 unsigned count_SIGCHLD;
979 unsigned handled_SIGCHLD;
980 smallint we_have_children;
981#endif
982#if ENABLE_HUSH_LINENO_VAR
983 unsigned parse_lineno;
984 unsigned execute_lineno;
985#endif
986 HFILE *HFILE_list;
987 HFILE *HFILE_stdin;
988
989
990
991
992
993
994
995 unsigned special_sig_mask;
996#if ENABLE_HUSH_JOB
997 unsigned fatal_sig_mask;
998# define G_fatal_sig_mask (G.fatal_sig_mask)
999#else
1000# define G_fatal_sig_mask 0
1001#endif
1002#if ENABLE_HUSH_TRAP
1003 int pre_trap_exitcode;
1004# if ENABLE_HUSH_FUNCTIONS
1005 int return_exitcode;
1006# endif
1007 char **traps;
1008# define G_traps G.traps
1009#else
1010# define G_traps ((char**)NULL)
1011#endif
1012 sigset_t pending_set;
1013#if ENABLE_HUSH_MEMLEAK
1014 unsigned long memleak_value;
1015#endif
1016#if ENABLE_HUSH_MODE_X
1017 unsigned x_mode_depth;
1018
1019
1020
1021
1022 int x_mode_fd;
1023 o_string x_mode_buf;
1024#endif
1025#if HUSH_DEBUG >= 2
1026 int debug_indent;
1027#endif
1028 struct sigaction sa;
1029 char optstring_buf[sizeof("eixcs")];
1030#if BASH_EPOCH_VARS
1031 char epoch_buf[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
1032#endif
1033#if ENABLE_FEATURE_EDITING
1034 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
1035#endif
1036};
1037#define G (*ptr_to_globals)
1038
1039
1040
1041#define INIT_G() do { \
1042 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
1043 \
1044 sigfillset(&G.sa.sa_mask); \
1045 G.sa.sa_flags = SA_RESTART; \
1046} while (0)
1047
1048
1049
1050static int builtin_cd(char **argv) FAST_FUNC;
1051#if ENABLE_HUSH_ECHO
1052static int builtin_echo(char **argv) FAST_FUNC;
1053#endif
1054static int builtin_eval(char **argv) FAST_FUNC;
1055static int builtin_exec(char **argv) FAST_FUNC;
1056static int builtin_exit(char **argv) FAST_FUNC;
1057#if ENABLE_HUSH_EXPORT
1058static int builtin_export(char **argv) FAST_FUNC;
1059#endif
1060#if ENABLE_HUSH_READONLY
1061static int builtin_readonly(char **argv) FAST_FUNC;
1062#endif
1063#if ENABLE_HUSH_JOB
1064static int builtin_fg_bg(char **argv) FAST_FUNC;
1065static int builtin_jobs(char **argv) FAST_FUNC;
1066#endif
1067#if ENABLE_HUSH_GETOPTS
1068static int builtin_getopts(char **argv) FAST_FUNC;
1069#endif
1070#if ENABLE_HUSH_HELP
1071static int builtin_help(char **argv) FAST_FUNC;
1072#endif
1073#if MAX_HISTORY && ENABLE_FEATURE_EDITING
1074static int builtin_history(char **argv) FAST_FUNC;
1075#endif
1076#if ENABLE_HUSH_LOCAL
1077static int builtin_local(char **argv) FAST_FUNC;
1078#endif
1079#if ENABLE_HUSH_MEMLEAK
1080static int builtin_memleak(char **argv) FAST_FUNC;
1081#endif
1082#if ENABLE_HUSH_PRINTF
1083static int builtin_printf(char **argv) FAST_FUNC;
1084#endif
1085static int builtin_pwd(char **argv) FAST_FUNC;
1086#if ENABLE_HUSH_READ
1087static int builtin_read(char **argv) FAST_FUNC;
1088#endif
1089#if ENABLE_HUSH_SET
1090static int builtin_set(char **argv) FAST_FUNC;
1091#endif
1092static int builtin_shift(char **argv) FAST_FUNC;
1093static int builtin_source(char **argv) FAST_FUNC;
1094#if ENABLE_HUSH_TEST || BASH_TEST2
1095static int builtin_test(char **argv) FAST_FUNC;
1096#endif
1097#if ENABLE_HUSH_TRAP
1098static int builtin_trap(char **argv) FAST_FUNC;
1099#endif
1100#if ENABLE_HUSH_TYPE
1101static int builtin_type(char **argv) FAST_FUNC;
1102#endif
1103#if ENABLE_HUSH_TIMES
1104static int builtin_times(char **argv) FAST_FUNC;
1105#endif
1106static int builtin_true(char **argv) FAST_FUNC;
1107#if ENABLE_HUSH_UMASK
1108static int builtin_umask(char **argv) FAST_FUNC;
1109#endif
1110#if ENABLE_HUSH_UNSET
1111static int builtin_unset(char **argv) FAST_FUNC;
1112#endif
1113#if ENABLE_HUSH_KILL
1114static int builtin_kill(char **argv) FAST_FUNC;
1115#endif
1116#if ENABLE_HUSH_WAIT
1117static int builtin_wait(char **argv) FAST_FUNC;
1118#endif
1119#if ENABLE_HUSH_LOOPS
1120static int builtin_break(char **argv) FAST_FUNC;
1121static int builtin_continue(char **argv) FAST_FUNC;
1122#endif
1123#if ENABLE_HUSH_FUNCTIONS
1124static int builtin_return(char **argv) FAST_FUNC;
1125#endif
1126
1127
1128
1129
1130
1131
1132
1133struct built_in_command {
1134 const char *b_cmd;
1135 int (*b_function)(char **argv) FAST_FUNC;
1136#if ENABLE_HUSH_HELP
1137 const char *b_descr;
1138# define BLTIN(cmd, func, help) { cmd, func, help }
1139#else
1140# define BLTIN(cmd, func, help) { cmd, func }
1141#endif
1142};
1143
1144static const struct built_in_command bltins1[] ALIGN_PTR = {
1145 BLTIN("." , builtin_source , "Run commands in file"),
1146 BLTIN(":" , builtin_true , NULL),
1147#if ENABLE_HUSH_JOB
1148 BLTIN("bg" , builtin_fg_bg , "Resume job in background"),
1149#endif
1150#if ENABLE_HUSH_LOOPS
1151 BLTIN("break" , builtin_break , "Exit loop"),
1152#endif
1153 BLTIN("cd" , builtin_cd , "Change directory"),
1154#if ENABLE_HUSH_LOOPS
1155 BLTIN("continue" , builtin_continue, "Start new loop iteration"),
1156#endif
1157 BLTIN("eval" , builtin_eval , "Construct and run shell command"),
1158 BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"),
1159 BLTIN("exit" , builtin_exit , NULL),
1160#if ENABLE_HUSH_EXPORT
1161 BLTIN("export" , builtin_export , "Set environment variables"),
1162#endif
1163#if ENABLE_HUSH_JOB
1164 BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"),
1165#endif
1166#if ENABLE_HUSH_GETOPTS
1167 BLTIN("getopts" , builtin_getopts , NULL),
1168#endif
1169#if ENABLE_HUSH_HELP
1170 BLTIN("help" , builtin_help , NULL),
1171#endif
1172#if MAX_HISTORY && ENABLE_FEATURE_EDITING
1173 BLTIN("history" , builtin_history , "Show history"),
1174#endif
1175#if ENABLE_HUSH_JOB
1176 BLTIN("jobs" , builtin_jobs , "List jobs"),
1177#endif
1178#if ENABLE_HUSH_KILL
1179 BLTIN("kill" , builtin_kill , "Send signals to processes"),
1180#endif
1181#if ENABLE_HUSH_LOCAL
1182 BLTIN("local" , builtin_local , "Set local variables"),
1183#endif
1184#if ENABLE_HUSH_MEMLEAK
1185 BLTIN("memleak" , builtin_memleak , NULL),
1186#endif
1187#if ENABLE_HUSH_READ
1188 BLTIN("read" , builtin_read , "Input into variable"),
1189#endif
1190#if ENABLE_HUSH_READONLY
1191 BLTIN("readonly" , builtin_readonly, "Make variables read-only"),
1192#endif
1193#if ENABLE_HUSH_FUNCTIONS
1194 BLTIN("return" , builtin_return , "Return from function"),
1195#endif
1196#if ENABLE_HUSH_SET
1197 BLTIN("set" , builtin_set , "Set positional parameters"),
1198#endif
1199 BLTIN("shift" , builtin_shift , "Shift positional parameters"),
1200#if BASH_SOURCE
1201 BLTIN("source" , builtin_source , NULL),
1202#endif
1203#if ENABLE_HUSH_TIMES
1204 BLTIN("times" , builtin_times , NULL),
1205#endif
1206#if ENABLE_HUSH_TRAP
1207 BLTIN("trap" , builtin_trap , "Trap signals"),
1208#endif
1209 BLTIN("true" , builtin_true , NULL),
1210#if ENABLE_HUSH_TYPE
1211 BLTIN("type" , builtin_type , "Show command type"),
1212#endif
1213#if ENABLE_HUSH_ULIMIT
1214 BLTIN("ulimit" , shell_builtin_ulimit, "Control resource limits"),
1215#endif
1216#if ENABLE_HUSH_UMASK
1217 BLTIN("umask" , builtin_umask , "Set file creation mask"),
1218#endif
1219#if ENABLE_HUSH_UNSET
1220 BLTIN("unset" , builtin_unset , "Unset variables"),
1221#endif
1222#if ENABLE_HUSH_WAIT
1223 BLTIN("wait" , builtin_wait , "Wait for process to finish"),
1224#endif
1225};
1226
1227
1228
1229static const struct built_in_command bltins2[] ALIGN_PTR = {
1230#if ENABLE_HUSH_TEST
1231 BLTIN("[" , builtin_test , NULL),
1232#endif
1233#if BASH_TEST2
1234 BLTIN("[[" , builtin_test , NULL),
1235#endif
1236#if ENABLE_HUSH_ECHO
1237 BLTIN("echo" , builtin_echo , NULL),
1238#endif
1239#if ENABLE_HUSH_PRINTF
1240 BLTIN("printf" , builtin_printf , NULL),
1241#endif
1242 BLTIN("pwd" , builtin_pwd , NULL),
1243#if ENABLE_HUSH_TEST
1244 BLTIN("test" , builtin_test , NULL),
1245#endif
1246};
1247
1248
1249
1250
1251#if HUSH_DEBUG >= 2
1252
1253# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "")
1254# define debug_enter() (G.debug_indent++)
1255# define debug_leave() (G.debug_indent--)
1256#else
1257# define indent() ((void)0)
1258# define debug_enter() ((void)0)
1259# define debug_leave() ((void)0)
1260#endif
1261
1262#ifndef debug_printf
1263# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__))
1264#endif
1265
1266#ifndef debug_printf_parse
1267# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__))
1268#endif
1269
1270#ifndef debug_printf_heredoc
1271# define debug_printf_heredoc(...) (indent(), fdprintf(2, __VA_ARGS__))
1272#endif
1273
1274#ifndef debug_printf_exec
1275#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__))
1276#endif
1277
1278#ifndef debug_printf_env
1279# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__))
1280#endif
1281
1282#ifndef debug_printf_jobs
1283# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__))
1284# define DEBUG_JOBS 1
1285#else
1286# define DEBUG_JOBS 0
1287#endif
1288
1289#ifndef debug_printf_expand
1290# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__))
1291# define DEBUG_EXPAND 1
1292#else
1293# define DEBUG_EXPAND 0
1294#endif
1295
1296#ifndef debug_printf_varexp
1297# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__))
1298#endif
1299
1300#ifndef debug_printf_glob
1301# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__))
1302# define DEBUG_GLOB 1
1303#else
1304# define DEBUG_GLOB 0
1305#endif
1306
1307#ifndef debug_printf_redir
1308# define debug_printf_redir(...) (indent(), fdprintf(2, __VA_ARGS__))
1309#endif
1310
1311#ifndef debug_printf_list
1312# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__))
1313#endif
1314
1315#ifndef debug_printf_subst
1316# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__))
1317#endif
1318
1319#ifndef debug_printf_prompt
1320# define debug_printf_prompt(...) (indent(), fdprintf(2, __VA_ARGS__))
1321#endif
1322
1323#ifndef debug_printf_clean
1324# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__))
1325# define DEBUG_CLEAN 1
1326#else
1327# define DEBUG_CLEAN 0
1328#endif
1329
1330#if DEBUG_EXPAND
1331static void debug_print_strings(const char *prefix, char **vv)
1332{
1333 indent();
1334 fdprintf(2, "%s:\n", prefix);
1335 while (*vv)
1336 fdprintf(2, " '%s'\n", *vv++);
1337}
1338#else
1339# define debug_print_strings(prefix, vv) ((void)0)
1340#endif
1341
1342
1343
1344
1345#if LEAK_HUNTING
1346static void *xxmalloc(int lineno, size_t size)
1347{
1348 void *ptr = xmalloc((size + 0xff) & ~0xff);
1349 fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
1350 return ptr;
1351}
1352static void *xxrealloc(int lineno, void *ptr, size_t size)
1353{
1354 ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
1355 fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
1356 return ptr;
1357}
1358static char *xxstrdup(int lineno, const char *str)
1359{
1360 char *ptr = xstrdup(str);
1361 fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
1362 return ptr;
1363}
1364static void xxfree(void *ptr)
1365{
1366 fdprintf(2, "free %p\n", ptr);
1367 free(ptr);
1368}
1369# define xmalloc(s) xxmalloc(__LINE__, s)
1370# define xrealloc(p, s) xxrealloc(__LINE__, p, s)
1371# define xstrdup(s) xxstrdup(__LINE__, s)
1372# define free(p) xxfree(p)
1373#endif
1374
1375
1376
1377
1378
1379
1380
1381#if HUSH_DEBUG < 2
1382# define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__)
1383# define syntax_error(lineno, msg) syntax_error(msg)
1384# define syntax_error_at(lineno, msg) syntax_error_at(msg)
1385# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch)
1386# define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s)
1387# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
1388#endif
1389
1390static void die_if_script(void)
1391{
1392 if (!G_interactive_fd) {
1393 if (G.last_exitcode)
1394 xfunc_error_retval = G.last_exitcode;
1395 xfunc_die();
1396 }
1397}
1398
1399static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
1400{
1401 va_list p;
1402
1403#if HUSH_DEBUG >= 2
1404 bb_error_msg("hush.c:%u", lineno);
1405#endif
1406 va_start(p, fmt);
1407 bb_verror_msg(fmt, p, NULL);
1408 va_end(p);
1409 die_if_script();
1410}
1411
1412static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
1413{
1414 if (msg)
1415 bb_error_msg("syntax error: %s", msg);
1416 else
1417 bb_simple_error_msg("syntax error");
1418 die_if_script();
1419}
1420
1421static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
1422{
1423 bb_error_msg("syntax error at '%s'", msg);
1424 die_if_script();
1425}
1426
1427static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
1428{
1429 bb_error_msg("syntax error: unterminated %s", s);
1430
1431
1432}
1433
1434static void syntax_error_unterm_ch(unsigned lineno, char ch)
1435{
1436 char msg[2] = { ch, '\0' };
1437 syntax_error_unterm_str(lineno, msg);
1438}
1439
1440static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
1441{
1442 char msg[2];
1443 msg[0] = ch;
1444 msg[1] = '\0';
1445#if HUSH_DEBUG >= 2
1446 bb_error_msg("hush.c:%u", lineno);
1447#endif
1448 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
1449 die_if_script();
1450}
1451
1452#if HUSH_DEBUG < 2
1453# undef msg_and_die_if_script
1454# undef syntax_error
1455# undef syntax_error_at
1456# undef syntax_error_unterm_ch
1457# undef syntax_error_unterm_str
1458# undef syntax_error_unexpected_ch
1459#else
1460# define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__)
1461# define syntax_error(msg) syntax_error(__LINE__, msg)
1462# define syntax_error_at(msg) syntax_error_at(__LINE__, msg)
1463# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch)
1464# define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s)
1465# define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch)
1466#endif
1467
1468
1469
1470
1471
1472static char *unbackslash(char *src)
1473{
1474 char *dst = src = strchrnul(src, '\\');
1475 while (1) {
1476 if (*src == '\\') {
1477 src++;
1478 if (*src != '\0') {
1479
1480 *dst++ = *src++;
1481 continue;
1482 }
1483
1484
1485
1486 *dst++ = '\\';
1487
1488 }
1489 if ((*dst++ = *src++) == '\0')
1490 break;
1491 }
1492 return dst;
1493}
1494
1495static char **add_strings_to_strings(char **strings, char **add, int need_to_dup)
1496{
1497 int i;
1498 unsigned count1;
1499 unsigned count2;
1500 char **v;
1501
1502 v = strings;
1503 count1 = 0;
1504 if (v) {
1505 while (*v) {
1506 count1++;
1507 v++;
1508 }
1509 }
1510 count2 = 0;
1511 v = add;
1512 while (*v) {
1513 count2++;
1514 v++;
1515 }
1516 v = xrealloc(strings, (count1 + count2 + 1) * sizeof(char*));
1517 v[count1 + count2] = NULL;
1518 i = count2;
1519 while (--i >= 0)
1520 v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]);
1521 return v;
1522}
1523#if LEAK_HUNTING
1524static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup)
1525{
1526 char **ptr = add_strings_to_strings(strings, add, need_to_dup);
1527 fdprintf(2, "line %d: add_strings_to_strings %p\n", lineno, ptr);
1528 return ptr;
1529}
1530#define add_strings_to_strings(strings, add, need_to_dup) \
1531 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup)
1532#endif
1533
1534
1535static char **add_string_to_strings(char **strings, char *add)
1536{
1537 char *v[2];
1538 v[0] = add;
1539 v[1] = NULL;
1540 return add_strings_to_strings(strings, v, 0);
1541}
1542#if LEAK_HUNTING
1543static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
1544{
1545 char **ptr = add_string_to_strings(strings, add);
1546 fdprintf(2, "line %d: add_string_to_strings %p\n", lineno, ptr);
1547 return ptr;
1548}
1549#define add_string_to_strings(strings, add) \
1550 xx_add_string_to_strings(__LINE__, strings, add)
1551#endif
1552
1553static void free_strings(char **strings)
1554{
1555 char **v;
1556
1557 if (!strings)
1558 return;
1559 v = strings;
1560 while (*v) {
1561 free(*v);
1562 v++;
1563 }
1564 free(strings);
1565}
1566
1567static int dup_CLOEXEC(int fd, int avoid_fd)
1568{
1569 int newfd;
1570 repeat:
1571 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1572 if (newfd >= 0) {
1573 if (F_DUPFD_CLOEXEC == F_DUPFD)
1574 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1575 } else {
1576 if (errno == EBUSY)
1577 goto repeat;
1578 if (errno == EINTR)
1579 goto repeat;
1580 }
1581 return newfd;
1582}
1583
1584static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1585{
1586 int newfd;
1587 repeat:
1588 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1589 if (newfd < 0) {
1590 if (errno == EBUSY)
1591 goto repeat;
1592 if (errno == EINTR)
1593 goto repeat;
1594
1595 if (errno == EBADF)
1596 return fd;
1597 xfunc_die();
1598 }
1599 if (F_DUPFD_CLOEXEC == F_DUPFD)
1600 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1601 close(fd);
1602 return newfd;
1603}
1604
1605
1606
1607static HFILE *hfopen(const char *name)
1608{
1609 HFILE *fp;
1610 int fd;
1611
1612 fd = STDIN_FILENO;
1613 if (name) {
1614 fd = open(name, O_RDONLY | O_CLOEXEC);
1615 if (fd < 0)
1616 return NULL;
1617 if (O_CLOEXEC == 0)
1618 close_on_exec_on(fd);
1619 }
1620
1621 fp = xmalloc(sizeof(*fp));
1622 if (name == NULL)
1623 G.HFILE_stdin = fp;
1624 fp->fd = fd;
1625 fp->cur = fp->end = fp->buf;
1626 fp->next_hfile = G.HFILE_list;
1627 G.HFILE_list = fp;
1628 return fp;
1629}
1630static void hfclose(HFILE *fp)
1631{
1632 HFILE **pp = &G.HFILE_list;
1633 while (*pp) {
1634 HFILE *cur = *pp;
1635 if (cur == fp) {
1636 *pp = cur->next_hfile;
1637 break;
1638 }
1639 pp = &cur->next_hfile;
1640 }
1641 if (fp->fd >= 0)
1642 close(fp->fd);
1643 free(fp);
1644}
1645static int refill_HFILE_and_getc(HFILE *fp)
1646{
1647 int n;
1648
1649 if (fp->fd < 0) {
1650
1651 return EOF;
1652 }
1653#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING
1654
1655
1656
1657
1658 if (fp == G.HFILE_stdin) {
1659 struct pollfd pfd[1];
1660 pfd[0].fd = fp->fd;
1661 pfd[0].events = POLLIN;
1662 n = poll(pfd, 1, -1);
1663 if (n < 0
1664
1665 && sigismember(&G.pending_set, SIGINT)
1666 ) {
1667 return '\0';
1668 }
1669 }
1670#else
1671
1672#endif
1673
1674 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1675 if (n < 0) {
1676 bb_simple_perror_msg("read error");
1677 n = 0;
1678 }
1679 fp->cur = fp->buf;
1680 fp->end = fp->buf + n;
1681 if (n == 0) {
1682
1683 close(fp->fd);
1684 fp->fd = -1;
1685 return EOF;
1686 }
1687 return (unsigned char)(*fp->cur++);
1688}
1689
1690
1691static ALWAYS_INLINE int hfgetc(HFILE *fp)
1692{
1693 if (fp->cur < fp->end)
1694 return (unsigned char)(*fp->cur++);
1695
1696 return refill_HFILE_and_getc(fp);
1697}
1698static int move_HFILEs_on_redirect(int fd, int avoid_fd)
1699{
1700 HFILE *fl = G.HFILE_list;
1701 while (fl) {
1702 if (fd == fl->fd) {
1703
1704 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1705 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1706 return 1;
1707 }
1708 fl = fl->next_hfile;
1709 }
1710#if ENABLE_HUSH_MODE_X
1711 if (G.x_mode_fd > 0 && fd == G.x_mode_fd) {
1712 G.x_mode_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1713 return 1;
1714 }
1715#endif
1716 return 0;
1717}
1718#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
1719static void close_all_HFILE_list(void)
1720{
1721 HFILE *fl = G.HFILE_list;
1722 while (fl) {
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734 if (fl->fd > 0)
1735
1736 close(fl->fd);
1737 fl = fl->next_hfile;
1738 }
1739}
1740#endif
1741static int fd_in_HFILEs(int fd)
1742{
1743 HFILE *fl = G.HFILE_list;
1744 while (fl) {
1745 if (fl->fd == fd)
1746 return 1;
1747 fl = fl->next_hfile;
1748 }
1749 return 0;
1750}
1751
1752
1753
1754
1755typedef struct save_arg_t {
1756 char *sv_argv0;
1757 char **sv_g_argv;
1758 int sv_g_argc;
1759 IF_HUSH_SET(smallint sv_g_malloced;)
1760} save_arg_t;
1761
1762static void save_and_replace_G_args(save_arg_t *sv, char **argv)
1763{
1764 sv->sv_argv0 = argv[0];
1765 sv->sv_g_argv = G.global_argv;
1766 sv->sv_g_argc = G.global_argc;
1767 IF_HUSH_SET(sv->sv_g_malloced = G.global_args_malloced;)
1768
1769 argv[0] = G.global_argv[0];
1770 G.global_argv = argv;
1771 IF_HUSH_SET(G.global_args_malloced = 0;)
1772
1773 G.global_argc = 1 + string_array_len(argv + 1);
1774}
1775
1776static void restore_G_args(save_arg_t *sv, char **argv)
1777{
1778#if ENABLE_HUSH_SET
1779 if (G.global_args_malloced) {
1780
1781 char **pp = G.global_argv;
1782 while (*++pp)
1783 free(*pp);
1784 free(G.global_argv);
1785 }
1786#endif
1787 argv[0] = sv->sv_argv0;
1788 G.global_argv = sv->sv_g_argv;
1789 G.global_argc = sv->sv_g_argc;
1790 IF_HUSH_SET(G.global_args_malloced = sv->sv_g_malloced;)
1791}
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929enum {
1930 SPECIAL_INTERACTIVE_SIGS = 0
1931 | (1 << SIGTERM)
1932 | (1 << SIGINT)
1933 | (1 << SIGHUP)
1934 ,
1935 SPECIAL_JOBSTOP_SIGS = 0
1936#if ENABLE_HUSH_JOB
1937 | (1 << SIGTTIN)
1938 | (1 << SIGTTOU)
1939 | (1 << SIGTSTP)
1940#endif
1941 ,
1942};
1943
1944static void record_pending_signo(int sig)
1945{
1946 sigaddset(&G.pending_set, sig);
1947#if ENABLE_HUSH_FAST
1948 if (sig == SIGCHLD) {
1949 G.count_SIGCHLD++;
1950
1951 }
1952#endif
1953}
1954
1955static sighandler_t install_sighandler(int sig, sighandler_t handler)
1956{
1957 struct sigaction old_sa;
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968 G.sa.sa_handler = handler;
1969 sigaction(sig, &G.sa, &old_sa);
1970 return old_sa.sa_handler;
1971}
1972
1973static void hush_exit(int exitcode) NORETURN;
1974
1975static void restore_ttypgrp_and__exit(void) NORETURN;
1976static void restore_ttypgrp_and__exit(void)
1977{
1978
1979
1980 G.exiting = 1;
1981 hush_exit(xfunc_error_retval);
1982}
1983
1984#if ENABLE_HUSH_JOB
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999static void fflush_and__exit(void) NORETURN;
2000static void fflush_and__exit(void)
2001{
2002 fflush_all();
2003 _exit(xfunc_error_retval);
2004}
2005
2006
2007# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
2008
2009# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit)
2010
2011
2012
2013
2014
2015
2016
2017static void sigexit(int sig) NORETURN;
2018static void sigexit(int sig)
2019{
2020
2021
2022 if (G_saved_tty_pgrp && getpid() == G.root_pid) {
2023
2024
2025
2026 sigprocmask_allsigs(SIG_BLOCK);
2027 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
2028 }
2029
2030
2031 if (sig <= 0)
2032 _exit(- sig);
2033
2034 kill_myself_with_sig(sig);
2035}
2036#else
2037
2038# define disable_restore_tty_pgrp_on_exit() ((void)0)
2039# define enable_restore_tty_pgrp_on_exit() ((void)0)
2040
2041#endif
2042
2043static sighandler_t pick_sighandler(unsigned sig)
2044{
2045 sighandler_t handler = SIG_DFL;
2046 if (sig < sizeof(unsigned)*8) {
2047 unsigned sigmask = (1 << sig);
2048
2049#if ENABLE_HUSH_JOB
2050
2051 if (G_fatal_sig_mask & sigmask)
2052 handler = sigexit;
2053 else
2054#endif
2055
2056 if (G.special_sig_mask & sigmask) {
2057 handler = record_pending_signo;
2058
2059
2060
2061
2062
2063 if (SPECIAL_JOBSTOP_SIGS & sigmask)
2064 handler = SIG_IGN;
2065 }
2066 }
2067 return handler;
2068}
2069
2070
2071static void hush_exit(int exitcode)
2072{
2073#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2074 save_history(G.line_input_state);
2075#endif
2076
2077 fflush_all();
2078 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
2079 char *argv[3];
2080
2081 argv[1] = xstrdup(G_traps[0]);
2082 argv[2] = NULL;
2083 G.exiting = 1;
2084
2085
2086
2087 builtin_eval(argv);
2088 }
2089
2090#if ENABLE_FEATURE_CLEAN_UP
2091 {
2092 struct variable *cur_var;
2093 if (G.cwd != bb_msg_unknown)
2094 free((char*)G.cwd);
2095 cur_var = G.top_var;
2096 while (cur_var) {
2097 struct variable *tmp = cur_var;
2098 if (!cur_var->max_len)
2099 free(cur_var->varstr);
2100 cur_var = cur_var->next;
2101 free(tmp);
2102 }
2103 }
2104#endif
2105
2106 fflush_all();
2107#if ENABLE_HUSH_JOB
2108 sigexit(- (exitcode & 0xff));
2109#else
2110 _exit(exitcode);
2111#endif
2112}
2113
2114
2115static int check_and_run_traps(void)
2116{
2117 int last_sig = 0;
2118
2119 while (1) {
2120 int sig;
2121
2122 if (sigisemptyset(&G.pending_set))
2123 break;
2124 sig = 0;
2125 do {
2126 sig++;
2127 if (sigismember(&G.pending_set, sig)) {
2128 sigdelset(&G.pending_set, sig);
2129 goto got_sig;
2130 }
2131 } while (sig < NSIG);
2132 break;
2133 got_sig:
2134#if ENABLE_HUSH_TRAP
2135 if (G_traps && G_traps[sig]) {
2136 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
2137 if (G_traps[sig][0]) {
2138
2139 smalluint save_rcode;
2140 int save_pre;
2141 char *argv[3];
2142
2143 argv[1] = xstrdup(G_traps[sig]);
2144
2145 argv[2] = NULL;
2146 save_pre = G.pre_trap_exitcode;
2147 G.pre_trap_exitcode = save_rcode = G.last_exitcode;
2148 builtin_eval(argv);
2149 free(argv[1]);
2150 G.pre_trap_exitcode = save_pre;
2151 G.last_exitcode = save_rcode;
2152# if ENABLE_HUSH_FUNCTIONS
2153 if (G.return_exitcode >= 0) {
2154 debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
2155 G.last_exitcode = G.return_exitcode;
2156 }
2157# endif
2158 last_sig = sig;
2159 }
2160 continue;
2161 }
2162#endif
2163
2164 switch (sig) {
2165 case SIGINT:
2166 debug_printf_exec("%s: sig:%d default SIGINT handler\n", __func__, sig);
2167 G.flag_SIGINT = 1;
2168 last_sig = sig;
2169 break;
2170#if ENABLE_HUSH_JOB
2171 case SIGHUP: {
2172
2173
2174
2175 struct pipe *job;
2176 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
2177
2178
2179 for (job = G.job_list; job; job = job->next) {
2180 if (job->pgrp <= 0)
2181 continue;
2182 debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
2183 if (kill(- job->pgrp, SIGHUP) == 0)
2184 kill(- job->pgrp, SIGCONT);
2185 }
2186 sigexit(SIGHUP);
2187 }
2188#endif
2189#if ENABLE_HUSH_FAST
2190 case SIGCHLD:
2191 debug_printf_exec("%s: sig:%d default SIGCHLD handler\n", __func__, sig);
2192 G.count_SIGCHLD++;
2193
2194
2195
2196
2197
2198 break;
2199#endif
2200 default:
2201 debug_printf_exec("%s: sig:%d default handling is to ignore\n", __func__, sig);
2202
2203
2204
2205
2206
2207
2208 break;
2209 }
2210 }
2211 return last_sig;
2212}
2213
2214
2215static const char *get_cwd(int force)
2216{
2217 if (force || G.cwd == NULL) {
2218
2219
2220 if (G.cwd == bb_msg_unknown)
2221 G.cwd = NULL;
2222 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd);
2223 if (!G.cwd)
2224 G.cwd = bb_msg_unknown;
2225 }
2226 return G.cwd;
2227}
2228
2229
2230
2231
2232
2233static struct variable **get_ptr_to_local_var(const char *name, unsigned len)
2234{
2235 struct variable **pp;
2236 struct variable *cur;
2237
2238 pp = &G.top_var;
2239 while ((cur = *pp) != NULL) {
2240 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
2241 return pp;
2242 pp = &cur->next;
2243 }
2244 return NULL;
2245}
2246
2247static const char* FAST_FUNC get_local_var_value(const char *name)
2248{
2249 struct variable **vpp;
2250 unsigned len = strlen(name);
2251
2252 if (G.expanded_assignments) {
2253 char **cpp = G.expanded_assignments;
2254 while (*cpp) {
2255 char *cp = *cpp;
2256 if (strncmp(cp, name, len) == 0 && cp[len] == '=')
2257 return cp + len + 1;
2258 cpp++;
2259 }
2260 }
2261
2262 vpp = get_ptr_to_local_var(name, len);
2263 if (vpp)
2264 return (*vpp)->varstr + len + 1;
2265
2266 if (strcmp(name, "PPID") == 0)
2267 return utoa(G.root_ppid);
2268
2269#if ENABLE_HUSH_RANDOM_SUPPORT
2270 if (strcmp(name, "RANDOM") == 0)
2271 return utoa(next_random(&G.random_gen));
2272#endif
2273#if ENABLE_HUSH_LINENO_VAR
2274 if (strcmp(name, "LINENO") == 0)
2275 return utoa(G.execute_lineno);
2276#endif
2277#if BASH_EPOCH_VARS
2278 {
2279 const char *fmt = NULL;
2280 if (strcmp(name, "EPOCHSECONDS") == 0)
2281 fmt = "%llu";
2282 else if (strcmp(name, "EPOCHREALTIME") == 0)
2283 fmt = "%llu.%06u";
2284 if (fmt) {
2285 struct timeval tv;
2286 xgettimeofday(&tv);
2287 sprintf(G.epoch_buf, fmt, (unsigned long long)tv.tv_sec,
2288 (unsigned)tv.tv_usec);
2289 return G.epoch_buf;
2290 }
2291 }
2292#endif
2293 return NULL;
2294}
2295
2296#if ENABLE_HUSH_GETOPTS
2297static void handle_changed_special_names(const char *name, unsigned name_len)
2298{
2299 if (name_len == 6) {
2300 if (strncmp(name, "OPTIND", 6) == 0) {
2301 G.getopt_count = 0;
2302 return;
2303 }
2304 }
2305}
2306#else
2307
2308# define handle_changed_special_names(...) ((void)0)
2309#endif
2310
2311
2312
2313
2314#define SETFLAG_EXPORT (1 << 0)
2315#define SETFLAG_UNEXPORT (1 << 1)
2316#define SETFLAG_MAKE_RO (1 << 2)
2317#define SETFLAG_VARLVL_SHIFT 3
2318static int set_local_var(char *str, unsigned flags)
2319{
2320 struct variable **cur_pp;
2321 struct variable *cur;
2322 char *free_me = NULL;
2323 char *eq_sign;
2324 int name_len;
2325 int retval;
2326 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
2327
2328 eq_sign = strchr(str, '=');
2329 if (HUSH_DEBUG && !eq_sign)
2330 bb_simple_error_msg_and_die("BUG in setvar");
2331
2332 name_len = eq_sign - str + 1;
2333 cur_pp = &G.top_var;
2334 while ((cur = *cur_pp) != NULL) {
2335 if (strncmp(cur->varstr, str, name_len) != 0) {
2336 cur_pp = &cur->next;
2337 continue;
2338 }
2339
2340
2341 if (cur->flg_read_only) {
2342 bb_error_msg("%s: readonly variable", str);
2343 free(str);
2344
2345
2346 return -1;
2347 }
2348 if (flags & SETFLAG_UNEXPORT) {
2349 debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
2350 *eq_sign = '\0';
2351 unsetenv(str);
2352 *eq_sign = '=';
2353 }
2354 if (cur->var_nest_level < local_lvl) {
2355
2356
2357
2358
2359
2360
2361
2362
2363 if (cur->flg_export)
2364 flags |= SETFLAG_EXPORT;
2365
2366
2367
2368
2369
2370
2371 *cur_pp = cur->next;
2372 if (G.shadowed_vars_pp) {
2373
2374 debug_printf_env("shadowing %s'%s'/%u by '%s'/%u\n",
2375 cur->flg_export ? "exported " : "",
2376 cur->varstr, cur->var_nest_level, str, local_lvl
2377 );
2378 cur->next = *G.shadowed_vars_pp;
2379 *G.shadowed_vars_pp = cur;
2380 } else {
2381
2382 debug_printf_env("shadow-deleting %s'%s'/%u by '%s'/%u\n",
2383 cur->flg_export ? "exported " : "",
2384 cur->varstr, cur->var_nest_level, str, local_lvl
2385 );
2386 if (cur->max_len == 0)
2387 free_me = cur->varstr;
2388 free(cur);
2389 }
2390 break;
2391 }
2392
2393 if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
2394 debug_printf_env("assignement '%s' does not change anything\n", str);
2395 free_and_exp:
2396 free(str);
2397 goto exp;
2398 }
2399
2400
2401 if (cur->max_len != 0) {
2402 if (cur->max_len >= strnlen(str, cur->max_len + 1)) {
2403
2404 debug_printf_env("reusing startup env for '%s'\n", str);
2405 strcpy(cur->varstr, str);
2406 goto free_and_exp;
2407 }
2408
2409 cur->max_len = 0;
2410 goto set_str_and_exp;
2411 }
2412
2413
2414
2415
2416
2417
2418 free_me = cur->varstr;
2419 goto set_str_and_exp;
2420 }
2421
2422
2423 debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl);
2424 cur = xzalloc(sizeof(*cur));
2425 cur->var_nest_level = local_lvl;
2426 cur->next = *cur_pp;
2427 *cur_pp = cur;
2428
2429 set_str_and_exp:
2430 cur->varstr = str;
2431 exp:
2432#if !BB_MMU || ENABLE_HUSH_READONLY
2433 if (flags & SETFLAG_MAKE_RO) {
2434 cur->flg_read_only = 1;
2435 }
2436#endif
2437 if (flags & SETFLAG_EXPORT)
2438 cur->flg_export = 1;
2439 retval = 0;
2440 if (cur->flg_export) {
2441 if (flags & SETFLAG_UNEXPORT) {
2442 cur->flg_export = 0;
2443
2444 } else {
2445 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level);
2446 retval = putenv(cur->varstr);
2447
2448
2449
2450 }
2451 }
2452 free(free_me);
2453
2454 handle_changed_special_names(cur->varstr, name_len - 1);
2455
2456 return retval;
2457}
2458
2459static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2460{
2461 char *var = xasprintf("%s=%s", name, val);
2462 set_local_var(var, 0);
2463}
2464
2465
2466static void set_pwd_var(unsigned flag)
2467{
2468 set_local_var(xasprintf("PWD=%s", get_cwd( 1)), flag);
2469}
2470
2471#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2472static int unset_local_var_len(const char *name, int name_len)
2473{
2474 struct variable *cur;
2475 struct variable **cur_pp;
2476
2477 cur_pp = &G.top_var;
2478 while ((cur = *cur_pp) != NULL) {
2479 if (strncmp(cur->varstr, name, name_len) == 0
2480 && cur->varstr[name_len] == '='
2481 ) {
2482 if (cur->flg_read_only) {
2483 bb_error_msg("%s: readonly variable", name);
2484 return EXIT_FAILURE;
2485 }
2486
2487 *cur_pp = cur->next;
2488 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
2489 bb_unsetenv(cur->varstr);
2490 if (!cur->max_len)
2491 free(cur->varstr);
2492 free(cur);
2493
2494 break;
2495 }
2496 cur_pp = &cur->next;
2497 }
2498
2499
2500 handle_changed_special_names(name, name_len);
2501
2502 return EXIT_SUCCESS;
2503}
2504
2505static int unset_local_var(const char *name)
2506{
2507 return unset_local_var_len(name, strlen(name));
2508}
2509#endif
2510
2511
2512
2513
2514
2515static void add_vars(struct variable *var)
2516{
2517 struct variable *next;
2518
2519 while (var) {
2520 next = var->next;
2521 var->next = G.top_var;
2522 G.top_var = var;
2523 if (var->flg_export) {
2524 debug_printf_env("%s: restoring exported '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
2525 putenv(var->varstr);
2526 } else {
2527 debug_printf_env("%s: restoring variable '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
2528 }
2529 var = next;
2530 }
2531}
2532
2533
2534
2535
2536
2537
2538static void set_vars_and_save_old(char **strings)
2539{
2540 char **s;
2541
2542 if (!strings)
2543 return;
2544
2545 s = strings;
2546 while (*s) {
2547 struct variable *var_p;
2548 struct variable **var_pp;
2549 char *eq;
2550
2551 eq = strchr(*s, '=');
2552 if (HUSH_DEBUG && !eq)
2553 bb_simple_error_msg_and_die("BUG in varexp4");
2554 var_pp = get_ptr_to_local_var(*s, eq - *s);
2555 if (var_pp) {
2556 var_p = *var_pp;
2557 if (var_p->flg_read_only) {
2558 char **p;
2559 bb_error_msg("%s: readonly variable", *s);
2560
2561
2562
2563
2564
2565
2566 debug_printf_env("removing/freeing '%s' element\n", *s);
2567 free(*s);
2568 p = s;
2569 do { *p = p[1]; p++; } while (*p);
2570 goto next;
2571 }
2572
2573
2574
2575
2576 }
2577 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2578 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
2579 s++;
2580 next: ;
2581 }
2582 free(strings);
2583}
2584
2585
2586
2587
2588
2589static void reinit_unicode_for_hush(void)
2590{
2591
2592
2593
2594
2595 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2596 || ENABLE_UNICODE_USING_LOCALE
2597 ) {
2598 const char *s = get_local_var_value("LC_ALL");
2599 if (!s) s = get_local_var_value("LC_CTYPE");
2600 if (!s) s = get_local_var_value("LANG");
2601 reinit_unicode(s);
2602 }
2603}
2604
2605
2606
2607
2608
2609#if ENABLE_HUSH_INTERACTIVE
2610
2611
2612
2613
2614
2615
2616
2617
2618static const char *setup_prompt_string(void)
2619{
2620 const char *prompt_str;
2621
2622 debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode);
2623
2624# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2625 prompt_str = get_local_var_value(G.promptmode == 0 ? "PS1" : "PS2");
2626 if (!prompt_str)
2627 prompt_str = "";
2628# else
2629 prompt_str = "> ";
2630 if (G.promptmode == 0) {
2631
2632 free(G.PS1);
2633
2634
2635
2636 prompt_str = G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
2637 }
2638# endif
2639 debug_printf("prompt_str '%s'\n", prompt_str);
2640 return prompt_str;
2641}
2642static int get_user_input(struct in_str *i)
2643{
2644# if ENABLE_FEATURE_EDITING
2645
2646
2647
2648 int r;
2649 const char *prompt_str;
2650
2651 prompt_str = setup_prompt_string();
2652 for (;;) {
2653 reinit_unicode_for_hush();
2654 G.flag_SIGINT = 0;
2655
2656
2657 r = read_line_input(G.line_input_state, prompt_str,
2658 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
2659 );
2660
2661 if (r == 0) {
2662 raise(SIGINT);
2663 }
2664 check_and_run_traps();
2665 if (r != 0 && !G.flag_SIGINT)
2666 break;
2667
2668
2669 write(STDOUT_FILENO, "^C\n", 3);
2670 G.last_exitcode = 128 | SIGINT;
2671 }
2672 if (r < 0) {
2673
2674
2675 write(STDOUT_FILENO, "\n", 1);
2676 i->p = NULL;
2677 i->peek_buf[0] = r = EOF;
2678 return r;
2679 }
2680 i->p = G.user_input_buf;
2681 return (unsigned char)*i->p++;
2682# else
2683
2684
2685
2686 int r;
2687
2688 for (;;) {
2689 G.flag_SIGINT = 0;
2690 if (i->last_char == '\0' || i->last_char == '\n') {
2691 const char *prompt_str = setup_prompt_string();
2692
2693
2694
2695
2696
2697 check_and_run_traps();
2698 fputs_stdout(prompt_str);
2699 fflush_all();
2700 }
2701 r = hfgetc(i->file);
2702
2703
2704
2705
2706 check_and_run_traps();
2707 if (r != '\0' && !G.flag_SIGINT)
2708 break;
2709 if (G.flag_SIGINT) {
2710
2711
2712
2713 write(STDOUT_FILENO, "\n", 1);
2714 G.last_exitcode = 128 | SIGINT;
2715 }
2716 }
2717 return r;
2718# endif
2719}
2720
2721
2722static int fgetc_interactive(struct in_str *i)
2723{
2724 int ch;
2725
2726 if (G_interactive_fd && i->file == G.HFILE_stdin) {
2727
2728 ch = get_user_input(i);
2729 G.promptmode = 1;
2730 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
2731 } else {
2732
2733 do ch = hfgetc(i->file); while (ch == '\0');
2734 }
2735 return ch;
2736}
2737#else
2738static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
2739{
2740 int ch;
2741 do ch = hfgetc(i->file); while (ch == '\0');
2742 return ch;
2743}
2744#endif
2745
2746static int i_getch(struct in_str *i)
2747{
2748 int ch;
2749
2750 if (!i->file) {
2751
2752 ch = (unsigned char)*i->p;
2753 if (ch != '\0') {
2754 i->p++;
2755 i->last_char = ch;
2756 return ch;
2757 }
2758 return EOF;
2759 }
2760
2761
2762
2763#if ENABLE_FEATURE_EDITING
2764
2765 if (i->p && *i->p != '\0') {
2766 ch = (unsigned char)*i->p++;
2767 goto out;
2768 }
2769#endif
2770
2771 ch = i->peek_buf[0];
2772 if (ch != 0) {
2773 int ch2 = i->peek_buf[1];
2774 i->peek_buf[0] = ch2;
2775 if (ch2 == 0)
2776 goto out;
2777 i->peek_buf[1] = 0;
2778 goto out;
2779 }
2780
2781 ch = fgetc_interactive(i);
2782 out:
2783 debug_printf("file_get: got '%c' %d\n", ch, ch);
2784 i->last_char = ch;
2785#if ENABLE_HUSH_LINENO_VAR
2786 if (ch == '\n') {
2787 G.parse_lineno++;
2788 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
2789 }
2790#endif
2791 return ch;
2792}
2793
2794static int i_peek(struct in_str *i)
2795{
2796 int ch;
2797
2798 if (!i->file) {
2799
2800
2801 return (unsigned char)*i->p;
2802 }
2803
2804
2805
2806#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2807
2808 if (i->p && *i->p != '\0')
2809 return (unsigned char)*i->p;
2810#endif
2811
2812 ch = i->peek_buf[0];
2813 if (ch != 0)
2814 return ch;
2815
2816
2817 ch = fgetc_interactive(i);
2818 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2819
2820
2821#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2822 if (i->p) {
2823 i->p -= 1;
2824 return ch;
2825 }
2826#endif
2827 i->peek_buf[0] = ch;
2828
2829 return ch;
2830}
2831
2832
2833
2834
2835
2836static int i_peek2(struct in_str *i)
2837{
2838 int ch;
2839
2840
2841
2842
2843
2844
2845
2846 if (i->p)
2847 return (unsigned char)i->p[1];
2848
2849
2850
2851
2852
2853 ch = i->peek_buf[1];
2854 if (ch == 0) {
2855
2856 do ch = hfgetc(i->file); while (ch == '\0');
2857 i->peek_buf[1] = ch;
2858 }
2859
2860 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2861 return ch;
2862}
2863
2864static int i_getch_and_eat_bkslash_nl(struct in_str *input)
2865{
2866 for (;;) {
2867 int ch, ch2;
2868
2869 ch = i_getch(input);
2870 if (ch != '\\')
2871 return ch;
2872 ch2 = i_peek(input);
2873 if (ch2 != '\n')
2874 return ch;
2875
2876 i_getch(input);
2877 }
2878}
2879
2880
2881
2882
2883static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2884{
2885 for (;;) {
2886 int ch, ch2;
2887
2888 ch = i_peek(input);
2889 if (ch != '\\')
2890 return ch;
2891 ch2 = i_peek2(input);
2892 if (ch2 != '\n')
2893 return ch;
2894
2895 i_getch(input);
2896 i_getch(input);
2897 }
2898}
2899
2900static void setup_file_in_str(struct in_str *i, HFILE *fp)
2901{
2902 memset(i, 0, sizeof(*i));
2903 i->file = fp;
2904
2905}
2906
2907static void setup_string_in_str(struct in_str *i, const char *s)
2908{
2909 memset(i, 0, sizeof(*i));
2910 ;
2911 i->p = s;
2912}
2913
2914
2915
2916
2917
2918#define B_CHUNK (32 * sizeof(char*))
2919
2920static void o_reset_to_empty_unquoted(o_string *o)
2921{
2922 o->length = 0;
2923 o->has_quoted_part = 0;
2924 if (o->data)
2925 o->data[0] = '\0';
2926}
2927
2928static void o_free_and_set_NULL(o_string *o)
2929{
2930 free(o->data);
2931 memset(o, 0, sizeof(*o));
2932}
2933
2934static ALWAYS_INLINE void o_free(o_string *o)
2935{
2936 free(o->data);
2937}
2938
2939static void o_grow_by(o_string *o, int len)
2940{
2941 if (o->length + len > o->maxlen) {
2942 o->maxlen += (2 * len) | (B_CHUNK-1);
2943 o->data = xrealloc(o->data, 1 + o->maxlen);
2944 }
2945}
2946
2947static void o_addchr(o_string *o, int ch)
2948{
2949 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o);
2950 if (o->length < o->maxlen) {
2951
2952 add:
2953 o->data[o->length] = ch;
2954 o->length++;
2955 o->data[o->length] = '\0';
2956 return;
2957 }
2958 o_grow_by(o, 1);
2959 goto add;
2960}
2961
2962#if 0
2963
2964static void o_delchr(o_string *o)
2965{
2966 o->length--;
2967 o->data[o->length] = '\0';
2968}
2969#endif
2970
2971static void o_addblock(o_string *o, const char *str, int len)
2972{
2973 o_grow_by(o, len);
2974 ((char*)mempcpy(&o->data[o->length], str, len))[0] = '\0';
2975 o->length += len;
2976}
2977
2978static void o_addstr(o_string *o, const char *str)
2979{
2980 o_addblock(o, str, strlen(str));
2981}
2982
2983static void o_addstr_with_NUL(o_string *o, const char *str)
2984{
2985 o_addblock(o, str, strlen(str) + 1);
2986}
2987
2988#if !BB_MMU
2989static void nommu_addchr(o_string *o, int ch)
2990{
2991 if (o)
2992 o_addchr(o, ch);
2993}
2994#else
2995# define nommu_addchr(o, str) ((void)0)
2996#endif
2997
2998#if ENABLE_HUSH_MODE_X
2999static void x_mode_addchr(int ch)
3000{
3001 o_addchr(&G.x_mode_buf, ch);
3002}
3003static void x_mode_addstr(const char *str)
3004{
3005 o_addstr(&G.x_mode_buf, str);
3006}
3007static void x_mode_addblock(const char *str, int len)
3008{
3009 o_addblock(&G.x_mode_buf, str, len);
3010}
3011static void x_mode_prefix(void)
3012{
3013 int n = G.x_mode_depth;
3014 do x_mode_addchr('+'); while (--n >= 0);
3015}
3016static void x_mode_flush(void)
3017{
3018 int len = G.x_mode_buf.length;
3019 if (len <= 0)
3020 return;
3021 if (G.x_mode_fd > 0) {
3022 G.x_mode_buf.data[len] = '\n';
3023 full_write(G.x_mode_fd, G.x_mode_buf.data, len + 1);
3024 }
3025 G.x_mode_buf.length = 0;
3026}
3027#endif
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040#if ENABLE_HUSH_BRACE_EXPANSION
3041# define MAYBE_BRACES "{}"
3042#else
3043# define MAYBE_BRACES ""
3044#endif
3045
3046
3047
3048
3049static void o_addqchr(o_string *o, int ch)
3050{
3051 int sz = 1;
3052
3053
3054
3055 char *found = strchr("*?[-\\" MAYBE_BRACES, ch);
3056 if (found)
3057 sz++;
3058 o_grow_by(o, sz);
3059 if (found) {
3060 o->data[o->length] = '\\';
3061 o->length++;
3062 }
3063 o->data[o->length] = ch;
3064 o->length++;
3065 o->data[o->length] = '\0';
3066}
3067
3068static void o_addQchr(o_string *o, int ch)
3069{
3070 int sz = 1;
3071 if ((o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)
3072 && strchr("*?[-\\" MAYBE_BRACES, ch)
3073 ) {
3074 sz++;
3075 o->data[o->length] = '\\';
3076 o->length++;
3077 }
3078 o_grow_by(o, sz);
3079 o->data[o->length] = ch;
3080 o->length++;
3081 o->data[o->length] = '\0';
3082}
3083
3084static void o_addqblock(o_string *o, const char *str, int len)
3085{
3086 while (len) {
3087 char ch;
3088 int sz;
3089 int ordinary_cnt = strcspn(str, "*?[-\\" MAYBE_BRACES);
3090 if (ordinary_cnt > len)
3091 ordinary_cnt = len;
3092 o_addblock(o, str, ordinary_cnt);
3093 if (ordinary_cnt == len)
3094 return;
3095 str += ordinary_cnt;
3096 len -= ordinary_cnt + 1;
3097
3098 ch = *str++;
3099 sz = 1;
3100 if (ch) {
3101 sz++;
3102 o->data[o->length] = '\\';
3103 o->length++;
3104 }
3105 o_grow_by(o, sz);
3106 o->data[o->length] = ch;
3107 o->length++;
3108 }
3109 o->data[o->length] = '\0';
3110}
3111
3112static void o_addQblock(o_string *o, const char *str, int len)
3113{
3114 if (!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)) {
3115 o_addblock(o, str, len);
3116 return;
3117 }
3118 o_addqblock(o, str, len);
3119}
3120
3121static void o_addQstr(o_string *o, const char *str)
3122{
3123 o_addQblock(o, str, strlen(str));
3124}
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136#if DEBUG_EXPAND || DEBUG_GLOB
3137static void debug_print_list(const char *prefix, o_string *o, int n)
3138{
3139 char **list = (char**)o->data;
3140 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3141 int i = 0;
3142
3143 indent();
3144 fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n",
3145 prefix, list, n, string_start, o->length, o->maxlen,
3146 !!(o->o_expflags & EXP_FLAG_GLOB),
3147 o->has_quoted_part,
3148 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
3149 while (i < n) {
3150 indent();
3151 fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i],
3152 o->data + (int)(uintptr_t)list[i] + string_start,
3153 o->data + (int)(uintptr_t)list[i] + string_start);
3154 i++;
3155 }
3156 if (n) {
3157 const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start;
3158 indent();
3159 fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
3160 }
3161}
3162#else
3163# define debug_print_list(prefix, o, n) ((void)0)
3164#endif
3165
3166
3167
3168
3169static int o_save_ptr_helper(o_string *o, int n)
3170{
3171 char **list = (char**)o->data;
3172 int string_start;
3173 int string_len;
3174
3175 if (!o->has_empty_slot) {
3176 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3177 string_len = o->length - string_start;
3178 if (!(n & 0xf)) {
3179 debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start);
3180
3181 o->maxlen += 0x10 * sizeof(list[0]);
3182 o->data = xrealloc(o->data, o->maxlen + 1);
3183 list = (char**)o->data;
3184 memmove(list + n + 0x10, list + n, string_len);
3185
3186
3187
3188
3189
3190
3191 list[n + 0x10 - 1] = 0;
3192 o->length += 0x10 * sizeof(list[0]);
3193 } else {
3194 debug_printf_list("list[%d]=%d string_start=%d\n",
3195 n, string_len, string_start);
3196 }
3197 } else {
3198
3199 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]);
3200 string_len = o->length - string_start;
3201 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n",
3202 n, string_len, string_start);
3203 o->has_empty_slot = 0;
3204 }
3205 o->has_quoted_part = 0;
3206 list[n] = (char*)(uintptr_t)string_len;
3207 return n + 1;
3208}
3209
3210
3211static int o_get_last_ptr(o_string *o, int n)
3212{
3213 char **list = (char**)o->data;
3214 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3215
3216 return ((int)(uintptr_t)list[n-1]) + string_start;
3217}
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254#if ENABLE_HUSH_BRACE_EXPANSION
3255
3256
3257
3258
3259
3260
3261
3262static int glob_needed(const char *s)
3263{
3264 while (*s) {
3265 if (*s == '\\') {
3266 if (!s[1])
3267 return 0;
3268 s += 2;
3269 continue;
3270 }
3271 if (*s == '*' || *s == '[' || *s == '?' || *s == '{')
3272 return 1;
3273 s++;
3274 }
3275 return 0;
3276}
3277
3278static const char *next_brace_sub(const char *cp)
3279{
3280 unsigned depth = 0;
3281 cp++;
3282 while (*cp != '\0') {
3283 if (*cp == '\\') {
3284 if (*++cp == '\0')
3285 break;
3286 cp++;
3287 continue;
3288 }
3289 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
3290 break;
3291 if (*cp++ == '{')
3292 depth++;
3293 }
3294
3295 return *cp != '\0' ? cp : NULL;
3296}
3297
3298static int glob_brace(char *pattern, o_string *o, int n)
3299{
3300 char *new_pattern_buf;
3301 const char *begin;
3302 const char *next;
3303 const char *rest;
3304 const char *p;
3305 size_t rest_len;
3306
3307 debug_printf_glob("glob_brace('%s')\n", pattern);
3308
3309 begin = pattern;
3310 while (1) {
3311 if (*begin == '\0')
3312 goto simple_glob;
3313 if (*begin == '{') {
3314
3315
3316 next = next_brace_sub(begin);
3317 if (next == NULL) {
3318
3319 goto simple_glob;
3320 }
3321 if (*next == '}') {
3322
3323
3324 begin = next + 1;
3325 continue;
3326 }
3327 break;
3328 }
3329 if (*begin == '\\' && begin[1] != '\0')
3330 begin++;
3331 begin++;
3332 }
3333 debug_printf_glob("begin:%s\n", begin);
3334 debug_printf_glob("next:%s\n", next);
3335
3336
3337 rest = next;
3338 while (*rest != '}') {
3339 rest = next_brace_sub(rest);
3340 if (rest == NULL) {
3341
3342 goto simple_glob;
3343 }
3344 debug_printf_glob("rest:%s\n", rest);
3345 }
3346 rest_len = strlen(++rest) + 1;
3347
3348
3349
3350
3351 new_pattern_buf = xmalloc(strlen(pattern));
3352
3353
3354
3355
3356
3357
3358
3359 p = begin + 1;
3360 while (1) {
3361
3362 memcpy(
3363 mempcpy(
3364 mempcpy(new_pattern_buf,
3365
3366 pattern, begin - pattern),
3367 p, next - p),
3368 rest, rest_len);
3369
3370
3371
3372
3373 n = glob_brace(new_pattern_buf, o, n);
3374 if (*next == '}') {
3375
3376 break;
3377 }
3378 p = next + 1;
3379 next = next_brace_sub(next);
3380 }
3381 free(new_pattern_buf);
3382 return n;
3383
3384 simple_glob:
3385 {
3386 int gr;
3387 glob_t globdata;
3388
3389 memset(&globdata, 0, sizeof(globdata));
3390 gr = glob(pattern, 0, NULL, &globdata);
3391 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
3392 if (gr != 0) {
3393 if (gr == GLOB_NOMATCH) {
3394 globfree(&globdata);
3395
3396 unbackslash(pattern);
3397 o_addstr_with_NUL(o, pattern);
3398 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3399 return o_save_ptr_helper(o, n);
3400 }
3401 if (gr == GLOB_NOSPACE)
3402 bb_die_memory_exhausted();
3403
3404
3405 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
3406 }
3407 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3408 char **argv = globdata.gl_pathv;
3409 while (1) {
3410 o_addstr_with_NUL(o, *argv);
3411 n = o_save_ptr_helper(o, n);
3412 argv++;
3413 if (!*argv)
3414 break;
3415 }
3416 }
3417 globfree(&globdata);
3418 }
3419 return n;
3420}
3421
3422
3423
3424static int perform_glob(o_string *o, int n)
3425{
3426 char *pattern, *copy;
3427
3428 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
3429 if (!o->data)
3430 return o_save_ptr_helper(o, n);
3431 pattern = o->data + o_get_last_ptr(o, n);
3432 debug_printf_glob("glob pattern '%s'\n", pattern);
3433 if (!glob_needed(pattern)) {
3434
3435 o->length = unbackslash(pattern) - o->data;
3436 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3437 return o_save_ptr_helper(o, n);
3438 }
3439
3440 copy = xstrdup(pattern);
3441
3442 o->length = pattern - o->data;
3443 n = glob_brace(copy, o, n);
3444 free(copy);
3445 if (DEBUG_GLOB)
3446 debug_print_list("perform_glob returning", o, n);
3447 return n;
3448}
3449
3450#else
3451
3452
3453static int glob_needed(const char *s)
3454{
3455 while (*s) {
3456 if (*s == '\\') {
3457 if (!s[1])
3458 return 0;
3459 s += 2;
3460 continue;
3461 }
3462 if (*s == '*' || *s == '[' || *s == '?')
3463 return 1;
3464 s++;
3465 }
3466 return 0;
3467}
3468
3469
3470
3471static int perform_glob(o_string *o, int n)
3472{
3473 glob_t globdata;
3474 int gr;
3475 char *pattern;
3476
3477 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
3478 if (!o->data)
3479 return o_save_ptr_helper(o, n);
3480 pattern = o->data + o_get_last_ptr(o, n);
3481 debug_printf_glob("glob pattern '%s'\n", pattern);
3482 if (!glob_needed(pattern)) {
3483 literal:
3484
3485 o->length = unbackslash(pattern) - o->data;
3486 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
3487 return o_save_ptr_helper(o, n);
3488 }
3489
3490 memset(&globdata, 0, sizeof(globdata));
3491
3492
3493
3494
3495
3496 gr = glob(pattern, 0, NULL, &globdata);
3497 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
3498 if (gr != 0) {
3499 if (gr == GLOB_NOMATCH) {
3500 globfree(&globdata);
3501 goto literal;
3502 }
3503 if (gr == GLOB_NOSPACE)
3504 bb_die_memory_exhausted();
3505
3506
3507 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
3508 }
3509 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
3510 char **argv = globdata.gl_pathv;
3511
3512 o->length = pattern - o->data;
3513 while (1) {
3514 o_addstr_with_NUL(o, *argv);
3515 n = o_save_ptr_helper(o, n);
3516 argv++;
3517 if (!*argv)
3518 break;
3519 }
3520 }
3521 globfree(&globdata);
3522 if (DEBUG_GLOB)
3523 debug_print_list("perform_glob returning", o, n);
3524 return n;
3525}
3526
3527#endif
3528
3529
3530
3531static int o_save_ptr(o_string *o, int n)
3532{
3533 if (o->o_expflags & EXP_FLAG_GLOB) {
3534
3535
3536
3537 if (!o->has_empty_slot)
3538 return perform_glob(o, n);
3539 }
3540 return o_save_ptr_helper(o, n);
3541}
3542
3543
3544static char **o_finalize_list(o_string *o, int n)
3545{
3546 char **list;
3547 int string_start;
3548
3549 if (DEBUG_EXPAND)
3550 debug_print_list("finalized", o, n);
3551 debug_printf_expand("finalized n:%d\n", n);
3552 list = (char**)o->data;
3553 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
3554 list[--n] = NULL;
3555 while (n) {
3556 n--;
3557 list[n] = o->data + (int)(uintptr_t)list[n] + string_start;
3558 }
3559 return list;
3560}
3561
3562static void free_pipe_list(struct pipe *pi);
3563
3564
3565static struct pipe *free_pipe(struct pipe *pi)
3566{
3567 struct pipe *next;
3568 int i;
3569
3570 debug_printf_clean("free_pipe (pid %d)\n", getpid());
3571 for (i = 0; i < pi->num_cmds; i++) {
3572 struct command *command;
3573 struct redir_struct *r, *rnext;
3574
3575 command = &pi->cmds[i];
3576 debug_printf_clean(" command %d:\n", i);
3577 if (command->argv) {
3578 if (DEBUG_CLEAN) {
3579 int a;
3580 char **p;
3581 for (a = 0, p = command->argv; *p; a++, p++) {
3582 debug_printf_clean(" argv[%d] = %s\n", a, *p);
3583 }
3584 }
3585 free_strings(command->argv);
3586
3587 }
3588
3589 if (command->group) {
3590 debug_printf_clean(" begin group (cmd_type:%d)\n",
3591 command->cmd_type);
3592 free_pipe_list(command->group);
3593 debug_printf_clean(" end group\n");
3594
3595 }
3596
3597
3598#if ENABLE_HUSH_FUNCTIONS
3599 else if (command->child_func) {
3600 debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func);
3601 command->child_func->parent_cmd = NULL;
3602 }
3603#endif
3604#if !BB_MMU
3605 free(command->group_as_string);
3606
3607#endif
3608 for (r = command->redirects; r; r = rnext) {
3609 debug_printf_clean(" redirect %d%s",
3610 r->rd_fd, redir_table[r->rd_type].descrip);
3611
3612 if (r->rd_filename) {
3613 debug_printf_clean(" fname:'%s'\n", r->rd_filename);
3614 free(r->rd_filename);
3615
3616 }
3617 debug_printf_clean(" rd_dup:%d\n", r->rd_dup);
3618 rnext = r->next;
3619 free(r);
3620 }
3621
3622 }
3623 free(pi->cmds);
3624
3625#if ENABLE_HUSH_JOB
3626 free(pi->cmdtext);
3627
3628#endif
3629
3630 next = pi->next;
3631 free(pi);
3632 return next;
3633}
3634
3635static void free_pipe_list(struct pipe *pi)
3636{
3637 while (pi) {
3638#if HAS_KEYWORDS
3639 debug_printf_clean("pipe reserved word %d\n", pi->res_word);
3640#endif
3641 debug_printf_clean("pipe followup code %d\n", pi->followup);
3642 pi = free_pipe(pi);
3643 }
3644}
3645
3646
3647
3648
3649#ifndef debug_print_tree
3650static void debug_print_tree(struct pipe *pi, int lvl)
3651{
3652 static const char *const PIPE[] = {
3653 [PIPE_SEQ] = "SEQ",
3654 [PIPE_AND] = "AND",
3655 [PIPE_OR ] = "OR" ,
3656 [PIPE_BG ] = "BG" ,
3657 };
3658 static const char *RES[] = {
3659 [RES_NONE ] = "NONE" ,
3660# if ENABLE_HUSH_IF
3661 [RES_IF ] = "IF" ,
3662 [RES_THEN ] = "THEN" ,
3663 [RES_ELIF ] = "ELIF" ,
3664 [RES_ELSE ] = "ELSE" ,
3665 [RES_FI ] = "FI" ,
3666# endif
3667# if ENABLE_HUSH_LOOPS
3668 [RES_FOR ] = "FOR" ,
3669 [RES_WHILE] = "WHILE",
3670 [RES_UNTIL] = "UNTIL",
3671 [RES_DO ] = "DO" ,
3672 [RES_DONE ] = "DONE" ,
3673# endif
3674# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
3675 [RES_IN ] = "IN" ,
3676# endif
3677# if ENABLE_HUSH_CASE
3678 [RES_CASE ] = "CASE" ,
3679 [RES_CASE_IN ] = "CASE_IN" ,
3680 [RES_MATCH] = "MATCH",
3681 [RES_CASE_BODY] = "CASE_BODY",
3682 [RES_ESAC ] = "ESAC" ,
3683# endif
3684 [RES_XXXX ] = "XXXX" ,
3685 [RES_SNTX ] = "SNTX" ,
3686 };
3687 static const char *const CMDTYPE[] = {
3688 "{}",
3689 "()",
3690 "[noglob]",
3691# if ENABLE_HUSH_FUNCTIONS
3692 "func()",
3693# endif
3694 };
3695
3696 int pin, prn;
3697
3698 pin = 0;
3699 while (pi) {
3700 fdprintf(2, "%*spipe %d #cmds:%d %sres_word=%s followup=%d %s\n",
3701 lvl*2, "",
3702 pin,
3703 pi->num_cmds,
3704 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3705 RES[pi->res_word],
3706 pi->followup, PIPE[pi->followup]
3707 );
3708 prn = 0;
3709 while (prn < pi->num_cmds) {
3710 struct command *command = &pi->cmds[prn];
3711 char **argv = command->argv;
3712
3713 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3714 lvl*2, "", prn,
3715 command->assignment_cnt);
3716# if ENABLE_HUSH_LINENO_VAR
3717 fdprintf(2, " LINENO:%u", command->lineno);
3718# endif
3719 if (command->group) {
3720 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3721 CMDTYPE[command->cmd_type],
3722 argv
3723# if !BB_MMU
3724 , " group_as_string:", command->group_as_string
3725# else
3726 , "", ""
3727# endif
3728 );
3729 debug_print_tree(command->group, lvl+1);
3730 prn++;
3731 continue;
3732 }
3733 if (argv) while (*argv) {
3734 fdprintf(2, " '%s'", *argv);
3735 argv++;
3736 }
3737 if (command->redirects)
3738 fdprintf(2, " {redir}");
3739 fdprintf(2, "\n");
3740 prn++;
3741 }
3742 pi = pi->next;
3743 pin++;
3744 }
3745}
3746#endif
3747
3748static struct pipe *new_pipe(void)
3749{
3750 struct pipe *pi;
3751 pi = xzalloc(sizeof(struct pipe));
3752
3753 return pi;
3754}
3755
3756
3757
3758
3759
3760static int done_command(struct parse_context *ctx)
3761{
3762
3763
3764 struct pipe *pi = ctx->pipe;
3765 struct command *command = ctx->command;
3766
3767#if 0
3768 if (ctx->pending_redirect) {
3769
3770 syntax_error("invalid redirect");
3771 ctx->pending_redirect = NULL;
3772 }
3773#endif
3774
3775 if (command) {
3776 if (IS_NULL_CMD(command)) {
3777 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
3778 goto clear_and_ret;
3779 }
3780 pi->num_cmds++;
3781 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
3782
3783 } else {
3784 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds);
3785 }
3786
3787
3788
3789 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1));
3790 ctx->command = command = &pi->cmds[pi->num_cmds];
3791 clear_and_ret:
3792 memset(command, 0, sizeof(*command));
3793#if ENABLE_HUSH_LINENO_VAR
3794 command->lineno = G.parse_lineno;
3795 debug_printf_parse("command->lineno = G.parse_lineno (%u)\n", G.parse_lineno);
3796#endif
3797 return pi->num_cmds;
3798}
3799
3800static void done_pipe(struct parse_context *ctx, pipe_style type)
3801{
3802 int not_null;
3803
3804 debug_printf_parse("done_pipe entered, followup %d\n", type);
3805
3806 not_null = done_command(ctx);
3807#if HAS_KEYWORDS
3808 ctx->pipe->pi_inverted = ctx->ctx_inverted;
3809 ctx->ctx_inverted = 0;
3810 ctx->pipe->res_word = ctx->ctx_res_w;
3811#endif
3812 if (type == PIPE_BG && ctx->list_head != ctx->pipe) {
3813
3814
3815
3816
3817 struct pipe *pi;
3818 struct command *command;
3819
3820
3821 pi = ctx->list_head;
3822 while (pi != ctx->pipe) {
3823 if (pi->followup != PIPE_AND && pi->followup != PIPE_OR)
3824 goto no_conv;
3825 pi = pi->next;
3826 }
3827
3828 debug_printf_parse("BG with more than one pipe, converting to { p1 &&...pN; } &\n");
3829 pi->followup = PIPE_SEQ;
3830 pi = xzalloc(sizeof(*pi));
3831 pi->followup = PIPE_BG;
3832 pi->num_cmds = 1;
3833 pi->cmds = xzalloc(sizeof(pi->cmds[0]));
3834 command = &pi->cmds[0];
3835 if (CMD_NORMAL != 0)
3836 command->cmd_type = CMD_NORMAL;
3837 command->group = ctx->list_head;
3838#if !BB_MMU
3839 command->group_as_string = xstrndup(
3840 ctx->as_string.data,
3841 ctx->as_string.length - 1
3842 );
3843#endif
3844
3845 ctx->list_head = ctx->pipe = pi;
3846
3847
3848 not_null = 1;
3849 } else {
3850 no_conv:
3851 ctx->pipe->followup = type;
3852 }
3853
3854
3855
3856
3857 if (not_null
3858#if ENABLE_HUSH_IF
3859 || ctx->ctx_res_w == RES_FI
3860#endif
3861#if ENABLE_HUSH_LOOPS
3862 || ctx->ctx_res_w == RES_DONE
3863 || ctx->ctx_res_w == RES_FOR
3864 || ctx->ctx_res_w == RES_IN
3865#endif
3866#if ENABLE_HUSH_CASE
3867 || ctx->ctx_res_w == RES_ESAC
3868#endif
3869 ) {
3870 struct pipe *new_p;
3871 debug_printf_parse("done_pipe: adding new pipe: "
3872 "not_null:%d ctx->ctx_res_w:%d\n",
3873 not_null, ctx->ctx_res_w);
3874 new_p = new_pipe();
3875 ctx->pipe->next = new_p;
3876 ctx->pipe = new_p;
3877
3878
3879
3880
3881
3882
3883#if ENABLE_HUSH_LOOPS
3884 if (ctx->ctx_res_w == RES_FOR
3885 || ctx->ctx_res_w == RES_IN)
3886 ctx->ctx_res_w = RES_NONE;
3887#endif
3888#if ENABLE_HUSH_CASE
3889 if (ctx->ctx_res_w == RES_MATCH)
3890 ctx->ctx_res_w = RES_CASE_BODY;
3891 if (ctx->ctx_res_w == RES_CASE)
3892 ctx->ctx_res_w = RES_CASE_IN;
3893#endif
3894 ctx->command = NULL;
3895
3896
3897
3898
3899 done_command(ctx);
3900
3901 }
3902 debug_printf_parse("done_pipe return\n");
3903}
3904
3905static void initialize_context(struct parse_context *ctx)
3906{
3907 memset(ctx, 0, sizeof(*ctx));
3908 if (MAYBE_ASSIGNMENT != 0)
3909 ctx->is_assignment = MAYBE_ASSIGNMENT;
3910 ctx->pipe = ctx->list_head = new_pipe();
3911
3912
3913
3914
3915 done_command(ctx);
3916}
3917
3918
3919
3920
3921#if HAS_KEYWORDS
3922struct reserved_combo {
3923 char literal[6];
3924 unsigned char res;
3925 unsigned char assignment_flag;
3926 uint32_t flag;
3927};
3928enum {
3929 FLAG_END = (1 << RES_NONE ),
3930# if ENABLE_HUSH_IF
3931 FLAG_IF = (1 << RES_IF ),
3932 FLAG_THEN = (1 << RES_THEN ),
3933 FLAG_ELIF = (1 << RES_ELIF ),
3934 FLAG_ELSE = (1 << RES_ELSE ),
3935 FLAG_FI = (1 << RES_FI ),
3936# endif
3937# if ENABLE_HUSH_LOOPS
3938 FLAG_FOR = (1 << RES_FOR ),
3939 FLAG_WHILE = (1 << RES_WHILE),
3940 FLAG_UNTIL = (1 << RES_UNTIL),
3941 FLAG_DO = (1 << RES_DO ),
3942 FLAG_DONE = (1 << RES_DONE ),
3943 FLAG_IN = (1 << RES_IN ),
3944# endif
3945# if ENABLE_HUSH_CASE
3946 FLAG_MATCH = (1 << RES_MATCH),
3947 FLAG_ESAC = (1 << RES_ESAC ),
3948# endif
3949 FLAG_START = (1 << RES_XXXX ),
3950};
3951
3952static const struct reserved_combo* match_reserved_word(o_string *word)
3953{
3954
3955
3956
3957
3958
3959 static const struct reserved_combo reserved_list[] ALIGN4 = {
3960# if ENABLE_HUSH_IF
3961 { "!", RES_NONE, NOT_ASSIGNMENT , 0 },
3962 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START },
3963 { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
3964 { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN },
3965 { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI },
3966 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END },
3967# endif
3968# if ENABLE_HUSH_LOOPS
3969 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START },
3970 { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3971 { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
3972 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO },
3973 { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE },
3974 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END },
3975# endif
3976# if ENABLE_HUSH_CASE
3977 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START },
3978 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
3979# endif
3980 };
3981 const struct reserved_combo *r;
3982
3983 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
3984 if (strcmp(word->data, r->literal) == 0)
3985 return r;
3986 }
3987 return NULL;
3988}
3989
3990
3991static const struct reserved_combo* reserved_word(struct parse_context *ctx)
3992{
3993# if ENABLE_HUSH_CASE
3994 static const struct reserved_combo reserved_match = {
3995 "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
3996 };
3997# endif
3998 const struct reserved_combo *r;
3999
4000 if (ctx->word.has_quoted_part)
4001 return 0;
4002 r = match_reserved_word(&ctx->word);
4003 if (!r)
4004 return r;
4005
4006 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
4007# if ENABLE_HUSH_CASE
4008 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) {
4009
4010 r = &reserved_match;
4011 } else
4012# endif
4013 if (r->flag == 0) {
4014 if (ctx->ctx_inverted) {
4015 syntax_error("! ! command");
4016 ctx->ctx_res_w = RES_SNTX;
4017 }
4018 ctx->ctx_inverted = 1;
4019 return r;
4020 }
4021 if (r->flag & FLAG_START) {
4022 struct parse_context *old;
4023
4024 old = xmemdup(ctx, sizeof(*ctx));
4025 debug_printf_parse("push stack %p\n", old);
4026 initialize_context(ctx);
4027 ctx->stack = old;
4028 } else if ( !(ctx->old_flag & (1 << r->res))) {
4029 syntax_error_at(ctx->word.data);
4030 ctx->ctx_res_w = RES_SNTX;
4031 return r;
4032 } else {
4033
4034
4035
4036 if (ctx->command->group)
4037 done_pipe(ctx, PIPE_SEQ);
4038 }
4039
4040 ctx->ctx_res_w = r->res;
4041 ctx->old_flag = r->flag;
4042 ctx->is_assignment = r->assignment_flag;
4043 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
4044
4045 if (ctx->old_flag & FLAG_END) {
4046 struct parse_context *old;
4047
4048 done_pipe(ctx, PIPE_SEQ);
4049 debug_printf_parse("pop stack %p\n", ctx->stack);
4050 old = ctx->stack;
4051 old->command->group = ctx->list_head;
4052 old->command->cmd_type = CMD_NORMAL;
4053# if !BB_MMU
4054
4055
4056
4057
4058
4059
4060 {
4061 char *str;
4062 int len = old->as_string.length;
4063
4064 o_addstr(&old->as_string, ctx->as_string.data);
4065 o_free(&ctx->as_string);
4066
4067 str = old->as_string.data + len;
4068 if (str > old->as_string.data)
4069 str--;
4070 while (str > old->as_string.data && isalpha(str[-1]))
4071 str--;
4072
4073 old->command->group_as_string = xstrdup(str);
4074 debug_printf_parse("pop, remembering as:'%s'\n",
4075 old->command->group_as_string);
4076 }
4077# endif
4078 *ctx = *old;
4079 free(old);
4080 }
4081 return r;
4082}
4083#endif
4084
4085
4086
4087
4088
4089static int done_word(struct parse_context *ctx)
4090{
4091 struct command *command = ctx->command;
4092
4093 debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command);
4094 if (ctx->word.length == 0 && !ctx->word.has_quoted_part) {
4095 debug_printf_parse("done_word return 0: true null, ignored\n");
4096 return 0;
4097 }
4098
4099 if (ctx->pending_redirect) {
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124 ctx->pending_redirect->rd_filename = xstrdup(ctx->word.data);
4125
4126
4127
4128
4129
4130 if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) {
4131 unbackslash(ctx->pending_redirect->rd_filename);
4132
4133 if (ctx->word.has_quoted_part) {
4134 ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED;
4135 }
4136 }
4137 debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data);
4138 ctx->pending_redirect = NULL;
4139 } else {
4140#if HAS_KEYWORDS
4141# if ENABLE_HUSH_CASE
4142 if (ctx->ctx_dsemicolon
4143 && strcmp(ctx->word.data, "esac") != 0
4144 ) {
4145
4146
4147 ctx->ctx_dsemicolon = 0;
4148 } else
4149# endif
4150# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4151 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
4152 && strcmp(ctx->word.data, "]]") == 0
4153 ) {
4154
4155 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4156 } else
4157# endif
4158 if (!command->argv
4159# if ENABLE_HUSH_LOOPS
4160 && ctx->ctx_res_w != RES_FOR
4161 && ctx->ctx_res_w != RES_IN
4162# endif
4163# if ENABLE_HUSH_CASE
4164 && ctx->ctx_res_w != RES_CASE
4165# endif
4166 ) {
4167 const struct reserved_combo *reserved;
4168 reserved = reserved_word(ctx);
4169 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
4170 if (reserved) {
4171# if ENABLE_HUSH_LINENO_VAR
4172
4173
4174
4175
4176
4177
4178 if (0
4179 IF_HUSH_IF(|| reserved->res == RES_THEN)
4180 IF_HUSH_IF(|| reserved->res == RES_ELIF)
4181 IF_HUSH_IF(|| reserved->res == RES_ELSE)
4182 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
4183 ) {
4184 done_pipe(ctx, PIPE_SEQ);
4185 }
4186# endif
4187 o_reset_to_empty_unquoted(&ctx->word);
4188 debug_printf_parse("done_word return %d\n",
4189 (ctx->ctx_res_w == RES_SNTX));
4190 return (ctx->ctx_res_w == RES_SNTX);
4191 }
4192# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4193 if (strcmp(ctx->word.data, "[[") == 0) {
4194 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
4195 } else
4196# endif
4197# if defined(CMD_SINGLEWORD_NOGLOB)
4198 if (0
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214 IF_HUSH_LOCAL( || strcmp(ctx->word.data, "local") == 0)
4215 IF_HUSH_EXPORT( || strcmp(ctx->word.data, "export") == 0)
4216 IF_HUSH_READONLY(|| strcmp(ctx->word.data, "readonly") == 0)
4217 ) {
4218 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4219 }
4220# else
4221 { }
4222# endif
4223 }
4224#endif
4225
4226 if (command->group) {
4227
4228 syntax_error_at(ctx->word.data);
4229 debug_printf_parse("done_word return 1: syntax error, "
4230 "groups and arglists don't mix\n");
4231 return 1;
4232 }
4233
4234
4235
4236 if (ctx->is_assignment != DEFINITELY_ASSIGNMENT
4237 && ctx->is_assignment != WORD_IS_KEYWORD
4238 ) {
4239 ctx->is_assignment = NOT_ASSIGNMENT;
4240 } else {
4241 if (ctx->is_assignment == DEFINITELY_ASSIGNMENT) {
4242 command->assignment_cnt++;
4243 debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt);
4244 }
4245 debug_printf_parse("ctx->is_assignment was:'%s'\n", assignment_flag[ctx->is_assignment]);
4246 ctx->is_assignment = MAYBE_ASSIGNMENT;
4247 }
4248 debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
4249 command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data));
4250 debug_print_strings("word appended to argv", command->argv);
4251 }
4252
4253#if ENABLE_HUSH_LOOPS
4254 if (ctx->ctx_res_w == RES_FOR) {
4255 if (ctx->word.has_quoted_part
4256 || endofname(command->argv[0])[0] != '\0'
4257 ) {
4258
4259 syntax_error("bad variable name in for");
4260 return 1;
4261 }
4262
4263
4264
4265
4266 done_pipe(ctx, PIPE_SEQ);
4267 }
4268#endif
4269#if ENABLE_HUSH_CASE
4270
4271 if (ctx->ctx_res_w == RES_CASE) {
4272 done_pipe(ctx, PIPE_SEQ);
4273 }
4274#endif
4275
4276 o_reset_to_empty_unquoted(&ctx->word);
4277
4278 debug_printf_parse("done_word return 0\n");
4279 return 0;
4280}
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291#if BB_MMU
4292#define parse_redir_right_fd(as_string, input) \
4293 parse_redir_right_fd(input)
4294#endif
4295static int parse_redir_right_fd(o_string *as_string, struct in_str *input)
4296{
4297 int ch, d, ok;
4298
4299 ch = i_peek(input);
4300 if (ch != '&')
4301 return REDIRFD_TO_FILE;
4302
4303 ch = i_getch(input);
4304 nommu_addchr(as_string, ch);
4305 ch = i_peek(input);
4306 if (ch == '-') {
4307 ch = i_getch(input);
4308 nommu_addchr(as_string, ch);
4309 return REDIRFD_CLOSE;
4310 }
4311 d = 0;
4312 ok = 0;
4313 while (ch != EOF && isdigit(ch)) {
4314 d = d*10 + (ch-'0');
4315 ok = 1;
4316 ch = i_getch(input);
4317 nommu_addchr(as_string, ch);
4318 ch = i_peek(input);
4319 }
4320 if (ok) return d;
4321
4322
4323
4324 bb_simple_error_msg("ambiguous redirect");
4325 return REDIRFD_SYNTAX_ERR;
4326}
4327
4328
4329
4330static int parse_redirect(struct parse_context *ctx,
4331 int fd,
4332 redir_type style,
4333 struct in_str *input)
4334{
4335 struct command *command = ctx->command;
4336 struct redir_struct *redir;
4337 struct redir_struct **redirp;
4338 int dup_num;
4339
4340 dup_num = REDIRFD_TO_FILE;
4341 if (style != REDIRECT_HEREDOC) {
4342
4343 dup_num = parse_redir_right_fd(&ctx->as_string, input);
4344 if (dup_num == REDIRFD_SYNTAX_ERR)
4345 return 1;
4346 } else {
4347 int ch = i_peek_and_eat_bkslash_nl(input);
4348 dup_num = (ch == '-');
4349 if (dup_num) {
4350 ch = i_getch(input);
4351 nommu_addchr(&ctx->as_string, ch);
4352 ch = i_peek(input);
4353 }
4354 }
4355
4356 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) {
4357 int ch = i_peek_and_eat_bkslash_nl(input);
4358 if (ch == '|') {
4359
4360
4361
4362
4363 ch = i_getch(input);
4364 nommu_addchr(&ctx->as_string, ch);
4365 }
4366 }
4367
4368
4369 redirp = &command->redirects;
4370 while ((redir = *redirp) != NULL) {
4371 redirp = &(redir->next);
4372 }
4373 *redirp = redir = xzalloc(sizeof(*redir));
4374
4375
4376 redir->rd_type = style;
4377 redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd;
4378
4379 debug_printf_parse("redirect type %d %s\n", redir->rd_fd,
4380 redir_table[style].descrip);
4381
4382 redir->rd_dup = dup_num;
4383 if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) {
4384
4385
4386
4387 debug_printf_parse("duplicating redirect '%d>&%d'\n",
4388 redir->rd_fd, redir->rd_dup);
4389 } else {
4390#if 0
4391 if (ctx->pending_redirect) {
4392
4393 syntax_error("invalid redirect");
4394 }
4395#endif
4396
4397
4398 ctx->pending_redirect = redir;
4399 }
4400 return 0;
4401}
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423static int redirect_opt_num(o_string *o)
4424{
4425 int num;
4426
4427 if (o->data == NULL)
4428 return -1;
4429 num = bb_strtou(o->data, NULL, 10);
4430 if (errno || num < 0)
4431 return -1;
4432 o_reset_to_empty_unquoted(o);
4433 return num;
4434}
4435
4436#if BB_MMU
4437#define fetch_till_str(as_string, input, word, skip_tabs) \
4438 fetch_till_str(input, word, skip_tabs)
4439#endif
4440static char *fetch_till_str(o_string *as_string,
4441 struct in_str *input,
4442 const char *word,
4443 int heredoc_flags)
4444{
4445 o_string heredoc = NULL_O_STRING;
4446 unsigned past_EOL;
4447 int prev = 0;
4448 int ch;
4449
4450
4451
4452
4453
4454
4455
4456 heredoc.data = xzalloc(1);
4457
4458 goto jump_in;
4459
4460 while (1) {
4461 ch = i_getch(input);
4462 if (ch != EOF)
4463 nommu_addchr(as_string, ch);
4464 if (ch == '\n' || ch == EOF) {
4465 check_heredoc_end:
4466 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
4467
4468 if (strcmp(heredoc.data + past_EOL, word) == 0) {
4469 heredoc.data[past_EOL] = '\0';
4470 debug_printf_heredoc("parsed '%s' heredoc '%s'\n", word, heredoc.data);
4471 return heredoc.data;
4472 }
4473 if (ch == '\n') {
4474
4475
4476
4477 o_addchr(&heredoc, ch);
4478 prev = ch;
4479 jump_in:
4480 past_EOL = heredoc.length;
4481
4482 do {
4483 ch = i_getch(input);
4484 if (ch != EOF)
4485 nommu_addchr(as_string, ch);
4486 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
4487
4488
4489
4490 if (ch == '\n')
4491 goto check_heredoc_end;
4492 }
4493 } else {
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505 heredoc.data[--heredoc.length] = '\0';
4506 prev = 0;
4507 continue;
4508 }
4509 }
4510 if (ch == EOF) {
4511 o_free(&heredoc);
4512 return NULL;
4513 }
4514 o_addchr(&heredoc, ch);
4515 nommu_addchr(as_string, ch);
4516 if (prev == '\\' && ch == '\\')
4517
4518 prev = 0;
4519 else
4520 prev = ch;
4521 }
4522}
4523
4524
4525
4526
4527#if BB_MMU
4528#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
4529 fetch_heredocs(pi, heredoc_cnt, input)
4530#endif
4531static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
4532{
4533 while (pi && heredoc_cnt) {
4534 int i;
4535 struct command *cmd = pi->cmds;
4536
4537 debug_printf_heredoc("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n",
4538 pi->num_cmds,
4539 cmd->argv ? cmd->argv[0] : "NONE"
4540 );
4541 for (i = 0; i < pi->num_cmds; i++) {
4542 struct redir_struct *redir = cmd->redirects;
4543
4544 debug_printf_heredoc("fetch_heredocs: %d cmd argv0:'%s'\n",
4545 i, cmd->argv ? cmd->argv[0] : "NONE");
4546 while (redir) {
4547 if (redir->rd_type == REDIRECT_HEREDOC) {
4548 char *p;
4549
4550 redir->rd_type = REDIRECT_HEREDOC2;
4551
4552 p = fetch_till_str(as_string, input,
4553 redir->rd_filename, redir->rd_dup);
4554 if (!p) {
4555 syntax_error("unexpected EOF in here document");
4556 return -1;
4557 }
4558 free(redir->rd_filename);
4559 redir->rd_filename = p;
4560 heredoc_cnt--;
4561 }
4562 redir = redir->next;
4563 }
4564 if (cmd->group) {
4565
4566 heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
4567
4568 if (heredoc_cnt < 0)
4569 return heredoc_cnt;
4570 }
4571 cmd++;
4572 }
4573 pi = pi->next;
4574 }
4575 return heredoc_cnt;
4576}
4577
4578
4579static int run_list(struct pipe *pi);
4580#if BB_MMU
4581#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
4582 parse_stream(heredoc_cnt_ptr, input, end_trigger)
4583#endif
4584static struct pipe *parse_stream(char **pstring,
4585 int *heredoc_cnt_ptr,
4586 struct in_str *input,
4587 int end_trigger);
4588
4589
4590
4591
4592static int parse_group(struct parse_context *ctx,
4593 struct in_str *input, int ch)
4594{
4595
4596
4597
4598#if BB_MMU
4599# define as_string NULL
4600#else
4601 char *as_string = NULL;
4602#endif
4603 struct pipe *pipe_list;
4604 int heredoc_cnt = 0;
4605 int endch;
4606 struct command *command = ctx->command;
4607
4608 debug_printf_parse("parse_group entered\n");
4609#if ENABLE_HUSH_FUNCTIONS
4610 if (ch == '(' && !ctx->word.has_quoted_part) {
4611 if (ctx->word.length)
4612 if (done_word(ctx))
4613 return -1;
4614 if (!command->argv)
4615 goto skip;
4616 if (command->argv[1]) {
4617 syntax_error_unexpected_ch('(');
4618 return -1;
4619 }
4620
4621 do
4622 ch = i_getch(input);
4623 while (ch == ' ' || ch == '\t');
4624 if (ch != ')') {
4625 syntax_error_unexpected_ch(ch);
4626 return -1;
4627 }
4628 nommu_addchr(&ctx->as_string, ch);
4629 do
4630 ch = i_getch(input);
4631 while (ch == ' ' || ch == '\t' || ch == '\n');
4632 if (ch != '{' && ch != '(') {
4633 syntax_error_unexpected_ch(ch);
4634 return -1;
4635 }
4636 nommu_addchr(&ctx->as_string, ch);
4637 command->cmd_type = CMD_FUNCDEF;
4638 goto skip;
4639 }
4640#endif
4641
4642#if 0
4643 if (command->argv
4644 || ctx->word.length
4645 || ctx->word.has_quoted_part
4646 ) {
4647 syntax_error(NULL);
4648 debug_printf_parse("parse_group return -1: "
4649 "syntax error, groups and arglists don't mix\n");
4650 return -1;
4651 }
4652#endif
4653
4654 IF_HUSH_FUNCTIONS(skip:)
4655
4656 endch = '}';
4657 if (ch == '(') {
4658 endch = ')';
4659 IF_HUSH_FUNCTIONS(if (command->cmd_type != CMD_FUNCDEF))
4660 command->cmd_type = CMD_SUBSHELL;
4661 } else {
4662
4663 ch = i_peek(input);
4664 if (ch != ' ' && ch != '\t' && ch != '\n'
4665 && ch != '('
4666 ) {
4667 syntax_error_unexpected_ch(ch);
4668 return -1;
4669 }
4670 if (ch != '(') {
4671 ch = i_getch(input);
4672 nommu_addchr(&ctx->as_string, ch);
4673 }
4674 }
4675
4676 debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
4677 pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
4678 debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
4679#if !BB_MMU
4680 if (as_string)
4681 o_addstr(&ctx->as_string, as_string);
4682#endif
4683
4684
4685 if (!pipe_list || pipe_list == ERR_PTR) {
4686
4687 if (!BB_MMU)
4688 free(as_string);
4689 debug_printf_parse("parse_group return -1: "
4690 "parse_stream returned %p\n", pipe_list);
4691 return -1;
4692 }
4693#if !BB_MMU
4694 as_string[strlen(as_string) - 1] = '\0';
4695 command->group_as_string = as_string;
4696 debug_printf_parse("end of group, remembering as:'%s'\n",
4697 command->group_as_string);
4698#endif
4699
4700#if ENABLE_HUSH_FUNCTIONS
4701
4702 if (command->cmd_type == CMD_FUNCDEF && endch == ')') {
4703 struct command *cmd2;
4704
4705 cmd2 = xzalloc(sizeof(*cmd2));
4706 cmd2->cmd_type = CMD_SUBSHELL;
4707 cmd2->group = pipe_list;
4708# if !BB_MMU
4709
4710 cmd2->group_as_string = command->group_as_string;
4711 command->group_as_string = xasprintf("(%s)", command->group_as_string);
4712# endif
4713
4714 pipe_list = new_pipe();
4715 pipe_list->cmds = cmd2;
4716 pipe_list->num_cmds = 1;
4717 }
4718#endif
4719
4720 command->group = pipe_list;
4721
4722 debug_printf_parse("parse_group return %d\n", heredoc_cnt);
4723 return heredoc_cnt;
4724
4725#undef as_string
4726}
4727
4728#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4729
4730
4731static int add_till_single_quote(o_string *dest, struct in_str *input)
4732{
4733 while (1) {
4734 int ch = i_getch(input);
4735 if (ch == EOF) {
4736 syntax_error_unterm_ch('\'');
4737 return 0;
4738 }
4739 if (ch == '\'')
4740 return 1;
4741 o_addchr(dest, ch);
4742 }
4743}
4744static int add_till_single_quote_dquoted(o_string *dest, struct in_str *input)
4745{
4746 while (1) {
4747 int ch = i_getch(input);
4748 if (ch == EOF) {
4749 syntax_error_unterm_ch('\'');
4750 return 0;
4751 }
4752 if (ch == '\'')
4753 return 1;
4754 o_addqchr(dest, ch);
4755 }
4756}
4757
4758static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
4759static int add_till_double_quote(o_string *dest, struct in_str *input)
4760{
4761 while (1) {
4762 int ch = i_getch(input);
4763 if (ch == EOF) {
4764 syntax_error_unterm_ch('"');
4765 return 0;
4766 }
4767 if (ch == '"')
4768 return 1;
4769 if (ch == '\\') {
4770 o_addchr(dest, ch);
4771 ch = i_getch(input);
4772 }
4773 o_addchr(dest, ch);
4774 if (ch == '`') {
4775 if (!add_till_backquote(dest, input, 1))
4776 return 0;
4777 o_addchr(dest, ch);
4778 continue;
4779 }
4780
4781 }
4782}
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
4798{
4799 while (1) {
4800 int ch = i_getch(input);
4801 if (ch == '`')
4802 return 1;
4803 if (ch == '\\') {
4804
4805 ch = i_getch(input);
4806 if (ch != '`'
4807 && ch != '$'
4808 && ch != '\\'
4809 && (!in_dquote || ch != '"')
4810 ) {
4811 o_addchr(dest, '\\');
4812 }
4813 }
4814 if (ch == EOF) {
4815 syntax_error_unterm_ch('`');
4816 return 0;
4817 }
4818 o_addchr(dest, ch);
4819 }
4820}
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838#define DOUBLE_CLOSE_CHAR_FLAG 0x80
4839static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch)
4840{
4841 int ch;
4842 char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG;
4843# if BASH_SUBSTR || BASH_PATTERN_SUBST
4844 char end_char2 = end_ch >> 8;
4845# endif
4846 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1);
4847
4848# if ENABLE_HUSH_INTERACTIVE
4849 G.promptmode = 1;
4850# endif
4851 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
4852
4853 while (1) {
4854 ch = i_getch(input);
4855 if (ch == EOF) {
4856 syntax_error_unterm_ch(end_ch);
4857 return 0;
4858 }
4859 if (ch == end_ch
4860# if BASH_SUBSTR || BASH_PATTERN_SUBST
4861 || ch == end_char2
4862# endif
4863 ) {
4864 if (!dbl)
4865 break;
4866
4867 if (i_peek_and_eat_bkslash_nl(input) == end_ch) {
4868 i_getch(input);
4869 break;
4870 }
4871 }
4872 o_addchr(dest, ch);
4873
4874 if (ch == '(' || ch == '{') {
4875 ch = (ch == '(' ? ')' : '}');
4876 if (!add_till_closing_bracket(dest, input, ch))
4877 return 0;
4878 o_addchr(dest, ch);
4879 continue;
4880 }
4881 if (ch == '\'') {
4882 if (!add_till_single_quote(dest, input))
4883 return 0;
4884 o_addchr(dest, ch);
4885 continue;
4886 }
4887 if (ch == '"') {
4888 if (!add_till_double_quote(dest, input))
4889 return 0;
4890 o_addchr(dest, ch);
4891 continue;
4892 }
4893 if (ch == '`') {
4894 if (!add_till_backquote(dest, input, 0))
4895 return 0;
4896 o_addchr(dest, ch);
4897 continue;
4898 }
4899 if (ch == '\\') {
4900
4901 ch = i_getch(input);
4902 if (ch == EOF) {
4903 syntax_error_unterm_ch(end_ch);
4904 return 0;
4905 }
4906# if 0
4907 if (ch == '\n') {
4908
4909 o_delchr(dest);
4910 continue;
4911 }
4912# endif
4913 o_addchr(dest, ch);
4914
4915 continue;
4916 }
4917 }
4918 debug_printf_parse("%s return '%s' ch:'%c'\n", __func__, dest->data, ch);
4919 return ch;
4920}
4921#endif
4922
4923#if BASH_DOLLAR_SQUOTE
4924
4925# if BB_MMU
4926#define parse_dollar_squote(as_string, dest, input) \
4927 parse_dollar_squote(dest, input)
4928#define as_string NULL
4929# endif
4930static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input)
4931{
4932 int start;
4933 int ch = i_peek_and_eat_bkslash_nl(input);
4934 debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch);
4935 if (ch != '\'')
4936 return 0;
4937
4938 dest->has_quoted_part = 1;
4939 start = dest->length;
4940
4941 ch = i_getch(input);
4942 nommu_addchr(as_string, ch);
4943 while (1) {
4944 ch = i_getch(input);
4945 nommu_addchr(as_string, ch);
4946 if (ch == EOF) {
4947 syntax_error_unterm_ch('\'');
4948 return 0;
4949 }
4950 if (ch == '\'')
4951 break;
4952 if (ch == SPECIAL_VAR_SYMBOL) {
4953
4954 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4955 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
4956
4957 } else if (ch == '\\') {
4958 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
4959
4960 ch = i_getch(input);
4961 nommu_addchr(as_string, ch);
4962 if (strchr(C_escapes, ch)) {
4963 char buf[4];
4964 char *p = buf;
4965 int cnt = 2;
4966
4967 buf[0] = ch;
4968 if ((unsigned char)(ch - '0') <= 7) {
4969 do {
4970 ch = i_peek(input);
4971 if ((unsigned char)(ch - '0') > 7)
4972 break;
4973 *++p = ch = i_getch(input);
4974 nommu_addchr(as_string, ch);
4975 } while (--cnt != 0);
4976 } else if (ch == 'x') {
4977 do {
4978 ch = i_peek(input);
4979 if (!isxdigit(ch))
4980 break;
4981 *++p = ch = i_getch(input);
4982 nommu_addchr(as_string, ch);
4983 } while (--cnt != 0);
4984 if (cnt == 2) {
4985 ch = 'x';
4986 goto unrecognized;
4987 }
4988 }
4989 *++p = '\0';
4990 p = buf;
4991 ch = bb_process_escape_sequence((void*)&p);
4992
4993 if (ch == '\0')
4994 continue;
4995 } else {
4996 if (ch != '\'' && ch != '"') {
4997 unrecognized:
4998 o_addqchr(dest, '\\');
4999 }
5000 }
5001 }
5002 o_addqchr(dest, ch);
5003 }
5004
5005 if (dest->length == start) {
5006
5007 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5008 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5009 }
5010
5011 return 1;
5012# undef as_string
5013}
5014#else
5015# define parse_dollar_squote(as_string, dest, input) 0
5016#endif
5017
5018
5019#if BB_MMU
5020#define parse_dollar(as_string, dest, input, quote_mask) \
5021 parse_dollar(dest, input, quote_mask)
5022#define as_string NULL
5023#endif
5024static int parse_dollar(o_string *as_string,
5025 o_string *dest,
5026 struct in_str *input, unsigned char quote_mask)
5027{
5028 int ch = i_peek_and_eat_bkslash_nl(input);
5029
5030 debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask);
5031 if (isalpha(ch)) {
5032 make_var:
5033 ch = i_getch(input);
5034 nommu_addchr(as_string, ch);
5035
5036 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5037 while (1) {
5038 debug_printf_parse(": '%c'\n", ch);
5039 o_addchr(dest, ch | quote_mask);
5040 quote_mask = 0;
5041 ch = i_peek_and_eat_bkslash_nl(input);
5042 if (!isalnum(ch) && ch != '_') {
5043
5044 break;
5045 }
5046 ch = i_getch(input);
5047 nommu_addchr(as_string, ch);
5048 }
5049 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5050 } else if (isdigit(ch)) {
5051 make_one_char_var:
5052 ch = i_getch(input);
5053 nommu_addchr(as_string, ch);
5054 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5055 debug_printf_parse(": '%c'\n", ch);
5056 o_addchr(dest, ch | quote_mask);
5057 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5058 } else switch (ch) {
5059 case '$':
5060 case '!':
5061 case '?':
5062 case '#':
5063 case '*':
5064 case '@':
5065 case '-':
5066 goto make_one_char_var;
5067 case '{': {
5068 char len_single_ch;
5069
5070 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5071
5072 ch = i_getch(input);
5073 nommu_addchr(as_string, ch);
5074
5075 ch = i_getch_and_eat_bkslash_nl(input);
5076
5077
5078
5079
5080 if (ch == EOF
5081 || (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch))
5082 ) {
5083 bad_dollar_syntax:
5084 syntax_error_unterm_str("${name}");
5085 debug_printf_parse("parse_dollar return 0: unterminated ${name}\n");
5086 return 0;
5087 }
5088 nommu_addchr(as_string, ch);
5089 len_single_ch = ch;
5090 ch |= quote_mask;
5091
5092
5093
5094
5095
5096
5097 if (isdigit(len_single_ch)
5098 || (len_single_ch == '#' && isdigit(i_peek_and_eat_bkslash_nl(input)))
5099 ) {
5100
5101
5102
5103
5104
5105
5106 unsigned cnt = 9;
5107 while (1) {
5108 o_addchr(dest, ch);
5109 debug_printf_parse(": '%c'\n", ch);
5110 ch = i_getch_and_eat_bkslash_nl(input);
5111 nommu_addchr(as_string, ch);
5112 if (ch == '}')
5113 break;
5114 if (--cnt == 0)
5115 goto bad_dollar_syntax;
5116 if (len_single_ch != '#' && strchr(VAR_SUBST_OPS, ch))
5117
5118 goto eat_until_closing;
5119 if (!isdigit(ch))
5120 goto bad_dollar_syntax;
5121 }
5122 } else
5123 while (1) {
5124 unsigned pos;
5125
5126 o_addchr(dest, ch);
5127 debug_printf_parse(": '%c'\n", ch);
5128
5129 ch = i_getch(input);
5130 nommu_addchr(as_string, ch);
5131 if (ch == '}')
5132 break;
5133 if (!isalnum(ch) && ch != '_') {
5134 unsigned end_ch;
5135 unsigned char last_ch;
5136
5137
5138
5139 if (!strchr(VAR_SUBST_OPS, ch)) {
5140 if (len_single_ch != '#'
5141
5142 || i_peek(input) != '}'
5143 ) {
5144 goto bad_dollar_syntax;
5145 }
5146
5147
5148
5149
5150 }
5151 eat_until_closing:
5152
5153 end_ch = '}';
5154 if (BASH_SUBSTR
5155 && ch == ':'
5156 && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input))
5157 ) {
5158
5159 end_ch = '}' * 0x100 + ':';
5160 }
5161 if (BASH_PATTERN_SUBST
5162 && ch == '/'
5163 ) {
5164
5165 if (i_peek(input) == '/') {
5166 i_getch(input);
5167 nommu_addchr(as_string, '/');
5168 ch = '\\';
5169 }
5170 end_ch = '}' * 0x100 + '/';
5171 }
5172 o_addchr(dest, ch);
5173
5174
5175
5176
5177
5178
5179 if (i_peek(input) == '/') {
5180 o_addchr(dest, i_getch(input));
5181 }
5182 again:
5183 if (!BB_MMU)
5184 pos = dest->length;
5185#if ENABLE_HUSH_DOLLAR_OPS
5186 last_ch = add_till_closing_bracket(dest, input, end_ch);
5187 if (last_ch == 0)
5188 return 0;
5189#else
5190# error Simple code to only allow ${var} is not implemented
5191#endif
5192 if (as_string) {
5193 o_addstr(as_string, dest->data + pos);
5194 o_addchr(as_string, last_ch);
5195 }
5196
5197 if ((BASH_SUBSTR || BASH_PATTERN_SUBST)
5198 && (end_ch & 0xff00)
5199 ) {
5200
5201 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5202
5203
5204 if ((end_ch & 0xff) == last_ch) {
5205
5206 end_ch = '}';
5207 goto again;
5208 }
5209
5210 if (BASH_SUBSTR && end_ch == '}' * 0x100 + ':') {
5211
5212 o_addstr(dest, "999999999");
5213 }
5214 }
5215 break;
5216 }
5217 len_single_ch = 0;
5218 }
5219 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5220 break;
5221 }
5222#if ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_TICK
5223 case '(': {
5224 unsigned pos;
5225
5226 ch = i_getch(input);
5227 nommu_addchr(as_string, ch);
5228# if ENABLE_FEATURE_SH_MATH
5229 if (i_peek_and_eat_bkslash_nl(input) == '(') {
5230 ch = i_getch(input);
5231 nommu_addchr(as_string, ch);
5232 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5233 o_addchr(dest, quote_mask | '+');
5234 if (!BB_MMU)
5235 pos = dest->length;
5236 if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG))
5237 return 0;
5238 if (as_string) {
5239 o_addstr(as_string, dest->data + pos);
5240 o_addchr(as_string, ')');
5241 o_addchr(as_string, ')');
5242 }
5243 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5244 break;
5245 }
5246# endif
5247# if ENABLE_HUSH_TICK
5248 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5249 o_addchr(dest, quote_mask | '`');
5250 if (!BB_MMU)
5251 pos = dest->length;
5252 if (!add_till_closing_bracket(dest, input, ')'))
5253 return 0;
5254 if (as_string) {
5255 o_addstr(as_string, dest->data + pos);
5256 o_addchr(as_string, ')');
5257 }
5258 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5259# endif
5260 break;
5261 }
5262#endif
5263 case '_':
5264 goto make_var;
5265#if 0
5266
5267
5268
5269
5270 ch = i_getch(input);
5271 nommu_addchr(as_string, ch);
5272 ch = i_peek_and_eat_bkslash_nl(input);
5273 if (isalnum(ch)) {
5274 ch = '_';
5275 goto make_var1;
5276 }
5277
5278#endif
5279 default:
5280 o_addQchr(dest, '$');
5281 }
5282 debug_printf_parse("parse_dollar return 1 (ok)\n");
5283 return 1;
5284#undef as_string
5285}
5286
5287#if BB_MMU
5288#define encode_string(as_string, dest, input, dquote_end) \
5289 encode_string(dest, input, dquote_end)
5290#define as_string NULL
5291#endif
5292static int encode_string(o_string *as_string,
5293 o_string *dest,
5294 struct in_str *input,
5295 int dquote_end)
5296{
5297 int ch;
5298 int next;
5299
5300 again:
5301 ch = i_getch(input);
5302 if (ch != EOF)
5303 nommu_addchr(as_string, ch);
5304 if (ch == dquote_end) {
5305 debug_printf_parse("encode_string return 1 (ok)\n");
5306 return 1;
5307 }
5308
5309 if (ch == EOF) {
5310 syntax_error_unterm_ch('"');
5311 return 0;
5312 }
5313 next = '\0';
5314 if (ch != '\n') {
5315 next = i_peek(input);
5316 }
5317 debug_printf_parse("\" ch=%c (%d) escape=%d\n",
5318 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5319 if (ch == '\\') {
5320 if (next == EOF) {
5321
5322
5323
5324
5325 syntax_error_unterm_ch('"');
5326 return 0;
5327 }
5328
5329
5330
5331
5332
5333
5334
5335
5336 if (next == dquote_end || strchr("$`\\\n", next)) {
5337 ch = i_getch(input);
5338 if (ch == '\n')
5339 goto again;
5340 }
5341 o_addqchr(dest, ch);
5342 nommu_addchr(as_string, ch);
5343 goto again;
5344 }
5345 if (ch == '$') {
5346
5347
5348 if (!parse_dollar(as_string, dest, input, 0x80)) {
5349 debug_printf_parse("encode_string return 0: "
5350 "parse_dollar returned 0 (error)\n");
5351 return 0;
5352 }
5353 goto again;
5354 }
5355#if ENABLE_HUSH_TICK
5356 if (ch == '`') {
5357
5358 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5359 o_addchr(dest, 0x80 | '`');
5360 if (!add_till_backquote(dest, input, dquote_end == '"'))
5361 return 0;
5362 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5363
5364 goto again;
5365 }
5366#endif
5367 o_addQchr(dest, ch);
5368 if (ch == SPECIAL_VAR_SYMBOL) {
5369
5370 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
5371 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5372 }
5373 goto again;
5374#undef as_string
5375}
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385static struct pipe *parse_stream(char **pstring,
5386 int *heredoc_cnt_ptr,
5387 struct in_str *input,
5388 int end_trigger)
5389{
5390 struct parse_context ctx;
5391 int heredoc_cnt;
5392
5393
5394
5395
5396 debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
5397 end_trigger ? end_trigger : 'X');
5398 debug_enter();
5399
5400 initialize_context(&ctx);
5401
5402
5403
5404
5405 ctx.word.data = xzalloc(1);
5406
5407
5408
5409
5410
5411
5412 heredoc_cnt = 0;
5413 while (1) {
5414 const char *is_blank;
5415 const char *is_special;
5416 int ch;
5417 int next;
5418 int redir_fd;
5419 redir_type redir_style;
5420
5421 ch = i_getch(input);
5422 debug_printf_parse(": ch=%c (%d) escape=%d\n",
5423 ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5424 if (ch == EOF) {
5425 struct pipe *pi;
5426
5427 if (heredoc_cnt) {
5428 syntax_error_unterm_str("here document");
5429 goto parse_error_exitcode1;
5430 }
5431 if (end_trigger == ')') {
5432 syntax_error_unterm_ch('(');
5433 goto parse_error_exitcode1;
5434 }
5435 if (end_trigger == '}') {
5436 syntax_error_unterm_ch('{');
5437 goto parse_error_exitcode1;
5438 }
5439
5440 if (done_word(&ctx)) {
5441 goto parse_error_exitcode1;
5442 }
5443 o_free_and_set_NULL(&ctx.word);
5444 done_pipe(&ctx, PIPE_SEQ);
5445 pi = ctx.list_head;
5446
5447
5448
5449 if (pi->num_cmds == 0
5450 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)
5451 ) {
5452 free_pipe_list(pi);
5453 pi = NULL;
5454 }
5455#if !BB_MMU
5456 debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
5457 if (pstring)
5458 *pstring = ctx.as_string.data;
5459 else
5460 o_free(&ctx.as_string);
5461#endif
5462
5463
5464
5465 debug_leave();
5466 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5467 debug_printf_parse("parse_stream return %p\n", pi);
5468 return pi;
5469 }
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479 if (ch == '\\') {
5480 ch = i_getch(input);
5481 if (ch == '\n')
5482 continue;
5483 nommu_addchr(&ctx.as_string, '\\');
5484 if (ch == SPECIAL_VAR_SYMBOL) {
5485 nommu_addchr(&ctx.as_string, ch);
5486
5487 goto case_SPECIAL_VAR_SYMBOL;
5488 }
5489 o_addchr(&ctx.word, '\\');
5490 if (ch == EOF) {
5491
5492
5493
5494
5495 continue;
5496 }
5497
5498
5499
5500 ctx.word.has_quoted_part = 1;
5501 nommu_addchr(&ctx.as_string, ch);
5502 o_addchr(&ctx.word, ch);
5503 continue;
5504 }
5505 nommu_addchr(&ctx.as_string, ch);
5506 if (ch == '\'') {
5507 ctx.word.has_quoted_part = 1;
5508 next = i_getch(input);
5509 if (next == '\'' && !ctx.pending_redirect)
5510 goto insert_empty_quoted_str_marker;
5511
5512 ch = next;
5513 while (1) {
5514 if (ch == EOF) {
5515 syntax_error_unterm_ch('\'');
5516 goto parse_error_exitcode1;
5517 }
5518 nommu_addchr(&ctx.as_string, ch);
5519 if (ch == '\'')
5520 break;
5521 if (ch == SPECIAL_VAR_SYMBOL) {
5522
5523 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5524 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
5525 }
5526 o_addqchr(&ctx.word, ch);
5527 ch = i_getch(input);
5528 }
5529 continue;
5530 }
5531
5532 next = '\0';
5533 if (ch != '\n')
5534 next = i_peek_and_eat_bkslash_nl(input);
5535
5536 is_special = "{}<>&|();#"
5537 "$\"" IF_HUSH_TICK("`")
5538 SPECIAL_VAR_SYMBOL_STR;
5539#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
5540 if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
5541
5542 is_special += 8;
5543 } else
5544#endif
5545
5546 if (ctx.command->argv
5547 || ctx.word.length
5548 || ctx.word.has_quoted_part
5549 || (next != ';'
5550 && next != ')'
5551 && next != '('
5552 && next != '&'
5553 && next != '|'
5554 && !strchr(defifs, next)
5555 )
5556 ) {
5557
5558 is_special += 2;
5559 }
5560 is_special = strchr(is_special, ch);
5561 is_blank = strchr(defifs, ch);
5562
5563 if (!is_special && !is_blank) {
5564 ordinary_char:
5565 o_addQchr(&ctx.word, ch);
5566 if ((ctx.is_assignment == MAYBE_ASSIGNMENT
5567 || ctx.is_assignment == WORD_IS_KEYWORD)
5568 && ch == '='
5569 && endofname(ctx.word.data)[0] == '='
5570 ) {
5571 ctx.is_assignment = DEFINITELY_ASSIGNMENT;
5572 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5573 }
5574 continue;
5575 }
5576
5577 if (is_blank) {
5578#if ENABLE_HUSH_LINENO_VAR
5579
5580
5581
5582
5583
5584
5585
5586 while (ch != '\n') {
5587 next = i_peek(input);
5588 if (next != ' ' && next != '\t' && next != '\n')
5589 break;
5590 ch = i_getch(input);
5591 }
5592
5593#endif
5594 if (done_word(&ctx)) {
5595 goto parse_error_exitcode1;
5596 }
5597 if (ch == '\n') {
5598
5599
5600
5601
5602
5603 if (IS_NULL_CMD(ctx.command)
5604 && ctx.word.length == 0
5605 && !ctx.word.has_quoted_part
5606 && heredoc_cnt == 0
5607 ) {
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625 struct pipe *pi = ctx.list_head;
5626 if (pi->num_cmds != 0
5627 && pi->followup != PIPE_BG
5628 ) {
5629 continue;
5630 }
5631 }
5632
5633 done_pipe(&ctx, PIPE_SEQ);
5634 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
5635 if (heredoc_cnt) {
5636 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5637 if (heredoc_cnt != 0)
5638 goto parse_error_exitcode1;
5639 }
5640 ctx.is_assignment = MAYBE_ASSIGNMENT;
5641 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5642 ch = ';';
5643
5644
5645 }
5646 }
5647
5648
5649
5650
5651
5652 if (ch == '}') {
5653 if (ctx.word.length != 0
5654 || ctx.word.has_quoted_part
5655 ) {
5656 goto ordinary_char;
5657 }
5658 if (!IS_NULL_CMD(ctx.command)) {
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668 if (ctx.command->group)
5669 goto term_group;
5670 goto ordinary_char;
5671 }
5672 if (!IS_NULL_PIPE(ctx.pipe))
5673
5674 goto skip_end_trigger;
5675
5676 }
5677 term_group:
5678 if (end_trigger && end_trigger == ch
5679 && (ch != ';' || heredoc_cnt == 0)
5680#if ENABLE_HUSH_CASE
5681 && (ch != ')'
5682 || ctx.ctx_res_w != RES_MATCH
5683 || (!ctx.word.has_quoted_part && strcmp(ctx.word.data, "esac") == 0)
5684 )
5685#endif
5686 ) {
5687 if (done_word(&ctx)) {
5688 goto parse_error_exitcode1;
5689 }
5690 done_pipe(&ctx, PIPE_SEQ);
5691 ctx.is_assignment = MAYBE_ASSIGNMENT;
5692 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5693
5694 if (!HAS_KEYWORDS
5695 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
5696 ) {
5697 o_free_and_set_NULL(&ctx.word);
5698#if !BB_MMU
5699 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
5700 if (pstring)
5701 *pstring = ctx.as_string.data;
5702 else
5703 o_free(&ctx.as_string);
5704#endif
5705 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
5706
5707 G.last_exitcode = 2;
5708 syntax_error_unexpected_ch(ch);
5709 goto parse_error;
5710 }
5711 if (heredoc_cnt_ptr)
5712 *heredoc_cnt_ptr = heredoc_cnt;
5713 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5714 debug_printf_parse("parse_stream return %p: "
5715 "end_trigger char found\n",
5716 ctx.list_head);
5717 debug_leave();
5718 return ctx.list_head;
5719 }
5720 }
5721
5722 if (is_blank)
5723 continue;
5724
5725
5726
5727 switch (ch) {
5728 case '>':
5729 redir_fd = redirect_opt_num(&ctx.word);
5730 if (done_word(&ctx)) {
5731 goto parse_error_exitcode1;
5732 }
5733 redir_style = REDIRECT_OVERWRITE;
5734 if (next == '>') {
5735 redir_style = REDIRECT_APPEND;
5736 ch = i_getch(input);
5737 nommu_addchr(&ctx.as_string, ch);
5738 }
5739#if 0
5740 else if (next == '(') {
5741 syntax_error(">(process) not supported");
5742 goto parse_error_exitcode1;
5743 }
5744#endif
5745 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5746 goto parse_error_exitcode1;
5747 continue;
5748 case '<':
5749 redir_fd = redirect_opt_num(&ctx.word);
5750 if (done_word(&ctx)) {
5751 goto parse_error_exitcode1;
5752 }
5753 redir_style = REDIRECT_INPUT;
5754 if (next == '<') {
5755 redir_style = REDIRECT_HEREDOC;
5756 heredoc_cnt++;
5757 debug_printf_heredoc("++heredoc_cnt=%d\n", heredoc_cnt);
5758 ch = i_getch(input);
5759 nommu_addchr(&ctx.as_string, ch);
5760 } else if (next == '>') {
5761 redir_style = REDIRECT_IO;
5762 ch = i_getch(input);
5763 nommu_addchr(&ctx.as_string, ch);
5764 }
5765#if 0
5766 else if (next == '(') {
5767 syntax_error("<(process) not supported");
5768 goto parse_error_exitcode1;
5769 }
5770#endif
5771 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5772 goto parse_error_exitcode1;
5773 continue;
5774 case '#':
5775 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
5776
5777
5778
5779
5780
5781
5782
5783
5784 while (1) {
5785 ch = i_peek(input);
5786 if (ch == '\n') {
5787 nommu_addchr(&ctx.as_string, '\n');
5788 break;
5789 }
5790 ch = i_getch(input);
5791 if (ch == EOF)
5792 break;
5793 }
5794 continue;
5795 }
5796 break;
5797 }
5798 skip_end_trigger:
5799
5800 if (ctx.is_assignment == MAYBE_ASSIGNMENT
5801
5802 && !ctx.pending_redirect
5803 ) {
5804
5805
5806 ctx.is_assignment = NOT_ASSIGNMENT;
5807 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5808 }
5809
5810
5811
5812 switch (ch) {
5813 case_SPECIAL_VAR_SYMBOL:
5814 case SPECIAL_VAR_SYMBOL:
5815
5816 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5817 o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS);
5818
5819 case '#':
5820
5821 o_addchr(&ctx.word, ch);
5822 continue;
5823 case '$':
5824 if (parse_dollar_squote(&ctx.as_string, &ctx.word, input))
5825 continue;
5826 if (!parse_dollar(&ctx.as_string, &ctx.word, input, 0)) {
5827 debug_printf_parse("parse_stream parse error: "
5828 "parse_dollar returned 0 (error)\n");
5829 goto parse_error_exitcode1;
5830 }
5831 continue;
5832 case '"':
5833 ctx.word.has_quoted_part = 1;
5834 if (next == '"' && !ctx.pending_redirect) {
5835 i_getch(input);
5836 insert_empty_quoted_str_marker:
5837 nommu_addchr(&ctx.as_string, next);
5838 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5839 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5840 continue;
5841 }
5842 if (ctx.is_assignment == NOT_ASSIGNMENT)
5843 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
5844 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
5845 goto parse_error_exitcode1;
5846 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
5847 continue;
5848#if ENABLE_HUSH_TICK
5849 case '`': {
5850 USE_FOR_NOMMU(unsigned pos;)
5851
5852 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5853 o_addchr(&ctx.word, '`');
5854 USE_FOR_NOMMU(pos = ctx.word.length;)
5855 if (!add_till_backquote(&ctx.word, input, 0))
5856 goto parse_error_exitcode1;
5857# if !BB_MMU
5858 o_addstr(&ctx.as_string, ctx.word.data + pos);
5859 o_addchr(&ctx.as_string, '`');
5860# endif
5861 o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
5862
5863 continue;
5864 }
5865#endif
5866 case ';':
5867#if ENABLE_HUSH_CASE
5868 case_semi:
5869#endif
5870 if (done_word(&ctx)) {
5871 goto parse_error_exitcode1;
5872 }
5873 done_pipe(&ctx, PIPE_SEQ);
5874#if ENABLE_HUSH_CASE
5875
5876
5877 while (1) {
5878 ch = i_peek_and_eat_bkslash_nl(input);
5879 if (ch != ';')
5880 break;
5881 ch = i_getch(input);
5882 nommu_addchr(&ctx.as_string, ch);
5883 if (ctx.ctx_res_w == RES_CASE_BODY) {
5884 ctx.ctx_dsemicolon = 1;
5885 ctx.ctx_res_w = RES_MATCH;
5886 break;
5887 }
5888 }
5889#endif
5890 new_cmd:
5891
5892
5893 ctx.is_assignment = MAYBE_ASSIGNMENT;
5894 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
5895 continue;
5896 case '&':
5897 if (done_word(&ctx)) {
5898 goto parse_error_exitcode1;
5899 }
5900 if (next == '&') {
5901 ch = i_getch(input);
5902 nommu_addchr(&ctx.as_string, ch);
5903 done_pipe(&ctx, PIPE_AND);
5904 } else {
5905 done_pipe(&ctx, PIPE_BG);
5906 }
5907 goto new_cmd;
5908 case '|':
5909 if (done_word(&ctx)) {
5910 goto parse_error_exitcode1;
5911 }
5912#if ENABLE_HUSH_CASE
5913 if (ctx.ctx_res_w == RES_MATCH)
5914 break;
5915#endif
5916 if (next == '|') {
5917 ch = i_getch(input);
5918 nommu_addchr(&ctx.as_string, ch);
5919 done_pipe(&ctx, PIPE_OR);
5920 } else {
5921
5922
5923
5924 done_command(&ctx);
5925 }
5926 goto new_cmd;
5927 case '(':
5928#if ENABLE_HUSH_CASE
5929
5930 if (ctx.ctx_res_w == RES_MATCH
5931 && ctx.command->argv == NULL
5932 && ctx.word.length == 0
5933 && ctx.word.has_quoted_part == 0
5934 ) {
5935 continue;
5936 }
5937#endif
5938
5939 case '{': {
5940 int n = parse_group(&ctx, input, ch);
5941 if (n < 0) {
5942 goto parse_error_exitcode1;
5943 }
5944 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5945 heredoc_cnt += n;
5946 goto new_cmd;
5947 }
5948 case ')':
5949#if ENABLE_HUSH_CASE
5950 if (ctx.ctx_res_w == RES_MATCH)
5951 goto case_semi;
5952#endif
5953 case '}':
5954
5955
5956
5957 G.last_exitcode = 2;
5958 syntax_error_unexpected_ch(ch);
5959 goto parse_error;
5960 default:
5961 if (HUSH_DEBUG)
5962 bb_error_msg_and_die("BUG: unexpected %c", ch);
5963 }
5964 }
5965
5966 parse_error_exitcode1:
5967 G.last_exitcode = 1;
5968 parse_error:
5969 {
5970 struct parse_context *pctx;
5971 IF_HAS_KEYWORDS(struct parse_context *p2;)
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981 pctx = &ctx;
5982 do {
5983
5984
5985 done_pipe(pctx, PIPE_SEQ);
5986 debug_printf_clean("freeing list %p from ctx %p\n",
5987 pctx->list_head, pctx);
5988 debug_print_tree(pctx->list_head, 0);
5989 free_pipe_list(pctx->list_head);
5990 debug_printf_clean("freed list %p\n", pctx->list_head);
5991#if !BB_MMU
5992 o_free(&pctx->as_string);
5993#endif
5994 IF_HAS_KEYWORDS(p2 = pctx->stack;)
5995 if (pctx != &ctx) {
5996 free(pctx);
5997 }
5998 IF_HAS_KEYWORDS(pctx = p2;)
5999 } while (HAS_KEYWORDS && pctx);
6000
6001 o_free(&ctx.word);
6002#if !BB_MMU
6003 if (pstring)
6004 *pstring = NULL;
6005#endif
6006 debug_leave();
6007 return ERR_PTR;
6008 }
6009}
6010
6011
6012
6013
6014
6015#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
6016#define expand_string_to_string(str, EXP_flags, do_unbackslash) \
6017 expand_string_to_string(str)
6018#endif
6019static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash);
6020#if ENABLE_HUSH_TICK
6021static int process_command_subs(o_string *dest, const char *s);
6022#endif
6023static int expand_vars_to_list(o_string *output, int n, char *arg);
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
6037{
6038 while (--len >= 0) {
6039 char c = *str++;
6040
6041#if ENABLE_HUSH_BRACE_EXPANSION
6042 if (c == '{' || c == '}') {
6043
6044 o_addchr(o, '\\');
6045
6046
6047
6048
6049
6050 }
6051#endif
6052 o_addchr(o, c);
6053 if (c == '\\') {
6054
6055 o_addchr(o, '\\');
6056 if (len) {
6057 len--;
6058 o_addchr(o, '\\');
6059 o_addchr(o, *str++);
6060 }
6061 }
6062 }
6063}
6064
6065
6066
6067
6068
6069
6070
6071static int expand_on_ifs(o_string *output, int n, const char *str)
6072{
6073 int last_is_ifs = 0;
6074
6075 while (1) {
6076 int word_len;
6077
6078 if (!*str)
6079 break;
6080 word_len = strcspn(str, G.ifs);
6081 if (word_len) {
6082
6083 if (!(output->o_expflags & EXP_FLAG_GLOB)) {
6084 o_addblock(output, str, word_len);
6085 } else {
6086
6087
6088
6089
6090 o_addblock_duplicate_backslash(output, str, word_len);
6091
6092
6093
6094 }
6095 last_is_ifs = 0;
6096 str += word_len;
6097 if (!*str)
6098 break;
6099 }
6100
6101
6102 last_is_ifs = 1;
6103 str += strspn(str, G.ifs_whitespace);
6104 if (!*str)
6105 break;
6106
6107 if (G.ifs_whitespace != G.ifs
6108 && strchr(G.ifs, *str)
6109 ) {
6110
6111
6112 str++;
6113 str += strspn(str, G.ifs_whitespace);
6114 goto new_word;
6115 }
6116
6117
6118
6119 if (output->has_quoted_part
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129 || output->data[output->length - 1]
6130 ) {
6131 new_word:
6132 o_addchr(output, '\0');
6133 debug_print_list("expand_on_ifs", output, n);
6134 n = o_save_ptr(output, n);
6135 }
6136 }
6137
6138 output->ended_in_ifs = last_is_ifs;
6139 debug_print_list("expand_on_ifs[1]", output, n);
6140 return n;
6141}
6142
6143
6144
6145
6146
6147
6148
6149
6150static char *encode_then_expand_string(const char *str)
6151{
6152 char *exp_str;
6153 struct in_str input;
6154 o_string dest = NULL_O_STRING;
6155 const char *cp;
6156
6157 cp = str;
6158 for (;;) {
6159 if (!*cp) return NULL;
6160 if (*cp == '$') break;
6161 if (*cp == '\\') break;
6162#if ENABLE_HUSH_TICK
6163 if (*cp == '`') break;
6164#endif
6165 cp++;
6166 }
6167
6168
6169
6170
6171 setup_string_in_str(&input, str);
6172 encode_string(NULL, &dest, &input, EOF);
6173
6174
6175 exp_str = expand_string_to_string(dest.data,
6176 EXP_FLAG_ESC_GLOB_CHARS,
6177 1
6178 );
6179
6180 o_free(&dest);
6181 return exp_str;
6182}
6183
6184static const char *first_special_char_in_vararg(const char *cp)
6185{
6186 for (;;) {
6187 if (!*cp) return NULL;
6188 if (*cp == '$') return cp;
6189 if (*cp == '\\') return cp;
6190 if (*cp == '\'') return cp;
6191 if (*cp == '"') return cp;
6192#if ENABLE_HUSH_TICK
6193 if (*cp == '`') return cp;
6194#endif
6195
6196
6197 if (*cp == '*') return cp;
6198 if (*cp == '?') return cp;
6199 if (*cp == '[') return cp;
6200 cp++;
6201 }
6202}
6203
6204
6205
6206
6207
6208
6209
6210
6211#if !BASH_PATTERN_SUBST
6212#define encode_then_expand_vararg(str, handle_squotes, do_unbackslash) \
6213 encode_then_expand_vararg(str, handle_squotes)
6214#endif
6215static char *encode_then_expand_vararg(const char *str, int handle_squotes, int do_unbackslash)
6216{
6217#if !BASH_PATTERN_SUBST && ENABLE_HUSH_CASE
6218 const int do_unbackslash = 0;
6219#endif
6220 char *exp_str;
6221 struct in_str input;
6222 o_string dest = NULL_O_STRING;
6223
6224 if (!first_special_char_in_vararg(str)) {
6225
6226 return NULL;
6227 }
6228
6229 setup_string_in_str(&input, str);
6230 dest.data = xzalloc(1);
6231 exp_str = NULL;
6232
6233 for (;;) {
6234 int ch;
6235
6236 ch = i_getch(&input);
6237 debug_printf_parse("%s: ch=%c (%d) escape=%d\n",
6238 __func__, ch, ch, !!dest.o_expflags);
6239
6240 if (!dest.o_expflags) {
6241 if (ch == EOF)
6242 break;
6243 if (handle_squotes && ch == '\'') {
6244 if (!add_till_single_quote_dquoted(&dest, &input))
6245 goto ret;
6246 continue;
6247 }
6248 }
6249 if (ch == EOF) {
6250 syntax_error_unterm_ch('"');
6251 goto ret;
6252 }
6253 if (ch == '"') {
6254 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
6255 continue;
6256 }
6257 if (ch == '\\') {
6258 ch = i_getch(&input);
6259 if (ch == EOF) {
6260
6261 debug_printf_parse("%s: error: \\<eof>\n", __func__);
6262 goto ret;
6263 }
6264 o_addqchr(&dest, ch);
6265 continue;
6266 }
6267 if (ch == '$') {
6268 if (parse_dollar_squote(NULL, &dest, &input))
6269 continue;
6270 if (!parse_dollar(NULL, &dest, &input, 0x80)) {
6271 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6272 goto ret;
6273 }
6274 continue;
6275 }
6276#if ENABLE_HUSH_TICK
6277 if (ch == '`') {
6278
6279 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6280 o_addchr(&dest, 0x80 | '`');
6281 if (!add_till_backquote(&dest, &input,
6282 dest.o_expflags
6283 )
6284 ) {
6285 goto ret;
6286 }
6287 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6288
6289 continue;
6290 }
6291#endif
6292 o_addQchr(&dest, ch);
6293 }
6294
6295 debug_printf_parse("encode: '%s' -> '%s'\n", str, dest.data);
6296 exp_str = expand_string_to_string(dest.data,
6297 do_unbackslash ? EXP_FLAG_ESC_GLOB_CHARS : 0,
6298 do_unbackslash
6299 );
6300 ret:
6301 debug_printf_parse("expand: '%s' -> '%s'\n", dest.data, exp_str);
6302 o_free(&dest);
6303 return exp_str;
6304}
6305
6306
6307
6308static int encode_then_append_var_plusminus(o_string *output, int n,
6309 char *str, int dquoted)
6310{
6311 struct in_str input;
6312 o_string dest = NULL_O_STRING;
6313
6314 if (!first_special_char_in_vararg(str)
6315 && '\0' == str[strcspn(str, G.ifs)]
6316 ) {
6317
6318
6319
6320 if (dquoted) {
6321
6322
6323
6324 output->has_quoted_part = 1;
6325 }
6326 return expand_vars_to_list(output, n, str);
6327 }
6328
6329 setup_string_in_str(&input, str);
6330
6331 for (;;) {
6332 int ch;
6333
6334 ch = i_getch(&input);
6335 debug_printf_parse("%s: ch=%c (%d) escape=%x\n",
6336 __func__, ch, ch, dest.o_expflags);
6337
6338 if (!dest.o_expflags) {
6339 if (ch == EOF)
6340 break;
6341 if (!dquoted && strchr(G.ifs, ch)) {
6342
6343
6344
6345 if (dest.data) {
6346 n = expand_vars_to_list(output, n, dest.data);
6347 o_free_and_set_NULL(&dest);
6348 o_addchr(output, '\0');
6349 n = o_save_ptr(output, n);
6350 } else
6351 if (output->length != o_get_last_ptr(output, n)
6352 || output->has_quoted_part
6353 ) {
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363 o_addchr(output, '\0');
6364 n = o_save_ptr(output, n);
6365 }
6366 continue;
6367 }
6368 if (!dquoted && ch == '\'') {
6369 if (!add_till_single_quote_dquoted(&dest, &input))
6370 goto ret;
6371 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6372 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6373 continue;
6374 }
6375 }
6376 if (ch == EOF) {
6377 syntax_error_unterm_ch('"');
6378 goto ret;
6379 }
6380 if (ch == '"') {
6381 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
6382 if (dest.o_expflags) {
6383 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6384 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6385 }
6386 continue;
6387 }
6388 if (ch == '\\') {
6389 ch = i_getch(&input);
6390 if (ch == EOF) {
6391
6392 debug_printf_parse("%s: error: \\<eof>\n", __func__);
6393 goto ret;
6394 }
6395 o_addqchr(&dest, ch);
6396 continue;
6397 }
6398 if (ch == '$') {
6399 if (!parse_dollar(NULL, &dest, &input, (dest.o_expflags || dquoted) ? 0x80 : 0)) {
6400 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6401 goto ret;
6402 }
6403 continue;
6404 }
6405#if ENABLE_HUSH_TICK
6406 if (ch == '`') {
6407
6408 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6409 o_addchr(&dest, (dest.o_expflags || dquoted) ? 0x80 | '`' : '`');
6410 if (!add_till_backquote(&dest, &input,
6411 dest.o_expflags
6412 )
6413 ) {
6414 goto ret;
6415 }
6416 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6417
6418 continue;
6419 }
6420#endif
6421 if (dquoted) {
6422
6423
6424
6425
6426 o_addqchr(&dest, ch);
6427 } else {
6428
6429
6430
6431
6432 o_addQchr(&dest, ch);
6433 }
6434 }
6435
6436 if (dest.data) {
6437 n = expand_vars_to_list(output, n, dest.data);
6438 }
6439 ret:
6440 o_free(&dest);
6441 return n;
6442}
6443
6444#if ENABLE_FEATURE_SH_MATH
6445static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
6446{
6447 arith_state_t math_state;
6448 arith_t res;
6449 char *exp_str;
6450
6451 math_state.lookupvar = get_local_var_value;
6452 math_state.setvar = set_local_var_from_halves;
6453
6454 exp_str = encode_then_expand_string(arg);
6455 res = arith(&math_state, exp_str ? exp_str : arg);
6456 free(exp_str);
6457 if (errmsg_p)
6458 *errmsg_p = math_state.errmsg;
6459 if (math_state.errmsg)
6460 msg_and_die_if_script(math_state.errmsg);
6461 return res;
6462}
6463#endif
6464
6465#if BASH_PATTERN_SUBST
6466
6467static char *strstr_pattern(char *val, const char *pattern, int *size)
6468{
6469 int sz = strcspn(pattern, "*?[\\");
6470 if (pattern[sz] == '\0') {
6471
6472
6473
6474
6475
6476
6477 *size = sz;
6478 return strstr(val, pattern);
6479 }
6480
6481 while (1) {
6482 char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF);
6483 debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end);
6484 if (end) {
6485 *size = end - val;
6486 return val;
6487 }
6488 if (*val == '\0')
6489 return NULL;
6490
6491
6492
6493 if (pattern[0] == '*')
6494 return NULL;
6495 val++;
6496 }
6497}
6498static char *replace_pattern(char *val, const char *pattern, const char *repl, char exp_op)
6499{
6500 char *result = NULL;
6501 unsigned res_len = 0;
6502 unsigned repl_len = strlen(repl);
6503
6504
6505 if (!pattern[0])
6506 return result;
6507
6508 while (1) {
6509 int size;
6510 char *s = strstr_pattern(val, pattern, &size);
6511 if (!s)
6512 break;
6513
6514 result = xrealloc(result, res_len + (s - val) + repl_len + 1);
6515 strcpy(mempcpy(result + res_len, val, s - val), repl);
6516 res_len += (s - val) + repl_len;
6517 debug_printf_varexp("val:'%s' s:'%s' result:'%s'\n", val, s, result);
6518
6519 val = s + size;
6520 if (exp_op == '/')
6521 break;
6522 }
6523 if (*val && result) {
6524 result = xrealloc(result, res_len + strlen(val) + 1);
6525 strcpy(result + res_len, val);
6526 debug_printf_varexp("val:'%s' result:'%s'\n", val, result);
6527 }
6528 debug_printf_varexp("result:'%s'\n", result);
6529 return result;
6530}
6531#endif
6532
6533static int append_str_maybe_ifs_split(o_string *output, int n,
6534 int first_ch, const char *val)
6535{
6536 if (!(first_ch & 0x80)) {
6537 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val,
6538 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6539 if (val && val[0])
6540 n = expand_on_ifs(output, n, val);
6541 } else {
6542 output->has_quoted_part = 1;
6543 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
6544 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6545 if (val && val[0])
6546 o_addQstr(output, val);
6547 }
6548 return n;
6549}
6550
6551
6552
6553static NOINLINE int expand_one_var(o_string *output, int n,
6554 int first_ch, char *arg, char **pp)
6555{
6556 const char *val;
6557 char *to_be_freed;
6558 char *p;
6559 char *var;
6560 char exp_op;
6561 char exp_save = exp_save;
6562 char *exp_saveptr;
6563 char *exp_word = exp_word;
6564 char arg0;
6565
6566 val = NULL;
6567 to_be_freed = NULL;
6568 p = *pp;
6569 *p = '\0';
6570 var = arg;
6571 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
6572 arg0 = arg[0];
6573 arg[0] = (arg0 & 0x7f);
6574 exp_op = 0;
6575
6576 if (arg[0] == '#' && arg[1]
6577 && (!exp_saveptr
6578 || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1]))
6579 )
6580 ) {
6581
6582 var++;
6583 exp_op = 'L';
6584 } else {
6585
6586 if (exp_saveptr
6587 && strchr(NUMERIC_SPECVARS_STR, arg[0])
6588 ) {
6589
6590 exp_saveptr = var + 1;
6591 } else {
6592
6593 exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS);
6594 }
6595 exp_op = exp_save = *exp_saveptr;
6596 if (exp_op) {
6597 exp_word = exp_saveptr + 1;
6598 if (exp_op == ':') {
6599 exp_op = *exp_word++;
6600
6601 if (BASH_SUBSTR
6602 && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op))
6603 ) {
6604
6605 exp_op = ':';
6606 exp_word--;
6607 }
6608 }
6609 *exp_saveptr = '\0';
6610 }
6611 }
6612
6613
6614 if (isdigit(var[0])) {
6615
6616 int nn = xatoi_positive(var);
6617 if (nn < G.global_argc)
6618 val = G.global_argv[nn];
6619
6620 } else {
6621 switch (var[0]) {
6622 case '$':
6623 val = utoa(G.root_pid);
6624 break;
6625 case '!':
6626 val = G.last_bg_pid ? utoa(G.last_bg_pid) : "";
6627 break;
6628 case '?':
6629 val = utoa(G.last_exitcode);
6630 break;
6631 case '#':
6632 val = utoa(G.global_argc ? G.global_argc-1 : 0);
6633 break;
6634 case '-': {
6635
6636 char *cp;
6637 val = cp = G.optstring_buf;
6638 if (G.o_opt[OPT_O_ERREXIT])
6639 *cp++ = 'e';
6640 if (G_interactive_fd)
6641 *cp++ = 'i';
6642 if (G_x_mode)
6643 *cp++ = 'x';
6644
6645
6646
6647
6648 if (G.opt_c)
6649 *cp++ = 'c';
6650 if (G.opt_s)
6651 *cp++ = 's';
6652 *cp = '\0';
6653 break;
6654 }
6655 default:
6656 val = get_local_var_value(var);
6657 }
6658 }
6659
6660
6661 if (exp_op == 'L') {
6662 reinit_unicode_for_hush();
6663 debug_printf_expand("expand: length(%s)=", val);
6664 val = utoa(val ? unicode_strlen(val) : 0);
6665 debug_printf_expand("%s\n", val);
6666 } else if (exp_op) {
6667 if (exp_op == '%' || exp_op == '#') {
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682 if (val && val[0]) {
6683 char *t;
6684 char *exp_exp_word;
6685 char *loc;
6686 unsigned scan_flags = pick_scan(exp_op, *exp_word);
6687 if (exp_op == *exp_word)
6688 exp_word++;
6689 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
6690 exp_exp_word = encode_then_expand_vararg(exp_word, 1, 0);
6691 if (exp_exp_word)
6692 exp_word = exp_exp_word;
6693 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
6694
6695
6696
6697
6698
6699
6700 t = (char*)val;
6701 loc = scan_and_match(t, exp_word, scan_flags);
6702 debug_printf_expand("op:%c str:'%s' pat:'%s' res:'%s'\n", exp_op, t, exp_word, loc);
6703 free(exp_exp_word);
6704 if (loc) {
6705 if (scan_flags & SCAN_MATCH_LEFT_HALF)
6706 val = loc;
6707 else
6708 val = to_be_freed = xstrndup(val, loc - val);
6709 }
6710 }
6711 }
6712#if BASH_PATTERN_SUBST
6713 else if (exp_op == '/' || exp_op == '\\') {
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725 if (val ) {
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736 char *pattern, *repl, *t;
6737 pattern = encode_then_expand_vararg(exp_word, 1, 0);
6738 if (!pattern)
6739 pattern = xstrdup(exp_word);
6740 debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern);
6741 *p++ = SPECIAL_VAR_SYMBOL;
6742 exp_word = p;
6743 p = strchr(p, SPECIAL_VAR_SYMBOL);
6744 *p = '\0';
6745 repl = encode_then_expand_vararg(exp_word, 1, 1);
6746 debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl);
6747
6748
6749
6750
6751 t = (char*)val;
6752 to_be_freed = replace_pattern(t,
6753 pattern,
6754 (repl ? repl : exp_word),
6755 exp_op);
6756 if (to_be_freed)
6757 val = to_be_freed;
6758 free(pattern);
6759 free(repl);
6760 } else {
6761
6762
6763
6764
6765 *p++ = SPECIAL_VAR_SYMBOL;
6766 p = strchr(p, SPECIAL_VAR_SYMBOL);
6767 *p = '\0';
6768 }
6769 }
6770#endif
6771 else if (exp_op == ':') {
6772#if BASH_SUBSTR && ENABLE_FEATURE_SH_MATH
6773
6774
6775
6776
6777 arith_t beg, len;
6778 unsigned vallen;
6779 const char *errmsg;
6780
6781 beg = expand_and_evaluate_arith(exp_word, &errmsg);
6782 if (errmsg)
6783 goto empty_result;
6784 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
6785 *p++ = SPECIAL_VAR_SYMBOL;
6786 exp_word = p;
6787 p = strchr(p, SPECIAL_VAR_SYMBOL);
6788 *p = '\0';
6789 vallen = val ? strlen(val) : 0;
6790 if (beg < 0) {
6791
6792 beg = (arith_t)vallen + beg;
6793 }
6794
6795 if (!val || beg < 0 || beg > vallen) {
6796
6797
6798
6799
6800 goto empty_result;
6801 }
6802 len = expand_and_evaluate_arith(exp_word, &errmsg);
6803 if (errmsg)
6804 goto empty_result;
6805 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
6806 debug_printf_varexp("from val:'%s'\n", val);
6807 if (len < 0) {
6808
6809 len = (arith_t)vallen - beg + len;
6810 if (len < 0)
6811 msg_and_die_if_script("%s: substring expression < 0", var);
6812 }
6813 if (len <= 0 || !val ) {
6814 empty_result:
6815 val = NULL;
6816 } else {
6817
6818
6819 if (len > INT_MAX)
6820 len = INT_MAX;
6821 val = to_be_freed = xstrndup(val + beg, len);
6822 }
6823 debug_printf_varexp("val:'%s'\n", val);
6824#else
6825 msg_and_die_if_script("malformed ${%s:...}", var);
6826 val = NULL;
6827#endif
6828 } else {
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880 int use_word = (!val || ((exp_save == ':') && !val[0]));
6881 if (exp_op == '+')
6882 use_word = !use_word;
6883 debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
6884 (exp_save == ':') ? "true" : "false", use_word);
6885 if (use_word) {
6886 if (exp_op == '+' || exp_op == '-') {
6887
6888
6889 n = encode_then_append_var_plusminus(output, n, exp_word,
6890 (arg0 & 0x80)
6891 );
6892 val = NULL;
6893 } else {
6894
6895
6896 to_be_freed = encode_then_expand_vararg(exp_word,
6897 !(arg0 & 0x80),
6898 0
6899 );
6900 if (to_be_freed)
6901 exp_word = to_be_freed;
6902 if (exp_op == '?') {
6903
6904 msg_and_die_if_script("%s: %s",
6905 var,
6906 exp_word[0]
6907 ? exp_word
6908 : "parameter null or not set"
6909
6910
6911 );
6912
6913
6914
6915
6916
6917
6918 } else {
6919 val = exp_word;
6920 }
6921 if (exp_op == '=') {
6922
6923 if (isdigit(var[0]) || var[0] == '#') {
6924
6925 msg_and_die_if_script("$%s: cannot assign in this way", var);
6926 val = NULL;
6927 } else {
6928 char *new_var = xasprintf("%s=%s", var, val);
6929 set_local_var(new_var, 0);
6930 }
6931 }
6932 }
6933 }
6934 }
6935
6936 *exp_saveptr = exp_save;
6937 }
6938
6939 arg[0] = arg0;
6940 *pp = p;
6941
6942 n = append_str_maybe_ifs_split(output, n, first_ch, val);
6943
6944 free(to_be_freed);
6945 return n;
6946}
6947
6948
6949
6950
6951
6952
6953static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6954{
6955
6956
6957
6958 char cant_be_null = 0;
6959 char *p;
6960
6961 debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg,
6962 !!(output->o_expflags & EXP_FLAG_SINGLEWORD));
6963 debug_print_list("expand_vars_to_list[0]", output, n);
6964
6965 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
6966 char first_ch;
6967#if ENABLE_FEATURE_SH_MATH
6968 char arith_buf[sizeof(arith_t)*3 + 2];
6969#endif
6970
6971 if (output->ended_in_ifs) {
6972 o_addchr(output, '\0');
6973 n = o_save_ptr(output, n);
6974 output->ended_in_ifs = 0;
6975 }
6976
6977 o_addblock(output, arg, p - arg);
6978 debug_print_list("expand_vars_to_list[1]", output, n);
6979 arg = ++p;
6980 p = strchr(p, SPECIAL_VAR_SYMBOL);
6981
6982
6983
6984
6985 first_ch = arg[0] | (output->o_expflags & EXP_FLAG_SINGLEWORD);
6986
6987
6988
6989
6990
6991 if ((first_ch & 0x7f) != '@')
6992 cant_be_null |= first_ch;
6993
6994 switch (first_ch & 0x7f) {
6995
6996 case '*':
6997 case '@': {
6998 int i;
6999 if (!G.global_argv[1])
7000 break;
7001 i = 1;
7002 cant_be_null |= first_ch;
7003 if (!(first_ch & 0x80)) {
7004 while (G.global_argv[i]) {
7005 n = expand_on_ifs(output, n, G.global_argv[i]);
7006 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
7007 if (G.global_argv[i++][0] && G.global_argv[i]) {
7008
7009
7010 o_addchr(output, '\0');
7011 debug_print_list("expand_vars_to_list[2]", output, n);
7012 n = o_save_ptr(output, n);
7013 debug_print_list("expand_vars_to_list[3]", output, n);
7014 }
7015 }
7016 } else
7017
7018
7019 if (first_ch == (char)('@'|0x80)
7020 && !(output->o_expflags & EXP_FLAG_SINGLEWORD)
7021 ) {
7022 while (1) {
7023 o_addQstr(output, G.global_argv[i]);
7024 if (++i >= G.global_argc)
7025 break;
7026 o_addchr(output, '\0');
7027 debug_print_list("expand_vars_to_list[4]", output, n);
7028 n = o_save_ptr(output, n);
7029 }
7030 } else {
7031 while (1) {
7032 o_addQstr(output, G.global_argv[i]);
7033 if (!G.global_argv[++i])
7034 break;
7035 if (G.ifs[0])
7036 o_addchr(output, G.ifs[0]);
7037 }
7038 output->has_quoted_part = 1;
7039 }
7040 break;
7041 }
7042 case SPECIAL_VAR_SYMBOL: {
7043
7044
7045 output->has_quoted_part = 1;
7046 cant_be_null = 0x80;
7047 arg++;
7048 break;
7049 }
7050 case SPECIAL_VAR_QUOTED_SVS:
7051
7052
7053 o_addchr(output, SPECIAL_VAR_SYMBOL);
7054 arg++;
7055 break;
7056#if ENABLE_HUSH_TICK
7057 case '`': {
7058
7059 o_string subst_result = NULL_O_STRING;
7060
7061 *p = '\0';
7062 arg++;
7063
7064
7065
7066 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
7067 G.last_exitcode = process_command_subs(&subst_result, arg);
7068 G.expand_exitcode = G.last_exitcode;
7069 debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data);
7070 n = append_str_maybe_ifs_split(output, n, first_ch, subst_result.data);
7071 o_free(&subst_result);
7072 break;
7073 }
7074#endif
7075#if ENABLE_FEATURE_SH_MATH
7076 case '+': {
7077
7078 arith_t res;
7079
7080 arg++;
7081 *p = '\0';
7082 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
7083 res = expand_and_evaluate_arith(arg, NULL);
7084 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
7085 sprintf(arith_buf, ARITH_FMT, res);
7086 if (res < 0
7087 && first_ch == (char)('+'|0x80)
7088
7089 ) {
7090
7091
7092
7093
7094 o_grow_by(output, 1);
7095 output->data[output->length++] = '\\';
7096 }
7097 o_addstr(output, arith_buf);
7098 break;
7099 }
7100#endif
7101 default:
7102
7103 n = expand_one_var(output, n, first_ch, arg, &p);
7104 break;
7105 }
7106
7107
7108
7109 if (*p != SPECIAL_VAR_SYMBOL)
7110 *p = SPECIAL_VAR_SYMBOL;
7111 arg = ++p;
7112 }
7113
7114 if (*arg) {
7115
7116 if (output->ended_in_ifs) {
7117 o_addchr(output, '\0');
7118 n = o_save_ptr(output, n);
7119 }
7120 debug_print_list("expand_vars_to_list[a]", output, n);
7121
7122
7123
7124 o_addstr(output, arg);
7125 debug_print_list("expand_vars_to_list[b]", output, n);
7126 } else
7127 if (output->length == o_get_last_ptr(output, n)
7128 && !(cant_be_null & 0x80)
7129 && !output->has_quoted_part
7130 ) {
7131 n--;
7132
7133 output->has_empty_slot = 1;
7134 }
7135
7136 return n;
7137}
7138
7139static char **expand_variables(char **argv, unsigned expflags)
7140{
7141 int n;
7142 char **list;
7143 o_string output = NULL_O_STRING;
7144
7145 output.o_expflags = expflags;
7146
7147 n = 0;
7148 for (;;) {
7149
7150 output.ended_in_ifs = 0;
7151 n = o_save_ptr(&output, n);
7152
7153 if (!*argv)
7154 break;
7155
7156
7157 n = expand_vars_to_list(&output, n, *argv++);
7158
7159 o_addchr(&output, '\0');
7160 }
7161 debug_print_list("expand_variables", &output, n);
7162
7163
7164 list = o_finalize_list(&output, n);
7165 debug_print_strings("expand_variables[1]", list);
7166 return list;
7167}
7168
7169static char **expand_strvec_to_strvec(char **argv)
7170{
7171 return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS);
7172}
7173
7174#if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB)
7175static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
7176{
7177 return expand_variables(argv, EXP_FLAG_SINGLEWORD);
7178}
7179#endif
7180
7181
7182
7183
7184
7185
7186
7187static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash)
7188{
7189#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
7190 const int do_unbackslash = 1;
7191 const int EXP_flags = EXP_FLAG_ESC_GLOB_CHARS;
7192#endif
7193 char *argv[2], **list;
7194
7195 debug_printf_expand("string_to_string<='%s'\n", str);
7196
7197
7198
7199
7200 if (!strchr(str, SPECIAL_VAR_SYMBOL) && !strchr(str, '\\')) {
7201
7202 debug_printf_expand("string_to_string(fast)=>'%s'\n", str);
7203 return xstrdup(str);
7204 }
7205
7206 argv[0] = (char*)str;
7207 argv[1] = NULL;
7208 list = expand_variables(argv, EXP_flags | EXP_FLAG_SINGLEWORD);
7209 if (!list[0]) {
7210
7211
7212
7213 ((char*)list)[0] = '\0';
7214 } else {
7215 if (HUSH_DEBUG)
7216 if (list[1])
7217 bb_simple_error_msg_and_die("BUG in varexp2");
7218
7219 overlapping_strcpy((char*)list, list[0]);
7220 if (do_unbackslash)
7221 unbackslash((char*)list);
7222 }
7223 debug_printf_expand("string_to_string=>'%s'\n", (char*)list);
7224 return (char*)list;
7225}
7226
7227#if 0
7228static char* expand_strvec_to_string(char **argv)
7229{
7230 char **list;
7231
7232 list = expand_variables(argv, EXP_FLAG_SINGLEWORD);
7233
7234 if (list[0]) {
7235 int n = 1;
7236 while (list[n]) {
7237 if (HUSH_DEBUG)
7238 if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
7239 bb_error_msg_and_die("BUG in varexp3");
7240
7241 list[n][-1] = ' ';
7242 n++;
7243 }
7244 }
7245 overlapping_strcpy((char*)list, list[0] ? list[0] : "");
7246 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
7247 return (char*)list;
7248}
7249#endif
7250
7251static char **expand_assignments(char **argv, int count)
7252{
7253 int i;
7254 char **p;
7255
7256 G.expanded_assignments = p = NULL;
7257
7258 for (i = 0; i < count; i++) {
7259 p = add_string_to_strings(p,
7260 expand_string_to_string(argv[i],
7261 EXP_FLAG_ESC_GLOB_CHARS,
7262 1
7263 )
7264 );
7265 G.expanded_assignments = p;
7266 }
7267 G.expanded_assignments = NULL;
7268 return p;
7269}
7270
7271
7272static void switch_off_special_sigs(unsigned mask)
7273{
7274 unsigned sig = 0;
7275 while ((mask >>= 1) != 0) {
7276 sig++;
7277 if (!(mask & 1))
7278 continue;
7279#if ENABLE_HUSH_TRAP
7280 if (G_traps) {
7281 if (G_traps[sig] && !G_traps[sig][0])
7282
7283 continue;
7284 free(G_traps[sig]);
7285 G_traps[sig] = NULL;
7286 }
7287#endif
7288
7289 install_sighandler(sig, SIG_DFL);
7290 }
7291}
7292
7293#if BB_MMU
7294
7295void re_execute_shell(char ***to_free, const char *s,
7296 char *g_argv0, char **g_argv,
7297 char **builtin_argv) NORETURN;
7298
7299static void reset_traps_to_defaults(void)
7300{
7301
7302
7303
7304 IF_HUSH_TRAP(unsigned sig;)
7305 unsigned mask;
7306
7307
7308
7309
7310
7311
7312 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask;
7313 if (!G_traps && !mask)
7314 return;
7315
7316
7317 switch_off_special_sigs(mask);
7318# if ENABLE_HUSH_JOB
7319 G_fatal_sig_mask = 0;
7320# endif
7321 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS;
7322
7323
7324
7325# if ENABLE_HUSH_TRAP
7326 if (!G_traps)
7327 return;
7328
7329
7330 for (sig = 0; sig < NSIG; sig++) {
7331 if (!G_traps[sig])
7332 continue;
7333 if (!G_traps[sig][0])
7334 continue;
7335
7336 free(G_traps[sig]);
7337 G_traps[sig] = NULL;
7338
7339 if (sig == 0)
7340 continue;
7341 install_sighandler(sig, pick_sighandler(sig));
7342 }
7343# endif
7344}
7345
7346#else
7347
7348static void re_execute_shell(char ***to_free, const char *s,
7349 char *g_argv0, char **g_argv,
7350 char **builtin_argv) NORETURN;
7351static void re_execute_shell(char ***to_free, const char *s,
7352 char *g_argv0, char **g_argv,
7353 char **builtin_argv)
7354{
7355# define NOMMU_HACK_FMT ("-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x"))
7356
7357 char param_buf[sizeof(NOMMU_HACK_FMT) + 2 * (sizeof(int)*6 + sizeof(long long)*1)];
7358 char *heredoc_argv[4];
7359 struct variable *cur;
7360# if ENABLE_HUSH_FUNCTIONS
7361 struct function *funcp;
7362# endif
7363 char **argv, **pp;
7364 unsigned cnt;
7365 unsigned long long empty_trap_mask;
7366
7367 if (!g_argv0) {
7368 argv = heredoc_argv;
7369 argv[0] = (char *) G.argv0_for_re_execing;
7370 argv[1] = (char *) "-<";
7371 argv[2] = (char *) s;
7372 argv[3] = NULL;
7373 pp = &argv[3];
7374 goto do_exec;
7375 }
7376
7377 cnt = 0;
7378 pp = builtin_argv;
7379 if (pp) while (*pp++)
7380 cnt++;
7381
7382 empty_trap_mask = 0;
7383 if (G_traps) {
7384 int sig;
7385 for (sig = 1; sig < NSIG; sig++) {
7386 if (G_traps[sig] && !G_traps[sig][0])
7387 empty_trap_mask |= 1LL << sig;
7388 }
7389 }
7390
7391 sprintf(param_buf, NOMMU_HACK_FMT
7392 , (unsigned) G.root_pid
7393 , (unsigned) G.root_ppid
7394 , (unsigned) G.last_bg_pid
7395 , (unsigned) G.last_exitcode
7396 , cnt
7397 , empty_trap_mask
7398 IF_HUSH_LOOPS(, G.depth_of_loop)
7399 );
7400# undef NOMMU_HACK_FMT
7401
7402
7403
7404 cnt += 6;
7405 for (cur = G.top_var; cur; cur = cur->next) {
7406 if (!cur->flg_export || cur->flg_read_only)
7407 cnt += 2;
7408 }
7409# if ENABLE_HUSH_FUNCTIONS
7410 for (funcp = G.top_func; funcp; funcp = funcp->next)
7411 cnt += 3;
7412# endif
7413 pp = g_argv;
7414 while (*pp++)
7415 cnt++;
7416 *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt);
7417 *pp++ = (char *) G.argv0_for_re_execing;
7418 *pp++ = param_buf;
7419 for (cur = G.top_var; cur; cur = cur->next) {
7420 if (strcmp(cur->varstr, hush_version_str) == 0)
7421 continue;
7422 if (cur->flg_read_only) {
7423 *pp++ = (char *) "-R";
7424 *pp++ = cur->varstr;
7425 } else if (!cur->flg_export) {
7426 *pp++ = (char *) "-V";
7427 *pp++ = cur->varstr;
7428 }
7429 }
7430# if ENABLE_HUSH_FUNCTIONS
7431 for (funcp = G.top_func; funcp; funcp = funcp->next) {
7432 *pp++ = (char *) "-F";
7433 *pp++ = funcp->name;
7434 *pp++ = funcp->body_as_string;
7435 }
7436# endif
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455 *pp++ = (char *) "-c";
7456 *pp++ = (char *) s;
7457 if (builtin_argv) {
7458 while (*++builtin_argv)
7459 *pp++ = *builtin_argv;
7460 *pp++ = (char *) "";
7461 }
7462 *pp++ = g_argv0;
7463 while (*g_argv)
7464 *pp++ = *g_argv++;
7465
7466 pp = environ;
7467
7468 do_exec:
7469 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
7470
7471 if (SPECIAL_JOBSTOP_SIGS != 0)
7472 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
7473 execve(bb_busybox_exec_path, argv, pp);
7474
7475 if (argv[0][0] == '/')
7476 execve(argv[0], argv, pp);
7477 xfunc_error_retval = 127;
7478 bb_simple_error_msg_and_die("can't re-execute the shell");
7479}
7480#endif
7481
7482
7483static int run_and_free_list(struct pipe *pi);
7484
7485
7486
7487
7488
7489
7490
7491static void parse_and_run_stream(struct in_str *inp, int end_trigger)
7492{
7493
7494
7495
7496
7497
7498
7499 bool empty = 1;
7500 while (1) {
7501 struct pipe *pipe_list;
7502
7503#if ENABLE_HUSH_INTERACTIVE
7504 if (end_trigger == ';') {
7505 G.promptmode = 0;
7506 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
7507 }
7508#endif
7509 pipe_list = parse_stream(NULL, NULL, inp, end_trigger);
7510 if (!pipe_list || pipe_list == ERR_PTR) {
7511
7512
7513
7514 if (pipe_list == ERR_PTR && end_trigger == ';') {
7515
7516 int ch = inp->last_char;
7517 while (ch != EOF && ch != '\n') {
7518
7519 ch = i_getch(inp);
7520 }
7521
7522 inp->p = NULL;
7523
7524 empty = 0;
7525 continue;
7526 }
7527 if (!pipe_list && empty)
7528 G.last_exitcode = 0;
7529 break;
7530 }
7531 debug_print_tree(pipe_list, 0);
7532 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
7533 run_and_free_list(pipe_list);
7534 empty = 0;
7535 if (G_flag_return_in_progress == 1)
7536 break;
7537 }
7538}
7539
7540static void parse_and_run_string(const char *s)
7541{
7542 struct in_str input;
7543
7544
7545 setup_string_in_str(&input, s);
7546 parse_and_run_stream(&input, '\0');
7547
7548}
7549
7550static void parse_and_run_file(HFILE *fp)
7551{
7552 struct in_str input;
7553 IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
7554
7555 IF_HUSH_LINENO_VAR(G.parse_lineno = 1;)
7556 setup_file_in_str(&input, fp);
7557 parse_and_run_stream(&input, ';');
7558 IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
7559}
7560
7561#if ENABLE_HUSH_TICK
7562static int generate_stream_from_string(const char *s, pid_t *pid_p)
7563{
7564 pid_t pid;
7565 int channel[2];
7566# if !BB_MMU
7567 char **to_free = NULL;
7568# endif
7569
7570 xpipe(channel);
7571 pid = BB_MMU ? xfork() : xvfork();
7572 if (pid == 0) {
7573 disable_restore_tty_pgrp_on_exit();
7574
7575
7576
7577
7578 bb_signals(0
7579 + (1 << SIGTSTP)
7580 + (1 << SIGTTIN)
7581 + (1 << SIGTTOU)
7582 , SIG_IGN);
7583 close(channel[0]);
7584 xmove_fd(channel[1], 1);
7585# if ENABLE_HUSH_TRAP
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620 s = skip_whitespace(s);
7621 if (is_prefixed_with(s, "trap")
7622 && skip_whitespace(s + 4)[0] == '\0'
7623 ) {
7624 static const char *const argv[] = { NULL, NULL };
7625 builtin_trap((char**)argv);
7626 fflush_all();
7627 _exit(0);
7628 }
7629# endif
7630# if BB_MMU
7631
7632 IF_HUSH_JOB(G.run_list_level = 1;)
7633 CLEAR_RANDOM_T(&G.random_gen);
7634 reset_traps_to_defaults();
7635 IF_HUSH_MODE_X(G.x_mode_depth++;)
7636
7637 parse_and_run_string(s);
7638 _exit(G.last_exitcode);
7639# else
7640
7641
7642
7643
7644
7645 re_execute_shell(&to_free,
7646 s,
7647 G.global_argv[0],
7648 G.global_argv + 1,
7649 NULL);
7650# endif
7651 }
7652
7653
7654 *pid_p = pid;
7655# if ENABLE_HUSH_FAST
7656 G.count_SIGCHLD++;
7657
7658
7659
7660# endif
7661 enable_restore_tty_pgrp_on_exit();
7662# if !BB_MMU
7663 free(to_free);
7664# endif
7665 close(channel[1]);
7666 return channel[0];
7667}
7668
7669
7670static int process_command_subs(o_string *dest, const char *s)
7671{
7672 FILE *fp;
7673 pid_t pid;
7674 int status, ch, eol_cnt;
7675
7676 fp = xfdopen_for_read(generate_stream_from_string(s, &pid));
7677
7678
7679 eol_cnt = 0;
7680 while ((ch = getc(fp)) != EOF) {
7681 if (ch == '\0')
7682 continue;
7683 if (ch == '\n') {
7684 eol_cnt++;
7685 continue;
7686 }
7687 while (eol_cnt) {
7688 o_addchr(dest, '\n');
7689 eol_cnt--;
7690 }
7691 o_addQchr(dest, ch);
7692 }
7693
7694 debug_printf("done reading from `cmd` pipe, closing it\n");
7695 fclose(fp);
7696
7697
7698
7699 safe_waitpid(pid, &status, 0);
7700 debug_printf("child exited. returning its exitcode:%d\n", WEXITSTATUS(status));
7701 return WEXITSTATUS(status);
7702}
7703#endif
7704
7705
7706static void setup_heredoc(struct redir_struct *redir)
7707{
7708 struct fd_pair pair;
7709 pid_t pid;
7710 int len, written;
7711
7712 const char *heredoc = redir->rd_filename;
7713 char *expanded;
7714#if !BB_MMU
7715 char **to_free;
7716#endif
7717
7718 expanded = NULL;
7719 if (!(redir->rd_dup & HEREDOC_QUOTED)) {
7720 expanded = encode_then_expand_string(heredoc);
7721 if (expanded)
7722 heredoc = expanded;
7723 }
7724 len = strlen(heredoc);
7725
7726 close(redir->rd_fd);
7727 xpiped_pair(pair);
7728 xmove_fd(pair.rd, redir->rd_fd);
7729
7730
7731
7732 ndelay_on(pair.wr);
7733 while (1) {
7734 written = write(pair.wr, heredoc, len);
7735 if (written <= 0)
7736 break;
7737 len -= written;
7738 if (len == 0) {
7739 close(pair.wr);
7740 free(expanded);
7741 return;
7742 }
7743 heredoc += written;
7744 }
7745 ndelay_off(pair.wr);
7746
7747
7748
7749
7750
7751
7752#if !BB_MMU
7753 to_free = NULL;
7754#endif
7755 pid = xvfork();
7756 if (pid == 0) {
7757
7758 disable_restore_tty_pgrp_on_exit();
7759 pid = BB_MMU ? xfork() : xvfork();
7760 if (pid != 0)
7761 _exit(0);
7762
7763 close(redir->rd_fd);
7764#if BB_MMU
7765 full_write(pair.wr, heredoc, len);
7766 _exit(0);
7767#else
7768
7769 xmove_fd(pair.wr, STDOUT_FILENO);
7770 re_execute_shell(&to_free, heredoc, NULL, NULL, NULL);
7771#endif
7772 }
7773
7774#if ENABLE_HUSH_FAST
7775 G.count_SIGCHLD++;
7776
7777#endif
7778 enable_restore_tty_pgrp_on_exit();
7779#if !BB_MMU
7780 free(to_free);
7781#endif
7782 close(pair.wr);
7783 free(expanded);
7784 wait(NULL);
7785}
7786
7787struct squirrel {
7788 int orig_fd;
7789 int moved_to;
7790
7791
7792};
7793
7794static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved)
7795{
7796 sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
7797 sq[i].orig_fd = orig;
7798 sq[i].moved_to = moved;
7799 sq[i+1].orig_fd = -1;
7800 return sq;
7801}
7802
7803static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7804{
7805 int moved_to;
7806 int i;
7807
7808 i = 0;
7809 if (sq) for (; sq[i].orig_fd >= 0; i++) {
7810
7811 if (fd == sq[i].moved_to) {
7812 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
7813 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
7814 if (sq[i].moved_to < 0)
7815 xfunc_die();
7816 return sq;
7817 }
7818 if (fd == sq[i].orig_fd) {
7819
7820 debug_printf_redir("redirect_fd %d: already moved\n", fd);
7821 return sq;
7822 }
7823 }
7824
7825
7826 moved_to = dup_CLOEXEC(fd, avoid_fd);
7827 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
7828 if (moved_to < 0 && errno != EBADF)
7829 xfunc_die();
7830 return append_squirrel(sq, i, fd, moved_to);
7831}
7832
7833static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
7834{
7835 int i;
7836
7837 i = 0;
7838 if (sq) for (; sq[i].orig_fd >= 0; i++) {
7839
7840 if (fd == sq[i].orig_fd) {
7841
7842
7843
7844
7845
7846
7847 debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
7848 return sq;
7849 }
7850 }
7851
7852 debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd);
7853 return append_squirrel(sq, i, fd, -1);
7854}
7855
7856
7857
7858
7859
7860static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7861{
7862 if (avoid_fd < 9)
7863 avoid_fd = 9;
7864
7865#if ENABLE_HUSH_INTERACTIVE
7866 if (fd != 0
7867 && fd == G_interactive_fd
7868 ) {
7869
7870 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd);
7871 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd);
7872 return 1;
7873 }
7874#endif
7875
7876
7877
7878 if (sqp == NULL) {
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890 return 0;
7891 }
7892
7893
7894 if (move_HFILEs_on_redirect(fd, avoid_fd))
7895 return 1;
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918 if (sqp == ERR_PTR) {
7919
7920
7921 return 0;
7922 }
7923
7924
7925 *sqp = add_squirrel(*sqp, fd, avoid_fd);
7926 return 0;
7927}
7928
7929static void restore_redirects(struct squirrel *sq)
7930{
7931 if (sq) {
7932 int i;
7933 for (i = 0; sq[i].orig_fd >= 0; i++) {
7934 if (sq[i].moved_to >= 0) {
7935
7936 debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd);
7937 xmove_fd(sq[i].moved_to, sq[i].orig_fd);
7938 } else {
7939
7940 debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
7941 close(sq[i].orig_fd);
7942 }
7943 }
7944 free(sq);
7945 }
7946 if (G.HFILE_stdin
7947 && G.HFILE_stdin->fd > STDIN_FILENO
7948
7949
7950
7951
7952 ) {
7953
7954
7955
7956
7957
7958
7959
7960 debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd);
7961 xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO);
7962 G.HFILE_stdin->fd = STDIN_FILENO;
7963 }
7964
7965
7966}
7967
7968#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
7969static void close_saved_fds_and_FILE_fds(void)
7970{
7971 if (G_interactive_fd)
7972 close(G_interactive_fd);
7973 close_all_HFILE_list();
7974}
7975#endif
7976
7977static int internally_opened_fd(int fd, struct squirrel *sq)
7978{
7979 int i;
7980
7981#if ENABLE_HUSH_INTERACTIVE
7982 if (fd == G_interactive_fd)
7983 return 1;
7984#endif
7985
7986 if (fd_in_HFILEs(fd))
7987 return 1;
7988
7989 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
7990 if (fd == sq[i].moved_to)
7991 return 1;
7992 }
7993 return 0;
7994}
7995
7996
7997
7998static int setup_redirects(struct command *prog, struct squirrel **sqp)
7999{
8000 struct redir_struct *redir;
8001
8002 for (redir = prog->redirects; redir; redir = redir->next) {
8003 int newfd;
8004 int closed;
8005
8006 if (redir->rd_type == REDIRECT_HEREDOC2) {
8007
8008 save_fd_on_redirect(redir->rd_fd, 0, sqp);
8009
8010
8011 debug_printf_redir("set heredoc '%s'\n",
8012 redir->rd_filename);
8013 setup_heredoc(redir);
8014 continue;
8015 }
8016
8017 if (redir->rd_dup == REDIRFD_TO_FILE) {
8018
8019 char *p;
8020 int mode;
8021
8022 if (redir->rd_filename == NULL) {
8023
8024
8025
8026
8027 syntax_error("invalid redirect");
8028 continue;
8029 }
8030 mode = redir_table[redir->rd_type].mode;
8031 p = expand_string_to_string(redir->rd_filename,
8032 EXP_FLAG_ESC_GLOB_CHARS, 1);
8033 newfd = open_or_warn(p, mode);
8034 free(p);
8035 if (newfd < 0) {
8036
8037
8038
8039
8040
8041 return 1;
8042 }
8043 if (newfd == redir->rd_fd && sqp) {
8044
8045
8046
8047
8048
8049 *sqp = add_squirrel_closed(*sqp, newfd);
8050 debug_printf_redir("redir to previously closed fd %d\n", newfd);
8051 }
8052 } else {
8053
8054 newfd = redir->rd_dup;
8055 }
8056
8057 if (newfd == redir->rd_fd)
8058 continue;
8059
8060
8061
8062
8063
8064 closed = save_fd_on_redirect(redir->rd_fd, newfd, sqp);
8065 if (newfd == REDIRFD_CLOSE) {
8066
8067 if (!closed) {
8068
8069
8070 close(redir->rd_fd);
8071 }
8072
8073
8074
8075
8076
8077 } else {
8078
8079 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) {
8080
8081
8082 newfd = -1;
8083 }
8084 xdup2(newfd, redir->rd_fd);
8085 if (redir->rd_dup == REDIRFD_TO_FILE)
8086
8087 close(newfd);
8088
8089 }
8090 }
8091 return 0;
8092}
8093
8094static char *find_in_path(const char *arg)
8095{
8096 char *ret = NULL;
8097 const char *PATH = get_local_var_value("PATH");
8098
8099 if (!PATH)
8100 return NULL;
8101
8102 while (1) {
8103 const char *end = strchrnul(PATH, ':');
8104 int sz = end - PATH;
8105
8106 free(ret);
8107 if (sz != 0) {
8108 ret = xasprintf("%.*s/%s", sz, PATH, arg);
8109 } else {
8110
8111
8112 ret = xstrdup(arg);
8113 }
8114 if (access(ret, F_OK) == 0)
8115 break;
8116
8117 if (*end == '\0') {
8118 free(ret);
8119 return NULL;
8120 }
8121 PATH = end + 1;
8122 }
8123
8124 return ret;
8125}
8126
8127static const struct built_in_command *find_builtin_helper(const char *name,
8128 const struct built_in_command *x,
8129 const struct built_in_command *end)
8130{
8131 while (x != end) {
8132 if (strcmp(name, x->b_cmd) != 0) {
8133 x++;
8134 continue;
8135 }
8136 debug_printf_exec("found builtin '%s'\n", name);
8137 return x;
8138 }
8139 return NULL;
8140}
8141static const struct built_in_command *find_builtin1(const char *name)
8142{
8143 return find_builtin_helper(name, bltins1, &bltins1[ARRAY_SIZE(bltins1)]);
8144}
8145static const struct built_in_command *find_builtin(const char *name)
8146{
8147 const struct built_in_command *x = find_builtin1(name);
8148 if (x)
8149 return x;
8150 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
8151}
8152
8153#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
8154static const char * FAST_FUNC get_builtin_name(int i)
8155{
8156 if ( i < ARRAY_SIZE(bltins1)) {
8157 return bltins1[i].b_cmd;
8158 }
8159 i -= ARRAY_SIZE(bltins1);
8160 if (i < ARRAY_SIZE(bltins2)) {
8161 return bltins2[i].b_cmd;
8162 }
8163 return NULL;
8164}
8165#endif
8166
8167static void remove_nested_vars(void)
8168{
8169 struct variable *cur;
8170 struct variable **cur_pp;
8171
8172 cur_pp = &G.top_var;
8173 while ((cur = *cur_pp) != NULL) {
8174 if (cur->var_nest_level <= G.var_nest_level) {
8175 cur_pp = &cur->next;
8176 continue;
8177 }
8178
8179 if (cur->flg_export) {
8180 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
8181 bb_unsetenv(cur->varstr);
8182 }
8183
8184 *cur_pp = cur->next;
8185
8186 if (!cur->max_len) {
8187 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
8188 free(cur->varstr);
8189 }
8190 free(cur);
8191 }
8192}
8193
8194static void enter_var_nest_level(void)
8195{
8196 G.var_nest_level++;
8197 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
8198
8199
8200
8201
8202
8203
8204
8205 if (G.var_nest_level > 0xff00)
8206 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
8207}
8208
8209static void leave_var_nest_level(void)
8210{
8211 G.var_nest_level--;
8212 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
8213 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
8214 bb_simple_error_msg_and_die("BUG: nesting underflow");
8215
8216 remove_nested_vars();
8217}
8218
8219#if ENABLE_HUSH_FUNCTIONS
8220static struct function **find_function_slot(const char *name)
8221{
8222 struct function *funcp;
8223 struct function **funcpp = &G.top_func;
8224
8225 while ((funcp = *funcpp) != NULL) {
8226 if (strcmp(name, funcp->name) == 0) {
8227 debug_printf_exec("found function '%s'\n", name);
8228 break;
8229 }
8230 funcpp = &funcp->next;
8231 }
8232 return funcpp;
8233}
8234
8235static ALWAYS_INLINE const struct function *find_function(const char *name)
8236{
8237 const struct function *funcp = *find_function_slot(name);
8238 return funcp;
8239}
8240
8241
8242static struct function *new_function(char *name)
8243{
8244 struct function **funcpp = find_function_slot(name);
8245 struct function *funcp = *funcpp;
8246
8247 if (funcp != NULL) {
8248 struct command *cmd = funcp->parent_cmd;
8249 debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd);
8250 if (!cmd) {
8251 debug_printf_exec("freeing & replacing function '%s'\n", funcp->name);
8252 free(funcp->name);
8253
8254
8255
8256 if (funcp->body) {
8257 free_pipe_list(funcp->body);
8258# if !BB_MMU
8259 free(funcp->body_as_string);
8260# endif
8261 }
8262 } else {
8263 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name);
8264 cmd->argv[0] = funcp->name;
8265 cmd->group = funcp->body;
8266# if !BB_MMU
8267 cmd->group_as_string = funcp->body_as_string;
8268# endif
8269 }
8270 } else {
8271 debug_printf_exec("remembering new function '%s'\n", name);
8272 funcp = *funcpp = xzalloc(sizeof(*funcp));
8273
8274 }
8275
8276 funcp->name = name;
8277 return funcp;
8278}
8279
8280# if ENABLE_HUSH_UNSET
8281static void unset_func(const char *name)
8282{
8283 struct function **funcpp = find_function_slot(name);
8284 struct function *funcp = *funcpp;
8285
8286 if (funcp != NULL) {
8287 debug_printf_exec("freeing function '%s'\n", funcp->name);
8288 *funcpp = funcp->next;
8289
8290
8291
8292
8293 if (funcp->body) {
8294 free_pipe_list(funcp->body);
8295 free(funcp->name);
8296# if !BB_MMU
8297 free(funcp->body_as_string);
8298# endif
8299 }
8300 free(funcp);
8301 }
8302}
8303# endif
8304
8305# if BB_MMU
8306#define exec_function(to_free, funcp, argv) \
8307 exec_function(funcp, argv)
8308# endif
8309static void exec_function(char ***to_free,
8310 const struct function *funcp,
8311 char **argv) NORETURN;
8312static void exec_function(char ***to_free,
8313 const struct function *funcp,
8314 char **argv)
8315{
8316# if BB_MMU
8317 int n;
8318
8319 argv[0] = G.global_argv[0];
8320 G.global_argv = argv;
8321 G.global_argc = n = 1 + string_array_len(argv + 1);
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338 G_flag_return_in_progress = -1;
8339 enter_var_nest_level();
8340 IF_HUSH_LOCAL(G.func_nest_level++;)
8341
8342
8343 n = run_list(funcp->body);
8344 _exit(n);
8345# else
8346
8347
8348
8349
8350 re_execute_shell(to_free,
8351 funcp->body_as_string,
8352 G.global_argv[0],
8353 argv + 1,
8354 NULL);
8355# endif
8356}
8357
8358static int run_function(const struct function *funcp, char **argv)
8359{
8360 int rc;
8361 save_arg_t sv;
8362 smallint sv_flg;
8363
8364 save_and_replace_G_args(&sv, argv);
8365
8366
8367 sv_flg = G_flag_return_in_progress;
8368 G_flag_return_in_progress = -1;
8369
8370
8371 IF_HUSH_LOCAL(enter_var_nest_level();)
8372 IF_HUSH_LOCAL(G.func_nest_level++;)
8373
8374
8375# if !BB_MMU
8376 if (!funcp->body) {
8377
8378 parse_and_run_string(funcp->body_as_string);
8379 rc = G.last_exitcode;
8380 } else
8381# endif
8382 {
8383 rc = run_list(funcp->body);
8384 }
8385
8386 IF_HUSH_LOCAL(G.func_nest_level--;)
8387 IF_HUSH_LOCAL(leave_var_nest_level();)
8388
8389 G_flag_return_in_progress = sv_flg;
8390# if ENABLE_HUSH_TRAP
8391 debug_printf_exec("G.return_exitcode=-1\n");
8392 G.return_exitcode = -1;
8393# endif
8394
8395 restore_G_args(&sv, argv);
8396
8397 return rc;
8398}
8399#endif
8400
8401
8402#if BB_MMU
8403#define exec_builtin(to_free, x, argv) \
8404 exec_builtin(x, argv)
8405#else
8406#define exec_builtin(to_free, x, argv) \
8407 exec_builtin(to_free, argv)
8408#endif
8409static void exec_builtin(char ***to_free,
8410 const struct built_in_command *x,
8411 char **argv) NORETURN;
8412static void exec_builtin(char ***to_free,
8413 const struct built_in_command *x,
8414 char **argv)
8415{
8416#if BB_MMU
8417 int rcode;
8418
8419 rcode = x->b_function(argv);
8420 fflush_all();
8421 _exit(rcode);
8422#else
8423 fflush_all();
8424
8425
8426
8427 re_execute_shell(to_free,
8428 argv[0],
8429 G.global_argv[0],
8430 G.global_argv + 1,
8431 argv);
8432#endif
8433}
8434
8435
8436static void execvp_or_die(char **argv) NORETURN;
8437static void execvp_or_die(char **argv)
8438{
8439 int e;
8440 debug_printf_exec("execing '%s'\n", argv[0]);
8441
8442 if (SPECIAL_JOBSTOP_SIGS != 0)
8443 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
8444 execvp(argv[0], argv);
8445 e = 2;
8446 if (errno == EACCES) e = 126;
8447 if (errno == ENOENT) e = 127;
8448 bb_perror_msg("can't execute '%s'", argv[0]);
8449 _exit(e);
8450}
8451
8452#if ENABLE_HUSH_MODE_X
8453static void x_mode_print_optionally_squoted(const char *str)
8454{
8455 unsigned len;
8456 const char *cp;
8457
8458 cp = str;
8459
8460
8461
8462 if (str[strcspn(str, "\\\"'`$(){}[]<>;#&|~*?!^"
8463 " " "\001\002\003\004\005\006\007"
8464 "\010\011\012\013\014\015\016\017"
8465 "\020\021\022\023\024\025\026\027"
8466 "\030\031\032\033\034\035\036\037"
8467 )
8468 ] == '\0'
8469 ) {
8470
8471 x_mode_addstr(str);
8472 return;
8473 }
8474
8475 cp = str;
8476 for (;;) {
8477
8478 len = (int)(strchrnul(cp, '\'') - cp);
8479 if (len != 0) {
8480 x_mode_addchr('\'');
8481 x_mode_addblock(cp, len);
8482 x_mode_addchr('\'');
8483 cp += len;
8484 }
8485 if (*cp == '\0')
8486 break;
8487
8488 x_mode_addchr('\\');
8489 x_mode_addchr('\'');
8490 cp++;
8491 }
8492}
8493static void dump_cmd_in_x_mode(char **argv)
8494{
8495 if (G_x_mode && argv) {
8496 unsigned n;
8497
8498
8499 x_mode_prefix();
8500 n = 0;
8501 while (argv[n]) {
8502 x_mode_addchr(' ');
8503 if (argv[n][0] == '\0') {
8504 x_mode_addchr('\'');
8505 x_mode_addchr('\'');
8506 } else {
8507 x_mode_print_optionally_squoted(argv[n]);
8508 }
8509 n++;
8510 }
8511 x_mode_flush();
8512 }
8513}
8514#else
8515# define dump_cmd_in_x_mode(argv) ((void)0)
8516#endif
8517
8518#if ENABLE_HUSH_COMMAND
8519static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
8520{
8521 char *to_free;
8522
8523 if (!opt_vV)
8524 return;
8525
8526 to_free = NULL;
8527 if (!explanation) {
8528 char *path = getenv("PATH");
8529 explanation = to_free = find_executable(cmd, &path);
8530 if (!explanation)
8531 _exit(1);
8532 if (opt_vV != 'V')
8533 cmd = to_free;
8534 }
8535 printf((opt_vV == 'V') ? "%s is %s\n" : "%s\n", cmd, explanation);
8536 free(to_free);
8537 fflush_all();
8538 _exit(0);
8539}
8540#else
8541# define if_command_vV_print_and_exit(a,b,c) ((void)0)
8542#endif
8543
8544#if BB_MMU
8545#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
8546 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
8547#define pseudo_exec(nommu_save, command, argv_expanded) \
8548 pseudo_exec(command, argv_expanded)
8549#endif
8550
8551
8552
8553
8554
8555
8556
8557static void pseudo_exec_argv(nommu_save_t *nommu_save,
8558 char **argv, int assignment_cnt,
8559 char **argv_expanded) NORETURN;
8560static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
8561 char **argv, int assignment_cnt,
8562 char **argv_expanded)
8563{
8564 const struct built_in_command *x;
8565 struct variable **sv_shadowed;
8566 char **new_env;
8567 IF_HUSH_COMMAND(char opt_vV = 0;)
8568 IF_HUSH_FUNCTIONS(const struct function *funcp;)
8569
8570 new_env = expand_assignments(argv, assignment_cnt);
8571 dump_cmd_in_x_mode(new_env);
8572
8573 if (!argv[assignment_cnt]) {
8574
8575
8576
8577
8578 free_strings(new_env);
8579 _exit(EXIT_SUCCESS);
8580 }
8581
8582 sv_shadowed = G.shadowed_vars_pp;
8583#if BB_MMU
8584 G.shadowed_vars_pp = NULL;
8585#else
8586 G.shadowed_vars_pp = &nommu_save->old_vars;
8587 G.var_nest_level++;
8588#endif
8589 set_vars_and_save_old(new_env);
8590 G.shadowed_vars_pp = sv_shadowed;
8591
8592 if (argv_expanded) {
8593 argv = argv_expanded;
8594 } else {
8595 argv = expand_strvec_to_strvec(argv + assignment_cnt);
8596#if !BB_MMU
8597 nommu_save->argv = argv;
8598#endif
8599 }
8600 dump_cmd_in_x_mode(argv);
8601
8602#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
8603 if (strchr(argv[0], '/') != NULL)
8604 goto skip;
8605#endif
8606
8607#if ENABLE_HUSH_FUNCTIONS
8608
8609 funcp = find_function(argv[0]);
8610 if (funcp)
8611 exec_function(&nommu_save->argv_from_re_execing, funcp, argv);
8612#endif
8613
8614#if ENABLE_HUSH_COMMAND
8615
8616
8617
8618
8619 while (strcmp(argv[0], "command") == 0 && argv[1]) {
8620 char *p;
8621
8622 argv++;
8623 p = *argv;
8624 if (p[0] != '-' || !p[1])
8625 continue;
8626
8627 for (;;) {
8628 p++;
8629 switch (*p) {
8630 case '\0':
8631 argv++;
8632 p = *argv;
8633 if (p[0] != '-' || !p[1])
8634 goto after_opts;
8635 continue;
8636 case 'v':
8637 case 'V':
8638 opt_vV = *p;
8639 continue;
8640 default:
8641 bb_error_msg_and_die("%s: %s: invalid option", "command", argv[0]);
8642 }
8643 }
8644 }
8645 after_opts:
8646# if ENABLE_HUSH_FUNCTIONS
8647 if (opt_vV && find_function(argv[0]))
8648 if_command_vV_print_and_exit(opt_vV, argv[0], "a function");
8649# endif
8650#endif
8651
8652
8653
8654
8655
8656
8657
8658
8659
8660
8661
8662 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
8663 if (x) {
8664 if_command_vV_print_and_exit(opt_vV, argv[0], "a shell builtin");
8665 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
8666 }
8667
8668#if ENABLE_FEATURE_SH_STANDALONE
8669
8670 {
8671 int a = find_applet_by_name(argv[0]);
8672 if (a >= 0) {
8673 if_command_vV_print_and_exit(opt_vV, argv[0], "an applet");
8674# if BB_MMU
8675 if (APPLET_IS_NOEXEC(a)) {
8676
8677
8678
8679
8680 close_saved_fds_and_FILE_fds();
8681
8682
8683
8684
8685
8686
8687 switch_off_special_sigs(G.special_sig_mask);
8688 debug_printf_exec("running applet '%s'\n", argv[0]);
8689 run_noexec_applet_and_exit(a, argv[0], argv);
8690 }
8691# endif
8692
8693 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
8694
8695 if (SPECIAL_JOBSTOP_SIGS != 0)
8696 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
8697 execv(bb_busybox_exec_path, argv);
8698
8699
8700 }
8701 }
8702#endif
8703
8704#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
8705 skip:
8706#endif
8707 if_command_vV_print_and_exit(opt_vV, argv[0], NULL);
8708 execvp_or_die(argv);
8709}
8710
8711
8712
8713static void pseudo_exec(nommu_save_t *nommu_save,
8714 struct command *command,
8715 char **argv_expanded) NORETURN;
8716static void pseudo_exec(nommu_save_t *nommu_save,
8717 struct command *command,
8718 char **argv_expanded)
8719{
8720#if ENABLE_HUSH_FUNCTIONS
8721 if (command->cmd_type == CMD_FUNCDEF) {
8722
8723
8724
8725 _exit(0);
8726 }
8727#endif
8728
8729 if (command->argv) {
8730 pseudo_exec_argv(nommu_save, command->argv,
8731 command->assignment_cnt, argv_expanded);
8732 }
8733
8734 if (command->group) {
8735
8736
8737
8738
8739
8740
8741#if BB_MMU
8742 int rcode;
8743 debug_printf_exec("pseudo_exec: run_list\n");
8744 reset_traps_to_defaults();
8745 rcode = run_list(command->group);
8746
8747
8748 _exit(rcode);
8749#else
8750 re_execute_shell(&nommu_save->argv_from_re_execing,
8751 command->group_as_string,
8752 G.global_argv[0],
8753 G.global_argv + 1,
8754 NULL);
8755#endif
8756 }
8757
8758
8759 debug_printf_exec("pseudo_exec'ed null command\n");
8760 _exit(EXIT_SUCCESS);
8761}
8762
8763#if ENABLE_HUSH_JOB
8764static const char *get_cmdtext(struct pipe *pi)
8765{
8766 char **argv;
8767 char *p;
8768 int len;
8769
8770
8771
8772
8773 if (pi->cmdtext)
8774 return pi->cmdtext;
8775
8776 argv = pi->cmds[0].argv;
8777 if (!argv) {
8778 pi->cmdtext = xzalloc(1);
8779 return pi->cmdtext;
8780 }
8781 len = 0;
8782 do {
8783 len += strlen(*argv) + 1;
8784 } while (*++argv);
8785 p = xmalloc(len);
8786 pi->cmdtext = p;
8787 argv = pi->cmds[0].argv;
8788 do {
8789 p = stpcpy(p, *argv);
8790 *p++ = ' ';
8791 } while (*++argv);
8792 p[-1] = '\0';
8793 return pi->cmdtext;
8794}
8795
8796static void remove_job_from_table(struct pipe *pi)
8797{
8798 struct pipe *prev_pipe;
8799
8800 if (pi == G.job_list) {
8801 G.job_list = pi->next;
8802 } else {
8803 prev_pipe = G.job_list;
8804 while (prev_pipe->next != pi)
8805 prev_pipe = prev_pipe->next;
8806 prev_pipe->next = pi->next;
8807 }
8808 G.last_jobid = 0;
8809 if (G.job_list)
8810 G.last_jobid = G.job_list->jobid;
8811}
8812
8813static void delete_finished_job(struct pipe *pi)
8814{
8815 remove_job_from_table(pi);
8816 free_pipe(pi);
8817}
8818
8819static void clean_up_last_dead_job(void)
8820{
8821 if (G.job_list && !G.job_list->alive_cmds)
8822 delete_finished_job(G.job_list);
8823}
8824
8825static void insert_job_into_table(struct pipe *pi)
8826{
8827 struct pipe *job, **jobp;
8828 int i;
8829
8830 clean_up_last_dead_job();
8831
8832
8833 i = 0;
8834 jobp = &G.job_list;
8835 while ((job = *jobp) != NULL) {
8836 if (job->jobid > i)
8837 i = job->jobid;
8838 jobp = &job->next;
8839 }
8840 pi->jobid = i + 1;
8841
8842
8843 job = *jobp = xmemdup(pi, sizeof(*pi));
8844 job->next = NULL;
8845 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
8846
8847 for (i = 0; i < pi->num_cmds; i++) {
8848 job->cmds[i].pid = pi->cmds[i].pid;
8849
8850 }
8851 job->cmdtext = xstrdup(get_cmdtext(pi));
8852
8853 if (G_interactive_fd)
8854 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext);
8855 G.last_jobid = job->jobid;
8856}
8857#endif
8858
8859static int job_exited_or_stopped(struct pipe *pi)
8860{
8861 int rcode, i;
8862
8863 if (pi->alive_cmds != pi->stopped_cmds)
8864 return -1;
8865
8866
8867 rcode = 0;
8868 i = pi->num_cmds;
8869 while (--i >= 0) {
8870 rcode = pi->cmds[i].cmd_exitcode;
8871
8872
8873 if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0)
8874 break;
8875 }
8876 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
8877 return rcode;
8878}
8879
8880static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8881{
8882#if ENABLE_HUSH_JOB
8883 struct pipe *pi;
8884#endif
8885 int i, dead;
8886
8887 dead = WIFEXITED(status) || WIFSIGNALED(status);
8888
8889#if DEBUG_JOBS
8890 if (WIFSTOPPED(status))
8891 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n",
8892 childpid, WSTOPSIG(status), WEXITSTATUS(status));
8893 if (WIFSIGNALED(status))
8894 debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n",
8895 childpid, WTERMSIG(status), WEXITSTATUS(status));
8896 if (WIFEXITED(status))
8897 debug_printf_jobs("pid %d exited, exitcode %d\n",
8898 childpid, WEXITSTATUS(status));
8899#endif
8900
8901 if (fg_pipe) {
8902 i = fg_pipe->num_cmds;
8903
8904 while (--i >= 0) {
8905 int rcode;
8906
8907 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid);
8908 if (fg_pipe->cmds[i].pid != childpid)
8909 continue;
8910 if (dead) {
8911 int ex;
8912 fg_pipe->cmds[i].pid = 0;
8913 fg_pipe->alive_cmds--;
8914 ex = WEXITSTATUS(status);
8915
8916
8917
8918
8919 if (WIFSIGNALED(status)) {
8920 int sig = WTERMSIG(status);
8921#if ENABLE_HUSH_JOB
8922 if (G.run_list_level == 1
8923
8924
8925
8926 && i == fg_pipe->num_cmds-1
8927 ) {
8928
8929 puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig));
8930 }
8931#endif
8932
8933
8934
8935
8936 ex = 128 | sig;
8937 }
8938 fg_pipe->cmds[i].cmd_exitcode = ex;
8939 } else {
8940 fg_pipe->stopped_cmds++;
8941 }
8942 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n",
8943 fg_pipe->alive_cmds, fg_pipe->stopped_cmds);
8944 rcode = job_exited_or_stopped(fg_pipe);
8945 if (rcode >= 0) {
8946
8947
8948
8949 if (G_interactive_fd) {
8950#if ENABLE_HUSH_JOB
8951 if (fg_pipe->alive_cmds != 0)
8952 insert_job_into_table(fg_pipe);
8953#endif
8954 return rcode;
8955 }
8956 if (fg_pipe->alive_cmds == 0)
8957 return rcode;
8958 }
8959
8960 return -1;
8961 }
8962
8963 }
8964
8965#if ENABLE_HUSH_JOB
8966
8967
8968 for (pi = G.job_list; pi; pi = pi->next) {
8969 for (i = 0; i < pi->num_cmds; i++) {
8970 if (pi->cmds[i].pid == childpid)
8971 goto found_pi_and_prognum;
8972 }
8973 }
8974
8975 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
8976 return -1;
8977
8978 found_pi_and_prognum:
8979 if (dead) {
8980
8981 int rcode = WEXITSTATUS(status);
8982 if (WIFSIGNALED(status))
8983
8984 rcode = 128 | WTERMSIG(status);
8985 pi->cmds[i].cmd_exitcode = rcode;
8986 if (G.last_bg_pid == pi->cmds[i].pid)
8987 G.last_bg_pid_exitcode = rcode;
8988 pi->cmds[i].pid = 0;
8989 pi->alive_cmds--;
8990 if (!pi->alive_cmds) {
8991# if ENABLE_HUSH_BASH_COMPAT
8992 G.dead_job_exitcode = job_exited_or_stopped(pi);
8993# endif
8994 if (G_interactive_fd) {
8995 printf(JOB_STATUS_FORMAT, pi->jobid,
8996 "Done", pi->cmdtext);
8997 delete_finished_job(pi);
8998 } else {
8999
9000
9001
9002
9003
9004
9005
9006
9007 if (pi != G.job_list)
9008 delete_finished_job(pi);
9009 }
9010 }
9011 } else {
9012
9013 pi->stopped_cmds++;
9014 }
9015#endif
9016 return -1;
9017}
9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029
9030
9031
9032
9033
9034static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid)
9035{
9036 int attributes;
9037 int status;
9038 int rcode = 0;
9039
9040 debug_printf_jobs("checkjobs %p\n", fg_pipe);
9041
9042 attributes = WUNTRACED;
9043 if (fg_pipe == NULL)
9044 attributes |= WNOHANG;
9045
9046 errno = 0;
9047#if ENABLE_HUSH_FAST
9048 if (G.handled_SIGCHLD == G.count_SIGCHLD) {
9049
9050
9051
9052
9053 if (!G.we_have_children) {
9054 errno = ECHILD;
9055 return -1;
9056 }
9057 if (fg_pipe == NULL) {
9058
9059
9060 return 0;
9061 }
9062
9063 }
9064#endif
9065
9066
9067
9068
9069
9070
9071
9072
9073
9074 while (1) {
9075 pid_t childpid;
9076#if ENABLE_HUSH_FAST
9077 int i;
9078 i = G.count_SIGCHLD;
9079#endif
9080 childpid = waitpid(-1, &status, attributes);
9081 if (childpid <= 0) {
9082 if (childpid && errno != ECHILD)
9083 bb_simple_perror_msg("waitpid");
9084#if ENABLE_HUSH_FAST
9085 else {
9086 G.we_have_children = (childpid == 0);
9087 G.handled_SIGCHLD = i;
9088
9089 }
9090#endif
9091
9092 rcode = childpid;
9093 break;
9094 }
9095 rcode = process_wait_result(fg_pipe, childpid, status);
9096 if (rcode >= 0) {
9097
9098 break;
9099 }
9100 if (childpid == waitfor_pid) {
9101 debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status);
9102 rcode = WEXITSTATUS(status);
9103 if (WIFSIGNALED(status))
9104 rcode = 128 | WTERMSIG(status);
9105 if (WIFSTOPPED(status))
9106
9107 rcode = 128 | WSTOPSIG(status);
9108 rcode++;
9109 break;
9110 }
9111#if ENABLE_HUSH_BASH_COMPAT
9112 if (-1 == waitfor_pid
9113 && G.dead_job_exitcode >= 0
9114 ) {
9115 debug_printf_exec("waitfor_pid:-1\n");
9116 rcode = G.dead_job_exitcode + 1;
9117 break;
9118 }
9119#endif
9120
9121
9122 }
9123
9124 return rcode;
9125}
9126
9127#if ENABLE_HUSH_JOB
9128static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
9129{
9130 pid_t p;
9131 int rcode = checkjobs(fg_pipe, 0 );
9132 if (G_saved_tty_pgrp) {
9133
9134 p = getpgrp();
9135 debug_printf_jobs("fg'ing ourself: getpgrp()=%d\n", (int)p);
9136 tcsetpgrp(G_interactive_fd, p);
9137 }
9138 return rcode;
9139}
9140#endif
9141
9142
9143
9144
9145
9146
9147
9148
9149
9150
9151
9152
9153
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168#if !ENABLE_HUSH_MODE_X
9169#define redirect_and_varexp_helper(command, sqp, argv_expanded) \
9170 redirect_and_varexp_helper(command, sqp)
9171#endif
9172static int redirect_and_varexp_helper(
9173 struct command *command,
9174 struct squirrel **sqp,
9175 char **argv_expanded)
9176{
9177
9178
9179
9180
9181 char **new_env = expand_assignments(command->argv, command->assignment_cnt);
9182 dump_cmd_in_x_mode(new_env);
9183 dump_cmd_in_x_mode(argv_expanded);
9184
9185 set_vars_and_save_old(new_env);
9186
9187 return setup_redirects(command, sqp);
9188}
9189static NOINLINE int run_pipe(struct pipe *pi)
9190{
9191 static const char *const null_ptr = NULL;
9192
9193 int cmd_no;
9194 int next_infd;
9195 struct command *command;
9196 char **argv_expanded;
9197 char **argv;
9198 struct squirrel *squirrel = NULL;
9199 int rcode;
9200
9201 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
9202 debug_enter();
9203
9204
9205
9206
9207 if (G.ifs_whitespace != G.ifs)
9208 free(G.ifs_whitespace);
9209 G.ifs = get_local_var_value("IFS");
9210 if (G.ifs) {
9211 char *p;
9212 G.ifs_whitespace = (char*)G.ifs;
9213 p = skip_whitespace(G.ifs);
9214 if (*p) {
9215
9216 char *d;
9217 int len = p - G.ifs;
9218 p = skip_non_whitespace(p);
9219 G.ifs_whitespace = xmalloc(len + strlen(p) + 1);
9220 d = mempcpy(G.ifs_whitespace, G.ifs, len);
9221 while (*p) {
9222 if (isspace(*p))
9223 *d++ = *p;
9224 p++;
9225 }
9226 *d = '\0';
9227 }
9228 } else {
9229 G.ifs = defifs;
9230 G.ifs_whitespace = (char*)G.ifs;
9231 }
9232
9233 IF_HUSH_JOB(pi->pgrp = -1;)
9234 pi->stopped_cmds = 0;
9235 command = &pi->cmds[0];
9236 argv_expanded = NULL;
9237
9238 if (pi->num_cmds != 1
9239 || pi->followup == PIPE_BG
9240 || command->cmd_type == CMD_SUBSHELL
9241 ) {
9242 goto must_fork;
9243 }
9244
9245 pi->alive_cmds = 1;
9246
9247 debug_printf_exec(": group:%p argv:'%s'\n",
9248 command->group, command->argv ? command->argv[0] : "NONE");
9249
9250 if (command->group) {
9251#if ENABLE_HUSH_FUNCTIONS
9252 if (command->cmd_type == CMD_FUNCDEF) {
9253
9254 struct function *funcp;
9255
9256 funcp = new_function(command->argv[0]);
9257
9258 funcp->body = command->group;
9259# if !BB_MMU
9260 funcp->body_as_string = command->group_as_string;
9261 command->group_as_string = NULL;
9262# endif
9263 command->group = NULL;
9264 command->argv[0] = NULL;
9265 debug_printf_exec("cmd %p has child func at %p\n", command, funcp);
9266 funcp->parent_cmd = command;
9267 command->child_func = funcp;
9268
9269 debug_printf_exec("run_pipe: return EXIT_SUCCESS\n");
9270 debug_leave();
9271 return EXIT_SUCCESS;
9272 }
9273#endif
9274
9275 debug_printf_exec("non-subshell group\n");
9276 rcode = 1;
9277 if (setup_redirects(command, &squirrel) == 0) {
9278 debug_printf_exec(": run_list\n");
9279
9280
9281
9282
9283
9284
9285 rcode = run_list(command->group) & 0xff;
9286 }
9287 restore_redirects(squirrel);
9288 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9289 debug_leave();
9290 debug_printf_exec("run_pipe: return %d\n", rcode);
9291 return rcode;
9292 }
9293
9294 argv = command->argv ? command->argv : (char **) &null_ptr;
9295 {
9296 const struct built_in_command *x;
9297 IF_HUSH_FUNCTIONS(const struct function *funcp;)
9298 IF_NOT_HUSH_FUNCTIONS(enum { funcp = 0 };)
9299 struct variable **sv_shadowed;
9300 struct variable *old_vars;
9301
9302#if ENABLE_HUSH_LINENO_VAR
9303 G.execute_lineno = command->lineno;
9304#endif
9305
9306 if (argv[command->assignment_cnt] == NULL) {
9307
9308
9309
9310
9311 unsigned i;
9312 G.expand_exitcode = 0;
9313 only_assignments:
9314 rcode = setup_redirects(command, &squirrel);
9315 restore_redirects(squirrel);
9316
9317
9318 i = 0;
9319 while (i < command->assignment_cnt) {
9320 char *p = expand_string_to_string(argv[i],
9321 EXP_FLAG_ESC_GLOB_CHARS,
9322 1
9323 );
9324#if ENABLE_HUSH_MODE_X
9325 if (G_x_mode) {
9326 char *eq;
9327 if (i == 0)
9328 x_mode_prefix();
9329 x_mode_addchr(' ');
9330 eq = strchrnul(p, '=');
9331 if (*eq) eq++;
9332 x_mode_addblock(p, (eq - p));
9333 x_mode_print_optionally_squoted(eq);
9334 x_mode_flush();
9335 }
9336#endif
9337 debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
9338 if (set_local_var(p, 0)) {
9339
9340 rcode = 1;
9341 }
9342 i++;
9343 }
9344
9345
9346
9347
9348
9349
9350
9351 if (rcode == 0)
9352 rcode = G.expand_exitcode;
9353 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9354 debug_leave();
9355 debug_printf_exec("run_pipe: return %d\n", rcode);
9356 return rcode;
9357 }
9358
9359
9360#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
9361 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB)
9362 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
9363 else
9364#endif
9365#if defined(CMD_SINGLEWORD_NOGLOB)
9366 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB)
9367 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
9368 else
9369#endif
9370 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
9371
9372
9373 if (!argv_expanded[0]) {
9374 free(argv_expanded);
9375
9376 G.expand_exitcode = G.last_exitcode;
9377 goto only_assignments;
9378 }
9379
9380 old_vars = NULL;
9381 sv_shadowed = G.shadowed_vars_pp;
9382
9383
9384 IF_HUSH_FUNCTIONS(funcp = find_function(argv_expanded[0]);)
9385 IF_HUSH_FUNCTIONS(x = NULL;)
9386 IF_HUSH_FUNCTIONS(if (!funcp))
9387 x = find_builtin(argv_expanded[0]);
9388 if (x || funcp) {
9389 if (x && x->b_function == builtin_exec && argv_expanded[1] == NULL) {
9390 debug_printf("exec with redirects only\n");
9391
9392
9393
9394
9395
9396 enter_var_nest_level();
9397 G.shadowed_vars_pp = &old_vars;
9398 rcode = redirect_and_varexp_helper(command,
9399 ERR_PTR,
9400 argv_expanded
9401 );
9402 G.shadowed_vars_pp = sv_shadowed;
9403
9404
9405 goto clean_up_and_ret1;
9406 }
9407
9408
9409
9410
9411 enter_var_nest_level();
9412
9413
9414
9415
9416 G.shadowed_vars_pp = &old_vars;
9417 rcode = redirect_and_varexp_helper(command, &squirrel, argv_expanded);
9418 if (rcode == 0) {
9419 if (!funcp) {
9420
9421
9422
9423
9424
9425
9426 G.shadowed_vars_pp = sv_shadowed;
9427
9428 debug_printf_exec(": builtin '%s' '%s'...\n",
9429 x->b_cmd, argv_expanded[1]);
9430 fflush_all();
9431 rcode = x->b_function(argv_expanded) & 0xff;
9432 fflush_all();
9433 }
9434#if ENABLE_HUSH_FUNCTIONS
9435 else {
9436 debug_printf_exec(": function '%s' '%s'...\n",
9437 funcp->name, argv_expanded[1]);
9438 rcode = run_function(funcp, argv_expanded) & 0xff;
9439
9440
9441
9442
9443
9444 G.shadowed_vars_pp = sv_shadowed;
9445 }
9446#endif
9447 }
9448 } else
9449 if (ENABLE_FEATURE_SH_NOFORK && NUM_APPLETS > 1) {
9450 int n = find_applet_by_name(argv_expanded[0]);
9451 if (n < 0 || !APPLET_IS_NOFORK(n))
9452 goto must_fork;
9453
9454 enter_var_nest_level();
9455
9456 G.shadowed_vars_pp = &old_vars;
9457 rcode = redirect_and_varexp_helper(command, &squirrel, argv_expanded);
9458 G.shadowed_vars_pp = sv_shadowed;
9459
9460 if (rcode == 0) {
9461 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
9462 argv_expanded[0], argv_expanded[1]);
9463
9464
9465
9466
9467
9468
9469
9470
9471 rcode = run_nofork_applet(n, argv_expanded);
9472 }
9473 } else
9474 goto must_fork;
9475
9476 restore_redirects(squirrel);
9477 clean_up_and_ret1:
9478 leave_var_nest_level();
9479 add_vars(old_vars);
9480
9481
9482
9483
9484
9485 if (!funcp) {
9486
9487
9488
9489
9490
9491
9492
9493
9494
9495
9496 if (sigismember(&G.pending_set, SIGINT))
9497 rcode = 128 | SIGINT;
9498 }
9499 free(argv_expanded);
9500 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
9501 debug_leave();
9502 debug_printf_exec("run_pipe return %d\n", rcode);
9503 return rcode;
9504 }
9505
9506 must_fork:
9507
9508
9509
9510
9511
9512 pi->alive_cmds = 0;
9513 next_infd = 0;
9514
9515 cmd_no = 0;
9516 while (cmd_no < pi->num_cmds) {
9517 struct fd_pair pipefds;
9518#if !BB_MMU
9519 int sv_var_nest_level = G.var_nest_level;
9520 volatile nommu_save_t nommu_save;
9521 nommu_save.old_vars = NULL;
9522 nommu_save.argv = NULL;
9523 nommu_save.argv_from_re_execing = NULL;
9524#endif
9525 command = &pi->cmds[cmd_no];
9526 cmd_no++;
9527 if (command->argv) {
9528 debug_printf_exec(": pipe member '%s' '%s'...\n",
9529 command->argv[0], command->argv[1]);
9530 } else {
9531 debug_printf_exec(": pipe member with no argv\n");
9532 }
9533
9534
9535 pipefds.rd = 0;
9536 pipefds.wr = 1;
9537 if (cmd_no < pi->num_cmds)
9538 xpiped_pair(pipefds);
9539
9540#if ENABLE_HUSH_LINENO_VAR
9541 G.execute_lineno = command->lineno;
9542#endif
9543
9544 command->pid = BB_MMU ? fork() : vfork();
9545 if (!command->pid) {
9546#if ENABLE_HUSH_JOB
9547 disable_restore_tty_pgrp_on_exit();
9548 CLEAR_RANDOM_T(&G.random_gen);
9549
9550
9551
9552 if (G.run_list_level == 1 && G_interactive_fd) {
9553 pid_t pgrp;
9554 pgrp = pi->pgrp;
9555 if (pgrp < 0)
9556 pgrp = getpid();
9557 if (setpgid(0, pgrp) == 0
9558 && pi->followup != PIPE_BG
9559 && G_saved_tty_pgrp
9560 ) {
9561
9562
9563 tcsetpgrp(G_interactive_fd, pgrp);
9564 }
9565 }
9566#endif
9567 if (pi->alive_cmds == 0 && pi->followup == PIPE_BG) {
9568
9569
9570 close(0);
9571 if (open(bb_dev_null, O_RDONLY))
9572 xopen("/", O_RDONLY);
9573 } else {
9574 xmove_fd(next_infd, 0);
9575 }
9576 xmove_fd(pipefds.wr, 1);
9577 if (pipefds.rd > 1)
9578 close(pipefds.rd);
9579
9580
9581
9582
9583
9584 if (setup_redirects(command, NULL)) {
9585
9586
9587
9588
9589
9590
9591
9592 _exit(1);
9593 }
9594
9595
9596
9597
9598 pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded);
9599
9600 }
9601
9602
9603#if ENABLE_HUSH_FAST
9604 G.count_SIGCHLD++;
9605
9606#endif
9607 enable_restore_tty_pgrp_on_exit();
9608#if !BB_MMU
9609
9610 free(nommu_save.argv);
9611 free(nommu_save.argv_from_re_execing);
9612 G.var_nest_level = sv_var_nest_level;
9613 remove_nested_vars();
9614 add_vars(nommu_save.old_vars);
9615#endif
9616 free(argv_expanded);
9617 argv_expanded = NULL;
9618 if (command->pid < 0) {
9619
9620 bb_simple_perror_msg(BB_MMU ? "vfork"+1 : "vfork");
9621 } else {
9622 pi->alive_cmds++;
9623#if ENABLE_HUSH_JOB
9624
9625 if (pi->pgrp < 0)
9626 pi->pgrp = command->pid;
9627#endif
9628 }
9629
9630 if (cmd_no > 1)
9631 close(next_infd);
9632 if (cmd_no < pi->num_cmds)
9633 close(pipefds.wr);
9634
9635 next_infd = pipefds.rd;
9636 }
9637
9638 if (!pi->alive_cmds) {
9639 debug_leave();
9640 debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n");
9641 return 1;
9642 }
9643
9644 debug_leave();
9645 debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds);
9646 return -1;
9647}
9648
9649
9650
9651static int run_list(struct pipe *pi)
9652{
9653#if ENABLE_HUSH_CASE
9654 char *case_word = NULL;
9655#endif
9656#if ENABLE_HUSH_LOOPS
9657 struct pipe *loop_top = NULL;
9658 char **for_lcur = NULL;
9659 char **for_list = NULL;
9660#endif
9661 smallint last_followup;
9662 smalluint rcode;
9663#if ENABLE_HUSH_IF || ENABLE_HUSH_CASE
9664 smalluint cond_code = 0;
9665#else
9666 enum { cond_code = 0 };
9667#endif
9668#if HAS_KEYWORDS
9669 smallint rword;
9670 smallint last_rword;
9671#endif
9672
9673 debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
9674 debug_enter();
9675
9676#if ENABLE_HUSH_LOOPS
9677
9678 {
9679 struct pipe *cpipe;
9680 for (cpipe = pi; cpipe; cpipe = cpipe->next) {
9681 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN)
9682 continue;
9683
9684 if (cpipe->next == NULL) {
9685 syntax_error("malformed for");
9686 debug_leave();
9687 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
9688 return 1;
9689 }
9690
9691 if (cpipe->next->res_word == RES_DO)
9692 continue;
9693
9694 if (cpipe->res_word == RES_IN
9695 || cpipe->next->res_word != RES_IN
9696 ) {
9697 syntax_error("malformed for");
9698 debug_leave();
9699 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
9700 return 1;
9701 }
9702 }
9703 }
9704#endif
9705
9706
9707
9708
9709
9710#if ENABLE_HUSH_JOB
9711 G.run_list_level++;
9712#endif
9713
9714#if HAS_KEYWORDS
9715 rword = RES_NONE;
9716 last_rword = RES_XXXX;
9717#endif
9718 last_followup = PIPE_SEQ;
9719 rcode = G.last_exitcode;
9720
9721
9722 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
9723 int r;
9724 int sv_errexit_depth;
9725
9726 if (G.flag_SIGINT)
9727 break;
9728 if (G_flag_return_in_progress == 1)
9729 break;
9730
9731 IF_HAS_KEYWORDS(rword = pi->res_word;)
9732 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
9733 rword, cond_code, last_rword);
9734
9735 sv_errexit_depth = G.errexit_depth;
9736 if (
9737#if ENABLE_HUSH_IF
9738 rword == RES_IF || rword == RES_ELIF ||
9739#endif
9740 pi->followup != PIPE_SEQ
9741 ) {
9742 G.errexit_depth++;
9743 }
9744#if ENABLE_HUSH_LOOPS
9745 if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
9746 && loop_top == NULL
9747 ) {
9748
9749 loop_top = pi;
9750 G.depth_of_loop++;
9751 }
9752#endif
9753
9754 if (IF_HAS_KEYWORDS(rword == last_rword &&) 1) {
9755 if ((rcode == 0 && last_followup == PIPE_OR)
9756 || (rcode != 0 && last_followup == PIPE_AND)
9757 ) {
9758
9759
9760 debug_printf_exec("skipped cmd because of || or &&\n");
9761 last_followup = pi->followup;
9762 goto dont_check_jobs_but_continue;
9763 }
9764 }
9765 last_followup = pi->followup;
9766 IF_HAS_KEYWORDS(last_rword = rword;)
9767#if ENABLE_HUSH_IF
9768 if (cond_code) {
9769 if (rword == RES_THEN) {
9770
9771 G.last_exitcode = rcode = EXIT_SUCCESS;
9772
9773 continue;
9774 }
9775 } else {
9776 if (rword == RES_ELSE || rword == RES_ELIF) {
9777
9778
9779 break;
9780 }
9781 }
9782#endif
9783#if ENABLE_HUSH_LOOPS
9784 if (rword == RES_FOR) {
9785 if (!for_lcur) {
9786
9787
9788 static const char encoded_dollar_at[] ALIGN1 = {
9789 SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0'
9790 };
9791 static const char *const encoded_dollar_at_argv[] = {
9792 encoded_dollar_at, NULL
9793 };
9794 char **vals;
9795
9796 G.last_exitcode = rcode = EXIT_SUCCESS;
9797 vals = (char**)encoded_dollar_at_argv;
9798 if (pi->next->res_word == RES_IN) {
9799
9800 if (!pi->next->cmds[0].argv) {
9801 debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n");
9802 break;
9803 }
9804 vals = pi->next->cmds[0].argv;
9805 }
9806
9807 debug_print_strings("for_list made from", vals);
9808 for_list = expand_strvec_to_strvec(vals);
9809 for_lcur = for_list;
9810 debug_print_strings("for_list", for_list);
9811 }
9812 if (!*for_lcur) {
9813
9814 free(for_list);
9815 for_list = NULL;
9816 for_lcur = NULL;
9817 break;
9818 }
9819
9820
9821 set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), 0);
9822 continue;
9823 }
9824 if (rword == RES_IN) {
9825 continue;
9826 }
9827 if (rword == RES_DONE) {
9828 continue;
9829 }
9830#endif
9831#if ENABLE_HUSH_CASE
9832 if (rword == RES_CASE) {
9833 debug_printf_exec("CASE cond_code:%d\n", cond_code);
9834 case_word = expand_string_to_string(pi->cmds->argv[0],
9835 EXP_FLAG_ESC_GLOB_CHARS, 1);
9836 debug_printf_exec("CASE word1:'%s'\n", case_word);
9837
9838
9839 continue;
9840 }
9841 if (rword == RES_MATCH) {
9842 char **argv;
9843
9844 debug_printf_exec("MATCH cond_code:%d\n", cond_code);
9845 if (!case_word)
9846 break;
9847
9848 argv = pi->cmds->argv;
9849 while (*argv) {
9850 char *pattern;
9851 debug_printf_exec("expand_string_to_string('%s')\n", *argv);
9852 pattern = expand_string_to_string(*argv,
9853 EXP_FLAG_ESC_GLOB_CHARS,
9854 0
9855 );
9856
9857 cond_code = (fnmatch(pattern, case_word, 0) != 0);
9858 debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n",
9859 pattern, case_word, cond_code);
9860 free(pattern);
9861 if (cond_code == 0) {
9862
9863 free(case_word);
9864 case_word = NULL;
9865 break;
9866 }
9867 argv++;
9868 }
9869 continue;
9870 }
9871 if (rword == RES_CASE_BODY) {
9872 debug_printf_exec("CASE_BODY cond_code:%d\n", cond_code);
9873 if (cond_code != 0)
9874 continue;
9875 }
9876 if (rword == RES_ESAC) {
9877 debug_printf_exec("ESAC cond_code:%d\n", cond_code);
9878 if (case_word) {
9879
9880 G.last_exitcode = rcode = EXIT_SUCCESS;
9881 }
9882 }
9883#endif
9884
9885
9886
9887 if (pi->num_cmds == 0) {
9888 if (G_interactive_fd)
9889 goto check_jobs_and_continue;
9890 continue;
9891 }
9892
9893
9894
9895
9896
9897 debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds);
9898#if ENABLE_HUSH_LOOPS
9899 G.flag_break_continue = 0;
9900#endif
9901 rcode = r = run_pipe(pi);
9902 if (r != -1) {
9903
9904
9905
9906 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
9907 G.last_exitcode = rcode;
9908 check_and_run_traps();
9909#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9910 rcode = G.last_exitcode;
9911#endif
9912#if ENABLE_HUSH_LOOPS
9913
9914 if (G.flag_break_continue) {
9915 smallint fbc = G.flag_break_continue;
9916
9917
9918 if (loop_top) {
9919 G.depth_break_continue--;
9920 if (G.depth_break_continue == 0)
9921 G.flag_break_continue = 0;
9922
9923 }
9924 if (G.depth_break_continue != 0 || fbc == BC_BREAK) {
9925 checkjobs(NULL, 0 );
9926 break;
9927 }
9928
9929 rword = RES_DONE;
9930 continue;
9931 }
9932#endif
9933 if (G_flag_return_in_progress == 1) {
9934 checkjobs(NULL, 0 );
9935 break;
9936 }
9937 } else if (pi->followup == PIPE_BG) {
9938
9939
9940
9941
9942#if ENABLE_HUSH_JOB
9943 if (G.run_list_level == 1)
9944 insert_job_into_table(pi);
9945#endif
9946
9947 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
9948 G.last_bg_pid_exitcode = 0;
9949 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
9950
9951 rcode = EXIT_SUCCESS;
9952 goto check_traps;
9953 } else {
9954#if ENABLE_HUSH_JOB
9955 if (G.run_list_level == 1 && G_interactive_fd) {
9956
9957 rcode = checkjobs_and_fg_shell(pi);
9958 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
9959 goto check_traps;
9960 }
9961#endif
9962
9963 rcode = checkjobs(pi, 0 );
9964 debug_printf_exec(": checkjobs exitcode %d\n", rcode);
9965 check_traps:
9966 G.last_exitcode = rcode;
9967 check_and_run_traps();
9968#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
9969 rcode = G.last_exitcode;
9970#endif
9971 }
9972
9973
9974 if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
9975 debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
9976 if (G.errexit_depth == 0)
9977 hush_exit(rcode);
9978 }
9979 G.errexit_depth = sv_errexit_depth;
9980
9981
9982#if ENABLE_HUSH_IF
9983 if (rword == RES_IF || rword == RES_ELIF)
9984 cond_code = rcode;
9985#endif
9986 check_jobs_and_continue:
9987 checkjobs(NULL, 0 );
9988 dont_check_jobs_but_continue: ;
9989#if ENABLE_HUSH_LOOPS
9990
9991 if (pi->next
9992 && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE)
9993
9994 ) {
9995 if (rword == RES_WHILE) {
9996 if (rcode) {
9997
9998 G.last_exitcode = rcode = EXIT_SUCCESS;
9999 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n");
10000 break;
10001 }
10002 }
10003 if (rword == RES_UNTIL) {
10004 if (!rcode) {
10005 debug_printf_exec(": until expr is true: breaking\n");
10006 break;
10007 }
10008 }
10009 }
10010#endif
10011 }
10012
10013#if ENABLE_HUSH_JOB
10014 G.run_list_level--;
10015#endif
10016#if ENABLE_HUSH_LOOPS
10017 if (loop_top)
10018 G.depth_of_loop--;
10019 free(for_list);
10020#endif
10021#if ENABLE_HUSH_CASE
10022 free(case_word);
10023#endif
10024 debug_leave();
10025 debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
10026 return rcode;
10027}
10028
10029
10030static int run_and_free_list(struct pipe *pi)
10031{
10032 int rcode = 0;
10033 debug_printf_exec("run_and_free_list entered\n");
10034 if (!G.o_opt[OPT_O_NOEXEC]) {
10035 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
10036 rcode = run_list(pi);
10037 }
10038
10039
10040
10041 free_pipe_list(pi);
10042 debug_printf_exec("run_and_free_list return %d\n", rcode);
10043 return rcode;
10044}
10045
10046
10047static void install_sighandlers(unsigned mask)
10048{
10049 sighandler_t old_handler;
10050 unsigned sig = 0;
10051 while ((mask >>= 1) != 0) {
10052 sig++;
10053 if (!(mask & 1))
10054 continue;
10055 old_handler = install_sighandler(sig, pick_sighandler(sig));
10056
10057
10058
10059
10060 if (sig == SIGCHLD)
10061 continue;
10062
10063
10064
10065
10066
10067 if (sig == SIGHUP && G_interactive_fd)
10068 continue;
10069
10070 if (old_handler == SIG_IGN) {
10071
10072 install_sighandler(sig, old_handler);
10073#if ENABLE_HUSH_TRAP
10074 if (!G_traps)
10075 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
10076 free(G_traps[sig]);
10077 G_traps[sig] = xzalloc(1);
10078#endif
10079 }
10080 }
10081}
10082
10083
10084static void install_special_sighandlers(void)
10085{
10086 unsigned mask;
10087
10088
10089 mask = (1 << SIGQUIT) | (1 << SIGCHLD);
10090 if (G_interactive_fd) {
10091 mask |= SPECIAL_INTERACTIVE_SIGS;
10092 if (G_saved_tty_pgrp)
10093 mask |= SPECIAL_JOBSTOP_SIGS;
10094 }
10095
10096 if (G.special_sig_mask != mask) {
10097 unsigned diff = mask & ~G.special_sig_mask;
10098 G.special_sig_mask = mask;
10099 install_sighandlers(diff);
10100 }
10101}
10102
10103#if ENABLE_HUSH_JOB
10104
10105
10106static void install_fatal_sighandlers(void)
10107{
10108 unsigned mask;
10109
10110
10111 mask = 0
10112
10113
10114 + (1 << SIGBUS ) * HUSH_DEBUG
10115 + (1 << SIGSEGV) * HUSH_DEBUG
10116
10117 + (1 << SIGABRT)
10118
10119 + (1 << SIGPIPE)
10120 + (1 << SIGALRM)
10121
10122
10123
10124
10125
10126
10127
10128 ;
10129 G_fatal_sig_mask = mask;
10130
10131 install_sighandlers(mask);
10132}
10133#endif
10134
10135static int set_mode(int state, char mode, const char *o_opt)
10136{
10137 int idx;
10138 switch (mode) {
10139 case 'n':
10140 G.o_opt[OPT_O_NOEXEC] = state;
10141 break;
10142 case 'x':
10143 IF_HUSH_MODE_X(G_x_mode = state;)
10144 IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);)
10145 break;
10146 case 'e':
10147 G.o_opt[OPT_O_ERREXIT] = state;
10148 break;
10149 case 'o':
10150 if (!o_opt) {
10151
10152
10153
10154
10155
10156
10157
10158 const char *p = o_opt_strings;
10159 idx = 0;
10160 while (*p) {
10161 printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p);
10162 idx++;
10163 p += strlen(p) + 1;
10164 }
10165 break;
10166 }
10167 idx = index_in_strings(o_opt_strings, o_opt);
10168 if (idx >= 0) {
10169 G.o_opt[idx] = state;
10170 break;
10171 }
10172
10173 default:
10174 return EXIT_FAILURE;
10175 }
10176 return EXIT_SUCCESS;
10177}
10178
10179int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
10180int hush_main(int argc, char **argv)
10181{
10182 pid_t cached_getpid;
10183 enum {
10184 OPT_login = (1 << 0),
10185 };
10186 unsigned flags;
10187#if !BB_MMU
10188 unsigned builtin_argc = 0;
10189#endif
10190 char **e;
10191 struct variable *cur_var;
10192 struct variable *shell_ver;
10193
10194 INIT_G();
10195 if (EXIT_SUCCESS != 0)
10196 G.last_exitcode = EXIT_SUCCESS;
10197#if ENABLE_HUSH_TRAP
10198# if ENABLE_HUSH_FUNCTIONS
10199 G.return_exitcode = -1;
10200# endif
10201 G.pre_trap_exitcode = -1;
10202#endif
10203
10204#if ENABLE_HUSH_FAST
10205 G.count_SIGCHLD++;
10206#endif
10207#if !BB_MMU
10208 G.argv0_for_re_execing = argv[0];
10209#endif
10210
10211 cached_getpid = getpid();
10212 G.root_pid = cached_getpid;
10213 G.root_ppid = getppid();
10214
10215
10216 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
10217 unsetenv("HUSH_VERSION");
10218 shell_ver = xzalloc(sizeof(*shell_ver));
10219 shell_ver->flg_export = 1;
10220 shell_ver->flg_read_only = 1;
10221
10222
10223 shell_ver->varstr = xstrdup(hush_version_str);
10224
10225
10226
10227 G.top_var = shell_ver;
10228 cur_var = G.top_var;
10229 e = environ;
10230 if (e) while (*e) {
10231 char *value = strchr(*e, '=');
10232 if (value) {
10233 cur_var->next = xzalloc(sizeof(*cur_var));
10234 cur_var = cur_var->next;
10235 cur_var->varstr = *e;
10236 cur_var->max_len = strlen(*e);
10237 cur_var->flg_export = 1;
10238 }
10239 e++;
10240 }
10241
10242 debug_printf_env("putenv '%s'\n", shell_ver->varstr);
10243 putenv(shell_ver->varstr);
10244
10245
10246 set_pwd_var(SETFLAG_EXPORT);
10247
10248#if BASH_HOSTNAME_VAR
10249
10250 if (!get_local_var_value("HOSTNAME")) {
10251 struct utsname uts;
10252 uname(&uts);
10253 set_local_var_from_halves("HOSTNAME", uts.nodename);
10254 }
10255#endif
10256
10257 set_local_var_from_halves("IFS", defifs);
10258
10259 if (!get_local_var_value("PATH"))
10260 set_local_var_from_halves("PATH", bb_default_root_path);
10261
10262
10263
10264
10265
10266
10267
10268
10269
10270
10271
10272
10273
10274
10275
10276
10277
10278
10279
10280
10281
10282
10283
10284
10285
10286
10287
10288
10289
10290
10291
10292
10293
10294
10295
10296
10297#if NUM_SCRIPTS > 0
10298 if (argc < 0) {
10299 char *script = get_script_content(-argc - 1);
10300 G.global_argv = argv;
10301 G.global_argc = string_array_len(argv);
10302
10303 parse_and_run_string(script);
10304 goto final_return;
10305 }
10306#endif
10307
10308
10309 die_func = restore_ttypgrp_and__exit;
10310
10311
10312
10313
10314
10315
10316
10317
10318
10319
10320 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
10321 while (1) {
10322 int opt = getopt(argc, argv, "+"
10323 "cexinsl"
10324#if !BB_MMU
10325 "<:$:R:V:"
10326# if ENABLE_HUSH_FUNCTIONS
10327 "F:"
10328# endif
10329#endif
10330 );
10331 if (opt <= 0)
10332 break;
10333 switch (opt) {
10334 case 'c':
10335
10336
10337
10338 G.opt_c = 1;
10339 break;
10340 case 'i':
10341
10342
10343
10344 break;
10345 case 's':
10346 G.opt_s = 1;
10347 break;
10348 case 'l':
10349 flags |= OPT_login;
10350 break;
10351#if !BB_MMU
10352 case '<':
10353 full_write1_str(optarg);
10354 _exit(0);
10355 case '$': {
10356 unsigned long long empty_trap_mask;
10357
10358 G.root_pid = bb_strtou(optarg, &optarg, 16);
10359 optarg++;
10360 G.root_ppid = bb_strtou(optarg, &optarg, 16);
10361 optarg++;
10362 G.last_bg_pid = bb_strtou(optarg, &optarg, 16);
10363 optarg++;
10364 G.last_exitcode = bb_strtou(optarg, &optarg, 16);
10365 optarg++;
10366 builtin_argc = bb_strtou(optarg, &optarg, 16);
10367 optarg++;
10368 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
10369 if (empty_trap_mask != 0) {
10370 IF_HUSH_TRAP(int sig;)
10371 install_special_sighandlers();
10372# if ENABLE_HUSH_TRAP
10373 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
10374 for (sig = 1; sig < NSIG; sig++) {
10375 if (empty_trap_mask & (1LL << sig)) {
10376 G_traps[sig] = xzalloc(1);
10377 install_sighandler(sig, SIG_IGN);
10378 }
10379 }
10380# endif
10381 }
10382# if ENABLE_HUSH_LOOPS
10383 optarg++;
10384 G.depth_of_loop = bb_strtou(optarg, &optarg, 16);
10385# endif
10386
10387
10388
10389
10390 IF_HUSH_JOB(G.run_list_level = 1;)
10391# if ENABLE_HUSH_FUNCTIONS
10392
10393
10394
10395
10396 G_flag_return_in_progress = -1;
10397# endif
10398 break;
10399 }
10400 case 'R':
10401 case 'V':
10402 set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0);
10403 break;
10404# if ENABLE_HUSH_FUNCTIONS
10405 case 'F': {
10406 struct function *funcp = new_function(optarg);
10407
10408
10409 funcp->body_as_string = argv[optind];
10410 optind++;
10411 break;
10412 }
10413# endif
10414#endif
10415
10416
10417
10418
10419 default:
10420 if (set_mode(1, opt, NULL) == 0)
10421 break;
10422 bb_show_usage();
10423 }
10424 }
10425
10426
10427 G.global_argc = argc - (optind - 1);
10428 G.global_argv = argv + (optind - 1);
10429 G.global_argv[0] = argv[0];
10430
10431
10432 if (flags & OPT_login) {
10433 const char *hp = NULL;
10434 HFILE *input;
10435
10436 debug_printf("sourcing /etc/profile\n");
10437 input = hfopen("/etc/profile");
10438 run_profile:
10439 if (input != NULL) {
10440 install_special_sighandlers();
10441 parse_and_run_file(input);
10442 hfclose(input);
10443 }
10444
10445
10446
10447
10448
10449
10450
10451 if (!hp) {
10452 hp = get_local_var_value("HOME");
10453 if (hp && hp[0]) {
10454 debug_printf("sourcing ~/.profile\n");
10455 hp = concat_path_file(hp, ".profile");
10456 input = hfopen(hp);
10457 free((char*)hp);
10458 goto run_profile;
10459 }
10460 }
10461 }
10462
10463
10464 if (G.opt_c) {
10465
10466
10467
10468
10469
10470
10471
10472
10473
10474
10475 char *script;
10476
10477 install_special_sighandlers();
10478
10479 G.global_argc--;
10480 G.global_argv++;
10481#if !BB_MMU
10482 if (builtin_argc) {
10483
10484 const struct built_in_command *x;
10485 x = find_builtin(G.global_argv[0]);
10486 if (x) {
10487 argv = G.global_argv;
10488 G.global_argc -= builtin_argc + 1;
10489 G.global_argv += builtin_argc + 1;
10490 G.global_argv[-1] = NULL;
10491 G.last_exitcode = x->b_function(argv);
10492 }
10493 goto final_return;
10494 }
10495#endif
10496
10497 script = G.global_argv[0];
10498 if (!script)
10499 bb_error_msg_and_die(bb_msg_requires_arg, "-c");
10500 if (!G.global_argv[1]) {
10501
10502 G.global_argv[0] = argv[0];
10503 } else {
10504 G.global_argc--;
10505 G.global_argv++;
10506 }
10507 parse_and_run_string(script);
10508 goto final_return;
10509 }
10510
10511
10512 if (!G.opt_s && G.global_argv[1]) {
10513 HFILE *input;
10514
10515
10516
10517
10518
10519
10520 G.global_argc--;
10521 G.global_argv++;
10522 debug_printf("running script '%s'\n", G.global_argv[0]);
10523 xfunc_error_retval = 127;
10524 input = hfopen(G.global_argv[0]);
10525 if (!input) {
10526 bb_simple_perror_msg_and_die(G.global_argv[0]);
10527 }
10528 xfunc_error_retval = 1;
10529 install_special_sighandlers();
10530 parse_and_run_file(input);
10531#if ENABLE_FEATURE_CLEAN_UP
10532 hfclose(input);
10533#endif
10534 goto final_return;
10535 }
10536
10537 G.opt_s = 1;
10538
10539
10540
10541
10542
10543
10544
10545
10546
10547
10548
10549
10550
10551#if ENABLE_HUSH_JOB
10552 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
10553 G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
10554 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp);
10555 if (G_saved_tty_pgrp < 0)
10556 G_saved_tty_pgrp = 0;
10557
10558
10559 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
10560 if (G_interactive_fd < 0) {
10561
10562 G_interactive_fd = dup(STDIN_FILENO);
10563 if (G_interactive_fd < 0) {
10564
10565 G_interactive_fd = 0;
10566 G_saved_tty_pgrp = 0;
10567 }
10568 }
10569 }
10570 debug_printf("interactive_fd:%d\n", G_interactive_fd);
10571 if (G_interactive_fd) {
10572 close_on_exec_on(G_interactive_fd);
10573
10574 if (G_saved_tty_pgrp) {
10575
10576
10577
10578
10579
10580 while (1) {
10581 pid_t shell_pgrp = getpgrp();
10582 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
10583 if (G_saved_tty_pgrp == shell_pgrp)
10584 break;
10585
10586 kill(- shell_pgrp, SIGTTIN);
10587 }
10588 }
10589
10590
10591 install_special_sighandlers();
10592
10593 if (G_saved_tty_pgrp) {
10594
10595 install_fatal_sighandlers();
10596
10597
10598 bb_setpgrp();
10599
10600 tcsetpgrp(G_interactive_fd, cached_getpid);
10601 }
10602 enable_restore_tty_pgrp_on_exit();
10603
10604# if ENABLE_FEATURE_EDITING
10605 G.line_input_state = new_line_input_t(FOR_SHELL);
10606# if EDITING_HAS_get_exe_name
10607 G.line_input_state->get_exe_name = get_builtin_name;
10608# endif
10609# endif
10610# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
10611 {
10612 const char *hp = get_local_var_value("HISTFILE");
10613 if (!hp) {
10614 hp = get_local_var_value("HOME");
10615 if (hp)
10616 hp = concat_path_file(hp, ".hush_history");
10617 } else {
10618 hp = xstrdup(hp);
10619 }
10620 if (hp) {
10621 G.line_input_state->hist_file = hp;
10622
10623 }
10624# if ENABLE_FEATURE_SH_HISTFILESIZE
10625 hp = get_local_var_value("HISTFILESIZE");
10626 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10627# endif
10628 }
10629# endif
10630 } else {
10631 install_special_sighandlers();
10632 }
10633#elif ENABLE_HUSH_INTERACTIVE
10634
10635 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
10636 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
10637 if (G_interactive_fd < 0) {
10638
10639 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
10640 if (G_interactive_fd < 0)
10641
10642 G_interactive_fd = 0;
10643 }
10644 }
10645 if (G_interactive_fd) {
10646 close_on_exec_on(G_interactive_fd);
10647 }
10648 install_special_sighandlers();
10649#else
10650
10651 install_special_sighandlers();
10652#endif
10653
10654
10655
10656
10657
10658 if (G_interactive_fd) {
10659#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
10660
10661 if (!get_local_var_value("PS1"))
10662 set_local_var_from_halves("PS1", "\\w \\$ ");
10663 if (!get_local_var_value("PS2"))
10664 set_local_var_from_halves("PS2", "> ");
10665#endif
10666 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
10667
10668 printf("\n\n%s %s\n"
10669 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n")
10670 "\n",
10671 bb_banner,
10672 "hush - the humble shell"
10673 );
10674 }
10675 }
10676
10677 parse_and_run_file(hfopen(NULL));
10678
10679 final_return:
10680 hush_exit(G.last_exitcode);
10681}
10682
10683
10684
10685
10686
10687static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM)
10688{
10689 return 0;
10690}
10691
10692#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL
10693static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv))
10694{
10695 int argc = string_array_len(argv);
10696 return applet_main_func(argc, argv);
10697}
10698#endif
10699#if ENABLE_HUSH_TEST || BASH_TEST2
10700static int FAST_FUNC builtin_test(char **argv)
10701{
10702 return run_applet_main(argv, test_main);
10703}
10704#endif
10705#if ENABLE_HUSH_ECHO
10706static int FAST_FUNC builtin_echo(char **argv)
10707{
10708 return run_applet_main(argv, echo_main);
10709}
10710#endif
10711#if ENABLE_HUSH_PRINTF
10712static int FAST_FUNC builtin_printf(char **argv)
10713{
10714 return run_applet_main(argv, printf_main);
10715}
10716#endif
10717
10718#if ENABLE_HUSH_HELP
10719static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
10720{
10721 const struct built_in_command *x;
10722
10723 printf(
10724 "Built-in commands:\n"
10725 "------------------\n");
10726 for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) {
10727 if (x->b_descr)
10728 printf("%-10s%s\n", x->b_cmd, x->b_descr);
10729 }
10730 return EXIT_SUCCESS;
10731}
10732#endif
10733
10734#if MAX_HISTORY && ENABLE_FEATURE_EDITING
10735static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
10736{
10737 show_history(G.line_input_state);
10738 return EXIT_SUCCESS;
10739}
10740#endif
10741
10742static char **skip_dash_dash(char **argv)
10743{
10744 argv++;
10745 if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == '\0')
10746 argv++;
10747 return argv;
10748}
10749
10750static int FAST_FUNC builtin_cd(char **argv)
10751{
10752 const char *newdir;
10753
10754 argv = skip_dash_dash(argv);
10755 newdir = argv[0];
10756 if (newdir == NULL) {
10757
10758
10759
10760
10761 const char *home = get_local_var_value("HOME");
10762 newdir = home ? home : "/";
10763 }
10764 if (chdir(newdir)) {
10765
10766 bb_perror_msg("cd: %s", newdir);
10767 return EXIT_FAILURE;
10768 }
10769
10770
10771
10772
10773 set_pwd_var( 0);
10774 return EXIT_SUCCESS;
10775}
10776
10777static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
10778{
10779 puts(get_cwd(0));
10780 return EXIT_SUCCESS;
10781}
10782
10783static int FAST_FUNC builtin_eval(char **argv)
10784{
10785 argv = skip_dash_dash(argv);
10786
10787 if (!argv[0])
10788 return EXIT_SUCCESS;
10789
10790 IF_HUSH_MODE_X(G.x_mode_depth++;)
10791
10792 if (!argv[1]) {
10793
10794
10795
10796
10797 parse_and_run_string(argv[0]);
10798 } else {
10799
10800
10801
10802
10803 char *str, *p;
10804 unsigned len = 0;
10805 char **pp = argv;
10806 do
10807 len += strlen(*pp) + 1;
10808 while (*++pp);
10809 str = p = xmalloc(len);
10810 pp = argv;
10811 for (;;) {
10812 p = stpcpy(p, *pp);
10813 pp++;
10814 if (!*pp)
10815 break;
10816 *p++ = ' ';
10817 }
10818 parse_and_run_string(str);
10819 free(str);
10820 }
10821 IF_HUSH_MODE_X(G.x_mode_depth--;)
10822
10823 return G.last_exitcode;
10824}
10825
10826static int FAST_FUNC builtin_exec(char **argv)
10827{
10828 argv = skip_dash_dash(argv);
10829 if (argv[0] == NULL)
10830 return EXIT_SUCCESS;
10831
10832
10833
10834 if (G_saved_tty_pgrp && getpid() == G.root_pid)
10835 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
10836
10837
10838
10839
10840
10841
10842
10843
10844
10845
10846
10847
10848
10849 execvp_or_die(argv);
10850}
10851
10852static int FAST_FUNC builtin_exit(char **argv)
10853{
10854 debug_printf_exec("%s()\n", __func__);
10855
10856
10857
10858
10859
10860
10861
10862
10863
10864
10865
10866
10867
10868
10869
10870 argv = skip_dash_dash(argv);
10871 if (argv[0] == NULL) {
10872#if ENABLE_HUSH_TRAP
10873 if (G.pre_trap_exitcode >= 0)
10874 hush_exit(G.pre_trap_exitcode);
10875#endif
10876 hush_exit(G.last_exitcode);
10877 }
10878
10879 xfunc_error_retval = 255;
10880
10881 hush_exit(xatoi(argv[0]) & 0xff);
10882}
10883
10884#if ENABLE_HUSH_TYPE
10885
10886static int FAST_FUNC builtin_type(char **argv)
10887{
10888 int ret = EXIT_SUCCESS;
10889
10890 while (*++argv) {
10891 const char *type;
10892 char *path = NULL;
10893
10894 if (0) {}
10895
10896
10897# if ENABLE_HUSH_FUNCTIONS
10898 else if (find_function(*argv))
10899 type = "a function";
10900# endif
10901 else if (find_builtin(*argv))
10902 type = "a shell builtin";
10903 else if ((path = find_in_path(*argv)) != NULL)
10904 type = path;
10905 else {
10906 bb_error_msg("type: %s: not found", *argv);
10907 ret = EXIT_FAILURE;
10908 continue;
10909 }
10910
10911 printf("%s is %s\n", *argv, type);
10912 free(path);
10913 }
10914
10915 return ret;
10916}
10917#endif
10918
10919#if ENABLE_HUSH_READ
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944static int FAST_FUNC builtin_read(char **argv)
10945{
10946 const char *r;
10947 struct builtin_read_params params;
10948
10949 memset(¶ms, 0, sizeof(params));
10950
10951
10952
10953
10954 params.read_flags = getopt32(argv,
10955# if BASH_READ_D
10956 IF_NOT_HUSH_BASH_COMPAT("^")
10957 "!srn:p:t:u:d:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"),
10958 ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d
10959# else
10960 IF_NOT_HUSH_BASH_COMPAT("^")
10961 "!srn:p:t:u:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"),
10962 ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u
10963# endif
10964
10965
10966
10967 );
10968 if ((uint32_t)params.read_flags == (uint32_t)-1)
10969 return EXIT_FAILURE;
10970 argv += optind;
10971 params.argv = argv;
10972 params.setvar = set_local_var_from_halves;
10973 params.ifs = get_local_var_value("IFS");
10974
10975 again:
10976 r = shell_builtin_read(¶ms);
10977
10978 if ((uintptr_t)r == 1 && errno == EINTR) {
10979 unsigned sig = check_and_run_traps();
10980 if (sig != SIGINT)
10981 goto again;
10982 }
10983
10984 if ((uintptr_t)r > 1) {
10985 bb_simple_error_msg(r);
10986 r = (char*)(uintptr_t)1;
10987 }
10988
10989 return (uintptr_t)r;
10990}
10991#endif
10992
10993#if ENABLE_HUSH_UMASK
10994static int FAST_FUNC builtin_umask(char **argv)
10995{
10996 int rc;
10997 mode_t mask;
10998
10999 rc = 1;
11000 mask = umask(0);
11001 argv = skip_dash_dash(argv);
11002 if (argv[0]) {
11003 mode_t old_mask = mask;
11004
11005
11006
11007 if (!isdigit(argv[0][0]))
11008 mask ^= 0777;
11009 mask = bb_parse_mode(argv[0], mask);
11010 if (!isdigit(argv[0][0]))
11011 mask ^= 0777;
11012 if ((unsigned)mask > 0777) {
11013 mask = old_mask;
11014
11015
11016
11017
11018 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
11019 rc = 0;
11020 }
11021 } else {
11022
11023 printf("%04o\n", (unsigned) mask);
11024
11025 }
11026 umask(mask);
11027
11028 return !rc;
11029}
11030#endif
11031
11032#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP
11033static void print_escaped(const char *s)
11034{
11035 if (*s == '\'')
11036 goto squote;
11037 do {
11038 const char *p = strchrnul(s, '\'');
11039
11040 printf("'%.*s'", (int)(p - s), s);
11041 if (*p == '\0')
11042 break;
11043 s = p;
11044 squote:
11045
11046 putchar('"');
11047 do putchar('\''); while (*++s == '\'');
11048 putchar('"');
11049 } while (*s);
11050}
11051#endif
11052
11053#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY
11054static int helper_export_local(char **argv, unsigned flags)
11055{
11056 do {
11057 char *name = *argv;
11058 const char *name_end = endofname(name);
11059
11060 if (*name_end == '\0') {
11061 struct variable *var, **vpp;
11062
11063 vpp = get_ptr_to_local_var(name, name_end - name);
11064 var = vpp ? *vpp : NULL;
11065
11066 if (flags & SETFLAG_UNEXPORT) {
11067
11068 if (var) {
11069 var->flg_export = 0;
11070 debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
11071 unsetenv(name);
11072 }
11073 continue;
11074 }
11075 if (flags & SETFLAG_EXPORT) {
11076
11077 if (var) {
11078 var->flg_export = 1;
11079 debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
11080 putenv(var->varstr);
11081 continue;
11082 }
11083 }
11084 if (flags & SETFLAG_MAKE_RO) {
11085
11086 if (var) {
11087 var->flg_read_only = 1;
11088 continue;
11089 }
11090 }
11091# if ENABLE_HUSH_LOCAL
11092
11093 if (!(flags & (SETFLAG_EXPORT|SETFLAG_UNEXPORT|SETFLAG_MAKE_RO))) {
11094 unsigned lvl = flags >> SETFLAG_VARLVL_SHIFT;
11095 if (var && var->var_nest_level == lvl) {
11096
11097 continue;
11098 }
11099 }
11100# endif
11101
11102
11103
11104
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114 name = xasprintf("%s=", name);
11115 } else {
11116 if (*name_end != '=') {
11117 bb_error_msg("'%s': bad variable name", name);
11118
11119 return 1;
11120 }
11121
11122 name = xstrdup(name);
11123
11124 unbackslash(name);
11125 }
11126 debug_printf_env("%s: set_local_var('%s')\n", __func__, name);
11127 if (set_local_var(name, flags))
11128 return EXIT_FAILURE;
11129 } while (*++argv);
11130 return EXIT_SUCCESS;
11131}
11132#endif
11133
11134#if ENABLE_HUSH_EXPORT
11135static int FAST_FUNC builtin_export(char **argv)
11136{
11137 unsigned opt_unexport;
11138
11139# if ENABLE_HUSH_EXPORT_N
11140
11141 opt_unexport = getopt32(argv, "!n");
11142 if (opt_unexport == (uint32_t)-1)
11143 return EXIT_FAILURE;
11144 argv += optind;
11145# else
11146 opt_unexport = 0;
11147 argv++;
11148# endif
11149
11150 if (argv[0] == NULL) {
11151 char **e = environ;
11152 if (e) {
11153 while (*e) {
11154# if 0
11155 puts(*e++);
11156# else
11157
11158
11159
11160 const char *s = *e++;
11161 const char *p = strchr(s, '=');
11162
11163 if (!p)
11164 continue;
11165
11166 printf("export %.*s", (int)(p - s) + 1, s);
11167 print_escaped(p + 1);
11168 putchar('\n');
11169# endif
11170 }
11171
11172 }
11173 return EXIT_SUCCESS;
11174 }
11175
11176 return helper_export_local(argv, opt_unexport ? SETFLAG_UNEXPORT : SETFLAG_EXPORT);
11177}
11178#endif
11179
11180#if ENABLE_HUSH_LOCAL
11181static int FAST_FUNC builtin_local(char **argv)
11182{
11183 if (G.func_nest_level == 0) {
11184 bb_error_msg("%s: not in a function", argv[0]);
11185 return EXIT_FAILURE;
11186 }
11187 argv++;
11188
11189
11190
11191
11192 return helper_export_local(argv, (G.var_nest_level - 1) << SETFLAG_VARLVL_SHIFT);
11193}
11194#endif
11195
11196#if ENABLE_HUSH_READONLY
11197static int FAST_FUNC builtin_readonly(char **argv)
11198{
11199 argv++;
11200 if (*argv == NULL) {
11201
11202
11203
11204 struct variable *e;
11205 for (e = G.top_var; e; e = e->next) {
11206 if (e->flg_read_only) {
11207
11208 printf("readonly %s\n", e->varstr);
11209 }
11210 }
11211 return EXIT_SUCCESS;
11212 }
11213 return helper_export_local(argv, SETFLAG_MAKE_RO);
11214}
11215#endif
11216
11217#if ENABLE_HUSH_UNSET
11218
11219static int FAST_FUNC builtin_unset(char **argv)
11220{
11221 int ret;
11222 unsigned opts;
11223
11224
11225
11226 opts = getopt32(argv, "!+vf");
11227 if (opts == (unsigned)-1)
11228 return EXIT_FAILURE;
11229 if (opts == 3) {
11230 bb_simple_error_msg("unset: -v and -f are exclusive");
11231 return EXIT_FAILURE;
11232 }
11233 argv += optind;
11234
11235 ret = EXIT_SUCCESS;
11236 while (*argv) {
11237 if (!(opts & 2)) {
11238 if (unset_local_var(*argv)) {
11239
11240
11241
11242 ret = EXIT_FAILURE;
11243 }
11244 }
11245# if ENABLE_HUSH_FUNCTIONS
11246 else {
11247 unset_func(*argv);
11248 }
11249# endif
11250 argv++;
11251 }
11252 return ret;
11253}
11254#endif
11255
11256#if ENABLE_HUSH_SET
11257
11258
11259
11260
11261
11262
11263
11264
11265
11266
11267
11268
11269
11270
11271
11272
11273
11274
11275
11276
11277
11278static int FAST_FUNC builtin_set(char **argv)
11279{
11280 int n;
11281 char **pp, **g_argv;
11282 char *arg = *++argv;
11283
11284 if (arg == NULL) {
11285 struct variable *e;
11286 for (e = G.top_var; e; e = e->next)
11287 puts(e->varstr);
11288 return EXIT_SUCCESS;
11289 }
11290
11291 do {
11292 if (strcmp(arg, "--") == 0) {
11293 ++argv;
11294 goto set_argv;
11295 }
11296 if (arg[0] != '+' && arg[0] != '-')
11297 break;
11298 for (n = 1; arg[n]; ++n) {
11299 if (set_mode((arg[0] == '-'), arg[n], argv[1])) {
11300 bb_error_msg("%s: %s: invalid option", "set", arg);
11301 return EXIT_FAILURE;
11302 }
11303 if (arg[n] == 'o' && argv[1])
11304 argv++;
11305 }
11306 } while ((arg = *++argv) != NULL);
11307
11308
11309 if (arg == NULL)
11310 return EXIT_SUCCESS;
11311 set_argv:
11312
11313
11314 g_argv = G.global_argv;
11315 if (G.global_args_malloced) {
11316 pp = g_argv;
11317 while (*++pp)
11318 free(*pp);
11319 g_argv[1] = NULL;
11320 } else {
11321 G.global_args_malloced = 1;
11322 pp = xzalloc(sizeof(pp[0]) * 2);
11323 pp[0] = g_argv[0];
11324 g_argv = pp;
11325 }
11326
11327 G.global_argv = pp = add_strings_to_strings(g_argv, argv, 1);
11328
11329 G.global_argc = 1 + string_array_len(pp + 1);
11330
11331 return EXIT_SUCCESS;
11332}
11333#endif
11334
11335static int FAST_FUNC builtin_shift(char **argv)
11336{
11337 int n = 1;
11338 argv = skip_dash_dash(argv);
11339 if (argv[0]) {
11340 n = bb_strtou(argv[0], NULL, 10);
11341 if (errno || n < 0) {
11342
11343 bb_error_msg("Illegal number: %s", argv[0]);
11344
11345
11346
11347
11348
11349
11350
11351 }
11352 }
11353 if (n >= 0 && n < G.global_argc) {
11354 if (G_global_args_malloced) {
11355 int m = 1;
11356 while (m <= n)
11357 free(G.global_argv[m++]);
11358 }
11359 G.global_argc -= n;
11360 memmove(&G.global_argv[1], &G.global_argv[n+1],
11361 G.global_argc * sizeof(G.global_argv[0]));
11362 return EXIT_SUCCESS;
11363 }
11364 return EXIT_FAILURE;
11365}
11366
11367#if ENABLE_HUSH_GETOPTS
11368static int FAST_FUNC builtin_getopts(char **argv)
11369{
11370
11371
11372
11373
11374
11375
11376
11377
11378
11379
11380
11381
11382
11383 char cbuf[2];
11384 const char *cp, *optstring, *var;
11385 int c, n, exitcode, my_opterr;
11386 unsigned count;
11387
11388 optstring = *++argv;
11389 if (!optstring || !(var = *++argv)) {
11390 bb_simple_error_msg("usage: getopts OPTSTRING VAR [ARGS]");
11391 return EXIT_FAILURE;
11392 }
11393
11394 if (argv[1])
11395 argv[0] = G.global_argv[0];
11396 else
11397 argv = G.global_argv;
11398 cbuf[1] = '\0';
11399
11400 my_opterr = 0;
11401 if (optstring[0] != ':') {
11402 cp = get_local_var_value("OPTERR");
11403
11404 my_opterr = (!cp || NOT_LONE_CHAR(cp, '0'));
11405 }
11406
11407
11408 {
11409 char *s = alloca(strlen(optstring) + 2);
11410 sprintf(s, "+%s", optstring);
11411 optstring = s;
11412 }
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440 GETOPT_RESET();
11441 count = 0;
11442 n = string_array_len(argv);
11443 do {
11444 optarg = NULL;
11445 opterr = (count < G.getopt_count) ? 0 : my_opterr;
11446 c = getopt(n, argv, optstring);
11447 if (c < 0)
11448 break;
11449 count++;
11450 } while (count <= G.getopt_count);
11451
11452
11453 set_local_var_from_halves("OPTIND", utoa(optind));
11454 G.getopt_count = count;
11455 GETOPT_RESET();
11456
11457
11458
11459
11460
11461
11462 cp = optarg;
11463 if (c == '?') {
11464
11465
11466
11467 if (optstring[1] == ':') {
11468 cbuf[0] = optopt;
11469 cp = cbuf;
11470 }
11471 }
11472 if (cp)
11473 set_local_var_from_halves("OPTARG", cp);
11474 else
11475 unset_local_var("OPTARG");
11476
11477
11478 exitcode = EXIT_SUCCESS;
11479 if (c < 0) {
11480 exitcode = EXIT_FAILURE;
11481 c = '?';
11482 }
11483
11484
11485 cbuf[0] = c;
11486 set_local_var_from_halves(var, cbuf);
11487
11488 return exitcode;
11489}
11490#endif
11491
11492static int FAST_FUNC builtin_source(char **argv)
11493{
11494 char *arg_path, *filename;
11495 HFILE *input;
11496 save_arg_t sv;
11497 char *args_need_save;
11498#if ENABLE_HUSH_FUNCTIONS
11499 smallint sv_flg;
11500#endif
11501
11502 argv = skip_dash_dash(argv);
11503 filename = argv[0];
11504 if (!filename) {
11505
11506 return 2;
11507 }
11508 arg_path = NULL;
11509 if (!strchr(filename, '/')) {
11510 arg_path = find_in_path(filename);
11511 if (arg_path)
11512 filename = arg_path;
11513 else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) {
11514 errno = ENOENT;
11515 bb_simple_perror_msg(filename);
11516 return EXIT_FAILURE;
11517 }
11518 }
11519 input = hfopen(filename);
11520 free(arg_path);
11521 if (!input) {
11522 bb_perror_msg("%s", filename);
11523
11524
11525
11526 return EXIT_FAILURE;
11527 }
11528
11529#if ENABLE_HUSH_FUNCTIONS
11530 sv_flg = G_flag_return_in_progress;
11531
11532 G_flag_return_in_progress = -1;
11533#endif
11534 args_need_save = argv[1];
11535 if (args_need_save)
11536 save_and_replace_G_args(&sv, argv);
11537
11538
11539 G.last_exitcode = 0;
11540 parse_and_run_file(input);
11541 hfclose(input);
11542
11543 if (args_need_save)
11544 restore_G_args(&sv, argv);
11545#if ENABLE_HUSH_FUNCTIONS
11546 G_flag_return_in_progress = sv_flg;
11547#endif
11548
11549 return G.last_exitcode;
11550}
11551
11552#if ENABLE_HUSH_TRAP
11553static int FAST_FUNC builtin_trap(char **argv)
11554{
11555 int sig;
11556 char *new_cmd;
11557
11558 if (!G_traps)
11559 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
11560
11561 argv++;
11562 if (!*argv) {
11563 int i;
11564
11565 for (i = 0; i < NSIG; ++i) {
11566 if (G_traps[i]) {
11567 printf("trap -- ");
11568 print_escaped(G_traps[i]);
11569
11570
11571
11572
11573 printf(" %s\n", get_signame(i));
11574 }
11575 }
11576
11577 return EXIT_SUCCESS;
11578 }
11579
11580 new_cmd = NULL;
11581
11582 sig = bb_strtou(*argv, NULL, 10);
11583 if (errno == 0) {
11584 int ret;
11585 process_sig_list:
11586 ret = EXIT_SUCCESS;
11587 while (*argv) {
11588 sighandler_t handler;
11589
11590 sig = get_signum(*argv++);
11591 if (sig < 0) {
11592 ret = EXIT_FAILURE;
11593
11594 bb_error_msg("trap: %s: invalid signal specification", argv[-1]);
11595 continue;
11596 }
11597
11598 free(G_traps[sig]);
11599 G_traps[sig] = xstrdup(new_cmd);
11600
11601 debug_printf("trap: setting SIG%s (%i) to '%s'\n",
11602 get_signame(sig), sig, G_traps[sig]);
11603
11604
11605 if (sig == 0)
11606 continue;
11607
11608 if (new_cmd)
11609 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN);
11610 else
11611
11612 handler = pick_sighandler(sig);
11613 install_sighandler(sig, handler);
11614 }
11615 return ret;
11616 }
11617
11618 if (!argv[1]) {
11619 bb_simple_error_msg("trap: invalid arguments");
11620 return EXIT_FAILURE;
11621 }
11622
11623
11624
11625
11626
11627 if (argv[0][0] == '-') {
11628 if (argv[0][1] == '\0') {
11629
11630 goto reset_traps;
11631 }
11632 if (argv[0][1] == '-' && argv[0][2] == '\0') {
11633 argv++;
11634 }
11635
11636 }
11637 new_cmd = *argv;
11638 reset_traps:
11639 argv++;
11640 goto process_sig_list;
11641}
11642#endif
11643
11644#if ENABLE_HUSH_JOB
11645static struct pipe *parse_jobspec(const char *str)
11646{
11647 struct pipe *pi;
11648 unsigned jobnum;
11649
11650 if (sscanf(str, "%%%u", &jobnum) != 1) {
11651 if (str[0] != '%'
11652 || (str[1] != '%' && str[1] != '+' && str[1] != '\0')
11653 ) {
11654 bb_error_msg("bad argument '%s'", str);
11655 return NULL;
11656 }
11657
11658 jobnum = G.last_jobid;
11659 if (jobnum == 0) {
11660 bb_simple_error_msg("no current job");
11661 return NULL;
11662 }
11663 }
11664 for (pi = G.job_list; pi; pi = pi->next) {
11665 if (pi->jobid == jobnum) {
11666 return pi;
11667 }
11668 }
11669 bb_error_msg("%u: no such job", jobnum);
11670 return NULL;
11671}
11672
11673static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
11674{
11675 struct pipe *job;
11676 const char *status_string;
11677
11678 checkjobs(NULL, 0 );
11679 for (job = G.job_list; job; job = job->next) {
11680 if (job->alive_cmds == job->stopped_cmds)
11681 status_string = "Stopped";
11682 else
11683 status_string = "Running";
11684
11685 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
11686 }
11687
11688 clean_up_last_dead_job();
11689
11690 return EXIT_SUCCESS;
11691}
11692
11693
11694static int FAST_FUNC builtin_fg_bg(char **argv)
11695{
11696 int i;
11697 struct pipe *pi;
11698
11699 if (!G_interactive_fd)
11700 return EXIT_FAILURE;
11701
11702
11703 if (!argv[1]) {
11704 for (pi = G.job_list; pi; pi = pi->next) {
11705 if (pi->jobid == G.last_jobid) {
11706 goto found;
11707 }
11708 }
11709 bb_error_msg("%s: no current job", argv[0]);
11710 return EXIT_FAILURE;
11711 }
11712
11713 pi = parse_jobspec(argv[1]);
11714 if (!pi)
11715 return EXIT_FAILURE;
11716 found:
11717
11718
11719 if (argv[0][0] == 'f' && G_saved_tty_pgrp) {
11720
11721 tcsetpgrp(G_interactive_fd, pi->pgrp);
11722 }
11723
11724
11725 debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_cmds, pi->pgrp);
11726 for (i = 0; i < pi->num_cmds; i++) {
11727 debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid);
11728 }
11729 pi->stopped_cmds = 0;
11730
11731 i = kill(- pi->pgrp, SIGCONT);
11732 if (i < 0) {
11733 if (errno == ESRCH) {
11734 delete_finished_job(pi);
11735 return EXIT_SUCCESS;
11736 }
11737 bb_simple_perror_msg("kill (SIGCONT)");
11738 }
11739
11740 if (argv[0][0] == 'f') {
11741 remove_job_from_table(pi);
11742 return checkjobs_and_fg_shell(pi);
11743 }
11744 return EXIT_SUCCESS;
11745}
11746#endif
11747
11748#if ENABLE_HUSH_KILL
11749static int FAST_FUNC builtin_kill(char **argv)
11750{
11751 int ret = 0;
11752
11753# if ENABLE_HUSH_JOB
11754 if (argv[1] && strcmp(argv[1], "-l") != 0) {
11755 int i = 1;
11756
11757 do {
11758 struct pipe *pi;
11759 char *dst;
11760 int j, n;
11761
11762 if (argv[i][0] != '%')
11763 continue;
11764
11765
11766
11767
11768 pi = parse_jobspec(argv[i]);
11769 if (!pi) {
11770
11771 j = i;
11772 do {
11773 j++;
11774 argv[j - 1] = argv[j];
11775 } while (argv[j]);
11776 ret = 1;
11777 i--;
11778 continue;
11779 }
11780
11781
11782
11783
11784
11785
11786
11787
11788
11789
11790
11791
11792 n = G_interactive_fd ? 1 : pi->num_cmds;
11793 dst = alloca(n * sizeof(int)*4);
11794 argv[i] = dst;
11795 if (G_interactive_fd)
11796 dst += sprintf(dst, " -%u", (int)pi->pgrp);
11797 else for (j = 0; j < n; j++) {
11798 struct command *cmd = &pi->cmds[j];
11799
11800 if (cmd->pid == 0)
11801 continue;
11802
11803
11804
11805
11806
11807 dst += sprintf(dst, " %u", (int)cmd->pid);
11808 }
11809 *dst = '\0';
11810 } while (argv[++i]);
11811 }
11812# endif
11813
11814 if (argv[1] || ret == 0) {
11815 ret = run_applet_main(argv, kill_main);
11816 }
11817
11818 return ret;
11819}
11820#endif
11821
11822#if ENABLE_HUSH_WAIT
11823
11824# if !ENABLE_HUSH_JOB
11825# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid)
11826# endif
11827static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid)
11828{
11829 int ret = 0;
11830 for (;;) {
11831 int sig;
11832 sigset_t oldset;
11833
11834 if (!sigisemptyset(&G.pending_set))
11835 goto check_sig;
11836
11837
11838
11839
11840
11841
11842
11843
11844
11845
11846 sigfillset(&oldset);
11847 sigprocmask2(SIG_SETMASK, &oldset);
11848
11849 if (!sigisemptyset(&G.pending_set)) {
11850
11851 goto restore;
11852 }
11853
11854
11855
11856 ret = checkjobs(NULL, waitfor_pid);
11857 debug_printf_exec("checkjobs:%d\n", ret);
11858# if ENABLE_HUSH_JOB
11859 if (waitfor_pipe) {
11860 int rcode = job_exited_or_stopped(waitfor_pipe);
11861 debug_printf_exec("job_exited_or_stopped:%d\n", rcode);
11862 if (rcode >= 0) {
11863 ret = rcode;
11864 sigprocmask(SIG_SETMASK, &oldset, NULL);
11865 break;
11866 }
11867 }
11868# endif
11869
11870
11871
11872 if (errno == ECHILD || ret) {
11873 ret--;
11874 if (ret < 0)
11875 ret = 0;
11876# if ENABLE_HUSH_BASH_COMPAT
11877 if (waitfor_pid == -1 && errno == ECHILD) {
11878
11879 ret = 127;
11880 }
11881# endif
11882 sigprocmask(SIG_SETMASK, &oldset, NULL);
11883 break;
11884 }
11885
11886
11887
11888 sigsuspend(&oldset);
11889
11890
11891
11892
11893
11894
11895
11896
11897
11898
11899 restore:
11900 sigprocmask(SIG_SETMASK, &oldset, NULL);
11901 check_sig:
11902
11903 sig = check_and_run_traps();
11904 if (sig ) {
11905
11906 ret = 128 | sig;
11907 break;
11908 }
11909
11910 }
11911 return ret;
11912}
11913
11914static int FAST_FUNC builtin_wait(char **argv)
11915{
11916 int ret;
11917 int status;
11918
11919 argv = skip_dash_dash(argv);
11920# if ENABLE_HUSH_BASH_COMPAT
11921 if (argv[0] && strcmp(argv[0], "-n") == 0) {
11922
11923
11924 G.dead_job_exitcode = -1;
11925 return wait_for_child_or_signal(NULL, -1 );
11926 }
11927# endif
11928 if (argv[0] == NULL) {
11929
11930
11931
11932
11933
11934
11935
11936
11937
11938
11939
11940
11941
11942
11943
11944
11945 return wait_for_child_or_signal(NULL, 0 );
11946 }
11947
11948 do {
11949 pid_t pid = bb_strtou(*argv, NULL, 10);
11950 if (errno || pid <= 0) {
11951# if ENABLE_HUSH_JOB
11952 if (argv[0][0] == '%') {
11953 struct pipe *wait_pipe;
11954 ret = 127;
11955 wait_pipe = parse_jobspec(*argv);
11956 if (wait_pipe) {
11957 ret = job_exited_or_stopped(wait_pipe);
11958 if (ret < 0) {
11959 ret = wait_for_child_or_signal(wait_pipe, 0);
11960 } else {
11961
11962 clean_up_last_dead_job();
11963 }
11964 }
11965
11966 continue;
11967 }
11968# endif
11969
11970 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv);
11971 ret = EXIT_FAILURE;
11972 continue;
11973 }
11974
11975
11976 ret = waitpid(pid, &status, WNOHANG);
11977 if (ret < 0) {
11978
11979 ret = 127;
11980 if (errno == ECHILD) {
11981 if (pid == G.last_bg_pid) {
11982
11983
11984
11985
11986
11987 ret = G.last_bg_pid_exitcode;
11988 } else {
11989
11990 bb_error_msg("wait: pid %u is not a child of this shell", (unsigned)pid);
11991 }
11992 } else {
11993
11994 bb_perror_msg("wait %s", *argv);
11995 }
11996 continue;
11997 }
11998 if (ret == 0) {
11999
12000 ret = wait_for_child_or_signal(NULL, pid);
12001 } else {
12002
12003 process_wait_result(NULL, pid, status);
12004 ret = WEXITSTATUS(status);
12005 if (WIFSIGNALED(status))
12006 ret = 128 | WTERMSIG(status);
12007 }
12008 } while (*++argv);
12009
12010 return ret;
12011}
12012#endif
12013
12014#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS
12015static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min)
12016{
12017 if (argv[1]) {
12018 def = bb_strtou(argv[1], NULL, 10);
12019 if (errno || def < def_min || argv[2]) {
12020 bb_error_msg("%s: bad arguments", argv[0]);
12021 def = UINT_MAX;
12022 }
12023 }
12024 return def;
12025}
12026#endif
12027
12028#if ENABLE_HUSH_LOOPS
12029static int FAST_FUNC builtin_break(char **argv)
12030{
12031 unsigned depth;
12032 if (G.depth_of_loop == 0) {
12033 bb_error_msg("%s: only meaningful in a loop", argv[0]);
12034
12035 G.flag_break_continue = 0;
12036 return EXIT_SUCCESS;
12037 }
12038 G.flag_break_continue++;
12039
12040 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
12041 if (depth == UINT_MAX)
12042 G.flag_break_continue = BC_BREAK;
12043 if (G.depth_of_loop < depth)
12044 G.depth_break_continue = G.depth_of_loop;
12045
12046 return EXIT_SUCCESS;
12047}
12048
12049static int FAST_FUNC builtin_continue(char **argv)
12050{
12051 G.flag_break_continue = 1;
12052 return builtin_break(argv);
12053}
12054#endif
12055
12056#if ENABLE_HUSH_FUNCTIONS
12057static int FAST_FUNC builtin_return(char **argv)
12058{
12059 int rc;
12060
12061 if (G_flag_return_in_progress != -1) {
12062 bb_error_msg("%s: not in a function or sourced script", argv[0]);
12063 return EXIT_FAILURE;
12064 }
12065
12066 G_flag_return_in_progress = 1;
12067
12068
12069
12070
12071
12072
12073
12074
12075 rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
12076# if ENABLE_HUSH_TRAP
12077 if (argv[1]) {
12078 debug_printf_exec("G.return_exitcode=%d\n", rc);
12079 G.return_exitcode = rc;
12080 }
12081# endif
12082 return rc;
12083}
12084#endif
12085
12086#if ENABLE_HUSH_TIMES
12087static int FAST_FUNC builtin_times(char **argv UNUSED_PARAM)
12088{
12089 static const uint8_t times_tbl[] ALIGN1 = {
12090 ' ', offsetof(struct tms, tms_utime),
12091 '\n', offsetof(struct tms, tms_stime),
12092 ' ', offsetof(struct tms, tms_cutime),
12093 '\n', offsetof(struct tms, tms_cstime),
12094 0
12095 };
12096 const uint8_t *p;
12097 unsigned clk_tck;
12098 struct tms buf;
12099
12100 clk_tck = bb_clk_tck();
12101
12102 times(&buf);
12103 p = times_tbl;
12104 do {
12105 unsigned sec, frac;
12106 unsigned long t;
12107 t = *(clock_t *)(((char *) &buf) + p[1]);
12108 sec = t / clk_tck;
12109 frac = t % clk_tck;
12110 printf("%um%u.%03us%c",
12111 sec / 60, sec % 60,
12112 (frac * 1000) / clk_tck,
12113 p[0]);
12114 p += 2;
12115 } while (*p);
12116
12117 return EXIT_SUCCESS;
12118}
12119#endif
12120
12121#if ENABLE_HUSH_MEMLEAK
12122static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
12123{
12124 void *p;
12125 unsigned long l;
12126
12127# ifdef M_TRIM_THRESHOLD
12128
12129 malloc_trim(0);
12130# endif
12131
12132
12133 p = malloc(240);
12134 l = (unsigned long)p;
12135 free(p);
12136 p = malloc(3400);
12137 if (l < (unsigned long)p) l = (unsigned long)p;
12138 free(p);
12139
12140
12141# if 0
12142 {
12143 struct mallinfo mi = mallinfo();
12144 printf("top alloc:0x%lx malloced:%d+%d=%d\n", l,
12145 mi.arena, mi.hblkhd, mi.arena + mi.hblkhd);
12146 }
12147# endif
12148
12149 if (!G.memleak_value)
12150 G.memleak_value = l;
12151
12152 l -= G.memleak_value;
12153 if ((long)l < 0)
12154 l = 0;
12155 l /= 1024;
12156 if (l > 127)
12157 l = 127;
12158
12159
12160 return l;
12161}
12162#endif
12163