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