diff --git a/src/bin/mkfs/FsCreator.cpp b/src/bin/mkfs/FsCreator.cpp index f8ed32b28e..6be5bf1f13 100644 --- a/src/bin/mkfs/FsCreator.cpp +++ b/src/bin/mkfs/FsCreator.cpp @@ -4,6 +4,7 @@ * * Authors: * Marco Minutoli, mminutoli@gmail.com + * Axel Dörfler, axeld@pinc-software.de */ #include "FsCreator.h" @@ -13,63 +14,116 @@ #include -FsCreator::FsCreator(const char* devPath, BString& type, - BString& volumeName, const char* fsOpt, bool verbose) +class UnregisterFileDevice { +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), - fDevicePath(devPath), + fPath(path), fVolumeName(volumeName), - fFsOptions(fsOpt), - fVerbose(verbose) + fFsOptions(fsOptions), + 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 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 - if (fDevice.IsReadOnly()) { - std::cerr << "Error: Can't Inizialize the device. " - "It is read only.\n"; + if (partition->IsReadOnly()) { + std::cerr << kProgramName << ": Cannot initialize read-only device.\n"; return false; } // check if the device is mounted - if (fDevice.IsMounted()) { - std::cerr << "Error: The device has to be unmounted before.\n"; + if (partition->IsMounted()) { + std::cerr << kProgramName << ": Cannot initialize mounted device.\n"; return false; } BDiskSystem diskSystem; - BDiskDeviceRoster dDRoster; - bool found = false; - while (dDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { - 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"; + if (roster.GetDiskSystem(&diskSystem, fType) != B_OK) { + std::cerr << kProgramName << ": " << fType + << " is an invalid or unsupported file system type.\n"; return false; } // prepare the device for modifications - status_t ret = fDevice.PrepareModifications(); - if (ret != B_OK) { - std::cerr << "Error: A problem occurred preparing the device for the" - "modifications\n"; + status = device.PrepareModifications(); + if (status != B_OK) { + std::cerr << kProgramName << ": A problem occurred preparing the " + "device for the modifications\n"; return false; } if (fVerbose) @@ -77,52 +131,64 @@ FsCreator::Run() // validate parameters BString name(fVolumeName); - if (fDevice.ValidateInitialize(diskSystem.PrettyName(), - &fVolumeName, fFsOptions) != B_OK) { - std::cerr << "Error: Parameters validation failed. " + if (partition->ValidateInitialize(diskSystem.PrettyName(), + &name, fFsOptions) != B_OK) { + std::cerr << kProgramName << ": Parameters validation failed. " "Check what you wrote\n"; - std::cerr << ret; + std::cerr << status; return false; } if (fVerbose) std::cout << "Parameters Validation...\n\n"; - if (name != fVolumeName) + if (name != fVolumeName) { std::cout << "Volume name was adjusted to " - << fVolumeName.String() << std::endl; + << name.String() << std::endl; + } // Initialize the partition - ret = fDevice.Initialize(diskSystem.PrettyName(), - fVolumeName.String(), fFsOptions); - if (ret != B_OK) { - std::cerr << "Initialization failed: " << strerror(ret) << std::endl; + status = partition->Initialize(diskSystem.PrettyName(), name.String(), + fFsOptions); + if (status != B_OK) { + std::cerr << kProgramName << ": Initialization failed: " + << strerror(status) << std::endl; return false; } - std::cout << "\nAre you sure you want to do this now?\n" - << "\nALL YOUR DATA in " << fDevicePath.String() - << " will be lost forever.\n"; + if (!fQuick) { + std::cout << "\nAbout to initialize " << fPath << " with " + << diskSystem.PrettyName() + << "\nAre you sure you want to do this now?\n" + << "\nALL YOUR DATA in " << fPath << " will be lost forever.\n"; - BString reply; - do { - std::cout << "Continue? [yes|no]: "; - reply = _ReadLine(); - if (reply == "") - reply = "no"; // silence is dissence - } while (reply != "yes" && reply != "no"); + BString reply; + do { + std::cout << "Continue (yes|[no])? "; + reply = _ReadLine(); + if (reply == "") + reply = "no"; // silence is dissence + } while (reply != "yes" && reply != "no"); - if (reply == "yes") { - ret = fDevice.CommitModifications(); - 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; - } + if (reply != "yes") + return true; } + + 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; } diff --git a/src/bin/mkfs/FsCreator.h b/src/bin/mkfs/FsCreator.h index b05241014e..ce88eb3990 100644 --- a/src/bin/mkfs/FsCreator.h +++ b/src/bin/mkfs/FsCreator.h @@ -13,22 +13,24 @@ #include #include + class FsCreator { public: - FsCreator(const char* devPath, BString& type, BString& volumeName, - const char* fsOpt, bool verbose); + FsCreator(const char* path, const char* type, + const char* volumeName, const char* fsOptions, + bool quick, bool verbose); + + bool Run(); - bool Run(); private: - inline BString _ReadLine(); + BString _ReadLine(); - BString fType; - BString fDevicePath; - BString& fVolumeName; - const char* fFsOptions; - BDiskDevice fDevice; - BPartition* fPartition; - const bool fVerbose; + const char* fType; + const char* fPath; + const char* fVolumeName; + const char* fFsOptions; + bool fVerbose; + bool fQuick; }; -#endif // _FSCREATOR_H_ +#endif // _FSCREATOR_H_ diff --git a/src/bin/mkfs/main.cpp b/src/bin/mkfs/main.cpp index 2016e80e8e..fd4db493e3 100644 --- a/src/bin/mkfs/main.cpp +++ b/src/bin/mkfs/main.cpp @@ -4,43 +4,42 @@ * * Authors: * Marco Minutoli, mminutoli@gmail.com + * Axel Dörfler, axeld@pinc-software.de */ -#include -#include -#include -#include #include +#include +#include + +#include + #include "FsCreator.h" + extern "C" const char* __progname; static const char* kProgramName = __progname; -static const char* kUsage = -"Usage: %s -t \n" -"\n" -"Options:\n" -" -t, --type - set type of filesystem to create\n\n" -" -h, --help - print this help text\n" -" -o, --options - set fs specific options\n" -" -v, --verbose - set verbose output\n" -; - -/* - * Print program help on the right stream - */ -inline void +/*! Print program help on the right stream */ +static void print_help(bool out) { - fprintf(out ? stdout : stderr, kUsage, kProgramName, kProgramName); + fprintf(out ? stdout : stderr, + "Usage: %s \n" + "\n" + "Options:\n" + " -t, --type - 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 - 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 - */ -inline void +/*! Print program help and exit */ +static void print_help_exit(bool 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 main(int argc, char* const* argv) { - const struct option longOptions[] = { + const struct option kLongOptions[] = { { "help", 0, NULL, 'h' }, { "options", 0, NULL, 'o' }, { "type", 1, NULL, 't' }, + { "list-types", 0, NULL, 'l' }, { "verbose", 0, NULL, 'v' }, + { "dont-ask", 0, NULL, 'q' }, { NULL, 0, NULL, 0 } }; - const char *shortOptions = "t:o:hv"; + const char* kShortOptions = "t:o:lhvq"; // parse argument list - int32 nextOption; - BString fsType; - BString fsOptions; + const char* fsType = "bfs"; + const char* fsOptions = NULL; bool verbose = false; + bool quick = false; - nextOption = getopt_long(argc, argv, shortOptions, longOptions, NULL); - if (nextOption == 't') - fsType = optarg; - else - print_help_exit(nextOption == 'h' ? true : false); - - do { - nextOption = getopt_long(argc, argv, shortOptions, longOptions, NULL); + while (true) { + int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions, + NULL); + if (nextOption == -1) + break; switch (nextOption) { - case 't': // -t or --type again? - print_help_exit(false); + case 't': // -t or --type + fsType = optarg; break; case 'h': // -h or --help print_help_exit(true); @@ -86,8 +106,14 @@ main(int argc, char* const* argv) verbose = true; break; case 'o': // -o or --options - fsOptions << optarg; + fsOptions = optarg; break; + case 'q': // -q or --quick + quick = true; + break; + case 'l': // list types + list_types(); + return 0; case '?': // invalid option break; case -1: // done with options @@ -96,21 +122,24 @@ main(int argc, char* const* argv) print_help(false); 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; }