1 #include "server_config.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <glib.h>
10 #ifdef __FreeBSD__
11 #include <sys/param.h>
12 #include <sys/ucred.h>
13 #include <sys/mount.h>
14 #endif
15 #include "gam_error.h"
16 #include "gam_fs.h"
17
18 #define DEFAULT_POLL_TIMEOUT 0
19
20 typedef struct _gam_fs_properties {
21 char * fsname;
22 gam_fs_mon_type mon_type;
23 int poll_timeout;
24 } gam_fs_properties;
25
26 typedef struct _gam_fs {
27 char *path;
28 char *fsname;
29 guint64 flags;
30 } gam_fs;
31
32 static gboolean initialized = FALSE;
33 #ifdef __FreeBSD__
34 static gboolean initializing = FALSE;
35 #endif
36 static GList *filesystems = NULL;
37 static GList *fs_props = NULL;
38 static struct stat mtab_sbuf;
39
40 static void
gam_fs_free_filesystems(void)41 gam_fs_free_filesystems (void)
42 {
43 GList *iterator = NULL;
44 gam_fs *fs = NULL;
45
46 iterator = filesystems;
47
48 while (iterator)
49 {
50 fs = iterator->data;
51
52 iterator = g_list_next (iterator);
53
54 filesystems = g_list_remove (filesystems, fs);
55
56 g_free (fs->path);
57 g_free (fs->fsname);
58 g_free (fs);
59 }
60 }
61
62
63 static const gam_fs *
gam_fs_find_fs(const char * path)64 gam_fs_find_fs (const char *path)
65 {
66 GList *iterator = NULL;
67 gam_fs *fs = NULL;
68
69 gam_fs_init ();
70
71 iterator = filesystems;
72
73 while (iterator)
74 {
75 fs = iterator->data;
76
77 if (g_str_has_prefix (path, fs->path)) {
78 return fs;
79 }
80 iterator = g_list_next (iterator);
81 }
82
83 return NULL;
84 }
85
86 static const gam_fs_properties *
gam_fs_find_fs_props(const char * path)87 gam_fs_find_fs_props (const char *path)
88 {
89 const gam_fs *fs = NULL;
90 gam_fs_properties *props = NULL;
91 GList *iterator = NULL;
92
93 fs = gam_fs_find_fs (path);
94 if (!fs)
95 return NULL;
96
97 iterator = fs_props;
98
99 while (iterator)
100 {
101 props = iterator->data;
102
103 if (!strcmp (props->fsname, fs->fsname)) {
104 return props;
105 }
106 iterator = g_list_next (iterator);
107 }
108
109 return NULL;
110 }
111
112
113 static gint
gam_fs_filesystem_sort_cb(gconstpointer a,gconstpointer b)114 gam_fs_filesystem_sort_cb (gconstpointer a, gconstpointer b)
115 {
116 const gam_fs *fsa = a;
117 const gam_fs *fsb = b;
118
119 return strlen(fsb->path) - strlen (fsa->path);
120 }
121
122 #ifdef __linux__
123 static void
gam_fs_scan_mtab(void)124 gam_fs_scan_mtab (void)
125 {
126 gchar *contents, **lines, *line, **words;
127 gsize len;
128 GList *new_filesystems = NULL;
129 gam_fs *fs = NULL;
130 int i;
131
132 g_file_get_contents ("/etc/mtab", &contents, &len, NULL);
133 if (contents == NULL)
134 return;
135
136 lines = g_strsplit (contents, "\n", 0);
137 if (lines != NULL)
138 {
139 for (i = 0; lines[i] != NULL; i++)
140 {
141 line = lines[i];
142
143 if (line[0] == '\0')
144 continue;
145
146 words = g_strsplit (line, " ", 0);
147
148 if (words == NULL)
149 continue;
150
151 if (words[0] == NULL || words[1] == NULL || words[2] == NULL)
152 {
153 g_strfreev (words);
154 continue;
155 }
156 if (words[1][0] == '\0' || words[2][0] == '\0')
157 {
158 g_strfreev (words);
159 continue;
160 }
161
162 fs = g_new0 (gam_fs, 1);
163 fs->path = g_strdup (words[1]);
164 fs->fsname = g_strdup (words[2]);
165
166 g_strfreev (words);
167
168 new_filesystems = g_list_prepend (new_filesystems, fs);
169 }
170 g_strfreev (lines);
171 }
172 g_free (contents);
173
174 /* Replace the old file systems list with the new one */
175 gam_fs_free_filesystems ();
176 filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb);
177 }
178 #endif
179
180 #ifdef __FreeBSD__
181 static void
gam_fs_getmntinfo(void)182 gam_fs_getmntinfo (void)
183 {
184 struct statfs *stat;
185 GList *new_filesystems = NULL;
186 gam_fs *fs = NULL;
187 int i, n;
188
189 n = getmntinfo(&stat, MNT_NOWAIT);
190 if (n == -1)
191 return;
192
193 for (i = 0; i < n; i++)
194 {
195 fs = g_new0 (gam_fs, 1);
196 fs->path = g_strdup (stat[i].f_mntonname);
197 fs->fsname = g_strdup (stat[i].f_fstypename);
198 fs->flags = stat[i].f_flags;
199
200 new_filesystems = g_list_prepend (new_filesystems, fs);
201 }
202
203 /* Replace the old file systems list with the new one */
204 gam_fs_free_filesystems ();
205 filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb);
206 }
207 #endif
208
209 void
gam_fs_init(void)210 gam_fs_init (void)
211 {
212 #if defined(__linux__)
213 if (initialized == FALSE)
214 {
215 initialized = TRUE;
216 gam_fs_set ("ext3", GFS_MT_DEFAULT, 0);
217 gam_fs_set ("ext2", GFS_MT_DEFAULT, 0);
218 gam_fs_set ("reiser4", GFS_MT_DEFAULT, 0);
219 gam_fs_set ("reiserfs", GFS_MT_DEFAULT, 0);
220 gam_fs_set ("novfs", GFS_MT_POLL, 30);
221 gam_fs_set ("nfs", GFS_MT_POLL, 5);
222 if (stat("/etc/mtab", &mtab_sbuf) != 0)
223 {
224 GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
225 return;
226 }
227 gam_fs_scan_mtab ();
228 } else {
229 struct stat sbuf;
230
231 if (stat("/etc/mtab", &sbuf) != 0)
232 {
233 GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
234 return;
235 }
236
237 /* /etc/mtab has changed */
238 if (sbuf.st_mtime != mtab_sbuf.st_mtime) {
239 GAM_DEBUG(DEBUG_INFO, "Updating list of mounted filesystems\n");
240 gam_fs_scan_mtab ();
241 }
242
243 mtab_sbuf = sbuf;
244 }
245 #elif defined(__FreeBSD__)
246 if (initialized == FALSE && initializing == FALSE)
247 {
248 GList *iterator = NULL;
249 GHashTable *fs_hash = NULL;
250 gam_fs *fs = NULL;
251
252 initialized = TRUE;
253 initializing = TRUE;
254
255 gam_fs_getmntinfo ();
256
257 iterator = filesystems;
258 fs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
259
260 while (iterator) {
261 fs = iterator->data;
262
263 if (!g_hash_table_lookup (fs_hash, fs->fsname)) {
264 if (fs->flags & MNT_LOCAL)
265 gam_fs_set (fs->fsname, GFS_MT_DEFAULT, 0);
266 else
267 gam_fs_set (fs->fsname, GFS_MT_POLL, 5);
268
269 g_hash_table_insert (fs_hash, g_strdup (fs->fsname), GINT_TO_POINTER (1));
270 }
271
272 iterator = g_list_next (iterator);
273 }
274
275 g_hash_table_destroy (fs_hash);
276 initializing = FALSE;
277 } else if (initializing == FALSE) {
278 struct stat sbuf;
279
280 if (stat ("/etc/fstab", &sbuf) != 0) {
281 GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/fstab\n");
282 return;
283 }
284
285 if (sbuf.st_mtime != mtab_sbuf.st_mtime) {
286 GAM_DEBUG(DEBUG_INFO, "Updating list of mounted filesystems\n");
287 gam_fs_getmntinfo ();
288 }
289
290 mtab_sbuf = sbuf;
291 }
292 #endif
293 }
294
295 gam_fs_mon_type
gam_fs_get_mon_type(const char * path)296 gam_fs_get_mon_type (const char *path)
297 {
298 const gam_fs_properties *props = NULL;
299 gam_fs_init ();
300
301 props = gam_fs_find_fs_props (path);
302
303 if (!props)
304 #ifdef USE_GAMIN_POLLER
305 return GFS_MT_POLL;
306 #else
307 return GFS_MT_DEFAULT;
308 #endif
309
310 return props->mon_type;
311 }
312
313 int
gam_fs_get_poll_timeout(const char * path)314 gam_fs_get_poll_timeout (const char *path)
315 {
316 const gam_fs_properties *props = NULL;
317 gam_fs_init ();
318
319 props = gam_fs_find_fs_props (path);
320
321 if (!props)
322 return DEFAULT_POLL_TIMEOUT;
323
324 return props->poll_timeout;
325 }
326
327 void
gam_fs_set(const char * fsname,gam_fs_mon_type type,int poll_timeout)328 gam_fs_set (const char *fsname, gam_fs_mon_type type, int poll_timeout)
329 {
330 GList *iterator = NULL;
331 gam_fs_properties *prop = NULL;
332
333 gam_fs_init ();
334 iterator = fs_props;
335
336 while (iterator)
337 {
338 prop = iterator->data;
339
340 if (!strcmp (prop->fsname, fsname)) {
341 prop->mon_type = type;
342 if (poll_timeout >= 0)
343 prop->poll_timeout = poll_timeout;
344 return;
345 }
346
347 iterator = g_list_next (iterator);
348 }
349
350 prop = g_new0(gam_fs_properties, 1);
351
352 prop->fsname = g_strdup (fsname);
353 prop->mon_type = type;
354 if (poll_timeout >= 0)
355 prop->poll_timeout = poll_timeout;
356 else
357 prop->poll_timeout = DEFAULT_POLL_TIMEOUT;
358
359 fs_props = g_list_prepend (fs_props, prop);
360 }
361
362 void
gam_fs_unset(const char * fsname)363 gam_fs_unset (const char *fsname)
364 {
365 GList *iterator = NULL;
366 gam_fs_properties *prop = NULL;
367
368 gam_fs_init ();
369
370 iterator = fs_props;
371
372 while (iterator)
373 {
374 prop = iterator->data;
375
376 if (!strcmp (prop->fsname, fsname)) {
377 fs_props = g_list_remove (fs_props, prop);
378 g_free (prop->fsname);
379 g_free (prop);
380 return;
381 }
382 iterator = g_list_next (iterator);
383 }
384 }
385
386 void
gam_fs_debug(void)387 gam_fs_debug (void)
388 {
389 GList *iterator = NULL;
390 gam_fs_properties *prop = NULL;
391 gam_fs *fs = NULL;
392
393 gam_fs_init ();
394
395 iterator = filesystems;
396
397 GAM_DEBUG (DEBUG_INFO, "Dumping mounted file systems\n");
398 while (iterator)
399 {
400 fs = iterator->data;
401 GAM_DEBUG (DEBUG_INFO, "%s filesystem mounted at %s\n", fs->fsname, fs->path);
402 iterator = g_list_next (iterator);
403 }
404
405 iterator = fs_props;
406 GAM_DEBUG (DEBUG_INFO, "Dumping file system properties\n");
407 while (iterator)
408 {
409 prop = iterator->data;
410 GAM_DEBUG (DEBUG_INFO, "fstype %s monitor %s poll timeout %d\n", prop->fsname, (prop->mon_type == GFS_MT_KERNEL) ? "kernel" : (prop->mon_type == GFS_MT_POLL) ? "poll" : "none", prop->poll_timeout);
411 iterator = g_list_next (iterator);
412 }
413 }
414