2020-12-31 01:39:32 +00:00
|
|
|
import fnmatch
|
|
|
|
import subprocess
|
|
|
|
import re
|
|
|
|
|
|
|
|
from settings import *
|
2021-02-01 17:39:50 +00:00
|
|
|
|
2021-07-31 15:52:09 +00:00
|
|
|
|
2021-08-22 19:37:43 +00:00
|
|
|
valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.hdr", "*.iso", "*.cdr", "*.toast", "*.img", "*.zip"]
|
2021-07-31 15:52:09 +00:00
|
|
|
valid_file_types = r"|".join([fnmatch.translate(x) for x in valid_file_suffix])
|
2020-12-31 01:39:32 +00:00
|
|
|
# List of SCSI ID's you'd like to exclude - eg if you are on a Mac, the System is usually 7
|
|
|
|
EXCLUDE_SCSI_IDS = [7]
|
|
|
|
|
|
|
|
|
|
|
|
def is_active():
|
|
|
|
process = subprocess.run(["systemctl", "is-active", "rascsi"], capture_output=True)
|
|
|
|
return process.stdout.decode("utf-8").strip() == "active"
|
|
|
|
|
|
|
|
|
|
|
|
def list_files():
|
|
|
|
files_list = []
|
|
|
|
for path, dirs, files in os.walk(base_dir):
|
|
|
|
# Only list valid file types
|
|
|
|
files = [f for f in files if re.match(valid_file_types, f)]
|
2021-02-01 17:39:50 +00:00
|
|
|
files_list.extend(
|
|
|
|
[
|
|
|
|
(
|
|
|
|
os.path.join(path, file),
|
|
|
|
# TODO: move formatting to template
|
|
|
|
"{:,.0f}".format(
|
|
|
|
os.path.getsize(os.path.join(path, file)) / float(1 << 20)
|
|
|
|
)
|
|
|
|
+ " MB",
|
|
|
|
)
|
|
|
|
for file in files
|
|
|
|
]
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
return files_list
|
|
|
|
|
|
|
|
|
2021-02-01 18:24:59 +00:00
|
|
|
def list_config_files():
|
|
|
|
files_list = []
|
|
|
|
for root, dirs, files in os.walk(base_dir):
|
|
|
|
for file in files:
|
|
|
|
if file.endswith(".csv"):
|
|
|
|
files_list.append(file)
|
|
|
|
return files_list
|
|
|
|
|
|
|
|
|
2020-12-31 01:39:32 +00:00
|
|
|
def get_valid_scsi_ids(devices):
|
|
|
|
invalid_list = EXCLUDE_SCSI_IDS.copy()
|
|
|
|
for device in devices:
|
2021-02-01 17:39:50 +00:00
|
|
|
if device["file"] != "NO MEDIA" and device["file"] != "-":
|
|
|
|
invalid_list.append(int(device["id"]))
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
valid_list = list(range(8))
|
|
|
|
for id in invalid_list:
|
|
|
|
valid_list.remove(id)
|
|
|
|
valid_list.reverse()
|
|
|
|
|
|
|
|
return valid_list
|
|
|
|
|
|
|
|
|
|
|
|
def get_type(scsi_id):
|
|
|
|
return list_devices()[int(scsi_id)]["type"]
|
|
|
|
|
|
|
|
|
2021-08-23 08:30:14 +00:00
|
|
|
def attach_image(scsi_id, image, image_type):
|
|
|
|
if image_type == "SCCD" and get_type(scsi_id) == "SCCD":
|
2020-12-31 01:39:32 +00:00
|
|
|
return insert(scsi_id, image)
|
|
|
|
else:
|
2021-02-01 17:39:50 +00:00
|
|
|
return subprocess.run(
|
2021-08-23 08:30:14 +00:00
|
|
|
["rasctl", "-c", "attach", "-t", image_type, "-i", scsi_id, "-f", image],
|
2021-02-01 17:39:50 +00:00
|
|
|
capture_output=True,
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
def detach_by_id(scsi_id):
|
|
|
|
return subprocess.run(["rasctl", "-c" "detach", "-i", scsi_id], capture_output=True)
|
|
|
|
|
|
|
|
|
2021-02-01 18:24:59 +00:00
|
|
|
def detach_all():
|
|
|
|
for scsi_id in range(0, 7):
|
|
|
|
subprocess.run(["rasctl", "-c" "detach", "-i", str(scsi_id)])
|
|
|
|
|
|
|
|
|
2020-12-31 01:39:32 +00:00
|
|
|
def disconnect_by_id(scsi_id):
|
2021-02-01 17:39:50 +00:00
|
|
|
return subprocess.run(
|
|
|
|
["rasctl", "-c", "disconnect", "-i", scsi_id], capture_output=True
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
def eject_by_id(scsi_id):
|
|
|
|
return subprocess.run(["rasctl", "-i", scsi_id, "-c", "eject"])
|
|
|
|
|
|
|
|
|
|
|
|
def insert(scsi_id, image):
|
2021-02-01 17:39:50 +00:00
|
|
|
return subprocess.run(
|
|
|
|
["rasctl", "-i", scsi_id, "-c", "insert", "-f", image], capture_output=True
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
|
2021-02-01 18:24:59 +00:00
|
|
|
def attach_daynaport(scsi_id):
|
|
|
|
return subprocess.run(
|
Refactoring, device handling extensions, additional settings, improved error handling, 64 bit OS support, fixed issues (#184)
* Device type unification, support of removable media
* Added support for .hdr extension
* Removable flag cleanup
* Manpage update
* Enriched PbOperation with PbDevice
* Added file size to PbImageFile
* Added device list support
* Set image_file
* Make remote interface more robust by ignoring SIGPIPE
* Return status only once
* Fixed typo
* Error handling update
* When starting rascsi parse everything before attaching devices
* Added dry run mode
* Comment update
* Updated logging
* Added Device base class, Disk class inherits from it
* Renaming
* Use vectors for controllers and disks, as preparation for using maps
* Updated file support handling
* Comment update
* DaynaPort and Bridge inherit from Device instead of Disk
* ProcessCmd() now works with devices instead of disks
* Renaming
* Added DeviceFactory
* Improved factory
* Comment update
* protected disk_t
* Code cleanup, added translations
* Device name can be set for rascsi
* rasctl can set device name
* Manpage update
* Manpage update
* Formatting update
* Check for missing name
* Initialize fd
* Initialize type
* Fixed string length issue
* Updated capacity formatting
* Fixed typo
* Split PbDevice into device and device definition
* Added TODO
* Renaming
* Renaming
* Device types can be explicitly specified with -t (no FILE:TYPE syntax anymore)
* Fixed compile-time issue
* Removed unused Append mode, updated read-only handling
* Type handling and manpage update
* Cleanup
* rasctl parser cleanup
* Review
* Constructor update
* Added .hdr (SCRM) support to web interface, tested web interface
* Default folder can be set remotely
* Removed deprecated operation
* DETACH supports all parameters in order to detach all devices
* include cleanup
* Logging should not depend on NDEBUG, for RaSCSI it is not peformance-critical
* INFO is default log level
* Exception renaming
* Updated GetPaddedName()
* Inheritance update
* Added BlockDevice class
* Removed unused code
* Updated typedefs
* Revert "Updated typedefs"
This reverts commit 546b46215a4d9b65067a11698e59ab1123cc6d64.
* Removed unused code
* Fixed warnign
* Use standard C++ integer types, use streams to resolve printf data type issues
* Added TODOs
* Added TODO
* Renaming
* Added TODO
* Added TODO
* Improved dry-run
* Code cleanup
* Updated handling of unknown options, code review and cleanup
* Manpage update
* Added PrimaryDevice
* Include cleanup
* Added pure virtual methods
* Comment updates
* Split rasutil
* Replaced some occurrences of BOOL
* Removed obsolete RASCSI definition in xm6.h
* Removed unused code, updated TODOs, replaced BOOL
* Added capacity check (issue #192)
* Fixed (most likely) https://github.com/akuker/RASCSI/issues/191
* Fixed wrong error messages
* For root the default image folder is /home/pi/images, updated error handling
* Dynaport code review
* Improved error handling
* Implemented READ CAPACITY(16)
* Comment update
* Commands can be 16 bytes long
* Implemented READ/WRITE/VERIFY(16)
* Comment update
* Renamed method to reflect the name of the respective SCSI command
* Do not created devices during dryRun
* Fixed padding of SCSIHD_APPLE vendor and product
* Initial implementation
* Updated ReportLuns
* Byte count update
* Fixed typo
* Finalized REPORT LUNS
* Removed TODO
* Updated TODO
* TODO update
* Updated device factory
* Comment update
* 64 bit update, tested on Ubuntu 64 bit system
* Removed assertion
* SCSI hard disks always have Apple specific mode pages (resolves issue #193)
* Error messsage update, 64 bit cleanup
* Reduced streams usage
* Updated handling of device flags
* MOs are protectable
* Removed duplicate error code handling
* Removed duplicate code
* Fixed CmdReadToc buffer overflow (https://github.com/akuker/RASCSI/issues/194)
* Added naive implementation of GET EVENT STATUS NOTIFICATION to avoid wranings
* HD must set removable device bit if the media is removable
* Removed duplicate logging
* Updated daynaport additional length
* Removed broken daynaport REQUEST SENSE. Successfully tested with my Mac.
* EnableInterface should not always return TRUE
* Updated Inquiry
* Updated LUN handling
* Replaced incorrect free by delete
* Updated comments and write-protection handling
* Made default HD name consistent
* STATUS_NOERROR is default
* Fixed Eject
* More eject handling updates
* Manpage updates
* Logging update
* Changed debug level
* Logging update
* Log capacity of all media types
* Logging update
* Encapsulated disk.blocks
* Encapsulated sector size
* Added overrides
* Added more overrides
* Fixed error message
* Fixed typos
* Fixed logging
* Added logging
* Use PrimaryDevice when calling Inquiry
* Comment update
* Changed default buffer size for testing
* Reverted last change
* Removed debug output
* De-inlined methods because optimized code did not work with them inlined
* Web interface can attach Daynaport again
* Improved handling of read-only hard disks
* Fixed issue with "all" semantics of DETACH
* rasctl supports adding removable media devices without providing a filename
* Removed unused flag in PbDeviceDefinition
* Updated rasctl output for ecjected media (resolves issue #199)
* Validate default folder name when changing default folder
2021-08-21 21:45:30 +00:00
|
|
|
["rasctl", "-i", scsi_id, "-c", "attach", "-t", "scdp"],
|
2021-02-01 18:24:59 +00:00
|
|
|
capture_output=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def is_bridge_setup(interface):
|
|
|
|
process = subprocess.run(["brctl", "show"], capture_output=True)
|
|
|
|
output = process.stdout.decode("utf-8")
|
|
|
|
if "rascsi_bridge" in output and interface in output:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def daynaport_setup_bridge(interface):
|
|
|
|
return subprocess.run(
|
|
|
|
[f"{base_dir}../RASCSI/src/raspberrypi/setup_bridge.sh", interface],
|
|
|
|
capture_output=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-12-31 01:39:32 +00:00
|
|
|
def rascsi_service(action):
|
|
|
|
# start/stop/restart
|
2021-02-01 17:39:50 +00:00
|
|
|
return (
|
|
|
|
subprocess.run(["sudo", "/bin/systemctl", action, "rascsi.service"]).returncode
|
|
|
|
== 0
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
def list_devices():
|
|
|
|
device_list = []
|
|
|
|
for id in range(8):
|
|
|
|
device_list.append({"id": str(id), "un": "-", "type": "-", "file": "-"})
|
2021-02-01 17:39:50 +00:00
|
|
|
output = subprocess.run(["rasctl", "-l"], capture_output=True).stdout.decode(
|
|
|
|
"utf-8"
|
|
|
|
)
|
2020-12-31 01:39:32 +00:00
|
|
|
for line in output.splitlines():
|
|
|
|
# Valid line to process, continue
|
2021-02-01 17:39:50 +00:00
|
|
|
if (
|
|
|
|
not line.startswith("+")
|
|
|
|
and not line.startswith("| ID |")
|
|
|
|
and (
|
|
|
|
not line.startswith("No device is installed.")
|
|
|
|
or line.startswith("No images currently attached.")
|
|
|
|
)
|
|
|
|
and len(line) > 0
|
|
|
|
):
|
2020-12-31 01:39:32 +00:00
|
|
|
line.rstrip()
|
|
|
|
device = {}
|
|
|
|
segments = line.split("|")
|
|
|
|
if len(segments) > 4:
|
|
|
|
idx = int(segments[1].strip())
|
|
|
|
device_list[idx]["id"] = str(idx)
|
2021-02-01 17:39:50 +00:00
|
|
|
device_list[idx]["un"] = segments[2].strip()
|
|
|
|
device_list[idx]["type"] = segments[3].strip()
|
|
|
|
device_list[idx]["file"] = segments[4].strip()
|
2020-12-31 01:39:32 +00:00
|
|
|
|
|
|
|
return device_list
|