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