summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-17 15:38:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-17 15:38:46 +0000
commitc8be5ee325a374525f503d11eccb5da3ee35a509 (patch)
tree0d2e996f0222c828da06bbbe25d32098aaa18dfa /shell/hush.c
parentb6a741ffa7be0926049c663e218864288e9161c1 (diff)
downloadbusybox-w32-c8be5ee325a374525f503d11eccb5da3ee35a509.tar.gz
busybox-w32-c8be5ee325a374525f503d11eccb5da3ee35a509.tar.bz2
busybox-w32-c8be5ee325a374525f503d11eccb5da3ee35a509.zip
hush: do "struct globals" trick. hush.o data+bss = 0 bytes now.
+60 bytes to image, but -8000 bytes in bss.
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c239
1 files changed, 134 insertions, 105 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 9f0cc641e..a462090c6 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -81,6 +81,7 @@
81#include <glob.h> /* glob, of course */ 81#include <glob.h> /* glob, of course */
82#include <getopt.h> /* should be pretty obvious */ 82#include <getopt.h> /* should be pretty obvious */
83/* #include <dmalloc.h> */ 83/* #include <dmalloc.h> */
84extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
84 85
85 86
86/* If you comment out one of these below, it will be #defined later 87/* If you comment out one of these below, it will be #defined later
@@ -273,49 +274,6 @@ struct variables {
273 int flg_read_only; 274 int flg_read_only;
274}; 275};
275 276
276/* globals, connect us to the outside world
277 * the first three support $?, $#, and $1 */
278static char **global_argv;
279static int global_argc;
280static int last_return_code;
281extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
282
283/* "globals" within this file */
284enum {
285 CHAR_ORDINARY = 0,
286 CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */
287 CHAR_IFS = 2, /* treated as ordinary if quoted */
288 CHAR_SPECIAL = 3, /* example: $ */
289};
290static unsigned char charmap[256];
291static const char *ifs;
292static int fake_mode;
293static struct close_me *close_me_head;
294static const char *cwd;
295static unsigned last_bg_pid;
296#if !ENABLE_HUSH_INTERACTIVE
297enum { interactive_fd = 0 };
298#else
299/* 'interactive_fd' is a fd# open to ctty, if we have one
300 * _AND_ if we decided to act interactively */
301static int interactive_fd;
302#if ENABLE_HUSH_JOB
303static pid_t saved_task_pgrp;
304static pid_t saved_tty_pgrp;
305static int last_jobid;
306static struct pipe *job_list;
307#endif
308static const char *PS1;
309static const char *PS2;
310#endif
311
312#define HUSH_VER_STR "0.02"
313static struct variables shell_ver = { NULL, "HUSH_VERSION", HUSH_VER_STR, 1, 1 };
314static struct variables *top_vars = &shell_ver;
315
316#define B_CHUNK 100
317#define B_NOSPAC 1
318
319typedef struct { 277typedef struct {
320 char *data; 278 char *data;
321 int length; 279 int length;
@@ -324,8 +282,7 @@ typedef struct {
324 int nonnull; 282 int nonnull;
325} o_string; 283} o_string;
326#define NULL_O_STRING {NULL,0,0,0,0} 284#define NULL_O_STRING {NULL,0,0,0,0}
327/* used for initialization: 285/* used for initialization: o_string foo = NULL_O_STRING; */
328 o_string foo = NULL_O_STRING; */
329 286
330/* I can almost use ordinary FILE *. Is open_memstream() universally 287/* I can almost use ordinary FILE *. Is open_memstream() universally
331 * available? Where is it documented? */ 288 * available? Where is it documented? */
@@ -345,14 +302,114 @@ struct in_str {
345#define b_getch(input) ((input)->get(input)) 302#define b_getch(input) ((input)->get(input))
346#define b_peek(input) ((input)->peek(input)) 303#define b_peek(input) ((input)->peek(input))
347 304
348#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 305enum {
306 CHAR_ORDINARY = 0,
307 CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */
308 CHAR_IFS = 2, /* treated as ordinary if quoted */
309 CHAR_SPECIAL = 3, /* example: $ */
310};
349 311
350struct built_in_command { 312
351 const char *cmd; /* name */ 313/* "Globals" within this file */
352 const char *descr; /* description */ 314
353 int (*function) (char **argv); /* function ptr */ 315#define HUSH_VER_STR "0.02"
316static const struct variables const_shell_ver = {
317 NULL, "HUSH_VERSION", HUSH_VER_STR, 1, 1
318};
319
320/* Sorted roughly by size (smaller offsets == smaller code) */
321struct globals {
322#if ENABLE_HUSH_INTERACTIVE
323 /* 'interactive_fd' is a fd# open to ctty, if we have one
324 * _AND_ if we decided to act interactively */
325 int interactive_fd;
326 const char *PS1;
327 const char *PS2;
328#endif
329#if ENABLE_FEATURE_EDITING
330 line_input_t *line_input_state;
331#endif
332#if ENABLE_HUSH_JOB
333 int run_list_level;
334 pid_t saved_task_pgrp;
335 pid_t saved_tty_pgrp;
336 int last_jobid;
337 struct pipe *job_list;
338 struct pipe *toplevel_list;
339 smallint ctrl_z_flag;
340#endif
341 smallint fake_mode;
342 /* these three support $?, $#, and $1 */
343 char **global_argv;
344 int global_argc;
345 int last_return_code;
346 const char *ifs;
347 struct close_me *close_me_head;
348 const char *cwd;
349 unsigned last_bg_pid;
350 struct variables *top_vars; /* = &shell_ver (both are set in main()) */
351 struct variables shell_ver; /* = const_shell_ver */
352#if ENABLE_FEATURE_SH_STANDALONE
353 struct nofork_save_area nofork_save;
354#endif
355#if ENABLE_HUSH_JOB
356 sigjmp_buf toplevel_jb;
357#endif
358 unsigned char charmap[256];
359 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
354}; 360};
355 361
362#define G (*ptr_to_globals)
363
364#if !ENABLE_HUSH_INTERACTIVE
365enum { interactive_fd = 0 };
366#endif
367#if !ENABLE_HUSH_JOB
368enum { run_list_level = 0 };
369#endif
370
371#if ENABLE_HUSH_INTERACTIVE
372#define interactive_fd (G.interactive_fd )
373#define PS1 (G.PS1 )
374#define PS2 (G.PS2 )
375#endif
376#if ENABLE_FEATURE_EDITING
377#define line_input_state (G.line_input_state)
378#endif
379#if ENABLE_HUSH_JOB
380#define run_list_level (G.run_list_level )
381#define saved_task_pgrp (G.saved_task_pgrp )
382#define saved_tty_pgrp (G.saved_tty_pgrp )
383#define last_jobid (G.last_jobid )
384#define job_list (G.job_list )
385#define toplevel_list (G.toplevel_list )
386#define toplevel_jb (G.toplevel_jb )
387#define ctrl_z_flag (G.ctrl_z_flag )
388#endif /* JOB */
389#define global_argv (G.global_argv )
390#define global_argc (G.global_argc )
391#define last_return_code (G.last_return_code)
392#define ifs (G.ifs )
393#define fake_mode (G.fake_mode )
394#define close_me_head (G.close_me_head )
395#define cwd (G.cwd )
396#define last_bg_pid (G.last_bg_pid )
397#define top_vars (G.top_vars )
398#define shell_ver (G.shell_ver )
399#if ENABLE_FEATURE_SH_STANDALONE
400#define nofork_save (G.nofork_save )
401#endif
402#if ENABLE_HUSH_JOB
403#define toplevel_jb (G.toplevel_jb )
404#endif
405#define charmap (G.charmap )
406#define user_input_buf (G.user_input_buf )
407
408
409#define B_CHUNK 100
410#define B_NOSPAC 1
411#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
412
356static void __syntax(int line) 413static void __syntax(int line)
357{ 414{
358 bb_error_msg("syntax error hush.c:%d", line); 415 bb_error_msg("syntax error hush.c:%d", line);
@@ -457,6 +514,12 @@ static void unset_local_var(const char *name);
457 * in the parent shell process. If forked, of course they cannot. 514 * in the parent shell process. If forked, of course they cannot.
458 * For example, 'unset foo | whatever' will parse and run, but foo will 515 * For example, 'unset foo | whatever' will parse and run, but foo will
459 * still be set at the end. */ 516 * still be set at the end. */
517struct built_in_command {
518 const char *cmd; /* name */
519 const char *descr; /* description */
520 int (*function) (char **argv); /* function ptr */
521};
522
460static const struct built_in_command bltins[] = { 523static const struct built_in_command bltins[] = {
461#if ENABLE_HUSH_JOB 524#if ENABLE_HUSH_JOB
462 { "bg", "Resume a job in the background", builtin_fg_bg }, 525 { "bg", "Resume a job in the background", builtin_fg_bg },
@@ -487,10 +550,6 @@ static const struct built_in_command bltins[] = {
487 { NULL, NULL, NULL } 550 { NULL, NULL, NULL }
488}; 551};
489 552
490#if ENABLE_FEATURE_SH_STANDALONE
491struct nofork_save_area nofork_save;
492#endif
493
494#if ENABLE_HUSH_JOB 553#if ENABLE_HUSH_JOB
495 554
496/* move to libbb? */ 555/* move to libbb? */
@@ -539,9 +598,6 @@ static void set_every_sighandler(void (*handler)(int))
539 signal(SIGCHLD, handler); 598 signal(SIGCHLD, handler);
540} 599}
541 600
542static struct pipe *toplevel_list;
543static sigjmp_buf toplevel_jb;
544smallint ctrl_z_flag;
545static void handler_ctrl_c(int sig) 601static void handler_ctrl_c(int sig)
546{ 602{
547 debug_printf_jobs("got sig %d\n", sig); 603 debug_printf_jobs("got sig %d\n", sig);
@@ -1062,14 +1118,8 @@ static const char* setup_prompt_string(int promptmode)
1062 return prompt_str; 1118 return prompt_str;
1063} 1119}
1064 1120
1065#if ENABLE_FEATURE_EDITING
1066static line_input_t *line_input_state;
1067#endif
1068
1069static void get_user_input(struct in_str *i) 1121static void get_user_input(struct in_str *i)
1070{ 1122{
1071 static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
1072
1073 int r; 1123 int r;
1074 const char *prompt_str; 1124 const char *prompt_str;
1075 1125
@@ -1081,20 +1131,20 @@ static void get_user_input(struct in_str *i)
1081 ** atexit() handlers and other unwanted stuff to our 1131 ** atexit() handlers and other unwanted stuff to our
1082 ** child processes (rob@sysgo.de) 1132 ** child processes (rob@sysgo.de)
1083 */ 1133 */
1084 r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state); 1134 r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state);
1085 i->eof_flag = (r < 0); 1135 i->eof_flag = (r < 0);
1086 if (i->eof_flag) { /* EOF/error detected */ 1136 if (i->eof_flag) { /* EOF/error detected */
1087 the_command[0] = EOF; /* yes, it will be truncated, it's ok */ 1137 user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
1088 the_command[1] = '\0'; 1138 user_input_buf[1] = '\0';
1089 } 1139 }
1090#else 1140#else
1091 fputs(prompt_str, stdout); 1141 fputs(prompt_str, stdout);
1092 fflush(stdout); 1142 fflush(stdout);
1093 the_command[0] = r = fgetc(i->file); 1143 user_input_buf[0] = r = fgetc(i->file);
1094 /*the_command[1] = '\0'; - already is and never changed */ 1144 /*user_input_buf[1] = '\0'; - already is and never changed */
1095 i->eof_flag = (r == EOF); 1145 i->eof_flag = (r == EOF);
1096#endif 1146#endif
1097 i->p = the_command; 1147 i->p = user_input_buf;
1098} 1148}
1099#endif /* INTERACTIVE */ 1149#endif /* INTERACTIVE */
1100 1150
@@ -1879,12 +1929,6 @@ static void debug_print_tree(struct pipe *pi, int lvl)
1879 * global data until exec/_exit (we can be a child after vfork!) */ 1929 * global data until exec/_exit (we can be a child after vfork!) */
1880static int run_list_real(struct pipe *pi) 1930static int run_list_real(struct pipe *pi)
1881{ 1931{
1882#if ENABLE_HUSH_JOB
1883 static int level;
1884#else
1885 enum { level = 0 };
1886#endif
1887
1888 char *for_varname = NULL; 1932 char *for_varname = NULL;
1889 char **for_lcur = NULL; 1933 char **for_lcur = NULL;
1890 char **for_list = NULL; 1934 char **for_list = NULL;
@@ -1897,7 +1941,7 @@ static int run_list_real(struct pipe *pi)
1897 int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ 1941 int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */
1898 reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; 1942 reserved_style rmode, skip_more_in_this_rmode = RES_XXXX;
1899 1943
1900 debug_printf_exec("run_list_real start lvl %d\n", level + 1); 1944 debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1);
1901 1945
1902 /* check syntax for "for" */ 1946 /* check syntax for "for" */
1903 for (rpipe = pi; rpipe; rpipe = rpipe->next) { 1947 for (rpipe = pi; rpipe; rpipe = rpipe->next) {
@@ -1905,7 +1949,7 @@ static int run_list_real(struct pipe *pi)
1905 && (rpipe->next == NULL) 1949 && (rpipe->next == NULL)
1906 ) { 1950 ) {
1907 syntax(); /* unterminated FOR (no IN or no commands after IN) */ 1951 syntax(); /* unterminated FOR (no IN or no commands after IN) */
1908 debug_printf_exec("run_list_real lvl %d return 1\n", level); 1952 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
1909 return 1; 1953 return 1;
1910 } 1954 }
1911 if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs[0].argv != NULL) 1955 if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs[0].argv != NULL)
@@ -1913,7 +1957,7 @@ static int run_list_real(struct pipe *pi)
1913 ) { 1957 ) {
1914 /* TODO: what is tested in the first condition? */ 1958 /* TODO: what is tested in the first condition? */
1915 syntax(); /* 2nd: malformed FOR (not followed by IN) */ 1959 syntax(); /* 2nd: malformed FOR (not followed by IN) */
1916 debug_printf_exec("run_list_real lvl %d return 1\n", level); 1960 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
1917 return 1; 1961 return 1;
1918 } 1962 }
1919 } 1963 }
@@ -1923,7 +1967,7 @@ static int run_list_real(struct pipe *pi)
1923 * We are saving state before entering outermost list ("while...done") 1967 * We are saving state before entering outermost list ("while...done")
1924 * so that ctrl-Z will correctly background _entire_ outermost list, 1968 * so that ctrl-Z will correctly background _entire_ outermost list,
1925 * not just a part of it (like "sleep 1 | exit 2") */ 1969 * not just a part of it (like "sleep 1 | exit 2") */
1926 if (++level == 1 && interactive_fd) { 1970 if (++run_list_level == 1 && interactive_fd) {
1927 if (sigsetjmp(toplevel_jb, 1)) { 1971 if (sigsetjmp(toplevel_jb, 1)) {
1928 /* ctrl-Z forked and we are parent; or ctrl-C. 1972 /* ctrl-Z forked and we are parent; or ctrl-C.
1929 * Sighandler has longjmped us here */ 1973 * Sighandler has longjmped us here */
@@ -1931,7 +1975,7 @@ static int run_list_real(struct pipe *pi)
1931 signal(SIGTSTP, SIG_IGN); 1975 signal(SIGTSTP, SIG_IGN);
1932 /* Restore level (we can be coming from deep inside 1976 /* Restore level (we can be coming from deep inside
1933 * nested levels) */ 1977 * nested levels) */
1934 level = 1; 1978 run_list_level = 1;
1935#if ENABLE_FEATURE_SH_STANDALONE 1979#if ENABLE_FEATURE_SH_STANDALONE
1936 if (nofork_save.saved) { /* if save area is valid */ 1980 if (nofork_save.saved) { /* if save area is valid */
1937 debug_printf_jobs("exiting nofork early\n"); 1981 debug_printf_jobs("exiting nofork early\n");
@@ -2039,7 +2083,7 @@ static int run_list_real(struct pipe *pi)
2039 /* Even bash 3.2 doesn't do that well with nested bg: 2083 /* Even bash 3.2 doesn't do that well with nested bg:
2040 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 2084 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
2041 * I'm considering NOT treating inner bgs as jobs - 2085 * I'm considering NOT treating inner bgs as jobs -
2042 * thus maybe "if (level == 1 && pi->followup == PIPE_BG)" 2086 * thus maybe "if (run_list_level == 1 && pi->followup == PIPE_BG)"
2043 * above? */ 2087 * above? */
2044#if ENABLE_HUSH_JOB 2088#if ENABLE_HUSH_JOB
2045 insert_bg_job(pi); 2089 insert_bg_job(pi);
@@ -2048,7 +2092,7 @@ static int run_list_real(struct pipe *pi)
2048 } else { 2092 } else {
2049#if ENABLE_HUSH_JOB 2093#if ENABLE_HUSH_JOB
2050 /* Paranoia, just "interactive_fd" should be enough */ 2094 /* Paranoia, just "interactive_fd" should be enough */
2051 if (level == 1 && interactive_fd) { 2095 if (run_list_level == 1 && interactive_fd) {
2052 rcode = checkjobs_and_fg_shell(pi); 2096 rcode = checkjobs_and_fg_shell(pi);
2053 } else 2097 } else
2054#endif 2098#endif
@@ -2081,9 +2125,9 @@ static int run_list_real(struct pipe *pi)
2081 exit(rcode); 2125 exit(rcode);
2082 } 2126 }
2083 ret: 2127 ret:
2084 level--; 2128 run_list_level--;
2085#endif 2129#endif
2086 debug_printf_exec("run_list_real lvl %d return %d\n", level + 1, rcode); 2130 debug_printf_exec("run_list_real lvl %d return %d\n", run_list_level + 1, rcode);
2087 return rcode; 2131 return rcode;
2088} 2132}
2089 2133
@@ -3544,40 +3588,25 @@ int hush_main(int argc, char **argv)
3544 FILE *input; 3588 FILE *input;
3545 char **e; 3589 char **e;
3546 3590
3591 PTR_TO_GLOBALS = xzalloc(sizeof(G));
3592 top_vars = &shell_ver;
3593 shell_ver = const_shell_ver; /* copying struct here */
3594
3547#if ENABLE_FEATURE_EDITING 3595#if ENABLE_FEATURE_EDITING
3548 line_input_state = new_line_input_t(FOR_SHELL); 3596 line_input_state = new_line_input_t(FOR_SHELL);
3549#endif 3597#endif
3550
3551 /* XXX what should these be while sourcing /etc/profile? */ 3598 /* XXX what should these be while sourcing /etc/profile? */
3552 global_argc = argc; 3599 global_argc = argc;
3553 global_argv = argv; 3600 global_argv = argv;
3554
3555 /* (re?) initialize globals. Sometimes hush_main() ends up calling
3556 * hush_main(), therefore we cannot rely on the BSS to zero out this
3557 * stuff. Reset these to 0 every time. */
3558 ifs = NULL;
3559 /* charmap[] is taken care of with call to update_charmap() */
3560 fake_mode = 0;
3561 close_me_head = NULL;
3562#if ENABLE_HUSH_INTERACTIVE
3563 interactive_fd = 0;
3564#endif
3565#if ENABLE_HUSH_JOB
3566 last_bg_pid = 0;
3567 job_list = NULL;
3568 last_jobid = 0;
3569#endif
3570
3571 /* Initialize some more globals to non-zero values */ 3601 /* Initialize some more globals to non-zero values */
3572 set_cwd(); 3602 set_cwd();
3573#if ENABLE_HUSH_INTERACTIVE 3603#if ENABLE_HUSH_INTERACTIVE
3574#if ENABLE_FEATURE_EDITING 3604#if ENABLE_FEATURE_EDITING
3575 cmdedit_set_initial_prompt(); 3605 cmdedit_set_initial_prompt();
3576#else
3577 PS1 = NULL;
3578#endif 3606#endif
3579 PS2 = "> "; 3607 PS2 = "> ";
3580#endif 3608#endif
3609
3581 /* initialize our shell local variables with the values 3610 /* initialize our shell local variables with the values
3582 * currently living in the environment */ 3611 * currently living in the environment */
3583 e = environ; 3612 e = environ;
@@ -3612,7 +3641,7 @@ int hush_main(int argc, char **argv)
3612 /* interactive_fd++; */ 3641 /* interactive_fd++; */
3613 break; 3642 break;
3614 case 'f': 3643 case 'f':
3615 fake_mode++; 3644 fake_mode = 1;
3616 break; 3645 break;
3617 default: 3646 default:
3618#ifndef BB_VER 3647#ifndef BB_VER