btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / bin / diskimage.cpp
blob85033d091f91958822e04f18896d8e39326da47f
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <errno.h>
8 #include <getopt.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
15 #include <DiskDevice.h>
16 #include <DiskDeviceRoster.h>
17 #include <Path.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"
27 " %s list\n"
28 "Registers a regular file as disk device, unregisters an already "
29 "registered\n"
30 "one, or lists all file disk devices.\n"
31 "\n"
32 "Options:\n"
33 " -h, --help - Print this usage info.\n"
37 static void
38 print_usage_and_exit(bool error)
40 fprintf(error ? stderr : stdout, kUsage, kCommandName, kCommandName,
41 kCommandName);
42 exit(error ? 1 : 0);
46 static status_t
47 list_file_disk_devices()
49 printf(" ID File Device\n");
50 printf("------------------------------------------------------------------"
51 "-------------\n");
53 BDiskDeviceRoster roster;
54 BDiskDevice device;
55 while (roster.GetNextDevice(&device) == B_OK) {
56 if (!device.IsFile())
57 continue;
59 // ID
60 printf("%6" B_PRId32 " ", device.ID());
62 // file path
63 BPath path;
64 printf("%-35s",
65 device.GetFilePath(&path) == B_OK ? path.Path() : "???");
67 // device path
68 printf("%s", device.GetPath(&path) == B_OK ? path.Path() : "???");
69 printf("\n");
72 return B_OK;
76 static status_t
77 register_file_disk_device(const char* fileName)
79 // stat() the file to verify that it's a regular file
80 struct stat st;
81 if (lstat(fileName, &st) != 0) {
82 status_t error = errno;
83 fprintf(stderr, "Error: Failed to stat() \"%s\": %s\n", fileName,
84 strerror(error));
85 return error;
88 if (!S_ISREG(st.st_mode)) {
89 fprintf(stderr, "Error: \"%s\" is not a regular file.\n", fileName);
90 return B_BAD_VALUE;
93 // register the file
94 BDiskDeviceRoster roster;
95 partition_id id = roster.RegisterFileDevice(fileName);
96 if (id < 0) {
97 fprintf(stderr, "Error: Failed to register file disk device: %s\n",
98 strerror(id));
99 return id;
102 // print the success message (get the device path)
103 BDiskDevice device;
104 BPath 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",
108 path.Path(), id);
109 } else {
110 printf("Registered file as disk device with ID %" B_PRId32 ", "
111 "but failed to get the device path.\n", id);
114 return B_OK;
118 static status_t
119 unregister_file_disk_device(const char* fileNameOrID)
121 // try to parse the parameter as ID
122 char* numberEnd;
123 partition_id id = strtol(fileNameOrID, &numberEnd, 0);
124 BDiskDeviceRoster roster;
125 if (id >= 0 && numberEnd != fileNameOrID && *numberEnd == '\0') {
126 BDiskDevice device;
127 if (roster.GetDeviceWithID(id, &device) == B_OK && device.IsFile()) {
128 status_t error = roster.UnregisterFileDevice(id);
129 if (error != B_OK) {
130 fprintf(stderr, "Error: Failed to unregister file disk device "
131 "with ID %" B_PRId32 ": %s\n", id, strerror(error));
132 return error;
135 printf("Unregistered file disk device with ID %" B_PRId32 ".\n",
136 id);
137 return B_OK;
138 } else {
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
145 struct stat st;
146 if (lstat(fileNameOrID, &st) != 0) {
147 status_t error = errno;
148 fprintf(stderr, "Error: Failed to stat() \"%s\": %s\n", fileNameOrID,
149 strerror(error));
150 return error;
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
160 BDiskDevice device;
161 while (roster.GetNextDevice(&device) == B_OK) {
162 if (!device.IsFile())
163 continue;
165 // get file path and stat it, same for the device path
166 BPath 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());
174 if (error != B_OK) {
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(),
178 strerror(error));
179 return error;
182 printf("Unregistered file disk device%s \"%s\" "
183 "(ID: %" B_PRId32 ")\n", isFilePath ? " for file" : "",
184 fileNameOrID, device.ID());
186 return B_OK;
190 fprintf(stderr, "Error: \"%s\" does not refer to a file disk device.\n",
191 fileNameOrID);
192 return B_BAD_VALUE;
197 main(int argc, const char* const* argv)
199 while (true) {
200 static struct option sLongOptions[] = {
201 { "help", no_argument, 0, 'h' },
202 { 0, 0, 0, 0 }
205 opterr = 0; // don't print errors
206 int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
207 if (c == -1)
208 break;
210 switch (c) {
211 case 'h':
212 print_usage_and_exit(false);
213 break;
215 default:
216 print_usage_and_exit(true);
217 break;
221 // Of the remaining arguments the next one should be the command.
222 if (optind >= argc)
223 print_usage_and_exit(true);
225 status_t error = B_OK;
226 const char* command = argv[optind++];
228 if (strcmp(command, "list") == 0) {
229 if (optind < argc)
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);
245 } else
246 print_usage_and_exit(true);
248 return error == B_OK ? 0 : 1;