]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
eject: use O_EXCL on default
authorKarel Zak <kzak@redhat.com>
Thu, 22 Aug 2019 11:05:06 +0000 (13:05 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 22 Aug 2019 11:05:06 +0000 (13:05 +0200)
* by default we assume all is umounted; so O_EXCL is no problem,
  otherwise there is bug or race (someone else remounted the device)...

* --force and --no-umount disable O_EXCL

Addresses: https://github.com/karelzak/util-linux/issues/423
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/eject.1
sys-utils/eject.c

index f901b239d6e20ac46545ad4d9198a3ccfd435529..0958e052e2f4c319876020d2ff0b377acab42d59 100644 (file)
@@ -27,8 +27,12 @@ There are four different methods of ejecting, depending on whether the device
 is a CD-ROM, SCSI device, removable floppy, or tape.  By default \fBeject\fR tries
 all four methods in order until it succeeds.
 .PP
-If a device partition is specified, the whole-disk device is used.  If the device
-or a device partition is currently mounted, it is unmounted before ejecting.
+If a device partition is specified, the whole-disk device is used.
+.PP
+If the device or a device partition is currently mounted, it is unmounted
+before ejecting.  The eject is processed on exclusive open block device
+file descriptor if \fB\-\-no\-unmount\fP or \fB\-\-force\fP are not specified.
+
 .SH OPTIONS
 .TP
 .BR \-a , " \-\-auto on" | off
@@ -45,7 +49,8 @@ is referred to as 0, not 1.
 List the default device name.
 .TP
 .BR \-F , " \-\-force"
-Force eject, don't check device type.
+Force eject, don't check device type, don't open device with exclusive lock.
+The successful result may be false positive on non hot-pluggable devices.
 .TP
 .BR \-f , " \-\-floppy"
 This option specifies that the drive should be ejected using a removable floppy
@@ -67,7 +72,11 @@ to eject the media.  It will attempt to unmount only the device or mountpoint
 given on the command line.
 .TP
 .BR \-m , " \-\-no\-unmount"
-The option tells eject to not try to unmount at all.
+The option tells eject to not try to unmount at all.  If this option is not
+specified than
+.B eject
+opens the device with O_EXCL flag to be sure that the device is not used (since
+v2.35).
 .TP
 .BR \-n , " \-\-noop"
 With this option the selected device is displayed but no action is performed.
index d2e76d2ffeabbb5c488582c4b6249f0845f1c3e6..2f3b200bf8dee07695dc57306e31093e14ecc640 100644 (file)
@@ -96,6 +96,9 @@ struct eject_control {
                x_option:1,
                a_arg:1,
                i_arg:1;
+
+       unsigned int force_exclusive;   /* use O_EXCL */
+
        long int c_arg;                 /* changer slot number */
        long int x_arg;                 /* cd speed */
 };
@@ -686,9 +689,12 @@ static void umount_one(const struct eject_control *ctl, const char *name)
 /* Open a device file. */
 static void open_device(struct eject_control *ctl)
 {
-       ctl->fd = open(ctl->device, O_RDWR | O_NONBLOCK);
+       int extra = ctl->F_option == 0 &&               /* never use O_EXCL on --force */
+                   ctl->force_exclusive ? O_EXCL : 0;
+
+       ctl->fd = open(ctl->device, O_RDWR | O_NONBLOCK | extra);
        if (ctl->fd < 0)
-               ctl->fd = open(ctl->device, O_RDONLY | O_NONBLOCK);
+               ctl->fd = open(ctl->device, O_RDONLY | O_NONBLOCK | extra);
        if (ctl->fd == -1)
                err(EXIT_FAILURE, _("cannot open %s"), ctl->device);
 }
@@ -755,6 +761,9 @@ static char *get_disk_devname(const char *device)
        return st.st_rdev == diskno ? NULL : find_device(diskname);
 }
 
+/* umount all partitions if -M not specified, otherwise returns
+ * number of the mounted partitions only.
+ */
 static int umount_partitions(struct eject_control *ctl)
 {
        struct path_cxt *pc = NULL;
@@ -970,7 +979,7 @@ int main(int argc, char **argv)
         * partition is mounted.
         */
        if (!ctl.m_option) {
-               int ct = umount_partitions(&ctl);
+               int ct = umount_partitions(&ctl); /* umount all, or count mounted on -M */
 
                if (ct == 0 && mountpoint)
                        umount_one(&ctl, mountpoint); /* probably whole-device */
@@ -981,6 +990,11 @@ int main(int argc, char **argv)
                        else if (ct)
                                errx(EXIT_FAILURE, _("error: %s: device in use"), ctl.device);
                }
+               /* Now, we assume the device is no more used, use O_EXCL to be
+                * resistant against our bugs and possible races (someone else
+                * remounted the device).
+                */
+               ctl.force_exclusive = 1;
        }
 
        /* handle -c option */