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