189 lines
6.6 KiB
Python
189 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""Author: Hendrik Schutter, localhorst@mosad.xyz
|
|
Date of creation: 2025/12/05
|
|
Date of last modification: 2025/12/05
|
|
"""
|
|
|
|
import ctypes
|
|
import os
|
|
import time
|
|
import argparse
|
|
|
|
# Constants
|
|
STR_BUFFER_SIZE = 64
|
|
MSG_QUEUE_KEY = 0x1B11193C0
|
|
IPC_CREAT = 0o1000
|
|
|
|
terminate = False
|
|
|
|
class TDriveData(ctypes.Structure):
|
|
_fields_ = [
|
|
("caDriveIndex", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveHours", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveCycles", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveErrors", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveShredTimestamp", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveShredDuration", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveCapacity", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveState", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveConnectionType", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveModelFamily", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveModelName", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveSerialnumber", ctypes.c_char * STR_BUFFER_SIZE),
|
|
("caDriveReHddVersion", ctypes.c_char * STR_BUFFER_SIZE),
|
|
]
|
|
|
|
|
|
class TMsgQueueData(ctypes.Structure):
|
|
_fields_ = [
|
|
("msg_queue_type", ctypes.c_long),
|
|
("driveData", TDriveData),
|
|
]
|
|
|
|
|
|
# IPC bindings - enable errno support
|
|
libc = ctypes.CDLL("libc.so.6", use_errno=True)
|
|
msgget = libc.msgget
|
|
msgrcv = libc.msgrcv
|
|
|
|
msgget.argtypes = [ctypes.c_int, ctypes.c_int]
|
|
msgget.restype = ctypes.c_int
|
|
|
|
msgrcv.argtypes = [
|
|
ctypes.c_int,
|
|
ctypes.POINTER(TMsgQueueData),
|
|
ctypes.c_size_t,
|
|
ctypes.c_long,
|
|
ctypes.c_int,
|
|
]
|
|
msgrcv.restype = ctypes.c_ssize_t
|
|
|
|
|
|
def create_drive_objects(drive_info):
|
|
"""Convert dictionary to layouter-compatible DriveData and ReHddInfo objects"""
|
|
drive = layouter.DriveData(
|
|
drive_index=int(drive_info["driveIndex"]),
|
|
drive_state=drive_info["driveState"],
|
|
modelfamily=drive_info["driveModelFamily"],
|
|
modelname=drive_info["driveModelName"],
|
|
capacity=int(drive_info["driveCapacity"]),
|
|
serialnumber=drive_info["driveSerialnumber"],
|
|
power_on_hours=int(drive_info["driveHours"]),
|
|
power_cycle=int(drive_info["driveCycles"]),
|
|
smart_error_count=int(drive_info["driveErrors"]),
|
|
shred_timestamp=int(drive_info["driveShredTimestamp"]),
|
|
shred_duration=int(drive_info["driveShredDuration"]),
|
|
connection_type=drive_info["driveConnectionType"],
|
|
)
|
|
|
|
rehdd_info = layouter.ReHddInfo(
|
|
link="https://git.mosad.xyz/localhorst/reHDD",
|
|
version=drive_info["driveReHddVersion"],
|
|
)
|
|
|
|
return drive, rehdd_info
|
|
|
|
|
|
def worker(queue_id, test_mode=False):
|
|
try:
|
|
while not terminate:
|
|
time.sleep(3)
|
|
if test_mode:
|
|
drive_info = {
|
|
"driveIndex": "42",
|
|
"driveHours": 44,
|
|
"driveCycles": 45,
|
|
"driveErrors": 43,
|
|
"driveShredTimestamp": int(time.time()),
|
|
"driveShredDuration": 0,
|
|
"driveCapacity": 42,
|
|
"driveState": "shredded",
|
|
"driveConnectionType": "sata",
|
|
"driveModelFamily": "modelFamily",
|
|
"driveModelName": "modelName",
|
|
"driveSerialnumber": "serial",
|
|
"driveReHddVersion": "V1.1.2",
|
|
}
|
|
else:
|
|
msg = TMsgQueueData()
|
|
print("Waiting for message from queue...")
|
|
|
|
# Calculate message size - must match C++ side: sizeof(t_msgQueueData) - sizeof(long)
|
|
# This is the size of the data portion (excluding msg_queue_type)
|
|
msg_size = ctypes.sizeof(TMsgQueueData) - ctypes.sizeof(ctypes.c_long)
|
|
|
|
print(f"Message size to receive: {msg_size} bytes")
|
|
|
|
result = msgrcv(
|
|
queue_id,
|
|
ctypes.byref(msg),
|
|
msg_size,
|
|
0, # msg type (0 = get first message)
|
|
0, # flags (0 = blocking)
|
|
)
|
|
|
|
if result == -1:
|
|
err = ctypes.get_errno()
|
|
print(
|
|
f"Error reading from message queue: {os.strerror(err)} (errno: {err})"
|
|
)
|
|
break
|
|
|
|
print(f"Received {result} bytes from queue")
|
|
|
|
d = msg.driveData
|
|
drive_info = {
|
|
"driveIndex": d.caDriveIndex.decode().strip("\x00"),
|
|
"driveHours": int(d.caDriveHours.decode().strip("\x00")),
|
|
"driveCycles": int(d.caDriveCycles.decode().strip("\x00")),
|
|
"driveErrors": int(d.caDriveErrors.decode().strip("\x00")),
|
|
"driveShredTimestamp": int(
|
|
d.caDriveShredTimestamp.decode().strip("\x00")
|
|
),
|
|
"driveShredDuration": int(
|
|
d.caDriveShredDuration.decode().strip("\x00")
|
|
),
|
|
"driveCapacity": int(d.caDriveCapacity.decode().strip("\x00")),
|
|
"driveState": d.caDriveState.decode().strip("\x00"),
|
|
"driveConnectionType": d.caDriveConnectionType.decode().strip("\x00"),
|
|
"driveModelFamily": d.caDriveModelFamily.decode().strip("\x00"),
|
|
"driveModelName": d.caDriveModelName.decode().strip("\x00"),
|
|
"driveSerialnumber": d.caDriveSerialnumber.decode().strip("\x00"),
|
|
"driveReHddVersion": d.caDriveReHddVersion.decode().strip("\x00"),
|
|
}
|
|
|
|
print(f"Received Drive Data: {drive_info}")
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
print(f"Worker encountered an error: {e}")
|
|
traceback.print_exc()
|
|
|
|
|
|
def main():
|
|
while True:
|
|
try:
|
|
# Create or connect to the message queue with IPC_CREAT flag
|
|
# This matches the C++ sender's flags (IPC_CREAT | 0666)
|
|
queue_id = msgget(MSG_QUEUE_KEY, IPC_CREAT | 0o666)
|
|
if queue_id == -1:
|
|
err = ctypes.get_errno()
|
|
raise RuntimeError(
|
|
f"Failed to create/connect to the message queue: {os.strerror(err)}"
|
|
)
|
|
|
|
print(f"Successfully connected to message queue (ID: {queue_id})")
|
|
worker(queue_id)
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
print(f"Main process encountered an error: {e}")
|
|
traceback.print_exc()
|
|
time.sleep(30)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|