1/*
2 * Copyright 2008-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Marco Minutoli, mminutoli@gmail.com
7 *		Axel D��rfler, axeld@pinc-software.de
8 */
9
10#include "FsCreator.h"
11
12#include <iostream>
13
14#include <DiskSystem.h>
15
16
17class UnregisterFileDevice {
18public:
19	UnregisterFileDevice()
20		:
21		fID(-1)
22	{
23	}
24
25	~UnregisterFileDevice()
26	{
27		if (fID >= 0) {
28			BDiskDeviceRoster roster;
29			roster.UnregisterFileDevice(fID);
30		}
31	}
32
33	void SetTo(partition_id id)
34	{
35		fID = id;
36	}
37
38	void Detach()
39	{
40		fID = -1;
41	}
42
43private:
44	partition_id	fID;
45};
46
47
48extern "C" const char* __progname;
49static const char* kProgramName = __progname;
50
51
52FsCreator::FsCreator(const char* path, const char* type, const char* volumeName,
53		const char* fsOptions, bool quick, bool verbose)
54	:
55	fType(type),
56	fPath(path),
57	fVolumeName(volumeName),
58	fFsOptions(fsOptions),
59	fVerbose(verbose),
60	fQuick(quick)
61{
62}
63
64
65bool
66FsCreator::Run()
67{
68	UnregisterFileDevice unregisterFileDevice;
69
70	BDiskDeviceRoster roster;
71	BPartition* partition;
72	BDiskDevice device;
73
74	status_t status = roster.GetPartitionForPath(fPath, &device,
75		&partition);
76	if (status != B_OK) {
77		if (!strncmp(fPath, "/dev", 4)) {
78			std::cerr << kProgramName << ": Failed to get disk device for path "
79				<< fPath << ": " << strerror(status) << std::endl;
80			return false;
81		}
82
83		// try to register file device
84
85		partition_id id = roster.RegisterFileDevice(fPath);
86		if (id < B_OK) {
87			std::cerr << kProgramName << ": Could not register file device for "
88				"path " << fPath << ": " << strerror(status) << std::endl;
89			return false;
90		}
91
92		unregisterFileDevice.SetTo(id);
93
94		status = roster.GetPartitionWithID(id, &device, &partition);
95		if (!strncmp(fPath, "/dev", 4)) {
96			std::cerr << kProgramName << ": Cannot find registered file device "
97				"for path " << fPath << ": " << strerror(status)
98				<< std::endl;
99			return false;
100		}
101	}
102
103	// check that the device is writable
104	if (partition->IsReadOnly()) {
105		std::cerr << kProgramName << ": Cannot initialize read-only device.\n";
106		return false;
107	}
108
109	// check if the device is mounted
110	if (partition->IsMounted()) {
111		std::cerr << kProgramName << ": Cannot initialize mounted device.\n";
112		return false;
113	}
114
115	BDiskSystem diskSystem;
116	if (roster.GetDiskSystem(&diskSystem, fType) != B_OK) {
117		std::cerr << kProgramName << ": " << fType
118			<< " is an invalid or unsupported file system type.\n";
119		return false;
120	}
121
122	// prepare the device for modifications
123	status = device.PrepareModifications();
124	if (status != B_OK) {
125		std::cerr << kProgramName << ": A problem occurred preparing the "
126			"device for the modifications\n";
127		return false;
128	}
129	if (fVerbose)
130		std::cout << "Preparing for modifications...\n\n";
131
132	// validate parameters
133	BString name(fVolumeName);
134	if (partition->ValidateInitialize(diskSystem.PrettyName(),
135			&name, fFsOptions) != B_OK) {
136		std::cerr << kProgramName << ": Parameters validation failed. "
137			"Check what you wrote\n";
138		std::cerr << status;
139		return false;
140	}
141	if (fVerbose)
142		std::cout << "Parameters Validation...\n\n";
143	if (name != fVolumeName) {
144		std::cout << "Volume name was adjusted to "
145			<< name.String() << std::endl;
146	}
147
148	// Initialize the partition
149	status = partition->Initialize(diskSystem.PrettyName(), name.String(),
150		fFsOptions);
151	if (status != B_OK) {
152		std::cerr << kProgramName << ": Initialization failed: "
153			<< strerror(status) << std::endl;
154		return false;
155	}
156
157	if (!fQuick) {
158		std::cout << "\nAbout to initialize " << fPath << " with "
159			<< diskSystem.PrettyName()
160			<< "\nAre you sure you want to do this now?\n"
161			<< "\nALL YOUR DATA in " << fPath << " will be lost forever.\n";
162
163		BString reply;
164		do {
165			std::cout << "Continue (yes|[no])? ";
166			reply = _ReadLine();
167			if (reply == "")
168				reply = "no"; // silence is dissence
169		} while (reply != "yes" && reply != "no");
170
171		if (reply != "yes")
172			return true;
173	}
174
175	BString contentName = partition->ContentName();
176		// CommitModifications() will invalidate our partition object
177
178	status = device.CommitModifications();
179	if (status == B_OK) {
180		if (fVerbose) {
181			std::cout << "Volume \"" << contentName.String()
182				<< "\" has been initialized successfully!" << std::endl;
183		}
184	} else {
185		std::cout << kProgramName << ": Initialization of \""
186			<< contentName.String() << "\" failed: " << strerror(status)
187			<< std::endl;
188		return false;
189	}
190
191	// TODO: should we keep the file device around, or unregister it
192	// after we're done? This could be an option, too (for now, we'll
193	// just keep them if everything went well).
194	unregisterFileDevice.Detach();
195	return true;
196}
197
198
199inline BString
200FsCreator::_ReadLine()
201{
202	char line[255];
203
204	std::cin.getline(line, sizeof(line), '\n');
205
206	return line;
207}
208