diff --git a/doc/rasctl.1 b/doc/rasctl.1 index 471d99bb..0afc03dc 100644 --- a/doc/rasctl.1 +++ b/doc/rasctl.1 @@ -3,6 +3,8 @@ rasctl \- Sends management commands to the rascsi process .SH SYNOPSIS .B rasctl +\fB\-e\fR | +\fB\-k\fR | \fB\-l\fR | \fB\-s\fR | [\fB\-d\fR \fIIMAGE_FOLDER\fR] @@ -32,7 +34,7 @@ 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 +.BR \-d\fI " "\fIIMAGE_FOLDER Set the default image folder. .TP .BR \-g\fI " "\fILOG_LEVEL @@ -41,6 +43,12 @@ Set the rascsi log level (trace, debug, info, warn, err, critical, off). .BR \-h\fI " " \fIHOST The rascsi host to connect to, default is 'localhost'. .TP +.BR \-e\fI +List all images files in the default image folder. +.TP +.BR \-k\fI +Lists all available network interfaces provided that they are up. +.TP .BR \-l\fI List all of the devices that are currently being emulated by RaSCSI, as well as their current status. .TP diff --git a/doc/rasctl_man_page.txt b/doc/rasctl_man_page.txt index abc62b16..4c729faf 100644 --- a/doc/rasctl_man_page.txt +++ b/doc/rasctl_man_page.txt @@ -6,9 +6,9 @@ NAME rasctl - Sends management commands to the rascsi process SYNOPSIS - 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] + rasctl -e | -k | -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‐ @@ -26,7 +26,7 @@ OPTIONS Create an image file in the default image folder with the speci‐ fied name and size in bytes. - -g IMAGE_FOLDER + -d IMAGE_FOLDER Set the default image folder. -g LOG_LEVEL @@ -36,7 +36,12 @@ OPTIONS -h HOST The rascsi host to connect to, default is 'localhost'. - -l List all of the devices that are currently being emulated by + -e List all images files in the default image folder. + + -k Lists all available network interfaces provided that they are + up. + + -l List all of the devices that are currently being emulated by RaSCSI, as well as their current status. -m CURRENT_NAME:NEW_NAME @@ -48,7 +53,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. @@ -66,7 +71,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) @@ -76,18 +81,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 @@ -97,16 +102,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/devices/device_factory.cpp b/src/raspberrypi/devices/device_factory.cpp index bf55d330..ce773e31 100644 --- a/src/raspberrypi/devices/device_factory.cpp +++ b/src/raspberrypi/devices/device_factory.cpp @@ -16,6 +16,7 @@ #include "scsi_daynaport.h" #include "exceptions.h" #include "device_factory.h" +#include #include #include @@ -48,13 +49,21 @@ DeviceFactory::DeviceFactory() geometries[SCBR] = {}; geometries[SCDP] = {}; + string network_interfaces; + for (const auto& network_interface : GetNetworkInterfaces()) { + if (!network_interfaces.empty()) { + network_interfaces += ","; + } + network_interfaces += network_interface; + } + default_params[SAHD] = {}; default_params[SCHD] = {}; default_params[SCRM] = {}; default_params[SCMO] = {}; default_params[SCCD] = {}; - default_params[SCBR]["interfaces"] = "eth0,wlan0"; - default_params[SCDP]["interfaces"] = "eth0,wlan0"; + default_params[SCBR]["interfaces"] = network_interfaces; + default_params[SCDP]["interfaces"] = network_interfaces; } DeviceFactory& DeviceFactory::instance() @@ -194,3 +203,41 @@ const set DeviceFactory::GetCapacities(PbDeviceType type) return keys; } + +const list DeviceFactory::GetNetworkInterfaces() const +{ + list network_interfaces; + + struct ifaddrs *addrs; + getifaddrs(&addrs); + struct ifaddrs *tmp = addrs; + + while (tmp) { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET && + strcmp(tmp->ifa_name, "lo") && strcmp(tmp->ifa_name, "rascsi_bridge")) { + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + + strcpy(ifr.ifr_name, tmp->ifa_name); + if (!ioctl(fd, SIOCGIFFLAGS, &ifr)) { + close(fd); + + // Only list interfaces that are up + if (ifr.ifr_flags & IFF_UP) { + network_interfaces.push_back(tmp->ifa_name); + } + } + else { + close(fd); + } + } + + tmp = tmp->ifa_next; + } + + freeifaddrs(addrs); + + return network_interfaces; +} diff --git a/src/raspberrypi/devices/device_factory.h b/src/raspberrypi/devices/device_factory.h index c35b9cb0..3ed972c0 100644 --- a/src/raspberrypi/devices/device_factory.h +++ b/src/raspberrypi/devices/device_factory.h @@ -33,12 +33,13 @@ public: static DeviceFactory& instance(); + Device *CreateDevice(PbDeviceType type, const string& filename, const string& ext); + const set& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; } const set& GetSectorSizes(const string&); const set GetCapacities(PbDeviceType); const map& GetDefaultParams(PbDeviceType type) { return default_params[type]; } - - Device *CreateDevice(PbDeviceType type, const string& filename, const string& ext); + const list GetNetworkInterfaces() const; private: diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 500f31cc..2f1595a7 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -528,15 +528,40 @@ void GetAllDeviceTypeProperties(PbServerInfo& server_info) void GetAvailableImages(PbServerInfo& server_info) { + PbImageFilesInfo *image_files_info = new PbImageFilesInfo(); + server_info.set_allocated_image_files_info(image_files_info); + + image_files_info->set_default_image_folder(default_image_folder); + if (!access(default_image_folder.c_str(), F_OK)) { for (const auto& entry : filesystem::directory_iterator(default_image_folder, filesystem::directory_options::skip_permission_denied)) { if (entry.is_regular_file() && entry.file_size() && !(entry.file_size() & 0x1ff)) { - GetImageFile(server_info.add_image_files(), entry.path().filename()); + GetImageFile(image_files_info->add_image_files(), entry.path().filename()); } } } } +void GetAvailableImages(PbImageFilesInfo& image_files_info) +{ + image_files_info.set_default_image_folder(default_image_folder); + + if (!access(default_image_folder.c_str(), F_OK)) { + for (const auto& entry : filesystem::directory_iterator(default_image_folder, filesystem::directory_options::skip_permission_denied)) { + if (entry.is_regular_file() && entry.file_size() && !(entry.file_size() & 0x1ff)) { + GetImageFile(image_files_info.add_image_files(), entry.path().filename()); + } + } + } +} + +void GetNetworkInterfacesInfo(PbNetworkInterfacesInfo& network_interfaces_info) +{ + for (const auto& network_interface : device_factory.GetNetworkInterfaces()) { + network_interfaces_info.add_name(network_interface); + } +} + void GetDevice(const Device *device, PbDevice *pb_device) { pb_device->set_id(device->GetId()); @@ -634,9 +659,11 @@ void GetServerInfo(PbResult& result) server_info->set_patch_version(rascsi_patch_version); GetLogLevels(*server_info); server_info->set_current_log_level(current_log_level); - server_info->set_default_image_folder(default_image_folder); GetAllDeviceTypeProperties(*server_info); GetAvailableImages(*server_info); + PbNetworkInterfacesInfo * network_interfaces_info = new PbNetworkInterfacesInfo(); + server_info->set_allocated_network_interfaces_info(network_interfaces_info); + GetNetworkInterfacesInfo(*network_interfaces_info); GetDevices(*server_info); for (int id : reserved_ids) { server_info->add_reserved_ids(id); @@ -1703,7 +1730,7 @@ static void *MonThread(void *param) switch(command.operation()) { case LOG_LEVEL: { - LOGTRACE(string("Received " + PbOperation_Name(LOG_LEVEL) + " command").c_str()); + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); string log_level = GetParam(command, "level"); bool status = SetLogLevel(log_level); @@ -1717,7 +1744,7 @@ static void *MonThread(void *param) } case DEFAULT_FOLDER: { - LOGTRACE(string("Received " + PbOperation_Name(DEFAULT_FOLDER) + " command").c_str()); + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); string folder = GetParam(command, "folder"); if (folder.empty()) { @@ -1734,7 +1761,7 @@ static void *MonThread(void *param) } case DEVICE_INFO: { - LOGTRACE(string("Received " + PbOperation_Name(DEVICE_INFO) + " command").c_str()); + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); PbResult result; result.set_status(true); @@ -1750,7 +1777,7 @@ static void *MonThread(void *param) } case SERVER_INFO: { - LOGTRACE(string("Received " + PbOperation_Name(SERVER_INFO) + " command").c_str()); + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); PbResult result; result.set_status(true); @@ -1759,6 +1786,30 @@ static void *MonThread(void *param) break; } + case IMAGE_FILES_INFO: { + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); + + PbImageFilesInfo *image_files_info = new PbImageFilesInfo(); + GetAvailableImages(*image_files_info); + PbResult result; + result.set_status(true); + result.set_allocated_image_files_info(image_files_info); + SerializeMessage(fd, result); + break; + } + + case NETWORK_INTERFACES_INFO: { + LOGTRACE(string("Received " + PbOperation_Name(command.operation()) + " command").c_str()); + + PbNetworkInterfacesInfo *network_interfaces_info = new PbNetworkInterfacesInfo(); + GetNetworkInterfacesInfo(*network_interfaces_info); + PbResult result; + result.set_status(true); + result.set_allocated_network_interfaces_info(network_interfaces_info); + SerializeMessage(fd, result); + break; + } + default: { // Wait until we become idle while (active) { diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index df821e56..d8ddccaa 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -66,59 +66,65 @@ enum PbOperation { // Gets the server information SERVER_INFO = 10; - // Gets information for a list of attached devices. Returns data for all attached devices if empty. + // Gets information on attached devices. Returns data for all attached devices if empty. DEVICE_INFO = 11; + // Gets information on available image files. A lightweight alternative to getting the complete server info. + IMAGE_FILES_INFO = 12; + + // Gets the names of the available network interfaces. Only lists interfaces that are up. + NETWORK_INTERFACES_INFO = 13; + // Set the default folder for image files. // Parameters: // "folder": The default folder name. - DEFAULT_FOLDER = 12; + DEFAULT_FOLDER = 14; // Set server log level. // Parameters: // "level": The new log level - LOG_LEVEL = 13; + LOG_LEVEL = 15; // Block IDs from being used, usually the IDs of the initiators (computers) in the SCSI chain. // Parameters: // "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID. - RESERVE = 14; - + RESERVE = 16; + // Create an image file. The image file must not yet exist. // Parameters: // "file": The filename, relative to the default image folder. It must not contain a slash. // "size": The file size in bytes, must be a multiple of 512 // "read_only": "true" (case-insensitive) in order to create a read-only file, otherwise "false" - CREATE_IMAGE = 15; + CREATE_IMAGE = 17; // Delete an image file. // Parameters: // "file": The filename, relative to the default image folder. It must not contain a slash. - DELETE_IMAGE = 16; + DELETE_IMAGE = 18; // Rename an image file. // Parameters: // "from": The old filename, relative to the default image folder. It must not contain a slash. // "to": The new filename, relative to the default image folder. It must not contain a slash. // The new filename must not yet exist. - RENAME_IMAGE = 17; + RENAME_IMAGE = 19; // Copy an image file. // Parameters: // "from": The source filename, relative to the default image folder. It must not contain a slash. // "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; + COPY_IMAGE = 20; // Write-protect an image file. // Parameters: // "file": The filename, relative to the default image folder. It must not contain a slash. - PROTECT_IMAGE = 19; + PROTECT_IMAGE = 21; // Make an image file writable. // Parameters: // "file": The filename, relative to the default image folder. It must not contain a slash. - UNPROTECT_IMAGE = 20; + UNPROTECT_IMAGE = 22; } // The properties supported by a device @@ -172,6 +178,17 @@ message PbImageFile { int64 size = 3; } +// The default image folder and the image files it contains +message PbImageFilesInfo { + string default_image_folder = 1; + repeated PbImageFile image_files = 2; +} + +// The network interfaces information +message PbNetworkInterfacesInfo { + repeated string name = 1; +} + // The device definition, sent from the client to the server message PbDeviceDefinition { int32 id = 1; @@ -234,6 +251,10 @@ message PbResult { PbServerInfo server_info = 3; // The result of a DEVICE_INFO command PbDevices device_info = 4; + // The result of an IMAGE_FILES_INFO command + PbImageFilesInfo image_files_info = 5; + // The result of a NETWORK_INTERFACES_INFO command + PbNetworkInterfacesInfo network_interfaces_info = 6; } } @@ -247,11 +268,10 @@ message PbServerInfo { // List of available log levels, ordered by increasing by severity repeated string log_levels = 4; string current_log_level = 5; - string default_image_folder = 6; // Supported device types and their properties - repeated PbDeviceTypeProperties types_properties = 7; - // Unordered list of files in the default image folder - repeated PbImageFile image_files = 8; + repeated PbDeviceTypeProperties types_properties = 6; + PbImageFilesInfo image_files_info = 7; + PbNetworkInterfacesInfo network_interfaces_info = 8; // The attached devices repeated PbDevice devices = 9; // The unsorted list of reserved IDs diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index a6f0867a..ae0008c5 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -154,23 +154,50 @@ void DisplayDeviceInfo(const PbDevice& pb_device) cout << endl; } +void DisplayImageFiles(const list image_files, const string& default_image_folder) +{ + cout << "Default image file folder: " << default_image_folder << endl; + + if (image_files.empty()) { + cout << " No image files available" << endl; + } + else { + list files = { image_files.begin(), image_files.end() }; + files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); }); + + cout << "Available image files:" << endl; + for (const auto& file : files) { + cout << " " << file.name() << " (" << file.size() << " bytes)"; + if (file.read_only()) { + cout << ", read-only"; + } + cout << endl; + } + } +} + +void DisplayNetworkInterfaces(list interfaces) +{ + interfaces.sort([](const auto& a, const auto& b) { return a < b; }); + + cout << "Available (up) network interfaces:" << endl; + bool isFirst = true; + for (const auto& interface : interfaces) { + if (!isFirst) { + cout << ", "; + } + isFirst = false; + cout << interface; + } + cout << endl; +} + //--------------------------------------------------------------------------- // // Command implementations // //--------------------------------------------------------------------------- -const PbServerInfo GetServerInfo(const string& hostname, int port) -{ - PbCommand command; - command.set_operation(SERVER_INFO); - - PbResult result; - SendCommand(hostname.c_str(), port, command, result); - - return result.server_info(); -} - void CommandList(const string& hostname, int port) { PbCommand command; @@ -183,31 +210,32 @@ void CommandList(const string& hostname, int port) cout << ListDevices(devices) << endl; } -void CommandLogLevel(const string& hostname, int port, const string& log_level) +const PbServerInfo GetServerInfo(const PbCommand& command, const string& hostname, int port) +{ + PbResult result; + SendCommand(hostname.c_str(), port, command, result); + + return result.server_info(); +} + +void CommandLogLevel(PbCommand& command, const string& hostname, int port, const string& log_level) { - PbCommand command; - command.set_operation(LOG_LEVEL); AddParam(command, "level", log_level); PbResult result; SendCommand(hostname.c_str(), port, command, result); } -void CommandReserve(const string&hostname, int port, const string& reserved_ids) +void CommandReserve(PbCommand& command, const string&hostname, int port, const string& reserved_ids) { - PbCommand command; - command.set_operation(RESERVE); AddParam(command, "ids", reserved_ids); PbResult result; SendCommand(hostname.c_str(), port, command, result); } -void CommandCreateImage(const string&hostname, int port, const string& image_params) +void CommandCreateImage(PbCommand& command, 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) { AddParam(command, "file", image_params.substr(0, separatorPos)); @@ -224,21 +252,16 @@ void CommandCreateImage(const string&hostname, int port, const string& image_par SendCommand(hostname.c_str(), port, command, result); } -void CommandDeleteImage(const string&hostname, int port, const string& filename) +void CommandDeleteImage(PbCommand& command, const string&hostname, int port, const string& filename) { - PbCommand command; - command.set_operation(DELETE_IMAGE); AddParam(command, "file", filename); PbResult result; SendCommand(hostname.c_str(), port, command, result); } -void CommandRenameImage(const string&hostname, int port, const string& image_params) +void CommandRenameImage(PbCommand& command, const string&hostname, int port, const string& image_params) { - PbCommand command; - command.set_operation(RENAME_IMAGE); - size_t separatorPos = image_params.find(COMPONENT_SEPARATOR); if (separatorPos != string::npos) { AddParam(command, "from", image_params.substr(0, separatorPos)); @@ -253,11 +276,8 @@ void CommandRenameImage(const string&hostname, int port, const string& image_par SendCommand(hostname.c_str(), port, command, result); } -void CommandCopyImage(const string&hostname, int port, const string& image_params) +void CommandCopyImage(PbCommand& command, const string&hostname, int port, const string& image_params) { - PbCommand command; - command.set_operation(COPY_IMAGE); - size_t separatorPos = image_params.find(COMPONENT_SEPARATOR); if (separatorPos != string::npos) { AddParam(command, "from", image_params.substr(0, separatorPos)); @@ -272,17 +292,15 @@ void CommandCopyImage(const string&hostname, int port, const string& image_param SendCommand(hostname.c_str(), port, command, result); } -void CommandDefaultImageFolder(const string& hostname, int port, const string& folder) +void CommandDefaultImageFolder(PbCommand& command, const string& hostname, int port, const string& folder) { - PbCommand command; - command.set_operation(DEFAULT_FOLDER); AddParam(command, "folder", folder); PbResult result; SendCommand(hostname.c_str(), port, command, result); } -void CommandDeviceInfo(const string& hostname, int port, const PbCommand& command) +void CommandDeviceInfo(const PbCommand& command, const string& hostname, int port) { PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -292,11 +310,8 @@ void CommandDeviceInfo(const string& hostname, int port, const PbCommand& comman } } -void CommandServerInfo(const string& hostname, int port) +void CommandServerInfo(PbCommand& command, const string& hostname, int port) { - PbCommand command; - command.set_operation(SERVER_INFO); - PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -316,30 +331,20 @@ void CommandServerInfo(const string& hostname, int port) } else { cout << "rascsi log levels, sorted by severity:" << endl; - for (int i = 0; i < server_info.log_levels_size(); i++) { - cout << " " << server_info.log_levels(i) << endl; + for (const auto& log_level : server_info.log_levels()) { + cout << " " << log_level << endl; } cout << "Current rascsi log level: " << server_info.current_log_level() << endl; } - cout << "Default image file folder: " << server_info.default_image_folder() << endl; - if (!server_info.image_files_size()) { - cout << " No image files available" << endl; - } - else { - list files = { server_info.image_files().begin(), server_info.image_files().end() }; - files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); }); + const list image_files = + { server_info.image_files_info().image_files().begin(), server_info.image_files_info().image_files().end() }; + DisplayImageFiles(image_files, server_info.image_files_info().default_image_folder()); - cout << "Available image files:" << endl; - for (const auto& file : files) { - cout << " " << file.name() << " (" << file.size() << " bytes)"; - if (file.read_only()) { - cout << ", read-only"; - } - cout << endl; - } - } + const list network_interfaces = + { server_info.network_interfaces_info().name().begin(), server_info.network_interfaces_info().name().end() }; + DisplayNetworkInterfaces(network_interfaces); cout << "Supported device types and their properties:" << endl; for (auto it = server_info.types_properties().begin(); it != server_info.types_properties().end(); ++it) { @@ -459,6 +464,26 @@ void CommandServerInfo(const string& hostname, int port) } } +void CommandImageFilesInfo(const PbCommand& command, const string& hostname, int port) +{ + PbResult result; + SendCommand(hostname.c_str(), port, command, result); + + const list image_files = + { result.image_files_info().image_files().begin(),result.image_files_info().image_files().end() }; + DisplayImageFiles(image_files, result.image_files_info().default_image_folder()); +} + +void CommandNetworkInterfacesInfo(const PbCommand& command, const string&hostname, int port) +{ + PbResult result; + SendCommand(hostname.c_str(), port, command, result); + + list network_interfaces = + { result.network_interfaces_info().name().begin(), result.network_interfaces_info().name().end() }; + DisplayNetworkInterfaces(network_interfaces); +} + PbOperation ParseOperation(const char *optarg) { switch (tolower(optarg[0])) { @@ -539,7 +564,7 @@ int main(int argc, char* argv[]) cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] "; 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 << "[-e] [-k] [-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; @@ -575,7 +600,7 @@ int main(int argc, char* argv[]) opterr = 1; int opt; - while ((opt = getopt(argc, argv, "a:b:c:d:f:g:h:i:m:n:p:r:t:u:x:w:lsv")) != -1) { + while ((opt = getopt(argc, argv, "a:b:c:d:f:g:h:i:m:n:p:r:t:u:x:w:eklsv")) != -1) { switch (opt) { case 'i': device->set_id(optarg[0] - '0'); @@ -612,10 +637,18 @@ int main(int argc, char* argv[]) default_folder = optarg; break; + case'e': + command.set_operation(IMAGE_FILES_INFO); + break; + case 'f': param = optarg; break; + case 'k': + command.set_operation(NETWORK_INTERFACES_INFO); + break; + case 't': device->set_type(ParseType(optarg)); if (device->type() == UNDEFINED) { @@ -710,39 +743,47 @@ int main(int argc, char* argv[]) switch(command.operation()) { case LOG_LEVEL: - CommandLogLevel(hostname, port, log_level); + CommandLogLevel(command, hostname, port, log_level); exit(EXIT_SUCCESS); case DEFAULT_FOLDER: - CommandDefaultImageFolder(hostname, port, default_folder); + CommandDefaultImageFolder(command, hostname, port, default_folder); exit(EXIT_SUCCESS); case RESERVE: - CommandReserve(hostname, port, reserved_ids); + CommandReserve(command, hostname, port, reserved_ids); exit(EXIT_SUCCESS); case CREATE_IMAGE: - CommandCreateImage(hostname, port, image_params); + CommandCreateImage(command, hostname, port, image_params); exit(EXIT_SUCCESS); case DELETE_IMAGE: - CommandDeleteImage(hostname, port, image_params); + CommandDeleteImage(command, hostname, port, image_params); exit(EXIT_SUCCESS); case RENAME_IMAGE: - CommandRenameImage(hostname, port, image_params); + CommandRenameImage(command, hostname, port, image_params); exit(EXIT_SUCCESS); case COPY_IMAGE: - CommandCopyImage(hostname, port, image_params); + CommandCopyImage(command, hostname, port, image_params); exit(EXIT_SUCCESS); case DEVICE_INFO: - CommandDeviceInfo(hostname, port, command); + CommandDeviceInfo(command, hostname, port); exit(EXIT_SUCCESS); case SERVER_INFO: - CommandServerInfo(hostname, port); + CommandServerInfo(command, hostname, port); + exit(EXIT_SUCCESS); + + case IMAGE_FILES_INFO: + CommandImageFilesInfo(command, hostname, port); + exit(EXIT_SUCCESS); + + case NETWORK_INTERFACES_INFO: + CommandNetworkInterfacesInfo(command, hostname, port); exit(EXIT_SUCCESS); default: