xref: /haiku/src/bin/mkfs/FsCreator.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
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 
17 class UnregisterFileDevice {
18 public:
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 
43 private:
44 	partition_id	fID;
45 };
46 
47 
48 extern "C" const char* __progname;
49 static const char* kProgramName = __progname;
50 
51 
52 FsCreator::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 
65 bool
66 FsCreator::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 
199 inline BString
200 FsCreator::_ReadLine()
201 {
202 	char line[255];
203 
204 	std::cin.getline(line, sizeof(line), '\n');
205 
206 	return line;
207 }
208