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