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