hush: reorder builtins (cd and pwd ought to be close, etc), no code changes
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 10 Jan 2017 14:58:02 +0000 (15:58 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 10 Jan 2017 14:58:02 +0000 (15:58 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c

index c0325cf5e416901c684ea9d3547b57d3846e938d..7cce891835f1b621f962962cc58b910628e61664 100644 (file)
@@ -8832,6 +8832,30 @@ static int FAST_FUNC builtin_printf(char **argv)
 }
 #endif
 
+#if ENABLE_HUSH_HELP
+static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
+{
+       const struct built_in_command *x;
+
+       printf(
+               "Built-in commands:\n"
+               "------------------\n");
+       for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) {
+               if (x->b_descr)
+                       printf("%-10s%s\n", x->b_cmd, x->b_descr);
+       }
+       return EXIT_SUCCESS;
+}
+#endif
+
+#if MAX_HISTORY && ENABLE_FEATURE_EDITING
+static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
+{
+       show_history(G.line_input_state);
+       return EXIT_SUCCESS;
+}
+#endif
+
 static char **skip_dash_dash(char **argv)
 {
        argv++;
@@ -8840,24 +8864,6 @@ static char **skip_dash_dash(char **argv)
        return argv;
 }
 
-static int FAST_FUNC builtin_eval(char **argv)
-{
-       int rcode = EXIT_SUCCESS;
-
-       argv = skip_dash_dash(argv);
-       if (*argv) {
-               char *str = expand_strvec_to_string(argv);
-               /* bash:
-                * eval "echo Hi; done" ("done" is syntax error):
-                * "echo Hi" will not execute too.
-                */
-               parse_and_run_string(str);
-               free(str);
-               rcode = G.last_exitcode;
-       }
-       return rcode;
-}
-
 static int FAST_FUNC builtin_cd(char **argv)
 {
        const char *newdir;
@@ -8885,6 +8891,30 @@ static int FAST_FUNC builtin_cd(char **argv)
        return EXIT_SUCCESS;
 }
 
+static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
+{
+       puts(get_cwd(0));
+       return EXIT_SUCCESS;
+}
+
+static int FAST_FUNC builtin_eval(char **argv)
+{
+       int rcode = EXIT_SUCCESS;
+
+       argv = skip_dash_dash(argv);
+       if (*argv) {
+               char *str = expand_strvec_to_string(argv);
+               /* bash:
+                * eval "echo Hi; done" ("done" is syntax error):
+                * "echo Hi" will not execute too.
+                */
+               parse_and_run_string(str);
+               free(str);
+               rcode = G.last_exitcode;
+       }
+       return rcode;
+}
+
 static int FAST_FUNC builtin_exec(char **argv)
 {
        argv = skip_dash_dash(argv);
@@ -8930,6 +8960,147 @@ static int FAST_FUNC builtin_exit(char **argv)
        hush_exit(xatoi(argv[0]) & 0xff);
 }
 
