2 * Copyright (c) 2003-2011, Haiku Inc.
3 * Distributed under the terms of the MIT license.
6 * François Revol <mmu_man@users.sf.net>
9 * Description: ejects physical media from a drive.
10 * This version also loads a media and can query for the status.
18 #include <device/scsi.h>
19 #include <DiskDevice.h>
20 #include <DiskDeviceRoster.h>
21 #include <DiskDeviceVisitor.h>
24 #include <ObjectList.h>
29 class RemovableDevice
{
31 RemovableDevice(BDiskDevice
* device
) {
32 fName
= device
->Name();
33 device
->GetPath(&fPath
);
36 inline const char* Name() { return fName
.String(); }
37 inline const char* Path() { return fPath
.Path(); }
45 class RemovableDeviceVisitor
: public BDiskDeviceVisitor
{
47 virtual bool Visit(BDiskDevice
* device
) {
48 if (device
->IsRemovableMedia())
49 fRemovableDevices
.AddItem(new RemovableDevice(device
));
50 return false; // Don't stop yet!
53 virtual bool Visit(BPartition
* partition
, int32 level
) { return false; }
55 inline BObjectList
<RemovableDevice
>& RemovableDevices() { return fRemovableDevices
; }
58 BObjectList
<RemovableDevice
> fRemovableDevices
;
62 static int usage(char *prog
)
64 printf("usage: eject [-q|-l|-s|-b|-u] /dev/disk/.../raw\n");
65 // printf("usage: eject [-q|-l|-s|-b|-u] [scsi|ide|/dev/disk/.../raw]\n");
66 printf(" eject the device, or:\n");
67 printf(" -l: load it (close the tray)\n");
68 printf(" -q: query for media status\n");
69 printf(" -s: swap tray position (close/eject)\n");
70 printf(" -b: block (lock) tray position (prevent close/eject)\n");
71 printf(" -u: unblock (unlock) tray position (allow close/eject)\n");
72 // printf(" scsi: act on all scsi devices\n");
73 // printf(" ide: act on all ide devices\n");
74 // printf(" acts on all scsi and ide devices and floppy by default\n");
78 static int do_eject(char operation
, char *device
);
80 int main(int argc
, char **argv
)
87 for (i
= 1; i
< argc
; i
++) {
88 if (strncmp(argv
[i
], "--h", 3) == 0) {
89 return usage("eject");
90 } else if (strncmp(argv
[i
], "-", 1) == 0) {
91 if (strlen(argv
[i
]) > 1)
92 operation
= argv
[i
][1];
99 ret
= do_eject(operation
, device
);
104 if (device
== NULL
) {
105 BDiskDeviceRoster diskDeviceRoster
;
106 RemovableDeviceVisitor visitor
;
107 diskDeviceRoster
.VisitEachDevice(&visitor
);
109 int32 count
= visitor
.RemovableDevices().CountItems();
111 printf("No removable device found!\n");
116 printf("Multiple removable devices available:\n");
117 for (i
= 0; i
< count
; i
++) {
118 RemovableDevice
* item
= visitor
.RemovableDevices().ItemAt(i
);
119 printf(" %s\t\"%s\"\n", item
->Path(), item
->Name());
124 // Default to single removable device found
125 device
= (char*)visitor
.RemovableDevices().FirstItem()->Path();
126 return do_eject(operation
, device
);
133 static int do_eject(char operation
, char *device
)
140 // if the path is not on devfs, it's probably on
141 // the mountpoint of the device we want to act on.
142 // (should rather stat() for blk(char) device though).
143 if (fs_stat_dev(dev_for_path(device
), &info
) >= B_OK
) {
144 if (strcmp(info
.fsh_name
, "devfs"))
145 device
= info
.device_name
;
148 fd
= open(device
, O_RDONLY
);
155 if (ioctl(fd
, B_EJECT_DEVICE
, NULL
, 0) < 0) {
162 if (ioctl(fd
, B_LOAD_MEDIA
, NULL
, 0) < 0) {
170 if (ioctl(fd
, B_SCSI_PREVENT_ALLOW
, &bval
, sizeof(bval
)) < 0) {
178 if (ioctl(fd
, B_SCSI_PREVENT_ALLOW
, &bval
, sizeof(bval
)) < 0) {
185 if (ioctl(fd
, B_GET_MEDIA_STATUS
, &devstatus
, sizeof(devstatus
))
193 puts("Media present");
196 puts(strerror(devstatus
));
200 if (ioctl(fd
, B_GET_MEDIA_STATUS
, &devstatus
, sizeof(devstatus
))
209 if (ioctl(fd
, B_EJECT_DEVICE
, NULL
, 0) < 0) {
215 case B_DEV_DOOR_OPEN
:
216 if (ioctl(fd
, B_LOAD_MEDIA
, NULL
, 0) < 0) {
229 return usage("eject");