]>
Commit | Line | Data |
---|---|---|
ccafadb7 KZ |
1 | |
2 | #include <blkid.h> | |
3 | ||
4 | #ifdef HAVE_LIBUDEV | |
5 | # include <libudev.h> | |
6 | #endif | |
7 | ||
8 | #include "c.h" | |
9 | #include "xalloc.h" | |
10 | #include "mangle.h" | |
7408a5d9 | 11 | #include "path.h" |
107e9559 | 12 | #include "nls.h" |
ccafadb7 KZ |
13 | |
14 | #include "lsblk.h" | |
15 | ||
16 | #ifdef HAVE_LIBUDEV | |
17 | static struct udev *udev; | |
18 | #endif | |
19 | ||
20 | void lsblk_device_free_properties(struct lsblk_devprop *p) | |
21 | { | |
22 | if (!p) | |
23 | return; | |
24 | ||
25 | free(p->fstype); | |
9cca1ef2 | 26 | free(p->fsversion); |
ccafadb7 KZ |
27 | free(p->uuid); |
28 | free(p->ptuuid); | |
29 | free(p->pttype); | |
30 | free(p->label); | |
31 | free(p->parttype); | |
32 | free(p->partuuid); | |
33 | free(p->partlabel); | |
34 | free(p->wwn); | |
35 | free(p->serial); | |
36 | free(p->model); | |
7408a5d9 | 37 | free(p->partflags); |
ccafadb7 | 38 | |
6f74ede5 KZ |
39 | free(p->mode); |
40 | free(p->owner); | |
41 | free(p->group); | |
42 | ||
ccafadb7 KZ |
43 | free(p); |
44 | } | |
45 | ||
46 | #ifndef HAVE_LIBUDEV | |
fed34a1e | 47 | static struct lsblk_devprop *get_properties_by_udev(struct lsblk_device *dev |
ccafadb7 KZ |
48 | __attribute__((__unused__))) |
49 | { | |
50 | return NULL; | |
51 | } | |
52 | #else | |
fed34a1e | 53 | static struct lsblk_devprop *get_properties_by_udev(struct lsblk_device *ld) |
ccafadb7 KZ |
54 | { |
55 | struct udev_device *dev; | |
56 | ||
fed34a1e KZ |
57 | if (ld->udev_requested) |
58 | return ld->properties; | |
ccafadb7 | 59 | |
ccafadb7 KZ |
60 | if (!udev) |
61 | udev = udev_new(); /* global handler */ | |
62 | if (!udev) | |
63 | goto done; | |
64 | ||
fed34a1e | 65 | dev = udev_device_new_from_subsystem_sysname(udev, "block", ld->name); |
ccafadb7 KZ |
66 | if (dev) { |
67 | const char *data; | |
68 | struct lsblk_devprop *prop; | |
69 | ||
fed34a1e KZ |
70 | if (ld->properties) |
71 | lsblk_device_free_properties(ld->properties); | |
72 | prop = ld->properties = xcalloc(1, sizeof(*ld->properties)); | |
ccafadb7 KZ |
73 | |
74 | if ((data = udev_device_get_property_value(dev, "ID_FS_LABEL_ENC"))) { | |
75 | prop->label = xstrdup(data); | |
76 | unhexmangle_string(prop->label); | |
77 | } | |
78 | if ((data = udev_device_get_property_value(dev, "ID_FS_UUID_ENC"))) { | |
79 | prop->uuid = xstrdup(data); | |
80 | unhexmangle_string(prop->uuid); | |
81 | } | |
82 | if ((data = udev_device_get_property_value(dev, "ID_PART_TABLE_UUID"))) | |
83 | prop->ptuuid = xstrdup(data); | |
84 | if ((data = udev_device_get_property_value(dev, "ID_PART_TABLE_TYPE"))) | |
85 | prop->pttype = xstrdup(data); | |
86 | if ((data = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME"))) { | |
87 | prop->partlabel = xstrdup(data); | |
88 | unhexmangle_string(prop->partlabel); | |
89 | } | |
90 | if ((data = udev_device_get_property_value(dev, "ID_FS_TYPE"))) | |
91 | prop->fstype = xstrdup(data); | |
9cca1ef2 KZ |
92 | if ((data = udev_device_get_property_value(dev, "ID_FS_VERSION"))) |
93 | prop->fsversion = xstrdup(data); | |
ccafadb7 KZ |
94 | if ((data = udev_device_get_property_value(dev, "ID_PART_ENTRY_TYPE"))) |
95 | prop->parttype = xstrdup(data); | |
96 | if ((data = udev_device_get_property_value(dev, "ID_PART_ENTRY_UUID"))) | |
97 | prop->partuuid = xstrdup(data); | |
98 | if ((data = udev_device_get_property_value(dev, "ID_PART_ENTRY_FLAGS"))) | |
99 | prop->partflags = xstrdup(data); | |
100 | ||
101 | data = udev_device_get_property_value(dev, "ID_WWN_WITH_EXTENSION"); | |
102 | if (!data) | |
103 | data = udev_device_get_property_value(dev, "ID_WWN"); | |
104 | if (data) | |
105 | prop->wwn = xstrdup(data); | |
106 | ||
c2f6513c SW |
107 | data = udev_device_get_property_value(dev, "ID_SCSI_SERIAL"); |
108 | if(!data) | |
109 | data = udev_device_get_property_value(dev, "ID_SERIAL_SHORT"); | |
e81d0f80 SW |
110 | if(!data) |
111 | data = udev_device_get_property_value(dev, "ID_SERIAL"); | |
c2f6513c | 112 | if (data) |
ccafadb7 | 113 | prop->serial = xstrdup(data); |
c2f6513c | 114 | |
ccafadb7 KZ |
115 | if ((data = udev_device_get_property_value(dev, "ID_MODEL"))) |
116 | prop->model = xstrdup(data); | |
117 | ||
118 | udev_device_unref(dev); | |
fed34a1e | 119 | DBG(DEV, ul_debugobj(ld, "%s: found udev properties", ld->name)); |
ccafadb7 KZ |
120 | } |
121 | ||
122 | done: | |
fed34a1e | 123 | ld->udev_requested = 1; |
7408a5d9 KZ |
124 | |
125 | DBG(DEV, ul_debugobj(ld, " from udev")); | |
fed34a1e | 126 | return ld->properties; |
ccafadb7 KZ |
127 | } |
128 | #endif /* HAVE_LIBUDEV */ | |
129 | ||
7408a5d9 KZ |
130 | |
131 | static int lookup(char *buf, char *pattern, char **value) | |
132 | { | |
133 | char *p, *v; | |
134 | int len; | |
135 | ||
136 | /* do not re-fill value */ | |
137 | if (!buf || *value) | |
138 | return 0; | |
139 | ||
140 | len = strlen(pattern); | |
ad296391 | 141 | if (strncmp(buf, pattern, len) != 0) |
7408a5d9 KZ |
142 | return 0; |
143 | ||
144 | p = buf + len; | |
145 | if (*p != '=') | |
146 | return 0; | |
147 | p++; | |
148 | if (!*p || *p == '\n') | |
149 | return 0; | |
150 | v = p; | |
151 | for (; *p && *p != '\n'; p++) ; | |
152 | if (*p == '\n') | |
153 | *p = '\0'; | |
154 | ||
155 | *value = xstrdup(v); | |
156 | return 1; | |
157 | } | |
158 | ||
159 | /* read device properties from fake text file (used on --sysroot) */ | |
160 | static struct lsblk_devprop *get_properties_by_file(struct lsblk_device *ld) | |
161 | { | |
162 | struct lsblk_devprop *prop; | |
163 | struct path_cxt *pc; | |
164 | FILE *fp = NULL; | |
165 | struct stat sb; | |
166 | char buf[BUFSIZ]; | |
167 | ||
eea06b92 KZ |
168 | assert(lsblk->sysroot); |
169 | ||
7408a5d9 KZ |
170 | if (ld->file_requested) |
171 | return ld->properties; | |
172 | ||
7408a5d9 KZ |
173 | if (ld->properties || ld->filename) { |
174 | lsblk_device_free_properties(ld->properties); | |
175 | ld->properties = NULL; | |
176 | } | |
177 | ||
178 | pc = ul_new_path("/"); | |
179 | if (!pc) | |
180 | return NULL; | |
181 | if (ul_path_set_prefix(pc, lsblk->sysroot) != 0) | |
182 | goto done; | |
183 | if (ul_path_stat(pc, &sb, ld->filename) != 0 || !S_ISREG(sb.st_mode)) | |
184 | goto done; | |
185 | ||
186 | fp = ul_path_fopen(pc, "r", ld->filename); | |
187 | if (!fp) | |
188 | goto done; | |
189 | ||
190 | prop = ld->properties; | |
191 | if (!prop) | |
192 | prop = ld->properties = xcalloc(1, sizeof(*ld->properties)); | |
193 | ||
194 | while (fgets(buf, sizeof(buf), fp) != NULL) { | |
6f74ede5 | 195 | /* udev based */ |
7408a5d9 KZ |
196 | if (lookup(buf, "ID_FS_LABEL_ENC", &prop->label)) |
197 | unhexmangle_string(prop->label); | |
198 | else if (lookup(buf, "ID_FS_UUID_ENC", &prop->uuid)) | |
199 | unhexmangle_string(prop->uuid); | |
200 | else if (lookup(buf, "ID_PART_ENTRY_NAME", &prop->partlabel)) | |
201 | unhexmangle_string(prop->partlabel); | |
202 | else if (lookup(buf, "ID_PART_TABLE_UUID", &prop->ptuuid)) ; | |
203 | else if (lookup(buf, "ID_PART_TABLE_TYPE", &prop->pttype)) ; | |
204 | else if (lookup(buf, "ID_FS_TYPE", &prop->fstype)) ; | |
9cca1ef2 | 205 | else if (lookup(buf, "ID_FS_VERSION", &prop->fsversion)) ; |
7408a5d9 KZ |
206 | else if (lookup(buf, "ID_PART_ENTRY_TYPE", &prop->parttype)) ; |
207 | else if (lookup(buf, "ID_PART_ENTRY_UUID", &prop->partuuid)) ; | |
208 | else if (lookup(buf, "ID_PART_ENTRY_FLAGS", &prop->partflags)) ; | |
209 | else if (lookup(buf, "ID_MODEL", &prop->model)) ; | |
210 | else if (lookup(buf, "ID_WWN_WITH_EXTENSION", &prop->wwn)) ; | |
211 | else if (lookup(buf, "ID_WWN", &prop->wwn)) ; | |
212 | else if (lookup(buf, "ID_SCSI_SERIAL", &prop->serial)) ; | |
213 | else if (lookup(buf, "ID_SERIAL_SHORT", &prop->serial)) ; | |
e81d0f80 | 214 | else if (lookup(buf, "ID_SERIAL", &prop->serial)) ; |
6f74ede5 KZ |
215 | |
216 | /* lsblk specific */ | |
217 | else if (lookup(buf, "MODE", &prop->mode)) ; | |
218 | else if (lookup(buf, "OWNER", &prop->owner)) ; | |
219 | else if (lookup(buf, "GROUP", &prop->group)) ; | |
220 | ||
7408a5d9 KZ |
221 | else |
222 | continue; | |
223 | } | |
224 | done: | |
225 | if (fp) | |
226 | fclose(fp); | |
227 | ul_unref_path(pc); | |
228 | ld->file_requested = 1; | |
229 | ||
230 | DBG(DEV, ul_debugobj(ld, " from fake-file")); | |
231 | return ld->properties; | |
232 | } | |
233 | ||
234 | ||
fed34a1e | 235 | static struct lsblk_devprop *get_properties_by_blkid(struct lsblk_device *dev) |
ccafadb7 KZ |
236 | { |
237 | blkid_probe pr = NULL; | |
238 | ||
fed34a1e KZ |
239 | if (dev->blkid_requested) |
240 | return dev->properties; | |
ccafadb7 | 241 | |
fed34a1e | 242 | if (!dev->size) |
ccafadb7 KZ |
243 | goto done; |
244 | if (getuid() != 0) | |
245 | goto done;; /* no permissions to read from the device */ | |
246 | ||
fed34a1e | 247 | pr = blkid_new_probe_from_filename(dev->filename); |
ccafadb7 KZ |
248 | if (!pr) |
249 | goto done; | |
250 | ||
251 | blkid_probe_enable_superblocks(pr, 1); | |
252 | blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_LABEL | | |
253 | BLKID_SUBLKS_UUID | | |
254 | BLKID_SUBLKS_TYPE); | |
255 | blkid_probe_enable_partitions(pr, 1); | |
256 | blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); | |
257 | ||
258 | if (!blkid_do_safeprobe(pr)) { | |
259 | const char *data = NULL; | |
260 | struct lsblk_devprop *prop; | |
261 | ||
fed34a1e KZ |
262 | if (dev->properties) |
263 | lsblk_device_free_properties(dev->properties); | |
264 | prop = dev->properties = xcalloc(1, sizeof(*dev->properties)); | |
ccafadb7 KZ |
265 | |
266 | if (!blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) | |
267 | prop->fstype = xstrdup(data); | |
268 | if (!blkid_probe_lookup_value(pr, "UUID", &data, NULL)) | |
269 | prop->uuid = xstrdup(data); | |
270 | if (!blkid_probe_lookup_value(pr, "PTUUID", &data, NULL)) | |
271 | prop->ptuuid = xstrdup(data); | |
272 | if (!blkid_probe_lookup_value(pr, "PTTYPE", &data, NULL)) | |
273 | prop->pttype = xstrdup(data); | |
274 | if (!blkid_probe_lookup_value(pr, "LABEL", &data, NULL)) | |
275 | prop->label = xstrdup(data); | |
9cca1ef2 KZ |
276 | if (!blkid_probe_lookup_value(pr, "VERSION", &data, NULL)) |
277 | prop->fsversion = xstrdup(data); | |
ccafadb7 KZ |
278 | if (!blkid_probe_lookup_value(pr, "PART_ENTRY_TYPE", &data, NULL)) |
279 | prop->parttype = xstrdup(data); | |
280 | if (!blkid_probe_lookup_value(pr, "PART_ENTRY_UUID", &data, NULL)) | |
281 | prop->partuuid = xstrdup(data); | |
282 | if (!blkid_probe_lookup_value(pr, "PART_ENTRY_NAME", &data, NULL)) | |
283 | prop->partlabel = xstrdup(data); | |
284 | if (!blkid_probe_lookup_value(pr, "PART_ENTRY_FLAGS", &data, NULL)) | |
285 | prop->partflags = xstrdup(data); | |
286 | ||
fed34a1e | 287 | DBG(DEV, ul_debugobj(dev, "%s: found blkid properties", dev->name)); |
ccafadb7 KZ |
288 | } |
289 | ||
290 | done: | |
291 | blkid_free_probe(pr); | |
292 | ||
7408a5d9 | 293 | DBG(DEV, ul_debugobj(dev, " from blkid")); |
fed34a1e KZ |
294 | dev->blkid_requested = 1; |
295 | return dev->properties; | |
ccafadb7 KZ |
296 | } |
297 | ||
fed34a1e | 298 | struct lsblk_devprop *lsblk_device_get_properties(struct lsblk_device *dev) |
ccafadb7 | 299 | { |
7408a5d9 | 300 | struct lsblk_devprop *p = NULL; |
ccafadb7 | 301 | |
7408a5d9 KZ |
302 | DBG(DEV, ul_debugobj(dev, "%s: properties requested", dev->filename)); |
303 | if (lsblk->sysroot) | |
eea06b92 KZ |
304 | return get_properties_by_file(dev); |
305 | ||
306 | p = get_properties_by_udev(dev); | |
ccafadb7 | 307 | if (!p) |
fed34a1e | 308 | p = get_properties_by_blkid(dev); |
ccafadb7 KZ |
309 | return p; |
310 | } | |
311 | ||
312 | void lsblk_properties_deinit(void) | |
313 | { | |
314 | #ifdef HAVE_LIBUDEV | |
315 | udev_unref(udev); | |
316 | #endif | |
317 | } | |
107e9559 KZ |
318 | |
319 | ||
320 | ||
321 | /* | |
322 | * Partition types | |
323 | */ | |
324 | struct lsblk_parttype { | |
325 | unsigned int code; /* type as number or zero */ | |
326 | char *name; /* description */ | |
327 | char *typestr; /* type as string or NULL */ | |
328 | }; | |
329 | ||
330 | static const struct lsblk_parttype mbr_types[] = | |
331 | { | |
332 | #include "pt-mbr-partnames.h" | |
333 | }; | |
334 | ||
335 | #define DEF_GUID(_u, _n) \ | |
336 | { \ | |
337 | .typestr = (_u), \ | |
338 | .name = (_n), \ | |
339 | } | |
340 | static const struct lsblk_parttype gpt_types[] = | |
341 | { | |
342 | #include "pt-gpt-partnames.h" | |
343 | }; | |
344 | ||
345 | const char *lsblk_parttype_code_to_string(const char *code, const char *pttype) | |
346 | { | |
347 | size_t i; | |
348 | ||
349 | if (!code || !pttype) | |
350 | return NULL; | |
351 | ||
352 | if (strcmp(pttype, "dos") == 0 || strcmp(pttype, "mbr") == 0) { | |
353 | char *end = NULL; | |
354 | unsigned int xcode; | |
355 | ||
356 | errno = 0; | |
357 | xcode = strtol(code, &end, 16); | |
358 | ||
359 | if (errno || *end != '\0') | |
360 | return NULL; | |
361 | ||
362 | for (i = 0; i < ARRAY_SIZE(mbr_types); i++) { | |
363 | const struct lsblk_parttype *t = &mbr_types[i]; | |
364 | ||
365 | if (t->name && t->code == xcode) | |
366 | return t->name; | |
367 | } | |
368 | ||
369 | } else if (strcmp(pttype, "gpt") == 0) { | |
370 | for (i = 0; i < ARRAY_SIZE(gpt_types); i++) { | |
371 | const struct lsblk_parttype *t = &gpt_types[i]; | |
372 | ||
373 | if (t->name && t->typestr && | |
374 | strcasecmp(code, t->typestr) == 0) | |
375 | return t->name; | |
376 | } | |
377 | } | |
378 | ||
379 | return NULL; | |
380 | } |