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