Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.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  * @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  */
115 static int partitions_probe(blkid_probe pr, struct blkid_chain *chn);
116 static void partitions_free_data(blkid_probe pr, void *data);
117
118 /*
119  * Partitions chain probing functions
120  */
121 static 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  */
139 const 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" */
161 struct 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
167         struct list_head t_tabs;        /* all tables */
168 };
169
170 /* exported as opaque type "blkid_partition" */
171 struct blkid_struct_partition {
172         blkid_loff_t    start;          /* begin of the partition */
173         blkid_loff_t    size;           /* size of the partitions */
174
175         int             type;           /* partition type */
176         char            typestr[37];    /* partition type string (GPT and Mac) */
177
178         unsigned long long flags;       /* partition flags / attributes */
179
180         int             partno;         /* partition number */
181         char            uuid[37];       /* UUID (when supported by PT), e.g GPT */
182         unsigned char   name[128];      /* Partition in UTF8 name (when supporte by PT), e.g. Mac */
183
184         blkid_parttable tab;            /* partition table */
185 };
186
187 /* exported as opaque type "blkid_partlist" */
188 struct blkid_struct_partlist {
189         int             next_partno;    /* next partition number */
190         blkid_partition next_parent;    /* next parent if parsing nested PT */
191
192         int             nparts;         /* number of partitions */
193         int             nparts_max;     /* max.number of partitions */
194         blkid_partition parts;          /* array of partitions */
195
196         struct list_head l_tabs;        /* list of partition tables */
197 };
198
199 static int blkid_partitions_probe_partition(blkid_probe pr);
200
201 /**
202  * blkid_probe_enable_partitions:
203  * @pr: probe
204  * @enable: TRUE/FALSE
205  *
206  * Enables/disables the partitions probing for non-binary interface.
207  *
208  * Returns: 0 on success, or -1 in case of error.
209  */
210 int blkid_probe_enable_partitions(blkid_probe pr, int enable)
211 {
212         if (!pr)
213                 return -1;
214         pr->chains[BLKID_CHAIN_PARTS].enabled = enable;
215         return 0;
216 }
217
218 /**
219  * blkid_probe_set_partitions_flags:
220  * @pr: prober
221  * @flags: BLKID_PARTS_* flags
222  *
223  * Sets probing flags to the partitions prober. This function is optional.
224  *
225  * Returns: 0 on success, or -1 in case of error.
226  */
227 int blkid_probe_set_partitions_flags(blkid_probe pr, int flags)
228 {
229         if (!pr)
230                 return -1;
231
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  */
244 int blkid_probe_reset_partitions_filter(blkid_probe pr)
245 {
246         return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS);
247 }
248
249 /**
250  * blkid_probe_invert_partitions_filter:
251  * @pr: prober
252  *
253  * Inverts partitions probing filter
254  *
255  * Returns: 0 on success, or -1 in case of error.
256  */
257 int blkid_probe_invert_partitions_filter(blkid_probe pr)
258 {
259         return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS);
260 }
261
262 /**
263  * blkid_probe_filter_partitions_type:
264  * @pr: prober
265  * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
266  * @names: NULL terminated array of probing function names (e.g. "vfat").
267  *
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  */
274 int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[])
275 {
276         return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names);
277 }
278
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  */
296 blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
297 {
298         return (blkid_partlist) blkid_probe_get_binary_data(pr,
299                         &pr->chains[BLKID_CHAIN_PARTS]);
300 }
301
302 /* for internal usage only */
303 blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
304 {
305         return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data;
306 }
307
308 static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls)
309 {
310         pr->chains[BLKID_CHAIN_PARTS].data = ls;
311 }
312
313 static void ref_parttable(blkid_parttable tab)
314 {
315         tab->nparts++;
316 }
317
318 static void unref_parttable(blkid_parttable tab)
319 {
320         tab->nparts--;
321
322         if (tab->nparts <= 0) {
323                 list_del(&tab->t_tabs);
324                 free(tab);
325         }
326 }
327
328 /* free all allocated parttables */
329 static void free_parttables(blkid_partlist ls)
330 {
331         if (!ls || !ls->l_tabs.next)
332                 return;
333
334         /* remove unassigned partition tables */
335         while (!list_empty(&ls->l_tabs)) {
336                 blkid_parttable tab = list_entry(ls->l_tabs.next,
337                                         struct blkid_struct_parttable, t_tabs);
338                 unref_parttable(tab);
339         }
340 }
341
342 static 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 reseted\n"));
365 }
366
367 static 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
389 static 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
404 blkid_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
425 static 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
450 blkid_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) */
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 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                         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
533 static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id)
534 {
535         const struct blkid_idmag *mag;
536         int rc = 1;             /* = nothing detected */
537
538         if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
539                 goto nothing;   /* the device is too small */
540
541         if (blkid_probe_get_idmag(pr, id, NULL, &mag))
542                 goto nothing;
543
544         /* final check by probing function */
545         if (id->probefunc) {
546                 DBG(DEBUG_LOWPROBE, printf(
547                         "%s: ---> call probefunc()\n", id->name));
548                 rc = id->probefunc(pr, mag);
549                 if (rc == -1) {
550                         /* reset after error */
551                         reset_partlist(blkid_probe_get_partlist(pr));
552                         DBG(DEBUG_LOWPROBE, printf(
553                                 "%s probefunc failed\n", id->name));
554                 }
555                 DBG(DEBUG_LOWPROBE, printf(
556                         "%s: <--- (rc = %d)\n", id->name, rc));
557         }
558
559 nothing:
560         return rc;
561 }
562
563 /*
564  * The blkid_do_probe() backend.
565  */
566 static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
567 {
568         int rc = 1;
569         size_t i;
570
571         if (!pr || chn->idx < -1)
572                 return -1;
573         blkid_probe_chain_reset_vals(pr, chn);
574
575         if (chn->binary)
576                 partitions_init_data(chn);
577
578         if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
579                 goto details_only;
580
581         DBG(DEBUG_LOWPROBE,
582                 printf("--> starting probing loop [PARTS idx=%d]\n",
583                 chn->idx));
584
585         i = chn->idx < 0 ? 0 : chn->idx + 1U;
586
587         for ( ; i < ARRAY_SIZE(idinfos); i++) {
588                 const char *name;
589
590                 chn->idx = i;
591
592                 /* apply filter */
593                 if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
594                         continue;
595
596                 /* apply checks from idinfo */
597                 if (idinfo_probe(pr, idinfos[i]) != 0)
598                         continue;
599
600                 name = idinfos[i]->name;
601
602                 /* all checks passed */
603                 if (!chn->binary)
604                         blkid_probe_set_value(pr, "PTTYPE",
605                                                 (unsigned char *) name,
606                                                 strlen(name) + 1);
607                 DBG(DEBUG_LOWPROBE,
608                         printf("<-- leaving probing loop (type=%s) [PARTS idx=%d]\n",
609                         name, chn->idx));
610                 rc = 0;
611                 break;
612         }
613
614         if (rc == 1) {
615                 DBG(DEBUG_LOWPROBE,
616                         printf("<-- leaving probing loop (failed) [PARTS idx=%d]\n",
617                         chn->idx));
618         }
619
620 details_only:
621         /*
622          * Gather PART_ENTRY_* values if the current device is a partition.
623          */
624         if (!chn->binary &&
625             (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
626
627                 if (!blkid_partitions_probe_partition(pr))
628                         rc = 0;
629         }
630
631         return rc;
632 }
633
634 /* Probe for nested partition table within the parental partition */
635 int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
636                 const struct blkid_idinfo *id)
637 {
638         blkid_probe prc;
639         int rc = 1;
640         blkid_partlist ls;
641         blkid_loff_t sz, off;
642
643         DBG(DEBUG_LOWPROBE, printf(
644                 "parts: ----> %s subprobe requested (parent=%p)\n",
645                 id->name, parent));
646
647         if (!pr || !parent || !parent->size)
648                 return -1;
649
650         /* range defined by parent */
651         sz = ((blkid_loff_t) parent->size) << 9;
652         off = ((blkid_loff_t) parent->start) << 9;
653
654         if (off < pr->off || pr->off + pr->size < off + sz) {
655                 DBG(DEBUG_LOWPROBE, printf(
656                         "ERROR: parts: <---- '%s' subprobe: overflow detected.\n",
657                         id->name));
658                 return -1;
659         }
660
661         /* create private prober */
662         prc = blkid_clone_probe(pr);
663         if (!prc)
664                 return -1;
665
666         blkid_probe_set_dimension(prc, off, sz);
667
668         /* clone is always with reseted chain, fix it */
669         prc->cur_chain = blkid_probe_get_chain(pr);
670
671         /*
672          * Set 'parent' to the current list of the partitions and use the list
673          * in cloned prober (so the cloned prober will extend the current list
674          * of partitions rather than create a new).
675          */
676         ls = blkid_probe_get_partlist(pr);
677         blkid_partlist_set_parent(ls, parent);
678
679         blkid_probe_set_partlist(prc, ls);
680
681         rc = idinfo_probe(prc, id);
682
683         blkid_probe_set_partlist(prc, NULL);
684         blkid_partlist_set_parent(ls, NULL);
685
686         blkid_free_probe(prc);  /* free cloned prober */
687
688         DBG(DEBUG_LOWPROBE, printf(
689                 "parts: <---- %s subprobe done (parent=%p, rc=%d)\n",
690                 id->name, parent, rc));
691
692         return rc;
693 }
694
695 static int blkid_partitions_probe_partition(blkid_probe pr)
696 {
697         int rc = 1;
698         blkid_probe disk_pr = NULL;
699         blkid_partlist ls;
700         blkid_partition par;
701         dev_t devno;
702
703         devno = blkid_probe_get_devno(pr);
704         if (!devno)
705                 goto nothing;
706
707         disk_pr = blkid_probe_get_wholedisk_probe(pr);
708         if (!disk_pr)
709                 goto nothing;
710
711         /* parse PT */
712         ls = blkid_probe_get_partitions(disk_pr);
713         if (!ls)
714                 goto nothing;
715
716         par = blkid_partlist_devno_to_partition(ls, devno);
717         if (par) {
718                 const char *v;
719                 blkid_parttable tab = blkid_partition_get_table(par);
720                 dev_t disk = blkid_probe_get_devno(disk_pr);
721
722                 if (tab) {
723                         v = blkid_parttable_get_type(tab);
724                         if (v)
725                                 blkid_probe_set_value(pr, "PART_ENTRY_SCHEME",
726                                         (unsigned char *) v, strlen(v) + 1);
727                 }
728
729                 v = blkid_partition_get_name(par);
730                 if (v)
731                         blkid_probe_set_value(pr, "PART_ENTRY_NAME",
732                                 (unsigned char *) v, strlen(v) + 1);
733
734                 v = blkid_partition_get_uuid(par);
735                 if (v)
736                         blkid_probe_set_value(pr, "PART_ENTRY_UUID",
737                                 (unsigned char *) v, strlen(v) + 1);
738
739                 /* type */
740                 v = blkid_partition_get_type_string(par);
741                 if (v)
742                         blkid_probe_set_value(pr, "PART_ENTRY_TYPE",
743                                 (unsigned char *) v, strlen(v) + 1);
744                 else
745                         blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE",
746                                 "0x%x", blkid_partition_get_type(par));
747
748                 if (blkid_partition_get_flags(par))
749                         blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS",
750                                 "0x%llx", blkid_partition_get_flags(par));
751
752                 blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER",
753                                 "%d", blkid_partition_get_partno(par));
754
755                 blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd",
756                                 blkid_partition_get_start(par));
757                 blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd",
758                                 blkid_partition_get_size(par));
759
760                 blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
761                                 major(disk), minor(disk));
762         }
763         rc = 0;
764 nothing:
765         return rc;
766 }
767
768 /*
769  * Returns 1 if the device is whole-disk and the area specified by @offset and
770  * @size is covered by any partition.
771  */
772 int blkid_probe_is_covered_by_pt(blkid_probe pr,
773                                  blkid_loff_t offset, blkid_loff_t size)
774 {
775         blkid_probe prc;
776         blkid_partlist ls = NULL;
777         blkid_loff_t start, end;
778         int nparts, i, rc = 0;
779
780         DBG(DEBUG_LOWPROBE, printf(
781                 "=> checking if off=%jd size=%jd covered by PT\n",
782                 offset, size));
783
784         prc = blkid_clone_probe(pr);
785         if (!prc)
786                 goto done;
787
788         ls = blkid_probe_get_partitions(prc);
789         if (!ls)
790                 goto done;
791
792         nparts = blkid_partlist_numof_partitions(ls);
793         if (!nparts)
794                 goto done;
795
796         end = (offset + size) >> 9;
797         start = offset >> 9;
798
799         /* check if the partition table fits into the device */
800         for (i = 0; i < nparts; i++) {
801                 blkid_partition par = &ls->parts[i];
802
803                 if (par->start + par->size > (pr->size >> 9)) {
804                         DBG(DEBUG_LOWPROBE, printf("partition #%d overflows "
805                                 "device (off=%" PRId64 " size=%" PRId64 ")\n",
806                                 par->partno, par->start, par->size));
807                         goto done;
808                 }
809         }
810
811         /* check if the requested area is covered by PT */
812         for (i = 0; i < nparts; i++) {
813                 blkid_partition par = &ls->parts[i];
814
815                 if (start >= par->start && end <= par->start + par->size) {
816                         rc = 1;
817                         break;
818                 }
819         }
820 done:
821         blkid_free_probe(prc);
822
823         DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT"));
824         return rc;
825 }
826
827 /**
828  * blkid_known_pttype:
829  * @pttype: partiton name
830  *
831  * Returns: 1 for known or 0 for unknown partition type.
832  */
833 int blkid_known_pttype(const char *pttype)
834 {
835         size_t i;
836
837         if (!pttype)
838                 return 0;
839
840         for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
841                 const struct blkid_idinfo *id = idinfos[i];
842                 if (strcmp(id->name, pttype) == 0)
843                         return 1;
844         }
845         return 0;
846 }
847
848 /**
849  * blkid_partlist_numof_partitions:
850  * @ls: partitions list
851  *
852  * Returns: number of partitions in the list or -1 in case of error.
853  */
854 int blkid_partlist_numof_partitions(blkid_partlist ls)
855 {
856         return ls ? ls->nparts : -1;
857 }
858
859 /**
860  * blkid_partlist_get_table:
861  * @ls: partitions list
862  *
863  * Returns: top-level partition table or NULL of there is not a partition table
864  * on the device.
865  */
866 blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
867 {
868         if (!ls || list_empty(&ls->l_tabs))
869                 return NULL;
870
871         return list_entry(ls->l_tabs.next,
872                         struct blkid_struct_parttable, t_tabs);
873 }
874
875
876 /**
877  * blkid_partlist_get_partition:
878  * @ls: partitions list
879  * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions().
880  *
881  * It's possible that the list of partitions is *empty*, but there is a valid
882  * partition table on the disk. This happen when on-disk details about
883  * partitions are unknown or the partition table is empty.
884  *
885  * See also blkid_partlist_get_table().
886  *
887  * Returns: partition object or NULL in case or error.
888  */
889 blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
890 {
891         if (!ls || n < 0 || n >= ls->nparts)
892                 return NULL;
893
894         return &ls->parts[n];
895 }
896
897 /**
898  * blkid_partlist_devno_to_partition:
899  * @ls: partitions list
900  * @devno: requested partition
901  *
902  * This function tries to get start and size for @devno from sysfs and
903  * returns a partition from @ls which matches with the values from sysfs.
904  *
905  * This funtion is necessary when you want to make a relation between an entry
906  * in the partition table (@ls) and block devices in your system.
907  *
908  * Returns: partition object or NULL in case or error.
909  */
910 blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
911 {
912         struct sysfs_cxt sysfs;
913         uint64_t start, size;
914         int i, rc, partno = 0;
915
916         DBG(DEBUG_LOWPROBE,
917                 printf("triyng to convert devno 0x%llx to partition\n",
918                         (long long) devno));
919
920         if (sysfs_init(&sysfs, devno, NULL)) {
921                 DBG(DEBUG_LOWPROBE, printf("failed t init sysfs context\n"));
922                 return NULL;
923         }
924         rc = sysfs_read_u64(&sysfs, "size", &size);
925         if (!rc) {
926                 rc = sysfs_read_u64(&sysfs, "start", &start);
927                 if (rc) {
928                         /* try to get partition number from DM uuid.
929                          */
930                         char *uuid = sysfs_strdup(&sysfs, "dm/uuid");
931                         char *tmp = uuid;
932                         char *prefix = uuid ? strsep(&tmp, "-") : NULL;
933
934                         if (prefix && strncasecmp(prefix, "part", 4) == 0) {
935                                 char *end = NULL;
936
937                                 partno = strtol(prefix + 4, &end, 10);
938                                 if (prefix == end || (end && *end))
939                                         partno = 0;
940                                 else
941                                         rc = 0;         /* success */
942                         }
943                         free(uuid);
944                 }
945         }
946
947         sysfs_deinit(&sysfs);
948
949         if (rc)
950                 return NULL;
951
952         if (partno) {
953                 DBG(DEBUG_LOWPROBE, printf("mapped by DM, using partno %d\n", partno));
954
955                 /*
956                  * Partition mapped by kpartx does not provide "start" offset
957                  * in /sys, but if we know partno and size of the partition
958                  * that we can probably make the releation bettween the device
959                  * and an entry in partition table.
960                  */
961                  for (i = 0; i < ls->nparts; i++) {
962                          blkid_partition par = &ls->parts[i];
963
964                          if (partno != blkid_partition_get_partno(par))
965                                  continue;
966
967                          if ((blkid_loff_t) size == blkid_partition_get_size(par) ||
968                              (blkid_partition_is_extended(par) && size <= 1024))
969                                  return par;
970
971                  }
972                  return NULL;
973         }
974
975         DBG(DEBUG_LOWPROBE, printf("searching by offset/size\n"));
976
977         for (i = 0; i < ls->nparts; i++) {
978                 blkid_partition par = &ls->parts[i];
979
980                 if (blkid_partition_get_start(par) == (blkid_loff_t) start &&
981                     blkid_partition_get_size(par) == (blkid_loff_t) size)
982                         return par;
983
984                 /* exception for extended dos partitions */
985                 if (blkid_partition_get_start(par) == (blkid_loff_t) start &&
986                     blkid_partition_is_extended(par) && size <= 1024)
987                         return par;
988
989         }
990
991         DBG(DEBUG_LOWPROBE, printf("not found partition for device\n"));
992         return NULL;
993 }
994
995 int blkid_partition_set_type(blkid_partition par, int type)
996 {
997         if (!par)
998                 return -1;
999         par->type = type;
1000         return 0;
1001 }
1002
1003 /**
1004  * blkid_parttable_get_type:
1005  * @tab: partition table
1006  *
1007  * Returns: partition table type (type name, e.g. "dos", "gpt", ...)
1008  */
1009 const char *blkid_parttable_get_type(blkid_parttable tab)
1010 {
1011         return tab ? tab->type : NULL;
1012 }
1013
1014 /**
1015  * blkid_parttable_get_parent:
1016  * @tab: partition table
1017  *
1018  * Returns: parent for nexted partitition tables or NULL.
1019  */
1020 blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
1021 {
1022         return tab ? tab->parent : NULL;
1023 }
1024
1025 /**
1026  * blkid_parttable_get_offset:
1027  * @tab: partition table
1028  *
1029  * Note the position is relative to begin of the device as defined by
1030  * blkid_probe_set_device() for primary partition table, and relative
1031  * to parental partition for nested patition tables.
1032  *
1033  * <informalexample>
1034  *   <programlisting>
1035  * off_t offset;
1036  * blkid_partition parent = blkid_parttable_get_parent(tab);
1037  *
1038  * offset = blkid_parttable_get_offset(tab);
1039  *
1040  * if (parent)
1041  *      / * 'tab' is nested partition table * /
1042  *      offset += blkid_partition_get_start(parent);
1043  *   </programlisting>
1044  * </informalexample>
1045
1046  * Returns: position (in bytes) of the partition table or -1 in case of error.
1047  *
1048  */
1049 blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
1050 {
1051         return tab ? tab->offset : -1;
1052 }
1053
1054 /**
1055  * blkid_partition_get_table:
1056  * @par: partition
1057  *
1058  * The "parttable" describes partition table. The table is usually the same for
1059  * all partitions -- except nested partition tables.
1060  *
1061  * For example bsd, solaris, etc. use a nested partition table within
1062  * standard primary dos partition:
1063  *
1064  * <informalexample>
1065  *   <programlisting>
1066  *
1067  *  -- dos partition table
1068  *  0: sda1     dos primary partition
1069  *  1: sda2     dos primary partition
1070  *     -- bsd partition table (with in sda2)
1071  *  2:    sda5  bds partition
1072  *  3:    sda6  bds partition
1073  *
1074  *   </programlisting>
1075  * </informalexample>
1076  *
1077  * The library does not to use a separate partition table object for dos logical
1078  * partitions (partitions within extended partition). It's possible to
1079  * differentiate between logical, extended and primary partitions by
1080  *
1081  *      blkid_partition_is_{extended,primary,logical}().
1082  *
1083  * Returns: partition table object or NULL in case of error.
1084  */
1085 blkid_parttable blkid_partition_get_table(blkid_partition par)
1086 {
1087         return par ? par->tab : NULL;
1088 }
1089
1090 static int partition_get_logical_type(blkid_partition par)
1091 {
1092         blkid_parttable tab;
1093
1094         if (!par)
1095                 return -1;
1096
1097         tab = blkid_partition_get_table(par);
1098         if (!tab || !tab->type)
1099                 return -1;
1100
1101         if (tab->parent)
1102                 return 'L';  /* report nested partitions as logical */
1103
1104         if (!strcmp(tab->type, "dos")) {
1105                 if (par->partno > 4)
1106                         return 'L';     /* logical */
1107
1108                 if(par->type == BLKID_DOS_EXTENDED_PARTITION ||
1109                    par->type == BLKID_W95_EXTENDED_PARTITION ||
1110                    par->type == BLKID_LINUX_EXTENDED_PARTITION)
1111                         return 'E';
1112         }
1113         return 'P';
1114 }
1115
1116 /**
1117  * blkid_partition_is_primary:
1118  * @par: partition
1119  *
1120  * Note, this function returns FALSE for DOS extended partitions and
1121  * all partitions in nested partition tables.
1122  *
1123  * Returns: 1 if the partitions is primary partition or 0 if not.
1124  */
1125 int blkid_partition_is_primary(blkid_partition par)
1126 {
1127         return partition_get_logical_type(par) == 'P' ? TRUE : FALSE;
1128 }
1129
1130 /**
1131  * blkid_partition_is_extended:
1132  * @par: partition
1133  *
1134  * Returns: 1 if the partitions is extended (dos, windows or linux)
1135  * partition or 0 if not.
1136  */
1137 int blkid_partition_is_extended(blkid_partition par)
1138 {
1139         return partition_get_logical_type(par) == 'E' ? TRUE : FALSE;
1140 }
1141
1142 /**
1143  * blkid_partition_is_logical:
1144  * @par: partition
1145  *
1146  * Note that this function returns TRUE for all partitions in all
1147  * nested partition tables (e.g. BSD labels).
1148  *
1149  * Returns: 1 if the partitions is logical partition or 0 if not.
1150  */
1151 int blkid_partition_is_logical(blkid_partition par)
1152 {
1153         return partition_get_logical_type(par) == 'L' ? TRUE : FALSE;
1154 }
1155
1156 static void set_string(unsigned char *item, size_t max,
1157                                 const unsigned char *data, size_t len)
1158 {
1159         if (len >= max)
1160                 len = max - 1;
1161
1162         memcpy(item, data, len);
1163         item[len] = '\0';
1164
1165         blkid_rtrim_whitespace(item);
1166 }
1167
1168 int blkid_partition_set_name(blkid_partition par,
1169                 const unsigned char *name, size_t len)
1170 {
1171         if (!par)
1172                 return -1;
1173
1174         set_string(par->name, sizeof(par->name), name, len);
1175         return 0;
1176 }
1177
1178 int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name,
1179                 size_t len, int enc)
1180 {
1181         if (!par)
1182                 return -1;
1183
1184         blkid_encode_to_utf8(enc, par->name, sizeof(par->name), name, len);
1185         blkid_rtrim_whitespace(par->name);
1186         return 0;
1187 }
1188
1189 int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid)
1190 {
1191         if (!par)
1192                 return -1;
1193
1194         blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid));
1195         return 0;
1196 }
1197
1198 /**
1199  * blkid_partition_get_name:
1200  * @par: partition
1201  *
1202  * Returns: partition name string if supported by PT (e.g. Mac) or NULL.
1203  */
1204 const char *blkid_partition_get_name(blkid_partition par)
1205 {
1206         return par && *par->name ? (char *) par->name : NULL;
1207 }
1208
1209 /**
1210  * blkid_partition_get_uuid:
1211  * @par: partition
1212  *
1213  * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL.
1214  */
1215 const char *blkid_partition_get_uuid(blkid_partition par)
1216 {
1217         return par && *par->uuid ? par->uuid : NULL;
1218 }
1219
1220 /**
1221  * blkid_partition_get_partno:
1222  * @par: partition
1223  *
1224  * Returns: proposed partitin number (e.g. 'N' from sda'N') or -1 in case of
1225  * error. Note that the number is generate by library independenly on your OS.
1226  */
1227 int blkid_partition_get_partno(blkid_partition par)
1228 {
1229         return par ? par->partno : -1;
1230 }
1231
1232 /**
1233  * blkid_partition_get_start:
1234  * @par: partition
1235  *
1236  * Be careful if you _not_ probe whole disk:
1237  *
1238  * 1) the offset is usully relative to begin of the disk -- but if you probe a
1239  *    fragment of the disk only -- then the offset could be still relative to
1240  *    the begin of the disk rather that relative to the fragment.
1241  *
1242  * 2) the offset for nested partitions could be releative to parent (e.g. Solaris)
1243  *    _or_ relative to the begin of the whole disk (e.g. bsd).
1244  *
1245  * You don't have to care about such details if you proble whole disk. In such
1246  * a case libblkid always returns the offset relative to the begin of the disk.
1247  *
1248  * Returns: start of the partition (in 512-sectors).
1249  */
1250 blkid_loff_t blkid_partition_get_start(blkid_partition par)
1251 {
1252         return par ? par->start : -1;
1253 }
1254
1255 /**
1256  * blkid_partition_get_size:
1257  * @par: partition
1258  *
1259  * WARNING: be very careful when you work with MS-DOS extended partitions. The
1260  *          library always returns full size of the partition. If you want add
1261  *          the partition to the Linux system (BLKPG_ADD_PARTITION ioctl) you
1262  *          need to reduce the size of the partition to 1 or 2 blocks. The
1263  *          rest of the partition has to be unaccessible for mkfs or mkswap
1264  *          programs, we need a small space for boot loaders only.
1265  *
1266  *          For some unknown reason this (safe) practice is not to used for
1267  *          nested BSD, Solaris, ..., partition tables in Linux kernel.
1268  *
1269  * Returns: size of the partition (in 512-sectors).
1270  */
1271 blkid_loff_t blkid_partition_get_size(blkid_partition par)
1272 {
1273         return par ? par->size : -1;
1274 }
1275
1276 /**
1277  * blkid_partition_get_type:
1278  * @par: partition
1279  *
1280  * Returns: partition type.
1281  */
1282 int blkid_partition_get_type(blkid_partition par)
1283 {
1284         return par ? par->type : 0;
1285 }
1286
1287 /* Sets partition 'type' for PT where the type is defined by string rather
1288  * than by number
1289  */
1290 int blkid_partition_set_type_string(blkid_partition par,
1291                 const unsigned char *type, size_t len)
1292 {
1293         if (!par)
1294                 return -1;
1295
1296         set_string((unsigned char *) par->typestr,
1297                         sizeof(par->typestr), type, len);
1298         return 0;
1299 }
1300
1301 /* Sets partition 'type' for PT where the type is defined by UUIDrather
1302  * than by number
1303  */
1304 int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid)
1305 {
1306         if (!par)
1307                 return -1;
1308
1309         blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr));
1310         return 0;
1311 }
1312
1313 /**
1314  * blkid_partition_get_type_string:
1315  * @par: partition
1316  *
1317  * The type string is supported by a small subset of partition tables (e.g Mac
1318  * and EFI GPT).  Note that GPT uses type UUID and this function returns this
1319  * UUID as string.
1320  *
1321  * Returns: partition type string or NULL.
1322  */
1323 const char *blkid_partition_get_type_string(blkid_partition par)
1324 {
1325         return par && *par->typestr ? par->typestr : NULL;
1326 }
1327
1328
1329 int blkid_partition_set_flags(blkid_partition par, unsigned long long flags)
1330 {
1331         if (!par)
1332                 return -1;
1333         par->flags = flags;
1334         return 0;
1335 }
1336
1337 /**
1338  * blkid_partition_get_flags
1339  * @par: partition
1340  *
1341  * Returns: partition flags (or attributes for gpt).
1342  */
1343 unsigned long long blkid_partition_get_flags(blkid_partition par)
1344 {
1345         return par ? par->flags : 0;
1346 }
1347