diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-03 17:37:32 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-03 17:37:32 +0200 |
| commit | 58a54fbd5a48a96036cecd07ba54ff37518af373 (patch) | |
| tree | c2f902f30ab888fa2fdf0e27f758a33bd65907b7 /shell | |
| parent | 778fce3e7089c9546fe3f147d355a008f5e12c42 (diff) | |
| download | busybox-w32-58a54fbd5a48a96036cecd07ba54ff37518af373.tar.gz busybox-w32-58a54fbd5a48a96036cecd07ba54ff37518af373.tar.bz2 busybox-w32-58a54fbd5a48a96036cecd07ba54ff37518af373.zip | |
hush: disentangle interactiveness/job_control setup code
...and discover that we can do away with 1-3 initialization syscalls.
function old new delta
hush_main 1152 1146 -6
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 146 |
1 files changed, 67 insertions, 79 deletions
diff --git a/shell/hush.c b/shell/hush.c index 98812b507..debae4d58 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -10790,100 +10790,86 @@ int hush_main(int argc, char **argv) | |||
| 10790 | 10790 | ||
| 10791 | /* A shell is interactive if the '-i' flag was given, | 10791 | /* A shell is interactive if the '-i' flag was given, |
| 10792 | * or if all of the following conditions are met: | 10792 | * or if all of the following conditions are met: |
| 10793 | * no -c command | 10793 | * not -c 'CMD' |
| 10794 | * no arguments remaining or the -s flag given | 10794 | * not running a script (no arguments remaining, or -s flag given) |
| 10795 | * standard input is a terminal | 10795 | * standard input is a terminal |
| 10796 | * standard output is a terminal | 10796 | * standard output is a terminal |
| 10797 | * Refer to Posix.2, the description of the 'sh' utility. | 10797 | * Refer to Posix.2, the description of the 'sh' utility. |
| 10798 | */ | 10798 | */ |
| 10799 | #if ENABLE_HUSH_JOB | 10799 | #if ENABLE_HUSH_INTERACTIVE |
| 10800 | if (!G_reexeced_on_NOMMU | ||
| 10801 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) | ||
| 10802 | ) { | ||
| 10803 | G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); | ||
| 10804 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); | ||
| 10805 | if (G_saved_tty_pgrp < 0) | ||
| 10806 | G_saved_tty_pgrp = 0; | ||
| 10807 | |||
| 10808 | /* try to dup stdin to high fd#, >= 255 */ | ||
| 10809 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | ||
| 10810 | if (G_interactive_fd < 0) { | ||
| 10811 | /* try to dup to any fd */ | ||
| 10812 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | ||
| 10813 | if (G_interactive_fd < 0) { | ||
| 10814 | /* give up */ | ||
| 10815 | G_interactive_fd = 0; | ||
| 10816 | G_saved_tty_pgrp = 0; | ||
| 10817 | } | ||
| 10818 | } | ||
| 10819 | } | ||
| 10820 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | ||
| 10821 | if (G_interactive_fd) { | ||
| 10822 | if (G_saved_tty_pgrp) { | ||
| 10823 | /* If we were run as 'hush &', sleep until we are | ||
| 10824 | * in the foreground (tty pgrp == our pgrp). | ||
| 10825 | * If we get started under a job aware app (like bash), | ||
| 10826 | * make sure we are now in charge so we don't fight over | ||
| 10827 | * who gets the foreground */ | ||
| 10828 | while (1) { | ||
| 10829 | pid_t shell_pgrp = getpgrp(); | ||
| 10830 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | ||
| 10831 | if (G_saved_tty_pgrp == shell_pgrp) | ||
| 10832 | break; | ||
| 10833 | /* send TTIN to ourself (should stop us) */ | ||
| 10834 | kill(- shell_pgrp, SIGTTIN); | ||
| 10835 | } | ||
| 10836 | } | ||
| 10837 | |||
| 10838 | /* Install more signal handlers */ | ||
| 10839 | install_special_sighandlers(); | ||
| 10840 | |||
| 10841 | if (G_saved_tty_pgrp) { | ||
| 10842 | /* Set fatal signals to restore saved_tty_pgrp */ | ||
| 10843 | install_fatal_sighandlers(); | ||
| 10844 | /* Put ourselves in our own process group | ||
| 10845 | * (bash, too, does this only if ctty is available) */ | ||
| 10846 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
| 10847 | /* Grab control of the terminal */ | ||
| 10848 | tcsetpgrp(G_interactive_fd, G.root_pid); | ||
| 10849 | } | ||
| 10850 | init_line_editing(); | ||
| 10851 | } | ||
| 10852 | #elif ENABLE_HUSH_INTERACTIVE | ||
| 10853 | /* No job control compiled in, only prompt/line editing */ | ||
| 10854 | if (!G_reexeced_on_NOMMU | 10800 | if (!G_reexeced_on_NOMMU |
| 10855 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) | 10801 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
| 10856 | ) { | 10802 | ) { |
| 10803 | /* Try to dup stdin to high fd#, >= 255 */ | ||
| 10857 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10804 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
| 10858 | if (G_interactive_fd < 0) { | 10805 | if (G_interactive_fd < 0) { |
| 10859 | /* try to dup to any fd */ | 10806 | /* Try to dup to any fd */ |
| 10860 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | 10807 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); |
| 10861 | if (G_interactive_fd < 0) | 10808 | if (G_interactive_fd < 0) |
| 10862 | /* give up */ | 10809 | /* Give up */ |
| 10863 | G_interactive_fd = 0; | 10810 | G_interactive_fd = 0; |
| 10864 | } | 10811 | } |
| 10812 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | ||
| 10865 | if (G_interactive_fd) { | 10813 | if (G_interactive_fd) { |
| 10814 | // TODO? bash: | ||
| 10815 | // if interactive but not a login shell, sources ~/.bashrc | ||
| 10816 | // (--norc turns this off, --rcfile <file> overrides) | ||
| 10817 | # if ENABLE_HUSH_JOB | ||
| 10818 | /* Can we do job control? */ | ||
| 10819 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | ||
| 10820 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); | ||
| 10821 | if (G_saved_tty_pgrp < 0) | ||
| 10822 | G_saved_tty_pgrp = 0; /* no */ | ||
| 10823 | if (G_saved_tty_pgrp) { | ||
| 10824 | /* If we were run as 'hush &', sleep until we are | ||
| 10825 | * in the foreground (tty pgrp == our pgrp). | ||
| 10826 | * If we get started under a job aware app (like bash), | ||
| 10827 | * make sure we are now in charge so we don't fight over | ||
| 10828 | * who gets the foreground */ | ||
| 10829 | while (1) { | ||
| 10830 | pid_t shell_pgrp = getpgrp(); | ||
| 10831 | if (G_saved_tty_pgrp == shell_pgrp) { | ||
| 10832 | /* Often both pgrps here are set to our pid - but not always! | ||
| 10833 | * Example: sh -c 'echo $$; hush; echo FIN' | ||
| 10834 | * Here, the parent shell is not interactive, so it does NOT set up | ||
| 10835 | * a separate process group for its children, and we (hush) initinally | ||
| 10836 | * run in parent's process group (until we set up our own a few lines down). | ||
| 10837 | */ | ||
| 10838 | //bb_error_msg("process groups tty:%d hush:%d", G_saved_tty_pgrp, shell_pgrp); | ||
| 10839 | break; | ||
| 10840 | } | ||
| 10841 | /* Send TTIN to ourself (should stop us) */ | ||
| 10842 | kill(- shell_pgrp, SIGTTIN); | ||
| 10843 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | ||
| 10844 | } | ||
| 10845 | } | ||
| 10846 | # endif | ||
| 10847 | /* Install more signal handlers */ | ||
| 10866 | install_special_sighandlers(); | 10848 | install_special_sighandlers(); |
| 10849 | # if ENABLE_HUSH_JOB | ||
| 10850 | if (G_saved_tty_pgrp) { | ||
| 10851 | /* Set fatal signals to restore saved_tty_pgrp */ | ||
| 10852 | install_fatal_sighandlers(); | ||
| 10853 | /* (The if() is an optimization: can avoid two redundant syscalls) */ | ||
| 10854 | if (G_saved_tty_pgrp != G.root_pid) { | ||
| 10855 | /* Put ourselves in our own process group | ||
| 10856 | * (bash, too, does this only if ctty is available) */ | ||
| 10857 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
| 10858 | /* Grab control of the terminal */ | ||
| 10859 | tcsetpgrp(G_interactive_fd, G.root_pid); | ||
| 10860 | } | ||
| 10861 | } | ||
| 10862 | # endif | ||
| 10863 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 10864 | /* Set (but not export) PS1/2 unless already set */ | ||
| 10865 | if (!get_local_var_value("PS1")) | ||
| 10866 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
| 10867 | if (!get_local_var_value("PS2")) | ||
| 10868 | set_local_var_from_halves("PS2", "> "); | ||
| 10869 | # endif | ||
| 10867 | init_line_editing(); | 10870 | init_line_editing(); |
| 10868 | } | ||
| 10869 | } | ||
| 10870 | #else | ||
| 10871 | /* We have interactiveness code disabled */ | ||
| 10872 | #endif | ||
| 10873 | /* bash: | ||
| 10874 | * if interactive but not a login shell, sources ~/.bashrc | ||
| 10875 | * (--norc turns this off, --rcfile <file> overrides) | ||
| 10876 | */ | ||
| 10877 | 10871 | ||
| 10878 | if (G_interactive_fd) { | 10872 | # if !ENABLE_FEATURE_SH_EXTRA_QUIET |
| 10879 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 10880 | /* Set (but not export) PS1/2 unless already set */ | ||
| 10881 | if (!get_local_var_value("PS1")) | ||
| 10882 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
| 10883 | if (!get_local_var_value("PS2")) | ||
| 10884 | set_local_var_from_halves("PS2", "> "); | ||
| 10885 | #endif | ||
| 10886 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | ||
| 10887 | /* note: ash and hush share this string */ | 10873 | /* note: ash and hush share this string */ |
| 10888 | printf("\n\n%s %s\n" | 10874 | printf("\n\n%s %s\n" |
| 10889 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") | 10875 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") |
| @@ -10891,8 +10877,10 @@ int hush_main(int argc, char **argv) | |||
| 10891 | bb_banner, | 10877 | bb_banner, |
| 10892 | "hush - the humble shell" | 10878 | "hush - the humble shell" |
| 10893 | ); | 10879 | ); |
| 10894 | } | 10880 | # endif |
| 10895 | } | 10881 | } /* if become interactive */ |
| 10882 | } /* if on tty */ | ||
| 10883 | #endif /* if INTERACTIVE is allowed by build config */ | ||
| 10896 | 10884 | ||
| 10897 | parse_and_run_file(hfopen(NULL)); /* stdin */ | 10885 | parse_and_run_file(hfopen(NULL)); /* stdin */ |
| 10898 | 10886 | ||
