xref: /haiku/src/tests/kits/storage/disk_device/DiskDeviceTest.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 //----------------------------------------------------------------------
2 //  This software is part of the Haiku distribution and is covered
3 //  by the MIT License.
4 //---------------------------------------------------------------------
5 
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include <Application.h>
10 #include <DiskDevice.h>
11 #include <DiskDeviceJob.h>
12 //#include <DiskDeviceList.h>
13 #include <DiskDeviceRoster.h>
14 #include <DiskDeviceVisitor.h>
15 #include <DiskSystem.h>
16 #include <KDiskDeviceManager.h>	// for userland testing only
17 #include <Message.h>
18 #include <Messenger.h>
19 #include <Partition.h>
20 #include <Path.h>
21 //#include <ObjectList.h>
22 #include <OS.h>
23 
24 const char *kTestFileDevice = "/boot/home/tmp/test-file-device";
25 
26 // DumpVisitor
27 class DumpVisitor : public BDiskDeviceVisitor {
28 public:
29 	virtual bool Visit(BDiskDevice *device)
30 	{
31 		BPath path;
32 		status_t error = device->GetPath(&path);
33 		const char *pathString = NULL;
34 		if (error == B_OK)
35 			pathString = path.Path();
36 		else
37 			pathString = strerror(error);
38 		printf("device %ld: `%s'\n", device->ID(), pathString);
39 		printf("  has media:      %d\n", device->HasMedia());
40 		printf("  removable:      %d\n", device->IsRemovableMedia());
41 		printf("  read only:      %d\n", device->IsReadOnlyMedia());
42 		printf("  write once:     %d\n", device->IsWriteOnceMedia());
43 		printf("  ---\n");
44 		Visit(device, 0);
45 		return false;
46 	}
47 
48 	virtual bool Visit(BPartition *partition, int32 level)
49 	{
50 		char prefix[128];
51 		sprintf(prefix, "%*s", 2 * (int)level, "");
52 		if (level > 0) {
53 			BPath path;
54 			status_t error = partition->GetPath(&path);
55 			const char *pathString = NULL;
56 			if (error == B_OK)
57 				pathString = path.Path();
58 			else
59 				pathString = strerror(error);
60 			printf("%spartition %ld: `%s'\n", prefix, partition->ID(),
61 				   pathString);
62 		}
63 		printf("%s  offset:         %lld\n", prefix, partition->Offset());
64 		printf("%s  size:           %lld\n", prefix, partition->Size());
65 		printf("%s  block size:     %lu\n", prefix, partition->BlockSize());
66 		printf("%s  index:          %ld\n", prefix, partition->Index());
67 		printf("%s  status:         %lu\n", prefix, partition->Status());
68 		printf("%s  file system:    %d\n", prefix,
69 			   partition->ContainsFileSystem());
70 		printf("%s  part. system:   %d\n", prefix,
71 			   partition->ContainsPartitioningSystem());
72 		printf("%s  device:         %d\n", prefix, partition->IsDevice());
73 		printf("%s  read only:      %d\n", prefix, partition->IsReadOnly());
74 		printf("%s  mounted:        %d\n", prefix, partition->IsMounted());
75 		printf("%s  flags:          %lx\n", prefix, partition->Flags());
76 		printf("%s  name:           `%s'\n", prefix, partition->Name());
77 		printf("%s  content name:   `%s'\n", prefix, partition->ContentName());
78 		printf("%s  type:           `%s'\n", prefix, partition->Type());
79 		printf("%s  content type:   `%s'\n", prefix, partition->ContentType());
80 		// volume, icon,...
81 		return false;
82 	}
83 };
84 
85 /*
86 // print_time
87 void
88 print_time(const char *format, bigtime_t &time)
89 {
90 	bigtime_t lastTime = time;
91 	time = system_time();
92 	printf("%lld: %s took: %lld us\n", time, format, time - lastTime);
93 }
94 
95 // TestApp
96 class TestApp : public BApplication {
97 public:
98 	TestApp(const char *signature)
99 		: BApplication(signature),
100 		  fDevices(20, true)
101 	{
102 		BDiskDeviceRoster roster;
103 		bool done = false;
104 		do {
105 			BDiskDevice *device = new BDiskDevice;
106 			done = (roster.GetNextDevice(device) != B_OK);
107 			if (done)
108 				delete device;
109 			else
110 				fDevices.AddItem(device);
111 		} while (!done);
112 	}
113 
114 	~TestApp()
115 	{
116 		for (int32 i = 0; BDiskDevice *device = fDevices.ItemAt(i); i++) {
117 			status_t error = device->Eject(true);
118 			printf("eject device `%s': %s\n", device->Path(), strerror(error));
119 		}
120 	}
121 
122 	virtual void MessageReceived(BMessage *message)
123 	{
124 printf("TestApp::MessageReceived(%.4s)\n", (char*)&message->what);
125 		switch (message->what) {
126 			case B_DEVICE_UPDATE:
127 			{
128 				uint32 event;
129 				if (message->FindInt32("event", (int32*)&event) == B_OK) {
130 					switch (event) {
131 						case B_DEVICE_MOUNT_POINT_MOVED:
132 							MountPointMoved(message);
133 							break;
134 						case B_DEVICE_PARTITION_MOUNTED:
135 							PartitionMounted(message);
136 							break;
137 						case B_DEVICE_PARTITION_UNMOUNTED:
138 							PartitionUnmounted(message);
139 							break;
140 						case B_DEVICE_PARTITION_CHANGED:
141 							PartitionChanged(message);
142 							break;
143 						case B_DEVICE_PARTITION_ADDED:
144 							PartitionAdded(message);
145 							break;
146 						case B_DEVICE_PARTITION_REMOVED:
147 							PartitionRemoved(message);
148 							break;
149 						case B_DEVICE_SESSION_ADDED:
150 							SessionAdded(message);
151 							break;
152 						case B_DEVICE_SESSION_REMOVED:
153 							SessionRemoved(message);
154 							break;
155 						case B_DEVICE_MEDIA_CHANGED:
156 							MediaChanged(message);
157 							break;
158 						case B_DEVICE_ADDED:
159 							DeviceAdded(message);
160 							break;
161 						case B_DEVICE_REMOVED:
162 							DeviceRemoved(message);
163 							break;
164 						default:
165 							printf("unhandled event\n");
166 							message->PrintToStream();
167 							break;
168 					}
169 				}
170 				break;
171 			}
172 			default:
173 				BApplication::MessageReceived(message);
174 				break;
175 		}
176 	}
177 
178 
179 	void MountPointMoved(BMessage *message)
180 	{
181 		printf("TestApp::MountPointMoved()\n");
182 		PrintPartitionInfo(message);
183 		entry_ref oldRoot, newRoot;
184 		BPath oldPath, newPath;
185 		if (message->FindRef("old_directory", &oldRoot) == B_OK
186 			&& message->FindRef("new_directory", &newRoot) == B_OK
187 			&& oldPath.SetTo(&oldRoot) == B_OK
188 			&& newPath.SetTo(&newRoot) == B_OK) {
189 			printf("old mount point: `%s'\n", oldPath.Path());
190 			printf("new mount point: `%s'\n", newPath.Path());
191 		}
192 
193 	}
194 
195 	void PartitionMounted(BMessage *message)
196 	{
197 		printf("TestApp::PartitionMounted()\n");
198 		PrintPartitionInfo(message);
199 	}
200 
201 	void PartitionUnmounted(BMessage *message)
202 	{
203 		printf("TestApp::PartitionUnmounted()\n");
204 		PrintPartitionInfo(message);
205 	}
206 
207 	// PartitionChanged
208 	void PartitionChanged(BMessage *message)
209 	{
210 		printf("TestApp::PartitionUnmounted()\n");
211 		PrintPartitionInfo(message);
212 	}
213 
214 	// PartitionAdded
215 	void PartitionAdded(BMessage *message)
216 	{
217 		printf("TestApp::PartitionAdded()\n");
218 		PrintPartitionInfo(message);
219 	}
220 
221 	// PartitionRemoved
222 	void PartitionRemoved(BMessage *message)
223 	{
224 		printf("TestApp::PartitionRemoved()\n");
225 		PrintPartitionInfo(message);
226 	}
227 
228 	// SessionAdded
229 	void SessionAdded(BMessage *message)
230 	{
231 		printf("TestApp::SessionAdded()\n");
232 		PrintSessionInfo(message);
233 	}
234 
235 	// SessionRemoved
236 	void SessionRemoved(BMessage *message)
237 	{
238 		printf("TestApp::SessionRemoved()\n");
239 		PrintSessionInfo(message);
240 	}
241 
242 	// MediaChanged
243 	void MediaChanged(BMessage *message)
244 	{
245 		printf("TestApp::MediaChanged()\n");
246 		PrintDeviceInfo(message);
247 		int32 id;
248 		if (message->FindInt32("device_id", &id) == B_OK) {
249 			for (int32 i = 0; BDiskDevice *device = fDevices.ItemAt(i); i++) {
250 				if (device->ID() == id) {
251 					bool updated;
252 					status_t error = device->Update(&updated);
253 					printf("updated: %d\n", updated);
254 					if (error == B_OK) {
255 						DumpVisitor visitor;
256 						device->Traverse(&visitor);
257 					} else {
258 						printf("device->Update() failed: %s\n",
259 							   strerror(error));
260 					}
261 					break;
262 				}
263 			}
264 		}
265 	}
266 
267 	// DeviceAdded
268 	void DeviceAdded(BMessage *message)
269 	{
270 		printf("TestApp::DeviceAdded()\n");
271 		PrintDeviceInfo(message);
272 	}
273 
274 	// DeviceRemoved
275 	void DeviceRemoved(BMessage *message)
276 	{
277 		printf("TestApp::DeviceRemoved()\n");
278 		PrintDeviceInfo(message);
279 	}
280 
281 	// PrintPartitionInfo
282 	void PrintPartitionInfo(BMessage *message)
283 	{
284 		int32 deviceID;
285 		int32 sessionID;
286 		int32 partitionID;
287 		if (message->FindInt32("device_id", &deviceID) == B_OK
288 			&& message->FindInt32("session_id", &sessionID) == B_OK
289 			&& message->FindInt32("partition_id", &partitionID) == B_OK) {
290 			BDiskDeviceRoster roster;
291 			BDiskDevice device;
292 			BPartition *partition;
293 			if (roster.GetPartitionWithID(partitionID, &device, &partition)
294 				== B_OK) {
295 				DumpVisitor().Visit(partition);
296 			}
297 		}
298 	}
299 
300 	// PrintSessionInfo
301 	void PrintSessionInfo(BMessage *message)
302 	{
303 		int32 deviceID;
304 		int32 sessionID;
305 		if (message->FindInt32("device_id", &deviceID) == B_OK
306 			&& message->FindInt32("session_id", &sessionID) == B_OK) {
307 			BDiskDeviceRoster roster;
308 			BDiskDevice device;
309 			BSession *session;
310 			if (roster.GetSessionWithID(sessionID, &device, &session)
311 				== B_OK) {
312 				DumpVisitor().Visit(session);
313 			}
314 		}
315 	}
316 
317 	// PrintDeviceInfo
318 	void PrintDeviceInfo(BMessage *message)
319 	{
320 		int32 deviceID;
321 		if (message->FindInt32("device_id", &deviceID) == B_OK) {
322 			BDiskDeviceRoster roster;
323 			BDiskDevice device;
324 			if (roster.GetDeviceWithID(deviceID, &device) == B_OK)
325 				DumpVisitor().Visit(&device);
326 		}
327 	}
328 
329 private:
330 	BObjectList<BDiskDevice>	fDevices;
331 };
332 
333 class MyDeviceList : public BDiskDeviceList {
334 public:
335 	MyDeviceList(bool useOwnLocker)
336 		: BDiskDeviceList(useOwnLocker)
337 	{
338 	}
339 
340 	virtual void MountPointMoved(BPartition *partition)
341 	{
342 		printf("MountPointMoved()\n");
343 		DumpVisitor().Visit(partition);
344 	}
345 
346 	virtual void PartitionMounted(BPartition *partition)
347 	{
348 		printf("PartitionMounted()\n");
349 		DumpVisitor().Visit(partition);
350 	}
351 
352 	virtual void PartitionUnmounted(BPartition *partition)
353 	{
354 		printf("PartitionUnmounted()\n");
355 		DumpVisitor().Visit(partition);
356 	}
357 
358 	virtual void PartitionChanged(BPartition *partition)
359 	{
360 		printf("PartitionChanged()\n");
361 		DumpVisitor().Visit(partition);
362 	}
363 
364 	virtual void PartitionAdded(BPartition *partition)
365 	{
366 		printf("PartitionAdded()\n");
367 		DumpVisitor().Visit(partition);
368 	}
369 
370 	virtual void PartitionRemoved(BPartition *partition)
371 	{
372 		printf("PartitionRemoved()\n");
373 		DumpVisitor().Visit(partition);
374 	}
375 
376 	virtual void SessionAdded(BSession *session)
377 	{
378 		printf("SessionAdded()\n");
379 		DumpVisitor().Visit(session);
380 	}
381 
382 	virtual void SessionRemoved(BSession *session)
383 	{
384 		printf("SessionRemoved()\n");
385 		DumpVisitor().Visit(session);
386 	}
387 
388 	virtual void MediaChanged(BDiskDevice *device)
389 	{
390 		printf("MediaChanged()\n");
391 		DumpVisitor().Visit(device);
392 	}
393 
394 	virtual void DeviceAdded(BDiskDevice *device)
395 	{
396 		printf("DeviceAdded()\n");
397 		DumpVisitor().Visit(device);
398 	}
399 
400 	virtual void DeviceRemoved(BDiskDevice *device)
401 	{
402 		printf("DeviceRemoved()\n");
403 		DumpVisitor().Visit(device);
404 	}
405 };
406 
407 
408 // TestApp2
409 class TestApp2 : public BApplication {
410 public:
411 	TestApp2(const char *signature)
412 		: BApplication(signature),
413 		  fDeviceList(false)
414 	{
415 		printf("dumping empty list...\n");
416 		DumpVisitor visitor;
417 		fDeviceList.Traverse(&visitor);
418 		printf("dumping done\n");
419 		printf("fetching\n");
420 		status_t error = fDeviceList.Fetch();
421 		if (error == B_OK)
422 			fDeviceList.Traverse(&visitor);
423 		else
424 			printf("fetching failed: %s\n", strerror(error));
425 		printf("unset\n");
426 		fDeviceList.Unset();
427 		printf("dumping empty list...\n");
428 		fDeviceList.Traverse(&visitor);
429 		printf("dumping done\n");
430 		AddHandler(&fDeviceList);
431 		error = fDeviceList.Fetch();
432 		if (error != B_OK)
433 			printf("fetching failed: %s\n", strerror(error));
434 	}
435 
436 	~TestApp2()
437 	{
438 		Lock();
439 		RemoveHandler(&fDeviceList);
440 		Unlock();
441 	}
442 
443 	virtual void ReadyToRun()
444 	{
445 		// list the available partition add-ons
446 		BDiskDeviceRoster roster;
447 		char shortName[B_FILE_NAME_LENGTH];
448 		char longName[B_FILE_NAME_LENGTH];
449 		printf("partition add-ons:\n");
450 		while (roster.GetNextPartitioningSystem(shortName, longName) == B_OK) {
451 			printf("  `%s' (`%s')\n", shortName, longName);
452 		}
453 		fDeviceList.Lock();
454 		for (int32 i = 0; BDiskDevice *device = fDeviceList.DeviceAt(i); i++) {
455 printf("device: `%s'\n", device->Path());
456 			if (!strcmp(device->Path(), "/dev/disk/virtual/0/raw")) {
457 				if (BSession *session = device->SessionAt(0)) {
458 					BString parameters;
459 					bool cancelled = false;
460 					status_t error = session->GetPartitioningParameters(
461 						"intel", &parameters, BRect(), &cancelled);
462 					if (error == B_OK) {
463 						printf("partitioning parameters: `%s'\n",
464 							   parameters.String());
465 					} else if (error == B_ERROR && cancelled) {
466 						printf("partitioning dialog cancelled\n");
467 					} else {
468 						printf("error getting partitioning parameters: %s\n",
469 							   strerror(error));
470 					}
471 				}
472 				break;
473 			}
474 		}
475 		fDeviceList.Unlock();
476 	}
477 
478 private:
479 	MyDeviceList	fDeviceList;
480 };
481 */
482 
483 // wait_for_jobs
484 void
485 wait_for_jobs()
486 {
487 	BDiskDeviceRoster roster;
488 	bool activeJobs = false;
489 	do {
490 		if (activeJobs)
491 			snooze(50000);
492 		activeJobs = false;
493 		printf("disk device jobs at time %lld\n", system_time());
494 		roster.RewindActiveJobs();
495 		BDiskDeviceJob job;
496 		while (roster.GetNextActiveJob(&job) == B_OK) {
497 			activeJobs = true;
498 			printf("  job %ld:\n", job.ID());
499 			printf("    type:        %lu\n", job.Type());
500 			printf("    description: `%s'\n", job.Description());
501 			printf("    partition:   %ld\n", job.PartitionID());
502 			printf("    status:      %lu\n", job.Status());
503 			printf("    progress:    %f\n", job.Progress());
504 		}
505 		if (!activeJobs)
506 			printf("  none\n");
507 	} while (activeJobs);
508 }
509 
510 // main
511 int
512 main()
513 {
514 /*
515 	TestApp app("application/x-vnd.obos-disk-device-test");
516 	BDiskDeviceRoster roster;
517 	DumpVisitor visitor;
518 	roster.Traverse(&visitor);
519 	status_t error = B_OK;
520 	error = roster.StartWatching(BMessenger(&app));
521 	if (error != B_OK)
522 		printf("start watching failed: %s\n", strerror(error));
523 	if (error == B_OK)
524 		app.Run();
525 	error = roster.StopWatching(BMessenger(&app));
526 	if (error != B_OK)
527 		printf("stop watching failed: %s\n", strerror(error));
528 */
529 /*
530 	TestApp2 app("application/x-vnd.obos-disk-device-test");
531 	app.Run();
532 	return 0;
533 */
534 
535 	// for userland testing only
536 	KDiskDeviceManager::CreateDefault();
537 	KDiskDeviceManager::Default()->InitialDeviceScan();
538 
539 	// wait till all (scan) jobs are done
540 	wait_for_jobs();
541 	// add a file device
542 	BDiskDeviceRoster roster;
543 	partition_id id = roster.RegisterFileDevice(kTestFileDevice);
544 	if (id < B_OK)
545 		printf("registering the file device failed: %s\n", strerror(id));
546 	else {
547 		// wait till all (scan) jobs are done
548 		wait_for_jobs();
549 	}
550 	// list all disk devices and partitions
551 	DumpVisitor visitor;
552 	roster.VisitEachPartition(&visitor);
553 	// list disk systems
554 	BDiskSystem diskSystem;
555 	while (roster.GetNextDiskSystem(&diskSystem) == B_OK) {
556 		printf("disk system:\n");
557 		printf("  name:        `%s'\n", diskSystem.Name());
558 		printf("  pretty name: `%s'\n", diskSystem.PrettyName());
559 		printf("  file system: %d (!%d)\n", diskSystem.IsFileSystem(),
560 			   diskSystem.IsPartitioningSystem());
561 		// flags
562 		printf("  flags:\n");
563 		bool mounted = false;
564 		bool supports = diskSystem.SupportsDefragmenting(&mounted);
565 		printf("    defragmenting:          %d (%d)\n", supports, mounted);
566 		supports = diskSystem.SupportsRepairing(true, &mounted);
567 		printf("    checking:               %d (%d)\n", supports, mounted);
568 		supports = diskSystem.SupportsRepairing(false, &mounted);
569 		printf("    repairing:              %d (%d)\n", supports, mounted);
570 		supports = diskSystem.SupportsResizing(&mounted);
571 		printf("    resizing:               %d (%d)\n", supports, mounted);
572 		supports = diskSystem.SupportsResizingChild();
573 		printf("    resizing child:         %d\n", supports);
574 		supports = diskSystem.SupportsMoving(&mounted);
575 		printf("    moving:                 %d (%d)\n", supports, mounted);
576 		supports = diskSystem.SupportsMovingChild();
577 		printf("    moving child:           %d\n", supports);
578 		supports = diskSystem.SupportsSettingName();
579 		printf("    setting name:           %d\n", supports);
580 		supports = diskSystem.SupportsSettingContentName(&mounted);
581 		printf("    setting content name:   %d (%d)\n", supports, mounted);
582 		supports = diskSystem.SupportsSettingType();
583 		printf("    setting type:           %d\n", supports);
584 		supports = diskSystem.SupportsSettingParameters();
585 		printf("    setting params:         %d\n", supports);
586 		supports = diskSystem.SupportsSettingContentParameters(&mounted);
587 		printf("    setting content params: %d (%d)\n", supports, mounted);
588 		supports = diskSystem.SupportsCreatingChild();
589 		printf("    creating child:         %d\n", supports);
590 		supports = diskSystem.SupportsDeletingChild();
591 		printf("    deleting child:         %d\n", supports);
592 		supports = diskSystem.SupportsInitializing();
593 		printf("    initializing:           %d\n", supports);
594 	}
595 	// get the file device
596 	BDiskDevice device;
597 	status_t error = roster.GetDeviceWithID(id, &device);
598 	if (error != B_OK)
599 		printf("Couldn't get device: %s\n", strerror(error));
600 	// prepare for modifications
601 	error = device.PrepareModifications();
602 	if (error != B_OK)
603 		printf("Preparing modifications failed: %s\n", strerror(error));
604 	// test resize a partition
605 	if (error == B_OK) {
606 		if (BPartition *partition = device.ChildAt(1)) {
607 			// uninitialize contents
608 			status_t status = partition->Uninitialize();
609 			if (status != B_OK) {
610 				printf("Uninitializing the partition failed: %s\n",
611 					   strerror(status));
612 			}
613 			// resize
614 			status = partition->Resize(1024 * 200);
615 			if (status != B_OK) {
616 				printf("Resizing the partition failed: %s\n",
617 					   strerror(status));
618 			}
619 		}
620 		printf("\nDevice after changing it:\n");
621 		device.VisitEachDescendant(&visitor);
622 	}
623 	// cancel modifications
624 /*	if (error == B_OK) {
625 		error = device.CancelModifications();
626 		if (error != B_OK)
627 			printf("Cancelling modifications failed: %s\n", strerror(error));
628 	}
629 */	// commit modifications
630 	if (error == B_OK) {
631 		error = device.CommitModifications();
632 		if (error != B_OK)
633 			printf("Committing modifications failed: %s\n", strerror(error));
634 	}
635 	wait_for_jobs();
636 //	printf("\nDevice after cancelling the changes:\n");
637 	printf("\nDevice after committing the changes:\n");
638 	device.VisitEachDescendant(&visitor);
639 
640 	// for userland testing only
641 	KDiskDeviceManager::DeleteDefault();
642 }
643 
644