plug part of the history problems until we can do better:

do not change the underlying file when truncating; rather,
copy everything back from the tmpfile to histfd while the
latter is locked
This commit is contained in:
tg 2017-08-07 20:40:57 +00:00
parent b903a5e66a
commit bfa79a4e4b
2 changed files with 96 additions and 37 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.725 2017/05/15 13:35:38 tg Exp $' srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.726 2017/08/07 20:40:56 tg Exp $'
#- #-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016, 2017 # 2011, 2012, 2013, 2014, 2015, 2016, 2017
@ -2090,6 +2090,11 @@ ac_test mmap lock_fcntl 0 'for mmap and munmap' <<-'EOF'
munmap(NULL, 0)); } munmap(NULL, 0)); }
EOF EOF
ac_test ftruncate mmap 0 'for ftruncate' <<-'EOF'
#include <unistd.h>
int main(void) { return (ftruncate(0, 0)); }
EOF
ac_test nice <<-'EOF' ac_test nice <<-'EOF'
#include <unistd.h> #include <unistd.h>
int main(void) { return (nice(4)); } int main(void) { return (nice(4)); }
@ -2244,8 +2249,8 @@ EOF
# other checks # other checks
# #
fd='if to use persistent history' fd='if to use persistent history'
ac_cache PERSISTENT_HISTORY || case $HAVE_MMAP$HAVE_FLOCK$HAVE_LOCK_FCNTL in ac_cache PERSISTENT_HISTORY || case $HAVE_FTRUNCATE$HAVE_MMAP$HAVE_FLOCK$HAVE_LOCK_FCNTL in
11*|101) fv=1 ;; 111*|1101) fv=1 ;;
esac esac
test 1 = $fv || check_categories="$check_categories no-histfile" test 1 = $fv || check_categories="$check_categories no-histfile"
ac_testdone ac_testdone
@ -2404,7 +2409,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
add_cppflags -DMKSH_BUILD_R=551 add_cppflags -DMKSH_BUILD_R=561
$e $bi$me: Finished configuration testing, now producing output.$ao $e $bi$me: Finished configuration testing, now producing output.$ao

120
histrap.c
View File

