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