18 static struct udev
*udev
;
21 void lsblk_device_free_properties(struct lsblk_devprop
*p
)
49 static struct lsblk_devprop
*get_properties_by_udev(struct lsblk_device
*dev
50 __attribute__((__unused__
)))
56 #define LSBLK_UDEV_BYID_PREFIX "/dev/disk/by-id/"
57 #define LSBLK_UDEV_BYID_PREFIXSZ (sizeof(LSBLK_UDEV_BYID_PREFIX) - 1)
59 static struct lsblk_devprop
*get_properties_by_udev(struct lsblk_device
*ld
)
61 struct udev_device
*dev
;
62 struct udev_list_entry
*le
;
64 struct lsblk_devprop
*prop
;
67 if (ld
->udev_requested
)
68 return ld
->properties
;
71 udev
= udev_new(); /* global handler */
75 dev
= udev_device_new_from_subsystem_sysname(udev
, "block", ld
->name
);
79 DBG(DEV
, ul_debugobj(ld
, "%s: found udev properties", ld
->name
));
82 lsblk_device_free_properties(ld
->properties
);
83 prop
= ld
->properties
= xcalloc(1, sizeof(*ld
->properties
));
85 if ((data
= udev_device_get_property_value(dev
, "ID_FS_LABEL_ENC"))) {
86 prop
->label
= xstrdup(data
);
87 unhexmangle_string(prop
->label
);
89 if ((data
= udev_device_get_property_value(dev
, "ID_FS_UUID_ENC"))) {
90 prop
->uuid
= xstrdup(data
);
91 unhexmangle_string(prop
->uuid
);
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
);
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
);
112 data
= udev_device_get_property_value(dev
, "ID_WWN_WITH_EXTENSION");
114 data
= udev_device_get_property_value(dev
, "ID_WWN");
116 prop
->wwn
= xstrdup(data
);
118 data
= udev_device_get_property_value(dev
, "SCSI_IDENT_SERIAL"); /* sg3_utils do not use I_D prefix */
120 data
= udev_device_get_property_value(dev
, "ID_SCSI_SERIAL");
122 data
= udev_device_get_property_value(dev
, "ID_SERIAL_SHORT");
124 data
= udev_device_get_property_value(dev
, "ID_SERIAL");
126 prop
->serial
= xstrdup(data
);
127 normalize_whitespace((unsigned char *) prop
->serial
);
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
);
139 /* select the shortest udev by-id symlink */
141 udev_list_entry_foreach(le
, udev_device_get_devlinks_list_entry(dev
)) {
142 const char *name
= udev_list_entry_get_name(le
);
145 if (!name
|| !startswith(name
, LSBLK_UDEV_BYID_PREFIX
))
147 name
+= LSBLK_UDEV_BYID_PREFIXSZ
;
151 if (!len
|| sz
< len
) {
154 prop
->idlink
= xstrdup(name
);
158 udev_device_unref(dev
);
160 ld
->udev_requested
= 1;
162 DBG(DEV
, ul_debugobj(ld
, " from udev"));
163 return ld
->properties
;
165 #endif /* HAVE_LIBUDEV */
168 static int lookup(char *buf
, char *pattern
, char **value
)
173 /* do not re-fill value */
177 len
= strlen(pattern
);
178 if (strncmp(buf
, pattern
, len
) != 0)
185 if (!*p
|| *p
== '\n')
188 for (; *p
&& *p
!= '\n'; p
++) ;
196 /* read device properties from fake text file (used on --sysroot) */
197 static struct lsblk_devprop
*get_properties_by_file(struct lsblk_device
*ld
)
199 struct lsblk_devprop
*prop
;
205 assert(lsblk
->sysroot
);
207 if (ld
->file_requested
)
208 return ld
->properties
;
210 if (ld
->properties
|| ld
->filename
) {
211 lsblk_device_free_properties(ld
->properties
);
212 ld
->properties
= NULL
;
215 pc
= ul_new_path("/");
218 if (ul_path_set_prefix(pc
, lsblk
->sysroot
) != 0)
220 if (ul_path_stat(pc
, &sb
, 0, ld
->filename
) != 0 || !S_ISREG(sb
.st_mode
))
223 fp
= ul_path_fopen(pc
, "r", ld
->filename
);
227 prop
= ld
->properties
;
229 prop
= ld
->properties
= xcalloc(1, sizeof(*ld
->properties
));
231 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
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
)) ;
242 else if (lookup(buf
, "ID_FS_VERSION", &prop
->fsversion
)) ;
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
)) ;
249 else if (lookup(buf
, "SCSI_IDENT_SERIAL", &prop
->serial
)) ; /* serial from sg3_utils */
250 else if (lookup(buf
, "ID_SCSI_SERIAL", &prop
->serial
)) ;
251 else if (lookup(buf
, "ID_SERIAL_SHORT", &prop
->serial
)) ;
252 else if (lookup(buf
, "ID_SERIAL", &prop
->serial
)) ;
255 else if (lookup(buf
, "MODE", &prop
->mode
)) ;
256 else if (lookup(buf
, "OWNER", &prop
->owner
)) ;
257 else if (lookup(buf
, "GROUP", &prop
->group
)) ;
266 ld
->file_requested
= 1;
268 DBG(DEV
, ul_debugobj(ld
, " from fake-file"));
269 return ld
->properties
;
273 static struct lsblk_devprop
*get_properties_by_blkid(struct lsblk_device
*dev
)
275 blkid_probe pr
= NULL
;
277 if (dev
->blkid_requested
)
278 return dev
->properties
;
283 goto done
;; /* no permissions to read from the device */
285 pr
= blkid_new_probe_from_filename(dev
->filename
);
289 blkid_probe_enable_superblocks(pr
, 1);
290 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_LABEL
|
293 blkid_probe_enable_partitions(pr
, 1);
294 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_ENTRY_DETAILS
);
296 if (!blkid_do_safeprobe(pr
)) {
297 const char *data
= NULL
;
298 struct lsblk_devprop
*prop
;
301 lsblk_device_free_properties(dev
->properties
);
302 prop
= dev
->properties
= xcalloc(1, sizeof(*dev
->properties
));
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
);
314 if (!blkid_probe_lookup_value(pr
, "VERSION", &data
, NULL
))
315 prop
->fsversion
= xstrdup(data
);
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
);
325 DBG(DEV
, ul_debugobj(dev
, "%s: found blkid properties", dev
->name
));
329 blkid_free_probe(pr
);
331 DBG(DEV
, ul_debugobj(dev
, " from blkid"));
332 dev
->blkid_requested
= 1;
333 return dev
->properties
;
336 struct lsblk_devprop
*lsblk_device_get_properties(struct lsblk_device
*dev
)
338 struct lsblk_devprop
*p
= NULL
;
340 DBG(DEV
, ul_debugobj(dev
, "%s: properties requested", dev
->filename
));
342 return get_properties_by_file(dev
);
344 p
= get_properties_by_udev(dev
);
346 p
= get_properties_by_blkid(dev
);
350 void lsblk_properties_deinit(void)
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 */
368 static const struct lsblk_parttype mbr_types
[] =
370 #include "pt-mbr-partnames.h"
373 #define DEF_GUID(_u, _n) \
378 static const struct lsblk_parttype gpt_types
[] =
380 #include "pt-gpt-partnames.h"
383 const char *lsblk_parttype_code_to_string(const char *code
, const char *pttype
)
387 if (!code
|| !pttype
)
390 if (strcmp(pttype
, "dos") == 0 || strcmp(pttype
, "mbr") == 0) {
395 xcode
= strtol(code
, &end
, 16);
397 if (errno
|| *end
!= '\0')
400 for (i
= 0; i
< ARRAY_SIZE(mbr_types
); i
++) {
401 const struct lsblk_parttype
*t
= &mbr_types
[i
];
403 if (t
->name
&& t
->code
== xcode
)
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
];
411 if (t
->name
&& t
->typestr
&&
412 strcasecmp(code
, t
->typestr
) == 0)