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