|
|
|
@ -7,15 +7,20 @@ let |
|
|
|
|
inherit (config.environment) etc; |
|
|
|
|
apparmor = config.security.apparmor; |
|
|
|
|
rootDir = "/run/transmission"; |
|
|
|
|
homeDir = "/var/lib/transmission"; |
|
|
|
|
settingsDir = ".config/transmission-daemon"; |
|
|
|
|
downloadsDir = "Downloads"; |
|
|
|
|
incompleteDir = ".incomplete"; |
|
|
|
|
watchDir = "watchdir"; |
|
|
|
|
# TODO: switch to configGen.json once RFC0042 is implemented |
|
|
|
|
settingsFile = pkgs.writeText "settings.json" (builtins.toJSON cfg.settings); |
|
|
|
|
settingsFormat = pkgs.formats.json {}; |
|
|
|
|
settingsFile = settingsFormat.generate "settings.json" cfg.settings; |
|
|
|
|
in |
|
|
|
|
{ |
|
|
|
|
imports = [ |
|
|
|
|
(mkRenamedOptionModule ["services" "transmission" "port"] |
|
|
|
|
["services" "transmission" "settings" "rpc-port"]) |
|
|
|
|
(mkAliasOptionModule ["services" "transmission" "openFirewall"] |
|
|
|
|
["services" "transmission" "openPeerPorts"]) |
|
|
|
|
]; |
|
|
|
|
options = { |
|
|
|
|
services.transmission = { |
|
|
|
|
enable = mkEnableOption ''the headless Transmission BitTorrent daemon. |
|
|
|
@ -24,48 +29,141 @@ in |
|
|
|
|
transmission-remote, the WebUI (http://127.0.0.1:9091/ by default), |
|
|
|
|
or other clients like stig or tremc. |
|
|
|
|
|
|
|
|
|
Torrents are downloaded to ${homeDir}/${downloadsDir} by default and are |
|
|
|
|
Torrents are downloaded to <xref linkend="opt-services.transmission.home"/>/${downloadsDir} by default and are |
|
|
|
|
accessible to users in the "transmission" group''; |
|
|
|
|
|
|
|
|
|
settings = mkOption rec { |
|
|
|
|
# TODO: switch to types.config.json as prescribed by RFC0042 once it's implemented |
|
|
|
|
type = types.attrs; |
|
|
|
|
apply = recursiveUpdate default; |
|
|
|
|
default = |
|
|
|
|
{ |
|
|
|
|
download-dir = "${cfg.home}/${downloadsDir}"; |
|
|
|
|
incomplete-dir = "${cfg.home}/${incompleteDir}"; |
|
|
|
|
incomplete-dir-enabled = true; |
|
|
|
|
watch-dir = "${cfg.home}/${watchDir}"; |
|
|
|
|
watch-dir-enabled = false; |
|
|
|
|
message-level = 1; |
|
|
|
|
peer-port = 51413; |
|
|
|
|
peer-port-random-high = 65535; |
|
|
|
|
peer-port-random-low = 49152; |
|
|
|
|
peer-port-random-on-start = false; |
|
|
|
|
rpc-bind-address = "127.0.0.1"; |
|
|
|
|
rpc-port = 9091; |
|
|
|
|
script-torrent-done-enabled = false; |
|
|
|
|
script-torrent-done-filename = ""; |
|
|
|
|
umask = 2; # 0o002 in decimal as expected by Transmission |
|
|
|
|
utp-enabled = true; |
|
|
|
|
}; |
|
|
|
|
example = |
|
|
|
|
{ |
|
|
|
|
download-dir = "/srv/torrents/"; |
|
|
|
|
incomplete-dir = "/srv/torrents/.incomplete/"; |
|
|
|
|
incomplete-dir-enabled = true; |
|
|
|
|
rpc-whitelist = "127.0.0.1,192.168.*.*"; |
|
|
|
|
}; |
|
|
|
|
settings = mkOption { |
|
|
|
|
description = '' |
|
|
|
|
Attribute set whose fields overwrites fields in |
|
|
|
|
Settings whose options overwrite fields in |
|
|
|
|
<literal>.config/transmission-daemon/settings.json</literal> |
|
|
|
|
(each time the service starts). String values must be quoted, integer and |
|
|
|
|
boolean values must not. |
|
|
|
|
(each time the service starts). |
|
|
|
|
|
|
|
|
|
See <link xlink:href="https://github.com/transmission/transmission/wiki/Editing-Configuration-Files">Transmission's Wiki</link> |
|
|
|
|
for documentation. |
|
|
|
|
for documentation of settings not explicitely covered by this module. |
|
|
|
|
''; |
|
|
|
|
default = {}; |
|
|
|
|
type = types.submodule { |
|
|
|
|
freeformType = settingsFormat.type; |
|
|
|
|
options.download-dir = mkOption { |
|
|
|
|
type = types.path; |
|
|
|
|
default = "${cfg.home}/${downloadsDir}"; |
|
|
|
|
description = "Directory where to download torrents."; |
|
|
|
|
}; |
|
|
|
|
options.incomplete-dir = mkOption { |
|
|
|
|
type = types.path; |
|
|
|
|
default = "${cfg.home}/${incompleteDir}"; |
|
|
|
|
description = '' |
|
|
|
|
When enabled with |
|
|
|
|
services.transmission.home |
|
|
|
|
<xref linkend="opt-services.transmission.settings.incomplete-dir-enabled"/>, |
|
|
|
|
new torrents will download the files to this directory. |
|
|
|
|
When complete, the files will be moved to download-dir |
|
|
|
|
<xref linkend="opt-services.transmission.settings.download-dir"/>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.incomplete-dir-enabled = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = true; |
|
|
|
|
description = ""; |
|
|
|
|
}; |
|
|
|
|
options.message-level = mkOption { |
|
|
|
|
type = types.ints.between 0 2; |
|
|
|
|
default = 2; |
|
|
|
|
description = "Set verbosity of transmission messages."; |
|
|
|
|
}; |
|
|
|
|
options.peer-port = mkOption { |
|
|
|
|
type = types.port; |
|
|
|
|
default = 51413; |
|
|
|
|
description = "The peer port to listen for incoming connections."; |
|
|
|
|
}; |
|
|
|
|
options.peer-port-random-high = mkOption { |
|
|
|
|
type = types.port; |
|
|
|
|
default = 65535; |
|
|
|
|
description = '' |
|
|
|
|
The maximum peer port to listen to for incoming connections |
|
|
|
|
when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.peer-port-random-low = mkOption { |
|
|
|
|
type = types.port; |
|
|
|
|
default = 65535; |
|
|
|
|
description = '' |
|
|
|
|
The minimal peer port to listen to for incoming connections |
|
|
|
|
when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.peer-port-random-on-start = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = false; |
|
|
|
|
description = "Randomize the peer port."; |
|
|
|
|
}; |
|
|
|
|
options.rpc-bind-address = mkOption { |
|
|
|
|
type = types.str; |
|
|
|
|
default = "127.0.0.1"; |
|
|
|
|
example = "0.0.0.0"; |
|
|
|
|
description = '' |
|
|
|
|
Where to listen for RPC connections. |
|
|
|
|
Use \"0.0.0.0\" to listen on all interfaces. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.rpc-port = mkOption { |
|
|
|
|
type = types.port; |
|
|
|
|
default = 9091; |
|
|
|
|
description = "The RPC port to listen to."; |
|
|
|
|
}; |
|
|
|
|
options.script-torrent-done-enabled = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = false; |
|
|
|
|
description = '' |
|
|
|
|
Whether to run |
|
|
|
|
<xref linkend="opt-services.transmission.settings.script-torrent-done-filename"/> |
|
|
|
|
at torrent completion. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.script-torrent-done-filename = mkOption { |
|
|
|
|
type = types.nullOr types.path; |
|
|
|
|
default = null; |
|
|
|
|
description = "Executable to be run at torrent completion."; |
|
|
|
|
}; |
|
|
|
|
options.umask = mkOption { |
|
|
|
|
type = types.int; |
|
|
|
|
default = 2; |
|
|
|
|
description = '' |
|
|
|
|
Sets transmission's file mode creation mask. |
|
|
|
|
See the umask(2) manpage for more information. |
|
|
|
|
Users who want their saved torrents to be world-writable |
|
|
|
|
may want to set this value to 0. |
|
|
|
|
Bear in mind that the json markup language only accepts numbers in base 10, |
|
|
|
|
so the standard umask(2) octal notation "022" is written in settings.json as 18. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.utp-enabled = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = true; |
|
|
|
|
description = '' |
|
|
|
|
Whether to enable <link xlink:href="http://en.wikipedia.org/wiki/Micro_Transport_Protocol">Micro Transport Protocol (µTP)</link>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.watch-dir = mkOption { |
|
|
|
|
type = types.path; |
|
|
|
|
default = "${cfg.home}/${watchDir}"; |
|
|
|
|
description = "Watch a directory for torrent files and add them to transmission."; |
|
|
|
|
}; |
|
|
|
|
options.watch-dir-enabled = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = false; |
|
|
|
|
description = ''Whether to enable the |
|
|
|
|
<xref linkend="opt-services.transmission.settings.watch-dir"/>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
options.trash-original-torrent-files = mkOption { |
|
|
|
|
type = types.bool; |
|
|
|
|
default = false; |
|
|
|
|
description = ''Whether to delete torrents added from the |
|
|
|
|
<xref linkend="opt-services.transmission.settings.watch-dir"/>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
downloadDirPermissions = mkOption { |
|
|
|
@ -74,31 +172,22 @@ in |
|
|
|
|
example = "775"; |
|
|
|
|
description = '' |
|
|
|
|
The permissions set by <literal>systemd.activationScripts.transmission-daemon</literal> |
|
|
|
|
on the directories <link linkend="opt-services.transmission.settings">settings.download-dir</link> |
|
|
|
|
and <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link>. |
|
|
|
|
on the directories <xref linkend="opt-services.transmission.settings.download-dir"/> |
|
|
|
|
and <xref linkend="opt-services.transmission.settings.incomplete-dir"/>. |
|
|
|
|
Note that you may also want to change |
|
|
|
|
<link linkend="opt-services.transmission.settings">settings.umask</link>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
port = mkOption { |
|
|
|
|
type = types.port; |
|
|
|
|
description = '' |
|
|
|
|
TCP port number to run the RPC/web interface. |
|
|
|
|
|
|
|
|
|
If instead you want to change the peer port, |
|
|
|
|
use <link linkend="opt-services.transmission.settings">settings.peer-port</link> |
|
|
|
|
or <link linkend="opt-services.transmission.settings">settings.peer-port-random-on-start</link>. |
|
|
|
|
<xref linkend="opt-services.transmission.settings.umask"/>. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
home = mkOption { |
|
|
|
|
type = types.path; |
|
|
|
|
default = homeDir; |
|
|
|
|
default = "/var/lib/transmission"; |
|
|
|
|
description = '' |
|
|
|
|
The directory where Transmission will create <literal>${settingsDir}</literal>. |
|
|
|
|
as well as <literal>${downloadsDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.download-dir</link> is changed, |
|
|
|
|
and <literal>${incompleteDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link> is changed. |
|
|
|
|
as well as <literal>${downloadsDir}/</literal> unless |
|
|
|
|
<xref linkend="opt-services.transmission.settings.download-dir"/> is changed, |
|
|
|
|
and <literal>${incompleteDir}/</literal> unless |
|
|
|
|
<xref linkend="opt-services.transmission.settings.incomplete-dir"/> is changed. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -119,19 +208,21 @@ in |
|
|
|
|
description = '' |
|
|
|
|
Path to a JSON file to be merged with the settings. |
|
|
|
|
Useful to merge a file which is better kept out of the Nix store |
|
|
|
|
because it contains sensible data like <link linkend="opt-services.transmission.settings">settings.rpc-password</link>. |
|
|
|
|
to set secret config parameters like <code>rpc-password</code>. |
|
|
|
|
''; |
|
|
|
|
default = "/dev/null"; |
|
|
|
|
example = "/var/lib/secrets/transmission/settings.json"; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
openFirewall = mkEnableOption "opening of the peer port(s) in the firewall"; |
|
|
|
|
openPeerPorts = mkEnableOption "opening of the peer port(s) in the firewall"; |
|
|
|
|
|
|
|
|
|
openRPCPort = mkEnableOption "opening of the RPC port in the firewall"; |
|
|
|
|
|
|
|
|
|
performanceNetParameters = mkEnableOption ''tweaking of kernel parameters |
|
|
|
|
to open many more connections at the same time. |
|
|
|
|
|
|
|
|
|
Note that you may also want to increase |
|
|
|
|
<link linkend="opt-services.transmission.settings">settings.peer-limit-global</link>. |
|
|
|
|
<code>peer-limit-global"</code>. |
|
|
|
|
And be aware that these settings are quite aggressive |
|
|
|
|
and might not suite your regular desktop use. |
|
|
|
|
For instance, SSH sessions may time out more easily''; |
|
|
|
@ -156,34 +247,6 @@ in |
|
|
|
|
install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.watch-dir}' |
|
|
|
|
''; |
|
|
|
|
|
|
|
|
|
assertions = [ |
|
|
|
|
{ assertion = builtins.match "^/.*" cfg.home != null; |
|
|
|
|
message = "`services.transmission.home' must be an absolute path."; |
|
|
|
|
} |
|
|
|
|
{ assertion = types.path.check cfg.settings.download-dir; |
|
|
|
|
message = "`services.transmission.settings.download-dir' must be an absolute path."; |
|
|
|
|
} |
|
|
|
|
{ assertion = types.path.check cfg.settings.incomplete-dir; |
|
|
|
|
message = "`services.transmission.settings.incomplete-dir' must be an absolute path."; |
|
|
|
|
} |
|
|
|
|
{ assertion = types.path.check cfg.settings.watch-dir; |
|
|
|
|
message = "`services.transmission.settings.watch-dir' must be an absolute path."; |
|
|
|
|
} |
|
|
|
|
{ assertion = cfg.settings.script-torrent-done-filename == "" || types.path.check cfg.settings.script-torrent-done-filename; |
|
|
|
|
message = "`services.transmission.settings.script-torrent-done-filename' must be an absolute path."; |
|
|
|
|
} |
|
|
|
|
{ assertion = types.port.check cfg.settings.rpc-port; |
|
|
|
|
message = "${toString cfg.settings.rpc-port} is not a valid port number for `services.transmission.settings.rpc-port`."; |
|
|
|
|
} |
|
|
|
|
# In case both port and settings.rpc-port are explicitely defined: they must be the same. |
|
|
|
|
{ assertion = !options.services.transmission.port.isDefined || cfg.port == cfg.settings.rpc-port; |
|
|
|
|
message = "`services.transmission.port' is not equal to `services.transmission.settings.rpc-port'"; |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
services.transmission.settings = |
|
|
|
|
optionalAttrs options.services.transmission.port.isDefined { rpc-port = cfg.port; }; |
|
|
|
|
|
|
|
|
|
systemd.services.transmission = { |
|
|
|
|
description = "Transmission BitTorrent Service"; |
|
|
|
|
after = [ "network.target" ] ++ optional apparmor.enable "apparmor.service"; |
|
|
|
@ -228,11 +291,9 @@ in |
|
|
|
|
cfg.settings.download-dir |
|
|
|
|
] ++ |
|
|
|
|
optional cfg.settings.incomplete-dir-enabled |
|
|
|
|
cfg.settings.incomplete-dir |
|
|
|
|
++ |
|
|
|
|
optional cfg.settings.watch-dir-enabled |
|
|
|
|
cfg.settings.watch-dir |
|
|
|
|
; |
|
|
|
|
cfg.settings.incomplete-dir ++ |
|
|
|
|
optional (cfg.settings.watch-dir-enabled && cfg.settings.trash-original-torrent-files) |
|
|
|
|
cfg.settings.watch-dir; |
|
|
|
|
BindReadOnlyPaths = [ |
|
|
|
|
# No confinement done of /nix/store here like in systemd-confinement.nix, |
|
|
|
|
# an AppArmor profile is provided to get a confinement based upon paths and rights. |
|
|
|
@ -241,8 +302,10 @@ in |
|
|
|
|
"/run" |
|
|
|
|
] ++ |
|
|
|
|
optional (cfg.settings.script-torrent-done-enabled && |
|
|
|
|
cfg.settings.script-torrent-done-filename != "") |
|
|
|
|
cfg.settings.script-torrent-done-filename; |
|
|
|
|
cfg.settings.script-torrent-done-filename != null) |
|
|
|
|
cfg.settings.script-torrent-done-filename ++ |
|
|
|
|
optional (cfg.settings.watch-dir-enabled && !cfg.settings.trash-original-torrent-files) |
|
|
|
|
cfg.settings.watch-dir; |
|
|
|
|
# The following options are only for optimizing: |
|
|
|
|
# systemd-analyze security transmission |
|
|
|
|
AmbientCapabilities = ""; |
|
|
|
@ -309,25 +372,28 @@ in |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
networking.firewall = mkIf cfg.openFirewall ( |
|
|
|
|
if cfg.settings.peer-port-random-on-start |
|
|
|
|
then |
|
|
|
|
{ allowedTCPPortRanges = |
|
|
|
|
[ { from = cfg.settings.peer-port-random-low; |
|
|
|
|
to = cfg.settings.peer-port-random-high; |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
allowedUDPPortRanges = |
|
|
|
|
[ { from = cfg.settings.peer-port-random-low; |
|
|
|
|
to = cfg.settings.peer-port-random-high; |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ allowedTCPPorts = [ cfg.settings.peer-port ]; |
|
|
|
|
allowedUDPPorts = [ cfg.settings.peer-port ]; |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
networking.firewall = mkMerge [ |
|
|
|
|
(mkIf cfg.openPeerPorts ( |
|
|
|
|
if cfg.settings.peer-port-random-on-start |
|
|
|
|
then |
|
|
|
|
{ allowedTCPPortRanges = |
|
|
|
|
[ { from = cfg.settings.peer-port-random-low; |
|
|
|
|
to = cfg.settings.peer-port-random-high; |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
allowedUDPPortRanges = |
|
|
|
|
[ { from = cfg.settings.peer-port-random-low; |
|
|
|
|
to = cfg.settings.peer-port-random-high; |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ allowedTCPPorts = [ cfg.settings.peer-port ]; |
|
|
|
|
allowedUDPPorts = [ cfg.settings.peer-port ]; |
|
|
|
|
} |
|
|
|
|
)) |
|
|
|
|
(mkIf cfg.openRPCPort { allowedTCPPorts = [ cfg.settings.rpc-port ]; }) |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
boot.kernel.sysctl = mkMerge [ |
|
|
|
|
# Transmission uses a single UDP socket in order to implement multiple uTP sockets, |
|
|
|
@ -342,21 +408,21 @@ in |
|
|
|
|
# Increase the number of available source (local) TCP and UDP ports to 49151. |
|
|
|
|
# Usual default is 32768 60999, ie. 28231 ports. |
|
|
|
|
# Find out your current usage with: ss -s |
|
|
|
|
"net.ipv4.ip_local_port_range" = "16384 65535"; |
|
|
|
|
"net.ipv4.ip_local_port_range" = mkDefault "16384 65535"; |
|
|
|
|
# Timeout faster generic TCP states. |
|
|
|
|
# Usual default is 600. |
|
|
|
|
# Find out your current usage with: watch -n 1 netstat -nptuo |
|
|
|
|
"net.netfilter.nf_conntrack_generic_timeout" = 60; |
|
|
|
|
"net.netfilter.nf_conntrack_generic_timeout" = mkDefault 60; |
|
|
|
|
# Timeout faster established but inactive connections. |
|
|
|
|
# Usual default is 432000. |
|
|
|
|
"net.netfilter.nf_conntrack_tcp_timeout_established" = 600; |
|
|
|
|
"net.netfilter.nf_conntrack_tcp_timeout_established" = mkDefault 600; |
|
|
|
|
# Clear immediately TCP states after timeout. |
|
|
|
|
# Usual default is 120. |
|
|
|
|
"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1; |
|
|
|
|
"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = mkDefault 1; |
|
|
|
|
# Increase the number of trackable connections. |
|
|
|
|
# Usual default is 262144. |
|
|
|
|
# Find out your current usage with: conntrack -C |
|
|
|
|
"net.netfilter.nf_conntrack_max" = 1048576; |
|
|
|
|
"net.netfilter.nf_conntrack_max" = mkDefault 1048576; |
|
|
|
|
}) |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
@ -372,7 +438,7 @@ in |
|
|
|
|
rw ${cfg.settings.incomplete-dir}/**, |
|
|
|
|
''} |
|
|
|
|
${optionalString cfg.settings.watch-dir-enabled '' |
|
|
|
|
rw ${cfg.settings.watch-dir}/**, |
|
|
|
|
r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**, |
|
|
|
|
''} |
|
|
|
|
profile dirs { |
|
|
|
|
rw ${cfg.settings.download-dir}/**, |
|
|
|
@ -380,12 +446,12 @@ in |
|
|
|
|
rw ${cfg.settings.incomplete-dir}/**, |
|
|
|
|
''} |
|
|
|
|
${optionalString cfg.settings.watch-dir-enabled '' |
|
|
|
|
rw ${cfg.settings.watch-dir}/**, |
|
|
|
|
r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**, |
|
|
|
|
''} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
${optionalString (cfg.settings.script-torrent-done-enabled && |
|
|
|
|
cfg.settings.script-torrent-done-filename != "") '' |
|
|
|
|
cfg.settings.script-torrent-done-filename != null) '' |
|
|
|
|
# Stack transmission_directories profile on top of |
|
|
|
|
# any existing profile for script-torrent-done-filename |
|
|
|
|
# FIXME: to be tested as I'm not sure it works well with NoNewPrivileges= |
|
|
|
|