Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/shell/hush.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/shell/hush.c
r821 r1770 21 21 * 22 22 * Other credits: 23 * simple_itoa() was lifted from boa-0.93.1524 23 * b_addchr() derived from similar w_addchar function in glibc-2.2 25 24 * setup_redirect(), redirect_opt_num(), and big chunks of main() 26 * 25 * and many builtins derived from contributions by Erik Andersen 27 26 * miscellaneous bugfixes from Matt Kraai 28 27 * … … 39 38 * 40 39 * Bash grammar not implemented: (how many of these were in original sh?) 41 * $@ (those sure look like weird quoting rules)42 40 * $_ 43 41 * ! negation operator for pipes … … 53 51 * Functions 54 52 * Major bugs: 55 * job handling woefully incomplete and buggy 53 * job handling woefully incomplete and buggy (improved --vda) 56 54 * reserved word execution woefully incomplete and buggy 57 55 * to-do: … … 73 71 * more testing, especially quoting rules and redirection 74 72 * document how quoting rules not precisely followed for variable assignments 75 * maybe change map[] to use 2-bit entries73 * maybe change charmap[] to use 2-bit entries 76 74 * (eventually) remove all the printf's 77 75 * … … 79 77 */ 80 78 81 #include "busybox.h" 82 #include <ctype.h> /* isalpha, isdigit */ 83 #include <unistd.h> /* getpid */ 84 #include <stdlib.h> /* getenv, atoi */ 85 #include <string.h> /* strchr */ 86 #include <stdio.h> /* popen etc. */ 79 87 80 #include <glob.h> /* glob, of course */ 88 #include <stdarg.h> /* va_list */89 #include <errno.h>90 #include <fcntl.h>91 81 #include <getopt.h> /* should be pretty obvious */ 92 93 #include <sys/stat.h> /* ulimit */94 #include <sys/types.h>95 #include <sys/wait.h>96 #include <signal.h>97 98 82 /* #include <dmalloc.h> */ 99 /* #define DEBUG_SHELL */ 100 101 #if 1 102 #include "cmdedit.h" 103 #else 104 #define bb_applet_name "hush" 105 //#include "standalone.h" 106 #define hush_main main 107 #undef CONFIG_FEATURE_SH_FANCY_PROMPT 108 #define BB_BANNER "" 109 #endif 110 #define SPECIAL_VAR_SYMBOL 03 111 #define FLAG_EXIT_FROM_LOOP 1 112 #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ 113 #define FLAG_REPARSING (1 << 2) /* >=2nd pass */ 83 84 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */ 85 86 #include "busybox.h" /* for struct bb_applet */ 87 88 89 /* If you comment out one of these below, it will be #defined later 90 * to perform debug printfs to stderr: */ 91 #define debug_printf(...) do {} while (0) 92 /* Finer-grained debug switches */ 93 #define debug_printf_parse(...) do {} while (0) 94 #define debug_print_tree(a, b) do {} while (0) 95 #define debug_printf_exec(...) do {} while (0) 96 #define debug_printf_jobs(...) do {} while (0) 97 #define debug_printf_expand(...) do {} while (0) 98 #define debug_printf_clean(...) do {} while (0) 99 100 #ifndef debug_printf 101 #define debug_printf(...) fprintf(stderr, __VA_ARGS__) 102 #endif 103 104 #ifndef debug_printf_parse 105 #define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__) 106 #endif 107 108 #ifndef debug_printf_exec 109 #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) 110 #endif 111 112 #ifndef debug_printf_jobs 113 #define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__) 114 #define DEBUG_SHELL_JOBS 1 115 #endif 116 117 #ifndef debug_printf_expand 118 #define debug_printf_expand(...) fprintf(stderr, __VA_ARGS__) 119 #define DEBUG_EXPAND 1 120 #endif 121 122 /* Keep unconditionally on for now */ 123 #define ENABLE_HUSH_DEBUG 1 124 125 #ifndef debug_printf_clean 126 /* broken, of course, but OK for testing */ 127 static const char *indenter(int i) 128 { 129 static const char blanks[] ALIGN1 = 130 " "; 131 return &blanks[sizeof(blanks) - i - 1]; 132 } 133 #define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__) 134 #define DEBUG_CLEAN 1 135 #endif 136 137 138 #if !ENABLE_HUSH_INTERACTIVE 139 #undef ENABLE_FEATURE_EDITING 140 #define ENABLE_FEATURE_EDITING 0 141 #undef ENABLE_FEATURE_EDITING_FANCY_PROMPT 142 #define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 143 #endif 144 145 #define SPECIAL_VAR_SYMBOL 3 146 147 #define PARSEFLAG_EXIT_FROM_LOOP 1 148 #define PARSEFLAG_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ 149 #define PARSEFLAG_REPARSING (1 << 2) /* >= 2nd pass */ 114 150 115 151 typedef enum { … … 123 159 /* The descrip member of this structure is only used to make debugging 124 160 * output pretty */ 125 static const struct {int mode; int default_fd; const char *descrip;} redir_table[] = { 161 static const struct { 162 int mode; 163 signed char default_fd; 164 char descrip[3]; 165 } redir_table[] = { 126 166 { 0, 0, "()" }, 127 167 { O_RDONLY, 0, "<" }, … … 142 182 typedef enum { 143 183 RES_NONE = 0, 184 #if ENABLE_HUSH_IF 144 185 RES_IF = 1, 145 186 RES_THEN = 2, … … 147 188 RES_ELSE = 4, 148 189 RES_FI = 5, 190 #endif 191 #if ENABLE_HUSH_LOOPS 149 192 RES_FOR = 6, 150 193 RES_WHILE = 7, … … 152 195 RES_DO = 9, 153 196 RES_DONE = 10, 154 RES_XXXX = 11, 155 RES_IN = 12, 197 RES_IN = 11, 198 #endif 199 RES_XXXX = 12, 156 200 RES_SNTX = 13 157 201 } reserved_style; 158 #define FLAG_END (1<<RES_NONE) 159 #define FLAG_IF (1<<RES_IF) 160 #define FLAG_THEN (1<<RES_THEN) 161 #define FLAG_ELIF (1<<RES_ELIF) 162 #define FLAG_ELSE (1<<RES_ELSE) 163 #define FLAG_FI (1<<RES_FI) 164 #define FLAG_FOR (1<<RES_FOR) 165 #define FLAG_WHILE (1<<RES_WHILE) 166 #define FLAG_UNTIL (1<<RES_UNTIL) 167 #define FLAG_DO (1<<RES_DO) 168 #define FLAG_DONE (1<<RES_DONE) 169 #define FLAG_IN (1<<RES_IN) 170 #define FLAG_START (1<<RES_XXXX) 202 enum { 203 FLAG_END = (1 << RES_NONE ), 204 #if ENABLE_HUSH_IF 205 FLAG_IF = (1 << RES_IF ), 206 FLAG_THEN = (1 << RES_THEN ), 207 FLAG_ELIF = (1 << RES_ELIF ), 208 FLAG_ELSE = (1 << RES_ELSE ), 209 FLAG_FI = (1 << RES_FI ), 210 #endif 211 #if ENABLE_HUSH_LOOPS 212 FLAG_FOR = (1 << RES_FOR ), 213 FLAG_WHILE = (1 << RES_WHILE), 214 FLAG_UNTIL = (1 << RES_UNTIL), 215 FLAG_DO = (1 << RES_DO ), 216 FLAG_DONE = (1 << RES_DONE ), 217 FLAG_IN = (1 << RES_IN ), 218 #endif 219 FLAG_START = (1 << RES_XXXX ), 220 }; 171 221 172 222 /* This holds pointers to the various results of parsing */ … … 176 226 struct pipe *pipe; 177 227 struct redir_struct *pending_redirect; 178 reserved_style w; 179 int old_flag; /* for figuring out valid reserved words */ 228 smallint res_w; 229 smallint parse_type; /* bitmask of PARSEFLAG_xxx, defines type of parser : ";$" common or special symbol */ 230 int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ 180 231 struct p_context *stack; 181 int type; /* define type of parser : ";$" common or special symbol */182 232 /* How about quoting status? */ 183 233 }; 184 234 185 235 struct redir_struct { 186 redir_type type; /* type of redirection*/187 int fd; /* file descriptor being redirected*/188 int dup; /* -1, or file descriptor being duplicated */189 struct redir_struct *next; /* pointer to the next redirect in the list*/190 glob_t word; 236 struct redir_struct *next; /* pointer to the next redirect in the list */ 237 redir_type type; /* type of redirection */ 238 int fd; /* file descriptor being redirected */ 239 int dup; /* -1, or file descriptor being duplicated */ 240 glob_t word; /* *word.gl_pathv is the filename */ 191 241 }; 192 242 193 243 struct child_prog { 194 pid_t pid; /* 0 if exited */ 195 char **argv; /* program name and arguments */ 196 struct pipe *group; /* if non-NULL, first in group or subshell */ 197 int subshell; /* flag, non-zero if group must be forked */ 198 struct redir_struct *redirects; /* I/O redirections */ 199 glob_t glob_result; /* result of parameter globbing */ 200 int is_stopped; /* is the program currently running? */ 201 struct pipe *family; /* pointer back to the child's parent pipe */ 202 int sp; /* number of SPECIAL_VAR_SYMBOL */ 203 int type; 244 pid_t pid; /* 0 if exited */ 245 char **argv; /* program name and arguments */ 246 struct pipe *group; /* if non-NULL, first in group or subshell */ 247 smallint subshell; /* flag, non-zero if group must be forked */ 248 smallint is_stopped; /* is the program currently running? */ 249 struct redir_struct *redirects; /* I/O redirections */ 250 glob_t glob_result; /* result of parameter globbing */ 251 struct pipe *family; /* pointer back to the child's parent pipe */ 252 //sp counting seems to be broken... so commented out, grep for '//sp:' 253 //sp: int sp; /* number of SPECIAL_VAR_SYMBOL */ 254 //seems to be unused, grep for '//pt:' 255 //pt: int parse_type; 204 256 }; 257 /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) 258 * and on execution these are substituted with their values. 259 * Substitution can make _several_ words out of one argv[n]! 260 * Example: argv[0]=='.^C*^C.' here: echo .$*. 261 */ 205 262 206 263 struct pipe { 207 int jobid; /* job number */ 208 int num_progs; /* total number of programs in job */ 209 int running_progs; /* number of programs running */ 210 char *text; /* name of job */ 211 char *cmdbuf; /* buffer various argv's point into */ 212 pid_t pgrp; /* process group ID for the job */ 213 struct child_prog *progs; /* array of commands in pipe */ 214 struct pipe *next; /* to track background commands */ 215 int stopped_progs; /* number of programs alive, but stopped */ 216 int job_context; /* bitmask defining current context */ 217 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 218 reserved_style r_mode; /* supports if, for, while, until */ 264 struct pipe *next; 265 int num_progs; /* total number of programs in job */ 266 int running_progs; /* number of programs running (not exited) */ 267 int stopped_progs; /* number of programs alive, but stopped */ 268 #if ENABLE_HUSH_JOB 269 int jobid; /* job number */ 270 pid_t pgrp; /* process group ID for the job */ 271 char *cmdtext; /* name of job */ 272 #endif 273 char *cmdbuf; /* buffer various argv's point into */ 274 struct child_prog *progs; /* array of commands in pipe */ 275 int job_context; /* bitmask defining current context */ 276 smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 277 smallint res_word; /* needed for if, for, while, until... */ 219 278 }; 220 279 221 280 struct close_me { 281 struct close_me *next; 222 282 int fd; 223 struct close_me *next;224 283 }; 225 284 226 struct variables { 227 char *name; 228 char *value; 229 int flg_export; 230 int flg_read_only; 231 struct variables *next; 285 /* On program start, environ points to initial environment. 286 * putenv adds new pointers into it, unsetenv removes them. 287 * Neither of these (de)allocates the strings. 288 * setenv allocates new strings in malloc space and does putenv, 289 * and thus setenv is unusable (leaky) for shell's purposes */ 290 #define setenv(...) setenv_is_leaky_dont_use() 291 struct variable { 292 struct variable *next; 293 char *varstr; /* points to "name=" portion */ 294 int max_len; /* if > 0, name is part of initial env; else name is malloced */ 295 smallint flg_export; /* putenv should be done on this var */ 296 smallint flg_read_only; 232 297 }; 233 234 /* globals, connect us to the outside world235 * the first three support $?, $#, and $1 */236 static char **global_argv;237 static int global_argc;238 static int last_return_code;239 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */240 241 /* "globals" within this file */242 static char *ifs;243 static unsigned char map[256];244 static int fake_mode;245 static int interactive;246 static struct close_me *close_me_head;247 static const char *cwd;248 static struct pipe *job_list;249 static unsigned int last_bg_pid;250 static int last_jobid;251 static unsigned int shell_terminal;252 static char *PS1;253 static char *PS2;254 static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };255 static struct variables *top_vars = &shell_ver;256 257 258 #define B_CHUNK (100)259 #define B_NOSPAC 1260 298 261 299 typedef struct { … … 267 305 } o_string; 268 306 #define NULL_O_STRING {NULL,0,0,0,0} 269 /* used for initialization: 270 o_string foo = NULL_O_STRING; */ 307 /* used for initialization: o_string foo = NULL_O_STRING; */ 271 308 272 309 /* I can almost use ordinary FILE *. Is open_memstream() universally … … 274 311 struct in_str { 275 312 const char *p; 313 /* eof_flag=1: last char in ->p is really an EOF */ 314 char eof_flag; /* meaningless if ->p == NULL */ 276 315 char peek_buf[2]; 277 int __promptme; 278 int promptmode; 316 #if ENABLE_HUSH_INTERACTIVE 317 smallint promptme; 318 smallint promptmode; /* 0: PS1, 1: PS2 */ 319 #endif 279 320 FILE *file; 280 321 int (*get) (struct in_str *); … … 284 325 #define b_peek(input) ((input)->peek(input)) 285 326 327 enum { 328 CHAR_ORDINARY = 0, 329 CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */ 330 CHAR_IFS = 2, /* treated as ordinary if quoted */ 331 CHAR_SPECIAL = 3, /* example: $ */ 332 }; 333 334 #define HUSH_VER_STR "0.02" 335 336 /* "Globals" within this file */ 337 338 /* Sorted roughly by size (smaller offsets == smaller code) */ 339 struct globals { 340 #if ENABLE_HUSH_INTERACTIVE 341 /* 'interactive_fd' is a fd# open to ctty, if we have one 342 * _AND_ if we decided to act interactively */ 343 int interactive_fd; 344 const char *PS1; 345 const char *PS2; 346 #endif 347 #if ENABLE_FEATURE_EDITING 348 line_input_t *line_input_state; 349 #endif 350 #if ENABLE_HUSH_JOB 351 int run_list_level; 352 pid_t saved_task_pgrp; 353 pid_t saved_tty_pgrp; 354 int last_jobid; 355 struct pipe *job_list; 356 struct pipe *toplevel_list; 357 smallint ctrl_z_flag; 358 #endif 359 smallint fake_mode; 360 /* these three support $?, $#, and $1 */ 361 char **global_argv; 362 int global_argc; 363 int last_return_code; 364 const char *ifs; 365 struct close_me *close_me_head; 366 const char *cwd; 367 unsigned last_bg_pid; 368 struct variable *top_var; /* = &shell_ver (set in main()) */ 369 struct variable shell_ver; 370 #if ENABLE_FEATURE_SH_STANDALONE 371 struct nofork_save_area nofork_save; 372 #endif 373 #if ENABLE_HUSH_JOB 374 sigjmp_buf toplevel_jb; 375 #endif 376 unsigned char charmap[256]; 377 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 378 }; 379 380 #define G (*ptr_to_globals) 381 382 #if !ENABLE_HUSH_INTERACTIVE 383 enum { interactive_fd = 0 }; 384 #endif 385 #if !ENABLE_HUSH_JOB 386 enum { run_list_level = 0 }; 387 #endif 388 389 #if ENABLE_HUSH_INTERACTIVE 390 #define interactive_fd (G.interactive_fd ) 391 #define PS1 (G.PS1 ) 392 #define PS2 (G.PS2 ) 393 #endif 394 #if ENABLE_FEATURE_EDITING 395 #define line_input_state (G.line_input_state) 396 #endif 397 #if ENABLE_HUSH_JOB 398 #define run_list_level (G.run_list_level ) 399 #define saved_task_pgrp (G.saved_task_pgrp ) 400 #define saved_tty_pgrp (G.saved_tty_pgrp ) 401 #define last_jobid (G.last_jobid ) 402 #define job_list (G.job_list ) 403 #define toplevel_list (G.toplevel_list ) 404 #define toplevel_jb (G.toplevel_jb ) 405 #define ctrl_z_flag (G.ctrl_z_flag ) 406 #endif /* JOB */ 407 #define global_argv (G.global_argv ) 408 #define global_argc (G.global_argc ) 409 #define last_return_code (G.last_return_code) 410 #define ifs (G.ifs ) 411 #define fake_mode (G.fake_mode ) 412 #define close_me_head (G.close_me_head ) 413 #define cwd (G.cwd ) 414 #define last_bg_pid (G.last_bg_pid ) 415 #define top_var (G.top_var ) 416 #define shell_ver (G.shell_ver ) 417 #if ENABLE_FEATURE_SH_STANDALONE 418 #define nofork_save (G.nofork_save ) 419 #endif 420 #if ENABLE_HUSH_JOB 421 #define toplevel_jb (G.toplevel_jb ) 422 #endif 423 #define charmap (G.charmap ) 424 #define user_input_buf (G.user_input_buf ) 425 426 427 #define B_CHUNK 100 428 #define B_NOSPAC 1 286 429 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 287 430 288 struct built_in_command { 289 const char *cmd; /* name */ 290 const char *descr; /* description */ 291 int (*function) (struct child_prog *); /* function ptr */ 292 }; 293 294 /* belongs in busybox.h */ 295 static inline int max(int a, int b) { 296 return (a>b)?a:b; 297 } 298 299 /* This should be in utility.c */ 300 #ifdef DEBUG_SHELL 301 static void debug_printf(const char *format, ...) 302 { 303 va_list args; 304 va_start(args, format); 305 vfprintf(stderr, format, args); 306 va_end(args); 307 } 431 #if 1 432 /* Normal */ 433 static void syntax(const char *msg) 434 { 435 /* Was using fancy stuff: 436 * (interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...) 437 * but it SEGVs. ?! Oh well... explicit temp ptr works around that */ 438 void (*fp)(const char *s, ...); 439 440 fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); 441 fp(msg ? "%s: %s" : "syntax error", "syntax error", msg); 442 } 443 308 444 #else 309 static inline void debug_printf(const char *format ATTRIBUTE_UNUSED, ...) { } 310 #endif 311 #define final_printf debug_printf 312 313 static void __syntax(char *file, int line) { 314 bb_error_msg("syntax error %s:%d", file, line); 315 } 316 #define syntax() __syntax(__FILE__, __LINE__) 445 /* Debug */ 446 static void syntax_lineno(int line) 447 { 448 void (*fp)(const char *s, ...); 449 450 fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); 451 fp("syntax error hush.c:%d", line); 452 } 453 #define syntax(str) syntax_lineno(__LINE__) 454 #endif 317 455 318 456 /* Index of subroutines: */ 319 457 /* function prototypes for builtins */ 320 static int builtin_cd(struct child_prog *child); 321 static int builtin_env(struct child_prog *child); 322 static int builtin_eval(struct child_prog *child); 323 static int builtin_exec(struct child_prog *child); 324 static int builtin_exit(struct child_prog *child); 325 static int builtin_export(struct child_prog *child); 326 static int builtin_fg_bg(struct child_prog *child); 327 static int builtin_help(struct child_prog *child); 328 static int builtin_jobs(struct child_prog *child); 329 static int builtin_pwd(struct child_prog *child); 330 static int builtin_read(struct child_prog *child); 331 static int builtin_set(struct child_prog *child); 332 static int builtin_shift(struct child_prog *child); 333 static int builtin_source(struct child_prog *child); 334 static int builtin_umask(struct child_prog *child); 335 static int builtin_unset(struct child_prog *child); 336 static int builtin_not_written(struct child_prog *child); 458 static int builtin_cd(char **argv); 459 static int builtin_eval(char **argv); 460 static int builtin_exec(char **argv); 461 static int builtin_exit(char **argv); 462 static int builtin_export(char **argv); 463 #if ENABLE_HUSH_JOB 464 static int builtin_fg_bg(char **argv); 465 static int builtin_jobs(char **argv); 466 #endif 467 #if ENABLE_HUSH_HELP 468 static int builtin_help(char **argv); 469 #endif 470 static int builtin_pwd(char **argv); 471 static int builtin_read(char **argv); 472 static int builtin_set(char **argv); 473 static int builtin_shift(char **argv); 474 static int builtin_source(char **argv); 475 static int builtin_umask(char **argv); 476 static int builtin_unset(char **argv); 477 //static int builtin_not_written(char **argv); 337 478 /* o_string manipulation: */ 338 479 static int b_check_space(o_string *o, int len); … … 340 481 static void b_reset(o_string *o); 341 482 static int b_addqchr(o_string *o, int ch, int quote); 342 static int b_adduint(o_string *o, unsigned int i);343 483 /* in_str manipulations: */ 344 484 static int static_get(struct in_str *i); … … 353 493 static void close_all(void); 354 494 /* "run" the final data structures: */ 355 static char *indenter(int i); 495 #if !defined(DEBUG_CLEAN) 496 #define free_pipe_list(head, indent) free_pipe_list(head) 497 #define free_pipe(pi, indent) free_pipe(pi) 498 #endif 356 499 static int free_pipe_list(struct pipe *head, int indent); 357 500 static int free_pipe(struct pipe *pi, int indent); … … 359 502 static int setup_redirects(struct child_prog *prog, int squirrel[]); 360 503 static int run_list_real(struct pipe *pi); 504 static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; 361 505 static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; 362 506 static int run_pipe_real(struct pipe *pi); … … 376 520 static int redirect_dup_num(struct in_str *input); 377 521 static int redirect_opt_num(o_string *o); 378 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); 522 #if ENABLE_HUSH_TICK 523 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, const char *subst_end); 524 #endif 379 525 static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 380 static char *lookup_param(char *src); 381 static char *make_string(char **inp); 526 static const char *lookup_param(const char *src); 382 527 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 383 static int parse_string(o_string *dest, struct p_context *ctx, const char *src); 384 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); 528 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 385 529 /* setup: */ 386 static int parse_ stream_outer(struct in_str *inp, intflag);387 static int parse_ string_outer(const char *s, intflag);388 static int parse_ file_outer(FILE *f);530 static int parse_and_run_stream(struct in_str *inp, int parse_flag); 531 static int parse_and_run_string(const char *s, int parse_flag); 532 static int parse_and_run_file(FILE *f); 389 533 /* job management: */ 390 534 static int checkjobs(struct pipe* fg_pipe); 535 #if ENABLE_HUSH_JOB 536 static int checkjobs_and_fg_shell(struct pipe* fg_pipe); 391 537 static void insert_bg_job(struct pipe *pi); 392 538 static void remove_bg_job(struct pipe *pi); 539 static void delete_finished_bg_job(struct pipe *pi); 540 #else 541 int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ 542 #endif 393 543 /* local variable support */ 394 static char **make_list_in(char **inp, char *name); 395 static char *insert_var_value(char *inp); 396 static char *get_local_var(const char *var); 397 static void unset_local_var(const char *name); 398 static int set_local_var(const char *s, int flg_export); 544 static char **expand_strvec_to_strvec(char **argv); 545 /* used for eval */ 546 static char *expand_strvec_to_string(char **argv); 547 /* used for expansion of right hand of assignments */ 548 static char *expand_string_to_string(const char *str); 549 static struct variable *get_local_var(const char *name); 550 static int set_local_var(char *str, int flg_export); 551 static void unset_local_var(const char *name); 399 552 400 553 /* Table of built-in functions. They can be forked or not, depending on 401 554 * context: within pipes, they fork. As simple commands, they do not. 402 555 * When used in non-forking context, they can change global variables 403 * in the parent shell process. If forked, of course they can 556 * in the parent shell process. If forked, of course they cannot. 404 557 * For example, 'unset foo | whatever' will parse and run, but foo will 405 558 * still be set at the end. */ 559 struct built_in_command { 560 const char *cmd; /* name */ 561 int (*function) (char **argv); /* function ptr */ 562 #if ENABLE_HUSH_HELP 563 const char *descr; /* description */ 564 #define BLTIN(cmd, func, help) { cmd, func, help } 565 #else 566 #define BLTIN(cmd, func, help) { cmd, func } 567 #endif 568 }; 569 406 570 static const struct built_in_command bltins[] = { 407 {"bg", "Resume a job in the background", builtin_fg_bg}, 408 {"break", "Exit for, while or until loop", builtin_not_written}, 409 {"cd", "Change working directory", builtin_cd}, 410 {"continue", "Continue for, while or until loop", builtin_not_written}, 411 {"env", "Print all environment variables", builtin_env}, 412 {"eval", "Construct and run shell command", builtin_eval}, 413 {"exec", "Exec command, replacing this shell with the exec'd process", 414 builtin_exec}, 415 {"exit", "Exit from shell()", builtin_exit}, 416 {"export", "Set environment variable", builtin_export}, 417 {"fg", "Bring job into the foreground", builtin_fg_bg}, 418 {"jobs", "Lists the active jobs", builtin_jobs}, 419 {"pwd", "Print current directory", builtin_pwd}, 420 {"read", "Input environment variable", builtin_read}, 421 {"return", "Return from a function", builtin_not_written}, 422 {"set", "Set/unset shell local variables", builtin_set}, 423 {"shift", "Shift positional parameters", builtin_shift}, 424 {"trap", "Trap signals", builtin_not_written}, 425 {"ulimit","Controls resource limits", builtin_not_written}, 426 {"umask","Sets file creation mask", builtin_umask}, 427 {"unset", "Unset environment variable", builtin_unset}, 428 {".", "Source-in and run commands in a file", builtin_source}, 429 {"help", "List shell built-in commands", builtin_help}, 430 {NULL, NULL, NULL} 571 #if ENABLE_HUSH_JOB 572 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"), 573 #endif 574 // BLTIN("break" , builtin_not_written, "Exit for, while or until loop"), 575 BLTIN("cd" , builtin_cd, "Change working directory"), 576 // BLTIN("continue", builtin_not_written, "Continue for, while or until loop"), 577 BLTIN("eval" , builtin_eval, "Construct and run shell command"), 578 BLTIN("exec" , builtin_exec, "Exec command, replacing this shell with the exec'd process"), 579 BLTIN("exit" , builtin_exit, "Exit from shell"), 580 BLTIN("export", builtin_export, "Set environment variable"), 581 #if ENABLE_HUSH_JOB 582 BLTIN("fg" , builtin_fg_bg, "Bring job into the foreground"), 583 BLTIN("jobs" , builtin_jobs, "Lists the active jobs"), 584 #endif 585 // TODO: remove pwd? we have it as an applet... 586 BLTIN("pwd" , builtin_pwd, "Print current directory"), 587 BLTIN("read" , builtin_read, "Input environment variable"), 588 // BLTIN("return", builtin_not_written, "Return from a function"), 589 BLTIN("set" , builtin_set, "Set/unset shell local variables"), 590 BLTIN("shift" , builtin_shift, "Shift positional parameters"), 591 // BLTIN("trap" , builtin_not_written, "Trap signals"), 592 // BLTIN("ulimit", builtin_not_written, "Controls resource limits"), 593 BLTIN("umask" , builtin_umask, "Sets file creation mask"), 594 BLTIN("unset" , builtin_unset, "Unset environment variable"), 595 BLTIN("." , builtin_source, "Source-in and run commands in a file"), 596 #if ENABLE_HUSH_HELP 597 BLTIN("help" , builtin_help, "List shell built-in commands"), 598 #endif 599 BLTIN(NULL, NULL, NULL) 431 600 }; 432 601 602 #if ENABLE_HUSH_JOB 603 604 /* move to libbb? */ 605 static void signal_SA_RESTART(int sig, void (*handler)(int)) 606 { 607 struct sigaction sa; 608 sa.sa_handler = handler; 609 sa.sa_flags = SA_RESTART; 610 sigemptyset(&sa.sa_mask); 611 sigaction(sig, &sa, NULL); 612 } 613 614 /* Signals are grouped, we handle them in batches */ 615 static void set_fatal_sighandler(void (*handler)(int)) 616 { 617 signal(SIGILL , handler); 618 signal(SIGTRAP, handler); 619 signal(SIGABRT, handler); 620 signal(SIGFPE , handler); 621 signal(SIGBUS , handler); 622 signal(SIGSEGV, handler); 623 /* bash 3.2 seems to handle these just like 'fatal' ones */ 624 signal(SIGHUP , handler); 625 signal(SIGPIPE, handler); 626 signal(SIGALRM, handler); 627 } 628 static void set_jobctrl_sighandler(void (*handler)(int)) 629 { 630 signal(SIGTSTP, handler); 631 signal(SIGTTIN, handler); 632 signal(SIGTTOU, handler); 633 } 634 static void set_misc_sighandler(void (*handler)(int)) 635 { 636 signal(SIGINT , handler); 637 signal(SIGQUIT, handler); 638 signal(SIGTERM, handler); 639 } 640 /* SIGCHLD is special and handled separately */ 641 642 static void set_every_sighandler(void (*handler)(int)) 643 { 644 set_fatal_sighandler(handler); 645 set_jobctrl_sighandler(handler); 646 set_misc_sighandler(handler); 647 signal(SIGCHLD, handler); 648 } 649 650 static void handler_ctrl_c(int sig) 651 { 652 debug_printf_jobs("got sig %d\n", sig); 653 // as usual we can have all kinds of nasty problems with leaked malloc data here 654 siglongjmp(toplevel_jb, 1); 655 } 656 657 static void handler_ctrl_z(int sig) 658 { 659 pid_t pid; 660 661 debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid()); 662 pid = fork(); 663 if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */ 664 return; 665 ctrl_z_flag = 1; 666 if (!pid) { /* child */ 667 setpgrp(); 668 debug_printf_jobs("set pgrp for child %d ok\n", getpid()); 669 set_every_sighandler(SIG_DFL); 670 raise(SIGTSTP); /* resend TSTP so that child will be stopped */ 671 debug_printf_jobs("returning in child\n"); 672 /* return to nofork, it will eventually exit now, 673 * not return back to shell */ 674 return; 675 } 676 /* parent */ 677 /* finish filling up pipe info */ 678 toplevel_list->pgrp = pid; /* child is in its own pgrp */ 679 toplevel_list->progs[0].pid = pid; 680 /* parent needs to longjmp out of running nofork. 681 * we will "return" exitcode 0, with child put in background */ 682 // as usual we can have all kinds of nasty problems with leaked malloc data here 683 debug_printf_jobs("siglongjmp in parent\n"); 684 siglongjmp(toplevel_jb, 1); 685 } 686 687 /* Restores tty foreground process group, and exits. 688 * May be called as signal handler for fatal signal 689 * (will faithfully resend signal to itself, producing correct exit state) 690 * or called directly with -EXITCODE. 691 * We also call it if xfunc is exiting. */ 692 static void sigexit(int sig) ATTRIBUTE_NORETURN; 693 static void sigexit(int sig) 694 { 695 sigset_t block_all; 696 697 /* Disable all signals: job control, SIGPIPE, etc. */ 698 sigfillset(&block_all); 699 sigprocmask(SIG_SETMASK, &block_all, NULL); 700 701 if (interactive_fd) 702 tcsetpgrp(interactive_fd, saved_tty_pgrp); 703 704 /* Not a signal, just exit */ 705 if (sig <= 0) 706 _exit(- sig); 707 708 /* Enable only this sig and kill ourself with it */ 709 signal(sig, SIG_DFL); 710 sigdelset(&block_all, sig); 711 sigprocmask(SIG_SETMASK, &block_all, NULL); 712 raise(sig); 713 _exit(1); /* Should not reach it */ 714 } 715 716 /* Restores tty foreground process group, and exits. */ 717 static void hush_exit(int exitcode) ATTRIBUTE_NORETURN; 718 static void hush_exit(int exitcode) 719 { 720 fflush(NULL); /* flush all streams */ 721 sigexit(- (exitcode & 0xff)); 722 } 723 724 #else /* !JOB */ 725 726 #define set_fatal_sighandler(handler) ((void)0) 727 #define set_jobctrl_sighandler(handler) ((void)0) 728 #define set_misc_sighandler(handler) ((void)0) 729 #define hush_exit(e) exit(e) 730 731 #endif /* JOB */ 732 733 433 734 static const char *set_cwd(void) 434 735 { 435 if (cwd==bb_msg_unknown)436 cwd = NULL; /* x getcwd(arg) called free(arg)*/437 cwd = x getcwd((char *)cwd);736 if (cwd == bb_msg_unknown) 737 cwd = NULL; /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */ 738 cwd = xrealloc_getcwd_or_warn((char *)cwd); 438 739 if (!cwd) 439 740 cwd = bb_msg_unknown; … … 442 743 443 744 /* built-in 'eval' handler */ 444 static int builtin_eval(struct child_prog *child) 445 { 446 char *str = NULL; 745 static int builtin_eval(char **argv) 746 { 447 747 int rcode = EXIT_SUCCESS; 448 748 449 if ( child->argv[1]) {450 str = make_string(child->argv + 1);451 parse_ string_outer(str,FLAG_EXIT_FROM_LOOP |452 FLAG_PARSE_SEMICOLON);749 if (argv[1]) { 750 char *str = expand_strvec_to_string(argv + 1); 751 parse_and_run_string(str, PARSEFLAG_EXIT_FROM_LOOP | 752 PARSEFLAG_SEMICOLON); 453 753 free(str); 454 754 rcode = last_return_code; … … 458 758 459 759 /* built-in 'cd <path>' handler */ 460 static int builtin_cd( struct child_prog *child)461 { 462 c har *newdir;463 if ( child->argv[1] == NULL)464 newdir = getenv("HOME") ;760 static int builtin_cd(char **argv) 761 { 762 const char *newdir; 763 if (argv[1] == NULL) 764 newdir = getenv("HOME") ? : "/"; 465 765 else 466 newdir = child->argv[1];766 newdir = argv[1]; 467 767 if (chdir(newdir)) { 468 768 printf("cd: %s: %s\n", newdir, strerror(errno)); … … 473 773 } 474 774 475 /* built-in 'env' handler */ 476 static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED) 477 { 478 char **e = environ; 479 if (e == NULL) return EXIT_FAILURE; 480 for (; *e; e++) { 481 puts(*e); 482 } 775 /* built-in 'exec' handler */ 776 static int builtin_exec(char **argv) 777 { 778 if (argv[1] == NULL) 779 return EXIT_SUCCESS; /* Really? */ 780 pseudo_exec_argv(argv + 1); 781 /* never returns */ 782 } 783 784 /* built-in 'exit' handler */ 785 static int builtin_exit(char **argv) 786 { 787 // TODO: bash does it ONLY on top-level sh exit (+interacive only?) 788 //puts("exit"); /* bash does it */ 789 // TODO: warn if we have background jobs: "There are stopped jobs" 790 // On second consecutive 'exit', exit anyway. 791 792 if (argv[1] == NULL) 793 hush_exit(last_return_code); 794 /* mimic bash: exit 123abc == exit 255 + error msg */ 795 xfunc_error_retval = 255; 796 /* bash: exit -2 == exit 254, no error msg */ 797 hush_exit(xatoi(argv[1]) & 0xff); 798 } 799 800 /* built-in 'export VAR=value' handler */ 801 static int builtin_export(char **argv) 802 { 803 const char *value; 804 char *name = argv[1]; 805 806 if (name == NULL) { 807 // TODO: 808 // ash emits: export VAR='VAL' 809 // bash: declare -x VAR="VAL" 810 // (both also escape as needed (quotes, $, etc)) 811 char **e = environ; 812 if (e) 813 while (*e) 814 puts(*e++); 815 return EXIT_SUCCESS; 816 } 817 818 value = strchr(name, '='); 819 if (!value) { 820 /* They are exporting something without a =VALUE */ 821 struct variable *var; 822 823 var = get_local_var(name); 824 if (var) { 825 var->flg_export = 1; 826 putenv(var->varstr); 827 } 828 /* bash does not return an error when trying to export 829 * an undefined variable. Do likewise. */ 830 return EXIT_SUCCESS; 831 } 832 833 set_local_var(xstrdup(name), 1); 483 834 return EXIT_SUCCESS; 484 835 } 485 836 486 /* built-in 'exec' handler */ 487 static int builtin_exec(struct child_prog *child) 488 { 489 if (child->argv[1] == NULL) 490 return EXIT_SUCCESS; /* Really? */ 491 child->argv++; 492 pseudo_exec(child); 493 /* never returns */ 494 } 495 496 /* built-in 'exit' handler */ 497 static int builtin_exit(struct child_prog *child) 498 { 499 if (child->argv[1] == NULL) 500 exit(last_return_code); 501 exit (atoi(child->argv[1])); 502 } 503 504 /* built-in 'export VAR=value' handler */ 505 static int builtin_export(struct child_prog *child) 506 { 507 int res = 0; 508 char *name = child->argv[1]; 509 510 if (name == NULL) { 511 return (builtin_env(child)); 512 } 513 514 name = strdup(name); 515 516 if(name) { 517 char *value = strchr(name, '='); 518 519 if (!value) { 520 char *tmp; 521 /* They are exporting something without an =VALUE */ 522 523 value = get_local_var(name); 524 if (value) { 525 size_t ln = strlen(name); 526 527 tmp = realloc(name, ln+strlen(value)+2); 528 if(tmp==NULL) 529 res = -1; 530 else { 531 sprintf(tmp+ln, "=%s", value); 532 name = tmp; 533 } 534 } else { 535 /* bash does not return an error when trying to export 536 * an undefined variable. Do likewise. */ 537 res = 1; 538 } 539 } 540 } 541 if (res<0) 542 bb_perror_msg("export"); 543 else if(res==0) 544 res = set_local_var(name, 1); 545 else 546 res = 0; 547 free(name); 548 return res; 549 } 550 837 #if ENABLE_HUSH_JOB 551 838 /* built-in 'fg' and 'bg' handler */ 552 static int builtin_fg_bg( struct child_prog *child)839 static int builtin_fg_bg(char **argv) 553 840 { 554 841 int i, jobnum; 555 struct pipe *pi =NULL;556 557 if (!interactive )842 struct pipe *pi; 843 844 if (!interactive_fd) 558 845 return EXIT_FAILURE; 559 846 /* If they gave us no args, assume they want the last backgrounded task */ 560 if (! child->argv[1]) {847 if (!argv[1]) { 561 848 for (pi = job_list; pi; pi = pi->next) { 562 849 if (pi->jobid == last_jobid) { 563 break; 564 } 565 } 566 if (!pi) { 567 bb_error_msg("%s: no current job", child->argv[0]); 568 return EXIT_FAILURE; 569 } 570 } else { 571 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 572 bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); 573 return EXIT_FAILURE; 574 } 575 for (pi = job_list; pi; pi = pi->next) { 576 if (pi->jobid == jobnum) { 577 break; 578 } 579 } 580 if (!pi) { 581 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 582 return EXIT_FAILURE; 583 } 584 } 585 586 if (*child->argv[0] == 'f') { 850 goto found; 851 } 852 } 853 bb_error_msg("%s: no current job", argv[0]); 854 return EXIT_FAILURE; 855 } 856 if (sscanf(argv[1], "%%%d", &jobnum) != 1) { 857 bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]); 858 return EXIT_FAILURE; 859 } 860 for (pi = job_list; pi; pi = pi->next) { 861 if (pi->jobid == jobnum) { 862 goto found; 863 } 864 } 865 bb_error_msg("%s: %d: no such job", argv[0], jobnum); 866 return EXIT_FAILURE; 867 found: 868 // TODO: bash prints a string representation 869 // of job being foregrounded (like "sleep 1 | cat") 870 if (*argv[0] == 'f') { 587 871 /* Put the job into the foreground. */ 588 tcsetpgrp( shell_terminal, pi->pgrp);872 tcsetpgrp(interactive_fd, pi->pgrp); 589 873 } 590 874 591 875 /* Restart the processes in the job */ 592 for (i = 0; i < pi->num_progs; i++) 876 debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp); 877 for (i = 0; i < pi->num_progs; i++) { 878 debug_printf_jobs("reviving pid %d\n", pi->progs[i].pid); 593 879 pi->progs[i].is_stopped = 0; 594 595 if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { 596 if (i == ESRCH) { 597 remove_bg_job(pi); 880 } 881 pi->stopped_progs = 0; 882 883 i = kill(- pi->pgrp, SIGCONT); 884 if (i < 0) { 885 if (errno == ESRCH) { 886 delete_finished_bg_job(pi); 887 return EXIT_SUCCESS; 598 888 } else { 599 889 bb_perror_msg("kill (SIGCONT)"); … … 601 891 } 602 892 603 pi->stopped_progs = 0; 893 if (*argv[0] == 'f') { 894 remove_bg_job(pi); 895 return checkjobs_and_fg_shell(pi); 896 } 604 897 return EXIT_SUCCESS; 605 898 } 899 #endif 606 900 607 901 /* built-in 'help' handler */ 608 static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED) 902 #if ENABLE_HUSH_HELP 903 static int builtin_help(char **argv ATTRIBUTE_UNUSED) 609 904 { 610 905 const struct built_in_command *x; … … 613 908 printf("-------------------\n"); 614 909 for (x = bltins; x->cmd; x++) { 615 if (x->descr==NULL)616 continue;617 910 printf("%s\t%s\n", x->cmd, x->descr); 618 911 } … … 620 913 return EXIT_SUCCESS; 621 914 } 622 915 #endif 916 917 #if ENABLE_HUSH_JOB 623 918 /* built-in 'jobs' handler */ 624 static int builtin_jobs( struct child_prog *childATTRIBUTE_UNUSED)919 static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) 625 920 { 626 921 struct pipe *job; 627 c har *status_string;922 const char *status_string; 628 923 629 924 for (job = job_list; job; job = job->next) { … … 633 928 status_string = "Running"; 634 929 635 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job-> text);930 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 636 931 } 637 932 return EXIT_SUCCESS; 638 933 } 639 934 #endif 640 935 641 936 /* built-in 'pwd' handler */ 642 static int builtin_pwd( struct child_prog *dummyATTRIBUTE_UNUSED)937 static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) 643 938 { 644 939 puts(set_cwd()); … … 647 942 648 943 /* built-in 'read VAR' handler */ 649 static int builtin_read(struct child_prog *child) 650 { 651 int res; 652 653 if (child->argv[1]) { 654 char string[BUFSIZ]; 655 char *var = 0; 656 657 string[0] = 0; /* In case stdin has only EOF */ 658 /* read string */ 659 fgets(string, sizeof(string), stdin); 660 chomp(string); 661 var = malloc(strlen(child->argv[1])+strlen(string)+2); 662 if(var) { 663 sprintf(var, "%s=%s", child->argv[1], string); 664 res = set_local_var(var, 0); 665 } else 666 res = -1; 667 if (res) 668 bb_perror_msg("read"); 669 free(var); /* So not move up to avoid breaking errno */ 670 return res; 671 } else { 672 do res=getchar(); while(res!='\n' && res!=EOF); 673 return 0; 674 } 675 } 676 677 /* built-in 'set VAR=value' handler */ 678 static int builtin_set(struct child_prog *child) 679 { 680 char *temp = child->argv[1]; 681 struct variables *e; 944 static int builtin_read(char **argv) 945 { 946 char *string; 947 const char *name = argv[1] ? argv[1] : "REPLY"; 948 949 string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name)); 950 return set_local_var(string, 0); 951 } 952 953 /* built-in 'set [VAR=value]' handler */ 954 static int builtin_set(char **argv) 955 { 956 char *temp = argv[1]; 957 struct variable *e; 682 958 683 959 if (temp == NULL) 684 for (e = top_vars; e; e=e->next)685 p rintf("%s=%s\n", e->name, e->value);960 for (e = top_var; e; e = e->next) 961 puts(e->varstr); 686 962 else 687 set_local_var( temp, 0);688 689 963 set_local_var(xstrdup(temp), 0); 964 965 return EXIT_SUCCESS; 690 966 } 691 967 692 968 693 969 /* Built-in 'shift' handler */ 694 static int builtin_shift( struct child_prog *child)695 { 696 int n =1;697 if ( child->argv[1]) {698 n =atoi(child->argv[1]);699 } 700 if (n >=0 && n<global_argc) {701 /* XXX This probably breaks $0 */970 static int builtin_shift(char **argv) 971 { 972 int n = 1; 973 if (argv[1]) { 974 n = atoi(argv[1]); 975 } 976 if (n >= 0 && n < global_argc) { 977 global_argv[n] = global_argv[0]; 702 978 global_argc -= n; 703 979 global_argv += n; 704 980 return EXIT_SUCCESS; 705 } else { 706 return EXIT_FAILURE; 707 } 981 } 982 return EXIT_FAILURE; 708 983 } 709 984 710 985 /* Built-in '.' handler (read-in and execute commands from file) */ 711 static int builtin_source( struct child_prog *child)986 static int builtin_source(char **argv) 712 987 { 713 988 FILE *input; 714 989 int status; 715 990 716 if ( child->argv[1] == NULL)991 if (argv[1] == NULL) 717 992 return EXIT_FAILURE; 718 993 719 994 /* XXX search through $PATH is missing */ 720 input = fopen( child->argv[1], "r");995 input = fopen(argv[1], "r"); 721 996 if (!input) { 722 bb_error_msg(" Couldn't open file '%s'", child->argv[1]);997 bb_error_msg("cannot open '%s'", argv[1]); 723 998 return EXIT_FAILURE; 724 999 } … … 727 1002 /* XXX argv and argc are broken; need to save old global_argv 728 1003 * (pointer only is OK!) on this stack frame, 729 * set global_argv= child->argv+1, recurse, and restore. */1004 * set global_argv=argv+1, recurse, and restore. */ 730 1005 mark_open(fileno(input)); 731 status = parse_ file_outer(input);1006 status = parse_and_run_file(input); 732 1007 mark_closed(fileno(input)); 733 1008 fclose(input); 734 return (status);735 } 736 737 static int builtin_umask( struct child_prog *child)1009 return status; 1010 } 1011 1012 static int builtin_umask(char **argv) 738 1013 { 739 1014 mode_t new_umask; 740 const char *arg = child->argv[1];1015 const char *arg = argv[1]; 741 1016 char *end; 742 1017 if (arg) { 743 new_umask =strtoul(arg, &end, 8);744 if (*end !='\0' || end == arg) {1018 new_umask = strtoul(arg, &end, 8); 1019 if (*end != '\0' || end == arg) { 745 1020 return EXIT_FAILURE; 746 1021 } 747 1022 } else { 748 printf("%.3o\n", (unsigned int) (new_umask=umask(0))); 1023 new_umask = umask(0); 1024 printf("%.3o\n", (unsigned) new_umask); 749 1025 } 750 1026 umask(new_umask); … … 753 1029 754 1030 /* built-in 'unset VAR' handler */ 755 static int builtin_unset( struct child_prog *child)756 { 757 /* bash returned alreadytrue */758 unset_local_var( child->argv[1]);1031 static int builtin_unset(char **argv) 1032 { 1033 /* bash always returns true */ 1034 unset_local_var(argv[1]); 759 1035 return EXIT_SUCCESS; 760 1036 } 761 1037 762 static int builtin_not_written(struct child_prog *child)763 {764 printf("builtin_%s not written\n",child->argv[0]);765 return EXIT_FAILURE;766 }1038 //static int builtin_not_written(char **argv) 1039 //{ 1040 // printf("builtin_%s not written\n", argv[0]); 1041 // return EXIT_FAILURE; 1042 //} 767 1043 768 1044 static int b_check_space(o_string *o, int len) … … 771 1047 * in here, such as setting a maximum string length */ 772 1048 if (o->length + len > o->maxlen) { 773 char *old_data = o->data; 774 /* assert (data == NULL || o->maxlen != 0); */ 775 o->maxlen += max(2*len, B_CHUNK); 776 o->data = realloc(o->data, 1 + o->maxlen); 777 if (o->data == NULL) { 778 free(old_data); 779 } 1049 /* assert(data == NULL || o->maxlen != 0); */ 1050 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); 1051 o->data = xrealloc(o->data, 1 + o->maxlen); 780 1052 } 781 1053 return o->data == NULL; … … 784 1056 static int b_addchr(o_string *o, int ch) 785 1057 { 786 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); 787 if (b_check_space(o, 1)) return B_NOSPAC; 1058 debug_printf("b_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o); 1059 if (b_check_space(o, 1)) 1060 return B_NOSPAC; 788 1061 o->data[o->length] = ch; 789 1062 o->length++; … … 796 1069 o->length = 0; 797 1070 o->nonnull = 0; 798 if (o->data != NULL) *o->data = '\0'; 1071 if (o->data != NULL) 1072 *o->data = '\0'; 799 1073 } 800 1074 … … 812 1086 static int b_addqchr(o_string *o, int ch, int quote) 813 1087 { 814 if (quote && strchr("*?[\\", ch)) {1088 if (quote && strchr("*?[\\", ch)) { 815 1089 int rc; 816 1090 rc = b_addchr(o, '\\'); 817 if (rc) return rc; 1091 if (rc) 1092 return rc; 818 1093 } 819 1094 return b_addchr(o, ch); 820 1095 } 821 1096 822 /* belongs in utility.c */823 static char *simple_itoa(unsigned int i)824 {825 /* 21 digits plus null terminator, good for 64-bit or smaller ints */826 static char local[22];827 char *p = &local[21];828 *p-- = '\0';829 do {830 *p-- = '0' + i % 10;831 i /= 10;832 } while (i > 0);833 return p + 1;834 }835 836 static int b_adduint(o_string *o, unsigned int i)837 {838 int r;839 char *p = simple_itoa(i);840 /* no escape checking necessary */841 do r=b_addchr(o, *p++); while (r==0 && *p);842 return r;843 }844 845 1097 static int static_get(struct in_str *i) 846 1098 { 847 int ch =*i->p++;848 if (ch =='\0') return EOF;1099 int ch = *i->p++; 1100 if (ch == '\0') return EOF; 849 1101 return ch; 850 1102 } … … 855 1107 } 856 1108 857 static inline void cmdedit_set_initial_prompt(void) 858 { 859 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT 1109 #if ENABLE_HUSH_INTERACTIVE 1110 #if ENABLE_FEATURE_EDITING 1111 static void cmdedit_set_initial_prompt(void) 1112 { 1113 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 860 1114 PS1 = NULL; 861 1115 #else 862 1116 PS1 = getenv("PS1"); 863 if (PS1==0)1117 if (PS1 == NULL) 864 1118 PS1 = "\\w \\$ "; 865 1119 #endif 866 1120 } 867 868 static inline void setup_prompt_string(int promptmode, char **prompt_str) 869 { 870 debug_printf("setup_prompt_string %d ",promptmode); 871 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT 1121 #endif /* EDITING */ 1122 1123 static const char* setup_prompt_string(int promptmode) 1124 { 1125 const char *prompt_str; 1126 debug_printf("setup_prompt_string %d ", promptmode); 1127 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 872 1128 /* Set up the prompt */ 873 if (promptmode == 1) { 874 free(PS1); 875 PS1=xmalloc(strlen(cwd)+4); 876 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); 877 *prompt_str = PS1; 1129 if (promptmode == 0) { /* PS1 */ 1130 free((char*)PS1); 1131 PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#'); 1132 prompt_str = PS1; 878 1133 } else { 879 *prompt_str = PS2;1134 prompt_str = PS2; 880 1135 } 881 1136 #else 882 *prompt_str = (promptmode==1)? PS1 : PS2; 883 #endif 884 debug_printf("result %s\n",*prompt_str); 1137 prompt_str = (promptmode == 0) ? PS1 : PS2; 1138 #endif 1139 debug_printf("result '%s'\n", prompt_str); 1140 return prompt_str; 885 1141 } 886 1142 887 1143 static void get_user_input(struct in_str *i) 888 1144 { 889 char *prompt_str; 890 static char the_command[BUFSIZ]; 891 892 setup_prompt_string(i->promptmode, &prompt_str); 893 #ifdef CONFIG_FEATURE_COMMAND_EDITING 894 /* 895 ** enable command line editing only while a command line 896 ** is actually being read; otherwise, we'll end up bequeathing 897 ** atexit() handlers and other unwanted stuff to our 898 ** child processes (rob@sysgo.de) 899 */ 900 cmdedit_read_input(prompt_str, the_command); 1145 int r; 1146 const char *prompt_str; 1147 1148 prompt_str = setup_prompt_string(i->promptmode); 1149 #if ENABLE_FEATURE_EDITING 1150 /* Enable command line editing only while a command line 1151 * is actually being read; otherwise, we'll end up bequeathing 1152 * atexit() handlers and other unwanted stuff to our 1153 * child processes (rob@sysgo.de) */ 1154 r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state); 1155 i->eof_flag = (r < 0); 1156 if (i->eof_flag) { /* EOF/error detected */ 1157 user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 1158 user_input_buf[1] = '\0'; 1159 } 901 1160 #else 902 1161 fputs(prompt_str, stdout); 903 1162 fflush(stdout); 904 the_command[0]=fgetc(i->file); 905 the_command[1]='\0'; 906 #endif 907 fflush(stdout); 908 i->p = the_command; 909 } 1163 user_input_buf[0] = r = fgetc(i->file); 1164 /*user_input_buf[1] = '\0'; - already is and never changed */ 1165 i->eof_flag = (r == EOF); 1166 #endif 1167 i->p = user_input_buf; 1168 } 1169 #endif /* INTERACTIVE */ 910 1170 911 1171 /* This is the magic location that prints prompts … … 915 1175 int ch; 916 1176 917 ch = 0;918 1177 /* If there is data waiting, eat it up */ 919 1178 if (i->p && *i->p) { 920 ch=*i->p++; 1179 #if ENABLE_HUSH_INTERACTIVE 1180 take_cached: 1181 #endif 1182 ch = *i->p++; 1183 if (i->eof_flag && !*i->p) 1184 ch = EOF; 921 1185 } else { 922 1186 /* need to double check i->file because we might be doing something 923 1187 * more complicated by now, like sourcing or substituting. */ 924 if (i->__promptme && interactive && i->file == stdin) { 925 while(! i->p || (interactive && strlen(i->p)==0) ) { 1188 #if ENABLE_HUSH_INTERACTIVE 1189 if (interactive_fd && i->promptme && i->file == stdin) { 1190 do { 926 1191 get_user_input(i); 927 } 928 i->promptmode =2;929 i-> __promptme = 0;930 if (i->p && *i->p) {931 ch=*i->p++;932 } 933 } else {934 ch = fgetc(i->file);935 }936 937 debug_printf("b_getch: got a %d\n", ch);938 }939 if (ch == '\n') i->__promptme=1; 1192 } while (!*i->p); /* need non-empty line */ 1193 i->promptmode = 1; /* PS2 */ 1194 i->promptme = 0; 1195 goto take_cached; 1196 } 1197 #endif 1198 ch = fgetc(i->file); 1199 } 1200 debug_printf("file_get: got a '%c' %d\n", ch, ch); 1201 #if ENABLE_HUSH_INTERACTIVE 1202 if (ch == '\n') 1203 i->promptme = 1; 1204 #endif 940 1205 return ch; 941 1206 } … … 946 1211 static int file_peek(struct in_str *i) 947 1212 { 1213 int ch; 948 1214 if (i->p && *i->p) { 1215 if (i->eof_flag && !i->p[1]) 1216 return EOF; 949 1217 return *i->p; 950 } else { 951 i->peek_buf[0] = fgetc(i->file); 952 i->peek_buf[1] = '\0'; 953 i->p = i->peek_buf; 954 debug_printf("b_peek: got a %d\n", *i->p); 955 return *i->p; 956 } 1218 } 1219 ch = fgetc(i->file); 1220 i->eof_flag = (ch == EOF); 1221 i->peek_buf[0] = ch; 1222 i->peek_buf[1] = '\0'; 1223 i->p = i->peek_buf; 1224 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p); 1225 return ch; 957 1226 } 958 1227 … … 961 1230 i->peek = file_peek; 962 1231 i->get = file_get; 963 i->__promptme=1; 964 i->promptmode=1; 1232 #if ENABLE_HUSH_INTERACTIVE 1233 i->promptme = 1; 1234 i->promptmode = 0; /* PS1 */ 1235 #endif 965 1236 i->file = f; 966 1237 i->p = NULL; … … 971 1242 i->peek = static_peek; 972 1243 i->get = static_get; 973 i->__promptme=1; 974 i->promptmode=1; 1244 #if ENABLE_HUSH_INTERACTIVE 1245 i->promptme = 1; 1246 i->promptmode = 0; /* PS1 */ 1247 #endif 975 1248 i->p = s; 1249 i->eof_flag = 0; 976 1250 } 977 1251 … … 997 1271 { 998 1272 struct close_me *c; 999 for (c =close_me_head; c; c=c->next) {1273 for (c = close_me_head; c; c = c->next) { 1000 1274 close(c->fd); 1001 1275 } … … 1010 1284 struct redir_struct *redir; 1011 1285 1012 for (redir =prog->redirects; redir; redir=redir->next) {1286 for (redir = prog->redirects; redir; redir = redir->next) { 1013 1287 if (redir->dup == -1 && redir->word.gl_pathv == NULL) { 1014 1288 /* something went wrong in the parse. Pretend it didn't happen */ … … 1016 1290 } 1017 1291 if (redir->dup == -1) { 1018 mode =redir_table[redir->type].mode;1019 openfd = open (redir->word.gl_pathv[0], mode, 0666);1292 mode = redir_table[redir->type].mode; 1293 openfd = open_or_warn(redir->word.gl_pathv[0], mode); 1020 1294 if (openfd < 0) { 1021 1295 /* this could get lost if stderr has been redirected, but 1022 1296 bash and ash both lose it as well (though zsh doesn't!) */ 1023 bb_perror_msg("error opening %s", redir->word.gl_pathv[0]);1024 1297 return 1; 1025 1298 } … … 1037 1310 dup2(openfd, redir->fd); 1038 1311 if (redir->dup == -1) 1039 close 1312 close(openfd); 1040 1313 } 1041 1314 } … … 1047 1320 { 1048 1321 int i, fd; 1049 for (i =0; i<3; i++) {1322 for (i = 0; i < 3; i++) { 1050 1323 fd = squirrel[i]; 1051 1324 if (fd != -1) { 1052 /* No error checking. I sure wouldn't know what 1053 * to do with an error if I found one! */ 1054 dup2(fd, i); 1055 close(fd); 1325 /* We simply die on error */ 1326 xmove_fd(fd, i); 1056 1327 } 1057 1328 } … … 1061 1332 /* XXX no exit() here. If you don't exec, use _exit instead. 1062 1333 * The at_exit handlers apparently confuse the calling process, 1063 * in particular stdin handling. Not sure why? */1064 static void pseudo_exec (struct child_prog *child)1334 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 1335 static void pseudo_exec_argv(char **argv) 1065 1336 { 1066 1337 int i, rcode; 1067 1338 char *p; 1068 1339 const struct built_in_command *x; 1340 1341 for (i = 0; is_assignment(argv[i]); i++) { 1342 debug_printf_exec("pid %d environment modification: %s\n", 1343 getpid(), argv[i]); 1344 // FIXME: vfork case?? 1345 p = expand_string_to_string(argv[i]); 1346 putenv(p); 1347 } 1348 argv += i; 1349 /* If a variable is assigned in a forest, and nobody listens, 1350 * was it ever really set? 1351 */ 1352 if (argv[0] == NULL) { 1353 _exit(EXIT_SUCCESS); 1354 } 1355 1356 argv = expand_strvec_to_strvec(argv); 1357 1358 /* 1359 * Check if the command matches any of the builtins. 1360 * Depending on context, this might be redundant. But it's 1361 * easier to waste a few CPU cycles than it is to figure out 1362 * if this is one of those cases. 1363 */ 1364 for (x = bltins; x->cmd; x++) { 1365 if (strcmp(argv[0], x->cmd) == 0) { 1366 debug_printf_exec("running builtin '%s'\n", argv[0]); 1367 rcode = x->function(argv); 1368 fflush(stdout); 1369 _exit(rcode); 1370 } 1371 } 1372 1373 /* Check if the command matches any busybox applets */ 1374 #if ENABLE_FEATURE_SH_STANDALONE 1375 if (strchr(argv[0], '/') == NULL) { 1376 const struct bb_applet *a = find_applet_by_name(argv[0]); 1377 if (a) { 1378 if (a->noexec) { 1379 current_applet = a; 1380 debug_printf_exec("running applet '%s'\n", argv[0]); 1381 // is it ok that run_current_applet_and_exit() does exit(), not _exit()? 1382 run_current_applet_and_exit(argv); 1383 } 1384 /* re-exec ourselves with the new arguments */ 1385 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 1386 execvp(bb_busybox_exec_path, argv); 1387 /* If they called chroot or otherwise made the binary no longer 1388 * executable, fall through */ 1389 } 1390 } 1391 #endif 1392 1393 debug_printf_exec("execing '%s'\n", argv[0]); 1394 execvp(argv[0], argv); 1395 bb_perror_msg("cannot exec '%s'", argv[0]); 1396 _exit(1); 1397 } 1398 1399 static void pseudo_exec(struct child_prog *child) 1400 { 1401 // FIXME: buggy wrt NOMMU! Must not modify any global data 1402 // until it does exec/_exit, but currently it does. 1403 int rcode; 1404 1069 1405 if (child->argv) { 1070 for (i=0; is_assignment(child->argv[i]); i++) { 1071 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); 1072 p = insert_var_value(child->argv[i]); 1073 putenv(strdup(p)); 1074 if (p != child->argv[i]) free(p); 1075 } 1076 child->argv+=i; /* XXX this hack isn't so horrible, since we are about 1077 to exit, and therefore don't need to keep data 1078 structures consistent for free() use. */ 1079 /* If a variable is assigned in a forest, and nobody listens, 1080 * was it ever really set? 1081 */ 1082 if (child->argv[0] == NULL) { 1083 _exit(EXIT_SUCCESS); 1084 } 1085 1086 /* 1087 * Check if the command matches any of the builtins. 1088 * Depending on context, this might be redundant. But it's 1089 * easier to waste a few CPU cycles than it is to figure out 1090 * if this is one of those cases. 1091 */ 1092 for (x = bltins; x->cmd; x++) { 1093 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1094 debug_printf("builtin exec %s\n", child->argv[0]); 1095 rcode = x->function(child); 1096 fflush(stdout); 1097 _exit(rcode); 1098 } 1099 } 1100 1101 /* Check if the command matches any busybox internal commands 1102 * ("applets") here. 1103 * FIXME: This feature is not 100% safe, since 1104 * BusyBox is not fully reentrant, so we have no guarantee the things 1105 * from the .bss are still zeroed, or that things from .data are still 1106 * at their defaults. We could exec ourself from /proc/self/exe, but I 1107 * really dislike relying on /proc for things. We could exec ourself 1108 * from global_argv[0], but if we are in a chroot, we may not be able 1109 * to find ourself... */ 1110 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 1111 { 1112 int argc_l; 1113 char** argv_l=child->argv; 1114 char *name = child->argv[0]; 1115 1116 /* Count argc for use in a second... */ 1117 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); 1118 optind = 1; 1119 debug_printf("running applet %s\n", name); 1120 run_applet_by_name(name, argc_l, child->argv); 1121 } 1122 #endif 1123 debug_printf("exec of %s\n",child->argv[0]); 1124 execvp(child->argv[0],child->argv); 1125 bb_perror_msg("couldn't exec: %s",child->argv[0]); 1126 _exit(1); 1127 } else if (child->group) { 1128 debug_printf("runtime nesting to group\n"); 1129 interactive=0; /* crucial!!!! */ 1406 pseudo_exec_argv(child->argv); 1407 } 1408 1409 if (child->group) { 1410 // FIXME: do not modify globals! Think vfork! 1411 #if ENABLE_HUSH_INTERACTIVE 1412 debug_printf_exec("pseudo_exec: setting interactive_fd=0\n"); 1413 interactive_fd = 0; /* crucial!!!! */ 1414 #endif 1415 debug_printf_exec("pseudo_exec: run_list_real\n"); 1130 1416 rcode = run_list_real(child->group); 1131 1417 /* OK to leak memory by not calling free_pipe_list, 1132 1418 * since this process is about to exit */ 1133 1419 _exit(rcode); 1134 } else { 1135 /* Can happen. See what bash does with ">foo" by itself. */ 1136 debug_printf("trying to pseudo_exec null command\n"); 1137 _exit(EXIT_SUCCESS); 1138 } 1420 } 1421 1422 /* Can happen. See what bash does with ">foo" by itself. */ 1423 debug_printf("trying to pseudo_exec null command\n"); 1424 _exit(EXIT_SUCCESS); 1425 } 1426 1427 #if ENABLE_HUSH_JOB 1428 static const char *get_cmdtext(struct pipe *pi) 1429 { 1430 char **argv; 1431 char *p; 1432 int len; 1433 1434 /* This is subtle. ->cmdtext is created only on first backgrounding. 1435 * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...) 1436 * On subsequent bg argv is trashed, but we won't use it */ 1437 if (pi->cmdtext) 1438 return pi->cmdtext; 1439 argv = pi->progs[0].argv; 1440 if (!argv || !argv[0]) 1441 return (pi->cmdtext = xzalloc(1)); 1442 1443 len = 0; 1444 do len += strlen(*argv) + 1; while (*++argv); 1445 pi->cmdtext = p = xmalloc(len); 1446 argv = pi->progs[0].argv; 1447 do { 1448 len = strlen(*argv); 1449 memcpy(p, *argv, len); 1450 p += len; 1451 *p++ = ' '; 1452 } while (*++argv); 1453 p[-1] = '\0'; 1454 return pi->cmdtext; 1139 1455 } 1140 1456 … … 1142 1458 { 1143 1459 struct pipe *thejob; 1460 int i; 1144 1461 1145 1462 /* Linear search for the ID of the job to use */ … … 1149 1466 pi->jobid = thejob->jobid + 1; 1150 1467 1151 /* add thejob to the list of running jobs */1468 /* Add thejob to the list of running jobs */ 1152 1469 if (!job_list) { 1153 1470 thejob = job_list = xmalloc(sizeof(*thejob)); 1154 1471 } else { 1155 for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; 1472 for (thejob = job_list; thejob->next; thejob = thejob->next) 1473 continue; 1156 1474 thejob->next = xmalloc(sizeof(*thejob)); 1157 1475 thejob = thejob->next; 1158 1476 } 1159 1477 1160 /* physically copy the struct job */1478 /* Physically copy the struct job */ 1161 1479 memcpy(thejob, pi, sizeof(struct pipe)); 1480 thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs); 1481 /* We cannot copy entire pi->progs[] vector! Double free()s will happen */ 1482 for (i = 0; i < pi->num_progs; i++) { 1483 // TODO: do we really need to have so many fields which are just dead weight 1484 // at execution stage? 1485 thejob->progs[i].pid = pi->progs[i].pid; 1486 /* all other fields are not used and stay zero */ 1487 } 1162 1488 thejob->next = NULL; 1163 thejob->running_progs = thejob->num_progs; 1164 thejob->stopped_progs = 0; 1165 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ 1166 1167 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) 1168 { 1169 char *bar=thejob->text; 1170 char **foo=pi->progs[0].argv; 1171 while(foo && *foo) { 1172 bar += sprintf(bar, "%s ", *foo++); 1173 } 1174 } 1175 1176 /* we don't wait for background thejobs to return -- append it 1489 thejob->cmdtext = xstrdup(get_cmdtext(pi)); 1490 1491 /* We don't wait for background thejobs to return -- append it 1177 1492 to the list of backgrounded thejobs and leave it alone */ 1178 printf("[%d] %d \n", thejob->jobid, thejob->progs[0].pid);1493 printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); 1179 1494 last_bg_pid = thejob->progs[0].pid; 1180 1495 last_jobid = thejob->jobid; 1181 1496 } 1182 1497 1183 /* remove a backgrounded job */1184 1498 static void remove_bg_job(struct pipe *pi) 1185 1499 { … … 1198 1512 else 1199 1513 last_jobid = 0; 1200 1514 } 1515 1516 /* remove a backgrounded job */ 1517 static void delete_finished_bg_job(struct pipe *pi) 1518 { 1519 remove_bg_job(pi); 1201 1520 pi->stopped_progs = 0; 1202 1521 free_pipe(pi, 0); 1203 1522 free(pi); 1204 1523 } 1524 #endif /* JOB */ 1205 1525 1206 1526 /* Checks to see if any processes have exited -- if they … … 1210 1530 int attributes; 1211 1531 int status; 1532 #if ENABLE_HUSH_JOB 1212 1533 int prognum = 0; 1213 1534 struct pipe *pi; 1535 #endif 1214 1536 pid_t childpid; 1537 int rcode = 0; 1215 1538 1216 1539 attributes = WUNTRACED; 1217 if (fg_pipe ==NULL) {1540 if (fg_pipe == NULL) { 1218 1541 attributes |= WNOHANG; 1219 1542 } 1220 1543 1544 /* Do we do this right? 1545 * bash-3.00# sleep 20 | false 1546 * <ctrl-Z pressed> 1547 * [3]+ Stopped sleep 20 | false 1548 * bash-3.00# echo $? 1549 * 1 <========== bg pipe is not fully done, but exitcode is already known! 1550 */ 1551 1552 //FIXME: non-interactive bash does not continue even if all processes in fg pipe 1553 //are stopped. Testcase: "cat | cat" in a script (not on command line) 1554 // + killall -STOP cat 1555 1556 wait_more: 1221 1557 while ((childpid = waitpid(-1, &status, attributes)) > 0) { 1558 const int dead = WIFEXITED(status) || WIFSIGNALED(status); 1559 1560 #ifdef DEBUG_SHELL_JOBS 1561 if (WIFSTOPPED(status)) 1562 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n", 1563 childpid, WSTOPSIG(status), WEXITSTATUS(status)); 1564 if (WIFSIGNALED(status)) 1565 debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n", 1566 childpid, WTERMSIG(status), WEXITSTATUS(status)); 1567 if (WIFEXITED(status)) 1568 debug_printf_jobs("pid %d exited, exitcode %d\n", 1569 childpid, WEXITSTATUS(status)); 1570 #endif 1571 /* Were we asked to wait for fg pipe? */ 1222 1572 if (fg_pipe) { 1223 int i, rcode = 0; 1224 for (i=0; i < fg_pipe->num_progs; i++) { 1573 int i; 1574 for (i = 0; i < fg_pipe->num_progs; i++) { 1575 debug_printf_jobs("check pid %d\n", fg_pipe->progs[i].pid); 1225 1576 if (fg_pipe->progs[i].pid == childpid) { 1226 if (i==fg_pipe->num_progs-1) 1227 rcode=WEXITSTATUS(status); 1228 (fg_pipe->num_progs)--; 1229 return(rcode); 1577 /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ 1578 if (dead) { 1579 fg_pipe->progs[i].pid = 0; 1580 fg_pipe->running_progs--; 1581 if (i == fg_pipe->num_progs-1) 1582 /* last process gives overall exitstatus */ 1583 rcode = WEXITSTATUS(status); 1584 } else { 1585 fg_pipe->progs[i].is_stopped = 1; 1586 fg_pipe->stopped_progs++; 1587 } 1588 debug_printf_jobs("fg_pipe: running_progs %d stopped_progs %d\n", 1589 fg_pipe->running_progs, fg_pipe->stopped_progs); 1590 if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) { 1591 /* All processes in fg pipe have exited/stopped */ 1592 #if ENABLE_HUSH_JOB 1593 if (fg_pipe->running_progs) 1594 insert_bg_job(fg_pipe); 1595 #endif 1596 return rcode; 1597 } 1598 /* There are still running processes in the fg pipe */ 1599 goto wait_more; 1230 1600 } 1231 1601 } 1232 } 1233 1602 /* fall through to searching process in bg pipes */ 1603 } 1604 1605 #if ENABLE_HUSH_JOB 1606 /* We asked to wait for bg or orphaned children */ 1607 /* No need to remember exitcode in this case */ 1234 1608 for (pi = job_list; pi; pi = pi->next) { 1235 1609 prognum = 0; 1236 while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { 1610 while (prognum < pi->num_progs) { 1611 if (pi->progs[prognum].pid == childpid) 1612 goto found_pi_and_prognum; 1237 1613 prognum++; 1238 1614 } 1239 if (prognum < pi->num_progs)1240 break; 1241 } 1242 1243 if(pi==NULL) {1244 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);1245 continue; 1246 } 1247 1248 if ( WIFEXITED(status) || WIFSIGNALED(status)) {1615 } 1616 #endif 1617 1618 /* Happens when shell is used as init process (init=/bin/sh) */ 1619 debug_printf("checkjobs: pid %d was not in our list!\n", childpid); 1620 goto wait_more; 1621 1622 #if ENABLE_HUSH_JOB 1623 found_pi_and_prognum: 1624 if (dead) { 1249 1625 /* child exited */ 1626 pi->progs[prognum].pid = 0; 1250 1627 pi->running_progs--; 1251 pi->progs[prognum].pid = 0;1252 1253 1628 if (!pi->running_progs) { 1254 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); 1255 remove_bg_job(pi); 1629 printf(JOB_STATUS_FORMAT, pi->jobid, 1630 "Done", pi->cmdtext); 1631 delete_finished_bg_job(pi); 1256 1632 } 1257 1633 } else { … … 1259 1635 pi->stopped_progs++; 1260 1636 pi->progs[prognum].is_stopped = 1; 1261 1262 #if 0 1263 /* Printing this stuff is a pain, since it tends to 1264 * overwrite the prompt an inconveinient moments. So 1265 * don't do that. */ 1266 if (pi->stopped_progs == pi->num_progs) { 1267 printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); 1268 } 1269 #endif 1270 } 1271 } 1272 1273 if (childpid == -1 && errno != ECHILD) 1637 } 1638 #endif 1639 } 1640 1641 /* wait found no children or failed */ 1642 1643 if (childpid && errno != ECHILD) 1274 1644 bb_perror_msg("waitpid"); 1275 1276 /* move the shell to the foreground */ 1277 //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) 1278 // bb_perror_msg("tcsetpgrp-2"); 1279 return -1; 1280 } 1281 1282 /* Figure out our controlling tty, checking in order stderr, 1283 * stdin, and stdout. If check_pgrp is set, also check that 1284 * we belong to the foreground process group associated with 1285 * that tty. The value of shell_terminal is needed in order to call 1286 * tcsetpgrp(shell_terminal, ...); */ 1287 #if 0 1288 static void controlling_tty(int check_pgrp) 1289 { 1290 pid_t curpgrp; 1291 1292 if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 1293 && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 1294 && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) 1295 goto shell_terminal_error; 1296 1297 if (check_pgrp && curpgrp != getpgid(0)) 1298 goto shell_terminal_error; 1299 1300 return; 1301 1302 shell_terminal_error: 1303 shell_terminal = -1; 1304 return; 1645 return rcode; 1646 } 1647 1648 #if ENABLE_HUSH_JOB 1649 static int checkjobs_and_fg_shell(struct pipe* fg_pipe) 1650 { 1651 pid_t p; 1652 int rcode = checkjobs(fg_pipe); 1653 /* Job finished, move the shell to the foreground */ 1654 p = getpgid(0); /* pgid of our process */ 1655 debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p); 1656 if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY) 1657 bb_perror_msg("tcsetpgrp-4a"); 1658 return rcode; 1305 1659 } 1306 1660 #endif … … 1321 1675 * now has its stdout directed to the input of the appropriate pipe, 1322 1676 * so this routine is noticeably simpler. 1677 * 1678 * Returns -1 only if started some children. IOW: we have to 1679 * mask out retvals of builtins etc with 0xff! 1323 1680 */ 1324 1681 static int run_pipe_real(struct pipe *pi) … … 1330 1687 const struct built_in_command *x; 1331 1688 char *p; 1689 /* it is not always needed, but we aim to smaller code */ 1690 int squirrel[] = { -1, -1, -1 }; 1691 int rcode; 1692 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); 1693 1694 debug_printf_exec("run_pipe_real start: single_fg=%d\n", single_fg); 1332 1695 1333 1696 nextin = 0; 1697 #if ENABLE_HUSH_JOB 1334 1698 pi->pgrp = -1; 1699 #endif 1700 pi->running_progs = 1; 1701 pi->stopped_progs = 0; 1335 1702 1336 1703 /* Check if this is a simple builtin (not part of a pipe). … … 1338 1705 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. 1339 1706 */ 1340 if (pi->num_progs == 1) child = & (pi->progs[0]); 1341 if (pi->num_progs == 1 && child->group && child->subshell == 0) { 1342 int squirrel[] = {-1, -1, -1}; 1343 int rcode; 1707 child = &(pi->progs[0]); 1708 if (single_fg && child->group && child->subshell == 0) { 1344 1709 debug_printf("non-subshell grouping\n"); 1345 1710 setup_redirects(child, squirrel); 1346 /* XXX could we merge code with following builtin case, 1347 * by creating a pseudo builtin that calls run_list_real? */ 1711 debug_printf_exec(": run_list_real\n"); 1348 1712 rcode = run_list_real(child->group); 1349 1713 restore_redirects(squirrel); 1350 return rcode; 1351 } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { 1352 for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } 1353 if (i!=0 && child->argv[i]==NULL) { 1714 debug_printf_exec("run_pipe_real return %d\n", rcode); 1715 return rcode; // do we need to add '... & 0xff' ? 1716 } 1717 1718 if (single_fg && child->argv != NULL) { 1719 char **argv_expanded; 1720 char **argv = child->argv; 1721 1722 for (i = 0; is_assignment(argv[i]); i++) 1723 continue; 1724 if (i != 0 && argv[i] == NULL) { 1354 1725 /* assignments, but no command: set the local environment */ 1355 for (i=0; child->argv[i]!=NULL; i++) { 1356 1357 /* Ok, this case is tricky. We have to decide if this is a 1358 * local variable, or an already exported variable. If it is 1359 * already exported, we have to export the new value. If it is 1360 * not exported, we need only set this as a local variable. 1361 * This junk is all to decide whether or not to export this 1362 * variable. */ 1363 int export_me=0; 1364 char *name, *value; 1365 name = bb_xstrdup(child->argv[i]); 1366 debug_printf("Local environment set: %s\n", name); 1367 value = strchr(name, '='); 1368 if (value) 1369 *value=0; 1370 if ( get_local_var(name)) { 1371 export_me=1; 1372 } 1373 free(name); 1374 p = insert_var_value(child->argv[i]); 1375 set_local_var(p, export_me); 1376 if (p != child->argv[i]) free(p); 1726 for (i = 0; argv[i] != NULL; i++) { 1727 debug_printf("local environment set: %s\n", argv[i]); 1728 p = expand_string_to_string(argv[i]); 1729 set_local_var(p, 0); 1377 1730 } 1378 1731 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1379 1732 } 1380 for (i = 0; is_assignment(child->argv[i]); i++) { 1381 p = insert_var_value(child->argv[i]); 1382 putenv(strdup(p)); 1383 if (p != child->argv[i]) { 1384 child->sp--; 1385 free(p); 1386 } 1387 } 1388 if (child->sp) { 1389 char * str = NULL; 1390 1391 str = make_string((child->argv + i)); 1392 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); 1393 free(str); 1394 return last_return_code; 1733 for (i = 0; is_assignment(argv[i]); i++) { 1734 p = expand_string_to_string(argv[i]); 1735 //sp: child->sp--; 1736 putenv(p); 1395 1737 } 1396 1738 for (x = bltins; x->cmd; x++) { 1397 if (strcmp(child->argv[i], x->cmd) == 0 ) { 1398 int squirrel[] = {-1, -1, -1}; 1399 int rcode; 1400 if (x->function == builtin_exec && child->argv[i+1]==NULL) { 1739 if (strcmp(argv[i], x->cmd) == 0) { 1740 if (x->function == builtin_exec && argv[i+1] == NULL) { 1401 1741 debug_printf("magic exec\n"); 1402 setup_redirects(child, NULL);1742 setup_redirects(child, NULL); 1403 1743 return EXIT_SUCCESS; 1404 1744 } 1405 debug_printf("builtin inline %s\n", child->argv[0]);1745 debug_printf("builtin inline %s\n", argv[0]); 1406 1746 /* XXX setup_redirects acts on file descriptors, not FILEs. 1407 1747 * This is perfect for work that comes after exec(). … … 1409 1749 * things seem to work with glibc. */ 1410 1750 setup_redirects(child, squirrel); 1411 child->argv+=i; /* XXX horrible hack */ 1412 rcode = x->function(child); 1413 child->argv-=i; /* XXX restore hack so free() can work right */ 1751 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); 1752 //sp: if (child->sp) /* btw we can do it unconditionally... */ 1753 argv_expanded = expand_strvec_to_strvec(argv + i); 1754 rcode = x->function(argv_expanded) & 0xff; 1755 free(argv_expanded); 1414 1756 restore_redirects(squirrel); 1757 debug_printf_exec("run_pipe_real return %d\n", rcode); 1415 1758 return rcode; 1416 1759 } 1417 1760 } 1418 } 1761 #if ENABLE_FEATURE_SH_STANDALONE 1762 { 1763 const struct bb_applet *a = find_applet_by_name(argv[i]); 1764 if (a && a->nofork) { 1765 setup_redirects(child, squirrel); 1766 save_nofork_data(&nofork_save); 1767 argv_expanded = argv + i; 1768 //sp: if (child->sp) 1769 argv_expanded = expand_strvec_to_strvec(argv + i); 1770 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); 1771 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded) & 0xff; 1772 free(argv_expanded); 1773 restore_redirects(squirrel); 1774 debug_printf_exec("run_pipe_real return %d\n", rcode); 1775 return rcode; 1776 } 1777 } 1778 #endif 1779 } 1780 1781 /* Going to fork a child per each pipe member */ 1782 pi->running_progs = 0; 1783 1784 /* Disable job control signals for shell (parent) and 1785 * for initial child code after fork */ 1786 set_jobctrl_sighandler(SIG_IGN); 1419 1787 1420 1788 for (i = 0; i < pi->num_progs; i++) { 1421 child = & (pi->progs[i]); 1789 child = &(pi->progs[i]); 1790 if (child->argv) 1791 debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); 1792 else 1793 debug_printf_exec(": pipe member with no argv\n"); 1422 1794 1423 1795 /* pipes are inserted between pairs of commands */ 1424 1796 if ((i + 1) < pi->num_progs) { 1425 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");1797 pipe(pipefds); 1426 1798 nextout = pipefds[1]; 1427 1799 } else { 1428 nextout =1;1800 nextout = 1; 1429 1801 pipefds[0] = -1; 1430 1802 } 1431 1803 1432 1804 /* XXX test for failed fork()? */ 1433 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)1434 if (!(child->pid = fork()))1805 #if BB_MMU 1806 child->pid = fork(); 1435 1807 #else 1436 if (!(child->pid = vfork())) 1437 #endif 1438 { 1439 /* Set the handling for job control signals back to the default. */ 1440 signal(SIGINT, SIG_DFL); 1441 signal(SIGQUIT, SIG_DFL); 1442 signal(SIGTERM, SIG_DFL); 1443 signal(SIGTSTP, SIG_DFL); 1444 signal(SIGTTIN, SIG_DFL); 1445 signal(SIGTTOU, SIG_DFL); 1446 signal(SIGCHLD, SIG_DFL); 1447 1808 child->pid = vfork(); 1809 #endif 1810 if (!child->pid) { /* child */ 1811 /* Every child adds itself to new process group 1812 * with pgid == pid of first child in pipe */ 1813 #if ENABLE_HUSH_JOB 1814 if (run_list_level == 1 && interactive_fd) { 1815 /* Don't do pgrp restore anymore on fatal signals */ 1816 set_fatal_sighandler(SIG_DFL); 1817 if (pi->pgrp < 0) /* true for 1st process only */ 1818 pi->pgrp = getpid(); 1819 if (setpgid(0, pi->pgrp) == 0 && pi->followup != PIPE_BG) { 1820 /* We do it in *every* child, not just first, 1821 * to avoid races */ 1822 tcsetpgrp(interactive_fd, pi->pgrp); 1823 } 1824 } 1825 #endif 1826 /* in non-interactive case fatal sigs are already SIG_DFL */ 1448 1827 close_all(); 1449 1450 1828 if (nextin != 0) { 1451 1829 dup2(nextin, 0); … … 1456 1834 close(nextout); 1457 1835 } 1458 if (pipefds[0] !=-1) {1836 if (pipefds[0] != -1) { 1459 1837 close(pipefds[0]); /* opposite end of our output pipe */ 1460 1838 } 1461 1462 1839 /* Like bash, explicit redirects override pipes, 1463 1840 * and the pipe fd is available for dup'ing. */ 1464 setup_redirects(child,NULL); 1465 1466 if (interactive && pi->followup!=PIPE_BG) { 1467 /* If we (the child) win the race, put ourselves in the process 1468 * group whose leader is the first process in this pipe. */ 1469 if (pi->pgrp < 0) { 1470 pi->pgrp = getpid(); 1471 } 1472 if (setpgid(0, pi->pgrp) == 0) { 1473 tcsetpgrp(2, pi->pgrp); 1474 } 1475 } 1476 1841 setup_redirects(child, NULL); 1842 1843 /* Restore default handlers just prior to exec */ 1844 set_jobctrl_sighandler(SIG_DFL); 1845 set_misc_sighandler(SIG_DFL); 1846 signal(SIGCHLD, SIG_DFL); 1477 1847 pseudo_exec(child); 1478 1848 } 1479 1849 1480 1481 /* put our child in the process group whose leader is the 1482 first process in this pipe */ 1483 if (pi->pgrp < 0) { 1850 pi->running_progs++; 1851 1852 #if ENABLE_HUSH_JOB 1853 /* Second and next children need to know pid of first one */ 1854 if (pi->pgrp < 0) 1484 1855 pi->pgrp = child->pid; 1485 } 1486 /* Don't check for errors. The child may be dead already, 1487 * in which case setpgid returns error code EACCES. */ 1488 setpgid(child->pid, pi->pgrp); 1489 1856 #endif 1490 1857 if (nextin != 0) 1491 1858 close(nextin); … … 1497 1864 nextin = pipefds[0]; 1498 1865 } 1866 debug_printf_exec("run_pipe_real return -1\n"); 1499 1867 return -1; 1500 1868 } 1501 1869 1870 #ifndef debug_print_tree 1871 static void debug_print_tree(struct pipe *pi, int lvl) 1872 { 1873 static const char *PIPE[] = { 1874 [PIPE_SEQ] = "SEQ", 1875 [PIPE_AND] = "AND", 1876 [PIPE_OR ] = "OR" , 1877 [PIPE_BG ] = "BG" , 1878 }; 1879 static const char *RES[] = { 1880 [RES_NONE ] = "NONE" , 1881 #if ENABLE_HUSH_IF 1882 [RES_IF ] = "IF" , 1883 [RES_THEN ] = "THEN" , 1884 [RES_ELIF ] = "ELIF" , 1885 [RES_ELSE ] = "ELSE" , 1886 [RES_FI ] = "FI" , 1887 #endif 1888 #if ENABLE_HUSH_LOOPS 1889 [RES_FOR ] = "FOR" , 1890 [RES_WHILE] = "WHILE", 1891 [RES_UNTIL] = "UNTIL", 1892 [RES_DO ] = "DO" , 1893 [RES_DONE ] = "DONE" , 1894 [RES_IN ] = "IN" , 1895 #endif 1896 [RES_XXXX ] = "XXXX" , 1897 [RES_SNTX ] = "SNTX" , 1898 }; 1899 1900 int pin, prn; 1901 1902 pin = 0; 1903 while (pi) { 1904 fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", 1905 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); 1906 prn = 0; 1907 while (prn < pi->num_progs) { 1908 struct child_prog *child = &pi->progs[prn]; 1909 char **argv = child->argv; 1910 1911 fprintf(stderr, "%*s prog %d", lvl*2, "", prn); 1912 if (child->group) { 1913 fprintf(stderr, " group %s: (argv=%p)\n", 1914 (child->subshell ? "()" : "{}"), 1915 argv); 1916 debug_print_tree(child->group, lvl+1); 1917 prn++; 1918 continue; 1919 } 1920 if (argv) while (*argv) { 1921 fprintf(stderr, " '%s'", *argv); 1922 argv++; 1923 } 1924 fprintf(stderr, "\n"); 1925 prn++; 1926 } 1927 pi = pi->next; 1928 pin++; 1929 } 1930 } 1931 #endif 1932 1933 /* NB: called by pseudo_exec, and therefore must not modify any 1934 * global data until exec/_exit (we can be a child after vfork!) */ 1502 1935 static int run_list_real(struct pipe *pi) 1503 1936 { 1504 char *save_name = NULL;1505 char **list = NULL;1506 char **save_list = NULL;1507 1937 struct pipe *rpipe; 1938 #if ENABLE_HUSH_LOOPS 1939 char *for_varname = NULL; 1940 char **for_lcur = NULL; 1941 char **for_list = NULL; 1508 1942 int flag_rep = 0; 1943 #endif 1509 1944 int save_num_progs; 1510 int rcode=0, flag_skip=1; 1945 int flag_skip = 1; 1946 int rcode = 0; /* probably for gcc only */ 1511 1947 int flag_restore = 0; 1512 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ 1513 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; 1948 #if ENABLE_HUSH_IF 1949 int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ 1950 #else 1951 enum { if_code = 0, next_if_code = 0 }; 1952 #endif 1953 reserved_style rword; 1954 reserved_style skip_more_for_this_rword = RES_XXXX; 1955 1956 debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1); 1957 1958 #if ENABLE_HUSH_LOOPS 1514 1959 /* check syntax for "for" */ 1515 1960 for (rpipe = pi; rpipe; rpipe = rpipe->next) { 1516 if ((rpipe->r_mode == RES_IN || 1517 rpipe->r_mode == RES_FOR) && 1518 (rpipe->next == NULL)) { 1519 syntax(); 1520 return 1; 1521 } 1522 if ((rpipe->r_mode == RES_IN && 1523 (rpipe->next->r_mode == RES_IN && 1524 rpipe->next->progs->argv != NULL))|| 1525 (rpipe->r_mode == RES_FOR && 1526 rpipe->next->r_mode != RES_IN)) { 1527 syntax(); 1528 return 1; 1529 } 1530 } 1531 for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { 1532 if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || 1533 pi->r_mode == RES_FOR) { 1534 flag_restore = 0; 1535 if (!rpipe) { 1536 flag_rep = 0; 1537 rpipe = pi; 1538 } 1539 } 1540 rmode = pi->r_mode; 1541 debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); 1542 if (rmode == skip_more_in_this_rmode && flag_skip) { 1543 if (pi->followup == PIPE_SEQ) flag_skip=0; 1961 if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR) 1962 && (rpipe->next == NULL) 1963 ) { 1964 syntax("malformed for"); /* no IN or no commands after IN */ 1965 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 1966 return 1; 1967 } 1968 if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) 1969 || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) 1970 ) { 1971 /* TODO: what is tested in the first condition? */ 1972 syntax("malformed for"); /* 2nd condition: not followed by IN */ 1973 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 1974 return 1; 1975 } 1976 } 1977 #else 1978 rpipe = NULL; 1979 #endif 1980 1981 #if ENABLE_HUSH_JOB 1982 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". 1983 * We are saving state before entering outermost list ("while...done") 1984 * so that ctrl-Z will correctly background _entire_ outermost list, 1985 * not just a part of it (like "sleep 1 | exit 2") */ 1986 if (++run_list_level == 1 && interactive_fd) { 1987 if (sigsetjmp(toplevel_jb, 1)) { 1988 /* ctrl-Z forked and we are parent; or ctrl-C. 1989 * Sighandler has longjmped us here */ 1990 signal(SIGINT, SIG_IGN); 1991 signal(SIGTSTP, SIG_IGN); 1992 /* Restore level (we can be coming from deep inside 1993 * nested levels) */ 1994 run_list_level = 1; 1995 #if ENABLE_FEATURE_SH_STANDALONE 1996 if (nofork_save.saved) { /* if save area is valid */ 1997 debug_printf_jobs("exiting nofork early\n"); 1998 restore_nofork_data(&nofork_save); 1999 } 2000 #endif 2001 if (ctrl_z_flag) { 2002 /* ctrl-Z has forked and stored pid of the child in pi->pid. 2003 * Remember this child as background job */ 2004 insert_bg_job(pi); 2005 } else { 2006 /* ctrl-C. We just stop doing whatever we were doing */ 2007 putchar('\n'); 2008 } 2009 rcode = 0; 2010 goto ret; 2011 } 2012 /* ctrl-Z handler will store pid etc in pi */ 2013 toplevel_list = pi; 2014 ctrl_z_flag = 0; 2015 #if ENABLE_FEATURE_SH_STANDALONE 2016 nofork_save.saved = 0; /* in case we will run a nofork later */ 2017 #endif 2018 signal_SA_RESTART(SIGTSTP, handler_ctrl_z); 2019 signal(SIGINT, handler_ctrl_c); 2020 } 2021 #endif 2022 2023 for (; pi; pi = flag_restore ? rpipe : pi->next) { 2024 rword = pi->res_word; 2025 #if ENABLE_HUSH_LOOPS 2026 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { 2027 flag_restore = 0; 2028 if (!rpipe) { 2029 flag_rep = 0; 2030 rpipe = pi; 2031 } 2032 } 2033 #endif 2034 debug_printf_exec(": rword=%d if_code=%d next_if_code=%d skip_more=%d\n", 2035 rword, if_code, next_if_code, skip_more_for_this_rword); 2036 if (rword == skip_more_for_this_rword && flag_skip) { 2037 if (pi->followup == PIPE_SEQ) 2038 flag_skip = 0; 1544 2039 continue; 1545 2040 } 1546 2041 flag_skip = 1; 1547 skip_more_in_this_rmode = RES_XXXX; 1548 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; 1549 if (rmode == RES_THEN && if_code) continue; 1550 if (rmode == RES_ELSE && !if_code) continue; 1551 if (rmode == RES_ELIF && !if_code) break; 1552 if (rmode == RES_FOR && pi->num_progs) { 1553 if (!list) { 2042 skip_more_for_this_rword = RES_XXXX; 2043 #if ENABLE_HUSH_IF 2044 if (rword == RES_THEN || rword == RES_ELSE) 2045 if_code = next_if_code; 2046 if (rword == RES_THEN && if_code) 2047 continue; 2048 if (rword == RES_ELSE && !if_code) 2049 continue; 2050 if (rword == RES_ELIF && !if_code) 2051 break; 2052 #endif 2053 #if ENABLE_HUSH_LOOPS 2054 if (rword == RES_FOR && pi->num_progs) { 2055 if (!for_lcur) { 1554 2056 /* if no variable values after "in" we skip "for" */ 1555 if (!pi->next->progs->argv) continue; 2057 if (!pi->next->progs->argv) 2058 continue; 1556 2059 /* create list of variable values */ 1557 list = make_list_in(pi->next->progs->argv, 1558 pi->progs->argv[0]); 1559 save_list = list; 1560 save_name = pi->progs->argv[0]; 2060 for_list = expand_strvec_to_strvec(pi->next->progs->argv); 2061 for_lcur = for_list; 2062 for_varname = pi->progs->argv[0]; 1561 2063 pi->progs->argv[0] = NULL; 1562 2064 flag_rep = 1; 1563 2065 } 1564 if (!(*list)) {1565 free(pi->progs->argv[0]);1566 free( save_list);1567 list= NULL;2066 free(pi->progs->argv[0]); 2067 if (!*for_lcur) { 2068 free(for_list); 2069 for_lcur = NULL; 1568 2070 flag_rep = 0; 1569 pi->progs->argv[0] = save_name; 1570 pi->progs->glob_result.gl_pathv[0] = 1571 pi->progs->argv[0]; 2071 pi->progs->argv[0] = for_varname; 2072 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; 1572 2073 continue; 1573 } else { 1574 /* insert new value from list for variable */ 1575 if (pi->progs->argv[0]) 1576 free(pi->progs->argv[0]); 1577 pi->progs->argv[0] = *list++; 1578 pi->progs->glob_result.gl_pathv[0] = 1579 pi->progs->argv[0]; 1580 } 1581 } 1582 if (rmode == RES_IN) continue; 1583 if (rmode == RES_DO) { 1584 if (!flag_rep) continue; 1585 } 1586 if ((rmode == RES_DONE)) { 2074 } 2075 /* insert next value from for_lcur */ 2076 /* vda: does it need escaping? */ 2077 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); 2078 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; 2079 } 2080 if (rword == RES_IN) 2081 continue; 2082 if (rword == RES_DO) { 2083 if (!flag_rep) 2084 continue; 2085 } 2086 if (rword == RES_DONE) { 1587 2087 if (flag_rep) { 1588 2088 flag_restore = 1; … … 1591 2091 } 1592 2092 } 1593 if (pi->num_progs == 0) continue; 2093 #endif 2094 if (pi->num_progs == 0) 2095 continue; 1594 2096 save_num_progs = pi->num_progs; /* save number of programs */ 2097 debug_printf_exec(": run_pipe_real with %d members\n", pi->num_progs); 1595 2098 rcode = run_pipe_real(pi); 1596 debug_printf("run_pipe_real returned %d\n",rcode); 1597 if (rcode!=-1) { 2099 if (rcode != -1) { 1598 2100 /* We only ran a builtin: rcode was set by the return value 1599 2101 * of run_pipe_real(), and we don't need to wait for anything. */ 1600 } else if (pi->followup==PIPE_BG) { 1601 /* XXX check bash's behavior with nontrivial pipes */ 1602 /* XXX compute jobid */ 1603 /* XXX what does bash do with attempts to background builtins? */ 1604 insert_bg_job(pi); 2102 } else if (pi->followup == PIPE_BG) { 2103 /* What does bash do with attempts to background builtins? */ 2104 /* Even bash 3.2 doesn't do that well with nested bg: 2105 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 2106 * I'm NOT treating inner &'s as jobs */ 2107 #if ENABLE_HUSH_JOB 2108 if (run_list_level == 1) 2109 insert_bg_job(pi); 2110 #endif 1605 2111 rcode = EXIT_SUCCESS; 1606 2112 } else { 1607 if (interactive) { 1608 /* move the new process group into the foreground */ 1609 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) 1610 bb_perror_msg("tcsetpgrp-3"); 2113 #if ENABLE_HUSH_JOB 2114 /* Paranoia, just "interactive_fd" should be enough? */ 2115 if (run_list_level == 1 && interactive_fd) { 2116 /* waits for completion, then fg's main shell */ 2117 rcode = checkjobs_and_fg_shell(pi); 2118 } else 2119 #endif 2120 { 2121 /* this one just waits for completion */ 1611 2122 rcode = checkjobs(pi); 1612 /* move the shell to the foreground */ 1613 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) 1614 bb_perror_msg("tcsetpgrp-4"); 1615 } else { 1616 rcode = checkjobs(pi); 1617 } 1618 debug_printf("checkjobs returned %d\n",rcode); 1619 } 1620 last_return_code=rcode; 2123 } 2124 debug_printf_exec(": checkjobs returned %d\n", rcode); 2125 } 2126 debug_printf_exec(": setting last_return_code=%d\n", rcode); 2127 last_return_code = rcode; 1621 2128 pi->num_progs = save_num_progs; /* restore number of programs */ 1622 if ( rmode == RES_IF || rmode == RES_ELIF ) 1623 next_if_code=rcode; /* can be overwritten a number of times */ 1624 if (rmode == RES_WHILE) 2129 #if ENABLE_HUSH_IF 2130 if (rword == RES_IF || rword == RES_ELIF) 2131 next_if_code = rcode; /* can be overwritten a number of times */ 2132 #endif 2133 #if ENABLE_HUSH_LOOPS 2134 if (rword == RES_WHILE) 1625 2135 flag_rep = !last_return_code; 1626 if (r mode== RES_UNTIL)2136 if (rword == RES_UNTIL) 1627 2137 flag_rep = last_return_code; 1628 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || 1629 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) 1630 skip_more_in_this_rmode=rmode; 2138 #endif 2139 if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR) 2140 || (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND) 2141 ) { 2142 skip_more_for_this_rword = rword; 2143 } 1631 2144 checkjobs(NULL); 1632 2145 } 2146 2147 #if ENABLE_HUSH_JOB 2148 if (ctrl_z_flag) { 2149 /* ctrl-Z forked somewhere in the past, we are the child, 2150 * and now we completed running the list. Exit. */ 2151 exit(rcode); 2152 } 2153 ret: 2154 if (!--run_list_level && interactive_fd) { 2155 signal(SIGTSTP, SIG_IGN); 2156 signal(SIGINT, SIG_IGN); 2157 } 2158 #endif 2159 debug_printf_exec("run_list_real lvl %d return %d\n", run_list_level + 1, rcode); 1633 2160 return rcode; 1634 }1635 1636 /* broken, of course, but OK for testing */1637 static char *indenter(int i)1638 {1639 static char blanks[]=" ";1640 return &blanks[sizeof(blanks)-i-1];1641 2161 } 1642 2162 … … 1647 2167 struct child_prog *child; 1648 2168 struct redir_struct *r, *rnext; 1649 int a, i, ret_code=0; 1650 char *ind = indenter(indent); 2169 int a, i, ret_code = 0; 1651 2170 1652 2171 if (pi->stopped_progs > 0) 1653 2172 return ret_code; 1654 final_printf("%s run pipe: (pid %d)\n",ind,getpid());1655 for (i =0; i<pi->num_progs; i++) {2173 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); 2174 for (i = 0; i < pi->num_progs; i++) { 1656 2175 child = &pi->progs[i]; 1657 final_printf("%s command %d:\n",ind,i);2176 debug_printf_clean("%s command %d:\n", indenter(indent), i); 1658 2177 if (child->argv) { 1659 for (a =0,p=child->argv; *p; a++,p++) {1660 final_printf("%s argv[%d] = %s\n",ind,a,*p);2178 for (a = 0, p = child->argv; *p; a++, p++) { 2179 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); 1661 2180 } 1662 2181 globfree(&child->glob_result); 1663 child->argv =NULL;2182 child->argv = NULL; 1664 2183 } else if (child->group) { 1665 final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);1666 ret_code = free_pipe_list(child->group, indent+3);1667 final_printf("%s end group\n",ind);2184 debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), child->subshell); 2185 ret_code = free_pipe_list(child->group, indent+3); 2186 debug_printf_clean("%s end group\n", indenter(indent)); 1668 2187 } else { 1669 final_printf("%s (nil)\n",ind);1670 } 1671 for (r =child->redirects; r; r=rnext) {1672 final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);2188 debug_printf_clean("%s (nil)\n", indenter(indent)); 2189 } 2190 for (r = child->redirects; r; r = rnext) { 2191 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip); 1673 2192 if (r->dup == -1) { 1674 2193 /* guard against the case >$FOO, where foo is unset or blank */ 1675 2194 if (r->word.gl_pathv) { 1676 final_printf(" %s\n", *r->word.gl_pathv);2195 debug_printf_clean(" %s\n", *r->word.gl_pathv); 1677 2196 globfree(&r->word); 1678 2197 } 1679 2198 } else { 1680 final_printf("&%d\n", r->dup);1681 } 1682 rnext =r->next;2199 debug_printf_clean("&%d\n", r->dup); 2200 } 2201 rnext = r->next; 1683 2202 free(r); 1684 2203 } 1685 child->redirects =NULL;2204 child->redirects = NULL; 1686 2205 } 1687 2206 free(pi->progs); /* children are an array, they get freed all at once */ 1688 pi->progs=NULL; 2207 pi->progs = NULL; 2208 #if ENABLE_HUSH_JOB 2209 free(pi->cmdtext); 2210 pi->cmdtext = NULL; 2211 #endif 1689 2212 return ret_code; 1690 2213 } … … 1692 2215 static int free_pipe_list(struct pipe *head, int indent) 1693 2216 { 1694 int rcode =0; /* if list has no members */2217 int rcode = 0; /* if list has no members */ 1695 2218 struct pipe *pi, *next; 1696 char *ind = indenter(indent); 1697 for (pi =head; pi; pi=next) {1698 final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);2219 2220 for (pi = head; pi; pi = next) { 2221 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); 1699 2222 rcode = free_pipe(pi, indent); 1700 final_printf("%s pipe followup code %d\n", ind, pi->followup);1701 next =pi->next;1702 pi->next=NULL;2223 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); 2224 next = pi->next; 2225 /*pi->next = NULL;*/ 1703 2226 free(pi); 1704 2227 } … … 1709 2232 static int run_list(struct pipe *pi) 1710 2233 { 1711 int rcode=0; 1712 if (fake_mode==0) { 2234 int rcode = 0; 2235 debug_printf_exec("run_list entered\n"); 2236 if (fake_mode == 0) { 2237 debug_printf_exec(": run_list_real with %d members\n", pi->num_progs); 1713 2238 rcode = run_list_real(pi); 1714 2239 } 1715 /* free_pipe_list has the side effect of clearing memory 2240 /* free_pipe_list has the side effect of clearing memory. 1716 2241 * In the long run that function can be merged with run_list_real, 1717 2242 * but doing that now would hobble the debugging effort. */ 1718 free_pipe_list(pi,0); 2243 free_pipe_list(pi, 0); 2244 debug_printf_exec("run_list return %d\n", rcode); 1719 2245 return rcode; 1720 2246 } … … 1729 2255 static int globhack(const char *src, int flags, glob_t *pglob) 1730 2256 { 1731 int cnt =0, pathc;2257 int cnt = 0, pathc; 1732 2258 const char *s; 1733 2259 char *dest; 1734 for (cnt =1, s=src; s && *s; s++) {2260 for (cnt = 1, s = src; s && *s; s++) { 1735 2261 if (*s == '\\') s++; 1736 2262 cnt++; 1737 2263 } 1738 dest = malloc(cnt); 1739 if (!dest) return GLOB_NOSPACE; 2264 dest = xmalloc(cnt); 1740 2265 if (!(flags & GLOB_APPEND)) { 1741 pglob->gl_pathv =NULL;1742 pglob->gl_pathc =0;1743 pglob->gl_offs =0;1744 pglob->gl_offs =0;2266 pglob->gl_pathv = NULL; 2267 pglob->gl_pathc = 0; 2268 pglob->gl_offs = 0; 2269 pglob->gl_offs = 0; 1745 2270 } 1746 2271 pathc = ++pglob->gl_pathc; 1747 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); 1748 if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; 1749 pglob->gl_pathv[pathc-1]=dest; 1750 pglob->gl_pathv[pathc]=NULL; 1751 for (s=src; s && *s; s++, dest++) { 2272 pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv)); 2273 pglob->gl_pathv[pathc-1] = dest; 2274 pglob->gl_pathv[pathc] = NULL; 2275 for (s = src; s && *s; s++, dest++) { 1752 2276 if (*s == '\\') s++; 1753 2277 *dest = *s; 1754 2278 } 1755 *dest ='\0';2279 *dest = '\0'; 1756 2280 return 0; 1757 2281 } … … 1762 2286 for (; *s; s++) { 1763 2287 if (*s == '\\') s++; 1764 if (strchr("*[?", *s)) return 1;2288 if (strchr("*[?", *s)) return 1; 1765 2289 } 1766 2290 return 0; 1767 2291 } 1768 1769 #if 01770 static void globprint(glob_t *pglob)1771 {1772 int i;1773 debug_printf("glob_t at %p:\n", pglob);1774 debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",1775 pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);1776 for (i=0; i<pglob->gl_pathc; i++)1777 debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,1778 pglob->gl_pathv[i], pglob->gl_pathv[i]);1779 }1780 #endif1781 2292 1782 2293 static int xglob(o_string *dest, int flags, glob_t *pglob) … … 1790 2301 /* bash man page calls this an "explicit" null */ 1791 2302 gr = globhack(dest->data, flags, pglob); 1792 debug_printf("globhack returned %d\n", gr);2303 debug_printf("globhack returned %d\n", gr); 1793 2304 } else { 1794 2305 return 0; … … 1796 2307 } else if (glob_needed(dest->data)) { 1797 2308 gr = glob(dest->data, flags, NULL, pglob); 1798 debug_printf("glob returned %d\n", gr);2309 debug_printf("glob returned %d\n", gr); 1799 2310 if (gr == GLOB_NOMATCH) { 1800 2311 /* quote removal, or more accurately, backslash removal */ 1801 2312 gr = globhack(dest->data, flags, pglob); 1802 debug_printf("globhack returned %d\n", gr);2313 debug_printf("globhack returned %d\n", gr); 1803 2314 } 1804 2315 } else { 1805 2316 gr = globhack(dest->data, flags, pglob); 1806 debug_printf("globhack returned %d\n", gr);2317 debug_printf("globhack returned %d\n", gr); 1807 2318 } 1808 2319 if (gr == GLOB_NOSPACE) 1809 2320 bb_error_msg_and_die("out of memory during glob"); 1810 2321 if (gr != 0) { /* GLOB_ABORTED ? */ 1811 bb_error_msg("glob(3) error %d", gr);2322 bb_error_msg("glob(3) error %d", gr); 1812 2323 } 1813 2324 /* globprint(glob_target); */ … … 1815 2326 } 1816 2327 2328 /* expand_strvec_to_strvec() takes a list of strings, expands 2329 * all variable references within and returns a pointer to 2330 * a list of expanded strings, possibly with larger number 2331 * of strings. (Think VAR="a b"; echo $VAR). 2332 * This new list is allocated as a single malloc block. 2333 * NULL-terminated list of char* pointers is at the beginning of it, 2334 * followed by strings themself. 2335 * Caller can deallocate entire list by single free(list). */ 2336 2337 /* Helpers first: 2338 * count_XXX estimates size of the block we need. It's okay 2339 * to over-estimate sizes a bit, if it makes code simpler */ 2340 static int count_ifs(const char *str) 2341 { 2342 int cnt = 0; 2343 debug_printf_expand("count_ifs('%s') ifs='%s'", str, ifs); 2344 while (1) { 2345 str += strcspn(str, ifs); 2346 if (!*str) break; 2347 str++; /* str += strspn(str, ifs); */ 2348 cnt++; /* cnt += strspn(str, ifs); - but this code is larger */ 2349 } 2350 debug_printf_expand(" return %d\n", cnt); 2351 return cnt; 2352 } 2353 2354 static void count_var_expansion_space(int *countp, int *lenp, char *arg) 2355 { 2356 char first_ch; 2357 int i; 2358 int len = *lenp; 2359 int count = *countp; 2360 const char *val; 2361 char *p; 2362 2363 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { 2364 len += p - arg; 2365 arg = ++p; 2366 p = strchr(p, SPECIAL_VAR_SYMBOL); 2367 first_ch = arg[0]; 2368 2369 switch (first_ch & 0x7f) { 2370 /* high bit in 1st_ch indicates that var is double-quoted */ 2371 case '$': /* pid */ 2372 case '!': /* bg pid */ 2373 case '?': /* exitcode */ 2374 case '#': /* argc */ 2375 len += sizeof(int)*3 + 1; /* enough for int */ 2376 break; 2377 case '*': 2378 case '@': 2379 for (i = 1; i < global_argc; i++) { 2380 len += strlen(global_argv[i]) + 1; 2381 count++; 2382 if (!(first_ch & 0x80)) 2383 count += count_ifs(global_argv[i]); 2384 } 2385 break; 2386 default: 2387 *p = '\0'; 2388 arg[0] = first_ch & 0x7f; 2389 if (isdigit(arg[0])) { 2390 i = xatoi_u(arg); 2391 val = NULL; 2392 if (i < global_argc) 2393 val = global_argv[i]; 2394 } else 2395 val = lookup_param(arg); 2396 arg[0] = first_ch; 2397 *p = SPECIAL_VAR_SYMBOL; 2398 2399 if (val) { 2400 len += strlen(val) + 1; 2401 if (!(first_ch & 0x80)) 2402 count += count_ifs(val); 2403 } 2404 } 2405 arg = ++p; 2406 } 2407 2408 len += strlen(arg) + 1; 2409 count++; 2410 *lenp = len; 2411 *countp = count; 2412 } 2413 2414 /* Store given string, finalizing the word and starting new one whenever 2415 * we encounter ifs char(s). This is used for expanding variable values. 2416 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 2417 static int expand_on_ifs(char **list, int n, char **posp, const char *str) 2418 { 2419 char *pos = *posp; 2420 while (1) { 2421 int word_len = strcspn(str, ifs); 2422 if (word_len) { 2423 memcpy(pos, str, word_len); /* store non-ifs chars */ 2424 pos += word_len; 2425 str += word_len; 2426 } 2427 if (!*str) /* EOL - do not finalize word */ 2428 break; 2429 *pos++ = '\0'; 2430 if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' " 2431 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2432 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2433 list[n++] = pos; 2434 str += strspn(str, ifs); /* skip ifs chars */ 2435 } 2436 *posp = pos; 2437 return n; 2438 } 2439 2440 /* Expand all variable references in given string, adding words to list[] 2441 * at n, n+1,... positions. Return updated n (so that list[n] is next one 2442 * to be filled). This routine is extremely tricky: has to deal with 2443 * variables/parameters with whitespace, $* and $@, and constructs like 2444 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ 2445 /* NB: another bug is that we cannot detect empty strings yet: 2446 * "" or $empty"" expands to zero words, has to expand to empty word */ 2447 static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask) 2448 { 2449 /* or_mask is either 0 (normal case) or 0x80 2450 * (expansion of right-hand side of assignment == 1-element expand) */ 2451 2452 char first_ch, ored_ch; 2453 int i; 2454 const char *val; 2455 char *p; 2456 char *pos = *posp; 2457 2458 ored_ch = 0; 2459 2460 if (n) debug_printf_expand("expand_vars_to_list finalized list[%d]=%p '%s' " 2461 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2462 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2463 list[n++] = pos; 2464 2465 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { 2466 memcpy(pos, arg, p - arg); 2467 pos += (p - arg); 2468 arg = ++p; 2469 p = strchr(p, SPECIAL_VAR_SYMBOL); 2470 2471 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ 2472 ored_ch |= first_ch; 2473 val = NULL; 2474 switch (first_ch & 0x7f) { 2475 /* Highest bit in first_ch indicates that var is double-quoted */ 2476 case '$': /* pid */ 2477 /* FIXME: (echo $$) should still print pid of main shell */ 2478 val = utoa(getpid()); 2479 break; 2480 case '!': /* bg pid */ 2481 val = last_bg_pid ? utoa(last_bg_pid) : (char*)""; 2482 break; 2483 case '?': /* exitcode */ 2484 val = utoa(last_return_code); 2485 break; 2486 case '#': /* argc */ 2487 val = utoa(global_argc ? global_argc-1 : 0); 2488 break; 2489 case '*': 2490 case '@': 2491 i = 1; 2492 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 2493 while (i < global_argc) { 2494 n = expand_on_ifs(list, n, &pos, global_argv[i]); 2495 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1); 2496 if (global_argv[i++][0] && i < global_argc) { 2497 /* this argv[] is not empty and not last: 2498 * put terminating NUL, start new word */ 2499 *pos++ = '\0'; 2500 if (n) debug_printf_expand("expand_vars_to_list 2 finalized list[%d]=%p '%s' " 2501 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2502 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2503 list[n++] = pos; 2504 } 2505 } 2506 } else 2507 /* If or_mask is nonzero, we handle assignment 'a=....$@.....' 2508 * and in this case should theat it like '$*' */ 2509 if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ 2510 while (1) { 2511 strcpy(pos, global_argv[i]); 2512 pos += strlen(global_argv[i]); 2513 if (++i >= global_argc) 2514 break; 2515 *pos++ = '\0'; 2516 if (n) debug_printf_expand("expand_vars_to_list 3 finalized list[%d]=%p '%s' " 2517 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2518 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2519 list[n++] = pos; 2520 } 2521 } else { /* quoted $*: add as one word */ 2522 while (1) { 2523 strcpy(pos, global_argv[i]); 2524 pos += strlen(global_argv[i]); 2525 if (++i >= global_argc) 2526 break; 2527 if (ifs[0]) 2528 *pos++ = ifs[0]; 2529 } 2530 } 2531 break; 2532 default: 2533 *p = '\0'; 2534 arg[0] = first_ch & 0x7f; 2535 if (isdigit(arg[0])) { 2536 i = xatoi_u(arg); 2537 val = NULL; 2538 if (i < global_argc) 2539 val = global_argv[i]; 2540 } else 2541 val = lookup_param(arg); 2542 arg[0] = first_ch; 2543 *p = SPECIAL_VAR_SYMBOL; 2544 if (!(first_ch & 0x80)) { /* unquoted $VAR */ 2545 if (val) { 2546 n = expand_on_ifs(list, n, &pos, val); 2547 val = NULL; 2548 } 2549 } /* else: quoted $VAR, val will be appended at pos */ 2550 } 2551 if (val) { 2552 strcpy(pos, val); 2553 pos += strlen(val); 2554 } 2555 arg = ++p; 2556 } 2557 debug_printf_expand("expand_vars_to_list adding tail '%s' at %p\n", arg, pos); 2558 strcpy(pos, arg); 2559 pos += strlen(arg) + 1; 2560 if (pos == list[n-1] + 1) { /* expansion is empty */ 2561 if (!(ored_ch & 0x80)) { /* all vars were not quoted... */ 2562 debug_printf_expand("expand_vars_to_list list[%d] empty, going back\n", n); 2563 pos--; 2564 n--; 2565 } 2566 } 2567 2568 *posp = pos; 2569 return n; 2570 } 2571 2572 static char **expand_variables(char **argv, char or_mask) 2573 { 2574 int n; 2575 int count = 1; 2576 int len = 0; 2577 char *pos, **v, **list; 2578 2579 v = argv; 2580 if (!*v) debug_printf_expand("count_var_expansion_space: " 2581 "argv[0]=NULL count=%d len=%d alloc_space=%d\n", 2582 count, len, sizeof(char*) * count + len); 2583 while (*v) { 2584 count_var_expansion_space(&count, &len, *v); 2585 debug_printf_expand("count_var_expansion_space: " 2586 "'%s' count=%d len=%d alloc_space=%d\n", 2587 *v, count, len, sizeof(char*) * count + len); 2588 v++; 2589 } 2590 len += sizeof(char*) * count; /* total to alloc */ 2591 list = xmalloc(len); 2592 pos = (char*)(list + count); 2593 debug_printf_expand("list=%p, list[0] should be %p\n", list, pos); 2594 n = 0; 2595 v = argv; 2596 while (*v) 2597 n = expand_vars_to_list(list, n, &pos, *v++, or_mask); 2598 2599 if (n) debug_printf_expand("finalized list[%d]=%p '%s' " 2600 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2601 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2602 list[n] = NULL; 2603 2604 #ifdef DEBUG_EXPAND 2605 { 2606 int m = 0; 2607 while (m <= n) { 2608 debug_printf_expand("list[%d]=%p '%s'\n", m, list[m], list[m]); 2609 m++; 2610 } 2611 debug_printf_expand("used_space=%d\n", pos - (char*)list); 2612 } 2613 #endif 2614 if (ENABLE_HUSH_DEBUG) 2615 if (pos - (char*)list > len) 2616 bb_error_msg_and_die("BUG in varexp"); 2617 return list; 2618 } 2619 2620 static char **expand_strvec_to_strvec(char **argv) 2621 { 2622 return expand_variables(argv, 0); 2623 } 2624 2625 static char *expand_string_to_string(const char *str) 2626 { 2627 char *argv[2], **list; 2628 2629 argv[0] = (char*)str; 2630 argv[1] = NULL; 2631 list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */ 2632 if (ENABLE_HUSH_DEBUG) 2633 if (!list[0] || list[1]) 2634 bb_error_msg_and_die("BUG in varexp2"); 2635 /* actually, just move string 2*sizeof(char*) bytes back */ 2636 strcpy((char*)list, list[0]); 2637 debug_printf_expand("string_to_string='%s'\n", (char*)list); 2638 return (char*)list; 2639 } 2640 2641 static char* expand_strvec_to_string(char **argv) 2642 { 2643 char **list; 2644 2645 list = expand_variables(argv, 0x80); 2646 /* Convert all NULs to spaces */ 2647 if (list[0]) { 2648 int n = 1; 2649 while (list[n]) { 2650 if (ENABLE_HUSH_DEBUG) 2651 if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) 2652 bb_error_msg_and_die("BUG in varexp3"); 2653 list[n][-1] = ' '; /* TODO: or to ifs[0]? */ 2654 n++; 2655 } 2656 } 2657 strcpy((char*)list, list[0]); 2658 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 2659 return (char*)list; 2660 } 2661 1817 2662 /* This is used to get/check local shell variables */ 1818 static char *get_local_var(const char *s) 1819 { 1820 struct variables *cur; 1821 1822 if (!s) 2663 static struct variable *get_local_var(const char *name) 2664 { 2665 struct variable *cur; 2666 int len; 2667 2668 if (!name) 1823 2669 return NULL; 1824 for (cur = top_vars; cur; cur=cur->next) 1825 if(strcmp(cur->name, s)==0) 1826 return cur->value; 2670 len = strlen(name); 2671 for (cur = top_var; cur; cur = cur->next) { 2672 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') 2673 return cur; 2674 } 1827 2675 return NULL; 1828 2676 } 1829 2677 1830 /* This is used to set local shell variables 1831 flg_export==0 if only local (not exporting) variable 1832 flg_export==1 if "new" exporting environ 1833 flg_export>1 if current startup environ (not call putenv()) */ 1834 static int set_local_var(const char *s, int flg_export) 1835 { 1836 char *name, *value; 1837 int result=0; 1838 struct variables *cur; 1839 1840 name=strdup(s); 1841 1842 /* Assume when we enter this function that we are already in 1843 * NAME=VALUE format. So the first order of business is to 1844 * split 's' on the '=' into 'name' and 'value' */ 1845 value = strchr(name, '='); 1846 if (value==0 && ++value==0) { 1847 free(name); 2678 /* str holds "NAME=VAL" and is expected to be malloced. 2679 * We take ownership of it. */ 2680 static int set_local_var(char *str, int flg_export) 2681 { 2682 struct variable *cur; 2683 char *value; 2684 int name_len; 2685 2686 value = strchr(str, '='); 2687 if (!value) { /* not expected to ever happen? */ 2688 free(str); 1848 2689 return -1; 1849 2690 } 1850 *value++ = 0; 1851 1852 for(cur = top_vars; cur; cur = cur->next) { 1853 if(strcmp(cur->name, name)==0) 1854 break; 1855 } 1856 1857 if(cur) { 1858 if(strcmp(cur->value, value)==0) { 1859 if(flg_export>0 && cur->flg_export==0) 1860 cur->flg_export=flg_export; 1861 else 1862 result++; 1863 } else { 1864 if(cur->flg_read_only) { 1865 bb_error_msg("%s: readonly variable", name); 1866 result = -1; 1867 } else { 1868 if(flg_export>0 || cur->flg_export>1) 1869 cur->flg_export=1; 1870 free(cur->value); 1871 1872 cur->value = strdup(value); 1873 } 1874 } 1875 } else { 1876 cur = malloc(sizeof(struct variables)); 1877 if(!cur) { 1878 result = -1; 1879 } else { 1880 cur->name = strdup(name); 1881 if(cur->name == 0) { 1882 free(cur); 1883 result = -1; 1884 } else { 1885 struct variables *bottom = top_vars; 1886 cur->value = strdup(value); 1887 cur->next = 0; 1888 cur->flg_export = flg_export; 1889 cur->flg_read_only = 0; 1890 while(bottom->next) bottom=bottom->next; 1891 bottom->next = cur; 1892 } 1893 } 1894 } 1895 1896 if(result==0 && cur->flg_export==1) { 1897 *(value-1) = '='; 1898 result = putenv(name); 1899 } else { 1900 free(name); 1901 if(result>0) /* equivalent to previous set */ 1902 result = 0; 1903 } 1904 return result; 2691 2692 name_len = value - str + 1; /* including '=' */ 2693 cur = top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */ 2694 while (1) { 2695 if (strncmp(cur->varstr, str, name_len) != 0) { 2696 if (!cur->next) { 2697 /* Bail out. Note that now cur points 2698 * to last var in linked list */ 2699 break; 2700 } 2701 cur = cur->next; 2702 continue; 2703 } 2704 /* We found an existing var with this name */ 2705 *value = '\0'; 2706 if (cur->flg_read_only) { 2707 bb_error_msg("%s: readonly variable", str); 2708 free(str); 2709 return -1; 2710 } 2711 unsetenv(str); /* just in case */ 2712 *value = '='; 2713 if (strcmp(cur->varstr, str) == 0) { 2714 free_and_exp: 2715 free(str); 2716 goto exp; 2717 } 2718 if (cur->max_len >= strlen(str)) { 2719 /* This one is from startup env, reuse space */ 2720 strcpy(cur->varstr, str); 2721 goto free_and_exp; 2722 } 2723 /* max_len == 0 signifies "malloced" var, which we can 2724 * (and has to) free */ 2725 if (!cur->max_len) 2726 free(cur->varstr); 2727 cur->max_len = 0; 2728 goto set_str_and_exp; 2729 } 2730 2731 /* Not found - create next variable struct */ 2732 cur->next = xzalloc(sizeof(*cur)); 2733 cur = cur->next; 2734 2735 set_str_and_exp: 2736 cur->varstr = str; 2737 exp: 2738 if (flg_export) 2739 cur->flg_export = 1; 2740 if (cur->flg_export) 2741 return putenv(cur->varstr); 2742 return 0; 1905 2743 } 1906 2744 1907 2745 static void unset_local_var(const char *name) 1908 2746 { 1909 struct variables *cur; 1910 1911 if (name) { 1912 for (cur = top_vars; cur; cur=cur->next) { 1913 if(strcmp(cur->name, name)==0) 1914 break; 1915 } 1916 if(cur!=0) { 1917 struct variables *next = top_vars; 1918 if(cur->flg_read_only) { 2747 struct variable *cur; 2748 struct variable *prev = prev; /* for gcc */ 2749 int name_len; 2750 2751 if (!name) 2752 return; 2753 name_len = strlen(name); 2754 cur = top_var; 2755 while (cur) { 2756 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 2757 if (cur->flg_read_only) { 1919 2758 bb_error_msg("%s: readonly variable", name); 1920 2759 return; 1921 } else { 1922 if(cur->flg_export) 1923 unsetenv(cur->name); 1924 free(cur->name); 1925 free(cur->value); 1926 while (next->next != cur) 1927 next = next->next; 1928 next->next = cur->next; 1929 } 2760 } 2761 /* prev is ok to use here because 1st variable, HUSH_VERSION, 2762 * is ro, and we cannot reach this code on the 1st pass */ 2763 prev->next = cur->next; 2764 unsetenv(cur->varstr); 2765 if (!cur->max_len) 2766 free(cur->varstr); 1930 2767 free(cur); 1931 } 2768 return; 2769 } 2770 prev = cur; 2771 cur = cur->next; 1932 2772 } 1933 2773 } … … 1935 2775 static int is_assignment(const char *s) 1936 2776 { 1937 if (s==NULL || !isalpha(*s)) return 0; 1938 ++s; 1939 while(isalnum(*s) || *s=='_') ++s; 1940 return *s=='='; 2777 if (!s || !isalpha(*s)) 2778 return 0; 2779 s++; 2780 while (isalnum(*s) || *s == '_') 2781 s++; 2782 return *s == '='; 1941 2783 } 1942 2784 … … 1948 2790 struct in_str *input) 1949 2791 { 1950 struct child_prog *child =ctx->child;2792 struct child_prog *child = ctx->child; 1951 2793 struct redir_struct *redir = child->redirects; 1952 struct redir_struct *last_redir =NULL;2794 struct redir_struct *last_redir = NULL; 1953 2795 1954 2796 /* Create a new redir_struct and drop it onto the end of the linked list */ 1955 while (redir) {1956 last_redir =redir;1957 redir =redir->next;2797 while (redir) { 2798 last_redir = redir; 2799 redir = redir->next; 1958 2800 } 1959 2801 redir = xmalloc(sizeof(struct redir_struct)); 1960 redir->next =NULL;1961 redir->word.gl_pathv =NULL;2802 redir->next = NULL; 2803 redir->word.gl_pathv = NULL; 1962 2804 if (last_redir) { 1963 last_redir->next =redir;2805 last_redir->next = redir; 1964 2806 } else { 1965 child->redirects =redir;1966 } 1967 1968 redir->type =style;1969 redir->fd = (fd==-1) ? redir_table[style].default_fd : fd;2807 child->redirects = redir; 2808 } 2809 2810 redir->type = style; 2811 redir->fd = (fd == -1) ? redir_table[style].default_fd : fd; 1970 2812 1971 2813 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); … … 1983 2825 * since we need to return and let src be expanded first. 1984 2826 * Set ctx->pending_redirect, so we know what to do at the 1985 * end of the next parsed word. 1986 */ 2827 * end of the next parsed word. */ 1987 2828 ctx->pending_redirect = redir; 1988 2829 } … … 1990 2831 } 1991 2832 1992 static struct pipe *new_pipe(void) { 2833 static struct pipe *new_pipe(void) 2834 { 1993 2835 struct pipe *pi; 1994 pi = xmalloc(sizeof(struct pipe)); 1995 pi->num_progs = 0; 1996 pi->progs = NULL; 1997 pi->next = NULL; 1998 pi->followup = 0; /* invalid */ 1999 pi->r_mode = RES_NONE; 2836 pi = xzalloc(sizeof(struct pipe)); 2837 /*pi->num_progs = 0;*/ 2838 /*pi->progs = NULL;*/ 2839 /*pi->next = NULL;*/ 2840 /*pi->followup = 0; invalid */ 2841 if (RES_NONE) 2842 pi->res_word = RES_NONE; 2000 2843 return pi; 2001 2844 } … … 2003 2846 static void initialize_context(struct p_context *ctx) 2004 2847 { 2005 ctx->pipe=NULL; 2006 ctx->pending_redirect=NULL; 2007 ctx->child=NULL; 2008 ctx->list_head=new_pipe(); 2009 ctx->pipe=ctx->list_head; 2010 ctx->w=RES_NONE; 2011 ctx->stack=NULL; 2012 ctx->old_flag=0; 2848 ctx->child = NULL; 2849 ctx->pipe = ctx->list_head = new_pipe(); 2850 ctx->pending_redirect = NULL; 2851 ctx->res_w = RES_NONE; 2852 //only ctx->parse_type is not touched... is this intentional? 2853 ctx->old_flag = 0; 2854 ctx->stack = NULL; 2013 2855 done_command(ctx); /* creates the memory for working child */ 2014 2856 } … … 2019 2861 * case, function, and select are obnoxious, save those for later. 2020 2862 */ 2863 #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS 2021 2864 static int reserved_word(o_string *dest, struct p_context *ctx) 2022 2865 { 2023 2866 struct reserved_combo { 2024 char *literal;2025 intcode;2026 longflag;2867 char literal[7]; 2868 unsigned char code; 2869 int flag; 2027 2870 }; 2028 2871 /* Mostly a list of accepted follow-up reserved words. … … 2031 2874 * FLAG_START means the word must start a new compound list. 2032 2875 */ 2033 static struct reserved_combo reserved_list[] = { 2876 static const struct reserved_combo reserved_list[] = { 2877 #if ENABLE_HUSH_IF 2034 2878 { "if", RES_IF, FLAG_THEN | FLAG_START }, 2035 2879 { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, … … 2037 2881 { "else", RES_ELSE, FLAG_FI }, 2038 2882 { "fi", RES_FI, FLAG_END }, 2883 #endif 2884 #if ENABLE_HUSH_LOOPS 2039 2885 { "for", RES_FOR, FLAG_IN | FLAG_START }, 2040 2886 { "while", RES_WHILE, FLAG_DO | FLAG_START }, … … 2043 2889 { "do", RES_DO, FLAG_DONE }, 2044 2890 { "done", RES_DONE, FLAG_END } 2891 #endif 2045 2892 }; 2046 struct reserved_combo *r; 2047 for (r=reserved_list; 2048 #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) 2049 r<reserved_list+NRES; r++) { 2050 if (strcmp(dest->data, r->literal) == 0) { 2051 debug_printf("found reserved word %s, code %d\n",r->literal,r->code); 2052 if (r->flag & FLAG_START) { 2053 struct p_context *new = xmalloc(sizeof(struct p_context)); 2054 debug_printf("push stack\n"); 2055 if (ctx->w == RES_IN || ctx->w == RES_FOR) { 2056 syntax(); 2057 free(new); 2058 ctx->w = RES_SNTX; 2059 b_reset(dest); 2060 return 1; 2061 } 2062 *new = *ctx; /* physical copy */ 2063 initialize_context(ctx); 2064 ctx->stack=new; 2065 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { 2066 syntax(); 2067 ctx->w = RES_SNTX; 2893 2894 const struct reserved_combo *r; 2895 2896 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) { 2897 if (strcmp(dest->data, r->literal) != 0) 2898 continue; 2899 debug_printf("found reserved word %s, code %d\n", r->literal, r->code); 2900 if (r->flag & FLAG_START) { 2901 struct p_context *new; 2902 debug_printf("push stack\n"); 2903 #if ENABLE_HUSH_LOOPS 2904 if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { 2905 syntax("malformed for"); /* example: 'for if' */ 2906 ctx->res_w = RES_SNTX; 2068 2907 b_reset(dest); 2069 2908 return 1; 2070 2909 } 2071 ctx->w=r->code; 2072 ctx->old_flag = r->flag; 2073 if (ctx->old_flag & FLAG_END) { 2074 struct p_context *old; 2075 debug_printf("pop stack\n"); 2076 done_pipe(ctx,PIPE_SEQ); 2077 old = ctx->stack; 2078 old->child->group = ctx->list_head; 2079 old->child->subshell = 0; 2080 *ctx = *old; /* physical copy */ 2081 free(old); 2082 } 2083 b_reset (dest); 2910 #endif 2911 new = xmalloc(sizeof(*new)); 2912 *new = *ctx; /* physical copy */ 2913 initialize_context(ctx); 2914 ctx->stack = new; 2915 } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { 2916 syntax(NULL); 2917 ctx->res_w = RES_SNTX; 2918 b_reset(dest); 2084 2919 return 1; 2085 2920 } 2921 ctx->res_w = r->code; 2922 ctx->old_flag = r->flag; 2923 if (ctx->old_flag & FLAG_END) { 2924 struct p_context *old; 2925 debug_printf("pop stack\n"); 2926 done_pipe(ctx, PIPE_SEQ); 2927 old = ctx->stack; 2928 old->child->group = ctx->list_head; 2929 old->child->subshell = 0; 2930 *ctx = *old; /* physical copy */ 2931 free(old); 2932 } 2933 b_reset(dest); 2934 return 1; 2086 2935 } 2087 2936 return 0; 2088 2937 } 2089 2090 /* normal return is 0. 2938 #else 2939 #define reserved_word(dest, ctx) ((int)0) 2940 #endif 2941 2942 /* Normal return is 0. 2091 2943 * Syntax or xglob errors return 1. */ 2092 2944 static int done_word(o_string *dest, struct p_context *ctx) 2093 2945 { 2094 struct child_prog *child =ctx->child;2946 struct child_prog *child = ctx->child; 2095 2947 glob_t *glob_target; 2096 2948 int gr, flags = 0; 2097 2949 2098 debug_printf ("done_word: %s%p\n", dest->data, child);2950 debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child); 2099 2951 if (dest->length == 0 && !dest->nonnull) { 2100 debug_printf ("true null, ignored\n");2952 debug_printf_parse("done_word return 0: true null, ignored\n"); 2101 2953 return 0; 2102 2954 } … … 2105 2957 } else { 2106 2958 if (child->group) { 2107 syntax(); 2108 return 1; /* syntax error, groups and arglists don't mix */ 2109 } 2110 if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { 2111 debug_printf("checking %s for reserved-ness\n",dest->data); 2112 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; 2959 syntax(NULL); 2960 debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); 2961 return 1; 2962 } 2963 if (!child->argv && (ctx->parse_type & PARSEFLAG_SEMICOLON)) { 2964 debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data); 2965 if (reserved_word(dest, ctx)) { 2966 debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); 2967 return (ctx->res_w == RES_SNTX); 2968 } 2113 2969 } 2114 2970 glob_target = &child->glob_result; 2115 if (child->argv) flags |= GLOB_APPEND; 2971 if (child->argv) 2972 flags |= GLOB_APPEND; 2116 2973 } 2117 2974 gr = xglob(dest, flags, glob_target); 2118 if (gr != 0) return 1; 2975 if (gr != 0) { 2976 debug_printf_parse("done_word return 1: xglob returned %d\n", gr); 2977 return 1; 2978 } 2119 2979 2120 2980 b_reset(dest); 2121 2981 if (ctx->pending_redirect) { 2122 ctx->pending_redirect =NULL;2982 ctx->pending_redirect = NULL; 2123 2983 if (glob_target->gl_pathc != 1) { 2124 2984 bb_error_msg("ambiguous redirect"); 2985 debug_printf_parse("done_word return 1: ambiguous redirect\n"); 2125 2986 return 1; 2126 2987 } … … 2128 2989 child->argv = glob_target->gl_pathv; 2129 2990 } 2130 if (ctx->w == RES_FOR) { 2131 done_word(dest,ctx); 2132 done_pipe(ctx,PIPE_SEQ); 2133 } 2991 #if ENABLE_HUSH_LOOPS 2992 if (ctx->res_w == RES_FOR) { 2993 done_word(dest, ctx); 2994 done_pipe(ctx, PIPE_SEQ); 2995 } 2996 #endif 2997 debug_printf_parse("done_word return 0\n"); 2134 2998 return 0; 2135 2999 } … … 2140 3004 { 2141 3005 /* The child is really already in the pipe structure, so 2142 * advance the pipe counter and make a new, null child. 2143 * Only real trickiness here is that the uncommitted 2144 * child structure, to which ctx->child points, is not 2145 * counted in pi->num_progs. */ 2146 struct pipe *pi=ctx->pipe; 2147 struct child_prog *prog=ctx->child; 2148 2149 if (prog && prog->group == NULL 2150 && prog->argv == NULL 2151 && prog->redirects == NULL) { 2152 debug_printf("done_command: skipping null command\n"); 2153 return 0; 2154 } else if (prog) { 3006 * advance the pipe counter and make a new, null child. */ 3007 struct pipe *pi = ctx->pipe; 3008 struct child_prog *child = ctx->child; 3009 3010 if (child) { 3011 if (child->group == NULL 3012 && child->argv == NULL 3013 && child->redirects == NULL 3014 ) { 3015 debug_printf_parse("done_command: skipping null cmd, num_progs=%d\n", pi->num_progs); 3016 return pi->num_progs; 3017 } 2155 3018 pi->num_progs++; 2156 debug_printf ("done_command: num_progs incremented to %d\n",pi->num_progs);3019 debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); 2157 3020 } else { 2158 debug_printf("done_command: initializing\n"); 2159 } 3021 debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs); 3022 } 3023 3024 /* Only real trickiness here is that the uncommitted 3025 * child structure is not counted in pi->num_progs. */ 2160 3026 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); 2161 2162 prog = pi->progs + pi->num_progs; 2163 prog->redirects = NULL; 2164 prog->argv = NULL; 2165 prog->is_stopped = 0; 2166 prog->group = NULL; 2167 prog->glob_result.gl_pathv = NULL; 2168 prog->family = pi; 2169 prog->sp = 0; 2170 ctx->child = prog; 2171 prog->type = ctx->type; 2172 3027 child = &pi->progs[pi->num_progs]; 3028 3029 memset(child, 0, sizeof(*child)); 3030 /*child->redirects = NULL;*/ 3031 /*child->argv = NULL;*/ 3032 /*child->is_stopped = 0;*/ 3033 /*child->group = NULL;*/ 3034 /*child->glob_result.gl_pathv = NULL;*/ 3035 child->family = pi; 3036 //sp: /*child->sp = 0;*/ 3037 //pt: child->parse_type = ctx->parse_type; 3038 3039 ctx->child = child; 2173 3040 /* but ctx->pipe and ctx->list_head remain unchanged */ 2174 return 0; 3041 3042 return pi->num_progs; /* used only for 0/nonzero check */ 2175 3043 } 2176 3044 … … 2178 3046 { 2179 3047 struct pipe *new_p; 2180 done_command(ctx); /* implicit closure of previous command */ 2181 debug_printf("done_pipe, type %d\n", type); 3048 int not_null; 3049 3050 debug_printf_parse("done_pipe entered, followup %d\n", type); 3051 not_null = done_command(ctx); /* implicit closure of previous command */ 2182 3052 ctx->pipe->followup = type; 2183 ctx->pipe->r_mode = ctx->w; 2184 new_p=new_pipe(); 2185 ctx->pipe->next = new_p; 2186 ctx->pipe = new_p; 2187 ctx->child = NULL; 2188 done_command(ctx); /* set up new pipe to accept commands */ 3053 ctx->pipe->res_word = ctx->res_w; 3054 /* Without this check, even just <enter> on command line generates 3055 * tree of three NOPs (!). Which is harmless but annoying. 3056 * IOW: it is safe to do it unconditionally. */ 3057 if (not_null) { 3058 new_p = new_pipe(); 3059 ctx->pipe->next = new_p; 3060 ctx->pipe = new_p; 3061 ctx->child = NULL; 3062 done_command(ctx); /* set up new pipe to accept commands */ 3063 } 3064 debug_printf_parse("done_pipe return 0\n"); 2189 3065 return 0; 2190 3066 } … … 2196 3072 static int redirect_dup_num(struct in_str *input) 2197 3073 { 2198 int ch, d =0, ok=0;3074 int ch, d = 0, ok = 0; 2199 3075 ch = b_peek(input); 2200 3076 if (ch != '&') return -1; 2201 3077 2202 3078 b_getch(input); /* get the & */ 2203 ch =b_peek(input);3079 ch = b_peek(input); 2204 3080 if (ch == '-') { 2205 3081 b_getch(input); … … 2207 3083 } 2208 3084 while (isdigit(ch)) { 2209 d = d*10 +(ch-'0');2210 ok =1;3085 d = d*10 + (ch-'0'); 3086 ok = 1; 2211 3087 b_getch(input); 2212 3088 ch = b_peek(input); … … 2233 3109 int num; 2234 3110 2235 if (o->length==0) return -1; 2236 for(num=0; num<o->length; num++) { 2237 if (!isdigit(*(o->data+num))) { 3111 if (o->length == 0) 3112 return -1; 3113 for (num = 0; num < o->length; num++) { 3114 if (!isdigit(*(o->data + num))) { 2238 3115 return -1; 2239 3116 } 2240 3117 } 2241 3118 /* reuse num (and save an int) */ 2242 num =atoi(o->data);3119 num = atoi(o->data); 2243 3120 b_reset(o); 2244 3121 return num; 2245 3122 } 2246 3123 3124 #if ENABLE_HUSH_TICK 2247 3125 static FILE *generate_stream_from_list(struct pipe *head) 2248 3126 { 2249 3127 FILE *pf; 2250 #if 12251 3128 int pid, channel[2]; 2252 if (pipe(channel)<0) bb_perror_msg_and_die("pipe"); 2253 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__) 2254 pid=fork(); 3129 3130 xpipe(channel); 3131 #if BB_MMU 3132 pid = fork(); 2255 3133 #else 2256 pid =vfork();2257 #endif 2258 if (pid <0) {3134 pid = vfork(); 3135 #endif 3136 if (pid < 0) { 2259 3137 bb_perror_msg_and_die("fork"); 2260 } else if (pid ==0) {3138 } else if (pid == 0) { 2261 3139 close(channel[0]); 2262 3140 if (channel[1] != 1) { 2263 dup2(channel[1], 1);3141 dup2(channel[1], 1); 2264 3142 close(channel[1]); 2265 3143 } 2266 #if 0 2267 #define SURROGATE "surrogate response" 2268 write(1,SURROGATE,sizeof(SURROGATE)); 2269 _exit(run_list(head)); 2270 #else 3144 /* Prevent it from trying to handle ctrl-z etc */ 3145 #if ENABLE_HUSH_JOB 3146 run_list_level = 1; 3147 #endif 3148 /* Process substitution is not considered to be usual 3149 * 'command execution'. 3150 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */ 3151 /* Not needed, we are relying on it being disabled 3152 * everywhere outside actual command execution. */ 3153 /*set_jobctrl_sighandler(SIG_IGN);*/ 3154 set_misc_sighandler(SIG_DFL); 2271 3155 _exit(run_list_real(head)); /* leaks memory */ 2272 #endif 2273 } 2274 debug_printf("forked child %d\n",pid); 3156 } 2275 3157 close(channel[1]); 2276 pf = fdopen(channel[0],"r"); 2277 debug_printf("pipe on FILE *%p\n",pf); 2278 #else 2279 free_pipe_list(head,0); 2280 pf=popen("echo surrogate response","r"); 2281 debug_printf("started fake pipe on FILE *%p\n",pf); 2282 #endif 3158 pf = fdopen(channel[0], "r"); 2283 3159 return pf; 2284 3160 } 2285 3161 2286 /* this version hacked for testing purposes*/2287 /* return code is exit status of the process that is run. */ 2288 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, intsubst_end)2289 { 2290 int retcode ;2291 o_string result =NULL_O_STRING;3162 /* Return code is exit status of the process that is run. */ 3163 static int process_command_subs(o_string *dest, struct p_context *ctx, 3164 struct in_str *input, const char *subst_end) 3165 { 3166 int retcode, ch, eol_cnt; 3167 o_string result = NULL_O_STRING; 2292 3168 struct p_context inner; 2293 3169 FILE *p; 2294 3170 struct in_str pipe_str; 3171 2295 3172 initialize_context(&inner); 2296 3173 2297 3174 /* recursion to generate command */ 2298 3175 retcode = parse_stream(&result, &inner, input, subst_end); 2299 if (retcode != 0) return retcode; /* syntax error or EOF */ 3176 if (retcode != 0) 3177 return retcode; /* syntax error or EOF */ 2300 3178 done_word(&result, &inner); 2301 3179 done_pipe(&inner, PIPE_SEQ); 2302 3180 b_free(&result); 2303 3181 2304 p =generate_stream_from_list(inner.list_head);2305 if (p ==NULL) return 1;3182 p = generate_stream_from_list(inner.list_head); 3183 if (p == NULL) return 1; 2306 3184 mark_open(fileno(p)); 2307 3185 setup_file_in_str(&pipe_str, p); 2308 3186 2309 3187 /* now send results of command back into original context */ 2310 retcode = parse_stream(dest, ctx, &pipe_str, '\0'); 2311 /* XXX In case of a syntax error, should we try to kill the child? 2312 * That would be tough to do right, so just read until EOF. */ 2313 if (retcode == 1) { 2314 while (b_getch(&pipe_str)!=EOF) { /* discard */ }; 3188 eol_cnt = 0; 3189 while ((ch = b_getch(&pipe_str)) != EOF) { 3190 if (ch == '\n') { 3191 eol_cnt++; 3192 continue; 3193 } 3194 while (eol_cnt) { 3195 b_addqchr(dest, '\n', dest->quote); 3196 eol_cnt--; 3197 } 3198 b_addqchr(dest, ch, dest->quote); 2315 3199 } 2316 3200 … … 2318 3202 /* This is the step that wait()s for the child. Should be pretty 2319 3203 * safe, since we just read an EOF from its stdout. We could try 2320 * to better, by using wait(), and keeping track of background jobs3204 * to do better, by using wait(), and keeping track of background jobs 2321 3205 * at the same time. That would be a lot of work, and contrary 2322 3206 * to the KISS philosophy of this program. */ 2323 3207 mark_closed(fileno(p)); 2324 retcode=pclose(p); 2325 free_pipe_list(inner.list_head,0); 2326 debug_printf("pclosed, retcode=%d\n",retcode); 2327 /* XXX this process fails to trim a single trailing newline */ 3208 retcode = fclose(p); 3209 free_pipe_list(inner.list_head, 0); 3210 debug_printf("closed FILE from child, retcode=%d\n", retcode); 2328 3211 return retcode; 2329 3212 } 3213 #endif 2330 3214 2331 3215 static int parse_group(o_string *dest, struct p_context *ctx, 2332 3216 struct in_str *input, int ch) 2333 3217 { 2334 int rcode, endch=0; 3218 int rcode; 3219 const char *endch = NULL; 2335 3220 struct p_context sub; 2336 3221 struct child_prog *child = ctx->child; 3222 3223 debug_printf_parse("parse_group entered\n"); 2337 3224 if (child->argv) { 2338 syntax(); 2339 return 1; /* syntax error, groups and arglists don't mix */ 3225 syntax(NULL); 3226 debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); 3227 return 1; 2340 3228 } 2341 3229 initialize_context(&sub); 2342 switch(ch) { 2343 case '(': endch=')'; child->subshell=1; break; 2344 case '{': endch='}'; break; 2345 default: syntax(); /* really logic error */ 2346 } 2347 rcode=parse_stream(dest,&sub,input,endch); 2348 done_word(dest,&sub); /* finish off the final word in the subcontext */ 3230 endch = "}"; 3231 if (ch == '(') { 3232 endch = ")"; 3233 child->subshell = 1; 3234 } 3235 rcode = parse_stream(dest, &sub, input, endch); 3236 //vda: err chk? 3237 done_word(dest, &sub); /* finish off the final word in the subcontext */ 2349 3238 done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ 2350 3239 child->group = sub.list_head; 3240 3241 debug_printf_parse("parse_group return %d\n", rcode); 2351 3242 return rcode; 2352 3243 /* child remains "open", available for possible redirects */ 2353 3244 } 2354 3245 2355 /* basically useful version until someone wants to get fancier,3246 /* Basically useful version until someone wants to get fancier, 2356 3247 * see the bash man page under "Parameter Expansion" */ 2357 static char *lookup_param(char *src) 2358 { 2359 char *p=NULL; 2360 if (src) { 2361 p = getenv(src); 2362 if (!p) 2363 p = get_local_var(src); 2364 } 2365 return p; 3248 static const char *lookup_param(const char *src) 3249 { 3250 struct variable *var = get_local_var(src); 3251 if (var) 3252 return strchr(var->varstr, '=') + 1; 3253 return NULL; 2366 3254 } 2367 3255 … … 2369 3257 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) 2370 3258 { 2371 int i, advance=0;2372 char sep[]=" ";2373 int ch = input->peek(input); /* first character after the $ */ 2374 debug_printf ("handle_dollar: ch=%c\n",ch);3259 int ch = b_peek(input); /* first character after the $ */ 3260 unsigned char quote_mask = dest->quote ? 0x80 : 0; 3261 3262 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); 2375 3263 if (isalpha(ch)) { 2376 3264 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2377 ctx->child->sp++; 2378 while(ch=b_peek(input),isalnum(ch) || ch=='_') { 3265 //sp: ctx->child->sp++; 3266 while (1) { 3267 debug_printf_parse(": '%c'\n", ch); 2379 3268 b_getch(input); 2380 b_addchr(dest,ch); 3269 b_addchr(dest, ch | quote_mask); 3270 quote_mask = 0; 3271 ch = b_peek(input); 3272 if (!isalnum(ch) && ch != '_') 3273 break; 2381 3274 } 2382 3275 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2383 3276 } else if (isdigit(ch)) { 2384 i = ch-'0'; /* XXX is $0 special? */ 2385 if (i<global_argc) { 2386 parse_string(dest, ctx, global_argv[i]); /* recursion */ 2387 } 2388 advance = 1; 3277 make_one_char_var: 3278 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3279 //sp: ctx->child->sp++; 3280 debug_printf_parse(": '%c'\n", ch); 3281 b_getch(input); 3282 b_addchr(dest, ch | quote_mask); 3283 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2389 3284 } else switch (ch) { 2390 case '$': 2391 b_adduint(dest,getpid()); 2392 advance = 1; 2393 break; 2394 case '!': 2395 if (last_bg_pid > 0) b_adduint(dest, last_bg_pid); 2396 advance = 1; 2397 break; 2398 case '?': 2399 b_adduint(dest,last_return_code); 2400 advance = 1; 2401 break; 2402 case '#': 2403 b_adduint(dest,global_argc ? global_argc-1 : 0); 2404 advance = 1; 2405 break; 3285 case '$': /* pid */ 3286 case '!': /* last bg pid */ 3287 case '?': /* last exit code */ 3288 case '#': /* number of args */ 3289 case '*': /* args */ 3290 case '@': /* args */ 3291 goto make_one_char_var; 2406 3292 case '{': 2407 3293 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2408 ctx->child->sp++;3294 //sp: ctx->child->sp++; 2409 3295 b_getch(input); 2410 3296 /* XXX maybe someone will try to escape the '}' */ 2411 while(ch=b_getch(input),ch!=EOF && ch!='}') { 2412 b_addchr(dest,ch); 2413 } 2414 if (ch != '}') { 2415 syntax(); 2416 return 1; 3297 while (1) { 3298 ch = b_getch(input); 3299 if (ch == '}') 3300 break; 3301 if (!isalnum(ch) && ch != '_') { 3302 syntax("unterminated ${name}"); 3303 debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); 3304 return 1; 3305 } 3306 debug_printf_parse(": '%c'\n", ch); 3307 b_addchr(dest, ch | quote_mask); 3308 quote_mask = 0; 2417 3309 } 2418 3310 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2419 3311 break; 3312 #if ENABLE_HUSH_TICK 2420 3313 case '(': 2421 3314 b_getch(input); 2422 process_command_subs(dest, ctx, input, ')');3315 process_command_subs(dest, ctx, input, ")"); 2423 3316 break; 2424 case '*': 2425 sep[0]=ifs[0]; 2426 for (i=1; i<global_argc; i++) { 2427 parse_string(dest, ctx, global_argv[i]); 2428 if (i+1 < global_argc) parse_string(dest, ctx, sep); 2429 } 2430 break; 2431 case '@': 3317 #endif 2432 3318 case '-': 2433 3319 case '_': 2434 3320 /* still unhandled, but should be eventually */ 2435 bb_error_msg("unhandled syntax: $%c", ch);3321 bb_error_msg("unhandled syntax: $%c", ch); 2436 3322 return 1; 2437 3323 break; 2438 3324 default: 2439 b_addqchr(dest,'$',dest->quote); 2440 } 2441 /* Eat the character if the flag was set. If the compiler 2442 * is smart enough, we could substitute "b_getch(input);" 2443 * for all the "advance = 1;" above, and also end up with 2444 * a nice size-optimized program. Hah! That'll be the day. 2445 */ 2446 if (advance) b_getch(input); 3325 b_addqchr(dest, '$', dest->quote); 3326 } 3327 debug_printf_parse("handle_dollar return 0\n"); 2447 3328 return 0; 2448 3329 } 2449 3330 2450 int parse_string(o_string *dest, struct p_context *ctx, const char *src)2451 {2452 struct in_str foo;2453 setup_string_in_str(&foo, src);2454 return parse_stream(dest, ctx, &foo, '\0');2455 }2456 2457 3331 /* return code is 0 for normal exit, 1 for syntax error */ 2458 int parse_stream(o_string *dest, struct p_context *ctx,2459 struct in_str *input, intend_trigger)3332 static int parse_stream(o_string *dest, struct p_context *ctx, 3333 struct in_str *input, const char *end_trigger) 2460 3334 { 2461 3335 int ch, m; … … 2468 3342 * found. When recursing, quote state is passed in via dest->quote. */ 2469 3343 2470 debug_printf("parse_stream, end_trigger=%d\n",end_trigger); 2471 while ((ch=b_getch(input))!=EOF) { 2472 m = map[ch]; 2473 next = (ch == '\n') ? 0 : b_peek(input); 2474 debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", 2475 ch,ch,m,dest->quote); 2476 if (m==0 || ((m==1 || m==2) && dest->quote)) { 3344 debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger); 3345 3346 while (1) { 3347 m = CHAR_IFS; 3348 next = '\0'; 3349 ch = b_getch(input); 3350 if (ch != EOF) { 3351 m = charmap[ch]; 3352 if (ch != '\n') 3353 next = b_peek(input); 3354 } 3355 debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", 3356 ch, ch, m, dest->quote); 3357 if (m == CHAR_ORDINARY 3358 || (m != CHAR_SPECIAL && dest->quote) 3359 ) { 3360 if (ch == EOF) { 3361 syntax("unterminated \""); 3362 debug_printf_parse("parse_stream return 1: unterminated \"\n"); 3363 return 1; 3364 } 2477 3365 b_addqchr(dest, ch, dest->quote); 2478 } else { 2479 if (m==2) { /* unquoted IFS */ 2480 if (done_word(dest, ctx)) { 2481 return 1; 2482 } 2483 /* If we aren't performing a substitution, treat a newline as a 2484 * command separator. */ 2485 if (end_trigger != '\0' && ch=='\n') 2486 done_pipe(ctx,PIPE_SEQ); 2487 } 2488 if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) { 2489 debug_printf("leaving parse_stream (triggered)\n"); 2490 return 0; 2491 } 2492 #if 0 2493 if (ch=='\n') { 2494 /* Yahoo! Time to run with it! */ 2495 done_pipe(ctx,PIPE_SEQ); 2496 run_list(ctx->list_head); 2497 initialize_context(ctx); 2498 } 2499 #endif 2500 if (m!=2) switch (ch) { 3366 continue; 3367 } 3368 if (m == CHAR_IFS) { 3369 if (done_word(dest, ctx)) { 3370 debug_printf_parse("parse_stream return 1: done_word!=0\n"); 3371 return 1; 3372 } 3373 if (ch == EOF) 3374 break; 3375 /* If we aren't performing a substitution, treat 3376 * a newline as a command separator. 3377 * [why we don't handle it exactly like ';'? --vda] */ 3378 if (end_trigger && ch == '\n') { 3379 done_pipe(ctx, PIPE_SEQ); 3380 } 3381 } 3382 if ((end_trigger && strchr(end_trigger, ch)) 3383 && !dest->quote && ctx->res_w == RES_NONE 3384 ) { 3385 debug_printf_parse("parse_stream return 0: end_trigger char found\n"); 3386 return 0; 3387 } 3388 if (m == CHAR_IFS) 3389 continue; 3390 switch (ch) { 2501 3391 case '#': 2502 3392 if (dest->length == 0 && !dest->quote) { 2503 while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); } 3393 while (1) { 3394 ch = b_peek(input); 3395 if (ch == EOF || ch == '\n') 3396 break; 3397 b_getch(input); 3398 } 2504 3399 } else { 2505 3400 b_addqchr(dest, ch, dest->quote); … … 2508 3403 case '\\': 2509 3404 if (next == EOF) { 2510 syntax(); 3405 syntax("\\<eof>"); 3406 debug_printf_parse("parse_stream return 1: \\<eof>\n"); 2511 3407 return 1; 2512 3408 } … … 2515 3411 break; 2516 3412 case '$': 2517 if (handle_dollar(dest, ctx, input)!=0) return 1; 3413 if (handle_dollar(dest, ctx, input) != 0) { 3414 debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n"); 3415 return 1; 3416 } 2518 3417 break; 2519 3418 case '\'': 2520 3419 dest->nonnull = 1; 2521 while(ch=b_getch(input),ch!=EOF && ch!='\'') { 2522 b_addchr(dest,ch); 2523 } 2524 if (ch==EOF) { 2525 syntax(); 3420 while (1) { 3421 ch = b_getch(input); 3422 if (ch == EOF || ch == '\'') 3423 break; 3424 b_addchr(dest, ch); 3425 } 3426 if (ch == EOF) { 3427 syntax("unterminated '"); 3428 debug_printf_parse("parse_stream return 1: unterminated '\n"); 2526 3429 return 1; 2527 3430 } … … 2531 3434 dest->quote = !dest->quote; 2532 3435 break; 3436 #if ENABLE_HUSH_TICK 2533 3437 case '`': 2534 process_command_subs(dest, ctx, input, '`');3438 process_command_subs(dest, ctx, input, "`"); 2535 3439 break; 3440 #endif 2536 3441 case '>': 2537 3442 redir_fd = redirect_opt_num(dest); 2538 3443 done_word(dest, ctx); 2539 redir_style =REDIRECT_OVERWRITE;3444 redir_style = REDIRECT_OVERWRITE; 2540 3445 if (next == '>') { 2541 redir_style =REDIRECT_APPEND;3446 redir_style = REDIRECT_APPEND; 2542 3447 b_getch(input); 2543 } else if (next == '(') { 2544 syntax(); /* until we support >(list) Process Substitution */ 3448 } 3449 #if 0 3450 else if (next == '(') { 3451 syntax(">(process) not supported"); 3452 debug_printf_parse("parse_stream return 1: >(process) not supported\n"); 2545 3453 return 1; 2546 3454 } 3455 #endif 2547 3456 setup_redirect(ctx, redir_fd, redir_style, input); 2548 3457 break; … … 2550 3459 redir_fd = redirect_opt_num(dest); 2551 3460 done_word(dest, ctx); 2552 redir_style =REDIRECT_INPUT;3461 redir_style = REDIRECT_INPUT; 2553 3462 if (next == '<') { 2554 redir_style =REDIRECT_HEREIS;3463 redir_style = REDIRECT_HEREIS; 2555 3464 b_getch(input); 2556 3465 } else if (next == '>') { 2557 redir_style =REDIRECT_IO;3466 redir_style = REDIRECT_IO; 2558 3467 b_getch(input); 2559 } else if (next == '(') { 2560 syntax(); /* until we support <(list) Process Substitution */ 3468 } 3469 #if 0 3470 else if (next == '(') { 3471 syntax("<(process) not supported"); 3472 debug_printf_parse("parse_stream return 1: <(process) not supported\n"); 2561 3473 return 1; 2562 3474 } 3475 #endif 2563 3476 setup_redirect(ctx, redir_fd, redir_style, input); 2564 3477 break; 2565 3478 case ';': 2566 3479 done_word(dest, ctx); 2567 done_pipe(ctx, PIPE_SEQ);3480 done_pipe(ctx, PIPE_SEQ); 2568 3481 break; 2569 3482 case '&': 2570 3483 done_word(dest, ctx); 2571 if (next =='&') {3484 if (next == '&') { 2572 3485 b_getch(input); 2573 done_pipe(ctx, PIPE_AND);3486 done_pipe(ctx, PIPE_AND); 2574 3487 } else { 2575 done_pipe(ctx, PIPE_BG);3488 done_pipe(ctx, PIPE_BG); 2576 3489 } 2577 3490 break; 2578 3491 case '|': 2579 3492 done_word(dest, ctx); 2580 if (next =='|') {3493 if (next == '|') { 2581 3494 b_getch(input); 2582 done_pipe(ctx, PIPE_OR);3495 done_pipe(ctx, PIPE_OR); 2583 3496 } else { 2584 3497 /* we could pick up a file descriptor choice here … … 2590 3503 case '(': 2591 3504 case '{': 2592 if (parse_group(dest, ctx, input, ch)!=0) return 1; 3505 if (parse_group(dest, ctx, input, ch) != 0) { 3506 debug_printf_parse("parse_stream return 1: parse_group returned non-0\n"); 3507 return 1; 3508 } 2593 3509 break; 2594 3510 case ')': 2595 3511 case '}': 2596 syntax(); /* Proper use of this character caught by end_trigger */ 3512 syntax("unexpected }"); /* Proper use of this character is caught by end_trigger */ 3513 debug_printf_parse("parse_stream return 1: unexpected '}'\n"); 2597 3514 return 1; 2598 break;2599 3515 default: 2600 syntax(); /* this is really an internal logic error */ 2601 return 1; 2602 } 2603 } 2604 } 2605 /* complain if quote? No, maybe we just finished a command substitution 3516 if (ENABLE_HUSH_DEBUG) 3517 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 3518 } 3519 } 3520 /* Complain if quote? No, maybe we just finished a command substitution 2606 3521 * that was quoted. Example: 2607 3522 * $ echo "`cat foo` plus more" 2608 3523 * and we just got the EOF generated by the subshell that ran "cat foo" 2609 * The only real complaint is if we got an EOF when end_trigger != '\0',3524 * The only real complaint is if we got an EOF when end_trigger != NULL, 2610 3525 * that is, we were really supposed to get end_trigger, and never got 2611 3526 * one before the EOF. Can't use the standard "syntax error" return code, 2612 3527 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ 2613 debug_printf("leaving parse_stream (EOF)\n"); 2614 if (end_trigger != '\0') return -1; 3528 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); 3529 if (end_trigger) 3530 return -1; 2615 3531 return 0; 2616 3532 } 2617 3533 2618 static void mapset(const char *set, int code)2619 { 2620 const unsigned char *s;2621 for (s = (const unsigned char *)set; *s; s++) map[(int)*s] = code;2622 } 2623 2624 static void update_ ifs_map(void)2625 { 2626 /* char *ifs and char map[256] are both globals. */3534 static void set_in_charmap(const char *set, int code) 3535 { 3536 while (*set) 3537 charmap[(unsigned char)*set++] = code; 3538 } 3539 3540 static void update_charmap(void) 3541 { 3542 /* char *ifs and char charmap[256] are both globals. */ 2627 3543 ifs = getenv("IFS"); 2628 if (ifs == NULL) ifs=" \t\n"; 3544 if (ifs == NULL) 3545 ifs = " \t\n"; 2629 3546 /* Precompute a list of 'flow through' behavior so it can be treated 2630 3547 * quickly up front. Computation is necessary because of IFS. 2631 3548 * Special case handling of IFS == " \t\n" is not implemented. 2632 * The map[] array only really needs two bits each, and on most machines2633 * that would be faster because of the reduced L1 cache footprint.3549 * The charmap[] array only really needs two bits each, 3550 * and on most machines that would be faster (reduced L1 cache use). 2634 3551 */ 2635 memset(map,0,sizeof(map)); /* most characters flow through always */ 2636 mapset("\\$'\"`", 3); /* never flow through */ 2637 mapset("<>;&|(){}#", 1); /* flow through if quoted */ 2638 mapset(ifs, 2); /* also flow through if quoted */ 3552 memset(charmap, CHAR_ORDINARY, sizeof(charmap)); 3553 #if ENABLE_HUSH_TICK 3554 set_in_charmap("\\$\"`", CHAR_SPECIAL); 3555 #else 3556 set_in_charmap("\\$\"", CHAR_SPECIAL); 3557 #endif 3558 set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED); 3559 set_in_charmap(ifs, CHAR_IFS); /* are ordinary if quoted */ 2639 3560 } 2640 3561 2641 3562 /* most recursion does not come through here, the exception is 2642 * from builtin_source() */ 2643 int parse_stream_outer(struct in_str *inp, int flag) 2644 { 2645 3563 * from builtin_source() and builtin_eval() */ 3564 static int parse_and_run_stream(struct in_str *inp, int parse_flag) 3565 { 2646 3566 struct p_context ctx; 2647 o_string temp =NULL_O_STRING;3567 o_string temp = NULL_O_STRING; 2648 3568 int rcode; 2649 3569 do { 2650 ctx. type =flag;3570 ctx.parse_type = parse_flag; 2651 3571 initialize_context(&ctx); 2652 update_ifs_map(); 2653 if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); 2654 inp->promptmode=1; 2655 rcode = parse_stream(&temp, &ctx, inp, '\n'); 3572 update_charmap(); 3573 if (!(parse_flag & PARSEFLAG_SEMICOLON) || (parse_flag & PARSEFLAG_REPARSING)) 3574 set_in_charmap(";$&|", CHAR_ORDINARY); 3575 #if ENABLE_HUSH_INTERACTIVE 3576 inp->promptmode = 0; /* PS1 */ 3577 #endif 3578 /* We will stop & execute after each ';' or '\n'. 3579 * Example: "sleep 9999; echo TEST" + ctrl-C: 3580 * TEST should be printed */ 3581 rcode = parse_stream(&temp, &ctx, inp, ";\n"); 2656 3582 if (rcode != 1 && ctx.old_flag != 0) { 2657 syntax( );3583 syntax(NULL); 2658 3584 } 2659 3585 if (rcode != 1 && ctx.old_flag == 0) { 2660 3586 done_word(&temp, &ctx); 2661 done_pipe(&ctx,PIPE_SEQ); 3587 done_pipe(&ctx, PIPE_SEQ); 3588 debug_print_tree(ctx.list_head, 0); 3589 debug_printf_exec("parse_stream_outer: run_list\n"); 2662 3590 run_list(ctx.list_head); 2663 3591 } else { … … 2669 3597 temp.quote = 0; 2670 3598 inp->p = NULL; 2671 free_pipe_list(ctx.list_head, 0);3599 free_pipe_list(ctx.list_head, 0); 2672 3600 } 2673 3601 b_free(&temp); 2674 } while (rcode != -1 && !( flag &FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */3602 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ 2675 3603 return 0; 2676 3604 } 2677 3605 2678 static int parse_ string_outer(const char *s, intflag)3606 static int parse_and_run_string(const char *s, int parse_flag) 2679 3607 { 2680 3608 struct in_str input; 2681 3609 setup_string_in_str(&input, s); 2682 return parse_ stream_outer(&input,flag);2683 } 2684 2685 static int parse_ file_outer(FILE *f)3610 return parse_and_run_stream(&input, parse_flag); 3611 } 3612 3613 static int parse_and_run_file(FILE *f) 2686 3614 { 2687 3615 int rcode; 2688 3616 struct in_str input; 2689 3617 setup_file_in_str(&input, f); 2690 rcode = parse_ stream_outer(&input, FLAG_PARSE_SEMICOLON);3618 rcode = parse_and_run_stream(&input, PARSEFLAG_SEMICOLON); 2691 3619 return rcode; 2692 3620 } 2693 3621 3622 #if ENABLE_HUSH_JOB 2694 3623 /* Make sure we have a controlling tty. If we get started under a job 2695 3624 * aware app (like bash for example), make sure we are now in charge so … … 2697 3626 static void setup_job_control(void) 2698 3627 { 2699 static pid_t shell_pgrp; 2700 /* Loop until we are in the foreground. */ 2701 while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ())) 2702 kill (- shell_pgrp, SIGTTIN); 2703 2704 /* Ignore interactive and job-control signals. */ 2705 signal(SIGINT, SIG_IGN); 2706 signal(SIGQUIT, SIG_IGN); 2707 signal(SIGTERM, SIG_IGN); 2708 signal(SIGTSTP, SIG_IGN); 2709 signal(SIGTTIN, SIG_IGN); 2710 signal(SIGTTOU, SIG_IGN); 2711 signal(SIGCHLD, SIG_IGN); 3628 pid_t shell_pgrp; 3629 3630 saved_task_pgrp = shell_pgrp = getpgrp(); 3631 debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp); 3632 fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); 3633 3634 /* If we were ran as 'hush &', 3635 * sleep until we are in the foreground. */ 3636 while (tcgetpgrp(interactive_fd) != shell_pgrp) { 3637 /* Send TTIN to ourself (should stop us) */ 3638 kill(- shell_pgrp, SIGTTIN); 3639 shell_pgrp = getpgrp(); 3640 } 3641 3642 /* Ignore job-control and misc signals. */ 3643 set_jobctrl_sighandler(SIG_IGN); 3644 set_misc_sighandler(SIG_IGN); 3645 //huh? signal(SIGCHLD, SIG_IGN); 3646 3647 /* We _must_ restore tty pgrp on fatal signals */ 3648 set_fatal_sighandler(sigexit); 2712 3649 2713 3650 /* Put ourselves in our own process group. */ 2714 setsid(); 2715 shell_pgrp = getpid (); 2716 setpgid (shell_pgrp, shell_pgrp); 2717 3651 setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 2718 3652 /* Grab control of the terminal. */ 2719 tcsetpgrp(shell_terminal, shell_pgrp); 2720 } 2721 3653 tcsetpgrp(interactive_fd, getpid()); 3654 } 3655 #endif 3656 3657 int hush_main(int argc, char **argv); 2722 3658 int hush_main(int argc, char **argv) 2723 3659 { 3660 static const char version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR; 3661 static const struct variable const_shell_ver = { 3662 .next = NULL, 3663 .varstr = (char*)version_str, 3664 .max_len = 1, /* 0 can provoke free(name) */ 3665 .flg_export = 1, 3666 .flg_read_only = 1, 3667 }; 3668 2724 3669 int opt; 2725 3670 FILE *input; 2726 char **e = environ; 2727 3671 char **e; 3672 struct variable *cur_var; 3673 3674 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 3675 3676 /* Deal with HUSH_VERSION */ 3677 shell_ver = const_shell_ver; /* copying struct here */ 3678 top_var = &shell_ver; 3679 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ 3680 /* Initialize our shell local variables with the values 3681 * currently living in the environment */ 3682 cur_var = top_var; 3683 e = environ; 3684 if (e) while (*e) { 3685 char *value = strchr(*e, '='); 3686 if (value) { /* paranoia */ 3687 cur_var->next = xzalloc(sizeof(*cur_var)); 3688 cur_var = cur_var->next; 3689 cur_var->varstr = *e; 3690 cur_var->max_len = strlen(*e); 3691 cur_var->flg_export = 1; 3692 } 3693 e++; 3694 } 3695 putenv((char *)version_str); /* reinstate HUSH_VERSION */ 3696 3697 #if ENABLE_FEATURE_EDITING 3698 line_input_state = new_line_input_t(FOR_SHELL); 3699 #endif 2728 3700 /* XXX what should these be while sourcing /etc/profile? */ 2729 3701 global_argc = argc; 2730 3702 global_argv = argv; 2731 2732 /* (re?) initialize globals. Sometimes hush_main() ends up calling2733 * hush_main(), therefore we cannot rely on the BSS to zero out this2734 * stuff. Reset these to 0 every time. */2735 ifs = NULL;2736 /* map[] is taken care of with call to update_ifs_map() */2737 fake_mode = 0;2738 interactive = 0;2739 close_me_head = NULL;2740 last_bg_pid = 0;2741 job_list = NULL;2742 last_jobid = 0;2743 2744 3703 /* Initialize some more globals to non-zero values */ 2745 3704 set_cwd(); 2746 #ifdef CONFIG_FEATURE_COMMAND_EDITING 3705 #if ENABLE_HUSH_INTERACTIVE 3706 #if ENABLE_FEATURE_EDITING 2747 3707 cmdedit_set_initial_prompt(); 2748 #else2749 PS1 = NULL;2750 3708 #endif 2751 3709 PS2 = "> "; 2752 2753 /* initialize our shell local variables with the values 2754 * currently living in the environment */ 2755 if (e) { 2756 for (; *e; e++) 2757 set_local_var(*e, 2); /* without call putenv() */ 2758 } 2759 2760 last_return_code=EXIT_SUCCESS; 2761 3710 #endif 3711 3712 if (EXIT_SUCCESS) /* otherwise is already done */ 3713 last_return_code = EXIT_SUCCESS; 2762 3714 2763 3715 if (argv[0] && argv[0][0] == '-') { 2764 debug_printf("\nsourcing /etc/profile\n"); 2765 if ((input = fopen("/etc/profile", "r")) != NULL) { 3716 debug_printf("sourcing /etc/profile\n"); 3717 input = fopen("/etc/profile", "r"); 3718 if (input != NULL) { 2766 3719 mark_open(fileno(input)); 2767 parse_ file_outer(input);3720 parse_and_run_file(input); 2768 3721 mark_closed(fileno(input)); 2769 3722 fclose(input); 2770 3723 } 2771 3724 } 2772 input =stdin;3725 input = stdin; 2773 3726 2774 3727 while ((opt = getopt(argc, argv, "c:xif")) > 0) { 2775 3728 switch (opt) { 2776 case 'c': 2777 { 2778 global_argv = argv+optind; 2779 global_argc = argc-optind; 2780 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); 2781 goto final_return; 2782 } 2783 break; 2784 case 'i': 2785 interactive++; 2786 break; 2787 case 'f': 2788 fake_mode++; 2789 break; 2790 default: 3729 case 'c': 3730 global_argv = argv + optind; 3731 global_argc = argc - optind; 3732 opt = parse_and_run_string(optarg, PARSEFLAG_SEMICOLON); 3733 goto final_return; 3734 case 'i': 3735 /* Well, we cannot just declare interactiveness, 3736 * we have to have some stuff (ctty, etc) */ 3737 /* interactive_fd++; */ 3738 break; 3739 case 'f': 3740 fake_mode = 1; 3741 break; 3742 default: 2791 3743 #ifndef BB_VER 2792 2793 2794 3744 fprintf(stderr, "Usage: sh [FILE]...\n" 3745 " or: sh -c command [args]...\n\n"); 3746 exit(EXIT_FAILURE); 2795 3747 #else 2796 bb_show_usage(); 2797 #endif 2798 } 2799 } 2800 /* A shell is interactive if the `-i' flag was given, or if all of 3748 bb_show_usage(); 3749 #endif 3750 } 3751 } 3752 #if ENABLE_HUSH_JOB 3753 /* A shell is interactive if the '-i' flag was given, or if all of 2801 3754 * the following conditions are met: 2802 * 3755 * no -c command 2803 3756 * no arguments remaining or the -s flag given 2804 3757 * standard input is a terminal 2805 3758 * standard output is a terminal 2806 * Refer to Posix.2, the description of the `sh' utility. */ 2807 if (argv[optind]==NULL && input==stdin && 2808 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 2809 interactive++; 2810 } 2811 2812 debug_printf("\ninteractive=%d\n", interactive); 2813 if (interactive) { 3759 * Refer to Posix.2, the description of the 'sh' utility. */ 3760 if (argv[optind] == NULL && input == stdin 3761 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 3762 ) { 3763 saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 3764 debug_printf("saved_tty_pgrp=%d\n", saved_tty_pgrp); 3765 if (saved_tty_pgrp >= 0) { 3766 /* try to dup to high fd#, >= 255 */ 3767 interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 3768 if (interactive_fd < 0) { 3769 /* try to dup to any fd */ 3770 interactive_fd = dup(STDIN_FILENO); 3771 if (interactive_fd < 0) 3772 /* give up */ 3773 interactive_fd = 0; 3774 } 3775 // TODO: track & disallow any attempts of user 3776 // to (inadvertently) close/redirect it 3777 } 3778 } 3779 debug_printf("interactive_fd=%d\n", interactive_fd); 3780 if (interactive_fd) { 2814 3781 /* Looks like they want an interactive shell */ 2815 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET2816 printf( "\n\n%s hush - the humble shell v0.01 (testing)\n",2817 BB_BANNER);2818 printf( "Enter 'help' for a list of built-in commands.\n\n");2819 #endif2820 3782 setup_job_control(); 2821 } 2822 2823 if (argv[optind]==NULL) { 2824 opt=parse_file_outer(stdin); 3783 /* Make xfuncs do cleanup on exit */ 3784 die_sleep = -1; /* flag */ 3785 // FIXME: should we reset die_sleep = 0 whereever we fork? 3786 if (setjmp(die_jmp)) { 3787 /* xfunc has failed! die die die */ 3788 hush_exit(xfunc_error_retval); 3789 } 3790 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 3791 printf("\n\n%s hush - the humble shell v"HUSH_VER_STR"\n", bb_banner); 3792 printf("Enter 'help' for a list of built-in commands.\n\n"); 3793 #endif 3794 } 3795 #elif ENABLE_HUSH_INTERACTIVE 3796 /* no job control compiled, only prompt/line editing */ 3797 if (argv[optind] == NULL && input == stdin 3798 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 3799 ) { 3800 interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 3801 if (interactive_fd < 0) { 3802 /* try to dup to any fd */ 3803 interactive_fd = dup(STDIN_FILENO); 3804 if (interactive_fd < 0) 3805 /* give up */ 3806 interactive_fd = 0; 3807 } 3808 } 3809 3810 #endif 3811 3812 if (argv[optind] == NULL) { 3813 opt = parse_and_run_file(stdin); 2825 3814 goto final_return; 2826 3815 } 2827 3816 2828 3817 debug_printf("\nrunning script '%s'\n", argv[optind]); 2829 global_argv = argv+optind; 2830 global_argc = argc-optind; 2831 input = bb_xfopen(argv[optind], "r"); 2832 opt = parse_file_outer(input); 2833 2834 #ifdef CONFIG_FEATURE_CLEAN_UP 3818 global_argv = argv + optind; 3819 global_argc = argc - optind; 3820 input = xfopen(argv[optind], "r"); 3821 opt = parse_and_run_file(input); 3822 3823 final_return: 3824 3825 #if ENABLE_FEATURE_CLEAN_UP 2835 3826 fclose(input); 2836 if (cwd && cwd!= bb_msg_unknown)3827 if (cwd != bb_msg_unknown) 2837 3828 free((char*)cwd); 2838 { 2839 struct variables *cur, *tmp; 2840 for(cur = top_vars; cur; cur = tmp) { 2841 tmp = cur->next; 2842 if (!cur->flg_read_only) { 2843 free(cur->name); 2844 free(cur->value); 2845 free(cur); 2846 } 2847 } 2848 } 2849 #endif 2850 2851 final_return: 2852 return(opt?opt:last_return_code); 2853 } 2854 2855 static char *insert_var_value(char *inp) 2856 { 2857 int res_str_len = 0; 2858 int len; 2859 int done = 0; 2860 char *p, *p1, *res_str = NULL; 2861 2862 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { 2863 if (p != inp) { 2864 len = p - inp; 2865 res_str = xrealloc(res_str, (res_str_len + len)); 2866 strncpy((res_str + res_str_len), inp, len); 2867 res_str_len += len; 2868 } 2869 inp = ++p; 2870 p = strchr(inp, SPECIAL_VAR_SYMBOL); 2871 *p = '\0'; 2872 if ((p1 = lookup_param(inp))) { 2873 len = res_str_len + strlen(p1); 2874 res_str = xrealloc(res_str, (1 + len)); 2875 strcpy((res_str + res_str_len), p1); 2876 res_str_len = len; 2877 } 2878 *p = SPECIAL_VAR_SYMBOL; 2879 inp = ++p; 2880 done = 1; 2881 } 2882 if (done) { 2883 res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); 2884 strcpy((res_str + res_str_len), inp); 2885 while ((p = strchr(res_str, '\n'))) { 2886 *p = ' '; 2887 } 2888 } 2889 return (res_str == NULL) ? inp : res_str; 2890 } 2891 2892 static char **make_list_in(char **inp, char *name) 2893 { 2894 int len, i; 2895 int name_len = strlen(name); 2896 int n = 0; 2897 char **list; 2898 char *p1, *p2, *p3; 2899 2900 /* create list of variable values */ 2901 list = xmalloc(sizeof(*list)); 2902 for (i = 0; inp[i]; i++) { 2903 p3 = insert_var_value(inp[i]); 2904 p1 = p3; 2905 while (*p1) { 2906 if ((*p1 == ' ')) { 2907 p1++; 2908 continue; 2909 } 2910 if ((p2 = strchr(p1, ' '))) { 2911 len = p2 - p1; 2912 } else { 2913 len = strlen(p1); 2914 p2 = p1 + len; 2915 } 2916 /* we use n + 2 in realloc for list,because we add 2917 * new element and then we will add NULL element */ 2918 list = xrealloc(list, sizeof(*list) * (n + 2)); 2919 list[n] = xmalloc(2 + name_len + len); 2920 strcpy(list[n], name); 2921 strcat(list[n], "="); 2922 strncat(list[n], p1, len); 2923 list[n++][name_len + len + 1] = '\0'; 2924 p1 = p2; 2925 } 2926 if (p3 != inp[i]) free(p3); 2927 } 2928 list[n] = NULL; 2929 return list; 2930 } 2931 2932 /* Make new string for parser */ 2933 static char * make_string(char ** inp) 2934 { 2935 char *p; 2936 char *str = NULL; 2937 int n; 2938 int len = 2; 2939 2940 for (n = 0; inp[n]; n++) { 2941 p = insert_var_value(inp[n]); 2942 str = xrealloc(str, (len + strlen(p))); 2943 if (n) { 2944 strcat(str, " "); 2945 } else { 2946 *str = '\0'; 2947 } 2948 strcat(str, p); 2949 len = strlen(str) + 3; 2950 if (p != inp[n]) free(p); 2951 } 2952 len = strlen(str); 2953 *(str + len) = '\n'; 2954 *(str + len + 1) = '\0'; 2955 return str; 2956 } 3829 cur_var = top_var->next; 3830 while (cur_var) { 3831 struct variable *tmp = cur_var; 3832 if (!cur_var->max_len) 3833 free(cur_var->varstr); 3834 cur_var = cur_var->next; 3835 free(tmp); 3836 } 3837 #endif 3838 hush_exit(opt ? opt : last_return_code); 3839 }
Note:
See TracChangeset
for help on using the changeset viewer.