* 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:
+132
-66
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user