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