From: Karel Zak Date: Tue, 3 Nov 2020 16:06:09 +0000 (+0100) Subject: libblkid: add blkid_probe_{set,get}_hint() X-Git-Tag: v2.37-rc1~266^2~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=67719fbbda6de60c63496e62dae8617336f9ac7b;p=thirdparty%2Futil-linux.git libblkid: add blkid_probe_{set,get}_hint() Add new API for additional probing hints (offsets). The idea is that probing function can optionally use the hint to detect superblock or partition table if on unusual place where the library does not expects (etc.) The hints use strings as identifiers (e.g. "last-medium-session") to make it extendable and prober specific (if necessary). The function blkid_probe_set_hint() always add a new hint, so you can specify more offsets with the same (hint) name. The function blkid_probe_get_hint() is not public. For now it returns the first hint only. Addresses: https://github.com/karelzak/util-linux/issues/1161 Signed-off-by: Karel Zak --- diff --git a/libblkid/docs/libblkid-sections.txt b/libblkid/docs/libblkid-sections.txt index 8163d2d82b..0f18d929cb 100644 --- a/libblkid/docs/libblkid-sections.txt +++ b/libblkid/docs/libblkid-sections.txt @@ -58,6 +58,7 @@ blkid_probe_hide_range blkid_probe_is_wholedisk blkid_probe_reset_buffers blkid_probe_set_device +blkid_probe_set_hint blkid_probe_set_sectorsize blkid_probe_step_back blkid_reset_probe diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in index 7328d0e306..6550ed7a6d 100644 --- a/libblkid/src/blkid.h.in +++ b/libblkid/src/blkid.h.in @@ -255,6 +255,9 @@ extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr) extern int blkid_probe_get_fd(blkid_probe pr) __ul_attribute__((nonnull)); +extern int blkid_probe_set_hint(blkid_probe pr, const char *name, uint64_t value) + __ul_attribute__((nonnull)); + /* * superblocks probing */ diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h index fe3736f744..c3b1056216 100644 --- a/libblkid/src/blkidP.h +++ b/libblkid/src/blkidP.h @@ -183,6 +183,15 @@ struct blkid_bufinfo { struct list_head bufs; /* list of buffers */ }; +/* + * Probing hint + */ +struct blkid_hint { + char *name; + uint64_t value; + struct list_head hints; +}; + /* * Low-level probing control struct */ @@ -205,6 +214,7 @@ struct blkid_struct_probe struct blkid_chain *wipe_chain; /* superblock, partition, ... */ struct list_head buffers; /* list of buffers */ + struct list_head hints; struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ struct blkid_chain *cur_chain; /* current chain */ @@ -521,6 +531,10 @@ extern int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, extern void blkid_probe_use_wiper(blkid_probe pr, uint64_t off, uint64_t size) __attribute__((nonnull)); +extern int blkid_probe_get_hint(blkid_probe pr, const char *name, uint64_t *value) + __attribute__((nonnull(1,2))) + __attribute__((warn_unused_result)); + /* filter bitmap macros */ #define blkid_bmp_wordsize (8 * sizeof(unsigned long)) #define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) diff --git a/libblkid/src/libblkid.sym b/libblkid/src/libblkid.sym index 50a976b9be..4eb4c18e0e 100644 --- a/libblkid/src/libblkid.sym +++ b/libblkid/src/libblkid.sym @@ -178,3 +178,7 @@ BLKID_2_31 { BLKID_2_36 { blkid_topology_get_dax; } BLKID_2_31; + +BLKID_2_37 { + blkid_probe_set_hint; +} BLKID_2_36; diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index 8f5f59da3b..7a7c902f0d 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -121,6 +121,7 @@ static const struct blkid_chaindrv *chains_drvs[] = { }; static void blkid_probe_reset_values(blkid_probe pr); +static void blkid_probe_reset_hints(blkid_probe pr); /** * blkid_new_probe: @@ -147,6 +148,7 @@ blkid_probe blkid_new_probe(void) } INIT_LIST_HEAD(&pr->buffers); INIT_LIST_HEAD(&pr->values); + INIT_LIST_HEAD(&pr->hints); return pr; } @@ -248,6 +250,7 @@ void blkid_free_probe(blkid_probe pr) close(pr->fd); blkid_probe_reset_buffers(pr); blkid_probe_reset_values(pr); + blkid_probe_reset_hints(pr); blkid_free_probe(pr->disk_probe); DBG(LOWPROBE, ul_debug("free probe")); @@ -403,6 +406,7 @@ void blkid_reset_probe(blkid_probe pr) int i; blkid_probe_reset_values(pr); + blkid_probe_reset_hints(pr); blkid_probe_set_wiper(pr, 0, 0); pr->cur_chain = NULL; @@ -757,6 +761,7 @@ int blkid_probe_hide_range(blkid_probe pr, uint64_t off, uint64_t len) return rc; } + static void blkid_probe_reset_values(blkid_probe pr) { if (list_empty(&pr->values)) @@ -2031,3 +2036,98 @@ void blkid_probe_use_wiper(blkid_probe pr, uint64_t off, uint64_t size) blkid_probe_chain_reset_values(pr, chn); } } + +/** + * blkid_probe_set_hint + * @pr: probe + * @name: hint name or NAME=value + * @value: offset or another number + * + * Sets extra hint for low-level prober. If the hint is set by NAME=value + * notation than @value is ignored. The functions blkid_probe_set_device() + * and blkid_reset_probe() resets all hints. + * + * The hints are optional way how to force libblkid probing functions to check + * for example another location. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_set_hint(blkid_probe pr, const char *name, uint64_t value) +{ + struct blkid_hint *hint = NULL; + char *n = NULL, *v = NULL; + + if (strchr(name, '=')) { + char *end = NULL; + + if (blkid_parse_tag_string(name, &n, &v) != 0) + goto done; + + errno = 0; + value = strtoumax(v, &end, 10); + + if (errno || v == end || (end && *end)) + goto done; + } else { + n = strdup(name); + if (!n) + goto done; + } + + /* allocate info and space for data by one malloc call */ + hint = malloc(sizeof(*hint)); + if (!hint) + goto done; + + INIT_LIST_HEAD(&hint->hints); + hint->name = n; + hint->value = value; + n = NULL; + list_add_tail(&hint->hints, &pr->hints); + + DBG(LOWPROBE, + ul_debug("new hint '%s' is %"PRIu64"", hint->name, hint->value)); +done: + free(n); + free(v); + if (!hint) + return errno ? -errno : -EINVAL; + return 0; +} + +int blkid_probe_get_hint(blkid_probe pr, const char *name, uint64_t *value) +{ + struct list_head *p; + + if (list_empty(&pr->hints)) + return -EINVAL; + + list_for_each(p, &pr->hints) { + struct blkid_hint *h = list_entry(p, struct blkid_hint, hints); + + if (h->name && strcmp(name, h->name) == 0) { + if (value) + *value = h->value; + return 0; + } + } + return -EINVAL; +} + +static void blkid_probe_reset_hints(blkid_probe pr) +{ + if (list_empty(&pr->hints)) + return; + + DBG(LOWPROBE, ul_debug("resetting hints")); + + while (!list_empty(&pr->hints)) { + struct blkid_hint *h = list_entry(pr->hints.next, + struct blkid_hint, hints); + list_del(&h->hints); + free(h->name); + free(h); + } + + INIT_LIST_HEAD(&pr->hints); +}