replace ash history buffer by global delayed writing (ash and hush)
authorDennis Groenen <tj.groenen@gmail.com>
Sun, 21 Aug 2011 11:49:23 +0000 (13:49 +0200)
committerDennis Groenen <tj.groenen@gmail.com>
Sun, 21 Aug 2011 11:49:23 +0000 (13:49 +0200)
debian/config/config.busybox
debian/patches/0001-add-support-for-delayed-history-saving.patch [new file with mode: 0644]
debian/patches/0002-hush-don-t-save-history-when-non-interactive.patch [new file with mode: 0644]
debian/patches/ash-history-buffer.patch [deleted file]
debian/patches/obselete/ash-history-buffer.patch [new file with mode: 0644]
debian/patches/series

index 4c4f8b6..0c09289 100644 (file)
@@ -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 (file)
index 0000000..ce9e112
--- /dev/null
@@ -0,0 +1,137 @@
+From 772cc01d3739d50ae43858fed8ec733c0c7bf00c Mon Sep 17 00:00:00 2001
+From: Dennis Groenen <tj.groenen@gmail.com>
+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 (file)
index 0000000..c37dcab
--- /dev/null
@@ -0,0 +1,37 @@
+From 03b2e51fbe2d69823cea54e6b3ecb7db7d981879 Mon Sep 17 00:00:00 2001
+From: Dennis Groenen <tj.groenen@gmail.com>
+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 (file)
index 3ce219d..0000000
+++ /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 <tj.groenen@gmail.com> - 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 (file)
index 0000000..3ce219d
--- /dev/null
@@ -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 <tj.groenen@gmail.com> - 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
+                       }
+               }
+       }
index b86d70c..6036e3c 100644 (file)
@@ -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