git: 988b1bb0c54e - main - sh: implement persistent history storage

Baptiste Daroussin bapt at FreeBSD.org
Mon May 10 16:57:28 UTC 2021


The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=988b1bb0c54e50654112f0bd649aee68307a5a80

commit 988b1bb0c54e50654112f0bd649aee68307a5a80
Author:     Baptiste Daroussin <bapt at FreeBSD.org>
AuthorDate: 2021-03-30 08:28:08 +0000
Commit:     Baptiste Daroussin <bapt at FreeBSD.org>
CommitDate: 2021-05-10 16:57:13 +0000

    sh: implement persistent history storage
    
    Implement persistent history storage:
    the strategy is simple at start: loads the existing .sh_history file
    at exit dump it.
    
    The implementation respects the HISTFILE variable and its POSIX
    definition: ~/.sh_history is used if HISTFILE is not set.
    
    to avoid sh to create the history file, set HISTSIZE to 0 or HISTFILE to
    en empty value
    
    Co-authored-by: pstef
    Reviewed by:    jilles
    Differential Revision:  https://reviews.freebsd.org/D29493
---
 bin/sh/histedit.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 bin/sh/main.c       |  7 +++++++
 bin/sh/myhistedit.h |  3 ++-
 bin/sh/sh.1         | 11 +++++++++-
 bin/sh/trap.c       |  3 +++
 5 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c
index ba2bec357181..596145790f31 100644
--- a/bin/sh/histedit.c
+++ b/bin/sh/histedit.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <paths.h>
 #include <stdio.h>
@@ -78,6 +79,64 @@ static int comparator(const void *, const void *, void *);
 static char **sh_matches(const char *, int, int);
 static unsigned char sh_complete(EditLine *, int);
 
+static const char *
+get_histfile(void)
+{
+	const char *histfile;
+
+	/* don't try to save if the history size is 0 */
+	if (hist == NULL || histsizeval() == 0)
+		return (NULL);
+	histfile = expandstr("${HISTFILE-${HOME-}/.sh_history}");
+
+	if (histfile[0] == '\0')
+		return (NULL);
+	return (histfile);
+}
+
+void
+histsave(void)
+{
+	HistEvent he;
+	char *histtmpname = NULL;
+	const char *histfile;
+	int fd;
+	FILE *f;
+
+	if ((histfile = get_histfile()) == NULL)
+		return;
+	INTOFF;
+	asprintf(&histtmpname, "%s.XXXXXXXXXX", histfile);
+	if (histtmpname == NULL) {
+		INTON;
+		return;
+	}
+	fd = mkstemp(histtmpname);
+	if (fd == -1 || (f = fdopen(fd, "w")) == NULL) {
+		free(histtmpname);
+		INTON;
+		return;
+	}
+	if (history(hist, &he, H_SAVE_FP, f) < 1 ||
+	    rename(histtmpname, histfile) == -1)
+		unlink(histtmpname);
+	fclose(f);
+	free(histtmpname);
+	INTON;
+
+}
+
+void
+histload(void)
+{
+	const char *histfile;
+	HistEvent he;
+
+	if ((histfile = get_histfile()) == NULL)
+		return;
+	history(hist, &he, H_LOAD, histfile);
+}
+
 /*
  * Set history and editing status.  Called whenever the status may
  * have changed (figures out what to do).
diff --git a/bin/sh/main.c b/bin/sh/main.c
index cbe026e13640..b0a5fac6fd4e 100644
--- a/bin/sh/main.c
+++ b/bin/sh/main.c
@@ -75,6 +75,9 @@ __FBSDID("$FreeBSD$");
 #include "cd.h"
 #include "redir.h"
 #include "builtins.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
 
 int rootpid;
 int rootshell;
@@ -157,6 +160,10 @@ state2:
 			read_profile(shinit);
 		}
 	}
+#ifndef NO_HISTORY
+	if (iflag)
+		histload();
+#endif
 state3:
 	state = 4;
 	popstackmark(&smark2);
diff --git a/bin/sh/myhistedit.h b/bin/sh/myhistedit.h
index 968d23c9c1f8..1f513f0ae206 100644
--- a/bin/sh/myhistedit.h
+++ b/bin/sh/myhistedit.h
@@ -43,4 +43,5 @@ extern int displayhist;
 void histedit(void);
 void sethistsize(const char *);
 void setterm(const char *);
-
+void histload(void);
+void histsave(void);
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index 76335cfaa2cd..ca3faeff13af 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
 .\"	from: @(#)sh.1	8.6 (Berkeley) 5/4/95
 .\" $FreeBSD$
 .\"
-.Dd July 6, 2020
+.Dd May 10, 2021
 .Dt SH 1
 .Os
 .Sh NAME
@@ -1351,6 +1351,15 @@ If not set, the default editor is
 The default editor used with the
 .Ic fc
 built-in.
+.It Va HISTFILE
+File used for persistent history storage.
+If unset
+.Pa ~/.sh_history
+will be used.
+If set but empty or
+.Va HISTSIZE
+is set to 0
+the shell will not load and save the history.
 .It Va HISTSIZE
 The number of previous commands that are accessible.
 .It Va HOME
diff --git a/bin/sh/trap.c b/bin/sh/trap.c
index d7ef40274270..2dd394035ca4 100644
--- a/bin/sh/trap.c
+++ b/bin/sh/trap.c
@@ -535,6 +535,9 @@ exitshell_savedstatus(void)
 		flushall();
 #if JOBS
 		setjobctl(0);
+#endif
+#ifndef NO_HISTORY
+		histsave();
 #endif
 	}
 	if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&


More information about the dev-commits-src-all mailing list