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