diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-10 15:58:02 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-10 15:58:02 +0100 |
commit | a1184af5f87b82df34af7782f76df9a1041200f1 (patch) | |
tree | 4fa027f9c981897ffb084e1df5a76ac30b9ff30a /shell | |
parent | f35ad3bd1287627fc6ca7cc9c1f48b186257dd87 (diff) | |
download | busybox-w32-a1184af5f87b82df34af7782f76df9a1041200f1.tar.gz busybox-w32-a1184af5f87b82df34af7782f76df9a1041200f1.tar.bz2 busybox-w32-a1184af5f87b82df34af7782f76df9a1041200f1.zip |
hush: reorder builtins (cd and pwd ought to be close, etc), no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 592 |
1 files changed, 295 insertions, 297 deletions
diff --git a/shell/hush.c b/shell/hush.c index c0325cf5e..7cce89183 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -8832,6 +8832,30 @@ static int FAST_FUNC builtin_printf(char **argv) | |||
8832 | } | 8832 | } |
8833 | #endif | 8833 | #endif |
8834 | 8834 | ||
8835 | #if ENABLE_HUSH_HELP | ||
8836 | static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM) | ||
8837 | { | ||
8838 | const struct built_in_command *x; | ||
8839 | |||
8840 | printf( | ||
8841 | "Built-in commands:\n" | ||
8842 | "------------------\n"); | ||
8843 | for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) { | ||
8844 | if (x->b_descr) | ||
8845 | printf("%-10s%s\n", x->b_cmd, x->b_descr); | ||
8846 | } | ||
8847 | return EXIT_SUCCESS; | ||
8848 | } | ||
8849 | #endif | ||
8850 | |||
8851 | #if MAX_HISTORY && ENABLE_FEATURE_EDITING | ||
8852 | static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) | ||
8853 | { | ||
8854 | show_history(G.line_input_state); | ||
8855 | return EXIT_SUCCESS; | ||
8856 | } | ||
8857 | #endif | ||
8858 | |||
8835 | static char **skip_dash_dash(char **argv) | 8859 | static char **skip_dash_dash(char **argv) |
8836 | { | 8860 | { |
8837 | argv++; | 8861 | argv++; |
@@ -8840,24 +8864,6 @@ static char **skip_dash_dash(char **argv) | |||
8840 | return argv; | 8864 | return argv; |
8841 | } | 8865 | } |
8842 | 8866 | ||
8843 | static int FAST_FUNC builtin_eval(char **argv) | ||
8844 | { | ||
8845 | int rcode = EXIT_SUCCESS; | ||
8846 | |||
8847 | argv = skip_dash_dash(argv); | ||
8848 | if (*argv) { | ||
8849 | char *str = expand_strvec_to_string(argv); | ||
8850 | /* bash: | ||
8851 | * eval "echo Hi; done" ("done" is syntax error): | ||
8852 | * "echo Hi" will not execute too. | ||
8853 | */ | ||
8854 | parse_and_run_string(str); | ||
8855 | free(str); | ||
8856 | rcode = G.last_exitcode; | ||
8857 | } | ||
8858 | return rcode; | ||
8859 | } | ||
8860 | |||
8861 | static int FAST_FUNC builtin_cd(char **argv) | 8867 | static int FAST_FUNC builtin_cd(char **argv) |
8862 | { | 8868 | { |
8863 | const char *newdir; | 8869 | const char *newdir; |
@@ -8885,6 +8891,30 @@ static int FAST_FUNC builtin_cd(char **argv) | |||
8885 | return EXIT_SUCCESS; | 8891 | return EXIT_SUCCESS; |
8886 | } | 8892 | } |
8887 | 8893 | ||
8894 | static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) | ||
8895 | { | ||
8896 | puts(get_cwd(0)); | ||
8897 | return EXIT_SUCCESS; | ||
8898 | } | ||
8899 | |||
8900 | static int FAST_FUNC builtin_eval(char **argv) | ||
8901 | { | ||
8902 | int rcode = EXIT_SUCCESS; | ||
8903 | |||
8904 | argv = skip_dash_dash(argv); | ||
8905 | if (*argv) { | ||
8906 | char *str = expand_strvec_to_string(argv); | ||
8907 | /* bash: | ||
8908 | * eval "echo Hi; done" ("done" is syntax error): | ||
8909 | * "echo Hi" will not execute too. | ||
8910 | */ | ||
8911 | parse_and_run_string(str); | ||
8912 | free(str); | ||
8913 | rcode = G.last_exitcode; | ||
8914 | } | ||
8915 | return rcode; | ||
8916 | } | ||
8917 | |||
8888 | static int FAST_FUNC builtin_exec(char **argv) | 8918 | static int FAST_FUNC builtin_exec(char **argv) |
8889 | { | 8919 | { |
8890 | argv = skip_dash_dash(argv); | 8920 | argv = skip_dash_dash(argv); |
@@ -8930,6 +8960,147 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
8930 | hush_exit(xatoi(argv[0]) & 0xff); | 8960 | hush_exit(xatoi(argv[0]) & 0xff); |
8931 | } | 8961 | } |
8932 | 8962 | ||
8963 | #if ENABLE_HUSH_TYPE | ||
8964 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */ | ||
8965 | static int FAST_FUNC builtin_type(char **argv) | ||
8966 | { | ||
8967 | int ret = EXIT_SUCCESS; | ||
8968 | |||
8969 | while (*++argv) { | ||
8970 | const char *type; | ||
8971 | char *path = NULL; | ||
8972 | |||
8973 | if (0) {} /* make conditional compile easier below */ | ||
8974 | /*else if (find_alias(*argv)) | ||
8975 | type = "an alias";*/ | ||
8976 | #if ENABLE_HUSH_FUNCTIONS | ||
8977 | else if (find_function(*argv)) | ||
8978 | type = "a function"; | ||
8979 | #endif | ||
8980 | else if (find_builtin(*argv)) | ||
8981 | type = "a shell builtin"; | ||
8982 | else if ((path = find_in_path(*argv)) != NULL) | ||
8983 | type = path; | ||
8984 | else { | ||
8985 | bb_error_msg("type: %s: not found", *argv); | ||
8986 | ret = EXIT_FAILURE; | ||
8987 | continue; | ||
8988 | } | ||
8989 | |||
8990 | printf("%s is %s\n", *argv, type); | ||
8991 | free(path); | ||
8992 | } | ||
8993 | |||
8994 | return ret; | ||
8995 | } | ||
8996 | #endif | ||
8997 | |||
8998 | #if ENABLE_HUSH_READ | ||
8999 | /* Interruptibility of read builtin in bash | ||
9000 | * (tested on bash-4.2.8 by sending signals (not by ^C)): | ||
9001 | * | ||
9002 | * Empty trap makes read ignore corresponding signal, for any signal. | ||
9003 | * | ||
9004 | * SIGINT: | ||
9005 | * - terminates non-interactive shell; | ||
9006 | * - interrupts read in interactive shell; | ||
9007 | * if it has non-empty trap: | ||
9008 | * - executes trap and returns to command prompt in interactive shell; | ||
9009 | * - executes trap and returns to read in non-interactive shell; | ||
9010 | * SIGTERM: | ||
9011 | * - is ignored (does not interrupt) read in interactive shell; | ||
9012 | * - terminates non-interactive shell; | ||
9013 | * if it has non-empty trap: | ||
9014 | * - executes trap and returns to read; | ||
9015 | * SIGHUP: | ||
9016 | * - terminates shell (regardless of interactivity); | ||
9017 | * if it has non-empty trap: | ||
9018 | * - executes trap and returns to read; | ||
9019 | */ | ||
9020 | static int FAST_FUNC builtin_read(char **argv) | ||
9021 | { | ||
9022 | const char *r; | ||
9023 | char *opt_n = NULL; | ||
9024 | char *opt_p = NULL; | ||
9025 | char *opt_t = NULL; | ||
9026 | char *opt_u = NULL; | ||
9027 | const char *ifs; | ||
9028 | int read_flags; | ||
9029 | |||
9030 | /* "!": do not abort on errors. | ||
9031 | * Option string must start with "sr" to match BUILTIN_READ_xxx | ||
9032 | */ | ||
9033 | read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); | ||
9034 | if (read_flags == (uint32_t)-1) | ||
9035 | return EXIT_FAILURE; | ||
9036 | argv += optind; | ||
9037 | ifs = get_local_var_value("IFS"); /* can be NULL */ | ||
9038 | |||
9039 | again: | ||
9040 | r = shell_builtin_read(set_local_var_from_halves, | ||
9041 | argv, | ||
9042 | ifs, | ||
9043 | read_flags, | ||
9044 | opt_n, | ||
9045 | opt_p, | ||
9046 | opt_t, | ||
9047 | opt_u | ||
9048 | ); | ||
9049 | |||
9050 | if ((uintptr_t)r == 1 && errno == EINTR) { | ||
9051 | unsigned sig = check_and_run_traps(); | ||
9052 | if (sig && sig != SIGINT) | ||
9053 | goto again; | ||
9054 | } | ||
9055 | |||
9056 | if ((uintptr_t)r > 1) { | ||
9057 | bb_error_msg("%s", r); | ||
9058 | r = (char*)(uintptr_t)1; | ||
9059 | } | ||
9060 | |||
9061 | return (uintptr_t)r; | ||
9062 | } | ||
9063 | #endif | ||
9064 | |||
9065 | #if ENABLE_HUSH_UMASK | ||
9066 | static int FAST_FUNC builtin_umask(char **argv) | ||
9067 | { | ||
9068 | int rc; | ||
9069 | mode_t mask; | ||
9070 | |||
9071 | rc = 1; | ||
9072 | mask = umask(0); | ||
9073 | argv = skip_dash_dash(argv); | ||
9074 | if (argv[0]) { | ||
9075 | mode_t old_mask = mask; | ||
9076 | |||
9077 | /* numeric umasks are taken as-is */ | ||
9078 | /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ | ||
9079 | if (!isdigit(argv[0][0])) | ||
9080 | mask ^= 0777; | ||
9081 | mask = bb_parse_mode(argv[0], mask); | ||
9082 | if (!isdigit(argv[0][0])) | ||
9083 | mask ^= 0777; | ||
9084 | if ((unsigned)mask > 0777) { | ||
9085 | mask = old_mask; | ||
9086 | /* bash messages: | ||
9087 | * bash: umask: 'q': invalid symbolic mode operator | ||
9088 | * bash: umask: 999: octal number out of range | ||
9089 | */ | ||
9090 | bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); | ||
9091 | rc = 0; | ||
9092 | } | ||
9093 | } else { | ||
9094 | /* Mimic bash */ | ||
9095 | printf("%04o\n", (unsigned) mask); | ||
9096 | /* fall through and restore mask which we set to 0 */ | ||
9097 | } | ||
9098 | umask(mask); | ||
9099 | |||
9100 | return !rc; /* rc != 0 - success */ | ||
9101 | } | ||
9102 | #endif | ||
9103 | |||
8933 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP | 9104 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP |
8934 | static void print_escaped(const char *s) | 9105 | static void print_escaped(const char *s) |
8935 | { | 9106 | { |
@@ -9218,72 +9389,60 @@ static int FAST_FUNC builtin_shift(char **argv) | |||
9218 | return EXIT_FAILURE; | 9389 | return EXIT_FAILURE; |
9219 | } | 9390 | } |
9220 | 9391 | ||
9221 | #if ENABLE_HUSH_READ | 9392 | static int FAST_FUNC builtin_source(char **argv) |
9222 | /* Interruptibility of read builtin in bash | ||
9223 | * (tested on bash-4.2.8 by sending signals (not by ^C)): | ||
9224 | * | ||
9225 | * Empty trap makes read ignore corresponding signal, for any signal. | ||
9226 | * | ||
9227 | * SIGINT: | ||
9228 | * - terminates non-interactive shell; | ||
9229 | * - interrupts read in interactive shell; | ||
9230 | * if it has non-empty trap: | ||
9231 | * - executes trap and returns to command prompt in interactive shell; | ||
9232 | * - executes trap and returns to read in non-interactive shell; | ||
9233 | * SIGTERM: | ||
9234 | * - is ignored (does not interrupt) read in interactive shell; | ||
9235 | * - terminates non-interactive shell; | ||
9236 | * if it has non-empty trap: | ||
9237 | * - executes trap and returns to read; | ||
9238 | * SIGHUP: | ||
9239 | * - terminates shell (regardless of interactivity); | ||
9240 | * if it has non-empty trap: | ||
9241 | * - executes trap and returns to read; | ||
9242 | */ | ||
9243 | static int FAST_FUNC builtin_read(char **argv) | ||
9244 | { | 9393 | { |
9245 | const char *r; | 9394 | char *arg_path, *filename; |
9246 | char *opt_n = NULL; | 9395 | FILE *input; |
9247 | char *opt_p = NULL; | 9396 | save_arg_t sv; |
9248 | char *opt_t = NULL; | 9397 | char *args_need_save; |
9249 | char *opt_u = NULL; | 9398 | #if ENABLE_HUSH_FUNCTIONS |
9250 | const char *ifs; | 9399 | smallint sv_flg; |
9251 | int read_flags; | 9400 | #endif |
9252 | 9401 | ||
9253 | /* "!": do not abort on errors. | 9402 | argv = skip_dash_dash(argv); |
9254 | * Option string must start with "sr" to match BUILTIN_READ_xxx | 9403 | filename = argv[0]; |
9255 | */ | 9404 | if (!filename) { |
9256 | read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); | 9405 | /* bash says: "bash: .: filename argument required" */ |
9257 | if (read_flags == (uint32_t)-1) | 9406 | return 2; /* bash compat */ |
9407 | } | ||
9408 | arg_path = NULL; | ||
9409 | if (!strchr(filename, '/')) { | ||
9410 | arg_path = find_in_path(filename); | ||
9411 | if (arg_path) | ||
9412 | filename = arg_path; | ||
9413 | } | ||
9414 | input = remember_FILE(fopen_or_warn(filename, "r")); | ||
9415 | free(arg_path); | ||
9416 | if (!input) { | ||
9417 | /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ | ||
9418 | /* POSIX: non-interactive shell should abort here, | ||
9419 | * not merely fail. So far no one complained :) | ||
9420 | */ | ||
9258 | return EXIT_FAILURE; | 9421 | return EXIT_FAILURE; |
9259 | argv += optind; | 9422 | } |
9260 | ifs = get_local_var_value("IFS"); /* can be NULL */ | ||
9261 | 9423 | ||
9262 | again: | 9424 | #if ENABLE_HUSH_FUNCTIONS |
9263 | r = shell_builtin_read(set_local_var_from_halves, | 9425 | sv_flg = G_flag_return_in_progress; |
9264 | argv, | 9426 | /* "we are inside sourced file, ok to use return" */ |
9265 | ifs, | 9427 | G_flag_return_in_progress = -1; |
9266 | read_flags, | 9428 | #endif |
9267 | opt_n, | 9429 | args_need_save = argv[1]; /* used as a boolean variable */ |
9268 | opt_p, | 9430 | if (args_need_save) |
9269 | opt_t, | 9431 | save_and_replace_G_args(&sv, argv); |
9270 | opt_u | ||
9271 | ); | ||
9272 | 9432 | ||
9273 | if ((uintptr_t)r == 1 && errno == EINTR) { | 9433 | /* "false; . ./empty_line; echo Zero:$?" should print 0 */ |
9274 | unsigned sig = check_and_run_traps(); | 9434 | G.last_exitcode = 0; |
9275 | if (sig && sig != SIGINT) | 9435 | parse_and_run_file(input); |
9276 | goto again; | 9436 | fclose_and_forget(input); |
9277 | } | ||
9278 | 9437 | ||
9279 | if ((uintptr_t)r > 1) { | 9438 | if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */ |
9280 | bb_error_msg("%s", r); | 9439 | restore_G_args(&sv, argv); |
9281 | r = (char*)(uintptr_t)1; | 9440 | #if ENABLE_HUSH_FUNCTIONS |
9282 | } | 9441 | G_flag_return_in_progress = sv_flg; |
9442 | #endif | ||
9283 | 9443 | ||
9284 | return (uintptr_t)r; | 9444 | return G.last_exitcode; |
9285 | } | 9445 | } |
9286 | #endif | ||
9287 | 9446 | ||
9288 | #if ENABLE_HUSH_TRAP | 9447 | #if ENABLE_HUSH_TRAP |
9289 | static int FAST_FUNC builtin_trap(char **argv) | 9448 | static int FAST_FUNC builtin_trap(char **argv) |
@@ -9377,41 +9536,6 @@ static int FAST_FUNC builtin_trap(char **argv) | |||
9377 | } | 9536 | } |
9378 | #endif | 9537 | #endif |
9379 | 9538 | ||
9380 | #if ENABLE_HUSH_TYPE | ||
9381 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */ | ||
9382 | static int FAST_FUNC builtin_type(char **argv) | ||
9383 | { | ||
9384 | int ret = EXIT_SUCCESS; | ||
9385 | |||
9386 | while (*++argv) { | ||
9387 | const char *type; | ||
9388 | char *path = NULL; | ||
9389 | |||
9390 | if (0) {} /* make conditional compile easier below */ | ||
9391 | /*else if (find_alias(*argv)) | ||
9392 | type = "an alias";*/ | ||
9393 | #if ENABLE_HUSH_FUNCTIONS | ||
9394 | else if (find_function(*argv)) | ||
9395 | type = "a function"; | ||
9396 | #endif | ||
9397 | else if (find_builtin(*argv)) | ||
9398 | type = "a shell builtin"; | ||
9399 | else if ((path = find_in_path(*argv)) != NULL) | ||
9400 | type = path; | ||
9401 | else { | ||
9402 | bb_error_msg("type: %s: not found", *argv); | ||
9403 | ret = EXIT_FAILURE; | ||
9404 | continue; | ||
9405 | } | ||
9406 | |||
9407 | printf("%s is %s\n", *argv, type); | ||
9408 | free(path); | ||
9409 | } | ||
9410 | |||
9411 | return ret; | ||
9412 | } | ||
9413 | #endif | ||
9414 | |||
9415 | #if ENABLE_HUSH_JOB | 9539 | #if ENABLE_HUSH_JOB |
9416 | static struct pipe *parse_jobspec(const char *str) | 9540 | static struct pipe *parse_jobspec(const char *str) |
9417 | { | 9541 | { |
@@ -9441,6 +9565,23 @@ static struct pipe *parse_jobspec(const char *str) | |||
9441 | return NULL; | 9565 | return NULL; |
9442 | } | 9566 | } |
9443 | 9567 | ||
9568 | static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM) | ||
9569 | { | ||
9570 | struct pipe *job; | ||
9571 | const char *status_string; | ||
9572 | |||
9573 | checkjobs(NULL, 0 /*(no pid to wait for)*/); | ||
9574 | for (job = G.job_list; job; job = job->next) { | ||
9575 | if (job->alive_cmds == job->stopped_cmds) | ||
9576 | status_string = "Stopped"; | ||
9577 | else | ||
9578 | status_string = "Running"; | ||
9579 | |||
9580 | printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); | ||
9581 | } | ||
9582 | return EXIT_SUCCESS; | ||
9583 | } | ||
9584 | |||
9444 | /* built-in 'fg' and 'bg' handler */ | 9585 | /* built-in 'fg' and 'bg' handler */ |
9445 | static int FAST_FUNC builtin_fg_bg(char **argv) | 9586 | static int FAST_FUNC builtin_fg_bg(char **argv) |
9446 | { | 9587 | { |
@@ -9496,192 +9637,6 @@ static int FAST_FUNC builtin_fg_bg(char **argv) | |||
9496 | } | 9637 | } |
9497 | #endif | 9638 | #endif |
9498 | 9639 | ||
9499 | #if ENABLE_HUSH_HELP | ||
9500 | static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM) | ||
9501 | { | ||
9502 | const struct built_in_command *x; | ||
9503 | |||
9504 | printf( | ||
9505 | "Built-in commands:\n" | ||
9506 | "------------------\n"); | ||
9507 | for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) { | ||
9508 | if (x->b_descr) | ||
9509 | printf("%-10s%s\n", x->b_cmd, x->b_descr); | ||
9510 | } | ||
9511 | return EXIT_SUCCESS; | ||
9512 | } | ||
9513 | #endif | ||
9514 | |||
9515 | #if MAX_HISTORY && ENABLE_FEATURE_EDITING | ||
9516 | static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) | ||
9517 | { | ||
9518 | show_history(G.line_input_state); | ||
9519 | return EXIT_SUCCESS; | ||
9520 | } | ||
9521 | #endif | ||
9522 | |||
9523 | #if ENABLE_HUSH_JOB | ||
9524 | static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM) | ||
9525 | { | ||
9526 | struct pipe *job; | ||
9527 | const char *status_string; | ||
9528 | |||
9529 | checkjobs(NULL, 0 /*(no pid to wait for)*/); | ||
9530 | for (job = G.job_list; job; job = job->next) { | ||
9531 | if (job->alive_cmds == job->stopped_cmds) | ||
9532 | status_string = "Stopped"; | ||
9533 | else | ||
9534 | status_string = "Running"; | ||
9535 | |||
9536 | printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); | ||
9537 | } | ||
9538 | return EXIT_SUCCESS; | ||
9539 | } | ||
9540 | #endif | ||
9541 | |||
9542 | #if ENABLE_HUSH_MEMLEAK | ||
9543 | static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) | ||
9544 | { | ||
9545 | void *p; | ||
9546 | unsigned long l; | ||
9547 | |||
9548 | # ifdef M_TRIM_THRESHOLD | ||
9549 | /* Optional. Reduces probability of false positives */ | ||
9550 | malloc_trim(0); | ||
9551 | # endif | ||
9552 | /* Crude attempt to find where "free memory" starts, | ||
9553 | * sans fragmentation. */ | ||
9554 | p = malloc(240); | ||
9555 | l = (unsigned long)p; | ||
9556 | free(p); | ||
9557 | p = malloc(3400); | ||
9558 | if (l < (unsigned long)p) l = (unsigned long)p; | ||
9559 | free(p); | ||
9560 | |||
9561 | |||
9562 | # if 0 /* debug */ | ||
9563 | { | ||
9564 | struct mallinfo mi = mallinfo(); | ||
9565 | printf("top alloc:0x%lx malloced:%d+%d=%d\n", l, | ||
9566 | mi.arena, mi.hblkhd, mi.arena + mi.hblkhd); | ||
9567 | } | ||
9568 | # endif | ||
9569 | |||
9570 | if (!G.memleak_value) | ||
9571 | G.memleak_value = l; | ||
9572 | |||
9573 | l -= G.memleak_value; | ||
9574 | if ((long)l < 0) | ||
9575 | l = 0; | ||
9576 | l /= 1024; | ||
9577 | if (l > 127) | ||
9578 | l = 127; | ||
9579 | |||
9580 | /* Exitcode is "how many kilobytes we leaked since 1st call" */ | ||
9581 | return l; | ||
9582 | } | ||
9583 | #endif | ||
9584 | |||
9585 | static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) | ||
9586 | { | ||
9587 | puts(get_cwd(0)); | ||
9588 | return EXIT_SUCCESS; | ||
9589 | } | ||
9590 | |||
9591 | static int FAST_FUNC builtin_source(char **argv) | ||
9592 | { | ||
9593 | char *arg_path, *filename; | ||
9594 | FILE *input; | ||
9595 | save_arg_t sv; | ||
9596 | char *args_need_save; | ||
9597 | #if ENABLE_HUSH_FUNCTIONS | ||
9598 | smallint sv_flg; | ||
9599 | #endif | ||
9600 | |||
9601 | argv = skip_dash_dash(argv); | ||
9602 | filename = argv[0]; | ||
9603 | if (!filename) { | ||
9604 | /* bash says: "bash: .: filename argument required" */ | ||
9605 | return 2; /* bash compat */ | ||
9606 | } | ||
9607 | arg_path = NULL; | ||
9608 | if (!strchr(filename, '/')) { | ||
9609 | arg_path = find_in_path(filename); | ||
9610 | if (arg_path) | ||
9611 | filename = arg_path; | ||
9612 | } | ||
9613 | input = remember_FILE(fopen_or_warn(filename, "r")); | ||
9614 | free(arg_path); | ||
9615 | if (!input) { | ||
9616 | /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ | ||
9617 | /* POSIX: non-interactive shell should abort here, | ||
9618 | * not merely fail. So far no one complained :) | ||
9619 | */ | ||
9620 | return EXIT_FAILURE; | ||
9621 | } | ||
9622 | |||
9623 | #if ENABLE_HUSH_FUNCTIONS | ||
9624 | sv_flg = G_flag_return_in_progress; | ||
9625 | /* "we are inside sourced file, ok to use return" */ | ||
9626 | G_flag_return_in_progress = -1; | ||
9627 | #endif | ||
9628 | args_need_save = argv[1]; /* used as a boolean variable */ | ||
9629 | if (args_need_save) | ||
9630 | save_and_replace_G_args(&sv, argv); | ||
9631 | |||
9632 | /* "false; . ./empty_line; echo Zero:$?" should print 0 */ | ||
9633 | G.last_exitcode = 0; | ||
9634 | parse_and_run_file(input); | ||
9635 | fclose_and_forget(input); | ||
9636 | |||
9637 | if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */ | ||
9638 | restore_G_args(&sv, argv); | ||
9639 | #if ENABLE_HUSH_FUNCTIONS | ||
9640 | G_flag_return_in_progress = sv_flg; | ||
9641 | #endif | ||
9642 | |||
9643 | return G.last_exitcode; | ||
9644 | } | ||
9645 | |||
9646 | #if ENABLE_HUSH_UMASK | ||
9647 | static int FAST_FUNC builtin_umask(char **argv) | ||
9648 | { | ||
9649 | int rc; | ||
9650 | mode_t mask; | ||
9651 | |||
9652 | rc = 1; | ||
9653 | mask = umask(0); | ||
9654 | argv = skip_dash_dash(argv); | ||
9655 | if (argv[0]) { | ||
9656 | mode_t old_mask = mask; | ||
9657 | |||
9658 | /* numeric umasks are taken as-is */ | ||
9659 | /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ | ||
9660 | if (!isdigit(argv[0][0])) | ||
9661 | mask ^= 0777; | ||
9662 | mask = bb_parse_mode(argv[0], mask); | ||
9663 | if (!isdigit(argv[0][0])) | ||
9664 | mask ^= 0777; | ||
9665 | if ((unsigned)mask > 0777) { | ||
9666 | mask = old_mask; | ||
9667 | /* bash messages: | ||
9668 | * bash: umask: 'q': invalid symbolic mode operator | ||
9669 | * bash: umask: 999: octal number out of range | ||
9670 | */ | ||
9671 | bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); | ||
9672 | rc = 0; | ||
9673 | } | ||
9674 | } else { | ||
9675 | /* Mimic bash */ | ||
9676 | printf("%04o\n", (unsigned) mask); | ||
9677 | /* fall through and restore mask which we set to 0 */ | ||
9678 | } | ||
9679 | umask(mask); | ||
9680 | |||
9681 | return !rc; /* rc != 0 - success */ | ||
9682 | } | ||
9683 | #endif | ||
9684 | |||
9685 | #if ENABLE_HUSH_KILL | 9640 | #if ENABLE_HUSH_KILL |
9686 | static int FAST_FUNC builtin_kill(char **argv) | 9641 | static int FAST_FUNC builtin_kill(char **argv) |
9687 | { | 9642 | { |
@@ -9984,3 +9939,46 @@ static int FAST_FUNC builtin_return(char **argv) | |||
9984 | return rc; | 9939 | return rc; |
9985 | } | 9940 | } |
9986 | #endif | 9941 | #endif |
9942 | |||
9943 | #if ENABLE_HUSH_MEMLEAK | ||
9944 | static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) | ||
9945 | { | ||
9946 | void *p; | ||
9947 | unsigned long l; | ||
9948 | |||
9949 | # ifdef M_TRIM_THRESHOLD | ||
9950 | /* Optional. Reduces probability of false positives */ | ||
9951 | malloc_trim(0); | ||
9952 | # endif | ||
9953 | /* Crude attempt to find where "free memory" starts, | ||
9954 | * sans fragmentation. */ | ||
9955 | p = malloc(240); | ||
9956 | l = (unsigned long)p; | ||
9957 | free(p); | ||
9958 | p = malloc(3400); | ||
9959 | if (l < (unsigned long)p) l = (unsigned long)p; | ||
9960 | free(p); | ||
9961 | |||
9962 | |||
9963 | # if 0 /* debug */ | ||
9964 | { | ||
9965 | struct mallinfo mi = mallinfo(); | ||
9966 | printf("top alloc:0x%lx malloced:%d+%d=%d\n", l, | ||
9967 | mi.arena, mi.hblkhd, mi.arena + mi.hblkhd); | ||
9968 | } | ||
9969 | # endif | ||
9970 | |||
9971 | if (!G.memleak_value) | ||
9972 | G.memleak_value = l; | ||
9973 | |||
9974 | l -= G.memleak_value; | ||
9975 | if ((long)l < 0) | ||
9976 | l = 0; | ||
9977 | l /= 1024; | ||
9978 | if (l > 127) | ||
9979 | l = 127; | ||
9980 | |||
9981 | /* Exitcode is "how many kilobytes we leaked since 1st call" */ | ||
9982 | return l; | ||
9983 | } | ||
9984 | #endif | ||