here comes the big header include rewrite
[monky] / src / fs.c
index 136a035..dbdea8e 100644 (file)
--- a/src/fs.c
+++ b/src/fs.c
@@ -1,15 +1,34 @@
-/*
- * Conky, a system monitor, based on torsmo
+/* Conky, a system monitor, based on torsmo
  *
- * This program is licensed under BSD license, read COPYING
+ * Any original torsmo code is licensed under the BSD license
+ *
+ * All code written since the fork of torsmo is licensed under the GPL
+ *
+ * Please see COPYING for details
+ *
+ * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
+ * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
+ *     (see AUTHORS)
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
- *  $Id$
  */
 
 #include "conky.h"
+#include "logging.h"
+#include "fs.h"
 #include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/mount.h>
 #endif
 
-/* TODO: benchmark which is faster, fstatvfs() or pre-opened fd and
- * statvfs() (fstatvfs() would handle mounts I think...) */
+#if !defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && !defined (__OpenBSD__) && !defined(__FreeBSD__)
+#include <mntent.h>
+#endif
+
+#define MAX_FS_STATS 64
 
-static struct fs_stat fs_stats_[64];
+static struct fs_stat fs_stats_[MAX_FS_STATS];
 struct fs_stat *fs_stats = fs_stats_;
 
