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