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 can be used 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 
fdisk_probe_labels(struct fdisk_context * cxt)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  */
fdisk_label_get_name(const struct fdisk_label * lb)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  */
fdisk_label_get_type(const struct fdisk_label * lb)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  */
fdisk_label_require_geometry(const struct fdisk_label * lb)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  */
fdisk_label_get_fields_ids(const struct fdisk_label * lb,struct fdisk_context * cxt,int ** ids,size_t * nids)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  */
fdisk_label_get_fields_ids_all(const struct fdisk_label * lb,struct fdisk_context * cxt,int ** ids,size_t * nids)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  */
fdisk_label_get_field(const struct fdisk_label * lb,int id)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  */
fdisk_label_get_field_by_name(const struct fdisk_label * lb,const char * name)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 enabled by fdisk_enable_wipe()) and then
251  * it writes in-memory changes to disk. Be careful!
252  *
253  * Returns: 0 on success, otherwise, a corresponding error.
254  */
fdisk_write_disklabel(struct fdisk_context * cxt)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, <1 runtime or option errors, >0 number of detected issues
273  */
fdisk_verify_disklabel(struct fdisk_context * cxt)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  */
fdisk_list_disklabel(struct fdisk_context * cxt)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  */
fdisk_create_disklabel(struct fdisk_context * cxt,const char * name)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  */
fdisk_locate_disklabel(struct fdisk_context * cxt,int n,const char ** name,uint64_t * offset,size_t * size)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  */
fdisk_get_disklabel_id(struct fdisk_context * cxt,char ** id)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  */
fdisk_get_disklabel_item(struct fdisk_context * cxt,int id,struct fdisk_labelitem * item)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  */
fdisk_set_disklabel_id(struct fdisk_context * cxt)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, NULL);
485 }
486 
487 /**
488  * fdisk_set_disklabel_id_from_string
489  * @cxt: fdisk context
490  * @str: new Id
491  *
492  * Returns: 0 on success, otherwise, a corresponding error.
493  *
494  * Since: 2.36
495  */
fdisk_set_disklabel_id_from_string(struct fdisk_context * cxt,const char * str)496 int fdisk_set_disklabel_id_from_string(struct fdisk_context *cxt, const char *str)
497 {
498 	if (!cxt || !cxt->label || !str)
499 		return -EINVAL;
500 	if (!cxt->label->op->set_id)
501 		return -ENOSYS;
502 
503 	DBG(CXT, ul_debugobj(cxt, "setting %s disk ID from '%s'", cxt->label->name, str));
504 	return cxt->label->op->set_id(cxt, str);
505 }
506 
507 /**
508  * fdisk_set_partition_type:
509  * @cxt: fdisk context
510  * @partnum: partition number
511  * @t: new type
512  *
513  * Returns: 0 on success, < 0 on error.
514  */
fdisk_set_partition_type(struct fdisk_context * cxt,size_t partnum,struct fdisk_parttype * t)515 int fdisk_set_partition_type(struct fdisk_context *cxt,
516 			     size_t partnum,
517 			     struct fdisk_parttype *t)
518 {
519 	if (!cxt || !cxt->label || !t)
520 		return -EINVAL;
521 
522 
523 	if (cxt->label->op->set_part) {
524 		struct fdisk_partition *pa = fdisk_new_partition();
525 		int rc;
526 
527 		if (!pa)
528 			return -ENOMEM;
529 		fdisk_partition_set_type(pa, t);
530 
531 		DBG(CXT, ul_debugobj(cxt, "partition: %zd: set type", partnum));
532 		rc = cxt->label->op->set_part(cxt, partnum, pa);
533 		fdisk_unref_partition(pa);
534 		return rc;
535 	}
536 
537 	return -ENOSYS;
538 }
539 
540 
541 /**
542  * fdisk_toggle_partition_flag:
543  * @cxt: fdisk context
544  * @partnum: partition number
545  * @flag: flag ID
546  *
547  * Returns: 0 on success, otherwise, a corresponding error.
548  */
fdisk_toggle_partition_flag(struct fdisk_context * cxt,size_t partnum,unsigned long flag)549 int fdisk_toggle_partition_flag(struct fdisk_context *cxt,
550 			       size_t partnum,
551 			       unsigned long flag)
552 {
553 	int rc;
554 
555 	if (!cxt || !cxt->label)
556 		return -EINVAL;
557 	if (!cxt->label->op->part_toggle_flag)
558 		return -ENOSYS;
559 
560 	rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag);
561 
562 	DBG(CXT, ul_debugobj(cxt, "partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc));
563 	return rc;
564 }
565 
566 /**
567  * fdisk_reorder_partitions
568  * @cxt: fdisk context
569  *
570  * Sort partitions according to the partition start sector.
571  *
572  * Returns: 0 on success, 1 reorder unnecessary, otherwise a corresponding error.
573  */
fdisk_reorder_partitions(struct fdisk_context * cxt)574 int fdisk_reorder_partitions(struct fdisk_context *cxt)
575 {
576 	if (!cxt || !cxt->label)
577 		return -EINVAL;
578 	if (!cxt->label->op->reorder)
579 		return -ENOSYS;
580 
581 	return cxt->label->op->reorder(cxt);
582 }
583 
584 /*
585  * Resets the current used label driver to initial state
586  */
fdisk_deinit_label(struct fdisk_label * lb)587 void fdisk_deinit_label(struct fdisk_label *lb)
588 {
589 	assert(lb);
590 
591 	/* private label information */
592 	if (lb->op->deinit)
593 		lb->op->deinit(lb);
594 }
595 
596 /**
597  * fdisk_label_set_changed:
598  * @lb: label
599  * @changed: 0/1
600  *
601  * Marks in-memory data as changed, to force fdisk_write_disklabel() to write
602  * to device. This should be unnecessary by default, the library keeps track
603  * about changes.
604  */
fdisk_label_set_changed(struct fdisk_label * lb,int changed)605 void fdisk_label_set_changed(struct fdisk_label *lb, int changed)
606 {
607 	assert(lb);
608 	lb->changed = changed ? 1 : 0;
609 }
610 
611 /**
612  * fdisk_label_is_changed:
613  * @lb: label
614  *
615  * Returns: 1 if in-memory data has been changed.
616  */
fdisk_label_is_changed(const struct fdisk_label * lb)617 int fdisk_label_is_changed(const struct fdisk_label *lb)
618 {
619 	return lb ? lb->changed : 0;
620 }
621 
622 /**
623  * fdisk_label_set_disabled:
624  * @lb: label
625  * @disabled: 0 or 1
626  *
627  * Mark label as disabled, then libfdisk is going to ignore the label when
628  * probe device for labels.
629  */
fdisk_label_set_disabled(struct fdisk_label * lb,int disabled)630 void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled)
631 {
632 	assert(lb);
633 
634 	DBG(LABEL, ul_debug("%s label %s",
635 				lb->name,
636 				disabled ? "DISABLED" : "ENABLED"));
637 	lb->disabled = disabled ? 1 : 0;
638 }
639 
640 /**
641  * fdisk_label_is_disabled:
642  * @lb: label
643  *
644  * Returns: 1 if label driver disabled.
645  */
fdisk_label_is_disabled(const struct fdisk_label * lb)646 int fdisk_label_is_disabled(const struct fdisk_label *lb)
647 {
648 	assert(lb);
649 	return lb ? lb->disabled : 0;
650 }
651 
652 /**
653  * fdisk_label_get_geomrange_sectors:
654  * @lb: label
655  * @mi: minimal number
656  * @ma: maximal number
657  *
658  * The function provides minimal and maximal geometry supported for the label,
659  * if no range defined by library then returns -ENOSYS.
660  *
661  * Since: 2.32
662  *
663  * Returns: 0 on success, otherwise, a corresponding error.
664  */
fdisk_label_get_geomrange_sectors(const struct fdisk_label * lb,fdisk_sector_t * mi,fdisk_sector_t * ma)665 int fdisk_label_get_geomrange_sectors(const struct fdisk_label *lb,
666 					fdisk_sector_t *mi, fdisk_sector_t *ma)
667 {
668 	if (!lb || lb->geom_min.sectors == 0)
669 		return -ENOSYS;
670 	if (mi)
671 		*mi = lb->geom_min.sectors;
672 	if (ma)
673 		*ma = lb->geom_max.sectors;
674 	return 0;
675 }
676 
677 /**
678  * fdisk_label_get_geomrange_heads:
679  * @lb: label
680  * @mi: minimal number
681  * @ma: maximal number
682  *
683  * The function provides minimal and maximal geometry supported for the label,
684  * if no range defined by library then returns -ENOSYS.
685  *
686  * Since: 2.32
687  *
688  * Returns: 0 on success, otherwise, a corresponding error.
689  */
fdisk_label_get_geomrange_heads(const struct fdisk_label * lb,unsigned int * mi,unsigned int * ma)690 int fdisk_label_get_geomrange_heads(const struct fdisk_label *lb,
691 					unsigned int *mi, unsigned int *ma)
692 {
693 	if (!lb || lb->geom_min.heads == 0)
694 		return -ENOSYS;
695 	if (mi)
696 		*mi = lb->geom_min.heads;
697 	if (ma)
698 		*ma = lb->geom_max.heads;
699 	return 0;
700 }
701 
702 /**
703  * fdisk_label_get_geomrange_cylinders:
704  * @lb: label
705  * @mi: minimal number
706  * @ma: maximal number
707  *
708  * The function provides minimal and maximal geometry supported for the label,
709  * if no range defined by library then returns -ENOSYS.
710  *
711  * Since: 2.32
712  *
713  * Returns: 0 on success, otherwise, a corresponding error.
714  */
fdisk_label_get_geomrange_cylinders(const struct fdisk_label * lb,fdisk_sector_t * mi,fdisk_sector_t * ma)715 int fdisk_label_get_geomrange_cylinders(const struct fdisk_label *lb,
716 					fdisk_sector_t *mi, fdisk_sector_t *ma)
717 {
718 	if (!lb || lb->geom_min.cylinders == 0)
719 		return -ENOSYS;
720 	if (mi)
721 		*mi = lb->geom_min.cylinders;
722 	if (ma)
723 		*ma = lb->geom_max.cylinders;
724 	return 0;
725 }
726 
727