@ -27,7 +27,7 @@
#include <sys/file.h> #include <sys/file.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.162 2017/04/29 22:04:28 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.163 2017/08/07 20:40:57 tg Exp $");
Trap sigtraps[ksh_NSIG + 1]; Trap sigtraps[ksh_NSIG + 1];
static struct sigaction Sigact_ign; static struct sigaction Sigact_ign;
@ -714,26 +714,65 @@ histsave(int *lnp, const char *cmd, int svmode, bool ignoredups)
#if HAVE_PERSISTENT_HISTORY #if HAVE_PERSISTENT_HISTORY
static const unsigned char sprinkle[2] = { HMAGIC1, HMAGIC2 }; static const unsigned char sprinkle[2] = { HMAGIC1, HMAGIC2 };
#endif
void static int
hist_init(Source *s) hist_persist_back(int srcfd)
{
off_t tot, mis;
ssize_t n, w;
char *buf, *cp;
int rv = 0;
#define MKSH_HS_BUFSIZ 4096
if ((buf = malloc_osfunc(MKSH_HS_BUFSIZ)) == NULL)
return (1);
tot = lseek(srcfd, (off_t)0, SEEK_END);
lseek(srcfd, (off_t)0, SEEK_SET);
lseek(histfd, (off_t)0, SEEK_SET);
mis = tot;
while (mis > 0) {
if ((n = blocking_read(srcfd, (cp = buf),
MKSH_HS_BUFSIZ)) == -1) {
if (errno == EINTR) {
intrcheck();
continue;
}
goto copy_error;
}
mis -= n;
while (n) {
if (intrsig)
goto has_intrsig;
if ((w = write(histfd, cp, n)) != -1) {
n -= w;
cp += w;
continue;
}
if (errno == EINTR) {
has_intrsig:
intrcheck();
continue;
}
goto copy_error;
}
}
if (ftruncate(histfd, tot)) {
copy_error:
rv = 1;
}
free_osfunc(buf);
return (rv);
}
static void
hist_persist_init(void)
{ {
#if HAVE_PERSISTENT_HISTORY
unsigned char *base; unsigned char *base;
int lines, fd; int lines, fd;
enum { hist_init_first, hist_init_retry, hist_init_restore } hs; enum { hist_init_first, hist_init_retry, hist_use_it } hs;
#endif
histsave(NULL, NULL, HIST_DISCARD, true);
if (Flag(FTALKING) == 0)
return;
hstarted = true;
hist_source = s;
#if HAVE_PERSISTENT_HISTORY
if (((hname = str_val(global("HISTFILE"))) == NULL) || !*hname) { if (((hname = str_val(global("HISTFILE"))) == NULL) || !*hname) {
hname = NULL; hname = NULL;
return; return;
@ -753,9 +792,8 @@ hist_init(Source *s)
mksh_lockfd(histfd); mksh_lockfd(histfd);
histfsize = lseek(histfd, (off_t)0, SEEK_END); histfsize = lseek(histfd, (off_t)0, SEEK_END);
if (histfsize > MKSH_MAXHISTFSIZE || hs == hist_init_restore) { if (histfsize > MKSH_MAXHISTFSIZE) {
/* we ignore too large files but still append to them */ /* we ignore too large files but still append to them */
/* we also don't need to re-read after truncation */
goto hist_init_tail; goto hist_init_tail;
} else if (histfsize > 2) { } else if (histfsize > 2) {
/* we have some data, check its validity */ /* we have some data, check its validity */
@ -781,6 +819,7 @@ hist_init(Source *s)
if ((fd = binopen3(nhname, O_RDWR | O_CREAT | O_TRUNC | if ((fd = binopen3(nhname, O_RDWR | O_CREAT | O_TRUNC |
O_EXCL, 0600)) < 0) { O_EXCL, 0600)) < 0) {
/* just don't truncate then, meh. */ /* just don't truncate then, meh. */
hs = hist_use_it;
goto hist_trunc_dont; goto hist_trunc_dont;
} }
if (fstat(histfd, &sb) >= 0 && if (fstat(histfd, &sb) >= 0 &&
@ -795,28 +834,26 @@ hist_init(Source *s)
hp = history; hp = history;
while (hp < histptr) { while (hp < histptr) {
if (!writehistline(fd, if (!writehistline(fd,
s->line - (histptr - hp), *hp)) hist_source->line - (histptr - hp), *hp))
goto hist_trunc_abort; goto hist_trunc_abort;
++hp; ++hp;
} }
/* now unlock, close both, rename, rinse, repeat */ /* now transfer back */
if (!hist_persist_back(fd)) {
/* success! */
hs = hist_use_it;
}
hist_trunc_abort:
/* remove temporary file */
close(fd); close(fd);
fd = -1; fd = -1;
hist_finish(); unlink(nhname);
if (rename(nhname, hname) < 0) { /* use whatever is in the file now */
hist_trunc_abort:
if (fd != -1)
close(fd);
unlink(nhname);
if (fd != -1)
goto hist_trunc_dont;
/* darn! restore histfd and pray */
}
hs = hist_init_restore;
hist_trunc_dont: hist_trunc_dont:
afree(nhname, ATEMP); afree(nhname, ATEMP);
if (hs == hist_init_restore) if (hs == hist_use_it)
goto retry; goto hist_trunc_done;
goto hist_init_fail;
} }
} else if (histfsize != 0) { } else if (histfsize != 0) {
/* negative or too small... */ /* negative or too small... */
@ -840,9 +877,26 @@ hist_init(Source *s)
return; return;
} }
} }
hist_trunc_done:
histfsize = lseek(histfd, (off_t)0, SEEK_END); histfsize = lseek(histfd, (off_t)0, SEEK_END);
hist_init_tail: hist_init_tail:
mksh_unlkfd(histfd); mksh_unlkfd(histfd);
}
#endif
void
hist_init(Source *s)
{
histsave(NULL, NULL, HIST_DISCARD, true);
if (Flag(FTALKING) == 0)
return;
hstarted = true;
hist_source = s;
#if HAVE_PERSISTENT_HISTORY
hist_persist_init();
#endif #endif
} }