]>
Commit | Line | Data |
---|---|---|
8c0a7f91 KZ |
1 | |
2 | #include "c.h" | |
3 | #include "strutils.h" | |
4 | ||
5 | #include "fdiskP.h" | |
6 | ||
7 | struct fdisk_partition *fdisk_new_partition(void) | |
8 | { | |
9 | struct fdisk_partition *pa = calloc(1, sizeof(*pa)); | |
10 | ||
d6cfa8b3 | 11 | pa->refcount = 1; |
6c89f750 | 12 | INIT_LIST_HEAD(&pa->parts); |
77d6a70a | 13 | pa->partno = FDISK_EMPTY_PARTNO; |
bd5e8291 | 14 | pa->parent_partno = FDISK_EMPTY_PARTNO; |
d71bd2f0 | 15 | DBG(PART, ul_debugobj(pa, "alloc")); |
8c0a7f91 KZ |
16 | return pa; |
17 | } | |
18 | ||
19 | void fdisk_reset_partition(struct fdisk_partition *pa) | |
20 | { | |
d6cfa8b3 KZ |
21 | int ref; |
22 | ||
8c0a7f91 KZ |
23 | if (!pa) |
24 | return; | |
d6cfa8b3 | 25 | |
d71bd2f0 | 26 | DBG(PART, ul_debugobj(pa, "reset")); |
d6cfa8b3 | 27 | ref = pa->refcount; |
8c0a7f91 KZ |
28 | fdisk_free_parttype(pa->type); |
29 | free(pa->name); | |
30 | free(pa->uuid); | |
31 | free(pa->attrs); | |
32 | memset(pa, 0, sizeof(*pa)); | |
77d6a70a | 33 | pa->partno = FDISK_EMPTY_PARTNO; |
bd5e8291 | 34 | pa->parent_partno = FDISK_EMPTY_PARTNO; |
d6cfa8b3 | 35 | pa->refcount = ref; |
6c89f750 | 36 | INIT_LIST_HEAD(&pa->parts); |
8c0a7f91 KZ |
37 | } |
38 | ||
d6cfa8b3 KZ |
39 | void fdisk_ref_partition(struct fdisk_partition *pa) |
40 | { | |
41 | if (pa) | |
42 | pa->refcount++; | |
43 | } | |
44 | ||
45 | void fdisk_unref_partition(struct fdisk_partition *pa) | |
8c0a7f91 KZ |
46 | { |
47 | if (!pa) | |
48 | return; | |
d6cfa8b3 KZ |
49 | |
50 | pa->refcount--; | |
51 | if (pa->refcount <= 0) { | |
d71bd2f0 | 52 | DBG(PART, ul_debugobj(pa, "free")); |
6c89f750 KZ |
53 | fdisk_reset_partition(pa); |
54 | list_del(&pa->parts); | |
d6cfa8b3 KZ |
55 | free(pa); |
56 | } | |
8c0a7f91 KZ |
57 | } |
58 | ||
5139eca7 KZ |
59 | int fdisk_dump_partition(struct fdisk_partition *pa, FILE *f) |
60 | { | |
61 | assert(pa); | |
62 | assert(f); | |
63 | ||
64 | if (pa->partno == FDISK_EMPTY_PARTNO) | |
65 | fputs("# ", f); | |
66 | else | |
67 | fprintf(f, "#%zu ", pa->partno); | |
68 | ||
69 | fprintf(f, "[%p] start=%ju, end=%ju, size=%ju", | |
70 | pa, pa->start, pa->end, pa->size); | |
71 | if (pa->parent_partno != FDISK_EMPTY_PARTNO) | |
72 | fprintf(f, ", parent=%zu", pa->parent_partno); | |
73 | if (fdisk_partition_is_freespace(pa)) | |
74 | fputs(" freespace", f); | |
75 | if (fdisk_partition_is_container(pa)) | |
76 | fputs(" container", f); | |
77 | if (fdisk_partition_is_nested(pa)) | |
78 | fputs(" nested", f); | |
79 | fputc('\n', f); | |
80 | return 0; | |
81 | } | |
82 | ||
8c0a7f91 KZ |
83 | int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off) |
84 | { | |
85 | if (!pa) | |
86 | return -EINVAL; | |
87 | pa->start = off; | |
88 | return 0; | |
89 | } | |
90 | ||
91 | uint64_t fdisk_partition_get_start(struct fdisk_partition *pa) | |
92 | { | |
93 | return pa ? pa->start : 0; | |
94 | } | |
95 | ||
e5c93999 KZ |
96 | int fdisk_partition_cmp_start(struct fdisk_partition *a, |
97 | struct fdisk_partition *b) | |
98 | { | |
99 | return a->start - b->start; | |
100 | } | |
101 | ||
03643931 | 102 | int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off) |
8c0a7f91 KZ |
103 | { |
104 | if (!pa) | |
105 | return -EINVAL; | |
106 | pa->end = off; | |
107 | pa->size = 0; | |
8c0a7f91 KZ |
108 | return 0; |
109 | } | |
110 | ||
111 | uint64_t fdisk_partition_get_end(struct fdisk_partition *pa) | |
112 | { | |
732aefdf | 113 | return pa ? pa->end : 0; |
8c0a7f91 KZ |
114 | } |
115 | ||
116 | ||
117 | int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t size) | |
118 | { | |
119 | if (!pa) | |
120 | return -EINVAL; | |
121 | pa->size = size; | |
122 | pa->end = 0; | |
123 | return 0; | |
124 | } | |
125 | ||
126 | uint64_t fdisk_partition_get_size(struct fdisk_partition *pa) | |
127 | { | |
128 | return pa ? pa->size : 0; | |
129 | } | |
130 | ||
131 | int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t n) | |
132 | { | |
133 | if (!pa) | |
134 | return -EINVAL; | |
135 | pa->partno = n; | |
136 | return 0; | |
137 | } | |
138 | ||
139 | size_t fdisk_partition_get_partno(struct fdisk_partition *pa) | |
140 | { | |
141 | return pa ? pa->partno : (size_t) -1; | |
142 | } | |
143 | ||
e5c93999 KZ |
144 | int fdisk_partition_cmp_partno(struct fdisk_partition *a, |
145 | struct fdisk_partition *b) | |
146 | { | |
147 | return a->partno - b->partno; | |
148 | } | |
149 | ||
8c0a7f91 KZ |
150 | int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type) |
151 | { | |
152 | if (!pa) | |
153 | return -EINVAL; | |
85151521 | 154 | fdisk_free_parttype(pa->type); |
8c0a7f91 KZ |
155 | pa->type = type; |
156 | return 0; | |
157 | } | |
158 | ||
159 | const struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa) | |
160 | { | |
161 | return pa ? pa->type : NULL; | |
162 | } | |
163 | ||
164 | int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name) | |
165 | { | |
166 | char *p = NULL; | |
167 | ||
168 | if (!pa) | |
169 | return -EINVAL; | |
170 | if (name) { | |
171 | p = strdup(name); | |
172 | if (!p) | |
173 | return -ENOMEM; | |
174 | } | |
175 | free(pa->name); | |
176 | pa->name = p; | |
177 | return 0; | |
178 | } | |
179 | ||
180 | const char *fdisk_partition_get_name(struct fdisk_partition *pa) | |
181 | { | |
182 | return pa ? pa->name : NULL; | |
183 | } | |
184 | ||
185 | int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid) | |
186 | { | |
187 | char *p = NULL; | |
188 | ||
189 | if (!pa) | |
190 | return -EINVAL; | |
191 | if (uuid) { | |
192 | p = strdup(uuid); | |
193 | if (!p) | |
194 | return -ENOMEM; | |
195 | } | |
196 | free(pa->uuid); | |
197 | pa->uuid = p; | |
198 | return 0; | |
199 | } | |
200 | ||
732aefdf KZ |
201 | int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable) |
202 | { | |
203 | if (!pa) | |
204 | return -EINVAL; | |
205 | pa->partno_follow_default = enable ? 1 : 0; | |
206 | return 0; | |
207 | } | |
208 | ||
209 | int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable) | |
210 | { | |
211 | if (!pa) | |
212 | return -EINVAL; | |
213 | pa->start_follow_default = enable ? 1 : 0; | |
214 | return 0; | |
215 | } | |
216 | ||
217 | int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable) | |
218 | { | |
219 | if (!pa) | |
220 | return -EINVAL; | |
221 | pa->end_follow_default = enable ? 1 : 0; | |
222 | return 0; | |
223 | } | |
224 | ||
8c0a7f91 KZ |
225 | const char *fdisk_partition_get_uuid(struct fdisk_partition *pa) |
226 | { | |
227 | return pa ? pa->uuid : NULL; | |
228 | } | |
229 | ||
230 | const char *fdisk_partition_get_attrs(struct fdisk_partition *pa) | |
231 | { | |
232 | return pa ? pa->attrs : NULL; | |
233 | } | |
234 | ||
bd5e8291 | 235 | int fdisk_partition_is_nested(struct fdisk_partition *pa) |
8c0a7f91 | 236 | { |
bd5e8291 | 237 | return pa && pa->parent_partno != FDISK_EMPTY_PARTNO; |
8c0a7f91 KZ |
238 | } |
239 | ||
bd5e8291 | 240 | int fdisk_partition_is_container(struct fdisk_partition *pa) |
8c0a7f91 | 241 | { |
bd5e8291 | 242 | return pa && pa->container; |
8c0a7f91 KZ |
243 | } |
244 | ||
03643931 KZ |
245 | int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent) |
246 | { | |
247 | if (pa && parent) | |
248 | *parent = pa->parent_partno; | |
249 | else | |
250 | return -EINVAL; | |
251 | return 0; | |
252 | } | |
253 | ||
8c0a7f91 KZ |
254 | int fdisk_partition_is_used(struct fdisk_partition *pa) |
255 | { | |
256 | return pa && pa->used; | |
257 | } | |
258 | ||
1de9fddb KZ |
259 | int fdisk_partition_is_freespace(struct fdisk_partition *pa) |
260 | { | |
261 | return pa && pa->freespace; | |
262 | } | |
263 | ||
77d6a70a | 264 | int fdisk_partition_next_partno( |
77d6a70a | 265 | struct fdisk_partition *pa, |
6c89f750 | 266 | struct fdisk_context *cxt, |
77d6a70a KZ |
267 | size_t *n) |
268 | { | |
269 | assert(cxt); | |
270 | assert(n); | |
271 | ||
272 | if (pa && pa->partno_follow_default) { | |
273 | size_t i; | |
274 | ||
d71bd2f0 | 275 | DBG(PART, ul_debugobj(pa, "next partno (follow default)")); |
732aefdf | 276 | |
6c89f750 | 277 | for (i = 0; i < cxt->label->nparts_max; i++) { |
77d6a70a KZ |
278 | if (!fdisk_is_partition_used(cxt, i)) { |
279 | *n = i; | |
732aefdf | 280 | return 0; |
77d6a70a KZ |
281 | } |
282 | } | |
732aefdf KZ |
283 | return -ERANGE; |
284 | ||
77d6a70a | 285 | } else if (pa && pa->partno != FDISK_EMPTY_PARTNO) { |
732aefdf | 286 | |
d71bd2f0 | 287 | DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno)); |
732aefdf | 288 | |
6c89f750 | 289 | if (pa->partno >= cxt->label->nparts_max) |
77d6a70a KZ |
290 | return -ERANGE; |
291 | *n = pa->partno; | |
292 | } else | |
293 | return fdisk_ask_partnum(cxt, n, 1); | |
294 | ||
295 | return 0; | |
296 | } | |
8c0a7f91 KZ |
297 | |
298 | /** | |
299 | * fdisk_partition_to_string: | |
300 | * @pa: partition | |
bd85d11f | 301 | * @id: field (FDISK_FIELD_*) |
8c0a7f91 KZ |
302 | * @data: returns string with allocated data |
303 | * | |
304 | * Returns info about partition converted to printable string. | |
305 | * | |
0e65dcde | 306 | * For example |
8c0a7f91 | 307 | * |
d6cfa8b3 | 308 | * struct fdisk_parition *pa; |
8c0a7f91 KZ |
309 | * |
310 | * fdisk_get_partition(cxt, 0, &pa); | |
bd85d11f | 311 | * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data); |
8c0a7f91 KZ |
312 | * printf("first partition uuid: %s\n", data); |
313 | * free(data); | |
d6cfa8b3 | 314 | * fdisk_unref_partition(pa); |
8c0a7f91 KZ |
315 | * |
316 | * returns UUID for the first partition. | |
317 | * | |
318 | * Returns 0 on success, otherwise, a corresponding error. | |
319 | */ | |
320 | ||
321 | int fdisk_partition_to_string(struct fdisk_partition *pa, | |
6c89f750 | 322 | struct fdisk_context *cxt, |
8c0a7f91 KZ |
323 | int id, |
324 | char **data) | |
325 | { | |
326 | char *p = NULL; | |
327 | int rc = 0; | |
77d6a70a | 328 | uint64_t x; |
8c0a7f91 | 329 | |
6c89f750 | 330 | if (!pa || !cxt) |
8c0a7f91 KZ |
331 | return -EINVAL; |
332 | ||
333 | switch (id) { | |
bd85d11f | 334 | case FDISK_FIELD_DEVICE: |
1de9fddb KZ |
335 | if (pa->freespace) |
336 | p = strdup(_("Free space")); | |
6c89f750 | 337 | else if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO) |
82ebc7de KZ |
338 | rc = asprintf(&p, "%c", (int) pa->partno + 'a'); |
339 | else | |
6c89f750 | 340 | p = fdisk_partname(cxt->dev_path, pa->partno + 1); |
8c0a7f91 | 341 | break; |
bd85d11f | 342 | case FDISK_FIELD_BOOT: |
d6faa8e0 KZ |
343 | rc = asprintf(&p, "%c", pa->boot); |
344 | break; | |
bd85d11f | 345 | case FDISK_FIELD_START: |
6c89f750 | 346 | x = fdisk_cround(cxt, pa->start); |
82ebc7de | 347 | rc = pa->start_post ? |
77d6a70a KZ |
348 | asprintf(&p, "%ju%c", x, pa->start_post) : |
349 | asprintf(&p, "%ju", x); | |
8c0a7f91 | 350 | break; |
bd85d11f | 351 | case FDISK_FIELD_END: |
6c89f750 | 352 | x = fdisk_cround(cxt, pa->end); |
82ebc7de | 353 | rc = pa->end_post ? |
77d6a70a KZ |
354 | asprintf(&p, "%ju%c", x, pa->end_post) : |
355 | asprintf(&p, "%ju", x); | |
8c0a7f91 | 356 | break; |
bd85d11f | 357 | case FDISK_FIELD_SIZE: |
77d6a70a | 358 | { |
6c89f750 | 359 | uint64_t sz = pa->size * cxt->sector_size; |
77d6a70a | 360 | |
6c89f750 | 361 | if (fdisk_context_display_details(cxt)) { |
82ebc7de | 362 | rc = pa->size_post ? |
77d6a70a KZ |
363 | asprintf(&p, "%ju%c", sz, pa->size_post) : |
364 | asprintf(&p, "%ju", sz); | |
8c0a7f91 | 365 | } else { |
77d6a70a | 366 | p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz); |
8c0a7f91 KZ |
367 | if (!p) |
368 | rc = -ENOMEM; | |
369 | } | |
370 | break; | |
77d6a70a | 371 | } |
bd85d11f | 372 | case FDISK_FIELD_CYLINDERS: |
77d6a70a | 373 | rc = asprintf(&p, "%ju", (uintmax_t) |
6c89f750 | 374 | fdisk_cround(cxt, pa->size)); |
77d6a70a | 375 | break; |
bd85d11f | 376 | case FDISK_FIELD_SECTORS: |
77d6a70a | 377 | rc = asprintf(&p, "%ju", pa->size); |
d6faa8e0 | 378 | break; |
bd85d11f | 379 | case FDISK_FIELD_BSIZE: |
82ebc7de KZ |
380 | rc = asprintf(&p, "%ju", pa->bsize); |
381 | break; | |
bd85d11f | 382 | case FDISK_FIELD_FSIZE: |
82ebc7de KZ |
383 | rc = asprintf(&p, "%ju", pa->fsize); |
384 | break; | |
bd85d11f | 385 | case FDISK_FIELD_CPG: |
82ebc7de KZ |
386 | rc = asprintf(&p, "%ju", pa->cpg); |
387 | break; | |
bd85d11f | 388 | case FDISK_FIELD_TYPE: |
8c0a7f91 KZ |
389 | p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL; |
390 | break; | |
bd85d11f | 391 | case FDISK_FIELD_TYPEID: |
d6faa8e0 KZ |
392 | if (pa->type && pa->type->typestr) |
393 | rc = asprintf(&p, "%s", pa->type->typestr); | |
394 | else if (pa->type) | |
395 | rc = asprintf(&p, "%x", pa->type->type); | |
396 | break; | |
bd85d11f | 397 | case FDISK_FIELD_UUID: |
8c0a7f91 KZ |
398 | p = pa->uuid ? strdup(pa->uuid) : NULL; |
399 | break; | |
bd85d11f | 400 | case FDISK_FIELD_NAME: |
8c0a7f91 KZ |
401 | p = pa->name ? strdup(pa->name) : NULL; |
402 | break; | |
bd85d11f | 403 | case FDISK_FIELD_ATTR: |
8c0a7f91 KZ |
404 | p = pa->attrs ? strdup(pa->attrs) : NULL; |
405 | break; | |
bd85d11f | 406 | case FDISK_FIELD_SADDR: |
d6faa8e0 KZ |
407 | p = pa->start_addr ? strdup(pa->start_addr) : NULL; |
408 | break; | |
bd85d11f | 409 | case FDISK_FIELD_EADDR: |
d6faa8e0 KZ |
410 | p = pa->end_addr ? strdup(pa->end_addr) : NULL; |
411 | break; | |
8c0a7f91 KZ |
412 | default: |
413 | return -EINVAL; | |
414 | } | |
415 | ||
82ebc7de KZ |
416 | if (rc < 0) |
417 | rc = -ENOMEM; | |
418 | else if (rc > 0) | |
419 | rc = 0; | |
420 | ||
8c0a7f91 KZ |
421 | if (data) |
422 | *data = p; | |
423 | return rc; | |
424 | } | |
187de51c KZ |
425 | |
426 | /** | |
427 | * fdisk_get_partition: | |
428 | * @cxt: | |
429 | * @partno: | |
430 | * @pa: pointer to partition struct | |
431 | * | |
432 | * Fills in @pa with data about partition @n. | |
433 | * | |
434 | * Returns: 0 on success, otherwise, a corresponding error. | |
435 | */ | |
436 | int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, | |
437 | struct fdisk_partition **pa) | |
438 | { | |
439 | int rc; | |
6c89f750 | 440 | struct fdisk_partition *np = NULL; |
187de51c KZ |
441 | |
442 | if (!cxt || !cxt->label || !pa) | |
443 | return -EINVAL; | |
444 | if (!cxt->label->op->get_part) | |
445 | return -ENOSYS; | |
6c89f750 KZ |
446 | if (!fdisk_is_partition_used(cxt, partno)) |
447 | return -EINVAL; | |
187de51c KZ |
448 | |
449 | if (!*pa) { | |
6c89f750 | 450 | np = *pa = fdisk_new_partition(); |
187de51c KZ |
451 | if (!*pa) |
452 | return -ENOMEM; | |
453 | } else | |
454 | fdisk_reset_partition(*pa); | |
6c89f750 | 455 | |
187de51c KZ |
456 | (*pa)->partno = partno; |
457 | rc = cxt->label->op->get_part(cxt, partno, *pa); | |
6c89f750 KZ |
458 | |
459 | if (rc) { | |
460 | if (np) { | |
461 | fdisk_unref_partition(np); | |
462 | *pa = NULL; | |
463 | } else | |
464 | fdisk_reset_partition(*pa); | |
465 | } | |
187de51c KZ |
466 | return rc; |
467 | } | |
468 | ||
469 | /* | |
470 | * This is faster than fdisk_get_partition() + fdisk_partition_is_used() | |
471 | */ | |
472 | int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n) | |
473 | { | |
474 | if (!cxt || !cxt->label) | |
475 | return -EINVAL; | |
476 | if (!cxt->label->op->part_is_used) | |
477 | return -ENOSYS; | |
478 | ||
479 | return cxt->label->op->part_is_used(cxt, n); | |
480 | } | |
481 | ||
482 | /** | |
483 | * fdisk_add_partition: | |
484 | * @cxt: fdisk context | |
485 | * @pa: template for the partition | |
486 | * | |
487 | * If @pa is not specified or any @pa item is missiong the libfdisk will ask by | |
488 | * fdisk_ask_ API. | |
489 | * | |
490 | * Creates a new partition. | |
491 | * | |
492 | * Returns 0. | |
493 | */ | |
494 | int fdisk_add_partition(struct fdisk_context *cxt, | |
495 | struct fdisk_partition *pa) | |
496 | { | |
732aefdf KZ |
497 | int rc; |
498 | ||
187de51c KZ |
499 | assert(cxt); |
500 | assert(cxt->label); | |
501 | ||
502 | if (!cxt || !cxt->label) | |
503 | return -EINVAL; | |
504 | if (!cxt->label->op->add_part) | |
505 | return -ENOSYS; | |
506 | if (fdisk_missing_geometry(cxt)) | |
507 | return -EINVAL; | |
508 | ||
d71bd2f0 | 509 | DBG(CXT, ul_debugobj(cxt, "adding new partition (start=%ju, end=%ju, size=%ju, " |
732aefdf KZ |
510 | "defaults(start=%s, end=%s, partno=%s)", |
511 | pa ? pa->start : 0, | |
512 | pa ? pa->end : 0, | |
513 | pa ? pa->size : 0, | |
514 | pa && pa->start_follow_default ? "yes" : "no", | |
515 | pa && pa->end_follow_default ? "yes" : "no", | |
516 | pa && pa->partno_follow_default ? "yes" : "no")); | |
517 | ||
518 | rc = cxt->label->op->add_part(cxt, pa); | |
519 | ||
d71bd2f0 | 520 | DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc)); |
732aefdf | 521 | return rc; |
187de51c KZ |
522 | } |
523 | ||
524 | /** | |
525 | * fdisk_delete_partition: | |
526 | * @cxt: fdisk context | |
527 | * @partnum: partition number to delete | |
528 | * | |
529 | * Deletes a @partnum partition. | |
530 | * | |
531 | * Returns 0 on success, otherwise, a corresponding error. | |
532 | */ | |
533 | int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum) | |
534 | { | |
535 | if (!cxt || !cxt->label) | |
536 | return -EINVAL; | |
537 | if (!cxt->label->op->part_delete) | |
538 | return -ENOSYS; | |
539 | ||
d71bd2f0 | 540 | DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd", |
187de51c KZ |
541 | cxt->label->name, partnum)); |
542 | return cxt->label->op->part_delete(cxt, partnum); | |
543 | } |