]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/partition.c
libfdisk: add fdisk_partition_is_bootable()
[thirdparty/util-linux.git] / libfdisk / src / partition.c
1
2 #include "c.h"
3 #include "strutils.h"
4
5 #include "fdiskP.h"
6
7 /**
8 * fdisk_new_partition:
9 *
10 * Returns: new instance.
11 */
12 struct fdisk_partition *fdisk_new_partition(void)
13 {
14 struct fdisk_partition *pa = calloc(1, sizeof(*pa));
15
16 pa->refcount = 1;
17 INIT_LIST_HEAD(&pa->parts);
18 pa->partno = FDISK_EMPTY_PARTNO;
19 pa->parent_partno = FDISK_EMPTY_PARTNO;
20 DBG(PART, ul_debugobj(pa, "alloc"));
21 return pa;
22 }
23
24 /**
25 * fdisk_reset_partition:
26 * @pa: partition
27 *
28 * Resets partition content.
29 */
30 void fdisk_reset_partition(struct fdisk_partition *pa)
31 {
32 int ref;
33
34 if (!pa)
35 return;
36
37 DBG(PART, ul_debugobj(pa, "reset"));
38 ref = pa->refcount;
39 fdisk_free_parttype(pa->type);
40 free(pa->name);
41 free(pa->uuid);
42 free(pa->attrs);
43 memset(pa, 0, sizeof(*pa));
44 pa->partno = FDISK_EMPTY_PARTNO;
45 pa->parent_partno = FDISK_EMPTY_PARTNO;
46 pa->refcount = ref;
47 INIT_LIST_HEAD(&pa->parts);
48 }
49
50 /**
51 * fdisk_ref_partition:
52 * @tb: partition pointer
53 *
54 * Incremparts reference counter.
55 */
56 void fdisk_ref_partition(struct fdisk_partition *pa)
57 {
58 if (pa)
59 pa->refcount++;
60 }
61
62 /**
63 * fdisk_unref_partition:
64 * @tb: partition pointer
65 *
66 * De-incremparts reference counter, on zero the @tb is automatically
67 * deallocated.
68 */
69 void fdisk_unref_partition(struct fdisk_partition *pa)
70 {
71 if (!pa)
72 return;
73
74 pa->refcount--;
75 if (pa->refcount <= 0) {
76 DBG(PART, ul_debugobj(pa, "free"));
77 fdisk_reset_partition(pa);
78 list_del(&pa->parts);
79 free(pa);
80 }
81 }
82
83 /**
84 * fdisk_partition_set_start:
85 * @pa: partition
86 * @off: offset in sectors
87 *
88 * Returns: 0 on success, <0 on error.
89 */
90 int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off)
91 {
92 if (!pa)
93 return -EINVAL;
94 pa->start = off;
95 return 0;
96 }
97
98 /**
99 * fdisk_partition_get_start:
100 * @pa: partition
101 *
102 * Returns: start offset in sectors
103 */
104 uint64_t fdisk_partition_get_start(struct fdisk_partition *pa)
105 {
106 return pa ? pa->start : 0;
107 }
108
109 /**
110 * fdisk_partition_cmp_start:
111 * @a: partition
112 * @b: partition
113 * See fdisk_sort_table().
114 */
115 int fdisk_partition_cmp_start(struct fdisk_partition *a,
116 struct fdisk_partition *b)
117 {
118 return a->start - b->start;
119 }
120
121 /**
122 * fdisk_partition_set_end:
123 * @pa: partition
124 * @off: offset in sectors
125 *
126 * Sets end offset, and zeroize size.
127 *
128 * The usual way is to address end of the partition by fdisk_partition_set_size().
129 *
130 * Returns: 0 on success, <0 on error.
131 */
132 int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off)
133 {
134 if (!pa)
135 return -EINVAL;
136 pa->end = off;
137 pa->size = 0;
138 return 0;
139 }
140
141 /**
142 * fdisk_partition_get_start:
143 * @pa: partition
144 *
145 * Returns: start offset in sectors
146 */
147 uint64_t fdisk_partition_get_end(struct fdisk_partition *pa)
148 {
149 return pa ? pa->end : 0;
150 }
151
152 /**
153 * fdisk_partition_set_size
154 * @pa: partition
155 * @size: in bytes
156 *
157 * Sets size, zeroize end offset. See also fdisk_partition_set_end().
158 *
159 * Returns: 0 on success, <0 on error.
160 */
161 int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t size)
162 {
163 if (!pa)
164 return -EINVAL;
165 pa->size = size;
166 pa->end = 0;
167 return 0;
168 }
169
170 /**
171 * fdisk_partition_get_start:
172 * @pa: partition
173 *
174 * Returns: size in sectors
175 */
176 uint64_t fdisk_partition_get_size(struct fdisk_partition *pa)
177 {
178 return pa ? pa->size : 0;
179 }
180
181 /**
182 * fdisk_partition_set_partno
183 * @pa: partition
184 * @n: partitiion number
185 *
186 * When @pa used as a tempalate for fdisk_add_partition() when infor label driver
187 * about wanted partition position.
188 *
189 * Returns: 0 on success, <0 on error.
190 */
191 int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t n)
192 {
193 if (!pa)
194 return -EINVAL;
195 pa->partno = n;
196 return 0;
197 }
198
199 size_t fdisk_partition_get_partno(struct fdisk_partition *pa)
200 {
201 return pa ? pa->partno : (size_t) -1;
202 }
203
204 int fdisk_partition_cmp_partno(struct fdisk_partition *a,
205 struct fdisk_partition *b)
206 {
207 return a->partno - b->partno;
208 }
209
210 int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type)
211 {
212 if (!pa)
213 return -EINVAL;
214 fdisk_free_parttype(pa->type);
215 pa->type = type;
216 return 0;
217 }
218
219 const struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
220 {
221 return pa ? pa->type : NULL;
222 }
223
224 int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name)
225 {
226 char *p = NULL;
227
228 if (!pa)
229 return -EINVAL;
230 if (name) {
231 p = strdup(name);
232 if (!p)
233 return -ENOMEM;
234 }
235 free(pa->name);
236 pa->name = p;
237 return 0;
238 }
239
240 const char *fdisk_partition_get_name(struct fdisk_partition *pa)
241 {
242 return pa ? pa->name : NULL;
243 }
244
245 int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid)
246 {
247 char *p = NULL;
248
249 if (!pa)
250 return -EINVAL;
251 if (uuid) {
252 p = strdup(uuid);
253 if (!p)
254 return -ENOMEM;
255 }
256 free(pa->uuid);
257 pa->uuid = p;
258 return 0;
259 }
260
261 /**
262 * fdisk_partition_partno_follow_default
263 * @pa: partition
264 * @enable: 0|1
265 *
266 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
267 * to add a new partition to the default (next) position.
268 *
269 * Returns: 0 on success, <0 on error.
270 */
271 int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable)
272 {
273 if (!pa)
274 return -EINVAL;
275 pa->partno_follow_default = enable ? 1 : 0;
276 return 0;
277 }
278
279 /**
280 * fdisk_partition_start_follow_default
281 * @pa: partition
282 * @enable: 0|1
283 *
284 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
285 * to use the first possible space for the new partition.
286 *
287 * Returns: 0 on success, <0 on error.
288 */
289 int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable)
290 {
291 if (!pa)
292 return -EINVAL;
293 pa->start_follow_default = enable ? 1 : 0;
294 return 0;
295 }
296
297 /**
298 * fdisk_partition_start_follow_default
299 * @pa: partition
300 * @enable: 0|1
301 *
302 * When @pa used as a tempalate for fdisk_add_partition() when force label driver
303 * to use all the possible space for the new partition.
304 *
305 * Returns: 0 on success, <0 on error.
306 */
307 int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable)
308 {
309 if (!pa)
310 return -EINVAL;
311 pa->end_follow_default = enable ? 1 : 0;
312 return 0;
313 }
314
315 const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
316 {
317 return pa ? pa->uuid : NULL;
318 }
319
320 const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
321 {
322 return pa ? pa->attrs : NULL;
323 }
324
325 int fdisk_partition_is_nested(struct fdisk_partition *pa)
326 {
327 return pa && pa->parent_partno != FDISK_EMPTY_PARTNO;
328 }
329
330 int fdisk_partition_is_container(struct fdisk_partition *pa)
331 {
332 return pa && pa->container;
333 }
334
335 int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
336 {
337 if (pa && parent)
338 *parent = pa->parent_partno;
339 else
340 return -EINVAL;
341 return 0;
342 }
343
344 int fdisk_partition_is_used(struct fdisk_partition *pa)
345 {
346 return pa && pa->used;
347 }
348
349 int fdisk_partition_is_bootable(struct fdisk_partition *pa)
350 {
351 return pa && pa->boot;
352 }
353
354 int fdisk_partition_is_freespace(struct fdisk_partition *pa)
355 {
356 return pa && pa->freespace;
357 }
358
359 int fdisk_partition_next_partno(
360 struct fdisk_partition *pa,
361 struct fdisk_context *cxt,
362 size_t *n)
363 {
364 assert(cxt);
365 assert(n);
366
367 if (pa && pa->partno_follow_default) {
368 size_t i;
369
370 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
371
372 for (i = 0; i < cxt->label->nparts_max; i++) {
373 if (!fdisk_is_partition_used(cxt, i)) {
374 *n = i;
375 return 0;
376 }
377 }
378 return -ERANGE;
379
380 } else if (pa && pa->partno != FDISK_EMPTY_PARTNO) {
381
382 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
383
384 if (pa->partno >= cxt->label->nparts_max)
385 return -ERANGE;
386 *n = pa->partno;
387 } else
388 return fdisk_ask_partnum(cxt, n, 1);
389
390 return 0;
391 }
392
393 /**
394 * fdisk_partition_to_string:
395 * @pa: partition
396 * @id: field (FDISK_FIELD_*)
397 * @data: returns string with allocated data
398 *
399 * Returns info about partition converted to printable string.
400 *
401 * For example
402 *
403 * struct fdisk_parition *pa;
404 *
405 * fdisk_get_partition(cxt, 0, &pa);
406 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
407 * printf("first partition uuid: %s\n", data);
408 * free(data);
409 * fdisk_unref_partition(pa);
410 *
411 * returns UUID for the first partition.
412 *
413 * Returns 0 on success, otherwise, a corresponding error.
414 */
415
416 int fdisk_partition_to_string(struct fdisk_partition *pa,
417 struct fdisk_context *cxt,
418 int id,
419 char **data)
420 {
421 char *p = NULL;
422 int rc = 0;
423 uint64_t x;
424
425 if (!pa || !cxt)
426 return -EINVAL;
427
428 switch (id) {
429 case FDISK_FIELD_DEVICE:
430 if (pa->freespace)
431 p = strdup(_("Free space"));
432 else if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
433 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
434 else
435 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
436 break;
437 case FDISK_FIELD_BOOT:
438 rc = asprintf(&p, "%c", pa->boot ? '*' : ' ');
439 break;
440 case FDISK_FIELD_START:
441 x = fdisk_cround(cxt, pa->start);
442 rc = pa->start_post ?
443 asprintf(&p, "%ju%c", x, pa->start_post) :
444 asprintf(&p, "%ju", x);
445 break;
446 case FDISK_FIELD_END:
447 x = fdisk_cround(cxt, pa->end);
448 rc = pa->end_post ?
449 asprintf(&p, "%ju%c", x, pa->end_post) :
450 asprintf(&p, "%ju", x);
451 break;
452 case FDISK_FIELD_SIZE:
453 {
454 uint64_t sz = pa->size * cxt->sector_size;
455
456 if (fdisk_is_details(cxt)) {
457 rc = pa->size_post ?
458 asprintf(&p, "%ju%c", sz, pa->size_post) :
459 asprintf(&p, "%ju", sz);
460 } else {
461 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
462 if (!p)
463 rc = -ENOMEM;
464 }
465 break;
466 }
467 case FDISK_FIELD_CYLINDERS:
468 rc = asprintf(&p, "%ju", (uintmax_t)
469 fdisk_cround(cxt, pa->size));
470 break;
471 case FDISK_FIELD_SECTORS:
472 rc = asprintf(&p, "%ju", pa->size);
473 break;
474 case FDISK_FIELD_BSIZE:
475 rc = asprintf(&p, "%ju", pa->bsize);
476 break;
477 case FDISK_FIELD_FSIZE:
478 rc = asprintf(&p, "%ju", pa->fsize);
479 break;
480 case FDISK_FIELD_CPG:
481 rc = asprintf(&p, "%ju", pa->cpg);
482 break;
483 case FDISK_FIELD_TYPE:
484 p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL;
485 break;
486 case FDISK_FIELD_TYPEID:
487 if (pa->type && fdisk_parttype_get_string(pa->type))
488 rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
489 else if (pa->type)
490 rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
491 break;
492 case FDISK_FIELD_UUID:
493 p = pa->uuid ? strdup(pa->uuid) : NULL;
494 break;
495 case FDISK_FIELD_NAME:
496 p = pa->name ? strdup(pa->name) : NULL;
497 break;
498 case FDISK_FIELD_ATTR:
499 p = pa->attrs ? strdup(pa->attrs) : NULL;
500 break;
501 case FDISK_FIELD_SADDR:
502 p = pa->start_addr ? strdup(pa->start_addr) : NULL;
503 break;
504 case FDISK_FIELD_EADDR:
505 p = pa->end_addr ? strdup(pa->end_addr) : NULL;
506 break;
507 default:
508 return -EINVAL;
509 }
510
511 if (rc < 0)
512 rc = -ENOMEM;
513 else if (rc > 0)
514 rc = 0;
515
516 if (data)
517 *data = p;
518 return rc;
519 }
520
521 /**
522 * fdisk_get_partition:
523 * @cxt:
524 * @partno:
525 * @pa: pointer to partition struct
526 *
527 * Fills in @pa with data about partition @n.
528 *
529 * Returns: 0 on success, otherwise, a corresponding error.
530 */
531 int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
532 struct fdisk_partition **pa)
533 {
534 int rc;
535 struct fdisk_partition *np = NULL;
536
537 if (!cxt || !cxt->label || !pa)
538 return -EINVAL;
539 if (!cxt->label->op->get_part)
540 return -ENOSYS;
541 if (!fdisk_is_partition_used(cxt, partno))
542 return -EINVAL;
543
544 if (!*pa) {
545 np = *pa = fdisk_new_partition();
546 if (!*pa)
547 return -ENOMEM;
548 } else
549 fdisk_reset_partition(*pa);
550
551 (*pa)->partno = partno;
552 rc = cxt->label->op->get_part(cxt, partno, *pa);
553
554 if (rc) {
555 if (np) {
556 fdisk_unref_partition(np);
557 *pa = NULL;
558 } else
559 fdisk_reset_partition(*pa);
560 }
561 return rc;
562 }
563
564 /*
565 * This is faster than fdisk_get_partition() + fdisk_partition_is_used()
566 */
567 int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
568 {
569 if (!cxt || !cxt->label)
570 return -EINVAL;
571 if (!cxt->label->op->part_is_used)
572 return -ENOSYS;
573
574 return cxt->label->op->part_is_used(cxt, n);
575 }
576
577 /**
578 * fdisk_add_partition:
579 * @cxt: fdisk context
580 * @pa: template for the partition
581 *
582 * If @pa is not specified or any @pa item is missiong the libfdisk will ask by
583 * fdisk_ask_ API.
584 *
585 * Creates a new partition.
586 *
587 * Returns 0.
588 */
589 int fdisk_add_partition(struct fdisk_context *cxt,
590 struct fdisk_partition *pa)
591 {
592 int rc;
593
594 assert(cxt);
595 assert(cxt->label);
596
597 if (!cxt || !cxt->label)
598 return -EINVAL;
599 if (!cxt->label->op->add_part)
600 return -ENOSYS;
601 if (fdisk_missing_geometry(cxt))
602 return -EINVAL;
603
604 DBG(CXT, ul_debugobj(cxt, "adding new partition (start=%ju, end=%ju, size=%ju, "
605 "defaults(start=%s, end=%s, partno=%s)",
606 pa ? pa->start : 0,
607 pa ? pa->end : 0,
608 pa ? pa->size : 0,
609 pa && pa->start_follow_default ? "yes" : "no",
610 pa && pa->end_follow_default ? "yes" : "no",
611 pa && pa->partno_follow_default ? "yes" : "no"));
612
613 rc = cxt->label->op->add_part(cxt, pa);
614
615 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
616 return rc;
617 }
618
619 /**
620 * fdisk_delete_partition:
621 * @cxt: fdisk context
622 * @partnum: partition number to delete
623 *
624 * Deletes a @partnum partition.
625 *
626 * Returns 0 on success, otherwise, a corresponding error.
627 */
628 int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum)
629 {
630 if (!cxt || !cxt->label)
631 return -EINVAL;
632 if (!cxt->label->op->part_delete)
633 return -ENOSYS;
634
635 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
636 cxt->label->name, partnum));
637 return cxt->label->op->part_delete(cxt, partnum);
638 }
639
640 /**
641 * fdisk_delete_all_partitions:
642 * @cxt: fdisk context
643 *
644 * Delete all used partitions.
645 *
646 * Returns: 0 on success, otherwise, a corresponding error.
647 */
648 int fdisk_delete_all_partitions(struct fdisk_context *cxt)
649 {
650 size_t i;
651 int rc;
652
653 if (!cxt || !cxt->label)
654 return -EINVAL;
655
656 for (i = 0; i < cxt->label->nparts_max; i++) {
657
658 if (!fdisk_is_partition_used(cxt, i))
659 continue;
660 rc = fdisk_delete_partition(cxt, i);
661 if (rc)
662 break;
663 }
664
665 return rc;
666 }
667