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