]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/context.c
3b2a4d25fa02311b0d77cbb9b69bd6f4c6897892
18 * @short_description: stores info about device, labels etc.
20 * The library distinguish between three types of partitioning objects.
23 * - disk label specific
24 * - probed and read by disklabel drivers when assign device to the context
25 * or when switch to another disk label type
26 * - only fdisk_write_disklabel() modify on-disk data
28 * in-memory label data
29 * - generic data and disklabel specific data stored in struct fdisk_label
30 * - all partitioning operations are based on in-memory data only
32 * struct fdisk_partition
33 * - provides abstraction to present partitions to users
34 * - fdisk_partition is possible to gather to fdisk_table container
35 * - used as unified template for new partitions
36 * - used (with fdisk_table) in fdisk scripts
37 * - the struct fdisk_partition is always completely independent object and
38 * any change to the object has no effect to in-memory (or on-disk) label data
40 * Don't forget to inform kernel about changes by fdisk_reread_partition_table()
41 * or more smart fdisk_reread_changes().
47 * Returns: newly allocated libfdisk handler
49 struct fdisk_context
*fdisk_new_context(void)
51 struct fdisk_context
*cxt
;
53 cxt
= calloc(1, sizeof(*cxt
));
57 DBG(CXT
, ul_debugobj(cxt
, "alloc"));
61 INIT_LIST_HEAD(&cxt
->wipes
);
64 * Allocate label specific structs.
66 * This is necessary (for example) to store label specific
69 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_gpt_label(cxt
);
70 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_dos_label(cxt
);
71 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_bsd_label(cxt
);
72 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_sgi_label(cxt
);
73 cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_sun_label(cxt
);
75 bindtextdomain(LIBFDISK_TEXTDOMAIN
, LOCALEDIR
);
80 static int init_nested_from_parent(struct fdisk_context
*cxt
, int isnew
)
82 struct fdisk_context
*parent
;
89 INIT_LIST_HEAD(&cxt
->wipes
);
91 cxt
->alignment_offset
= parent
->alignment_offset
;
92 cxt
->ask_cb
= parent
->ask_cb
;
93 cxt
->ask_data
= parent
->ask_data
;
94 cxt
->dev_fd
= parent
->dev_fd
;
95 cxt
->first_lba
= parent
->first_lba
;
96 cxt
->firstsector_bufsz
= parent
->firstsector_bufsz
;
97 cxt
->firstsector
= parent
->firstsector
;
98 cxt
->geom
= parent
->geom
;
99 cxt
->grain
= parent
->grain
;
100 cxt
->io_size
= parent
->io_size
;
101 cxt
->last_lba
= parent
->last_lba
;
102 cxt
->min_io_size
= parent
->min_io_size
;
103 cxt
->optimal_io_size
= parent
->optimal_io_size
;
104 cxt
->phy_sector_size
= parent
->phy_sector_size
;
105 cxt
->readonly
= parent
->readonly
;
106 cxt
->script
= parent
->script
;
107 fdisk_ref_script(cxt
->script
);
108 cxt
->sector_size
= parent
->sector_size
;
109 cxt
->total_sectors
= parent
->total_sectors
;
110 cxt
->user_geom
= parent
->user_geom
;
111 cxt
->user_log_sector
= parent
->user_log_sector
;
112 cxt
->user_pyh_sector
= parent
->user_pyh_sector
;
114 /* parent <--> nested independent setting, initialize for new nested
117 cxt
->listonly
= parent
->listonly
;
118 cxt
->display_details
= parent
->display_details
;
119 cxt
->display_in_cyl_units
= parent
->display_in_cyl_units
;
120 cxt
->protect_bootbits
= parent
->protect_bootbits
;
123 free(cxt
->dev_model
);
124 cxt
->dev_model
= NULL
;
125 cxt
->dev_model_probed
= 0;
127 return strdup_between_structs(cxt
, parent
, dev_path
);
131 * fdisk_new_nested_context:
132 * @parent: parental context
133 * @name: optional label name (e.g. "bsd")
135 * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
136 * The function also probes for the nested label on the device if device is
137 * already assigned to parent.
139 * The new context is initialized according to @parent and both context shares
140 * some settings and file descriptor to the device. The child propagate some
141 * changes (like fdisk_assign_device()) to parent, but it does not work
142 * vice-versa. The behavior is undefined if you assign another device to
145 * Returns: new context for nested partition table.
147 struct fdisk_context
*fdisk_new_nested_context(struct fdisk_context
*parent
,
150 struct fdisk_context
*cxt
;
151 struct fdisk_label
*lb
= NULL
;
155 cxt
= calloc(1, sizeof(*cxt
));
159 DBG(CXT
, ul_debugobj(parent
, "alloc nested [%p] [name=%s]", cxt
, name
));
162 fdisk_ref_context(parent
);
163 cxt
->parent
= parent
;
165 if (init_nested_from_parent(cxt
, 1) != 0) {
167 fdisk_unref_context(cxt
);
172 if (c_strcasecmp(name
, "bsd") == 0)
173 lb
= cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_bsd_label(cxt
);
174 else if (c_strcasecmp(name
, "dos") == 0 || c_strcasecmp(name
, "mbr") == 0)
175 lb
= cxt
->labels
[ cxt
->nlabels
++ ] = fdisk_new_dos_label(cxt
);
178 if (lb
&& parent
->dev_fd
>= 0) {
179 DBG(CXT
, ul_debugobj(cxt
, "probing for nested %s", lb
->name
));
183 if (lb
->op
->probe(cxt
) == 1)
184 __fdisk_switch_label(cxt
, lb
);
186 DBG(CXT
, ul_debugobj(cxt
, "not found %s label", lb
->name
));
199 * @cxt: context pointer
201 * Increments reference counter.
203 void fdisk_ref_context(struct fdisk_context
*cxt
)
211 * @cxt: context instance
212 * @name: label name (e.g. "gpt")
214 * If no @name specified then returns the current context label.
216 * The label is allocated and maintained within the context #cxt. There is
217 * nothing like reference counting for labels, you cannot deallocate the
220 * Returns: label struct or NULL in case of error.
222 struct fdisk_label
*fdisk_get_label(struct fdisk_context
*cxt
, const char *name
)
231 if (c_strcasecmp(name
, "mbr") == 0)
234 for (i
= 0; i
< cxt
->nlabels
; i
++)
236 && c_strcasecmp(cxt
->labels
[i
]->name
, name
) == 0)
237 return cxt
->labels
[i
];
239 DBG(CXT
, ul_debugobj(cxt
, "failed to found %s label driver", name
));
245 * @cxt: context instance
246 * @lb: returns pointer to the next label
250 * // print all supported labels
251 * struct fdisk_context *cxt = fdisk_new_context();
252 * struct fdisk_label *lb = NULL;
254 * while (fdisk_next_label(cxt, &lb) == 0)
255 * print("label name: %s\n", fdisk_label_get_name(lb));
256 * fdisk_unref_context(cxt);
260 * Returns: <0 in case of error, 0 on success, 1 at the end.
262 int fdisk_next_label(struct fdisk_context
*cxt
, struct fdisk_label
**lb
)
265 struct fdisk_label
*res
= NULL
;
271 res
= cxt
->labels
[0];
273 for (i
= 1; i
< cxt
->nlabels
; i
++) {
274 if (*lb
== cxt
->labels
[i
- 1]) {
275 res
= cxt
->labels
[i
];
289 * Returns: number of supported label types
291 size_t fdisk_get_nlabels(struct fdisk_context
*cxt
)
293 return cxt
? cxt
->nlabels
: 0;
296 int __fdisk_switch_label(struct fdisk_context
*cxt
, struct fdisk_label
*lb
)
301 DBG(CXT
, ul_debugobj(cxt
, "*** attempt to switch to disabled label %s -- ignore!", lb
->name
));
305 DBG(CXT
, ul_debugobj(cxt
, "--> switching context to %s!", lb
->name
));
307 return fdisk_apply_label_device_properties(cxt
);
312 * @cxt: fdisk context
314 * Returns: return 1 if there is label on the device.
316 int fdisk_has_label(struct fdisk_context
*cxt
)
318 return cxt
&& cxt
->label
;
322 * fdisk_has_protected_bootbits:
323 * @cxt: fdisk context
325 * Returns: return 1 if boot bits protection enabled.
327 int fdisk_has_protected_bootbits(struct fdisk_context
*cxt
)
329 return cxt
&& cxt
->protect_bootbits
;
333 * fdisk_enable_bootbits_protection:
334 * @cxt: fdisk context
337 * The library zeroizes all the first sector when create a new disk label by
338 * default. This function can be used to control this behavior. For now it's
339 * supported for MBR and GPT.
341 * Returns: 0 on success, < 0 on error.
343 int fdisk_enable_bootbits_protection(struct fdisk_context
*cxt
, int enable
)
347 cxt
->protect_bootbits
= enable
? 1 : 0;
351 * fdisk_disable_dialogs
352 * @cxt: fdisk context
355 * The library uses dialog driven partitioning by default.
357 * Returns: 0 on success, < 0 on error.
361 int fdisk_disable_dialogs(struct fdisk_context
*cxt
, int disable
)
366 cxt
->no_disalogs
= disable
;
372 * @cxt: fdisk context
374 * See fdisk_disable_dialogs()
376 * Returns: 1 if dialog driven partitioning enabled (default), or 0.
380 int fdisk_has_dialogs(struct fdisk_context
*cxt
)
382 return cxt
->no_disalogs
== 0;
387 * @cxt: fdisk context
390 * The library removes all PT/filesystem/RAID signatures before it writes
391 * partition table. The probing area where it looks for signatures is from
392 * the begin of the disk. The device is wiped by libblkid.
394 * See also fdisk_wipe_partition().
396 * Returns: 0 on success, < 0 on error.
398 int fdisk_enable_wipe(struct fdisk_context
*cxt
, int enable
)
403 fdisk_set_wipe_area(cxt
, 0, cxt
->total_sectors
, enable
);
409 * @cxt: fdisk context
411 * Returns the current wipe setting. See fdisk_enable_wipe().
413 * Returns: 0 on success, < 0 on error.
415 int fdisk_has_wipe(struct fdisk_context
*cxt
)
420 return fdisk_has_wipe_area(cxt
, 0, cxt
->total_sectors
);
425 * fdisk_get_collision
426 * @cxt: fdisk context
428 * Returns: name of the filesystem or RAID detected on the device or NULL.
430 const char *fdisk_get_collision(struct fdisk_context
*cxt
)
432 return cxt
->collision
;
436 * fdisk_is_ptcollision:
437 * @cxt: fdisk context
439 * The collision detected by libblkid (usually another partition table). Note
440 * that libfdisk does not support all partitions tables, so fdisk_has_label()
441 * may return false, but fdisk_is_ptcollision() may return true.
447 int fdisk_is_ptcollision(struct fdisk_context
*cxt
)
449 return cxt
->pt_collision
;
453 * fdisk_get_npartitions:
456 * The maximal number of the partitions depends on disklabel and does not
457 * have to describe the real limit of PT.
459 * For example the limit for MBR without extend partition is 4, with extended
460 * partition it's unlimited (so the function returns the current number of all
461 * partitions in this case).
463 * And for example for GPT it depends on space allocated on disk for array of
464 * entry records (usually 128).
466 * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
467 * partition may be unused (see fdisk_is_partition_used()).
471 * struct fdisk_partition *pa = NULL;
472 * size_t i, nmax = fdisk_get_npartitions(cxt);
474 * for (i = 0; i < nmax; i++) {
475 * if (!fdisk_is_partition_used(cxt, i))
477 * ... do something ...
482 * Note that the recommended way to list partitions is to use
483 * fdisk_get_partitions() and struct fdisk_table then ask disk driver for each
484 * individual partitions.
486 * Returns: maximal number of partitions for the current label.
488 size_t fdisk_get_npartitions(struct fdisk_context
*cxt
)
490 return cxt
&& cxt
->label
? cxt
->label
->nparts_max
: 0;
494 * fdisk_is_labeltype:
495 * @cxt: fdisk context
496 * @id: FDISK_DISKLABEL_*
498 * See also fdisk_is_label() macro in libfdisk.h.
500 * Returns: return 1 if the current label is @id
502 int fdisk_is_labeltype(struct fdisk_context
*cxt
, enum fdisk_labeltype id
)
506 return cxt
->label
&& (unsigned)fdisk_label_get_type(cxt
->label
) == id
;
511 * @cxt: nested fdisk context
513 * Returns: pointer to parental context, or NULL
515 struct fdisk_context
*fdisk_get_parent(struct fdisk_context
*cxt
)
521 static void reset_context(struct fdisk_context
*cxt
)
525 DBG(CXT
, ul_debugobj(cxt
, "*** resetting context"));
527 /* reset drives' private data */
528 for (i
= 0; i
< cxt
->nlabels
; i
++)
529 fdisk_deinit_label(cxt
->labels
[i
]);
532 /* the first sector may be independent on parent */
533 if (cxt
->parent
->firstsector
!= cxt
->firstsector
) {
534 DBG(CXT
, ul_debugobj(cxt
, " firstsector independent on parent (freeing)"));
535 free(cxt
->firstsector
);
538 /* we close device only in primary context */
539 if (cxt
->dev_fd
> -1 && cxt
->is_priv
)
541 DBG(CXT
, ul_debugobj(cxt
, " freeing firstsector"));
542 free(cxt
->firstsector
);
546 cxt
->dev_path
= NULL
;
548 free(cxt
->dev_model
);
549 cxt
->dev_model
= NULL
;
550 cxt
->dev_model_probed
= 0;
552 free(cxt
->collision
);
553 cxt
->collision
= NULL
;
555 memset(&cxt
->dev_st
, 0, sizeof(cxt
->dev_st
));
560 cxt
->firstsector
= NULL
;
561 cxt
->firstsector_bufsz
= 0;
563 fdisk_zeroize_device_properties(cxt
);
565 fdisk_unref_script(cxt
->script
);
570 fdisk_free_wipe_areas(cxt
);
573 /* fdisk_assign_device() body */
574 static int fdisk_assign_fd(struct fdisk_context
*cxt
, int fd
,
575 const char *fname
, int readonly
,
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
, priv
, excl
);
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
? 1 : 0;
609 cxt
->is_priv
= priv
? 1 : 0;
610 cxt
->is_excl
= excl
? 1 : 0;
612 cxt
->dev_path
= fname
? strdup(fname
) : NULL
;
616 fdisk_discover_topology(cxt
);
617 fdisk_discover_geometry(cxt
);
619 fdisk_apply_user_device_properties(cxt
);
621 if (fdisk_read_firstsector(cxt
) < 0)
624 /* warn about obsolete stuff on the device if we aren't in list-only */
625 if (!fdisk_is_listonly(cxt
) && fdisk_check_collisions(cxt
) < 0)
628 fdisk_probe_labels(cxt
);
629 fdisk_apply_label_device_properties(cxt
);
631 /* Don't report collision if there is already a valid partition table.
632 * The bootbits are wiped when we create a *new* partition table only. */
633 if (fdisk_is_ptcollision(cxt
) && fdisk_has_label(cxt
)) {
634 DBG(CXT
, ul_debugobj(cxt
, "ignore old %s", cxt
->collision
));
635 cxt
->pt_collision
= 0;
636 free(cxt
->collision
);
637 cxt
->collision
= NULL
;
640 DBG(CXT
, ul_debugobj(cxt
, "initialized for %s [%s %s %s]",
642 cxt
->readonly
? "READ-ONLY" : "READ-WRITE",
643 cxt
->is_excl
? "EXCL" : "",
644 cxt
->is_priv
? "PRIV" : ""));
648 int rc
= errno
? -errno
: -EINVAL
;
650 DBG(CXT
, ul_debugobj(cxt
, "failed to assign device [rc=%d]", rc
));
656 * fdisk_assign_device:
658 * @fname: path to the device to be handled
659 * @readonly: how to open the device
661 * Open the device, discovery topology, geometry, detect disklabel, check for
662 * collisions and switch the current label driver to reflect the probing
665 * If in standard mode (!= non-listonly mode) then also detects for collisions.
666 * The result is accessible by fdisk_get_collision() and
667 * fdisk_is_ptcollision(). The collision (e.g. old obsolete PT) may be removed
668 * by fdisk_enable_wipe(). Note that new PT and old PT may be on different
671 * Note that this function resets all generic setting in context.
673 * If the @cxt is nested context (necessary for example to edit BSD or PMBR)
674 * then the device is assigned to the parental context and necessary properties
675 * are copied to the @cxt. The change is propagated in child->parent direction
676 * only. It's impossible to use a different device for primary and nested
679 * Returns: 0 on success, < 0 on error.
681 int fdisk_assign_device(struct fdisk_context
*cxt
,
682 const char *fname
, int readonly
)
684 int fd
, rc
, flags
= O_CLOEXEC
;
686 DBG(CXT
, ul_debugobj(cxt
, "assigning device %s", fname
));
692 flags
|= (O_RDWR
| O_EXCL
);
695 fd
= open(fname
,flags
);
696 if (fd
< 0 && errno
== EBUSY
&& (flags
& O_EXCL
)) {
699 fd
= open(fname
, flags
);
704 DBG(CXT
, ul_debugobj(cxt
, "failed to assign device [rc=%d]", rc
));
708 rc
= fdisk_assign_fd(cxt
, fd
, fname
, readonly
, 1, flags
& O_EXCL
);
715 * fdisk_assign_device_by_fd:
717 * @fd: device file descriptor
718 * @fname: path to the device (used for dialogs, debugging, partition names, ...)
719 * @readonly: how to use the device
721 * Like fdisk_assign_device(), but caller is responsible to open and close the
722 * device. The library only fsync() the device on fdisk_deassign_device().
724 * The device has to be open O_RDWR on @readonly=0.
726 * Returns: 0 on success, < 0 on error.
730 int fdisk_assign_device_by_fd(struct fdisk_context
*cxt
, int fd
,
731 const char *fname
, int readonly
)
733 DBG(CXT
, ul_debugobj(cxt
, "assign by fd"));
734 return fdisk_assign_fd(cxt
, fd
, fname
, readonly
, 0, 0);
738 * fdisk_deassign_device:
740 * @nosync: disable sync() after close().
742 * Call fsync(), close() and than sync(), but for read-only handler close the
743 * device only. If the @cxt is nested context then the request is redirected to
746 * Returns: 0 on success, < 0 on error.
748 int fdisk_deassign_device(struct fdisk_context
*cxt
, int nosync
)
751 assert(cxt
->dev_fd
>= 0);
754 int rc
= fdisk_deassign_device(cxt
->parent
, nosync
);
757 rc
= init_nested_from_parent(cxt
, 0);
761 DBG(CXT
, ul_debugobj(cxt
, "de-assigning device %s", cxt
->dev_path
));
763 if (cxt
->readonly
&& cxt
->is_priv
)
766 if (fsync(cxt
->dev_fd
)) {
767 fdisk_warn(cxt
, _("%s: fsync device failed"),
771 if (cxt
->is_priv
&& close(cxt
->dev_fd
)) {
772 fdisk_warn(cxt
, _("%s: close device failed"),
776 if (S_ISBLK(cxt
->dev_st
.st_mode
) && !nosync
) {
777 fdisk_info(cxt
, _("Syncing disks."));
783 cxt
->dev_path
= NULL
;
792 * fdisk_reassign_device:
795 * This function is "hard reset" of the context and it does not write anything
796 * to the device. All in-memory changes associated with the context will be
797 * lost. It's recommended to use this function after some fatal problem when the
798 * context (and label specific driver) is in an undefined state.
800 * Returns: 0 on success, < 0 on error.
802 int fdisk_reassign_device(struct fdisk_context
*cxt
)
805 int rdonly
, rc
, fd
, priv
, excl
;
808 assert(cxt
->dev_fd
>= 0);
810 DBG(CXT
, ul_debugobj(cxt
, "re-assigning device %s", cxt
->dev_path
));
812 devname
= strdup(cxt
->dev_path
);
816 rdonly
= cxt
->readonly
;
821 fdisk_deassign_device(cxt
, 1);
824 /* reopen and assign */
825 rc
= fdisk_assign_device(cxt
, devname
, rdonly
);
828 rc
= fdisk_assign_fd(cxt
, fd
, devname
, rdonly
, priv
, excl
);
835 * fdisk_reread_partition_table:
838 * Force *kernel* to re-read partition table on block devices.
840 * Returns: 0 on success, < 0 in case of error.
842 int fdisk_reread_partition_table(struct fdisk_context
*cxt
)
847 assert(cxt
->dev_fd
>= 0);
849 if (!S_ISBLK(cxt
->dev_st
.st_mode
))
852 DBG(CXT
, ul_debugobj(cxt
, "calling re-read ioctl"));
855 fdisk_info(cxt
, _("Calling ioctl() to re-read partition table."));
856 i
= ioctl(cxt
->dev_fd
, BLKRRPART
);
863 fdisk_warn(cxt
, _("Re-reading the partition table failed."));
865 "The kernel still uses the old table. The "
866 "new table will be used at the next reboot "
867 "or after you run partprobe(8) or partx(8)."));
875 static inline int add_to_partitions_array(
876 struct fdisk_partition
***ary
,
877 struct fdisk_partition
*pa
,
878 size_t *n
, size_t nmax
)
881 *ary
= calloc(nmax
, sizeof(struct fdisk_partition
*));
892 * fdisk_reread_changes:
894 * @org: original layout (on disk)
896 * Like fdisk_reread_partition_table() but don't forces kernel re-read all
897 * partition table. The BLKPG_* ioctls are used for individual partitions. The
898 * advantage is that unmodified partitions maybe mounted.
900 * The function behaves like fdisk_reread_partition_table() on systems where
901 * are no available BLKPG_* ioctls.
903 * Returns: <0 on error, or 0.
906 int fdisk_reread_changes(struct fdisk_context
*cxt
, struct fdisk_table
*org
)
908 struct fdisk_table
*tb
= NULL
;
909 struct fdisk_iter itr
;
910 struct fdisk_partition
*pa
;
911 struct fdisk_partition
**rem
= NULL
, **add
= NULL
, **upd
= NULL
;
912 int change
, rc
= 0, err
= 0;
913 size_t nparts
, i
, nadds
= 0, nupds
= 0, nrems
= 0;
916 DBG(CXT
, ul_debugobj(cxt
, "rereading changes"));
918 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
920 /* the current layout */
921 fdisk_get_partitions(cxt
, &tb
);
922 /* maximal number of partitions */
923 nparts
= max(fdisk_table_get_nents(tb
), fdisk_table_get_nents(org
));
925 while (fdisk_diff_tables(org
, tb
, &itr
, &pa
, &change
) == 0) {
926 if (change
== FDISK_DIFF_UNCHANGED
)
929 case FDISK_DIFF_REMOVED
:
930 rc
= add_to_partitions_array(&rem
, pa
, &nrems
, nparts
);
932 case FDISK_DIFF_ADDED
:
933 rc
= add_to_partitions_array(&add
, pa
, &nadds
, nparts
);
935 case FDISK_DIFF_RESIZED
:
936 rc
= add_to_partitions_array(&upd
, pa
, &nupds
, nparts
);
938 case FDISK_DIFF_MOVED
:
939 rc
= add_to_partitions_array(&rem
, pa
, &nrems
, nparts
);
941 rc
= add_to_partitions_array(&add
, pa
, &nadds
, nparts
);
948 /* sector size factor -- used to recount from real to 512-byte sectors */
949 ssf
= cxt
->sector_size
/ 512;
951 for (i
= 0; i
< nrems
; i
++) {
953 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_DEL_PARTITION", pa
->partno
));
954 if (partx_del_partition(cxt
->dev_fd
, pa
->partno
+ 1) != 0) {
955 fdisk_warn(cxt
, _("Failed to remove partition %zu from system"), pa
->partno
+ 1);
959 for (i
= 0; i
< nupds
; i
++) {
961 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_RESIZE_PARTITION", pa
->partno
));
962 if (partx_resize_partition(cxt
->dev_fd
, pa
->partno
+ 1,
963 pa
->start
* ssf
, pa
->size
* ssf
) != 0) {
964 fdisk_warn(cxt
, _("Failed to update system information about partition %zu"), pa
->partno
+ 1);
968 for (i
= 0; i
< nadds
; i
++) {
974 DBG(PART
, ul_debugobj(pa
, "#%zu calling BLKPG_ADD_PARTITION", pa
->partno
));
976 if (fdisk_is_label(cxt
, DOS
) && fdisk_partition_is_container(pa
))
977 /* Let's follow the Linux kernel and reduce
978 * DOS extended partition to 1 or 2 sectors.
980 sz
= min(sz
, (uint64_t) 2);
982 if (partx_add_partition(cxt
->dev_fd
, pa
->partno
+ 1,
983 pa
->start
* ssf
, sz
) != 0) {
984 fdisk_warn(cxt
, _("Failed to add partition %zu to system"), pa
->partno
+ 1);
990 "The kernel still uses the old partitions. The new "
991 "table will be used at the next reboot. "));
996 fdisk_unref_table(tb
);
1000 int fdisk_reread_changes(struct fdisk_context
*cxt
,
1001 struct fdisk_table
*org
__attribute__((__unused__
))) {
1002 return fdisk_reread_partition_table(cxt
);
1007 * fdisk_device_is_used:
1010 * The function returns always 0 if the device has not been opened by
1011 * fdisk_assign_device() or if open read-only.
1013 * Returns: 1 if the device assigned to the context is used by system, or 0.
1015 int fdisk_device_is_used(struct fdisk_context
*cxt
)
1019 assert(cxt
->dev_fd
>= 0);
1021 rc
= cxt
->readonly
? 0 :
1023 cxt
->is_priv
? 1 : 0;
1025 DBG(CXT
, ul_debugobj(cxt
, "device used: %s [read-only=%d, excl=%d, priv:%d]",
1026 rc
? "TRUE" : "FALSE", cxt
->readonly
,
1027 cxt
->is_excl
, cxt
->is_priv
));
1032 * fdisk_is_readonly:
1035 * Returns: 1 if device open readonly
1037 int fdisk_is_readonly(struct fdisk_context
*cxt
)
1040 return cxt
->readonly
;
1049 * Returns: 1 if open file descriptor is regular file rather than a block device.
1051 int fdisk_is_regfile(struct fdisk_context
*cxt
)
1054 return S_ISREG(cxt
->dev_st
.st_mode
);
1058 * fdisk_unref_context:
1059 * @cxt: fdisk context
1061 * Deallocates context struct.
1063 void fdisk_unref_context(struct fdisk_context
*cxt
)
1071 if (cxt
->refcount
<= 0) {
1072 DBG(CXT
, ul_debugobj(cxt
, "freeing context %p for %s", cxt
, cxt
->dev_path
));
1074 reset_context(cxt
); /* this is sensitive to parent<->child relationship! */
1076 /* deallocate label's private stuff */
1077 for (i
= 0; i
< cxt
->nlabels
; i
++) {
1078 if (!cxt
->labels
[i
])
1080 if (cxt
->labels
[i
]->op
->free
)
1081 cxt
->labels
[i
]->op
->free(cxt
->labels
[i
]);
1083 free(cxt
->labels
[i
]);
1084 cxt
->labels
[i
] = NULL
;
1087 fdisk_unref_context(cxt
->parent
);
1096 * fdisk_enable_details:
1098 * @enable: true/false
1100 * Enables or disables "details" display mode. This function has effect to
1101 * fdisk_partition_to_string() function.
1103 * Returns: 0 on success, < 0 on error.
1105 int fdisk_enable_details(struct fdisk_context
*cxt
, int enable
)
1108 cxt
->display_details
= enable
? 1 : 0;
1116 * Returns: 1 if details are enabled
1118 int fdisk_is_details(struct fdisk_context
*cxt
)
1121 return cxt
->display_details
== 1;
1125 * fdisk_enable_listonly:
1127 * @enable: true/false
1129 * Just list partition only, don't care about another details, mistakes, ...
1131 * Returns: 0 on success, < 0 on error.
1133 int fdisk_enable_listonly(struct fdisk_context
*cxt
, int enable
)
1136 cxt
->listonly
= enable
? 1 : 0;
1141 * fdisk_is_listonly:
1144 * Returns: 1 if list-only mode enabled
1146 int fdisk_is_listonly(struct fdisk_context
*cxt
)
1149 return cxt
->listonly
== 1;
1156 * @str: "cylinder" or "sector".
1158 * This is pure shit, unfortunately for example Sun addresses begin of the
1159 * partition by cylinders...
1161 * Returns: 0 on success, <0 on error.
1163 int fdisk_set_unit(struct fdisk_context
*cxt
, const char *str
)
1167 cxt
->display_in_cyl_units
= 0;
1172 if (strcmp(str
, "cylinder") == 0 || strcmp(str
, "cylinders") == 0)
1173 cxt
->display_in_cyl_units
= 1;
1175 else if (strcmp(str
, "sector") == 0 || strcmp(str
, "sectors") == 0)
1176 cxt
->display_in_cyl_units
= 0;
1178 DBG(CXT
, ul_debugobj(cxt
, "display unit: %s", fdisk_get_unit(cxt
, 0)));
1185 * @n: FDISK_PLURAL or FDISK_SINGULAR
1187 * Returns: unit name.
1189 const char *fdisk_get_unit(struct fdisk_context
*cxt
, int n
)
1193 if (fdisk_use_cylinders(cxt
))
1194 return P_("cylinder", "cylinders", n
);
1195 return P_("sector", "sectors", n
);
1199 * fdisk_use_cylinders:
1202 * Returns: 1 if user wants to display in cylinders.
1204 int fdisk_use_cylinders(struct fdisk_context
*cxt
)
1207 return cxt
->display_in_cyl_units
== 1;
1211 * fdisk_get_units_per_sector:
1214 * This is necessary only for brain dead situations when we use "cylinders";
1216 * Returns: number of "units" per sector, default is 1 if display unit is sector.
1218 unsigned int fdisk_get_units_per_sector(struct fdisk_context
*cxt
)
1222 if (fdisk_use_cylinders(cxt
)) {
1223 assert(cxt
->geom
.heads
);
1224 return cxt
->geom
.heads
* cxt
->geom
.sectors
;
1230 * fdisk_get_optimal_iosize:
1233 * The optimal I/O is optional and does not have to be provided by device,
1234 * anyway libfdisk never returns zero. If the optimal I/O size is not provided
1235 * then libfdisk returns minimal I/O size or sector size.
1237 * Returns: optimal I/O size in bytes.
1239 unsigned long fdisk_get_optimal_iosize(struct fdisk_context
*cxt
)
1242 return cxt
->optimal_io_size
? cxt
->optimal_io_size
: cxt
->io_size
;
1246 * fdisk_get_minimal_iosize:
1249 * Returns: minimal I/O size in bytes
1251 unsigned long fdisk_get_minimal_iosize(struct fdisk_context
*cxt
)
1254 return cxt
->min_io_size
;
1258 * fdisk_get_physector_size:
1261 * Returns: physical sector size in bytes
1263 unsigned long fdisk_get_physector_size(struct fdisk_context
*cxt
)
1266 return cxt
->phy_sector_size
;
1270 * fdisk_get_sector_size:
1273 * Returns: logical sector size in bytes
1275 unsigned long fdisk_get_sector_size(struct fdisk_context
*cxt
)
1278 return cxt
->sector_size
;
1282 * fdisk_get_alignment_offset
1285 * The alignment offset is offset between logical and physical sectors. For
1286 * backward compatibility the first logical sector on 4K disks does no have to
1287 * start on the same place like physical sectors.
1289 * Returns: alignment offset in bytes
1291 unsigned long fdisk_get_alignment_offset(struct fdisk_context
*cxt
)
1294 return cxt
->alignment_offset
;
1298 * fdisk_get_grain_size:
1301 * Returns: grain in bytes used to align partitions (usually 1MiB)
1303 unsigned long fdisk_get_grain_size(struct fdisk_context
*cxt
)
1310 * fdisk_get_first_lba:
1313 * Returns: first possible LBA on disk for data partitions.
1315 fdisk_sector_t
fdisk_get_first_lba(struct fdisk_context
*cxt
)
1318 return cxt
->first_lba
;
1322 * fdisk_set_first_lba:
1323 * @cxt: fdisk context
1324 * @lba: first possible logical sector for data
1326 * It's strongly recommended to use the default library setting. The first LBA
1327 * is always reset by fdisk_assign_device(), fdisk_override_geometry()
1328 * and fdisk_reset_alignment(). This is very low level function and library
1329 * does not check if your setting makes any sense.
1331 * This function is necessary only when you want to work with very unusual
1332 * partition tables like GPT protective MBR or hybrid partition tables on
1333 * bootable media where the first partition may start on very crazy offsets.
1335 * Note that this function changes only runtime information. It does not update
1336 * any range in on-disk partition table. For example GPT Header contains First
1337 * and Last usable LBA fields. These fields are not updated by this function.
1340 * Returns: 0 on success, <0 on error.
1342 fdisk_sector_t
fdisk_set_first_lba(struct fdisk_context
*cxt
, fdisk_sector_t lba
)
1345 DBG(CXT
, ul_debugobj(cxt
, "setting first LBA from %ju to %ju",
1346 (uintmax_t) cxt
->first_lba
, (uintmax_t) lba
));
1347 cxt
->first_lba
= lba
;
1352 * fdisk_get_last_lba:
1353 * @cxt: fdisk context
1355 * Note that the device has to be already assigned.
1357 * Returns: last possible LBA on device
1359 fdisk_sector_t
fdisk_get_last_lba(struct fdisk_context
*cxt
)
1361 return cxt
->last_lba
;
1365 * fdisk_set_last_lba:
1366 * @cxt: fdisk context
1367 * @lba: last possible logical sector
1369 * It's strongly recommended to use the default library setting. The last LBA
1370 * is always reset by fdisk_assign_device(), fdisk_override_geometry() and
1371 * fdisk_reset_alignment().
1373 * The default is number of sectors on the device, but maybe modified by the
1374 * current disklabel driver (for example GPT uses the end of disk for backup
1375 * header, so last_lba is smaller than total number of sectors).
1377 * Returns: 0 on success, <0 on error.
1379 fdisk_sector_t
fdisk_set_last_lba(struct fdisk_context
*cxt
, fdisk_sector_t lba
)
1383 if (lba
> cxt
->total_sectors
- 1 || lba
< 1)
1385 cxt
->last_lba
= lba
;
1390 * fdisk_set_size_unit:
1391 * @cxt: fdisk context
1392 * @unit: FDISK_SIZEUNIT_*
1394 * Sets unit for SIZE output field (see fdisk_partition_to_string()).
1396 * Returns: 0 on success, <0 on error.
1398 int fdisk_set_size_unit(struct fdisk_context
*cxt
, int unit
)
1401 cxt
->sizeunit
= unit
;
1406 * fdisk_get_size_unit:
1407 * @cxt: fdisk context
1409 * Gets unit for SIZE output field (see fdisk_partition_to_string()).
1413 int fdisk_get_size_unit(struct fdisk_context
*cxt
)
1416 return cxt
->sizeunit
;
1420 * fdisk_get_nsectors:
1423 * Returns: size of the device in logical sectors.
1425 fdisk_sector_t
fdisk_get_nsectors(struct fdisk_context
*cxt
)
1428 return cxt
->total_sectors
;
1432 * fdisk_get_devname:
1435 * Returns: device name.
1437 const char *fdisk_get_devname(struct fdisk_context
*cxt
)
1440 return cxt
->dev_path
;
1447 * Returns: device number or zero for non-block devices
1451 dev_t
fdisk_get_devno(struct fdisk_context
*cxt
)
1454 return S_ISBLK(cxt
->dev_st
.st_mode
) ? cxt
->dev_st
.st_rdev
: 0;
1458 * fdisk_get_devmodel:
1461 * Returns: device model string or NULL.
1466 const char *fdisk_get_devmodel(struct fdisk_context
*cxt
)
1470 if (cxt
->dev_model_probed
)
1471 return cxt
->dev_model
;
1473 if (fdisk_get_devno(cxt
)) {
1474 struct path_cxt
*pc
= ul_new_sysfs_path(fdisk_get_devno(cxt
), NULL
, NULL
);
1477 ul_path_read_string(pc
, &cxt
->dev_model
, "device/model");
1481 cxt
->dev_model_probed
= 1;
1482 return cxt
->dev_model
;
1485 const char *fdisk_get_devmodel(struct fdisk_context
*cxt
__attribute__((__unused__
)))
1495 * Returns: device file descriptor.
1497 int fdisk_get_devfd(struct fdisk_context
*cxt
)
1504 * fdisk_get_geom_heads:
1507 * Returns: number of geometry heads.
1509 unsigned int fdisk_get_geom_heads(struct fdisk_context
*cxt
)
1512 return cxt
->geom
.heads
;
1515 * fdisk_get_geom_sectors:
1518 * Returns: number of geometry sectors.
1520 fdisk_sector_t
fdisk_get_geom_sectors(struct fdisk_context
*cxt
)
1523 return cxt
->geom
.sectors
;
1528 * fdisk_get_geom_cylinders:
1531 * Returns: number of geometry cylinders
1533 fdisk_sector_t
fdisk_get_geom_cylinders(struct fdisk_context
*cxt
)
1536 return cxt
->geom
.cylinders
;
1539 int fdisk_missing_geometry(struct fdisk_context
*cxt
)
1543 if (!cxt
|| !cxt
->label
)
1546 rc
= (fdisk_label_require_geometry(cxt
->label
) &&
1547 (!cxt
->geom
.heads
|| !cxt
->geom
.sectors
1548 || !cxt
->geom
.cylinders
));
1550 if (rc
&& !fdisk_is_listonly(cxt
))
1551 fdisk_warnx(cxt
, _("Incomplete geometry setting."));