plug part of the history problems until we can do better:
authortg <tg@mirbsd.org>
Mon, 7 Aug 2017 20:40:57 +0000 (20:40 +0000)
committertg <tg@mirbsd.org>
Mon, 7 Aug 2017 20:40:57 +0000 (20:40 +0000)
do not change the underlying file when truncating; rather,
copy everything back from the tmpfile to histfd while the
latter is locked

Build.sh
histrap.c

index e34f93f..eaf27af 100644 (file)
--- a/Build.sh
+++ b/Build.sh
@@ -1,5 +1,5 @@
 #!/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,
 #              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)); }
 EOF
 
+ac_test ftruncate mmap 0 'for ftruncate' <<-'EOF'
+       #include <unistd.h>
+       int main(void) { return (ftruncate(0, 0)); }
+EOF
+
 ac_test nice <<-'EOF'
        #include <unistd.h>
        int main(void) { return (nice(4)); }
@@ -2244,8 +2249,8 @@ EOF
 # other checks
 #
 fd='if to use persistent history'
-ac_cache PERSISTENT_HISTORY || case $HAVE_MMAP$HAVE_FLOCK$HAVE_LOCK_FCNTL in
-11*|101) fv=1 ;;
+ac_cache PERSISTENT_HISTORY || case $HAVE_FTRUNCATE$HAVE_MMAP$HAVE_FLOCK$HAVE_LOCK_FCNTL in
+111*|1101) fv=1 ;;
 esac
 test 1 = $fv || check_categories="$check_categories no-histfile"
 ac_testdone
@@ -2404,7 +2409,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
 addsrcs USE_PRINTF_BUILTIN printf.c
 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
 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
 
index 79d0340..4410b84 100644 (file)
--- a/histrap.c
+++ b/histrap.c
@@ -27,7 +27,7 @@
 #include <sys/file.h>
 #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];
 static struct sigaction Sigact_ign;
@@ -714,26 +714,65 @@ histsave(int *lnp, const char *cmd, int svmode, bool ignoredups)
 
 #if HAVE_PERSISTENT_HISTORY
 static const unsigned char sprinkle[2] = { HMAGIC1, HMAGIC2 };
-#endif
 
-void
-hist_init(Source *s)
+static int
+hist_persist_back(int srcfd)
 {
-#if HAVE_PERSISTENT_HISTORY
-       unsigned char *base;
-       int lines, fd;
-       enum { hist_init_first, hist_init_retry, hist_init_restore } hs;
-#endif
+       off_t tot, mis;
+       ssize_t n, w;
+       char *buf, *cp;
+       int rv = 0;
+#define MKSH_HS_BUFSIZ 4096
 
-       histsave(NULL, NULL, HIST_DISCARD, true);
+       if ((buf = malloc_osfunc(MKSH_HS_BUFSIZ)) == NULL)
+               return (1);
 
-       if (Flag(FTALKING) == 0)
-               return;
+       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);
+}
 
-       hstarted = true;
-       hist_source = s;
+static void
+hist_persist_init(void)
+{
+       unsigned char *base;
+       int lines, fd;
+       enum { hist_init_first, hist_init_retry, hist_use_it } hs;
 
-#if HAVE_PERSISTENT_HISTORY
        if (((hname = str_val(global("HISTFILE"))) == NULL) || !*hname) {
                hname = NULL;
                return;
@@ -753,9 +792,8 @@ hist_init(Source *s)
        mksh_lockfd(histfd);
 
        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 also don't need to re-read after truncation */
                goto hist_init_tail;
        } else if (histfsize > 2) {
                /* 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 |
                            O_EXCL, 0600)) < 0) {
                                /* just don't truncate then, meh. */
+                               hs = hist_use_it;
                                goto hist_trunc_dont;
                        }
                        if (fstat(histfd, &sb) >= 0 &&
@@ -795,28 +834,26 @@ hist_init(Source *s)
                        hp = history;
                        while (hp < histptr) {
                                if (!writehistline(fd,
-                                   s->line - (histptr - hp), *hp))
+                                   hist_source->line - (histptr - hp), *hp))
                                        goto hist_trunc_abort;
                                ++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);
                        fd = -1;
-                       hist_finish();
-                       if (rename(nhname, hname) < 0) {
- 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;
+                       unlink(nhname);
+                       /* use whatever is in the file now */
  hist_trunc_dont:
                        afree(nhname, ATEMP);
-                       if (hs == hist_init_restore)
-                               goto retry;
+                       if (hs == hist_use_it)
+                               goto hist_trunc_done;
+                       goto hist_init_fail;
                }
        } else if (histfsize != 0) {
                /* negative or too small... */
@@ -840,9 +877,26 @@ hist_init(Source *s)
                        return;
                }
        }
+ hist_trunc_done:
        histfsize = lseek(histfd, (off_t)0, SEEK_END);
  hist_init_tail:
        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
 }