1 /*
2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <limits.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <map>
16 #include <vector>
17
18 #include <module.h>
19
20 #include <disk_device_manager/ddm_modules.h>
21 #include <disk_device_manager.h>
22
23
24 struct partition_entry;
25 typedef std::vector<partition_entry*> PartitionVector;
26
27 struct partition_entry : partition_data {
28 partition_entry* parent;
29 PartitionVector children;
30 char path[PATH_MAX];
31 };
32
33 typedef std::map<partition_id, partition_entry*> PartitionMap;
34 typedef std::map<partition_id, disk_device_data*> DiskDeviceMap;
35
36
37 static PartitionMap sPartitions;
38 static DiskDeviceMap sDiskDevices;
39 static partition_id sNextID = 1;
40
41
42 static status_t
create_disk_device(int fd,const char * path,partition_id * _id)43 create_disk_device(int fd, const char* path, partition_id* _id)
44 {
45 partition_entry* partition = new partition_entry;
46 memset(partition, 0, sizeof(partition_entry));
47 partition->id = sNextID++;
48 strlcpy(partition->path, path, sizeof(partition->path));
49
50 disk_device_data* device = new disk_device_data;
51 device->id = partition->id;
52 device->path = partition->path;
53 device->flags = 0;
54
55 if (ioctl(fd, B_GET_GEOMETRY, &device->geometry) < 0) {
56 // maybe it's just a file
57 struct stat stat;
58 if (fstat(fd, &stat) < 0) {
59 delete partition;
60 delete device;
61 return errno;
62 }
63
64 uint32 blockSize = 512;
65 off_t blocks = stat.st_size / blockSize;
66 uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX;
67 if (heads == 0)
68 heads = 1;
69 device->geometry.bytes_per_sector = blockSize;
70 device->geometry.sectors_per_track = 1;
71 device->geometry.cylinder_count = blocks / heads;
72 device->geometry.head_count = heads;
73 device->geometry.device_type = B_DISK;
74 device->geometry.removable = false;
75 device->geometry.read_only = true;
76 device->geometry.write_once = false;
77 }
78
79 partition->offset = 0;
80 partition->size = 1LL * device->geometry.head_count
81 * device->geometry.cylinder_count * device->geometry.sectors_per_track
82 * device->geometry.bytes_per_sector;
83 partition->block_size = device->geometry.bytes_per_sector;
84
85 sDiskDevices.insert(std::make_pair(partition->id, device));
86 sPartitions.insert(std::make_pair(partition->id, partition));
87
88 if (_id != NULL)
89 *_id = partition->id;
90
91 return B_OK;
92 }
93
94
95 static void
print_disk_device(partition_id id)96 print_disk_device(partition_id id)
97 {
98 disk_device_data* data = get_disk_device(id);
99
100 printf("device ID %ld\n", id);
101 printf(" path %s\n", data->path);
102 printf(" geometry\n");
103 printf(" bytes per sector %lu\n", data->geometry.bytes_per_sector);
104 printf(" sectors per track %lu\n", data->geometry.sectors_per_track);
105 printf(" cylinder count %lu\n", data->geometry.cylinder_count);
106 printf(" head count %lu (size %lld bytes)\n",
107 data->geometry.head_count, 1LL * data->geometry.head_count
108 * data->geometry.cylinder_count * data->geometry.sectors_per_track
109 * data->geometry.bytes_per_sector);
110 printf(" device type %d\n", data->geometry.device_type);
111 printf(" removable %d\n", data->geometry.removable);
112 printf(" read only %d\n", data->geometry.read_only);
113 printf(" write once %d\n\n", data->geometry.write_once);
114 }
115
116
117 static void
print_partition(partition_id id)118 print_partition(partition_id id)
119 {
120 partition_data* data = get_partition(id);
121
122 printf("partition ID %ld\n", id);
123 printf(" offset %lld\n", data->offset);
124 printf(" size %lld\n", data->size);
125 printf(" content_size %lld\n", data->content_size);
126 printf(" block_size %lu\n", data->block_size);
127 printf(" child_count %ld\n", data->child_count);
128 printf(" index %ld\n", data->index);
129 printf(" status %#lx\n", data->status);
130 printf(" flags %#lx\n", data->flags);
131 printf(" name %s\n", data->name);
132 printf(" type %s\n", data->type);
133 printf(" content_name %s\n", data->content_name);
134 printf(" content_type %s\n", data->content_type);
135 printf(" parameters %s\n", data->parameters);
136 printf(" content_parameters %s\n", data->content_parameters);
137 }
138
139
140 status_t
scan_partition(int fd,partition_id partitionID)141 scan_partition(int fd, partition_id partitionID)
142 {
143 partition_data* data = get_partition(partitionID);
144
145 void* list = open_module_list("partitioning_systems");
146 char name[PATH_MAX];
147 size_t nameSize = sizeof(name);
148 while (read_next_module_name(list, name, &nameSize) == B_OK) {
149 partition_module_info* moduleInfo;
150 if (get_module(name, (module_info**)&moduleInfo) == B_OK
151 && moduleInfo->identify_partition != NULL) {
152 void* cookie;
153 float priority = moduleInfo->identify_partition(fd, data, &cookie);
154
155 printf("%s: %g\n", name, priority);
156
157 if (priority >= 0) {
158 // scan partitions
159 moduleInfo->scan_partition(fd, data, cookie);
160 moduleInfo->free_identify_partition_cookie(data, cookie);
161
162 free((char*)data->content_type);
163 data->content_type = strdup(moduleInfo->pretty_name);
164 }
165
166 put_module(name);
167 }
168 nameSize = sizeof(name);
169 }
170
171 return B_OK;
172 }
173
174
175 // #pragma mark - disk device manager API
176
177
178 disk_device_data*
write_lock_disk_device(partition_id partitionID)179 write_lock_disk_device(partition_id partitionID)
180 {
181 // TODO: we could check if the device is properly unlocked again
182 return get_disk_device(partitionID);
183 }
184
185
186 void
write_unlock_disk_device(partition_id partitionID)187 write_unlock_disk_device(partition_id partitionID)
188 {
189 }
190
191
192 disk_device_data*
read_lock_disk_device(partition_id partitionID)193 read_lock_disk_device(partition_id partitionID)
194 {
195 // TODO: we could check if the device is properly unlocked again
196 return get_disk_device(partitionID);
197 }
198
199
200 void
read_unlock_disk_device(partition_id partitionID)201 read_unlock_disk_device(partition_id partitionID)
202 {
203 }
204
205
206 disk_device_data*
get_disk_device(partition_id partitionID)207 get_disk_device(partition_id partitionID)
208 {
209 DiskDeviceMap::iterator found = sDiskDevices.find(partitionID);
210 if (found == sDiskDevices.end())
211 return NULL;
212
213 return found->second;
214 }
215
216
217 partition_data*
get_partition(partition_id partitionID)218 get_partition(partition_id partitionID)
219 {
220 PartitionMap::iterator found = sPartitions.find(partitionID);
221 if (found == sPartitions.end())
222 return NULL;
223
224 return found->second;
225 }
226
227
228 partition_data*
get_parent_partition(partition_id partitionID)229 get_parent_partition(partition_id partitionID)
230 {
231 PartitionMap::iterator found = sPartitions.find(partitionID);
232 if (found == sPartitions.end())
233 return NULL;
234
235 return found->second->parent;
236 }
237
238
239 partition_data*
get_child_partition(partition_id partitionID,int32 index)240 get_child_partition(partition_id partitionID, int32 index)
241 {
242 PartitionMap::iterator found = sPartitions.find(partitionID);
243 if (found == sPartitions.end())
244 return NULL;
245
246 partition_entry* partition = found->second;
247
248 if (index < 0 || index >= (int32)partition->children.size())
249 return NULL;
250
251 return partition->children[index];
252 }
253
254
255 int
open_partition(partition_id partitionID,int openMode)256 open_partition(partition_id partitionID, int openMode)
257 {
258 return -1;
259 }
260
261
262 partition_data*
create_child_partition(partition_id partitionID,int32 index,off_t offset,off_t size,partition_id childID)263 create_child_partition(partition_id partitionID, int32 index, off_t offset,
264 off_t size, partition_id childID)
265 {
266 PartitionMap::iterator found = sPartitions.find(partitionID);
267 if (found == sPartitions.end())
268 return NULL;
269
270 partition_entry* parent = found->second;
271
272 partition_entry* child = new partition_entry();
273 memset(child, 0, sizeof(partition_entry));
274
275 child->id = sNextID++;
276 child->offset = offset;
277 child->size = size;
278 child->index = parent->children.size();
279
280 parent->children.push_back(child);
281 parent->child_count++;
282 sPartitions.insert(std::make_pair(child->id, child));
283
284 printf(" new partition ID %ld (child of %ld)\n", child->id, parent->id);
285 return child;
286 }
287
288
289 bool
delete_partition(partition_id partitionID)290 delete_partition(partition_id partitionID)
291 {
292 // TODO
293 return false;
294 }
295
296
297 void
partition_modified(partition_id partitionID)298 partition_modified(partition_id partitionID)
299 {
300 // TODO: implemented
301 }
302
303
304 status_t
scan_partition(partition_id partitionID)305 scan_partition(partition_id partitionID)
306 {
307 PartitionMap::iterator found = sPartitions.find(partitionID);
308 if (found == sPartitions.end())
309 return B_ENTRY_NOT_FOUND;
310
311 if (sDiskDevices.find(partitionID) == sDiskDevices.end()) {
312 // TODO: we would need to fake child partitons
313 return B_NOT_SUPPORTED;
314 }
315
316 partition_entry* partition = found->second;
317 int fd = open(partition->path, O_RDONLY);
318 if (fd < 0)
319 return errno;
320
321 scan_partition(fd, partitionID);
322 void* list = open_module_list("partitioning_systems");
323 char name[PATH_MAX];
324 size_t nameSize = sizeof(name);
325 while (read_next_module_name(list, name, &nameSize) == B_OK) {
326 puts(name);
327 nameSize = sizeof(name);
328 }
329 return B_ERROR;
330 }
331
332
333 bool
update_disk_device_job_progress(disk_job_id jobID,float progress)334 update_disk_device_job_progress(disk_job_id jobID, float progress)
335 {
336 return false;
337 }
338
339
340 bool
set_disk_device_job_error_message(disk_job_id jobID,const char * message)341 set_disk_device_job_error_message(disk_job_id jobID, const char* message)
342 {
343 #if 0
344 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
345 if (ManagerLocker locker = manager) {
346 if (KDiskDeviceJob* job = manager->FindJob(jobID)) {
347 job->SetErrorMessage(message);
348 return true;
349 }
350 }
351 #endif
352 return false;
353 }
354
355
356 // #pragma mark -
357
358
359 static void
usage()360 usage()
361 {
362 extern const char* __progname;
363
364 fprintf(stderr, "usage: %s <device>\n"
365 "Must be started from the top-level Haiku directory to find its "
366 "add-ons.\n", __progname);
367 exit(1);
368 }
369
370
371 int
main(int argc,char ** argv)372 main(int argc, char** argv)
373 {
374 if (argc != 2)
375 usage();
376
377 const char* deviceName = argv[1];
378
379 int device = open(deviceName, O_RDONLY);
380 if (device < 0) {
381 fprintf(stderr, "Could not open device \"%s\": %s\n", deviceName,
382 strerror(errno));
383 return 1;
384 }
385
386 partition_id id;
387 status_t status = create_disk_device(device, deviceName, &id);
388 if (status != B_OK) {
389 fprintf(stderr, "Could not get device size \"%s\": %s\n", deviceName,
390 strerror(status));
391 return 1;
392 }
393
394 print_disk_device(id);
395 scan_partition(device, id);
396
397 PartitionMap::iterator iterator = sPartitions.begin();
398 for (; iterator != sPartitions.end(); iterator++) {
399 print_partition(iterator->first);
400 }
401
402 close(device);
403 return 0;
404 }
405
406