* Now supports formatting file devices as well as partitions.

* Fixed crash when it couldn't find the device.
* Added a "-l|--list-types" option that list all file systems that support
  initializing (currently only BFS).
* Added a "-q|--dont-ask" option that prevents mkfs from questioning your
  command :-)
* Fixed return value - would return failure to the shell when it actually
  succeeded and vice versa.
* Improved/clarified some output and fixed spelling errors.
* Errors now have the command name as prefix, as that's how it is usually
  done (and very useful for batch processing).
* Cleanup, though I kept the FsCreator class which is kinda superfluous.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26564 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-22 14:11:54 +00:00
parent 6cc43bfbb0
commit 6835a76dfe
3 changed files with 229 additions and 132 deletions
+132 -66
View File
@@ -4,6 +4,7 @@
* *
* Authors: * Authors:
* Marco Minutoli, [email protected] * Marco Minutoli, [email protected]
* Axel Dörfler, [email protected]
*/ */
#include "FsCreator.h" #include "FsCreator.h"
@@ -13,63 +14,116 @@
#include <DiskSystem.h> #include <DiskSystem.h>
FsCreator::FsCreator(const char* devPath, BString& type, class UnregisterFileDevice {
BString& volumeName, const char* fsOpt, bool verbose) public:
UnregisterFileDevice()
:
fID(-1)
{
}
~UnregisterFileDevice()
{
if (fID >= 0) {
BDiskDeviceRoster roster;
roster.UnregisterFileDevice(fID);
}
}
void SetTo(partition_id id)
{
fID = id;
}
void Detach()
{
fID = -1;
}
private:
partition_id fID;
};
extern "C" const char* __progname;
static const char* kProgramName = __progname;
FsCreator::FsCreator(const char* path, const char* type, const char* volumeName,
const char* fsOptions, bool quick, bool verbose)
: :
fType(type), fType(type),
fDevicePath(devPath), fPath(path),
fVolumeName(volumeName), fVolumeName(volumeName),
fFsOptions(fsOpt), fFsOptions(fsOptions),
fVerbose(verbose) fVerbose(verbose),
fQuick(quick)
{ {
BDiskDeviceRoster roster;
status_t ret = roster.GetDeviceForPath(devPath, &fDevice);
if (ret != B_OK) {
std::cerr << "Error: Failed to get disk device for path "
<< devPath << ": " << strerror(ret);
}
} }
bool bool
FsCreator::Run() FsCreator::Run()
{ {
UnregisterFileDevice unregisterFileDevice;
BDiskDeviceRoster roster;
BPartition* partition;
BDiskDevice device;
status_t status = roster.GetPartitionForPath(fPath, &device,
&partition);
if (status != B_OK) {
if (!strncmp(fPath, "/dev", 4)) {
std::cerr << kProgramName << ": Failed to get disk device for path "
<< fPath << ": " << strerror(status) << std::endl;
return false;
}
// try to register file device
partition_id id = roster.RegisterFileDevice(fPath);
if (id < B_OK) {
std::cerr << kProgramName << ": Could not register file device for "
"path " << fPath << ": " << strerror(status) << std::endl;
return false;
}
unregisterFileDevice.SetTo(id);
status = roster.GetPartitionWithID(id, &device, &partition);
if (!strncmp(fPath, "/dev", 4)) {
std::cerr << kProgramName << ": Cannot find registered file device "
"for path " << fPath << ": " << strerror(status)
<< std::endl;
return false;
}
}
// check that the device is writable // check that the device is writable
if (fDevice.IsReadOnly()) { if (partition->IsReadOnly()) {
std::cerr << "Error: Can't Inizialize the device. " std::cerr << kProgramName << ": Cannot initialize read-only device.\n";
"It is read only.\n";
return false; return false;
} }
// check if the device is mounted // check if the device is mounted
if (fDevice.IsMounted()) { if (partition->IsMounted()) {
std::cerr << "Error: The device has to be unmounted before.\n"; std::cerr << kProgramName << ": Cannot initialize mounted device.\n";
return false; return false;
} }
BDiskSystem diskSystem; BDiskSystem diskSystem;
BDiskDeviceRoster dDRoster; if (roster.GetDiskSystem(&diskSystem, fType) != B_OK) {
bool found = false; std::cerr << kProgramName << ": " << fType
while (dDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { << " is an invalid or unsupported file system type.\n";
if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) {
if (diskSystem.ShortName() == fType) {
found = true;
break;
}
}
}
if (!found) {
std::cerr << "Error: " << fType.String()
<< " is an invalid or unsupported file system type.\n";
return false; return false;
} }
// prepare the device for modifications // prepare the device for modifications
status_t ret = fDevice.PrepareModifications(); status = device.PrepareModifications();
if (ret != B_OK) { if (status != B_OK) {
std::cerr << "Error: A problem occurred preparing the device for the" std::cerr << kProgramName << ": A problem occurred preparing the "
"modifications\n"; "device for the modifications\n";
return false; return false;
} }
if (fVerbose) if (fVerbose)
@@ -77,52 +131,64 @@ FsCreator::Run()
// validate parameters // validate parameters
BString name(fVolumeName); BString name(fVolumeName);
if (fDevice.ValidateInitialize(diskSystem.PrettyName(), if (partition->ValidateInitialize(diskSystem.PrettyName(),
&fVolumeName, fFsOptions) != B_OK) { &name, fFsOptions) != B_OK) {
std::cerr << "Error: Parameters validation failed. " std::cerr << kProgramName << ": Parameters validation failed. "
"Check what you wrote\n"; "Check what you wrote\n";
std::cerr << ret; std::cerr << status;
return false; return false;
} }
if (fVerbose) if (fVerbose)
std::cout << "Parameters Validation...\n\n"; std::cout << "Parameters Validation...\n\n";
if (name != fVolumeName) if (name != fVolumeName) {
std::cout << "Volume name was adjusted to " std::cout << "Volume name was adjusted to "
<< fVolumeName.String() << std::endl; << name.String() << std::endl;
}
// Initialize the partition // Initialize the partition
ret = fDevice.Initialize(diskSystem.PrettyName(), status = partition->Initialize(diskSystem.PrettyName(), name.String(),
fVolumeName.String(), fFsOptions); fFsOptions);
if (ret != B_OK) { if (status != B_OK) {
std::cerr << "Initialization failed: " << strerror(ret) << std::endl; std::cerr << kProgramName << ": Initialization failed: "
<< strerror(status) << std::endl;
return false; return false;
} }
std::cout << "\nAre you sure you want to do this now?\n" if (!fQuick) {
<< "\nALL YOUR DATA in " << fDevicePath.String() std::cout << "\nAbout to initialize " << fPath << " with "
<< " will be lost forever.\n"; << diskSystem.PrettyName()
<< "\nAre you sure you want to do this now?\n"
<< "\nALL YOUR DATA in " << fPath << " will be lost forever.\n";
BString reply; BString reply;
do { do {
std::cout << "Continue? [yes|no]: "; std::cout << "Continue (yes|[no])? ";
reply = _ReadLine(); reply = _ReadLine();
if (reply == "") if (reply == "")
reply = "no"; // silence is dissence reply = "no"; // silence is dissence
} while (reply != "yes" && reply != "no"); } while (reply != "yes" && reply != "no");
if (reply == "yes") { if (reply != "yes")
ret = fDevice.CommitModifications(); return true;
if (ret == B_OK) {
if (fVerbose) {
std::cout << "Volume " << fDevice.ContentName()
<< " has been initialized successfully!\n";
}
} else {
std::cout << "Error: Initialization of " << fDevice.ContentName()
<< " failed: " << strerror(ret) << std::endl;
return false;
}
} }
status = device.CommitModifications();
if (status == B_OK) {
if (fVerbose) {
std::cout << "Volume " << partition->ContentName()
<< " has been initialized successfully!\n";
}
} else {
std::cout << kProgramName << ": Initialization of "
<< partition->ContentName() << " failed: " << strerror(status)
<< std::endl;
return false;
}
// TODO: should we keep the file device around, or unregister it
// after we're done? This could be an option, too (for now, we'll
// just keep them if everything went well).
unregisterFileDevice.Detach();
return true; return true;
} }
+14 -12
View File
@@ -13,22 +13,24 @@
#include <DiskDevice.h> #include <DiskDevice.h>
#include <DiskDeviceRoster.h> #include <DiskDeviceRoster.h>
class FsCreator { class FsCreator {
public: public:
FsCreator(const char* devPath, BString& type, BString& volumeName, FsCreator(const char* path, const char* type,
const char* fsOpt, bool verbose); const char* volumeName, const char* fsOptions,
bool quick, bool verbose);
bool Run();
bool Run();
private: private:
inline BString _ReadLine(); BString _ReadLine();
BString fType; const char* fType;
BString fDevicePath; const char* fPath;
BString& fVolumeName; const char* fVolumeName;
const char* fFsOptions; const char* fFsOptions;
BDiskDevice fDevice; bool fVerbose;
BPartition* fPartition; bool fQuick;
const bool fVerbose;
}; };
#endif // _FSCREATOR_H_ #endif // _FSCREATOR_H_
+83 -54
View File
@@ -4,43 +4,42 @@
* *
* Authors: * Authors:
* Marco Minutoli, [email protected] * Marco Minutoli, [email protected]
* Axel Dörfler, [email protected]
*/ */
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <String.h>
#include <getopt.h> #include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <DiskSystem.h>
#include "FsCreator.h" #include "FsCreator.h"
extern "C" const char* __progname; extern "C" const char* __progname;
static const char* kProgramName = __progname; static const char* kProgramName = __progname;
static const char* kUsage =
"Usage: %s -t <fs> <options> <device> <volume name>\n"
"\n"
"Options:\n"
" -t, --type <fs> - set type of filesystem to create\n\n"
" -h, --help - print this help text\n"
" -o, --options <opt> - set fs specific options\n"
" -v, --verbose - set verbose output\n"
;
/*! Print program help on the right stream */
/* static void
* Print program help on the right stream
*/
inline void
print_help(bool out) print_help(bool out)
{ {
fprintf(out ? stdout : stderr, kUsage, kProgramName, kProgramName); fprintf(out ? stdout : stderr,
"Usage: %s <options> <device> <volume name>\n"
"\n"
"Options:\n"
" -t, --type <fs> - set type of file system to create\n\n"
" -l, --list-types - list file systems that support initializing\n"
" -h, --help - print this help text\n"
" -o, --options <opt> - set fs specific options\n"
" -q, --dont-ask - do not ask before initializing\n"
" -v, --verbose - set verbose output\n",
kProgramName);
} }
/* /*! Print program help and exit */
* Print program help and exit static void
*/
inline void
print_help_exit(bool out) print_help_exit(bool out)
{ {
print_help(out); print_help(out);
@@ -48,36 +47,57 @@ print_help_exit(bool out)
} }
static void
list_types()
{
const char* kFormat = "%-10s %-25s %s\n";
BDiskDeviceRoster roster;
BDiskSystem diskSystem;
printf("Installed file systems that support initializing:\n\n");
printf(kFormat, "Name", "Pretty Name", "Module");
printf(kFormat, "--", "--", "--");
while (roster.GetNextDiskSystem(&diskSystem) == B_OK) {
if (!diskSystem.SupportsInitializing()
|| !diskSystem.IsFileSystem())
continue;
printf(kFormat, diskSystem.ShortName(), diskSystem.PrettyName(),
diskSystem.Name());
}
}
int int
main(int argc, char* const* argv) main(int argc, char* const* argv)
{ {
const struct option longOptions[] = { const struct option kLongOptions[] = {
{ "help", 0, NULL, 'h' }, { "help", 0, NULL, 'h' },
{ "options", 0, NULL, 'o' }, { "options", 0, NULL, 'o' },
{ "type", 1, NULL, 't' }, { "type", 1, NULL, 't' },
{ "list-types", 0, NULL, 'l' },
{ "verbose", 0, NULL, 'v' }, { "verbose", 0, NULL, 'v' },
{ "dont-ask", 0, NULL, 'q' },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
const char *shortOptions = "t:o:hv"; const char* kShortOptions = "t:o:lhvq";
// parse argument list // parse argument list
int32 nextOption; const char* fsType = "bfs";
BString fsType; const char* fsOptions = NULL;
BString fsOptions;
bool verbose = false; bool verbose = false;
bool quick = false;
nextOption = getopt_long(argc, argv, shortOptions, longOptions, NULL); while (true) {
if (nextOption == 't') int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions,
fsType = optarg; NULL);
else if (nextOption == -1)
print_help_exit(nextOption == 'h' ? true : false); break;
do {
nextOption = getopt_long(argc, argv, shortOptions, longOptions, NULL);
switch (nextOption) { switch (nextOption) {
case 't': // -t or --type again? case 't': // -t or --type
print_help_exit(false); fsType = optarg;
break; break;
case 'h': // -h or --help case 'h': // -h or --help
print_help_exit(true); print_help_exit(true);
@@ -86,8 +106,14 @@ main(int argc, char* const* argv)
verbose = true; verbose = true;
break; break;
case 'o': // -o or --options case 'o': // -o or --options
fsOptions << optarg; fsOptions = optarg;
break; break;
case 'q': // -q or --quick
quick = true;
break;
case 'l': // list types
list_types();
return 0;
case '?': // invalid option case '?': // invalid option
break; break;
case -1: // done with options case -1: // done with options
@@ -96,21 +122,24 @@ main(int argc, char* const* argv)
print_help(false); print_help(false);
abort(); abort();
} }
} while (nextOption != -1);
// the device name should be the first non-option element
// right before the VolumeName
if (optind != argc - 2)
print_help_exit(false);
const char* devPath = argv[optind];
BString volName = argv[argc-1];
FsCreator* creator = new FsCreator(devPath, fsType, volName,
fsOptions.String(), verbose);
if (creator == NULL) {
std::cerr << "Error: FsCreator can't be allocated\n";
abort();
} }
return creator->Run(); // the device name should be the first non-option element
// right before the volume name
if (optind > argc - 1)
print_help_exit(false);
const char* device = argv[optind];
const char* volumeName = NULL;
if (optind == argc - 2)
volumeName = argv[argc - 1];
else {
if (!strncmp(device, "/dev", 4))
volumeName = "Unnamed";
else
volumeName = "Unnamed Image";
}
FsCreator creator(device, fsType, volumeName, fsOptions, quick, verbose);
return creator.Run() ? 0 : 1;
} }