common fstab and libc funcs

This commit is contained in:
Maxim Devaev
2022-11-07 03:23:06 +03:00
parent 648316931a
commit 53f8b052de
6 changed files with 64 additions and 56 deletions

50
kvmd/fstab.py Normal file
View File

@@ -0,0 +1,50 @@
# ========================================================================== #
# #
# KVMD - The main PiKVM daemon. #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
# ========================================================================== #
import re
import dataclasses
# =====
@dataclasses.dataclass(frozen=True)
class FstabStorage:
mount_path: str
root_path: str
user: str
def find_storage(target: str) -> FstabStorage:
fstab_path = "/etc/fstab"
with open(fstab_path) as file:
for line in file.read().split("\n"):
line = line.strip()
if line and not line.startswith("#"):
parts = line.split()
if len(parts) == 6:
options = dict(re.findall(r"X-kvmd\.%s-(root|user)(?:=([^,]+))?" % (target), parts[3]))
if options:
return FstabStorage(
mount_path=parts[1],
root_path=(options.get("root", "") or parts[1]),
user=options.get("user", ""),
)
raise RuntimeError(f"Can't find {target!r} mountpoint in {fstab_path}")

View File

@@ -22,23 +22,10 @@
import sys import sys
import os import os
import re
import shutil import shutil
import dataclasses
import subprocess import subprocess
from ... import fstab
# ====
_MOUNT_PATH = "/bin/mount"
_FSTAB_PATH = "/etc/fstab"
# =====
@dataclasses.dataclass(frozen=True)
class _Storage:
mount_path: str
root_path: str
user: str
# ===== # =====
@@ -46,29 +33,11 @@ def _log(msg: str) -> None:
print(msg, file=sys.stderr) print(msg, file=sys.stderr)
def _find_storage(target: str) -> _Storage:
assert target
with open(_FSTAB_PATH) as fstab_file:
for line in fstab_file.read().split("\n"):
line = line.strip()
if line and not line.startswith("#"):
parts = line.split()
if len(parts) == 6:
options = dict(re.findall(r"X-kvmd\.%s-(root|user)(?:=([^,]+))?" % (target), parts[3]))
if options:
return _Storage(
mount_path=parts[1],
root_path=(options.get("root", "") or parts[1]),
user=options.get("user", ""),
)
raise SystemExit(f"Can't find {target!r} mountpoint in {_FSTAB_PATH}")
def _remount(path: str, rw: bool) -> None: def _remount(path: str, rw: bool) -> None:
mode = ("rw" if rw else "ro") mode = ("rw" if rw else "ro")
_log(f"Remounting {path} to {mode.upper()}-mode ...") _log(f"Remounting {path} to {mode.upper()}-mode ...")
try: try:
subprocess.check_call([_MOUNT_PATH, "--options", f"remount,{mode}", path]) subprocess.check_call(["/bin/mount", "--options", f"remount,{mode}", path])
except subprocess.CalledProcessError as err: except subprocess.CalledProcessError as err:
raise SystemExit(f"Can't remount: {err}") raise SystemExit(f"Can't remount: {err}")
@@ -109,7 +78,8 @@ def main() -> None:
rw = (sys.argv[1] == "rw") rw = (sys.argv[1] == "rw")
storage = _find_storage(target) assert target
storage = fstab.find_storage(target)
_remount(storage.mount_path, rw) _remount(storage.mount_path, rw)
if rw and storage.root_path: if rw and storage.root_path:
for name in dirs: for name in dirs:

View File

@@ -22,12 +22,8 @@
import sys import sys
import os import os
import ctypes
import ctypes.util
from ctypes import c_int from ... import libc
from ctypes import c_uint
from ctypes import c_char_p
# ===== # =====
@@ -35,14 +31,6 @@ def main() -> None:
if len(sys.argv) != 3: if len(sys.argv) != 3:
raise SystemExit(f"Usage: {sys.argv[0]} <file1> <file2>") raise SystemExit(f"Usage: {sys.argv[0]} <file1> <file2>")
path = ctypes.util.find_library("c")
if not path:
raise SystemExit("Where is libc?")
assert path
libc = ctypes.CDLL(path)
libc.renameat2.restype = c_int
libc.renameat2.argtypes = [c_int, c_char_p, c_int, c_char_p, c_uint]
result = libc.renameat2( result = libc.renameat2(
-100, # AT_FDCWD -100, # AT_FDCWD
os.fsencode(sys.argv[1]), os.fsencode(sys.argv[1]),
@@ -52,4 +40,4 @@ def main() -> None:
) )
if result != 0: if result != 0:
raise SystemExit(f"{sys.argv[0]}: {os.strerror(ctypes.get_errno())}") raise SystemExit(f"{sys.argv[0]}: {os.strerror(libc.get_errno())}")

