]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/label.c
libfdisk: (docs) add notes about fdisk_enable_wipe()
[thirdparty/util-linux.git] / libfdisk / src / label.c
1
2 #include "fdiskP.h"
3
4
5 /**
6 * SECTION: label
7 * @title: Label
8 * @short_description: disk label (PT) specific data and functions
9 *
10 * The fdisk_new_context() initializes all label drivers, and allocate
11 * per-label specific data struct. This concept allows to store label specific
12 * settings to the label driver independently on the currently active label
13 * driver. Note that label struct cannot be deallocated, so there is no
14 * reference counting for fdisk_label objects. All is destroyed by
15 * fdisk_unref_context() only.
16 *
17 * Anyway, all label drives share in-memory first sector. The function
18 * fdisk_create_disklabel() overwrites this in-memory sector. But it's possible that
19 * label driver also uses another buffers, for example GPT reads more sectors
20 * from the device.
21 *
22 * All label operations are in-memory only, except fdisk_write_disklabel().
23 *
24 * All functions that use "struct fdisk_context" rather than "struct
25 * fdisk_label" use the currently active label driver.
26 */
27
28
29 int fdisk_probe_labels(struct fdisk_context *cxt)
30 {
31 size_t i;
32
33 cxt->label = NULL;
34
35 for (i = 0; i < cxt->nlabels; i++) {
36 struct fdisk_label *lb = cxt->labels[i];
37 struct fdisk_label *org = fdisk_get_label(cxt, NULL);
38 int rc;
39
40 if (!lb->op->probe)
41 continue;
42 if (lb->disabled) {
43 DBG(CXT, ul_debugobj(cxt, "%s: disabled -- ignore", lb->name));
44 continue;
45 }
46 DBG(CXT, ul_debugobj(cxt, "probing for %s", lb->name));
47
48 cxt->label = lb;
49 rc = lb->op->probe(cxt);
50 cxt->label = org;
51
52 if (rc != 1) {
53 if (lb->op->deinit)
54 lb->op->deinit(lb); /* for sure */
55 continue;
56 }
57
58 __fdisk_switch_label(cxt, lb);
59 return 0;
60 }
61
62 DBG(CXT, ul_debugobj(cxt, "no label found"));
63 return 1; /* not found */
64 }
65
66 /**
67 * fdisk_label_get_name:
68 * @lb: label
69 *
70 * Returns: label name
71 */
72 const char *fdisk_label_get_name(const struct fdisk_label *lb)
73 {
74 return lb ? lb->name : NULL;
75 }
76
77 /**
78 * fdisk_label_is_labeltype:
79 * @lb: label
80 *
81 * Returns: FDISK_DISKLABEL_*.
82 */
83 int fdisk_label_get_type(const struct fdisk_label *lb)
84 {
85 return lb->id;
86 }
87
88 /**
89 * fdisk_label_require_geometry:
90 * @lb: label
91 *
92 * Returns: 1 if label requires CHS geometry
93 */
94 int fdisk_label_require_geometry(const struct fdisk_label *lb)
95 {
96 assert(lb);
97
98 return lb->flags & FDISK_LABEL_FL_REQUIRE_GEOMETRY ? 1 : 0;
99 }
100
101 /**
102 * fdisk_label_get_fields_ids
103 * @lb: label (or NULL for the current label)
104 * @cxt: context
105 * @ids: returns allocated array with FDISK_FIELD_* IDs
106 * @nids: returns number of items in fields
107 *
108 * This function returns the default fields for the label.
109 *
110 * Note that the set of the default fields depends on fdisk_enable_details()
111 * function. If the details are enabled then this function usually returns more
112 * fields.
113 *
114 * Returns: 0 on success, otherwise, a corresponding error.
115 */
116 int fdisk_label_get_fields_ids(
117 const struct fdisk_label *lb,
118 struct fdisk_context *cxt,
119 int **ids, size_t *nids)
120 {
121 size_t i, n;
122 int *c;
123
124 if (!cxt || (!lb && !cxt->label))
125 return -EINVAL;
126
127 lb = cxt->label;
128 if (!lb->fields || !lb->nfields)
129 return -ENOSYS;
130 c = calloc(lb->nfields, sizeof(int));
131 if (!c)
132 return -ENOMEM;
133 for (n = 0, i = 0; i < lb->nfields; i++) {
134 int id = lb->fields[i].id;
135
136 if ((fdisk_is_details(cxt) &&
137 (lb->fields[i].flags & FDISK_FIELDFL_EYECANDY))
138 || (!fdisk_is_details(cxt) &&
139 (lb->fields[i].flags & FDISK_FIELDFL_DETAIL))
140 || (id == FDISK_FIELD_SECTORS &&
141 fdisk_use_cylinders(cxt))
142 || (id == FDISK_FIELD_CYLINDERS &&
143 !fdisk_use_cylinders(cxt)))
144 continue;
145
146 c[n++] = id;
147 }
148 if (ids)
149 *ids = c;
150 else
151 free(c);
152 if (nids)
153 *nids = n;
154 return 0;
155 }
156
157 /**
158 * fdisk_label_get_fields_ids_all
159 * @lb: label (or NULL for the current label)
160 * @cxt: context
161 * @ids: returns allocated array with FDISK_FIELD_* IDs
162 * @nids: returns number of items in fields
163 *
164 * This function returns all fields for the label.
165 *
166 * Returns: 0 on success, otherwise, a corresponding error.
167 */
168 int fdisk_label_get_fields_ids_all(
169 const struct fdisk_label *lb,
170 struct fdisk_context *cxt,
171 int **ids, size_t *nids)
172 {
173 size_t i, n;
174 int *c;
175
176 if (!cxt || (!lb && !cxt->label))
177 return -EINVAL;
178
179 lb = cxt->label;
180 if (!lb->fields || !lb->nfields)
181 return -ENOSYS;
182 c = calloc(lb->nfields, sizeof(int));
183 if (!c)
184 return -ENOMEM;
185 for (n = 0, i = 0; i < lb->nfields; i++)
186 c[n++] = lb->fields[i].id;
187 if (ids)
188 *ids = c;
189 else
190 free(c);
191 if (nids)
192 *nids = n;
193 return 0;
194 }
195
196 /**
197 * fdisk_label_get_field:
198 * @lb: label
199 * @id: FDISK_FIELD_*
200 *
201 * The field struct describes data stored in struct fdisk_partition. The info
202 * about data is usable for example to generate human readable output (e.g.
203 * fdisk 'p'rint command). See fdisk_partition_to_string() and fdisk code.
204 *
205 * Returns: pointer to static instance of the field.
206 */
207 const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id)
208 {
209 size_t i;
210
211 assert(lb);
212 assert(id > 0);
213
214 for (i = 0; i < lb->nfields; i++) {
215 if (lb->fields[i].id == id)
216 return &lb->fields[i];
217 }
218
219 return NULL;
220 }
221
222 /**
223 * fdisk_label_get_field_by_name
224 * @lb: label
225 * @name: field name
226 *
227 * Returns: pointer to static instance of the field.
228 */
229 const struct fdisk_field *fdisk_label_get_field_by_name(
230 const struct fdisk_label *lb,
231 const char *name)
232 {
233 size_t i;
234
235 assert(lb);
236 assert(name);
237
238 for (i = 0; i < lb->nfields; i++) {
239 if (lb->fields[i].name && strcasecmp(lb->fields[i].name, name) == 0)
240 return &lb->fields[i];
241 }
242
243 return NULL;
244 }
245
246 /**
247 * fdisk_write_disklabel:
248 * @cxt: fdisk context
249 *
250 * This function wipes the device (if eanbled by fdisk_enable_wipe() and than
251 * it writes in-memory changes to disk. Be careful!
252 *
253 * Returns: 0 on success, otherwise, a corresponding error.
254 */
255 int fdisk_write_disklabel(struct fdisk_context *cxt)
256 {
257 if (!cxt || !cxt->label || cxt->readonly)
258 return -EINVAL;
259 if (!cxt->label->op->write)
260 return -ENOSYS;
261
262 fdisk_do_wipe(cxt);
263 return cxt->label->op->write(cxt);
264 }
265
266 /**
267 * fdisk_verify_disklabel:
268 * @cxt: fdisk context
269 *
270 * Verifies the partition table.
271 *
272 * Returns: 0 on success, otherwise, a corresponding error.
273 */
274 int fdisk_verify_disklabel(struct fdisk_context *cxt)
275 {
276 if (!cxt || !cxt->label)
277 return -EINVAL;
278 if (!cxt->label->op->verify)
279 return -ENOSYS;
280 if (fdisk_missing_geometry(cxt))
281 return -EINVAL;
282
283 return cxt->label->op->verify(cxt);
284 }
285
286 /**
287 * fdisk_list_disklabel:
288 * @cxt: fdisk context
289 *
290 * Lists details about disklabel, but no partitions.
291 *
292 * This function is based on fdisk_get_disklabel_item() and prints all label
293 * specific information by ASK interface (FDISK_ASKTYPE_INFO, aka fdisk_info()).
294 * The function requires enabled "details" by fdisk_enable_details().
295 *
296 * It's recommended to use fdisk_get_disklabel_item() if you need better
297 * control on output and formatting.
298 *
299 * Returns: 0 on success, otherwise, a corresponding error.
300 */
301 int fdisk_list_disklabel(struct fdisk_context *cxt)
302 {
303 int id = 0, rc = 0;
304 struct fdisk_labelitem item = { .id = id };
305
306 if (!cxt || !cxt->label)
307 return -EINVAL;
308
309 if (!cxt->display_details)
310 return 0;
311
312 /* List all label items */
313 do {
314 /* rc: < 0 error, 0 success, 1 unknown item, 2 out of range */
315 rc = fdisk_get_disklabel_item(cxt, id++, &item);
316 if (rc != 0)
317 continue;
318 switch (item.type) {
319 case 'j':
320 fdisk_info(cxt, "%s: %ju", item.name, item.data.num64);
321 break;
322 case 's':
323 if (item.data.str && item.name)
324 fdisk_info(cxt, "%s: %s", item.name, item.data.str);
325 break;
326 }
327 fdisk_reset_labelitem(&item);
328 } while (rc == 0 || rc == 1);
329
330 return rc < 0 ? rc : 0;
331 }
332
333 /**
334 * fdisk_create_disklabel:
335 * @cxt: fdisk context
336 * @name: label name
337 *
338 * Creates a new disk label of type @name. If @name is NULL, then it will
339 * create a default system label type, either SUN or DOS. The function
340 * automatically switches the current label driver to @name. The function
341 * fdisk_get_label() returns the current label driver.
342 *
343 * The function modifies in-memory data only.
344 *
345 * Returns: 0 on success, otherwise, a corresponding error.
346 */
347 int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
348 {
349 int haslabel = 0;
350 struct fdisk_label *lb;
351
352 if (!cxt)
353 return -EINVAL;
354
355 if (!name) { /* use default label creation */
356 #ifdef __sparc__
357 name = "sun";
358 #else
359 name = "dos";
360 #endif
361 }
362
363 if (cxt->label) {
364 fdisk_deinit_label(cxt->label);
365 haslabel = 1;
366 }
367
368 lb = fdisk_get_label(cxt, name);
369 if (!lb || lb->disabled)
370 return -EINVAL;
371
372 if (!haslabel || (lb && cxt->label != lb))
373 fdisk_check_collisions(cxt);
374
375 if (!lb->op->create)
376 return -ENOSYS;
377
378 __fdisk_switch_label(cxt, lb);
379 assert(cxt->label == lb);
380
381 if (haslabel && !cxt->parent)
382 fdisk_reset_device_properties(cxt);
383
384 DBG(CXT, ul_debugobj(cxt, "create a new %s label", lb->name));
385 return lb->op->create(cxt);
386 }
387
388 /**
389 * fdisk_locate_disklabel:
390 * @cxt: context
391 * @n: N item
392 * @name: return item name
393 * @offset: return offset where is item
394 * @size: of the item
395 *
396 * Locate disklabel and returns info about @n item of the label. For example
397 * GPT is composed from two items, PMBR and GPT, n=0 return offset to PMBR and n=1
398 * return offset to GPT. For more details see 'D' expert fdisk command.
399 *
400 * Returns: 0 on success, <0 on error, 1 no more items.
401 */
402 int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name,
403 uint64_t *offset, size_t *size)
404 {
405 if (!cxt || !cxt->label)
406 return -EINVAL;
407 if (!cxt->label->op->locate)
408 return -ENOSYS;
409
410 DBG(CXT, ul_debugobj(cxt, "locating %d chunk of %s.", n, cxt->label->name));
411 return cxt->label->op->locate(cxt, n, name, offset, size);
412 }
413
414
415 /**
416 * fdisk_get_disklabel_id:
417 * @cxt: fdisk context
418 * @id: returns pointer to allocated string (MBR Id or GPT dirk UUID)
419 *
420 * Returns: 0 on success, otherwise, a corresponding error.
421 */
422 int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id)
423 {
424 struct fdisk_labelitem item = FDISK_LABELITEM_INIT;
425 int rc;
426
427 if (!cxt || !cxt->label || !id)
428 return -EINVAL;
429
430 DBG(CXT, ul_debugobj(cxt, "asking for disk %s ID", cxt->label->name));
431
432 rc = fdisk_get_disklabel_item(cxt, FDISK_LABELITEM_ID, &item);
433 if (rc == 0) {
434 *id = item.data.str;
435 item.data.str = NULL;
436 }
437 fdisk_reset_labelitem(&item);
438 if (rc > 0)
439 rc = 0;
440 return rc;
441 }
442
443 /**
444 * fdisk_get_disklabel_item:
445 * @cxt: fdisk context
446 * @id: item ID (FDISK_LABELITEM_* or *_LABELITEM_*)
447 * @item: specifies and returns the item
448 *
449 * Note that @id is always in range 0..N. It's fine to use the function in loop
450 * until it returns error or 2, the result in @item should be ignored when
451 * function returns 1. Don't forget to use fdisk_reset_labelitem() or fdisk_unref_labelitem().
452 *
453 * Returns: 0 on success, < 0 on error, 1 on unsupported item, 2 id out of range
454 */
455 int fdisk_get_disklabel_item(struct fdisk_context *cxt, int id, struct fdisk_labelitem *item)
456 {
457 if (!cxt || !cxt->label || !item)
458 return -EINVAL;
459
460 fdisk_reset_labelitem(item);
461 item->id = id;
462 DBG(CXT, ul_debugobj(cxt, "asking for disk %s item %d", cxt->label->name, item->id));
463
464 if (!cxt->label->op->get_item)
465 return -ENOSYS;
466
467 return cxt->label->op->get_item(cxt, item);
468 }
469
470 /**
471 * fdisk_set_disklabel_id:
472 * @cxt: fdisk context
473 *
474 * Returns: 0 on success, otherwise, a corresponding error.
475 */
476 int fdisk_set_disklabel_id(struct fdisk_context *cxt)
477 {
478 if (!cxt || !cxt->label)
479 return -EINVAL;
480 if (!cxt->label->op->set_id)
481 return -ENOSYS;
482
483 DBG(CXT, ul_debugobj(cxt, "setting %s disk ID", cxt->label->name));
484 return cxt->label->op->set_id(cxt);
485 }
486
487 /**
488 * fdisk_set_partition_type:
489 * @cxt: fdisk context
490 * @partnum: partition number
491 * @t: new type
492 *
493 * Returns: 0 on success, < 0 on error.
494 */
495 int fdisk_set_partition_type(struct fdisk_context *cxt,
496 size_t partnum,
497 struct fdisk_parttype *t)
498 {
499 if (!cxt || !cxt->label || !t)
500 return -EINVAL;
501
502
503 if (cxt->label->op->set_part) {
504 struct fdisk_partition *pa = fdisk_new_partition();
505 int rc;
506
507 if (!pa)
508 return -ENOMEM;
509 fdisk_partition_set_type(pa, t);
510
511 DBG(CXT, ul_debugobj(cxt, "partition: %zd: set type", partnum));
512 rc = cxt->label->op->set_part(cxt, partnum, pa);
513 fdisk_unref_partition(pa);
514 return rc;
515 }
516
517 return -ENOSYS;
518 }
519
520
521 /**
522 * fdisk_toggle_partition_flag:
523 * @cxt: fdisk context
524 * @partnum: partition number
525 * @flag: flag ID
526 *
527 * Returns: 0 on success, otherwise, a corresponding error.
528 */
529 int fdisk_toggle_partition_flag(struct fdisk_context *cxt,
530 size_t partnum,
531 unsigned long flag)
532 {
533 int rc;
534
535 if (!cxt || !cxt->label)
536 return -EINVAL;
537 if (!cxt->label->op->part_toggle_flag)
538 return -ENOSYS;
539
540 rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag);
541
542 DBG(CXT, ul_debugobj(cxt, "partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc));
543 return rc;
544 }
545
546 /**
547 * fdisk_reorder_partitions
548 * @cxt: fdisk context
549 *
550 * Sort partitions according to the partition start sector.
551 *
552 * Returns: 0 on success, 1 reorder unnecessary, otherwise a corresponding error.
553 */
554 int fdisk_reorder_partitions(struct fdisk_context *cxt)
555 {
556 if (!cxt || !cxt->label)
557 return -EINVAL;
558 if (!cxt->label->op->reorder)
559 return -ENOSYS;
560
561 return cxt->label->op->reorder(cxt);
562 }
563
564 /*
565 * Resets the current used label driver to initial state
566 */
567 void fdisk_deinit_label(struct fdisk_label *lb)
568 {
569 assert(lb);
570
571 /* private label information */
572 if (lb->op->deinit)
573 lb->op->deinit(lb);
574 }
575
576 /**
577 * fdisk_label_set_changed:
578 * @lb: label
579 * @changed: 0/1
580 *
581 * Marks in-memory data as changed, to force fdisk_write_disklabel() to write
582 * to device. This should be unnecessary by default, the library keeps track
583 * about changes.
584 */
585 void fdisk_label_set_changed(struct fdisk_label *lb, int changed)
586 {
587 assert(lb);
588 lb->changed = changed ? 1 : 0;
589 }
590
591 /**
592 * fdisk_label_is_changed:
593 * @lb: label
594 *
595 * Returns: 1 if in-memory data has been changed.
596 */
597 int fdisk_label_is_changed(const struct fdisk_label *lb)
598 {
599 assert(lb);
600 return lb ? lb->changed : 0;
601 }
602
603 /**
604 * fdisk_label_set_disabled:
605 * @lb: label
606 * @disabled: 0 or 1
607 *
608 * Mark label as disabled, then libfdisk is going to ignore the label when
609 * probe device for labels.
610 */
611 void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled)
612 {
613 assert(lb);
614
615 DBG(LABEL, ul_debug("%s label %s",
616 lb->name,
617 disabled ? "DISABLED" : "ENABLED"));
618 lb->disabled = disabled ? 1 : 0;
619 }
620
621 /**
622 * fdisk_label_is_disabled:
623 * @lb: label
624 *
625 * Returns: 1 if label driver disabled.
626 */
627 int fdisk_label_is_disabled(const struct fdisk_label *lb)
628 {
629 assert(lb);
630 return lb ? lb->disabled : 0;
631 }
632
633 /**
634 * fdisk_label_get_geomrange_sectors:
635 * @lb: label
636 * @mi: minimal number
637 * @ma: maximal number
638 *
639 * The function provides minimal and maximal geometry supported for the label,
640 * if no range defined by library than returns -ENOSYS.
641 *
642 * Since: 2.32
643 *
644 * Returns: 0 on success, otherwise, a corresponding error.
645 */
646 int fdisk_label_get_geomrange_sectors(const struct fdisk_label *lb,
647 fdisk_sector_t *mi, fdisk_sector_t *ma)
648 {
649 if (!lb || lb->geom_min.sectors == 0)
650 return -ENOSYS;
651 if (mi)
652 *mi = lb->geom_min.sectors;
653 if (ma)
654 *ma = lb->geom_max.sectors;
655 return 0;
656 }
657
658 /**
659 * fdisk_label_get_geomrange_heads:
660 * @lb: label
661 * @mi: minimal number
662 * @ma: maximal number
663 *
664 * The function provides minimal and maximal geometry supported for the label,
665 * if no range defined by library than returns -ENOSYS.
666 *
667 * Since: 2.32
668 *
669 * Returns: 0 on success, otherwise, a corresponding error.
670 */
671 int fdisk_label_get_geomrange_heads(const struct fdisk_label *lb,
672 unsigned int *mi, unsigned int *ma)
673 {
674 if (!lb || lb->geom_min.heads == 0)
675 return -ENOSYS;
676 if (mi)
677 *mi = lb->geom_min.heads;
678 if (ma)
679 *ma = lb->geom_max.heads;
680 return 0;
681 }
682
683 /**
684 * fdisk_label_get_geomrange_cylinders:
685 * @lb: label
686 * @mi: minimal number
687 * @ma: maximal number
688 *
689 * The function provides minimal and maximal geometry supported for the label,
690 * if no range defined by library than returns -ENOSYS.
691 *
692 * Since: 2.32
693 *
694 * Returns: 0 on success, otherwise, a corresponding error.
695 */
696 int fdisk_label_get_geomrange_cylinders(const struct fdisk_label *lb,
697 fdisk_sector_t *mi, fdisk_sector_t *ma)
698 {
699 if (!lb || lb->geom_min.cylinders == 0)
700 return -ENOSYS;
701 if (mi)
702 *mi = lb->geom_min.cylinders;
703 if (ma)
704 *ma = lb->geom_max.cylinders;
705 return 0;
706 }
707