]>
Commit | Line | Data |
---|---|---|
e4799a35 KZ |
1 | /* |
2 | * partitions - partition tables parsing | |
3 | * | |
4 | * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> | |
5 | * | |
6 | * This file may be redistributed under the terms of the | |
7 | * GNU Lesser General Public License. | |
8 | * | |
9 | */ | |
10 | #include <stdio.h> | |
11 | #include <string.h> | |
12 | #include <stdlib.h> | |
13 | #include <unistd.h> | |
14 | #include <fcntl.h> | |
15 | #include <ctype.h> | |
16 | #include <sys/types.h> | |
17 | #include <sys/stat.h> | |
18 | #include <errno.h> | |
19 | #include <stdint.h> | |
94decb7c | 20 | #include <inttypes.h> |
e4799a35 KZ |
21 | #include <stdarg.h> |
22 | ||
23 | #include "partitions.h" | |
d8a84552 | 24 | #include "sysfs.h" |
e4799a35 KZ |
25 | |
26 | /** | |
fd7c9e35 | 27 | * SECTION: partitions |
e4799a35 KZ |
28 | * @title: Partitions probing |
29 | * @short_description: partitions tables detection and parsing | |
30 | * | |
31 | * This chain supports binary and NAME=value interfaces, but complete PT | |
9f4664ee KZ |
32 | * description is provided by binary interface only. The libblkid prober is |
33 | * compatible with kernel partition tables parser. The parser does not return | |
34 | * empty (size=0) partitions or special hidden partitions. | |
e4799a35 KZ |
35 | * |
36 | * NAME=value interface, supported tags: | |
37 | * | |
38 | * @PTTYPE: partition table type (dos, gpt, etc.). | |
39 | * | |
62e83b1d KZ |
40 | * @PTUUID: partition table id (uuid for gpt, hex for dos). |
41 | ||
385c3535 KZ |
42 | * @PART_ENTRY_SCHEME: partition table type |
43 | * | |
0c6dc615 KZ |
44 | * @PART_ENTRY_NAME: partition name (gpt and mac only) |
45 | * | |
f948a147 | 46 | * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR) |
0c6dc615 | 47 | * |
dcc58f62 | 48 | * @PART_ENTRY_TYPE: partition type, 0xNN (e.g 0x82) or type UUID (gpt only) or type string (mac) |
0c6dc615 | 49 | * |
75838802 KZ |
50 | * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or attributes (e.g. gpt attributes) |
51 | * | |
385c3535 KZ |
52 | * @PART_ENTRY_NUMBER: partition number |
53 | * | |
d945f469 KZ |
54 | * @PART_ENTRY_OFFSET: the begin of the partition |
55 | * | |
56 | * @PART_ENTRY_SIZE: size of the partition | |
57 | * | |
fd7c9e35 | 58 | * @PART_ENTRY_DISK: whole-disk maj:min |
d945f469 | 59 | * |
e4799a35 KZ |
60 | * Example: |
61 | * | |
62 | * <informalexample> | |
63 | * <programlisting> | |
64 | * blkid_probe pr; | |
e4799a35 KZ |
65 | * const char *ptname; |
66 | * | |
ab347a14 KZ |
67 | * pr = blkid_new_probe_from_filename(devname); |
68 | * if (!pr) | |
9e930041 | 69 | * err("%s: failed to open device", devname); |
e4799a35 KZ |
70 | * |
71 | * blkid_probe_enable_partitions(pr, TRUE); | |
72 | * blkid_do_fullprobe(pr); | |
73 | * | |
74 | * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL); | |
75 | * printf("%s partition type detected\n", pttype); | |
76 | * | |
77 | * blkid_free_probe(pr); | |
e4799a35 KZ |
78 | * |
79 | * // don't forget to check return codes in your code! | |
80 | * </programlisting> | |
81 | * </informalexample> | |
82 | * | |
83 | * Binary interface: | |
84 | * | |
85 | * <informalexample> | |
86 | * <programlisting> | |
87 | * blkid_probe pr; | |
88 | * blkid_partlist ls; | |
89 | * int nparts, i; | |
e4799a35 | 90 | * |
ab347a14 KZ |
91 | * pr = blkid_new_probe_from_filename(devname); |
92 | * if (!pr) | |
9e930041 | 93 | * err("%s: failed to open device", devname); |
e4799a35 KZ |
94 | * |
95 | * ls = blkid_probe_get_partitions(pr); | |
96 | * nparts = blkid_partlist_numof_partitions(ls); | |
97 | * | |
98 | * for (i = 0; i < nparts; i++) { | |
99 | * blkid_partition par = blkid_partlist_get_partition(ls, i); | |
100 | * printf("#%d: %llu %llu 0x%x", | |
101 | * blkid_partition_get_partno(par), | |
102 | * blkid_partition_get_start(par), | |
103 | * blkid_partition_get_size(par), | |
104 | * blkid_partition_get_type(par)); | |
105 | * } | |
106 | * | |
107 | * blkid_free_probe(pr); | |
e4799a35 KZ |
108 | * |
109 | * // don't forget to check return codes in your code! | |
110 | * </programlisting> | |
111 | * </informalexample> | |
112 | */ | |
113 | ||
114 | /* | |
115 | * Chain driver function | |
116 | */ | |
117 | static int partitions_probe(blkid_probe pr, struct blkid_chain *chn); | |
118 | static void partitions_free_data(blkid_probe pr, void *data); | |
119 | ||
120 | /* | |
121 | * Partitions chain probing functions | |
122 | */ | |
123 | static const struct blkid_idinfo *idinfos[] = | |
124 | { | |
c472fc8e | 125 | &aix_pt_idinfo, |
0e728765 | 126 | &sgi_pt_idinfo, |
d23768d8 | 127 | &sun_pt_idinfo, |
60ad0bbb | 128 | &dos_pt_idinfo, |
7a8f74e8 | 129 | &gpt_pt_idinfo, |
e3c69a7d | 130 | &pmbr_pt_idinfo, /* always after GPT */ |
5c9204dc | 131 | &mac_pt_idinfo, |
dad504d9 | 132 | &ultrix_pt_idinfo, |
85ecbfe7 KZ |
133 | &bsd_pt_idinfo, |
134 | &unixware_pt_idinfo, | |
b507ce03 | 135 | &solaris_x86_pt_idinfo, |
50c71f25 VD |
136 | &minix_pt_idinfo, |
137 | &atari_pt_idinfo | |
e4799a35 KZ |
138 | }; |
139 | ||
140 | /* | |
141 | * Driver definition | |
142 | */ | |
143 | const struct blkid_chaindrv partitions_drv = { | |
144 | .id = BLKID_CHAIN_PARTS, | |
145 | .name = "partitions", | |
146 | .dflt_enabled = FALSE, | |
147 | .idinfos = idinfos, | |
148 | .nidinfos = ARRAY_SIZE(idinfos), | |
149 | .has_fltr = TRUE, | |
150 | .probe = partitions_probe, | |
151 | .safeprobe = partitions_probe, | |
152 | .free_data = partitions_free_data | |
153 | }; | |
154 | ||
155 | ||
156 | /* | |
157 | * For compatibility with the rest of libblkid API (with the old high-level | |
158 | * API) we use completely opaque typedefs for all structs. Don't forget that | |
159 | * the final blkid_* types are pointers! See blkid.h. | |
160 | * | |
161 | * [Just for the record, I hate typedef for pointers --kzak] | |
162 | */ | |
163 | ||
164 | /* exported as opaque type "blkid_parttable" */ | |
165 | struct blkid_struct_parttable { | |
166 | const char *type; /* partition table type */ | |
f12cd8d1 | 167 | uint64_t offset; /* begin of the partition table (in bytes) */ |
e4799a35 KZ |
168 | int nparts; /* number of partitions */ |
169 | blkid_partition parent; /* parent of nested partition table */ | |
b443c177 | 170 | char id[UUID_STR_LEN]; /* PT identifier (e.g. UUID for GPT) */ |
e4799a35 KZ |
171 | |
172 | struct list_head t_tabs; /* all tables */ | |
173 | }; | |
174 | ||
175 | /* exported as opaque type "blkid_partition" */ | |
176 | struct blkid_struct_partition { | |
f12cd8d1 KZ |
177 | uint64_t start; /* begin of the partition (512-bytes sectors) */ |
178 | uint64_t size; /* size of the partitions (512-bytes sectors) */ | |
0e8a8065 | 179 | |
e4799a35 | 180 | int type; /* partition type */ |
b443c177 | 181 | char typestr[UUID_STR_LEN]; /* partition type string (GPT and Mac) */ |
e4799a35 | 182 | |
75838802 KZ |
183 | unsigned long long flags; /* partition flags / attributes */ |
184 | ||
e4799a35 | 185 | int partno; /* partition number */ |
b443c177 | 186 | char uuid[UUID_STR_LEN]; /* UUID (when supported by PT), e.g GPT */ |
9e930041 | 187 | unsigned char name[128]; /* Partition in UTF8 name (when supported by PT), e.g. Mac */ |
e4799a35 KZ |
188 | |
189 | blkid_parttable tab; /* partition table */ | |
190 | }; | |
191 | ||
192 | /* exported as opaque type "blkid_partlist" */ | |
193 | struct blkid_struct_partlist { | |
194 | int next_partno; /* next partition number */ | |
195 | blkid_partition next_parent; /* next parent if parsing nested PT */ | |
196 | ||
197 | int nparts; /* number of partitions */ | |
198 | int nparts_max; /* max.number of partitions */ | |
199 | blkid_partition parts; /* array of partitions */ | |
200 | ||
201 | struct list_head l_tabs; /* list of partition tables */ | |
202 | }; | |
203 | ||
0c6dc615 KZ |
204 | static int blkid_partitions_probe_partition(blkid_probe pr); |
205 | ||
e4799a35 KZ |
206 | /** |
207 | * blkid_probe_enable_partitions: | |
208 | * @pr: probe | |
209 | * @enable: TRUE/FALSE | |
210 | * | |
211 | * Enables/disables the partitions probing for non-binary interface. | |
212 | * | |
213 | * Returns: 0 on success, or -1 in case of error. | |
214 | */ | |
215 | int blkid_probe_enable_partitions(blkid_probe pr, int enable) | |
216 | { | |
e4799a35 KZ |
217 | pr->chains[BLKID_CHAIN_PARTS].enabled = enable; |
218 | return 0; | |
219 | } | |
220 | ||
221 | /** | |
222 | * blkid_probe_set_partitions_flags: | |
223 | * @pr: prober | |
224 | * @flags: BLKID_PARTS_* flags | |
225 | * | |
226 | * Sets probing flags to the partitions prober. This function is optional. | |
227 | * | |
228 | * Returns: 0 on success, or -1 in case of error. | |
229 | */ | |
230 | int blkid_probe_set_partitions_flags(blkid_probe pr, int flags) | |
231 | { | |
e4799a35 KZ |
232 | pr->chains[BLKID_CHAIN_PARTS].flags = flags; |
233 | return 0; | |
234 | } | |
235 | ||
48805d56 KZ |
236 | /** |
237 | * blkid_probe_reset_partitions_filter: | |
238 | * @pr: prober | |
239 | * | |
240 | * Resets partitions probing filter | |
241 | * | |
242 | * Returns: 0 on success, or -1 in case of error. | |
243 | */ | |
244 | int blkid_probe_reset_partitions_filter(blkid_probe pr) | |
245 | { | |
246 | return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS); | |
247 | } | |
248 | ||
249 | /** | |
250 | * blkid_probe_invert_partitions_filter: | |
251 | * @pr: prober | |
252 | * | |
253 | * Inverts partitions probing filter | |
254 | * | |
255 | * Returns: 0 on success, or -1 in case of error. | |
256 | */ | |
257 | int blkid_probe_invert_partitions_filter(blkid_probe pr) | |
258 | { | |
259 | return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS); | |
260 | } | |
261 | ||
262 | /** | |
263 | * blkid_probe_filter_partitions_type: | |
264 | * @pr: prober | |
265 | * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag | |
266 | * @names: NULL terminated array of probing function names (e.g. "vfat"). | |
267 | * | |
fd7c9e35 KZ |
268 | * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names |
269 | * | |
270 | * %BLKID_FLTR_ONLYIN - probe for items which are IN @names | |
48805d56 KZ |
271 | * |
272 | * Returns: 0 on success, or -1 in case of error. | |
273 | */ | |
274 | int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]) | |
275 | { | |
276 | return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names); | |
277 | } | |
278 | ||
e4799a35 KZ |
279 | /** |
280 | * blkid_probe_get_partitions: | |
281 | * @pr: probe | |
282 | * | |
283 | * This is a binary interface for partitions. See also blkid_partlist_* | |
284 | * functions. | |
285 | * | |
286 | * This function is independent on blkid_do_[safe,full]probe() and | |
287 | * blkid_probe_enable_partitions() calls. | |
288 | * | |
a0fff7ce KZ |
289 | * WARNING: the returned object will be overwritten by the next |
290 | * blkid_probe_get_partitions() call for the same @pr. If you want to | |
291 | * use more blkid_partlist objects in the same time you have to create | |
292 | * more blkid_probe handlers (see blkid_new_probe()). | |
293 | * | |
e4799a35 KZ |
294 | * Returns: list of partitions, or NULL in case of error. |
295 | */ | |
296 | blkid_partlist blkid_probe_get_partitions(blkid_probe pr) | |
297 | { | |
298 | return (blkid_partlist) blkid_probe_get_binary_data(pr, | |
299 | &pr->chains[BLKID_CHAIN_PARTS]); | |
300 | } | |
301 | ||
302 | /* for internal usage only */ | |
303 | blkid_partlist blkid_probe_get_partlist(blkid_probe pr) | |
304 | { | |
305 | return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data; | |
306 | } | |
307 | ||
ac8874ca KZ |
308 | static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls) |
309 | { | |
310 | pr->chains[BLKID_CHAIN_PARTS].data = ls; | |
311 | } | |
312 | ||
e4799a35 KZ |
313 | static void ref_parttable(blkid_parttable tab) |
314 | { | |
315 | tab->nparts++; | |
316 | } | |
317 | ||
318 | static void unref_parttable(blkid_parttable tab) | |
319 | { | |
320 | tab->nparts--; | |
321 | ||
322 | if (tab->nparts <= 0) { | |
323 | list_del(&tab->t_tabs); | |
324 | free(tab); | |
325 | } | |
326 | } | |
327 | ||
328 | /* free all allocated parttables */ | |
329 | static void free_parttables(blkid_partlist ls) | |
330 | { | |
331 | if (!ls || !ls->l_tabs.next) | |
332 | return; | |
333 | ||
334 | /* remove unassigned partition tables */ | |
335 | while (!list_empty(&ls->l_tabs)) { | |
336 | blkid_parttable tab = list_entry(ls->l_tabs.next, | |
337 | struct blkid_struct_parttable, t_tabs); | |
338 | unref_parttable(tab); | |
339 | } | |
340 | } | |
341 | ||
01fb8c00 | 342 | static void reset_partlist(blkid_partlist ls) |
e4799a35 KZ |
343 | { |
344 | if (!ls) | |
345 | return; | |
346 | ||
347 | free_parttables(ls); | |
348 | ||
349 | if (ls->next_partno) { | |
350 | /* already initialized - reset */ | |
351 | int tmp_nparts = ls->nparts_max; | |
352 | blkid_partition tmp_parts = ls->parts; | |
353 | ||
354 | memset(ls, 0, sizeof(struct blkid_struct_partlist)); | |
355 | ||
356 | ls->nparts_max = tmp_nparts; | |
357 | ls->parts = tmp_parts; | |
358 | } | |
359 | ||
360 | ls->nparts = 0; | |
361 | ls->next_partno = 1; | |
362 | INIT_LIST_HEAD(&ls->l_tabs); | |
363 | ||
c62a6311 | 364 | DBG(LOWPROBE, ul_debug("partlist reset")); |
e4799a35 KZ |
365 | } |
366 | ||
01fb8c00 | 367 | static blkid_partlist partitions_init_data(struct blkid_chain *chn) |
e4799a35 KZ |
368 | { |
369 | blkid_partlist ls; | |
370 | ||
371 | if (chn->data) | |
372 | ls = (blkid_partlist) chn->data; | |
373 | else { | |
374 | /* allocate the new list of partitions */ | |
375 | ls = calloc(1, sizeof(struct blkid_struct_partlist)); | |
376 | if (!ls) | |
377 | return NULL; | |
378 | chn->data = (void *) ls; | |
379 | } | |
380 | ||
01fb8c00 | 381 | reset_partlist(ls); |
e4799a35 | 382 | |
63c9c05d | 383 | DBG(LOWPROBE, ul_debug("parts: initialized partitions list (size=%d)", ls->nparts_max)); |
e4799a35 KZ |
384 | return ls; |
385 | } | |
386 | ||
01fb8c00 KZ |
387 | static void partitions_free_data(blkid_probe pr __attribute__((__unused__)), |
388 | void *data) | |
e4799a35 KZ |
389 | { |
390 | blkid_partlist ls = (blkid_partlist) data; | |
391 | ||
392 | if (!ls) | |
393 | return; | |
394 | ||
395 | free_parttables(ls); | |
396 | ||
397 | /* deallocate partitions and partlist */ | |
398 | free(ls->parts); | |
399 | free(ls); | |
400 | } | |
401 | ||
402 | blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls, | |
f12cd8d1 | 403 | const char *type, uint64_t offset) |
e4799a35 KZ |
404 | { |
405 | blkid_parttable tab; | |
406 | ||
407 | tab = calloc(1, sizeof(struct blkid_struct_parttable)); | |
408 | if (!tab) | |
409 | return NULL; | |
410 | tab->type = type; | |
411 | tab->offset = offset; | |
412 | tab->parent = ls->next_parent; | |
413 | ||
414 | INIT_LIST_HEAD(&tab->t_tabs); | |
415 | list_add_tail(&tab->t_tabs, &ls->l_tabs); | |
416 | ||
c62a6311 | 417 | DBG(LOWPROBE, ul_debug("parts: create a new partition table " |
63c9c05d | 418 | "(type=%s, offset=%"PRId64")", type, offset)); |
e4799a35 KZ |
419 | return tab; |
420 | } | |
421 | ||
422 | static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab) | |
423 | { | |
424 | blkid_partition par; | |
425 | ||
426 | if (ls->nparts + 1 > ls->nparts_max) { | |
427 | /* Linux kernel has DISK_MAX_PARTS=256, but it's too much for | |
9e930041 | 428 | * generic Linux machine -- let start with 32 partitions. |
e4799a35 | 429 | */ |
8a2c2dab | 430 | void *tmp = realloc(ls->parts, (ls->nparts_max + 32) * |
e4799a35 | 431 | sizeof(struct blkid_struct_partition)); |
8a2c2dab | 432 | if (!tmp) |
e4799a35 | 433 | return NULL; |
8a2c2dab | 434 | ls->parts = tmp; |
e4799a35 KZ |
435 | ls->nparts_max += 32; |
436 | } | |
437 | ||
438 | par = &ls->parts[ls->nparts++]; | |
439 | memset(par, 0, sizeof(struct blkid_struct_partition)); | |
440 | ||
441 | ref_parttable(tab); | |
442 | par->tab = tab; | |
9f4664ee | 443 | par->partno = blkid_partlist_increment_partno(ls); |
e4799a35 KZ |
444 | |
445 | return par; | |
446 | } | |
447 | ||
448 | blkid_partition blkid_partlist_add_partition(blkid_partlist ls, | |
f12cd8d1 | 449 | blkid_parttable tab, uint64_t start, uint64_t size) |
e4799a35 KZ |
450 | { |
451 | blkid_partition par = new_partition(ls, tab); | |
452 | ||
453 | if (!par) | |
454 | return NULL; | |
455 | ||
e4799a35 KZ |
456 | par->start = start; |
457 | par->size = size; | |
458 | ||
63c9c05d KZ |
459 | DBG(LOWPROBE, ul_debug("parts: add partition (start=%" |
460 | PRIu64 ", size=%" PRIu64 ")", | |
461 | par->start, par->size)); | |
e4799a35 KZ |
462 | return par; |
463 | } | |
464 | ||
465 | /* allows to modify used partitions numbers (for example for logical partitions) */ | |
466 | int blkid_partlist_set_partno(blkid_partlist ls, int partno) | |
467 | { | |
468 | if (!ls) | |
469 | return -1; | |
470 | ls->next_partno = partno; | |
471 | return 0; | |
472 | } | |
473 | ||
9f4664ee KZ |
474 | int blkid_partlist_increment_partno(blkid_partlist ls) |
475 | { | |
476 | return ls ? ls->next_partno++ : -1; | |
477 | } | |
478 | ||
e4799a35 | 479 | /* allows to set "parent" for the next nested partition */ |
b55b9fcc | 480 | static int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par) |
e4799a35 KZ |
481 | { |
482 | if (!ls) | |
483 | return -1; | |
484 | ls->next_parent = par; | |
485 | return 0; | |
486 | } | |
487 | ||
488 | blkid_partition blkid_partlist_get_parent(blkid_partlist ls) | |
489 | { | |
490 | if (!ls) | |
491 | return NULL; | |
492 | return ls->next_parent; | |
493 | } | |
494 | ||
495 | int blkid_partitions_need_typeonly(blkid_probe pr) | |
496 | { | |
497 | struct blkid_chain *chn = blkid_probe_get_chain(pr); | |
498 | ||
499 | return chn && chn->data && chn->binary ? FALSE : TRUE; | |
500 | } | |
501 | ||
502 | /* get private chain flags */ | |
503 | int blkid_partitions_get_flags(blkid_probe pr) | |
504 | { | |
505 | struct blkid_chain *chn = blkid_probe_get_chain(pr); | |
506 | ||
507 | return chn ? chn->flags : 0; | |
508 | } | |
509 | ||
510 | /* check if @start and @size are within @par partition */ | |
511 | int blkid_is_nested_dimension(blkid_partition par, | |
f12cd8d1 | 512 | uint64_t start, uint64_t size) |
e4799a35 | 513 | { |
f12cd8d1 KZ |
514 | uint64_t pstart; |
515 | uint64_t psize; | |
e4799a35 KZ |
516 | |
517 | if (!par) | |
518 | return 0; | |
519 | ||
520 | pstart = blkid_partition_get_start(par); | |
521 | psize = blkid_partition_get_size(par); | |
522 | ||
523 | if (start < pstart || start + size > pstart + psize) | |
524 | return 0; | |
525 | ||
526 | return 1; | |
527 | } | |
528 | ||
44765fdd KZ |
529 | static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id, |
530 | struct blkid_chain *chn) | |
e4799a35 | 531 | { |
c03d12d8 | 532 | const struct blkid_idmag *mag = NULL; |
f12cd8d1 | 533 | uint64_t off; |
d2a8b8d1 | 534 | int rc = BLKID_PROBE_NONE; /* default is nothing */ |
e4799a35 | 535 | |
b9710f1f | 536 | if (pr->size <= 0 || (id->minsz && (unsigned)id->minsz > pr->size)) |
cc62a975 | 537 | goto nothing; /* the device is too small */ |
20e1c3dc KZ |
538 | if (pr->flags & BLKID_FL_NOSCAN_DEV) |
539 | goto nothing; | |
cc62a975 | 540 | |
296d96e2 HR |
541 | rc = blkid_probe_get_idmag(pr, id, &off, &mag); |
542 | if (rc != BLKID_PROBE_OK) | |
e4799a35 KZ |
543 | goto nothing; |
544 | ||
545 | /* final check by probing function */ | |
546 | if (id->probefunc) { | |
c62a6311 | 547 | DBG(LOWPROBE, ul_debug( |
0540ea54 | 548 | "%s: ---> call probefunc()", id->name)); |
e4799a35 | 549 | rc = id->probefunc(pr, mag); |
296d96e2 | 550 | if (rc < 0) { |
e4799a35 | 551 | /* reset after error */ |
01fb8c00 | 552 | reset_partlist(blkid_probe_get_partlist(pr)); |
44765fdd | 553 | if (chn && !chn->binary) |
af17d349 | 554 | blkid_probe_chain_reset_values(pr, chn); |
c62a6311 | 555 | DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d", |
296d96e2 | 556 | id->name, rc)); |
e4799a35 | 557 | } |
296d96e2 | 558 | if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary) |
2b6e6d55 | 559 | rc = blkid_probe_set_magic(pr, off, mag->len, |
44765fdd KZ |
560 | (unsigned char *) mag->magic); |
561 | ||
c62a6311 | 562 | DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc)); |
e4799a35 KZ |
563 | } |
564 | ||
e4799a35 | 565 | return rc; |
d2a8b8d1 KZ |
566 | |
567 | nothing: | |
568 | return BLKID_PROBE_NONE; | |
e4799a35 KZ |
569 | } |
570 | ||
571 | /* | |
572 | * The blkid_do_probe() backend. | |
573 | */ | |
574 | static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) | |
575 | { | |
296d96e2 | 576 | int rc = BLKID_PROBE_NONE; |
01fb8c00 | 577 | size_t i; |
e4799a35 KZ |
578 | |
579 | if (!pr || chn->idx < -1) | |
296d96e2 | 580 | return -EINVAL; |
20e1c3dc | 581 | |
af17d349 | 582 | blkid_probe_chain_reset_values(pr, chn); |
e4799a35 | 583 | |
d2a8b8d1 KZ |
584 | if (pr->flags & BLKID_FL_NOSCAN_DEV) |
585 | return BLKID_PROBE_NONE; | |
586 | ||
e4799a35 | 587 | if (chn->binary) |
01fb8c00 | 588 | partitions_init_data(chn); |
e4799a35 | 589 | |
a9eef56c | 590 | if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT)) |
c81e7008 KZ |
591 | goto details_only; |
592 | ||
c62a6311 | 593 | DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]", |
e4799a35 KZ |
594 | chn->idx)); |
595 | ||
01fb8c00 | 596 | i = chn->idx < 0 ? 0 : chn->idx + 1U; |
e4799a35 KZ |
597 | |
598 | for ( ; i < ARRAY_SIZE(idinfos); i++) { | |
599 | const char *name; | |
600 | ||
601 | chn->idx = i; | |
602 | ||
603 | /* apply filter */ | |
604 | if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) | |
605 | continue; | |
606 | ||
607 | /* apply checks from idinfo */ | |
296d96e2 HR |
608 | rc = idinfo_probe(pr, idinfos[i], chn); |
609 | if (rc < 0) | |
610 | break; | |
611 | if (rc != BLKID_PROBE_OK) | |
e4799a35 KZ |
612 | continue; |
613 | ||
614 | name = idinfos[i]->name; | |
615 | ||
19f87d1d | 616 | if (!chn->binary) |
62e83b1d KZ |
617 | /* |
618 | * Non-binary interface, set generic variables. Note | |
619 | * that the another variables could be set in prober | |
620 | * functions. | |
621 | */ | |
19f87d1d KZ |
622 | blkid_probe_set_value(pr, "PTTYPE", |
623 | (unsigned char *) name, | |
624 | strlen(name) + 1); | |
62e83b1d | 625 | |
c62a6311 | 626 | DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]", |
e4799a35 | 627 | name, chn->idx)); |
d2a8b8d1 | 628 | rc = BLKID_PROBE_OK; |
0c6dc615 | 629 | break; |
e4799a35 | 630 | } |
0c6dc615 | 631 | |
296d96e2 | 632 | if (rc != BLKID_PROBE_OK) { |
c62a6311 | 633 | DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]", |
296d96e2 | 634 | rc, chn->idx)); |
0c6dc615 KZ |
635 | } |
636 | ||
c81e7008 | 637 | details_only: |
0c6dc615 KZ |
638 | /* |
639 | * Gather PART_ENTRY_* values if the current device is a partition. | |
640 | */ | |
5b575d43 | 641 | if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary && |
781aa7b3 KZ |
642 | (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) { |
643 | ||
5b575d43 | 644 | int xrc = blkid_partitions_probe_partition(pr); |
a6161898 KZ |
645 | |
646 | /* partition entry probing is optional, and "not-found" from | |
647 | * this sub-probing must not to overwrite previous success. */ | |
5b575d43 | 648 | if (xrc < 0) |
a6161898 KZ |
649 | rc = xrc; /* always propagate errors */ |
650 | else if (rc == BLKID_PROBE_NONE) | |
651 | rc = xrc; | |
0c6dc615 KZ |
652 | } |
653 | ||
a6161898 | 654 | DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]", rc)); |
0c6dc615 | 655 | return rc; |
e4799a35 KZ |
656 | } |
657 | ||
658 | /* Probe for nested partition table within the parental partition */ | |
659 | int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent, | |
660 | const struct blkid_idinfo *id) | |
661 | { | |
ac8874ca | 662 | blkid_probe prc; |
296d96e2 | 663 | int rc; |
e4799a35 | 664 | blkid_partlist ls; |
f12cd8d1 | 665 | uint64_t sz, off; |
e4799a35 | 666 | |
c62a6311 | 667 | DBG(LOWPROBE, ul_debug( |
63c9c05d KZ |
668 | "parts: ----> %s subprobe requested)", |
669 | id->name)); | |
e4799a35 KZ |
670 | |
671 | if (!pr || !parent || !parent->size) | |
296d96e2 | 672 | return -EINVAL; |
20e1c3dc KZ |
673 | if (pr->flags & BLKID_FL_NOSCAN_DEV) |
674 | return BLKID_PROBE_NONE; | |
e4799a35 | 675 | |
ac8874ca | 676 | /* range defined by parent */ |
f12cd8d1 KZ |
677 | sz = parent->size << 9; |
678 | off = parent->start << 9; | |
e4799a35 | 679 | |
ac8874ca | 680 | if (off < pr->off || pr->off + pr->size < off + sz) { |
c62a6311 | 681 | DBG(LOWPROBE, ul_debug( |
0540ea54 | 682 | "ERROR: parts: <---- '%s' subprobe: overflow detected.", |
e4799a35 | 683 | id->name)); |
296d96e2 | 684 | return -ENOSPC; |
e4799a35 KZ |
685 | } |
686 | ||
ac8874ca KZ |
687 | /* create private prober */ |
688 | prc = blkid_clone_probe(pr); | |
689 | if (!prc) | |
296d96e2 | 690 | return -ENOMEM; |
ac8874ca KZ |
691 | |
692 | blkid_probe_set_dimension(prc, off, sz); | |
ccdf9fda | 693 | |
3b159691 | 694 | /* clone is always with reset chain, fix it */ |
ac8874ca | 695 | prc->cur_chain = blkid_probe_get_chain(pr); |
e4799a35 | 696 | |
ac8874ca KZ |
697 | /* |
698 | * Set 'parent' to the current list of the partitions and use the list | |
699 | * in cloned prober (so the cloned prober will extend the current list | |
700 | * of partitions rather than create a new). | |
701 | */ | |
702 | ls = blkid_probe_get_partlist(pr); | |
e4799a35 KZ |
703 | blkid_partlist_set_parent(ls, parent); |
704 | ||
ac8874ca | 705 | blkid_probe_set_partlist(prc, ls); |
e4799a35 | 706 | |
44765fdd | 707 | rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr)); |
e4799a35 | 708 | |
ac8874ca KZ |
709 | blkid_probe_set_partlist(prc, NULL); |
710 | blkid_partlist_set_parent(ls, NULL); | |
e4799a35 | 711 | |
ac8874ca | 712 | blkid_free_probe(prc); /* free cloned prober */ |
ccdf9fda | 713 | |
c62a6311 | 714 | DBG(LOWPROBE, ul_debug( |
63c9c05d KZ |
715 | "parts: <---- %s subprobe done (rc=%d)", |
716 | id->name, rc)); | |
e4799a35 KZ |
717 | |
718 | return rc; | |
719 | } | |
720 | ||
0c6dc615 KZ |
721 | static int blkid_partitions_probe_partition(blkid_probe pr) |
722 | { | |
0c6dc615 KZ |
723 | blkid_probe disk_pr = NULL; |
724 | blkid_partlist ls; | |
725 | blkid_partition par; | |
fd9f45e1 | 726 | dev_t devno; |
0c6dc615 | 727 | |
a6161898 KZ |
728 | DBG(LOWPROBE, ul_debug("parts: start probing for partition entry")); |
729 | ||
20e1c3dc KZ |
730 | if (pr->flags & BLKID_FL_NOSCAN_DEV) |
731 | goto nothing; | |
732 | ||
0c6dc615 KZ |
733 | devno = blkid_probe_get_devno(pr); |
734 | if (!devno) | |
735 | goto nothing; | |
736 | ||
fd9f45e1 | 737 | disk_pr = blkid_probe_get_wholedisk_probe(pr); |
0c6dc615 KZ |
738 | if (!disk_pr) |
739 | goto nothing; | |
740 | ||
741 | /* parse PT */ | |
742 | ls = blkid_probe_get_partitions(disk_pr); | |
743 | if (!ls) | |
744 | goto nothing; | |
745 | ||
746 | par = blkid_partlist_devno_to_partition(ls, devno); | |
d2a8b8d1 KZ |
747 | if (!par) |
748 | goto nothing; | |
749 | else { | |
0c6dc615 | 750 | const char *v; |
fbe66f6b | 751 | blkid_parttable tab = blkid_partition_get_table(par); |
ffb06a15 | 752 | dev_t disk = blkid_probe_get_devno(disk_pr); |
fbe66f6b KZ |
753 | |
754 | if (tab) { | |
755 | v = blkid_parttable_get_type(tab); | |
756 | if (v) | |
757 | blkid_probe_set_value(pr, "PART_ENTRY_SCHEME", | |
758 | (unsigned char *) v, strlen(v) + 1); | |
759 | } | |
0c6dc615 KZ |
760 | |
761 | v = blkid_partition_get_name(par); | |
762 | if (v) | |
763 | blkid_probe_set_value(pr, "PART_ENTRY_NAME", | |
764 | (unsigned char *) v, strlen(v) + 1); | |
765 | ||
766 | v = blkid_partition_get_uuid(par); | |
767 | if (v) | |
768 | blkid_probe_set_value(pr, "PART_ENTRY_UUID", | |
769 | (unsigned char *) v, strlen(v) + 1); | |
770 | ||
771 | /* type */ | |
772 | v = blkid_partition_get_type_string(par); | |
773 | if (v) | |
774 | blkid_probe_set_value(pr, "PART_ENTRY_TYPE", | |
775 | (unsigned char *) v, strlen(v) + 1); | |
776 | else | |
777 | blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE", | |
75838802 KZ |
778 | "0x%x", blkid_partition_get_type(par)); |
779 | ||
780 | if (blkid_partition_get_flags(par)) | |
781 | blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS", | |
782 | "0x%llx", blkid_partition_get_flags(par)); | |
fbe66f6b KZ |
783 | |
784 | blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER", | |
785 | "%d", blkid_partition_get_partno(par)); | |
ffb06a15 KZ |
786 | |
787 | blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd", | |
fdbd7bb9 | 788 | (intmax_t)blkid_partition_get_start(par)); |
ffb06a15 | 789 | blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd", |
fdbd7bb9 | 790 | (intmax_t)blkid_partition_get_size(par)); |
ffb06a15 KZ |
791 | |
792 | blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u", | |
793 | major(disk), minor(disk)); | |
0c6dc615 | 794 | } |
d2a8b8d1 KZ |
795 | |
796 | DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]")); | |
797 | return BLKID_PROBE_OK; | |
798 | ||
0c6dc615 | 799 | nothing: |
d2a8b8d1 KZ |
800 | DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]")); |
801 | return BLKID_PROBE_NONE; | |
802 | ||
803 | ||
0c6dc615 KZ |
804 | } |
805 | ||
c81e7008 KZ |
806 | /* |
807 | * Returns 1 if the device is whole-disk and the area specified by @offset and | |
808 | * @size is covered by any partition. | |
809 | */ | |
810 | int blkid_probe_is_covered_by_pt(blkid_probe pr, | |
f12cd8d1 | 811 | uint64_t offset, uint64_t size) |
c81e7008 | 812 | { |
20e1c3dc | 813 | blkid_probe prc = NULL; |
c81e7008 | 814 | blkid_partlist ls = NULL; |
f12cd8d1 | 815 | uint64_t start, end; |
c81e7008 KZ |
816 | int nparts, i, rc = 0; |
817 | ||
c62a6311 | 818 | DBG(LOWPROBE, ul_debug( |
fdbd7bb9 | 819 | "=> checking if off=%"PRIu64" size=%"PRIu64" covered by PT", |
c81e7008 KZ |
820 | offset, size)); |
821 | ||
20e1c3dc KZ |
822 | if (pr->flags & BLKID_FL_NOSCAN_DEV) |
823 | goto done; | |
824 | ||
fd9f45e1 KZ |
825 | prc = blkid_clone_probe(pr); |
826 | if (!prc) | |
827 | goto done; | |
828 | ||
829 | ls = blkid_probe_get_partitions(prc); | |
c81e7008 KZ |
830 | if (!ls) |
831 | goto done; | |
832 | ||
833 | nparts = blkid_partlist_numof_partitions(ls); | |
834 | if (!nparts) | |
835 | goto done; | |
836 | ||
837 | end = (offset + size) >> 9; | |
838 | start = offset >> 9; | |
839 | ||
66d8e050 KZ |
840 | /* check if the partition table fits into the device */ |
841 | for (i = 0; i < nparts; i++) { | |
842 | blkid_partition par = &ls->parts[i]; | |
843 | ||
a09f0933 | 844 | if (par->start + par->size > (pr->size >> 9)) { |
c62a6311 | 845 | DBG(LOWPROBE, ul_debug("partition #%d overflows " |
0540ea54 | 846 | "device (off=%" PRId64 " size=%" PRId64 ")", |
94decb7c | 847 | par->partno, par->start, par->size)); |
66d8e050 KZ |
848 | goto done; |
849 | } | |
850 | } | |
851 | ||
852 | /* check if the requested area is covered by PT */ | |
c81e7008 KZ |
853 | for (i = 0; i < nparts; i++) { |
854 | blkid_partition par = &ls->parts[i]; | |
855 | ||
856 | if (start >= par->start && end <= par->start + par->size) { | |
857 | rc = 1; | |
858 | break; | |
859 | } | |
860 | } | |
861 | done: | |
fd9f45e1 | 862 | blkid_free_probe(prc); |
c81e7008 | 863 | |
c62a6311 | 864 | DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT")); |
c81e7008 KZ |
865 | return rc; |
866 | } | |
867 | ||
e4799a35 KZ |
868 | /** |
869 | * blkid_known_pttype: | |
9e930041 | 870 | * @pttype: partition name |
e4799a35 KZ |
871 | * |
872 | * Returns: 1 for known or 0 for unknown partition type. | |
873 | */ | |
874 | int blkid_known_pttype(const char *pttype) | |
875 | { | |
01fb8c00 | 876 | size_t i; |
e4799a35 KZ |
877 | |
878 | if (!pttype) | |
879 | return 0; | |
880 | ||
881 | for (i = 0; i < ARRAY_SIZE(idinfos); i++) { | |
882 | const struct blkid_idinfo *id = idinfos[i]; | |
883 | if (strcmp(id->name, pttype) == 0) | |
884 | return 1; | |
885 | } | |
886 | return 0; | |
887 | } | |
888 | ||
635d9aa5 SK |
889 | /** |
890 | * blkid_partitions_get_name: | |
891 | * @idx: number >= 0 | |
892 | * @name: returns name of a supported partition | |
893 | * | |
ae4e2abc KZ |
894 | * Since: 2.30 |
895 | * | |
635d9aa5 SK |
896 | * Returns: -1 if @idx is out of range, or 0 on success. |
897 | */ | |
898 | int blkid_partitions_get_name(const size_t idx, const char **name) | |
899 | { | |
900 | if (idx < ARRAY_SIZE(idinfos)) { | |
901 | *name = idinfos[idx]->name; | |
902 | return 0; | |
903 | } | |
904 | return -1; | |
905 | } | |
906 | ||
e4799a35 KZ |
907 | /** |
908 | * blkid_partlist_numof_partitions: | |
909 | * @ls: partitions list | |
910 | * | |
911 | * Returns: number of partitions in the list or -1 in case of error. | |
912 | */ | |
913 | int blkid_partlist_numof_partitions(blkid_partlist ls) | |
914 | { | |
7f787ced | 915 | return ls->nparts; |
e4799a35 KZ |
916 | } |
917 | ||
19f87d1d KZ |
918 | /** |
919 | * blkid_partlist_get_table: | |
fd7c9e35 | 920 | * @ls: partitions list |
19f87d1d | 921 | * |
fd7c9e35 | 922 | * Returns: top-level partition table or NULL of there is not a partition table |
19f87d1d KZ |
923 | * on the device. |
924 | */ | |
925 | blkid_parttable blkid_partlist_get_table(blkid_partlist ls) | |
926 | { | |
7f787ced | 927 | if (list_empty(&ls->l_tabs)) |
19f87d1d KZ |
928 | return NULL; |
929 | ||
930 | return list_entry(ls->l_tabs.next, | |
931 | struct blkid_struct_parttable, t_tabs); | |
932 | } | |
933 | ||
934 | ||
e4799a35 KZ |
935 | /** |
936 | * blkid_partlist_get_partition: | |
937 | * @ls: partitions list | |
938 | * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions(). | |
939 | * | |
940 | * It's possible that the list of partitions is *empty*, but there is a valid | |
941 | * partition table on the disk. This happen when on-disk details about | |
e9c2d185 KZ |
942 | * partitions are unknown or the partition table is empty. |
943 | * | |
944 | * See also blkid_partlist_get_table(). | |
e4799a35 KZ |
945 | * |
946 | * Returns: partition object or NULL in case or error. | |
947 | */ | |
948 | blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n) | |
949 | { | |
7f787ced | 950 | if (n < 0 || n >= ls->nparts) |
e4799a35 KZ |
951 | return NULL; |
952 | ||
953 | return &ls->parts[n]; | |
954 | } | |
955 | ||
50d1594c KZ |
956 | blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start) |
957 | { | |
958 | int i, nparts; | |
959 | blkid_partition par; | |
960 | ||
961 | nparts = blkid_partlist_numof_partitions(ls); | |
962 | for (i = 0; i < nparts; i++) { | |
963 | par = blkid_partlist_get_partition(ls, i); | |
964 | if ((uint64_t) blkid_partition_get_start(par) == start) | |
965 | return par; | |
966 | } | |
967 | return NULL; | |
968 | } | |
969 | ||
a3ebe0ec KZ |
970 | /** |
971 | * blkid_partlist_get_partition_by_partno | |
972 | * @ls: partitions list | |
973 | * @n: the partition number (e.g. 'N' from sda'N') | |
974 | * | |
975 | * This does not assume any order of the input blkid_partlist. And correctly | |
976 | * handles "out of order" partition tables. partition N is located after | |
977 | * partition N+1 on the disk. | |
978 | * | |
979 | * Returns: partition object or NULL in case or error. | |
980 | */ | |
981 | blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n) | |
982 | { | |
983 | int i, nparts; | |
984 | blkid_partition par; | |
985 | ||
a3ebe0ec KZ |
986 | nparts = blkid_partlist_numof_partitions(ls); |
987 | for (i = 0; i < nparts; i++) { | |
988 | par = blkid_partlist_get_partition(ls, i); | |
989 | if (n == blkid_partition_get_partno(par)) | |
990 | return par; | |
991 | } | |
992 | return NULL; | |
993 | } | |
994 | ||
995 | ||
0c6dc615 KZ |
996 | /** |
997 | * blkid_partlist_devno_to_partition: | |
998 | * @ls: partitions list | |
999 | * @devno: requested partition | |
1000 | * | |
1001 | * This function tries to get start and size for @devno from sysfs and | |
1002 | * returns a partition from @ls which matches with the values from sysfs. | |
1003 | * | |
455fe9a0 | 1004 | * This function is necessary when you want to make a relation between an entry |
0c6dc615 KZ |
1005 | * in the partition table (@ls) and block devices in your system. |
1006 | * | |
1007 | * Returns: partition object or NULL in case or error. | |
1008 | */ | |
1009 | blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno) | |
1010 | { | |
d8a84552 | 1011 | struct sysfs_cxt sysfs; |
0c6dc615 | 1012 | uint64_t start, size; |
a44fe768 | 1013 | int i, rc, partno = 0; |
0c6dc615 | 1014 | |
9e930041 | 1015 | DBG(LOWPROBE, ul_debug("trying to convert devno 0x%llx to partition", |
c13d3432 | 1016 | (long long) devno)); |
0c6dc615 | 1017 | |
c13d3432 | 1018 | if (sysfs_init(&sysfs, devno, NULL)) { |
c62a6311 | 1019 | DBG(LOWPROBE, ul_debug("failed t init sysfs context")); |
c13d3432 KZ |
1020 | return NULL; |
1021 | } | |
a44fe768 KZ |
1022 | rc = sysfs_read_u64(&sysfs, "size", &size); |
1023 | if (!rc) { | |
1024 | rc = sysfs_read_u64(&sysfs, "start", &start); | |
1025 | if (rc) { | |
1026 | /* try to get partition number from DM uuid. | |
1027 | */ | |
1028 | char *uuid = sysfs_strdup(&sysfs, "dm/uuid"); | |
1029 | char *tmp = uuid; | |
1030 | char *prefix = uuid ? strsep(&tmp, "-") : NULL; | |
1031 | ||
1032 | if (prefix && strncasecmp(prefix, "part", 4) == 0) { | |
1033 | char *end = NULL; | |
1034 | ||
1035 | partno = strtol(prefix + 4, &end, 10); | |
1036 | if (prefix == end || (end && *end)) | |
1037 | partno = 0; | |
1038 | else | |
1039 | rc = 0; /* success */ | |
1040 | } | |
1041 | free(uuid); | |
1042 | } | |
1043 | } | |
d8a84552 KZ |
1044 | |
1045 | sysfs_deinit(&sysfs); | |
1046 | ||
90e9fcda KZ |
1047 | if (rc) |
1048 | return NULL; | |
1049 | ||
a44fe768 | 1050 | if (partno) { |
c62a6311 | 1051 | DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno)); |
c13d3432 | 1052 | |
a44fe768 KZ |
1053 | /* |
1054 | * Partition mapped by kpartx does not provide "start" offset | |
1055 | * in /sys, but if we know partno and size of the partition | |
9e930041 | 1056 | * that we can probably make the relation between the device |
a44fe768 KZ |
1057 | * and an entry in partition table. |
1058 | */ | |
1059 | for (i = 0; i < ls->nparts; i++) { | |
1060 | blkid_partition par = &ls->parts[i]; | |
1061 | ||
1062 | if (partno != blkid_partition_get_partno(par)) | |
1063 | continue; | |
1064 | ||
b9710f1f | 1065 | if (size == (uint64_t)blkid_partition_get_size(par) || |
f12cd8d1 | 1066 | (blkid_partition_is_extended(par) && size <= 1024ULL)) |
a44fe768 KZ |
1067 | return par; |
1068 | ||
1069 | } | |
1070 | return NULL; | |
1071 | } | |
1072 | ||
c62a6311 | 1073 | DBG(LOWPROBE, ul_debug("searching by offset/size")); |
c13d3432 | 1074 | |
0c6dc615 KZ |
1075 | for (i = 0; i < ls->nparts; i++) { |
1076 | blkid_partition par = &ls->parts[i]; | |
1077 | ||
b9710f1f RM |
1078 | if ((uint64_t)blkid_partition_get_start(par) == start && |
1079 | (uint64_t)blkid_partition_get_size(par) == size) | |
0c6dc615 | 1080 | return par; |
4720bb19 KZ |
1081 | |
1082 | /* exception for extended dos partitions */ | |
b9710f1f | 1083 | if ((uint64_t)blkid_partition_get_start(par) == start && |
f12cd8d1 | 1084 | blkid_partition_is_extended(par) && size <= 1024ULL) |
4720bb19 KZ |
1085 | return par; |
1086 | ||
0c6dc615 | 1087 | } |
c13d3432 | 1088 | |
c62a6311 | 1089 | DBG(LOWPROBE, ul_debug("not found partition for device")); |
0c6dc615 KZ |
1090 | return NULL; |
1091 | } | |
1092 | ||
a3ebe0ec | 1093 | |
635c0acc | 1094 | int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id) |
58312037 KZ |
1095 | { |
1096 | if (!tab) | |
1097 | return -1; | |
1098 | ||
635c0acc KZ |
1099 | blkid_unparse_uuid(id, tab->id, sizeof(tab->id)); |
1100 | return 0; | |
1101 | } | |
1102 | ||
1103 | int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id) | |
1104 | { | |
1105 | if (!tab) | |
1106 | return -1; | |
58312037 | 1107 | |
635c0acc | 1108 | strncpy(tab->id, (const char *) id, sizeof(tab->id)); |
58312037 KZ |
1109 | return 0; |
1110 | } | |
1111 | ||
62e83b1d KZ |
1112 | /* set PTUUID variable for non-binary API */ |
1113 | int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid) | |
1114 | { | |
1115 | struct blkid_chain *chn = blkid_probe_get_chain(pr); | |
1116 | struct blkid_prval *v; | |
1117 | ||
1118 | if (chn->binary || blkid_uuid_is_empty(uuid, 16)) | |
1119 | return 0; | |
1120 | ||
1121 | v = blkid_probe_assign_value(pr, "PTUUID"); | |
6c4a7811 OO |
1122 | if (!v) |
1123 | return -ENOMEM; | |
62e83b1d | 1124 | |
b443c177 | 1125 | v->len = UUID_STR_LEN; |
6c4a7811 OO |
1126 | v->data = calloc(1, v->len); |
1127 | if (v->data) { | |
1128 | blkid_unparse_uuid(uuid, (char *) v->data, v->len); | |
1129 | return 0; | |
1130 | } | |
62e83b1d | 1131 | |
af17d349 | 1132 | blkid_probe_free_value(v); |
6c4a7811 | 1133 | return -ENOMEM; |
62e83b1d KZ |
1134 | } |
1135 | ||
1136 | /* set PTUUID variable for non-binary API for tables where | |
1137 | * the ID is just a string */ | |
1138 | int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str) | |
1139 | { | |
1140 | struct blkid_chain *chn = blkid_probe_get_chain(pr); | |
62e83b1d KZ |
1141 | |
1142 | if (chn->binary || !str || !*str) | |
1143 | return 0; | |
1144 | ||
6c4a7811 OO |
1145 | if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1)) |
1146 | return -ENOMEM; | |
62e83b1d | 1147 | |
6c4a7811 | 1148 | return 0; |
62e83b1d KZ |
1149 | } |
1150 | ||
58312037 KZ |
1151 | /** |
1152 | * blkid_parttable_get_id: | |
1153 | * @tab: partition table | |
1154 | * | |
1155 | * The ID is GPT disk UUID or DOS disk ID (in hex format). | |
1156 | * | |
1157 | * Returns: partition table ID (for example GPT disk UUID) or NULL | |
1158 | */ | |
1159 | const char *blkid_parttable_get_id(blkid_parttable tab) | |
1160 | { | |
7f787ced | 1161 | return *tab->id ? tab->id : NULL; |
58312037 KZ |
1162 | } |
1163 | ||
1164 | ||
c2dacc61 KZ |
1165 | int blkid_partition_set_type(blkid_partition par, int type) |
1166 | { | |
c2dacc61 KZ |
1167 | par->type = type; |
1168 | return 0; | |
1169 | } | |
1170 | ||
e4799a35 KZ |
1171 | /** |
1172 | * blkid_parttable_get_type: | |
1173 | * @tab: partition table | |
1174 | * | |
1175 | * Returns: partition table type (type name, e.g. "dos", "gpt", ...) | |
1176 | */ | |
1177 | const char *blkid_parttable_get_type(blkid_parttable tab) | |
1178 | { | |
7f787ced | 1179 | return tab->type; |
e4799a35 KZ |
1180 | } |
1181 | ||
1182 | /** | |
1183 | * blkid_parttable_get_parent: | |
1184 | * @tab: partition table | |
1185 | * | |
9e930041 | 1186 | * Returns: parent for nested partition tables or NULL. |
e4799a35 KZ |
1187 | */ |
1188 | blkid_partition blkid_parttable_get_parent(blkid_parttable tab) | |
1189 | { | |
7f787ced | 1190 | return tab->parent; |
e4799a35 KZ |
1191 | } |
1192 | ||
1193 | /** | |
1194 | * blkid_parttable_get_offset: | |
1195 | * @tab: partition table | |
1196 | * | |
e4799a35 KZ |
1197 | * Note the position is relative to begin of the device as defined by |
1198 | * blkid_probe_set_device() for primary partition table, and relative | |
9e930041 | 1199 | * to parental partition for nested partition tables. |
e4799a35 KZ |
1200 | * |
1201 | * <informalexample> | |
1202 | * <programlisting> | |
1203 | * off_t offset; | |
1204 | * blkid_partition parent = blkid_parttable_get_parent(tab); | |
1205 | * | |
1206 | * offset = blkid_parttable_get_offset(tab); | |
1207 | * | |
1208 | * if (parent) | |
1209 | * / * 'tab' is nested partition table * / | |
1210 | * offset += blkid_partition_get_start(parent); | |
1211 | * </programlisting> | |
1212 | * </informalexample> | |
fd7c9e35 KZ |
1213 | |
1214 | * Returns: position (in bytes) of the partition table or -1 in case of error. | |
1215 | * | |
e4799a35 KZ |
1216 | */ |
1217 | blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab) | |
1218 | { | |
7f787ced | 1219 | return (blkid_loff_t)tab->offset; |
e4799a35 KZ |
1220 | } |
1221 | ||
1222 | /** | |
1223 | * blkid_partition_get_table: | |
1224 | * @par: partition | |
1225 | * | |
1226 | * The "parttable" describes partition table. The table is usually the same for | |
1227 | * all partitions -- except nested partition tables. | |
1228 | * | |
1229 | * For example bsd, solaris, etc. use a nested partition table within | |
1230 | * standard primary dos partition: | |
1231 | * | |
1232 | * <informalexample> | |
1233 | * <programlisting> | |
1234 | * | |
1235 | * -- dos partition table | |
1236 | * 0: sda1 dos primary partition | |
1237 | * 1: sda2 dos primary partition | |
1238 | * -- bsd partition table (with in sda2) | |
1239 | * 2: sda5 bds partition | |
1240 | * 3: sda6 bds partition | |
1241 | * | |
1242 | * </programlisting> | |
1243 | * </informalexample> | |
1244 | * | |
1245 | * The library does not to use a separate partition table object for dos logical | |
1246 | * partitions (partitions within extended partition). It's possible to | |
1247 | * differentiate between logical, extended and primary partitions by | |
1248 | * | |
1249 | * blkid_partition_is_{extended,primary,logical}(). | |
1250 | * | |
1251 | * Returns: partition table object or NULL in case of error. | |
1252 | */ | |
1253 | blkid_parttable blkid_partition_get_table(blkid_partition par) | |
1254 | { | |
7f787ced | 1255 | return par->tab; |
e4799a35 KZ |
1256 | } |
1257 | ||
1258 | static int partition_get_logical_type(blkid_partition par) | |
1259 | { | |
1260 | blkid_parttable tab; | |
1261 | ||
1262 | if (!par) | |
1263 | return -1; | |
1264 | ||
1265 | tab = blkid_partition_get_table(par); | |
1266 | if (!tab || !tab->type) | |
1267 | return -1; | |
1268 | ||
1269 | if (tab->parent) | |
1270 | return 'L'; /* report nested partitions as logical */ | |
1271 | ||
1272 | if (!strcmp(tab->type, "dos")) { | |
1273 | if (par->partno > 4) | |
1274 | return 'L'; /* logical */ | |
1275 | ||
7e5f8f38 KZ |
1276 | if(par->type == MBR_DOS_EXTENDED_PARTITION || |
1277 | par->type == MBR_W95_EXTENDED_PARTITION || | |
1278 | par->type == MBR_LINUX_EXTENDED_PARTITION) | |
e4799a35 KZ |
1279 | return 'E'; |
1280 | } | |
1281 | return 'P'; | |
1282 | } | |
1283 | ||
1284 | /** | |
1285 | * blkid_partition_is_primary: | |
1286 | * @par: partition | |
1287 | * | |
1288 | * Note, this function returns FALSE for DOS extended partitions and | |
1289 | * all partitions in nested partition tables. | |
1290 | * | |
1291 | * Returns: 1 if the partitions is primary partition or 0 if not. | |
1292 | */ | |
1293 | int blkid_partition_is_primary(blkid_partition par) | |
1294 | { | |
1295 | return partition_get_logical_type(par) == 'P' ? TRUE : FALSE; | |
1296 | } | |
1297 | ||
1298 | /** | |
1299 | * blkid_partition_is_extended: | |
1300 | * @par: partition | |
1301 | * | |
1302 | * Returns: 1 if the partitions is extended (dos, windows or linux) | |
1303 | * partition or 0 if not. | |
1304 | */ | |
1305 | int blkid_partition_is_extended(blkid_partition par) | |
1306 | { | |
1307 | return partition_get_logical_type(par) == 'E' ? TRUE : FALSE; | |
1308 | } | |
1309 | ||
1310 | /** | |
1311 | * blkid_partition_is_logical: | |
1312 | * @par: partition | |
1313 | * | |
1314 | * Note that this function returns TRUE for all partitions in all | |
1315 | * nested partition tables (e.g. BSD labels). | |
1316 | * | |
1317 | * Returns: 1 if the partitions is logical partition or 0 if not. | |
1318 | */ | |
1319 | int blkid_partition_is_logical(blkid_partition par) | |
1320 | { | |
1321 | return partition_get_logical_type(par) == 'L' ? TRUE : FALSE; | |
1322 | } | |
1323 | ||
0e8a8065 KZ |
1324 | static void set_string(unsigned char *item, size_t max, |
1325 | const unsigned char *data, size_t len) | |
e4799a35 | 1326 | { |
0e8a8065 KZ |
1327 | if (len >= max) |
1328 | len = max - 1; | |
e4799a35 | 1329 | |
0e8a8065 KZ |
1330 | memcpy(item, data, len); |
1331 | item[len] = '\0'; | |
e4799a35 | 1332 | |
c2dbd49b | 1333 | blkid_rtrim_whitespace(item); |
0e8a8065 KZ |
1334 | } |
1335 | ||
1336 | int blkid_partition_set_name(blkid_partition par, | |
1337 | const unsigned char *name, size_t len) | |
1338 | { | |
1339 | if (!par) | |
1340 | return -1; | |
1341 | ||
1342 | set_string(par->name, sizeof(par->name), name, len); | |
e4799a35 KZ |
1343 | return 0; |
1344 | } | |
1345 | ||
1346 | int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name, | |
1347 | size_t len, int enc) | |
1348 | { | |
1349 | if (!par) | |
1350 | return -1; | |
c2dbd49b | 1351 | |
e4799a35 | 1352 | blkid_encode_to_utf8(enc, par->name, sizeof(par->name), name, len); |
c2dbd49b | 1353 | blkid_rtrim_whitespace(par->name); |
e4799a35 KZ |
1354 | return 0; |
1355 | } | |
1356 | ||
1357 | int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid) | |
1358 | { | |
1359 | if (!par) | |
1360 | return -1; | |
1361 | ||
1362 | blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid)); | |
1363 | return 0; | |
1364 | } | |
1365 | ||
d67cc288 KZ |
1366 | int blkid_partition_gen_uuid(blkid_partition par) |
1367 | { | |
1368 | if (!par || !par->tab || !*par->tab->id) | |
1369 | return -1; | |
1370 | ||
feeeaca9 | 1371 | snprintf(par->uuid, sizeof(par->uuid), "%.33s-%02x", |
d67cc288 KZ |
1372 | par->tab->id, par->partno); |
1373 | return 0; | |
1374 | } | |
1375 | ||
e4799a35 KZ |
1376 | /** |
1377 | * blkid_partition_get_name: | |
1378 | * @par: partition | |
1379 | * | |
1380 | * Returns: partition name string if supported by PT (e.g. Mac) or NULL. | |
1381 | */ | |
1382 | const char *blkid_partition_get_name(blkid_partition par) | |
1383 | { | |
7f787ced | 1384 | return *par->name ? (char *) par->name : NULL; |
e4799a35 KZ |
1385 | } |
1386 | ||
1387 | /** | |
1388 | * blkid_partition_get_uuid: | |
1389 | * @par: partition | |
1390 | * | |
1391 | * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL. | |
1392 | */ | |
1393 | const char *blkid_partition_get_uuid(blkid_partition par) | |
1394 | { | |
7f787ced | 1395 | return *par->uuid ? par->uuid : NULL; |
e4799a35 KZ |
1396 | } |
1397 | ||
1398 | /** | |
1399 | * blkid_partition_get_partno: | |
1400 | * @par: partition | |
1401 | * | |
9e930041 SR |
1402 | * Returns: proposed partition number (e.g. 'N' from sda'N') or -1 in case of |
1403 | * error. Note that the number is generate by library independently on your OS. | |
e4799a35 KZ |
1404 | */ |
1405 | int blkid_partition_get_partno(blkid_partition par) | |
1406 | { | |
7f787ced | 1407 | return par->partno; |
e4799a35 KZ |
1408 | } |
1409 | ||
1410 | /** | |
1411 | * blkid_partition_get_start: | |
1412 | * @par: partition | |
1413 | * | |
1414 | * Be careful if you _not_ probe whole disk: | |
1415 | * | |
9e930041 | 1416 | * 1) the offset is usually relative to begin of the disk -- but if you probe a |
e4799a35 KZ |
1417 | * fragment of the disk only -- then the offset could be still relative to |
1418 | * the begin of the disk rather that relative to the fragment. | |
1419 | * | |
9e930041 | 1420 | * 2) the offset for nested partitions could be relative to parent (e.g. Solaris) |
e4799a35 KZ |
1421 | * _or_ relative to the begin of the whole disk (e.g. bsd). |
1422 | * | |
9e930041 | 1423 | * You don't have to care about such details if you probe whole disk. In such |
e4799a35 KZ |
1424 | * a case libblkid always returns the offset relative to the begin of the disk. |
1425 | * | |
1426 | * Returns: start of the partition (in 512-sectors). | |
1427 | */ | |
1428 | blkid_loff_t blkid_partition_get_start(blkid_partition par) | |
1429 | { | |
7f787ced | 1430 | return (blkid_loff_t)par->start; |
e4799a35 KZ |
1431 | } |
1432 | ||
1433 | /** | |
1434 | * blkid_partition_get_size: | |
1435 | * @par: partition | |
1436 | * | |
1437 | * WARNING: be very careful when you work with MS-DOS extended partitions. The | |
1438 | * library always returns full size of the partition. If you want add | |
1439 | * the partition to the Linux system (BLKPG_ADD_PARTITION ioctl) you | |
1440 | * need to reduce the size of the partition to 1 or 2 blocks. The | |
9e930041 | 1441 | * rest of the partition has to be inaccessible for mkfs or mkswap |
e4799a35 KZ |
1442 | * programs, we need a small space for boot loaders only. |
1443 | * | |
1444 | * For some unknown reason this (safe) practice is not to used for | |
1445 | * nested BSD, Solaris, ..., partition tables in Linux kernel. | |
1446 | * | |
1447 | * Returns: size of the partition (in 512-sectors). | |
1448 | */ | |
1449 | blkid_loff_t blkid_partition_get_size(blkid_partition par) | |
1450 | { | |
7f787ced | 1451 | return (blkid_loff_t)par->size; |
e4799a35 KZ |
1452 | } |
1453 | ||
1454 | /** | |
1455 | * blkid_partition_get_type: | |
1456 | * @par: partition | |
1457 | * | |
0e8a8065 | 1458 | * Returns: partition type. |
e4799a35 KZ |
1459 | */ |
1460 | int blkid_partition_get_type(blkid_partition par) | |
1461 | { | |
e3436956 | 1462 | return par->type; |
e4799a35 | 1463 | } |
0e8a8065 KZ |
1464 | |
1465 | /* Sets partition 'type' for PT where the type is defined by string rather | |
1466 | * than by number | |
1467 | */ | |
1468 | int blkid_partition_set_type_string(blkid_partition par, | |
1469 | const unsigned char *type, size_t len) | |
1470 | { | |
0e8a8065 KZ |
1471 | set_string((unsigned char *) par->typestr, |
1472 | sizeof(par->typestr), type, len); | |
1473 | return 0; | |
1474 | } | |
1475 | ||
1476 | /* Sets partition 'type' for PT where the type is defined by UUIDrather | |
1477 | * than by number | |
1478 | */ | |
1479 | int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid) | |
1480 | { | |
0e8a8065 KZ |
1481 | blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr)); |
1482 | return 0; | |
1483 | } | |
1484 | ||
1485 | /** | |
1486 | * blkid_partition_get_type_string: | |
1487 | * @par: partition | |
1488 | * | |
1489 | * The type string is supported by a small subset of partition tables (e.g Mac | |
1490 | * and EFI GPT). Note that GPT uses type UUID and this function returns this | |
1491 | * UUID as string. | |
1492 | * | |
1493 | * Returns: partition type string or NULL. | |
1494 | */ | |
1495 | const char *blkid_partition_get_type_string(blkid_partition par) | |
1496 | { | |
7f787ced | 1497 | return *par->typestr ? par->typestr : NULL; |
0e8a8065 KZ |
1498 | } |
1499 | ||
75838802 KZ |
1500 | |
1501 | int blkid_partition_set_flags(blkid_partition par, unsigned long long flags) | |
1502 | { | |
75838802 KZ |
1503 | par->flags = flags; |
1504 | return 0; | |
1505 | } | |
1506 | ||
1507 | /** | |
1508 | * blkid_partition_get_flags | |
1509 | * @par: partition | |
1510 | * | |
1511 | * Returns: partition flags (or attributes for gpt). | |
1512 | */ | |
1513 | unsigned long long blkid_partition_get_flags(blkid_partition par) | |
1514 | { | |
e3436956 | 1515 | return par->flags; |
75838802 KZ |
1516 | } |
1517 |