install: refresh active uvc helper safely
This commit is contained in:
parent
955cfb3b7b
commit
b47627ad5b
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1686,7 +1686,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1698,7 +1698,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -976,6 +976,28 @@ restart_lesavka_server_only() {
|
|||||||
validate_server_ready
|
validate_server_ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restart_lesavka_uvc_helper_only() {
|
||||||
|
if [[ -n ${LESAVKA_DISABLE_UVC:-} ]]; then
|
||||||
|
echo "⚠️ UVC is disabled; skipping lesavka-uvc helper refresh." >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! uvc_gadget_present; then
|
||||||
|
echo "⚠️ live UVC function is missing; skipping helper-only refresh until the next safe gadget rebuild." >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! systemctl list-unit-files lesavka-uvc.service --no-pager --no-legend 2>/dev/null \
|
||||||
|
| grep -q '^lesavka-uvc\.service'; then
|
||||||
|
echo "⚠️ lesavka-uvc unit is not installed yet; skipping helper-only refresh." >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo install -d -m 0755 /var/log/lesavka
|
||||||
|
sudo truncate -s 0 /var/log/lesavka/uvc.stderr
|
||||||
|
sudo systemctl reset-failed lesavka-uvc >/dev/null 2>&1 || true
|
||||||
|
sudo systemctl restart lesavka-uvc
|
||||||
|
echo "✅ lesavka-uvc helper restarted with updated binaries without cycling lesavka-core or the USB gadget."
|
||||||
|
}
|
||||||
|
|
||||||
normalize_hdmi_connector() {
|
normalize_hdmi_connector() {
|
||||||
local name="$1"
|
local name="$1"
|
||||||
if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then
|
if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then
|
||||||
@ -1664,7 +1686,7 @@ if [[ "$HOST_GADGET_PROTECTED" == "1" ]] \
|
|||||||
fi
|
fi
|
||||||
if [[ "$ATTACHED_UVC_CHANGE_DEFERRED" == "1" ]]; then
|
if [[ "$ATTACHED_UVC_CHANGE_DEFERRED" == "1" ]]; then
|
||||||
echo "⚠️ UVC/UAC runtime settings or live descriptors differ while the host is attached." >&2
|
echo "⚠️ UVC/UAC runtime settings or live descriptors differ while the host is attached." >&2
|
||||||
echo " The installer will not restart lesavka-core or lesavka-uvc because that can wedge the Pi USB controller." >&2
|
echo " The installer will not restart lesavka-core or rewrite attached USB descriptors because that can wedge the Pi USB controller." >&2
|
||||||
echo " To apply descriptor-changing UVC settings, use a maintenance window with LESAVKA_ALLOW_GADGET_RESET=1 LESAVKA_FORCE_GADGET_REBUILD=1." >&2
|
echo " To apply descriptor-changing UVC settings, use a maintenance window with LESAVKA_ALLOW_GADGET_RESET=1 LESAVKA_FORCE_GADGET_REBUILD=1." >&2
|
||||||
if lesavka_server_has_active_clients && [[ "${LESAVKA_INSTALL_RESTART_WITH_CLIENTS:-0}" != "1" ]]; then
|
if lesavka_server_has_active_clients && [[ "${LESAVKA_INSTALL_RESTART_WITH_CLIENTS:-0}" != "1" ]]; then
|
||||||
echo "⚠️ Active gRPC clients are connected; leaving the running server untouched for this install." >&2
|
echo "⚠️ Active gRPC clients are connected; leaving the running server untouched for this install." >&2
|
||||||
@ -1682,8 +1704,8 @@ if [[ "$ATTACHED_UVC_CHANGE_DEFERRED" == "1" ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✅ No active gRPC clients detected; applying runtime env and restarting lesavka-server only." >&2
|
echo "✅ No active gRPC clients detected; applying runtime env and restarting lesavka-server." >&2
|
||||||
echo " Preserving lesavka-core and lesavka-uvc so the attached USB gadget is not cycled." >&2
|
echo " Preserving lesavka-core and live USB descriptors; refreshing only the user-space UVC helper if the live UVC function exists." >&2
|
||||||
sudo install -m 0644 "$SERVER_ENV_TMP" /etc/lesavka/server.env
|
sudo install -m 0644 "$SERVER_ENV_TMP" /etc/lesavka/server.env
|
||||||
sudo install -m 0644 "$UVC_ENV_TMP" /etc/lesavka/uvc.env
|
sudo install -m 0644 "$UVC_ENV_TMP" /etc/lesavka/uvc.env
|
||||||
rm -f "$SERVER_ENV_TMP" "$UVC_ENV_TMP"
|
rm -f "$SERVER_ENV_TMP" "$UVC_ENV_TMP"
|
||||||
@ -1693,11 +1715,12 @@ if [[ "$ATTACHED_UVC_CHANGE_DEFERRED" == "1" ]]; then
|
|||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo systemctl enable lesavka-server >/dev/null 2>&1 || true
|
sudo systemctl enable lesavka-server >/dev/null 2>&1 || true
|
||||||
restart_lesavka_server_only
|
restart_lesavka_server_only
|
||||||
|
restart_lesavka_uvc_helper_only
|
||||||
sudo /usr/local/bin/lesavka-recovery-ladder snapshot || true
|
sudo /usr/local/bin/lesavka-recovery-ladder snapshot || true
|
||||||
INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true)
|
INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true)
|
||||||
INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true)
|
INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true)
|
||||||
sudo systemctl start lesavka-recovery-ladder.timer >/dev/null 2>&1 || true
|
sudo systemctl start lesavka-recovery-ladder.timer >/dev/null 2>&1 || true
|
||||||
echo "✅ lesavka-server binaries, runtime env, and server unit installed; server-only restart completed."
|
echo "✅ lesavka-server binaries, runtime env, and server unit installed; server restart plus helper-only UVC refresh completed."
|
||||||
echo "➡️ Installed and running: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}"
|
echo "➡️ Installed and running: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}"
|
||||||
echo "➡️ Recovery ladder: installed, enabled, and started in server-only mode"
|
echo "➡️ Recovery ladder: installed, enabled, and started in server-only mode"
|
||||||
echo "➡️ UVC codec request persisted for the next safe gadget rebuild: ${INSTALL_UVC_CODEC}"
|
echo "➡️ UVC codec request persisted for the next safe gadget rebuild: ${INSTALL_UVC_CODEC}"
|
||||||
@ -1709,16 +1732,8 @@ sudo install -m 0644 "$UVC_ENV_TMP" /etc/lesavka/uvc.env
|
|||||||
rm -f "$SERVER_ENV_TMP" "$UVC_ENV_TMP"
|
rm -f "$SERVER_ENV_TMP" "$UVC_ENV_TMP"
|
||||||
if [[ "$ATTACHED_UVC_RESTART_DEFERRED" == "1" ]]; then
|
if [[ "$ATTACHED_UVC_RESTART_DEFERRED" == "1" ]]; then
|
||||||
echo "⚠️ UVC runtime env changed while the host is attached, but the requested descriptor matches the live gadget." >&2
|
echo "⚠️ UVC runtime env changed while the host is attached, but the requested descriptor matches the live gadget." >&2
|
||||||
echo " Updated /etc/lesavka/server.env and /etc/lesavka/uvc.env without restarting live services." >&2
|
echo " The installer will not rebuild lesavka-core or attached USB descriptors." >&2
|
||||||
echo " Rerun the installer with the same UVC settings to restart services after the env is stable, or use LESAVKA_ALLOW_GADGET_RESET=1 LESAVKA_FORCE_GADGET_REBUILD=1 during a maintenance window." >&2
|
echo " It will refresh the user-space lesavka-uvc helper after unit files are updated so helper-only fixes become live." >&2
|
||||||
INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true)
|
|
||||||
INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true)
|
|
||||||
sudo systemctl start lesavka-recovery-ladder.timer >/dev/null 2>&1 || true
|
|
||||||
echo "✅ lesavka-server binaries and runtime env installed; live service restart deferred for attached-gadget safety."
|
|
||||||
echo "➡️ Installed binaries: lesavka-server ${INSTALLED_VERSION:-unknown}${INSTALLED_SHA:+ ($INSTALLED_SHA)}"
|
|
||||||
echo "➡️ Recovery ladder: installed, enabled, and started in server-only mode"
|
|
||||||
echo "➡️ Deferred restart UVC codec: ${INSTALL_UVC_CODEC}"
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "==> 6a. Systemd units - lesavka-core"
|
echo "==> 6a. Systemd units - lesavka-core"
|
||||||
@ -1759,7 +1774,8 @@ if [[ -z ${LESAVKA_DISABLE_UVC:-} ]] && ! uvc_gadget_present; then
|
|||||||
GADGET_REBUILD_REASON="UVC function is missing from the live gadget"
|
GADGET_REBUILD_REASON="UVC function is missing from the live gadget"
|
||||||
echo "⚠️ UVC function is missing from the live gadget; forcing a rebuild before server start."
|
echo "⚠️ UVC function is missing from the live gadget; forcing a rebuild before server start."
|
||||||
fi
|
fi
|
||||||
if [[ "$UVC_ENV_CHANGED" == "1" ]] && [[ "$HOST_GADGET_PROTECTED" == "1" ]]; then
|
if [[ "$UVC_ENV_CHANGED" == "1" ]] && [[ "$HOST_GADGET_PROTECTED" == "1" ]] \
|
||||||
|
&& { [[ "$LIVE_UVC_DESCRIPTOR_MISMATCH" == "1" ]] || [[ "$LIVE_UAC_DESCRIPTOR_MISMATCH" == "1" ]] || [[ "$LIVE_UVC_FUNCTION_MISSING" == "1" ]]; }; then
|
||||||
FORCE_GADGET_REBUILD=1
|
FORCE_GADGET_REBUILD=1
|
||||||
GADGET_REBUILD_REASON="UVC runtime settings changed while the host is attached"
|
GADGET_REBUILD_REASON="UVC runtime settings changed while the host is attached"
|
||||||
echo "⚠️ UVC runtime settings changed while the host is attached; forcing a gadget rebuild so the new descriptors take effect."
|
echo "⚠️ UVC runtime settings changed while the host is attached; forcing a gadget rebuild so the new descriptors take effect."
|
||||||
@ -1854,7 +1870,7 @@ if [[ "$HOST_GADGET_PROTECTED" == "1" ]] \
|
|||||||
CAN_TOUCH_UVC_SERVICE=0
|
CAN_TOUCH_UVC_SERVICE=0
|
||||||
fi
|
fi
|
||||||
if [[ "$CAN_TOUCH_UVC_SERVICE" != "1" ]] && systemctl is-active --quiet lesavka-uvc; then
|
if [[ "$CAN_TOUCH_UVC_SERVICE" != "1" ]] && systemctl is-active --quiet lesavka-uvc; then
|
||||||
echo "✅ lesavka-uvc already active; preserving it during attached-gadget version update."
|
restart_lesavka_uvc_helper_only
|
||||||
elif [[ "$CAN_TOUCH_UVC_SERVICE" != "1" ]]; then
|
elif [[ "$CAN_TOUCH_UVC_SERVICE" != "1" ]]; then
|
||||||
echo "⚠️ lesavka-uvc is inactive, but the host/gadget is protected; not starting it during a version-only install." >&2
|
echo "⚠️ lesavka-uvc is inactive, but the host/gadget is protected; not starting it during a version-only install." >&2
|
||||||
elif [[ "$UVC_ENV_CHANGED" == "1" ]] && systemctl is-active --quiet lesavka-uvc; then
|
elif [[ "$UVC_ENV_CHANGED" == "1" ]] && systemctl is-active --quiet lesavka-uvc; then
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.22.33"
|
version = "0.22.34"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
@ -194,6 +194,7 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_WIDTH 1280"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_WIDTH 1280"));
|
||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_HEIGHT 720"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_HEIGHT 720"));
|
||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_CONTROL_READ_ONLY 0"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_CONTROL_READ_ONLY 0"));
|
||||||
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_QUEUE_PACING 1"));
|
||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_BULK 1"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_BULK 1"));
|
||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_FRAME_SIZE_GUARD 1"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_FRAME_SIZE_GUARD 1"));
|
||||||
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_FRAME_MAX_BYTES 0"));
|
assert!(SERVER_INSTALL.contains("uvc_env_value LESAVKA_UVC_FRAME_MAX_BYTES 0"));
|
||||||
@ -314,16 +315,16 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL
|
SERVER_INSTALL
|
||||||
.contains("No active gRPC clients detected; applying runtime env and restarting lesavka-server only")
|
.contains("No active gRPC clients detected; applying runtime env and restarting lesavka-server")
|
||||||
&& SERVER_INSTALL
|
&& SERVER_INSTALL
|
||||||
.contains("Preserving lesavka-core and lesavka-uvc so the attached USB gadget is not cycled")
|
.contains("Preserving lesavka-core and live USB descriptors; refreshing only the user-space UVC helper")
|
||||||
&& SERVER_INSTALL.contains("restart_lesavka_server_only"),
|
&& SERVER_INSTALL.contains("restart_lesavka_server_only"),
|
||||||
"idle attached-gadget installs should leave the newest server running without cycling USB gadget services"
|
"idle attached-gadget installs should leave the newest server and UVC helper running without cycling USB gadget descriptors"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("server-only restart completed")
|
SERVER_INSTALL.contains("server restart plus helper-only UVC refresh completed")
|
||||||
&& SERVER_INSTALL.contains("Live UVC descriptors may still differ"),
|
&& SERVER_INSTALL.contains("Live UVC descriptors may still differ"),
|
||||||
"idle attached-gadget installs should be explicit about server readiness and deferred descriptor rebuilds"
|
"idle attached-gadget installs should be explicit about server/helper readiness and deferred descriptor rebuilds"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL
|
SERVER_INSTALL
|
||||||
@ -362,11 +363,13 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("ATTACHED_UVC_RESTART_DEFERRED=1"),
|
SERVER_INSTALL.contains("ATTACHED_UVC_RESTART_DEFERRED=1"),
|
||||||
"attached UVC env changes that match the live descriptor should still defer service restarts"
|
"attached UVC env changes that match the live descriptor should take the helper-only refresh path"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("Updated /etc/lesavka/server.env and /etc/lesavka/uvc.env without restarting live services"),
|
SERVER_INSTALL.contains(
|
||||||
"safe env repairs should not immediately restart the attached gadget path"
|
"It will refresh the user-space lesavka-uvc helper after unit files are updated"
|
||||||
|
),
|
||||||
|
"safe env repairs should refresh the helper without rebuilding the attached gadget"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("dwDefaultFrameInterval"),
|
SERVER_INSTALL.contains("dwDefaultFrameInterval"),
|
||||||
@ -393,16 +396,16 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
< SERVER_INSTALL
|
< SERVER_INSTALL
|
||||||
.find("if [[ \"$ATTACHED_UVC_RESTART_DEFERRED\" == \"1\" ]]")
|
.find("if [[ \"$ATTACHED_UVC_RESTART_DEFERRED\" == \"1\" ]]")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"safe env repair should install env files before exiting without service restarts"
|
"safe env repair should install env files before choosing the helper-only refresh path"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL
|
SERVER_INSTALL
|
||||||
.find("if [[ \"$ATTACHED_UVC_RESTART_DEFERRED\" == \"1\" ]]")
|
.find("if [[ \"$ATTACHED_UVC_RESTART_DEFERRED\" == \"1\" ]]")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
< SERVER_INSTALL
|
< SERVER_INSTALL
|
||||||
.find("sudo systemctl restart lesavka-uvc")
|
.rfind("restart_lesavka_uvc_helper_only")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"safe env repair must exit before live UVC helper restarts"
|
"safe env repair should reach the helper-only restart after unit files are refreshed"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL
|
SERVER_INSTALL
|
||||||
@ -418,9 +421,9 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
.find("ATTACHED_UVC_CHANGE_DEFERRED=1")
|
.find("ATTACHED_UVC_CHANGE_DEFERRED=1")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
< SERVER_INSTALL
|
< SERVER_INSTALL
|
||||||
.find("sudo systemctl restart lesavka-uvc")
|
.rfind("restart_lesavka_uvc_helper_only")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"attached UVC deferral must run before any live UVC helper restart"
|
"attached UVC deferral must run before any helper-only refresh"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("[[ \"$EXPLICIT_GADGET_REBUILD\" != \"1\" ]] || [[ -z ${LESAVKA_ALLOW_GADGET_RESET:-} ]]"),
|
SERVER_INSTALL.contains("[[ \"$EXPLICIT_GADGET_REBUILD\" != \"1\" ]] || [[ -z ${LESAVKA_ALLOW_GADGET_RESET:-} ]]"),
|
||||||
@ -470,9 +473,9 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("CAN_TOUCH_UVC_SERVICE=0")
|
SERVER_INSTALL.contains("CAN_TOUCH_UVC_SERVICE=0")
|
||||||
&& SERVER_INSTALL.contains("preserving it during attached-gadget version update")
|
&& SERVER_INSTALL.contains("restart_lesavka_uvc_helper_only")
|
||||||
&& SERVER_INSTALL.contains("not starting it during a version-only install"),
|
&& SERVER_INSTALL.contains("not starting it during a version-only install"),
|
||||||
"ordinary attached-gadget version updates must not start or restart the UVC helper"
|
"ordinary attached-gadget version updates should refresh an active UVC helper without starting an inactive one"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
SERVER_INSTALL.contains("sudo systemctl start lesavka-uvc"),
|
SERVER_INSTALL.contains("sudo systemctl start lesavka-uvc"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user