2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
15 #include <DiskDevice.h>
16 #include <DiskDeviceRoster.h>
20 extern const char* __progname
;
21 const char* kCommandName
= __progname
;
24 static const char* kUsage
=
25 "Usage: %s register <file>\n"
26 " %s unregister ( <file> | <device path> | <device ID> )\n"
28 "Registers a regular file as disk device, unregisters an already "
30 "one, or lists all file disk devices.\n"
33 " -h, --help - Print this usage info.\n"
38 print_usage_and_exit(bool error
)
40 fprintf(error
? stderr
: stdout
, kUsage
, kCommandName
, kCommandName
,
47 list_file_disk_devices()
49 printf(" ID File Device\n");
50 printf("------------------------------------------------------------------"
53 BDiskDeviceRoster roster
;
55 while (roster
.GetNextDevice(&device
) == B_OK
) {
60 printf("%6" B_PRId32
" ", device
.ID());
65 device
.GetFilePath(&path
) == B_OK
? path
.Path() : "???");
68 printf("%s", device
.GetPath(&path
) == B_OK
? path
.Path() : "???");
77 register_file_disk_device(const char* fileName
)
79 // stat() the file to verify that it's a regular file
81 if (lstat(fileName
, &st
) != 0) {
82 status_t error
= errno
;
83 fprintf(stderr
, "Error: Failed to stat() \"%s\": %s\n", fileName
,
88 if (!S_ISREG(st
.st_mode
)) {
89 fprintf(stderr
, "Error: \"%s\" is not a regular file.\n", fileName
);
94 BDiskDeviceRoster roster
;
95 partition_id id
= roster
.RegisterFileDevice(fileName
);
97 fprintf(stderr
, "Error: Failed to register file disk device: %s\n",
102 // print the success message (get the device path)
105 if (roster
.GetDeviceWithID(id
, &device
) == B_OK
106 && device
.GetPath(&path
) == B_OK
) {
107 printf("Registered file as disk device \"%s\" with ID %" B_PRId32
".\n",
110 printf("Registered file as disk device with ID %" B_PRId32
", "
111 "but failed to get the device path.\n", id
);
119 unregister_file_disk_device(const char* fileNameOrID
)
121 // try to parse the parameter as ID
123 partition_id id
= strtol(fileNameOrID
, &numberEnd
, 0);
124 BDiskDeviceRoster roster
;
125 if (id
>= 0 && numberEnd
!= fileNameOrID
&& *numberEnd
== '\0') {
127 if (roster
.GetDeviceWithID(id
, &device
) == B_OK
&& device
.IsFile()) {
128 status_t error
= roster
.UnregisterFileDevice(id
);
130 fprintf(stderr
, "Error: Failed to unregister file disk device "
131 "with ID %" B_PRId32
": %s\n", id
, strerror(error
));
135 printf("Unregistered file disk device with ID %" B_PRId32
".\n",
139 fprintf(stderr
, "No file disk device with ID %" B_PRId32
","
140 "trying file \"%s\"\n", id
, fileNameOrID
);
144 // the parameter must be a file name -- stat() it
146 if (lstat(fileNameOrID
, &st
) != 0) {
147 status_t error
= errno
;
148 fprintf(stderr
, "Error: Failed to stat() \"%s\": %s\n", fileNameOrID
,
153 // remember the volume and node ID, so we can identify the file
154 // NOTE: There's a race condition -- we would need to open the file and
155 // keep it open to avoid it.
156 dev_t volumeID
= st
.st_dev
;
157 ino_t nodeID
= st
.st_ino
;
159 // iterate through all file disk devices and try to find a match
161 while (roster
.GetNextDevice(&device
) == B_OK
) {
162 if (!device
.IsFile())
165 // get file path and stat it, same for the device path
167 bool isFilePath
= true;
168 if ((device
.GetFilePath(&path
) == B_OK
&& lstat(path
.Path(), &st
) == 0
169 && volumeID
== st
.st_dev
&& nodeID
== st
.st_ino
)
170 || (isFilePath
= false, false)
171 || (device
.GetPath(&path
) == B_OK
&& lstat(path
.Path(), &st
) == 0
172 && volumeID
== st
.st_dev
&& nodeID
== st
.st_ino
)) {
173 status_t error
= roster
.UnregisterFileDevice(device
.ID());
175 fprintf(stderr
, "Error: Failed to unregister file disk device"
176 "%s \"%s\" (ID: %" B_PRId32
"): %s\n",
177 isFilePath
? " for file" : "", fileNameOrID
, device
.ID(),
182 printf("Unregistered file disk device%s \"%s\" "
183 "(ID: %" B_PRId32
")\n", isFilePath
? " for file" : "",
184 fileNameOrID
, device
.ID());
190 fprintf(stderr
, "Error: \"%s\" does not refer to a file disk device.\n",
197 main(int argc
, const char* const* argv
)
200 static struct option sLongOptions
[] = {
201 { "help", no_argument
, 0, 'h' },
205 opterr
= 0; // don't print errors
206 int c
= getopt_long(argc
, (char**)argv
, "+h", sLongOptions
, NULL
);
212 print_usage_and_exit(false);
216 print_usage_and_exit(true);
221 // Of the remaining arguments the next one should be the command.
223 print_usage_and_exit(true);
225 status_t error
= B_OK
;
226 const char* command
= argv
[optind
++];
228 if (strcmp(command
, "list") == 0) {
230 print_usage_and_exit(true);
232 list_file_disk_devices();
233 } else if (strcmp(command
, "register") == 0) {
234 if (optind
+ 1 != argc
)
235 print_usage_and_exit(true);
237 const char* fileName
= argv
[optind
++];
238 register_file_disk_device(fileName
);
239 } else if (strcmp(command
, "unregister") == 0) {
240 if (optind
+ 1 != argc
)
241 print_usage_and_exit(true);
243 const char* fileName
= argv
[optind
++];
244 unregister_file_disk_device(fileName
);
246 print_usage_and_exit(true);
248 return error
== B_OK
? 0 : 1;