Escape paths and profile names when generating launchd, systemd, and Windows service files
This commit is contained in:
1 parent
3007c1caa1
commit
ed49dbf429
1 file changed
+32
-11
+32
-11
@@ -2,6 +2,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from xml.sax.saxutils import escape as xml_escape
|
||||||
|
|
||||||
from . import paths
|
from . import paths
|
||||||
|
|
||||||
@@ -73,13 +74,20 @@ def environment():
|
|||||||
|
|
||||||
|
|
||||||
def launchd_plist(profile_name):
|
def launchd_plist(profile_name):
|
||||||
label = service_label(profile_name)
|
label = xml_escape(service_label(profile_name))
|
||||||
|
python = xml_escape(preferred_python())
|
||||||
script = script_path()
|
script = script_path()
|
||||||
|
script_escaped = xml_escape(script)
|
||||||
|
working_dir = xml_escape(str(Path(script).parent))
|
||||||
|
profile_arg = xml_escape(profile_name)
|
||||||
log_dir = paths.LOG_DIR
|
log_dir = paths.LOG_DIR
|
||||||
|
|
||||||
env_entries = ""
|
env_entries = ""
|
||||||
for key, value in environment().items():
|
for key, value in environment().items():
|
||||||
env_entries += f" <key>{key}</key>\n <string>{value}</string>\n"
|
env_entries += (
|
||||||
|
f" <key>{xml_escape(key)}</key>\n"
|
||||||
|
f" <string>{xml_escape(value)}</string>\n"
|
||||||
|
)
|
||||||
|
|
||||||
env_block = ""
|
env_block = ""
|
||||||
if env_entries:
|
if env_entries:
|
||||||
@@ -90,6 +98,9 @@ def launchd_plist(profile_name):
|
|||||||
" </dict>\n"
|
" </dict>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
out_path = xml_escape(str(log_dir / f"{profile_name}.out.log"))
|
||||||
|
err_path = xml_escape(str(log_dir / f"{profile_name}.err.log"))
|
||||||
|
|
||||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
@@ -100,15 +111,15 @@ def launchd_plist(profile_name):
|
|||||||
|
|
||||||
<key>ProgramArguments</key>
|
<key>ProgramArguments</key>
|
||||||
<array>
|
<array>
|
||||||
<string>{preferred_python()}</string>
|
<string>{python}</string>
|
||||||
<string>{script}</string>
|
<string>{script_escaped}</string>
|
||||||
<string>run</string>
|
<string>run</string>
|
||||||
<string>{profile_name}</string>
|
<string>{profile_arg}</string>
|
||||||
<string>--quiet</string>
|
<string>--quiet</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<key>WorkingDirectory</key>
|
<key>WorkingDirectory</key>
|
||||||
<string>{Path(script).parent}</string>
|
<string>{working_dir}</string>
|
||||||
|
|
||||||
{env_block} <key>RunAtLoad</key>
|
{env_block} <key>RunAtLoad</key>
|
||||||
<true/>
|
<true/>
|
||||||
@@ -120,19 +131,29 @@ def launchd_plist(profile_name):
|
|||||||
<integer>60</integer>
|
<integer>60</integer>
|
||||||
|
|
||||||
<key>StandardOutPath</key>
|
<key>StandardOutPath</key>
|
||||||
<string>{log_dir / f"{profile_name}.out.log"}</string>
|
<string>{out_path}</string>
|
||||||
|
|
||||||
<key>StandardErrorPath</key>
|
<key>StandardErrorPath</key>
|
||||||
<string>{log_dir / f"{profile_name}.err.log"}</string>
|
<string>{err_path}</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _systemd_quote(value):
|
||||||
|
escaped = str(value).replace("\\", "\\\\").replace('"', '\\"')
|
||||||
|
return f'"{escaped}"'
|
||||||
|
|
||||||
|
|
||||||
def systemd_unit(profile_name):
|
def systemd_unit(profile_name):
|
||||||
script = script_path()
|
script = script_path()
|
||||||
|
exec_start = " ".join(
|
||||||
|
_systemd_quote(token)
|
||||||
|
for token in (preferred_python(), script, "run", profile_name, "--quiet")
|
||||||
|
)
|
||||||
env_lines = "".join(
|
env_lines = "".join(
|
||||||
f"Environment={key}={value}\n" for key, value in environment().items()
|
f"Environment={_systemd_quote(f'{key}={value}')}\n"
|
||||||
|
for key, value in environment().items()
|
||||||
)
|
)
|
||||||
|
|
||||||
return f"""[Unit]
|
return f"""[Unit]
|
||||||
@@ -141,7 +162,7 @@ After=network-online.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart={preferred_python()} {script} run {profile_name} --quiet
|
ExecStart={exec_start}
|
||||||
WorkingDirectory={Path(script).parent}
|
WorkingDirectory={Path(script).parent}
|
||||||
{env_lines}Restart=always
|
{env_lines}Restart=always
|
||||||
RestartSec=60
|
RestartSec=60
|
||||||
@@ -158,7 +179,7 @@ def windows_instructions(profile_name):
|
|||||||
others. Use Task Scheduler:
|
others. Use Task Scheduler:
|
||||||
|
|
||||||
schtasks /create /tn "{label}" /sc onlogon /rl highest ^
|
schtasks /create /tn "{label}" /sc onlogon /rl highest ^
|
||||||
/tr "\\"{preferred_python()}\\" \\"{script}\\" run {profile_name} --quiet"
|
/tr "\\"{preferred_python()}\\" \\"{script}\\" run \\"{profile_name}\\" --quiet"
|
||||||
|
|
||||||
To remove it:
|
To remove it:
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user