summaryrefslogtreecommitdiffstats
path: root/mtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'mtab.c')
-rw-r--r--mtab.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/mtab.c b/mtab.c
new file mode 100644
index 0000000..0311c50
--- /dev/null
+++ b/mtab.c
@@ -0,0 +1,174 @@
+/*********************************************************************
+ * bfs *
+ * Copyright (C) 2017 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This program is free software. It comes without any warranty, to *
+ * the extent permitted by applicable law. You can redistribute it *
+ * and/or modify it under the terms of the Do What The Fuck You Want *
+ * To Public License, Version 2, as published by Sam Hocevar. See *
+ * the COPYING file or http://www.wtfpl.net/ for more details. *
+ *********************************************************************/
+
+#include "mtab.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if __linux__
+# include <mntent.h>
+#elif BSD
+# include <sys/mount.h>
+# include <sys/ucred.h>
+#endif
+
+/**
+ * A mount point in the mount table.
+ */
+struct bfs_mtab_entry {
+ /** The device number for this mount point. */
+ dev_t dev;
+ /** The file system type of this mount point. */
+ char *type;
+};
+
+struct bfs_mtab {
+ /** The array of mtab entries. */
+ struct bfs_mtab_entry *table;
+ /** The size of the array. */
+ size_t size;
+ /** Capacity of the array. */
+ size_t capacity;
+};
+
+/**
+ * Add an entry to the mount table.
+ */
+static int bfs_mtab_push(struct bfs_mtab *mtab, dev_t dev, const char *type) {
+ size_t size = mtab->size + 1;
+
+ if (size >= mtab->capacity) {
+ size_t capacity = 2*size;
+ struct bfs_mtab_entry *table = realloc(mtab->table, capacity*sizeof(*table));
+ if (!table) {
+ return -1;
+ }
+ mtab->table = table;
+ mtab->capacity = capacity;
+ }
+
+ struct bfs_mtab_entry *entry = mtab->table + (size - 1);
+ entry->dev = dev;
+ entry->type = strdup(type);
+ if (!entry->type) {
+ return -1;
+ }
+
+ mtab->size = size;
+ return 0;
+}
+
+struct bfs_mtab *parse_bfs_mtab() {
+#if __linux__
+
+ FILE *file = setmntent("/etc/mtab", "r");
+ if (!file) {
+ goto fail;
+ }
+
+ struct bfs_mtab *mtab = malloc(sizeof(*mtab));
+ if (!mtab) {
+ goto fail_file;
+ }
+ mtab->table = NULL;
+ mtab->size = 0;
+ mtab->capacity = 0;
+
+ struct mntent *mnt;
+ while ((mnt = getmntent(file))) {
+ struct stat sb;
+ if (stat(mnt->mnt_dir, &sb) != 0) {
+ continue;
+ }
+
+ if (bfs_mtab_push(mtab, sb.st_dev, mnt->mnt_type) != 0) {
+ goto fail_mtab;
+ }
+ }
+
+ endmntent(file);
+ return mtab;
+
+fail_mtab:
+ free_bfs_mtab(mtab);
+fail_file:
+ endmntent(file);
+fail:
+ return NULL;
+
+#elif BSD
+
+ struct statfs *mntbuf;
+ int size = getmntinfo(&mntbuf, MNT_WAIT);
+ if (size < 0) {
+ return NULL;
+ }
+
+ struct bfs_mtab *mtab = malloc(sizeof(*mtab));
+ if (!mtab) {
+ goto fail;
+ }
+
+ mtab->size = 0;
+ mtab->table = malloc(size*sizeof(*mtab->table));
+ if (!mtab->table) {
+ goto fail_mtab;
+ }
+ mtab->capacity = size;
+
+ for (struct statfs *mnt = mntbuf; mnt < mntbuf + size; ++mnt) {
+ struct stat sb;
+ if (stat(mnt->f_mntonname, &sb) != 0) {
+ continue;
+ }
+
+ if (bfs_mtab_push(mtab, sb.st_dev, mnt->f_fstypename) != 0) {
+ goto fail_mtab;
+ }
+ }
+
+ return mtab;
+
+fail_mtab:
+ free_bfs_mtab(mtab);
+fail:
+ return NULL;
+
+#else
+
+ errno = ENOTSUP;
+ return NULL;
+#endif
+}
+
+const char *bfs_fstype(const struct bfs_mtab *mtab, const struct stat *statbuf) {
+ for (struct bfs_mtab_entry *mnt = mtab->table; mnt < mtab->table + mtab->size; ++mnt) {
+ if (statbuf->st_dev == mnt->dev) {
+ return mnt->type;
+ }
+ }
+
+ return "unknown";
+}
+
+void free_bfs_mtab(struct bfs_mtab *mtab) {
+ if (mtab) {
+ for (struct bfs_mtab_entry *mnt = mtab->table; mnt < mtab->table + mtab->size; ++mnt) {
+ free(mnt->type);
+ }
+ free(mtab->table);
+ free(mtab);
+ }
+}