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