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
This commit is contained in:
Baptiste Daroussin 2021-03-30 10:28:08 +02:00
parent 9867224bab
commit 988b1bb0c5
5 changed files with 81 additions and 2 deletions

View file

@ -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).

View file

@ -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);

View file

@ -43,4 +43,5 @@ extern int displayhist;
void histedit(void);
void sethistsize(const char *);
void setterm(const char *);
void histload(void);
void histsave(void);

View file

@ -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

View file

@ -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 &&