Upload Tizen:Base source
[framework/base/util-linux-ng.git] / lib / fsprobe.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <stdlib.h>
9
10 #ifdef HAVE_BLKID_BLKID_H
11 #include <blkid/blkid.h>
12 #else
13 #include <blkid.h>
14 #endif
15
16 #include "blkdev.h"
17 #include "canonicalize.h"
18 #include "pathnames.h"
19 #include "fsprobe.h"
20
21 static blkid_cache blcache;
22
23 #ifdef HAVE_BLKID_EVALUATE_TAG
24 /* ask kernel developers why we need such ugly open() method... */
25 static int
26 open_device(const char *devname)
27 {
28         int retries = 0;
29
30         do {
31                 int fd = open(devname, O_RDONLY);
32                 if (fd >= 0)
33                         return fd;
34                 if (errno != ENOMEDIUM)
35                         break;
36                 if (retries >= CRDOM_NOMEDIUM_RETRIES)
37                         break;
38                 ++retries;
39                 sleep(3);
40         } while(1);
41
42         return -1;
43 }
44 #endif
45
46 /*
47  * Parses NAME=value, returns -1 on parse error, 0 success. The success is also
48  * when the 'spec' doesn't contain name=value pair (because the spec could be
49  * a devname too). In particular case the pointer 'name' is set to NULL.
50  */
51 int
52 fsprobe_parse_spec(const char *spec, char **name, char **value)
53 {
54         *name = NULL;
55         *value = NULL;
56
57         if (strchr(spec, '='))
58                 return blkid_parse_tag_string(spec, name, value);
59
60         return 0;
61 }
62
63 char *
64 fsprobe_get_devname_by_spec(const char *spec)
65 {
66         char *name, *value;
67
68         if (!spec)
69                 return NULL;
70         if (fsprobe_parse_spec(spec, &name, &value) != 0)
71                 return NULL;                            /* parse error */
72         if (name) {
73                 char *nspec = NULL;
74
75                 if (!strcmp(name,"LABEL"))
76                         nspec = fsprobe_get_devname_by_label(value);
77                 else if (!strcmp(name,"UUID"))
78                         nspec = fsprobe_get_devname_by_uuid(value);
79
80                 free(name);
81                 free(value);
82                 return nspec;
83         }
84
85         return canonicalize_path(spec);
86 }
87
88 void
89 fsprobe_init(void)
90 {
91         blcache = NULL;
92 }
93
94 int
95 fsprobe_known_fstype(const char *fstype)
96 {
97         return blkid_known_fstype(fstype);
98 }
99
100 #ifdef HAVE_BLKID_EVALUATE_TAG
101 /*
102  * libblkid from util-linux-ng
103  * -- recommended
104  */
105 static blkid_probe blprobe;
106
107 void
108 fsprobe_exit(void)
109 {
110         if (blprobe)
111                 blkid_free_probe(blprobe);
112         if (blcache)
113                 blkid_put_cache(blcache);
114 }
115
116 /* returns device LABEL, UUID, FSTYPE, ... by low-level
117  * probing interface
118  */
119 static char *
120 fsprobe_get_value(const char *name, const char *devname)
121 {
122         int fd;
123         const char *data = NULL;
124
125         if (!devname || !name)
126                 return NULL;
127         fd = open_device(devname);
128         if (fd < 0)
129                 return NULL;
130         if (!blprobe)
131                 blprobe = blkid_new_probe();
132         if (!blprobe)
133                 goto done;
134         if (blkid_probe_set_device(blprobe, fd, 0, 0))
135                 goto done;
136         if (blkid_probe_set_request(blprobe, BLKID_PROBREQ_LABEL |
137                          BLKID_PROBREQ_UUID | BLKID_PROBREQ_TYPE ))
138                 goto done;
139         if (blkid_do_safeprobe(blprobe))
140                 goto done;
141         if (blkid_probe_lookup_value(blprobe, name, &data, NULL))
142                 goto done;
143 done:
144         close(fd);
145         return data ? strdup((char *) data) : NULL;
146 }
147
148 char *
149 fsprobe_get_label_by_devname(const char *devname)
150 {
151         return fsprobe_get_value("LABEL", devname);
152 }
153
154 char *
155 fsprobe_get_uuid_by_devname(const char *devname)
156 {
157         return fsprobe_get_value("UUID", devname);
158 }
159
160 char *
161 fsprobe_get_fstype_by_devname(const char *devname)
162 {
163         return fsprobe_get_value("TYPE", devname);
164 }
165
166 char *
167 fsprobe_get_devname_by_uuid(const char *uuid)
168 {
169         return blkid_evaluate_tag("UUID", uuid, &blcache);
170 }
171
172 char *
173 fsprobe_get_devname_by_label(const char *label)
174 {
175         return blkid_evaluate_tag("LABEL", label, &blcache);
176 }
177
178 #else /* !HAVE_BLKID_EVALUATE_TAG */
179
180 /*
181  * Classic libblkid (from e2fsprogs) without blkid_evaluate_tag()
182  * -- deprecated
183  */
184 #define BLKID_EMPTY_CACHE       "/dev/null"
185
186 void
187 fsprobe_exit(void)
188 {
189         if (blcache)
190                 blkid_put_cache(blcache);
191 }
192
193 char *
194 fsprobe_get_devname_by_uuid(const char *uuid)
195 {
196         if (!blcache)
197                 blkid_get_cache(&blcache, NULL);
198
199         return blkid_get_devname(blcache, "UUID", uuid);
200 }
201
202 char *
203 fsprobe_get_devname_by_label(const char *label)
204 {
205         if (!blcache)
206                 blkid_get_cache(&blcache, NULL);
207
208         return blkid_get_devname(blcache, "LABEL", label);
209 }
210
211 char *
212 fsprobe_get_fstype_by_devname(const char *devname)
213 {
214         blkid_cache c;
215         char *tp;
216
217         if (blcache)
218                 return blkid_get_tag_value(blcache, "TYPE", devname);
219
220         /* The cache is not initialized yet. Use empty cache rather than waste
221          * time with /etc/blkid.tab. It seems that probe FS is faster than
222          * parse the cache file.  -- kzak (17-May-2007)
223          */
224         blkid_get_cache(&c, BLKID_EMPTY_CACHE);
225         tp = blkid_get_tag_value(c, "TYPE", devname);
226         blkid_put_cache(c);
227
228         return tp;
229 }
230
231 char *
232 fsprobe_get_label_by_devname(const char *devname)
233 {
234         if (!blcache)
235                 blkid_get_cache(&blcache, NULL);
236
237         return blkid_get_tag_value(blcache, "LABEL", devname);
238 }
239
240 char *
241 fsprobe_get_uuid_by_devname(const char *devname)
242 {
243         if (!blcache)
244                 blkid_get_cache(&blcache, NULL);
245
246         return blkid_get_tag_value(blcache, "UUID", devname);
247 }
248
249 #endif /* !HAVE_BLKID_EVALUATE_TAG */