This mail is a follow up to "[PATCH] ash: add support for history buffer"

On 08/09/2011 05:05 AM, Denys Vlasenko wrote:
All you need is to create a CONFIG_ option which disables
"save history to disk after every command" behavior in remember_in_history()
function, makes save_history() non-static and calls it on shell exit
in both ash and hush.

Pardon the late reply, I was outside the country last week. I gave what you said a shot. Attached is the resulting patch that implements bash like history saving in BusyBox.

All introduced code resides behind the new FEATURE_EDITING_DELAYEDHISTORY config option. When a shell gets closed, its history will get appended to its respective history file. This is modeled after how bash handles (parallel) shells with regards to shell history. There are no signs of history contamination when using parallel shells.

There is, however, one (major) blocker with my patch. For some reason, both the conditions "G.line_input_state->flags & SAVE_HISTORY" and "G.line_input_state->hist_file" are true in hush when hush is not being ran as an interactive shell (e.g. hush -c "echo hello"). Saving shell history upon shell exit then will of course cause hush to segfault. Is there a bug in hush causing those conditions to be true, or am I overlooking something (in hush_exit())? This problem does not occur in ash, which shares most of its history handling code with hush. Any input on this is highly appreciated.

--Dennis
>From c7f39e550a60976f4de4cb4ddc93b53d55be5acc Mon Sep 17 00:00:00 2001
From: Dennis Groenen <[email protected]>
Date: Thu, 18 Aug 2011 15:02:01 +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     |    9 ++++++++-
 5 files changed, 47 insertions(+), 2 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..6c68bfe 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1158,7 +1158,6 @@ static void cmdedit_update_prompt(void);
 # define cmdedit_update_prompt() ((void)0)
 #endif
 
-
 /* Utility functions
  */
 /* Replace each \x with x in place, return ptr past NUL. */
@@ -1541,6 +1540,14 @@ static sighandler_t pick_sighandler(unsigned sig)
 static void hush_exit(int exitcode) NORETURN;
 static void hush_exit(int exitcode)
 {
+
+/* The following if statement always returns true?
+ * Therefore, hush will segfault when being ran with -c "command" */
+#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

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to