+#if ENABLE_HUSH_TYPE
+/* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */
+static int FAST_FUNC builtin_type(char **argv)
+{
+       int ret = EXIT_SUCCESS;
+
+       while (*++argv) {
+               const char *type;
+               char *path = NULL;
+
+               if (0) {} /* make conditional compile easier below */
+               /*else if (find_alias(*argv))
+                       type = "an alias";*/
+#if ENABLE_HUSH_FUNCTIONS
+               else if (find_function(*argv))
+                       type = "a function";
+#endif
+               else if (find_builtin(*argv))
+                       type = "a shell builtin";
+               else if ((path = find_in_path(*argv)) != NULL)
+                       type = path;
+               else {
+                       bb_error_msg("type: %s: not found", *argv);
+                       ret = EXIT_FAILURE;
+                       continue;
+               }
+
+               printf("%s is %s\n", *argv, type);
+               free(path);
+       }
+
+       return ret;
+}
+#endif
+
+#if ENABLE_HUSH_READ
+/* Interruptibility of read builtin in bash
+ * (tested on bash-4.2.8 by sending signals (not by ^C)):
+ *
+ * Empty trap makes read ignore corresponding signal, for any signal.
+ *
+ * SIGINT:
+ * - terminates non-interactive shell;
+ * - interrupts read in interactive shell;
+ * if it has non-empty trap:
+ * - executes trap and returns to command prompt in interactive shell;
+ * - executes trap and returns to read in non-interactive shell;
+ * SIGTERM:
+ * - is ignored (does not interrupt) read in interactive shell;
+ * - terminates non-interactive shell;
+ * if it has non-empty trap:
+ * - executes trap and returns to read;
+ * SIGHUP:
+ * - terminates shell (regardless of interactivity);
+ * if it has non-empty trap:
+ * - executes trap and returns to read;
+ */
+static int FAST_FUNC builtin_read(char **argv)
+{
+       const char *r;
+       char *opt_n = NULL;
+       char *opt_p = NULL;
+       char *opt_t = NULL;
+       char *opt_u = NULL;
+       const char *ifs;
+       int read_flags;
+
+       /* "!": do not abort on errors.
+        * Option string must start with "sr" to match BUILTIN_READ_xxx
+        */
+       read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
+       if (read_flags == (uint32_t)-1)
+               return EXIT_FAILURE;
+       argv += optind;
+       ifs = get_local_var_value("IFS"); /* can be NULL */
+
+ again:
+       r = shell_builtin_read(set_local_var_from_halves,
+               argv,
+               ifs,
+               read_flags,
+               opt_n,
+               opt_p,
+               opt_t,
+               opt_u
+       );
+
+       if ((uintptr_t)r == 1 && errno == EINTR) {
+               unsigned sig = check_and_run_traps();
+               if (sig && sig != SIGINT)
+                       goto again;
+       }
+
+       if ((uintptr_t)r > 1) {
+               bb_error_msg("%s", r);
+               r = (char*)(uintptr_t)1;
+       }
+
+       return (uintptr_t)r;
+}
+#endif
+
+#if ENABLE_HUSH_UMASK
+static int FAST_FUNC builtin_umask(char **argv)
+{
+       int rc;
+       mode_t mask;
+
+       rc = 1;
+       mask = umask(0);
+       argv = skip_dash_dash(argv);
+       if (argv[0]) {
+               mode_t old_mask = mask;
+
+               /* numeric umasks are taken as-is */
+               /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
+               if (!isdigit(argv[0][0]))
+                       mask ^= 0777;
+               mask = bb_parse_mode(argv[0], mask);
+               if (!isdigit(argv[0][0]))
+                       mask ^= 0777;
+               if ((unsigned)mask > 0777) {
+                       mask = old_mask;
+                       /* bash messages:
+                        * bash: umask: 'q': invalid symbolic mode operator
+                        * bash: umask: 999: octal number out of range
+                        */
+                       bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
+                       rc = 0;
+               }
+       } else {
+               /* Mimic bash */
+               printf("%04o\n", (unsigned) mask);
+               /* fall through and restore mask which we set to 0 */
+       }
+       umask(mask);
+
+       return !rc; /* rc != 0 - success */
+}
+#endif
+
 #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP
 static void print_escaped(const char *s)
 {
@@ -9218,72 +9389,60 @@ static int FAST_FUNC builtin_shift(char **argv)
        return EXIT_FAILURE;
 }
 
