1
2 #include "c.h"
3 #include "strutils.h"
4
5 #ifdef HAVE_LIBBLKID
6 # include <blkid.h>
7 #endif
8
9 #include "fdiskP.h"
10
11 /**
12 * SECTION: partition
13 * @title: Partition
14 * @short_description: generic label independent partition abstraction
15 *
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.
19 *
20 * The fdisk_partition is possible to use as a template for
21 * fdisk_add_partition() or fdisk_set_partition() operations.
22 */
23
init_partition(struct fdisk_partition * pa)24 static void init_partition(struct fdisk_partition *pa)
25 {
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);
31
32 INIT_LIST_HEAD(&pa->parts);
33 }
34
35 /**
36 * fdisk_new_partition:
37 *
38 * Returns: new instance.
39 */
fdisk_new_partition(void)40 struct fdisk_partition *fdisk_new_partition(void)
41 {
42 struct fdisk_partition *pa = calloc(1, sizeof(*pa));
43
44 pa->refcount = 1;
45 init_partition(pa);
46 DBG(PART, ul_debugobj(pa, "alloc"));
47 return pa;
48 }
49
50 /**
51 * fdisk_reset_partition:
52 * @pa: partition
53 *
54 * Resets partition content.
55 */
fdisk_reset_partition(struct fdisk_partition * pa)56 void fdisk_reset_partition(struct fdisk_partition *pa)
57 {
58 int ref;
59
60 if (!pa)
61 return;
62
63 DBG(PART, ul_debugobj(pa, "reset"));
64 ref = pa->refcount;
65
66 fdisk_unref_parttype(pa->type);
67 free(pa->name);
68 free(pa->uuid);
69 free(pa->attrs);
70 free(pa->fstype);
71 free(pa->fsuuid);
72 free(pa->fslabel);
73 free(pa->start_chs);
74 free(pa->end_chs);
75
76 memset(pa, 0, sizeof(*pa));
77 pa->refcount = ref;
78
79 init_partition(pa);
80 }
81
__copy_partition(struct fdisk_partition * o)82 static struct fdisk_partition *__copy_partition(struct fdisk_partition *o)
83 {
84 struct fdisk_partition *n = fdisk_new_partition();
85 int rc;
86
87 if (!n)
88 return NULL;
89
90 memcpy(n, o, sizeof(*n));
91
92 /* do not copy reference to lists, etc.*/
93 n->refcount = 1;
94 INIT_LIST_HEAD(&n->parts);
95
96 if (n->type)
97 fdisk_ref_parttype(n->type);
98
99 /* note that strdup_between_structs() deallocates destination pointer,
100 * so make sure it's NULL as we call memcpy() before ... */
101 n->name = NULL;
102 rc = strdup_between_structs(n, o, name);
103
104 n->uuid = NULL;
105 if (!rc)
106 rc = strdup_between_structs(n, o, uuid);
107 n->attrs = NULL;
108 if (!rc)
109 rc = strdup_between_structs(n, o, attrs);
110 n->fstype = NULL;
111 if (!rc)
112 rc = strdup_between_structs(n, o, fstype);
113 n->fsuuid = NULL;
114 if (!rc)
115 rc = strdup_between_structs(n, o, fsuuid);
116 n->fslabel = NULL;
117 if (!rc)
118 rc = strdup_between_structs(n, o, fslabel);
119 n->start_chs = NULL;
120 if (!rc)
121 rc = strdup_between_structs(n, o, start_chs);
122 n->end_chs = NULL;
123 if (!rc)
124 rc = strdup_between_structs(n, o, end_chs);
125
126 if (rc) {
127 fdisk_unref_partition(n);
128 n = NULL;
129 }
130 return n;
131 }
132
133 /**
134 * fdisk_ref_partition:
135 * @pa: partition pointer
136 *
137 * Increments reference counter.
138 */
fdisk_ref_partition(struct fdisk_partition * pa)139 void fdisk_ref_partition(struct fdisk_partition *pa)
140 {
141 if (pa)
142 pa->refcount++;
143 }
144
145 /**
146 * fdisk_unref_partition:
147 * @pa: partition pointer
148 *
149 * Decrements reference counter, on zero the @pa is automatically
150 * deallocated.
151 */
fdisk_unref_partition(struct fdisk_partition * pa)152 void fdisk_unref_partition(struct fdisk_partition *pa)
153 {
154 if (!pa)
155 return;
156
157 pa->refcount--;
158 if (pa->refcount <= 0) {
159 list_del(&pa->parts);
160 fdisk_reset_partition(pa);
161 DBG(PART, ul_debugobj(pa, "free"));
162 free(pa);
163 }
164 }
165
166 /**
167 * fdisk_partition_set_start:
168 * @pa: partition
169 * @off: offset in sectors, maximal is UINT64_MAX-1
170 *
171 * Note that zero is valid offset too. Use fdisk_partition_unset_start() to
172 * undefine the offset.
173 *
174 * Returns: 0 on success, <0 on error.
175 */
fdisk_partition_set_start(struct fdisk_partition * pa,fdisk_sector_t off)176 int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off)
177 {
178 if (!pa)
179 return -EINVAL;
180 if (FDISK_IS_UNDEF(off))
181 return -ERANGE;
182 pa->start = off;
183 pa->fs_probed = 0;
184 return 0;
185 }
186
187 /**
188 * fdisk_partition_unset_start:
189 * @pa: partition
190 *
191 * Sets the size as undefined. See fdisk_partition_has_start().
192 *
193 * Returns: 0 on success, <0 on error.
194 */
fdisk_partition_unset_start(struct fdisk_partition * pa)195 int fdisk_partition_unset_start(struct fdisk_partition *pa)
196 {
197 if (!pa)
198 return -EINVAL;
199 FDISK_INIT_UNDEF(pa->start);
200 pa->fs_probed = 0;
201 return 0;
202 }
203
204 /**
205 * fdisk_partition_get_start:
206 * @pa: partition
207 *
208 * The zero is also valid offset. The function may return random undefined
209 * value when start offset is undefined (for example after
210 * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be
211 * sure that you work with valid numbers.
212 *
213 * Returns: start offset in sectors
214 */
fdisk_partition_get_start(struct fdisk_partition * pa)215 fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa)
216 {
217 return pa->start;
218 }
219
220 /**
221 * fdisk_partition_has_start:
222 * @pa: partition
223 *
224 * Returns: 1 or 0
225 */
fdisk_partition_has_start(struct fdisk_partition * pa)226 int fdisk_partition_has_start(struct fdisk_partition *pa)
227 {
228 return pa && !FDISK_IS_UNDEF(pa->start);
229 }
230
231
232 /**
233 * fdisk_partition_cmp_start:
234 * @a: partition
235 * @b: partition
236 *
237 * Compares partitions according to start offset, See fdisk_table_sort_partitions().
238 *
239 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
240 */
fdisk_partition_cmp_start(struct fdisk_partition * a,struct fdisk_partition * b)241 int fdisk_partition_cmp_start(struct fdisk_partition *a,
242 struct fdisk_partition *b)
243 {
244 int no_a = FDISK_IS_UNDEF(a->start),
245 no_b = FDISK_IS_UNDEF(b->start);
246
247 if (no_a && no_b)
248 return 0;
249 if (no_a)
250 return -1;
251 if (no_b)
252 return 1;
253
254 return cmp_numbers(a->start, b->start);
255 }
256
257 /**
258 * fdisk_partition_start_follow_default
259 * @pa: partition
260 * @enable: 0|1
261 *
262 * When @pa used as a template for fdisk_add_partition() when force label driver
263 * to use the first possible space for the new partition.
264 *
265 * Returns: 0 on success, <0 on error.
266 */
fdisk_partition_start_follow_default(struct fdisk_partition * pa,int enable)267 int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable)
268 {
269 if (!pa)
270 return -EINVAL;
271 pa->start_follow_default = enable ? 1 : 0;
272 return 0;
273 }
274
275 /**
276 * fdisk_partition_start_is_default:
277 * @pa: partition
278 *
279 * See fdisk_partition_start_follow_default().
280 *
281 * Returns: 1 if the partition follows default
282 */
fdisk_partition_start_is_default(struct fdisk_partition * pa)283 int fdisk_partition_start_is_default(struct fdisk_partition *pa)
284 {
285 assert(pa);
286 return pa->start_follow_default;
287 }
288
289 /**
290 * fdisk_partition_set_size:
291 * @pa: partition
292 * @sz: size in sectors, maximal is UIN64_MAX-1
293 *
294 * Note that zero is valid size too. Use fdisk_partition_unset_size() to
295 * undefine the size.
296 *
297 * Returns: 0 on success, <0 on error.
298 */
fdisk_partition_set_size(struct fdisk_partition * pa,fdisk_sector_t sz)299 int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz)
300 {
301 if (!pa)
302 return -EINVAL;
303 if (FDISK_IS_UNDEF(sz))
304 return -ERANGE;
305 pa->size = sz;
306 pa->fs_probed = 0;
307 return 0;
308 }
309
310 /**
311 * fdisk_partition_unset_size:
312 * @pa: partition
313 *
314 * Sets the size as undefined. See fdisk_partition_has_size().
315 *
316 * Returns: 0 on success, <0 on error.
317 */
fdisk_partition_unset_size(struct fdisk_partition * pa)318 int fdisk_partition_unset_size(struct fdisk_partition *pa)
319 {
320 if (!pa)
321 return -EINVAL;
322 FDISK_INIT_UNDEF(pa->size);
323 pa->fs_probed = 0;
324 return 0;
325 }
326
327 /**
328 * fdisk_partition_get_size:
329 * @pa: partition
330 *
331 * The zero is also valid size. The function may return random undefined
332 * value when size is undefined (for example after fdisk_partition_unset_size()).
333 * Always use fdisk_partition_has_size() to be sure that you work with valid
334 * numbers.
335 *
336 * Returns: size offset in sectors
337 */
fdisk_partition_get_size(struct fdisk_partition * pa)338 fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa)
339 {
340 return pa->size;
341 }
342
343 /**
344 * fdisk_partition_has_size:
345 * @pa: partition
346 *
347 * Returns: 1 or 0
348 */
fdisk_partition_has_size(struct fdisk_partition * pa)349 int fdisk_partition_has_size(struct fdisk_partition *pa)
350 {
351 return pa && !FDISK_IS_UNDEF(pa->size);
352 }
353
354 /**
355 * fdisk_partition_size_explicit:
356 * @pa: partition
357 * @enable: 0|1
358 *
359 * By default libfdisk aligns the size when add the new partition (by
360 * fdisk_add_partition()). If you want to disable this functionality use
361 * @enable = 1.
362 *
363 * Returns: 0 on success, <0 on error.
364 */
fdisk_partition_size_explicit(struct fdisk_partition * pa,int enable)365 int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable)
366 {
367 if (!pa)
368 return -EINVAL;
369 pa->size_explicit = enable ? 1 : 0;
370 return 0;
371 }
372
373 /**
374 * fdisk_partition_set_partno:
375 * @pa: partition
376 * @num: partition number (0 is the first partition, maximal is SIZE_MAX-1)
377 *
378 * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to
379 * undefine the partno.
380 *
381 * Returns: 0 on success, <0 on error.
382 */
fdisk_partition_set_partno(struct fdisk_partition * pa,size_t num)383 int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num)
384 {
385 if (!pa)
386 return -EINVAL;
387 if (FDISK_IS_UNDEF(num))
388 return -ERANGE;
389 pa->partno = num;
390 return 0;
391 }
392
393 /**
394 * fdisk_partition_unset_partno:
395 * @pa: partition
396 *
397 * Sets the partno as undefined. See fdisk_partition_has_partno().
398 *
399 * Returns: 0 on success, <0 on error.
400 */
fdisk_partition_unset_partno(struct fdisk_partition * pa)401 int fdisk_partition_unset_partno(struct fdisk_partition *pa)
402 {
403 if (!pa)
404 return -EINVAL;
405 FDISK_INIT_UNDEF(pa->partno);
406 return 0;
407 }
408
409 /**
410 * fdisk_partition_get_partno:
411 * @pa: partition
412 *
413 * The zero is also valid partition number. The function may return random
414 * value when partno is undefined (for example after fdisk_partition_unset_partno()).
415 * Always use fdisk_partition_has_partno() to be sure that you work with valid
416 * numbers.
417 *
418 * Returns: partition number (0 is the first partition)
419 */
fdisk_partition_get_partno(struct fdisk_partition * pa)420 size_t fdisk_partition_get_partno(struct fdisk_partition *pa)
421 {
422 return pa->partno;
423 }
424
425 /**
426 * fdisk_partition_has_partno:
427 * @pa: partition
428 *
429 * Returns: 1 or 0
430 */
fdisk_partition_has_partno(struct fdisk_partition * pa)431 int fdisk_partition_has_partno(struct fdisk_partition *pa)
432 {
433 return pa && !FDISK_IS_UNDEF(pa->partno);
434 }
435
436
437 /**
438 * fdisk_partition_cmp_partno:
439 * @a: partition
440 * @b: partition
441 *
442 * Compares partitions according to partition number See fdisk_table_sort_partitions().
443 *
444 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
445 */
fdisk_partition_cmp_partno(struct fdisk_partition * a,struct fdisk_partition * b)446 int fdisk_partition_cmp_partno(struct fdisk_partition *a,
447 struct fdisk_partition *b)
448 {
449 return a->partno - b->partno;
450 }
451
452 /**
453 * fdisk_partition_partno_follow_default
454 * @pa: partition
455 * @enable: 0|1
456 *
457 * When @pa used as a template for fdisk_add_partition() when force label driver
458 * to add a new partition to the default (next) position.
459 *
460 * Returns: 0 on success, <0 on error.
461 */
fdisk_partition_partno_follow_default(struct fdisk_partition * pa,int enable)462 int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable)
463 {
464 if (!pa)
465 return -EINVAL;
466 pa->partno_follow_default = enable ? 1 : 0;
467 return 0;
468 }
469
470 /**
471 * fdisk_partition_set_type:
472 * @pa: partition
473 * @type: partition type
474 *
475 * Sets partition type.
476 *
477 * Returns: 0 on success, <0 on error.
478 */
fdisk_partition_set_type(struct fdisk_partition * pa,struct fdisk_parttype * type)479 int fdisk_partition_set_type(struct fdisk_partition *pa,
480 struct fdisk_parttype *type)
481 {
482 if (!pa)
483 return -EINVAL;
484
485 fdisk_ref_parttype(type);
486 fdisk_unref_parttype(pa->type);
487 pa->type = type;
488
489 return 0;
490 }
491
492 /**
493 * fdisk_partition_get_type:
494 * @pa: partition
495 *
496 * Returns: pointer to partition type.
497 */
fdisk_partition_get_type(struct fdisk_partition * pa)498 struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
499 {
500 return pa ? pa->type : NULL;
501 }
502
503 /**
504 * fdisk_partition_set_name:
505 * @pa: partition
506 * @name: partition name
507 *
508 * Returns: 0 on success, <0 on error.
509 */
fdisk_partition_set_name(struct fdisk_partition * pa,const char * name)510 int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name)
511 {
512 if (!pa)
513 return -EINVAL;
514 return strdup_to_struct_member(pa, name, name);
515 }
516
517 /**
518 * fdisk_partition_get_name:
519 * @pa: partition
520 *
521 * Returns: partition name
522 */
fdisk_partition_get_name(struct fdisk_partition * pa)523 const char *fdisk_partition_get_name(struct fdisk_partition *pa)
524 {
525 return pa ? pa->name : NULL;
526 }
527
528 /**
529 * fdisk_partition_set_uuid:
530 * @pa: partition
531 * @uuid: UUID of the partition
532 *
533 * Returns: 0 on success, <0 on error.
534 */
fdisk_partition_set_uuid(struct fdisk_partition * pa,const char * uuid)535 int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid)
536 {
537 if (!pa)
538 return -EINVAL;
539 return strdup_to_struct_member(pa, uuid, uuid);
540 }
541
542 /**
543 * fdisk_partition_has_end:
544 * @pa: partition
545 *
546 * Returns: 1 if the partition has defined last sector
547 */
fdisk_partition_has_end(struct fdisk_partition * pa)548 int fdisk_partition_has_end(struct fdisk_partition *pa)
549 {
550 return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size);
551 }
552
553 /**
554 * fdisk_partition_get_end:
555 * @pa: partition
556 *
557 * This function may returns absolute non-sense, always check
558 * fdisk_partition_has_end().
559 *
560 * Note that partition end is defined by fdisk_partition_set_start() and
561 * fdisk_partition_set_size().
562 *
563 * Returns: last partition sector LBA.
564 */
fdisk_partition_get_end(struct fdisk_partition * pa)565 fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa)
566 {
567 return pa->start + pa->size - (pa->size == 0 ? 0 : 1);
568 }
569
570 /**
571 * fdisk_partition_end_follow_default
572 * @pa: partition
573 * @enable: 0|1
574 *
575 * When @pa used as a template for fdisk_add_partition() when force label
576 * driver to use all the possible space for the new partition.
577 *
578 * Returns: 0 on success, <0 on error.
579 */
fdisk_partition_end_follow_default(struct fdisk_partition * pa,int enable)580 int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable)
581 {
582 if (!pa)
583 return -EINVAL;
584 pa->end_follow_default = enable ? 1 : 0;
585 return 0;
586 }
587
588 /**
589 * fdisk_partition_end_is_default:
590 * @pa: partition
591 *
592 * Returns: 1 if the partition follows default
593 */
fdisk_partition_end_is_default(struct fdisk_partition * pa)594 int fdisk_partition_end_is_default(struct fdisk_partition *pa)
595 {
596 assert(pa);
597 return pa->end_follow_default;
598 }
599
600 /**
601 * fdisk_partition_get_uuid:
602 * @pa: partition
603 *
604 * Returns: partition UUID as string
605 */
fdisk_partition_get_uuid(struct fdisk_partition * pa)606 const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
607 {
608 return pa ? pa->uuid : NULL;
609 }
610
611 /**
612 * fdisk_partition_get_attrs:
613 * @pa: partition
614 *
615 * Returns: partition attributes in string format
616 */
fdisk_partition_get_attrs(struct fdisk_partition * pa)617 const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
618 {
619 return pa ? pa->attrs : NULL;
620 }
621
622 /**
623 * fdisk_partition_set_attrs:
624 * @pa: partition
625 * @attrs: attributes
626 *
627 * Sets @attrs to @pa.
628 *
629 * Return: 0 on success, <0 on error.
630 */
fdisk_partition_set_attrs(struct fdisk_partition * pa,const char * attrs)631 int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs)
632 {
633 if (!pa)
634 return -EINVAL;
635 return strdup_to_struct_member(pa, attrs, attrs);
636 }
637
638 /**
639 * fdisk_partition_is_nested:
640 * @pa: partition
641 *
642 * Returns: 1 if the partition is nested (e.g. MBR logical partition)
643 */
fdisk_partition_is_nested(struct fdisk_partition * pa)644 int fdisk_partition_is_nested(struct fdisk_partition *pa)
645 {
646 return pa && !FDISK_IS_UNDEF(pa->parent_partno);
647 }
648
649 /**
650 * fdisk_partition_is_container:
651 * @pa: partition
652 *
653 * Returns: 1 if the partition is container (e.g. MBR extended partition)
654 */
fdisk_partition_is_container(struct fdisk_partition * pa)655 int fdisk_partition_is_container(struct fdisk_partition *pa)
656 {
657 return pa && pa->container;
658 }
659
660 /**
661 * fdisk_partition_get_parent:
662 * @pa: partition
663 * @parent: parent parno
664 *
665 * Returns: returns devno of the parent
666 */
fdisk_partition_get_parent(struct fdisk_partition * pa,size_t * parent)667 int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
668 {
669 if (pa && parent)
670 *parent = pa->parent_partno;
671 else
672 return -EINVAL;
673 return 0;
674 }
675
676 /**
677 * fdisk_partition_is_used:
678 * @pa: partition
679 *
680 * Returns: 1 if the partition points to some area
681 */
fdisk_partition_is_used(struct fdisk_partition * pa)682 int fdisk_partition_is_used(struct fdisk_partition *pa)
683 {
684 return pa && pa->used;
685 }
686
687 /**
688 * fdisk_partition_is_bootable:
689 * @pa: partition
690 *
691 * Returns: 1 if the partition has enabled boot flag
692 */
fdisk_partition_is_bootable(struct fdisk_partition * pa)693 int fdisk_partition_is_bootable(struct fdisk_partition *pa)
694 {
695 return pa && pa->boot == 1;
696 }
697
698 /**
699 * fdisk_partition_is_freespace:
700 * @pa: partition
701 *
702 * Returns: 1 if @pa points to freespace
703 */
fdisk_partition_is_freespace(struct fdisk_partition * pa)704 int fdisk_partition_is_freespace(struct fdisk_partition *pa)
705 {
706 return pa && pa->freespace;
707 }
708
709 /**
710 * fdisk_partition_is_wholedisk:
711 * @pa: partition
712 *
713 * Returns: 1 if the partition is special whole-disk (e.g. SUN) partition
714 */
fdisk_partition_is_wholedisk(struct fdisk_partition * pa)715 int fdisk_partition_is_wholedisk(struct fdisk_partition *pa)
716 {
717 return pa && pa->wholedisk;
718 }
719
720 /**
721 * fdisk_partition_next_partno:
722 * @pa: partition
723 * @cxt: context
724 * @n: returns partition number
725 *
726 * If @pa specified and partno-follow-default (see fdisk_partition_partno_follow_default())
727 * enabled then returns next expected partno or -ERANGE on error.
728 *
729 * If @pa is NULL, or @pa does not specify any semantic for the next partno
730 * then use Ask API to ask user for the next partno. In this case returns 1 if
731 * no free partition available. If fdisk dialogs are disabled then returns -EINVAL.
732 *
733 * Returns: 0 on success, <0 on error, or 1 for non-free partno by Ask API.
734 */
fdisk_partition_next_partno(struct fdisk_partition * pa,struct fdisk_context * cxt,size_t * n)735 int fdisk_partition_next_partno(
736 struct fdisk_partition *pa,
737 struct fdisk_context *cxt,
738 size_t *n)
739 {
740 if (!cxt || !n)
741 return -EINVAL;
742
743 if (pa && pa->partno_follow_default) {
744 size_t i;
745
746 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
747
748 for (i = 0; i < cxt->label->nparts_max; i++) {
749 if (!fdisk_is_partition_used(cxt, i)) {
750 *n = i;
751 return 0;
752 }
753 }
754 return -ERANGE;
755
756 }
757
758 if (pa && fdisk_partition_has_partno(pa)) {
759
760 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
761
762 if (pa->partno >= cxt->label->nparts_max ||
763 fdisk_is_partition_used(cxt, pa->partno))
764 return -ERANGE;
765 *n = pa->partno;
766 return 0;
767
768 }
769
770 if (fdisk_has_dialogs(cxt))
771 return fdisk_ask_partnum(cxt, n, 1);
772
773 return -EINVAL;
774 }
775
probe_partition_content(struct fdisk_context * cxt,struct fdisk_partition * pa)776 static int probe_partition_content(struct fdisk_context *cxt, struct fdisk_partition *pa)
777 {
778 int rc = 1; /* nothing */
779
780 DBG(PART, ul_debugobj(pa, "start probe #%zu partition [cxt %p] >>>", pa->partno, cxt));
781
782 /* zeroize the current setting */
783 strdup_to_struct_member(pa, fstype, NULL);
784 strdup_to_struct_member(pa, fsuuid, NULL);
785 strdup_to_struct_member(pa, fslabel, NULL);
786
787 if (!fdisk_partition_has_start(pa) ||
788 !fdisk_partition_has_size(pa))
789 goto done;
790
791 #ifdef HAVE_LIBBLKID
792 else {
793 uintmax_t start, size;
794
795 blkid_probe pr = blkid_new_probe();
796 if (!pr)
797 goto done;
798
799 DBG(PART, ul_debugobj(pa, "blkid prober: %p", pr));
800
801 start = fdisk_partition_get_start(pa) * fdisk_get_sector_size(cxt);
802 size = fdisk_partition_get_size(pa) * fdisk_get_sector_size(cxt);
803
804 if (blkid_probe_set_device(pr, cxt->dev_fd, start, size) == 0
805 && blkid_do_fullprobe(pr) == 0) {
806
807 const char *data;
808 rc = 0;
809
810 if (!blkid_probe_lookup_value(pr, "TYPE", &data, NULL))
811 rc = strdup_to_struct_member(pa, fstype, data);
812
813 if (!rc && !blkid_probe_lookup_value(pr, "LABEL", &data, NULL))
814 rc = strdup_to_struct_member(pa, fslabel, data);
815
816 if (!rc && !blkid_probe_lookup_value(pr, "UUID", &data, NULL))
817 rc = strdup_to_struct_member(pa, fsuuid, data);
818 }
819
820 blkid_free_probe(pr);
821 pa->fs_probed = 1;
822 }
823 #endif /* HAVE_LIBBLKID */
824
825 done:
826 DBG(PART, ul_debugobj(pa, "<<< end probe #%zu partition[cxt %p, rc=%d]", pa->partno, cxt, rc));
827 return rc;
828 }
829
830 /**
831 * fdisk_partition_to_string:
832 * @pa: partition
833 * @cxt: context
834 * @id: field (FDISK_FIELD_*)
835 * @data: returns string with allocated data
836 *
837 * Returns info about partition converted to printable string.
838 *
839 * For example
840 * <informalexample>
841 * <programlisting>
842 * struct fdisk_partition *pa;
843 *
844 * fdisk_get_partition(cxt, 0, &pa);
845 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
846 * printf("first partition uuid: %s\n", data);
847 * free(data);
848 * fdisk_unref_partition(pa);
849 * </programlisting>
850 * </informalexample>
851 *
852 * returns UUID for the first partition.
853 *
854 * Returns: 0 on success, otherwise, a corresponding error.
855 */
fdisk_partition_to_string(struct fdisk_partition * pa,struct fdisk_context * cxt,int id,char ** data)856 int fdisk_partition_to_string(struct fdisk_partition *pa,
857 struct fdisk_context *cxt,
858 int id,
859 char **data)
860 {
861 char *p = NULL;
862 int rc = 0;
863 uint64_t x;
864
865 if (!pa || !cxt || !data)
866 return -EINVAL;
867
868 switch (id) {
869 case FDISK_FIELD_DEVICE:
870 if (pa->freespace)
871 p = strdup(_("Free space"));
872 else if (fdisk_partition_has_partno(pa) && cxt->dev_path) {
873 if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
874 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
875 else
876 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
877 }
878 break;
879 case FDISK_FIELD_BOOT:
880 p = fdisk_partition_is_bootable(pa) ? strdup("*") : NULL;
881 break;
882 case FDISK_FIELD_START:
883 if (fdisk_partition_has_start(pa)) {
884 x = fdisk_cround(cxt, pa->start);
885 rc = pa->start_post ?
886 asprintf(&p, "%"PRIu64"%c", x, pa->start_post) :
887 asprintf(&p, "%"PRIu64, x);
888 }
889 break;
890 case FDISK_FIELD_END:
891 if (fdisk_partition_has_end(pa)) {
892 x = fdisk_cround(cxt, fdisk_partition_get_end(pa));
893 rc = pa->end_post ?
894 asprintf(&p, "%"PRIu64"%c", x, pa->end_post) :
895 asprintf(&p, "%"PRIu64, x);
896 }
897 break;
898 case FDISK_FIELD_SIZE:
899 if (fdisk_partition_has_size(pa)) {
900 uint64_t sz = pa->size * cxt->sector_size;
901
902 switch (cxt->sizeunit) {
903 case FDISK_SIZEUNIT_BYTES:
904 rc = asprintf(&p, "%"PRIu64"", sz);
905 break;
906 case FDISK_SIZEUNIT_HUMAN:
907 if (fdisk_is_details(cxt))
908 rc = pa->size_post ?
909 asprintf(&p, "%"PRIu64"%c", sz, pa->size_post) :
910 asprintf(&p, "%"PRIu64, sz);
911 else {
912 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
913 if (!p)
914 rc = -ENOMEM;
915 }
916 break;
917 }
918 }
919 break;
920 case FDISK_FIELD_CYLINDERS:
921 {
922 uintmax_t sz = fdisk_partition_has_size(pa) ? pa->size : 0;
923 if (sz)
924 /* Why we need to cast that to uintmax_t? */
925 rc = asprintf(&p, "%ju", (uintmax_t)(sz / (cxt->geom.heads * cxt->geom.sectors)) + 1);
926 break;
927 }
928 case FDISK_FIELD_SECTORS:
929 rc = asprintf(&p, "%ju",
930 fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0);
931 break;
932 case FDISK_FIELD_BSIZE:
933 rc = asprintf(&p, "%"PRIu64, pa->bsize);
934 break;
935 case FDISK_FIELD_FSIZE:
936 rc = asprintf(&p, "%"PRIu64, pa->fsize);
937 break;
938 case FDISK_FIELD_CPG:
939 rc = asprintf(&p, "%"PRIu64, pa->cpg);
940 break;
941 case FDISK_FIELD_TYPE:
942 p = pa->type && pa->type->name ? strdup(_(pa->type->name)) : NULL;
943 break;
944 case FDISK_FIELD_TYPEID:
945 if (pa->type && fdisk_parttype_get_string(pa->type))
946 rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
947 else if (pa->type)
948 rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
949 break;
950 case FDISK_FIELD_UUID:
951 p = pa->uuid && *pa->uuid? strdup(pa->uuid) : NULL;
952 break;
953 case FDISK_FIELD_NAME:
954 p = pa->name && *pa->name ? strdup(pa->name) : NULL;
955 break;
956 case FDISK_FIELD_ATTR:
957 p = pa->attrs && *pa->attrs ? strdup(pa->attrs) : NULL;
958 break;
959 case FDISK_FIELD_SADDR:
960 p = pa->start_chs && *pa->start_chs ? strdup(pa->start_chs) : NULL;
961 break;
962 case FDISK_FIELD_EADDR:
963 p = pa->end_chs && *pa->end_chs? strdup(pa->end_chs) : NULL;
964 break;
965 case FDISK_FIELD_FSUUID:
966 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
967 p = pa->fsuuid && *pa->fsuuid ? strdup(pa->fsuuid) : NULL;
968 break;
969 case FDISK_FIELD_FSLABEL:
970 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
971 p = pa->fslabel && *pa->fslabel ? strdup(pa->fslabel) : NULL;
972 break;
973 case FDISK_FIELD_FSTYPE:
974 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
975 p = pa->fstype && *pa->fstype ? strdup(pa->fstype) : NULL;
976 break;
977 default:
978 return -EINVAL;
979 }
980
981 if (rc < 0) {
982 rc = -ENOMEM;
983 free(p);
984 p = NULL;
985
986 } else if (rc > 0)
987 rc = 0;
988
989 *data = p;
990
991 return rc;
992 }
993
994
995 /**
996 * fdisk_get_partition:
997 * @cxt: context
998 * @partno: partition number (0 is the first partition)
999 * @pa: returns data about partition
1000 *
1001 * Reads disklabel and fills in @pa with data about partition @n.
1002 *
1003 * Note that partno may address unused partition and then this function does
1004 * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to
1005 * NULL then the function allocates a newly allocated fdisk_partition struct,
1006 * use fdisk_unref_partition() to deallocate.
1007 *
1008 * Returns: 0 on success, otherwise, a corresponding error.
1009 */
fdisk_get_partition(struct fdisk_context * cxt,size_t partno,struct fdisk_partition ** pa)1010 int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
1011 struct fdisk_partition **pa)
1012 {
1013 int rc;
1014 struct fdisk_partition *np = NULL;
1015
1016 if (!cxt || !cxt->label || !pa)
1017 return -EINVAL;
1018 if (!cxt->label->op->get_part)
1019 return -ENOSYS;
1020 if (!fdisk_is_partition_used(cxt, partno))
1021 return -EINVAL;
1022
1023 if (!*pa) {
1024 np = *pa = fdisk_new_partition();
1025 if (!*pa)
1026 return -ENOMEM;
1027 } else
1028 fdisk_reset_partition(*pa);
1029
1030 (*pa)->partno = partno;
1031 rc = cxt->label->op->get_part(cxt, partno, *pa);
1032
1033 if (rc) {
1034 if (np) {
1035 fdisk_unref_partition(np);
1036 *pa = NULL;
1037 } else
1038 fdisk_reset_partition(*pa);
1039 } else
1040 (*pa)->size_explicit = 1;
1041 return rc;
1042 }
1043
resize_get_by_offset(struct fdisk_table * tb,struct fdisk_partition * cur,fdisk_sector_t off)1044 static struct fdisk_partition *resize_get_by_offset(
1045 struct fdisk_table *tb,
1046 struct fdisk_partition *cur,
1047 fdisk_sector_t off)
1048 {
1049 struct fdisk_partition *pa = NULL;
1050 struct fdisk_iter itr;
1051
1052 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
1053
1054 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
1055 if (!fdisk_partition_has_start(pa) || !fdisk_partition_has_size(pa))
1056 continue;
1057 if (fdisk_partition_is_nested(cur) &&
1058 pa->parent_partno != cur->parent_partno)
1059 continue;
1060 if (off >= pa->start && off < pa->start + pa->size)
1061 return pa;
1062 }
1063
1064 return NULL;
1065 }
1066
1067 /*
1068 * Verify that area addressed by @start is freespace or the @cur[rent]
1069 * partition and continue to the next table entries until it's freespace, and
1070 * counts size of all this space.
1071 *
1072 * This is core of the partition start offset move operation. We can move the
1073 * start within the current partition of to the another free space. It's
1074 * forbidden to move start of the partition to another already defined
1075 * partition.
1076 */
resize_get_last_possible(struct fdisk_table * tb,struct fdisk_partition * cur,fdisk_sector_t start,fdisk_sector_t * maxsz)1077 static int resize_get_last_possible(
1078 struct fdisk_table *tb,
1079 struct fdisk_partition *cur,
1080 fdisk_sector_t start,
1081 fdisk_sector_t *maxsz)
1082 {
1083 struct fdisk_partition *pa = NULL, *last = NULL;
1084 struct fdisk_iter itr;
1085
1086 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
1087
1088 *maxsz = 0;
1089 DBG(TAB, ul_debugobj(tb, "checking last possible for start=%ju", (uintmax_t) start));
1090
1091
1092 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
1093
1094 DBG(TAB, ul_debugobj(tb, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]",
1095 pa,
1096 fdisk_partition_get_partno(pa),
1097 (uintmax_t) fdisk_partition_get_start(pa),
1098 (uintmax_t) fdisk_partition_get_end(pa),
1099 (uintmax_t) fdisk_partition_get_size(pa),
1100 fdisk_partition_is_freespace(pa) ? " freespace" : "",
1101 fdisk_partition_is_nested(pa) ? " nested" : "",
1102 fdisk_partition_is_container(pa) ? " container" : ""));
1103
1104 if (!fdisk_partition_has_start(pa) ||
1105 !fdisk_partition_has_size(pa) ||
1106 (fdisk_partition_is_container(pa) && pa != cur)) {
1107 DBG(TAB, ul_debugobj(tb, " ignored (no start/size or container)"));
1108 continue;
1109 }
1110
1111 if (fdisk_partition_is_nested(pa)
1112 && fdisk_partition_is_container(cur)
1113 && pa->parent_partno == cur->partno) {
1114 DBG(TAB, ul_debugobj(tb, " ignore (nested child of the current partition)"));
1115 continue;
1116 }
1117
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)"));
1122 continue;
1123 }
1124
1125 if (!last) {
1126 if (start >= pa->start && start < pa->start + pa->size) {
1127 if (fdisk_partition_is_freespace(pa) || pa == cur) {
1128 DBG(TAB, ul_debugobj(tb, " accepted as last"));
1129 last = pa;
1130 } else {
1131 DBG(TAB, ul_debugobj(tb, " failed to set last"));
1132 break;
1133 }
1134
1135
1136 *maxsz = pa->size - (start - pa->start);
1137 DBG(TAB, ul_debugobj(tb, " new max=%ju", (uintmax_t) *maxsz));
1138 }
1139 } else if (!fdisk_partition_is_freespace(pa) && pa != cur) {
1140 DBG(TAB, ul_debugobj(tb, " no free space behind current"));
1141 break;
1142 } else {
1143 last = pa;
1144 *maxsz = pa->size - (start - pa->start);
1145 DBG(TAB, ul_debugobj(tb, " new max=%ju (last updated)", (uintmax_t) *maxsz));
1146 }
1147 }
1148
1149 if (last)
1150 DBG(PART, ul_debugobj(cur, "resize: max size=%ju", (uintmax_t) *maxsz));
1151 else
1152 DBG(PART, ul_debugobj(cur, "resize: nothing usable after %ju", (uintmax_t) start));
1153
1154 return last ? 0 : -1;
1155 }
1156
1157 /*
1158 * Uses template @tpl to recount start and size change of the partition @res. The
1159 * @tpl->size and @tpl->start are interpreted as relative to the current setting.
1160 */
recount_resize(struct fdisk_context * cxt,size_t partno,struct fdisk_partition * res,struct fdisk_partition * tpl)1161 static int recount_resize(
1162 struct fdisk_context *cxt, size_t partno,
1163 struct fdisk_partition *res, struct fdisk_partition *tpl)
1164 {
1165 fdisk_sector_t start, size, xsize;
1166 struct fdisk_partition *cur = NULL;
1167 struct fdisk_table *tb = NULL;
1168 int rc;
1169
1170 DBG(PART, ul_debugobj(tpl, ">>> resize requested"));
1171
1172 FDISK_INIT_UNDEF(start);
1173 FDISK_INIT_UNDEF(size);
1174
1175 rc = fdisk_get_partitions(cxt, &tb);
1176 if (!rc) {
1177 /* For resize we do not follow grain to detect free-space, but
1178 * we support to resize with very small granulation. */
1179 unsigned long org = cxt->grain;
1180
1181 cxt->grain = cxt->sector_size;
1182 rc = fdisk_get_freespaces(cxt, &tb);
1183 cxt->grain = org;
1184 }
1185 if (rc) {
1186 fdisk_unref_table(tb);
1187 return rc;
1188 }
1189
1190 fdisk_table_sort_partitions(tb, fdisk_partition_cmp_start);
1191
1192 DBG(PART, ul_debugobj(tpl, "resize partition partno=%zu in table:", partno));
1193 ON_DBG(PART, fdisk_debug_print_table(tb));
1194
1195 cur = fdisk_table_get_partition_by_partno(tb, partno);
1196 if (!cur) {
1197 fdisk_unref_table(tb);
1198 return -EINVAL;
1199 }
1200
1201 /* 1a) set new start - change relative to the current on-disk setting */
1202 if (tpl->movestart && fdisk_partition_has_start(tpl)) {
1203 start = fdisk_partition_get_start(cur);
1204 if (tpl->movestart == FDISK_MOVE_DOWN) {
1205 if (fdisk_partition_get_start(tpl) > start)
1206 goto erange;
1207 start -= fdisk_partition_get_start(tpl);
1208 } else
1209 start += fdisk_partition_get_start(tpl);
1210
1211 DBG(PART, ul_debugobj(tpl, "resize: moving start %s relative, new start: %ju",
1212 tpl->movestart == FDISK_MOVE_DOWN ? "DOWN" : "UP", (uintmax_t)start));
1213
1214 /* 1b) set new start - absolute number */
1215 } else if (fdisk_partition_has_start(tpl)) {
1216 start = fdisk_partition_get_start(tpl);
1217 DBG(PART, ul_debugobj(tpl, "resize: moving start to absolute offset: %ju",
1218 (uintmax_t)start));
1219 }
1220
1221 /* 2) verify that start is within the current partition or any freespace area */
1222 if (!FDISK_IS_UNDEF(start)) {
1223 struct fdisk_partition *area = resize_get_by_offset(tb, cur, start);
1224
1225 if (area == cur)
1226 DBG(PART, ul_debugobj(tpl, "resize: start points to the current partition"));
1227 else if (area && fdisk_partition_is_freespace(area))
1228 DBG(PART, ul_debugobj(tpl, "resize: start points to freespace"));
1229 else if (!area && start >= cxt->first_lba && start < cxt->first_lba + (cxt->grain / cxt->sector_size))
1230 DBG(PART, ul_debugobj(tpl, "resize: start points before first partition"));
1231 else {
1232 DBG(PART, ul_debugobj(tpl, "resize: start verification failed"));
1233 goto erange;
1234 }
1235 } else {
1236 /* no change, start points to the current partition */
1237 DBG(PART, ul_debugobj(tpl, "resize: start unchanged"));
1238 start = fdisk_partition_get_start(cur);
1239 }
1240
1241 /* 3a) set new size -- reduce */
1242 if (tpl->resize == FDISK_RESIZE_REDUCE && fdisk_partition_has_size(tpl)) {
1243 DBG(PART, ul_debugobj(tpl, "resize: reduce"));
1244 size = fdisk_partition_get_size(cur);
1245 if (fdisk_partition_get_size(tpl) > size)
1246 goto erange;
1247 size -= fdisk_partition_get_size(tpl);
1248
1249 /* 3b) set new size -- enlarge */
1250 } else if (tpl->resize == FDISK_RESIZE_ENLARGE && fdisk_partition_has_size(tpl)) {
1251 DBG(PART, ul_debugobj(tpl, "resize: enlarge"));
1252 size = fdisk_partition_get_size(cur);
1253 size += fdisk_partition_get_size(tpl);
1254
1255 /* 3c) set new size -- no size specified, enlarge to all freespace */
1256 } else if (tpl->resize == FDISK_RESIZE_ENLARGE) {
1257 DBG(PART, ul_debugobj(tpl, "resize: enlarge to all possible"));
1258 if (resize_get_last_possible(tb, cur, start, &size))
1259 goto erange;
1260
1261 /* 3d) set new size -- absolute number */
1262 } else if (fdisk_partition_has_size(tpl)) {
1263 DBG(PART, ul_debugobj(tpl, "resize: new absolute size"));
1264 size = fdisk_partition_get_size(tpl);
1265 }
1266
1267 /* 4) verify that size is within the current partition or next free space */
1268 xsize = !FDISK_IS_UNDEF(size) ? size : fdisk_partition_get_size(cur);
1269
1270 if (fdisk_partition_has_size(cur)) {
1271 fdisk_sector_t maxsz;
1272
1273 if (resize_get_last_possible(tb, cur, start, &maxsz))
1274 goto erange;
1275 DBG(PART, ul_debugobj(tpl, "resize: size=%ju, max=%ju",
1276 (uintmax_t) xsize, (uintmax_t) maxsz));
1277 if (xsize > maxsz)
1278 goto erange;
1279 }
1280
1281 if (FDISK_IS_UNDEF(size)) {
1282 DBG(PART, ul_debugobj(tpl, "resize: size unchanged (undefined)"));
1283 }
1284
1285
1286 DBG(PART, ul_debugobj(tpl, "<<< resize: SUCCESS: start %ju->%ju; size %ju->%ju",
1287 (uintmax_t) fdisk_partition_get_start(cur), (uintmax_t) start,
1288 (uintmax_t) fdisk_partition_get_size(cur), (uintmax_t) size));
1289 res->start = start;
1290 res->size = size;
1291 fdisk_unref_table(tb);
1292 return 0;
1293 erange:
1294 DBG(PART, ul_debugobj(tpl, "<<< resize: FAILED"));
1295 fdisk_warnx(cxt, _("Failed to resize partition #%zu."), partno + 1);
1296 fdisk_unref_table(tb);
1297 return -ERANGE;
1298
1299 }
1300
1301 /**
1302 * fdisk_set_partition:
1303 * @cxt: context
1304 * @partno: partition number (0 is the first partition)
1305 * @pa: new partition setting
1306 *
1307 * Modifies disklabel according to setting with in @pa.
1308 *
1309 * Returns: 0 on success, <0 on error.
1310 */
fdisk_set_partition(struct fdisk_context * cxt,size_t partno,struct fdisk_partition * pa)1311 int fdisk_set_partition(struct fdisk_context *cxt, size_t partno,
1312 struct fdisk_partition *pa)
1313 {
1314 struct fdisk_partition *xpa = pa, *tmp = NULL;
1315 int rc, wipe = 0;
1316
1317 if (!cxt || !cxt->label || !pa)
1318 return -EINVAL;
1319 if (!cxt->label->op->set_part)
1320 return -ENOSYS;
1321
1322 pa->fs_probed = 0;
1323
1324 if (!fdisk_is_partition_used(cxt, partno)) {
1325 pa->partno = partno;
1326 return fdisk_add_partition(cxt, pa, NULL);
1327 }
1328
1329 if (pa->resize || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) {
1330 xpa = __copy_partition(pa);
1331 if (!xpa) {
1332 rc = -ENOMEM;
1333 goto done;
1334 }
1335 xpa->movestart = 0;
1336 xpa->resize = 0;
1337 FDISK_INIT_UNDEF(xpa->size);
1338 FDISK_INIT_UNDEF(xpa->start);
1339
1340 rc = recount_resize(cxt, partno, xpa, pa);
1341 if (rc)
1342 goto done;
1343 }
1344
1345 DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju)",
1346 partno, xpa,
1347 (uintmax_t) fdisk_partition_get_start(xpa),
1348 (uintmax_t) fdisk_partition_get_end(xpa),
1349 (uintmax_t) fdisk_partition_get_size(xpa)));
1350
1351 /* disable wipe for old offset/size setting */
1352 if (fdisk_get_partition(cxt, partno, &tmp) == 0 && tmp) {
1353 wipe = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(tmp),
1354 fdisk_partition_get_size(tmp), FALSE);
1355 fdisk_unref_partition(tmp);
1356 }
1357
1358 /* call label driver */
1359 rc = cxt->label->op->set_part(cxt, partno, xpa);
1360
1361 /* enable wipe for new offset/size */
1362 if (!rc && wipe)
1363 fdisk_wipe_partition(cxt, partno, TRUE);
1364 done:
1365 DBG(CXT, ul_debugobj(cxt, "set_partition() rc=%d", rc));
1366 if (xpa != pa)
1367 fdisk_unref_partition(xpa);
1368 return rc;
1369 }
1370
1371 /**
1372 * fdisk_wipe_partition:
1373 * @cxt: fdisk context
1374 * @partno: partition number
1375 * @enable: 0 or 1
1376 *
1377 * Enable/disable filesystems/RAIDs wiping in area defined by partition start and size.
1378 *
1379 * Returns: <0 in case of error, 0 on success
1380 * Since: 2.29
1381 */
fdisk_wipe_partition(struct fdisk_context * cxt,size_t partno,int enable)1382 int fdisk_wipe_partition(struct fdisk_context *cxt, size_t partno, int enable)
1383 {
1384 struct fdisk_partition *pa = NULL;
1385 int rc;
1386
1387 rc = fdisk_get_partition(cxt, partno, &pa);
1388 if (rc)
1389 return rc;
1390
1391 rc = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(pa),
1392 fdisk_partition_get_size(pa), enable);
1393 fdisk_unref_partition(pa);
1394 return rc < 0 ? rc : 0;
1395 }
1396
1397 /**
1398 * fdisk_partition_has_wipe:
1399 * @cxt: fdisk context
1400 * @pa: partition
1401 *
1402 * Since: 2.30
1403 *
1404 * Returns: 1 if the area specified by @pa will be wiped by write command, or 0.
1405 */
fdisk_partition_has_wipe(struct fdisk_context * cxt,struct fdisk_partition * pa)1406 int fdisk_partition_has_wipe(struct fdisk_context *cxt, struct fdisk_partition *pa)
1407 {
1408 return fdisk_has_wipe_area(cxt, fdisk_partition_get_start(pa),
1409 fdisk_partition_get_size(pa));
1410 }
1411
1412
1413 /**
1414 * fdisk_add_partition:
1415 * @cxt: fdisk context
1416 * @pa: template for the partition (or NULL)
1417 * @partno: NULL or returns new partition number
1418 *
1419 * If @pa is not specified or any @pa item is missing the libfdisk will ask by
1420 * fdisk_ask_ API.
1421 *
1422 * The @pa template is important for non-interactive partitioning,
1423 * especially for MBR where is necessary to differentiate between
1424 * primary/logical; this is done by start offset or/and partno.
1425 * The rules for MBR:
1426 *
1427 * A) template specifies start within extended partition: add logical
1428 * B) template specifies start out of extended partition: add primary
1429 * C) template specifies start (or default), partno < 4: add primary
1430 * D) template specifies default start, partno >= 4: add logical
1431 *
1432 * otherwise MBR driver uses Ask-API to get missing information.
1433 *
1434 * Adds a new partition to disklabel.
1435 *
1436 * Returns: 0 on success, <0 on error.
1437 */
fdisk_add_partition(struct fdisk_context * cxt,struct fdisk_partition * pa,size_t * partno)1438 int fdisk_add_partition(struct fdisk_context *cxt,
1439 struct fdisk_partition *pa,
1440 size_t *partno)
1441 {
1442 int rc;
1443
1444 if (!cxt || !cxt->label)
1445 return -EINVAL;
1446 if (!cxt->label->op->add_part)
1447 return -ENOSYS;
1448 if (fdisk_missing_geometry(cxt))
1449 return -EINVAL;
1450
1451 if (pa) {
1452 pa->fs_probed = 0;
1453 DBG(CXT, ul_debugobj(cxt, "adding new partition %p", pa));
1454 if (fdisk_partition_has_start(pa))
1455 DBG(CXT, ul_debugobj(cxt, " start: %ju", (uintmax_t) fdisk_partition_get_start(pa)));
1456 if (fdisk_partition_has_end(pa))
1457 DBG(CXT, ul_debugobj(cxt, " end: %ju", (uintmax_t) fdisk_partition_get_end(pa)));
1458 if (fdisk_partition_has_size(pa))
1459 DBG(CXT, ul_debugobj(cxt, " size: %ju", (uintmax_t) fdisk_partition_get_size(pa)));
1460
1461 DBG(CXT, ul_debugobj(cxt, " defaults: start=%s, end=%s, partno=%s",
1462 pa->start_follow_default ? "yes" : "no",
1463 pa->end_follow_default ? "yes" : "no",
1464 pa->partno_follow_default ? "yes" : "no"));
1465 } else
1466 DBG(CXT, ul_debugobj(cxt, "adding partition"));
1467
1468 rc = cxt->label->op->add_part(cxt, pa, partno);
1469
1470 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
1471 return rc;
1472 }
1473
1474 /**
1475 * fdisk_delete_partition:
1476 * @cxt: fdisk context
1477 * @partno: partition number to delete (0 is the first partition)
1478 *
1479 * Deletes a @partno partition from disklabel.
1480 *
1481 * Returns: 0 on success, <0 on error
1482 */
fdisk_delete_partition(struct fdisk_context * cxt,size_t partno)1483 int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno)
1484 {
1485 if (!cxt || !cxt->label)
1486 return -EINVAL;
1487 if (!cxt->label->op->del_part)
1488 return -ENOSYS;
1489
1490 fdisk_wipe_partition(cxt, partno, 0);
1491
1492 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
1493 cxt->label->name, partno));
1494 return cxt->label->op->del_part(cxt, partno);
1495 }
1496
1497 /**
1498 * fdisk_delete_all_partitions:
1499 * @cxt: fdisk context
1500 *
1501 * Delete all used partitions from disklabel.
1502 *
1503 * Returns: 0 on success, otherwise, a corresponding error.
1504 */
fdisk_delete_all_partitions(struct fdisk_context * cxt)1505 int fdisk_delete_all_partitions(struct fdisk_context *cxt)
1506 {
1507 size_t i;
1508 int rc = 0;
1509
1510 if (!cxt || !cxt->label)
1511 return -EINVAL;
1512
1513 for (i = 0; i < cxt->label->nparts_max; i++) {
1514
1515 if (!fdisk_is_partition_used(cxt, i))
1516 continue;
1517 rc = fdisk_delete_partition(cxt, i);
1518 if (rc)
1519 break;
1520 }
1521
1522 return rc;
1523 }
1524
1525 /**
1526 * fdisk_is_partition_used:
1527 * @cxt: context
1528 * @n: partition number (0 is the first partition)
1529 *
1530 * Check if the partition number @n is used by partition table. This function
1531 * does not check if the device is used (e.g. mounted) by system!
1532 *
1533 * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
1534 *
1535 * Returns: 0 or 1
1536 */
fdisk_is_partition_used(struct fdisk_context * cxt,size_t n)1537 int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
1538 {
1539 if (!cxt || !cxt->label)
1540 return -EINVAL;
1541 if (!cxt->label->op->part_is_used)
1542 return -ENOSYS;
1543
1544 return cxt->label->op->part_is_used(cxt, n);
1545 }
1546
1547