Upload Tizen:Base source
[framework/base/util-linux-ng.git] / shlibs / blkid / src / evaluate.c
1 /*
2  * evaluate.c - very high-level API to evaluate LABELs or UUIDs
3  *
4  * This is simular to blkid_get_devname() from resolve.c, but this
5  * API supports udev /dev/disk/by-{label,uuid} links.
6  *
7  * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
8  *
9  * This file may be redistributed under the terms of the
10  * GNU Lesser General Public License.
11  */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <ctype.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_STAT_H
21 #include <sys/stat.h>
22 #endif
23 #ifdef HAVE_SYS_MKDEV_H
24 #include <sys/mkdev.h>
25 #endif
26 #ifdef HAVE_ERRNO_H
27 #include <errno.h>
28 #endif
29 #include <stdint.h>
30 #include <stdarg.h>
31
32 #include "pathnames.h"
33 #include "canonicalize.h"
34
35 #include "blkdev.h"
36 #include "blkidP.h"
37
38 /* returns zero when the device has NAME=value (LABEL/UUID) */
39 static int verify_tag(const char *devname, const char *name, const char *value)
40 {
41         blkid_probe pr;
42         int fd = -1, rc = -1;
43         size_t len;
44         const char *data;
45         int errsv = 0;
46
47         pr = blkid_new_probe();
48         if (!pr)
49                 return -1;
50
51         blkid_probe_set_request(pr, BLKID_PROBREQ_LABEL | BLKID_PROBREQ_UUID);
52
53         fd = open(devname, O_RDONLY);
54         if (fd < 0) {
55                 errsv = errno;
56                 goto done;
57         }
58         if (blkid_probe_set_device(pr, fd, 0, 0))
59                 goto done;
60         rc = blkid_do_safeprobe(pr);
61         if (rc)
62                 goto done;
63         rc = blkid_probe_lookup_value(pr, name, &data, &len);
64         if (!rc)
65                 rc = memcmp(value, data, len);
66 done:
67         DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n",
68                         devname, name, rc == 0 ? "PASS" : "FAILED"));
69         if (fd >= 0)
70                 close(fd);
71         blkid_free_probe(pr);
72
73         /* for non-root users we use unverified udev links */
74         return errsv == EACCES ? 0 : rc;
75 }
76
77 /**
78  * blkid_send_uevent:
79  * @devname: absolute path to the device
80  *
81  * Returns -1 in case of failure, or 0 on success.
82  */
83 int blkid_send_uevent(const char *devname, const char *action)
84 {
85         char uevent[PATH_MAX];
86         struct stat st;
87         FILE *f;
88         int rc = -1;
89
90         DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action));
91
92         if (!devname || !action)
93                 return -1;
94         if (stat(devname, &st) || !S_ISBLK(st.st_mode))
95                 return -1;
96
97         snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent",
98                         major(st.st_rdev), minor(st.st_rdev));
99
100         f = fopen(uevent, "w");
101         if (f) {
102                 rc = 0;
103                 if (fputs(action, f) >= 0)
104                         rc = 0;
105                 fclose(f);
106         }
107         DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n",
108                         uevent, rc == 0 ? "SUCCES" : "FAILED"));
109         return rc;
110 }
111
112 static char *evaluate_by_udev(const char *token, const char *value, int uevent)
113 {
114         char dev[PATH_MAX];
115         char *path = NULL;
116         size_t len;
117         struct stat st;
118
119         DBG(DEBUG_EVALUATE,
120             printf("evaluating by udev %s=%s\n", token, value));
121
122         if (!strcmp(token, "UUID"))
123                 strcpy(dev, _PATH_DEV_BYUUID "/");
124         else if (!strcmp(token, "LABEL"))
125                 strcpy(dev, _PATH_DEV_BYLABEL "/");
126         else {
127                 DBG(DEBUG_EVALUATE,
128                     printf("unsupported token %s\n", token));
129                 return NULL;    /* unsupported tag */
130         }
131
132         len = strlen(dev);
133         if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0)
134                 return NULL;
135
136         DBG(DEBUG_EVALUATE,
137             printf("expected udev link: %s\n", dev));
138
139         if (stat(dev, &st))
140                 goto failed;    /* link or device does not exist */
141
142         if (!S_ISBLK(st.st_mode))
143                 return NULL;
144
145         path = canonicalize_path(dev);
146         if (!path)
147                 return NULL;
148
149         if (verify_tag(path, token, value))
150                 goto failed;
151         return path;
152
153 failed:
154         DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n"));
155
156         if (uevent && path)
157                 blkid_send_uevent(path, "change");
158         free(path);
159         return NULL;
160 }
161
162 static char *evaluate_by_scan(const char *token, const char *value,
163                 blkid_cache *cache, struct blkid_config *conf)
164 {
165         blkid_cache c = cache ? *cache : NULL;
166         char *res;
167
168         DBG(DEBUG_EVALUATE,
169             printf("evaluating by blkid scan %s=%s\n", token, value));
170
171         if (!c) {
172                 char *cachefile = blkid_get_cache_filename(conf);
173                 blkid_get_cache(&c, cachefile);
174                 free(cachefile);
175         }
176         if (!c)
177                 return NULL;
178
179         res = blkid_get_devname(c, token, value);
180
181         if (cache)
182                 *cache = c;
183         else
184                 blkid_put_cache(c);
185
186         return res;
187 }
188
189 /**
190  * blkid_evaluate_tag:
191  * @token: token name (e.g "LABEL" or "UUID")
192  * @value: token data
193  * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
194  *
195  * Returns allocated string with device name.
196  */
197 char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache)
198 {
199         struct blkid_config *conf = NULL;
200         char *t = NULL, *v = NULL;
201         char *ret = NULL;
202         int i;
203
204         if (!token)
205                 return NULL;
206
207         if (!cache || !*cache)
208                 blkid_init_debug(0);
209
210         DBG(DEBUG_EVALUATE,
211             printf("evaluating  %s%s%s\n", token, value ? "=" : "",
212                    value ? value : ""));
213
214         if (!value) {
215                 if (!strchr(token, '=')) {
216                         ret = blkid_strdup(token);
217                         goto out;
218                 }
219                 blkid_parse_tag_string(token, &t, &v);
220                 if (!t || !v)
221                         goto out;
222                 token = t;
223                 value = v;
224         }
225
226         conf = blkid_read_config(NULL);
227         if (!conf)
228                 goto out;
229
230         for (i = 0; i < conf->nevals; i++) {
231                 if (conf->eval[i] == BLKID_EVAL_UDEV)
232                         ret = evaluate_by_udev(token, value, conf->uevent);
233                 else if (conf->eval[i] == BLKID_EVAL_SCAN)
234                         ret = evaluate_by_scan(token, value, cache, conf);
235                 if (ret)
236                         break;
237         }
238
239         DBG(DEBUG_EVALUATE,
240             printf("%s=%s evaluated as %s\n", token, value, ret));
241 out:
242         blkid_free_config(conf);
243         free(t);
244         free(v);
245         return ret;
246 }
247
248 #ifdef TEST_PROGRAM
249 int main(int argc, char *argv[])
250 {
251         blkid_cache cache = NULL;
252         char *res;
253
254         if (argc < 3) {
255                 fprintf(stderr, "usage: %s <token> <value>\n", argv[0]);
256                 return EXIT_FAILURE;
257         }
258
259         blkid_init_debug(0);
260
261         res = blkid_evaluate_tag(argv[1], argv[2], &cache);
262         if (res)
263                 printf("%s\n", res);
264         if (cache)
265                 blkid_put_cache(cache);
266
267         return res ? EXIT_SUCCESS : EXIT_FAILURE;
268 }
269 #endif