mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-29 16:49:55 +00:00
Initial image file creation
This commit is contained in:
parent
8a3642bf9a
commit
8172c9fdfe
@ -28,8 +28,11 @@ Note: The command and type arguments are case insensitive. Only the first letter
|
|||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
.BR \-a\fI " "\fIFILENAME:FILESIZE
|
||||||
|
Create a disk image file with the specified name and size in bytes.
|
||||||
|
.TP
|
||||||
.BR \-g\fI " "\fILOG_LEVEL
|
.BR \-g\fI " "\fILOG_LEVEL
|
||||||
The rascsi log level to set (trace, debug, info, warn, err, critical, off)
|
Set the rascsi log level (trace, debug, info, warn, err, critical, off).
|
||||||
.TP
|
.TP
|
||||||
.BR \-h\fI " " \fIHOST
|
.BR \-h\fI " " \fIHOST
|
||||||
The rascsi host to connect to, default is 'localhost'.
|
The rascsi host to connect to, default is 'localhost'.
|
||||||
|
@ -1,32 +1,39 @@
|
|||||||
!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!!
|
!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!!
|
||||||
!! ------ The native file is rasctl.1. Re-run 'make docs' after updating
|
!! ------ The native file is rasctl.1. Re-run 'make docs' after updating\n\n
|
||||||
|
rascsi(1) General Commands Manual rascsi(1)
|
||||||
|
|
||||||
rascsi(1) General Commands Manual rascsi(1)
|
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
rasctl - Sends management commands to the rascsi process
|
rasctl - Sends management commands to the rascsi process
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] [-v] -i ID [-c CMD] [-f FILE] [-n NAME] [-t TYPE] [-u UNIT]
|
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS]
|
||||||
|
[-v] -i ID [-c CMD] [-f FILE] [-n NAME] [-t TYPE] [-u UNIT]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
rasctl Sends commands to the rascsi process to make configuration adjustments at runtime or to check the status of the devices.
|
rasctl Sends commands to the rascsi process to make configuration ad‐
|
||||||
|
justments at runtime or to check the status of the devices.
|
||||||
|
|
||||||
Either the -i or -l option should be specified at one time. Not both.
|
Either the -i or -l option should be specified at one time. Not both.
|
||||||
|
|
||||||
You do NOT need root privileges to use rasctl.
|
You do NOT need root privileges to use rasctl.
|
||||||
|
|
||||||
Note: The command and type arguments are case insensitive. Only the first letter of the command/type is evaluated by the tool.
|
Note: The command and type arguments are case insensitive. Only the
|
||||||
|
first letter of the command/type is evaluated by the tool.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
|
-a FILENAME:FILESIZE
|
||||||
|
Create a disk image file with the specified name and size in
|
||||||
|
bytes.
|
||||||
|
|
||||||
-g LOG_LEVEL
|
-g LOG_LEVEL
|
||||||
The rascsi log level to set (trace, debug, info, warn, err, critical, off)
|
Set the rascsi log level (trace, debug, info, warn, err, criti‐
|
||||||
|
cal, off).
|
||||||
|
|
||||||
-h HOST
|
-h HOST
|
||||||
The rascsi host to connect to, default is 'localhost'.
|
The rascsi host to connect to, default is 'localhost'.
|
||||||
|
|
||||||
-l List all of the devices that are currently being emulated by RaSCSI, as well as their current status.
|
-l List all of the devices that are currently being emulated by
|
||||||
|
RaSCSI, as well as their current status.
|
||||||
|
|
||||||
-p PORT
|
-p PORT
|
||||||
The rascsi port to connect to, default is 6868.
|
The rascsi port to connect to, default is 6868.
|
||||||
@ -34,7 +41,8 @@ OPTIONS
|
|||||||
-r RESERVED_IDS
|
-r RESERVED_IDS
|
||||||
Comma-separated list of IDs to reserve.
|
Comma-separated list of IDs to reserve.
|
||||||
|
|
||||||
-s Display server-side settings like available images or supported device types.
|
-s Display server-side settings like available images or supported
|
||||||
|
device types.
|
||||||
|
|
||||||
-v Display the rascsi version.
|
-v Display the rascsi version.
|
||||||
|
|
||||||
@ -45,21 +53,28 @@ OPTIONS
|
|||||||
d(etach): Detach disk
|
d(etach): Detach disk
|
||||||
i(nsert): Insert media (removable media devices only)
|
i(nsert): Insert media (removable media devices only)
|
||||||
e(ject): Eject media (removable media devices only)
|
e(ject): Eject media (removable media devices only)
|
||||||
p(rotect): Write protect the medium (not for CD-ROMs, which are always read-only)
|
p(rotect): Write protect the medium (not for CD-ROMs, which
|
||||||
u(nprotect): Remove write protection from the medium (not for CD-ROMs, which are always read-only)
|
are always read-only)
|
||||||
|
u(nprotect): Remove write protection from the medium (not for
|
||||||
|
CD-ROMs, which are always read-only)
|
||||||
s(how): Display device information
|
s(how): Display device information
|
||||||
|
|
||||||
eject, protect and unprotect are idempotent.
|
eject, protect and unprotect are idempotent.
|
||||||
|
|
||||||
-b BLOCK_SIZE
|
-b BLOCK_SIZE
|
||||||
The optional block size. For SCSI drives 512, 1024, 2048 or 4096 bytes, default size is 512 bytes. For SASI drives 256 or 1024 bytes, default is 256 bytes.
|
The optional block size. For SCSI drives 512, 1024, 2048 or 4096
|
||||||
|
bytes, default size is 512 bytes. For SASI drives 256 or 1024
|
||||||
|
bytes, default is 256 bytes.
|
||||||
|
|
||||||
-f FILE
|
-f FILE
|
||||||
Path to the disk image file. See the rascsi(1) man page for allowable file types.
|
Path to the disk image file. See the rascsi(1) man page for al‐
|
||||||
|
lowable file types.
|
||||||
|
|
||||||
-t TYPE
|
-t TYPE
|
||||||
Specifies the device type. This type overrides the type derived from the file extension of the specified image. See the rascsi(1) man page for the available device types.
|
Specifies the device type. This type overrides the type derived
|
||||||
For some types there are shortcuts (only the first letter is required):
|
from the file extension of the specified image. See the
|
||||||
|
rascsi(1) man page for the available device types. For some
|
||||||
|
types there are shortcuts (only the first letter is required):
|
||||||
hd: SCSI hard disk drive
|
hd: SCSI hard disk drive
|
||||||
rm: SCSI removable media drive
|
rm: SCSI removable media drive
|
||||||
cd: CD-ROM
|
cd: CD-ROM
|
||||||
@ -68,11 +83,17 @@ OPTIONS
|
|||||||
daynaport: DaynaPORT network adapter
|
daynaport: DaynaPORT network adapter
|
||||||
|
|
||||||
-n VENDOR:PRODUCT:REVISION
|
-n VENDOR:PRODUCT:REVISION
|
||||||
The vendor, product and revision for the device, to be returned with the INQUIRY data. A complete set of name components must be provided. VENDOR may have up to 8, PRODUCT
|
The vendor, product and revision for the device, to be returned
|
||||||
up to 16, REVISION up to 4 characters. Padding with blanks to the maxium length is automatically applied. Once set the name of a device cannot be changed.
|
with the INQUIRY data. A complete set of name components must be
|
||||||
|
provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up
|
||||||
|
to 4 characters. Padding with blanks to the maxium length is au‐
|
||||||
|
tomatically applied. Once set the name of a device cannot be
|
||||||
|
changed.
|
||||||
|
|
||||||
-u UNIT
|
-u UNIT
|
||||||
Unit number (0 or 1). This will default to 0. This option is only used when there are multiple SCSI devices on a shared SCSI controller. (This is not common)
|
Unit number (0 or 1). This will default to 0. This option is
|
||||||
|
only used when there are multiple SCSI devices on a shared SCSI
|
||||||
|
controller. (This is not common)
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
Show a listing of all of the SCSI devices and their current status.
|
Show a listing of all of the SCSI devices and their current status.
|
||||||
@ -85,12 +106,14 @@ EXAMPLES
|
|||||||
| 0 | 1 | SCHD | /home/pi/harddisk.hda
|
| 0 | 1 | SCHD | /home/pi/harddisk.hda
|
||||||
+----+----+------+-------------------------------------
|
+----+----+------+-------------------------------------
|
||||||
|
|
||||||
Request the RaSCSI process to attach a disk (assumed) to SCSI ID 0 with the contents of the file system image "HDIIMAGE0.HDS".
|
Request the RaSCSI process to attach a disk (assumed) to SCSI ID 0 with
|
||||||
|
the contents of the file system image "HDIIMAGE0.HDS".
|
||||||
rasctl -i 0 -f HDIIMAGE0.HDS
|
rasctl -i 0 -f HDIIMAGE0.HDS
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
rascsi(1) scsimon(1)
|
rascsi(1) scsimon(1)
|
||||||
|
|
||||||
Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/>
|
Full documentation is available at:
|
||||||
|
<https://www.github.com/akuker/RASCSI/wiki/>
|
||||||
|
|
||||||
rascsi(1)
|
rascsi(1)
|
||||||
|
@ -705,6 +705,55 @@ string SetReservedIds(const list<string>& ids_to_reserve)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CreateImage(int fd, const PbCommand& command)
|
||||||
|
{
|
||||||
|
if (command.params().size() < 2 || command.params().Get(0).empty() || command.params().Get(1).empty()) {
|
||||||
|
return ReturnStatus(fd, false, "Can't create image file: Missing filename or file size");
|
||||||
|
}
|
||||||
|
|
||||||
|
string filename = command.params().Get(0);
|
||||||
|
if (filename[0] != '/') {
|
||||||
|
filename = default_image_folder + "/" + filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t len;
|
||||||
|
try {
|
||||||
|
len = stoul(command.params().Get(1));
|
||||||
|
}
|
||||||
|
catch(const invalid_argument& e) {
|
||||||
|
return ReturnStatus(fd, false, "Invalid image file size " + command.params().Get(1));
|
||||||
|
}
|
||||||
|
catch(const out_of_range& e) {
|
||||||
|
return ReturnStatus(fd, false, "Invalid image file size " + command.params().Get(1));
|
||||||
|
}
|
||||||
|
if (len < 256) {
|
||||||
|
ostringstream error;
|
||||||
|
error << "Invalid image file size " << len;
|
||||||
|
return ReturnStatus(fd, false, error.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (!stat(filename.c_str(), &st)) {
|
||||||
|
return ReturnStatus(fd, false, "Image file '" + filename + "' already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since rascsi is running as root ensure that others can access the file
|
||||||
|
int image_fd = open(filename.c_str(), O_CREAT|O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||||
|
if (image_fd == -1) {
|
||||||
|
return ReturnStatus(fd, false, "Can't create image file '" + filename + "': " + string(strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallocate(image_fd, 0, 0, len) == -1) {
|
||||||
|
close(image_fd);
|
||||||
|
|
||||||
|
return ReturnStatus(fd, false, "Can't allocate space for image file '" + filename + "': " + string(strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(image_fd);
|
||||||
|
|
||||||
|
return ReturnStatus(fd);
|
||||||
|
}
|
||||||
|
|
||||||
void DetachAll()
|
void DetachAll()
|
||||||
{
|
{
|
||||||
Device *map[devices.size()];
|
Device *map[devices.size()];
|
||||||
@ -1146,11 +1195,14 @@ bool ProcessCmd(const int fd, const PbCommand& command)
|
|||||||
const list<string> ids = { command.params().begin(), command.params().end() };
|
const list<string> ids = { command.params().begin(), command.params().end() };
|
||||||
string invalid_id = SetReservedIds(ids);
|
string invalid_id = SetReservedIds(ids);
|
||||||
if (!invalid_id.empty()) {
|
if (!invalid_id.empty()) {
|
||||||
return ReturnStatus(fd, false,"Invalid ID " + invalid_id + " for " + PbOperation_Name(RESERVE));
|
return ReturnStatus(fd, false, "Invalid ID " + invalid_id + " for " + PbOperation_Name(RESERVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReturnStatus(fd);
|
return ReturnStatus(fd);
|
||||||
}
|
}
|
||||||
|
else if (command.operation() == CREATE_IMAGE) {
|
||||||
|
return CreateImage(fd, command);
|
||||||
|
}
|
||||||
|
|
||||||
const vector<string> params = { command.params().begin(), command.params().end() };
|
const vector<string> params = { command.params().begin(), command.params().end() };
|
||||||
|
|
||||||
|
@ -59,6 +59,10 @@ enum PbOperation {
|
|||||||
// IDs blocked from being used, usually the IDs of the initiators (computers) in the SCSI chain.
|
// IDs blocked from being used, usually the IDs of the initiators (computers) in the SCSI chain.
|
||||||
// PbCommand.params contains the list of IDs to reserve, or is empty in order not to reserve any ID.
|
// PbCommand.params contains the list of IDs to reserve, or is empty in order not to reserve any ID.
|
||||||
RESERVE = 14;
|
RESERVE = 14;
|
||||||
|
// Create an image file. The image file must not yet exist.
|
||||||
|
// PbCommand.params(0) contains the filename, PbCommand.params(1) contains the file size in bytes.
|
||||||
|
// If the filename is relative (does not start with a slash) the file is created in the default image folder.
|
||||||
|
CREATE_IMAGE = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The properties supported by a device, helping clients to offer a good user experience
|
// The properties supported by a device, helping clients to offer a good user experience
|
||||||
|
@ -206,6 +206,21 @@ void CommandReserve(const string&hostname, int port, const string& reserved_ids)
|
|||||||
SendCommand(hostname.c_str(), port, command, result);
|
SendCommand(hostname.c_str(), port, command, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandCreateImage(const string&hostname, int port, const string& image_params)
|
||||||
|
{
|
||||||
|
PbCommand command;
|
||||||
|
command.set_operation(CREATE_IMAGE);
|
||||||
|
|
||||||
|
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
|
||||||
|
if (separatorPos != string::npos) {
|
||||||
|
command.add_params(image_params.substr(0, separatorPos));
|
||||||
|
command.add_params(image_params.substr(separatorPos + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
PbResult result;
|
||||||
|
SendCommand(hostname.c_str(), port, command, result);
|
||||||
|
}
|
||||||
|
|
||||||
void CommandDefaultImageFolder(const string& hostname, int port, const string& folder)
|
void CommandDefaultImageFolder(const string& hostname, int port, const string& folder)
|
||||||
{
|
{
|
||||||
PbCommand command;
|
PbCommand command;
|
||||||
@ -502,11 +517,12 @@ int main(int argc, char* argv[])
|
|||||||
string log_level;
|
string log_level;
|
||||||
string default_folder;
|
string default_folder;
|
||||||
string reserved_ids;
|
string reserved_ids;
|
||||||
|
string image_params;
|
||||||
bool list = false;
|
bool list = false;
|
||||||
|
|
||||||
opterr = 1;
|
opterr = 1;
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "b:c:d:f:g:h:i:n:p:r:t:u:lsv")) != -1) {
|
while ((opt = getopt(argc, argv, "a:b:c:d:f:g:h:i:n:p:r:t:u:lsv")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
device->set_id(optarg[0] - '0');
|
device->set_id(optarg[0] - '0');
|
||||||
@ -516,6 +532,11 @@ int main(int argc, char* argv[])
|
|||||||
device->set_unit(optarg[0] - '0');
|
device->set_unit(optarg[0] - '0');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
command.set_operation(CREATE_IMAGE);
|
||||||
|
image_params = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
int block_size;
|
int block_size;
|
||||||
if (!GetAsInt(optarg, block_size)) {
|
if (!GetAsInt(optarg, block_size)) {
|
||||||
@ -632,6 +653,10 @@ int main(int argc, char* argv[])
|
|||||||
CommandReserve(hostname, port, reserved_ids);
|
CommandReserve(hostname, port, reserved_ids);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
case CREATE_IMAGE:
|
||||||
|
CommandCreateImage(hostname, port, image_params);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
case DEVICE_INFO:
|
case DEVICE_INFO:
|
||||||
CommandDeviceInfo(hostname, port, command);
|
CommandDeviceInfo(hostname, port, command);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
Loading…
Reference in New Issue
Block a user