From 892a404cafaaf691ed4ecaa0c1b08cb3653747e8 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 4 Feb 2009 00:07:46 +0100 Subject: [PATCH] blkid: add blkid_evaluate_spec() Signed-off-by: Karel Zak --- libs/blkid/src/Makefile.am | 5 +- libs/blkid/src/blkid.h | 5 + libs/blkid/src/blkid.sym | 2 + libs/blkid/src/blkidP.h | 6 + libs/blkid/src/evaluate.c | 264 +++++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 libs/blkid/src/evaluate.c diff --git a/libs/blkid/src/Makefile.am b/libs/blkid/src/Makefile.am index 09d6609e..d7421e29 100644 --- a/libs/blkid/src/Makefile.am +++ b/libs/blkid/src/Makefile.am @@ -13,17 +13,18 @@ lib_LIBRARIES = libblkid.a libblkid_a_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \ probe.c read.c resolve.c save.c tag.c version.c verify.c \ encode.c blkid.h list.h probers/probers.h \ - config.c \ + config.c evaluate.c \ $(blkidinc_HEADERS) \ $(top_srcdir)/lib/blkdev.c \ $(top_srcdir)/lib/linux_version.c \ + $(top_srcdir)/lib/canonicalize.c \ $(top_srcdir)/lib/md5.c libblkid_a_LIBADD = probers/libprobers.a libblkid_a_CFLAGS = -fPIC tests = test_cache test_config test_dev test_devname test_devno test_getsize \ - test_read test_resolve test_save test_tag test_verify + test_read test_resolve test_save test_tag test_verify test_evaluate # shared library (note that we don't use LIBTOOL!) blkid_IMAGE = libblkid.so diff --git a/libs/blkid/src/blkid.h b/libs/blkid/src/blkid.h index 823eaeb3..06eba12b 100644 --- a/libs/blkid/src/blkid.h +++ b/libs/blkid/src/blkid.h @@ -115,6 +115,11 @@ extern int blkid_get_library_version(const char **ver_string, extern int blkid_encode_string(const char *str, char *str_enc, size_t len); extern int blkid_safe_string(const char *str, char *str_safe, size_t len); +/* evaluate.c */ +extern int blkid_send_uevent(const char *devname, const char *action); +extern char *blkid_evaluate_spec(const char *token, const char *value, + blkid_cache *cache); + /* probe.c */ extern int blkid_known_fstype(const char *fstype); extern blkid_probe blkid_new_probe(void); diff --git a/libs/blkid/src/blkid.sym b/libs/blkid/src/blkid.sym index 257d7c1a..26ecfe58 100644 --- a/libs/blkid/src/blkid.sym +++ b/libs/blkid/src/blkid.sym @@ -9,6 +9,7 @@ blkid_do_probe; blkid_do_safeprobe; blkid_encode_string; + blkid_evaluate_spec; blkid_find_dev_with_tag; blkid_free_probe; blkid_gc_cache; @@ -37,6 +38,7 @@ blkid_put_cache; blkid_reset_probe; blkid_safe_string; + blkid_send_uevent; blkid_tag_iterate_begin; blkid_tag_iterate_end; blkid_tag_next; diff --git a/libs/blkid/src/blkidP.h b/libs/blkid/src/blkidP.h index 92b42966..240a983f 100644 --- a/libs/blkid/src/blkidP.h +++ b/libs/blkid/src/blkidP.h @@ -34,6 +34,11 @@ #define FALSE 1 #endif +#include +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + /* TODO: move to some top-level util-linux include file */ #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -252,6 +257,7 @@ extern char *blkid_strndup(const char *s, const int length); #define DEBUG_TAG 0x0200 #define DEBUG_LOWPROBE 0x0400 #define DEBUG_CONFIG 0x0800 +#define DEBUG_EVALUATE 0x1000 #define DEBUG_INIT 0x8000 #define DEBUG_ALL 0xFFFF diff --git a/libs/blkid/src/evaluate.c b/libs/blkid/src/evaluate.c new file mode 100644 index 00000000..e0e7f81e --- /dev/null +++ b/libs/blkid/src/evaluate.c @@ -0,0 +1,264 @@ +/* + * evaluate.c - very high-level API to evaluate LABELs or UUIDs + * + * This is simular to blkid_get_devname() from resolve.c, but this + * API supports udev /dev/disk/by-{label,uuid} links. + * + * Copyright (C) 2009 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_LIBUUID +#include +#endif +#include + +#include "pathnames.h" +#include "canonicalize.h" + +#include "blkdev.h" +#include "blkidP.h" + +/* returns zero when the device has NAME=value (LABEL/UUID) */ +static int verify_tag(const char *devname, const char *name, const char *value) +{ + blkid_probe pr; + int fd = -1, rc = -1; + size_t len; + unsigned char *data; + + pr = blkid_new_probe(); + if (!pr) + return -1; + + blkid_probe_set_request(pr, BLKID_PROBREQ_LABEL | BLKID_PROBREQ_UUID); + + fd = open(devname, O_RDONLY); + if (fd < 0) + goto done; + if (blkid_probe_set_device(pr, fd, 0, 0)) + goto done; + rc = blkid_do_safeprobe(pr); + if (rc) + goto done; + rc = blkid_probe_lookup_value(pr, name, &data, &len); + if (!rc) + rc = memcmp(value, data, len); +done: + DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n", + devname, name, rc == 0 ? "PASS" : "FAILED")); + if (fd >= 0) + close(fd); + blkid_free_probe(pr); + return rc; +} + +/** + * blkid_send_uevent: + * @devname: absolute path to the device + * + * Returns -1 in case of failure, or 0 on success. + */ +int blkid_send_uevent(const char *devname, const char *action) +{ + char uevent[PATH_MAX]; + struct stat st; + FILE *f; + int rc = -1; + + DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action)); + + if (!devname || !action) + return -1; + if (stat(devname, &st) || !S_ISBLK(st.st_mode)) + return -1; + + snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent", + major(st.st_rdev), minor(st.st_rdev)); + + f = fopen(uevent, "w"); + if (f) { + rc = 0; + if (fputs(action, f) >= 0) + rc = 0; + fclose(f); + } + DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n", + uevent, rc == 0 ? "SUCCES" : "FAILED")); + return rc; +} + +static char *evaluate_by_udev(const char *token, const char *value, int uevent) +{ + char dev[PATH_MAX]; + char *path = NULL; + size_t len; + struct stat st; + + DBG(DEBUG_EVALUATE, + printf("evaluating by udev %s=%s\n", token, value)); + + if (!strcmp(token, "UUID")) + strcpy(dev, _PATH_DEV_BYUUID "/"); + else if (!strcmp(token, "LABEL")) + strcpy(dev, _PATH_DEV_BYLABEL "/"); + else { + DBG(DEBUG_EVALUATE, + printf("unsupported token %s\n", token)); + return NULL; /* unsupported tag */ + } + + len = strlen(dev); + if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0) + return NULL; + + DBG(DEBUG_EVALUATE, + printf("expected udev link: %s\n", dev)); + + if (stat(dev, &st)) + goto failed; /* link or device does not exist */ + + if (!S_ISBLK(st.st_mode)) + return NULL; + + path = canonicalize_path(dev); + if (!path) + return NULL; + + if (verify_tag(path, token, value)) + goto failed; + return path; + +failed: + DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n")); + + if (uevent && path) + blkid_send_uevent(path, "change"); + free(path); + return NULL; +} + +static char *evaluate_by_scan(const char *token, const char *value, + blkid_cache *cache, const char *cachefile) +{ + blkid_cache c = cache ? *cache : NULL; + char *res; + + DBG(DEBUG_EVALUATE, + printf("evaluating by blkid scan %s=%s\n", token, value)); + + if (!c) + blkid_get_cache(&c, cachefile); + if (!c) + return NULL; + + res = blkid_get_devname(c, token, value); + + if (cache) + *cache = c; + else + blkid_put_cache(c); + + return res; +} + +/** + * blkid_evaluate_spec: + * @token: token name (e.g "LABEL" or "UUID") + * @value: token data + * @cache: pointer to cache (or NULL when you don't want to re-use the cache) + * + * Returns allocated string with device name. + */ +char *blkid_evaluate_spec(const char *token, const char *value, blkid_cache *cache) +{ + struct blkid_config *conf = NULL; + char *t = NULL, *v = NULL; + char *ret = NULL; + int i; + + if (!token) + return NULL; + + if (!cache || !*cache) + blkid_debug_init(0); + + DBG(DEBUG_EVALUATE, + printf("evaluating %s%s%s\n", token, value ? "=" : "", + value ? value : "")); + + if (!value) { + if (!strchr(token, '=')) { + ret = blkid_strdup(token); + goto out; + } + blkid_parse_tag_string(token, &t, &v); + if (!t || !v) + goto out; + token = t; + value = v; + } + + conf = blkid_read_config(NULL); + if (!conf) + goto out; + + for (i = 0; i < conf->nevals; i++) { + if (conf->eval[i] == BLKID_EVAL_UDEV) + ret = evaluate_by_udev(token, value, conf->uevent); + else if (conf->eval[i] == BLKID_EVAL_SCAN) + ret = evaluate_by_scan(token, value, cache, conf->cachefile); + if (ret) + break; + } + + DBG(DEBUG_EVALUATE, + printf("%s=%s evaluated as %s\n", token, value, ret)); +out: + blkid_free_config(conf); + free(t); + free(v); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char *argv[]) +{ + blkid_cache cache = NULL; + char *res; + + if (argc < 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + blkid_debug_init(0); + + res = blkid_evaluate_spec(argv[1], argv[2], &cache); + if (res) + printf("%s\n", res); + if (cache) + blkid_put_cache(cache); + + return res ? EXIT_SUCCESS : EXIT_FAILURE; +} +#endif -- 2.39.5