#include "server_config.h" #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #include #include #endif #include "gam_error.h" #include "gam_fs.h" #define DEFAULT_POLL_TIMEOUT 0 typedef struct _gam_fs_properties { char * fsname; gam_fs_mon_type mon_type; int poll_timeout; } gam_fs_properties; typedef struct _gam_fs { char *path; char *fsname; guint64 flags; } gam_fs; static gboolean initialized = FALSE; #ifdef __FreeBSD__ static gboolean initializing = FALSE; #endif static GList *filesystems = NULL; static GList *fs_props = NULL; static struct stat mtab_sbuf; static void gam_fs_free_filesystems (void) { GList *iterator = NULL; gam_fs *fs = NULL; iterator = filesystems; while (iterator) { fs = iterator->data; filesystems = g_list_remove (filesystems, fs); g_free (fs->path); g_free (fs->fsname); g_free (fs); iterator = g_list_next (filesystems); } } static const gam_fs * gam_fs_find_fs (const char *path) { GList *iterator = NULL; gam_fs *fs = NULL; gam_fs_init (); iterator = filesystems; while (iterator) { fs = iterator->data; if (g_str_has_prefix (path, fs->path)) { return fs; } iterator = g_list_next (iterator); } return NULL; } static const gam_fs_properties * gam_fs_find_fs_props (const char *path) { const gam_fs *fs = NULL; gam_fs_properties *props = NULL; GList *iterator = NULL; fs = gam_fs_find_fs (path); if (!fs) return NULL; iterator = fs_props; while (iterator) { props = iterator->data; if (!strcmp (props->fsname, fs->fsname)) { return props; } iterator = g_list_next (iterator); } return NULL; } static gint gam_fs_filesystem_sort_cb (gconstpointer a, gconstpointer b) { const gam_fs *fsa = a; const gam_fs *fsb = b; return strlen(fsb->path) - strlen (fsa->path); } #ifdef __linux__ static void gam_fs_scan_mtab (void) { gchar *contents, **lines, *line, **words; gsize len; GList *new_filesystems = NULL; gam_fs *fs = NULL; int i; g_file_get_contents ("/etc/mtab", &contents, &len, NULL); if (contents == NULL) return; lines = g_strsplit (contents, "\n", 0); if (lines != NULL) { for (i = 0; lines[i] != NULL; i++) { line = lines[i]; if (line[0] == '\0') continue; words = g_strsplit (line, " ", 0); if (words == NULL) continue; if (words[0] == NULL || words[1] == NULL || words[2] == NULL) { g_strfreev (words); continue; } if (words[1][0] == '\0' || words[2][0] == '\0') { g_strfreev (words); continue; } fs = g_new0 (gam_fs, 1); fs->path = g_strdup (words[1]); fs->fsname = g_strdup (words[2]); g_strfreev (words); new_filesystems = g_list_prepend (new_filesystems, fs); } g_strfreev (lines); } g_free (contents); /* Replace the old file systems list with the new one */ gam_fs_free_filesystems (); filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb); } #endif #ifdef __FreeBSD__ static void gam_fs_getmntinfo (void) { struct statfs *stat; GList *new_filesystems = NULL; gam_fs *fs = NULL; int i, n; n = getmntinfo(&stat, MNT_NOWAIT); if (n == -1) return; for (i = 0; i < n; i++) { fs = g_new0 (gam_fs, 1); fs->path = g_strdup (stat[i].f_mntonname); fs->fsname = g_strdup (stat[i].f_fstypename); fs->flags = stat[i].f_flags; new_filesystems = g_list_prepend (new_filesystems, fs); } /* Replace the old file systems list with the new one */ gam_fs_free_filesystems (); filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb); } #endif void gam_fs_init (void) { #if defined(__linux__) if (initialized == FALSE) { initialized = TRUE; gam_fs_set ("ext3", GFS_MT_DEFAULT, 0); gam_fs_set ("ext2", GFS_MT_DEFAULT, 0); gam_fs_set ("reiser4", GFS_MT_DEFAULT, 0); gam_fs_set ("reiserfs", GFS_MT_DEFAULT, 0); gam_fs_set ("novfs", GFS_MT_POLL, 30); gam_fs_set ("nfs", GFS_MT_POLL, 5); if (stat("/etc/mtab", &mtab_sbuf) != 0) { GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n"); return; } gam_fs_scan_mtab (); } else { struct stat sbuf; if (stat("/etc/mtab", &sbuf) != 0) { GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n"); return; } /* /etc/mtab has changed */ if (sbuf.st_mtime != mtab_sbuf.st_mtime) { GAM_DEBUG(DEBUG_INFO, "Updating list of mounted filesystems\n"); gam_fs_scan_mtab (); } mtab_sbuf = sbuf; } #elif defined(__FreeBSD__) if (initialized == FALSE && initializing == FALSE) { GList *iterator = NULL; GHashTable *fs_hash = NULL; gam_fs *fs = NULL; initialized = TRUE; initializing = TRUE; gam_fs_getmntinfo (); iterator = filesystems; fs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); while (iterator) { fs = iterator->data; if (!g_hash_table_lookup (fs_hash, fs->fsname)) { if (fs->flags & MNT_LOCAL) gam_fs_set (fs->fsname, GFS_MT_DEFAULT, 0); else gam_fs_set (fs->fsname, GFS_MT_POLL, 5); g_hash_table_insert (fs_hash, g_strdup (fs->fsname), GINT_TO_POINTER (1)); } iterator = g_list_next (iterator); } g_hash_table_destroy (fs_hash); initializing = FALSE; } else if (initializing == FALSE) { struct stat sbuf; if (stat ("/etc/fstab", &sbuf) != 0) { GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/fstab\n"); return; } if (sbuf.st_mtime != mtab_sbuf.st_mtime) { GAM_DEBUG(DEBUG_INFO, "Updating list of mounted filesystems\n"); gam_fs_getmntinfo (); } mtab_sbuf = sbuf; } #endif } gam_fs_mon_type gam_fs_get_mon_type (const char *path) { const gam_fs_properties *props = NULL; gam_fs_init (); props = gam_fs_find_fs_props (path); if (!props) #ifdef USE_GAMIN_POLLER return GFS_MT_POLL; #else return GFS_MT_DEFAULT; #endif return props->mon_type; } int gam_fs_get_poll_timeout (const char *path) { const gam_fs_properties *props = NULL; gam_fs_init (); props = gam_fs_find_fs_props (path); if (!props) return DEFAULT_POLL_TIMEOUT; return props->poll_timeout; } void gam_fs_set (const char *fsname, gam_fs_mon_type type, int poll_timeout) { GList *iterator = NULL; gam_fs_properties *prop = NULL; gam_fs_init (); iterator = fs_props; while (iterator) { prop = iterator->data; if (!strcmp (prop->fsname, fsname)) { prop->mon_type = type; if (poll_timeout >= 0) prop->poll_timeout = poll_timeout; return; } iterator = g_list_next (iterator); } prop = g_new0(gam_fs_properties, 1); prop->fsname = g_strdup (fsname); prop->mon_type = type; if (poll_timeout >= 0) prop->poll_timeout = poll_timeout; else prop->poll_timeout = DEFAULT_POLL_TIMEOUT; fs_props = g_list_prepend (fs_props, prop); } void gam_fs_unset (const char *fsname) { GList *iterator = NULL; gam_fs_properties *prop = NULL; gam_fs_init (); iterator = fs_props; while (iterator) { prop = iterator->data; if (!strcmp (prop->fsname, fsname)) { fs_props = g_list_remove (fs_props, prop); g_free (prop->fsname); g_free (prop); return; } iterator = g_list_next (iterator); } } void gam_fs_debug (void) { GList *iterator = NULL; gam_fs_properties *prop = NULL; gam_fs *fs = NULL; gam_fs_init (); iterator = filesystems; GAM_DEBUG (DEBUG_INFO, "Dumping mounted file systems\n"); while (iterator) { fs = iterator->data; GAM_DEBUG (DEBUG_INFO, "%s filesystem mounted at %s\n", fs->fsname, fs->path); iterator = g_list_next (iterator); } iterator = fs_props; GAM_DEBUG (DEBUG_INFO, "Dumping file system properties\n"); while (iterator) { prop = iterator->data; 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); iterator = g_list_next (iterator); } }