blob: 2a4d377e05a43b76235284381c7fb238a79f8eac [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001#ifdef HAVE_LIBBLKID
2# include <blkid.h>
3#endif
4
5#include "fdiskP.h"
6
7
8/**
9 * SECTION: context
10 * @title: Context
11 * @short_description: stores info about device, labels etc.
12 *
13 * The library distinguish between three types of partitioning objects.
14 *
15 * on-disk data
16 * - disk label specific
17 * - probed and read by disklabel drivers when assign device to the context
18 * or when switch to another disk label type
19 * - only fdisk_write_disklabel() modify on-disk data
20 *
21 * in-memory data
22 * - generic data and disklabel specific data stored in struct fdisk_label
23 * - all partitioning operations are based on in-memory data only
24 *
25 * struct fdisk_partition
26 * - provides abstraction to present partitions to users
27 * - fdisk_partition is possible to gather to fdisk_table container
28 * - used as unified template for new partitions
29 * - the struct fdisk_partition is always completely independent object and
30 * any change to the object has no effect to in-memory (or on-disk) label data
31 */
32
33/**
34 * fdisk_new_context:
35 *
36 * Returns: newly allocated libfdisk handler
37 */
38struct fdisk_context *fdisk_new_context(void)
39{
40 struct fdisk_context *cxt;
41
42 cxt = calloc(1, sizeof(*cxt));
43 if (!cxt)
44 return NULL;
45
46 DBG(CXT, ul_debugobj(cxt, "alloc"));
47 cxt->dev_fd = -1;
48 cxt->refcount = 1;
49
50 /*
51 * Allocate label specific structs.
52 *
53 * This is necessary (for example) to store label specific
54 * context setting.
55 */
56 cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt);
57 cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
58 cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
59 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt);
60 cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt);
61
62 return cxt;
63}
64
65static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
66{
67 struct fdisk_context *parent;
68
69 assert(cxt);
70 assert(cxt->parent);
71
72 parent = cxt->parent;
73
74 cxt->alignment_offset = parent->alignment_offset;
75 cxt->ask_cb = parent->ask_cb;
76 cxt->ask_data = parent->ask_data;
77 cxt->dev_fd = parent->dev_fd;
78 cxt->first_lba = parent->first_lba;
79 cxt->firstsector_bufsz = parent->firstsector_bufsz;
80 cxt->firstsector = parent->firstsector;
81 cxt->geom = parent->geom;
82 cxt->grain = parent->grain;
83 cxt->io_size = parent->io_size;
84 cxt->last_lba = parent->last_lba;
85 cxt->min_io_size = parent->min_io_size;
86 cxt->optimal_io_size = parent->optimal_io_size;
87 cxt->phy_sector_size = parent->phy_sector_size;
88 cxt->readonly = parent->readonly;
89 cxt->script = parent->script;
90 fdisk_ref_script(cxt->script);
91 cxt->sector_size = parent->sector_size;
92 cxt->total_sectors = parent->total_sectors;
93 cxt->user_geom = parent->user_geom;
94 cxt->user_log_sector = parent->user_log_sector;
95 cxt->user_pyh_sector = parent->user_pyh_sector;
96
97 /* parent <--> nested independent setting, initialize for new nested
98 * contexts only */
99 if (isnew) {
100 cxt->listonly = parent->listonly;
101 cxt->display_details = parent->display_details;
102 cxt->display_in_cyl_units = parent->display_in_cyl_units;
103 }
104
105 free(cxt->dev_path);
106 cxt->dev_path = NULL;
107
108 if (parent->dev_path) {
109 cxt->dev_path = strdup(parent->dev_path);
110 if (!cxt->dev_path)
111 return -ENOMEM;
112 }
113
114 return 0;
115}
116
117/**
118 * fdisk_new_nested_context:
119 * @parent: parental context
120 * @name: optional label name (e.g. "bsd")
121 *
122 * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
123 * The function also probes for the nested label on the device if device is
124 * already assigned to parent.
125 *
126 * The new context is initialized according to @parent and both context shares
127 * some settings and file descriptor to the device. The child propagate some
128 * changes (like fdisk_assign_device()) to parent, but it does not work
129 * vice-versa. The behavior is undefined if you assign another device to
130 * parent.
131 *
132 * Returns: new context for nested partition table.
133 */
134struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent,
135 const char *name)
136{
137 struct fdisk_context *cxt;
138 struct fdisk_label *lb = NULL;
139
140 assert(parent);
141
142 cxt = calloc(1, sizeof(*cxt));
143 if (!cxt)
144 return NULL;
145
146 DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt));
147 cxt->refcount = 1;
148
149 fdisk_ref_context(parent);
150 cxt->parent = parent;
151
152 if (init_nested_from_parent(cxt, 1) != 0)
153 return NULL;
154
155 if (name) {
156 if (strcmp(name, "bsd") == 0)
157 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
158 else if (strcmp(name, "dos") == 0)
159 lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
160 }
161
162 if (lb && parent->dev_fd >= 0) {
163 DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name));
164
165 cxt->label = lb;
166
167 if (lb->op->probe(cxt) == 1)
168 __fdisk_switch_label(cxt, lb);
169 else {
170 DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name));
171 if (lb->op->deinit)
172 lb->op->deinit(lb);
173 cxt->label = NULL;
174 }
175 }
176
177 return cxt;
178}
179
180
181/**
182 * fdisk_ref_context:
183 * @cxt: context pointer
184 *
185 * Increments reference counter.
186 */
187void fdisk_ref_context(struct fdisk_context *cxt)
188{
189 if (cxt)
190 cxt->refcount++;
191}
192
193/**
194 * fdisk_get_label:
195 * @cxt: context instance
196 * @name: label name (e.g. "gpt")
197 *
198 * If no @name specified then returns the current context label.
199 *
200 * The label is allocated and maintained within the context #cxt. There is
201 * nothing like reference counting for labels, you cannot delallocate the
202 * label.
203 *
204 * Returns: label struct or NULL in case of error.
205 */
206struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name)
207{
208 size_t i;
209
210 assert(cxt);
211
212 if (!name)
213 return cxt->label;
214
215 for (i = 0; i < cxt->nlabels; i++)
216 if (cxt->labels[i]
217 && strcmp(cxt->labels[i]->name, name) == 0)
218 return cxt->labels[i];
219
220 DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name));
221 return NULL;
222}
223
224/**
225 * fdisk_next_label:
226 * @cxt: context instance
227 * @lb: returns pointer to the next label
228 *
229 * <informalexample>
230 * <programlisting>
231 * // print all supported labels
232 * struct fdisk_context *cxt = fdisk_new_context();
233 * struct fdisk_label *lb = NULL;
234 *
235 * while (fdisk_next_label(cxt, &lb) == 0)
236 * print("label name: %s\n", fdisk_label_get_name(lb));
237 * fdisk_unref_context(cxt);
238 * </programlisting>
239 * </informalexample>
240 *
241 * Returns: <0 in case of error, 0 on success, 1 at the end.
242 */
243int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb)
244{
245 size_t i;
246 struct fdisk_label *res = NULL;
247
248 if (!lb || !cxt)
249 return -EINVAL;
250
251 if (!*lb)
252 res = cxt->labels[0];
253 else {
254 for (i = 1; i < cxt->nlabels; i++) {
255 if (*lb == cxt->labels[i - 1]) {
256 res = cxt->labels[i];
257 break;
258 }
259 }
260 }
261
262 *lb = res;
263 return res ? 0 : 1;
264}
265
266/**
267 * fdisk_get_nlabels:
268 * @cxt: context
269 *
270 * Returns: number of supported label types
271 */
272size_t fdisk_get_nlabels(struct fdisk_context *cxt)
273{
274 return cxt ? cxt->nlabels : 0;
275}
276
277int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb)
278{
279 if (!lb || !cxt)
280 return -EINVAL;
281 if (lb->disabled) {
282 DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name));
283 return -EINVAL;
284 }
285 cxt->label = lb;
286 DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name));
287 return 0;
288}
289
290/**
291 * fdisk_has_label:
292 * @cxt: fdisk context
293 *
294 * Returns: return 1 if there is label on the device.
295 */
296int fdisk_has_label(struct fdisk_context *cxt)
297{
298 return cxt && cxt->label;
299}
300
301/**
302 * fdisk_get_npartitions:
303 * @cxt: context
304 *
305 * The maximal number of the partitions depends on disklabel and does not
306 * have to describe the real limit of PT.
307 *
308 * For example the limit for MBR without extend partition is 4, with extended
309 * partition it's unlimited (so the function returns the current number of all
310 * partitions in this case).
311 *
312 * And for example for GPT it depends on space allocated on disk for array of
313 * entry records (usually 128).
314 *
315 * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
316 * partition may be unused (see fdisk_is_partition_used()).
317 *
318 * <informalexample>
319 * <programlisting>
320 * struct fdisk_partition *pa = NULL;
321 * size_t i, nmax = fdisk_get_npartitions(cxt);
322 *
323 * for (i = 0; i < nmax; i++) {
324 * if (!fdisk_is_partition_used(cxt, i))
325 * continue;
326 * ... do something ...
327 * }
328 * </programlisting>
329 * </informalexample>
330 *
331 * Note that the recommended way to list partitions is to use
332 * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each
333 * individual partitions.
334 *
335 * Returns: maximal number of partitions for the current label.
336 */
337size_t fdisk_get_npartitions(struct fdisk_context *cxt)
338{
339 return cxt && cxt->label ? cxt->label->nparts_max : 0;
340}
341
342/**
343 * fdisk_is_labeltype:
344 * @cxt: fdisk context
345 * @id: FDISK_DISKLABEL_*
346 *
347 * See also fdisk_is_label() macro in libfdisk.h.
348 *
349 * Returns: return 1 if the current label is @id
350 */
351int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id)
352{
353 assert(cxt);
354
355 return cxt->label && fdisk_label_get_type(cxt->label) == id;
356}
357
358/**
359 * fdisk_get_parent:
360 * @cxt: nested fdisk context
361 *
362 * Returns: pointer to parental context, or NULL
363 */
364struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt)
365{
366 assert(cxt);
367 return cxt->parent;
368}
369
370static void reset_context(struct fdisk_context *cxt)
371{
372 size_t i;
373
374 DBG(CXT, ul_debugobj(cxt, "*** resetting context"));
375
376 /* reset drives' private data */
377 for (i = 0; i < cxt->nlabels; i++)
378 fdisk_deinit_label(cxt->labels[i]);
379
380 if (cxt->parent) {
381 /* the first sector may be independent on parent */
382 if (cxt->parent->firstsector != cxt->firstsector)
383 free(cxt->firstsector);
384 } else {
385 /* we close device only in primary context */
386 if (cxt->dev_fd > -1)
387 close(cxt->dev_fd);
388 free(cxt->firstsector);
389 }
390
391 free(cxt->dev_path);
392 cxt->dev_path = NULL;
393
394 cxt->dev_fd = -1;
395 cxt->firstsector = NULL;
396 cxt->firstsector_bufsz = 0;
397
398 fdisk_zeroize_device_properties(cxt);
399
400 fdisk_unref_script(cxt->script);
401 cxt->script = NULL;
402
403 cxt->label = NULL;
404}
405
406/*
407 * This function prints a warning if the device is not wiped (e.g. wipefs(8).
408 * Please don't call this function if there is already a PT.
409 *
410 * Returns: 0 if nothing found, < 0 on error, 1 if found a signature
411 */
412static int warn_wipe(struct fdisk_context *cxt)
413{
414#ifdef HAVE_LIBBLKID
415 blkid_probe pr;
416#endif
417 int rc = 0;
418
419 assert(cxt);
420
421 if (fdisk_has_label(cxt) || cxt->dev_fd < 0)
422 return -EINVAL;
423#ifdef HAVE_LIBBLKID
424 DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober"));
425
426 pr = blkid_new_probe();
427 if (!pr)
428 return -ENOMEM;
429 rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0);
430 if (rc)
431 return rc;
432
433 blkid_probe_enable_superblocks(pr, 1);
434 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
435 blkid_probe_enable_partitions(pr, 1);
436
437 /* we care about the first found FS/raid, so don't call blkid_do_probe()
438 * in loop or don't use blkid_do_fullprobe() ... */
439 rc = blkid_do_probe(pr);
440 if (rc == 0) {
441 const char *name = NULL;
442
443 if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 ||
444 blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
445 fdisk_warnx(cxt, _(
446 "%s: device contains a valid '%s' signature; it is "
447 "strongly recommended to wipe the device with "
448 "wipefs(8) if this is unexpected, in order to "
449 "avoid possible collisions"), cxt->dev_path, name);
450 rc = 1;
451 }
452 }
453
454 blkid_free_probe(pr);
455#endif
456 return rc;
457}
458
459/**
460 * fdisk_assign_device:
461 * @cxt: context
462 * @fname: path to the device to be handled
463 * @readonly: how to open the device
464 *
465 * Open the device, discovery topology, geometry, detect disklabel and switch
466 * the current label driver to reflect the probing result.
467 *
468 * Note that this function resets all generic setting in context. If the @cxt
469 * is nested context then the device is assigned to the parental context and
470 * necessary properties are copied to the @cxt. The change is propagated in
471 * child->parent direction only. It's impossible to use a different device for
472 * primary and nested contexts.
473 *
474 * Returns: 0 on success, < 0 on error.
475 */
476int fdisk_assign_device(struct fdisk_context *cxt,
477 const char *fname, int readonly)
478{
479 int fd;
480
481 DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
482 assert(cxt);
483
484 /* redirect request to parent */
485 if (cxt->parent) {
486 int rc, org = fdisk_is_listonly(cxt->parent);
487
488 /* assign_device() is sensitive to "listonly" mode, so let's
489 * follow the current context setting for the parent to avoid
490 * unwanted extra warnings. */
491 fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt));
492
493 rc = fdisk_assign_device(cxt->parent, fname, readonly);
494 fdisk_enable_listonly(cxt->parent, org);
495
496 if (!rc)
497 rc = init_nested_from_parent(cxt, 0);
498 if (!rc)
499 fdisk_probe_labels(cxt);
500 return rc;
501 }
502
503 reset_context(cxt);
504
505 fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
506 if (fd < 0)
507 return -errno;
508
509 cxt->readonly = readonly;
510 cxt->dev_fd = fd;
511 cxt->dev_path = strdup(fname);
512 if (!cxt->dev_path)
513 goto fail;
514
515 fdisk_discover_topology(cxt);
516 fdisk_discover_geometry(cxt);
517
518 if (fdisk_read_firstsector(cxt) < 0)
519 goto fail;
520
521 /* detect labels and apply labes specific stuff (e.g geomery)
522 * to the context */
523 fdisk_probe_labels(cxt);
524
525 /* let's apply user geometry *after* label prober
526 * to make it possible to override in-label setting */
527 fdisk_apply_user_device_properties(cxt);
528
529 /* warn about obsolete stuff on the device if we aren't in
530 * list-only mode and there is not PT yet */
531 if (!fdisk_is_listonly(cxt) && !fdisk_has_label(cxt))
532 warn_wipe(cxt);
533
534 DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]",
535 fname, readonly ? "READ-ONLY" : "READ-WRITE"));
536 return 0;
537fail:
538 DBG(CXT, ul_debugobj(cxt, "failed to assign device"));
539 return -errno;
540}
541
542/**
543 * fdisk_deassign_device:
544 * @cxt: context
545 * @nosync: disable fsync()
546 *
547 * Close device and call fsync(). If the @cxt is nested context than the
548 * request is redirected to the parent.
549 *
550 * Returns: 0 on success, < 0 on error.
551 */
552int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
553{
554 assert(cxt);
555 assert(cxt->dev_fd >= 0);
556
557 if (cxt->parent) {
558 int rc = fdisk_deassign_device(cxt->parent, nosync);
559
560 if (!rc)
561 rc = init_nested_from_parent(cxt, 0);
562 return rc;
563 }
564
565 if (cxt->readonly)
566 close(cxt->dev_fd);
567 else {
568 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
569 fdisk_warn(cxt, _("%s: close device failed"),
570 cxt->dev_path);
571 return -errno;
572 }
573
574 if (!nosync) {
575 fdisk_info(cxt, _("Syncing disks."));
576 sync();
577 }
578 }
579
580 free(cxt->dev_path);
581 cxt->dev_path = NULL;
582
583 cxt->dev_fd = -1;
584
585 return 0;
586}
587
588/**
589 * fdisk_is_readonly:
590 * @cxt: context
591 *
592 * Returns: 1 if device open readonly
593 */
594int fdisk_is_readonly(struct fdisk_context *cxt)
595{
596 assert(cxt);
597 return cxt->readonly;
598}
599
600/**
601 * fdisk_unref_context:
602 * @cxt: fdisk context
603 *
604 * Deallocates context struct.
605 */
606void fdisk_unref_context(struct fdisk_context *cxt)
607{
608 int i;
609
610 if (!cxt)
611 return;
612
613 cxt->refcount--;
614 if (cxt->refcount <= 0) {
615 DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path));
616
617 reset_context(cxt); /* this is sensitive to parent<->child relationship! */
618
619 /* deallocate label's private stuff */
620 for (i = 0; i < cxt->nlabels; i++) {
621 if (!cxt->labels[i])
622 continue;
623 if (cxt->labels[i]->op->free)
624 cxt->labels[i]->op->free(cxt->labels[i]);
625 else
626 free(cxt->labels[i]);
627 }
628
629 fdisk_unref_context(cxt->parent);
630 cxt->parent = NULL;
631
632 free(cxt);
633 }
634}
635
636
637/**
638 * fdisk_enable_details:
639 * @cxt: context
640 * @enable: true/flase
641 *
642 * Enables or disables "details" display mode. This function has effect to
643 * fdisk_partition_to_string() function.
644 *
645 * Returns: 0 on success, < 0 on error.
646 */
647int fdisk_enable_details(struct fdisk_context *cxt, int enable)
648{
649 assert(cxt);
650 cxt->display_details = enable ? 1 : 0;
651 return 0;
652}
653
654/**
655 * fdisk_is_details:
656 * @cxt: context
657 *
658 * Returns: 1 if details are enabled
659 */
660int fdisk_is_details(struct fdisk_context *cxt)
661{
662 assert(cxt);
663 return cxt->display_details == 1;
664}
665
666/**
667 * fdisk_enable_listonly:
668 * @cxt: context
669 * @enable: true/flase
670 *
671 * Just list partition only, don't care about another details, mistakes, ...
672 *
673 * Returns: 0 on success, < 0 on error.
674 */
675int fdisk_enable_listonly(struct fdisk_context *cxt, int enable)
676{
677 assert(cxt);
678 cxt->listonly = enable ? 1 : 0;
679 return 0;
680}
681
682/**
683 * fdisk_is_listonly:
684 * @cxt: context
685 *
686 * Returns: 1 if list-only mode enabled
687 */
688int fdisk_is_listonly(struct fdisk_context *cxt)
689{
690 assert(cxt);
691 return cxt->listonly == 1;
692}
693
694
695/**
696 * fdisk_set_unit:
697 * @cxt: context
698 * @str: "cylinder" or "sector".
699 *
700 * This is pure shit, unfortunately for example Sun addresses begin of the
701 * partition by cylinders...
702 *
703 * Returns: 0 on succes, <0 on error.
704 */
705int fdisk_set_unit(struct fdisk_context *cxt, const char *str)
706{
707 assert(cxt);
708
709 cxt->display_in_cyl_units = 0;
710
711 if (!str)
712 return 0;
713
714 if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0)
715 cxt->display_in_cyl_units = 1;
716
717 else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0)
718 cxt->display_in_cyl_units = 0;
719
720 DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0)));
721 return 0;
722}
723
724/**
725 * fdisk_get_unit:
726 * @cxt: context
727 * @n: FDISK_PLURAL or FDISK_SINGULAR
728 *
729 * Returns: unit name.
730 */
731const char *fdisk_get_unit(struct fdisk_context *cxt, int n)
732{
733 assert(cxt);
734
735 if (fdisk_use_cylinders(cxt))
736 return P_("cylinder", "cylinders", n);
737 return P_("sector", "sectors", n);
738}
739
740/**
741 * fdisk_use_cylinders:
742 * @cxt: context
743 *
744 * Returns: 1 if user wants to display in cylinders.
745 */
746int fdisk_use_cylinders(struct fdisk_context *cxt)
747{
748 assert(cxt);
749 return cxt->display_in_cyl_units == 1;
750}
751
752/**
753 * fdisk_get_units_per_sector:
754 * @cxt: context
755 *
756 * This is necessary only for brain dead situations when we use "cylinders";
757 *
758 * Returns: number of "units" per sector, default is 1 if display unit is sector.
759 */
760unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt)
761{
762 assert(cxt);
763
764 if (fdisk_use_cylinders(cxt)) {
765 assert(cxt->geom.heads);
766 return cxt->geom.heads * cxt->geom.sectors;
767 }
768 return 1;
769}
770
771/**
772 * fdisk_get_optimal_iosize:
773 * @cxt: context
774 *
775 * The optimal I/O is optional and does not have to be provided by device,
776 * anyway libfdisk never returns zero. If the optimal I/O size is not provided
777 * then libfdisk returns minimal I/O size or sector size.
778 *
779 * Returns: optimal I/O size in bytes.
780 */
781unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt)
782{
783 assert(cxt);
784 return cxt->optimal_io_size ? cxt->optimal_io_size : cxt->io_size;
785}
786
787/**
788 * fdisk_get_minimal_iosize:
789 * @cxt: context
790 *
791 * Returns: minimal I/O size in bytes
792 */
793unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt)
794{
795 assert(cxt);
796 return cxt->min_io_size;
797}
798
799/**
800 * fdisk_get_physector_size:
801 * @cxt: context
802 *
803 * Returns: physical sector size in bytes
804 */
805unsigned long fdisk_get_physector_size(struct fdisk_context *cxt)
806{
807 assert(cxt);
808 return cxt->phy_sector_size;
809}
810
811/**
812 * fdisk_get_sector_size:
813 * @cxt: context
814 *
815 * Returns: logical sector size in bytes
816 */
817unsigned long fdisk_get_sector_size(struct fdisk_context *cxt)
818{
819 assert(cxt);
820 return cxt->sector_size;
821}
822
823/**
824 * fdisk_get_alignment_offset
825 * @cxt: context
826 *
827 * The alignment offset is offset between logical and physical sectors. For
828 * backward compatibility the first logical sector on 4K disks does no have to
829 * start on the same place like physical sectors.
830 *
831 * Returns: alignment offset in bytes
832 */
833unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt)
834{
835 assert(cxt);
836 return cxt->alignment_offset;
837}
838
839/**
840 * fdisk_get_grain_size:
841 * @cxt: context
842 *
843 * Returns: grain in bytes used to align partitions (usually 1MiB)
844 */
845unsigned long fdisk_get_grain_size(struct fdisk_context *cxt)
846{
847 assert(cxt);
848 return cxt->grain;
849}
850
851/**
852 * fdisk_get_first_lba:
853 * @cxt: context
854 *
855 * Returns: first possible LBA on disk for data partitions.
856 */
857fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt)
858{
859 assert(cxt);
860 return cxt->first_lba;
861}
862
863/**
864 * fdisk_set_first_lba:
865 * @cxt: fdisk context
866 * @lba: first possible logical sector for data
867 *
868 * It's strongly recommended to use the default library setting. The first LBA
869 * is always reseted by fdisk_assign_device(), fdisk_override_geometry()
870 * and fdisk_reset_alignment(). This is very low level function and library
871 * does not check if your setting makes any sense.
872 *
873 * This function is necessary only when you want to work with very unusual
874 * partition tables like GPT protective MBR or hybrid partition tables on
875 * bootable media where the first partition may start on very crazy offsets.
876 *
877 * Returns: 0 on success, <0 on error.
878 */
879fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
880{
881 assert(cxt);
882 DBG(CXT, ul_debugobj(cxt, "setting first LBA from %ju to %ju",
883 (uintmax_t) cxt->first_lba, (uintmax_t) lba));
884 cxt->first_lba = lba;
885 return 0;
886}
887
888/**
889 * fdisk_get_last_lba:
890 * @cxt: fdisk context
891 *
892 * Note that the device has to be already assigned.
893 *
894 * Returns: last possible LBA on device
895 */
896fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt)
897{
898 return cxt->last_lba;
899}
900
901/**
902 * fdisk_set_last_lba:
903 * @cxt: fdisk context
904 * @lba: last possible logical sector
905 *
906 * It's strongly recommended to use the default library setting. The last LBA
907 * is always reseted by fdisk_assign_device(), fdisk_override_geometry() and
908 * fdisk_reset_alignment().
909 *
910 * The default is number of sectors on the device, but maybe modified by the
911 * current disklabel driver (for example GPT uses and of disk for backup
912 * header, so last_lba is smaller than total number of sectors).
913 *
914 * Returns: 0 on success, <0 on error.
915 */
916fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
917{
918 assert(cxt);
919
920 if (lba > cxt->total_sectors - 1 && lba < 1)
921 return -ERANGE;
922 cxt->last_lba = lba;
923 return 0;
924}
925
926
927/**
928 * fdisk_get_nsectors:
929 * @cxt: context
930 *
931 * Returns: size of the device in logical sectors.
932 */
933fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt)
934{
935 assert(cxt);
936 return cxt->total_sectors;
937}
938
939/**
940 * fdisk_get_devname:
941 * @cxt: context
942 *
943 * Returns: device name.
944 */
945const char *fdisk_get_devname(struct fdisk_context *cxt)
946{
947 assert(cxt);
948 return cxt->dev_path;
949}
950
951/**
952 * fdisk_get_devfd:
953 * @cxt: context
954 *
955 * Retruns: device file descriptor.
956 */
957int fdisk_get_devfd(struct fdisk_context *cxt)
958{
959 assert(cxt);
960 return cxt->dev_fd;
961}
962
963/**
964 * fdisk_get_geom_heads:
965 * @cxt: context
966 *
967 * Returns: number of geometry heads.
968 */
969unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt)
970{
971 assert(cxt);
972 return cxt->geom.heads;
973}
974/**
975 * fdisk_get_geom_sectors:
976 * @cxt: context
977 *
978 * Returns: number of geometry sectors.
979 */
980fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt)
981{
982 assert(cxt);
983 return cxt->geom.sectors;
984
985}
986
987/**
988 * fdisk_get_geom_cylinders:
989 * @cxt: context
990 *
991 * Returns: number of geometry cylinders
992 */
993fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt)
994{
995 assert(cxt);
996 return cxt->geom.cylinders;
997}
998
999int fdisk_missing_geometry(struct fdisk_context *cxt)
1000{
1001 int rc;
1002
1003 assert(cxt);
1004
1005 if (!cxt || !cxt->label)
1006 return 0;
1007
1008 rc = (fdisk_label_require_geometry(cxt->label) &&
1009 (!cxt->geom.heads || !cxt->geom.sectors
1010 || !cxt->geom.cylinders));
1011
1012 if (rc && !fdisk_is_listonly(cxt))
1013 fdisk_warnx(cxt, _("Incomplete geometry setting."));
1014
1015 return rc;
1016}
1017