Handle SIGWINCH

This commit is contained in:
Eelco Dolstra 2017-08-25 15:57:49 +02:00
parent ec9e0c03c3
commit db1d45037c
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
3 changed files with 39 additions and 8 deletions

View file

@ -17,6 +17,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <pwd.h> #include <pwd.h>
#include <sys/ioctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.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 Sync<std::list<std::function<void()>>> _interruptCallbacks;
static void signalHandlerThread(sigset_t set) static void signalHandlerThread(sigset_t set)
@ -1264,6 +1285,10 @@ static void signalHandlerThread(sigset_t set)
if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP) if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP)
triggerInterrupt(); triggerInterrupt();
else if (signal == SIGWINCH) {
updateWindowSize();
}
} }
} }
@ -1287,6 +1312,8 @@ static sigset_t savedSignalMask;
void startSignalHandlerThread() void startSignalHandlerThread()
{ {
updateWindowSize();
if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask)) if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
throw SysError("quering signal mask"); throw SysError("quering signal mask");
@ -1296,6 +1323,7 @@ void startSignalHandlerThread()
sigaddset(&set, SIGTERM); sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP); sigaddset(&set, SIGHUP);
sigaddset(&set, SIGPIPE); sigaddset(&set, SIGPIPE);
sigaddset(&set, SIGWINCH);
if (pthread_sigmask(SIG_BLOCK, &set, nullptr)) if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
throw SysError("blocking signals"); throw SysError("blocking signals");

View file

@ -349,6 +349,12 @@ bool hasSuffix(const string & s, const string & suffix);
std::string toLower(const std::string & s); 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 /* Exception handling in destructors: print an error message, then
ignore the exception. */ ignore the exception. */
void ignoreException(); 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();
} }

View file

@ -6,8 +6,6 @@
#include <map> #include <map>
#include <atomic> #include <atomic>
#include <sys/ioctl.h>
namespace nix { namespace nix {
static std::string getS(const std::vector<Logger::Field> & fields, size_t n) static std::string getS(const std::vector<Logger::Field> & fields, size_t n)
@ -99,15 +97,10 @@ private:
Sync<State> state_; Sync<State> state_;
int width = 0;
public: public:
ProgressBar() ProgressBar()
{ {
struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) == 0)
width = ws.ws_col;
} }
~ProgressBar() ~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) std::string getStatus(State & state)