diff --git a/doc/rasctl.1 b/doc/rasctl.1 index 93c8d436..471d99bb 100644 --- a/doc/rasctl.1 +++ b/doc/rasctl.1 @@ -5,6 +5,7 @@ rasctl \- Sends management commands to the rascsi process .B rasctl \fB\-l\fR | \fB\-s\fR | +[\fB\-d\fR \fIIMAGE_FOLDER\fR] [\fB\-g\fR \fILOG_LEVEL\fR] [\fB\-h\fR \fIHOST\fR] [\fB\-p\fR \fIPORT\fR] @@ -31,6 +32,9 @@ Note: The command and type arguments are case insensitive. Only the first letter .BR \-a\fI " "\fIFILENAME:FILESIZE Create an image file in the default image folder with the specified name and size in bytes. .TP +.BR \-g\fI " "\fIIMAGE_FOLDER +Set the default image folder. +.TP .BR \-g\fI " "\fILOG_LEVEL Set the rascsi log level (trace, debug, info, warn, err, critical, off). .TP diff --git a/doc/rasctl_man_page.txt b/doc/rasctl_man_page.txt index a02916b6..abc62b16 100644 --- a/doc/rasctl_man_page.txt +++ b/doc/rasctl_man_page.txt @@ -6,18 +6,19 @@ NAME rasctl - Sends management commands to the rascsi process SYNOPSIS - rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] - [-v] -i ID [-c CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u UNIT] + rasctl -l | -s | [-d IMAGE_FOLDER] [-g LOG_LEVEL] [-h HOST] [-p PORT] + [-r RESERVED_IDS] [-v] -i ID [-c CMD] [-f FILE|PARAM] [-n NAME] [-t + TYPE] [-u UNIT] DESCRIPTION - rasctl Sends commands to the rascsi process to make configuration ad‐ + 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. You do NOT need root privileges to use rasctl. - Note: The command and type arguments are case insensitive. Only the + Note: The command and type arguments are case insensitive. Only the first letter of the command/type is evaluated by the tool. OPTIONS @@ -25,14 +26,17 @@ OPTIONS Create an image file in the default image folder with the speci‐ fied name and size in bytes. + -g IMAGE_FOLDER + Set the default image folder. + -g LOG_LEVEL - Set the rascsi log level (trace, debug, info, warn, err, criti‐ + Set the rascsi log level (trace, debug, info, warn, err, criti‐ cal, off). -h HOST The rascsi host to connect to, default is 'localhost'. - -l List all of the devices that are currently being emulated by + -l List all of the devices that are currently being emulated by RaSCSI, as well as their current status. -m CURRENT_NAME:NEW_NAME @@ -44,7 +48,7 @@ OPTIONS -r RESERVED_IDS Comma-separated list of IDs to reserve. - -s Display server-side settings like available images or supported + -s Display server-side settings like available images or supported device types. -v Display the rascsi version. @@ -62,7 +66,7 @@ OPTIONS d(etach): Detach disk i(nsert): Insert media (removable media devices only) e(ject): Eject media (removable media devices only) - p(rotect): Write protect the medium (not for CD-ROMs, which + p(rotect): Write protect the medium (not for CD-ROMs, which are always read-only) u(nprotect): Remove write protection from the medium (not for CD-ROMs, which are always read-only) @@ -72,18 +76,18 @@ OPTIONS -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 size is 512 bytes. For SASI drives 256 or 1024 bytes, default is 256 bytes. -f FILE|PARAM Device-specific: Either a path to a disk image file, or a param‐ - eter for a non-disk device. See the rascsi(1) man page for per‐ + eter for a non-disk device. See the rascsi(1) man page for per‐ mitted file types. -t TYPE - Specifies the device type. This type overrides the type derived + 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. For some + 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 rm: SCSI removable media drive @@ -93,16 +97,16 @@ OPTIONS daynaport: DaynaPORT network adapter -n VENDOR:PRODUCT:REVISION - The vendor, product and revision for the device, to be returned + 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 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 + tomatically applied. Once set the name of a device cannot be changed. -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 + 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 diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 2b3673d3..1a7b976f 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -914,6 +914,39 @@ bool CopyImage(int fd, const PbCommand& command) return ReturnStatus(fd); } +bool SetImagePermissions(int fd, const PbCommand& command) +{ + string filename = GetParam(command, "file"); + if (filename.empty()) { + return ReturnStatus(fd, false, "Missing image filename"); + } + + if (filename.find('/') != string::npos) { + return ReturnStatus(fd, false, "The image filename '" + filename + "' must not contain a path"); + } + + filename = default_image_folder + "/" + filename; + + bool protect = command.operation() == PROTECT_IMAGE; + + int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + + if (chmod(filename.c_str(), permissions) == -1) { + ostringstream error; + error << "Can't " << (protect ? "protect" : "unprotect") << " image file '" << filename << "': " << strerror(errno); + return ReturnStatus(fd, false, error.str()); + } + + if (protect) { + LOGINFO("%s", string("Protected image file '" + filename + "'").c_str()); + } + else { + LOGINFO("%s", string("Unprotected image file '" + filename + "'").c_str()); + } + + return ReturnStatus(fd); +} + void DetachAll() { Device *map[devices.size()]; @@ -1381,6 +1414,10 @@ bool ProcessCmd(const int fd, const PbCommand& command) case COPY_IMAGE: return CopyImage(fd, command); + case PROTECT_IMAGE: + case UNPROTECT_IMAGE: + return SetImagePermissions(fd, command); + default: // This is a device-specific command handled below break; diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index 18c345c7..fa59232d 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -104,6 +104,16 @@ enum PbOperation { // "to": The destination filename, relative to the default image folder. It must not contain a slash. // The destination filename must not yet exist. COPY_IMAGE = 18; + + // Write-protect an image file. + // Parameters: + // "file": The filename, relative to the default image folder. It must not contain a slash. + PROTECT_IMAGE = 19; + + // Make an image file writable. + // Parameters: + // "file": The filename, relative to the default image folder. It must not contain a slash. + UNPROTECT_IMAGE = 20; } // The properties supported by a device diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index 985de5b7..38a89b41 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -532,19 +532,21 @@ int main(int argc, char* argv[]) cerr << "SCSI Target Emulator RaSCSI Controller" << endl; cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl; cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] "; - cerr << "[-d DEFAULT_IMAGE_FOLDER] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] [-l] [-v]" << endl; - cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl; - cerr << " UNIT := {0|1}, default setting is 0." << endl; + cerr << "[-d IMAGE_FOLDER] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] "; + cerr << "[-a FILENAME:FILESIZE] [-w FILENAME] [-m CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] "; + cerr << "[-l] [-v]" << endl; + cerr << " where ID := {0-7}" << endl; + cerr << " UNIT := {0|1}, default is 0" << endl; cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl; cerr << " TYPE := {sahd|schd|scrm|sccd|scmo|scbr|scdp} or convenience type {hd|rm|mo|cd|bridge|daynaport}" << endl; cerr << " BLOCK_SIZE := {256|512|1024|2048|4096) bytes per hard disk drive block" << endl; cerr << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)" << endl; cerr << " FILE|PARAM := image file path or device-specific parameter" << endl; - cerr << " DEFAULT_IMAGE_FOLDER := default location for image files, default is '~/images'" << endl; + cerr << " IMAGE_FOLDER := default location for image files, default is '~/images'" << endl; cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl; cerr << " PORT := rascsi port to connect to, default is 6868" << endl; cerr << " RESERVED_IDS := comma-separated list of IDs to reserve" << endl; - cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'trace'" << endl; + cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'info'" << endl; cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl; cerr << "Usage: " << argv[0] << " -l" << endl; cerr << " Print device list." << endl;