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