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