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
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
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.
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 */
};
/* 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);
}
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;
* 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 */
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 */