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 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 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 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 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* 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 187 write_unlock_disk_device(partition_id partitionID) 188 { 189 } 190 191 192 disk_device_data* 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 201 read_unlock_disk_device(partition_id partitionID) 202 { 203 } 204 205 206 disk_device_data* 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* 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* 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* 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 256 open_partition(partition_id partitionID, int openMode) 257 { 258 return -1; 259 } 260 261 262 partition_data* 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 290 delete_partition(partition_id partitionID) 291 { 292 // TODO 293 return false; 294 } 295 296 297 void 298 partition_modified(partition_id partitionID) 299 { 300 // TODO: implemented 301 } 302 303 304 status_t 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 334 update_disk_device_job_progress(disk_job_id jobID, float progress) 335 { 336 return false; 337 } 338 339 340 bool 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 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 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