]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/partition.c
libfdisk: rename fdisk_column to fdisk_field
[thirdparty/util-linux.git] / libfdisk / src / partition.c
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
11 pa->refcount = 1;
12 INIT_LIST_HEAD(&pa->parts);
13 pa->partno = FDISK_EMPTY_PARTNO;
14 pa->parent_partno = FDISK_EMPTY_PARTNO;
15 DBG(PART, ul_debugobj(pa, "alloc"));
16 return pa;
17 }
18
19 void fdisk_reset_partition(struct fdisk_partition *pa)
20 {
21 int ref;
22
23 if (!pa)
24 return;
25
26 DBG(PART, ul_debugobj(pa, "reset"));
27 ref = pa->refcount;
28 fdisk_free_parttype(pa->type);
29 free(pa->name);
30 free(pa->uuid);
31 free(pa->attrs);
32 memset(pa, 0, sizeof(*pa));
33 pa->partno = FDISK_EMPTY_PARTNO;
34 pa->parent_partno = FDISK_EMPTY_PARTNO;
35 pa->refcount = ref;
36 INIT_LIST_HEAD(&pa->parts);
37 }
38
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)
46 {
47 if (!pa)
48 return;
49
50 pa->refcount--;
51 if (pa->refcount <= 0) {
52 DBG(PART, ul_debugobj(pa, "free"));
53 fdisk_reset_partition(pa);
54 list_del(&pa->parts);
55 free(pa);
56 }
57 }
58
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
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
96 int fdisk_partition_cmp_start(struct fdisk_partition *a,
97 struct fdisk_partition *b)
98 {
99 return a->start - b->start;
100 }
101
102 int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off)
103 {
104 if (!pa)
105 return -EINVAL;
106 pa->end = off;
107 pa->size = 0;
108 return 0;
109 }
110
111 uint64_t fdisk_partition_get_end(struct fdisk_partition *pa)
112 {
113 return pa ? pa->end : 0;
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
144 int fdisk_partition_cmp_partno(struct fdisk_partition *a,
145 struct fdisk_partition *b)
146 {
147 return a->partno - b->partno;
148 }
149
150 int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type)
151 {
152 if (!pa)
153 return -EINVAL;
154 fdisk_free_parttype(pa->type);
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
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
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
235 int fdisk_partition_is_nested(struct fdisk_partition *pa)
236 {
237 return pa && pa->parent_partno != FDISK_EMPTY_PARTNO;
238 }
239
240 int fdisk_partition_is_container(struct fdisk_partition *pa)
241 {
242 return pa && pa->container;
243 }
244
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
254 int fdisk_partition_is_used(struct fdisk_partition *pa)
255 {
256 return pa && pa->used;
257 }
258
259 int fdisk_partition_is_freespace(struct fdisk_partition *pa)
260 {
261 return pa && pa->freespace;
262 }
263
264 int fdisk_partition_next_partno(
265 struct fdisk_partition *pa,
266 struct fdisk_context *cxt,
267 size_t *n)
268 {
269 assert(cxt);
270 assert(n);
271
272 if (pa && pa->partno_follow_default) {
273 size_t i;
274
275 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
276
277 for (i = 0; i < cxt->label->nparts_max; i++) {
278 if (!fdisk_is_partition_used(cxt, i)) {
279 *n = i;
280 return 0;
281 }
282 }
283 return -ERANGE;
284
285 } else if (pa && pa->partno != FDISK_EMPTY_PARTNO) {
286
287 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
288
289 if (pa->partno >= cxt->label->nparts_max)
290 return -ERANGE;
291 *n = pa->partno;
292 } else
293 return fdisk_ask_partnum(cxt, n, 1);
294
295 return 0;
296 }
297
298 /**
299 * fdisk_partition_to_string:
300 * @pa: partition
301 * @id: field (FDISK_FIELD_*)
302 * @data: returns string with allocated data
303 *
304 * Returns info about partition converted to printable string.
305 *
306 * For example
307 *
308 * struct fdisk_parition *pa;
309 *
310 * fdisk_get_partition(cxt, 0, &pa);
311 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
312 * printf("first partition uuid: %s\n", data);
313 * free(data);
314 * fdisk_unref_partition(pa);
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,
322 struct fdisk_context *cxt,
323 int id,
324 char **data)
325 {
326 char *p = NULL;
327 int rc = 0;
328 uint64_t x;
329
330 if (!pa || !cxt)
331 return -EINVAL;
332
333 switch (id) {
334 case FDISK_FIELD_DEVICE:
335 if (pa->freespace)
336 p = strdup(_("Free space"));
337 else if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
338 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
339 else
340 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
341 break;
342 case FDISK_FIELD_BOOT:
343 rc = asprintf(&p, "%c", pa->boot);
344 break;
345 case FDISK_FIELD_START:
346 x = fdisk_cround(cxt, pa->start);
347 rc = pa->start_post ?
348 asprintf(&p, "%ju%c", x, pa->start_post) :
349 asprintf(&p, "%ju", x);
350 break;
351 case FDISK_FIELD_END:
352 x = fdisk_cround(cxt, pa->end);
353 rc = pa->end_post ?
354 asprintf(&p, "%ju%c", x, pa->end_post) :
355 asprintf(&p, "%ju", x);
356 break;
357 case FDISK_FIELD_SIZE:
358 {
359 uint64_t sz = pa->size * cxt->sector_size;
360
361 if (fdisk_context_display_details(cxt)) {
362 rc = pa->size_post ?
363 asprintf(&p, "%ju%c", sz, pa->size_post) :
364 asprintf(&p, "%ju", sz);
365 } else {
366 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
367 if (!p)
368 rc = -ENOMEM;
369 }
370 break;
371 }
372 case FDISK_FIELD_CYLINDERS:
373 rc = asprintf(&p, "%ju", (uintmax_t)
374 fdisk_cround(cxt, pa->size));
375 break;
376 case FDISK_FIELD_SECTORS:
377 rc = asprintf(&p, "%ju", pa->size);
378 break;
379 case FDISK_FIELD_BSIZE:
380 rc = asprintf(&p, "%ju", pa->bsize);
381 break;
382 case FDISK_FIELD_FSIZE:
383 rc = asprintf(&p, "%ju", pa->fsize);
384 break;
385 case FDISK_FIELD_CPG:
386 rc = asprintf(&p, "%ju", pa->cpg);
387 break;
388 case FDISK_FIELD_TYPE:
389 p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL;
390 break;
391 case FDISK_FIELD_TYPEID:
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;
397 case FDISK_FIELD_UUID:
398 p = pa->uuid ? strdup(pa->uuid) : NULL;
399 break;
400 case FDISK_FIELD_NAME:
401 p = pa->name ? strdup(pa->name) : NULL;
402 break;
403 case FDISK_FIELD_ATTR:
404 p = pa->attrs ? strdup(pa->attrs) : NULL;
405 break;
406 case FDISK_FIELD_SADDR:
407 p = pa->start_addr ? strdup(pa->start_addr) : NULL;
408 break;
409 case FDISK_FIELD_EADDR:
410 p = pa->end_addr ? strdup(pa->end_addr) : NULL;
411 break;
412 default:
413 return -EINVAL;
414 }
415
416 if (rc < 0)
417 rc = -ENOMEM;
418 else if (rc > 0)
419 rc = 0;
420
421 if (data)
422 *data = p;
423 return rc;
424 }
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;
440 struct fdisk_partition *np = NULL;
441
442 if (!cxt || !cxt->label || !pa)
443 return -EINVAL;
444 if (!cxt->label->op->get_part)
445 return -ENOSYS;
446 if (!fdisk_is_partition_used(cxt, partno))
447 return -EINVAL;
448
449 if (!*pa) {
450 np = *pa = fdisk_new_partition();
451 if (!*pa)
452 return -ENOMEM;
453 } else
454 fdisk_reset_partition(*pa);
455
456 (*pa)->partno = partno;
457 rc = cxt->label->op->get_part(cxt, partno, *pa);
458
459 if (rc) {
460 if (np) {
461 fdisk_unref_partition(np);
462 *pa = NULL;
463 } else
464 fdisk_reset_partition(*pa);
465 }
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 {
497 int rc;
498
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
509 DBG(CXT, ul_debugobj(cxt, "adding new partition (start=%ju, end=%ju, size=%ju, "
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
520 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
521 return rc;
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
540 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
541 cxt->label->name, partnum));
542 return cxt->label->op->part_delete(cxt, partnum);
543 }