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