]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libblkid/src/evaluate.c
libblkid: update docs
[thirdparty/util-linux.git] / libblkid / src / evaluate.c
CommitLineData
892a404c
KZ
1/*
2 * evaluate.c - very high-level API to evaluate LABELs or UUIDs
3 *
892a404c
KZ
4 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
5 *
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
8 */
892a404c
KZ
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <fcntl.h>
14#include <ctype.h>
15#include <sys/types.h>
16#ifdef HAVE_SYS_STAT_H
17#include <sys/stat.h>
18#endif
892a404c
KZ
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <stdint.h>
892a404c
KZ
23#include <stdarg.h>
24
25#include "pathnames.h"
26#include "canonicalize.h"
27
892a404c
KZ
28#include "blkidP.h"
29
488e52be
KZ
30/**
31 * SECTION:evaluate
fd7c9e35 32 * @title: Tags and Spec evaluation
488e52be
KZ
33 * @short_description: top-level API for LABEL and UUID evaluation.
34 *
35 * This API provides very simple and portable way how evaluate LABEL and UUID
fd7c9e35
KZ
36 * tags. The blkid_evaluate_tag() and blkid_evaluate_spec() work on 2.4 and
37 * 2.6 systems and on systems with or without udev. Currently, the libblkid
38 * library supports "udev" and "scan" methods. The "udev" method uses udev
39 * /dev/disk/by-* symlinks and the "scan" method scans all block devices from
40 * the /proc/partitions file. The evaluation could be controlled by the
41 * /etc/blkid.conf config file. The default is to try "udev" and then "scan"
42 * method.
488e52be
KZ
43 *
44 * The blkid_evaluate_tag() also automatically informs udevd when an obsolete
45 * /dev/disk/by-* symlink is detected.
46 *
47 * If you are not sure how translate LABEL or UUID to the device name use this
48 * API.
49 */
50
892a404c
KZ
51/* returns zero when the device has NAME=value (LABEL/UUID) */
52static int verify_tag(const char *devname, const char *name, const char *value)
53{
54 blkid_probe pr;
55 int fd = -1, rc = -1;
56 size_t len;
6d042d0d 57 const char *data;
e9799b6d 58 int errsv = 0;
892a404c
KZ
59
60 pr = blkid_new_probe();
61 if (!pr)
62 return -1;
63
1b780848
KZ
64 blkid_probe_enable_superblocks(pr, TRUE);
65 blkid_probe_set_superblocks_flags(pr,
66 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID);
892a404c
KZ
67
68 fd = open(devname, O_RDONLY);
e9799b6d
KZ
69 if (fd < 0) {
70 errsv = errno;
892a404c 71 goto done;
e9799b6d 72 }
892a404c
KZ
73 if (blkid_probe_set_device(pr, fd, 0, 0))
74 goto done;
75 rc = blkid_do_safeprobe(pr);
76 if (rc)
77 goto done;
78 rc = blkid_probe_lookup_value(pr, name, &data, &len);
79 if (!rc)
80 rc = memcmp(value, data, len);
81done:
82 DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n",
83 devname, name, rc == 0 ? "PASS" : "FAILED"));
84 if (fd >= 0)
85 close(fd);
86 blkid_free_probe(pr);
e9799b6d
KZ
87
88 /* for non-root users we use unverified udev links */
89 return errsv == EACCES ? 0 : rc;
892a404c
KZ
90}
91
92/**
93 * blkid_send_uevent:
94 * @devname: absolute path to the device
fd7c9e35 95 * @action: event string
892a404c 96 *
488e52be 97 * Returns: -1 in case of failure, or 0 on success.
892a404c
KZ
98 */
99int blkid_send_uevent(const char *devname, const char *action)
100{
101 char uevent[PATH_MAX];
102 struct stat st;
103 FILE *f;
104 int rc = -1;
105
106 DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action));
107
108 if (!devname || !action)
109 return -1;
110 if (stat(devname, &st) || !S_ISBLK(st.st_mode))
111 return -1;
112
113 snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent",
114 major(st.st_rdev), minor(st.st_rdev));
115
116 f = fopen(uevent, "w");
117 if (f) {
118 rc = 0;
119 if (fputs(action, f) >= 0)
120 rc = 0;
121 fclose(f);
122 }
123 DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n",
124 uevent, rc == 0 ? "SUCCES" : "FAILED"));
125 return rc;
126}
127
128static char *evaluate_by_udev(const char *token, const char *value, int uevent)
129{
130 char dev[PATH_MAX];
131 char *path = NULL;
132 size_t len;
133 struct stat st;
134
135 DBG(DEBUG_EVALUATE,
136 printf("evaluating by udev %s=%s\n", token, value));
137
138 if (!strcmp(token, "UUID"))
139 strcpy(dev, _PATH_DEV_BYUUID "/");
140 else if (!strcmp(token, "LABEL"))
141 strcpy(dev, _PATH_DEV_BYLABEL "/");
142 else {
143 DBG(DEBUG_EVALUATE,
144 printf("unsupported token %s\n", token));
145 return NULL; /* unsupported tag */
146 }
147
148 len = strlen(dev);
149 if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0)
150 return NULL;
151
152 DBG(DEBUG_EVALUATE,
153 printf("expected udev link: %s\n", dev));
154
155 if (stat(dev, &st))
156 goto failed; /* link or device does not exist */
157
158 if (!S_ISBLK(st.st_mode))
159 return NULL;
160
161 path = canonicalize_path(dev);
162 if (!path)
163 return NULL;
164
165 if (verify_tag(path, token, value))
166 goto failed;
167 return path;
168
169failed:
170 DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n"));
171
172 if (uevent && path)
173 blkid_send_uevent(path, "change");
174 free(path);
175 return NULL;
176}
177
178static char *evaluate_by_scan(const char *token, const char *value,
bb5f2876 179 blkid_cache *cache, struct blkid_config *conf)
892a404c
KZ
180{
181 blkid_cache c = cache ? *cache : NULL;
182 char *res;
183
184 DBG(DEBUG_EVALUATE,
185 printf("evaluating by blkid scan %s=%s\n", token, value));
186
bb5f2876
KZ
187 if (!c) {
188 char *cachefile = blkid_get_cache_filename(conf);
892a404c 189 blkid_get_cache(&c, cachefile);
bb5f2876
KZ
190 free(cachefile);
191 }
892a404c
KZ
192 if (!c)
193 return NULL;
194
195 res = blkid_get_devname(c, token, value);
196
197 if (cache)
198 *cache = c;
199 else
200 blkid_put_cache(c);
201
202 return res;
203}
204
205/**
cee95a95 206 * blkid_evaluate_tag:
5298f728
KZ
207 * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo")
208 * @value: token data (e.g. "foo")
892a404c
KZ
209 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
210 *
488e52be 211 * Returns: allocated string with a device name.
892a404c 212 */
cee95a95 213char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache)
892a404c
KZ
214{
215 struct blkid_config *conf = NULL;
216 char *t = NULL, *v = NULL;
217 char *ret = NULL;
218 int i;
219
220 if (!token)
221 return NULL;
222
223 if (!cache || !*cache)
7a458332 224 blkid_init_debug(0);
892a404c
KZ
225
226 DBG(DEBUG_EVALUATE,
227 printf("evaluating %s%s%s\n", token, value ? "=" : "",
228 value ? value : ""));
229
230 if (!value) {
231 if (!strchr(token, '=')) {
232 ret = blkid_strdup(token);
233 goto out;
234 }
235 blkid_parse_tag_string(token, &t, &v);
236 if (!t || !v)
237 goto out;
238 token = t;
239 value = v;
240 }
241
242 conf = blkid_read_config(NULL);
243 if (!conf)
244 goto out;
245
246 for (i = 0; i < conf->nevals; i++) {
247 if (conf->eval[i] == BLKID_EVAL_UDEV)
248 ret = evaluate_by_udev(token, value, conf->uevent);
249 else if (conf->eval[i] == BLKID_EVAL_SCAN)
bb5f2876 250 ret = evaluate_by_scan(token, value, cache, conf);
892a404c
KZ
251 if (ret)
252 break;
253 }
254
255 DBG(DEBUG_EVALUATE,
256 printf("%s=%s evaluated as %s\n", token, value, ret));
257out:
258 blkid_free_config(conf);
259 free(t);
260 free(v);
261 return ret;
262}
263
5298f728
KZ
264/**
265 * blkid_evaluate_spec:
266 * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0)
267 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
268 *
269 * All returned paths are canonicalized, device-mapper paths are converted
fd7c9e35 270 * to the /dev/mapper/name format.
5298f728
KZ
271 *
272 * Returns: allocated string with a device name.
273 */
274char *blkid_evaluate_spec(const char *spec, blkid_cache *cache)
275{
276 char *t = NULL, *v = NULL, *res;
277
278 if (!spec)
279 return NULL;
280
281 if (strchr(spec, '=') &&
282 blkid_parse_tag_string(spec, &t, &v) != 0) /* parse error */
283 return NULL;
284
285 if (v)
286 res = blkid_evaluate_tag(t, v, cache);
287 else
288 res = canonicalize_path(spec);
289
290 free(t);
291 free(v);
292 return res;
293}
294
295
892a404c
KZ
296#ifdef TEST_PROGRAM
297int main(int argc, char *argv[])
298{
299 blkid_cache cache = NULL;
300 char *res;
301
5298f728
KZ
302 if (argc < 2) {
303 fprintf(stderr, "usage: %s <tag> | <spec>\n", argv[0]);
892a404c
KZ
304 return EXIT_FAILURE;
305 }
306
7a458332 307 blkid_init_debug(0);
892a404c 308
5298f728 309 res = blkid_evaluate_spec(argv[1], &cache);
892a404c
KZ
310 if (res)
311 printf("%s\n", res);
312 if (cache)
313 blkid_put_cache(cache);
314
315 return res ? EXIT_SUCCESS : EXIT_FAILURE;
316}
317#endif