sane.fs: dont generate systemd services for every file/dir/symlink
that's handled by systemd-tmpfiles now
This commit is contained in:
@@ -1,29 +1,10 @@
|
|||||||
{ config, lib, pkgs, utils, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
path-lib = sane-lib.path;
|
path-lib = sane-lib.path;
|
||||||
sane-types = sane-lib.types;
|
sane-types = sane-lib.types;
|
||||||
cfg = config.sane.fs;
|
cfg = config.sane.fs;
|
||||||
|
|
||||||
ensure-dir = pkgs.static-nix-shell.mkBash {
|
|
||||||
pname = "ensure-dir";
|
|
||||||
srcRoot = ./.;
|
|
||||||
};
|
|
||||||
ensure-file = pkgs.static-nix-shell.mkBash {
|
|
||||||
pname = "ensure-file";
|
|
||||||
srcRoot = ./.;
|
|
||||||
};
|
|
||||||
ensure-symlink = pkgs.static-nix-shell.mkBash {
|
|
||||||
pname = "ensure-symlink";
|
|
||||||
srcRoot = ./.;
|
|
||||||
};
|
|
||||||
ensure-perms = pkgs.static-nix-shell.mkBash {
|
|
||||||
pname = "ensure-perms";
|
|
||||||
srcRoot = ./.;
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceNameFor = path: "ensure-${utils.escapeSystemdPath path}";
|
|
||||||
|
|
||||||
# sane.fs."<path>" top-level options
|
# sane.fs."<path>" top-level options
|
||||||
fsEntry = types.submodule ({ name, config, ...}: let
|
fsEntry = types.submodule ({ name, config, ...}: let
|
||||||
parent = path-lib.parent name;
|
parent = path-lib.parent name;
|
||||||
@@ -71,13 +52,6 @@ let
|
|||||||
(sane-lib.filterNonNull config.symlink.acl))
|
(sane-lib.filterNonNull config.symlink.acl))
|
||||||
];
|
];
|
||||||
|
|
||||||
# actually generate the item
|
|
||||||
generated.command = lib.mkMerge [
|
|
||||||
(lib.mkIf (config.dir != null) (lib.escapeShellArgs [ "${ensure-dir}/bin/ensure-dir" name ]))
|
|
||||||
(lib.mkIf (config.file != null) (lib.escapeShellArgs [ "${ensure-file}/bin/ensure-file" name config.file.copyFrom ]))
|
|
||||||
(lib.mkIf (config.symlink != null) (lib.escapeShellArgs [ "${ensure-symlink}/bin/ensure-symlink" name config.symlink.target ]))
|
|
||||||
];
|
|
||||||
|
|
||||||
# if we were asked to mount, make sure we create the dir that we mount over
|
# if we were asked to mount, make sure we create the dir that we mount over
|
||||||
dir = lib.mkIf (config.mount != null) {};
|
dir = lib.mkIf (config.mount != null) {};
|
||||||
};
|
};
|
||||||
@@ -154,22 +128,6 @@ let
|
|||||||
acl = mkOption {
|
acl = mkOption {
|
||||||
type = sane-types.acl;
|
type = sane-types.acl;
|
||||||
};
|
};
|
||||||
depends = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
description = ''
|
|
||||||
list of systemd units needed to be run before this item can be generated.
|
|
||||||
'';
|
|
||||||
default = [];
|
|
||||||
};
|
|
||||||
command = mkOption {
|
|
||||||
type = types.coercedTo (types.listOf types.str) lib.escapeShellArgs types.str;
|
|
||||||
default = "";
|
|
||||||
description = ''
|
|
||||||
command to `exec` which will generate the output.
|
|
||||||
this can be a list -- in which case it's treated as some `argv` to exec,
|
|
||||||
or a string, in which case it's passed onto the CLI unescaped.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -205,35 +163,6 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mkGeneratedConfig = path: opt: let
|
|
||||||
gen-opt = opt.generated;
|
|
||||||
wrappedCommand = [
|
|
||||||
"${ensure-perms}/bin/ensure-perms"
|
|
||||||
path
|
|
||||||
gen-opt.acl.user
|
|
||||||
gen-opt.acl.group
|
|
||||||
gen-opt.acl.mode
|
|
||||||
];
|
|
||||||
in {
|
|
||||||
systemd.services."${serviceNameFor path}" = {
|
|
||||||
description = "prepare ${path}";
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true; # makes `systemctl start ensure-blah` a noop if already completed, instead of a restart
|
|
||||||
ExecStart = (escapeShellArgs wrappedCommand) + " " + gen-opt.command;
|
|
||||||
};
|
|
||||||
|
|
||||||
after = gen-opt.depends;
|
|
||||||
requires = gen-opt.depends;
|
|
||||||
# prevent systemd making this unit implicitly dependent on sysinit.target.
|
|
||||||
# see: <https://www.freedesktop.org/software/systemd/man/systemd.special.html>
|
|
||||||
unitConfig.DefaultDependencies = "no";
|
|
||||||
# try to create all entries at boot, but don't block on them. blocking can be more targeted, by higher layers, via e.g. `RequiresMountsFor`
|
|
||||||
wantedBy = [ "default.target" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# given a mountEntry definition, evaluate its toplevel `config` output.
|
# given a mountEntry definition, evaluate its toplevel `config` output.
|
||||||
mkMountConfig = path: opt: let
|
mkMountConfig = path: opt: let
|
||||||
fsEntry = config.fileSystems."${path}";
|
fsEntry = config.fileSystems."${path}";
|
||||||
@@ -292,7 +221,6 @@ let
|
|||||||
# satisfy mkTypedMerge
|
# satisfy mkTypedMerge
|
||||||
systemd.tmpfiles.settings."00-10-sane-fs" = {};
|
systemd.tmpfiles.settings."00-10-sane-fs" = {};
|
||||||
}]
|
}]
|
||||||
++ [ (mkGeneratedConfig path opt) ]
|
|
||||||
++ lib.optional (opt.mount != null) (mkMountConfig path opt)
|
++ lib.optional (opt.mount != null) (mkMountConfig path opt)
|
||||||
++ lib.optional (opt.dir != null) (mkDirConfig path opt)
|
++ lib.optional (opt.dir != null) (mkDirConfig path opt)
|
||||||
++ lib.optional (opt.file != null) (mkFileConfig path opt)
|
++ lib.optional (opt.file != null) (mkFileConfig path opt)
|
||||||
@@ -352,7 +280,6 @@ in {
|
|||||||
configs = lib.mapAttrsToList mkFsConfig cfg;
|
configs = lib.mapAttrsToList mkFsConfig cfg;
|
||||||
take = f: {
|
take = f: {
|
||||||
systemd.mounts = f.systemd.mounts;
|
systemd.mounts = f.systemd.mounts;
|
||||||
systemd.services = f.systemd.services;
|
|
||||||
fileSystems = f.fileSystems;
|
fileSystems = f.fileSystems;
|
||||||
systemd.tmpfiles.settings."00-10-sane-fs" = f.systemd.tmpfiles.settings."00-10-sane-fs";
|
systemd.tmpfiles.settings."00-10-sane-fs" = f.systemd.tmpfiles.settings."00-10-sane-fs";
|
||||||
};
|
};
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env nix-shell
|
|
||||||
#!nix-shell -i bash -p bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
dirpath="$1"
|
|
||||||
|
|
||||||
if ! test -d "$dirpath"
|
|
||||||
then
|
|
||||||
# if the directory *doesn't* exist, try creating it
|
|
||||||
# if we fail to create it, ensure we raced with something else and that it's actually a directory
|
|
||||||
mkdir "$dirpath" || test -d "$dirpath"
|
|
||||||
fi
|
|
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env nix-shell
|
|
||||||
#!nix-shell -i bash -p bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cpto="$1"
|
|
||||||
cpfrom="$2"
|
|
||||||
|
|
||||||
cpOverwrite() {
|
|
||||||
# -f flag in case the destination perms were set to 000
|
|
||||||
# --no-dereference in case the destination already exists as a symlink
|
|
||||||
# however, "no-dereference" has the edge case of copying `cpfrom` to `cpto`
|
|
||||||
# when `cpto` already exists as a symlink to `cpfom`:
|
|
||||||
# "cp: <cpto> and <cpfrom> are the same file"
|
|
||||||
# use `--remove-destination` for that
|
|
||||||
cp --no-dereference -f "$cpfrom" "$cpto" \
|
|
||||||
|| cp --no-dereference --remove-destination "$cpfrom" "$cpto"
|
|
||||||
}
|
|
||||||
|
|
||||||
cpNoOverwrite() {
|
|
||||||
# --no-dereference in case the destination already exists as a symlink.
|
|
||||||
# it will still follow directory-level intermediate symlinks: just not a leaf symlink
|
|
||||||
cp --no-clobber --no-dereference "$cpfrom" "$cpto" || test -f "$cpto"
|
|
||||||
}
|
|
||||||
|
|
||||||
cpNoOverwrite
|
|
@@ -1,31 +0,0 @@
|
|||||||
#!/usr/bin/env nix-shell
|
|
||||||
#!nix-shell -i bash -p bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
fspath="$1"
|
|
||||||
acluser="$2"
|
|
||||||
aclgroup="$3"
|
|
||||||
aclmode="$4"
|
|
||||||
shift 4
|
|
||||||
|
|
||||||
# ensure any things created by the user script have the desired mode.
|
|
||||||
# chmod doesn't work on symlinks, so we *have* to use this umask approach.
|
|
||||||
decmask=$(( 0777 - "$aclmode" ))
|
|
||||||
octmask=$(printf "%o" "$decmask")
|
|
||||||
umask "$octmask"
|
|
||||||
|
|
||||||
# try to chmod/chown the result even if the user script errors
|
|
||||||
set +e
|
|
||||||
("$@")
|
|
||||||
user_status=$?
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# claim ownership of the new thing (DON'T traverse symlinks)
|
|
||||||
chown --no-dereference "$acluser:$aclgroup" "$fspath"
|
|
||||||
# AS LONG AS IT'S NOT A SYMLINK, try to fix perms in case the entity existed before this script was called
|
|
||||||
if ! test -L "$fspath"
|
|
||||||
then
|
|
||||||
chmod "$aclmode" "$fspath"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit "$user_status"
|
|
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env nix-shell
|
|
||||||
#!nix-shell -i bash -p bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
lnfrom="$1"
|
|
||||||
lnto="$2"
|
|
||||||
|
|
||||||
# ln is clever when there's something else at the place we want to create the link
|
|
||||||
# only create the link if nothing's there or what is there is another link,
|
|
||||||
# otherwise you'll get links at unexpected fs locations
|
|
||||||
! test -e "$lnfrom" || test -L "$lnfrom" && ln -sf --no-dereference "$lnto" "$lnfrom"
|
|
Reference in New Issue
Block a user