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 #include #include +#include #include #include #include @@ -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 @@ main(int argc, char *argv[]) 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 &&