From 17592b0666a94ed1a5e3d495a3835156c702319b Mon Sep 17 00:00:00 2001 From: Dennis Groenen Date: Sun, 21 Aug 2011 13:49:23 +0200 Subject: [PATCH] replace ash history buffer by global delayed writing (ash and hush) --- debian/config/config.busybox | 3 +- ...01-add-support-for-delayed-history-saving.patch | 137 ++++++++++++++++++++ ...h-don-t-save-history-when-non-interactive.patch | 37 ++++++ debian/patches/ash-history-buffer.patch | 107 --------------- debian/patches/obselete/ash-history-buffer.patch | 107 +++++++++++++++ debian/patches/series | 3 +- 6 files changed, 284 insertions(+), 110 deletions(-) create mode 100644 debian/patches/0001-add-support-for-delayed-history-saving.patch create mode 100644 debian/patches/0002-hush-don-t-save-history-when-non-interactive.patch delete mode 100644 debian/patches/ash-history-buffer.patch create mode 100644 debian/patches/obselete/ash-history-buffer.patch diff --git a/debian/config/config.busybox b/debian/config/config.busybox index 4c4f8b6..0c09289 100644 --- a/debian/config/config.busybox +++ b/debian/config/config.busybox @@ -101,6 +101,7 @@ CONFIG_FEATURE_EDITING_MAX_LEN=1024 # CONFIG_FEATURE_EDITING_VI is not set CONFIG_FEATURE_EDITING_HISTORY=100 CONFIG_FEATURE_EDITING_SAVEHISTORY=y +CONFIG_FEATURE_EDITING_DELAYEDHISTORY=y CONFIG_FEATURE_REVERSE_SEARCH=y CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set @@ -965,8 +966,6 @@ CONFIG_ASH_CMDCMD=y CONFIG_ASH_OPTIMIZE_FOR_SIZE=y CONFIG_ASH_RANDOM_SUPPORT=y CONFIG_ASH_EXPAND_PRMT=y -CONFIG_ASH_HIST_BUFFER=y -CONFIG_ASH_HIST_BUFFER_PATH="/tmp" CONFIG_CTTYHACK=y CONFIG_HUSH=y CONFIG_HUSH_BASH_COMPAT=y diff --git a/debian/patches/0001-add-support-for-delayed-history-saving.patch b/debian/patches/0001-add-support-for-delayed-history-saving.patch new file mode 100644 index 0000000..ce9e112 --- /dev/null +++ b/debian/patches/0001-add-support-for-delayed-history-saving.patch @@ -0,0 +1,137 @@ +From 772cc01d3739d50ae43858fed8ec733c0c7bf00c Mon Sep 17 00:00:00 2001 +From: Dennis Groenen +Date: Sun, 21 Aug 2011 13:28:34 +0200 +Subject: [PATCH] add support for delayed history saving + +--- + include/libbb.h | 3 +++ + libbb/Config.src | 8 ++++++++ + libbb/lineedit.c | 24 +++++++++++++++++++++++- + shell/ash.c | 5 +++++ + shell/hush.c | 5 +++++ + 5 files changed, 44 insertions(+), 1 deletions(-) + +diff --git a/include/libbb.h b/include/libbb.h +index 63d0419..233b674 100644 +--- a/include/libbb.h ++++ b/include/libbb.h +@@ -1446,6 +1446,9 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC; + * >0 length of input string, including terminating '\n' + */ + int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; ++# if ENABLE_FEATURE_EDITING_DELAYEDHISTORY ++void save_history(line_input_t *st); ++# endif + #else + #define MAX_HISTORY 0 + int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; +diff --git a/libbb/Config.src b/libbb/Config.src +index aa44236..deee15f 100644 +--- a/libbb/Config.src ++++ b/libbb/Config.src +@@ -94,6 +94,14 @@ config FEATURE_EDITING_SAVEHISTORY + help + Enable history saving in shells. + ++config FEATURE_EDITING_DELAYEDHISTORY ++ bool "Delayed history saving" ++ default n ++ depends on FEATURE_EDITING_SAVEHISTORY ++ help ++ Disable saving history to disk after every command. Write out ++ history only upon shell closure instead. ++ + config FEATURE_REVERSE_SEARCH + bool "Reverse history search" + default y +diff --git a/libbb/lineedit.c b/libbb/lineedit.c +index 1026519..48ac509 100644 +--- a/libbb/lineedit.c ++++ b/libbb/lineedit.c +@@ -1392,10 +1392,29 @@ static void load_history(line_input_t *st_parm) + } + } + +-/* state->flags is already checked to be nonzero */ ++# if ENABLE_FEATURE_EDITING_DELAYEDHISTORY ++void save_history(line_input_t *st) ++# else + static void save_history(char *str) ++# endif + { + int fd; ++# if ENABLE_FEATURE_EDITING_DELAYEDHISTORY ++# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY ++ FILE *f_hist_file; ++ state = st ? st : (line_input_t*) &const_int_0; ++ f_hist_file = fopen(state->hist_file,"a"); ++ if (f_hist_file) { ++ int i; ++ for (i = state->cnt_history_in_file; i < state->cnt_history; i++) ++ fprintf(f_hist_file, "%s\n", state->history[i]); ++ } ++ fclose(f_hist_file); ++# else ++ return; ++# endif ++# else ++ /* state->flags is already checked to be nonzero */ + int len, len2; + + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); +@@ -1409,6 +1428,7 @@ static void save_history(char *str) + close(fd); + if (len2 != len + 1) + return; /* "wtf?" */ ++# endif /* FEATURE_EDITING_DELAYEDHISTORY */ + + /* did we write so much that history file needs trimming? */ + state->cnt_history_in_file++; +@@ -1475,10 +1495,12 @@ static void remember_in_history(char *str) + /* i <= state->max_history */ + state->cur_history = i; + state->cnt_history = i; ++#if !ENABLE_FEATURE_EDITING_DELAYEDHISTORY /* save_history() will be called by exit_shell() */ + # if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY + if ((state->flags & SAVE_HISTORY) && state->hist_file) + save_history(str); + # endif ++#endif + IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) + } + +diff --git a/shell/ash.c b/shell/ash.c +index d48cd01..08d4e92 100644 +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -12888,6 +12888,11 @@ exitshell(void) + char *p; + int status; + ++#if ENABLE_FEATURE_EDITING_DELAYEDHISTORY ++ if ((line_input_state->flags & SAVE_HISTORY) && line_input_state->hist_file) ++ save_history(line_input_state); ++#endif ++ + status = exitstatus; + TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); + if (setjmp(loc.loc)) { +diff --git a/shell/hush.c b/shell/hush.c +index e4138ad..a7428d6 100644 +--- a/shell/hush.c ++++ b/shell/hush.c +@@ -1541,6 +1541,11 @@ static sighandler_t pick_sighandler(unsigned sig) + static void hush_exit(int exitcode) NORETURN; + static void hush_exit(int exitcode) + { ++#if ENABLE_FEATURE_EDITING_DELAYEDHISTORY ++ if ((G.line_input_state->flags & SAVE_HISTORY) && G.line_input_state->hist_file) ++ save_history(G.line_input_state); ++#endif ++ + fflush_all(); + if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { + char *argv[3]; +-- +1.7.6 + diff --git a/debian/patches/0002-hush-don-t-save-history-when-non-interactive.patch b/debian/patches/0002-hush-don-t-save-history-when-non-interactive.patch new file mode 100644 index 0000000..c37dcab --- /dev/null +++ b/debian/patches/0002-hush-don-t-save-history-when-non-interactive.patch @@ -0,0 +1,37 @@ +From 03b2e51fbe2d69823cea54e6b3ecb7db7d981879 Mon Sep 17 00:00:00 2001 +From: Dennis Groenen +Date: Sun, 21 Aug 2011 13:31:41 +0200 +Subject: [PATCH] hush: don't save history when non-interactive + +--- + shell/hush.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/shell/hush.c b/shell/hush.c +index a7428d6..4ea641b 100644 +--- a/shell/hush.c ++++ b/shell/hush.c +@@ -7832,6 +7832,7 @@ int hush_main(int argc, char **argv) + //set_local_var(xasprintf("HISTFILE=%s", ...)); + } + } ++ G.line_input_state->flags &= ~SAVE_HISTORY; /* hush is non-interactive at this point */ + # if ENABLE_FEATURE_SH_HISTFILESIZE + hp = get_local_var_value("HISTFILESIZE"); + G.line_input_state->max_history = size_from_HISTFILESIZE(hp); +@@ -8053,6 +8054,12 @@ int hush_main(int argc, char **argv) + * standard output is a terminal + * Refer to Posix.2, the description of the 'sh' utility. + */ ++#if ENABLE_FEATURE_EDITING ++# if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY ++ G.line_input_state->flags |= SAVE_HISTORY; ++# endif ++#endif ++ + #if ENABLE_HUSH_JOB + if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { + G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); +-- +1.7.6 + diff --git a/debian/patches/ash-history-buffer.patch b/debian/patches/ash-history-buffer.patch deleted file mode 100644 index 3ce219d..0000000 --- a/debian/patches/ash-history-buffer.patch +++ /dev/null @@ -1,107 +0,0 @@ -Allows the user to specify a location at compile time for temporarily storing ash's history file until the shell is closed. -NB This is only useful if ASH_HIST_BUFFER_PATH points to an in-memory filesystem. -By Dennis Groenen - 2011-08-20 ---- - ---- a/shell/ash.c -+++ b/shell/ash.c -@@ -184,6 +184,24 @@ - //config: This option recreates the prompt string from the environment - //config: variable each time it is displayed. - //config: -+//config:config ASH_HIST_BUFFER -+//config: bool "History buffer" -+//config: default n -+//config: depends on ASH && FEATURE_EDITING_SAVEHISTORY -+//config: help -+//config: Allows you to set a temporary location for .ash_history. -+//config: History is saved to this custom location, and written out to -+//config: its default location (~/.ash_history) upon shell exit. -+//config: Useful to prevent wear on flash-based storage devices. -+//config: -+//config:config ASH_HIST_BUFFER_PATH -+//config: string "History buffer location" -+//config: default "/tmp" -+//config: depends on ASH && ASH_HIST_BUFFER -+//config: help -+//config: Directory which will be used to save the shell history until -+//config: ash is exited. -+//config: - - //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) - //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) -@@ -12888,6 +12906,14 @@ exitshell(void) - char *p; - int status; - -+#if ENABLE_ASH_HIST_BUFFER -+ const char *tmphistory = lookupvar("HISTFILE"); -+ const char *storedhistory = lookupvar("STOREDHISTFILE"); -+ -+ if (storedhistory) /* is NULL when setting up the history buffer failed; check for this before copying */ -+ copy_file(tmphistory, storedhistory, FILEUTILS_FORCE | FILEUTILS_DEREFERENCE | FILEUTILS_PRESERVE_STATUS); -+#endif -+ - status = exitstatus; - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc.loc)) { -@@ -13151,9 +13177,59 @@ int ash_main(int argc UNUSED_PARAM, char - if (!hp) { - hp = lookupvar("HOME"); - if (hp) { -+#if ENABLE_ASH_HIST_BUFFER -+ char *tmppath; -+ char *tmphistory; -+ char *storedhistory; -+ const char *user = lookupvar("USER"); -+ -+ tmppath = concat_path_file(CONFIG_ASH_HIST_BUFFER_PATH, user); -+ tmphistory = concat_path_file(tmppath, ".ash_history"); -+ storedhistory = concat_path_file(hp, ".ash_history"); -+ -+ if (access(CONFIG_ASH_HIST_BUFFER_PATH, R_OK == -1)) { -+ bb_simple_perror_msg("could not access history buffer path"); -+ goto bail; -+ } -+ -+ if (bb_make_directory(tmppath, S_IRWXU, FILEUTILS_RECUR)) { -+ /* bb_make_directory is noisy, no need for an additional error message */ -+ goto bail; -+ } else { -+ struct stat stat_tmppath; -+ stat(tmppath, &stat_tmppath); -+ if (stat_tmppath.st_uid != geteuid() || stat_tmppath.st_mode & (S_IRWXG | S_IRWXO)) { -+ errno = 0; -+ bb_simple_perror_msg("history buffer is not exclusive to the shell user"); -+ goto bail; -+ } -+ } -+ -+ if (access(tmphistory, R_OK | W_OK) == -1) { -+ if (access(storedhistory, R_OK) != -1) { -+ if (copy_file(storedhistory, tmphistory, FILEUTILS_FORCE | FILEUTILS_DEREFERENCE | FILEUTILS_PRESERVE_STATUS) == -1) { -+ /* copy_file is noisy too, no need for an additional error message */ -+ goto bail; -+ } -+ } -+ } -+ setvar("STOREDHISTFILE", storedhistory, 0); -+ goto out; -+ -+ bail: -+ errno = 0; -+ bb_simple_perror_msg("shell history will not be saved"); -+ tmphistory = xasprintf("/dev/null"); -+ out: -+ setvar("HISTFILE", tmphistory, 0); -+ free(storedhistory); -+ free(tmphistory); -+ free(tmppath); -+#else - char *defhp = concat_path_file(hp, ".ash_history"); - setvar("HISTFILE", defhp, 0); - free(defhp); -+#endif - } - } - } diff --git a/debian/patches/obselete/ash-history-buffer.patch b/debian/patches/obselete/ash-history-buffer.patch new file mode 100644 index 0000000..3ce219d --- /dev/null +++ b/debian/patches/obselete/ash-history-buffer.patch @@ -0,0 +1,107 @@ +Allows the user to specify a location at compile time for temporarily storing ash's history file until the shell is closed. +NB This is only useful if ASH_HIST_BUFFER_PATH points to an in-memory filesystem. +By Dennis Groenen - 2011-08-20 +--- + +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -184,6 +184,24 @@ + //config: This option recreates the prompt string from the environment + //config: variable each time it is displayed. + //config: ++//config:config ASH_HIST_BUFFER ++//config: bool "History buffer" ++//config: default n ++//config: depends on ASH && FEATURE_EDITING_SAVEHISTORY ++//config: help ++//config: Allows you to set a temporary location for .ash_history. ++//config: History is saved to this custom location, and written out to ++//config: its default location (~/.ash_history) upon shell exit. ++//config: Useful to prevent wear on flash-based storage devices. ++//config: ++//config:config ASH_HIST_BUFFER_PATH ++//config: string "History buffer location" ++//config: default "/tmp" ++//config: depends on ASH && ASH_HIST_BUFFER ++//config: help ++//config: Directory which will be used to save the shell history until ++//config: ash is exited. ++//config: + + //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) + //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) +@@ -12888,6 +12906,14 @@ exitshell(void) + char *p; + int status; + ++#if ENABLE_ASH_HIST_BUFFER ++ const char *tmphistory = lookupvar("HISTFILE"); ++ const char *storedhistory = lookupvar("STOREDHISTFILE"); ++ ++ if (storedhistory) /* is NULL when setting up the history buffer failed; check for this before copying */ ++ copy_file(tmphistory, storedhistory, FILEUTILS_FORCE | FILEUTILS_DEREFERENCE | FILEUTILS_PRESERVE_STATUS); ++#endif ++ + status = exitstatus; + TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); + if (setjmp(loc.loc)) { +@@ -13151,9 +13177,59 @@ int ash_main(int argc UNUSED_PARAM, char + if (!hp) { + hp = lookupvar("HOME"); + if (hp) { ++#if ENABLE_ASH_HIST_BUFFER ++ char *tmppath; ++ char *tmphistory; ++ char *storedhistory; ++ const char *user = lookupvar("USER"); ++ ++ tmppath = concat_path_file(CONFIG_ASH_HIST_BUFFER_PATH, user); ++ tmphistory = concat_path_file(tmppath, ".ash_history"); ++ storedhistory = concat_path_file(hp, ".ash_history"); ++ ++ if (access(CONFIG_ASH_HIST_BUFFER_PATH, R_OK == -1)) { ++ bb_simple_perror_msg("could not access history buffer path"); ++ goto bail; ++ } ++ ++ if (bb_make_directory(tmppath, S_IRWXU, FILEUTILS_RECUR)) { ++ /* bb_make_directory is noisy, no need for an additional error message */ ++ goto bail; ++ } else { ++ struct stat stat_tmppath; ++ stat(tmppath, &stat_tmppath); ++ if (stat_tmppath.st_uid != geteuid() || stat_tmppath.st_mode & (S_IRWXG | S_IRWXO)) { ++ errno = 0; ++ bb_simple_perror_msg("history buffer is not exclusive to the shell user"); ++ goto bail; ++ } ++ } ++ ++ if (access(tmphistory, R_OK | W_OK) == -1) { ++ if (access(storedhistory, R_OK) != -1) { ++ if (copy_file(storedhistory, tmphistory, FILEUTILS_FORCE | FILEUTILS_DEREFERENCE | FILEUTILS_PRESERVE_STATUS) == -1) { ++ /* copy_file is noisy too, no need for an additional error message */ ++ goto bail; ++ } ++ } ++ } ++ setvar("STOREDHISTFILE", storedhistory, 0); ++ goto out; ++ ++ bail: ++ errno = 0; ++ bb_simple_perror_msg("shell history will not be saved"); ++ tmphistory = xasprintf("/dev/null"); ++ out: ++ setvar("HISTFILE", tmphistory, 0); ++ free(storedhistory); ++ free(tmphistory); ++ free(tmppath); ++#else + char *defhp = concat_path_file(hp, ".ash_history"); + setvar("HISTFILE", defhp, 0); + free(defhp); ++#endif + } + } + } diff --git a/debian/patches/series b/debian/patches/series index b86d70c..6036e3c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -19,5 +19,6 @@ parse-complete-hostname.patch #New patches as per reported issues by users showkey-default-option.patch ps-accept-and-ignore-missing-options.patch -ash-history-buffer.patch +0001-add-support-for-delayed-history-saving.patch +0002-hush-don-t-save-history-when-non-interactive.patch -- 1.7.9.5