]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/partition.c
Merge branch 'fix-last' of https://github.com/rudimeier/util-linux
[thirdparty/util-linux.git] / libfdisk / src / partition.c
1
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
20 static 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 */
36 struct 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 */
52 void 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 */
79 void 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 */
92 void 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 */
116 int 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 */
134 int 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 */
153 fdisk_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 */
164 int 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 partitions according to start offset, See fdisk_table_sort_partitions().
176 *
177 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
178 */
179 int 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 template 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 */
205 int 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 */
221 int 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 */
238 int 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 */
256 int 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 */
275 fdisk_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 */
286 int 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_partition()). If you want to disable this functionality use
298 * @enable = 1.
299 *
300 * Returns: 0 on success, <0 on error.
301 */
302 int 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 */
320 int 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 */
338 int 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 partition 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 */
357 size_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 */
368 int 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 partitions according to partition number See fdisk_table_sort_partitions().
380 *
381 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
382 */
383 int 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 template 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 */
399 int 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 parititon type.
413 *
414 * Returns: 0 on success, <0 on error.
415 */
416 int 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 */
435 struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
436 {
437 return pa ? pa->type : NULL;
438 }
439
440 int 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
456 const char *fdisk_partition_get_name(struct fdisk_partition *pa)
457 {
458 return pa ? pa->name : NULL;
459 }
460
461 int 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 */
483 int 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 */
500 fdisk_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 template 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 */
515 int 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 */
529 int fdisk_partition_end_is_default(struct fdisk_partition *pa)
530 {
531 assert(pa);
532 return pa->end_follow_default;
533 }
534
535 /**
536 * fdisk_partition_get_uuid:
537 * @pa: partition
538 *
539 * Returns: partition UUID as string
540 */
541 const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
542 {
543 return pa ? pa->uuid : NULL;
544 }
545
546 /**
547 * fdisk_partition_get_attrs:
548 * @pa: partition
549 *
550 * Returns: partition attributes in string format
551 */
552 const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
553 {
554 return pa ? pa->attrs : NULL;
555 }
556
557 /**
558 * fdisk_partition_set_attrs:
559 * @pa: partition
560 * @attrs: attributes
561 *
562 * Sets @attrs to @pa.
563 *
564 * Return: 0 on success, <0 on error.
565 */
566 int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs)
567 {
568 char *p = NULL;
569
570 if (!pa)
571 return -EINVAL;
572 if (attrs) {
573 p = strdup(attrs);
574 if (!p)
575 return -ENOMEM;
576 }
577 free(pa->attrs);
578 pa->attrs = p;
579 return 0;
580 }
581
582 /**
583 * fdisk_partition_is_nested:
584 * @pa: partition
585 *
586 * Returns: 1 if the partition is nested (e.g. MBR logical partition)
587 */
588 int fdisk_partition_is_nested(struct fdisk_partition *pa)
589 {
590 return pa && !FDISK_IS_UNDEF(pa->parent_partno);
591 }
592
593 /**
594 * fdisk_partition_is_container:
595 * @pa: partition
596 *
597 * Returns: 1 if the partition is container (e.g. MBR extended partition)
598 */
599 int fdisk_partition_is_container(struct fdisk_partition *pa)
600 {
601 return pa && pa->container;
602 }
603
604 /**
605 * fdisk_partition_get_parent:
606 * @pa: partition
607 * @parent: parent parno
608 *
609 * Returns: returns devno of the parent
610 */
611 int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
612 {
613 if (pa && parent)
614 *parent = pa->parent_partno;
615 else
616 return -EINVAL;
617 return 0;
618 }
619
620 /**
621 * fdisk_partition_is_used:
622 * @pa: partition
623 *
624 * Returns: 1 if the partition points to some area
625 */
626 int fdisk_partition_is_used(struct fdisk_partition *pa)
627 {
628 return pa && pa->used;
629 }
630
631 /**
632 * fdisk_partition_is_bootable:
633 * @pa: partition
634 *
635 * Returns: 1 if the partition has enabled boot flag
636 */
637 int fdisk_partition_is_bootable(struct fdisk_partition *pa)
638 {
639 return pa && pa->boot == 1;
640 }
641
642 /**
643 * fdisk_partition_is_freespace:
644 * @pa: partition
645 *
646 * Returns: 1 if @pa points to freespace
647 */
648 int fdisk_partition_is_freespace(struct fdisk_partition *pa)
649 {
650 return pa && pa->freespace;
651 }
652
653 /**
654 * fdisk_partition_is_wholedisk:
655 * @pa: partition
656 *
657 * Returns: 1 if the partition is special whole-disk (e.g. SUN) partition
658 */
659 int fdisk_partition_is_wholedisk(struct fdisk_partition *pa)
660 {
661 return pa && pa->wholedisk;
662 }
663
664 /**
665 * fdisk_partition_next_partno:
666 * @pa: partition
667 * @cxt: context
668 * @n: returns partition number
669 *
670 * If partno-follow-default (see fdisk_partition_partno_follow_default())
671 * enabled then returns next expected partno, otherwise use Ask API to ask user
672 * for the next partno.
673 *
674 * Returns: 0 on success, <0 on error
675 */
676 int fdisk_partition_next_partno(
677 struct fdisk_partition *pa,
678 struct fdisk_context *cxt,
679 size_t *n)
680 {
681 assert(cxt);
682 assert(n);
683
684 if (pa && pa->partno_follow_default) {
685 size_t i;
686
687 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
688
689 for (i = 0; i < cxt->label->nparts_max; i++) {
690 if (!fdisk_is_partition_used(cxt, i)) {
691 *n = i;
692 return 0;
693 }
694 }
695 return -ERANGE;
696
697 } else if (pa && fdisk_partition_has_partno(pa)) {
698
699 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
700
701 if (pa->partno >= cxt->label->nparts_max)
702 return -ERANGE;
703 *n = pa->partno;
704 } else
705 return fdisk_ask_partnum(cxt, n, 1);
706
707 return 0;
708 }
709
710 /**
711 * fdisk_partition_to_string:
712 * @pa: partition
713 * @cxt: context
714 * @id: field (FDISK_FIELD_*)
715 * @data: returns string with allocated data
716 *
717 * Returns info about partition converted to printable string.
718 *
719 * For example
720 * <informalexample>
721 * <programlisting>
722 * struct fdisk_parition *pa;
723 *
724 * fdisk_get_partition(cxt, 0, &pa);
725 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
726 * printf("first partition uuid: %s\n", data);
727 * free(data);
728 * fdisk_unref_partition(pa);
729 * </programlisting>
730 * </informalexample>
731 *
732 * returns UUID for the first partition.
733 *
734 * Returns: 0 on success, otherwise, a corresponding error.
735 */
736 int fdisk_partition_to_string(struct fdisk_partition *pa,
737 struct fdisk_context *cxt,
738 int id,
739 char **data)
740 {
741 char *p = NULL;
742 int rc = 0;
743 uint64_t x;
744
745 if (!pa || !cxt || !data)
746 return -EINVAL;
747
748 switch (id) {
749 case FDISK_FIELD_DEVICE:
750 if (pa->freespace)
751 p = strdup(_("Free space"));
752 else if (fdisk_partition_has_partno(pa) && cxt->dev_path) {
753 if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
754 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
755 else
756 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
757 }
758 break;
759 case FDISK_FIELD_BOOT:
760 if (fdisk_partition_is_bootable(pa))
761 rc = asprintf(&p, "%c", pa->boot ? '*' : ' ');
762 break;
763 case FDISK_FIELD_START:
764 if (fdisk_partition_has_start(pa)) {
765 x = fdisk_cround(cxt, pa->start);
766 rc = pa->start_post ?
767 asprintf(&p, "%ju%c", x, pa->start_post) :
768 asprintf(&p, "%ju", x);
769 }
770 break;
771 case FDISK_FIELD_END:
772 if (fdisk_partition_has_end(pa)) {
773 x = fdisk_cround(cxt, fdisk_partition_get_end(pa));
774 rc = pa->end_post ?
775 asprintf(&p, "%ju%c", x, pa->end_post) :
776 asprintf(&p, "%ju", x);
777 }
778 break;
779 case FDISK_FIELD_SIZE:
780 if (fdisk_partition_has_size(pa)) {
781 uint64_t sz = pa->size * cxt->sector_size;
782
783 switch (cxt->sizeunit) {
784 case FDISK_SIZEUNIT_BYTES:
785 rc = asprintf(&p, "%ju", sz);
786 break;
787 case FDISK_SIZEUNIT_HUMAN:
788 if (fdisk_is_details(cxt))
789 rc = pa->size_post ?
790 asprintf(&p, "%ju%c", sz, pa->size_post) :
791 asprintf(&p, "%ju", sz);
792 else {
793 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
794 if (!p)
795 rc = -ENOMEM;
796 }
797 break;
798 }
799 }
800 break;
801 case FDISK_FIELD_CYLINDERS:
802 rc = asprintf(&p, "%ju", (uintmax_t)
803 fdisk_cround(cxt, fdisk_partition_has_size(pa) ? pa->size : 0));
804 break;
805 case FDISK_FIELD_SECTORS:
806 rc = asprintf(&p, "%ju",
807 fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0);
808 break;
809 case FDISK_FIELD_BSIZE:
810 rc = asprintf(&p, "%ju", pa->bsize);
811 break;
812 case FDISK_FIELD_FSIZE:
813 rc = asprintf(&p, "%ju", pa->fsize);
814 break;
815 case FDISK_FIELD_CPG:
816 rc = asprintf(&p, "%ju", pa->cpg);
817 break;
818 case FDISK_FIELD_TYPE:
819 p = pa->type && pa->type->name ? strdup(_(pa->type->name)) : NULL;
820 break;
821 case FDISK_FIELD_TYPEID:
822 if (pa->type && fdisk_parttype_get_string(pa->type))
823 rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
824 else if (pa->type)
825 rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
826 break;
827 case FDISK_FIELD_UUID:
828 p = pa->uuid && *pa->uuid? strdup(pa->uuid) : NULL;
829 break;
830 case FDISK_FIELD_NAME:
831 p = pa->name && *pa->name ? strdup(pa->name) : NULL;
832 break;
833 case FDISK_FIELD_ATTR:
834 p = pa->attrs && *pa->attrs ? strdup(pa->attrs) : NULL;
835 break;
836 case FDISK_FIELD_SADDR:
837 p = pa->start_chs && *pa->start_chs ? strdup(pa->start_chs) : NULL;
838 break;
839 case FDISK_FIELD_EADDR:
840 p = pa->end_chs && *pa->end_chs? strdup(pa->end_chs) : NULL;
841 break;
842 default:
843 return -EINVAL;
844 }
845
846 if (rc < 0) {
847 rc = -ENOMEM;
848 free(p);
849 p = NULL;
850
851 } else if (rc > 0)
852 rc = 0;
853
854 *data = p;
855
856 return rc;
857 }
858
859 /**
860 * fdisk_get_partition:
861 * @cxt: context
862 * @partno: partition number (0 is the first partition)
863 * @pa: returns data about partition
864 *
865 * Reads disklabel and fills in @pa with data about partition @n.
866 *
867 * Note that partno may address unused partition and then this function does
868 * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to
869 * NULL then the function allocates a newly allocated fdisk_partition struct,
870 * use fdisk_unref_partition() to deallocate.
871 *
872 * Returns: 0 on success, otherwise, a corresponding error.
873 */
874 int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
875 struct fdisk_partition **pa)
876 {
877 int rc;
878 struct fdisk_partition *np = NULL;
879
880 if (!cxt || !cxt->label || !pa)
881 return -EINVAL;
882 if (!cxt->label->op->get_part)
883 return -ENOSYS;
884 if (!fdisk_is_partition_used(cxt, partno))
885 return -EINVAL;
886
887 if (!*pa) {
888 np = *pa = fdisk_new_partition();
889 if (!*pa)
890 return -ENOMEM;
891 } else
892 fdisk_reset_partition(*pa);
893
894 (*pa)->partno = partno;
895 rc = cxt->label->op->get_part(cxt, partno, *pa);
896
897 if (rc) {
898 if (np) {
899 fdisk_unref_partition(np);
900 *pa = NULL;
901 } else
902 fdisk_reset_partition(*pa);
903 } else
904 (*pa)->size_explicit = 1;
905 return rc;
906 }
907
908 /**
909 * fdisk_set_partition:
910 * @cxt: context
911 * @partno: partition number (0 is the first partition)
912 * @pa: new partition setting
913 *
914 * Modifies disklabel according to setting with in @pa.
915 *
916 * Returns: 0 on success, <0 on error.
917 */
918 int fdisk_set_partition(struct fdisk_context *cxt, size_t partno,
919 struct fdisk_partition *pa)
920 {
921 if (!cxt || !cxt->label || !pa)
922 return -EINVAL;
923 if (!cxt->label->op->set_part)
924 return -ENOSYS;
925
926 DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju, "
927 "defaults(start=%s, end=%s, partno=%s)",
928 partno, pa,
929 (uintmax_t) fdisk_partition_get_start(pa),
930 (uintmax_t) fdisk_partition_get_end(pa),
931 (uintmax_t) fdisk_partition_get_size(pa),
932 pa->start_follow_default ? "yes" : "no",
933 pa->end_follow_default ? "yes" : "no",
934 pa->partno_follow_default ? "yes" : "no"));
935
936 return cxt->label->op->set_part(cxt, partno, pa);
937 }
938
939 /**
940 * fdisk_add_partition:
941 * @cxt: fdisk context
942 * @pa: template for the partition (or NULL)
943 * @partno: NULL or returns new partition number
944 *
945 * If @pa is not specified or any @pa item is missiong the libfdisk will ask by
946 * fdisk_ask_ API.
947 *
948 * Adds a new partition to disklabel.
949 *
950 * Returns: 0 on success, <0 on error.
951 */
952 int fdisk_add_partition(struct fdisk_context *cxt,
953 struct fdisk_partition *pa,
954 size_t *partno)
955 {
956 int rc;
957
958 assert(cxt);
959 assert(cxt->label);
960
961 if (!cxt || !cxt->label)
962 return -EINVAL;
963 if (!cxt->label->op->add_part)
964 return -ENOSYS;
965 if (fdisk_missing_geometry(cxt))
966 return -EINVAL;
967
968 if (pa)
969 DBG(CXT, ul_debugobj(cxt, "adding new partition %p (start=%ju, end=%ju, size=%ju, "
970 "defaults(start=%s, end=%s, partno=%s)",
971 pa,
972 (uintmax_t) fdisk_partition_get_start(pa),
973 (uintmax_t) fdisk_partition_get_end(pa),
974 (uintmax_t) fdisk_partition_get_size(pa),
975 pa->start_follow_default ? "yes" : "no",
976 pa->end_follow_default ? "yes" : "no",
977 pa->partno_follow_default ? "yes" : "no"));
978 else
979 DBG(CXT, ul_debugobj(cxt, "adding partition"));
980
981 rc = cxt->label->op->add_part(cxt, pa, partno);
982
983 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
984 return rc;
985 }
986
987 /**
988 * fdisk_delete_partition:
989 * @cxt: fdisk context
990 * @partno: partition number to delete (0 is the first partition)
991 *
992 * Deletes a @partno partition from disklabel.
993 *
994 * Returns: 0 on success, <0 on error
995 */
996 int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno)
997 {
998 if (!cxt || !cxt->label)
999 return -EINVAL;
1000 if (!cxt->label->op->del_part)
1001 return -ENOSYS;
1002
1003 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
1004 cxt->label->name, partno));
1005 return cxt->label->op->del_part(cxt, partno);
1006 }
1007
1008 /**
1009 * fdisk_delete_all_partitions:
1010 * @cxt: fdisk context
1011 *
1012 * Delete all used partitions from disklabel.
1013 *
1014 * Returns: 0 on success, otherwise, a corresponding error.
1015 */
1016 int fdisk_delete_all_partitions(struct fdisk_context *cxt)
1017 {
1018 size_t i;
1019 int rc;
1020
1021 if (!cxt || !cxt->label)
1022 return -EINVAL;
1023
1024 for (i = 0; i < cxt->label->nparts_max; i++) {
1025
1026 if (!fdisk_is_partition_used(cxt, i))
1027 continue;
1028 rc = fdisk_delete_partition(cxt, i);
1029 if (rc)
1030 break;
1031 }
1032
1033 return rc;
1034 }
1035
1036 /**
1037 * fdisk_is_partition_used:
1038 * @cxt: context
1039 * @n: partition number (0 is the first partition)
1040 *
1041 * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
1042 *
1043 * Returns: 0 or 1
1044 */
1045 int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
1046 {
1047 if (!cxt || !cxt->label)
1048 return -EINVAL;
1049 if (!cxt->label->op->part_is_used)
1050 return -ENOSYS;
1051
1052 return cxt->label->op->part_is_used(cxt, n);
1053 }
1054