]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/context.c
16 * @short_description: stores info about device, labels etc.
18 * The library distinguish between three types of partitioning objects.
21 * - disk label specific
22 * - probed and read by disklabel drivers when assign device to the context
23 * or when switch to another disk label type
24 * - only fdisk_write_disklabel() modify on-disk data
26 * in-memory label data
27 * - generic data and disklabel specific data stored in struct fdisk_label
28 * - all partitioning operations are based on in-memory data only
30 * struct fdisk_partition
31 * - provides abstraction to present partitions to users
32 * - fdisk_partition is possible to gather to fdisk_table container
33 * - used as unified template for new partitions
34 * - used (with fdisk_table) in fdisk scripts
35 * - the struct fdisk_partition is always completely independent object and
36 * any change to the object has no effect to in-memory (or on-disk) label data
38 * Don't forget to inform kernel about changes by fdisk_reread_partition_table()
39 * or more smart fdisk_reread_changes().
45 * Returns: newly allocated libfdisk handler
47 struct fdisk_context
*fdisk_new_context(void)
49 struct fdisk_context
*cxt
;
51 cxt
= calloc(1, sizeof(*cxt
));
55 DBG(CXT
, ul_debugobj(cxt
, "alloc"));
59 INIT_LIST_HEAD(&cxt
->wipes
);
62 * Allocate label specific structs.
64 * This is necessary (for example) to store label specific
67 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_gpt_label(cxt
);
68 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_dos_label(cxt
);
69 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_bsd_label(cxt
);
70 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_sgi_label(cxt
);
71 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_sun_label(cxt
);
73 bindtextdomain(LIBFDISK_TEXTDOMAIN
, LOCALEDIR
);
78 static int init_nested_from_parent(struct fdisk_context
*cxt
, int isnew
)
80 struct fdisk_context
*parent
;
87 cxt
->alignment_offset
= parent
->alignment_offset
;
88 cxt
->ask_cb
= parent
->ask_cb
;
89 cxt
->ask_data
= parent
->ask_data
;
90 cxt
->dev_fd
= parent
->dev_fd
;
91 cxt
->first_lba
= parent
->first_lba
;
92 cxt
->firstsector_bufsz
= parent
->firstsector_bufsz
;
93 cxt
->firstsector
= parent
->firstsector
;
94 cxt
->geom
= parent
->geom
;
95 cxt
->grain
= parent
->grain
;
96 cxt
->io_size
= parent
->io_size
;
97 cxt
->last_lba
= parent
->last_lba
;
98 cxt
->min_io_size
= parent
->min_io_size
;
99 cxt
->optimal_io_size
= parent
->optimal_io_size
;
100 cxt
->phy_sector_size
= parent
->phy_sector_size
;
101 cxt
->readonly
= parent
->readonly
;
102 cxt
->script
= parent
->script
;
103 fdisk_ref_script(cxt
->script
);
104 cxt
->sector_size
= parent
->sector_size
;
105 cxt
->total_sectors
= parent
->total_sectors
;
106 cxt
->user_geom
= parent
->user_geom
;
107 cxt
->user_log_sector
= parent
->user_log_sector
;
108 cxt
->user_pyh_sector
= parent
->user_pyh_sector
;
110 /* parent <--> nested independent setting, initialize for new nested
113 cxt
->listonly
= parent
->listonly
;
114 cxt
->display_details
= parent
->display_details
;
115 cxt
->display_in_cyl_units
= parent
->display_in_cyl_units
;
116 cxt
->protect_bootbits
= parent
->protect_bootbits
;
119 free(cxt
->dev_model
);
120 cxt
->dev_model
= NULL
;
121 cxt
->dev_model_probed
= 0;
124 cxt
->dev_path
= NULL
;
126 if (parent
->dev_path
) {
127 cxt
->dev_path
= strdup(parent
->dev_path
);
132 INIT_LIST_HEAD(&cxt
->wipes
);
138 * fdisk_new_nested_context:
139 * @parent: parental context
140 * @name: optional label name (e.g. "bsd")
142 * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
143 * The function also probes for the nested label on the device if device is
144 * already assigned to parent.
146 * The new context is initialized according to @parent and both context shares
147 * some settings and file descriptor to the device. The child propagate some
148 * changes (like fdisk_assign_device()) to parent, but it does not work
149 * vice-versa. The behavior is undefined if you assign another device to
152 * Returns: new context for nested partition table.
154 struct fdisk_context
*fdisk_new_nested_context(struct fdisk_context
*parent
,
157 struct fdisk_context
*cxt
;
158 struct fdisk_label
*lb
= NULL
;
162 cxt
= calloc(1, sizeof(*cxt
));
166 DBG(CXT
, ul_debugobj(parent
, "alloc nested [%p] [name=%s]", cxt
, name
));
169 fdisk_ref_context(parent
);
170 cxt
->parent
= parent
;
172 if (init_nested_from_parent(cxt
, 1) != 0) {
174 fdisk_unref_context(cxt
);
179 if (strcasecmp(name
, "bsd") == 0)
180 lb
= cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_bsd_label(cxt
);
181 else if (strcasecmp(name
, "dos") == 0 || strcasecmp(name
, "mbr") == 0)
182 lb
= cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_dos_label(cxt
);
185 if (lb
&& parent
->dev_fd
>= 0) {
186 DBG(CXT
, ul_debugobj(cxt
, "probing for nested %s", lb
->name
));
190 if (lb
->op
->probe(cxt
) == 1)
191 __fdisk_switch_label(cxt
, lb
);
193 DBG(CXT
, ul_debugobj(cxt
, "not found %s label", lb
->name
));
206 * @cxt: context pointer
208 * Increments reference counter.
210 void fdisk_ref_context(struct fdisk_context
*cxt
)
218 * @cxt: context instance
219 * @name: label name (e.g. "gpt")
221 * If no @name specified then returns the current context label.
223 * The label is allocated and maintained within the context #cxt. There is
224 * nothing like reference counting for labels, you cannot deallocate the
227 * Returns: label struct or NULL in case of error.
229 struct fdisk_label
*fdisk_get_label(struct fdisk_context
*cxt
, const char *name
)
237 else if (strcasecmp(name
, "mbr") == 0)
240 for (i
= 0; i
< cxt
->nlabels
; i
++)
242 && strcasecmp(cxt
->labels
[i
]->name
, name
) == 0)
243 return cxt
->labels
[i
];
245 DBG(CXT
, ul_debugobj(cxt
, "failed to found %s label driver", name
));
251 * @cxt: context instance
252 * @lb: returns pointer to the next label
256 * // print all supported labels
257 * struct fdisk_context *cxt = fdisk_new_context();
258 * struct fdisk_label *lb = NULL;
260 * while (fdisk_next_label(cxt, &lb) == 0)
261 * print("label name: %s\n", fdisk_label_get_name(lb));
262 * fdisk_unref_context(cxt);
266 * Returns: <0 in case of error, 0 on success, 1 at the end.
268 int fdisk_next_label(struct fdisk_context
*cxt
, struct fdisk_label
**lb
)
271 struct fdisk_label
*res
= NULL
;
277 res
= cxt
->labels
[0];
279 for (i
= 1; i
< cxt
->nlabels
; i
++) {
280 if (*lb
== cxt
->labels
[i
- 1]) {
281 res
= cxt
->labels
[i
];
295 * Returns: number of supported label types
297 size_t fdisk_get_nlabels(struct fdisk_context
*cxt
)
299 return cxt
? cxt
->nlabels
: 0;
302 int __fdisk_switch_label(struct fdisk_context
*cxt
, struct fdisk_label
*lb
)
307 DBG(CXT
, ul_debugobj(cxt
, "*** attempt to switch to disabled label %s -- ignore!", lb
->name
));
311 DBG(CXT
, ul_debugobj(cxt
, "--> switching context to %s!", lb
->name
));
313 fdisk_apply_label_device_properties(cxt
);
319 * @cxt: fdisk context
321 * Returns: return 1 if there is label on the device.
323 int fdisk_has_label(struct fdisk_context
*cxt
)
325 return cxt
&& cxt
->label
;
329 * fdisk_has_protected_bootbits:
330 * @cxt: fdisk context
332 * Returns: return 1 if boot bits protection enabled.
334 int fdisk_has_protected_bootbits(struct fdisk_context
*cxt
)
336 return cxt
&& cxt
->protect_bootbits
;
340 * fdisk_enable_bootbits_protection:
341 * @cxt: fdisk context
344 * The library zeroizes all the first sector when create a new disk label by
345 * default. This function allows to control this behavior. For now it's
346 * supported for MBR and GPT.
348 * Returns: 0 on success, < 0 on error.
350 int fdisk_enable_bootbits_protection(struct fdisk_context
*cxt
, int enable
)
354 cxt
->protect_bootbits
= enable
? 1 : 0;
358 * fdisk_disable_dialogs
359 * @cxt: fdisk context
362 * The library uses dialog driven partitioning by default.
364 * Returns: 0 on success, < 0 on error.
368 int fdisk_disable_dialogs(struct fdisk_context
*cxt
, int disable
)
373 cxt
->no_disalogs
= disable
;
379 * @cxt: fdisk context
381 * See fdisk_disable_dialogs()
383 * Returns: 1 if dialog driven partitioning enabled (default), or 0.
387 int fdisk_has_dialogs(struct fdisk_context
*cxt
)
389 return cxt
->no_disalogs
== 0;
394 * @cxt: fdisk context
397 * The library removes all PT/filesystem/RAID signatures before it writes
398 * partition table. The probing area where it looks for signatures is from
399 * the begin of the disk. The device is wiped by libblkid.
401 * See also fdisk_wipe_partition().
403 * Returns: 0 on success, < 0 on error.
405 int fdisk_enable_wipe(struct fdisk_context
*cxt
, int enable
)
410 fdisk_set_wipe_area(cxt
, 0, cxt
->total_sectors
, enable
);
416 * @cxt: fdisk context
418 * Returns the current wipe setting. See fdisk_enable_wipe().
420 * Returns: 0 on success, < 0 on error.
422 int fdisk_has_wipe(struct fdisk_context
*cxt
)
427 return fdisk_has_wipe_area(cxt
, 0, cxt
->total_sectors
);
432 * fdisk_get_collision
433 * @cxt: fdisk context
435 * Returns: name of the filesystem or RAID detected on the device or NULL.
437 const char *fdisk_get_collision(struct fdisk_context
*cxt
)
439 return cxt
->collision
;
443 * fdisk_is_ptcollision:
444 * @cxt: fdisk context
446 * The collision detected by libblkid (usually another partition table). Note
447 * that libfdisk does not support all partitions tables, so fdisk_has_label()
448 * may return false, but fdisk_is_ptcollision() may return true.
454 int fdisk_is_ptcollision(struct fdisk_context
*cxt
)
456 return cxt
->pt_collision
;
460 * fdisk_get_npartitions:
463 * The maximal number of the partitions depends on disklabel and does not
464 * have to describe the real limit of PT.
466 * For example the limit for MBR without extend partition is 4, with extended
467 * partition it's unlimited (so the function returns the current number of all
468 * partitions in this case).
470 * And for example for GPT it depends on space allocated on disk for array of
471 * entry records (usually 128).
473 * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
474 * partition may be unused (see fdisk_is_partition_used()).
478 * struct fdisk_partition *pa = NULL;
479 * size_t i, nmax = fdisk_get_npartitions(cxt);
481 * for (i = 0; i < nmax; i++) {
482 * if (!fdisk_is_partition_used(cxt, i))
484 * ... do something ...
489 * Note that the recommended way to list partitions is to use
490 * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each
491 * individual partitions.
493 * Returns: maximal number of partitions for the current label.
495 size_t fdisk_get_npartitions(struct fdisk_context
*cxt
)
497 return cxt
&& cxt
->label
? cxt
->label
->nparts_max
: 0;
501 * fdisk_is_labeltype:
502 * @cxt: fdisk context
503 * @id: FDISK_DISKLABEL_*
505 * See also fdisk_is_label() macro in libfdisk.h.
507 * Returns: return 1 if the current label is @id
509 int fdisk_is_labeltype(struct fdisk_context
*cxt
, enum fdisk_labeltype id
)
513 return cxt
->label
&& (unsigned)fdisk_label_get_type(cxt
->label
) == id
;
518 * @cxt: nested fdisk context
520 * Returns: pointer to parental context, or NULL
522 struct fdisk_context
*fdisk_get_parent(struct fdisk_context
*cxt
)
528 static void reset_context(struct fdisk_context
*cxt
)
532 DBG(CXT
, ul_debugobj(cxt
, "*** resetting context"));
534 /* reset drives' private data */
535 for (i
= 0; i
< cxt
->nlabels
; i
++)
536 fdisk_deinit_label(cxt
->labels
[i
]);
539 /* the first sector may be independent on parent */
540 if (cxt
->parent
->firstsector
!= cxt
->firstsector
)
541 free(cxt
->firstsector
);
543 /* we close device only in primary context */
544 if (cxt
->dev_fd
> -1 && cxt
->private_fd
)
546 free(cxt
->firstsector
);
550 cxt
->dev_path
= NULL
;
552 free(cxt
->dev_model
);
553 cxt
->dev_model
= NULL
;
554 cxt
->dev_model_probed
= 0;
556 free(cxt
->collision
);
557 cxt
->collision
= NULL
;
559 memset(&cxt
->dev_st
, 0, sizeof(cxt
->dev_st
));
563 cxt
->firstsector
= NULL
;
564 cxt
->firstsector_bufsz
= 0;
566 fdisk_zeroize_device_properties(cxt
);
568 fdisk_unref_script(cxt
->script
);
573 fdisk_free_wipe_areas(cxt
);
576 /* fdisk_assign_device() body */
577 static int fdisk_assign_fd(struct fdisk_context
*cxt
, int fd
,
578 const char *fname
, int readonly
, int privfd
)
583 /* redirect request to parent */
585 int rc
, org
= fdisk_is_listonly(cxt
->parent
);
587 /* assign_device() is sensitive to "listonly" mode, so let's
588 * follow the current context setting for the parent to avoid
589 * unwanted extra warnings. */
590 fdisk_enable_listonly(cxt
->parent
, fdisk_is_listonly(cxt
));
592 rc
= fdisk_assign_fd(cxt
->parent
, fd
, fname
, readonly
, privfd
);
593 fdisk_enable_listonly(cxt
->parent
, org
);
596 rc
= init_nested_from_parent(cxt
, 0);
598 fdisk_probe_labels(cxt
);
604 if (fstat(fd
, &cxt
->dev_st
) != 0)
607 cxt
->readonly
= readonly
;
609 cxt
->private_fd
= privfd
;
610 cxt
->dev_path
= fname
? strdup(fname
) : NULL
;
614 fdisk_discover_topology(cxt
);
615 fdisk_discover_geometry(cxt
);
617 fdisk_apply_user_device_properties(cxt
);
619 if (fdisk_read_firstsector(cxt
) < 0)
622 fdisk_probe_labels(cxt
);
623 fdisk_apply_label_device_properties(cxt
);
625 /* warn about obsolete stuff on the device if we aren't in
626 * list-only mode and there is not PT yet */
627 if (!fdisk_is_listonly(cxt
) && !fdisk_has_label(cxt
)
628 && fdisk_check_collisions(cxt
) < 0)
631 DBG(CXT
, ul_debugobj(cxt
, "initialized for %s [%s]",
632 fname
, readonly
? "READ-ONLY" : "READ-WRITE"));
637 DBG(CXT
, ul_debugobj(cxt
, "failed to assign device [rc=%d]", rc
));
643 * fdisk_assign_device:
645 * @fname: path to the device to be handled
646 * @readonly: how to open the device
648 * Open the device, discovery topology, geometry, detect disklabel, check for
649 * collisions and switch the current label driver to reflect the probing
652 * If in standard mode (!= non-listonly mode) than also detects for collisions.
653 * The result is accessible by fdisk_get_collision() and
654 * fdisk_is_ptcollision(). The collision (e.g. old obsolete PT) may be removed
655 * by fdisk_enable_wipe(). Note that new PT and old PT may be on different
658 * Note that this function resets all generic setting in context.
660 * If the @cxt is nested context (necessary for example to edit BSD or PMBR)
661 * then the device is assigned to the parental context and necessary properties
662 * are copied to the @cxt. The change is propagated in child->parent direction
663 * only. It's impossible to use a different device for primary and nested
666 * Returns: 0 on success, < 0 on error.
668 int fdisk_assign_device(struct fdisk_context
*cxt
,
669 const char *fname
, int readonly
)
673 DBG(CXT
, ul_debugobj(cxt
, "assigning device %s", fname
));
676 fd
= open(fname
, (readonly
? O_RDONLY
: O_RDWR
) | O_CLOEXEC
);
679 DBG(CXT
, ul_debugobj(cxt
, "failed to assign device [rc=%d]", rc
));
683 rc
= fdisk_assign_fd(cxt
, fd
, fname
, readonly
, 1);
690 * fdisk_assign_device_by_fd:
692 * @fd: device file descriptor
693 * @fname: path to the device (used for dialogs, debugging, partition names, ...)
694 * @readonly: how to use the device
696 * Like fdisk_assign_device(), but caller is responsible to open and close the
697 * device. The library only fsync() the device on fdisk_deassign_device().
699 * The device has to be open O_RDWR on @readonly=0.
701 * Returns: 0 on success, < 0 on error.
703 int fdisk_assign_device_by_fd(struct fdisk_context
*cxt
, int fd
,
704 const char *fname
, int readonly
)
706 return fdisk_assign_fd(cxt
, fd
, fname
, readonly
, 0);
710 * fdisk_deassign_device:
712 * @nosync: disable fsync()
714 * Close device and call fsync(). If the @cxt is nested context than the
715 * request is redirected to the parent.
717 * Returns: 0 on success, < 0 on error.
719 int fdisk_deassign_device(struct fdisk_context
*cxt
, int nosync
)
722 assert(cxt
->dev_fd
>= 0);
725 int rc
= fdisk_deassign_device(cxt
->parent
, nosync
);
728 rc
= init_nested_from_parent(cxt
, 0);
732 DBG(CXT
, ul_debugobj(cxt
, "de-assigning device %s", cxt
->dev_path
));
734 if (cxt
->readonly
&& cxt
->private_fd
)
737 if (fsync(cxt
->dev_fd
)) {
738 fdisk_warn(cxt
, _("%s: fsync device failed"),
742 if (cxt
->private_fd
&& close(cxt
->dev_fd
)) {
743 fdisk_warn(cxt
, _("%s: close device failed"),
748 fdisk_info(cxt
, _("Syncing disks."));
754 cxt
->dev_path
= NULL
;
761 * fdisk_reassign_device:
764 * This function is "hard reset" of the context and it does not write anything
765 * to the device. All in-memory changes associated with the context will be
766 * lost. It's recommended to use this function after some fatal problem when the
767 * context (and label specific driver) is in an undefined state.
769 * Returns: 0 on success, < 0 on error.
771 int fdisk_reassign_device(struct fdisk_context
*cxt
)
774 int rdonly
, rc
, fd
, privfd
;
777 assert(cxt
->dev_fd
>= 0);
779 DBG(CXT
, ul_debugobj(cxt
, "re-assigning device %s", cxt
->dev_path
));
781 devname
= strdup(cxt
->dev_path
);
785 rdonly
= cxt
->readonly
;
787 privfd
= cxt
->private_fd
;
789 fdisk_deassign_device(cxt
, 1);
792 /* reopen and assign */
793 rc
= fdisk_assign_device(cxt
, devname
, rdonly
);
796 rc
= fdisk_assign_fd(cxt
, fd
, devname
, rdonly
, privfd
);
803 * fdisk_reread_partition_table:
806 * Force *kernel* to re-read partition table on block devices.
808 * Returns: 0 on success, < 0 in case of error.
810 int fdisk_reread_partition_table(struct fdisk_context
*cxt
)
815 assert(cxt
->dev_fd
>= 0);
817 if (!S_ISBLK(cxt
->dev_st
.st_mode
))
820 DBG(CXT
, ul_debugobj(cxt
, "calling re-read ioctl"));
823 fdisk_info(cxt
, _("Calling ioctl() to re-read partition table."));
824 i
= ioctl(cxt
->dev_fd
, BLKRRPART
);
832 fdisk_warn(cxt
, _("Re-reading the partition table failed."));
834 "The kernel still uses the old table. The "
835 "new table will be used at the next reboot "
836 "or after you run partprobe(8) or kpartx(8)."));
844 static inline int add_to_partitions_array(
845 struct fdisk_partition
***ary
,
846 struct fdisk_partition
*pa
,
847 size_t *n
, size_t nmax
)
850 *ary
= calloc(nmax
, sizeof(struct fdisk_partition
*));
861 * fdisk_reread_changes:
863 * @org: original layout (on disk)
865 * Like fdisk_reread_partition_table() but don't forces kernel re-read all
866 * partition table. The BLKPG_* ioctls are used for individual partitions. The
867 * advantage is that unmodified partitions maybe mounted.
869 * The function behavies like fdisk_reread_partition_table() on systems where
870 * are no available BLKPG_* ioctls.
872 * Returns: <0 on error, or 0.
875 int fdisk_reread_changes(struct fdisk_context
*cxt
, struct fdisk_table
*org
)
877 struct fdisk_table
*tb
= NULL
;
878 struct fdisk_iter itr
;
879 struct fdisk_partition
*pa
;
880 struct fdisk_partition
**rem
= NULL
, **add
= NULL
, **upd
= NULL
;
881 int change
, rc
= 0, err
= 0;
882 size_t nparts
, i
, nadds
= 0, nupds
= 0, nrems
= 0;
884 DBG(CXT
, ul_debugobj(cxt
, "rereading changes"));
886 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
888 /* the current layout */
889 fdisk_get_partitions(cxt
, &tb
);
890 /* maximal number of partitions */
891 nparts
= max(fdisk_table_get_nents(tb
), fdisk_table_get_nents(org
));
893 while (fdisk_diff_tables(org
, tb
, &itr
, &pa
, &change
) == 0) {
894 if (change
== FDISK_DIFF_UNCHANGED
)
897 case FDISK_DIFF_REMOVED
:
898 rc
= add_to_partitions_array(&rem
, pa
, &nrems
, nparts
);
900 case FDISK_DIFF_ADDED
:
901 rc
= add_to_partitions_array(&add
, pa
, &nadds
, nparts
);
903 case FDISK_DIFF_RESIZED
:
904 rc
= add_to_partitions_array(&upd
, pa
, &nupds
, nparts
);
906 case FDISK_DIFF_MOVED
:
907 rc
= add_to_partitions_array(&rem
, pa
, &nrems
, nparts
);
909 rc
= add_to_partitions_array(&add
, pa
, &nadds
, nparts
);
916 for (i
= 0; i
< nrems
; i
++) {
918 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_DEL_PARTITION", pa
->partno
));
919 if (partx_del_partition(cxt
->dev_fd
, pa
->partno
+ 1) != 0) {
920 fdisk_warn(cxt
, _("Failed to remove partition %zu from system"), pa
->partno
+ 1);
924 for (i
= 0; i
< nupds
; i
++) {
926 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_RESIZE_PARTITION", pa
->partno
));
927 if (partx_resize_partition(cxt
->dev_fd
, pa
->partno
+ 1, pa
->start
, pa
->size
) != 0) {
928 fdisk_warn(cxt
, _("Failed to update system information about partition %zu"), pa
->partno
+ 1);
932 for (i
= 0; i
< nadds
; i
++) {
934 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_ADD_PARTITION", pa
->partno
));
935 if (partx_add_partition(cxt
->dev_fd
, pa
->partno
+ 1, pa
->start
, pa
->size
) != 0) {
936 fdisk_warn(cxt
, _("Failed to add partition %zu to system"), pa
->partno
+ 1);
942 "The kernel still uses the old partitions. The new "
943 "table will be used at the next reboot. "));
948 fdisk_unref_table(tb
);
952 int fdisk_reread_changes(struct fdisk_context
*cxt
,
953 struct fdisk_table
*org
__attribute__((__unused__
))) {
954 return fdisk_reread_partition_table(cxt
);
959 * fdisk_device_is_used:
962 * On systems where is no BLKRRPART ioctl the function returns zero and
963 * sets errno to ENOSYS.
965 * Returns: 1 if the device assigned to the context is used by system, or 0.
967 int fdisk_device_is_used(struct fdisk_context
*cxt
)
972 assert(cxt
->dev_fd
>= 0);
977 /* it seems kernel always return EINVAL for BLKRRPART on loopdevices */
978 if (S_ISBLK(cxt
->dev_st
.st_mode
)
979 && major(cxt
->dev_st
.st_rdev
) != LOOPDEV_MAJOR
) {
980 DBG(CXT
, ul_debugobj(cxt
, "calling re-read ioctl"));
981 rc
= ioctl(cxt
->dev_fd
, BLKRRPART
) != 0;
986 DBG(CXT
, ul_debugobj(cxt
, "device used: %s [errno=%d]", rc
? "TRUE" : "FALSE", errno
));
994 * Returns: 1 if device open readonly
996 int fdisk_is_readonly(struct fdisk_context
*cxt
)
999 return cxt
->readonly
;
1008 * Returns: 1 if open file descriptor is regular file rather than a block device.
1010 int fdisk_is_regfile(struct fdisk_context
*cxt
)
1013 return S_ISREG(cxt
->dev_st
.st_mode
);
1017 * fdisk_unref_context:
1018 * @cxt: fdisk context
1020 * Deallocates context struct.
1022 void fdisk_unref_context(struct fdisk_context
*cxt
)
1030 if (cxt
->refcount
<= 0) {
1031 DBG(CXT
, ul_debugobj(cxt
, "freeing context %p for %s", cxt
, cxt
->dev_path
));
1033 reset_context(cxt
); /* this is sensitive to parent<->child relationship! */
1035 /* deallocate label's private stuff */
1036 for (i
= 0; i
< cxt
->nlabels
; i
++) {
1037 if (!cxt
->labels
[i
])
1039 if (cxt
->labels
[i
]->op
->free
)
1040 cxt
->labels
[i
]->op
->free(cxt
->labels
[i
]);
1042 free(cxt
->labels
[i
]);
1045 fdisk_unref_context(cxt
->parent
);
1054 * fdisk_enable_details:
1056 * @enable: true/false
1058 * Enables or disables "details" display mode. This function has effect to
1059 * fdisk_partition_to_string() function.
1061 * Returns: 0 on success, < 0 on error.
1063 int fdisk_enable_details(struct fdisk_context
*cxt
, int enable
)
1066 cxt
->display_details
= enable
? 1 : 0;
1074 * Returns: 1 if details are enabled
1076 int fdisk_is_details(struct fdisk_context
*cxt
)
1079 return cxt
->display_details
== 1;
1083 * fdisk_enable_listonly:
1085 * @enable: true/false
1087 * Just list partition only, don't care about another details, mistakes, ...
1089 * Returns: 0 on success, < 0 on error.
1091 int fdisk_enable_listonly(struct fdisk_context
*cxt
, int enable
)
1094 cxt
->listonly
= enable
? 1 : 0;
1099 * fdisk_is_listonly:
1102 * Returns: 1 if list-only mode enabled
1104 int fdisk_is_listonly(struct fdisk_context
*cxt
)
1107 return cxt
->listonly
== 1;
1114 * @str: "cylinder" or "sector".
1116 * This is pure shit, unfortunately for example Sun addresses begin of the
1117 * partition by cylinders...
1119 * Returns: 0 on success, <0 on error.
1121 int fdisk_set_unit(struct fdisk_context
*cxt
, const char *str
)
1125 cxt
->display_in_cyl_units
= 0;
1130 if (strcmp(str
, "cylinder") == 0 || strcmp(str
, "cylinders") == 0)
1131 cxt
->display_in_cyl_units
= 1;
1133 else if (strcmp(str
, "sector") == 0 || strcmp(str
, "sectors") == 0)
1134 cxt
->display_in_cyl_units
= 0;
1136 DBG(CXT
, ul_debugobj(cxt
, "display unit: %s", fdisk_get_unit(cxt
, 0)));
1143 * @n: FDISK_PLURAL or FDISK_SINGULAR
1145 * Returns: unit name.
1147 const char *fdisk_get_unit(struct fdisk_context
*cxt
, int n
)
1151 if (fdisk_use_cylinders(cxt
))
1152 return P_("cylinder", "cylinders", n
);
1153 return P_("sector", "sectors", n
);
1157 * fdisk_use_cylinders:
1160 * Returns: 1 if user wants to display in cylinders.
1162 int fdisk_use_cylinders(struct fdisk_context
*cxt
)
1165 return cxt
->display_in_cyl_units
== 1;
1169 * fdisk_get_units_per_sector:
1172 * This is necessary only for brain dead situations when we use "cylinders";
1174 * Returns: number of "units" per sector, default is 1 if display unit is sector.
1176 unsigned int fdisk_get_units_per_sector(struct fdisk_context
*cxt
)
1180 if (fdisk_use_cylinders(cxt
)) {
1181 assert(cxt
->geom
.heads
);
1182 return cxt
->geom
.heads
* cxt
->geom
.sectors
;
1188 * fdisk_get_optimal_iosize:
1191 * The optimal I/O is optional and does not have to be provided by device,
1192 * anyway libfdisk never returns zero. If the optimal I/O size is not provided
1193 * then libfdisk returns minimal I/O size or sector size.
1195 * Returns: optimal I/O size in bytes.
1197 unsigned long fdisk_get_optimal_iosize(struct fdisk_context
*cxt
)
1200 return cxt
->optimal_io_size
? cxt
->optimal_io_size
: cxt
->io_size
;
1204 * fdisk_get_minimal_iosize:
1207 * Returns: minimal I/O size in bytes
1209 unsigned long fdisk_get_minimal_iosize(struct fdisk_context
*cxt
)
1212 return cxt
->min_io_size
;
1216 * fdisk_get_physector_size:
1219 * Returns: physical sector size in bytes
1221 unsigned long fdisk_get_physector_size(struct fdisk_context
*cxt
)
1224 return cxt
->phy_sector_size
;
1228 * fdisk_get_sector_size:
1231 * Returns: logical sector size in bytes
1233 unsigned long fdisk_get_sector_size(struct fdisk_context
*cxt
)
1236 return cxt
->sector_size
;
1240 * fdisk_get_alignment_offset
1243 * The alignment offset is offset between logical and physical sectors. For
1244 * backward compatibility the first logical sector on 4K disks does no have to
1245 * start on the same place like physical sectors.
1247 * Returns: alignment offset in bytes
1249 unsigned long fdisk_get_alignment_offset(struct fdisk_context
*cxt
)
1252 return cxt
->alignment_offset
;
1256 * fdisk_get_grain_size:
1259 * Returns: grain in bytes used to align partitions (usually 1MiB)
1261 unsigned long fdisk_get_grain_size(struct fdisk_context
*cxt
)
1268 * fdisk_get_first_lba:
1271 * Returns: first possible LBA on disk for data partitions.
1273 fdisk_sector_t
fdisk_get_first_lba(struct fdisk_context
*cxt
)
1276 return cxt
->first_lba
;
1280 * fdisk_set_first_lba:
1281 * @cxt: fdisk context
1282 * @lba: first possible logical sector for data
1284 * It's strongly recommended to use the default library setting. The first LBA
1285 * is always reset by fdisk_assign_device(), fdisk_override_geometry()
1286 * and fdisk_reset_alignment(). This is very low level function and library
1287 * does not check if your setting makes any sense.
1289 * This function is necessary only when you want to work with very unusual
1290 * partition tables like GPT protective MBR or hybrid partition tables on
1291 * bootable media where the first partition may start on very crazy offsets.
1293 * Note that this function changes only runtime information. It does not update
1294 * any range in on-disk partition table. For example GPT Header contains First
1295 * and Last usable LBA fields. These fields are not updated by this function.
1298 * Returns: 0 on success, <0 on error.
1300 fdisk_sector_t
fdisk_set_first_lba(struct fdisk_context
*cxt
, fdisk_sector_t lba
)
1303 DBG(CXT
, ul_debugobj(cxt
, "setting first LBA from %ju to %ju",
1304 (uintmax_t) cxt
->first_lba
, (uintmax_t) lba
));
1305 cxt
->first_lba
= lba
;
1310 * fdisk_get_last_lba:
1311 * @cxt: fdisk context
1313 * Note that the device has to be already assigned.
1315 * Returns: last possible LBA on device
1317 fdisk_sector_t
fdisk_get_last_lba(struct fdisk_context
*cxt
)
1319 return cxt
->last_lba
;
1323 * fdisk_set_last_lba:
1324 * @cxt: fdisk context
1325 * @lba: last possible logical sector
1327 * It's strongly recommended to use the default library setting. The last LBA
1328 * is always reset by fdisk_assign_device(), fdisk_override_geometry() and
1329 * fdisk_reset_alignment().
1331 * The default is number of sectors on the device, but maybe modified by the
1332 * current disklabel driver (for example GPT uses the end of disk for backup
1333 * header, so last_lba is smaller than total number of sectors).
1335 * Returns: 0 on success, <0 on error.
1337 fdisk_sector_t
fdisk_set_last_lba(struct fdisk_context
*cxt
, fdisk_sector_t lba
)
1341 if (lba
> cxt
->total_sectors
- 1 || lba
< 1)
1343 cxt
->last_lba
= lba
;
1348 * fdisk_set_size_unit:
1349 * @cxt: fdisk context
1350 * @unit: FDISK_SIZEUNIT_*
1352 * Sets unit for SIZE output field (see fdisk_partition_to_string()).
1354 * Returns: 0 on success, <0 on error.
1356 int fdisk_set_size_unit(struct fdisk_context
*cxt
, int unit
)
1359 cxt
->sizeunit
= unit
;
1364 * fdisk_get_size_unit:
1365 * @cxt: fdisk context
1367 * Gets unit for SIZE output field (see fdisk_partition_to_string()).
1371 int fdisk_get_size_unit(struct fdisk_context
*cxt
)
1374 return cxt
->sizeunit
;
1378 * fdisk_get_nsectors:
1381 * Returns: size of the device in logical sectors.
1383 fdisk_sector_t
fdisk_get_nsectors(struct fdisk_context
*cxt
)
1386 return cxt
->total_sectors
;
1390 * fdisk_get_devname:
1393 * Returns: device name.
1395 const char *fdisk_get_devname(struct fdisk_context
*cxt
)
1398 return cxt
->dev_path
;
1405 * Returns: device number or zero for non-block devices
1409 dev_t
fdisk_get_devno(struct fdisk_context
*cxt
)
1412 return S_ISBLK(cxt
->dev_st
.st_mode
) ? cxt
->dev_st
.st_rdev
: 0;
1416 * fdisk_get_devmodel:
1419 * Returns: device model string or NULL.
1424 const char *fdisk_get_devmodel(struct fdisk_context
*cxt
)
1428 if (cxt
->dev_model_probed
)
1429 return cxt
->dev_model
;
1431 if (fdisk_get_devno(cxt
)) {
1432 struct path_cxt
*pc
= ul_new_sysfs_path(fdisk_get_devno(cxt
), NULL
, NULL
);
1435 ul_path_read_string(pc
, &cxt
->dev_model
, "device/model");
1439 cxt
->dev_model_probed
= 1;
1440 return cxt
->dev_model
;
1443 const char *fdisk_get_devmodel(struct fdisk_context
*cxt
__attribute__((__unused__
)))
1453 * Returns: device file descriptor.
1455 int fdisk_get_devfd(struct fdisk_context
*cxt
)
1462 * fdisk_get_geom_heads:
1465 * Returns: number of geometry heads.
1467 unsigned int fdisk_get_geom_heads(struct fdisk_context
*cxt
)
1470 return cxt
->geom
.heads
;
1473 * fdisk_get_geom_sectors:
1476 * Returns: number of geometry sectors.
1478 fdisk_sector_t
fdisk_get_geom_sectors(struct fdisk_context
*cxt
)
1481 return cxt
->geom
.sectors
;
1486 * fdisk_get_geom_cylinders:
1489 * Returns: number of geometry cylinders
1491 fdisk_sector_t
fdisk_get_geom_cylinders(struct fdisk_context
*cxt
)
1494 return cxt
->geom
.cylinders
;
1497 int fdisk_missing_geometry(struct fdisk_context
*cxt
)
1501 if (!cxt
|| !cxt
->label
)
1504 rc
= (fdisk_label_require_geometry(cxt
->label
) &&
1505 (!cxt
->geom
.heads
|| !cxt
->geom
.sectors
1506 || !cxt
->geom
.cylinders
));
1508 if (rc
&& !fdisk_is_listonly(cxt
))
1509 fdisk_warnx(cxt
, _("Incomplete geometry setting."));