-#if ENABLE_HUSH_READ
-/* Interruptibility of read builtin in bash
- * (tested on bash-4.2.8 by sending signals (not by ^C)):
- *
- * Empty trap makes read ignore corresponding signal, for any signal.
- *
- * SIGINT:
- * - terminates non-interactive shell;
- * - interrupts read in interactive shell;
- * if it has non-empty trap:
- * - executes trap and returns to command prompt in interactive shell;
- * - executes trap and returns to read in non-interactive shell;
- * SIGTERM:
- * - is ignored (does not interrupt) read in interactive shell;
- * - terminates non-interactive shell;
- * if it has non-empty trap:
- * - executes trap and returns to read;
- * SIGHUP:
- * - terminates shell (regardless of interactivity);
- * if it has non-empty trap:
- * - executes trap and returns to read;
- */
-static int FAST_FUNC builtin_read(char **argv)
+static int FAST_FUNC builtin_source(char **argv)
 {
-       const char *r;
-       char *opt_n = NULL;
-       char *opt_p = NULL;
-       char *opt_t = NULL;
-       char *opt_u = NULL;
-       const char *ifs;
-       int read_flags;
+       char *arg_path, *filename;
+       FILE *input;
+       save_arg_t sv;
+       char *args_need_save;
+#if ENABLE_HUSH_FUNCTIONS
+       smallint sv_flg;
+#endif
 
-       /* "!": do not abort on errors.
-        * Option string must start with "sr" to match BUILTIN_READ_xxx
-        */
-       read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
-       if (read_flags == (uint32_t)-1)
+       argv = skip_dash_dash(argv);
+       filename = argv[0];
+       if (!filename) {
+               /* bash says: "bash: .: filename argument required" */
+               return 2; /* bash compat */
+       }
+       arg_path = NULL;
+       if (!strchr(filename, '/')) {
+               arg_path = find_in_path(filename);
+               if (arg_path)
+                       filename = arg_path;
+       }
+       input = remember_FILE(fopen_or_warn(filename, "r"));
+       free(arg_path);
+       if (!input) {
+               /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
+               /* POSIX: non-interactive shell should abort here,
+                * not merely fail. So far no one complained :)
+                */
                return EXIT_FAILURE;
-       argv += optind;
-       ifs = get_local_var_value("IFS"); /* can be NULL */
+       }
 
- again:
-       r = shell_builtin_read(set_local_var_from_halves,
-               argv,
-               ifs,
-               read_flags,
-               opt_n,
-               opt_p,
-               opt_t,
-               opt_u
-       );
+#if ENABLE_HUSH_FUNCTIONS
+       sv_flg = G_flag_return_in_progress;
+       /* "we are inside sourced file, ok to use return" */
+       G_flag_return_in_progress = -1;
+#endif
+       args_need_save = argv[1]; /* used as a boolean variable */
+       if (args_need_save)
+               save_and_replace_G_args(&sv, argv);
 
-       if ((uintptr_t)r == 1 && errno == EINTR) {
-               unsigned sig = check_and_run_traps();
-               if (sig && sig != SIGINT)
-                       goto again;
-       }
+       /* "false; . ./empty_line; echo Zero:$?" should print 0 */
+       G.last_exitcode = 0;
+       parse_and_run_file(input);
+       fclose_and_forget(input);
 
-       if ((uintptr_t)r > 1) {
-               bb_error_msg("%s", r);
-               r = (char*)(uintptr_t)1;
-       }
+       if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
+               restore_G_args(&sv, argv);
+#if ENABLE_HUSH_FUNCTIONS
+       G_flag_return_in_progress = sv_flg;
+#endif
 
-       return (uintptr_t)r;
+       return G.last_exitcode;
 }
-#endif
 
 #if ENABLE_HUSH_TRAP
 static int FAST_FUNC builtin_trap(char **argv)
@@ -9368,47 +9527,12 @@ static int FAST_FUNC builtin_trap(char **argv)
                if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */
                        argv++;
                }
-               /* else: "-something", no special meaning */
-       }
-       new_cmd = *argv;
- reset_traps:
-       argv++;
-       goto process_sig_list;
-}
-#endif
-
-#if ENABLE_HUSH_TYPE
-/* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */
-static int FAST_FUNC builtin_type(char **argv)
-{
-       int ret = EXIT_SUCCESS;
-
-       while (*++argv) {
-               const char *type;
-               char *path = NULL;
-
-               if (0) {} /* make conditional compile easier below */
-               /*else if (find_alias(*argv))
-                       type = "an alias";*/
-#if ENABLE_HUSH_FUNCTIONS
-               else if (find_function(*argv))
-                       type = "a function";
-#endif
-               else if (find_builtin(*argv))
-                       type = "a shell builtin";
-               else if ((path = find_in_path(*argv)) != NULL)
-                       type = path;
-               else {
-                       bb_error_msg("type: %s: not found", *argv);
-                       ret = EXIT_FAILURE;
-                       continue;
-               }
-
-               printf("%s is %s\n", *argv, type);
-               free(path);
+               /* else: "-something", no special meaning */
        }
-
-       return ret;
+       new_cmd = *argv;
+ reset_traps:
+       argv++;
+       goto process_sig_list;
 }
 #endif
 
