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
24const char *kTestFileDevice = "/boot/home/tmp/test-file-device";
25
26// DumpVisitor
27class DumpVisitor : public BDiskDeviceVisitor {
28public:
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
87void
88print_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
96class TestApp : public BApplication {
97public:
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	{
124printf("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
329private:
330	BObjectList<BDiskDevice>	fDevices;
331};
332
333class MyDeviceList : public BDiskDeviceList {
334public:
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
409class TestApp2 : public BApplication {
410public:
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++) {
455printf("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
478private:
479	MyDeviceList	fDeviceList;
480};
481*/
482
483// wait_for_jobs
484void
485wait_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
511int
512main()
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