about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-08-25T13·57+0200
committerEelco Dolstra <edolstra@gmail.com>2017-08-25T13·59+0200
commitdb1d45037cf923bf470a8581d5546bef8247c756 (patch)
tree4537c9cde61ef5d7680b869518dad8b64878aa1d
parentec9e0c03c398ca48fba81fd6e870dc396da01b08 (diff)
Handle SIGWINCH
-rw-r--r--src/libutil/util.cc28
-rw-r--r--src/libutil/util.hh10
-rw-r--r--src/nix/progress-bar.cc9
3 files changed, 39 insertions, 8 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index b7b32b3d384e..2f410f7e3fd5 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pwd.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -1254,6 +1255,26 @@ void callFailure(const std::function<void(std::exception_ptr exc)> & failure, st
 }
 
 
+static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
+
+
+static void updateWindowSize()
+{
+    struct winsize ws;
+    if (ioctl(1, TIOCGWINSZ, &ws) == 0) {
+        auto windowSize_(windowSize.lock());
+        windowSize_->first = ws.ws_row;
+        windowSize_->second = ws.ws_col;
+    }
+}
+
+
+std::pair<unsigned short, unsigned short> getWindowSize()
+{
+    return *windowSize.lock();
+}
+
+
 static Sync<std::list<std::function<void()>>> _interruptCallbacks;
 
 static void signalHandlerThread(sigset_t set)
@@ -1264,6 +1285,10 @@ static void signalHandlerThread(sigset_t set)
 
         if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP)
             triggerInterrupt();
+
+        else if (signal == SIGWINCH) {
+            updateWindowSize();
+        }
     }
 }
 
@@ -1287,6 +1312,8 @@ static sigset_t savedSignalMask;
 
 void startSignalHandlerThread()
 {
+    updateWindowSize();
+
     if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
         throw SysError("quering signal mask");
 
@@ -1296,6 +1323,7 @@ void startSignalHandlerThread()
     sigaddset(&set, SIGTERM);
     sigaddset(&set, SIGHUP);
     sigaddset(&set, SIGPIPE);
+    sigaddset(&set, SIGWINCH);
     if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
         throw SysError("blocking signals");
 
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 7340ca6c7478..30e3c0df1c1a 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -349,6 +349,12 @@ bool hasSuffix(const string & s, const string & suffix);
 std::string toLower(const std::string & s);
 
 
+/* Escape a string that contains octal-encoded escape codes such as
+   used in /etc/fstab and /proc/mounts (e.g. "foo\040bar" decodes to
+   "foo bar"). */
+string decodeOctalEscaped(const string & s);
+
+
 /* Exception handling in destructors: print an error message, then
    ignore the exception. */
 void ignoreException();
@@ -470,4 +476,8 @@ struct MaintainCount
 };
 
 
+/* Return the number of rows and columns of the terminal. */
+std::pair<unsigned short, unsigned short> getWindowSize();
+
+
 }
diff --git a/src/nix/progress-bar.cc b/src/nix/progress-bar.cc
index cd5a8fca26ee..2ad0994508fe 100644
--- a/src/nix/progress-bar.cc
+++ b/src/nix/progress-bar.cc
@@ -6,8 +6,6 @@
 #include <map>
 #include <atomic>
 
-#include <sys/ioctl.h>
-
 namespace nix {
 
 static std::string getS(const std::vector<Logger::Field> & fields, size_t n)
@@ -99,15 +97,10 @@ private:
 
     Sync<State> state_;
 
-    int width = 0;
-
 public:
 
     ProgressBar()
     {
-        struct winsize ws;
-        if (ioctl(1, TIOCGWINSZ, &ws) == 0)
-            width = ws.ws_col;
     }
 
     ~ProgressBar()
@@ -270,7 +263,7 @@ public:
             }
         }
 
-        writeToStderr("\r" + ansiTruncate(line, width) + "\e[K");
+        writeToStderr("\r" + ansiTruncate(line, getWindowSize().second) + "\e[K");
     }
 
     std::string getStatus(State & state)