18 static struct udev
*udev
;
21 void lsblk_device_free_properties(struct lsblk_devprop
*p
)
51 static struct lsblk_devprop
*get_properties_by_udev(struct lsblk_device
*dev
52 __attribute__((__unused__
)))
58 #define LSBLK_UDEV_BYID_PREFIX "/dev/disk/by-id/"
59 #define LSBLK_UDEV_BYID_PREFIXSZ (sizeof(LSBLK_UDEV_BYID_PREFIX) - 1)
61 static struct lsblk_devprop
*get_properties_by_udev(struct lsblk_device
*ld
)
63 struct udev_device
*dev
;
64 struct udev_list_entry
*le
;
66 struct lsblk_devprop
*prop
;
69 if (ld
->udev_requested
)
70 return ld
->properties
;
73 udev
= udev_new(); /* global handler */
77 dev
= udev_device_new_from_subsystem_sysname(udev
, "block", ld
->name
);
81 DBG(DEV
, ul_debugobj(ld
, "%s: found udev properties", ld
->name
));
84 lsblk_device_free_properties(ld
->properties
);
85 prop
= ld
->properties
= xcalloc(1, sizeof(*ld
->properties
));
87 if ((data
= udev_device_get_property_value(dev
, "ID_FS_LABEL_ENC"))) {
88 prop
->label
= xstrdup(data
);
89 unhexmangle_string(prop
->label
);
91 if ((data
= udev_device_get_property_value(dev
, "ID_FS_UUID_ENC"))) {
92 prop
->uuid
= xstrdup(data
);
93 unhexmangle_string(prop
->uuid
);
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
);
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
);
111 if ((data
= udev_device_get_property_value(dev
, "ID_PART_ENTRY_NUMBER")))
112 prop
->partn
= xstrdup(data
);
113 if ((data
= udev_device_get_property_value(dev
, "ID_PART_ENTRY_FLAGS")))
114 prop
->partflags
= xstrdup(data
);
116 data
= udev_device_get_property_value(dev
, "ID_WWN_WITH_EXTENSION");
118 data
= udev_device_get_property_value(dev
, "ID_WWN");
120 prop
->wwn
= xstrdup(data
);
122 data
= udev_device_get_property_value(dev
, "SCSI_IDENT_SERIAL"); /* sg3_utils do not use I_D prefix */
124 data
= udev_device_get_property_value(dev
, "ID_SCSI_SERIAL");
126 data
= udev_device_get_property_value(dev
, "ID_SERIAL_SHORT");
128 data
= udev_device_get_property_value(dev
, "ID_SERIAL");
130 prop
->serial
= xstrdup(data
);
131 normalize_whitespace((unsigned char *) prop
->serial
);
134 if ((data
= udev_device_get_property_value(dev
, "ID_REVISION")))
135 prop
->revision
= xstrdup(data
);
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
);
146 /* select the shortest udev by-id symlink */
148 udev_list_entry_foreach(le
, udev_device_get_devlinks_list_entry(dev
)) {
149 const char *name
= udev_list_entry_get_name(le
);
152 if (!name
|| !startswith(name
, LSBLK_UDEV_BYID_PREFIX
))
154 name
+= LSBLK_UDEV_BYID_PREFIXSZ
;
158 if (!len
|| sz
< len
) {
161 prop
->idlink
= xstrdup(name
);
165 udev_device_unref(dev
);
167 ld
->udev_requested
= 1;
169 DBG(DEV
, ul_debugobj(ld
, " from udev"));
170 return ld
->properties
;
172 #endif /* HAVE_LIBUDEV */
175 static int lookup(char *buf
, char *pattern
, char **value
)
180 /* do not re-fill value */
184 len
= strlen(pattern
);
185 if (strncmp(buf
, pattern
, len
) != 0)
192 if (!*p
|| *p
== '\n')
195 for (; *p
&& *p
!= '\n'; p
++) ;
203 /* read device properties from fake text file (used on --sysroot) */
204 static struct lsblk_devprop
*get_properties_by_file(struct lsblk_device
*ld
)
206 struct lsblk_devprop
*prop
;
212 assert(lsblk
->sysroot
);
214 if (ld
->file_requested
)
215 return ld
->properties
;
217 if (ld
->properties
|| ld
->filename
) {
218 lsblk_device_free_properties(ld
->properties
);
219 ld
->properties
= NULL
;
222 pc
= ul_new_path("/");
225 if (ul_path_set_prefix(pc
, lsblk
->sysroot
) != 0)
227 if (ul_path_stat(pc
, &sb
, 0, ld
->filename
) != 0 || !S_ISREG(sb
.st_mode
))
230 fp
= ul_path_fopen(pc
, "r", ld
->filename
);
234 prop
= ld
->properties
;
236 prop
= ld
->properties
= xcalloc(1, sizeof(*ld
->properties
));
238 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
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
)) ;
249 else if (lookup(buf
, "ID_FS_VERSION", &prop
->fsversion
)) ;
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
)) ;
253 else if (lookup(buf
, "ID_PART_ENTRY_NUMBER", &prop
->partn
)) ;
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
)) ;
257 else if (lookup(buf
, "SCSI_IDENT_SERIAL", &prop
->serial
)) ; /* serial from sg3_utils */
258 else if (lookup(buf
, "ID_SCSI_SERIAL", &prop
->serial
)) ;
259 else if (lookup(buf
, "ID_SERIAL_SHORT", &prop
->serial
)) ;
260 else if (lookup(buf
, "ID_SERIAL", &prop
->serial
)) ;
261 else if (lookup(buf
, "ID_REVISION", &prop
->revision
)) ;
264 else if (lookup(buf
, "MODE", &prop
->mode
)) ;
265 else if (lookup(buf
, "OWNER", &prop
->owner
)) ;
266 else if (lookup(buf
, "GROUP", &prop
->group
)) ;
275 ld
->file_requested
= 1;
277 DBG(DEV
, ul_debugobj(ld
, " from fake-file"));
278 return ld
->properties
;
282 static struct lsblk_devprop
*get_properties_by_blkid(struct lsblk_device
*dev
)
284 blkid_probe pr
= NULL
;
286 if (dev
->blkid_requested
)
287 return dev
->properties
;
292 goto done
;; /* no permissions to read from the device */
294 pr
= blkid_new_probe_from_filename(dev
->filename
);
298 blkid_probe_enable_superblocks(pr
, 1);
299 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_LABEL
|
302 blkid_probe_enable_partitions(pr
, 1);
303 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_ENTRY_DETAILS
);
305 if (!blkid_do_safeprobe(pr
)) {
306 const char *data
= NULL
;
307 struct lsblk_devprop
*prop
;
310 lsblk_device_free_properties(dev
->properties
);
311 prop
= dev
->properties
= xcalloc(1, sizeof(*dev
->properties
));
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
);
323 if (!blkid_probe_lookup_value(pr
, "VERSION", &data
, NULL
))
324 prop
->fsversion
= xstrdup(data
);
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
);
333 if (!blkid_probe_lookup_value(pr
, "PART_ENTRY_NUMBER", &data
, NULL
))
334 prop
->partn
= xstrdup(data
);
336 DBG(DEV
, ul_debugobj(dev
, "%s: found blkid properties", dev
->name
));
340 blkid_free_probe(pr
);
342 DBG(DEV
, ul_debugobj(dev
, " from blkid"));
343 dev
->blkid_requested
= 1;
344 return dev
->properties
;
347 struct lsblk_devprop
*lsblk_device_get_properties(struct lsblk_device
*dev
)
349 struct lsblk_devprop
*p
= NULL
;
351 DBG(DEV
, ul_debugobj(dev
, "%s: properties requested", dev
->filename
));
353 return get_properties_by_file(dev
);
355 p
= get_properties_by_udev(dev
);
357 p
= get_properties_by_blkid(dev
);
361 void lsblk_properties_deinit(void)
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 */
379 static const struct lsblk_parttype mbr_types
[] =
381 #include "pt-mbr-partnames.h"
384 #define DEF_GUID(_u, _n) \
389 static const struct lsblk_parttype gpt_types
[] =
391 #include "pt-gpt-partnames.h"
394 const char *lsblk_parttype_code_to_string(const char *code
, const char *pttype
)
398 if (!code
|| !pttype
)
401 if (strcmp(pttype
, "dos") == 0 || strcmp(pttype
, "mbr") == 0) {
406 xcode
= strtol(code
, &end
, 16);
408 if (errno
|| *end
!= '\0')
411 for (i
= 0; i
< ARRAY_SIZE(mbr_types
); i
++) {
412 const struct lsblk_parttype
*t
= &mbr_types
[i
];
414 if (t
->name
&& t
->code
== xcode
)
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
];
422 if (t
->name
&& t
->typestr
&&
423 strcasecmp(code
, t
->typestr
) == 0)