]>
Commit | Line | Data |
---|---|---|
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 | |
24 | static 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 |
40 | struct 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 |
58 | void 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 |
84 | static 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 |
141 | void 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 | 154 | void 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 | 178 | int 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 | */ | |
197 | int 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 | 217 | fdisk_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 | */ | |
228 | int 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 |
243 | int 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 | 270 | int 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 | 286 | int 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 | 302 | int 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 | */ | |
321 | int 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 | 341 | fdisk_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 | */ | |
352 | int 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 | */ | |
368 | int 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 | */ | |
386 | int 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 | 404 | int 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 |
423 | size_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 | */ | |
434 | int 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 |
449 | int 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 | */ | |
465 | int 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 | 482 | int 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 | */ | |
501 | struct 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 |
513 | int 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 |
526 | const 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 |
538 | int 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 | */ | |
551 | int 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 | */ | |
568 | fdisk_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 |
583 | int 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 | */ | |
597 | int 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 |
609 | const 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 |
620 | const 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 |
634 | int 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 | 647 | int 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 | 658 | int 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 |
670 | int 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 |
685 | int 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 |
696 | int 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 |
707 | int 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 |
718 | int 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 | 738 | int 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 |
779 | static 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 | ||
836 | done: | |
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 | 867 | int 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 | */ | |
1021 | int 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 | 1055 | static 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 |
1078 | static 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 | */ | |
1149 | static 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 | */ | |
1233 | static 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; | |
1374 | erange: | |
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 | */ | |
1392 | int 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 | 1446 | done: |
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 | */ |
1464 | int 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 | */ | |
1488 | int 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 | */ |
1520 | int 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 | 1565 | int 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 | */ | |
1587 | int 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 | */ |
1619 | int 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 | */ | |
1641 | int 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 | ||
1671 | out: | |
1672 | fdisk_unref_partition(cur); | |
1673 | fdisk_unref_table(tb); | |
1674 | ||
1675 | return rc; | |
1676 | ||
1677 | einval: | |
1678 | rc = -EINVAL; | |
1679 | goto out; | |
1680 | } |