]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: add fdisk_assign_device_by_fd()
authorKarel Zak <kzak@redhat.com>
Tue, 18 Jun 2019 11:30:42 +0000 (13:30 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 18 Jun 2019 11:30:42 +0000 (13:30 +0200)
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>
libfdisk/docs/libfdisk-sections.txt
libfdisk/src/context.c
libfdisk/src/fdiskP.h
libfdisk/src/libfdisk.h.in
libfdisk/src/libfdisk.sym

index d0d362f6020719b4ec1b102661a0cabb08eae86d..f148da5271e04256f9215dafe1042868a853447e 100644 (file)
@@ -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
index 1171f28a8a7613c925e7adc32ae16f0c4974cf62..b62d2b1017026f831d08e95cf5a5381fa32a5929 100644 (file)
@@ -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,13 +634,78 @@ 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
@@ -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;
 }
 
index 19c1c79536fcbfe978622db73f51fc5d6e3203da..fefebae2a9dfd41e74e8168fc1ce7dd372928220 100644 (file)
@@ -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 */
index 69c6fd820fa01572a962c358bd228909e8f59190..0669c0a7c3063eaa44a76b03ac6cb71fc5a99648 100644 (file)
@@ -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);
 
index 8ce943acc89b70cdb4e1204815aeb3b5268b7602..96fcadd7130326e27e91732edaf958df72151fc0 100644 (file)
@@ -306,4 +306,5 @@ FDISK_2.33 {
 
 FDISK_2.35 {
        fdisk_script_set_table;
+       fdisk_assign_device_by_fd;
 } FDISK_2.33;