]>
Commit | Line | Data |
---|---|---|
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) */ |
52 | static 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); | |
81 | done: | |
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 | */ |
99 | int 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 | ||
128 | static 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 | ||
169 | failed: | |
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 | ||
178 | static 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 | 213 | char *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)); | |
257 | out: | |
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 | */ | |
274 | char *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 |
297 | int 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 |