]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/lsblk-properties.c
Merge branch 'meson-more-build-options' of https://github.com/jwillikers/util-linux
[thirdparty/util-linux.git] / misc-utils / lsblk-properties.c
CommitLineData
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
18static struct udev *udev;
19#endif
20
21void 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 51static 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 61static 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 166done:
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
175static 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) */
204static 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 }
271done:
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 282static 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
339done:
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 347struct 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
361void 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 */
373struct 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
379static 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 }
389static const struct lsblk_parttype gpt_types[] =
390{
391 #include "pt-gpt-partnames.h"
392};
393
394const 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}