]>
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" |
ccafadb7 KZ |
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); | |
9cca1ef2 | 26 | free(p->fsversion); |
ccafadb7 KZ |
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); | |
7408a5d9 | 37 | free(p->partflags); |
ccafadb7 | 38 | |
6f74ede5 KZ |
39 | free(p->mode); |
40 | free(p->owner); | |
41 | free(p->group); | |
42 | ||
ccafadb7 KZ |
43 | free(p); |
44 | } | |
45 | ||
46 | #ifndef HAVE_LIBUDEV | |
fed34a1e | 47 | static struct lsblk_devprop *get_properties_by_udev(struct lsblk_device *dev |
ccafadb7 KZ |
48 | __attribute__((__unused__))) |
49 | { | |
50 | return NULL; | |
51 | } | |
52 | #else | |
fed34a1e | 53 | static struct lsblk_devprop *get_properties_by_udev(struct lsblk_device *ld) |
ccafadb7 KZ |
54 | { |
55 | struct udev_device *dev; | |
56 | ||
fed34a1e KZ |
57 | if (ld->udev_requested) |
58 | return ld->properties; | |
ccafadb7 | 59 | |
ccafadb7 KZ |
60 | if (!udev) |
61 | udev = udev_new(); /* global handler */ | |
62 | if (!udev) | |
63 | goto done; | |
64 | ||
fed34a1e | 65 | dev = udev_device_new_from_subsystem_sysname(udev, "block", ld->name); |
ccafadb7 KZ |
66 | if (dev) { |
67 | const char *data; | |
68 | struct lsblk_devprop *prop; | |
69 | ||
fed34a1e KZ |
70 | if (ld->properties) |
71 | lsblk_device_free_properties(ld->properties); | |
72 | prop = ld->properties = xcalloc(1, sizeof(*ld->properties)); | |
ccafadb7 KZ |
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); | |
9cca1ef2 KZ |
92 | if ((data = udev_device_get_property_value(dev, "ID_FS_VERSION"))) |
93 | prop->fsversion = xstrdup(data); | |
ccafadb7 KZ |
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 | ||
c2f6513c SW |
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) | |
ccafadb7 | 111 | prop->serial = xstrdup(data); |
c2f6513c | 112 | |
ccafadb7 KZ |
113 | if ((data = udev_device_get_property_value(dev, "ID_MODEL"))) |
114 | prop->model = xstrdup(data); | |
115 | ||
116 | udev_device_unref(dev); | |
fed34a1e | 117 | DBG(DEV, ul_debugobj(ld, "%s: found udev properties", ld->name)); |
ccafadb7 KZ |
118 | } |
119 | ||
120 | done: | |
fed34a1e | 121 | ld->udev_requested = 1; |
7408a5d9 KZ |
122 | |
123 | DBG(DEV, ul_debugobj(ld, " from udev")); | |
fed34a1e | 124 | return ld->properties; |
ccafadb7 KZ |
125 | } |
126 | #endif /* HAVE_LIBUDEV */ | |
127 | ||
7408a5d9 KZ |
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 | ||
eea06b92 KZ |
166 | assert(lsblk->sysroot); |
167 | ||
7408a5d9 KZ |
168 | if (ld->file_requested) |
169 | return ld->properties; | |
170 | ||
7408a5d9 KZ |
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) { | |
6f74ede5 | 193 | /* udev based */ |
7408a5d9 KZ |
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)) ; | |
9cca1ef2 | 203 | else if (lookup(buf, "ID_FS_VERSION", &prop->fsversion)) ; |
7408a5d9 KZ |
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)) ; | |
6f74ede5 KZ |
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 | ||
7408a5d9 KZ |
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 | ||
fed34a1e | 232 | static struct lsblk_devprop *get_properties_by_blkid(struct lsblk_device *dev) |
ccafadb7 KZ |
233 | { |
234 | blkid_probe pr = NULL; | |
235 | ||
fed34a1e KZ |
236 | if (dev->blkid_requested) |
237 | return dev->properties; | |
ccafadb7 | 238 | |
fed34a1e | 239 | if (!dev->size) |
ccafadb7 KZ |
240 | goto done; |
241 | if (getuid() != 0) | |
242 | goto done;; /* no permissions to read from the device */ | |
243 | ||
fed34a1e | 244 | pr = blkid_new_probe_from_filename(dev->filename); |
ccafadb7 KZ |
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 | ||
fed34a1e KZ |
259 | if (dev->properties) |
260 | lsblk_device_free_properties(dev->properties); | |
261 | prop = dev->properties = xcalloc(1, sizeof(*dev->properties)); | |
ccafadb7 KZ |
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); | |
9cca1ef2 KZ |
273 | if (!blkid_probe_lookup_value(pr, "VERSION", &data, NULL)) |
274 | prop->fsversion = xstrdup(data); | |
ccafadb7 KZ |
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 | ||
fed34a1e | 284 | DBG(DEV, ul_debugobj(dev, "%s: found blkid properties", dev->name)); |
ccafadb7 KZ |
285 | } |
286 | ||
287 | done: | |
288 | blkid_free_probe(pr); | |
289 | ||
7408a5d9 | 290 | DBG(DEV, ul_debugobj(dev, " from blkid")); |
fed34a1e KZ |
291 | dev->blkid_requested = 1; |
292 | return dev->properties; | |
ccafadb7 KZ |
293 | } |
294 | ||
fed34a1e | 295 | struct lsblk_devprop *lsblk_device_get_properties(struct lsblk_device *dev) |
ccafadb7 | 296 | { |
7408a5d9 | 297 | struct lsblk_devprop *p = NULL; |
ccafadb7 | 298 | |
7408a5d9 KZ |
299 | DBG(DEV, ul_debugobj(dev, "%s: properties requested", dev->filename)); |
300 | if (lsblk->sysroot) | |
eea06b92 KZ |
301 | return get_properties_by_file(dev); |
302 | ||
303 | p = get_properties_by_udev(dev); | |
ccafadb7 | 304 | if (!p) |
fed34a1e | 305 | p = get_properties_by_blkid(dev); |
ccafadb7 KZ |
306 | return p; |
307 | } | |
308 | ||
309 | void lsblk_properties_deinit(void) | |
310 | { | |
311 | #ifdef HAVE_LIBUDEV | |
312 | udev_unref(udev); | |
313 | #endif | |
314 | } | |
107e9559 KZ |
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 | } |