mirror of
https://github.com/naruxde/revpipyload.git
synced 2026-08-16 13:07:03 +02:00
Merge tag 'unstable/0.12.0_rc1' into pkg/debian_rc
This commit is contained in:
@@ -7,7 +7,7 @@ plcworkdir_set_uid = 1
|
|||||||
plcprogram = program.py
|
plcprogram = program.py
|
||||||
plcprogram_stop_timeout = 5
|
plcprogram_stop_timeout = 5
|
||||||
plcprogram_watchdog = 0
|
plcprogram_watchdog = 0
|
||||||
plcarguments =
|
plcarguments =
|
||||||
plcuid = 1000
|
plcuid = 1000
|
||||||
plcgid = 1000
|
plcgid = 1000
|
||||||
pythonversion = 3
|
pythonversion = 3
|
||||||
@@ -27,7 +27,8 @@ watchdog = 1
|
|||||||
[XMLRPC]
|
[XMLRPC]
|
||||||
xmlrpc = 1
|
xmlrpc = 1
|
||||||
aclfile = /etc/revpipyload/aclxmlrpc.conf
|
aclfile = /etc/revpipyload/aclxmlrpc.conf
|
||||||
bindip = 127.0.0.1
|
bindip = socket
|
||||||
|
unixgroup = picontrol
|
||||||
|
|
||||||
[MQTT]
|
[MQTT]
|
||||||
mqtt = 0
|
mqtt = 0
|
||||||
@@ -38,6 +39,6 @@ write_outputs = 0
|
|||||||
broker_address = localhost
|
broker_address = localhost
|
||||||
port = 1883
|
port = 1883
|
||||||
tls_set = 0
|
tls_set = 0
|
||||||
username =
|
username =
|
||||||
password =
|
password =
|
||||||
client_id =
|
client_id =
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ __author__ = "Sven Sager"
|
|||||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
__package__ = "revpipyload"
|
__package__ = "revpipyload"
|
||||||
__version__ = "0.11.0rc2"
|
__version__ = "0.12.0"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
|
from os import getpid
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ def configure():
|
|||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-c", "--conffile", dest="conffile",
|
"-c", "--conffile", dest="conffile",
|
||||||
default="revpipyload.conf",
|
default="/etc/revpipyload/revpipyload.conf",
|
||||||
help="Application configuration file"
|
help="Application configuration file"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -186,3 +187,6 @@ def configure():
|
|||||||
else:
|
else:
|
||||||
loglevel = logging.DEBUG
|
loglevel = logging.DEBUG
|
||||||
logger.setLevel(loglevel)
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
|
# Log PID for development purposes
|
||||||
|
logger.debug("Running with PID {}".format(getpid()))
|
||||||
|
|||||||
+100
-34
@@ -31,6 +31,7 @@ __license__ = "GPLv2"
|
|||||||
import gzip
|
import gzip
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
@@ -51,7 +52,7 @@ from . import proginit
|
|||||||
from .helper import get_revpiled_address, pi_control_reset, refullmatch
|
from .helper import get_revpiled_address, pi_control_reset, refullmatch
|
||||||
from .shared.ipaclmanager import IpAclManager
|
from .shared.ipaclmanager import IpAclManager
|
||||||
from .watchdogs import ResetDriverWatchdog
|
from .watchdogs import ResetDriverWatchdog
|
||||||
from .xrpcserver import SaveXMLRPCServer
|
from .xrpcserver import SaveXMLRPCServer, UnixStreamXMLRPCServer
|
||||||
|
|
||||||
min_revpimodio = "2.5.0"
|
min_revpimodio = "2.5.0"
|
||||||
|
|
||||||
@@ -69,7 +70,8 @@ class RevPiPyLoad:
|
|||||||
proginit.logger.debug("enter RevPiPyLoad.__init__()")
|
proginit.logger.debug("enter RevPiPyLoad.__init__()")
|
||||||
|
|
||||||
# Klassenattribute
|
# Klassenattribute
|
||||||
self._exit = True
|
self._evt_exit = Event()
|
||||||
|
self._evt_exit.set()
|
||||||
self.evt_loadconfig = Event()
|
self.evt_loadconfig = Event()
|
||||||
self.globalconfig = ConfigParser()
|
self.globalconfig = ConfigParser()
|
||||||
proginit.conf = self.globalconfig
|
proginit.conf = self.globalconfig
|
||||||
@@ -209,7 +211,9 @@ class RevPiPyLoad:
|
|||||||
proginit.logger.info(
|
proginit.logger.info(
|
||||||
"loading config file: {0}".format(proginit.globalconffile)
|
"loading config file: {0}".format(proginit.globalconffile)
|
||||||
)
|
)
|
||||||
self.globalconfig.read(proginit.globalconffile)
|
if not self.globalconfig.read(proginit.globalconffile):
|
||||||
|
raise RuntimeError("can not access config file '{0}'".format(proginit.globalconffile))
|
||||||
|
|
||||||
self.__translate_config()
|
self.__translate_config()
|
||||||
proginit.conf = self.globalconfig
|
proginit.conf = self.globalconfig
|
||||||
|
|
||||||
@@ -313,12 +317,23 @@ class RevPiPyLoad:
|
|||||||
# Bind IP lesen und anpassen
|
# Bind IP lesen und anpassen
|
||||||
self.xmlrpcbindip = \
|
self.xmlrpcbindip = \
|
||||||
self.globalconfig.get("XMLRPC", "bindip", fallback="127.0.0.1")
|
self.globalconfig.get("XMLRPC", "bindip", fallback="127.0.0.1")
|
||||||
if self.xmlrpcbindip == "*":
|
|
||||||
self.xmlrpcbindip = ""
|
if self.xmlrpcbindip.lower() == "socket":
|
||||||
elif self.xmlrpcbindip == "":
|
# Unix Domain Socket mit festem Pfad
|
||||||
self.xmlrpcbindip = "127.0.0.1"
|
self.xmlrpcbindip = "/run/revpipyload/xmlrpc.socket"
|
||||||
|
self.xmlrpcisunix = True
|
||||||
|
elif self.xmlrpcbindip.startswith("/"):
|
||||||
|
# Unix Domain Socket
|
||||||
|
self.xmlrpcisunix = True
|
||||||
|
else:
|
||||||
|
self.xmlrpcisunix = False
|
||||||
|
if self.xmlrpcbindip == "*":
|
||||||
|
self.xmlrpcbindip = ""
|
||||||
|
elif self.xmlrpcbindip == "":
|
||||||
|
self.xmlrpcbindip = "127.0.0.1"
|
||||||
|
|
||||||
self.xmlrpcport = self.globalconfig.getint("XMLRPC", "port", fallback=55123)
|
self.xmlrpcport = self.globalconfig.getint("XMLRPC", "port", fallback=55123)
|
||||||
|
self.xmlrpcunixgroup = self.globalconfig.get("XMLRPC", "unixgroup", fallback="picontrol")
|
||||||
|
|
||||||
# Workdirectory wechseln
|
# Workdirectory wechseln
|
||||||
if not os.access(self.plcworkdir, os.R_OK | os.W_OK | os.X_OK):
|
if not os.access(self.plcworkdir, os.R_OK | os.W_OK | os.X_OK):
|
||||||
@@ -343,7 +358,7 @@ class RevPiPyLoad:
|
|||||||
self.stop_plcmqtt()
|
self.stop_plcmqtt()
|
||||||
self.th_plcmqtt = self._plcmqtt()
|
self.th_plcmqtt = self._plcmqtt()
|
||||||
|
|
||||||
if not self._exit and self.th_plcmqtt is not None:
|
if not self._evt_exit.is_set() and self.th_plcmqtt is not None:
|
||||||
proginit.logger.info("restart mqtt publisher after reload")
|
proginit.logger.info("restart mqtt publisher after reload")
|
||||||
self.th_plcmqtt.start()
|
self.th_plcmqtt.start()
|
||||||
|
|
||||||
@@ -352,7 +367,7 @@ class RevPiPyLoad:
|
|||||||
self.stop_plcprogram()
|
self.stop_plcprogram()
|
||||||
self.plc = self._plcthread()
|
self.plc = self._plcthread()
|
||||||
|
|
||||||
if not self._exit and self.plc is not None and self.autostart:
|
if not self._evt_exit.is_set() and self.plc is not None and self.autostart:
|
||||||
proginit.logger.info("restart plc program after reload")
|
proginit.logger.info("restart plc program after reload")
|
||||||
self.plc.start()
|
self.plc.start()
|
||||||
|
|
||||||
@@ -372,7 +387,7 @@ class RevPiPyLoad:
|
|||||||
self.stop_plcserver()
|
self.stop_plcserver()
|
||||||
self.th_plcserver = self._plcserver()
|
self.th_plcserver = self._plcserver()
|
||||||
|
|
||||||
if not self._exit and self.th_plcserver is not None:
|
if not self._evt_exit.is_set() and self.th_plcserver is not None:
|
||||||
proginit.logger.info("restart plc server after reload")
|
proginit.logger.info("restart plc server after reload")
|
||||||
self.th_plcserver.start()
|
self.th_plcserver.start()
|
||||||
|
|
||||||
@@ -387,12 +402,35 @@ class RevPiPyLoad:
|
|||||||
self.xsrv = None
|
self.xsrv = None
|
||||||
else:
|
else:
|
||||||
proginit.logger.debug("create xmlrpc server")
|
proginit.logger.debug("create xmlrpc server")
|
||||||
self.xsrv = SaveXMLRPCServer(
|
|
||||||
(self.xmlrpcbindip, self.xmlrpcport),
|
if self.xmlrpcisunix:
|
||||||
logRequests=False,
|
# Unix Domain Socket Server
|
||||||
allow_none=True,
|
proginit.logger.info(
|
||||||
ipacl=self.xmlrpcacl
|
"starting xmlrpc unix server on {0}".format(self.xmlrpcbindip)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Vorherige Socket-Datei löschen
|
||||||
|
try:
|
||||||
|
os.unlink(self.xmlrpcbindip)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.xsrv = UnixStreamXMLRPCServer(
|
||||||
|
self.xmlrpcbindip,
|
||||||
|
logRequests=False,
|
||||||
|
allow_none=True,
|
||||||
|
unixgroup=self.xmlrpcunixgroup
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Standard IP Server
|
||||||
|
self.xsrv = SaveXMLRPCServer(
|
||||||
|
(self.xmlrpcbindip, self.xmlrpcport),
|
||||||
|
logRequests=False,
|
||||||
|
allow_none=True,
|
||||||
|
ipacl=self.xmlrpcacl
|
||||||
|
)
|
||||||
|
|
||||||
self.xsrv.register_introspection_functions()
|
self.xsrv.register_introspection_functions()
|
||||||
self.xsrv.register_multicall_functions()
|
self.xsrv.register_multicall_functions()
|
||||||
|
|
||||||
@@ -485,7 +523,7 @@ class RevPiPyLoad:
|
|||||||
proginit.logger.debug("created xmlrpc server")
|
proginit.logger.debug("created xmlrpc server")
|
||||||
|
|
||||||
# Neustart bei reload
|
# Neustart bei reload
|
||||||
if not self._exit:
|
if not self._evt_exit.is_set():
|
||||||
proginit.logger.info("bind xmlrpc-server")
|
proginit.logger.info("bind xmlrpc-server")
|
||||||
self.xsrv.server_bind()
|
self.xsrv.server_bind()
|
||||||
self.xsrv.server_activate()
|
self.xsrv.server_activate()
|
||||||
@@ -762,7 +800,7 @@ class RevPiPyLoad:
|
|||||||
proginit.logger.debug("enter RevPiPyLoad.start()")
|
proginit.logger.debug("enter RevPiPyLoad.start()")
|
||||||
|
|
||||||
proginit.logger.info("starting revpipyload")
|
proginit.logger.info("starting revpipyload")
|
||||||
self._exit = False
|
self._evt_exit.clear()
|
||||||
|
|
||||||
if self.xmlrpc and self.xsrv is not None:
|
if self.xmlrpc and self.xsrv is not None:
|
||||||
proginit.logger.info("bind xmlrpc-server")
|
proginit.logger.info("bind xmlrpc-server")
|
||||||
@@ -786,7 +824,7 @@ class RevPiPyLoad:
|
|||||||
pictory_reset_driver.register_call(self.xml_psstop)
|
pictory_reset_driver.register_call(self.xml_psstop)
|
||||||
|
|
||||||
# mainloop
|
# mainloop
|
||||||
while not self._exit:
|
while not self._evt_exit.is_set():
|
||||||
# Neue Konfiguration laden
|
# Neue Konfiguration laden
|
||||||
if self.evt_loadconfig.is_set():
|
if self.evt_loadconfig.is_set():
|
||||||
proginit.logger.info("got reqeust to reload config")
|
proginit.logger.info("got reqeust to reload config")
|
||||||
@@ -887,7 +925,7 @@ class RevPiPyLoad:
|
|||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stop revpipyload."""
|
"""Stop revpipyload."""
|
||||||
proginit.logger.debug("enter RevPiPyLoad.stop()")
|
proginit.logger.debug("enter RevPiPyLoad.stop()")
|
||||||
self._exit = True
|
self._evt_exit.set()
|
||||||
proginit.logger.debug("leave RevPiPyLoad.stop()")
|
proginit.logger.debug("leave RevPiPyLoad.stop()")
|
||||||
|
|
||||||
def stop_plcmqtt(self):
|
def stop_plcmqtt(self):
|
||||||
@@ -937,6 +975,14 @@ class RevPiPyLoad:
|
|||||||
proginit.logger.info("close xmlrpc-server")
|
proginit.logger.info("close xmlrpc-server")
|
||||||
self.xsrv.server_close()
|
self.xsrv.server_close()
|
||||||
|
|
||||||
|
# Unix Socket aufräumen
|
||||||
|
if hasattr(self.xsrv, "address_family") and \
|
||||||
|
self.xsrv.address_family == socket.AF_UNIX:
|
||||||
|
try:
|
||||||
|
os.unlink(self.xsrv.server_address)
|
||||||
|
except (FileNotFoundError, AttributeError):
|
||||||
|
pass
|
||||||
|
|
||||||
proginit.logger.debug("leave RevPiPyLoad.stop_xmlrpcserver()")
|
proginit.logger.debug("leave RevPiPyLoad.stop_xmlrpcserver()")
|
||||||
|
|
||||||
def xml_getconfig(self):
|
def xml_getconfig(self):
|
||||||
@@ -1064,11 +1110,19 @@ class RevPiPyLoad:
|
|||||||
:param file_name: File with full path relative to work directory
|
:param file_name: File with full path relative to work directory
|
||||||
:return: True on success
|
:return: True on success
|
||||||
"""
|
"""
|
||||||
file_name = os.path.join(self.plcworkdir, file_name)
|
plcworkdir = os.path.realpath(self.plcworkdir)
|
||||||
if os.path.exists(file_name):
|
file_path = os.path.realpath(os.path.join(plcworkdir, file_name))
|
||||||
os.remove(file_name)
|
|
||||||
dirname = os.path.dirname(file_name)
|
if os.path.commonpath([plcworkdir, file_path]) != plcworkdir:
|
||||||
if dirname != self.plcworkdir:
|
proginit.logger.warning(
|
||||||
|
"file path is not in plc working directory"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
os.remove(file_path)
|
||||||
|
dirname = os.path.dirname(file_path)
|
||||||
|
if dirname != plcworkdir:
|
||||||
try:
|
try:
|
||||||
# Try to remove directory, which will work if it is empty
|
# Try to remove directory, which will work if it is empty
|
||||||
os.rmdir(dirname)
|
os.rmdir(dirname)
|
||||||
@@ -1104,9 +1158,17 @@ class RevPiPyLoad:
|
|||||||
:param file_name: File with full path relative to work directory
|
:param file_name: File with full path relative to work directory
|
||||||
:return: Binary object in gzip format
|
:return: Binary object in gzip format
|
||||||
"""
|
"""
|
||||||
file_name = os.path.join(self.plcworkdir, file_name)
|
plcworkdir = os.path.realpath(self.plcworkdir)
|
||||||
if os.path.exists(file_name):
|
file_path = os.path.realpath(os.path.join(plcworkdir, file_name))
|
||||||
with open(file_name, "rb") as fh:
|
|
||||||
|
if os.path.commonpath([plcworkdir, file_path]) != plcworkdir:
|
||||||
|
proginit.logger.warning(
|
||||||
|
"file path is not in plc working directory"
|
||||||
|
)
|
||||||
|
return Binary()
|
||||||
|
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
with open(file_path, "rb") as fh:
|
||||||
xmldata = Binary(gzip.compress(fh.read()))
|
xmldata = Binary(gzip.compress(fh.read()))
|
||||||
return xmldata
|
return xmldata
|
||||||
return Binary()
|
return Binary()
|
||||||
@@ -1169,7 +1231,7 @@ class RevPiPyLoad:
|
|||||||
else:
|
else:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def xml_plcupload(self, filedata, filename):
|
def xml_plcupload(self, filedata: Binary, filename:str):
|
||||||
"""Empfaengt Dateien fuer das PLC Programm einzeln.
|
"""Empfaengt Dateien fuer das PLC Programm einzeln.
|
||||||
|
|
||||||
@param filedata GZIP Binary data der Datei
|
@param filedata GZIP Binary data der Datei
|
||||||
@@ -1185,14 +1247,18 @@ class RevPiPyLoad:
|
|||||||
# Windowszeichen prüfen
|
# Windowszeichen prüfen
|
||||||
filename = filename.replace("\\", "/")
|
filename = filename.replace("\\", "/")
|
||||||
|
|
||||||
# Build absolut path, join will return last element, if absolute
|
|
||||||
dirname = os.path.join(self.plcworkdir, os.path.dirname(filename))
|
plcworkdir = os.path.realpath(self.plcworkdir)
|
||||||
if os.path.abspath(dirname).find(self.plcworkdir) != 0:
|
file_path = os.path.realpath(os.path.join(plcworkdir, filename))
|
||||||
|
|
||||||
|
if os.path.commonpath([plcworkdir, file_path]) != plcworkdir:
|
||||||
proginit.logger.warning(
|
proginit.logger.warning(
|
||||||
"file path is not in plc working directory"
|
"file path is not in plc working directory"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
dirname = os.path.dirname(file_path)
|
||||||
|
|
||||||
set_uid = self.plcuid if self.plcworkdir_set_uid else 0
|
set_uid = self.plcuid if self.plcworkdir_set_uid else 0
|
||||||
set_gid = self.plcgid if self.plcworkdir_set_uid else 0
|
set_gid = self.plcgid if self.plcworkdir_set_uid else 0
|
||||||
|
|
||||||
@@ -1210,9 +1276,9 @@ class RevPiPyLoad:
|
|||||||
|
|
||||||
# Datei erzeugen
|
# Datei erzeugen
|
||||||
try:
|
try:
|
||||||
with open(filename, "wb") as fh:
|
with open(file_path, "wb") as fh:
|
||||||
fh.write(gzip.decompress(filedata.data))
|
fh.write(gzip.decompress(filedata.data))
|
||||||
os.chown(filename, set_uid, set_gid)
|
os.chown(file_path, set_uid, set_gid)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ def main() -> int:
|
|||||||
"""Secure installation script to use on Revolution Pi."""
|
"""Secure installation script to use on Revolution Pi."""
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from os import R_OK, access, getuid, system
|
from os import R_OK, access, getuid, system
|
||||||
|
from shutil import which
|
||||||
from re import match
|
from re import match
|
||||||
from sys import stderr, stdout
|
from sys import stderr, stdout
|
||||||
|
|
||||||
@@ -42,7 +43,9 @@ def main() -> int:
|
|||||||
# Prepare variables
|
# Prepare variables
|
||||||
xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4)
|
xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4)
|
||||||
xmlrpcacl.loadaclfile(aclxmlrpc)
|
xmlrpcacl.loadaclfile(aclxmlrpc)
|
||||||
xmlrpc_only_localhost = xmlrpcbindip.find("127.") == 0 or xmlrpcbindip == ""
|
xmlrpc_unix_socket = xmlrpcbindip == "socket" or xmlrpcbindip.startswith("/")
|
||||||
|
xmlrpc_only_localhost = xmlrpcbindip.find("127.") == 0 or xmlrpcbindip == "" or \
|
||||||
|
xmlrpc_unix_socket
|
||||||
|
|
||||||
# ----- Print summary of actual configuration
|
# ----- Print summary of actual configuration
|
||||||
stdout.write("""
|
stdout.write("""
|
||||||
@@ -58,7 +61,8 @@ def main() -> int:
|
|||||||
aclxmlrpc=aclxmlrpc,
|
aclxmlrpc=aclxmlrpc,
|
||||||
xmlrpc="" if xmlrpc else "NOT ",
|
xmlrpc="" if xmlrpc else "NOT ",
|
||||||
source="" if not xmlrpc
|
source="" if not xmlrpc
|
||||||
else " from this computer only (localhost)." if xmlrpc_only_localhost
|
else " from this computer / SSH only (unix socket)." if xmlrpcbindip == "socket" or xmlrpcbindip.startswith("/")
|
||||||
|
else " from this computer / SSH only (localhost)." if xmlrpc_only_localhost
|
||||||
else " from ACL listed remote computers!"
|
else " from ACL listed remote computers!"
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -81,7 +85,7 @@ def main() -> int:
|
|||||||
stdout.write("{0:15} - Level: {1:2}".format(ip, level))
|
stdout.write("{0:15} - Level: {1:2}".format(ip, level))
|
||||||
counter += 1
|
counter += 1
|
||||||
stdout.write("\n")
|
stdout.write("\n")
|
||||||
else:
|
elif not xmlrpc_unix_socket:
|
||||||
stderr.write(
|
stderr.write(
|
||||||
"\nWARNING: NO IP addresses defined in ACL!\n You will "
|
"\nWARNING: NO IP addresses defined in ACL!\n You will "
|
||||||
"not be able to connect with RevPiPyControl at this moment!\n"
|
"not be able to connect with RevPiPyControl at this moment!\n"
|
||||||
@@ -99,8 +103,14 @@ def main() -> int:
|
|||||||
stderr.write("\nYou need root permissions to change values (sudo).\n")
|
stderr.write("\nYou need root permissions to change values (sudo).\n")
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
cmd = input("\nDo you want to allow connections from remote hosts? (y/N) ").lower()
|
cmd = input("\nDo you want to allow connections ONLY via SSH/Unix-Socket? (y/N) ").lower()
|
||||||
if cmd == "y":
|
if cmd == "y":
|
||||||
|
conf.set("XMLRPC", "xmlrpc", "1")
|
||||||
|
conf.set("XMLRPC", "bindip", "socket")
|
||||||
|
xmlrpcacl.acl = ""
|
||||||
|
save_xmlrpcacls()
|
||||||
|
|
||||||
|
elif input("\nDo you want to allow connections from remote hosts? (y/N) ").lower() == "y":
|
||||||
conf.set("XMLRPC", "xmlrpc", "1")
|
conf.set("XMLRPC", "xmlrpc", "1")
|
||||||
conf.set("XMLRPC", "bindip", "*")
|
conf.set("XMLRPC", "bindip", "*")
|
||||||
|
|
||||||
@@ -169,15 +179,25 @@ def main() -> int:
|
|||||||
stdout.write("\n\nWe did no changes!\n")
|
stdout.write("\n\nWe did no changes!\n")
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
if system("/etc/init.d/revpipyload status > /dev/null") == 0:
|
# Check for service manager
|
||||||
|
if which("systemctl"):
|
||||||
|
cmd_status = "systemctl status revpipyload > /dev/null"
|
||||||
|
cmd_reload = "systemctl reload revpipyload"
|
||||||
|
hint_reload = "sudo systemctl reload revpipyload"
|
||||||
|
else:
|
||||||
|
cmd_status = "/etc/init.d/revpipyload status > /dev/null"
|
||||||
|
cmd_reload = "/etc/init.d/revpipyload reload"
|
||||||
|
hint_reload = "sudo /etc/init.d/revpipyload reload"
|
||||||
|
|
||||||
|
if system(cmd_status) == 0:
|
||||||
try:
|
try:
|
||||||
cmd = input("\nDo you want to apply the new settings now? (Y/n) ").lower()
|
cmd = input("\nDo you want to apply the new settings now? (Y/n) ").lower()
|
||||||
if cmd in ("", "y"):
|
if cmd in ("", "y"):
|
||||||
system("/etc/init.d/revpipyload reload")
|
system(cmd_reload)
|
||||||
else:
|
else:
|
||||||
stderr.write(
|
stderr.write(
|
||||||
"\nYou have to activate the new settings for RevPiPyLoad!\n"
|
"\nYou have to activate the new settings for RevPiPyLoad!\n"
|
||||||
" sudo /etc/init.d/revpipyload reload\n"
|
" {0}\n".format(hint_reload)
|
||||||
)
|
)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ __author__ = "Sven Sager"
|
|||||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
|
import grp
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
||||||
|
|
||||||
from . import proginit
|
from . import proginit
|
||||||
@@ -102,3 +105,92 @@ class SaveXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UnixStreamXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
|
"""XML-RPC Request-Handler fuer Unix Domain Sockets."""
|
||||||
|
|
||||||
|
timeout = 2.0
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
"""Initialisiert die Verbindung ohne TCP-spezifische Socket-Optionen."""
|
||||||
|
self.connection = self.request
|
||||||
|
if self.timeout is not None:
|
||||||
|
self.connection.settimeout(self.timeout)
|
||||||
|
self.rfile = self.connection.makefile("rb", self.rbufsize)
|
||||||
|
self.wfile = self.connection.makefile("wb", self.wbufsize)
|
||||||
|
|
||||||
|
def address_string(self):
|
||||||
|
"""Liefert einen Namen fuer Logging bei Unix Domain Sockets."""
|
||||||
|
return "localhost"
|
||||||
|
|
||||||
|
|
||||||
|
class UnixStreamXMLRPCServer(SimpleXMLRPCServer):
|
||||||
|
"""XML-RPC Server fuer Unix Domain Sockets."""
|
||||||
|
address_family = socket.AF_UNIX
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, addr, logRequests=True, allow_none=False, unixgroup="picontrol"):
|
||||||
|
"""Init UnixStreamXMLRPCServer class."""
|
||||||
|
proginit.logger.debug("enter UnixStreamXMLRPCServer.__init__()")
|
||||||
|
|
||||||
|
self.timeout = 0.5
|
||||||
|
self.unixgroup = unixgroup
|
||||||
|
|
||||||
|
# Create subdirectories for Unix Domain Socket
|
||||||
|
socket_dir = os.path.dirname(addr)
|
||||||
|
if socket_dir:
|
||||||
|
os.makedirs(socket_dir, exist_ok=True)
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
addr=addr,
|
||||||
|
requestHandler=UnixStreamXMLRPCRequestHandler,
|
||||||
|
logRequests=logRequests,
|
||||||
|
allow_none=allow_none,
|
||||||
|
encoding="utf-8",
|
||||||
|
bind_and_activate=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
proginit.logger.debug("leave UnixStreamXMLRPCServer.__init__()")
|
||||||
|
|
||||||
|
def server_bind(self):
|
||||||
|
"""Ueberschreibt server_bind um Berechtigungen zu setzen."""
|
||||||
|
super().server_bind()
|
||||||
|
|
||||||
|
# Gruppe setzen
|
||||||
|
try:
|
||||||
|
gid = grp.getgrnam(self.unixgroup).gr_gid
|
||||||
|
# -1 will leave the owner unchanged
|
||||||
|
os.chown(self.server_address, -1, gid)
|
||||||
|
except (KeyError, PermissionError):
|
||||||
|
proginit.logger.warning(
|
||||||
|
"can not set group of socket {0} to '{1}'"
|
||||||
|
"".format(self.server_address, self.unixgroup)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Berechtigungen fuer restliche Benutzer entziehen
|
||||||
|
try:
|
||||||
|
os.chmod(self.server_address, 0o660)
|
||||||
|
except PermissionError:
|
||||||
|
proginit.logger.warning(
|
||||||
|
"can not set permissions of socket {0}"
|
||||||
|
"".format(self.server_address)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _dispatch(self, method, params):
|
||||||
|
"""Prueft ACL Level fuer angeforderte Methode.
|
||||||
|
|
||||||
|
@param method Angeforderte Methode
|
||||||
|
@param params Argumente fuer Methode
|
||||||
|
@return Dispatched data
|
||||||
|
|
||||||
|
"""
|
||||||
|
# ACL on a socket is always max level
|
||||||
|
if method == "xmlmodus":
|
||||||
|
params = (4,)
|
||||||
|
|
||||||
|
return super()._dispatch(method, params)
|
||||||
|
|
||||||
|
def register_function(self, acl_level, function, name=None):
|
||||||
|
"""Override register_function to ignore acl_level for unix sockets."""
|
||||||
|
return super().register_function(function, name)
|
||||||
|
|||||||
Reference in New Issue
Block a user