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