diff options
Diffstat (limited to 'libmount/src')
-rw-r--r-- | libmount/src/context.c | 15 | ||||
-rw-r--r-- | libmount/src/context_umount.c | 85 | ||||
-rw-r--r-- | libmount/src/mountP.h | 8 | ||||
-rw-r--r-- | libmount/src/tab_parse.c | 62 | ||||
-rw-r--r-- | libmount/src/utils.c | 103 |
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 } }; |