1 #include "uwsgi.h"
2 
3 extern struct uwsgi_server uwsgi;
4 
5 #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
6 #ifndef OBSOLETE_LINUX_KERNEL
7 #include <sys/inotify.h>
8 #endif
9 #endif
10 
fsmon_add(struct uwsgi_fsmon * fs)11 static int fsmon_add(struct uwsgi_fsmon *fs) {
12 #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
13 #ifndef OBSOLETE_LINUX_KERNEL
14 	static int inotify_fd = -1;
15 	if (inotify_fd == -1) {
16 		inotify_fd = inotify_init();
17 		if (inotify_fd < 0) {
18 			uwsgi_error("fsmon_add()/inotify_init()");
19 			return -1;
20 		}
21 		if (event_queue_add_fd_read(uwsgi.master_queue, inotify_fd)) {
22 			uwsgi_error("fsmon_add()/event_queue_add_fd_read()");
23 			return -1;
24 		}
25 	}
26 	int wd = inotify_add_watch(inotify_fd, fs->path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
27 	if (wd < 0) {
28 		uwsgi_error("fsmon_add()/inotify_add_watch()");
29 		return -1;
30 	}
31 	fs->fd = inotify_fd;
32 	fs->id = wd;
33 	return 0;
34 #endif
35 #endif
36 #ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
37 	struct kevent kev;
38 	int fd = open(fs->path, O_RDONLY);
39 	if (fd < 0) {
40 		uwsgi_error_open(fs->path);
41 		uwsgi_error("fsmon_add()/open()");
42 		return -1;
43 	}
44 
45 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
46 	if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
47 		uwsgi_error("fsmon_add()/kevent()");
48 		return -1;
49 	}
50 	fs->fd = fd;
51 	return 0;
52 #endif
53 	uwsgi_log("[uwsgi-fsmon] filesystem monitoring interface not available in this platform !!!\n");
54 	return 1;
55 }
56 
fsmon_reload(struct uwsgi_fsmon * fs)57 static void fsmon_reload(struct uwsgi_fsmon *fs) {
58 	uwsgi_block_signal(SIGHUP);
59 	grace_them_all(0);
60 	uwsgi_unblock_signal(SIGHUP);
61 }
62 
fsmon_brutal_reload(struct uwsgi_fsmon * fs)63 static void fsmon_brutal_reload(struct uwsgi_fsmon *fs) {
64 	if (uwsgi.die_on_term) {
65 		uwsgi_block_signal(SIGQUIT);
66 		reap_them_all(0);
67 		uwsgi_unblock_signal(SIGQUIT);
68 	}
69 	else {
70 		uwsgi_block_signal(SIGTERM);
71 		reap_them_all(0);
72 		uwsgi_unblock_signal(SIGTERM);
73 	}
74 }
75 
fsmon_signal(struct uwsgi_fsmon * fs)76 static void fsmon_signal(struct uwsgi_fsmon *fs) {
77 	uwsgi_route_signal(atoi((char *) fs->data));
78 }
79 
uwsgi_fsmon_setup()80 void uwsgi_fsmon_setup() {
81 	struct uwsgi_string_list *usl = NULL;
82 	uwsgi_foreach(usl, uwsgi.fs_reload) {
83 		uwsgi_register_fsmon(usl->value, fsmon_reload, NULL);
84 	}
85 	uwsgi_foreach(usl, uwsgi.fs_brutal_reload) {
86 		uwsgi_register_fsmon(usl->value, fsmon_brutal_reload, NULL);
87 	}
88 	uwsgi_foreach(usl, uwsgi.fs_signal) {
89 		char *copy = uwsgi_str(usl->value);
90 		char *space = strchr(copy, ' ');
91 		if (!space) {
92 			uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
93 			free(copy);
94 			continue;
95 		}
96 		*space = 0;
97 		uwsgi_register_fsmon(copy, fsmon_signal, space + 1);
98 	}
99 
100 	struct uwsgi_fsmon *fs = uwsgi.fsmon;
101 	while (fs) {
102 		if (fsmon_add(fs)) {
103 			uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", fs->path);
104 		}
105 		else {
106 			uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", fs->path);
107 		}
108 		fs = fs->next;
109 	}
110 }
111 
112 
uwsgi_register_fsmon(char * path,void (* func)(struct uwsgi_fsmon *),void * data)113 struct uwsgi_fsmon *uwsgi_register_fsmon(char *path, void (*func) (struct uwsgi_fsmon *), void *data) {
114 	struct uwsgi_fsmon *old_fs = NULL, *fs = uwsgi.fsmon;
115 	while(fs) {
116 		old_fs = fs;
117 		fs = fs->next;
118 	}
119 
120 	fs = uwsgi_calloc(sizeof(struct uwsgi_fsmon));
121 	fs->path = path;
122 	fs->func = func;
123 	fs->data = data;
124 
125 	if (old_fs) {
126 		old_fs->next = fs;
127 	}
128 	else {
129 		uwsgi.fsmon = fs;
130 	}
131 
132 	return fs;
133 }
134 
uwsgi_fsmon_ack(int interesting_fd)135 static struct uwsgi_fsmon *uwsgi_fsmon_ack(int interesting_fd) {
136 	struct uwsgi_fsmon *found_fs = NULL;
137 	struct uwsgi_fsmon *fs = uwsgi.fsmon;
138 	while (fs) {
139 		if (fs->fd == interesting_fd) {
140 			found_fs = fs;
141 			break;
142 		}
143 		fs = fs->next;
144 	}
145 
146 #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
147 #ifndef OBSOLETE_LINUX_KERNEL
148 	if (!found_fs)
149 		return NULL;
150 	found_fs = NULL;
151 	unsigned int isize = 0;
152 	if (ioctl(interesting_fd, FIONREAD, &isize) < 0) {
153 		uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
154 		return NULL;
155 	}
156 	if (isize == 0)
157 		return NULL;
158 	struct inotify_event *ie = uwsgi_malloc(isize);
159 	// read from the inotify descriptor
160 	ssize_t len = read(interesting_fd, ie, isize);
161 	if (len < 0) {
162 		free(ie);
163 		uwsgi_error("uwsgi_fsmon_ack()/read()");
164 		return NULL;
165 	}
166 	fs = uwsgi.fsmon;
167 	while (fs) {
168 		if (fs->fd == interesting_fd && fs->id == ie->wd) {
169 			found_fs = fs;
170 			break;
171 		}
172 		fs = fs->next;
173 	}
174 	free(ie);
175 #endif
176 #endif
177 	return found_fs;
178 }
179 
uwsgi_fsmon_event(int interesting_fd)180 int uwsgi_fsmon_event(int interesting_fd) {
181 
182 	struct uwsgi_fsmon *fs = uwsgi_fsmon_ack(interesting_fd);
183 	if (!fs)
184 		return 0;
185 
186 	uwsgi_log_verbose("[uwsgi-fsmon] detected event on \"%s\"\n", fs->path);
187 	fs->func(fs);
188 	return 1;
189 }
190