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