aboutsummaryrefslogtreecommitdiff
path: root/vis.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2015-07-17 14:38:36 +0200
committerMarc André Tanner <mat@brain-dump.org>2015-07-19 14:12:43 +0200
commit0fa9885cda0778467ca5737ac888ece5ef371b3d (patch)
treefd3ab531ec8ab1e60b9ee9a782c2c38120202d7b /vis.c
parent8129933ca51caf788e0cd7c5fdbcb43fdc64601d (diff)
downloadvis-0fa9885cda0778467ca5737ac888ece5ef371b3d.tar.gz
vis-0fa9885cda0778467ca5737ac888ece5ef371b3d.tar.xz
vis: handle file truncation more gracefully
If we use the file / virtual memory system as cache (using mmap(2)) and another process truncates the file we are editing, we have a problem. All we can do is catch the resulting SIGBUS, close the corresponding window and print a warning message. To test this use: $ dd if=/dev/zero of=TEST bs=8M count=1 $ vis TEST :! echo TRUNCATE > TEST
Diffstat (limited to 'vis.c')
-rw-r--r--vis.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/vis.c b/vis.c
index 8e51bce..ffe45ce 100644
--- a/vis.c
+++ b/vis.c
@@ -2312,8 +2312,23 @@ static Key getkey(void) {
return key;
}
+static void sigbus_handler(int sig, siginfo_t *siginfo, void *context) {
+ for (File *file = vis->files; file; file = file->next) {
+ if (text_sigbus(file->text, siginfo->si_addr))
+ file->truncated = true;
+ }
+ vis->sigbus = true;
+ siglongjmp(vis->sigbus_jmpbuf, 1);
+}
+
static void mainloop() {
struct timespec idle = { .tv_nsec = 0 }, *timeout = NULL;
+ struct sigaction sa_sigbus;
+ memset(&sa_sigbus, 0, sizeof sa_sigbus);
+ sa_sigbus.sa_flags = SA_SIGINFO;
+ sa_sigbus.sa_sigaction = sigbus_handler;
+ if (sigaction(SIGBUS, &sa_sigbus, NULL))
+ die("sigaction: %s", strerror(errno));
sigset_t emptyset, blockset;
sigemptyset(&emptyset);
sigemptyset(&blockset);
@@ -2323,11 +2338,31 @@ static void mainloop() {
editor_draw(vis);
vis->running = true;
+ sigsetjmp(vis->sigbus_jmpbuf, 1);
+
while (vis->running) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
+ if (vis->sigbus) {
+ char *name = NULL;
+ for (Win *next, *win = vis->windows; win; win = next) {
+ next = win->next;
+ if (win->file->truncated) {
+ free(name);
+ name = strdup(win->file->name);
+ editor_window_close(win);
+ }
+ }
+ if (!vis->windows)
+ die("WARNING: file `%s' truncated!\n", name ? name : "-");
+ else
+ editor_info_show(vis, "WARNING: file `%s' truncated!\n", name ? name : "-");
+ vis->sigbus = false;
+ free(name);
+ }
+
editor_update(vis);
idle.tv_sec = vis->mode->idle_timeout;
int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset);