dotfiles

personal configuration files and scripts
git clone https://tongong.net/git/dotfiles.git
Log | Files | Refs | README

autoreload_inotify.c (2710B)


      1 /* Copyright 2017 Max Voit, Bert Muennich
      2  *
      3  * This file is part of sxiv.
      4  *
      5  * sxiv is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published
      7  * by the Free Software Foundation; either version 2 of the License,
      8  * or (at your option) any later version.
      9  *
     10  * sxiv is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with sxiv.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "sxiv.h"
     20 
     21 #include <errno.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <sys/inotify.h>
     26 
     27 void arl_init(arl_t *arl)
     28 {
     29 	arl->fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
     30 	arl->wd_dir = arl->wd_file = -1;
     31 	if (arl->fd == -1)
     32 		error(0, 0, "Could not initialize inotify, no automatic image reloading");
     33 }
     34 
     35 CLEANUP void arl_cleanup(arl_t *arl)
     36 {
     37 	if (arl->fd != -1)
     38 		close(arl->fd);
     39 	free(arl->filename);
     40 }
     41 
     42 static void rm_watch(int fd, int *wd)
     43 {
     44 	if (*wd != -1) {
     45 		inotify_rm_watch(fd, *wd);
     46 		*wd = -1;
     47 	}
     48 }
     49 
     50 static void add_watch(int fd, int *wd, const char *path, uint32_t mask)
     51 {
     52 	*wd = inotify_add_watch(fd, path, mask);
     53 	if (*wd == -1)
     54 		error(0, errno, "inotify: %s", path);
     55 }
     56 
     57 void arl_setup(arl_t *arl, const char *filepath)
     58 {
     59 	char *base = strrchr(filepath, '/');
     60 
     61 	if (arl->fd == -1)
     62 		return;
     63 
     64 	rm_watch(arl->fd, &arl->wd_dir);
     65 	rm_watch(arl->fd, &arl->wd_file);
     66 
     67 	add_watch(arl->fd, &arl->wd_file, filepath, IN_CLOSE_WRITE | IN_DELETE_SELF);
     68 
     69 	free(arl->filename);
     70 	arl->filename = estrdup(filepath);
     71 
     72 	if (base != NULL) {
     73 		arl->filename[++base - filepath] = '\0';
     74 		add_watch(arl->fd, &arl->wd_dir, arl->filename, IN_CREATE | IN_MOVED_TO);
     75 		strcpy(arl->filename, base);
     76 	}
     77 }
     78 
     79 union {
     80 	char d[4096]; /* aligned buffer */
     81 	struct inotify_event e;
     82 } buf;
     83 
     84 bool arl_handle(arl_t *arl)
     85 {
     86 	bool reload = false;
     87 	char *ptr;
     88 	const struct inotify_event *e;
     89 
     90 	for (;;) {
     91 		ssize_t len = read(arl->fd, buf.d, sizeof(buf.d));
     92 
     93 		if (len == -1) {
     94 			if (errno == EINTR)
     95 				continue;
     96 			break;
     97 		}
     98 		for (ptr = buf.d; ptr < buf.d + len; ptr += sizeof(*e) + e->len) {
     99 			e = (const struct inotify_event*) ptr;
    100 			if (e->wd == arl->wd_file && (e->mask & IN_CLOSE_WRITE)) {
    101 				reload = true;
    102 			} else if (e->wd == arl->wd_file && (e->mask & IN_DELETE_SELF)) {
    103 				rm_watch(arl->fd, &arl->wd_file);
    104 			} else if (e->wd == arl->wd_dir && (e->mask & (IN_CREATE | IN_MOVED_TO))) {
    105 				if (STREQ(e->name, arl->filename))
    106 					reload = true;
    107 			}
    108 		}
    109 	}
    110 	return reload;
    111 }
    112