]> err.no Git - util-linux/commitdiff
blkid: add blkid_evaluate_spec()
authorKarel Zak <kzak@redhat.com>
Tue, 3 Feb 2009 23:07:46 +0000 (00:07 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 11 Feb 2009 22:55:51 +0000 (23:55 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libs/blkid/src/Makefile.am
libs/blkid/src/blkid.h
libs/blkid/src/blkid.sym
libs/blkid/src/blkidP.h
libs/blkid/src/evaluate.c [new file with mode: 0644]

index 09d6609ebdfe0e1afd21bcffa9d6e07c00991f95..d7421e29e14a312925aa84b8190c677240570cb2 100644 (file)
@@ -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
index 823eaeb35d9dc911ce064f46b78546ae663b6c7e..06eba12bb5ecf7eafd57d505107371698f38147b 100644 (file)
@@ -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);
index 257d7c1abc89aa30d627dafa14b7d6a7d1594bbf..26ecfe582ea76f0f355e59640dc45e048188065b 100644 (file)
@@ -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;
index 92b4296684fceeb875007665e5d0ad1b5ea68806..240a983f308ba7c9eadf0aadea784ae814e07b9d 100644 (file)
 #define FALSE 1
 #endif
 
+#include <limits.h>
+#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 (file)
index 0000000..e0e7f81
--- /dev/null
@@ -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 <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdint.h>
+#ifdef HAVE_LIBUUID
+#include <uuid/uuid.h>
+#endif
+#include <stdarg.h>
+
+#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 <token> <value>\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