diff options
| author | Karel Zak <kzak@redhat.com> | 2023-12-05 11:09:38 +0100 |
|---|---|---|
| committer | Karel Zak <kzak@redhat.com> | 2023-12-05 11:09:38 +0100 |
| commit | a25ccda012a378c8e140b62e91fbd2d7f78c32f3 (patch) | |
| tree | 9b45e739dc23bd414d70f686b4195e4e17db53f7 /libmount/src | |
| parent | 6f7529a2a780bcf042bac570078f1127fcf862cc (diff) | |
| parent | 4e1d7bf84209e03ffe632f048fb8bbb1e6edacd4 (diff) | |
| download | util-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.h | 1 | ||||
| -rw-r--r-- | libmount/src/optstr.c | 100 | ||||
| -rw-r--r-- | libmount/src/tab_update.c | 81 |
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)) { |
