summaryrefslogtreecommitdiffstats
path: root/libfdisk
diff options
context:
space:
mode:
authorKarel Zak2019-06-18 13:30:42 +0200
committerKarel Zak2019-06-18 13:30:42 +0200
commit7571ec08a15d54ad05e4b619ccef5a6f10ce30bc (patch)
treee719f705734ae8f7f5744808f7265a22bb7aa6b3 /libfdisk
parentMerge branch 'su_err_msg' of https://github.com/jhrozek/util-linux (diff)
downloadkernel-qcow2-util-linux-7571ec08a15d54ad05e4b619ccef5a6f10ce30bc.tar.gz
kernel-qcow2-util-linux-7571ec08a15d54ad05e4b619ccef5a6f10ce30bc.tar.xz
kernel-qcow2-util-linux-7571ec08a15d54ad05e4b619ccef5a6f10ce30bc.zip
libfdisk: add fdisk_assign_device_by_fd()
It's possible that caller has the device already opened for some other task, so let's reuse the file descriptor. Requested-by: Lennart Poettering <lennart@poettering.net> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk')
-rw-r--r--libfdisk/docs/libfdisk-sections.txt1
-rw-r--r--libfdisk/src/context.c142
-rw-r--r--libfdisk/src/fdiskP.h1
-rw-r--r--libfdisk/src/libfdisk.h.in2
-rw-r--r--libfdisk/src/libfdisk.sym1
5 files changed, 99 insertions, 48 deletions
diff --git a/libfdisk/docs/libfdisk-sections.txt b/libfdisk/docs/libfdisk-sections.txt
index d0d362f60..f148da527 100644
--- a/libfdisk/docs/libfdisk-sections.txt
+++ b/libfdisk/docs/libfdisk-sections.txt
@@ -291,6 +291,7 @@ fdisk_unref_table
<FILE>context</FILE>
fdisk_context
fdisk_assign_device
+fdisk_assign_device_by_fd
fdisk_deassign_device
fdisk_reassign_device
fdisk_device_is_used
diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c
index 1171f28a8..b62d2b101 100644
--- a/libfdisk/src/context.c
+++ b/libfdisk/src/context.c
@@ -541,7 +541,7 @@ static void reset_context(struct fdisk_context *cxt)
free(cxt->firstsector);
} else {
/* we close device only in primary context */
- if (cxt->dev_fd > -1)
+ if (cxt->dev_fd > -1 && cxt->private_fd)
close(cxt->dev_fd);
free(cxt->firstsector);
}
@@ -559,6 +559,7 @@ static void reset_context(struct fdisk_context *cxt)
memset(&cxt->dev_st, 0, sizeof(cxt->dev_st));
cxt->dev_fd = -1;
+ cxt->private_fd = 0;
cxt->firstsector = NULL;
cxt->firstsector_bufsz = 0;
@@ -572,39 +573,12 @@ static void reset_context(struct fdisk_context *cxt)
fdisk_free_wipe_areas(cxt);
}
-/**
- * fdisk_assign_device:
- * @cxt: context
- * @fname: path to the device to be handled
- * @readonly: how to open the device
- *
- * Open the device, discovery topology, geometry, detect disklabel, check for
- * collisions and switch the current label driver to reflect the probing
- * result.
- *
- * If in standard mode (!= non-listonly mode) than also detects for collisions.
- * The result is accessible by fdisk_get_collision() and
- * fdisk_is_ptcollision(). The collision (e.g. old obsolete PT) may be removed
- * by fdisk_enable_wipe(). Note that new PT and old PT may be on different
- * locations.
- *
- * Note that this function resets all generic setting in context.
- *
- * If the @cxt is nested context (necessary for example to edit BSD or PMBR)
- * then the device is assigned to the parental context and necessary properties
- * are copied to the @cxt. The change is propagated in child->parent direction
- * only. It's impossible to use a different device for primary and nested
- * contexts.
- *
- * Returns: 0 on success, < 0 on error.
- */
-int fdisk_assign_device(struct fdisk_context *cxt,
- const char *fname, int readonly)
+/* fdisk_assign_device() body */
+static int fdisk_assign_fd(struct fdisk_context *cxt, int fd,
+ const char *fname, int readonly, int privfd)
{
- int fd;
-
- DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
assert(cxt);
+ assert(fd >= 0);
/* redirect request to parent */
if (cxt->parent) {
@@ -615,7 +589,7 @@ int fdisk_assign_device(struct fdisk_context *cxt,
* unwanted extra warnings. */
fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt));
- rc = fdisk_assign_device(cxt->parent, fname, readonly);
+ rc = fdisk_assign_fd(cxt->parent, fd, fname, readonly, privfd);
fdisk_enable_listonly(cxt->parent, org);
if (!rc)
@@ -627,16 +601,13 @@ int fdisk_assign_device(struct fdisk_context *cxt,
reset_context(cxt);
- fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
- if (fd < 0)
- goto fail;
-
if (fstat(fd, &cxt->dev_st) != 0)
goto fail;
cxt->readonly = readonly;
cxt->dev_fd = fd;
- cxt->dev_path = strdup(fname);
+ cxt->private_fd = privfd;
+ cxt->dev_path = fname ? strdup(fname) : NULL;
if (!cxt->dev_path)
goto fail;
@@ -649,7 +620,6 @@ int fdisk_assign_device(struct fdisk_context *cxt,
goto fail;
fdisk_probe_labels(cxt);
-
fdisk_apply_label_device_properties(cxt);
/* warn about obsolete stuff on the device if we aren't in
@@ -664,14 +634,79 @@ int fdisk_assign_device(struct fdisk_context *cxt,
fail:
{
int rc = -errno;
- if (fd >= 0)
- close(fd);
DBG(CXT, ul_debugobj(cxt, "failed to assign device [rc=%d]", rc));
return rc;
}
}
/**
+ * fdisk_assign_device:
+ * @cxt: context
+ * @fname: path to the device to be handled
+ * @readonly: how to open the device
+ *
+ * Open the device, discovery topology, geometry, detect disklabel, check for
+ * collisions and switch the current label driver to reflect the probing
+ * result.
+ *
+ * If in standard mode (!= non-listonly mode) than also detects for collisions.
+ * The result is accessible by fdisk_get_collision() and
+ * fdisk_is_ptcollision(). The collision (e.g. old obsolete PT) may be removed
+ * by fdisk_enable_wipe(). Note that new PT and old PT may be on different
+ * locations.
+ *
+ * Note that this function resets all generic setting in context.
+ *
+ * If the @cxt is nested context (necessary for example to edit BSD or PMBR)
+ * then the device is assigned to the parental context and necessary properties
+ * are copied to the @cxt. The change is propagated in child->parent direction
+ * only. It's impossible to use a different device for primary and nested
+ * contexts.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_assign_device(struct fdisk_context *cxt,
+ const char *fname, int readonly)
+{
+ int fd, rc;
+
+ DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
+ assert(cxt);
+
+ fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
+ if (fd < 0) {
+ int rc = -errno;
+ DBG(CXT, ul_debugobj(cxt, "failed to assign device [rc=%d]", rc));
+ return rc;
+ }
+
+ rc = fdisk_assign_fd(cxt, fd, fname, readonly, 1);
+ if (rc)
+ close(fd);
+ return rc;
+}
+
+/**
+ * fdisk_assign_device_by_fd:
+ * @cxt: context
+ * @fd: device file descriptor
+ * @fname: path to the device (used for dialogs, debugging, partition names, ...)
+ * @readonly: how to use the device
+ *
+ * Like fdisk_assign_device(), but caller is responsible to open and close the
+ * device. The library only fsync() the device on fdisk_deassign_device().
+ *
+ * The device has to be open O_RDWR on @readonly=0.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_assign_device_by_fd(struct fdisk_context *cxt, int fd,
+ const char *fname, int readonly)
+{
+ return fdisk_assign_fd(cxt, fd, fname, readonly, 0);
+}
+
+/**
* fdisk_deassign_device:
* @cxt: context
* @nosync: disable fsync()
@@ -696,15 +731,19 @@ int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
DBG(CXT, ul_debugobj(cxt, "de-assigning device %s", cxt->dev_path));
- if (cxt->readonly)
+ if (cxt->readonly && cxt->private_fd)
close(cxt->dev_fd);
else {
- if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
+ if (fsync(cxt->dev_fd)) {
+ fdisk_warn(cxt, _("%s: fsync device failed"),
+ cxt->dev_path);
+ return -errno;
+ }
+ if (cxt->private_fd && close(cxt->dev_fd)) {
fdisk_warn(cxt, _("%s: close device failed"),
cxt->dev_path);
return -errno;
}
-
if (!nosync) {
fdisk_info(cxt, _("Syncing disks."));
sync();
@@ -713,7 +752,6 @@ int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
free(cxt->dev_path);
cxt->dev_path = NULL;
-
cxt->dev_fd = -1;
return 0;
@@ -733,7 +771,7 @@ int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
int fdisk_reassign_device(struct fdisk_context *cxt)
{
char *devname;
- int rdonly, rc;
+ int rdonly, rc, fd, privfd;
assert(cxt);
assert(cxt->dev_fd >= 0);
@@ -745,11 +783,19 @@ int fdisk_reassign_device(struct fdisk_context *cxt)
return -ENOMEM;
rdonly = cxt->readonly;
+ fd = cxt->dev_fd;
+ privfd = cxt->private_fd;
fdisk_deassign_device(cxt, 1);
- rc = fdisk_assign_device(cxt, devname, rdonly);
- free(devname);
+ if (privfd)
+ /* reopen and assign */
+ rc = fdisk_assign_device(cxt, devname, rdonly);
+ else
+ /* assign only */
+ rc = fdisk_assign_fd(cxt, fd, devname, rdonly, privfd);
+
+ free(devname);
return rc;
}
diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h
index 19c1c7953..fefebae2a 100644
--- a/libfdisk/src/fdiskP.h
+++ b/libfdisk/src/fdiskP.h
@@ -389,6 +389,7 @@ struct fdisk_context {
pt_collision : 1, /* another PT detected by libblkid */
no_disalogs : 1, /* disable dialog-driven partititoning */
dev_model_probed : 1, /* tried to read from sys */
+ private_fd : 1, /* open by libfdisk */
listonly : 1; /* list partition, nothing else */
char *collision; /* name of already existing FS/PT */
diff --git a/libfdisk/src/libfdisk.h.in b/libfdisk/src/libfdisk.h.in
index 69c6fd820..0669c0a7c 100644
--- a/libfdisk/src/libfdisk.h.in
+++ b/libfdisk/src/libfdisk.h.in
@@ -195,6 +195,8 @@ int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id);
int fdisk_assign_device(struct fdisk_context *cxt,
const char *fname, int readonly);
+int fdisk_assign_device_by_fd(struct fdisk_context *cxt, int fd,
+ const char *fname, int readonly);
int fdisk_deassign_device(struct fdisk_context *cxt, int nosync);
int fdisk_reassign_device(struct fdisk_context *cxt);
diff --git a/libfdisk/src/libfdisk.sym b/libfdisk/src/libfdisk.sym
index 8ce943acc..96fcadd71 100644
--- a/libfdisk/src/libfdisk.sym
+++ b/libfdisk/src/libfdisk.sym
@@ -306,4 +306,5 @@ FDISK_2.33 {
FDISK_2.35 {
fdisk_script_set_table;
+ fdisk_assign_device_by_fd;
} FDISK_2.33;