aboutsummaryrefslogtreecommitdiffstats
path: root/libmount/src
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2023-12-05 11:09:38 +0100
committerKarel Zak <kzak@redhat.com>2023-12-05 11:09:38 +0100
commita25ccda012a378c8e140b62e91fbd2d7f78c32f3 (patch)
tree9b45e739dc23bd414d70f686b4195e4e17db53f7 /libmount/src
parent6f7529a2a780bcf042bac570078f1127fcf862cc (diff)
parent4e1d7bf84209e03ffe632f048fb8bbb1e6edacd4 (diff)
downloadutil-linux-a25ccda012a378c8e140b62e91fbd2d7f78c32f3.tar.gz
Merge branch 'PR/libmount-utab-external' of github.com:karelzak/util-linux-work
* 'PR/libmount-utab-external' of github.com:karelzak/util-linux-work: tests: make mount/special more robust tests: add missing file and improve options-missing test libmount: test utab options after helper call libmount: add missing utab options after helper call libmount: add private mnt_optstr_get_missing()
Diffstat (limited to 'libmount/src')
-rw-r--r--libmount/src/mountP.h1
-rw-r--r--libmount/src/optstr.c100
-rw-r--r--libmount/src/tab_update.c81
3 files changed, 163 insertions, 19 deletions
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index de44c064ab..59921cf740 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -508,6 +508,7 @@ extern const struct libmnt_optmap *mnt_optmap_get_entry(
/* optstr.c */
extern int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end);
+extern int mnt_optstr_get_missing(const char *optstr, const char *wanted, char **missing);
extern int mnt_buffer_append_option(struct ul_buffer *buf,
const char *name, size_t namesz,
diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
index 55888bde35..7ebc29555b 100644
--- a/libmount/src/optstr.c
+++ b/libmount/src/optstr.c
@@ -43,13 +43,16 @@ struct libmnt_optloc {
* Locates the first option that matches @name. The @end is set to the
* char behind the option (it means ',' or \0).
*
+ * @ol is optional.
+ *
* Returns negative number on parse error, 1 when not found and 0 on success.
*/
-static int mnt_optstr_locate_option(char *optstr, const char *name,
+static int mnt_optstr_locate_option(char *optstr,
+ const char *name, size_t namesz,
struct libmnt_optloc *ol)
{
char *n;
- size_t namesz, nsz;
+ size_t nsz;
int rc;
if (!optstr)
@@ -57,27 +60,30 @@ static int mnt_optstr_locate_option(char *optstr, const char *name,
assert(name);
- namesz = strlen(name);
+ if (!namesz)
+ namesz = strlen(name);
if (!namesz)
return 1;
do {
rc = ul_optstr_next(&optstr, &n, &nsz,
- &ol->value, &ol->valsz);
+ ol ? &ol->value : NULL,
+ ol ? &ol->valsz : NULL);
if (rc)
break;
if (namesz == nsz && strncmp(n, name, nsz) == 0) {
- ol->begin = n;
- ol->end = *(optstr - 1) == ',' ? optstr - 1 : optstr;
- ol->namesz = nsz;
+ if (ol) {
+ ol->begin = n;
+ ol->end = *(optstr - 1) == ',' ? optstr - 1 : optstr;
+ ol->namesz = nsz;
+ }
return 0;
}
} while(1);
return rc;
}
-
/**
* mnt_optstr_next_option:
* @optstr: option string, returns the position of the next option
@@ -223,7 +229,7 @@ int mnt_optstr_get_option(const char *optstr, const char *name,
if (!optstr || !name)
return -EINVAL;
- rc = mnt_optstr_locate_option((char *) optstr, name, &ol);
+ rc = mnt_optstr_locate_option((char *) optstr, name, 0, &ol);
if (!rc) {
if (value)
*value = ol.value;
@@ -255,7 +261,7 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
do {
struct libmnt_optloc ol = MNT_INIT_OPTLOC;
- rc = mnt_optstr_locate_option(opt, name, &ol);
+ rc = mnt_optstr_locate_option(opt, name, 0, &ol);
if (!rc) {
if (begin) {
/* remove the previous instance */
@@ -368,7 +374,7 @@ int mnt_optstr_set_option(char **optstr, const char *name, const char *value)
return -EINVAL;
if (*optstr)
- rc = mnt_optstr_locate_option(*optstr, name, &ol);
+ rc = mnt_optstr_locate_option(*optstr, name, 0, &ol);
if (rc < 0)
return rc; /* parse error */
if (rc == 1)
@@ -411,7 +417,7 @@ int mnt_optstr_remove_option(char **optstr, const char *name)
if (!optstr || !name)
return -EINVAL;
- rc = mnt_optstr_locate_option(*optstr, name, &ol);
+ rc = mnt_optstr_locate_option(*optstr, name, 0, &ol);
if (rc != 0)
return rc;
@@ -571,6 +577,51 @@ int mnt_optstr_get_options(const char *optstr, char **subset,
return rc;
}
+/*
+ * @optstr: string with comma separated list of options
+ * @wanted: options expected in @optstr
+ * @missing: returns options from @wanted which missing in @optstr (optional)
+ *
+ * Retursn: <0 on error, 0 on missing options, 1 if nothing is missing
+ */
+int mnt_optstr_get_missing(const char *optstr, const char *wanted, char **missing)
+{
+ char *name, *val, *str = (char *) wanted;
+ size_t namesz = 0, valsz = 0;
+ struct ul_buffer buf = UL_INIT_BUFFER;
+ int rc = 0;
+
+ if (!wanted)
+ return 1;
+ if (missing) {
+ /* caller wants data, prepare buffer */
+ ul_buffer_set_chunksize(&buf, strlen(wanted) + 3); /* to call realloc() only once */
+ *missing = NULL;
+ }
+
+ while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
+
+ rc = mnt_optstr_locate_option((char *) optstr, name, namesz, NULL);
+ if (rc == 1) { /* not found */
+ if (!missing)
+ return 0;
+ rc = mnt_buffer_append_option(&buf, name, namesz, val, valsz, 0);
+ }
+ if (rc < 0)
+ break;
+ rc = 0;
+ }
+
+ if (!rc && missing) {
+ if (ul_buffer_is_empty(&buf))
+ rc = 1;
+ else
+ *missing = ul_buffer_get_data(&buf, NULL, NULL);
+ } else
+ ul_buffer_free_data(&buf);
+
+ return rc;
+}
/**
* mnt_optstr_get_flags:
@@ -1101,6 +1152,30 @@ static int test_get(struct libmnt_test *ts __attribute__((unused)),
return rc;
}
+static int test_missing(struct libmnt_test *ts __attribute__((unused)),
+ int argc, char *argv[])
+{
+ const char *optstr;
+ const char *wanted;
+ char *missing = NULL;
+ int rc;
+
+ if (argc < 2)
+ return -EINVAL;
+ optstr = argv[1];
+ wanted = argv[2];
+
+ rc = mnt_optstr_get_missing(optstr, wanted, &missing);
+ if (rc == 0)
+ printf("missing: %s\n", missing);
+ else if (rc == 1) {
+ printf("nothing\n");
+ rc = 0;
+ } else
+ printf("parse error: %s\n", optstr);
+ return rc;
+}
+
static int test_remove(struct libmnt_test *ts __attribute__((unused)),
int argc, char *argv[])
{
@@ -1166,6 +1241,7 @@ int main(int argc, char *argv[])
{ "--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" },
+ { "--missing",test_missing,"<optstr> <wanted> what from wanted is missing" },
{ "--remove", test_remove, "<optstr> <name> remove name in optstr" },
{ "--dedup", test_dedup, "<optstr> <name> deduplicate name in optstr" },
{ "--match", test_match, "<optstr> <pattern> compare optstr with pattern" },
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
index e938ea4647..3a27937040 100644
--- a/libmount/src/tab_update.c
+++ b/libmount/src/tab_update.c
@@ -35,7 +35,9 @@ struct libmnt_update {
struct libmnt_fs *fs;
char *filename;
unsigned long mountflags;
- int ready;
+
+ unsigned int ready : 1,
+ missing_options : 1;
struct libmnt_table *mountinfo;
};
@@ -173,7 +175,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
mnt_unref_fs(upd->fs);
free(upd->target);
- upd->ready = FALSE;
+ upd->ready = 0;
upd->fs = NULL;
upd->target = NULL;
upd->mountflags = 0;
@@ -206,7 +208,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
}
DBG(UPDATE, ul_debugobj(upd, "ready"));
- upd->ready = TRUE;
+ upd->ready = 1;
return 0;
}
@@ -786,6 +788,7 @@ done:
return rc;
}
+/* replaces option in the table entry by new options from @udp */
static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc)
{
struct libmnt_table *tb = NULL;
@@ -826,6 +829,58 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
return rc;
}
+/* add user options missing in the table entry by new options from @udp */
+static int update_add_options(struct libmnt_update *upd, struct libmnt_lock *lc)
+{
+ struct libmnt_table *tb = NULL;
+ int rc = 0;
+ struct libmnt_fs *fs;
+
+ assert(upd);
+ assert(upd->fs);
+
+ if (!upd->fs->user_optstr)
+ return 0;
+
+ DBG(UPDATE, ul_debugobj(upd, "%s: add options", upd->filename));
+
+ fs = upd->fs;
+
+ if (lc)
+ rc = mnt_lock_file(lc);
+ if (rc)
+ return -MNT_ERR_LOCK;
+
+ tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
+ if (tb) {
+ struct libmnt_fs *cur = mnt_table_find_target(tb,
+ mnt_fs_get_target(fs),
+ MNT_ITER_BACKWARD);
+ if (cur) {
+ char *u = NULL;
+
+ rc = mnt_optstr_get_missing(cur->user_optstr, upd->fs->user_optstr, &u);
+ if (!rc && u) {
+ DBG(UPDATE, ul_debugobj(upd, " add missing: %s", u));
+ rc = mnt_optstr_append_option(&cur->user_optstr, u, NULL);
+ }
+ if (!rc && u)
+ rc = update_table(upd, tb);
+
+ if (rc == 1) /* nothing is missing */
+ rc = 0;
+ } else
+ rc = add_file_entry(tb, upd); /* not found, add new */
+ }
+
+ if (lc)
+ mnt_unlock_file(lc);
+
+ mnt_unref_table(tb);
+ return rc;
+
+}
+
/**
* mnt_update_table:
* @upd: update
@@ -866,10 +921,12 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
rc = update_modify_target(upd, lc); /* move */
else if (upd->mountflags & MS_REMOUNT)
rc = update_modify_options(upd, lc); /* remount */
+ else if (upd->fs && upd->missing_options)
+ rc = update_add_options(upd, lc); /* mount by externel helper */
else if (upd->fs)
- rc = update_add_entry(upd, lc); /* mount */
+ rc = update_add_entry(upd, lc); /* mount */
- upd->ready = FALSE;
+ upd->ready = 1;
DBG(UPDATE, ul_debugobj(upd, "%s: update tab: done [rc=%d]",
upd->filename, rc));
if (lc != lc0)
@@ -909,16 +966,26 @@ int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc)
if (upd->fs) {
/* mount */
+ struct libmnt_fs *fs;
const char *tgt = mnt_fs_get_target(upd->fs);
const char *src = mnt_fs_get_bindsrc(upd->fs) ?
mnt_fs_get_bindsrc(upd->fs) :
mnt_fs_get_source(upd->fs);
- if (mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD)) {
+ fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD);
+ if (fs) {
DBG(UPDATE, ul_debugobj(upd, "%s: found %s %s",
upd->filename, src, tgt));
+
+ /* Check if utab entry (probably writen by /sbin/mount.<type>
+ * helper) contains all options expected by this update */
+ if (mnt_optstr_get_missing(fs->user_optstr, upd->fs->user_optstr, NULL) == 0) {
+ upd->missing_options = 1;
+ DBG(UPDATE, ul_debugobj(upd, " missing options detected"));
+ }
+ } else
rc = 1;
- }
+
} else if (upd->target) {
/* umount */
if (!mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD)) {