View File

@@ -25,7 +25,6 @@
import sys import sys
import os import os
import asyncio import asyncio
import ctypes
import struct import struct
import dataclasses import dataclasses
import types import types
@@ -64,7 +63,7 @@ def _inotify_parsed_buffer(data: bytes) -> Generator[tuple[int, int, int, bytes]
def _inotify_check(retval: int) -> int: def _inotify_check(retval: int) -> int:
if retval < 0: if retval < 0:
c_errno = ctypes.get_errno() c_errno = libc.get_errno()
if c_errno == errno.ENOSPC: # pylint: disable=no-else-raise if c_errno == errno.ENOSPC: # pylint: disable=no-else-raise
raise OSError(c_errno, "Inotify watch limit reached") raise OSError(c_errno, "Inotify watch limit reached")
elif c_errno == errno.EMFILE: elif c_errno == errno.EMFILE:

View File

@@ -26,6 +26,7 @@ import ctypes
import ctypes.util import ctypes.util
from ctypes import c_int from ctypes import c_int
from ctypes import c_uint
from ctypes import c_uint32 from ctypes import c_uint32
from ctypes import c_char_p from ctypes import c_char_p
from ctypes import c_void_p from ctypes import c_void_p
@@ -42,6 +43,7 @@ def _load_libc() -> ctypes.CDLL:
("inotify_init", c_int, []), ("inotify_init", c_int, []),
("inotify_add_watch", c_int, [c_int, c_char_p, c_uint32]), ("inotify_add_watch", c_int, [c_int, c_char_p, c_uint32]),
("inotify_rm_watch", c_int, [c_int, c_uint32]), ("inotify_rm_watch", c_int, [c_int, c_uint32]),
("renameat2", c_int, [c_int, c_char_p, c_int, c_char_p, c_uint]),
("free", c_int, [c_void_p]), ("free", c_int, [c_void_p]),
]: ]:
func = getattr(lib, name) func = getattr(lib, name)
@@ -56,7 +58,10 @@ _libc = _load_libc()
# ===== # =====
get_errno = ctypes.get_errno
inotify_init = _libc.inotify_init inotify_init = _libc.inotify_init
inotify_add_watch = _libc.inotify_add_watch inotify_add_watch = _libc.inotify_add_watch
inotify_rm_watch = _libc.inotify_rm_watch inotify_rm_watch = _libc.inotify_rm_watch
renameat2 = _libc.renameat2
free = _libc.free free = _libc.free

View File

@@ -38,12 +38,12 @@ from ....yamlconf import Option
from ....validators.basic import valid_bool from ....validators.basic import valid_bool
from ....validators.basic import valid_number from ....validators.basic import valid_number
from ....validators.os import valid_abs_dir
from ....validators.os import valid_printable_filename from ....validators.os import valid_printable_filename
from ....validators.os import valid_command from ....validators.os import valid_command
from .... import aiotools from .... import aiotools
from .... import aiohelpers from .... import aiohelpers
from .... import fstab
from .. import MsdError from .. import MsdError
from .. import MsdIsBusyError from .. import MsdIsBusyError
@@ -143,8 +143,6 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
write_chunk_size: int, write_chunk_size: int,
sync_chunk_size: int, sync_chunk_size: int,
storage_path: str,
remount_cmd: list[str], remount_cmd: list[str],
initial: dict, initial: dict,
@@ -162,7 +160,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__initial_cdrom: bool = initial["cdrom"] self.__initial_cdrom: bool = initial["cdrom"]
self.__drive = Drive(gadget, instance=0, lun=0) self.__drive = Drive(gadget, instance=0, lun=0)
self.__storage = Storage(storage_path) self.__storage = Storage(fstab.find_storage("otgmsd").root_path)
self.__reader: (MsdFileReader | None) = None self.__reader: (MsdFileReader | None) = None
self.__writer: (MsdFileWriter | None) = None self.__writer: (MsdFileWriter | None) = None
@@ -181,8 +179,6 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
"write_chunk_size": Option(65536, type=functools.partial(valid_number, min=1024)), "write_chunk_size": Option(65536, type=functools.partial(valid_number, min=1024)),
"sync_chunk_size": Option(4194304, type=functools.partial(valid_number, min=1024)), "sync_chunk_size": Option(4194304, type=functools.partial(valid_number, min=1024)),
"storage": Option("/var/lib/kvmd/msd", type=valid_abs_dir, unpack_as="storage_path"),
"remount_cmd": Option([ "remount_cmd": Option([
"/usr/bin/sudo", "--non-interactive", "/usr/bin/sudo", "--non-interactive",
"/usr/bin/kvmd-helper-otgmsd-remount", "{mode}", "/usr/bin/kvmd-helper-otgmsd-remount", "{mode}",