xref: /haiku/src/tests/add-ons/kernel/partitioning_systems/PartitioningSystemsTest.cpp (revision 3af8011358bd4c624a0979336d48dabb466171ed)
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