summaryrefslogtreecommitdiff
path: root/libmount/src
diff options
context:
space:
mode:
Diffstat (limited to 'libmount/src')
-rw-r--r--libmount/src/Makemodule.am7
-rw-r--r--libmount/src/cache.c89
-rw-r--r--libmount/src/context.c266
-rw-r--r--libmount/src/context_loopdev.c39
-rw-r--r--libmount/src/context_mount.c130
-rw-r--r--libmount/src/context_umount.c61
-rw-r--r--libmount/src/fs.c222
-rw-r--r--libmount/src/init.c14
-rw-r--r--libmount/src/iter.c10
-rw-r--r--libmount/src/libmount.h.in42
-rw-r--r--libmount/src/libmount.sym35
-rw-r--r--libmount/src/lock.c36
-rw-r--r--libmount/src/mountP.h34
-rw-r--r--libmount/src/optmap.c9
-rw-r--r--libmount/src/optstr.c112
-rw-r--r--libmount/src/tab.c538
-rw-r--r--libmount/src/tab_diff.c25
-rw-r--r--libmount/src/tab_parse.c160
-rw-r--r--libmount/src/tab_update.c178
-rw-r--r--libmount/src/utils.c146
-rw-r--r--libmount/src/version.c6
21 files changed, 1564 insertions, 595 deletions
diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am
index 494e02a34..9101811f5 100644
--- a/libmount/src/Makemodule.am
+++ b/libmount/src/Makemodule.am
@@ -26,23 +26,26 @@ libmount_la_SOURCES = \
libmount/src/test.c \
libmount/src/utils.c \
libmount/src/version.c \
- $(mountinc_HEADERS)
+ $(nodist_mountinc_HEADERS)
nodist_libmount_la_SOURCES = libmount/src/mountP.h
libmount_la_LIBADD = libcommon.la libblkid.la $(SELINUX_LIBS)
libmount_la_CFLAGS = \
+ $(SOLIB_CFLAGS) \
-I$(ul_libblkid_incdir) \
-I$(ul_libmount_incdir) \
-I$(top_srcdir)/libmount/src
libmount_la_DEPENDENCIES = \
- $(libmount_la_LIBADD) \
+ libcommon.la \
+ libblkid.la \
libmount/src/libmount.sym \
libmount/src/libmount.h.in
libmount_la_LDFLAGS = \
+ $(SOLIB_LDFLAGS) \
-Wl,--version-script=$(top_srcdir)/libmount/src/libmount.sym \
-version-info $(LIBMOUNT_VERSION_INFO)
diff --git a/libmount/src/cache.c b/libmount/src/cache.c
index 7b651228a..92f469456 100644
--- a/libmount/src/cache.c
+++ b/libmount/src/cache.c
@@ -10,7 +10,7 @@
* @title: Cache
* @short_description: paths and tags (UUID/LABEL) caching
*
- * The cache is a very simple API for work with tags (LABEL, UUID, ...) and
+ * The cache is a very simple API for working with tags (LABEL, UUID, ...) and
* paths. The cache uses libblkid as a backend for TAGs resolution.
*
* All returned paths are always canonicalized.
@@ -48,6 +48,7 @@ struct libmnt_cache {
struct mnt_cache_entry *ents;
size_t nents;
size_t nallocs;
+ int refcount;
/* blkid_evaluate_tag() works in two ways:
*
@@ -72,6 +73,7 @@ struct libmnt_cache *mnt_new_cache(void)
if (!cache)
return NULL;
DBG(CACHE, mnt_debug_h(cache, "alloc"));
+ cache->refcount = 1;
return cache;
}
@@ -79,7 +81,8 @@ struct libmnt_cache *mnt_new_cache(void)
* mnt_free_cache:
* @cache: pointer to struct libmnt_cache instance
*
- * Deallocates the cache.
+ * Deallocates the cache. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_cache().
*/
void mnt_free_cache(struct libmnt_cache *cache)
{
@@ -89,6 +92,7 @@ void mnt_free_cache(struct libmnt_cache *cache)
return;
DBG(CACHE, mnt_debug_h(cache, "free"));
+ WARN_REFCOUNT(CACHE, cache, cache->refcount);
for (i = 0; i < cache->nents; i++) {
struct mnt_cache_entry *e = &cache->ents[i];
@@ -102,7 +106,39 @@ void mnt_free_cache(struct libmnt_cache *cache)
free(cache);
}
-/* note that the @key could be tha same pointer as @value */
+/**
+ * mnt_ref_cache:
+ * @cache: cache pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_cache(struct libmnt_cache *cache)
+{
+ if (cache) {
+ cache->refcount++;
+ /*DBG(CACHE, mnt_debug_h(cache, "ref=%d", cache->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_cache:
+ * @cache: cache pointer
+ *
+ * De-increments reference counter, on zero the cache is automatically
+ * deallocated by mnt_free_cache().
+ */
+void mnt_unref_cache(struct libmnt_cache *cache)
+{
+ if (cache) {
+ cache->refcount--;
+ /*DBG(CACHE, mnt_debug_h(cache, "unref=%d", cache->refcount));*/
+ if (cache->refcount <= 0)
+ mnt_free_cache(cache);
+ }
+}
+
+
+/* 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)
{
@@ -135,7 +171,7 @@ static int cache_add_entry(struct libmnt_cache *cache, char *key,
return 0;
}
-/* add tag to the cache, @devname has to be allocated string */
+/* add tag to the cache, @devname has to be an allocated string */
static int cache_add_tag(struct libmnt_cache *cache, const char *tagname,
const char *tagval, char *devname, int flag)
{
@@ -270,13 +306,13 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname)
DBG(CACHE, mnt_debug_h(cache, "tags for %s requested", devname));
- /* check is device is already cached */
+ /* check if device is already cached */
for (i = 0; i < cache->nents; i++) {
struct mnt_cache_entry *e = &cache->ents[i];
if (!(e->flag & MNT_CACHE_TAGREAD))
continue;
if (strcmp(e->value, devname) == 0)
- /* tags has been already read */
+ /* tags have already been read */
return 0;
}
@@ -335,7 +371,7 @@ error:
* @token: tag name (e.g "LABEL")
* @value: tag value
*
- * Look up @cache to check it @tag+@value are associated with @devname.
+ * Look up @cache to check if @tag+@value are associated with @devname.
*
* Returns: 1 on success or 0.
*/
@@ -421,7 +457,7 @@ char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache)
rc = blkid_do_safeprobe(pr);
- DBG(CACHE, mnt_debug_h(cache, "liblkid rc=%d", rc));
+ DBG(CACHE, mnt_debug_h(cache, "libblkid rc=%d", rc));
if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL))
type = strdup(data);
@@ -493,7 +529,7 @@ error:
* - /dev/loopN to the loop backing filename
* - empty path (NULL) to 'none'
*
- * Returns: new allocated string with path, result has to be always deallocated
+ * Returns: newly allocated string with path, result always has to be deallocated
* by free().
*/
char *mnt_pretty_path(const char *path, struct libmnt_cache *cache)
@@ -583,22 +619,18 @@ error:
char *mnt_resolve_spec(const char *spec, struct libmnt_cache *cache)
{
char *cn = NULL;
+ char *t = NULL, *v = NULL;
if (!spec)
return NULL;
- if (strchr(spec, '=')) {
- char *tag, *val;
-
- if (!blkid_parse_tag_string(spec, &tag, &val)) {
- cn = mnt_resolve_tag(tag, val, cache);
-
- free(tag);
- free(val);
- }
- } else
+ if (blkid_parse_tag_string(spec, &t, &v) == 0 && mnt_valid_tagname(t))
+ cn = mnt_resolve_tag(t, v, cache);
+ else
cn = mnt_resolve_path(spec, cache);
+ free(t);
+ free(v);
return cn;
}
@@ -624,7 +656,7 @@ int test_resolve_path(struct libmnt_test *ts, int argc, char *argv[])
p = mnt_resolve_path(line, cache);
printf("%s : %s\n", line, p);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
@@ -647,7 +679,7 @@ int test_resolve_spec(struct libmnt_test *ts, int argc, char *argv[])
p = mnt_resolve_spec(line, cache);
printf("%s : %s\n", line, p);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
@@ -663,6 +695,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
while(fgets(line, sizeof(line), stdin)) {
size_t sz = strlen(line);
+ char *t = NULL, *v = NULL;
if (sz > 0 && line[sz - 1] == '\n')
line[sz - 1] = '\0';
@@ -674,16 +707,14 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
if (mnt_cache_read_tags(cache, line) < 0)
fprintf(stderr, "%s: read tags failed\n", line);
- } else if (strchr(line, '=')) {
- char *tag, *val;
+ } else if (blkid_parse_tag_string(line, &t, &v) == 0) {
const char *cn = NULL;
- if (!blkid_parse_tag_string(line, &tag, &val)) {
- cn = cache_find_tag(cache, tag, val);
+ if (mnt_valid_tagname(t))
+ cn = cache_find_tag(cache, t, v);
+ free(t);
+ free(v);
- free(tag);
- free(val);
- }
if (cn)
printf("%s: %s\n", line, cn);
else
@@ -700,7 +731,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
e->key + strlen(e->key) + 1);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
diff --git a/libmount/src/context.c b/libmount/src/context.c
index af16f6472..8dca3c12a 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -89,10 +89,8 @@ void mnt_free_context(struct libmnt_context *cxt)
free(cxt->fstype_pattern);
free(cxt->optstr_pattern);
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
+ mnt_unref_table(cxt->fstab);
+ mnt_unref_cache(cxt->cache);
mnt_context_clear_loopdev(cxt);
mnt_free_lock(cxt->lock);
@@ -108,11 +106,11 @@ void mnt_free_context(struct libmnt_context *cxt)
* mnt_reset_context:
* @cxt: mount context
*
- * Resets all information in the context that are directly related to
- * the latest mount (spec, source, target, mount options, ....)
+ * Resets all information in the context that is directly related to
+ * the latest mount (spec, source, target, mount options, ...).
*
- * The match patters, cached fstab, cached canonicalized paths and tags and
- * [e]uid are not reseted. You have to use
+ * The match patterns, cached fstab, cached canonicalized paths and tags and
+ * [e]uid are not reset. You have to use
*
* mnt_context_set_fstab(cxt, NULL);
* mnt_context_set_cache(cxt, NULL);
@@ -120,7 +118,7 @@ void mnt_free_context(struct libmnt_context *cxt)
* mnt_context_set_options_pattern(cxt, NULL);
*
*
- * to reset these stuff.
+ * to reset this stuff.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -136,10 +134,8 @@ int mnt_reset_context(struct libmnt_context *cxt)
fl = cxt->flags;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
-
- mnt_free_table(cxt->mtab);
+ mnt_unref_fs(cxt->fs);
+ mnt_unref_table(cxt->mtab);
free(cxt->helper);
free(cxt->orig_user);
@@ -164,9 +160,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
mnt_context_reset_status(cxt);
mnt_context_set_tabfilter(cxt, NULL, NULL);
- /* restore non-resetable flags */
- cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB);
- cxt->flags |= (fl & MNT_FL_EXTERN_CACHE);
+ /* restore non-resettable flags */
cxt->flags |= (fl & MNT_FL_NOMTAB);
cxt->flags |= (fl & MNT_FL_FAKE);
cxt->flags |= (fl & MNT_FL_SLOPPY);
@@ -225,7 +219,7 @@ static int set_flag(struct libmnt_context *cxt, int flag, int enable)
* mnt_context_is_restricted:
* @cxt: mount context
*
- * Returns: 0 for unrestricted mount (user is root), or 1 for non-root mounts
+ * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
*/
int mnt_context_is_restricted(struct libmnt_context *cxt)
{
@@ -235,9 +229,9 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
/**
* mnt_context_set_optsmode
* @cxt: mount context
- * @mode: MNT_OMASK_* flags
+ * @mode: MNT_OMODE_* flags
*
- * Controls how to use mount optionsmsource and target paths from fstab/mtab.
+ * Controls how to use mount optionssource and target paths from fstab/mtab.
*
* @MNT_OMODE_IGNORE: ignore mtab/fstab options
*
@@ -247,7 +241,7 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
*
* @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
*
- * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target is defined)
+ * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
*
* @MNT_OMODE_FSTAB: read from fstab
*
@@ -262,8 +256,8 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
* Notes:
*
* - MNT_OMODE_USER is always used if mount context is in restricted mode
- * - MNT_OMODE_AUTO is used if nothing other is defined
- * - the flags are eavaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
+ * - MNT_OMODE_AUTO is used if nothing else is defined
+ * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
* MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
* are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
*
@@ -282,7 +276,7 @@ int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
* mnt_context_get_optsmode
* @cxt: mount context
*
- * Returns: MNT_OMASK_* mask or zero.
+ * Returns: MNT_OMODE_* mask or zero.
*/
int mnt_context_get_optsmode(struct libmnt_context *cxt)
@@ -297,12 +291,12 @@ int mnt_context_get_optsmode(struct libmnt_context *cxt)
* @disable: TRUE or FALSE
*
* Enable/disable paths canonicalization and tags evaluation. The libmount context
- * canonicalies paths when search in fstab and when prepare source and target paths
+ * canonicalizes paths when searching in fstab and when preparing source and target paths
* for mount(2) syscall.
*
- * This fuction has effect to the private (within context) fstab instance only
+ * This fuction has an effect on the private (within context) fstab instance only
* (see mnt_context_set_fstab()). If you want to use an external fstab then you
- * need manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
+ * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
* NULL).
*
* Returns: 0 on success, negative number in case of error.
@@ -316,7 +310,7 @@ int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
* mnt_context_is_nocanonicalize:
* @cxt: mount context
*
- * Returns: 1 if no-canonicalize mode enabled or 0.
+ * Returns: 1 if no-canonicalize mode is enabled or 0.
*/
int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
{
@@ -389,10 +383,13 @@ int mnt_context_is_parent(struct libmnt_context *cxt)
* mnt_context_is_child:
* @cxt: mount context
*
- * Return: 1 if mount -F enabled and the current context is child, or 0
+ * Return: 1 f the current context is child, or 0
*/
int mnt_context_is_child(struct libmnt_context *cxt)
{
+ /* See mnt_fork_context(), the for fork flag is always disabled
+ * for children to avoid recursive forking.
+ */
return !mnt_context_is_fork(cxt) && cxt->pid;
}
@@ -415,7 +412,7 @@ int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
* mnt_context_is_rdonly_umount
* @cxt: mount context
*
- * See also mnt_context_enable_rdonly_umount() and see umount(8) man page,
+ * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
* option -r.
*
* Returns: 1 if read-only remount failed umount(2) is enables or 0
@@ -607,7 +604,7 @@ int mnt_context_is_verbose(struct libmnt_context *cxt)
* @cxt: mount context
* @enable: TRUE or FALSE
*
- * Enable/disable loop delete (destroy) after umount (see umount(8), option -d)
+ * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -633,12 +630,13 @@ int mnt_context_is_loopdel(struct libmnt_context *cxt)
* @fs: filesystem description
*
* The mount context uses private @fs by default. This function allows to
- * overwrite the private @fs with an external instance. Note that the external
- * @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
+ * overwrite the private @fs with an external instance. This function
+ * increments @fs reference counter (and deincrement reference counter of the
+ * old fs).
*
* The @fs will be modified by mnt_context_set_{source,target,options,fstype}
- * functions, If the @fs is NULL then all current FS specific setting (source,
- * target, etc., exclude spec) is reseted.
+ * functions, If the @fs is NULL, then all current FS specific settings (source,
+ * target, etc., exclude spec) are reset.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -646,10 +644,9 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
- set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
+ mnt_ref_fs(fs); /* new */
+ mnt_unref_fs(cxt->fs); /* old */
cxt->fs = fs;
return 0;
}
@@ -662,25 +659,64 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
* Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
* functions.
*
- * Returns: pointer to FS description or NULL in case of calloc() errrr.
+ * Returns: pointer to FS description or NULL in case of a calloc() error.
*/
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
{
assert(cxt);
if (!cxt)
return NULL;
- if (!cxt->fs) {
+ if (!cxt->fs)
cxt->fs = mnt_new_fs();
- cxt->flags &= ~MNT_FL_EXTERN_FS;
- }
return cxt->fs;
}
/**
+ * mnt_context_get_fs_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
+}
+
+/**
+ * mnt_context_get_fstab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
+}
+
+/**
+ * mnt_context_get_mtab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
+}
+
+/**
* mnt_context_set_source:
* @cxt: mount context
* @source: mount source (device, directory, UUID, LABEL, ...)
*
+ * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
+ * mount option. The real return code is always returned, when
+ * the device does not exist then it's usually MNT_ERR_NOSOURCE
+ * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
+ *
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
@@ -693,7 +729,7 @@ int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
* mnt_context_get_source:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_source(struct libmnt_context *cxt)
{
@@ -718,7 +754,7 @@ int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
* mnt_context_get_target:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_target(struct libmnt_context *cxt)
{
@@ -731,8 +767,8 @@ const char *mnt_context_get_target(struct libmnt_context *cxt)
* @cxt: mount context
* @fstype: filesystem type
*
- * Note that the @fstype has to be the real FS type. For patterns with
- * comma-separated list of filesystems or for "nofs" notation use
+ * Note that the @fstype has to be a FS type. For patterns with
+ * comma-separated list of filesystems or for the "nofs" notation, use
* mnt_context_set_fstype_pattern().
*
* Returns: 0 on success, negative number in case of error.
@@ -747,7 +783,7 @@ int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
* mnt_context_get_fstype:
* @cxt: mount context
*
- * Returns: pointer or NULL in case of error pr if not set.
+ * Returns: pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
{
@@ -788,8 +824,8 @@ int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
* This function returns mount options set by mnt_context_set_options() or
* mnt_context_append_options().
*
- * Note that *after* mnt_context_prepare_mount() may the mount options string
- * also includes options set by mnt_context_set_mflags() or another options
+ * Note that *after* mnt_context_prepare_mount(), the mount options string
+ * may also include options set by mnt_context_set_mflags() or other options
* generated by this library.
*
* Returns: pointer or NULL
@@ -857,15 +893,19 @@ int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *patt
* @cxt: mount context
* @tb: fstab
*
- * The mount context reads /etc/fstab to the the private struct libmnt_table by default.
+ * The mount context reads /etc/fstab to the private struct libmnt_table by default.
* This function allows to overwrite the private fstab with an external
- * instance. Note that the external instance is not deallocated by mnt_free_context().
+ * instance.
+ *
+ * This function modify the @tb reference counter. This function does not set
+ * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
+ * mnt_context_get_cache(cxt));
*
* The fstab is used read-only and is not modified, it should be possible to
- * share the fstab between more mount contexts (TODO: tests it.)
+ * share the fstab between more mount contexts (TODO: test it.)
*
- * If the @tb argument is NULL then the current private fstab instance is
- * reseted.
+ * If the @tb argument is NULL, then the current private fstab instance is
+ * reset.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -874,10 +914,10 @@ int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
assert(cxt);
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
+ mnt_ref_table(tb); /* new */
+ mnt_unref_table(cxt->fstab); /* old */
+
cxt->fstab = tb;
return 0;
}
@@ -893,8 +933,6 @@ int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
*/
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
assert(cxt);
if (!cxt)
return -EINVAL;
@@ -906,18 +944,12 @@ int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
return -ENOMEM;
if (cxt->table_errcb)
mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
- cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
+ mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
rc = mnt_table_parse_fstab(cxt->fstab, NULL);
if (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
-
- /* never touch an external fstab */
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_table_set_cache(cxt->fstab, cache);
-
if (tb)
*tb = cxt->fstab;
return 0;
@@ -929,14 +961,12 @@ int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
* @tb: returns mtab
*
* See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
- * result will deallocated by mnt_free_context(@cxt).
+ * result will be deallocated by mnt_free_context(@cxt).
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
assert(cxt);
if (!cxt)
return -EINVAL;
@@ -954,14 +984,12 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
cxt->table_fltrcb,
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 (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
- mnt_table_set_cache(cxt->mtab, cache);
-
if (tb)
*tb = cxt->mtab;
@@ -971,8 +999,8 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
}
/*
- * Allows to specify filter for tab file entries. The filter is called by
- * table parser. Currently used for mtab and utab only.
+ * Allows to specify a filter for tab file entries. The filter is called by
+ * the table parser. Currently used for mtab and utab only.
*/
int mnt_context_set_tabfilter(struct libmnt_context *cxt,
int (*fltr)(struct libmnt_fs *, void *),
@@ -1004,7 +1032,7 @@ int mnt_context_set_tabfilter(struct libmnt_context *cxt,
* callback and cache for tags and paths is set according to the @cxt setting.
* See also mnt_table_parse_file().
*
- * It's strongly recommended use mnt_context_get_mtab() and
+ * It's strongly recommended to use the mnt_context_get_mtab() and
* mnt_context_get_fstab() functions for mtab and fstab files. This function
* does not care about LIBMOUNT_* env.variables and does not merge userspace
* options.
@@ -1016,7 +1044,6 @@ int mnt_context_set_tabfilter(struct libmnt_context *cxt,
int mnt_context_get_table(struct libmnt_context *cxt,
const char *filename, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
int rc;
assert(cxt);
@@ -1033,14 +1060,11 @@ int mnt_context_get_table(struct libmnt_context *cxt,
rc = mnt_table_parse_file(*tb, filename);
if (rc) {
- mnt_free_table(*tb);
+ mnt_unref_table(*tb);
return rc;
}
- cache = mnt_context_get_cache(cxt);
- if (cache)
- mnt_table_set_cache(*tb, cache);
-
+ mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
return 0;
}
@@ -1065,6 +1089,11 @@ int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
if (!cxt)
return -EINVAL;
+ if (cxt->mtab)
+ mnt_table_set_parser_errcb(cxt->mtab, cb);
+ if (cxt->fstab)
+ mnt_table_set_parser_errcb(cxt->fstab, cb);
+
cxt->table_errcb = cb;
return 0;
}
@@ -1074,12 +1103,15 @@ int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
* @cxt: mount context
* @cache: cache instance or nULL
*
- * The mount context maintains a private struct libmnt_cache by default. This function
- * allows to overwrite the private cache with an external instance. Note that
- * the external instance is not deallocated by mnt_free_context().
+ * The mount context maintains a private struct libmnt_cache by default. This
+ * function allows to overwrite the private cache with an external instance.
+ * This function increments cache reference counter.
*
- * If the @cache argument is NULL then the current private cache instance is
- * reseted.
+ * If the @cache argument is NULL, then the current cache instance is reset.
+ * This function apply the cache to fstab and mtab instances (if already
+ * exists).
+ *
+ * The old cache instance reference counter is de-incremented.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1087,11 +1119,17 @@ int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
- set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
+ mnt_ref_cache(cache); /* new */
+ mnt_unref_cache(cxt->cache); /* old */
+
cxt->cache = cache;
+
+ if (cxt->mtab)
+ mnt_table_set_cache(cxt->mtab, cache);
+ if (cxt->fstab)
+ mnt_table_set_cache(cxt->fstab, cache);
+
return 0;
}
@@ -1110,10 +1148,9 @@ struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
return NULL;
if (!cxt->cache) {
- cxt->cache = mnt_new_cache();
- if (!cxt->cache)
- return NULL;
- cxt->flags &= ~MNT_FL_EXTERN_CACHE;
+ struct libmnt_cache *cache = mnt_new_cache();
+ mnt_context_set_cache(cxt, cache);
+ mnt_unref_cache(cache);
}
return cxt->cache;
}
@@ -1125,7 +1162,7 @@ struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
* @release: callback to release (delallocate) password
*
* Sets callbacks for encryption password (e.g encrypted loopdev). This
- * function is deprecated (encrypted loops are no ore supported).
+ * function is deprecated (encrypted loops are no longer supported).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1151,7 +1188,7 @@ int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
*
* The default behavior is to ignore all signals (except SIGALRM and
* SIGTRAP for mtab udate) when the lock is locked. If this behavior
- * is unacceptable then use:
+ * is unacceptable, then use:
*
* lc = mnt_context_get_lock(cxt);
* if (lc)
@@ -1197,7 +1234,7 @@ struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
*
* mnt_context_set_options(cxt, "noexec,nosuid");
*
- * these both calls have the same effect.
+ * both of these calls have the same effect.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1227,7 +1264,7 @@ int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
* @flags: returns MS_* mount flags
*
* Converts mount options string to MS_* flags and bitewise-OR the result with
- * already defined flags (see mnt_context_set_mflags()).
+ * the already defined flags (see mnt_context_set_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1268,7 +1305,7 @@ int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
*
* Sets userspace mount flags.
*
- * See also notest for mnt_context_set_mflags().
+ * See also notes for mnt_context_set_mflags().
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1287,7 +1324,7 @@ int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
* @flags: returns mount flags
*
* Converts mount options string to MNT_MS_* flags and bitewise-OR the result
- * with already defined flags (see mnt_context_set_user_mflags()).
+ * with the already defined flags (see mnt_context_set_user_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1321,7 +1358,7 @@ int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags
* function allows to overwrite this behavior, and @data will be used instead
* of mount options.
*
- * The libmount does not deallocated the data by mnt_free_context(). Note that
+ * The libmount does not deallocate the data by mnt_free_context(). Note that
* NULL is also valid mount data.
*
* Returns: 0 on success, negative number in case of error.
@@ -1362,7 +1399,7 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
return mnt_fs_set_source(cxt->fs, "none");
/* ignore filesystems without source or filesystems
- * where the source is quasi-path (//foo/bar)
+ * where the source is a quasi-path (//foo/bar)
*/
if (!src || mnt_fs_is_netfs(cxt->fs))
return 0;
@@ -1504,8 +1541,8 @@ int mnt_context_prepare_target(struct libmnt_context *cxt)
}
/*
- * It's usully no error when we're not able to detect filesystem type -- we
- * will try to use types from /{etc,proc}/filesystems.
+ * It's usually no error when we're not able to detect the filesystem type -- we
+ * will try to use the types from /{etc,proc}/filesystems.
*/
int mnt_context_guess_fstype(struct libmnt_context *cxt)
{
@@ -1595,6 +1632,7 @@ int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
if (mnt_context_is_nohelpers(cxt)
|| !type
|| !strcmp(type, "none")
+ || strstr(type, "/..") /* don't try to smuggle path */
|| mnt_fs_is_swaparea(cxt->fs))
return 0;
@@ -1798,8 +1836,8 @@ static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
*
* mount /foo/bar
*
- * the path could be a mountpoint as well as source (for
- * example bind mount, symlink to device, ...).
+ * the path could be a mountpoint as well as a source (for
+ * example bind mount, symlink to a device, ...).
*/
if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
fs = mnt_table_find_target(tb, src, direction);
@@ -1869,7 +1907,7 @@ int mnt_context_apply_fstab(struct libmnt_context *cxt)
DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users!"));
cxt->optsmode = MNT_OMODE_USER;
} else if (cxt->optsmode == 0) {
- DBG(CXT, mnt_debug_h(cxt, "use default optmode"));
+ DBG(CXT, mnt_debug_h(cxt, "use default optsmode"));
cxt->optsmode = MNT_OMODE_AUTO;
} else if (cxt->optsmode & MNT_OMODE_NOTAB) {
cxt->optsmode &= ~MNT_OMODE_FSTAB;
@@ -1944,7 +1982,7 @@ int mnt_context_tab_applied(struct libmnt_context *cxt)
}
/*
- * This is not public function!
+ * This is not a public function!
*
* Returns 1 if *only propagation flags* change is requested.
*/
@@ -1974,7 +2012,7 @@ int mnt_context_propagation_only(struct libmnt_context *cxt)
* Global libmount status.
*
* The real exit code of the mount.type helper has to be tested by
- * mnt_context_get_helper_status(). The mnt_context_get_status() only inform
+ * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
* that exec() has been successful.
*
* Returns: 1 if mount.type or mount(2) syscall has been successfully called.
@@ -2046,7 +2084,7 @@ int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
*
* The @status should be 0 on success, or negative number on error (-errno).
*
- * This function should be used only if [u]mount(2) syscall is NOT called by
+ * This function should only be used if the [u]mount(2) syscall is NOT called by
* libmount code.
*
* Returns: 0 or negative number in case of error.
@@ -2086,11 +2124,11 @@ int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
* @action: MNT_ACT_{UMOUNT,MOUNT}
* @flags: not used now
*
- * This function infors libmount that used from [u]mount.type helper.
+ * This function informs libmount that used from [u]mount.type helper.
*
* The function also calls mnt_context_disable_helpers() to avoid recursive
* mount.type helpers calling. It you really want to call another
- * mount.type helper from your helper than you have to explicitly enable this
+ * mount.type helper from your helper, then you have to explicitly enable this
* feature by:
*
* mnt_context_disable_helpers(cxt, FALSE);
@@ -2120,7 +2158,7 @@ int mnt_context_init_helper(struct libmnt_context *cxt, int action,
* @c: getopt() result
* @arg: getopt() optarg
*
- * This function applies [u]mount.type command line option (for example parsed
+ * This function applies the [u]mount.type command line option (for example parsed
* by getopt or getopt_long) to @cxt. All unknown options are ignored and
* then 1 is returned.
*
@@ -2145,7 +2183,7 @@ int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
* @fs: filesystem
* @mounted: returns 1 for mounted and 0 for non-mounted filesystems
*
- * Please, read mnt_table_is_fs_mounted() description!
+ * Please, read the mnt_table_is_fs_mounted() description!
*
* Returns: 0 on success and negative number in case of error.
*/
@@ -2308,7 +2346,7 @@ int test_mount(struct libmnt_test *ts, int argc, char *argv[])
mnt_context_set_target(cxt, argv[idx++]);
}
- /* this is unnecessary! -- libmount is able to internaly
+ /* this is unnecessary! -- libmount is able to internally
* create and manage the lock
*/
lock = mnt_context_get_lock(cxt);
@@ -2317,7 +2355,7 @@ int test_mount(struct libmnt_test *ts, int argc, char *argv[])
rc = mnt_context_mount(cxt);
if (rc)
- printf("failed to mount: %m\n");
+ warn("failed to mount");
else
printf("successfully mounted\n");
diff --git a/libmount/src/context_loopdev.c b/libmount/src/context_loopdev.c
index 576b7f55a..44a7216b8 100644
--- a/libmount/src/context_loopdev.c
+++ b/libmount/src/context_loopdev.c
@@ -47,10 +47,10 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
/* Automatically create a loop device from a regular file if a
* filesystem is not specified or the filesystem is known for libblkid
* (these filesystems work with block devices only). The file size
- * should be at least 1KiB otherwise we will create empty loopdev where
- * is no mountable filesystem...
+ * should be at least 1KiB, otherwise we will create an empty loopdev with
+ * no mountable filesystem...
*
- * Note that there is not a restriction (on kernel side) that prevents regular
+ * Note that there is no restriction (on kernel side) that would prevent a regular
* file as a mount(2) source argument. A filesystem that is able to mount
* regular files could be implemented.
*/
@@ -73,7 +73,7 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
}
-/* Check, if there already exists a mounted loop device on the mountpoint node
+/* Check if there already exists a mounted loop device on the mountpoint node
* with the same parameters.
*/
static int __attribute__((nonnull))
@@ -86,6 +86,8 @@ is_mounted_same_loopfile(struct libmnt_context *cxt,
struct libmnt_iter itr;
struct libmnt_fs *fs;
struct libmnt_cache *cache;
+ const char *bf;
+ int rc = 0;
assert(cxt);
assert(cxt->fs);
@@ -100,39 +102,36 @@ is_mounted_same_loopfile(struct libmnt_context *cxt,
cache = mnt_context_get_cache(cxt);
mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
- /* Search for mountpoint node in mtab, procceed if any of these has the
+ bf = cache ? mnt_resolve_path(backing_file, cache) : backing_file;
+
+ /* Search for a mountpoint node in mtab, proceed if any of these have the
* loop option set or the device is a loop device
*/
- while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ while (rc == 0 && mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *src = mnt_fs_get_source(fs);
const char *opts = mnt_fs_get_user_options(fs);
char *val;
size_t len;
- int res = 0;
if (!src || !mnt_fs_match_target(fs, target, cache))
continue;
+ rc = 0;
+
if (strncmp(src, "/dev/loop", 9) == 0) {
- res = loopdev_is_used((char *) src, backing_file,
- offset, LOOPDEV_FL_OFFSET);
+ rc = loopdev_is_used((char *) src, bf, offset, LOOPDEV_FL_OFFSET);
} else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
val = strndup(val, len);
- res = loopdev_is_used((char *) val, backing_file,
- offset, LOOPDEV_FL_OFFSET);
+ rc = loopdev_is_used((char *) val, bf, offset, LOOPDEV_FL_OFFSET);
free(val);
}
-
- if (res) {
- DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
- return 1;
- }
}
-
- return 0;
+ if (rc)
+ DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
+ return rc;
}
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
@@ -282,7 +281,7 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
if ((cxt->user_mountflags & MNT_MS_LOOP) &&
loopcxt_is_autoclear(&lc)) {
/*
- * autoclear flag accepted by kernel, don't store
+ * autoclear flag accepted by the kernel, don't store
* the "loop=" option to mtab.
*/
cxt->user_mountflags &= ~MNT_MS_LOOP;
@@ -298,7 +297,7 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY);
/* we have to keep the device open until mount(1),
- * otherwise it will auto-cleared by kernel
+ * otherwise it will be auto-cleared by kernel
*/
cxt->loopdev_fd = loopcxt_get_fd(&lc);
loopcxt_set_fd(&lc, -1, 0);
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index d6691eb6a..89d1f4f29 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -21,6 +21,7 @@
#include "linux_version.h"
#include "mountP.h"
+#include "strutils.h"
/*
* Kernel supports only one MS_PROPAGATION flag change by one mount(2) syscall,
@@ -101,6 +102,30 @@ static int init_propagation(struct libmnt_context *cxt)
return 0;
}
+#if defined(HAVE_LIBSELINUX) || defined(HAVE_SMACK)
+struct libmnt_optname {
+ const char *name;
+ size_t namesz;
+};
+
+#define DEF_OPTNAME(n) { .name = n, .namesz = sizeof(n) - 1 }
+#define DEF_OPTNAME_LAST { .name = NULL }
+
+static int is_option(const char *name, size_t namesz,
+ const struct libmnt_optname *names)
+{
+ const struct libmnt_optname *p;
+
+ for (p = names; p && p->name; p++) {
+ if (p->namesz == namesz
+ && strncmp(name, p->name, namesz) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* HAVE_LIBSELINUX || HAVE_SMACK */
+
/*
* this has to be called after mnt_context_evaluate_permissions()
*/
@@ -113,6 +138,25 @@ static int fix_optstr(struct libmnt_context *cxt)
struct libmnt_fs *fs;
#ifdef HAVE_LIBSELINUX
int se_fix = 0, se_rem = 0;
+ static const struct libmnt_optname selinux_options[] = {
+ DEF_OPTNAME("context"),
+ DEF_OPTNAME("fscontext"),
+ DEF_OPTNAME("defcontext"),
+ DEF_OPTNAME("rootcontext"),
+ DEF_OPTNAME("seclabel"),
+ DEF_OPTNAME_LAST
+ };
+#endif
+#ifdef HAVE_SMACK
+ int sm_rem = 0;
+ static const struct libmnt_optname smack_options[] = {
+ DEF_OPTNAME("smackfsdef"),
+ DEF_OPTNAME("smackfsfloor"),
+ DEF_OPTNAME("smackfshat"),
+ DEF_OPTNAME("smackfsroot"),
+ DEF_OPTNAME("smackfstransmute"),
+ DEF_OPTNAME_LAST
+ };
#endif
assert(cxt);
assert(cxt->fs);
@@ -129,8 +173,8 @@ static int fix_optstr(struct libmnt_context *cxt)
/*
* The "user" options is our business (so we can modify the option),
- * but exception is command line for /sbin/mount.<type> helpers. Let's
- * save the original user=<name> to call the helpers with unchanged
+ * the exception is command line for /sbin/mount.<type> helpers. Let's
+ * save the original user=<name> to call the helpers with an unchanged
* "user" setting.
*/
if (cxt->user_mountflags & MNT_MS_USER) {
@@ -168,7 +212,6 @@ static int fix_optstr(struct libmnt_context *cxt)
free(fs->user_optstr);
fs->user_optstr = NULL;
}
-
if (cxt->mountflags & MS_PROPAGATION) {
rc = init_propagation(cxt);
if (rc)
@@ -198,13 +241,15 @@ static int fix_optstr(struct libmnt_context *cxt)
if (!se_rem) {
/* de-duplicate SELinux options */
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "context");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "fscontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "defcontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "rootcontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "seclabel");
+ const struct libmnt_optname *p;
+ for (p = selinux_options; p && p->name; p++)
+ mnt_optstr_deduplicate_option(&fs->fs_optstr, p->name);
}
#endif
+#ifdef HAVE_SMACK
+ if (access("/sys/fs/smackfs", F_OK) != 0)
+ sm_rem = 1;
+#endif
while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) {
if (namesz == 3 && !strncmp(name, "uid", 3))
@@ -212,12 +257,9 @@ static int fix_optstr(struct libmnt_context *cxt)
else if (namesz == 3 && !strncmp(name, "gid", 3))
rc = mnt_optstr_fix_gid(&fs->fs_optstr, val, valsz, &next);
#ifdef HAVE_LIBSELINUX
- else if ((se_rem || se_fix) &&
- namesz >= 7 && (!strncmp(name, "context", 7) ||
- !strncmp(name, "fscontext", 9) ||
- !strncmp(name, "defcontext", 10) ||
- !strncmp(name, "rootcontext", 11) ||
- !strncmp(name, "seclabel", 8))) {
+ else if ((se_rem || se_fix)
+ && is_option(name, namesz, selinux_options)) {
+
if (se_rem) {
/* remove context= option */
next = name;
@@ -231,6 +273,15 @@ static int fix_optstr(struct libmnt_context *cxt)
val, valsz, &next);
}
#endif
+#ifdef HAVE_SMACK
+ else if (sm_rem && is_option(name, namesz, smack_options)) {
+
+ next = name;
+ rc = mnt_optstr_remove_option_at(&fs->fs_optstr,
+ name,
+ val ? val + valsz : name + namesz);
+ }
+#endif
if (rc)
goto done;
}
@@ -255,7 +306,7 @@ done:
}
/*
- * Converts already evaluated and fixed options to the form that is compatible
+ * Converts the already evaluated and fixed options to the form that is compatible
* with /sbin/mount.type helpers.
*/
static int generate_helper_optstr(struct libmnt_context *cxt, char **optstr)
@@ -278,13 +329,13 @@ static int generate_helper_optstr(struct libmnt_context *cxt, char **optstr)
if (cxt->user_mountflags & MNT_MS_USER) {
/*
* This is unnecessary for real user-mounts as mount.<type>
- * helpers have to always follow fstab rather than mount
- * options on command line.
+ * helpers always have to follow fstab rather than mount
+ * options on the command line.
*
- * But if you call mount.<type> as root then the helper follows
- * command line. If there is (for example) "user,exec" in fstab
+ * However, if you call mount.<type> as root, then the helper follows
+ * the command line. If there is (for example) "user,exec" in fstab,
* then we have to manually append the "exec" back to the options
- * string, bacause there is nothing like MS_EXEC (we have only
+ * string, bacause there is nothing like MS_EXEC (we only have
* MS_NOEXEC in mount flags and we don't care about the original
* mount string in libmount for VFS options).
*/
@@ -330,7 +381,7 @@ err:
/*
* this has to be called before fix_optstr()
*
- * Note that user=<name> maybe be used by some filesystems as filesystem
+ * Note that user=<name> may be used by some filesystems as a filesystem
* specific option (e.g. cifs). Yes, developers of such filesystems have
* allocated pretty hot place in hell...
*/
@@ -361,7 +412,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
/*
* user mount
*/
- if (!(cxt->flags & MNT_FL_TAB_APPLIED))
+ if (!mnt_context_tab_applied(cxt))
{
DBG(CXT, mnt_debug_h(cxt, "perms: fstab not applied, ignore user mount"));
return -EPERM;
@@ -433,7 +484,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
/*
* mnt_context_helper_setopt() backend
*
- * This function applies mount.type command line option (for example parsed
+ * This function applies the mount.type command line option (for example parsed
* by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
* then 1 is returned.
*
@@ -519,7 +570,7 @@ static int exec_helper(struct libmnt_context *cxt)
/*
* TODO: remove the exception for "nfs", -s is documented
- * for years should be usable everywhere.
+ * for years and should be usable everywhere.
*/
if (mnt_context_is_sloppy(cxt) &&
type && startswith(type, "nfs"))
@@ -651,7 +702,7 @@ static int do_mount(struct libmnt_context *cxt, const char *try_type)
return -EINVAL;
if (!src) {
/* unnecessary, should be already resolved in
- * mnt_context_prepare_srcpath(), but for sure... */
+ * mnt_context_prepare_srcpath(), but to be sure... */
DBG(CXT, mnt_debug_h(cxt, "WARNING: source is NULL -- using \"none\"!"));
src = "none";
}
@@ -831,10 +882,10 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt)
* Call mount(2) or mount.type helper. Unnecessary for mnt_context_mount().
*
* Note that this function could be called only once. If you want to mount
- * another source or target than you have to call mnt_reset_context().
+ * another source or target, then you have to call mnt_reset_context().
*
- * If you want to call mount(2) for the same source and target with a different
- * mount flags or fstype then call mnt_context_reset_status() and then try
+ * If you want to call mount(2) for the same source and target with different
+ * mount flags or fstype, then call mnt_context_reset_status() and then try
* again mnt_context_do_mount().
*
* WARNING: non-zero return code does not mean that mount(2) syscall or
@@ -867,7 +918,7 @@ int mnt_context_do_mount(struct libmnt_context *cxt)
type = mnt_fs_get_fstype(cxt->fs);
if (type) {
if (strchr(type, ','))
- /* this only happens if fstab contains list of filesystems */
+ /* this only happens if fstab contains a list of filesystems */
res = do_mount_by_pattern(cxt, type);
else
res = do_mount(cxt, NULL);
@@ -935,7 +986,7 @@ int mnt_context_finalize_mount(struct libmnt_context *cxt)
* mnt_context_mount:
* @cxt: mount context
*
- * High-level, mounts filesystem by mount(2) or fork()+exec(/sbin/mount.type).
+ * High-level, mounts the filesystem by mount(2) or fork()+exec(/sbin/mount.type).
*
* This is similar to:
*
@@ -945,10 +996,10 @@ int mnt_context_finalize_mount(struct libmnt_context *cxt)
*
* See also mnt_context_disable_helpers().
*
- * Note that this function could be called only once. If you want to mount with
- * different setting than you have to call mnt_reset_context(). It's NOT enough
- * to call mnt_context_reset_status() if you want call this function more than
- * once, whole context has to be reseted.
+ * Note that this function should be called only once. If you want to mount with
+ * different settings, then you have to call mnt_reset_context(). It's NOT enough
+ * to call mnt_context_reset_status(). If you want to call this function more than
+ * once, the whole context has to be reset.
*
* WARNING: non-zero return code does not mean that mount(2) syscall or
* mount.type helper wasn't successfully called.
@@ -973,11 +1024,6 @@ int mnt_context_mount(struct libmnt_context *cxt)
rc = mnt_context_prepare_update(cxt);
if (!rc)
rc = mnt_context_do_mount(cxt);
-
- /* TODO: if mtab update is expected then check if the
- * target is really mounted read-write to avoid 'ro' in
- * mtab and 'rw' in /proc/mounts.
- */
if (!rc)
rc = mnt_context_update_tabs(cxt);
return rc;
@@ -989,7 +1035,7 @@ int mnt_context_mount(struct libmnt_context *cxt)
* @itr: iterator
* @fs: returns the current filesystem
* @mntrc: returns the return code from mnt_context_mount()
- * @ignored: returns 1 for not matching and 2 for already mounted filesystems
+ * @ignored: returns 1 for non-matching and 2 for already mounted filesystems
*
* This function tries to mount the next filesystem from fstab (as returned by
* mnt_context_get_fstab()). See also mnt_context_set_fstab().
@@ -1057,11 +1103,11 @@ int mnt_context_next_mount(struct libmnt_context *cxt,
/* ignore noauto filesystems */
(o && mnt_optstr_get_option(o, "noauto", NULL, NULL) == 0) ||
- /* ignore filesystems not match with options patterns */
+ /* ignore filesystems which don't match options patterns */
(cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
cxt->fstype_pattern)) ||
- /* ignore filesystems not match with type patterns */
+ /* ignore filesystems which don't match type patterns */
(cxt->optstr_pattern && !mnt_fs_match_options(*fs,
cxt->optstr_pattern))) {
if (ignored)
diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
index 4a8659c9c..dc16852c0 100644
--- a/libmount/src/context_umount.c
+++ b/libmount/src/context_umount.c
@@ -23,7 +23,7 @@
* umount2 flags
*/
#ifndef MNT_FORCE
-# define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+# define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
#endif
#ifndef MNT_DETACH
@@ -39,8 +39,8 @@
#endif
/*
- * Called by mtab parser to filter out entries, nonzero means that
- * entry has to be filter out.
+ * Called by mtab parser to filter out entries, non-zero means that
+ * an entry has to be filtered out.
*/
static int mtab_filter(struct libmnt_fs *fs, void *data)
{
@@ -71,19 +71,25 @@ int mnt_context_find_umount_fs(struct libmnt_context *cxt,
struct libmnt_cache *cache = NULL;
char *cn_tgt = NULL, *loopdev = NULL;
+ if (pfs)
+ *pfs = NULL;
+
if (!cxt || !tgt || !pfs)
return -EINVAL;
DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS for '%s'", tgt));
+ if (!*tgt)
+ return 1; /* empty string is not an error */
+
/*
- * The mtab file maybe huge and on systems with utab we have to merge
+ * The mtab file may be huge and on systems with utab we have to merge
* userspace mount options into /proc/self/mountinfo. This all is
* expensive. The mtab filter allows to filter out entries, then
* mtab and utab are very tiny files.
*
* *but*... the filter uses mnt_fs_streq_{target,srcpath} functions
- * where LABEL, UUID or symlinks are to canonicalized. It means that
+ * where LABEL, UUID or symlinks are canonicalized. It means that
* it's usable only for canonicalized stuff (e.g. kernel mountinfo).
*/
if (!cxt->mtab_writable && *tgt == '/' &&
@@ -92,7 +98,7 @@ 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 canonicalized /proc/self/mountinfo */
+ /* we'll canonicalize /proc/self/mountinfo */
cache = mnt_context_get_cache(cxt);
cn_tgt = mnt_resolve_path(tgt, cache);
if (cn_tgt)
@@ -155,7 +161,10 @@ try_loopdev:
struct stat st;
if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
- int count = loopdev_count_by_backing_file(tgt, &loopdev);
+ int count;
+ const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt;
+
+ count = loopdev_count_by_backing_file(bf, &loopdev);
if (count == 1) {
DBG(CXT, mnt_debug_h(cxt,
"umount: %s --> %s (retry)", tgt, loopdev));
@@ -169,15 +178,21 @@ try_loopdev:
}
}
- *pfs = fs;
+ if (pfs)
+ *pfs = fs;
free(loopdev);
+ DBG(CXT, mnt_debug_h(cxt, "umount fs: %s", fs ? mnt_fs_get_target(fs) :
+ "<not found>"));
return fs ? 0 : 1;
err:
free(loopdev);
return rc;
}
+/* 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;
@@ -197,8 +212,8 @@ static int lookup_umount_fs(struct libmnt_context *cxt)
if (rc < 0)
return rc;
if (rc == 1 || !fs) {
- DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
- return 0;
+ DBG(CXT, mnt_debug_h(cxt, "umount: cannot find '%s' in mtab", tgt));
+ return 0; /* this is correct! */
}
if (fs != cxt->fs) {
@@ -237,7 +252,7 @@ static int is_associated_fs(const char *devname, struct libmnt_fs *fs)
if (!src)
return 0;
- /* check for offset option in @fs */
+ /* check for the offset option in @fs */
optstr = (char *) mnt_fs_get_user_options(fs);
if (optstr &&
@@ -300,7 +315,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
DBG(CXT, mnt_debug_h(cxt, "umount: evaluating permissions"));
- if (!(cxt->flags & MNT_FL_TAB_APPLIED)) {
+ if (!mnt_context_tab_applied(cxt)) {
DBG(CXT, mnt_debug_h(cxt,
"cannot find %s in mtab and you are not root",
mnt_fs_get_target(cxt->fs)));
@@ -317,7 +332,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
}
/*
- * User mounts has to be in /etc/fstab
+ * User mounts have to be in /etc/fstab
*/
rc = mnt_context_get_fstab(cxt, &fstab);
if (rc)
@@ -336,18 +351,20 @@ static int evaluate_permissions(struct libmnt_context *cxt)
* /dev/sda1 /mnt/zip auto user,noauto 0 0
* /dev/sda4 /mnt/zip auto user,noauto 0 0
* then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail.
- * So, we must not look for file, but for the pair (dev,file) in fstab.
+ * So, we must not look for the file, but for the pair (dev,file) in fstab.
*/
fs = mnt_table_find_pair(fstab, src, tgt, MNT_ITER_FORWARD);
if (!fs) {
/*
* It's possible that there is /path/file.img in fstab and
- * /dev/loop0 in mtab -- then we have to check releation
+ * /dev/loop0 in mtab -- then we have to check the relation
* between loopdev and the file.
*/
fs = mnt_table_find_target(fstab, tgt, MNT_ITER_FORWARD);
if (fs) {
- const char *dev = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */
+ struct libmnt_cache *cache = mnt_context_get_cache(cxt);
+ const char *sp = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */
+ const char *dev = sp && cache ? mnt_resolve_path(sp, cache) : sp;
if (!dev || !is_associated_fs(dev, fs))
fs = NULL;
@@ -384,7 +401,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
return 0;
}
/*
- * Check user=<username> setting from mtab if there is user, owner or
+ * Check user=<username> setting from mtab if there is a user, owner or
* group option in /etc/fstab
*/
if (u_flags & (MNT_MS_USER | MNT_MS_OWNER | MNT_MS_GROUP)) {
@@ -409,6 +426,8 @@ static int evaluate_permissions(struct libmnt_context *cxt)
if (optstr && !mnt_optstr_get_option(optstr,
"user", &mtab_user, &sz) && sz)
ok = !strncmp(curr_user, mtab_user, sz);
+
+ free(curr_user);
}
if (ok) {
@@ -539,7 +558,7 @@ int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg)
return rc;
}
-/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
+/* Check whether the kernel supports the UMOUNT_NOFOLLOW flag */
static int umount_nofollow_support(void)
{
int res = umount2("", UMOUNT_UNUSED);
@@ -860,7 +879,7 @@ int mnt_context_umount(struct libmnt_context *cxt)
* mnt_context_set_options_pattern() to simulate umount -a -O pattern
* mnt_context_set_fstype_pattern() to simulate umount -a -t pattern
*
- * If the filesystem is not mounted or does not match defined criteria,
+ * If the filesystem is not mounted or does not match the defined criteria,
* then the function mnt_context_next_umount() returns zero, but the @ignored is
* non-zero. Note that the root filesystem is always ignored.
*
@@ -909,11 +928,11 @@ int mnt_context_next_umount(struct libmnt_context *cxt,
DBG(CXT, mnt_debug_h(cxt, "next-umount: trying %s", tgt));
- /* ignore filesystems not match with options patterns */
+ /* ignore filesystems which don't match options patterns */
if ((cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
cxt->fstype_pattern)) ||
- /* ignore filesystems not match with type patterns */
+ /* ignore filesystems which don't match type patterns */
(cxt->optstr_pattern && !mnt_fs_match_options(*fs,
cxt->optstr_pattern))) {
if (ignored)
diff --git a/libmount/src/fs.c b/libmount/src/fs.c
index c95cdc7e7..3ab614503 100644
--- a/libmount/src/fs.c
+++ b/libmount/src/fs.c
@@ -21,6 +21,9 @@
/**
* mnt_new_fs:
*
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the filesystem.
+ *
* Returns: newly allocated struct libmnt_fs.
*/
struct libmnt_fs *mnt_new_fs(void)
@@ -29,8 +32,9 @@ struct libmnt_fs *mnt_new_fs(void)
if (!fs)
return NULL;
- /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
+ fs->refcount = 1;
INIT_LIST_HEAD(&fs->ents);
+ /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
return fs;
}
@@ -38,7 +42,10 @@ struct libmnt_fs *mnt_new_fs(void)
* mnt_free_fs:
* @fs: fs pointer
*
- * Deallocates the fs.
+ * Deallocates the fs. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_fs().
+ *
+ * The reference counting is supported since util-linux v2.24.
*/
void mnt_free_fs(struct libmnt_fs *fs)
{
@@ -47,6 +54,7 @@ void mnt_free_fs(struct libmnt_fs *fs)
list_del(&fs->ents);
/*DBG(FS, mnt_debug_h(fs, "free"));*/
+ WARN_REFCOUNT(FS, fs, fs->refcount);
free(fs->source);
free(fs->bindsrc);
@@ -62,6 +70,7 @@ void mnt_free_fs(struct libmnt_fs *fs)
free(fs->user_optstr);
free(fs->attrs);
free(fs->opt_fields);
+ free(fs->comment);
free(fs);
}
@@ -74,8 +83,46 @@ void mnt_free_fs(struct libmnt_fs *fs)
*/
void mnt_reset_fs(struct libmnt_fs *fs)
{
- if (fs)
- memset(fs, 0, sizeof(*fs));
+ int ref;
+
+ if (!fs)
+ return;
+
+ ref = fs->refcount;
+ memset(fs, 0, sizeof(*fs));
+ INIT_LIST_HEAD(&fs->ents);
+ fs->refcount = ref;
+}
+
+/**
+ * mnt_ref_fs:
+ * @fs: fs pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_fs(struct libmnt_fs *fs)
+{
+ if (fs) {
+ fs->refcount++;
+ /*DBG(FS, mnt_debug_h(fs, "ref=%d", fs->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_fs:
+ * @fs: fs pointer
+ *
+ * De-increments reference counter, on zero the @fs is automatically
+ * deallocated by mnt_free_fs().
+ */
+void mnt_unref_fs(struct libmnt_fs *fs)
+{
+ if (fs) {
+ fs->refcount--;
+ /*DBG(FS, mnt_debug_h(fs, "unref=%d", fs->refcount));*/
+ if (fs->refcount <= 0)
+ mnt_free_fs(fs);
+ }
}
static inline int update_str(char **dest, const char *src)
@@ -106,7 +153,7 @@ static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
char **n = (char **) (new + offset);
if (*n)
- return 0; /* already set, not overwrite */
+ return 0; /* already set, don't overwrite */
return update_str(n, *o);
}
@@ -117,7 +164,7 @@ static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
* @src: source FS
*
* If @dest is NULL, then a new FS is allocated, if any @dest field is already
- * set then the field is NOT overwrited.
+ * set, then the field is NOT overwritten.
*
* This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is
* not linked with any existing mnt_tab.
@@ -250,7 +297,12 @@ err:
void *mnt_fs_get_userdata(struct libmnt_fs *fs)
{
assert(fs);
- return fs ? fs->userdata : NULL;
+
+ if (!fs)
+ return NULL;
+
+ /*DBG(FS, mnt_debug_h(fs, "get userdata [%p]", fs->userdata));*/
+ return fs->userdata;
}
/**
@@ -267,6 +319,8 @@ int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data)
assert(fs);
if (!fs)
return -EINVAL;
+
+ /*DBG(FS, mnt_debug_h(fs, "set userdata [%p]", fs->userdata));*/
fs->userdata = data;
return 0;
}
@@ -310,7 +364,7 @@ const char *mnt_fs_get_source(struct libmnt_fs *fs)
}
/*
- * Used by parser ONLY (@source has to be freed on error)
+ * Used by the parser ONLY (@source has to be freed on error)
*/
int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
{
@@ -318,9 +372,12 @@ int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
assert(fs);
- if (source && *source != '/' && strchr(source, '=')) {
- if (blkid_parse_tag_string(source, &t, &v) != 0)
- return -1;
+ if (source && blkid_parse_tag_string(source, &t, &v) == 0 &&
+ !mnt_valid_tagname(t)) {
+ /* parsable but unknown tag -- ignore */
+ free(t);
+ free(v);
+ t = v = NULL;
}
if (fs->source != source)
@@ -370,7 +427,7 @@ int mnt_fs_set_source(struct libmnt_fs *fs, const char *source)
* @fs: fs
* @path: source path
*
- * Compares @fs source path with @path. The tailing slash is ignored.
+ * Compares @fs source path with @path. The trailing slash is ignored.
* See also mnt_fs_match_source().
*
* Returns: 1 if @fs source path equal to @path, otherwise 0.
@@ -399,7 +456,7 @@ int mnt_fs_streq_srcpath(struct libmnt_fs *fs, const char *path)
* @fs: fs
* @path: mount point
*
- * Compares @fs target path with @path. The tailing slash is ignored.
+ * Compares @fs target path with @path. The trailing slash is ignored.
* See also mnt_fs_match_target().
*
* Returns: 1 if @fs target path equal to @path, otherwise 0.
@@ -418,8 +475,8 @@ int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
*
* "TAG" is NAME=VALUE (e.g. LABEL=foo)
*
- * The TAG is the first column in the fstab file. The TAG or "srcpath" has to
- * be always set for all entries.
+ * The TAG is the first column in the fstab file. The TAG or "srcpath" always has
+ * to be set for all entries.
*
* See also mnt_fs_get_source().
*
@@ -441,7 +498,7 @@ int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
* </programlisting>
* </informalexample>
*
- * Returns: 0 on success or negative number in case that a TAG is not defined.
+ * Returns: 0 on success or negative number in case a TAG is not defined.
*/
int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value)
{
@@ -502,10 +559,10 @@ static int mnt_fs_get_flags(struct libmnt_fs *fs)
/**
* mnt_fs_get_propagation:
* @fs: mountinfo entry
- * @flags: returns propagation MS_* flags as present in mountinfo file
+ * @flags: returns propagation MS_* flags as present in the mountinfo file
*
- * Note that this function set @flags to zero if not found any propagation flag
- * in mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
+ * Note that this function sets @flags to zero if no propagation flags are found
+ * in the mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
* in the mountinfo file.
*
* Returns: 0 on success or negative number in case of error.
@@ -594,7 +651,7 @@ const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
return fs ? fs->fstype : NULL;
}
-/* Used by struct libmnt_file parser only */
+/* Used by the struct libmnt_file parser only */
int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
{
assert(fs);
@@ -670,7 +727,7 @@ static char *merge_optstr(const char *vfs, const char *fs)
if (!strcmp(vfs, fs))
return strdup(vfs); /* e.g. "aaa" and "aaa" */
- /* leave space for leading "r[ow],", "," and trailing zero */
+ /* leave space for the leading "r[ow],", "," and the trailing zero */
sz = strlen(vfs) + strlen(fs) + 5;
res = malloc(sz);
if (!res)
@@ -701,7 +758,7 @@ static char *merge_optstr(const char *vfs, const char *fs)
* mnt_fs_strdup_options:
* @fs: fstab/mtab/mountinfo entry pointer
*
- * Merges all mount options (VFS, FS and userspace) to the one options string
+ * Merges all mount options (VFS, FS and userspace) to one options string
* and returns the result. This function does not modigy @fs.
*
* Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
@@ -757,10 +814,10 @@ const char *mnt_fs_get_optional_fields(struct libmnt_fs *fs)
* @fs: fstab/mtab/mountinfo entry pointer
* @optstr: options string
*
- * Splits @optstr to VFS, FS and userspace mount options and update relevat
+ * Splits @optstr to VFS, FS and userspace mount options and updates relevant
* parts of @fs.
*
- * Returns: 0 on success, or negative number icase of error.
+ * Returns: 0 on success, or negative number in case of error.
*/
int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
{
@@ -774,8 +831,12 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
if (rc)
return rc;
n = strdup(optstr);
- if (!n)
+ if (!n) {
+ free(u);
+ free(v);
+ free(f);
return -ENOMEM;
+ }
}
free(fs->fs_optstr);
@@ -799,7 +860,7 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
* Parses (splits) @optstr and appends results to VFS, FS and userspace lists
* of options.
*
- * If @optstr is NULL then @fs is not modified and 0 is returned.
+ * If @optstr is NULL, then @fs is not modified and 0 is returned.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -815,6 +876,9 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
return 0;
rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
+ if (rc)
+ return rc;
+
if (!rc && v)
rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
if (!rc && f)
@@ -836,10 +900,10 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
* @fs: fstab/mtab/mountinfo entry
* @optstr: mount options
*
- * Parses (splits) @optstr and prepands results to VFS, FS and userspace lists
+ * Parses (splits) @optstr and prepends the results to VFS, FS and userspace lists
* of options.
*
- * If @optstr is NULL then @fs is not modified and 0 is returned.
+ * If @optstr is NULL, then @fs is not modified and 0 is returned.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -855,6 +919,9 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
return 0;
rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
+ if (rc)
+ return rc;
+
if (!rc && v)
rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
if (!rc && f)
@@ -925,10 +992,10 @@ const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
* @optstr: options string
*
* Sets mount attributes. The attributes are mount(2) and mount(8) independent
- * options, these options are not send to kernel and are not interpreted by
+ * options, these options are not sent to the kernel and are not interpreted by
* libmount. The attributes are stored in /run/mount/utab only.
*
- * The atrtributes are managed by libmount in userspace only. It's possible
+ * The attributes are managed by libmount in userspace only. It's possible
* that information stored in userspace will not be available for libmount
* after CLONE_FS unshare. Be careful, and don't use attributes if possible.
*
@@ -1221,7 +1288,7 @@ dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
* mnt_fs_get_tid:
* @fs: /proc/tid/mountinfo entry
*
- * Returns: TID (task ID) for filesystems read from mountinfo file
+ * Returns: TID (task ID) for filesystems read from the mountinfo file
*/
pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
{
@@ -1233,10 +1300,10 @@ pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
* mnt_fs_get_option:
* @fs: fstab/mtab/mountinfo entry pointer
* @name: option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of options value or 0
*
- * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ * Returns: 0 on success, 1 when @name not found or negative number in case of error.
*/
int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
char **value, size_t *valsz)
@@ -1259,10 +1326,10 @@ int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
* mnt_fs_get_attribute:
* @fs: fstab/mtab/mountinfo entry pointer
* @name: option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of options value or 0
*
- * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ * Returns: 0 on success, 1 when @name not found or negative number in case of error.
*/
int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
char **value, size_t *valsz)
@@ -1278,6 +1345,67 @@ int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
}
/**
+ * mnt_fs_get_comment:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ */
+const char *mnt_fs_get_comment(struct libmnt_fs *fs)
+{
+ assert(fs);
+ if (!fs)
+ return NULL;
+ return fs->comment;
+}
+
+/**
+ * mnt_fs_set_comment:
+ * @fs: fstab entry pointer
+ * @comm: comment string
+ *
+ * Note that the comment has to be terminated by '\n' (new line), otherwise
+ * the whole filesystem entry will be written as a comment to the tabfile (e.g.
+ * fstab).
+ *
+ * Returns: 0 on success or <0 in case of error.
+ */
+int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm)
+{
+ char *p = NULL;
+
+ assert(fs);
+ if (!fs)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(fs->comment);
+ fs->comment = p;
+ return 0;
+}
+
+/**
+ * mnt_fs_append_comment:
+ * @fs: fstab entry pointer
+ * @comm: comment string
+ *
+ * See also mnt_fs_set_comment().
+ *
+ * Returns: 0 on success or <0 in case of error.
+ */
+int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm)
+{
+ assert(fs);
+ if (!fs)
+ return -EINVAL;
+
+ return append_string(&fs->comment, comm);
+}
+
+/**
* mnt_fs_match_target:
* @fs: filesystem
* @target: mountpoint path
@@ -1291,7 +1419,7 @@ int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
*
* The 2nd and 3rd attempts are not performed when @cache is NULL.
*
- * Returns: 1 if @fs target is equal to @target else 0.
+ * Returns: 1 if @fs target is equal to @target, else 0.
*/
int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
struct libmnt_cache *cache)
@@ -1326,7 +1454,7 @@ int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
* @source: tag or path (device or so) or NULL
* @cache: tags/paths cache or NULL
*
- * Possible are four attempts:
+ * Four attempts are possible:
* 1) compare @source with @fs->source
* 2) compare realpath(@source) with @fs->source
* 3) compare realpath(@source) with realpath(@fs->source)
@@ -1335,7 +1463,7 @@ int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
* The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
* 2nd and 3rd attempts are not performed if @fs->source is tag.
*
- * Returns: 1 if @fs source is equal to @source else 0.
+ * Returns: 1 if @fs source is equal to @source, else 0.
*/
int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
struct libmnt_cache *cache)
@@ -1379,14 +1507,14 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
return 1;
}
if (src || mnt_fs_get_tag(fs, &t, &v))
- /* src path does not match and tag is not defined */
+ /* src path does not match and the tag is not defined */
return 0;
/* read @source's tags to the cache */
if (mnt_cache_read_tags(cache, cn) < 0) {
if (errno == EACCES) {
/* we don't have permissions to read TAGs from
- * @source, but can translate @fs tag to devname.
+ * @source, but can translate the @fs tag to devname.
*
* (because libblkid uses udev symlinks and this is
* accessible for non-root uses)
@@ -1398,7 +1526,7 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
return 0;
}
- /* 4) has the @source a tag that matches with tag from @fs ? */
+ /* 4) has the @source a tag that matches with the tag from @fs ? */
if (mnt_cache_device_has_tag(cache, cn, t, v))
return 1;
@@ -1412,7 +1540,7 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
*
* For more details see mnt_match_fstype().
*
- * Returns: 1 if @fs type is matching to @types else 0. The function returns
+ * Returns: 1 if @fs type is matching to @types, else 0. The function returns
* 0 when types is NULL.
*/
int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
@@ -1428,7 +1556,7 @@ int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
*
* For more details see mnt_match_options().
*
- * Returns: 1 if @fs type is matching to @options else 0. The function returns
+ * Returns: 1 if @fs type is matching to @options, else 0. The function returns
* 0 when types is NULL.
*/
int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
@@ -1493,6 +1621,8 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
minor(mnt_fs_get_devno(fs)));
if (mnt_fs_get_tid(fs))
fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs));
+ if (mnt_fs_get_comment(fs))
+ fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs));
return 0;
}
@@ -1501,7 +1631,7 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
* mnt_free_mntent:
* @mnt: mount entry
*
- * Deallocates "mntent.h" mount entry.
+ * Deallocates the "mntent.h" mount entry.
*/
void mnt_free_mntent(struct mntent *mnt)
{
@@ -1519,11 +1649,11 @@ void mnt_free_mntent(struct mntent *mnt)
* @fs: filesystem
* @mnt: mount description (as described in mntent.h)
*
- * Copies information from @fs to struct mntent @mnt. If @mnt is already set
+ * Copies the information from @fs to struct mntent @mnt. If @mnt is already set,
* then the struct mntent items are reallocated and updated. See also
* mnt_free_mntent().
*
- * Returns: 0 on success and negative number in case of error.
+ * Returns: 0 on success and a negative number in case of error.
*/
int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
{
diff --git a/libmount/src/init.c b/libmount/src/init.c
index 4e5f489c4..a14637d75 100644
--- a/libmount/src/init.c
+++ b/libmount/src/init.c
@@ -8,7 +8,7 @@
/**
* SECTION: init
* @title: Library initialization
- * @short_description: initialize debuging
+ * @short_description: initialize debugging
*/
#include <stdarg.h>
@@ -19,13 +19,13 @@ int libmount_debug_mask;
/**
* mnt_init_debug:
- * @mask: debug mask (0xffff to enable full debuging)
+ * @mask: debug mask (0xffff to enable full debugging)
*
- * If the @mask is not specified then this function reads
- * LIBMOUNT_DEBUG environment variable to get the mask.
+ * If the @mask is not specified, then this function reads
+ * the LIBMOUNT_DEBUG environment variable to get the mask.
*
- * Already initialized debugging stuff cannot be changed. It does not
- * have effect to call this function twice.
+ * Already initialized debugging stuff cannot be changed. Calling
+ * this function twice has no effect.
*/
void mnt_init_debug(int mask)
{
@@ -40,7 +40,7 @@ void mnt_init_debug(int mask)
libmount_debug_mask |= MNT_DEBUG_INIT;
- if (libmount_debug_mask && libmount_debug_mask != MNT_DEBUG_INIT) {
+ if (libmount_debug_mask != MNT_DEBUG_INIT) {
const char *ver = NULL;
const char **features = NULL, **p;
diff --git a/libmount/src/iter.c b/libmount/src/iter.c
index d7b8adbef..016f88e35 100644
--- a/libmount/src/iter.c
+++ b/libmount/src/iter.c
@@ -10,8 +10,8 @@
* @title: Iterator
* @short_description: unified iterator
*
- * The iterator keeps direction and last position for access to the internal
- * library tables/lists.
+ * The iterator keeps the direction and the last position
+ * for access to the internal library tables/lists.
*/
#include <stdio.h>
#include <string.h>
@@ -38,7 +38,7 @@ struct libmnt_iter *mnt_new_iter(int direction)
* mnt_free_iter:
* @itr: iterator pointer
*
- * Deallocates iterator.
+ * Deallocates the iterator.
*/
void mnt_free_iter(struct libmnt_iter *itr)
{
@@ -48,9 +48,9 @@ void mnt_free_iter(struct libmnt_iter *itr)
/**
* mnt_reset_iter:
* @itr: iterator pointer
- * @direction: MNT_INTER_{FOR,BACK}WARD or -1 to keep the derection unchanged
+ * @direction: MNT_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
*
- * Resets iterator.
+ * Resets the iterator.
*/
void mnt_reset_iter(struct libmnt_iter *itr, int direction)
{
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index db479e186..8c8e739c9 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -41,7 +41,7 @@ struct libmnt_cache;
/**
* libmnt_lock:
*
- * Stores information about locked file (e.g. /etc/mtab)
+ * Stores information about the locked file (e.g. /etc/mtab)
*/
struct libmnt_lock;
@@ -197,6 +197,7 @@ extern char *mnt_mangle(const char *str)
extern char *mnt_unmangle(const char *str)
__ul_attribute__((warn_unused_result));
+extern int mnt_tag_is_valid(const char *tag);
extern int mnt_fstype_is_netfs(const char *type);
extern int mnt_fstype_is_pseudofs(const char *type);
@@ -216,6 +217,9 @@ extern struct libmnt_cache *mnt_new_cache(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_cache(struct libmnt_cache *cache);
+extern void mnt_ref_cache(struct libmnt_cache *cache);
+extern void mnt_unref_cache(struct libmnt_cache *cache);
+
extern int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname);
extern int mnt_cache_device_has_tag(struct libmnt_cache *cache,
@@ -302,6 +306,8 @@ extern int mnt_lock_block_signals(struct libmnt_lock *ml, int enable);
extern struct libmnt_fs *mnt_new_fs(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_fs(struct libmnt_fs *fs);
+extern void mnt_ref_fs(struct libmnt_fs *fs);
+extern void mnt_unref_fs(struct libmnt_fs *fs);
extern void mnt_reset_fs(struct libmnt_fs *fs);
extern struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
@@ -369,6 +375,10 @@ extern off_t mnt_fs_get_size(struct libmnt_fs *fs);
extern off_t mnt_fs_get_usedsize(struct libmnt_fs *fs);
extern int mnt_fs_get_priority(struct libmnt_fs *fs);
+extern const char *mnt_fs_get_comment(struct libmnt_fs *fs);
+extern int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm);
+extern int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm);
+
extern int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
struct libmnt_cache *cache);
extern int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
@@ -406,12 +416,31 @@ extern struct libmnt_table *mnt_new_table(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_table(struct libmnt_table *tb);
+extern void mnt_ref_table(struct libmnt_table *tb);
+extern void mnt_unref_table(struct libmnt_table *tb);
+
extern int mnt_reset_table(struct libmnt_table *tb);
extern int mnt_table_get_nents(struct libmnt_table *tb);
+extern int mnt_table_is_empty(struct libmnt_table *tb);
+
+extern int mnt_table_set_userdata(struct libmnt_table *tb, void *data);
+extern void *mnt_table_get_userdata(struct libmnt_table *tb);
+
+extern void mnt_table_enable_comments(struct libmnt_table *tb, int enable);
+extern int mnt_table_with_comments(struct libmnt_table *tb);
+extern const char *mnt_table_get_intro_comment(struct libmnt_table *tb);
+extern int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm);
+extern int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm);
+extern int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm);
+extern const char *mnt_table_get_trailing_comment(struct libmnt_table *tb);
+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 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_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs);
+extern int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs);
+extern int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs);
extern int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs **fs);
extern int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
@@ -449,6 +478,9 @@ extern struct libmnt_update *mnt_new_update(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_update(struct libmnt_update *upd);
+extern int mnt_table_replace_file(struct libmnt_table *tb, const char *filename);
+extern int mnt_table_write_file(struct libmnt_table *tb, FILE *file);
+
extern int mnt_update_is_ready(struct libmnt_update *upd);
extern int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
const char *target, struct libmnt_fs *fs);
@@ -578,6 +610,10 @@ extern const char *mnt_context_get_source(struct libmnt_context *cxt);
extern const char *mnt_context_get_target(struct libmnt_context *cxt);
extern const char *mnt_context_get_fstype(struct libmnt_context *cxt);
+extern void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt);
+extern void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt);
+extern void *mnt_context_get_fs_userdata(struct libmnt_context *cxt);
+
extern int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr);
extern int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr);
@@ -715,10 +751,10 @@ extern int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status
#define MS_NODIRATIME 0x800 /* 2048: Don't update directory access times */
#endif
#ifndef MS_BIND
-#define MS_BIND 0x1000 /* 4096: Mount existing tree also elsewhere */
+#define MS_BIND 0x1000 /* 4096: Mount existing tree elsewhere as well */
#endif
#ifndef MS_MOVE
-#define MS_MOVE 0x2000 /* 8192: Atomically move tree */
+#define MS_MOVE 0x2000 /* 8192: Atomically move the tree */
#endif
#ifndef MS_REC
#define MS_REC 0x4000 /* 16384: Recursive loopback */
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index 2ea483989..d1180d35b 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -256,3 +256,38 @@ global:
mnt_context_find_umount_fs;
mnt_table_find_mountpoint;
} MOUNT_2.22;
+
+MOUNT_2.24 {
+global:
+ mnt_context_get_fstab_userdata;
+ mnt_context_get_fs_userdata;
+ mnt_context_get_mtab_userdata;
+ mnt_fs_append_comment;
+ mnt_fs_get_comment;
+ mnt_fs_set_comment;
+ mnt_ref_cache;
+ mnt_ref_fs;
+ mnt_ref_table;
+ mnt_table_append_intro_comment;
+ mnt_table_append_trailing_comment;
+ mnt_table_enable_comments;
+ mnt_table_first_fs;
+ mnt_table_get_intro_comment;
+ mnt_table_get_trailing_comment;
+ mnt_table_get_userdata;
+ mnt_table_is_empty;
+ mnt_table_last_fs;
+ mnt_table_replace_file;
+ mnt_table_set_intro_comment;
+ mnt_table_set_trailing_comment;
+ mnt_table_set_userdata;
+ mnt_table_with_comments;
+ mnt_table_write_file;
+ mnt_unref_cache;
+ mnt_unref_fs;
+ mnt_unref_table;
+} MOUNT_2.23;
+
+MOUNT_2.25 {
+ mnt_tag_is_valid;
+} MOUNT_2.24;
diff --git a/libmount/src/lock.c b/libmount/src/lock.c
index e73edf54b..d9b6f5939 100644
--- a/libmount/src/lock.c
+++ b/libmount/src/lock.c
@@ -10,9 +10,9 @@
* @title: Locking
* @short_description: locking methods for /etc/mtab or another libmount files
*
- * The mtab lock is backwardly compatible with the standard linux /etc/mtab
+ * The mtab lock is backwards compatible with the standard linux /etc/mtab
* locking. Note, it's necessary to use the same locking schema in all
- * application that access the file.
+ * applications that access the file.
*/
#include <sys/time.h>
#include <time.h>
@@ -21,6 +21,8 @@
#include <limits.h>
#include <sys/file.h>
+#include "strutils.h"
+#include "closestream.h"
#include "pathnames.h"
#include "mountP.h"
@@ -246,7 +248,7 @@ static void mnt_lockalrm_handler(int sig __attribute__((__unused__)))
/*
* Waits for F_SETLKW, unfortunately we have to use SIGALRM here to interrupt
- * fcntl() to avoid never ending waiting.
+ * fcntl() to avoid neverending waiting.
*
* Returns: 0 on success, 1 on timeout, -errno on error.
*/
@@ -292,7 +294,7 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* soon as the lock file is deleted by the first mount, and immediately
* afterwards a third mount comes, creates a new /etc/mtab~, applies
* flock to that, and also proceeds, so that the second and third mount
- * now both are scribbling in /etc/mtab.
+ * are now both scribbling in /etc/mtab.
*
* The new code uses a link() instead of a creat(), where we proceed
* only if it was us that created the lock, and hence we always have
@@ -307,13 +309,13 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* The original mount locking code has used sleep(1) between attempts and
* maximal number of attempts has been 5.
*
- * There was very small number of attempts and extremely long waiting (1s)
+ * There was a very small number of attempts and extremely long waiting (1s)
* that is useless on machines with large number of mount processes.
*
- * Now we wait few thousand microseconds between attempts and we have a global
- * time limit (30s) rather than limit for number of attempts. The advantage
+ * Now we wait for a few thousand microseconds between attempts and we have a global
+ * time limit (30s) rather than a limit for the number of attempts. The advantage
* is that this method also counts time which we spend in fcntl(F_SETLKW) and
- * number of attempts is not restricted.
+ * the number of attempts is not restricted.
* -- kzak@redhat.com [Mar-2007]
*
*
@@ -326,7 +328,7 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* -- kzak@redhat.com [May-2009]
*/
-/* maximum seconds between first and last attempt */
+/* maximum seconds between the first and the last attempt */
#define MOUNTLOCK_MAXTIME 30
/* sleep time (in microseconds, max=999999) between attempts */
@@ -339,9 +341,9 @@ static void unlock_mtab(struct libmnt_lock *ml)
if (!ml->locked && ml->lockfile && ml->linkfile)
{
- /* We have (probably) all files, but we don't own the lock,
+ /* We (probably) have all the files, but we don't own the lock,
* Really? Check it! Maybe ml->locked wasn't set properly
- * because code was interrupted by signal. Paranoia? Yes.
+ * because the code was interrupted by a signal. Paranoia? Yes.
*
* We own the lock when linkfile == lockfile.
*/
@@ -491,10 +493,10 @@ failed:
* mnt_lock_file
* @ml: pointer to struct libmnt_lock instance
*
- * Creates lock file (e.g. /etc/mtab~). Note that this function may
+ * Creates a lock file (e.g. /etc/mtab~). Note that this function may
* use alarm().
*
- * Your application has to always call mnt_unlock_file() before exit.
+ * Your application always has to call mnt_unlock_file() before exit.
*
* Traditional mtab locking scheme:
*
@@ -521,7 +523,7 @@ int mnt_lock_file(struct libmnt_lock *ml)
* mnt_unlock_file:
* @ml: lock struct
*
- * Unlocks the file. The function could be called independently on the
+ * Unlocks the file. The function could be called independently of the
* lock status (for example from exit(3)).
*/
void mnt_unlock_file(struct libmnt_lock *ml)
@@ -573,7 +575,9 @@ void increment_data(const char *filename, int verbose, int loopno)
err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
fprintf(f, "%ld", num);
- fclose(f);
+
+ if (close_stream(f) != 0)
+ err(EXIT_FAILURE, "write failed: %s", filename);
if (verbose)
fprintf(stderr, "%d: %s: %ld --> %ld (loop=%d)\n", getpid(),
@@ -667,7 +671,7 @@ int test_lock(struct libmnt_test *ts, int argc, char *argv[])
mnt_free_lock(lock);
lock = NULL;
- /* The mount command usually finish after mtab update. We
+ /* The mount command usually finishes after a mtab update. We
* simulate this via short sleep -- it's also enough to make
* concurrent processes happy.
*/
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index e064a6849..9362c0042 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -55,6 +55,13 @@
# include <stdio.h>
# include <stdarg.h>
+# define WARN_REFCOUNT(m, o, r) \
+ do { \
+ if ((MNT_DEBUG_ ## m) & libmount_debug_mask && r != 0) \
+ fprintf(stderr, "%d: libmount: %8s: [%p]: *** deallocates with refcount=%d\n", \
+ getpid(), # m, o, r); \
+ } while (0)
+
# define ON_DBG(m, x) do { \
if ((MNT_DEBUG_ ## m) & libmount_debug_mask) { \
x; \
@@ -100,6 +107,7 @@ mnt_debug_h(void *handler, const char *mesg, ...)
}
#else /* !CONFIG_LIBMOUNT_DEBUG */
+# define WARN_REFCOUNT(m,o,r) do { ; } while (0)
# define ON_DBG(m,x) do { ; } while (0)
# define DBG(m,x) do { ; } while (0)
# define DBG_FLUSH do { ; } while(0)
@@ -129,13 +137,11 @@ extern int mnt_run_test(struct libmnt_test *tests, int argc, char *argv[]);
#endif
/* utils.c */
-extern int endswith(const char *s, const char *sx)
- __attribute__((nonnull));
-extern int startswith(const char *s, const char *sx)
- __attribute__((nonnull));
-
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 int is_file_empty(const char *name);
extern int mkdir_p(const char *path, mode_t mode);
@@ -200,12 +206,13 @@ struct libmnt_iter {
/*
- * This struct represents one entry in mtab/fstab/mountinfo file.
+ * This struct represents one entry in a mtab/fstab/mountinfo file.
* (note that fstab[1] means the first column from fstab, and so on...)
*/
struct libmnt_fs {
struct list_head ents;
+ int refcount; /* reference counter */
int id; /* mountinfo[1]: ID */
int parent; /* mountinfo[2]: parent */
dev_t devno; /* mountinfo[3]: st_dev */
@@ -240,6 +247,8 @@ struct libmnt_fs {
int flags; /* MNT_FS_* flags */
pid_t tid; /* /proc/<tid>/mountinfo otherwise zero */
+ char *comment; /* fstab comment */
+
void *userdata; /* library independent data */
};
@@ -261,7 +270,11 @@ struct libmnt_fs {
*/
struct libmnt_table {
int fmt; /* MNT_FMT_* file format */
- int nents; /* number of valid entries */
+ int nents; /* number of entries */
+ int refcount; /* reference counter */
+ int comms; /* enable/disable comment parsing */
+ char *comm_intro; /* First comment in file */
+ char *comm_tail; /* Last comment in file */
struct libmnt_cache *cache; /* canonicalized paths/tags cache */
@@ -273,6 +286,7 @@ struct libmnt_table {
struct list_head ents; /* list of entries (libmnt_fs) */
+ void *userdata;
};
extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt);
@@ -373,17 +387,13 @@ struct libmnt_context
#define MNT_FL_FORK (1 << 12)
#define MNT_FL_NOSWAPMATCH (1 << 13)
-#define MNT_FL_EXTERN_FS (1 << 15) /* cxt->fs is not private */
-#define MNT_FL_EXTERN_FSTAB (1 << 16) /* cxt->fstab is not private */
-#define MNT_FL_EXTERN_CACHE (1 << 17) /* cxt->cache is not private */
-
#define MNT_FL_MOUNTDATA (1 << 20)
#define MNT_FL_TAB_APPLIED (1 << 21) /* mtab/fstab merged to cxt->fs */
#define MNT_FL_MOUNTFLAGS_MERGED (1 << 22) /* MS_* flags was read from optstr */
#define MNT_FL_SAVED_USER (1 << 23)
#define MNT_FL_PREPARED (1 << 24)
#define MNT_FL_HELPER (1 << 25) /* [u]mount.<type> */
-#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by library */
+#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by the library */
#define MNT_FL_MOUNTOPTS_FIXED (1 << 27)
/* default flags */
diff --git a/libmount/src/optmap.c b/libmount/src/optmap.c
index 7c0a23508..5b25b8f29 100644
--- a/libmount/src/optmap.c
+++ b/libmount/src/optmap.c
@@ -58,6 +58,7 @@
* mount/mount.h.
*/
#include "mountP.h"
+#include "strutils.h"
/*
* fs-independent mount flags (built-in MNT_LINUX_MAP)
@@ -78,7 +79,7 @@ static const struct libmnt_optmap linux_flags_map[] =
{ "dirsync", MS_DIRSYNC }, /* synchronous directory modifications */
{ "remount", MS_REMOUNT, MNT_NOMTAB }, /* alter flags of mounted FS */
- { "bind", MS_BIND }, /* Remount part of tree elsewhere */
+ { "bind", MS_BIND }, /* Remount part of the tree elsewhere */
{ "rbind", MS_BIND | MS_REC }, /* Idem, plus mounted subtrees */
#ifdef MS_NOSUB
{ "sub", MS_NOSUB, MNT_INVERT }, /* allow submounts */
@@ -133,7 +134,7 @@ static const struct libmnt_optmap userspace_opts_map[] =
{ "defaults", 0, 0 }, /* default options */
{ "auto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_INVERT | MNT_NOMTAB }, /* Can be mounted using -a */
- { "noauto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_NOMTAB }, /* Can only be mounted explicitly */
+ { "noauto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_NOMTAB }, /* Can only be mounted explicitly */
{ "user[=]", MNT_MS_USER }, /* Allow ordinary user to mount (mtab) */
{ "nouser", MNT_MS_USER, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary user to mount */
@@ -148,7 +149,7 @@ static const struct libmnt_optmap userspace_opts_map[] =
{ "nogroup", MNT_MS_GROUP, MNT_INVERT | MNT_NOMTAB }, /* Device group has no special privs */
/*
- * Note that traditional init scripts assume _netdev option in /etc/mtab to
+ * Note that traditional init scripts assume the _netdev option in /etc/mtab to
* umount network block devices on shutdown.
*/
{ "_netdev", MNT_MS_NETDEV }, /* Device requires network */
@@ -194,7 +195,7 @@ const struct libmnt_optmap *mnt_get_builtin_optmap(int id)
}
/*
- * Lookups for the @name in @maps and returns a map and in @mapent
+ * Looks up the @name in @maps and returns a map and in @mapent
* returns the map entry
*/
const struct libmnt_optmap *mnt_optmap_get_entry(
diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
index 5e9e70807..2cd55685e 100644
--- a/libmount/src/optstr.c
+++ b/libmount/src/optstr.c
@@ -8,10 +8,10 @@
/**
* SECTION: optstr
* @title: Options string
- * @short_description: low-level API for work with mount options
+ * @short_description: low-level API for working with mount options
*
- * This is simple and low-level API to work with mount options that are stored
- * in string.
+ * This is a simple and low-level API to working with mount options that are stored
+ * in a string.
*/
#include <ctype.h>
@@ -39,8 +39,8 @@ struct libmnt_optloc {
(e && (e)->name && !strchr((e)->name, '=') && !((e)->mask & MNT_PREFIX))
/*
- * Parses the first option from @optstr. The @optstr pointer is set to begin of
- * the next option.
+ * Parses the first option from @optstr. The @optstr pointer is set to the beginning
+ * of the next option.
*
* Returns -EINVAL on parse error, 1 at the end of optstr and 0 on success.
*/
@@ -72,12 +72,12 @@ static int mnt_optstr_parse_next(char **optstr, char **name, size_t *namesz,
for (p = optstr0; p && *p; p++) {
if (!start)
- start = p; /* begin of the option item */
+ start = p; /* beginning of the option item */
if (*p == '"')
open_quote ^= 1; /* reverse the status */
if (open_quote)
continue; /* still in quoted block */
- if (!sep && *p == '=')
+ if (!sep && p > start && *p == '=')
sep = p; /* name and value separator */
if (*p == ',')
stop = p; /* terminate the option item */
@@ -111,7 +111,7 @@ error:
}
/*
- * Locates the first option that match with @name. The @end is set to
+ * Locates the first option that matches @name. The @end is set to the
* char behind the option (it means ',' or \0).
*
* Returns negative number on parse error, 1 when not found and 0 on success.
@@ -150,11 +150,11 @@ static int mnt_optstr_locate_option(char *optstr, const char *name,
/**
* mnt_optstr_next_option:
- * @optstr: option string, returns position to next option
- * @name: returns option name
- * @namesz: returns option name length
- * @value: returns option value or NULL
- * @valuesz: returns option value length or zero
+ * @optstr: option string, returns the position of the next option
+ * @name: returns the option name
+ * @namesz: returns the option name length
+ * @value: returns the option value or NULL
+ * @valuesz: returns the option value length or zero
*
* Parses the first option in @optstr.
*
@@ -214,11 +214,11 @@ static int __mnt_optstr_append_option(char **optstr,
/**
* mnt_optstr_append_option:
- * @optstr: option string or NULL, returns reallocated string
+ * @optstr: option string or NULL, returns a reallocated string
* @name: value name
* @value: value
*
- * Returns: 0 on success or -1 in case of error. After error the @optstr should
+ * Returns: 0 on success or -1 in case of error. After an error the @optstr should
* be unmodified.
*/
int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
@@ -238,11 +238,11 @@ int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
/**
* mnt_optstr_prepend_option:
- * @optstr: option string or NULL, returns reallocated string
+ * @optstr: option string or NULL, returns a reallocated string
* @name: value name
* @value: value
*
- * Returns: 0 on success or -1 in case of error. After error the @optstr should
+ * Returns: 0 on success or -1 in case of error. After an error the @optstr should
* be unmodified.
*/
int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value)
@@ -275,9 +275,9 @@ int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value
/**
* mnt_optstr_get_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns a pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of the value or 0
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
@@ -306,7 +306,7 @@ int mnt_optstr_get_option(const char *optstr, const char *name,
/**
* mnt_optstr_deduplicate_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
*
* Removes all instances of @name except the last one.
@@ -331,12 +331,12 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
rc = mnt_optstr_locate_option(opt, name, &ol);
if (!rc) {
if (begin) {
- /* remove previous instance */
+ /* remove the previous instance */
size_t shift = strlen(*optstr);
mnt_optstr_remove_option_at(optstr, begin, end);
- /* now all offset are not valied anymore - recount */
+ /* now all the offsets are not valid anymore - recount */
shift -= strlen(*optstr);
ol.begin -= shift;
ol.end -= shift;
@@ -351,7 +351,7 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
}
/*
- * The result never starts or ends with comma or contains two commas
+ * The result never starts or ends with a comma or contains two commas
* (e.g. ",aaa,bbb" or "aaa,,bbb" or "aaa,")
*/
int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end)
@@ -387,14 +387,14 @@ insert_value(char **str, char *pos, const char *substr, char **next)
/* is it necessary to prepend '=' before the substring ? */
sep = !(pos > *str && *(pos - 1) == '=');
- /* save an offset of the place where we need add substr */
+ /* save an offset of the place where we need to add substr */
posoff = pos - *str;
p = realloc(*str, strsz + sep + subsz + 1);
if (!p)
return -ENOMEM;
- /* zeroize new allocated memory -- valgind loves is... */
+ /* zeroize the newly allocated memory -- valgrind loves us... */
memset(p + strsz, 0, sep + subsz + 1);
/* set pointers to the reallocated string */
@@ -402,7 +402,7 @@ insert_value(char **str, char *pos, const char *substr, char **next)
pos = p + posoff;
if (possz)
- /* create a room for new substring */
+ /* create a room for the new substring */
memmove(pos + subsz + sep, pos, possz + 1);
if (sep)
*pos++ = '=';
@@ -420,11 +420,11 @@ insert_value(char **str, char *pos, const char *substr, char **next)
/**
* mnt_optstr_set_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option
* @value: new value or NULL
*
- * Set or unset option @value.
+ * Set or unset the option @value.
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
* of error.
@@ -473,7 +473,7 @@ int mnt_optstr_set_option(char **optstr, const char *name, const char *value)
/**
* mnt_optstr_remove_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
@@ -510,13 +510,13 @@ int mnt_optstr_remove_option(char **optstr, const char *name)
*
* mnt_split_optstr(optstr, &u, NULL, NULL, MNT_NOMTAB, 0);
*
- * returns all userspace options, the options that does not belong to
+ * returns all userspace options, the options that do not belong to
* mtab are ignored.
*
* Note that FS options are all options that are undefined in MNT_USERSPACE_MAP
* or MNT_LINUX_MAP.
*
- * Returns: 0 on success, or negative number in case of error.
+ * Returns: 0 on success, or a negative number in case of error.
*/
int mnt_split_optstr(const char *optstr, char **user, char **vfs,
char **fs, int ignore_user, int ignore_vfs)
@@ -540,7 +540,7 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
if (user)
*user = NULL;
- while(!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
+ while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
int rc = 0;
const struct libmnt_optmap *ent = NULL;
const struct libmnt_optmap *m =
@@ -567,12 +567,18 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
rc = __mnt_optstr_append_option(fs, name, namesz,
val, valsz);
if (rc) {
- if (vfs)
+ if (vfs) {
free(*vfs);
- if (fs)
+ *vfs = NULL;
+ }
+ if (fs) {
free(*fs);
- if (user)
+ *fs = NULL;
+ }
+ if (user) {
free(*user);
+ *user = NULL;
+ }
return rc;
}
}
@@ -582,21 +588,21 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
/**
* mnt_optstr_get_options
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @subset: returns newly allocated string with options
* @map: options map
* @ignore: mask of the options that should be ignored
*
- * Extracts options from @optstr that belongs to the @map, for example:
+ * Extracts options from @optstr that belong to the @map, for example:
*
* mnt_optstr_get_options(optstr, &p,
* mnt_get_builtin_optmap(MNT_LINUX_MAP),
* MNT_NOMTAB);
*
- * the 'p' returns all VFS options, the options that does not belong to mtab
+ * the 'p' returns all VFS options, the options that do not belong to mtab
* are ignored.
*
- * Returns: 0 on success, or negative number in case of error.
+ * Returns: 0 on success, or a negative number in case of error.
*/
int mnt_optstr_get_options(const char *optstr, char **subset,
const struct libmnt_optmap *map, int ignore)
@@ -652,8 +658,8 @@ int mnt_optstr_get_options(const char *optstr, char **subset,
*
* "bind,noexec,foo,bar" --returns-> MS_BIND|MS_NOEXEC
*
- * Note that @flags are not zeroized by this function! This function set/unset
- * bites in the @flags only.
+ * Note that @flags are not zeroized by this function! This function sets/unsets
+ * bits in the @flags only.
*
* Returns: 0 on success or negative number in case of error
*/
@@ -747,8 +753,8 @@ int mnt_optstr_apply_flags(char **optstr, unsigned long flags,
fl = flags;
/*
- * There is a convetion that 'rw/ro' flags is always at the begin of
- * the string (athough the 'rw' is unnecessary).
+ * There is a convention that 'rw/ro' flags are always at the beginning of
+ * the string (although the 'rw' is unnecessary).
*/
if (map == mnt_get_builtin_optmap(MNT_LINUX_MAP)) {
const char *o = (fl & MS_RDONLY) ? "ro" : "rw";
@@ -774,7 +780,7 @@ int mnt_optstr_apply_flags(char **optstr, unsigned long flags,
if (next && *next) {
/*
* scan @optstr and remove options that are missing in
- * the @flags
+ * @flags
*/
while(!mnt_optstr_next_option(&next, &name, &namesz,
&val, &valsz)) {
@@ -856,7 +862,7 @@ err:
* modify @optstr and returns zero if libmount is compiled without SELinux
* support.
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
#ifndef HAVE_LIBSELINUX
int mnt_optstr_fix_secontext(char **optstr __attribute__ ((__unused__)),
@@ -910,7 +916,7 @@ int mnt_optstr_fix_secontext(char **optstr,
return -EINVAL;
- /* create quoted string from the raw context */
+ /* create a quoted string from the raw context */
sz = strlen((char *) raw);
if (!sz)
return -EINVAL;
@@ -947,8 +953,8 @@ static int set_uint_value(char **optstr, unsigned int num,
}
/*
- * @optstr: string with comma separated list of options
- * @value: pointer to the begin of the uid value
+ * @optstr: string with a comma separated list of options
+ * @value: pointer to the beginning of the uid value
* @valsz: size of the value
* @next: returns pointer to the next option (optional argument)
@@ -958,7 +964,7 @@ static int set_uint_value(char **optstr, unsigned int num,
* if (!mnt_optstr_get_option(optstr, "uid", &val, &valsz))
* mnt_optstr_fix_uid(&optstr, val, valsz, NULL);
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next)
{
@@ -998,14 +1004,14 @@ int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next)
}
/*
- * @optstr: string with comma separated list of options
- * @value: pointer to the begin of the uid value
+ * @optstr: string with a comma separated list of options
+ * @value: pointer to the beginning of the uid value
* @valsz: size of the value
* @next: returns pointer to the next option (optional argument)
* Translates "groupname" or "usergid" to the real GID.
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
int mnt_optstr_fix_gid(char **optstr, char *value, size_t valsz, char **next)
{
@@ -1328,7 +1334,7 @@ int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
{ "--append", test_append, "<optstr> <name> [<value>] append value to optstr" },
- { "--prepend",test_prepend,"<optstr> <name> [<value>] prepend value to optstr" },
+ { "--prepend",test_prepend,"<optstr> <name> [<value>] prepend value to optstr" },
{ "--set", test_set, "<optstr> <name> [<value>] (un)set value" },
{ "--get", test_get, "<optstr> <name> search name in optstr" },
{ "--remove", test_remove, "<optstr> <name> remove name in optstr" },
diff --git a/libmount/src/tab.c b/libmount/src/tab.c
index 11a297814..b023504ad 100644
--- a/libmount/src/tab.c
+++ b/libmount/src/tab.c
@@ -11,9 +11,9 @@
* @short_description: container for entries from fstab, mtab or mountinfo
*
* Note that mnt_table_find_* functions are mount(8) compatible. These functions
- * try to find an entry in more iterations where the first attempt is always
+ * try to find an entry in more iterations, where the first attempt is always
* based on comparison with unmodified (non-canonicalized or un-evaluated)
- * paths or tags. For example fstab with two entries:
+ * paths or tags. For example a fstab with two entries:
* <informalexample>
* <programlisting>
* LABEL=foo /foo auto rw
@@ -39,7 +39,7 @@
* mnt_table_find_source(tb, "UUID=anyuuid", &fs);
* </programlisting>
* </informalexample>
- * will returns the first entry (if UUID matches with the device).
+ * will return the first entry (if UUID matches with the device).
*/
#include <blkid.h>
@@ -47,6 +47,8 @@
#include "strutils.h"
#include "loopdev.h"
+static int is_mountinfo(struct libmnt_table *tb);
+
/**
* mnt_new_table:
*
@@ -66,7 +68,7 @@ struct libmnt_table *mnt_new_table(void)
return NULL;
DBG(TAB, mnt_debug_h(tb, "alloc"));
-
+ tb->refcount = 1;
INIT_LIST_HEAD(&tb->ents);
return tb;
}
@@ -75,7 +77,8 @@ struct libmnt_table *mnt_new_table(void)
* mnt_reset_table:
* @tb: tab pointer
*
- * Dealocates all entries (filesystems) from the table
+ * Removes all entries (filesystems) from the table. The filesystems with zero
+ * reference count will be deallocated.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -89,7 +92,7 @@ int mnt_reset_table(struct libmnt_table *tb)
while (!list_empty(&tb->ents)) {
struct libmnt_fs *fs = list_entry(tb->ents.next,
struct libmnt_fs, ents);
- mnt_free_fs(fs);
+ mnt_table_remove_fs(tb, fs);
}
tb->nents = 0;
@@ -97,10 +100,46 @@ int mnt_reset_table(struct libmnt_table *tb)
}
/**
+ * mnt_ref_table:
+ * @tb: table pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount++;
+ /*DBG(FS, mnt_debug_h(tb, "ref=%d", tb->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_table:
+ * @tb: table pointer
+ *
+ * De-increments reference counter, on zero the @tb is automatically
+ * deallocated by mnt_free_table().
+ */
+void mnt_unref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount--;
+ /*DBG(FS, mnt_debug_h(tb, "unref=%d", tb->refcount));*/
+ if (tb->refcount <= 0)
+ mnt_free_table(tb);
+ }
+}
+
+
+/**
* mnt_free_table:
* @tb: tab pointer
*
- * Deallocates tab struct and all entries.
+ * Deallocates the table. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_table().
+ *
+ * The table entries (filesystems) are unrefrenced by mnt_reset_table() and
+ * cache by mnt_unref_cache().
*/
void mnt_free_table(struct libmnt_table *tb)
{
@@ -109,7 +148,12 @@ void mnt_free_table(struct libmnt_table *tb)
mnt_reset_table(tb);
+ WARN_REFCOUNT(TAB, tb, tb->refcount);
DBG(TAB, mnt_debug_h(tb, "free"));
+
+ mnt_unref_cache(tb->cache);
+ free(tb->comm_intro);
+ free(tb->comm_tail);
free(tb);
}
@@ -117,26 +161,228 @@ void mnt_free_table(struct libmnt_table *tb)
* mnt_table_get_nents:
* @tb: pointer to tab
*
- * Returns: number of valid entries in tab.
+ * Returns: number of entries in table.
*/
int mnt_table_get_nents(struct libmnt_table *tb)
{
- assert(tb);
return tb ? tb->nents : 0;
}
/**
+ * mnt_table_is_empty:
+ * @tb: pointer to tab
+ *
+ * Returns: 1 if the table is without filesystems, or 0.
+ */
+int mnt_table_is_empty(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb == NULL || list_empty(&tb->ents) ? 1 : 0;
+}
+
+/**
+ * mnt_table_set_userdata:
+ * @tb: pointer to tab
+ * @data: pointer to user data
+ *
+ * Sets pointer to the private user data.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_userdata(struct libmnt_table *tb, void *data)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ tb->userdata = data;
+ return 0;
+}
+
+/**
+ * mnt_table_get_userdata:
+ * @tb: pointer to tab
+ *
+ * Returns: pointer to user's data.
+ */
+void *mnt_table_get_userdata(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->userdata : NULL;
+}
+
+/**
+ * mnt_table_enable_comments:
+ * @tb: pointer to tab
+ * @enable: TRUE or FALSE
+ *
+ * Enables parsing of comments.
+ *
+ * The initial (intro) file comment is accessible by
+ * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
+ * entry has to be separated by blank line. The filesystem comments are
+ * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
+ * by mnt_table_get_trailing_comment().
+ *
+ * <informalexample>
+ * <programlisting>
+ * #
+ * # Intro comment
+ * #
+ *
+ * # this comments belongs to the first fs
+ * LABEL=foo /mnt/foo auto defaults 1 2
+ * # this comments belongs to the second fs
+ * LABEL=bar /mnt/bar auto defaults 1 2
+ * # tailing comment
+ * </programlisting>
+ * </informalexample>
+ */
+void mnt_table_enable_comments(struct libmnt_table *tb, int enable)
+{
+ assert(tb);
+ if (tb)
+ tb->comms = enable;
+}
+
+/**
+ * mnt_table_with_comments:
+ * @tb: pointer to table
+ *
+ * Returns: 1 if comments parsing is enabled, or 0.
+ */
+int mnt_table_with_comments(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comms : 0;
+}
+
+/**
+ * mnt_table_get_intro_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: initial comment in tb
+ */
+const char *mnt_table_get_intro_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_intro : NULL;
+}
+
+/**
+ * mnt_table_set_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment or NULL
+ *
+ * Sets the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_intro);
+ tb->comm_intro = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_intro, comm);
+}
+
+/**
+ * mnt_table_get_trailing_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: table trailing comment
+ */
+const char *mnt_table_get_trailing_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_tail : NULL;
+}
+
+/**
+ * mnt_table_set_trailing_comment
+ * @tb: pointer to tab
+ * @comm: comment string
+ *
+ * Sets the trailing comment in table.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_tail);
+ tb->comm_tail = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_trailing_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends to the trailing table comment.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_tail, comm);
+}
+
+/**
* mnt_table_set_cache:
* @tb: pointer to tab
* @mpc: pointer to struct libmnt_cache instance
*
- * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
+ * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
* cache is recommended for mnt_table_find_*() functions.
*
* The cache could be shared between more tabs. Be careful when you share the
* same cache between more threads -- currently the cache does not provide any
* locking method.
*
+ * This function increments cache refrence counter. It's recomented to use
+ * mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
+ * referenced by @tb only.
+ *
* See also mnt_new_cache().
*
* Returns: 0 on success or negative number in case of error.
@@ -146,6 +392,9 @@ int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
assert(tb);
if (!tb)
return -EINVAL;
+
+ mnt_ref_cache(mpc); /* new */
+ mnt_unref_cache(tb->cache); /* old */
tb->cache = mpc;
return 0;
}
@@ -167,7 +416,9 @@ struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
* @tb: tab pointer
* @fs: new entry
*
- * Adds a new entry to tab.
+ * Adds a new entry to tab and increment @fs reference counter. Don't forget to
+ * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
+ * referenced by the table only.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -179,11 +430,12 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+ mnt_ref_fs(fs);
list_add_tail(&fs->ents, &tb->ents);
+ tb->nents++;
DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
- tb->nents++;
return 0;
}
@@ -192,6 +444,10 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
* @tb: tab pointer
* @fs: new entry
*
+ * Removes the @fs from the table and de-increment reference counter of the @fs. The
+ * filesystem with zero reference counter will be deallocated. Don't forget to use
+ * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
+ *
* Returns: 0 on success or negative number in case of error.
*/
int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
@@ -201,7 +457,11 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+
list_del(&fs->ents);
+ INIT_LIST_HEAD(&fs->ents); /* otherwise FS still points to the list */
+
+ mnt_unref_fs(fs);
tb->nents--;
return 0;
}
@@ -211,18 +471,18 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
* @tb: mountinfo file (/proc/self/mountinfo)
* @root: returns pointer to the root filesystem (/)
*
- * The function uses parent ID from mountinfo file to determine root filesystem
+ * The function uses the parent ID from the mountinfo file to determine the root filesystem
* (the filesystem with the smallest ID). The function is designed mostly for
- * applications where is necessary to sort mountpoints by IDs to get the tree
+ * applications where it is necessary to sort mountpoints by IDs to get the tree
* of the mountpoints (e.g. findmnt default output).
*
- * If you're not sure than use
+ * If you're not sure, then use
*
* mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
*
- * this is more robust and usable for arbitrary tab file (including fstab).
+ * this is more robust and usable for arbitrary tab files (including fstab).
*
- * Returns: 0 on success or less then zero case of error.
+ * Returns: 0 on success or negative number in case of error.
*/
int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
{
@@ -233,16 +493,16 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
assert(tb);
assert(root);
- if (!tb || !root)
+ if (!tb || !root || !is_mountinfo(tb))
return -EINVAL;
DBG(TAB, mnt_debug_h(tb, "lookup root fs"));
+ *root = NULL;
+
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
int id = mnt_fs_get_parent_id(fs);
- if (!id)
- break; /* @tab is not mountinfo file? */
if (!*root || id < root_id) {
*root = fs;
@@ -250,7 +510,7 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
}
}
- return root_id ? 0 : -EINVAL;
+ return *root ? 0 : -EINVAL;
}
/**
@@ -260,10 +520,10 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
* @parent: parental FS
* @chld: returns the next child filesystem
*
- * Note that filesystems are returned in the order how was mounted (according to
+ * Note that filesystems are returned in the order of mounting (according to
* IDs in /proc/self/mountinfo).
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*/
int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs *parent, struct libmnt_fs **chld)
@@ -271,15 +531,13 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs *fs;
int parent_id, lastchld_id = 0, chld_id = 0;
- if (!tb || !itr || !parent)
+ if (!tb || !itr || !parent || !is_mountinfo(tb))
return -EINVAL;
- DBG(TAB, mnt_debug_h(tb, "lookup next child of %s",
+ DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'",
mnt_fs_get_target(parent)));
parent_id = mnt_fs_get_id(parent);
- if (!parent_id)
- return -EINVAL;
/* get ID of the previously returned child */
if (itr->head && itr->p != itr->head) {
@@ -298,7 +556,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
id = mnt_fs_get_id(fs);
- /* avoid infinite loop. This only happens in rare cases
+ /* avoid an infinite loop. This only happens in rare cases
* such as in early userspace when the rootfs is its own parent */
if (id == parent_id)
continue;
@@ -310,7 +568,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
}
}
- if (!chld_id)
+ if (!*chld)
return 1; /* end of iterator */
/* set the iterator to the @chld for the next call */
@@ -325,7 +583,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* @itr: iterator
* @fs: returns the next tab entry
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*
* Example:
* <informalexample>
@@ -334,11 +592,10 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* const char *dir = mnt_fs_get_target(fs);
* printf("mount point: %s\n", dir);
* }
- * mnt_free_table(fi);
* </programlisting>
* </informalexample>
*
- * lists all mountpoints from fstab in backward order.
+ * lists all mountpoints from fstab in reverse order.
*/
int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
{
@@ -363,14 +620,54 @@ int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct l
}
/**
+ * mnt_table_first_fs:
+ * @tb: tab pointer
+ * @fs: returns the first tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
+ * mnt_table_last_fs:
+ * @tb: tab pointer
+ * @fs: returns the last tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_last_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
* mnt_table_find_next_fs:
* @tb: table
* @itr: iterator
- * @match_func: function returns 1 or 0
+ * @match_func: function returning 1 or 0
* @userdata: extra data for match_func
* @fs: returns pointer to the next matching table entry
*
- * This function allows search in @tb.
+ * This function allows searching in @tb.
*
* Returns: negative number in case of error, 1 at end of table or 0 o success.
*/
@@ -431,7 +728,7 @@ int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct
* @path: directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Same like mnt_get_mountpoint(), but this function does not rely on
+ * Same as mnt_get_mountpoint(), except this function does not rely on
* st_dev numbers.
*
* Returns: a tab entry or NULL.
@@ -442,12 +739,12 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
{
char *mnt;
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: '%s'", path));
mnt = strdup(path);
if (!mnt)
@@ -478,10 +775,10 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
* @path: mountpoint directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are three iterations, first
- * with @path, second with realpath(@path) and third with realpath(@path)
+ * Try to lookup an entry in the given tab, three iterations are possible, the first
+ * with @path, the second with realpath(@path) and the third with realpath(@path)
* against realpath(fs->target). The 2nd and 3rd iterations are not performed
- * when @tb cache is not set (see mnt_table_set_cache()).
+ * when the @tb cache is not set (see mnt_table_set_cache()).
*
* Returns: a tab entry or NULL.
*/
@@ -494,12 +791,12 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
assert(tb);
assert(path);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup TARGET: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup TARGET: '%s'", path));
/* native @target */
mnt_reset_iter(&itr, direction);
@@ -510,6 +807,8 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical TARGET: '%s'", cn));
+
/* canonicalized paths in struct libmnt_table */
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -519,7 +818,7 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
/* non-canonicaled path in struct libmnt_table
* -- note that mountpoint in /proc/self/mountinfo is already
- * canonicalized by kernel
+ * canonicalized by the kernel
*/
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -545,11 +844,11 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
* @path: source path (devname or dirname) or NULL
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are four iterations, first
- * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
- * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
+ * Try to lookup an entry in the given tab, four iterations are possible, the first
+ * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
+ * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
*
- * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
+ * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
* set (see mnt_table_set_cache()).
*
* Note that NULL is a valid source path; it will be replaced with "none". The
@@ -561,17 +860,17 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
{
struct libmnt_iter itr;
struct libmnt_fs *fs = NULL;
- int ntags = 0;
+ int ntags = 0, nents;
char *cn;
const char *p;
assert(tb);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup srcpath: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup SRCPATH: '%s'", path));
/* native paths */
mnt_reset_iter(&itr, direction);
@@ -585,8 +884,12 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
if (!path || !tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical SRCPATH: '%s'", cn));
+
+ nents = mnt_table_get_nents(tb);
+
/* canonicalized paths in struct libmnt_table */
- if (ntags < mnt_table_get_nents(tb)) {
+ if (ntags < nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_streq_srcpath(fs, cn))
@@ -612,9 +915,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
return fs;
}
} else if (rc < 0 && errno == EACCES) {
- /* @path is unaccessible, try evaluate all TAGs in @tb
+ /* @path is inaccessible, try evaluating all TAGs in @tb
* by udev symlinks -- this could be expensive on systems
- * with huge fstab/mtab */
+ * with a huge fstab/mtab */
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *t, *v, *x;
if (mnt_fs_get_tag(fs, &t, &v))
@@ -629,7 +932,7 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
}
/* non-canonicalized paths in struct libmnt_table */
- if (ntags <= mnt_table_get_nents(tb)) {
+ if (ntags <= nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
@@ -655,9 +958,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
* @val: tag value
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, first attempt is lookup by @tag and
+ * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
* @val, for the second attempt the tag is evaluated (converted to the device
- * name) and mnt_table_find_srcpath() is preformed. The second attempt is not
+ * name) and mnt_table_find_srcpath() is performed. The second attempt is not
* performed when @tb cache is not set (see mnt_table_set_cache()).
* Returns: a tab entry or NULL.
@@ -672,7 +975,7 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
assert(tag);
assert(val);
- if (!tb || !tag || !val)
+ if (!tb || !tag || !*tag || !val)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -703,16 +1006,17 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
* @source: TAG or path
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * This is high-level API for mnt_table_find_{srcpath,tag}. You needn't to care
- * about @source format (device, LABEL, UUID, ...). This function parses @source
- * and calls mnt_table_find_tag() or mnt_table_find_srcpath().
+ * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
+ * about the @source format (device, LABEL, UUID, ...). This function parses
+ * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
*
* Returns: a tab entry or NULL.
*/
struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
const char *source, int direction)
{
- struct libmnt_fs *fs = NULL;
+ struct libmnt_fs *fs;
+ char *t = NULL, *v = NULL;
assert(tb);
@@ -721,20 +1025,15 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s", source));
-
- if (source && strchr(source, '=')) {
- char *tag, *val;
+ DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source));
- if (blkid_parse_tag_string(source, &tag, &val) == 0) {
-
- fs = mnt_table_find_tag(tb, tag, val, direction);
-
- free(tag);
- free(val);
- }
- } else
+ if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
fs = mnt_table_find_srcpath(tb, source, direction);
+ else
+ fs = mnt_table_find_tag(tb, t, v, direction);
+
+ free(t);
+ free(v);
return fs;
}
@@ -747,7 +1046,7 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
* This function is implemented by mnt_fs_match_source() and
- * mnt_fs_match_target() functions. It means that this is more expensive that
+ * mnt_fs_match_target() functions. It means that this is more expensive than
* others mnt_table_find_* function, because every @tab entry is fully evaluated.
*
* Returns: a tab entry or NULL.
@@ -761,7 +1060,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
assert(tb);
assert(target);
- if (!tb || !target)
+ if (!tb || !target || !*target || !source || !*source)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -785,7 +1084,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
* @devno: device number
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Note that zero could be valid device number for root pseudo filesystem (e.g.
+ * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
* tmpfs).
*
* Returns: a tab entry or NULL.
@@ -819,7 +1118,7 @@ struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
* tb: /proc/self/mountinfo
* fs: filesystem
* mountflags: MS_BIND or 0
- * fsroot: fs-root that will be probably used in the mountinfo file
+ * fsroot: fs-root that will probably be used in the mountinfo file
* for @fs after mount(2)
*
* For btrfs subvolumes this function returns NULL, but @fsroot properly set.
@@ -841,7 +1140,7 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
assert(fs);
assert(fsroot);
- DBG(TAB, mnt_debug("lookup fs-root for %s", mnt_fs_get_source(fs)));
+ DBG(TAB, mnt_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
fstype = mnt_fs_get_fstype(fs);
@@ -945,20 +1244,20 @@ static int is_mountinfo(struct libmnt_table *tb)
}
/**
- * mnt_table_is_mounted:
+ * mnt_table_is_fs__mounted:
* @tb: /proc/self/mountinfo file
* @fstab_fs: /etc/fstab entry
*
* Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
- * ignored. This function explicitly compares source, target and root of the
+ * ignored. This function explicitly compares the source, target and root of the
* filesystems.
*
* Note that source and target are canonicalized only if a cache for @tb is
* defined (see mnt_table_set_cache()). The target canonicalization may
- * triggers automount on autofs mountpoints!
+ * trigger automount on autofs mountpoints!
*
* Don't use it if you want to know if a device is mounted, just use
- * mnt_table_find_source() for the device.
+ * mnt_table_find_source() on the device.
*
* This function is designed mostly for "mount -a".
*
@@ -973,6 +1272,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
const char *src = NULL, *tgt = NULL;
char *xtgt = NULL;
int rc = 0;
+ dev_t devno = 0;
assert(tb);
assert(fstab_fs);
@@ -980,7 +1280,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
DBG(FS, mnt_debug_h(fstab_fs, "is FS mounted? [target=%s]",
mnt_fs_get_target(fstab_fs)));
- if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_get_nents(tb) == 0) {
+ if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_is_empty(tb)) {
DBG(FS, mnt_debug_h(fstab_fs, "- ignore (swap or no data)"));
return 0;
}
@@ -1004,6 +1304,14 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
if (src && tb->cache && !mnt_fs_is_pseudofs(fstab_fs))
src = mnt_resolve_spec(src, tb->cache);
+ if (src && root) {
+ struct stat st;
+
+ devno = mnt_fs_get_devno(fstab_fs);
+ if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
+ devno = st.st_rdev;
+ }
+
tgt = mnt_fs_get_target(fstab_fs);
if (!tgt || !src) {
@@ -1014,7 +1322,12 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
- if (!mnt_fs_streq_srcpath(fs, src)) {
+ int eq = mnt_fs_streq_srcpath(fs, src);
+
+ if (!eq && devno && mnt_fs_get_devno(fs) == devno)
+ eq = 1;
+
+ if (!eq) {
/* The source does not match. Maybe the source is a loop
* device backing file.
*/
@@ -1046,7 +1359,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
}
/*
- * Compare target, try to minimize number of situations when we
+ * Compare target, try to minimize the number of situations when we
* need to canonicalize the path to avoid readlink() on
* mountpoints.
*/
@@ -1076,10 +1389,10 @@ static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
{
fprintf(stderr, "%s:%d: parse error\n", filename, line);
- return 1; /* all errors are recoverable -- this is default */
+ return 1; /* all errors are recoverable -- this is the default */
}
-struct libmnt_table *create_table(const char *file)
+struct libmnt_table *create_table(const char *file, int comments)
{
struct libmnt_table *tb;
@@ -1089,6 +1402,7 @@ struct libmnt_table *create_table(const char *file)
if (!tb)
goto err;
+ mnt_table_enable_comments(tb, comments);
mnt_table_set_parser_errcb(tb, parser_errcb);
if (mnt_table_parse_file(tb, file) != 0)
@@ -1096,7 +1410,7 @@ struct libmnt_table *create_table(const char *file)
return tb;
err:
fprintf(stderr, "%s: parsing failed\n", file);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return NULL;
}
@@ -1106,7 +1420,7 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_fs *fs;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
@@ -1123,10 +1437,10 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
printf("COPY:\n");
mnt_fs_print_debug(fs, stdout);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
rc = 0;
done:
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1136,8 +1450,12 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_iter *itr = NULL;
struct libmnt_fs *fs;
int rc = -1;
+ int parse_comments = FALSE;
- tb = create_table(argv[1]);
+ if (argc == 3 && !strcmp(argv[2], "--comments"))
+ parse_comments = TRUE;
+
+ tb = create_table(argv[1], parse_comments);
if (!tb)
return -1;
@@ -1145,12 +1463,20 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
if (!itr)
goto done;
+ if (mnt_table_get_intro_comment(tb))
+ fprintf(stdout, "Initial comment:\n\"%s\"\n",
+ mnt_table_get_intro_comment(tb));
+
while(mnt_table_next_fs(tb, itr, &fs) == 0)
mnt_fs_print_debug(fs, stdout);
+
+ if (mnt_table_get_trailing_comment(tb))
+ fprintf(stdout, "Trailing comment:\n\"%s\"\n",
+ mnt_table_get_trailing_comment(tb));
rc = 0;
done:
mnt_free_iter(itr);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1169,7 +1495,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
file = argv[1], find = argv[2], what = argv[3];
- tb = create_table(file);
+ tb = create_table(file, FALSE);
if (!tb)
goto done;
@@ -1178,6 +1504,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
if (strcasecmp(find, "source") == 0)
fs = mnt_table_find_source(tb, what, dr);
@@ -1191,8 +1518,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
rc = 0;
}
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1213,13 +1539,14 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_cache *mpc = NULL;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
mpc = mnt_new_cache();
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
if (!fs)
@@ -1228,8 +1555,7 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1247,6 +1573,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_mountpoint(tb, argv[1], MNT_ITER_BACKWARD);
if (!fs)
@@ -1255,8 +1582,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1274,7 +1600,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
return -1;
}
- fstab = create_table(argv[1]);
+ fstab = create_table(argv[1], FALSE);
if (!fstab)
goto done;
@@ -1286,6 +1612,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
if (mnt_table_is_fs_mounted(tb, fs))
@@ -1300,9 +1627,8 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_table(fstab);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
+ mnt_unref_table(fstab);
mnt_free_iter(itr);
return rc;
}
@@ -1310,7 +1636,7 @@ done:
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
- { "--parse", test_parse, "<file> parse and print tab" },
+ { "--parse", test_parse, "<file> [--comments] parse and print tab" },
{ "--find-forward", test_find_fw, "<file> <source|target> <string>" },
{ "--find-backward", test_find_bw, "<file> <source|target> <string>" },
{ "--find-pair", test_find_pair, "<file> <source> <target>" },
diff --git a/libmount/src/tab_diff.c b/libmount/src/tab_diff.c
index f01f889f8..052278233 100644
--- a/libmount/src/tab_diff.c
+++ b/libmount/src/tab_diff.c
@@ -25,7 +25,7 @@ struct libmnt_tabdiff {
int nchanges; /* number of changes */
struct list_head changes; /* list with modified entries */
- struct list_head unused; /* list with unuused entries */
+ struct list_head unused; /* list with unused entries */
};
/**
@@ -54,6 +54,8 @@ static void free_tabdiff_entry(struct tabdiff_entry *de)
if (!de)
return;
list_del(&de->changes);
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
free(de);
}
@@ -89,7 +91,7 @@ void mnt_free_tabdiff(struct libmnt_tabdiff *df)
*
* The options @old_fs, @new_fs and @oper are optional.
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*/
int mnt_tabdiff_next_change(struct libmnt_tabdiff *df, struct libmnt_iter *itr,
struct libmnt_fs **old_fs, struct libmnt_fs **new_fs, int *oper)
@@ -124,9 +126,9 @@ static int tabdiff_reset(struct libmnt_tabdiff *df)
{
assert(df);
- DBG(DIFF, mnt_debug_h(df, "reseting"));
+ DBG(DIFF, mnt_debug_h(df, "resetting"));
- /* zeroize all entries and move them to the list of unuused
+ /* zeroize all entries and move them to the list of unused
*/
while (!list_empty(&df->changes)) {
struct tabdiff_entry *de = list_entry(df->changes.next,
@@ -135,6 +137,9 @@ static int tabdiff_reset(struct libmnt_tabdiff *df)
list_del(&de->changes);
list_add_tail(&de->changes, &df->unused);
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
+
de->new_fs = de->old_fs = NULL;
de->oper = 0;
}
@@ -164,6 +169,12 @@ static int tabdiff_add_entry(struct libmnt_tabdiff *df, struct libmnt_fs *old,
INIT_LIST_HEAD(&de->changes);
+ mnt_ref_fs(new);
+ mnt_ref_fs(old);
+
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
+
de->old_fs = old;
de->new_fs = new;
de->oper = oper;
@@ -280,6 +291,8 @@ int mnt_diff_tables(struct libmnt_tabdiff *df, struct libmnt_table *old_tab,
de = tabdiff_get_mount(df, src, mnt_fs_get_id(fs));
if (de) {
+ mnt_ref_fs(fs);
+ mnt_unref_fs(de->old_fs);
de->oper = MNT_TABDIFF_MOVE;
de->old_fs = fs;
} else
@@ -342,8 +355,8 @@ int test_diff(struct libmnt_test *ts, int argc, char *argv[])
rc = 0;
done:
- mnt_free_table(tb_old);
- mnt_free_table(tb_new);
+ mnt_unref_table(tb_old);
+ mnt_unref_table(tb_new);
mnt_free_tabdiff(diff);
mnt_free_iter(itr);
return rc;
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index e930fd841..38c48fdfa 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -47,7 +47,7 @@ static int next_number(char **s, int *num)
*s = end;
- /* valid end of number is space or terminator */
+ /* valid end of number is a space or a terminator */
if (*end == ' ' || *end == '\t' || *end == '\0')
return 0;
return -1;
@@ -82,7 +82,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s)
if (optstr && *optstr)
unmangle_string(optstr);
- /* note that __foo functions does not reallocate the string
+ /* note that __foo functions do not reallocate the string
*/
rc = __mnt_fs_set_source_ptr(fs, src);
if (!rc) {
@@ -128,7 +128,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s)
}
/*
- * Parses one line from mountinfo file
+ * Parses one line from a mountinfo file
*/
static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
{
@@ -158,7 +158,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
/* (7) optional fields, terminated by " - " */
p = strstr(s, " - ");
if (!p) {
- DBG(TAB, mnt_debug("mountinfo parse error: not found separator"));
+ DBG(TAB, mnt_debug("mountinfo parse error: separator not found"));
return -EINVAL;
}
if (p > s + 1)
@@ -174,9 +174,20 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
&fs->fs_optstr);
if (rc >= 10) {
+ size_t sz;
+
fs->flags |= MNT_FS_KERNEL;
fs->devno = makedev(maj, min);
+ /* remove "(deleted)" suffix */
+ sz = strlen(fs->target);
+ if (sz > PATH_DELETED_SUFFIX_SZ) {
+ char *p = fs->target + (sz - PATH_DELETED_SUFFIX_SZ);
+
+ if (strcmp(p, PATH_DELETED_SUFFIX) == 0)
+ *p = '\0';
+ }
+
unmangle_string(fs->root);
unmangle_string(fs->target);
unmangle_string(fs->vfs_optstr);
@@ -192,7 +203,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
src = NULL;
}
- /* merge VFS and FS options to the one string */
+ /* merge VFS and FS options to one string */
fs->optstr = mnt_fs_strdup_options(fs);
if (!fs->optstr)
rc = -ENOMEM;
@@ -323,8 +334,8 @@ static int mnt_parse_swaps_line(struct libmnt_fs *fs, char *s)
/*
* Returns {m,fs}tab or mountinfo file format (MNT_FMT_*)
*
- * Note that we aren't trying to guess utab file format, because this file has
- * to be always parsed by private libmount routines with explicitly defined
+ * Note that we aren't trying to guess the utab file format, because this file
+ * always has to be parsed by private libmount routines with an explicitly defined
* format.
*
* mountinfo: "<number> <number> ... "
@@ -344,10 +355,82 @@ static int guess_table_format(char *line)
return MNT_FMT_FSTAB; /* fstab, mtab or /proc/mounts */
}
+static int is_comment_line(char *line)
+{
+ char *p = skip_spaces(line);
+
+ if (p && (*p == '#' || *p == '\n'))
+ return 1;
+ return 0;
+}
+
+/* returns 1 if the last line in the @str is blank */
+static int is_terminated_by_blank(const char *str)
+{
+ size_t sz = str ? strlen(str) : 0;
+ const char *p = sz ? str + (sz - 1) : NULL;
+
+ if (!sz || !p || *p != '\n')
+ return 0; /* empty or not terminated by '\n' */
+ if (p == str)
+ return 1; /* only '\n' */
+ p--;
+ while (p >= str && (*p == ' ' || *p == '\t'))
+ p--;
+ return *p == '\n' ? 1 : 0;
+}
+
+/*
+ * Reads the next line from the file.
+ *
+ * Returns 0 if the line is a comment
+ * 1 if the line is not a comment
+ * <0 on error
+ */
+static int next_comment_line(char *buf, size_t bufsz,
+ FILE *f, char **last, int *nlines)
+{
+ if (fgets(buf, bufsz, f) == NULL)
+ return feof(f) ? 1 : -EINVAL;
+
+ ++*nlines;
+ *last = strchr(buf, '\n');
+
+ return is_comment_line(buf) ? 0 : 1;
+}
+
+static int append_comment(struct libmnt_table *tb,
+ struct libmnt_fs *fs,
+ const char *comm,
+ int eof)
+{
+ int rc, intro = mnt_table_get_nents(tb) == 0;
+
+ if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb)))
+ intro = 0;
+
+ DBG(TAB, mnt_debug_h(tb, "appending %s comment",
+ intro ? "intro" :
+ eof ? "trailing" : "fs"));
+ if (intro)
+ rc = mnt_table_append_intro_comment(tb, comm);
+ else if (eof) {
+ rc = mnt_table_set_trailing_comment(tb,
+ mnt_fs_get_comment(fs));
+ if (!rc)
+ rc = mnt_table_append_trailing_comment(tb, comm);
+ if (!rc)
+ rc = mnt_fs_set_comment(fs, NULL);
+ } else
+ rc = mnt_fs_append_comment(fs, comm);
+ return rc;
+}
+
/*
* Read and parse the next line from {fs,m}tab or mountinfo
*/
-static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f, struct libmnt_fs *fs,
+static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f,
+ struct libmnt_fs *fs,
const char *filename, int *nlines)
{
char buf[BUFSIZ];
@@ -366,7 +449,7 @@ next_line:
++*nlines;
s = strchr (buf, '\n');
if (!s) {
- /* Missing final newline? Otherwise extremely */
+ /* Missing final newline? Otherwise an extremely */
/* long line - assume file was corrupted */
if (feof(f)) {
DBG(TAB, mnt_debug_h(tb,
@@ -379,6 +462,26 @@ next_line:
goto err;
}
}
+
+ /* comments parser */
+ if (tb->comms
+ && (tb->fmt == MNT_FMT_GUESS || tb->fmt == MNT_FMT_FSTAB)
+ && is_comment_line(buf)) {
+ do {
+ rc = append_comment(tb, fs, buf, feof(f));
+ if (!rc)
+ rc = next_comment_line(buf,
+ sizeof(buf),
+ f, &s, nlines);
+ } while (rc == 0);
+
+ if (rc == 1 && feof(f))
+ rc = append_comment(tb, fs, NULL, 1);
+ if (rc < 0)
+ return rc;
+
+ }
+
*s = '\0';
if (--s >= buf && *s == '\r')
*s = '\0';
@@ -420,7 +523,7 @@ err:
tb->fmt == MNT_FMT_FSTAB ? "tab" : "utab"));
/* by default all errors are recoverable, otherwise behavior depends on
- * errcb() function. See mnt_table_set_parser_errcb().
+ * the errcb() function. See mnt_table_set_parser_errcb().
*/
return tb->errcb ? tb->errcb(tb, filename, *nlines) : 1;
}
@@ -461,7 +564,7 @@ static int kernel_fs_postparse(struct libmnt_table *tb,
int rc = 0;
const char *src = mnt_fs_get_srcpath(fs);
- /* This is filesystem description from /proc, so we're in some process
+ /* This is a filesystem description from /proc, so we're in some process
* namespace. Let's remember the process PID.
*/
if (filename && *tid == -1)
@@ -538,8 +641,9 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam
if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO)
rc = kernel_fs_postparse(tb, fs, &tid, filename);
}
+ mnt_unref_fs(fs);
+
if (rc) {
- mnt_free_fs(fs);
if (rc == 1)
continue; /* recoverable error */
if (feof(f))
@@ -561,10 +665,10 @@ err:
* @tb: tab pointer
* @filename: file
*
- * Parses whole table (e.g. /etc/mtab) and appends new records to the @tab.
+ * Parses the whole table (e.g. /etc/mtab) and appends new records to the @tab.
*
* The libmount parser ignores broken (syntax error) lines, these lines are
- * reported to caller by errcb() function (see mnt_table_set_parser_errcb()).
+ * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -663,7 +767,7 @@ static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
if (n <= 0)
return 0;
- /* let use "at" functions rather than play crazy games with paths... */
+ /* let's use "at" functions rather than playing crazy games with paths... */
dir = opendir(dirname);
if (!dir) {
r = -errno;
@@ -704,7 +808,7 @@ out:
*
* The directory:
* - files are sorted by strverscmp(3)
- * - files that starts with "." are ignored (e.g. ".10foo.fstab")
+ * - files that start with "." are ignored (e.g. ".10foo.fstab")
* - files without the ".fstab" extension are ignored
*
* Returns: 0 on success or negative number in case of error.
@@ -728,7 +832,7 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
if (tb) {
tb->fmt = fmt;
if (mnt_table_parse_file(tb, filename) != 0) {
- mnt_free_table(tb);
+ mnt_unref_table(tb);
tb = NULL;
}
}
@@ -740,7 +844,7 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
* @filename: /etc/{m,fs}tab or /proc/self/mountinfo path
*
* Same as mnt_new_table() + mnt_table_parse_file(). Use this function for private
- * files only. This function does not allow to use error callback, so you
+ * files only. This function does not allow using the error callback, so you
* cannot provide any feedback to end-users about broken records in files (e.g.
* fstab).
*
@@ -767,7 +871,7 @@ struct libmnt_table *mnt_new_table_from_dir(const char *dirname)
return NULL;
tb = mnt_new_table();
if (tb && mnt_table_parse_dir(tb, dirname) != 0) {
- mnt_free_table(tb);
+ mnt_unref_table(tb);
tb = NULL;
}
return tb;
@@ -779,13 +883,13 @@ struct libmnt_table *mnt_new_table_from_dir(const char *dirname)
* @cb: pointer to callback function
*
* The error callback function is called by table parser (mnt_table_parse_file())
- * in case of syntax error. The callback function could be used for errors
+ * in case of a syntax error. The callback function could be used for error
* evaluation, libmount will continue/stop parsing according to callback return
* codes:
*
* <0 : fatal error (abort parsing)
- * 0 : success (parsing continue)
- * >0 : recoverable error (the line is ignored, parsing continue).
+ * 0 : success (parsing continues)
+ * >0 : recoverable error (the line is ignored, parsing continues).
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -800,7 +904,7 @@ int mnt_table_set_parser_errcb(struct libmnt_table *tb,
}
/*
- * Filter out entries during tab file parsing. If @cb returns 1 then the entry
+ * Filter out entries during tab file parsing. If @cb returns 1, then the entry
* is ignored.
*/
int mnt_table_set_parser_fltrcb(struct libmnt_table *tb,
@@ -851,7 +955,7 @@ int mnt_table_parse_swaps(struct libmnt_table *tb, const char *filename)
* @filename: overwrites default (/etc/fstab or $LIBMOUNT_FSTAB) or NULL
*
* This function parses /etc/fstab and appends new lines to the @tab. If the
- * @filename is a directory then mnt_table_parse_dir() is called.
+ * @filename is a directory, then mnt_table_parse_dir() is called.
*
* See also mnt_table_set_parser_errcb().
*
@@ -884,7 +988,7 @@ int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename)
}
/*
- * This function uses @uf to found corresponding record in @tb, then the record
+ * This function uses @uf to find a corresponding record in @tb, then the record
* from @tb is updated (user specific mount options are added).
*
* Note that @uf must contain only user specific mount options instead of
@@ -986,7 +1090,7 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
if (mnt_table_get_nents(tb) == 0)
return 0; /* empty, ignore utab */
/*
- * try to read user specific information from /run/mount/utabs
+ * try to read the user specific information from /run/mount/utabs
*/
utab = mnt_get_utab_path();
if (!utab || is_file_empty(utab))
@@ -1005,11 +1109,11 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
- /* merge user options into mountinfo from kernel */
+ /* merge user options into mountinfo from the kernel */
while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
mnt_table_merge_user_fs(tb, u_fs);
}
- mnt_free_table(u_tb);
+ mnt_unref_table(u_tb);
return 0;
}
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
index 1e7f32be0..13f6f6ebe 100644
--- a/libmount/src/tab_update.c
+++ b/libmount/src/tab_update.c
@@ -10,10 +10,10 @@
* @title: Tables update
* @short_description: userspace mount information management
*
- * The struct libmnt_update provides abstraction to manage mount options in
- * userspace independently on system configuration. This low-level API works on
- * system with and without /etc/mtab. On systems without the regular /etc/mtab
- * file are userspace mount options (e.g. user=) stored to the /run/mount/utab
+ * The struct libmnt_update provides an abstraction to manage mount options in
+ * userspace independently of system configuration. This low-level API works on
+ * systems both with and without /etc/mtab. On systems without the regular /etc/mtab
+ * file, the userspace mount options (e.g. user=) are stored in the /run/mount/utab
* file.
*
* It's recommended to use high-level struct libmnt_context API.
@@ -70,8 +70,8 @@ void mnt_free_update(struct libmnt_update *upd)
DBG(UPDATE, mnt_debug_h(upd, "free"));
- mnt_free_fs(upd->fs);
- mnt_free_table(upd->mountinfo);
+ mnt_unref_fs(upd->fs);
+ mnt_unref_table(upd->mountinfo);
free(upd->target);
free(upd->filename);
free(upd);
@@ -125,7 +125,7 @@ int mnt_update_set_filename(struct libmnt_update *upd, const char *filename,
* mnt_update_get_filename:
* @upd: update
*
- * This function returns file name (e.g. /etc/mtab) for the up-dated file.
+ * This function returns the file name (e.g. /etc/mtab) of the up-dated file.
*
* Returns: pointer to filename that will be updated or NULL in case of error.
*/
@@ -140,7 +140,7 @@ const char *mnt_update_get_filename(struct libmnt_update *upd)
* @upd: update handler
*
* Returns: 1 if entry described by @upd is successfully prepared and will be
- * written to mtab/utab file.
+ * written to the mtab/utab file.
*/
int mnt_update_is_ready(struct libmnt_update *upd)
{
@@ -180,7 +180,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
}
- mnt_free_fs(upd->fs);
+ mnt_unref_fs(upd->fs);
free(upd->target);
upd->ready = FALSE;
upd->fs = NULL;
@@ -287,10 +287,10 @@ int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
}
/*
- * Allocates utab entry (upd->fs) for mount/remount. This function should be
+ * Allocates an utab entry (upd->fs) for mount/remount. This function should be
* called *before* mount(2) syscall. The @fs is used as a read-only template.
*
- * Returns: 0 on success, negative number on error, 1 if utabs update is
+ * Returns: 0 on success, negative number on error, 1 if utab's update is
* unnecessary.
*/
static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
@@ -350,14 +350,14 @@ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
return 0;
err:
free(u);
- mnt_free_fs(upd->fs);
+ mnt_unref_fs(upd->fs);
upd->fs = NULL;
return rc;
}
/*
* Sets fs-root and fs-type to @upd->fs according to the @fs template and
- * @mountfalgs. For MS_BIND mountflag it reads information about source
+ * @mountfalgs. For MS_BIND mountflag it reads information about the source
* filesystem from /proc/self/mountinfo.
*/
static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs,
@@ -408,13 +408,14 @@ err:
*/
static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
{
- const char *o, *src, *fstype;
+ const char *o, *src, *fstype, *comm;
char *m1, *m2, *m3, *m4;
int rc;
assert(fs);
assert(f);
+ comm = mnt_fs_get_comment(fs);
src = mnt_fs_get_source(fs);
fstype = mnt_fs_get_fstype(fs);
o = mnt_fs_get_options(fs);
@@ -425,6 +426,8 @@ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
m4 = o ? mangle(o) : "rw";
if (m1 && m2 && m3 && m4) {
+ if (comm)
+ fputs(comm, f);
rc = fprintf(f, "%s %s %s %s %d %d\n",
m1, m2, m3, m4,
mnt_fs_get_freq(fs),
@@ -527,6 +530,10 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
struct libmnt_fs *fs;
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ if (tb->comms && mnt_table_get_intro_comment(tb))
+ fputs(mnt_table_get_intro_comment(tb), f);
+
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (upd->userspace_only)
rc = fprintf_utab_fs(f, fs);
@@ -538,6 +545,8 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
goto leave;
}
}
+ if (tb->comms && mnt_table_get_trailing_comment(tb))
+ fputs(mnt_table_get_trailing_comment(tb), f);
if (fflush(f) != 0) {
rc = -errno;
@@ -570,6 +579,99 @@ leave:
return rc;
}
+/**
+ * mnt_table_write_file
+ * @tb: parsed file (e.g. fstab)
+ * @file: target
+ *
+ * This function writes @tb to @file.
+ *
+ * Returns: 0 on success, negative number on error.
+ */
+int mnt_table_write_file(struct libmnt_table *tb, FILE *file)
+{
+ int rc = 0;
+ struct libmnt_iter itr;
+ struct libmnt_fs *fs;
+
+ if (tb->comms && mnt_table_get_intro_comment(tb))
+ fputs(mnt_table_get_intro_comment(tb), file);
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ rc = fprintf_mtab_fs(file, fs);
+ if (rc)
+ return rc;
+ }
+ if (tb->comms && mnt_table_get_trailing_comment(tb))
+ fputs(mnt_table_get_trailing_comment(tb), file);
+
+ if (fflush(file) != 0)
+ rc = -errno;
+
+ DBG(TAB, mnt_debug_h(tb, "write file done [rc=%d]", rc));
+ return rc;
+}
+
+/**
+ * mnt_table_replace_file
+ * @tb: parsed file (e.g. fstab)
+ * @filename: target
+ *
+ * This function replaces @file by the new content from @tb.
+ *
+ * Returns: 0 on success, negative number on error.
+ */
+int mnt_table_replace_file(struct libmnt_table *tb, const char *filename)
+{
+ int fd, rc = 0;
+ FILE *f;
+ char *uq = NULL;
+
+ DBG(TAB, mnt_debug_h(tb, "%s: replacing", filename));
+
+ fd = mnt_open_uniq_filename(filename, &uq);
+ if (fd < 0)
+ return fd; /* error */
+
+ f = fdopen(fd, "w" UL_CLOEXECSTR);
+ if (f) {
+ struct stat st;
+
+ mnt_table_write_file(tb, f);
+
+ if (fflush(f) != 0) {
+ rc = -errno;
+ DBG(UPDATE, mnt_debug("%s: fflush failed: %m", uq));
+ goto leave;
+ }
+
+ rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
+
+ if (!rc && stat(filename, &st) == 0)
+ /* Copy uid/gid from the present file before renaming. */
+ rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
+
+ fclose(f);
+ f = NULL;
+
+ if (!rc)
+ rc = rename(uq, filename) ? -errno : 0;
+ } else {
+ rc = -errno;
+ close(fd);
+ }
+
+leave:
+ if (f)
+ fclose(f);
+ unlink(uq);
+ free(uq);
+
+ DBG(TAB, mnt_debug_h(tb, "replace done [rc=%d]", rc));
+ return rc;
+}
+
static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
{
struct libmnt_fs *fs;
@@ -581,6 +683,8 @@ static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
return -ENOMEM;
mnt_table_add_fs(tb, fs);
+ mnt_unref_fs(fs);
+
return update_table(upd, tb);
}
@@ -606,7 +710,7 @@ static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -632,13 +736,12 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc
if (rem) {
mnt_table_remove_fs(tb, rem);
rc = update_table(upd, tb);
- mnt_free_fs(rem);
}
}
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -670,7 +773,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -712,7 +815,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -724,7 +827,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
* High-level API to update /etc/mtab (or private /run/mount/utab file).
*
* The @lc lock is optional and will be created if necessary. Note that
- * the automatically created lock blocks all signals.
+ * an automatically created lock blocks all signals.
*
* See also mnt_lock_block_signals() and mnt_context_get_lock().
*
@@ -794,7 +897,7 @@ static int update(const char *target, struct libmnt_fs *fs, unsigned long mountf
goto done;
}
- /* [... here should be mount(2) call ...] */
+ /* [... mount(2) call should be here...] */
rc = mnt_update_table(upd, NULL);
done:
@@ -815,7 +918,7 @@ static int test_add(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_set_options(fs, argv[4]);
rc = update(NULL, fs, 0);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
return rc;
}
@@ -838,7 +941,7 @@ static int test_move(struct libmnt_test *ts, int argc, char *argv[])
rc = update(NULL, fs, MS_MOVE);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
return rc;
}
@@ -853,17 +956,42 @@ static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_set_options(fs, argv[2]);
rc = update(NULL, fs, MS_REMOUNT);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
+ return rc;
+}
+
+static int test_replace(struct libmnt_test *ts, int argc, char *argv[])
+{
+ struct libmnt_fs *fs = mnt_new_fs();
+ struct libmnt_table *tb = mnt_new_table();
+ int rc;
+
+ if (argc < 3)
+ return -1;
+
+ mnt_table_enable_comments(tb, TRUE);
+ mnt_table_parse_fstab(tb, NULL);
+
+ mnt_fs_set_source(fs, argv[1]);
+ mnt_fs_set_target(fs, argv[2]);
+ mnt_fs_append_comment(fs, "# this is new filesystem\n");
+
+ mnt_table_add_fs(tb, fs);
+ mnt_unref_fs(fs);
+
+ rc = mnt_table_replace_file(tb, mnt_get_fstab_path());
+ mnt_unref_table(tb);
return rc;
}
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
- { "--add", test_add, "<src> <target> <type> <options> add line to mtab" },
+ { "--add", test_add, "<src> <target> <type> <options> add a line to mtab" },
{ "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
{ "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
{ "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
+ { "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" },
{ NULL }
};
diff --git a/libmount/src/utils.c b/libmount/src/utils.c
index c328414f2..4111b595b 100644
--- a/libmount/src/utils.c
+++ b/libmount/src/utils.c
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
+#include <blkid.h>
#include "strutils.h"
#include "pathnames.h"
@@ -23,39 +24,33 @@
#include "env.h"
#include "match.h"
-int endswith(const char *s, const char *sx)
+int append_string(char **a, const char *b)
{
- ssize_t off;
+ size_t al, bl;
+ char *tmp;
- assert(s);
- assert(sx);
+ assert(a);
- off = strlen(s);
- if (!off)
+ if (!b || !*b)
return 0;
- off -= strlen(sx);
- if (off < 0)
- return 0;
-
- return !strcmp(s + off, sx);
-}
-
-int startswith(const char *s, const char *sx)
-{
- size_t off;
-
- assert(s);
- assert(sx);
+ if (!*a) {
+ *a = strdup(b);
+ return !*a ? -ENOMEM : 0;
+ }
- off = strlen(sx);
- if (!off)
- return 0;
+ al = strlen(*a);
+ bl = strlen(b);
- return !strncmp(s, sx, off);
+ tmp = realloc(*a, al + bl + 1);
+ if (!tmp)
+ return -ENOMEM;
+ *a = tmp;
+ memcpy((*a) + al, b, bl + 1);
+ return 0;
}
/*
- * Return 1 if the file does not accessible of empty
+ * Return 1 if the file is not accessible or empty
*/
int is_file_empty(const char *name)
{
@@ -65,6 +60,34 @@ int is_file_empty(const char *name)
return (stat(name, &st) != 0 || st.st_size == 0);
}
+int mnt_valid_tagname(const char *tagname)
+{
+ if (tagname && *tagname && (
+ strcmp("UUID", tagname) == 0 ||
+ strcmp("LABEL", tagname) == 0 ||
+ strcmp("PARTUUID", tagname) == 0 ||
+ strcmp("PARTLABEL", tagname) == 0))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * mnt_tag_is_valid:
+ * @tag: NAME=value string
+ *
+ * Returns: 1 if the @tag is parsable and tag NAME= is supported by libmount, or 0.
+ */
+int mnt_tag_is_valid(const char *tag)
+{
+ char *t = NULL;
+ int rc = tag && blkid_parse_tag_string(tag, &t, NULL) == 0
+ && mnt_valid_tagname(t);
+
+ free(t);
+ return rc;
+}
+
int mnt_parse_offset(const char *str, size_t len, uintmax_t *res)
{
char *p;
@@ -105,8 +128,8 @@ char *stripoff_last_component(char *path)
}
/*
- * Note that the @target has to be absolute path (so at least "/"). The
- * @filename returns allocated buffer with last path component, for example:
+ * Note that the @target has to be an absolute path (so at least "/"). The
+ * @filename returns an allocated buffer with the last path component, for example:
*
* mnt_chdir_to_parent("/mnt/test", &buf) ==> chdir("/mnt"), buf="test"
*/
@@ -159,8 +182,9 @@ int mnt_chdir_to_parent(const char *target, char **filename)
if (!last || !*last)
memcpy(*filename, ".", 2);
else
- memcpy(*filename, last, strlen(last) + 1);
- }
+ memmove(*filename, last, strlen(last) + 1);
+ } else
+ free(buf);
return 0;
err:
free(buf);
@@ -168,7 +192,7 @@ err:
}
/*
- * Check if @path is on read-only filesystem independently on file permissions.
+ * Check if @path is on a read-only filesystem independently of file permissions.
*/
int mnt_is_readonly(const char *path)
{
@@ -187,7 +211,7 @@ int mnt_is_readonly(const char *path)
* accessible for the current rUID. (Note that euidaccess(2) does not
* check for EROFS at all).
*
- * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
+ * - for a read-write filesystem with a read-only VFS node (aka -o remount,ro,bind)
*/
{
struct timespec times[2];
@@ -208,7 +232,7 @@ int mnt_is_readonly(const char *path)
*
* Encode @str to be compatible with fstab/mtab
*
- * Returns: new allocated string or NULL in case of error.
+ * Returns: newly allocated string or NULL in case of error.
*/
char *mnt_mangle(const char *str)
{
@@ -221,7 +245,7 @@ char *mnt_mangle(const char *str)
*
* Decode @str from fstab/mtab
*
- * Returns: new allocated string or NULL in case of error.
+ * Returns: newly allocated string or NULL in case of error.
*/
char *mnt_unmangle(const char *str)
{
@@ -250,8 +274,9 @@ int mnt_fstype_is_pseudofs(const char *type)
"devpts",
"devtmpfs",
"dlmfs",
- "fuse.gvfs-fuse-daemon",
+ "efivarfs",
"fusectl",
+ "fuse.gvfs-fuse-daemon",
"hugetlbfs",
"mqueue",
"nfsd",
@@ -300,7 +325,7 @@ int mnt_fstype_is_netfs(const char *type)
* @type: filesystem type
* @pattern: filesystem name or comma delimited list of names
*
- * The @pattern list of filesystem can be prefixed with a global
+ * The @pattern list of filesystems can be prefixed with a global
* "no" prefix to invert matching of the whole list. The "no" could
* also be used for individual items in the @pattern list. So,
* "nofoo,bar" has the same meaning as "nofoo,nobar".
@@ -358,14 +383,14 @@ static int check_option(const char *haystack, size_t len,
* @optstr: options string
* @pattern: comma delimited list of options
*
- * The "no" could used for individual items in the @options list. The "no"
+ * The "no" could be used for individual items in the @options list. The "no"
* prefix does not have a global meaning.
*
* Unlike fs type matching, nonetdev,user and nonetdev,nouser have
* DIFFERENT meanings; each option is matched explicitly as specified.
*
- * The "no" prefix interpretation could be disable by "+" prefix, for example
- * "+noauto" matches if @optstr literally contains "noauto" string.
+ * The "no" prefix interpretation could be disabled by the "+" prefix, for example
+ * "+noauto" matches if @optstr literally contains the "noauto" string.
*
* "xxx,yyy,zzz" : "nozzz" -> False
*
@@ -495,7 +520,7 @@ static int get_filesystems(const char *filename, char ***filesystems, const char
}
/*
- * Always check @filesystems pointer!
+ * Always check the @filesystems pointer!
*
* man mount:
*
@@ -520,7 +545,7 @@ int mnt_get_filesystems(char ***filesystems, const char *pattern)
rc = get_filesystems(_PATH_PROC_FILESYSTEMS, filesystems, pattern);
if (rc == 1 && *filesystems)
- rc = 0; /* not found /proc/filesystems */
+ rc = 0; /* /proc/filesystems not found */
return rc;
}
@@ -536,7 +561,7 @@ static size_t get_pw_record_size(void)
}
/*
- * Returns allocated string with username or NULL.
+ * Returns an allocated string with username or NULL.
*/
char *mnt_get_username(const uid_t uid)
{
@@ -662,8 +687,8 @@ static int try_write(const char *filename)
* @mtab: returns path to mtab
* @writable: returns 1 if the file is writable
*
- * If the file does not exist and @writable argument is not NULL then it will
- * try to create the file
+ * If the file does not exist and @writable argument is not NULL, then it will
+ * try to create the file.
*
* Returns: 1 if /etc/mtab is a regular file, and 0 in case of error (check
* errno for more details).
@@ -684,7 +709,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable)
rc = lstat(filename, &st);
if (rc == 0) {
- /* file exist */
+ /* file exists */
if (S_ISREG(st.st_mode)) {
if (writable)
*writable = !try_write(filename);
@@ -708,7 +733,7 @@ done:
/*
* Don't export this to libmount API -- utab is private library stuff.
*
- * If the file does not exist and @writable argument is not NULL then it will
+ * If the file does not exist and @writable argument is not NULL, then it will
* try to create the directory (e.g. /run/mount) and the file.
*
* Returns: 1 if utab is a regular file, and 0 in case of
@@ -730,13 +755,13 @@ int mnt_has_regular_utab(const char **utab, int *writable)
rc = lstat(filename, &st);
if (rc == 0) {
- /* file exist */
+ /* file exists */
if (S_ISREG(st.st_mode)) {
if (writable)
*writable = !try_write(filename);
return 1;
}
- goto done; /* it's not regular file */
+ goto done; /* it's not a regular file */
}
if (writable) {
@@ -788,7 +813,7 @@ const char *mnt_get_fstab_path(void)
/**
* mnt_get_mtab_path:
*
- * This function returns *default* location of the mtab file. The result does
+ * This function returns the *default* location of the mtab file. The result does
* not have to be writable. See also mnt_has_regular_mtab().
*
* Returns: path to /etc/mtab or $LIBMOUNT_MTAB.
@@ -819,7 +844,7 @@ const char *mnt_get_utab_path(void)
}
-/* returns file descriptor or -errno, @name returns uniques filename
+/* returns file descriptor or -errno, @name returns a unique filename
*/
int mnt_open_uniq_filename(const char *filename, char **name)
{
@@ -836,12 +861,14 @@ int mnt_open_uniq_filename(const char *filename, char **name)
if (rc <= 0)
return -errno;
- /* This is for very old glibc and for compatibility with Posix where is
+ /* This is for very old glibc and for compatibility with Posix, which says
* nothing about mkstemp() mode. All sane glibc use secure mode (0600).
*/
oldmode = umask(S_IRGRP|S_IWGRP|S_IXGRP|
S_IROTH|S_IWOTH|S_IXOTH);
fd = mkostemp(n, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC);
+ if (fd < 0)
+ fd = -errno;
umask(oldmode);
if (fd >= 0 && name)
@@ -849,7 +876,7 @@ int mnt_open_uniq_filename(const char *filename, char **name)
else
free(n);
- return fd < 0 ? -errno : fd;
+ return fd;
}
/**
@@ -859,7 +886,7 @@ int mnt_open_uniq_filename(const char *filename, char **name)
* This function finds the mountpoint that a given path resides in. @path
* should be canonicalized. The returned pointer should be freed by the caller.
*
- * Returns: allocated string with target of the mounted device or NULL on error
+ * Returns: allocated string with the target of the mounted device or NULL on error
*/
char *mnt_get_mountpoint(const char *path)
{
@@ -929,7 +956,7 @@ char *mnt_get_fs_root(const char *path, const char *mnt)
/*
* Search for @name kernel command parametr.
*
- * Returns newly allocated string with parameter argument if the @name is
+ * Returns newly allocated string with a parameter argument if the @name is
* specified as "name=" or returns pointer to @name or returns NULL if not
* found.
*
@@ -979,7 +1006,7 @@ char *mnt_get_kernel_cmdline_option(const char *name)
if (p != buf && !isblank(*(p - 1)))
continue; /* no space before the option */
if (!val && *(p + len) != '\0' && !isblank(*(p + len)))
- continue; /* no space behind the option */
+ continue; /* no space after the option */
if (val) {
char *v = p + len;
@@ -1070,6 +1097,18 @@ int test_endswith(struct libmnt_test *ts, int argc, char *argv[])
return 0;
}
+int test_appendstr(struct libmnt_test *ts, int argc, char *argv[])
+{
+ char *str = strdup(argv[1]);
+ const char *ap = argv[2];
+
+ append_string(&str, ap);
+ printf("new string: '%s'\n", str);
+
+ free(str);
+ return 0;
+}
+
int test_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
{
char *path = canonicalize_path(argv[1]),
@@ -1165,6 +1204,7 @@ int main(int argc, char *argv[])
{ "--filesystems", test_filesystems, "[<pattern>] list /{etc,proc}/filesystems" },
{ "--starts-with", test_startswith, "<string> <prefix>" },
{ "--ends-with", test_endswith, "<string> <prefix>" },
+ { "--append-string", test_appendstr, "<string> <appendix>" },
{ "--mountpoint", test_mountpoint, "<path>" },
{ "--fs-root", test_fsroot, "<path>" },
{ "--cd-parent", test_chdir, "<path>" },
diff --git a/libmount/src/version.c b/libmount/src/version.c
index 00b7c03e7..b72956230 100644
--- a/libmount/src/version.c
+++ b/libmount/src/version.c
@@ -10,7 +10,7 @@
/**
* SECTION: version
* @title: Version functions
- * @short_description: functions to get library version.
+ * @short_description: functions to get the library version.
*/
#include <ctype.h>
@@ -70,11 +70,11 @@ int mnt_get_library_version(const char **ver_string)
/**
* mnt_get_library_features:
- * @features: returns pointer to the static array of strings, the array is
+ * @features: returns a pointer to the static array of strings, the array is
* terminated by NULL.
*
* Returns: number of items in the features array not including the last NULL,
- * or less then zero in case of error
+ * or less than zero in case of error
*
* Example:
* <informalexample>