@@ -9441,6 +9565,23 @@ static struct pipe *parse_jobspec(const char *str)
        return NULL;
 }
 
+static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
+{
+       struct pipe *job;
+       const char *status_string;
+
+       checkjobs(NULL, 0 /*(no pid to wait for)*/);
+       for (job = G.job_list; job; job = job->next) {
+               if (job->alive_cmds == job->stopped_cmds)
+                       status_string = "Stopped";
+               else
+                       status_string = "Running";
+
+               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
+       }
+       return EXIT_SUCCESS;
+}
+
 /* built-in 'fg' and 'bg' handler */
 static int FAST_FUNC builtin_fg_bg(char **argv)
 {
@@ -9496,192 +9637,6 @@ static int FAST_FUNC builtin_fg_bg(char **argv)
 }
 #endif
 
-#if ENABLE_HUSH_HELP
-static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
-{
-       const struct built_in_command *x;
-
-       printf(
-               "Built-in commands:\n"
-               "------------------\n");
-       for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) {
-               if (x->b_descr)
-                       printf("%-10s%s\n", x->b_cmd, x->b_descr);
-       }
-       return EXIT_SUCCESS;
-}
-#endif
-
-#if MAX_HISTORY && ENABLE_FEATURE_EDITING
-static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
-{
-       show_history(G.line_input_state);
-       return EXIT_SUCCESS;
-}
-#endif
-
-#if ENABLE_HUSH_JOB
-static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
-{
-       struct pipe *job;
-       const char *status_string;
-
-       checkjobs(NULL, 0 /*(no pid to wait for)*/);
-       for (job = G.job_list; job; job = job->next) {
-               if (job->alive_cmds == job->stopped_cmds)
-                       status_string = "Stopped";
-               else
-                       status_string = "Running";
-
-               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
-       }
-       return EXIT_SUCCESS;
-}
-#endif
-
-#if ENABLE_HUSH_MEMLEAK
-static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
-{
-       void *p;
-       unsigned long l;
-
-# ifdef M_TRIM_THRESHOLD
-       /* Optional. Reduces probability of false positives */
-       malloc_trim(0);
-# endif
-       /* Crude attempt to find where "free memory" starts,
-        * sans fragmentation. */
-       p = malloc(240);
-       l = (unsigned long)p;
-       free(p);
-       p = malloc(3400);
-       if (l < (unsigned long)p) l = (unsigned long)p;
-       free(p);
-
-
-# if 0  /* debug */
-       {
-               struct mallinfo mi = mallinfo();
-               printf("top alloc:0x%lx malloced:%d+%d=%d\n", l,
-                       mi.arena, mi.hblkhd, mi.arena + mi.hblkhd);
-       }
-# endif
-
-       if (!G.memleak_value)
-               G.memleak_value = l;
-
-       l -= G.memleak_value;
-       if ((long)l < 0)
-               l = 0;
-       l /= 1024;
-       if (l > 127)
-               l = 127;
-
-       /* Exitcode is "how many kilobytes we leaked since 1st call" */
-       return l;
-}
-#endif
-
-static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
-{
-       puts(get_cwd(0));
-       return EXIT_SUCCESS;
-}
-
-static int FAST_FUNC builtin_source(char **argv)
-{
-       char *arg_path, *filename;
-       FILE *input;
-       save_arg_t sv;
-       char *args_need_save;
-#if ENABLE_HUSH_FUNCTIONS
-       smallint sv_flg;
-#endif
-
-       argv = skip_dash_dash(argv);
-       filename = argv[0];
-       if (!filename) {
-               /* bash says: "bash: .: filename argument required" */
-               return 2; /* bash compat */
-       }
-       arg_path = NULL;
-       if (!strchr(filename, '/')) {
-               arg_path = find_in_path(filename);
-               if (arg_path)
-                       filename = arg_path;
-       }
-       input = remember_FILE(fopen_or_warn(filename, "r"));
-       free(arg_path);
-       if (!input) {
-               /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
-               /* POSIX: non-interactive shell should abort here,
-                * not merely fail. So far no one complained :)
-                */
-               return EXIT_FAILURE;
-       }
-
-#if ENABLE_HUSH_FUNCTIONS
-       sv_flg = G_flag_return_in_progress;
-       /* "we are inside sourced file, ok to use return" */
-       G_flag_return_in_progress = -1;
-#endif
-       args_need_save = argv[1]; /* used as a boolean variable */
-       if (args_need_save)
-               save_and_replace_G_args(&sv, argv);
-
-       /* "false; . ./empty_line; echo Zero:$?" should print 0 */
-       G.last_exitcode = 0;
-       parse_and_run_file(input);
-       fclose_and_forget(input);
-
-       if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
-               restore_G_args(&sv, argv);
-#if ENABLE_HUSH_FUNCTIONS
-       G_flag_return_in_progress = sv_flg;
-#endif
-
-       return G.last_exitcode;
-}
-
-#if ENABLE_HUSH_UMASK
-static int FAST_FUNC builtin_umask(char **argv)
-{
-       int rc;
-       mode_t mask;
-
-       rc = 1;
-       mask = umask(0);
-       argv = skip_dash_dash(argv);
-       if (argv[0]) {
-               mode_t old_mask = mask;
-
-               /* numeric umasks are taken as-is */
-               /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
-               if (!isdigit(argv[0][0]))
-                       mask ^= 0777;
-               mask = bb_parse_mode(argv[0], mask);
-               if (!isdigit(argv[0][0]))
-                       mask ^= 0777;
-               if ((unsigned)mask > 0777) {
-                       mask = old_mask;
-                       /* bash messages:
-                        * bash: umask: 'q': invalid symbolic mode operator
-                        * bash: umask: 999: octal number out of range
-                        */
-                       bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
-                       rc = 0;
-               }
-       } else {
-               /* Mimic bash */
-               printf("%04o\n", (unsigned) mask);
-               /* fall through and restore mask which we set to 0 */
-       }
-       umask(mask);
-
-       return !rc; /* rc != 0 - success */
-}
-#endif
-
 #if ENABLE_HUSH_KILL
 static int FAST_FUNC builtin_kill(char **argv)
 {
@@ -9984,3 +9939,46 @@ static int FAST_FUNC builtin_return(char **argv)
        return rc;
 }
 #endif
+
+#if ENABLE_HUSH_MEMLEAK
+static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
+{
+       void *p;
+       unsigned long l;
+
+# ifdef M_TRIM_THRESHOLD
+       /* Optional. Reduces probability of false positives */
+       malloc_trim(0);
+# endif
+       /* Crude attempt to find where "free memory" starts,
+        * sans fragmentation. */
+       p = malloc(240);
+       l = (unsigned long)p;
+       free(p);
+       p = malloc(3400);
+       if (l < (unsigned long)p) l = (unsigned long)p;
+       free(p);
+
+
+# if 0  /* debug */
+       {
+               struct mallinfo mi = mallinfo();
+               printf("top alloc:0x%lx malloced:%d+%d=%d\n", l,
+                       mi.arena, mi.hblkhd, mi.arena + mi.hblkhd);
+       }
+# endif
+
+       if (!G.memleak_value)
+               G.memleak_value = l;
+
+       l -= G.memleak_value;
+       if ((long)l < 0)
+               l = 0;
+       l /= 1024;
+       if (l > 127)
+               l = 127;
+
+       /* Exitcode is "how many kilobytes we leaked since 1st call" */
+       return l;
+}
+#endif