blob: 8f8402716211582ac36ea396e903fa34a72603e4 [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001
2#include "c.h"
3#include "strutils.h"
4
5#include "fdiskP.h"
6
7/**
8 * SECTION: partition
9 * @title: Partition
10 * @short_description: generic label independent partition abstraction
11 *
12 * The fdisk_partition provides label independent abstraction. The partitions
13 * are not directly connected with partition table (label) data. Any change to
14 * fdisk_partition does not affects in-memory or on-disk label data.
15 *
16 * The fdisk_partition is possible to use as a template for
17 * fdisk_add_partition() or fdisk_set_partition() operations.
18 */
19
20static void init_partition(struct fdisk_partition *pa)
21{
22 FDISK_INIT_UNDEF(pa->size);
23 FDISK_INIT_UNDEF(pa->start);
24 FDISK_INIT_UNDEF(pa->partno);
25 FDISK_INIT_UNDEF(pa->parent_partno);
26 FDISK_INIT_UNDEF(pa->boot);
27
28 INIT_LIST_HEAD(&pa->parts);
29}
30
31/**
32 * fdisk_new_partition:
33 *
34 * Returns: new instance.
35 */
36struct fdisk_partition *fdisk_new_partition(void)
37{
38 struct fdisk_partition *pa = calloc(1, sizeof(*pa));
39
40 pa->refcount = 1;
41 init_partition(pa);
42 DBG(PART, ul_debugobj(pa, "alloc"));
43 return pa;
44}
45
46/**
47 * fdisk_reset_partition:
48 * @pa: partition
49 *
50 * Resets partition content.
51 */
52void fdisk_reset_partition(struct fdisk_partition *pa)
53{
54 int ref;
55
56 if (!pa)
57 return;
58
59 DBG(PART, ul_debugobj(pa, "reset"));
60 ref = pa->refcount;
61
62 fdisk_unref_parttype(pa->type);
63 free(pa->name);
64 free(pa->uuid);
65 free(pa->attrs);
66
67 memset(pa, 0, sizeof(*pa));
68 pa->refcount = ref;
69
70 init_partition(pa);
71}
72
73/**
74 * fdisk_ref_partition:
75 * @pa: partition pointer
76 *
77 * Incremparts reference counter.
78 */
79void fdisk_ref_partition(struct fdisk_partition *pa)
80{
81 if (pa)
82 pa->refcount++;
83}
84
85/**
86 * fdisk_unref_partition:
87 * @pa: partition pointer
88 *
89 * De-incremparts reference counter, on zero the @pa is automatically
90 * deallocated.
91 */
92void fdisk_unref_partition(struct fdisk_partition *pa)
93{
94 if (!pa)
95 return;
96
97 pa->refcount--;
98 if (pa->refcount <= 0) {
99 fdisk_reset_partition(pa);
100 list_del(&pa->parts);
101 DBG(PART, ul_debugobj(pa, "free"));
102 free(pa);
103 }
104}
105
106/**
107 * fdisk_partition_set_start:
108 * @pa: partition
109 * @off: offset in sectors, maximal is UINT64_MAX-1
110 *
111 * Note that zero is valid offset too. Use fdisk_partition_unset_start() to
112 * undefine the offset.
113 *
114 * Returns: 0 on success, <0 on error.
115 */
116int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off)
117{
118 if (!pa)
119 return -EINVAL;
120 if (FDISK_IS_UNDEF(off))
121 return -ERANGE;
122 pa->start = off;
123 return 0;
124}
125
126/**
127 * fdisk_partition_unset_start:
128 * @pa: partition
129 *
130 * Sets the size as undefined. See fdisk_partition_has_start().
131 *
132 * Returns: 0 on success, <0 on error.
133 */
134int fdisk_partition_unset_start(struct fdisk_partition *pa)
135{
136 if (!pa)
137 return -EINVAL;
138 FDISK_INIT_UNDEF(pa->start);
139 return 0;
140}
141
142/**
143 * fdisk_partition_get_start:
144 * @pa: partition
145 *
146 * The zero is also valid offset. The function may return random undefined
147 * value when start offset is undefined (for example after
148 * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be
149 * sure that you work with valid numbers.
150 *
151 * Returns: start offset in sectors
152 */
153fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa)
154{
155 return pa->start;
156}
157
158/**
159 * fdisk_partition_has_start:
160 * @pa: partition
161 *
162 * Returns: 1 or 0
163 */
164int fdisk_partition_has_start(struct fdisk_partition *pa)
165{
166 return pa && !FDISK_IS_UNDEF(pa->start);
167}
168
169
170/**
171 * fdisk_partition_cmp_start:
172 * @a: partition
173 * @b: partition
174 *
175 * Compares partitons according to start offset, See fdisk_sort_table().
176 *
177 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
178 */
179int fdisk_partition_cmp_start(struct fdisk_partition *a,
180 struct fdisk_partition *b)
181{
182 int no_a = FDISK_IS_UNDEF(a->start),
183 no_b = FDISK_IS_UNDEF(b->start);
184
185 if (no_a && no_b)
186 return 0;
187 if (no_a)
188 return -1;
189 if (no_b)
190 return 1;
191
192 return cmp_numbers(a->start, b->start);
193}
194
195/**
196 * fdisk_partition_start_follow_default
197 * @pa: partition
198 * @enable: 0|1
199 *
200 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
201 * to use the first possible space for the new partition.
202 *
203 * Returns: 0 on success, <0 on error.
204 */
205int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable)
206{
207 if (!pa)
208 return -EINVAL;
209 pa->start_follow_default = enable ? 1 : 0;
210 return 0;
211}
212
213/**
214 * fdisk_partition_start_is_default:
215 * @pa: partition
216 *
217 * See fdisk_partition_start_follow_default().
218 *
219 * Returns: 1 if the partition follows default
220 */
221int fdisk_partition_start_is_default(struct fdisk_partition *pa)
222{
223 assert(pa);
224 return pa->start_follow_default;
225}
226
227
228/**
229 * fdisk_partition_set_size:
230 * @pa: partition
231 * @sz: size in sectors, maximal is UIN64_MAX-1
232 *
233 * Note that zero is valid size too. Use fdisk_partition_unset_size() to
234 * undefine the size.
235 *
236 * Returns: 0 on success, <0 on error.
237 */
238int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz)
239{
240 if (!pa)
241 return -EINVAL;
242 if (FDISK_IS_UNDEF(sz))
243 return -ERANGE;
244 pa->size = sz;
245 return 0;
246}
247
248/**
249 * fdisk_partition_unset_size:
250 * @pa: partition
251 *
252 * Sets the size as undefined. See fdisk_partition_has_size().
253 *
254 * Returns: 0 on success, <0 on error.
255 */
256int fdisk_partition_unset_size(struct fdisk_partition *pa)
257{
258 if (!pa)
259 return -EINVAL;
260 FDISK_INIT_UNDEF(pa->size);
261 return 0;
262}
263
264/**
265 * fdisk_partition_get_size:
266 * @pa: partition
267 *
268 * The zero is also valid size. The function may return random undefined
269 * value when size is undefined (for example after fdisk_partition_unset_size()).
270 * Always use fdisk_partition_has_size() to be sure that you work with valid
271 * numbers.
272 *
273 * Returns: size offset in sectors
274 */
275fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa)
276{
277 return pa->size;
278}
279
280/**
281 * fdisk_partition_has_size:
282 * @pa: partition
283 *
284 * Returns: 1 or 0
285 */
286int fdisk_partition_has_size(struct fdisk_partition *pa)
287{
288 return pa && !FDISK_IS_UNDEF(pa->size);
289}
290
291/**
292 * fdisk_partition_size_explicit:
293 * @pa: partition
294 * @enable: 0|1
295 *
296 * By default libfdisk aligns the size when add the new partition (by
297 * fdisk_add_partrition()). If you want to disable this functionality use
298 * @enable = 1.
299 *
300 * Returns: 0 on success, <0 on error.
301 */
302int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable)
303{
304 if (!pa)
305 return -EINVAL;
306 pa->size_explicit = enable ? 1 : 0;
307 return 0;
308}
309
310/**
311 * fdisk_partition_set_partno:
312 * @pa: partition
313 * @num: partitin number (0 is the first partition, maximal is SIZE_MAX-1)
314 *
315 * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to
316 * undefine the partno.
317 *
318 * Returns: 0 on success, <0 on error.
319 */
320int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num)
321{
322 if (!pa)
323 return -EINVAL;
324 if (FDISK_IS_UNDEF(num))
325 return -ERANGE;
326 pa->partno = num;
327 return 0;
328}
329
330/**
331 * fdisk_partition_unset_partno:
332 * @pa: partition
333 *
334 * Sets the partno as undefined. See fdisk_partition_has_partno().
335 *
336 * Returns: 0 on success, <0 on error.
337 */
338int fdisk_partition_unset_partno(struct fdisk_partition *pa)
339{
340 if (!pa)
341 return -EINVAL;
342 FDISK_INIT_UNDEF(pa->partno);
343 return 0;
344}
345
346/**
347 * fdisk_partition_get_partno:
348 * @pa: partition
349 *
350 * The zero is also valid parition number. The function may return random
351 * value when partno is undefined (for example after fdisk_partition_unset_partno()).
352 * Always use fdisk_partition_has_partno() to be sure that you work with valid
353 * numbers.
354 *
355 * Returns: partition number (0 is the first partition)
356 */
357size_t fdisk_partition_get_partno(struct fdisk_partition *pa)
358{
359 return pa->partno;
360}
361
362/**
363 * fdisk_partition_has_partno:
364 * @pa: partition
365 *
366 * Returns: 1 or 0
367 */
368int fdisk_partition_has_partno(struct fdisk_partition *pa)
369{
370 return pa && !FDISK_IS_UNDEF(pa->partno);
371}
372
373
374/**
375 * fdisk_partition_cmp_partno:
376 * @a: partition
377 * @b: partition
378 *
379 * Compares partitons according to partition number See fdisk_sort_table().
380 *
381 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
382 */
383int fdisk_partition_cmp_partno(struct fdisk_partition *a,
384 struct fdisk_partition *b)
385{
386 return a->partno - b->partno;
387}
388
389/**
390 * fdisk_partition_partno_follow_default
391 * @pa: partition
392 * @enable: 0|1
393 *
394 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
395 * to add a new partition to the default (next) position.
396 *
397 * Returns: 0 on success, <0 on error.
398 */
399int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable)
400{
401 if (!pa)
402 return -EINVAL;
403 pa->partno_follow_default = enable ? 1 : 0;
404 return 0;
405}
406
407/**
408 * fdisk_partition_set_type:
409 * @pa: partition
410 * @type: partition type
411 *
412 * Sets parition type.
413 *
414 * Returns: 0 on success, <0 on error.
415 */
416int fdisk_partition_set_type(struct fdisk_partition *pa,
417 struct fdisk_parttype *type)
418{
419 if (!pa)
420 return -EINVAL;
421
422 fdisk_ref_parttype(type);
423 fdisk_unref_parttype(pa->type);
424 pa->type = type;
425
426 return 0;
427}
428
429/**
430 * fdisk_partition_get_type:
431 * @pa: partition
432 *
433 * Returns: pointer to partition type.
434 */
435struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
436{
437 return pa ? pa->type : NULL;
438}
439
440int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name)
441{
442 char *p = NULL;
443
444 if (!pa)
445 return -EINVAL;
446 if (name) {
447 p = strdup(name);
448 if (!p)
449 return -ENOMEM;
450 }
451 free(pa->name);
452 pa->name = p;
453 return 0;
454}
455
456const char *fdisk_partition_get_name(struct fdisk_partition *pa)
457{
458 return pa ? pa->name : NULL;
459}
460
461int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid)
462{
463 char *p = NULL;
464
465 if (!pa)
466 return -EINVAL;
467 if (uuid) {
468 p = strdup(uuid);
469 if (!p)
470 return -ENOMEM;
471 }
472 free(pa->uuid);
473 pa->uuid = p;
474 return 0;
475}
476
477/**
478 * fdisk_partition_has_end:
479 * @pa: partition
480 *
481 * Returns: 1 if the partition has defined last sector
482 */
483int fdisk_partition_has_end(struct fdisk_partition *pa)
484{
485 return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size);
486}
487
488/**
489 * fdisk_partition_get_end:
490 * @pa: partition
491 *
492 * This function may returns absolute non-sense, always check
493 * fdisk_partition_has_end().
494 *
495 * Note that partition end is defined by fdisk_partition_set_start() and
496 * fdisk_partition_set_size().
497 *
498 * Returns: last partition sector LBA.
499 */
500fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa)
501{
502 return pa->start + pa->size - (pa->size == 0 ? 0 : 1);
503}
504
505/**
506 * fdisk_partition_end_follow_default
507 * @pa: partition
508 * @enable: 0|1
509 *
510 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
511 * to use all the possible space for the new partition.
512 *
513 * Returns: 0 on success, <0 on error.
514 */
515int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable)
516{
517 if (!pa)
518 return -EINVAL;
519 pa->end_follow_default = enable ? 1 : 0;
520 return 0;
521}
522
523/**
524 * fdisk_partition_end_is_default:
525 * @pa: partition
526 *
527 * Returns: 1 if the partition follows default
528 */
529int fdisk_partition_end_is_default(struct fdisk_partition *pa)
530{
531 assert(pa);
532 return pa->end_follow_default;
533}
534
535const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
536{
537 return pa ? pa->uuid : NULL;
538}
539
540const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
541{
542 return pa ? pa->attrs : NULL;
543}
544
545int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs)
546{
547 char *p = NULL;
548
549 if (!pa)
550 return -EINVAL;
551 if (attrs) {
552 p = strdup(attrs);
553 if (!p)
554 return -ENOMEM;
555 }
556 free(pa->attrs);
557 pa->attrs = p;
558 return 0;
559}
560
561int fdisk_partition_is_nested(struct fdisk_partition *pa)
562{
563 return pa && !FDISK_IS_UNDEF(pa->parent_partno);
564}
565
566int fdisk_partition_is_container(struct fdisk_partition *pa)
567{
568 return pa && pa->container;
569}
570
571int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
572{
573 if (pa && parent)
574 *parent = pa->parent_partno;
575 else
576 return -EINVAL;
577 return 0;
578}
579
580int fdisk_partition_is_used(struct fdisk_partition *pa)
581{
582 return pa && pa->used;
583}
584
585int fdisk_partition_is_bootable(struct fdisk_partition *pa)
586{
587 return pa && pa->boot == 1;
588}
589
590int fdisk_partition_is_freespace(struct fdisk_partition *pa)
591{
592 return pa && pa->freespace;
593}
594
595int fdisk_partition_next_partno(
596 struct fdisk_partition *pa,
597 struct fdisk_context *cxt,
598 size_t *n)
599{
600 assert(cxt);
601 assert(n);
602
603 if (pa && pa->partno_follow_default) {
604 size_t i;
605
606 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
607
608 for (i = 0; i < cxt->label->nparts_max; i++) {
609 if (!fdisk_is_partition_used(cxt, i)) {
610 *n = i;
611 return 0;
612 }
613 }
614 return -ERANGE;
615
616 } else if (pa && fdisk_partition_has_partno(pa)) {
617
618 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
619
620 if (pa->partno >= cxt->label->nparts_max)
621 return -ERANGE;
622 *n = pa->partno;
623 } else
624 return fdisk_ask_partnum(cxt, n, 1);
625
626 return 0;
627}
628
629/**
630 * fdisk_partition_to_string:
631 * @pa: partition
632 * @cxt: context
633 * @id: field (FDISK_FIELD_*)
634 * @data: returns string with allocated data
635 *
636 * Returns info about partition converted to printable string.
637 *
638 * For example
639 * <informalexample>
640 * <programlisting>
641 * struct fdisk_parition *pa;
642 *
643 * fdisk_get_partition(cxt, 0, &pa);
644 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
645 * printf("first partition uuid: %s\n", data);
646 * free(data);
647 * fdisk_unref_partition(pa);
648 * </programlisting>
649 * </informalexample>
650 *
651 * returns UUID for the first partition.
652 *
653 * Returns: 0 on success, otherwise, a corresponding error.
654 */
655int fdisk_partition_to_string(struct fdisk_partition *pa,
656 struct fdisk_context *cxt,
657 int id,
658 char **data)
659{
660 char *p = NULL;
661 int rc = 0;
662 uint64_t x;
663
664 if (!pa || !cxt)
665 return -EINVAL;
666
667 switch (id) {
668 case FDISK_FIELD_DEVICE:
669 if (pa->freespace)
670 p = strdup(_("Free space"));
671 else if (fdisk_partition_has_partno(pa) && cxt->dev_path) {
672 if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
673 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
674 else
675 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
676 }
677 break;
678 case FDISK_FIELD_BOOT:
679 if (fdisk_partition_is_bootable(pa))
680 rc = asprintf(&p, "%c", pa->boot ? '*' : ' ');
681 break;
682 case FDISK_FIELD_START:
683 if (fdisk_partition_has_start(pa)) {
684 x = fdisk_cround(cxt, pa->start);
685 rc = pa->start_post ?
686 asprintf(&p, "%ju%c", x, pa->start_post) :
687 asprintf(&p, "%ju", x);
688 }
689 break;
690 case FDISK_FIELD_END:
691 if (fdisk_partition_has_end(pa)) {
692 x = fdisk_cround(cxt, fdisk_partition_get_end(pa));
693 rc = pa->end_post ?
694 asprintf(&p, "%ju%c", x, pa->end_post) :
695 asprintf(&p, "%ju", x);
696 }
697 break;
698 case FDISK_FIELD_SIZE:
699 if (fdisk_partition_has_size(pa)) {
700 uint64_t sz = pa->size * cxt->sector_size;
701
702 if (fdisk_is_details(cxt)) {
703 rc = pa->size_post ?
704 asprintf(&p, "%ju%c", sz, pa->size_post) :
705 asprintf(&p, "%ju", sz);
706 } else {
707 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
708 if (!p)
709 rc = -ENOMEM;
710 }
711 }
712 break;
713 case FDISK_FIELD_CYLINDERS:
714 rc = asprintf(&p, "%ju", (uintmax_t)
715 fdisk_cround(cxt, fdisk_partition_has_size(pa) ? pa->size : 0));
716 break;
717 case FDISK_FIELD_SECTORS:
718 rc = asprintf(&p, "%ju",
719 fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0);
720 break;
721 case FDISK_FIELD_BSIZE:
722 rc = asprintf(&p, "%ju", pa->bsize);
723 break;
724 case FDISK_FIELD_FSIZE:
725 rc = asprintf(&p, "%ju", pa->fsize);
726 break;
727 case FDISK_FIELD_CPG:
728 rc = asprintf(&p, "%ju", pa->cpg);
729 break;
730 case FDISK_FIELD_TYPE:
731 p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL;
732 break;
733 case FDISK_FIELD_TYPEID:
734 if (pa->type && fdisk_parttype_get_string(pa->type))
735 rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
736 else if (pa->type)
737 rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
738 break;
739 case FDISK_FIELD_UUID:
740 p = pa->uuid ? strdup(pa->uuid) : NULL;
741 break;
742 case FDISK_FIELD_NAME:
743 p = pa->name ? strdup(pa->name) : NULL;
744 break;
745 case FDISK_FIELD_ATTR:
746 p = pa->attrs ? strdup(pa->attrs) : NULL;
747 break;
748 case FDISK_FIELD_SADDR:
749 p = pa->start_chs ? strdup(pa->start_chs) : NULL;
750 break;
751 case FDISK_FIELD_EADDR:
752 p = pa->end_chs ? strdup(pa->end_chs) : NULL;
753 break;
754 default:
755 return -EINVAL;
756 }
757
758 if (rc < 0)
759 rc = -ENOMEM;
760 else if (rc > 0)
761 rc = 0;
762
763 if (data)
764 *data = p;
765 return rc;
766}
767
768/**
769 * fdisk_get_partition:
770 * @cxt: context
771 * @partno: partition number (0 is the first partition)
772 * @pa: returns data about partition
773 *
774 * Reads disklabel and fills in @pa with data about partition @n.
775 *
776 * Note that partno may address unused partition and then this function does
777 * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to
778 * NULL then the function allocates a newly allocated fdisk_partition struct,
779 * use fdisk_unref_partition() to deallocate.
780 *
781 * Returns: 0 on success, otherwise, a corresponding error.
782 */
783int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
784 struct fdisk_partition **pa)
785{
786 int rc;
787 struct fdisk_partition *np = NULL;
788
789 if (!cxt || !cxt->label || !pa)
790 return -EINVAL;
791 if (!cxt->label->op->get_part)
792 return -ENOSYS;
793 if (!fdisk_is_partition_used(cxt, partno))
794 return -EINVAL;
795
796 if (!*pa) {
797 np = *pa = fdisk_new_partition();
798 if (!*pa)
799 return -ENOMEM;
800 } else
801 fdisk_reset_partition(*pa);
802
803 (*pa)->partno = partno;
804 rc = cxt->label->op->get_part(cxt, partno, *pa);
805
806 if (rc) {
807 if (np) {
808 fdisk_unref_partition(np);
809 *pa = NULL;
810 } else
811 fdisk_reset_partition(*pa);
812 } else
813 (*pa)->size_explicit = 1;
814 return rc;
815}
816
817/**
818 * fdisk_set_partition:
819 * @cxt: context
820 * @partno: partition number (0 is the first partition)
821 * @pa: new partition setting
822 *
823 * Modifies disklabel according to setting with in @pa.
824 *
825 * Returns: 0 on success, <0 on error.
826 */
827int fdisk_set_partition(struct fdisk_context *cxt, size_t partno,
828 struct fdisk_partition *pa)
829{
830 if (!cxt || !cxt->label || !pa)
831 return -EINVAL;
832 if (!cxt->label->op->set_part)
833 return -ENOSYS;
834
835 DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju, "
836 "defaults(start=%s, end=%s, partno=%s)",
837 partno, pa,
838 (uintmax_t) fdisk_partition_get_start(pa),
839 (uintmax_t) fdisk_partition_get_end(pa),
840 (uintmax_t) fdisk_partition_get_size(pa),
841 pa->start_follow_default ? "yes" : "no",
842 pa->end_follow_default ? "yes" : "no",
843 pa->partno_follow_default ? "yes" : "no"));
844
845 return cxt->label->op->set_part(cxt, partno, pa);
846}
847
848/**
849 * fdisk_add_partition:
850 * @cxt: fdisk context
851 * @pa: template for the partition (or NULL)
852 * @partno: NULL or returns new partition number
853 *
854 * If @pa is not specified or any @pa item is missiong the libfdisk will ask by
855 * fdisk_ask_ API.
856 *
857 * Adds a new partition to disklabel.
858 *
859 * Returns: 0 on success, <0 on error.
860 */
861int fdisk_add_partition(struct fdisk_context *cxt,
862 struct fdisk_partition *pa,
863 size_t *partno)
864{
865 int rc;
866
867 assert(cxt);
868 assert(cxt->label);
869
870 if (!cxt || !cxt->label)
871 return -EINVAL;
872 if (!cxt->label->op->add_part)
873 return -ENOSYS;
874 if (fdisk_missing_geometry(cxt))
875 return -EINVAL;
876
877 if (pa)
878 DBG(CXT, ul_debugobj(cxt, "adding new partition %p (start=%ju, end=%ju, size=%ju, "
879 "defaults(start=%s, end=%s, partno=%s)",
880 pa,
881 (uintmax_t) fdisk_partition_get_start(pa),
882 (uintmax_t) fdisk_partition_get_end(pa),
883 (uintmax_t) fdisk_partition_get_size(pa),
884 pa->start_follow_default ? "yes" : "no",
885 pa->end_follow_default ? "yes" : "no",
886 pa->partno_follow_default ? "yes" : "no"));
887 else
888 DBG(CXT, ul_debugobj(cxt, "adding partition"));
889
890 rc = cxt->label->op->add_part(cxt, pa, partno);
891
892 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
893 return rc;
894}
895
896/**
897 * fdisk_delete_partition:
898 * @cxt: fdisk context
899 * @partno: partition number to delete (0 is the first partition)
900 *
901 * Deletes a @partno partition from disklabel.
902 *
903 * Returns: 0 on success, <0 on error
904 */
905int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno)
906{
907 if (!cxt || !cxt->label)
908 return -EINVAL;
909 if (!cxt->label->op->del_part)
910 return -ENOSYS;
911
912 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
913 cxt->label->name, partno));
914 return cxt->label->op->del_part(cxt, partno);
915}
916
917/**
918 * fdisk_delete_all_partitions:
919 * @cxt: fdisk context
920 *
921 * Delete all used partitions from disklabel.
922 *
923 * Returns: 0 on success, otherwise, a corresponding error.
924 */
925int fdisk_delete_all_partitions(struct fdisk_context *cxt)
926{
927 size_t i;
928 int rc;
929
930 if (!cxt || !cxt->label)
931 return -EINVAL;
932
933 for (i = 0; i < cxt->label->nparts_max; i++) {
934
935 if (!fdisk_is_partition_used(cxt, i))
936 continue;
937 rc = fdisk_delete_partition(cxt, i);
938 if (rc)
939 break;
940 }
941
942 return rc;
943}
944
945/**
946 * fdisk_is_partition_used:
947 * @cxt: context
948 * @n: partition number (0 is the first partition)
949 *
950 * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
951 *
952 * Returns: 0 or 1
953 */
954int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
955{
956 if (!cxt || !cxt->label)
957 return -EINVAL;
958 if (!cxt->label->op->part_is_used)
959 return -ENOSYS;
960
961 return cxt->label->op->part_is_used(cxt, n);
962}
963