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