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