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