blob: ffbe097e4179e28db15b5afeed7dbd4da35dce15 [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * evaluate.c - very high-level API to evaluate LABELs or UUIDs
3 *
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 */
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
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <stdint.h>
23#include <stdarg.h>
24
25#include "pathnames.h"
26#include "canonicalize.h"
bigbiff7b4c7a62015-01-01 19:44:14 -050027#include "closestream.h"
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050028
29#include "blkidP.h"
30
31/**
32 * SECTION:evaluate
33 * @title: Tags and Spec evaluation
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
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.
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
52#ifdef CONFIG_BLKID_VERIFY_UDEV
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;
59 const char *data;
60 int errsv = 0;
61
62 pr = blkid_new_probe();
63 if (!pr)
64 return -1;
65
66 blkid_probe_enable_superblocks(pr, TRUE);
67 blkid_probe_set_superblocks_flags(pr,
68 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID);
69
70 blkid_probe_enable_partitions(pr, TRUE);
71 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
72
73 fd = open(devname, O_RDONLY|O_CLOEXEC);
74 if (fd < 0) {
75 errsv = errno;
76 goto done;
77 }
78 if (blkid_probe_set_device(pr, fd, 0, 0))
79 goto done;
80 rc = blkid_do_safeprobe(pr);
81 if (rc)
82 goto done;
83 rc = blkid_probe_lookup_value(pr, name, &data, &len);
84 if (!rc)
85 rc = memcmp(value, data, len);
86done:
bigbiff7b4c7a62015-01-01 19:44:14 -050087 DBG(EVALUATE, ul_debug("%s: %s verification %s",
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050088 devname, name, rc == 0 ? "PASS" : "FAILED"));
89 if (fd >= 0)
90 close(fd);
91 blkid_free_probe(pr);
92
93 /* for non-root users we use unverified udev links */
94 return errsv == EACCES ? 0 : rc;
95}
96#endif /* CONFIG_BLKID_VERIFY_UDEV*/
97
98/**
99 * blkid_send_uevent:
100 * @devname: absolute path to the device
101 * @action: event string
102 *
103 * Returns: -1 in case of failure, or 0 on success.
104 */
105int blkid_send_uevent(const char *devname, const char *action)
106{
107 char uevent[PATH_MAX];
108 struct stat st;
109 FILE *f;
110 int rc = -1;
111
bigbiff7b4c7a62015-01-01 19:44:14 -0500112 DBG(EVALUATE, ul_debug("%s: uevent '%s' requested", devname, action));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500113
114 if (!devname || !action)
115 return -1;
116 if (stat(devname, &st) || !S_ISBLK(st.st_mode))
117 return -1;
118
119 snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent",
120 major(st.st_rdev), minor(st.st_rdev));
121
bigbiff7b4c7a62015-01-01 19:44:14 -0500122 f = fopen(uevent, "w" UL_CLOEXECSTR);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500123 if (f) {
124 rc = 0;
125 if (fputs(action, f) >= 0)
126 rc = 0;
bigbiff7b4c7a62015-01-01 19:44:14 -0500127 if (close_stream(f) != 0)
128 DBG(EVALUATE, ul_debug("write failed: %s", uevent));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500129 }
bigbiff7b4c7a62015-01-01 19:44:14 -0500130 DBG(EVALUATE, ul_debug("%s: send uevent %s",
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500131 uevent, rc == 0 ? "SUCCES" : "FAILED"));
132 return rc;
133}
134
135static char *evaluate_by_udev(const char *token, const char *value, int uevent)
136{
137 char dev[PATH_MAX];
138 char *path = NULL;
139 size_t len;
140 struct stat st;
141
bigbiff7b4c7a62015-01-01 19:44:14 -0500142 DBG(EVALUATE, ul_debug("evaluating by udev %s=%s", token, value));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500143
144 if (!strcmp(token, "UUID"))
145 strcpy(dev, _PATH_DEV_BYUUID "/");
146 else if (!strcmp(token, "LABEL"))
147 strcpy(dev, _PATH_DEV_BYLABEL "/");
148 else if (!strcmp(token, "PARTLABEL"))
149 strcpy(dev, _PATH_DEV_BYPARTLABEL "/");
150 else if (!strcmp(token, "PARTUUID"))
151 strcpy(dev, _PATH_DEV_BYPARTUUID "/");
152 else {
bigbiff7b4c7a62015-01-01 19:44:14 -0500153 DBG(EVALUATE, ul_debug("unsupported token %s", token));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500154 return NULL; /* unsupported tag */
155 }
156
157 len = strlen(dev);
158 if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0)
159 return NULL;
160
bigbiff7b4c7a62015-01-01 19:44:14 -0500161 DBG(EVALUATE, ul_debug("expected udev link: %s", dev));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500162
163 if (stat(dev, &st))
164 goto failed; /* link or device does not exist */
165
166 if (!S_ISBLK(st.st_mode))
167 return NULL;
168
169 path = canonicalize_path(dev);
170 if (!path)
171 return NULL;
172
173#ifdef CONFIG_BLKID_VERIFY_UDEV
174 if (verify_tag(path, token, value))
175 goto failed;
176#endif
177 return path;
178
179failed:
bigbiff7b4c7a62015-01-01 19:44:14 -0500180 DBG(EVALUATE, ul_debug("failed to evaluate by udev"));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500181
182 if (uevent && path)
183 blkid_send_uevent(path, "change");
184 free(path);
185 return NULL;
186}
187
188static char *evaluate_by_scan(const char *token, const char *value,
189 blkid_cache *cache, struct blkid_config *conf)
190{
191 blkid_cache c = cache ? *cache : NULL;
192 char *res;
193
bigbiff7b4c7a62015-01-01 19:44:14 -0500194 DBG(EVALUATE, ul_debug("evaluating by blkid scan %s=%s", token, value));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500195
196 if (!c) {
197 char *cachefile = blkid_get_cache_filename(conf);
198 blkid_get_cache(&c, cachefile);
199 free(cachefile);
200 }
201 if (!c)
202 return NULL;
203
204 res = blkid_get_devname(c, token, value);
205
206 if (cache)
207 *cache = c;
208 else
209 blkid_put_cache(c);
210
211 return res;
212}
213
214/**
215 * blkid_evaluate_tag:
216 * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo")
217 * @value: token data (e.g. "foo")
218 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
219 *
220 * Returns: allocated string with a device name.
221 */
222char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache)
223{
224 struct blkid_config *conf = NULL;
225 char *t = NULL, *v = NULL;
226 char *ret = NULL;
227 int i;
228
229 if (!token)
230 return NULL;
231
232 if (!cache || !*cache)
233 blkid_init_debug(0);
234
bigbiff7b4c7a62015-01-01 19:44:14 -0500235 DBG(EVALUATE, ul_debug("evaluating %s%s%s", token, value ? "=" : "",
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500236 value ? value : ""));
237
238 if (!value) {
239 if (!strchr(token, '=')) {
240 ret = strdup(token);
241 goto out;
242 }
243 blkid_parse_tag_string(token, &t, &v);
244 if (!t || !v)
245 goto out;
246 token = t;
247 value = v;
248 }
249
250 conf = blkid_read_config(NULL);
251 if (!conf)
252 goto out;
253
254 for (i = 0; i < conf->nevals; i++) {
255 if (conf->eval[i] == BLKID_EVAL_UDEV)
256 ret = evaluate_by_udev(token, value, conf->uevent);
257 else if (conf->eval[i] == BLKID_EVAL_SCAN)
258 ret = evaluate_by_scan(token, value, cache, conf);
259 if (ret)
260 break;
261 }
262
bigbiff7b4c7a62015-01-01 19:44:14 -0500263 DBG(EVALUATE, ul_debug("%s=%s evaluated as %s", token, value, ret));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500264out:
265 blkid_free_config(conf);
266 free(t);
267 free(v);
268 return ret;
269}
270
271/**
272 * blkid_evaluate_spec:
273 * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0)
274 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
275 *
276 * All returned paths are canonicalized, device-mapper paths are converted
277 * to the /dev/mapper/name format.
278 *
279 * Returns: allocated string with a device name.
280 */
281char *blkid_evaluate_spec(const char *spec, blkid_cache *cache)
282{
283 char *t = NULL, *v = NULL, *res;
284
285 if (!spec)
286 return NULL;
287
288 if (strchr(spec, '=') &&
289 blkid_parse_tag_string(spec, &t, &v) != 0) /* parse error */
290 return NULL;
291
292 if (v)
293 res = blkid_evaluate_tag(t, v, cache);
294 else
295 res = canonicalize_path(spec);
296
297 free(t);
298 free(v);
299 return res;
300}
301
302
303#ifdef TEST_PROGRAM
304int main(int argc, char *argv[])
305{
306 blkid_cache cache = NULL;
307 char *res;
308
309 if (argc < 2) {
310 fprintf(stderr, "usage: %s <tag> | <spec>\n", argv[0]);
311 return EXIT_FAILURE;
312 }
313
314 blkid_init_debug(0);
315
316 res = blkid_evaluate_spec(argv[1], &cache);
317 if (res)
318 printf("%s\n", res);
319 if (cache)
320 blkid_put_cache(cache);
321
322 return res ? EXIT_SUCCESS : EXIT_FAILURE;
323}
324#endif