int probe_sb_extra; /* extra BLKID_SUBLKS_* flags */
bool noprobe; /* disable libblkid device probing */
+ const struct ul_vfs_ops *vfs; /* borrowed VFS ops (not owned) */
+
/* blkid_evaluate_tag() works in two ways:
*
* 1/ all tags are evaluated by udev /dev/disk/by-* symlinks,
cache->noprobe = !!enable;
}
+/**
+ * mnt_cache_refer_vfs:
+ * @cache: cache pointer
+ * @vfs: VFS operations or NULL
+ *
+ * Set reference to VFS I/O operations. The cache does not own the @vfs
+ * pointer -- the caller is responsible for its lifetime (e.g. the mount
+ * context owns it).
+ *
+ * The VFS is used for blkid device probing (see mnt_cache_read_tags()).
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_cache_refer_vfs(struct libmnt_cache *cache, const struct ul_vfs_ops *vfs)
+{
+ if (!cache)
+ return -EINVAL;
+ cache->vfs = vfs;
+ return 0;
+}
+
/* note that the @key could be the same pointer as @value */
static int cache_add_entry(struct libmnt_cache *cache, char *key,
char *value, int flag)
DBG_OBJ(CACHE, cache, ul_debug("%s: reading from blkid", devname));
- pr = blkid_new_probe_from_filename(devname);
+ pr = blkid_new_probe();
if (!pr)
return -EINVAL;
+ if (cache->vfs)
+ blkid_probe_set_vfs(pr, cache->vfs);
+ if (blkid_probe_open_device(pr, devname, 0)) {
+ blkid_free_probe(pr);
+ return -errno;
+ }
+
blkid_probe_enable_superblocks(pr, 1);
blkid_probe_set_superblocks_flags(pr,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
return val;
}
-static char *fstype_from_blkid(const char *devname, int *ambi)
+static char *fstype_from_blkid(const char *devname, int *ambi,
+ const struct ul_vfs_ops *vfs)
{
blkid_probe pr;
const char *data;
char *type = NULL;
int rc;
- pr = blkid_new_probe_from_filename(devname);
+ pr = blkid_new_probe();
if (!pr)
return NULL;
+ if (vfs)
+ blkid_probe_set_vfs(pr, vfs);
+ if (blkid_probe_open_device(pr, devname, 0)) {
+ blkid_free_probe(pr);
+ return NULL;
+ }
blkid_probe_enable_superblocks(pr, 1);
blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
if (cache)
return fstype_from_cache(devname, cache);
- return fstype_from_blkid(devname, ambi);
+ return fstype_from_blkid(devname, ambi, NULL);
}
static char *canonicalize_path_and_cache(const char *path,
free(cxt->optstr_pattern);
free(cxt->tgt_prefix);
+ if (cxt->vfs) {
+ mnt_table_refer_vfs(cxt->fstab, NULL);
+ mnt_table_refer_vfs(cxt->mountinfo, NULL);
+ mnt_cache_refer_vfs(cxt->cache, NULL);
+ free(cxt->vfs);
+ }
mnt_unref_table(cxt->fstab);
mnt_unref_cache(cxt->cache);
mnt_unref_fs(cxt->fs);
return -MNT_ERR_NAMESPACE;
mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
+ if (cxt->vfs)
+ mnt_table_refer_vfs(cxt->fstab, cxt->vfs);
rc = mnt_table_parse_fstab(cxt->fstab, NULL);
if (!mnt_context_switch_ns(cxt, ns_old))
cxt->table_fltrcb_data);
mnt_table_set_cache(cxt->mountinfo, mnt_context_get_cache(cxt));
+ if (cxt->vfs)
+ mnt_table_refer_vfs(cxt->mountinfo, cxt->vfs);
}
/* Read the table; it's empty, because this first mnt_context_get_mountinfo()
if (cxt->table_errcb)
mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
+ if (cxt->vfs)
+ mnt_table_refer_vfs(*tb, cxt->vfs);
ns_old = mnt_context_switch_target_ns(cxt);
if (!ns_old)
return 0;
}
+/**
+ * mnt_context_set_vfs:
+ * @cxt: mount context
+ * @ops: VFS operations or NULL
+ *
+ * Set pluggable VFS I/O operations. The library stores a private copy of @ops.
+ * If @ops is NULL, the VFS is reset to defaults (standard libc I/O).
+ *
+ * The VFS is automatically propagated to the cache (see mnt_cache_refer_vfs())
+ * and to the tables (see mnt_table_refer_vfs()) when they are created or set.
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_set_vfs(struct libmnt_context *cxt, const struct ul_vfs_ops *ops)
+{
+ if (!cxt)
+ return -EINVAL;
+
+ if (!ops) {
+ free(cxt->vfs);
+ cxt->vfs = NULL;
+ return 0;
+ }
+ if (!cxt->vfs) {
+ cxt->vfs = calloc(1, sizeof(*cxt->vfs));
+ if (!cxt->vfs)
+ return -ENOMEM;
+ }
+ ul_vfs_init(cxt->vfs, ops);
+
+ if (cxt->cache)
+ mnt_cache_refer_vfs(cxt->cache, cxt->vfs);
+ if (cxt->fstab)
+ mnt_table_refer_vfs(cxt->fstab, cxt->vfs);
+ if (cxt->mountinfo)
+ mnt_table_refer_vfs(cxt->mountinfo, cxt->vfs);
+ return 0;
+}
+
/**
* mnt_context_set_cache:
* @cxt: mount context
cxt->cache = cache;
+ if (cache && cxt->vfs)
+ mnt_cache_refer_vfs(cache, cxt->vfs);
if (cxt->mountinfo)
mnt_table_set_cache(cxt->mountinfo, cache);
if (cxt->fstab)
*/
struct libmnt_statmnt;
+#ifndef UL_VFS_OPS_DEFINED
+#define UL_VFS_OPS_DEFINED
+
+struct ul_vfs_ops {
+ size_t size;
+
+ ssize_t (*vfs_read)(int fd, void *buf, size_t count);
+ ssize_t (*vfs_write)(int fd, const void *buf, size_t count);
+ int (*vfs_open)(const char *pathname, int flags, mode_t mode);
+ int (*vfs_close)(int fd);
+ off_t (*vfs_lseek)(int fd, off_t offset, int whence);
+ int (*vfs_fsync)(int fd);
+
+ FILE *(*vfs_fopen)(const char *pathname, const char *mode);
+};
+
+#endif /* UL_VFS_OPS_DEFINED */
+
/*
* Actions
*/
extern int mnt_cache_set_targets(struct libmnt_cache *cache,
struct libmnt_table *mountinfo);
extern int mnt_cache_set_sbprobe(struct libmnt_cache *cache, int flags);
+extern int mnt_cache_refer_vfs(struct libmnt_cache *cache, const struct ul_vfs_ops *vfs);
extern int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname);
extern int mnt_cache_device_has_tag(struct libmnt_cache *cache,
extern int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm);
extern int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc);
+extern int mnt_table_refer_vfs(struct libmnt_table *tb, const struct ul_vfs_ops *vfs);
extern struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb);
extern int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs);
extern int mnt_table_find_fs(struct libmnt_table *tb, struct libmnt_fs *fs);
extern int mnt_context_get_table(struct libmnt_context *cxt,
const char *filename,
struct libmnt_table **tb);
+extern int mnt_context_set_vfs(struct libmnt_context *cxt,
+ const struct ul_vfs_ops *ops);
extern int mnt_context_set_cache(struct libmnt_context *cxt,
struct libmnt_cache *cache);
extern struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt);
mnt_table_disable_useropts;
mnt_table_parse_utab;
} MOUNT_2_42;
+
+MOUNT_2_44 {
+ mnt_cache_refer_vfs;
+ mnt_context_set_vfs;
+ mnt_table_refer_vfs;
+} MOUNT_2_43;
#include "list.h"
#include "debug.h"
#include "buffer.h"
+#include "vfs.h"
#include "libmount.h"
#include "mountutils.h"
char *comm_tail; /* Last comment in file */
struct libmnt_cache *cache; /* canonicalized paths/tags cache */
+ const struct ul_vfs_ops *vfs; /* borrowed VFS ops (not owned) */
int (*errcb)(struct libmnt_table *tb,
const char *filename, int line);
const void *mountdata; /* final mount(2) data, string or binary data */
struct libmnt_cache *cache; /* paths cache */
+ struct ul_vfs_ops *vfs; /* pluggable I/O ops (owned, or NULL) */
struct libmnt_lock *lock; /* utab lock */
struct libmnt_update *update; /* utab update */
return 0;
}
+/**
+ * mnt_table_refer_vfs:
+ * @tb: pointer to tab
+ * @vfs: VFS operations or NULL
+ *
+ * Set reference to VFS I/O operations. The table does not own the @vfs
+ * pointer -- the caller is responsible for its lifetime.
+ *
+ * The VFS is used for table parsing (see mnt_table_parse_file()).
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_refer_vfs(struct libmnt_table *tb, const struct ul_vfs_ops *vfs)
+{
+ if (!tb)
+ return -EINVAL;
+ tb->vfs = vfs;
+ return 0;
+}
+
/**
* mnt_table_get_cache:
* @tb: pointer to tab
if (!filename || !tb)
return -EINVAL;
- f = fopen(filename, "r" UL_CLOEXECSTR);
+ f = ul_vfs_fopen(tb->vfs, filename, "r" UL_CLOEXECSTR);
if (f) {
rc = mnt_table_parse_stream(tb, f, filename);
fclose(f);