vfs: check userland buffers before reading them.
[haiku.git] / src / bin / eject.cpp
blob52f17cd39a51dc608403097dc136fd807b97bfe0
1 /*
2 * Copyright (c) 2003-2011, Haiku Inc.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * François Revol <mmu_man@users.sf.net>
7 * Philippe Houdoin
9 * Description: ejects physical media from a drive.
10 * This version also loads a media and can query for the status.
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
18 #include <device/scsi.h>
19 #include <DiskDevice.h>
20 #include <DiskDeviceRoster.h>
21 #include <DiskDeviceVisitor.h>
22 #include <Drivers.h>
23 #include <fs_info.h>
24 #include <ObjectList.h>
25 #include <Path.h>
26 #include <String.h>
29 class RemovableDevice {
30 public:
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(); }
39 private:
40 BString fName;
41 BPath fPath;
45 class RemovableDeviceVisitor : public BDiskDeviceVisitor {
46 public:
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; }
57 private:
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");
75 return 0;
78 static int do_eject(char operation, char *device);
80 int main(int argc, char **argv)
82 char *device = NULL;
83 char operation = 'e';
84 int i;
85 int ret;
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];
93 else {
94 usage("eject");
95 return 1;
97 } else {
98 device = argv[i];
99 ret = do_eject(operation, device);
100 if (ret != 0)
101 return ret;
104 if (device == NULL) {
105 BDiskDeviceRoster diskDeviceRoster;
106 RemovableDeviceVisitor visitor;
107 diskDeviceRoster.VisitEachDevice(&visitor);
109 int32 count = visitor.RemovableDevices().CountItems();
110 if (count < 1) {
111 printf("No removable device found!\n");
112 return 1;
115 if (count > 1) {
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());
121 return 1;
124 // Default to single removable device found
125 device = (char*)visitor.RemovableDevices().FirstItem()->Path();
126 return do_eject(operation, device);
129 return 0;
133 static int do_eject(char operation, char *device)
135 bool bval;
136 int fd;
137 status_t devstatus;
138 fs_info info;
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);
149 if (fd < 0) {
150 perror(device);
151 return 1;
153 switch (operation) {
154 case 'e':
155 if (ioctl(fd, B_EJECT_DEVICE, NULL, 0) < 0) {
156 perror(device);
157 close(fd);
158 return 1;
160 break;
161 case 'l':
162 if (ioctl(fd, B_LOAD_MEDIA, NULL, 0) < 0) {
163 perror(device);
164 close(fd);
165 return 1;
167 break;
168 case 'b':
169 bval = true;
170 if (ioctl(fd, B_SCSI_PREVENT_ALLOW, &bval, sizeof(bval)) < 0) {
171 perror(device);
172 close(fd);
173 return 1;
175 break;
176 case 'u':
177 bval = false;
178 if (ioctl(fd, B_SCSI_PREVENT_ALLOW, &bval, sizeof(bval)) < 0) {
179 perror(device);
180 close(fd);
181 return 1;
183 break;
184 case 'q':
185 if (ioctl(fd, B_GET_MEDIA_STATUS, &devstatus, sizeof(devstatus))
186 < 0) {
187 perror(device);
188 close(fd);
189 return 1;
191 switch (devstatus) {
192 case B_NO_ERROR:
193 puts("Media present");
194 break;
195 default:
196 puts(strerror(devstatus));
198 break;
199 case 's':
200 if (ioctl(fd, B_GET_MEDIA_STATUS, &devstatus, sizeof(devstatus))
201 < 0) {
202 perror(device);
203 close(fd);
204 return 1;
206 switch (devstatus) {
207 case B_NO_ERROR:
208 case B_DEV_NO_MEDIA:
209 if (ioctl(fd, B_EJECT_DEVICE, NULL, 0) < 0) {
210 perror(device);
211 close(fd);
212 return 1;
214 break;
215 case B_DEV_DOOR_OPEN:
216 if (ioctl(fd, B_LOAD_MEDIA, NULL, 0) < 0) {
217 perror(device);
218 close(fd);
219 return 1;
221 break;
222 default:
223 perror(device);
225 break;
226 case 'h':
227 default:
228 close(fd);
229 return usage("eject");
231 close(fd);
232 return 0;