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