14 * @short_description: generic label independent partition abstraction
16 * The fdisk_partition provides label independent abstraction. The partitions
17 * are not directly connected with partition table (label) data. Any change to
18 * fdisk_partition does not affects in-memory or on-disk label data.
20 * The fdisk_partition is possible to use as a template for
21 * fdisk_add_partition() or fdisk_set_partition() operations.
24 static void init_partition(struct fdisk_partition
*pa
)
26 FDISK_INIT_UNDEF(pa
->size
);
27 FDISK_INIT_UNDEF(pa
->start
);
28 FDISK_INIT_UNDEF(pa
->partno
);
29 FDISK_INIT_UNDEF(pa
->parent_partno
);
30 FDISK_INIT_UNDEF(pa
->boot
);
32 INIT_LIST_HEAD(&pa
->parts
);
36 * fdisk_new_partition:
38 * Returns: new instance.
40 struct fdisk_partition
*fdisk_new_partition(void)
42 struct fdisk_partition
*pa
= calloc(1, sizeof(*pa
));
48 DBG(PART
, ul_debugobj(pa
, "alloc"));
53 * fdisk_reset_partition:
56 * Resets partition content.
58 void fdisk_reset_partition(struct fdisk_partition
*pa
)
65 DBG(PART
, ul_debugobj(pa
, "reset"));
68 fdisk_unref_parttype(pa
->type
);
78 memset(pa
, 0, sizeof(*pa
));
84 static struct fdisk_partition
*__copy_partition(struct fdisk_partition
*o
)
86 struct fdisk_partition
*n
= fdisk_new_partition();
92 memcpy(n
, o
, sizeof(*n
));
94 /* do not copy reference to lists, etc.*/
96 INIT_LIST_HEAD(&n
->parts
);
99 fdisk_ref_parttype(n
->type
);
101 /* note that strdup_between_structs() deallocates destination pointer,
102 * so make sure it's NULL as we call memcpy() before ... */
104 rc
= strdup_between_structs(n
, o
, name
);
108 rc
= strdup_between_structs(n
, o
, uuid
);
111 rc
= strdup_between_structs(n
, o
, attrs
);
114 rc
= strdup_between_structs(n
, o
, fstype
);
117 rc
= strdup_between_structs(n
, o
, fsuuid
);
120 rc
= strdup_between_structs(n
, o
, fslabel
);
123 rc
= strdup_between_structs(n
, o
, start_chs
);
126 rc
= strdup_between_structs(n
, o
, end_chs
);
129 fdisk_unref_partition(n
);
136 * fdisk_ref_partition:
137 * @pa: partition pointer
139 * Increments reference counter.
141 void fdisk_ref_partition(struct fdisk_partition
*pa
)
148 * fdisk_unref_partition:
149 * @pa: partition pointer
151 * Decrements reference counter, on zero the @pa is automatically
154 void fdisk_unref_partition(struct fdisk_partition
*pa
)
160 if (pa
->refcount
<= 0) {
161 list_del(&pa
->parts
);
162 fdisk_reset_partition(pa
);
163 DBG(PART
, ul_debugobj(pa
, "free"));
169 * fdisk_partition_set_start:
171 * @off: offset in sectors, maximal is UINT64_MAX-1
173 * Note that zero is valid offset too. Use fdisk_partition_unset_start() to
174 * undefine the offset.
176 * Returns: 0 on success, <0 on error.
178 int fdisk_partition_set_start(struct fdisk_partition
*pa
, fdisk_sector_t off
)
182 if (FDISK_IS_UNDEF(off
))
190 * fdisk_partition_unset_start:
193 * Sets the size as undefined. See fdisk_partition_has_start().
195 * Returns: 0 on success, <0 on error.
197 int fdisk_partition_unset_start(struct fdisk_partition
*pa
)
201 FDISK_INIT_UNDEF(pa
->start
);
207 * fdisk_partition_get_start:
210 * The zero is also valid offset. The function may return random undefined
211 * value when start offset is undefined (for example after
212 * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be
213 * sure that you work with valid numbers.
215 * Returns: start offset in sectors
217 fdisk_sector_t
fdisk_partition_get_start(struct fdisk_partition
*pa
)
223 * fdisk_partition_has_start:
228 int fdisk_partition_has_start(struct fdisk_partition
*pa
)
230 return pa
&& !FDISK_IS_UNDEF(pa
->start
);
235 * fdisk_partition_cmp_start:
239 * Compares partitions according to start offset, See fdisk_table_sort_partitions().
241 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
243 int fdisk_partition_cmp_start(struct fdisk_partition
*a
,
244 struct fdisk_partition
*b
)
246 int no_a
= FDISK_IS_UNDEF(a
->start
),
247 no_b
= FDISK_IS_UNDEF(b
->start
);
256 return cmp_numbers(a
->start
, b
->start
);
260 * fdisk_partition_start_follow_default
264 * When @pa is used as a template for fdisk_add_partition(), it follows the driver's default for
265 * the beginning of the partition. For DOS, it is the first usable space, while for GPT, it is
266 * the first sector of the largest area.
268 * Returns: 0 on success, <0 on error.
270 int fdisk_partition_start_follow_default(struct fdisk_partition
*pa
, int enable
)
274 pa
->start_follow_default
= enable
? 1 : 0;
279 * fdisk_partition_start_is_default:
282 * See fdisk_partition_start_follow_default().
284 * Returns: 1 if the partition follows default
286 int fdisk_partition_start_is_default(struct fdisk_partition
*pa
)
289 return pa
->start_follow_default
;
293 * fdisk_partition_set_size:
295 * @sz: size in sectors, maximal is UIN64_MAX-1
297 * Note that zero is valid size too. Use fdisk_partition_unset_size() to
300 * Returns: 0 on success, <0 on error.
302 int fdisk_partition_set_size(struct fdisk_partition
*pa
, fdisk_sector_t sz
)
306 if (FDISK_IS_UNDEF(sz
))
314 * fdisk_partition_unset_size:
317 * Sets the size as undefined. See fdisk_partition_has_size().
319 * Returns: 0 on success, <0 on error.
321 int fdisk_partition_unset_size(struct fdisk_partition
*pa
)
325 FDISK_INIT_UNDEF(pa
->size
);
331 * fdisk_partition_get_size:
334 * The zero is also valid size. The function may return random undefined
335 * value when size is undefined (for example after fdisk_partition_unset_size()).
336 * Always use fdisk_partition_has_size() to be sure that you work with valid
339 * Returns: size offset in sectors
341 fdisk_sector_t
fdisk_partition_get_size(struct fdisk_partition
*pa
)
347 * fdisk_partition_has_size:
352 int fdisk_partition_has_size(struct fdisk_partition
*pa
)
354 return pa
&& !FDISK_IS_UNDEF(pa
->size
);
358 * fdisk_partition_size_explicit:
362 * By default libfdisk aligns the size when add the new partition (by
363 * fdisk_add_partition()). If you want to disable this functionality use
366 * Returns: 0 on success, <0 on error.
368 int fdisk_partition_size_explicit(struct fdisk_partition
*pa
, int enable
)
372 pa
->size_explicit
= enable
? 1 : 0;
377 * fdisk_partition_set_partno:
379 * @num: partition number (0 is the first partition, maximal is SIZE_MAX-1)
381 * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to
382 * undefine the partno.
384 * Returns: 0 on success, <0 on error.
386 int fdisk_partition_set_partno(struct fdisk_partition
*pa
, size_t num
)
390 if (FDISK_IS_UNDEF(num
))
397 * fdisk_partition_unset_partno:
400 * Sets the partno as undefined. See fdisk_partition_has_partno().
402 * Returns: 0 on success, <0 on error.
404 int fdisk_partition_unset_partno(struct fdisk_partition
*pa
)
408 FDISK_INIT_UNDEF(pa
->partno
);
413 * fdisk_partition_get_partno:
416 * The zero is also valid partition number. The function may return random
417 * value when partno is undefined (for example after fdisk_partition_unset_partno()).
418 * Always use fdisk_partition_has_partno() to be sure that you work with valid
421 * Returns: partition number (0 is the first partition)
423 size_t fdisk_partition_get_partno(struct fdisk_partition
*pa
)
429 * fdisk_partition_has_partno:
434 int fdisk_partition_has_partno(struct fdisk_partition
*pa
)
436 return pa
&& !FDISK_IS_UNDEF(pa
->partno
);
441 * fdisk_partition_cmp_partno:
445 * Compares partitions according to partition number See fdisk_table_sort_partitions().
447 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
449 int fdisk_partition_cmp_partno(struct fdisk_partition
*a
,
450 struct fdisk_partition
*b
)
452 return a
->partno
- b
->partno
;
456 * fdisk_partition_partno_follow_default
460 * When @pa used as a template for fdisk_add_partition() when force label driver
461 * to add a new partition to the default (next) position.
463 * Returns: 0 on success, <0 on error.
465 int fdisk_partition_partno_follow_default(struct fdisk_partition
*pa
, int enable
)
469 pa
->partno_follow_default
= enable
? 1 : 0;
474 * fdisk_partition_set_type:
476 * @type: partition type
478 * Sets partition type.
480 * Returns: 0 on success, <0 on error.
482 int fdisk_partition_set_type(struct fdisk_partition
*pa
,
483 struct fdisk_parttype
*type
)
488 fdisk_ref_parttype(type
);
489 fdisk_unref_parttype(pa
->type
);
496 * fdisk_partition_get_type:
499 * Returns: pointer to partition type.
501 struct fdisk_parttype
*fdisk_partition_get_type(struct fdisk_partition
*pa
)
503 return pa
? pa
->type
: NULL
;
507 * fdisk_partition_set_name:
509 * @name: partition name
511 * Returns: 0 on success, <0 on error.
513 int fdisk_partition_set_name(struct fdisk_partition
*pa
, const char *name
)
517 return strdup_to_struct_member(pa
, name
, name
);
521 * fdisk_partition_get_name:
524 * Returns: partition name
526 const char *fdisk_partition_get_name(struct fdisk_partition
*pa
)
528 return pa
? pa
->name
: NULL
;
532 * fdisk_partition_set_uuid:
534 * @uuid: UUID of the partition
536 * Returns: 0 on success, <0 on error.
538 int fdisk_partition_set_uuid(struct fdisk_partition
*pa
, const char *uuid
)
542 return strdup_to_struct_member(pa
, uuid
, uuid
);
546 * fdisk_partition_has_end:
549 * Returns: 1 if the partition has defined last sector
551 int fdisk_partition_has_end(struct fdisk_partition
*pa
)
553 return pa
&& !FDISK_IS_UNDEF(pa
->start
) && !FDISK_IS_UNDEF(pa
->size
);
557 * fdisk_partition_get_end:
560 * This function may returns absolute non-sense, always check
561 * fdisk_partition_has_end().
563 * Note that partition end is defined by fdisk_partition_set_start() and
564 * fdisk_partition_set_size().
566 * Returns: last partition sector LBA.
568 fdisk_sector_t
fdisk_partition_get_end(struct fdisk_partition
*pa
)
570 return pa
->start
+ pa
->size
- (pa
->size
== 0 ? 0 : 1);
574 * fdisk_partition_end_follow_default
578 * When @pa used as a template for fdisk_add_partition() when force label
579 * driver to use all the possible space for the new partition.
581 * Returns: 0 on success, <0 on error.
583 int fdisk_partition_end_follow_default(struct fdisk_partition
*pa
, int enable
)
587 pa
->end_follow_default
= enable
? 1 : 0;
592 * fdisk_partition_end_is_default:
595 * Returns: 1 if the partition follows default
597 int fdisk_partition_end_is_default(struct fdisk_partition
*pa
)
600 return pa
->end_follow_default
;
604 * fdisk_partition_get_uuid:
607 * Returns: partition UUID as string
609 const char *fdisk_partition_get_uuid(struct fdisk_partition
*pa
)
611 return pa
? pa
->uuid
: NULL
;
615 * fdisk_partition_get_attrs:
618 * Returns: partition attributes in string format
620 const char *fdisk_partition_get_attrs(struct fdisk_partition
*pa
)
622 return pa
? pa
->attrs
: NULL
;
626 * fdisk_partition_set_attrs:
630 * Sets @attrs to @pa.
632 * Return: 0 on success, <0 on error.
634 int fdisk_partition_set_attrs(struct fdisk_partition
*pa
, const char *attrs
)
638 return strdup_to_struct_member(pa
, attrs
, attrs
);
642 * fdisk_partition_is_nested:
645 * Returns: 1 if the partition is nested (e.g. MBR logical partition)
647 int fdisk_partition_is_nested(struct fdisk_partition
*pa
)
649 return pa
&& !FDISK_IS_UNDEF(pa
->parent_partno
);
653 * fdisk_partition_is_container:
656 * Returns: 1 if the partition is container (e.g. MBR extended partition)
658 int fdisk_partition_is_container(struct fdisk_partition
*pa
)
660 return pa
&& pa
->container
;
664 * fdisk_partition_get_parent:
666 * @parent: parent parno
668 * Returns: returns devno of the parent
670 int fdisk_partition_get_parent(struct fdisk_partition
*pa
, size_t *parent
)
673 *parent
= pa
->parent_partno
;
680 * fdisk_partition_is_used:
683 * Returns: 1 if the partition points to some area
685 int fdisk_partition_is_used(struct fdisk_partition
*pa
)
687 return pa
&& pa
->used
;
691 * fdisk_partition_is_bootable:
694 * Returns: 1 if the partition has enabled boot flag
696 int fdisk_partition_is_bootable(struct fdisk_partition
*pa
)
698 return pa
&& pa
->boot
== 1;
702 * fdisk_partition_is_freespace:
705 * Returns: 1 if @pa points to freespace
707 int fdisk_partition_is_freespace(struct fdisk_partition
*pa
)
709 return pa
&& pa
->freespace
;
713 * fdisk_partition_is_wholedisk:
716 * Returns: 1 if the partition is special whole-disk (e.g. SUN) partition
718 int fdisk_partition_is_wholedisk(struct fdisk_partition
*pa
)
720 return pa
&& pa
->wholedisk
;
724 * fdisk_partition_next_partno:
727 * @n: returns partition number
729 * If @pa specified and partno-follow-default (see fdisk_partition_partno_follow_default())
730 * enabled then returns next expected partno or -ERANGE on error.
732 * If @pa is NULL, or @pa does not specify any semantic for the next partno
733 * then use Ask API to ask user for the next partno. In this case returns 1 if
734 * no free partition available. If fdisk dialogs are disabled then returns -EINVAL.
736 * Returns: 0 on success, <0 on error, or 1 for non-free partno by Ask API.
738 int fdisk_partition_next_partno(
739 struct fdisk_partition
*pa
,
740 struct fdisk_context
*cxt
,
746 if (pa
&& pa
->partno_follow_default
) {
749 DBG(PART
, ul_debugobj(pa
, "next partno (follow default)"));
751 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
752 if (!fdisk_is_partition_used(cxt
, i
)) {
761 if (pa
&& fdisk_partition_has_partno(pa
)) {
763 DBG(PART
, ul_debugobj(pa
, "next partno (specified=%zu)", pa
->partno
));
765 if (pa
->partno
>= cxt
->label
->nparts_max
||
766 fdisk_is_partition_used(cxt
, pa
->partno
))
773 if (fdisk_has_dialogs(cxt
))
774 return fdisk_ask_partnum(cxt
, n
, 1);
779 static int probe_partition_content(struct fdisk_context
*cxt
, struct fdisk_partition
*pa
)
781 int rc
= 1; /* nothing */
783 DBG(PART
, ul_debugobj(pa
, "start probe #%zu partition [cxt %p] >>>", pa
->partno
, cxt
));
785 /* zeroize the current setting */
786 strdup_to_struct_member(pa
, fstype
, NULL
);
787 strdup_to_struct_member(pa
, fsuuid
, NULL
);
788 strdup_to_struct_member(pa
, fslabel
, NULL
);
790 if (!fdisk_partition_has_start(pa
) ||
791 !fdisk_partition_has_size(pa
))
796 uintmax_t start
, size
;
798 blkid_probe pr
= blkid_new_probe();
802 DBG(PART
, ul_debugobj(pa
, "blkid prober: %p", pr
));
804 blkid_probe_enable_superblocks(pr
, 1);
805 blkid_probe_set_superblocks_flags(pr
,
810 BLKID_SUBLKS_BADCSUM
);
812 start
= fdisk_partition_get_start(pa
) * fdisk_get_sector_size(cxt
);
813 size
= fdisk_partition_get_size(pa
) * fdisk_get_sector_size(cxt
);
815 if (blkid_probe_set_device(pr
, cxt
->dev_fd
, start
, size
) == 0
816 && blkid_do_fullprobe(pr
) == 0) {
821 if (!blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
))
822 rc
= strdup_to_struct_member(pa
, fstype
, data
);
824 if (!rc
&& !blkid_probe_lookup_value(pr
, "LABEL", &data
, NULL
))
825 rc
= strdup_to_struct_member(pa
, fslabel
, data
);
827 if (!rc
&& !blkid_probe_lookup_value(pr
, "UUID", &data
, NULL
))
828 rc
= strdup_to_struct_member(pa
, fsuuid
, data
);
831 blkid_free_probe(pr
);
834 #endif /* HAVE_LIBBLKID */
837 DBG(PART
, ul_debugobj(pa
, "<<< end probe #%zu partition[cxt %p, rc=%d]", pa
->partno
, cxt
, rc
));
842 * fdisk_partition_to_string:
845 * @id: field (FDISK_FIELD_*)
846 * @data: returns string with allocated data
848 * Returns info about partition converted to printable string.
853 * struct fdisk_partition *pa;
855 * fdisk_get_partition(cxt, 0, &pa);
856 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
857 * printf("first partition uuid: %s\n", data);
859 * fdisk_unref_partition(pa);
863 * returns UUID for the first partition.
865 * Returns: 0 on success, otherwise, a corresponding error.
867 int fdisk_partition_to_string(struct fdisk_partition
*pa
,
868 struct fdisk_context
*cxt
,
876 if (!pa
|| !cxt
|| !data
)
880 case FDISK_FIELD_DEVICE
:
882 p
= strdup(_("Free space"));
883 else if (fdisk_partition_has_partno(pa
) && cxt
->dev_path
) {
884 if (cxt
->label
->flags
& FDISK_LABEL_FL_INCHARS_PARTNO
)
885 rc
= asprintf(&p
, "%c", (int) pa
->partno
+ 'a');
887 p
= fdisk_partname(cxt
->dev_path
, pa
->partno
+ 1);
890 case FDISK_FIELD_BOOT
:
891 p
= fdisk_partition_is_bootable(pa
) ? strdup("*") : NULL
;
893 case FDISK_FIELD_START
:
894 if (fdisk_partition_has_start(pa
)) {
895 x
= fdisk_cround(cxt
, pa
->start
);
896 rc
= pa
->start_post
?
897 asprintf(&p
, "%"PRIu64
"%c", x
, pa
->start_post
) :
898 asprintf(&p
, "%"PRIu64
, x
);
901 case FDISK_FIELD_END
:
902 if (fdisk_partition_has_end(pa
)) {
903 x
= fdisk_cround(cxt
, fdisk_partition_get_end(pa
));
905 asprintf(&p
, "%"PRIu64
"%c", x
, pa
->end_post
) :
906 asprintf(&p
, "%"PRIu64
, x
);
909 case FDISK_FIELD_SIZE
:
910 if (fdisk_partition_has_size(pa
)) {
911 uint64_t sz
= pa
->size
* cxt
->sector_size
;
913 switch (cxt
->sizeunit
) {
914 case FDISK_SIZEUNIT_BYTES
:
915 rc
= asprintf(&p
, "%"PRIu64
"", sz
);
917 case FDISK_SIZEUNIT_HUMAN
:
918 if (fdisk_is_details(cxt
))
920 asprintf(&p
, "%"PRIu64
"%c", sz
, pa
->size_post
) :
921 asprintf(&p
, "%"PRIu64
, sz
);
923 p
= size_to_human_string(SIZE_SUFFIX_1LETTER
, sz
);
931 case FDISK_FIELD_CYLINDERS
:
933 uintmax_t sz
= fdisk_partition_has_size(pa
) ? pa
->size
: 0;
935 /* Why we need to cast that to uintmax_t? */
936 rc
= asprintf(&p
, "%ju", (uintmax_t)(sz
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
)) + 1);
939 case FDISK_FIELD_SECTORS
:
940 rc
= asprintf(&p
, "%ju",
941 fdisk_partition_has_size(pa
) ? (uintmax_t) pa
->size
: 0);
943 case FDISK_FIELD_BSIZE
:
944 rc
= asprintf(&p
, "%"PRIu64
, pa
->bsize
);
946 case FDISK_FIELD_FSIZE
:
947 rc
= asprintf(&p
, "%"PRIu64
, pa
->fsize
);
949 case FDISK_FIELD_CPG
:
950 rc
= asprintf(&p
, "%"PRIu64
, pa
->cpg
);
952 case FDISK_FIELD_TYPE
:
953 p
= pa
->type
&& pa
->type
->name
? strdup(_(pa
->type
->name
)) : NULL
;
955 case FDISK_FIELD_TYPEID
:
956 if (pa
->type
&& fdisk_parttype_get_string(pa
->type
))
957 rc
= asprintf(&p
, "%s", fdisk_parttype_get_string(pa
->type
));
959 rc
= asprintf(&p
, "%x", fdisk_parttype_get_code(pa
->type
));
961 case FDISK_FIELD_UUID
:
962 p
= pa
->uuid
&& *pa
->uuid
? strdup(pa
->uuid
) : NULL
;
964 case FDISK_FIELD_NAME
:
965 p
= pa
->name
&& *pa
->name
? strdup(pa
->name
) : NULL
;
967 case FDISK_FIELD_ATTR
:
968 p
= pa
->attrs
&& *pa
->attrs
? strdup(pa
->attrs
) : NULL
;
970 case FDISK_FIELD_SADDR
:
971 p
= pa
->start_chs
&& *pa
->start_chs
? strdup(pa
->start_chs
) : NULL
;
973 case FDISK_FIELD_EADDR
:
974 p
= pa
->end_chs
&& *pa
->end_chs
? strdup(pa
->end_chs
) : NULL
;
976 case FDISK_FIELD_FSUUID
:
977 if (pa
->fs_probed
|| probe_partition_content(cxt
, pa
) == 0)
978 p
= pa
->fsuuid
&& *pa
->fsuuid
? strdup(pa
->fsuuid
) : NULL
;
980 case FDISK_FIELD_FSLABEL
:
981 if (pa
->fs_probed
|| probe_partition_content(cxt
, pa
) == 0)
982 p
= pa
->fslabel
&& *pa
->fslabel
? strdup(pa
->fslabel
) : NULL
;
984 case FDISK_FIELD_FSTYPE
:
985 if (pa
->fs_probed
|| probe_partition_content(cxt
, pa
) == 0)
986 p
= pa
->fstype
&& *pa
->fstype
? strdup(pa
->fstype
) : NULL
;
1007 * fdisk_get_partition:
1009 * @partno: partition number (0 is the first partition)
1010 * @pa: returns data about partition
1012 * Reads disklabel and fills in @pa with data about partition @n.
1014 * Note that partno may address unused partition and then this function does
1015 * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to
1016 * NULL then the function allocates a newly allocated fdisk_partition struct,
1017 * use fdisk_unref_partition() to deallocate.
1019 * Returns: 0 on success, otherwise, a corresponding error.
1021 int fdisk_get_partition(struct fdisk_context
*cxt
, size_t partno
,
1022 struct fdisk_partition
**pa
)
1025 struct fdisk_partition
*np
= NULL
;
1027 if (!cxt
|| !cxt
->label
|| !pa
)
1029 if (!cxt
->label
->op
->get_part
)
1031 if (!fdisk_is_partition_used(cxt
, partno
))
1035 np
= *pa
= fdisk_new_partition();
1039 fdisk_reset_partition(*pa
);
1041 (*pa
)->partno
= partno
;
1042 rc
= cxt
->label
->op
->get_part(cxt
, partno
, *pa
);
1046 fdisk_unref_partition(np
);
1049 fdisk_reset_partition(*pa
);
1051 (*pa
)->size_explicit
= 1;
1055 static struct fdisk_partition
*area_by_offset(
1056 struct fdisk_table
*tb
,
1057 struct fdisk_partition
*cur
,
1060 struct fdisk_partition
*pa
= NULL
;
1061 struct fdisk_iter itr
;
1063 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
1065 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
1066 if (!fdisk_partition_has_start(pa
) || !fdisk_partition_has_size(pa
))
1068 if (fdisk_partition_is_nested(cur
) &&
1069 pa
->parent_partno
!= cur
->parent_partno
)
1071 if (off
>= pa
->start
&& off
< pa
->start
+ pa
->size
)
1078 static int resize_get_first_possible(
1079 struct fdisk_table
*tb
,
1080 struct fdisk_partition
*cur
,
1081 fdisk_sector_t
*start
)
1083 struct fdisk_partition
*pa
= NULL
, *first
= NULL
;
1084 struct fdisk_iter itr
;
1086 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
1089 DBG(TAB
, ul_debugobj(tb
, "checking first possible before start=%ju", (uintmax_t) cur
->start
));
1092 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
1094 if (pa
->start
> cur
->start
|| pa
== cur
)
1097 DBG(TAB
, ul_debugobj(tb
, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]",
1099 fdisk_partition_get_partno(pa
),
1100 (uintmax_t) fdisk_partition_get_start(pa
),
1101 (uintmax_t) fdisk_partition_get_end(pa
),
1102 (uintmax_t) fdisk_partition_get_size(pa
),
1103 fdisk_partition_is_freespace(pa
) ? " freespace" : "",
1104 fdisk_partition_is_nested(pa
) ? " nested" : "",
1105 fdisk_partition_is_container(pa
) ? " container" : ""));
1108 if (!fdisk_partition_is_freespace(pa
)) {
1109 DBG(TAB
, ul_debugobj(tb
, " ignored (no freespace)"));
1113 if (!fdisk_partition_has_start(pa
) || !fdisk_partition_has_size(pa
)) {
1114 DBG(TAB
, ul_debugobj(tb
, " ignored (no start/size)"));
1118 /* The current is nested, free space has to be nested within the same parent */
1119 if (fdisk_partition_is_nested(cur
)
1120 && pa
->parent_partno
!= cur
->parent_partno
) {
1121 DBG(TAB
, ul_debugobj(tb
, " ignore (nested required)"));
1125 if (pa
->start
+ pa
->size
<= cur
->start
) {
1127 DBG(TAB
, ul_debugobj(tb
, " entry usable"));
1132 *start
= first
->start
;
1134 DBG(PART
, ul_debugobj(cur
, "resize: nothing usable before %ju", (uintmax_t) cur
->start
));
1136 return first
? 0 : -1;
1140 * Verify that area addressed by @start is freespace or the @cur[rent]
1141 * partition and continue to the next table entries until it's freespace, and
1142 * counts size of all this space.
1144 * This is core of the partition start offset move operation. We can move the
1145 * start within the current partition to another free space. It's
1146 * forbidden to move start of the partition to another already defined
1149 static int resize_get_last_possible(
1150 struct fdisk_table
*tb
,
1151 struct fdisk_partition
*cur
,
1152 fdisk_sector_t start
,
1153 fdisk_sector_t
*maxsz
)
1155 struct fdisk_partition
*pa
= NULL
, *last
= NULL
;
1156 struct fdisk_iter itr
;
1158 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
1161 DBG(TAB
, ul_debugobj(tb
, "checking last possible for start=%ju", (uintmax_t) start
));
1164 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
1166 DBG(TAB
, ul_debugobj(tb
, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]",
1168 fdisk_partition_get_partno(pa
),
1169 (uintmax_t) fdisk_partition_get_start(pa
),
1170 (uintmax_t) fdisk_partition_get_end(pa
),
1171 (uintmax_t) fdisk_partition_get_size(pa
),
1172 fdisk_partition_is_freespace(pa
) ? " freespace" : "",
1173 fdisk_partition_is_nested(pa
) ? " nested" : "",
1174 fdisk_partition_is_container(pa
) ? " container" : ""));
1176 if (!fdisk_partition_has_start(pa
) ||
1177 !fdisk_partition_has_size(pa
) ||
1178 (fdisk_partition_is_container(pa
) && pa
!= cur
)) {
1179 DBG(TAB
, ul_debugobj(tb
, " ignored (no start/size or container)"));
1183 if (fdisk_partition_is_nested(pa
)
1184 && fdisk_partition_is_container(cur
)
1185 && pa
->parent_partno
== cur
->partno
) {
1186 DBG(TAB
, ul_debugobj(tb
, " ignore (nested child of the current partition)"));
1190 /* The current is nested, free space has to be nested within the same parent */
1191 if (fdisk_partition_is_nested(cur
)
1192 && pa
->parent_partno
!= cur
->parent_partno
) {
1193 DBG(TAB
, ul_debugobj(tb
, " ignore (nested required)"));
1198 if (start
>= pa
->start
&& start
< pa
->start
+ pa
->size
) {
1199 if (fdisk_partition_is_freespace(pa
) || pa
== cur
) {
1200 DBG(TAB
, ul_debugobj(tb
, " accepted as last"));
1203 DBG(TAB
, ul_debugobj(tb
, " failed to set last"));
1208 *maxsz
= pa
->size
- (start
- pa
->start
);
1209 DBG(TAB
, ul_debugobj(tb
, " new max=%ju", (uintmax_t) *maxsz
));
1211 } else if (!fdisk_partition_is_freespace(pa
) && pa
!= cur
) {
1212 DBG(TAB
, ul_debugobj(tb
, " no free space behind current"));
1216 *maxsz
= pa
->size
- (start
- pa
->start
);
1217 DBG(TAB
, ul_debugobj(tb
, " new max=%ju (last updated)", (uintmax_t) *maxsz
));
1222 DBG(PART
, ul_debugobj(cur
, "resize: max size=%ju", (uintmax_t) *maxsz
));
1224 DBG(PART
, ul_debugobj(cur
, "resize: nothing usable after %ju", (uintmax_t) start
));
1226 return last
? 0 : -1;
1230 * Uses template @tpl to recount start and size change of the partition @res. The
1231 * @tpl->size and @tpl->start are interpreted as relative to the current setting.
1233 static int recount_resize(
1234 struct fdisk_context
*cxt
, size_t partno
,
1235 struct fdisk_partition
*res
, struct fdisk_partition
*tpl
)
1237 fdisk_sector_t start
, size
, xsize
;
1238 struct fdisk_partition
*cur
= NULL
;
1239 struct fdisk_table
*tb
= NULL
;
1242 DBG(PART
, ul_debugobj(tpl
, ">>> resize requested"));
1244 FDISK_INIT_UNDEF(start
);
1245 FDISK_INIT_UNDEF(size
);
1247 rc
= fdisk_get_partitions(cxt
, &tb
);
1249 /* For resize we do not follow grain to detect free-space, but
1250 * we support to resize with very small granulation. */
1251 unsigned long org
= cxt
->grain
;
1253 cxt
->grain
= cxt
->sector_size
;
1254 rc
= fdisk_get_freespaces(cxt
, &tb
);
1258 fdisk_unref_table(tb
);
1262 fdisk_table_sort_partitions(tb
, fdisk_partition_cmp_start
);
1264 DBG(PART
, ul_debugobj(tpl
, "resize partition partno=%zu in table:", partno
));
1265 ON_DBG(PART
, fdisk_debug_print_table(tb
));
1267 cur
= fdisk_table_get_partition_by_partno(tb
, partno
);
1269 fdisk_unref_table(tb
);
1273 /* 1a) set new start - change relative to the current on-disk setting */
1274 if (tpl
->movestart
&& fdisk_partition_has_start(tpl
)) {
1275 start
= fdisk_partition_get_start(cur
);
1276 if (tpl
->movestart
== FDISK_MOVE_DOWN
) {
1277 if (fdisk_partition_get_start(tpl
) > start
)
1279 start
-= fdisk_partition_get_start(tpl
);
1281 start
+= fdisk_partition_get_start(tpl
);
1283 DBG(PART
, ul_debugobj(tpl
, "resize: moving start %s relative, new start: %ju",
1284 tpl
->movestart
== FDISK_MOVE_DOWN
? "DOWN" : "UP", (uintmax_t)start
));
1286 /* 1b) set new start - try freespace before the current partition */
1287 } else if (tpl
->movestart
== FDISK_MOVE_DOWN
) {
1289 if (resize_get_first_possible(tb
, cur
, &start
) != 0)
1292 DBG(PART
, ul_debugobj(tpl
, "resize: moving start DOWN (first possible), new start: %ju",
1295 /* 1c) set new start - absolute number */
1296 } else if (fdisk_partition_has_start(tpl
)) {
1297 start
= fdisk_partition_get_start(tpl
);
1298 DBG(PART
, ul_debugobj(tpl
, "resize: moving start to absolute offset: %ju",
1302 /* 2) verify that start is within the current partition or any freespace area */
1303 if (!FDISK_IS_UNDEF(start
)) {
1304 struct fdisk_partition
*area
= area_by_offset(tb
, cur
, start
);
1307 DBG(PART
, ul_debugobj(tpl
, "resize: start points to the current partition"));
1308 else if (area
&& fdisk_partition_is_freespace(area
))
1309 DBG(PART
, ul_debugobj(tpl
, "resize: start points to freespace"));
1310 else if (!area
&& start
>= cxt
->first_lba
&& start
< cxt
->first_lba
+ (cxt
->grain
/ cxt
->sector_size
))
1311 DBG(PART
, ul_debugobj(tpl
, "resize: start points before first partition"));
1313 DBG(PART
, ul_debugobj(tpl
, "resize: start verification failed"));
1317 /* no change, start points to the current partition */
1318 DBG(PART
, ul_debugobj(tpl
, "resize: start unchanged"));
1319 start
= fdisk_partition_get_start(cur
);
1322 /* 3a) set new size -- reduce */
1323 if (tpl
->resize
== FDISK_RESIZE_REDUCE
&& fdisk_partition_has_size(tpl
)) {
1324 DBG(PART
, ul_debugobj(tpl
, "resize: reduce"));
1325 size
= fdisk_partition_get_size(cur
);
1326 if (fdisk_partition_get_size(tpl
) > size
)
1328 size
-= fdisk_partition_get_size(tpl
);
1330 /* 3b) set new size -- enlarge */
1331 } else if (tpl
->resize
== FDISK_RESIZE_ENLARGE
&& fdisk_partition_has_size(tpl
)) {
1332 DBG(PART
, ul_debugobj(tpl
, "resize: enlarge"));
1333 size
= fdisk_partition_get_size(cur
);
1334 size
+= fdisk_partition_get_size(tpl
);
1336 /* 3c) set new size -- no size specified, enlarge to all freespace */
1337 } else if (tpl
->resize
== FDISK_RESIZE_ENLARGE
) {
1338 DBG(PART
, ul_debugobj(tpl
, "resize: enlarge to all possible"));
1339 if (resize_get_last_possible(tb
, cur
, start
, &size
))
1342 /* 3d) set new size -- absolute number */
1343 } else if (fdisk_partition_has_size(tpl
)) {
1344 DBG(PART
, ul_debugobj(tpl
, "resize: new absolute size"));
1345 size
= fdisk_partition_get_size(tpl
);
1348 /* 4) verify that size is within the current partition or next free space */
1349 xsize
= !FDISK_IS_UNDEF(size
) ? size
: fdisk_partition_get_size(cur
);
1351 if (fdisk_partition_has_size(cur
)) {
1352 fdisk_sector_t maxsz
;
1354 if (resize_get_last_possible(tb
, cur
, start
, &maxsz
))
1356 DBG(PART
, ul_debugobj(tpl
, "resize: size=%ju, max=%ju",
1357 (uintmax_t) xsize
, (uintmax_t) maxsz
));
1362 if (FDISK_IS_UNDEF(size
)) {
1363 DBG(PART
, ul_debugobj(tpl
, "resize: size unchanged (undefined)"));
1367 DBG(PART
, ul_debugobj(tpl
, "<<< resize: SUCCESS: start %ju->%ju; size %ju->%ju",
1368 (uintmax_t) fdisk_partition_get_start(cur
), (uintmax_t) start
,
1369 (uintmax_t) fdisk_partition_get_size(cur
), (uintmax_t) size
));
1372 fdisk_unref_table(tb
);
1375 DBG(PART
, ul_debugobj(tpl
, "<<< resize: FAILED"));
1376 fdisk_warnx(cxt
, _("Failed to resize partition #%zu."), partno
+ 1);
1377 fdisk_unref_table(tb
);
1383 * fdisk_set_partition:
1385 * @partno: partition number (0 is the first partition)
1386 * @pa: new partition setting
1388 * Modifies disklabel according to setting with in @pa.
1390 * Returns: 0 on success, <0 on error.
1392 int fdisk_set_partition(struct fdisk_context
*cxt
, size_t partno
,
1393 struct fdisk_partition
*pa
)
1395 struct fdisk_partition
*xpa
= pa
, *tmp
= NULL
;
1398 if (!cxt
|| !cxt
->label
|| !pa
)
1400 if (!cxt
->label
->op
->set_part
)
1405 if (!fdisk_is_partition_used(cxt
, partno
)) {
1406 pa
->partno
= partno
;
1407 return fdisk_add_partition(cxt
, pa
, NULL
);
1410 if (pa
->resize
|| pa
->movestart
1411 || fdisk_partition_has_start(pa
) || fdisk_partition_has_size(pa
)) {
1412 xpa
= __copy_partition(pa
);
1419 FDISK_INIT_UNDEF(xpa
->size
);
1420 FDISK_INIT_UNDEF(xpa
->start
);
1422 rc
= recount_resize(cxt
, partno
, xpa
, pa
);
1427 DBG(CXT
, ul_debugobj(cxt
, "setting partition %zu %p (start=%ju, end=%ju, size=%ju)",
1429 (uintmax_t) fdisk_partition_get_start(xpa
),
1430 (uintmax_t) fdisk_partition_get_end(xpa
),
1431 (uintmax_t) fdisk_partition_get_size(xpa
)));
1433 /* disable wipe for old offset/size setting */
1434 if (fdisk_get_partition(cxt
, partno
, &tmp
) == 0 && tmp
) {
1435 wipe
= fdisk_set_wipe_area(cxt
, fdisk_partition_get_start(tmp
),
1436 fdisk_partition_get_size(tmp
), FALSE
);
1437 fdisk_unref_partition(tmp
);
1440 /* call label driver */
1441 rc
= cxt
->label
->op
->set_part(cxt
, partno
, xpa
);
1443 /* enable wipe for new offset/size */
1445 fdisk_wipe_partition(cxt
, partno
, TRUE
);
1447 DBG(CXT
, ul_debugobj(cxt
, "set_partition() rc=%d", rc
));
1449 fdisk_unref_partition(xpa
);
1454 * fdisk_wipe_partition:
1455 * @cxt: fdisk context
1456 * @partno: partition number
1459 * Enable/disable filesystems/RAIDs wiping in area defined by partition start and size.
1461 * Returns: <0 in case of error, 0 on success
1464 int fdisk_wipe_partition(struct fdisk_context
*cxt
, size_t partno
, int enable
)
1466 struct fdisk_partition
*pa
= NULL
;
1469 rc
= fdisk_get_partition(cxt
, partno
, &pa
);
1473 rc
= fdisk_set_wipe_area(cxt
, fdisk_partition_get_start(pa
),
1474 fdisk_partition_get_size(pa
), enable
);
1475 fdisk_unref_partition(pa
);
1476 return rc
< 0 ? rc
: 0;
1480 * fdisk_partition_has_wipe:
1481 * @cxt: fdisk context
1486 * Returns: 1 if the area specified by @pa will be wiped by write command, or 0.
1488 int fdisk_partition_has_wipe(struct fdisk_context
*cxt
, struct fdisk_partition
*pa
)
1490 return fdisk_has_wipe_area(cxt
, fdisk_partition_get_start(pa
),
1491 fdisk_partition_get_size(pa
));
1496 * fdisk_add_partition:
1497 * @cxt: fdisk context
1498 * @pa: template for the partition (or NULL)
1499 * @partno: NULL or returns new partition number
1501 * If @pa is not specified or any @pa item is missing the libfdisk will ask by
1504 * The @pa template is important for non-interactive partitioning,
1505 * especially for MBR where is necessary to differentiate between
1506 * primary/logical; this is done by start offset or/and partno.
1507 * The rules for MBR:
1509 * A) template specifies start within extended partition: add logical
1510 * B) template specifies start out of extended partition: add primary
1511 * C) template specifies start (or default), partno < 4: add primary
1512 * D) template specifies default start, partno >= 4: add logical
1514 * otherwise MBR driver uses Ask-API to get missing information.
1516 * Adds a new partition to disklabel.
1518 * Returns: 0 on success, <0 on error.
1520 int fdisk_add_partition(struct fdisk_context
*cxt
,
1521 struct fdisk_partition
*pa
,
1526 if (!cxt
|| !cxt
->label
)
1528 if (!cxt
->label
->op
->add_part
)
1530 if (fdisk_missing_geometry(cxt
))
1535 DBG(CXT
, ul_debugobj(cxt
, "adding new partition %p", pa
));
1536 if (fdisk_partition_has_start(pa
))
1537 DBG(CXT
, ul_debugobj(cxt
, " start: %ju", (uintmax_t) fdisk_partition_get_start(pa
)));
1538 if (fdisk_partition_has_end(pa
))
1539 DBG(CXT
, ul_debugobj(cxt
, " end: %ju", (uintmax_t) fdisk_partition_get_end(pa
)));
1540 if (fdisk_partition_has_size(pa
))
1541 DBG(CXT
, ul_debugobj(cxt
, " size: %ju", (uintmax_t) fdisk_partition_get_size(pa
)));
1543 DBG(CXT
, ul_debugobj(cxt
, " defaults: start=%s, end=%s, partno=%s",
1544 pa
->start_follow_default
? "yes" : "no",
1545 pa
->end_follow_default
? "yes" : "no",
1546 pa
->partno_follow_default
? "yes" : "no"));
1548 DBG(CXT
, ul_debugobj(cxt
, "adding partition"));
1550 rc
= cxt
->label
->op
->add_part(cxt
, pa
, partno
);
1552 DBG(CXT
, ul_debugobj(cxt
, "add partition done (rc=%d)", rc
));
1557 * fdisk_delete_partition:
1558 * @cxt: fdisk context
1559 * @partno: partition number to delete (0 is the first partition)
1561 * Deletes a @partno partition from disklabel.
1563 * Returns: 0 on success, <0 on error
1565 int fdisk_delete_partition(struct fdisk_context
*cxt
, size_t partno
)
1567 if (!cxt
|| !cxt
->label
)
1569 if (!cxt
->label
->op
->del_part
)
1572 fdisk_wipe_partition(cxt
, partno
, 0);
1574 DBG(CXT
, ul_debugobj(cxt
, "deleting %s partition number %zd",
1575 cxt
->label
->name
, partno
));
1576 return cxt
->label
->op
->del_part(cxt
, partno
);
1580 * fdisk_delete_all_partitions:
1581 * @cxt: fdisk context
1583 * Delete all used partitions from disklabel.
1585 * Returns: 0 on success, otherwise, a corresponding error.
1587 int fdisk_delete_all_partitions(struct fdisk_context
*cxt
)
1592 if (!cxt
|| !cxt
->label
)
1595 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
1597 if (!fdisk_is_partition_used(cxt
, i
))
1599 rc
= fdisk_delete_partition(cxt
, i
);
1608 * fdisk_is_partition_used:
1610 * @n: partition number (0 is the first partition)
1612 * Check if the partition number @n is used by partition table. This function
1613 * does not check if the device is used (e.g. mounted) by system!
1615 * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
1619 int fdisk_is_partition_used(struct fdisk_context
*cxt
, size_t n
)
1621 if (!cxt
|| !cxt
->label
)
1623 if (!cxt
->label
->op
->part_is_used
)
1626 return cxt
->label
->op
->part_is_used(cxt
, n
);
1631 * fdisk_partition_max_size:
1633 * @n: partition number (0 is the first partition)
1634 * @maxsz: returns maximum size of partition
1636 * Find maximum size the partition can be resized to.
1637 * Takes into account free space between this partition and the next one.
1639 * Returns: 0 on success, <0 on error.
1641 int fdisk_partition_get_max_size(struct fdisk_context
*cxt
, size_t n
,
1642 fdisk_sector_t
*maxsz
)
1644 struct fdisk_partition
*cur
= NULL
;
1645 struct fdisk_table
*tb
= NULL
;
1648 rc
= fdisk_get_partitions(cxt
, &tb
);
1652 rc
= fdisk_get_freespaces(cxt
, &tb
);
1656 rc
= fdisk_table_sort_partitions(tb
, fdisk_partition_cmp_start
);
1660 cur
= fdisk_table_get_partition_by_partno(tb
, n
);
1664 if (!fdisk_partition_has_start(cur
))
1667 if (resize_get_last_possible(tb
, cur
,
1668 fdisk_partition_get_start(cur
), maxsz
))
1672 fdisk_unref_partition(cur
);
1673 fdisk_unref_table(tb
);