summaryrefslogtreecommitdiffstats
path: root/libmount
diff options
context:
space:
mode:
Diffstat (limited to 'libmount')
-rw-r--r--libmount/src/context.c15
-rw-r--r--libmount/src/context_umount.c85
-rw-r--r--libmount/src/mountP.h8
-rw-r--r--libmount/src/tab_parse.c62
-rw-r--r--libmount/src/utils.c103
5 files changed, 242 insertions, 31 deletions
diff --git a/libmount/src/context.c b/libmount/src/context.c
index 2ef3d3001..f1077968f 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -136,12 +136,14 @@ int mnt_reset_context(struct libmnt_context *cxt)
mnt_unref_fs(cxt->fs);
mnt_unref_table(cxt->mtab);
+ mnt_unref_table(cxt->utab);
free(cxt->helper);
free(cxt->orig_user);
cxt->fs = NULL;
cxt->mtab = NULL;
+ cxt->utab = NULL;
cxt->helper = NULL;
cxt->orig_user = NULL;
cxt->mountflags = 0;
@@ -158,7 +160,9 @@ int mnt_reset_context(struct libmnt_context *cxt)
}
mnt_context_reset_status(cxt);
- mnt_context_set_tabfilter(cxt, NULL, NULL);
+
+ if (cxt->table_fltrcb)
+ mnt_context_set_tabfilter(cxt, NULL, NULL);
/* restore non-resettable flags */
cxt->flags |= (fl & MNT_FL_NOMTAB);
@@ -980,7 +984,12 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
cxt->table_fltrcb_data);
mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
- rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
+ if (cxt->utab)
+ /* utab already parsed, don't parse it again */
+ rc = __mnt_table_parse_mtab(cxt->mtab,
+ cxt->mtab_path, cxt->utab);
+ else
+ rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
if (rc)
return rc;
}
@@ -1013,7 +1022,7 @@ int mnt_context_set_tabfilter(struct libmnt_context *cxt,
cxt->table_fltrcb,
cxt->table_fltrcb_data);
- DBG(CXT, mnt_debug_h(cxt, "tabfiler %s", fltr ? "ENABLED!" : "disabled"));
+ DBG(CXT, mnt_debug_h(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
return 0;
}
diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
index dc16852c0..2e22389f4 100644
--- a/libmount/src/context_umount.c
+++ b/libmount/src/context_umount.c
@@ -98,7 +98,6 @@ int mnt_context_find_umount_fs(struct libmnt_context *cxt,
struct stat st;
if (stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
- /* we'll canonicalize /proc/self/mountinfo */
cache = mnt_context_get_cache(cxt);
cn_tgt = mnt_resolve_path(tgt, cache);
if (cn_tgt)
@@ -190,14 +189,52 @@ err:
return rc;
}
+/* Check if there is something important in the utab file. The parsed utab is
+ * stored in context->utab and deallocated by mnt_free_context().
+ */
+static int has_utab_entry(struct libmnt_context *cxt, const char *target)
+{
+ struct libmnt_cache *cache = NULL;
+ struct libmnt_fs *fs;
+ struct libmnt_iter itr;
+ char *cn = NULL;
+
+ assert(cxt);
+
+ if (!cxt->utab) {
+ const char *path = mnt_get_utab_path();
+
+ if (!path || is_file_empty(path))
+ return 0;
+ cxt->utab = mnt_new_table();
+ if (!cxt->utab)
+ return 0;
+ cxt->utab->fmt = MNT_FMT_UTAB;
+ if (mnt_table_parse_file(cxt->utab, path))
+ return 0;
+ }
+
+ /* paths in utab are canonicalized */
+ cache = mnt_context_get_cache(cxt);
+ cn = mnt_resolve_path(target, cache);
+ mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
+
+ while (mnt_table_next_fs(cxt->utab, &itr, &fs) == 0) {
+ if (mnt_fs_streq_target(fs, cn))
+ return 1;
+ }
+ return 0;
+}
+
/* this is umount replacement to mnt_context_apply_fstab(), use
* mnt_context_tab_applied() to check result.
*/
static int lookup_umount_fs(struct libmnt_context *cxt)
{
const char *tgt;
+ struct stat st;
struct libmnt_fs *fs = NULL;
- int rc;
+ int rc = 0;
assert(cxt);
assert(cxt->fs);
@@ -208,9 +245,53 @@ static int lookup_umount_fs(struct libmnt_context *cxt)
return -EINVAL;
}
+ /*
+ * Let's try to avoid mountinfo usage at all to minimize performance
+ * degradation. Don't forget that kernel has to compose *whole*
+ * mountinfo about all mountpoints although we look for only one entry.
+ *
+ * All we need is fstype and to check if there is no userspace mount
+ * options for the target (e.g. helper=udisks to call /sbin/umount.udisks).
+ *
+ * So, let's use statfs() if possible (it's bad idea for --lazy/--force
+ * umounts as target is probably unreachable NFS).
+ */
+ if (!mnt_context_is_restricted(cxt)
+ && *tgt == '/'
+ && !(cxt->flags & MNT_FL_HELPER)
+ && !cxt->mtab_writable
+ && !mnt_context_is_force(cxt)
+ && !mnt_context_is_lazy(cxt)
+ && stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)
+ && !has_utab_entry(cxt, tgt)) {
+
+ const char *type = mnt_fs_get_fstype(cxt->fs);
+
+ /* !cxt->mtab_writable && has_utab_entry() verified that there
+ * is no stuff in utab, so disable all mtab/utab related actions */
+ mnt_context_disable_mtab(cxt, TRUE);
+
+ if (!type) {
+ struct statfs vfs;
+ if (statfs(tgt, &vfs) == 0)
+ type = mnt_statfs_get_fstype(&vfs);
+ if (type) {
+ rc = mnt_fs_set_fstype(cxt->fs, type);
+ if (rc)
+ return rc;
+ }
+ }
+ if (type) {
+ DBG(CXT, mnt_debug_h(cxt,
+ "umount: mountinfo unnecessary [type=%s]", type));
+ return 0;
+ }
+ }
+
rc = mnt_context_find_umount_fs(cxt, tgt, &fs);
if (rc < 0)
return rc;
+
if (rc == 1 || !fs) {
DBG(CXT, mnt_debug_h(cxt, "umount: cannot find '%s' in mtab", tgt));
return 0; /* this is correct! */
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index adc245af4..a580ae438 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -15,6 +15,7 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include "c.h"
@@ -142,6 +143,7 @@ extern char *stripoff_last_component(char *path);
extern int mnt_valid_tagname(const char *tagname);
extern int append_string(char **a, const char *b);
+extern const char *mnt_statfs_get_fstype(struct statfs *vfs);
extern int is_file_empty(const char *name);
extern int mkdir_p(const char *path, mode_t mode);
@@ -178,6 +180,11 @@ extern struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
struct libmnt_fs *fs,
unsigned long mountflags,
char **fsroot);
+extern int __mnt_table_parse_mtab(struct libmnt_table *tb,
+ const char *filename,
+ struct libmnt_table *u_tb);
+
+
/*
* Generic iterator
*/
@@ -327,6 +334,7 @@ struct libmnt_context
struct libmnt_table *fstab; /* fstab (or mtab for some remounts) entries */
struct libmnt_table *mtab; /* mtab entries */
+ struct libmnt_table *utab; /* rarely used by umount only */
int (*table_errcb)(struct libmnt_table *tb, /* callback for libmnt_table structs */
const char *filename, int line);
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index 81232736c..7c73cc553 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -1036,23 +1036,10 @@ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct
return fs;
}
-/**
- * mnt_table_parse_mtab:
- * @tb: table
- * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
- *
- * This function parses /etc/mtab or /proc/self/mountinfo +
- * /run/mount/utabs or /proc/mounts.
- *
- * See also mnt_table_set_parser_errcb().
- *
- * Returns: 0 on success or negative number in case of error.
- */
-int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
+int __mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename,
+ struct libmnt_table *u_tb)
{
- int rc;
- const char *utab = NULL;
- struct libmnt_table *u_tb;
+ int rc = 0, priv_utab = 0;
assert(tb);
@@ -1083,18 +1070,23 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
/*
* try to read the user specific information from /run/mount/utabs
*/
- utab = mnt_get_utab_path();
- if (!utab || is_file_empty(utab))
- return 0;
+ if (!u_tb) {
+ const char *utab = mnt_get_utab_path();
+ if (!utab || is_file_empty(utab))
+ return 0;
+
+ u_tb = mnt_new_table();
+ if (!u_tb)
+ return -ENOMEM;
- u_tb = mnt_new_table();
- if (!u_tb)
- return -ENOMEM;
+ u_tb->fmt = MNT_FMT_UTAB;
+ mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);
- u_tb->fmt = MNT_FMT_UTAB;
- mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);
+ rc = mnt_table_parse_file(u_tb, utab);
+ priv_utab = 1;
+ }
- if (mnt_table_parse_file(u_tb, utab) == 0) {
+ if (rc == 0) {
struct libmnt_fs *u_fs;
struct libmnt_iter itr;
@@ -1105,6 +1097,24 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
mnt_table_merge_user_fs(tb, u_fs);
}
- mnt_unref_table(u_tb);
+
+ if (priv_utab)
+ mnt_unref_table(u_tb);
return 0;
}
+/**
+ * mnt_table_parse_mtab:
+ * @tb: table
+ * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
+ *
+ * This function parses /etc/mtab or /proc/self/mountinfo +
+ * /run/mount/utabs or /proc/mounts.
+ *
+ * See also mnt_table_set_parser_errcb().
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
+{
+ return __mnt_table_parse_mtab(tb, filename, NULL);
+}
diff --git a/libmount/src/utils.c b/libmount/src/utils.c
index 4111b595b..6170752bc 100644
--- a/libmount/src/utils.c
+++ b/libmount/src/utils.c
@@ -15,6 +15,7 @@
#include <pwd.h>
#include <grp.h>
#include <blkid.h>
+#include <linux/magic.h>
#include "strutils.h"
#include "pathnames.h"
@@ -320,6 +321,92 @@ int mnt_fstype_is_netfs(const char *type)
return 0;
}
+#ifndef CIFS_SUPER_MAGIC
+# define CIFS_SUPER_MAGIC 0xFF534D42
+#endif
+#ifndef XFS_SUPER_MAGIC
+# define XFS_SUPER_MAGIC 0x58465342
+#endif
+#ifndef CGROUP_SUPER_MAGIC
+# define CGROUP_SUPER_MAGIC 0x1021994
+#endif
+#ifndef MQUEUE_SUPER_MAGIC
+# define MQUEUE_SUPER_MAGIC 0x19800202
+#endif
+#ifndef CONFIGFS_SUPER_MAGIC
+# define CONFIGFS_SUPER_MAGIC 0x62656570
+#endif
+
+const char *mnt_statfs_get_fstype(struct statfs *vfs)
+{
+ assert(vfs);
+
+ switch (vfs->f_type) {
+ case ADFS_SUPER_MAGIC: return "adfs";
+ case AFFS_SUPER_MAGIC: return "affs";
+ case AFS_SUPER_MAGIC: return "afs";
+ case AUTOFS_SUPER_MAGIC: return "autofs";
+ case CIFS_SUPER_MAGIC: return "cifs";
+ case CODA_SUPER_MAGIC: return "coda";
+ case CRAMFS_MAGIC: return "cramfs";
+ case DEBUGFS_MAGIC: return "debugfs";
+ case SECURITYFS_MAGIC: return "securityfs";
+ case SELINUX_MAGIC: return "selinuxfs";
+ case SMACK_MAGIC: return "smackfs";
+ case RAMFS_MAGIC: return "ramfs";
+ case TMPFS_MAGIC: return "tmpfs";
+ case HUGETLBFS_MAGIC: return "hugetlbfs";
+ case SQUASHFS_MAGIC: return "squashfs";
+ case ECRYPTFS_SUPER_MAGIC: return "ecryptfs";
+ case EFS_SUPER_MAGIC: return "efs";
+ case EXT4_SUPER_MAGIC: return "ext4";
+ case BTRFS_SUPER_MAGIC: return "btrfs";
+ case NILFS_SUPER_MAGIC: return "nilfs2";
+ case F2FS_SUPER_MAGIC: return "f2fs";
+ case HPFS_SUPER_MAGIC: return "hpfs";
+ case ISOFS_SUPER_MAGIC: return "iso9660";
+ case JFFS2_SUPER_MAGIC: return "jffs";
+ case EFIVARFS_MAGIC: return "efivarfs";
+ case HOSTFS_SUPER_MAGIC: return "hostfs";
+
+ case MINIX_SUPER_MAGIC:
+ case MINIX_SUPER_MAGIC2:
+ case MINIX2_SUPER_MAGIC: return "minix";
+
+ case MSDOS_SUPER_MAGIC: return "vfat";
+ case NCP_SUPER_MAGIC: return "ncp";
+ case NFS_SUPER_MAGIC: return "nfs";
+ case OPENPROM_SUPER_MAGIC: return "openprom";
+ case PROC_SUPER_MAGIC: return "proc";
+ case SOCKFS_MAGIC: return "sockfs";
+ case SYSFS_MAGIC: return "sysfs";
+ case USBDEVICE_SUPER_MAGIC: return "usbdevice";
+ case CGROUP_SUPER_MAGIC: return "cgroup";
+ case PSTOREFS_MAGIC: return "pstore";
+ case BINFMTFS_MAGIC: return "binfmt_misc";
+ case XENFS_SUPER_MAGIC: return "xenfs";
+
+ case QNX4_SUPER_MAGIC: return "qnx4";
+ case QNX6_SUPER_MAGIC: return "qnx4";
+ case REISERFS_SUPER_MAGIC: return "reiser4";
+ case SMB_SUPER_MAGIC: return "smb";
+
+ case DEVPTS_SUPER_MAGIC: return "devpts";
+ case FUTEXFS_SUPER_MAGIC: return "futexfs";
+ case PIPEFS_MAGIC: return "pipefs";
+ case MQUEUE_SUPER_MAGIC: return "mqueue";
+ case CONFIGFS_SUPER_MAGIC: return "configfs";
+
+ case BTRFS_TEST_MAGIC: return "btrfs";
+ case XFS_SUPER_MAGIC: return "xfs";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+
/**
* mnt_match_fstype:
* @type: filesystem type
@@ -1195,6 +1282,21 @@ int test_mkdir(struct libmnt_test *ts, int argc, char *argv[])
return rc;
}
+int test_statfs_type(struct libmnt_test *ts, int argc, char *argv[])
+{
+ struct statfs vfs;
+ int rc;
+
+ rc = statfs(argv[1], &vfs);
+ if (rc)
+ printf("%s: statfs failed: %m\n", argv[1]);
+ else
+ printf("%-30s: statfs type: %-12s [0x%lx]\n", argv[1],
+ mnt_statfs_get_fstype(&vfs),
+ (long) vfs.f_type);
+ return rc;
+}
+
int main(int argc, char *argv[])
{
@@ -1210,6 +1312,7 @@ int main(int argc, char *argv[])
{ "--cd-parent", test_chdir, "<path>" },
{ "--kernel-cmdline",test_kernel_cmdline, "<option> | <option>=" },
{ "--mkdir", test_mkdir, "<path>" },
+ { "--statfs-type", test_statfs_type, "<path>" },
{ NULL }
};