-void update_fs_stats()
+static void update_fs_stat(struct fs_stat *fs);
+
+void get_fs_type(const char *path, char *result);
+
+void update_fs_stats(void)
 {
-       unsigned int i;
-       struct statfs s;
-       for (i = 0; i < 16; i++) {
-               if (fs_stats[i].fd <= 0)
-                       break;
+       unsigned i;
 
-               fstatfs(fs_stats[i].fd, &s);
+       for (i = 0; i < MAX_FS_STATS; ++i) {
+               if (fs_stats[i].set) {
+                       update_fs_stat(&fs_stats[i]);
+               }
+       }
+}
 
-               fs_stats[i].size = (long long) s.f_blocks * s.f_bsize;
-               /* bfree (root) or bavail (non-roots) ? */
-               fs_stats[i].avail = (long long) s.f_bavail * s.f_bsize;
+void clear_fs_stats(void)
+{
+       unsigned i;
+       for (i = 0; i < MAX_FS_STATS; ++i) {
+               memset(&fs_stats[i], 0, sizeof(struct fs_stat));
        }
 }
 
-void clear_fs_stats()
+struct fs_stat *prepare_fs_stat(const char *s)
 {
-       unsigned int i;
-       for (i = 0; i < 16; i++) {
-               if (fs_stats[i].fd) {
-                       close(fs_stats[i].fd);
-                       fs_stats[i].fd = -1;
-               }
-               if (fs_stats[i].path != NULL) {
-                       free(fs_stats[i].path);
-                       fs_stats[i].path = NULL;
+       struct fs_stat *new = 0;
+       unsigned i;
+
+       /* lookup existing or get new */
+       for (i = 0; i < MAX_FS_STATS; ++i) {
+               if (fs_stats[i].set) {
+                       if (strncmp(fs_stats[i].path, s, DEFAULT_TEXT_BUFFER_SIZE) == 0) {
+                               return &fs_stats[i];
+                       }
+               } else {
+                       new = &fs_stats[i];
                }
        }
+       /* new path */
+       if (!new) {
+               ERR("too many fs stats");
+               return 0;
+       }
+       strncpy(new->path, s, DEFAULT_TEXT_BUFFER_SIZE);
+       new->set = 1;
+       update_fs_stat(new);
+       return new;
 }
 
-/*void clear_fs_stat(unsigned int i)
+static void update_fs_stat(struct fs_stat *fs)
 {
-       if (fs_stats[i].fd) {
-               close(fs_stats[i].fd);
-               fs_stats[i].fd = -1;
+       struct statfs s;
+
+       if (statfs(fs->path, &s) == 0) {
+               fs->size = (long long)s.f_blocks * s.f_bsize;
+               /* bfree (root) or bavail (non-roots) ? */
+               fs->avail = (long long)s.f_bavail * s.f_bsize;
+               fs->free = (long long)s.f_bfree * s.f_bsize;
+               get_fs_type(fs->path, fs->type);
+       } else {
+               fs->size = 0;
+               fs->avail = 0;
+               fs->free = 0;
+               strncpy(fs->type, "unknown", DEFAULT_TEXT_BUFFER_SIZE);
+               ERR("statfs '%s': %s", fs->path, strerror(errno));
        }
-       if (fs_stats[i].path != NULL) {
-               free(fs_stats[i].path);
-               fs_stats[i].path = NULL;
+}
+
+void get_fs_type(const char *path, char *result)
+{
+
+#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(__FreeBSD__) || defined (__OpenBSD__)
+
+       struct statfs s;
+       if (statfs(path, &s) == 0) {
+               strncpy(result, s.f_fstypename, DEFAULT_TEXT_BUFFER_SIZE);
+       } else {
+               ERR("statfs '%s': %s", path, strerror(errno));
        }
-}*/
+       return;
 
+#else                          /* HAVE_STRUCT_STATFS_F_FSTYPENAME */
 
-struct fs_stat *prepare_fs_stat(const char *s)
-{
-       unsigned int i;
-
-       for (i = 0; i < 16; i++) {
-               struct fs_stat *fs = &fs_stats[i];
-
-               if (fs->path && strcmp(fs->path, s) == 0)
-                       return fs;
-
-               if (fs->fd <= 0) {
-                       /* when compiled with icc, it crashes when leaving function and open()
-                        * is used, I don't know why 
-                        * fuck icc */
-
-                       /* this icc workaround didn't seem to work */
-#if 0
-                       {
-                               FILE *fp = fopen(s, "r");
-                               if (fp)
-                                       fs->fd = fileno(fp);
-                               else
-                                       fs->fd = -1;
-                       }
-#endif
+       struct mntent *me;
+       FILE *mtab = setmntent("/etc/mtab", "r");
+       char *search_path;
+       int match;
+       char *slash;
 
-                       fs->fd = open(s, O_RDONLY);
+       if (mtab == NULL) {
+               ERR("setmntent /etc/mtab: %s", strerror(errno));
+               strncpy(result, "unknown", DEFAULT_TEXT_BUFFER_SIZE);
+               return;
+       }
 
-                       if (fs->fd <= 0) {      /* 0 isn't error but actually it is :) */
-                               ERR("open '%s': %s", s, strerror(errno));
-                               return 0;
-                       }
+       me = getmntent(mtab);
 
-                       fs->path = strdup(s);
-                       update_fs_stats();
-                       return fs;
-               }
+       // find our path in the mtab
+       search_path = strdup(path);
+       do {
+               while ((match = strcmp(search_path, me->mnt_dir))
+                               && getmntent(mtab));
+               if (!match)
+                       break;
+               fseek(mtab, 0, SEEK_SET);
+               slash = strrchr(search_path, '/');
+               if (slash == NULL)
+                       CRIT_ERR("invalid path '%s'", path);
+               if (strlen(slash) == 1)         /* trailing slash */
+                       *(slash) = '\0';
+               else if (strlen(slash) > 1)
+                       *(slash + 1) = '\0';
+               else
+                       CRIT_ERR("found a crack in the matrix!");
+       } while (strlen(search_path) > 0);
+       free(search_path);
+
+       endmntent(mtab);
+
+       if (me && !match) {
+               strncpy(result, me->mnt_type, DEFAULT_TEXT_BUFFER_SIZE);
+               return;
        }
+#endif                         /* HAVE_STRUCT_STATFS_F_FSTYPENAME */
+
+       strncpy(result, "unknown", DEFAULT_TEXT_BUFFER_SIZE);
 
-       ERR("too many fs stats");
-       return 0;
 }