From a778bedfaea0f47e8e8df3e979466a8ce07e3725 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Mon, 29 Jun 2026 18:34:14 -0400 Subject: [PATCH 1/9] services/turnstiled: init --- modules/services/turnstiled/README.md | 9 + modules/services/turnstiled/default.nix | 186 ++++++++++++++++++ modules/services/turnstiled/package.nix | 52 +++++ modules/services/turnstiled/patch.diff | 26 +++ .../turnstiled/remove_graphical_monitor.diff | 38 ++++ 5 files changed, 311 insertions(+) create mode 100644 modules/services/turnstiled/README.md create mode 100644 modules/services/turnstiled/default.nix create mode 100644 modules/services/turnstiled/package.nix create mode 100644 modules/services/turnstiled/patch.diff create mode 100644 modules/services/turnstiled/remove_graphical_monitor.diff diff --git a/modules/services/turnstiled/README.md b/modules/services/turnstiled/README.md new file mode 100644 index 0000000..cd02c8f --- /dev/null +++ b/modules/services/turnstiled/README.md @@ -0,0 +1,9 @@ +# Turnstiled + +An experimental module for +[turnstile](https://github.com/chimera-linux/turnstile). + +Turnstile is a session/login tracker that runs a user level dinit/runit instance +when a user logs in and closes is safely when they log out. + +This module is subject to extreme changes at any point. diff --git a/modules/services/turnstiled/default.nix b/modules/services/turnstiled/default.nix new file mode 100644 index 0000000..d0ca67a --- /dev/null +++ b/modules/services/turnstiled/default.nix @@ -0,0 +1,186 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.turnstiled; + + package = pkgs.callPackage ./package.nix { graphicalMonitor = cfg.dinit.enableGraphicalMonitor; }; +in +{ + options.services.turnstiled = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable [turnstilel](${cfg.package.meta.homepage}). + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = package; + description = '' + The package to use for `turnstile`. + ''; + }; + + configFile = lib.mkOption { + type = lib.types.path; + default = "/etc/turnstiled.conf"; + description = "Configuration file location for tunrstiled"; + }; + + systemBootDir = lib.mkOption { + type = lib.types.path; + default = "/usr/lib/dinit.d/user/boot.d"; + description = "Location of boot services used for all users"; + }; + + settings = with lib; mkOption { + type = with types; submodule { + options = { + debug = mkOption { + type = enum [ "yes" "no" ]; + default = "no"; + description = "Whether or not to enable debug output in turnstiled"; + }; + backend = mkOption { + type = enum [ "dinit" "runit" ]; + default = "dinit"; + description = "`runit` is not currently supported, but changing this option may break things"; + }; + debug_stderr = mkOption { + type = enum [ "yes" "no" ]; + default = "no"; + description = "Whether or not to print debug to stderr in addition to stdout"; + }; + linger = mkOption { + type = enum [ "yes" "no" ]; + default = "no"; + description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; + }; + rundir_path = mkOption { + type = str; + default = "/run/user/%u"; + description = "Where the rundir is for the user. See [turnstiled](${cfg.package.meta.homepage}) documentation for available options"; + }; + manage_rundir = mkOption { + type = enum [ "yes" "no" ]; + default = "no"; + description = "Whether or not `turnstiled` should manage the runtime directory"; + + }; + export_dbus_address = mkOption { + type = enum [ "yes" "no" ]; + default = "yes"; + description = "Whether or not to export the D-Bus session address to the environment of the service manager"; + }; + login_timeout = mkOption { + type = ints.unsigned; + default = 60; + description = "How long the service manager waits on initial processes (in seconds) before giving up."; + }; + root_session = mkOption { + type = enum [ "yes" "no" ]; + default = "no"; + description = "Whether or not `turnstiled` acts for the root user."; + }; + }; + }; + }; + + dinit = with lib; mkOption { + type = with types; submodule { + options = { + enable = mkOption { + type = bool; + default = true; + description = "Whether or not to use the dinit backend for `turnstiled`."; + }; + + service_dir = mkOption { + type = str; + default = "$HOME/.config/dinit.d"; + description = "Users service dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + boot_dir = mkOption { + type = str; + default = "${cfg.dinit.service_dir}/boot.d"; + description = "Users service boot dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + system_boot_dir = mkOption { + type = path; + default = "/usr/lib/dinit.d/user/boot.d"; + description = "Systems service boot dir for `turnstiled`'s `dinit` backend."; + }; + + enableGraphicalMonitor = mkOption { + type = bool; + default = false; + description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; + }; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ] ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio pkgs.dinit); + + finit.tmpfiles.rules = [ + "d ${cfg.dinit.system_boot_dir} 0777" + ]; + + environment.etc = { + "turnstile/turnstiled.conf".text = '' +debug = ${cfg.settings.debug} +backend = ${cfg.settings.backend} +debug_stderr = ${cfg.settings.debug_stderr} +linger = ${cfg.settings.linger} +rundir_path = ${cfg.settings.rundir_path} +manage_rundir = ${cfg.settings.manage_rundir} +export_dbus_address = ${cfg.settings.export_dbus_address} +login_timeout = ${toString cfg.settings.login_timeout} +root_session = ${cfg.settings.root_session} + ''; + + "turnstile/backend/dinit.conf".text = '' +boot_dir="${cfg.dinit.boot_dir}" +system_boot_dir="${cfg.dinit.system_boot_dir}" +services_dir1="${cfg.dinit.service_dir}" +services_dir2="/etc/dinit.d/user" +services_dir3="/usr/local/lib/dinit.d/user" +services_dir4="/usr/lib/dinit.d/user" + ''; + + "pam.d/turnstiled".text = ''auth sufficient pam_rootok.so +session optional pam_keyinit.so force revoke +session optional pam_umask.so usergroups umask=022 +-session optional pam_elogind.so +session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) +session required ${cfg.package}/pam/pam_turnstile.so turnstiled +session required pam_limits.so +''; + }; + + security.pam.services = lib.mkMerge [ + { + login.text = lib.mkAfter "session optional ${cfg.package}/pam/pam_turnstile.so"; + } + ]; + + finit.services.turnstiled = { + description = "turnstiled, a user-service manager manager"; + command = "${cfg.package}/bin/turnstiled"; + conditions = "service/syslogd/ready"; + log = true; + pid = "/run/turnstiled.pid"; + path = with pkgs; [ cfg.package coreutils ] ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio dinit); + }; + }; +} diff --git a/modules/services/turnstiled/package.nix b/modules/services/turnstiled/package.nix new file mode 100644 index 0000000..2f18bcb --- /dev/null +++ b/modules/services/turnstiled/package.nix @@ -0,0 +1,52 @@ +{ + lib, + pkgs, + stdenv, + fetchFromGitHub, + graphicalMonitor ? true, +}: + +stdenv.mkDerivation { + pname = "turnstiled"; + version = "0-unstable-2025-12-15"; + + src = fetchFromGitHub { + owner = "chimera-linux"; + repo = "turnstile"; + rev = "e3413dad386bf72048646f9f9ffd3a8d60e10eb0"; + sha256 = "sha256-TH0zLYKgDup+byBxr68R3DWt1/+BFJIkXWSuqSHAEOE="; + }; + + nativeBuildInputs = with pkgs; [ + pkg-config + scdoc + meson + ninja + pam + ]; + + buildInputs = with pkgs; [ + dinit + ]; + + mesonFlags = [ + "-Ddefault_backend=dinit" + "-Ddinit=enabled" + "-Dstatedir=/var/lib/turnstiled" + "-Dpam_moddir=./pam" + ]; + + patches = [ ./patch.diff ] ++ lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); + + doInstallCheck = false; + + meta = with lib; { + homepage = "https://github.com/chimera-linux/turnstile"; + description = "This program waits for user logins and then runs the associated user-service manager"; + license = licenses.bsd2; + maintainers = with maintainers; [ vitrial ]; + platforms = platforms.linux; + mainProgram = "turnstiled"; + }; + +} diff --git a/modules/services/turnstiled/patch.diff b/modules/services/turnstiled/patch.diff new file mode 100644 index 0000000..02f1f82 --- /dev/null +++ b/modules/services/turnstiled/patch.diff @@ -0,0 +1,26 @@ +diff --git a/backend/dinit b/backend/dinit +index 7bacaac..065d14a 100644 +--- a/backend/dinit ++++ b/backend/dinit +@@ -136,7 +136,7 @@ cat << EOF > "${DINIT_DIR}/graphical.monitor" + type = process + depends-on = login.target + options = pass-cs-fd +-command = /usr/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY ++command = /run/current-system/sw/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY + EOF + + # this is needed for login to proceed +diff --git a/meson.build b/meson.build +index aa07c9c..fdf89fa 100644 +--- a/meson.build ++++ b/meson.build +@@ -28,7 +28,7 @@ have_runit = get_option('runit').enabled() + conf_data = configuration_data() + conf_data.set_quoted('RUN_PATH', get_option('rundir')) + conf_data.set_quoted('CONF_PATH', join_paths( +- get_option('prefix'), get_option('sysconfdir'), 'turnstile' ++ '/etc/', 'turnstile' + )) + conf_data.set10('MANAGE_RUNDIR', get_option('manage_rundir')) + diff --git a/modules/services/turnstiled/remove_graphical_monitor.diff b/modules/services/turnstiled/remove_graphical_monitor.diff new file mode 100644 index 0000000..b3721e4 --- /dev/null +++ b/modules/services/turnstiled/remove_graphical_monitor.diff @@ -0,0 +1,38 @@ +diff --git a/backend/dinit b/backend/dinit +index 7bacaac..27ee9b7 100644 +--- a/backend/dinit ++++ b/backend/dinit +@@ -121,8 +121,6 @@ type = internal + depends-on = system + waits-for.d = ${boot_dir} + depends-on = login.target +-depends-ms = graphical.monitor +-depends-ms = graphical.target + EOF + + # this must also succeed +@@ -131,24 +129,9 @@ type = internal + waits-for.d = ${system_boot_dir} + EOF + +-# monitor service to watch for environment changes +-cat << EOF > "${DINIT_DIR}/graphical.monitor" +-type = process +-depends-on = login.target +-options = pass-cs-fd +-command = /run/current-system/sw/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY +-EOF +- + # this is needed for login to proceed + cat << EOF > "${DINIT_DIR}/login.target" + type = internal + EOF + +-# this is not necessary to have started for login to proceed +-cat << EOF > "${DINIT_DIR}/graphical.target" +-type = triggered +-depends-on = graphical.monitor +-depends-on = login.target +-EOF +- + exec dinit --user --ready-fd 3 --services-dir "$DINIT_DIR" "$@" 3>"$DINIT_READY_PIPE" From fda5a2df8d5dd8da7556c1a3a90611df51cf6ca9 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Mon, 29 Jun 2026 19:05:01 -0400 Subject: [PATCH 2/9] services/turnstiled: fixed formatting --- modules/services/turnstiled/default.nix | 329 +++++++++++++----------- modules/services/turnstiled/package.nix | 45 ++-- 2 files changed, 208 insertions(+), 166 deletions(-) diff --git a/modules/services/turnstiled/default.nix b/modules/services/turnstiled/default.nix index d0ca67a..a9c46a9 100644 --- a/modules/services/turnstiled/default.nix +++ b/modules/services/turnstiled/default.nix @@ -27,160 +27,199 @@ in ''; }; - configFile = lib.mkOption { - type = lib.types.path; - default = "/etc/turnstiled.conf"; - description = "Configuration file location for tunrstiled"; - }; - - systemBootDir = lib.mkOption { - type = lib.types.path; - default = "/usr/lib/dinit.d/user/boot.d"; - description = "Location of boot services used for all users"; - }; - - settings = with lib; mkOption { - type = with types; submodule { - options = { - debug = mkOption { - type = enum [ "yes" "no" ]; - default = "no"; - description = "Whether or not to enable debug output in turnstiled"; - }; - backend = mkOption { - type = enum [ "dinit" "runit" ]; - default = "dinit"; - description = "`runit` is not currently supported, but changing this option may break things"; - }; - debug_stderr = mkOption { - type = enum [ "yes" "no" ]; - default = "no"; - description = "Whether or not to print debug to stderr in addition to stdout"; - }; - linger = mkOption { - type = enum [ "yes" "no" ]; - default = "no"; - description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; - }; - rundir_path = mkOption { - type = str; - default = "/run/user/%u"; - description = "Where the rundir is for the user. See [turnstiled](${cfg.package.meta.homepage}) documentation for available options"; - }; - manage_rundir = mkOption { - type = enum [ "yes" "no" ]; - default = "no"; - description = "Whether or not `turnstiled` should manage the runtime directory"; - - }; - export_dbus_address = mkOption { - type = enum [ "yes" "no" ]; - default = "yes"; - description = "Whether or not to export the D-Bus session address to the environment of the service manager"; - }; - login_timeout = mkOption { - type = ints.unsigned; - default = 60; - description = "How long the service manager waits on initial processes (in seconds) before giving up."; - }; - root_session = mkOption { - type = enum [ "yes" "no" ]; - default = "no"; - description = "Whether or not `turnstiled` acts for the root user."; - }; - }; - }; - }; - - dinit = with lib; mkOption { - type = with types; submodule { - options = { - enable = mkOption { - type = bool; - default = true; - description = "Whether or not to use the dinit backend for `turnstiled`."; - }; - - service_dir = mkOption { - type = str; - default = "$HOME/.config/dinit.d"; - description = "Users service dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; - }; - - boot_dir = mkOption { - type = str; - default = "${cfg.dinit.service_dir}/boot.d"; - description = "Users service boot dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; - }; - - system_boot_dir = mkOption { - type = path; - default = "/usr/lib/dinit.d/user/boot.d"; - description = "Systems service boot dir for `turnstiled`'s `dinit` backend."; - }; - - enableGraphicalMonitor = mkOption { - type = bool; - default = false; - description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; - }; - }; - }; - }; + configFile = lib.mkOption { + type = lib.types.path; + default = "/etc/turnstiled.conf"; + description = "Configuration file location for tunrstiled"; + }; + + systemBootDir = lib.mkOption { + type = lib.types.path; + default = "/usr/lib/dinit.d/user/boot.d"; + description = "Location of boot services used for all users"; + }; + + settings = + with lib; + mkOption { + type = + with types; + submodule { + options = { + debug = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not to enable debug output in turnstiled"; + }; + backend = mkOption { + type = enum [ + "dinit" + "runit" + ]; + default = "dinit"; + description = "`runit` is not currently supported, but changing this option may break things"; + }; + debug_stderr = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not to print debug to stderr in addition to stdout"; + }; + linger = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; + }; + rundir_path = mkOption { + type = str; + default = "/run/user/%u"; + description = "Where the rundir is for the user. See [turnstiled](${cfg.package.meta.homepage}) documentation for available options"; + }; + manage_rundir = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not `turnstiled` should manage the runtime directory"; + + }; + export_dbus_address = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "yes"; + description = "Whether or not to export the D-Bus session address to the environment of the service manager"; + }; + login_timeout = mkOption { + type = ints.unsigned; + default = 60; + description = "How long the service manager waits on initial processes (in seconds) before giving up."; + }; + root_session = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not `turnstiled` acts for the root user."; + }; + }; + }; + }; + + dinit = + with lib; + mkOption { + type = + with types; + submodule { + options = { + enable = mkOption { + type = bool; + default = true; + description = "Whether or not to use the dinit backend for `turnstiled`."; + }; + + service_dir = mkOption { + type = str; + default = "$HOME/.config/dinit.d"; + description = "Users service dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + boot_dir = mkOption { + type = str; + default = "${cfg.dinit.service_dir}/boot.d"; + description = "Users service boot dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + system_boot_dir = mkOption { + type = path; + default = "/usr/lib/dinit.d/user/boot.d"; + description = "Systems service boot dir for `turnstiled`'s `dinit` backend."; + }; + + enableGraphicalMonitor = mkOption { + type = bool; + default = false; + description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; + }; + }; + }; + }; }; config = lib.mkIf cfg.enable { - environment.systemPackages = [ cfg.package ] ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio pkgs.dinit); - - finit.tmpfiles.rules = [ - "d ${cfg.dinit.system_boot_dir} 0777" - ]; - - environment.etc = { - "turnstile/turnstiled.conf".text = '' -debug = ${cfg.settings.debug} -backend = ${cfg.settings.backend} -debug_stderr = ${cfg.settings.debug_stderr} -linger = ${cfg.settings.linger} -rundir_path = ${cfg.settings.rundir_path} -manage_rundir = ${cfg.settings.manage_rundir} -export_dbus_address = ${cfg.settings.export_dbus_address} -login_timeout = ${toString cfg.settings.login_timeout} -root_session = ${cfg.settings.root_session} - ''; - - "turnstile/backend/dinit.conf".text = '' -boot_dir="${cfg.dinit.boot_dir}" -system_boot_dir="${cfg.dinit.system_boot_dir}" -services_dir1="${cfg.dinit.service_dir}" -services_dir2="/etc/dinit.d/user" -services_dir3="/usr/local/lib/dinit.d/user" -services_dir4="/usr/lib/dinit.d/user" - ''; - - "pam.d/turnstiled".text = ''auth sufficient pam_rootok.so -session optional pam_keyinit.so force revoke -session optional pam_umask.so usergroups umask=022 --session optional pam_elogind.so -session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) -session required ${cfg.package}/pam/pam_turnstile.so turnstiled -session required pam_limits.so -''; - }; - - security.pam.services = lib.mkMerge [ - { - login.text = lib.mkAfter "session optional ${cfg.package}/pam/pam_turnstile.so"; - } - ]; + environment.systemPackages = [ + cfg.package + ] + ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio pkgs.dinit); + + finit.tmpfiles.rules = [ + "d ${cfg.dinit.system_boot_dir} 0777" + ]; + + environment.etc = { + "turnstile/turnstiled.conf".text = '' + debug = ${cfg.settings.debug} + backend = ${cfg.settings.backend} + debug_stderr = ${cfg.settings.debug_stderr} + linger = ${cfg.settings.linger} + rundir_path = ${cfg.settings.rundir_path} + manage_rundir = ${cfg.settings.manage_rundir} + export_dbus_address = ${cfg.settings.export_dbus_address} + login_timeout = ${toString cfg.settings.login_timeout} + root_session = ${cfg.settings.root_session} + ''; + + "turnstile/backend/dinit.conf".text = '' + boot_dir="${cfg.dinit.boot_dir}" + system_boot_dir="${cfg.dinit.system_boot_dir}" + services_dir1="${cfg.dinit.service_dir}" + services_dir2="/etc/dinit.d/user" + services_dir3="/usr/local/lib/dinit.d/user" + services_dir4="/usr/lib/dinit.d/user" + ''; + + "pam.d/turnstiled".text = '' + auth sufficient pam_rootok.so + session optional pam_keyinit.so force revoke + session optional pam_umask.so usergroups umask=022 + -session optional pam_elogind.so + session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) + session required ${cfg.package}/pam/pam_turnstile.so turnstiled + session required pam_limits.so + ''; + }; + + security.pam.services = lib.mkMerge [ + { + login.text = lib.mkAfter "session optional ${cfg.package}/pam/pam_turnstile.so"; + } + ]; finit.services.turnstiled = { description = "turnstiled, a user-service manager manager"; command = "${cfg.package}/bin/turnstiled"; conditions = "service/syslogd/ready"; log = true; - pid = "/run/turnstiled.pid"; - path = with pkgs; [ cfg.package coreutils ] ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio dinit); + pid = "/run/turnstiled.pid"; + path = + with pkgs; + [ + cfg.package + coreutils + ] + ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio dinit); }; }; } diff --git a/modules/services/turnstiled/package.nix b/modules/services/turnstiled/package.nix index 2f18bcb..f0996fb 100644 --- a/modules/services/turnstiled/package.nix +++ b/modules/services/turnstiled/package.nix @@ -1,9 +1,9 @@ { lib, - pkgs, + pkgs, stdenv, fetchFromGitHub, - graphicalMonitor ? true, + graphicalMonitor ? true, }: stdenv.mkDerivation { @@ -18,25 +18,28 @@ stdenv.mkDerivation { }; nativeBuildInputs = with pkgs; [ - pkg-config - scdoc - meson - ninja - pam - ]; - - buildInputs = with pkgs; [ - dinit - ]; - - mesonFlags = [ - "-Ddefault_backend=dinit" - "-Ddinit=enabled" - "-Dstatedir=/var/lib/turnstiled" - "-Dpam_moddir=./pam" - ]; - - patches = [ ./patch.diff ] ++ lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); + pkg-config + scdoc + meson + ninja + pam + ]; + + buildInputs = with pkgs; [ + dinit + ]; + + mesonFlags = [ + "-Ddefault_backend=dinit" + "-Ddinit=enabled" + "-Dstatedir=/var/lib/turnstiled" + "-Dpam_moddir=./pam" + ]; + + patches = [ + ./patch.diff + ] + ++ lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); doInstallCheck = false; From 1e8d85e4d665587c701a0c2cc313e5ffa459d315 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Mon, 29 Jun 2026 19:07:17 -0400 Subject: [PATCH 3/9] services/turnstile: changed service name to turnstile from turnstiled --- .../{turnstiled => turnstile}/README.md | 2 +- .../{turnstiled => turnstile}/default.nix | 20 +++++++++---------- .../{turnstiled => turnstile}/package.nix | 2 +- .../{turnstiled => turnstile}/patch.diff | 0 .../remove_graphical_monitor.diff | 0 5 files changed, 12 insertions(+), 12 deletions(-) rename modules/services/{turnstiled => turnstile}/README.md (95%) rename modules/services/{turnstiled => turnstile}/default.nix (90%) rename modules/services/{turnstiled => turnstile}/package.nix (97%) rename modules/services/{turnstiled => turnstile}/patch.diff (100%) rename modules/services/{turnstiled => turnstile}/remove_graphical_monitor.diff (100%) diff --git a/modules/services/turnstiled/README.md b/modules/services/turnstile/README.md similarity index 95% rename from modules/services/turnstiled/README.md rename to modules/services/turnstile/README.md index cd02c8f..f48cafe 100644 --- a/modules/services/turnstiled/README.md +++ b/modules/services/turnstile/README.md @@ -1,4 +1,4 @@ -# Turnstiled +# Turnstile An experimental module for [turnstile](https://github.com/chimera-linux/turnstile). diff --git a/modules/services/turnstiled/default.nix b/modules/services/turnstile/default.nix similarity index 90% rename from modules/services/turnstiled/default.nix rename to modules/services/turnstile/default.nix index a9c46a9..9b7e8e7 100644 --- a/modules/services/turnstiled/default.nix +++ b/modules/services/turnstile/default.nix @@ -5,12 +5,12 @@ ... }: let - cfg = config.services.turnstiled; + cfg = config.services.turnstile; package = pkgs.callPackage ./package.nix { graphicalMonitor = cfg.dinit.enableGraphicalMonitor; }; in { - options.services.turnstiled = { + options.services.turnstile = { enable = lib.mkOption { type = lib.types.bool; default = false; @@ -52,7 +52,7 @@ in "no" ]; default = "no"; - description = "Whether or not to enable debug output in turnstiled"; + description = "Whether or not to enable debug output in turnstile"; }; backend = mkOption { type = enum [ @@ -81,7 +81,7 @@ in rundir_path = mkOption { type = str; default = "/run/user/%u"; - description = "Where the rundir is for the user. See [turnstiled](${cfg.package.meta.homepage}) documentation for available options"; + description = "Where the rundir is for the user. See [turnstile](${cfg.package.meta.homepage}) documentation for available options"; }; manage_rundir = mkOption { type = enum [ @@ -89,7 +89,7 @@ in "no" ]; default = "no"; - description = "Whether or not `turnstiled` should manage the runtime directory"; + description = "Whether or not `turnstile` should manage the runtime directory"; }; export_dbus_address = mkOption { @@ -111,7 +111,7 @@ in "no" ]; default = "no"; - description = "Whether or not `turnstiled` acts for the root user."; + description = "Whether or not `turnstile` acts for the root user."; }; }; }; @@ -127,25 +127,25 @@ in enable = mkOption { type = bool; default = true; - description = "Whether or not to use the dinit backend for `turnstiled`."; + description = "Whether or not to use the dinit backend for `turnstile`."; }; service_dir = mkOption { type = str; default = "$HOME/.config/dinit.d"; - description = "Users service dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + description = "Users service dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; }; boot_dir = mkOption { type = str; default = "${cfg.dinit.service_dir}/boot.d"; - description = "Users service boot dir for `turnstiled`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + description = "Users service boot dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; }; system_boot_dir = mkOption { type = path; default = "/usr/lib/dinit.d/user/boot.d"; - description = "Systems service boot dir for `turnstiled`'s `dinit` backend."; + description = "Systems service boot dir for `turnstile`'s `dinit` backend."; }; enableGraphicalMonitor = mkOption { diff --git a/modules/services/turnstiled/package.nix b/modules/services/turnstile/package.nix similarity index 97% rename from modules/services/turnstiled/package.nix rename to modules/services/turnstile/package.nix index f0996fb..2cadeb0 100644 --- a/modules/services/turnstiled/package.nix +++ b/modules/services/turnstile/package.nix @@ -7,7 +7,7 @@ }: stdenv.mkDerivation { - pname = "turnstiled"; + pname = "turnstile"; version = "0-unstable-2025-12-15"; src = fetchFromGitHub { diff --git a/modules/services/turnstiled/patch.diff b/modules/services/turnstile/patch.diff similarity index 100% rename from modules/services/turnstiled/patch.diff rename to modules/services/turnstile/patch.diff diff --git a/modules/services/turnstiled/remove_graphical_monitor.diff b/modules/services/turnstile/remove_graphical_monitor.diff similarity index 100% rename from modules/services/turnstiled/remove_graphical_monitor.diff rename to modules/services/turnstile/remove_graphical_monitor.diff From 5bb80b91f6635824cd540ad3ed86b36eed6f5172 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Wed, 1 Jul 2026 16:46:10 -0400 Subject: [PATCH 4/9] services/turnstile: made requested changes to default.nix for quality --- modules/services/turnstile/default.nix | 260 ++++++++++++------------- 1 file changed, 122 insertions(+), 138 deletions(-) diff --git a/modules/services/turnstile/default.nix b/modules/services/turnstile/default.nix index 9b7e8e7..27ef71b 100644 --- a/modules/services/turnstile/default.nix +++ b/modules/services/turnstile/default.nix @@ -7,7 +7,9 @@ let cfg = config.services.turnstile; - package = pkgs.callPackage ./package.nix { graphicalMonitor = cfg.dinit.enableGraphicalMonitor; }; + package = pkgs.callPackage ./package.nix { + graphicalMonitor = cfg.dinit.settings.enableGraphicalMonitor; + }; in { options.services.turnstile = { @@ -27,135 +29,116 @@ in ''; }; - configFile = lib.mkOption { - type = lib.types.path; - default = "/etc/turnstiled.conf"; - description = "Configuration file location for tunrstiled"; - }; - systemBootDir = lib.mkOption { type = lib.types.path; default = "/usr/lib/dinit.d/user/boot.d"; description = "Location of boot services used for all users"; }; - settings = - with lib; - mkOption { - type = - with types; - submodule { - options = { - debug = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not to enable debug output in turnstile"; - }; - backend = mkOption { - type = enum [ - "dinit" - "runit" - ]; - default = "dinit"; - description = "`runit` is not currently supported, but changing this option may break things"; - }; - debug_stderr = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not to print debug to stderr in addition to stdout"; - }; - linger = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; - }; - rundir_path = mkOption { - type = str; - default = "/run/user/%u"; - description = "Where the rundir is for the user. See [turnstile](${cfg.package.meta.homepage}) documentation for available options"; - }; - manage_rundir = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not `turnstile` should manage the runtime directory"; - - }; - export_dbus_address = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "yes"; - description = "Whether or not to export the D-Bus session address to the environment of the service manager"; - }; - login_timeout = mkOption { - type = ints.unsigned; - default = 60; - description = "How long the service manager waits on initial processes (in seconds) before giving up."; - }; - root_session = mkOption { - type = enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not `turnstile` acts for the root user."; - }; - }; - }; + settings = with lib; { + debug = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not to enable debug output in turnstile"; + }; + backend = mkOption { + type = types.enum [ + "dinit" + "runit" + ]; + default = "dinit"; + description = "`runit` is not currently supported, but changing this option may break things"; + }; + debug_stderr = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not to print debug to stderr in addition to stdout"; + }; + linger = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; + }; + rundir_path = mkOption { + type = types.str; + default = "/run/user/%u"; + description = "Where the rundir is for the user. See [turnstile](${cfg.package.meta.homepage}) documentation for available options"; + }; + manage_rundir = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not `turnstile` should manage the runtime directory"; + + }; + export_dbus_address = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "yes"; + description = "Whether or not to export the D-Bus session address to the environment of the service manager"; + }; + login_timeout = mkOption { + type = types.ints.unsigned; + default = 60; + description = "How long the service manager waits on initial processes (in seconds) before giving up."; + }; + root_session = mkOption { + type = types.enum [ + "yes" + "no" + ]; + default = "no"; + description = "Whether or not `turnstile` acts for the root user."; + }; + }; + + dinit = with lib; { + enable = mkOption { + type = types.bool; + default = true; + description = "Whether or not to use the dinit backend for `turnstile`."; }; - dinit = - with lib; - mkOption { - type = - with types; - submodule { - options = { - enable = mkOption { - type = bool; - default = true; - description = "Whether or not to use the dinit backend for `turnstile`."; - }; - - service_dir = mkOption { - type = str; - default = "$HOME/.config/dinit.d"; - description = "Users service dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; - }; - - boot_dir = mkOption { - type = str; - default = "${cfg.dinit.service_dir}/boot.d"; - description = "Users service boot dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; - }; - - system_boot_dir = mkOption { - type = path; - default = "/usr/lib/dinit.d/user/boot.d"; - description = "Systems service boot dir for `turnstile`'s `dinit` backend."; - }; - - enableGraphicalMonitor = mkOption { - type = bool; - default = false; - description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; - }; - }; - }; + settings = with types; { + # TODO: make this accept a str or a list of strings + service_dir = mkOption { + type = str; + default = "$HOME/.config/dinit.d"; + description = "Users service dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + boot_dir = mkOption { + type = types.str; + default = "${cfg.dinit.settings.service_dir}/boot.d"; + description = "Users service boot dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + }; + + system_boot_dir = mkOption { + type = types.path; + default = "/usr/lib/dinit.d/user/boot.d"; + description = "Systems service boot dir for `turnstile`'s `dinit` backend."; + }; + + enableGraphicalMonitor = mkOption { + type = types.bool; + default = false; + description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; + }; }; + }; }; config = lib.mkIf cfg.enable { @@ -165,26 +148,18 @@ in ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio pkgs.dinit); finit.tmpfiles.rules = [ - "d ${cfg.dinit.system_boot_dir} 0777" + "d ${cfg.dinit.settings.system_boot_dir} 0777" ]; environment.etc = { - "turnstile/turnstiled.conf".text = '' - debug = ${cfg.settings.debug} - backend = ${cfg.settings.backend} - debug_stderr = ${cfg.settings.debug_stderr} - linger = ${cfg.settings.linger} - rundir_path = ${cfg.settings.rundir_path} - manage_rundir = ${cfg.settings.manage_rundir} - export_dbus_address = ${cfg.settings.export_dbus_address} - login_timeout = ${toString cfg.settings.login_timeout} - root_session = ${cfg.settings.root_session} - ''; + "turnstile/turnstiled.conf".source = + (pkgs.formats.keyValue { }).generate "turnstiled.conf" + cfg.settings; "turnstile/backend/dinit.conf".text = '' - boot_dir="${cfg.dinit.boot_dir}" - system_boot_dir="${cfg.dinit.system_boot_dir}" - services_dir1="${cfg.dinit.service_dir}" + boot_dir="${cfg.dinit.settings.boot_dir}" + system_boot_dir="${cfg.dinit.settings.system_boot_dir}" + services_dir1="${cfg.dinit.settings.service_dir}" services_dir2="/etc/dinit.d/user" services_dir3="/usr/local/lib/dinit.d/user" services_dir4="/usr/lib/dinit.d/user" @@ -204,6 +179,15 @@ in security.pam.services = lib.mkMerge [ { login.text = lib.mkAfter "session optional ${cfg.package}/pam/pam_turnstile.so"; + turnstiled.text = '' + auth sufficient pam_rootok.so + session optional pam_keyinit.so force revoke + session optional pam_umask.so usergroups umask=022 + -session optional pam_elogind.so + session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) + session required ${cfg.package}/pam/pam_turnstile.so turnstiled + session required pam_limits.so + ''; } ]; @@ -217,9 +201,9 @@ in with pkgs; [ cfg.package - coreutils + config.programs.coreutils.package ] - ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio dinit); + ++ lib.lists.optional cfg.dinit.enable dinit; }; }; } From 15a3dd5d710e1b82b1c8064b97a287dde5889bbc Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Wed, 1 Jul 2026 17:08:47 -0400 Subject: [PATCH 5/9] services/turnstile: made requested changes in package.nix for quality --- modules/services/turnstile/package.nix | 43 ++++++++++++------- .../turnstile/remove_graphical_monitor.diff | 2 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/modules/services/turnstile/package.nix b/modules/services/turnstile/package.nix index 2cadeb0..6fe6246 100644 --- a/modules/services/turnstile/package.nix +++ b/modules/services/turnstile/package.nix @@ -1,32 +1,50 @@ { lib, - pkgs, stdenv, fetchFromGitHub, + pkg-config, + scdoc, + meson, + ninja, + pam, + dinit, graphicalMonitor ? true, }: -stdenv.mkDerivation { +stdenv.mkDerivation (finalAttrs: { pname = "turnstile"; - version = "0-unstable-2025-12-15"; + version = "v0.1.11"; src = fetchFromGitHub { owner = "chimera-linux"; repo = "turnstile"; - rev = "e3413dad386bf72048646f9f9ffd3a8d60e10eb0"; - sha256 = "sha256-TH0zLYKgDup+byBxr68R3DWt1/+BFJIkXWSuqSHAEOE="; + rev = "${finalAttrs.version}"; + sha256 = "sha256-94J+w0RHxzw7wS70LcpEzMvgevAqAwl0EtiANUmdRYU="; }; - nativeBuildInputs = with pkgs; [ + buildInputs = [ pkg-config scdoc meson ninja pam + dinit ]; - buildInputs = with pkgs; [ - dinit + # nativeBuildInputs = [ + # dinit + # ]; + + postPatch = lib.strings.concatStrings [ + (lib.strings.optionalString graphicalMonitor '' + substituteInPlace backend/dinit \ + --replace-fail '/usr/bin/dinit-monitor' '${lib.getExe' dinit "dinit-monitor"}' + '') + + '' + substituteInPlace meson.build \ + --replace-fail "get_option('prefix'), get_option('sysconfdir'), 'turnstile'" "'/etc', 'turnstile'" + '' ]; mesonFlags = [ @@ -36,12 +54,7 @@ stdenv.mkDerivation { "-Dpam_moddir=./pam" ]; - patches = [ - ./patch.diff - ] - ++ lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); - - doInstallCheck = false; + patches = lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); meta = with lib; { homepage = "https://github.com/chimera-linux/turnstile"; @@ -52,4 +65,4 @@ stdenv.mkDerivation { mainProgram = "turnstiled"; }; -} +}) diff --git a/modules/services/turnstile/remove_graphical_monitor.diff b/modules/services/turnstile/remove_graphical_monitor.diff index b3721e4..cf1d90a 100644 --- a/modules/services/turnstile/remove_graphical_monitor.diff +++ b/modules/services/turnstile/remove_graphical_monitor.diff @@ -20,7 +20,7 @@ index 7bacaac..27ee9b7 100644 -type = process -depends-on = login.target -options = pass-cs-fd --command = /run/current-system/sw/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY +-command = /usr/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY -EOF - # this is needed for login to proceed From db831a71935b099d4f58feae3d6842ea924c2fe1 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Tue, 7 Jul 2026 15:34:56 -0400 Subject: [PATCH 6/9] modules/turnstile: leftover code removed --- modules/services/turnstile/default.nix | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/modules/services/turnstile/default.nix b/modules/services/turnstile/default.nix index 27ef71b..aacca9b 100644 --- a/modules/services/turnstile/default.nix +++ b/modules/services/turnstile/default.nix @@ -164,16 +164,6 @@ in services_dir3="/usr/local/lib/dinit.d/user" services_dir4="/usr/lib/dinit.d/user" ''; - - "pam.d/turnstiled".text = '' - auth sufficient pam_rootok.so - session optional pam_keyinit.so force revoke - session optional pam_umask.so usergroups umask=022 - -session optional pam_elogind.so - session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) - session required ${cfg.package}/pam/pam_turnstile.so turnstiled - session required pam_limits.so - ''; }; security.pam.services = lib.mkMerge [ From 94d1cff0d421138de923155f2f4f40e409e41149 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Sat, 18 Jul 2026 01:20:37 -0400 Subject: [PATCH 7/9] services/turnstile: implemented changes based on aanderse's branch --- modules/services/turnstile/default.nix | 321 +++++++++++------- modules/services/turnstile/package.nix | 42 +-- modules/services/turnstile/patch.diff | 26 -- .../turnstile/remove_graphical_monitor.diff | 38 --- 4 files changed, 212 insertions(+), 215 deletions(-) delete mode 100644 modules/services/turnstile/patch.diff delete mode 100644 modules/services/turnstile/remove_graphical_monitor.diff diff --git a/modules/services/turnstile/default.nix b/modules/services/turnstile/default.nix index aacca9b..fcd13db 100644 --- a/modules/services/turnstile/default.nix +++ b/modules/services/turnstile/default.nix @@ -6,10 +6,6 @@ }: let cfg = config.services.turnstile; - - package = pkgs.callPackage ./package.nix { - graphicalMonitor = cfg.dinit.settings.enableGraphicalMonitor; - }; in { options.services.turnstile = { @@ -17,183 +13,254 @@ in type = lib.types.bool; default = false; description = '' - Whether to enable [turnstilel](${cfg.package.meta.homepage}). + Whether to enable [turnstilel](${cfg.package.meta.homepage}) as a system service. ''; }; package = lib.mkOption { type = lib.types.package; - default = package; + default = pkgs.callPackage ./package.nix { }; description = '' The package to use for `turnstile`. ''; }; - systemBootDir = lib.mkOption { - type = lib.types.path; - default = "/usr/lib/dinit.d/user/boot.d"; - description = "Location of boot services used for all users"; - }; - - settings = with lib; { - debug = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not to enable debug output in turnstile"; + settings = { + debug = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to output debug information. This is verbose + logging that is only useful when investigating issues. + ''; }; - backend = mkOption { - type = types.enum [ + + backend = lib.mkOption { + type = lib.types.enum [ + "none" "dinit" "runit" ]; - default = "dinit"; - description = "`runit` is not currently supported, but changing this option may break things"; + default = "none"; + description = '' + The service backend to use. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - debug_stderr = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not to print debug to stderr in addition to stdout"; + + debug_stderr = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to print debug messages also to `stderr`. + ''; }; - linger = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not the service manager should linger after user logout. Requires ${cfg.settings.manage_rundir} to be enabled"; + + linger = lib.mkOption { + type = with lib.types; either bool (enum [ "maybe" ]); + default = "maybe"; + description = '' + Whether to keep already started services running even + after the last login of the user is gone. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - rundir_path = mkOption { - type = types.str; + + rundir_path = lib.mkOption { + type = lib.types.str; default = "/run/user/%u"; - description = "Where the rundir is for the user. See [turnstile](${cfg.package.meta.homepage}) documentation for available options"; + description = '' + The value of `XDG_RUNTIME_DIR` that is exported into the + user service environment. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - manage_rundir = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not `turnstile` should manage the runtime directory"; + manage_rundir = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to manage the `XDG_RUNTIME_DIR`. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - export_dbus_address = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "yes"; - description = "Whether or not to export the D-Bus session address to the environment of the service manager"; + + export_dbus_address = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to export `DBUS_SESSION_BUS_ADDRESS` into the + environment. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - login_timeout = mkOption { - type = types.ints.unsigned; + + login_timeout = lib.mkOption { + type = lib.types.ints.unsigned; default = 60; - description = "How long the service manager waits on initial processes (in seconds) before giving up."; + description = '' + The timeout for the login. + + See {manpage}`turnstiled.conf(5)` for additional details. + ''; }; - root_session = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - description = "Whether or not `turnstile` acts for the root user."; + + root_session = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + When using a backend that is not `none`, this controls + whether to run the user session manager for the `root` + user. The login session will still be tracked regardless + of the setting, + ''; }; }; - dinit = with lib; { - enable = mkOption { - type = types.bool; + dinit = { + enable = lib.mkOption { + type = lib.types.bool; default = true; - description = "Whether or not to use the dinit backend for `turnstile`."; + description = '' + Whether or not to use the dinit backend for `turnstile`. + ''; }; - settings = with types; { - # TODO: make this accept a str or a list of strings - service_dir = mkOption { - type = str; - default = "$HOME/.config/dinit.d"; - description = "Users service dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; - }; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.dinit; + defaultText = lib.literalExpression "pkgs.dinit"; + description = '' + # TODO: + ''; + }; - boot_dir = mkOption { - type = types.str; - default = "${cfg.dinit.settings.service_dir}/boot.d"; - description = "Users service boot dir for `turnstile`'s `dinit` backend. This should include a way to differentiate per user unless all users have identical services."; + settings = { + boot_dir = lib.mkOption { + type = with lib.types; either path str; + default = "\${HOME}/.config/dinit.d/boot.d"; + description = '' + # The directory containing service links that must be + # started in order for the login to proceed. Can be + # empty, in which case nothing is waited for. + ''; }; - system_boot_dir = mkOption { - type = types.path; - default = "/usr/lib/dinit.d/user/boot.d"; - description = "Systems service boot dir for `turnstile`'s `dinit` backend."; + system_boot_dir = lib.mkOption { + type = with lib.types; either path str; + default = "/etc/dinit.d/user/boot.d"; + description = '' + # This is just like boot_dir, but not controlled by the + # user. Instead, the system installs links there, and + # they are started for all users universally. + ''; }; - enableGraphicalMonitor = mkOption { - type = types.bool; - default = false; - description = "Whether or not to monitor environment changes to DISPLAY and WAYLAND_DISPLAY variables. Currently requires manually adding `dinitctl setenv VAR=$VAR`to any startup scripts for your graphical environment to function."; + services_dir = lib.mkOption { + type = with lib.types; listOf (either path str); + default = [ "\${HOME}/.config/dinit.d" ]; + description = '' + # A directory user service files are read from. Every + # additional directory needs to have its number incremented. + # The numbering matters (defines the order) and there must be + # no gaps (it starts with 1, ends at the last undefined). + ''; }; }; }; }; + # extend finit.ttys to add turnstile readiness conditions + options.finit = { + ttys = lib.mkOption { + type = + with lib.types; + attrsOf (submodule { + config = lib.mkIf cfg.enable { + conditions = "usr/turnstiled-start"; + }; + }); + }; + }; + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ] - ++ lib.lists.optional cfg.dinit.enable (lib.lowPrio pkgs.dinit); - - finit.tmpfiles.rules = [ - "d ${cfg.dinit.settings.system_boot_dir} 0777" - ]; + ++ lib.optionals cfg.dinit.enable [ (lib.lowPrio cfg.dinit.package) ]; environment.etc = { "turnstile/turnstiled.conf".source = - (pkgs.formats.keyValue { }).generate "turnstiled.conf" - cfg.settings; - - "turnstile/backend/dinit.conf".text = '' - boot_dir="${cfg.dinit.settings.boot_dir}" - system_boot_dir="${cfg.dinit.settings.system_boot_dir}" - services_dir1="${cfg.dinit.settings.service_dir}" - services_dir2="/etc/dinit.d/user" - services_dir3="/usr/local/lib/dinit.d/user" - services_dir4="/usr/lib/dinit.d/user" - ''; + let + format = pkgs.formats.keyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { + mkValueString = + v: + if v == true then + "yes" + else if v == false then + "no" + else + lib.generators.mkValueStringDefault { } v; + } " = "; + }; + in + format.generate "turnstiled.conf" cfg.settings; + } + // lib.optionalAttrs cfg.dinit.enable { + "turnstile/backend/dinit.conf".source = + let + format = pkgs.formats.keyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { + mkValueString = v: "\"" + lib.generators.mkValueStringDefault { } v + "\""; + } "="; + }; + in + format.generate "dinit.conf" ( + { + inherit (cfg.dinit.settings) boot_dir system_boot_dir; + } + // (lib.listToAttrs ( + lib.imap1 (i: v: lib.nameValuePair "services_dir${toString i}" v) cfg.dinit.settings.services_dir + )) + ); }; - security.pam.services = lib.mkMerge [ - { - login.text = lib.mkAfter "session optional ${cfg.package}/pam/pam_turnstile.so"; - turnstiled.text = '' - auth sufficient pam_rootok.so - session optional pam_keyinit.so force revoke - session optional pam_umask.so usergroups umask=022 - -session optional pam_elogind.so - session required pam_env.so conffile=/etc/security/pam_env.conf readenv=1 # env (order 10100) - session required ${cfg.package}/pam/pam_turnstile.so turnstiled - session required pam_limits.so - ''; - } - ]; + security.pam.services = { + login.text = lib.mkAfter "session optional ${cfg.package}/lib/security/pam_turnstile.so"; + + turnstiled.text = '' + # Authentication management. + auth sufficient pam_rootok.so # rootok (order 10200) + + # Session management. + session optional pam_keyinit.so force revoke + session optional pam_umask.so usergroups umask=022 + ${lib.optionalString config.services.elogind.enable "session optional ${pkgs.elogind}/lib/security/pam_elogind.so"} + session required pam_env.so conffile=/etc/security/pam_env.conf readenv=0 # env (order 10100) + session required ${cfg.package}/lib/security/pam_turnstile.so turnstiled + session required pam_limits.so + ''; + }; finit.services.turnstiled = { description = "turnstiled, a user-service manager manager"; - command = "${cfg.package}/bin/turnstiled"; + command = "${lib.getExe cfg.package} ${config.environment.etc."turnstile/turnstiled.conf".source}"; conditions = "service/syslogd/ready"; + pre = pkgs.writeShellScript "turnstiled-start" '' + ${lib.getExe' config.finit.package "initctl"} cond set usr/turnstiled-start + ''; log = true; - pid = "/run/turnstiled.pid"; - path = - with pkgs; - [ - cfg.package - config.programs.coreutils.package - ] - ++ lib.lists.optional cfg.dinit.enable dinit; + path = [ + cfg.package + config.programs.coreutils.package + ] + ++ lib.optionals cfg.dinit.enable [ cfg.dinit.package ]; }; }; } diff --git a/modules/services/turnstile/package.nix b/modules/services/turnstile/package.nix index 6fe6246..9829f0f 100644 --- a/modules/services/turnstile/package.nix +++ b/modules/services/turnstile/package.nix @@ -7,8 +7,9 @@ meson, ninja, pam, + dinitSupport ? true, dinit, - graphicalMonitor ? true, + runitSupport ? true, }: stdenv.mkDerivation (finalAttrs: { @@ -22,40 +23,33 @@ stdenv.mkDerivation (finalAttrs: { sha256 = "sha256-94J+w0RHxzw7wS70LcpEzMvgevAqAwl0EtiANUmdRYU="; }; - buildInputs = [ + nativeBuildInputs = [ pkg-config scdoc meson ninja - pam - dinit ]; - # nativeBuildInputs = [ - # dinit - # ]; - - postPatch = lib.strings.concatStrings [ - (lib.strings.optionalString graphicalMonitor '' - substituteInPlace backend/dinit \ - --replace-fail '/usr/bin/dinit-monitor' '${lib.getExe' dinit "dinit-monitor"}' - '') - - '' - substituteInPlace meson.build \ - --replace-fail "get_option('prefix'), get_option('sysconfdir'), 'turnstile'" "'/etc', 'turnstile'" - '' + buildInputs = [ + pam ]; + postPatch = '' + substituteInPlace meson.build \ + --replace-fail "get_option('prefix'), get_option('sysconfdir'), 'turnstile'" "'/etc', 'turnstile'" + '' + + lib.optionalString dinitSupport '' + substituteInPlace backend/dinit \ + --replace-fail '/usr/bin/dinit-monitor' '${lib.getExe' dinit "dinit-monitor"}' + ''; + mesonFlags = [ - "-Ddefault_backend=dinit" - "-Ddinit=enabled" - "-Dstatedir=/var/lib/turnstiled" - "-Dpam_moddir=./pam" + "-Dlocalstatedir=/var" + "-Dpam_moddir=${placeholder "out"}/lib/security" + (lib.mesonEnable "dinit" dinitSupport) + (lib.mesonEnable "runit" runitSupport) ]; - patches = lib.lists.optional (!graphicalMonitor) (./remove_graphical_monitor.diff); - meta = with lib; { homepage = "https://github.com/chimera-linux/turnstile"; description = "This program waits for user logins and then runs the associated user-service manager"; diff --git a/modules/services/turnstile/patch.diff b/modules/services/turnstile/patch.diff deleted file mode 100644 index 02f1f82..0000000 --- a/modules/services/turnstile/patch.diff +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/backend/dinit b/backend/dinit -index 7bacaac..065d14a 100644 ---- a/backend/dinit -+++ b/backend/dinit -@@ -136,7 +136,7 @@ cat << EOF > "${DINIT_DIR}/graphical.monitor" - type = process - depends-on = login.target - options = pass-cs-fd --command = /usr/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY -+command = /run/current-system/sw/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY - EOF - - # this is needed for login to proceed -diff --git a/meson.build b/meson.build -index aa07c9c..fdf89fa 100644 ---- a/meson.build -+++ b/meson.build -@@ -28,7 +28,7 @@ have_runit = get_option('runit').enabled() - conf_data = configuration_data() - conf_data.set_quoted('RUN_PATH', get_option('rundir')) - conf_data.set_quoted('CONF_PATH', join_paths( -- get_option('prefix'), get_option('sysconfdir'), 'turnstile' -+ '/etc/', 'turnstile' - )) - conf_data.set10('MANAGE_RUNDIR', get_option('manage_rundir')) - diff --git a/modules/services/turnstile/remove_graphical_monitor.diff b/modules/services/turnstile/remove_graphical_monitor.diff deleted file mode 100644 index cf1d90a..0000000 --- a/modules/services/turnstile/remove_graphical_monitor.diff +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/backend/dinit b/backend/dinit -index 7bacaac..27ee9b7 100644 ---- a/backend/dinit -+++ b/backend/dinit -@@ -121,8 +121,6 @@ type = internal - depends-on = system - waits-for.d = ${boot_dir} - depends-on = login.target --depends-ms = graphical.monitor --depends-ms = graphical.target - EOF - - # this must also succeed -@@ -131,24 +129,9 @@ type = internal - waits-for.d = ${system_boot_dir} - EOF - --# monitor service to watch for environment changes --cat << EOF > "${DINIT_DIR}/graphical.monitor" --type = process --depends-on = login.target --options = pass-cs-fd --command = /usr/bin/dinit-monitor -E -c "$0 graphical-notify" WAYLAND_DISPLAY DISPLAY --EOF -- - # this is needed for login to proceed - cat << EOF > "${DINIT_DIR}/login.target" - type = internal - EOF - --# this is not necessary to have started for login to proceed --cat << EOF > "${DINIT_DIR}/graphical.target" --type = triggered --depends-on = graphical.monitor --depends-on = login.target --EOF -- - exec dinit --user --ready-fd 3 --services-dir "$DINIT_DIR" "$@" 3>"$DINIT_READY_PIPE" From 762acd5630824ce47cbbd2e9598b2cd117832f16 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Mon, 3 Aug 2026 00:50:03 -0400 Subject: [PATCH 8/9] services/turnstiled: added runit support --- modules/services/turnstile/default.nix | 96 ++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/modules/services/turnstile/default.nix b/modules/services/turnstile/default.nix index fcd13db..6379645 100644 --- a/modules/services/turnstile/default.nix +++ b/modules/services/turnstile/default.nix @@ -19,7 +19,10 @@ in package = lib.mkOption { type = lib.types.package; - default = pkgs.callPackage ./package.nix { }; + default = pkgs.turnstile { + dinitSupprt = cfg.dinit.enable; + runitSupport = cfg.runit.enable; + }; description = '' The package to use for `turnstile`. ''; @@ -125,7 +128,7 @@ in dinit = { enable = lib.mkOption { type = lib.types.bool; - default = true; + default = false; description = '' Whether or not to use the dinit backend for `turnstile`. ''; @@ -145,9 +148,9 @@ in type = with lib.types; either path str; default = "\${HOME}/.config/dinit.d/boot.d"; description = '' - # The directory containing service links that must be - # started in order for the login to proceed. Can be - # empty, in which case nothing is waited for. + The directory containing service links that must be + started in order for the login to proceed. Can be + empty, in which case nothing is waited for. ''; }; @@ -155,9 +158,9 @@ in type = with lib.types; either path str; default = "/etc/dinit.d/user/boot.d"; description = '' - # This is just like boot_dir, but not controlled by the - # user. Instead, the system installs links there, and - # they are started for all users universally. + This is just like boot_dir, but not controlled by the + user. Instead, the system installs links there, and + they are started for all users universally. ''; }; @@ -165,10 +168,55 @@ in type = with lib.types; listOf (either path str); default = [ "\${HOME}/.config/dinit.d" ]; description = '' - # A directory user service files are read from. Every - # additional directory needs to have its number incremented. - # The numbering matters (defines the order) and there must be - # no gaps (it starts with 1, ends at the last undefined). + A directory user service files are read from. Every + additional directory needs to have its number incremented. + The numbering matters (defines the order) and there must be + no gaps (it starts with 1, ends at the last undefined). + ''; + }; + }; + }; + + runit = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether or not to use the runit backend for `turnstile`. + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.runit; + defaultText = lib.literalExpression "pkgs.runit"; + description = '' + # TODO: + ''; + }; + + settings = { + ready_sv = lib.mkOption { + type = with lib.types; str; + default = "turnstile-ready"; + description = '' + The name of the service that turnstile will check for login readiness + ''; + }; + + services_dir = lib.mkOption { + type = with lib.types; either path str; + default = "\${HOME}/.config/service"; + description = '' + The directory user service files are read from. Can include a way to differentiate between users, like `$HOME`. + ''; + }; + + service_env_dir = lib.mkOption { + type = with lib.types; either path str; + default = "\${HOME}/.config/service-env"; + description = '' + The environment variable directory user service files can read from. Can include a way to differentiate between users, like `$HOME`. ''; }; }; @@ -189,10 +237,16 @@ in }; config = lib.mkIf cfg.enable { + services.turnstile.package = pkgs.turnstile { + dinitSupprt = cfg.dinit.enable; + runitSupport = cfg.runit.enable; + }; + environment.systemPackages = [ cfg.package ] - ++ lib.optionals cfg.dinit.enable [ (lib.lowPrio cfg.dinit.package) ]; + ++ lib.optionals cfg.dinit.enable [ (lib.lowPrio cfg.dinit.package) ] + ++ lib.optionals cfg.runit.enable [ (lib.lowPrio cfg.runit.package) ]; environment.etc = { "turnstile/turnstiled.conf".source = @@ -229,6 +283,19 @@ in lib.imap1 (i: v: lib.nameValuePair "services_dir${toString i}" v) cfg.dinit.settings.services_dir )) ); + } + // lib.optionalAttrs cfg.runit.enable { + "turnstile/backend/runit.conf".source = + let + format = pkgs.formats.keyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { + mkValueString = v: "\"" + lib.generators.mkValueStringDefault { } v + "\""; + } "="; + }; + in + format.generate "runit.conf" { + inherit (cfg.runit.settings) ready_sv services_dir service_env_dir; + }; }; security.pam.services = { @@ -260,7 +327,8 @@ in cfg.package config.programs.coreutils.package ] - ++ lib.optionals cfg.dinit.enable [ cfg.dinit.package ]; + ++ lib.optionals cfg.dinit.enable [ cfg.dinit.package ] + ++ lib.optionals cfg.runit.enable [ cfg.runit.package ]; }; }; } From cf9fe58a20a0a214264d7a7c02f5bec1d5288802 Mon Sep 17 00:00:00 2001 From: xZecora <111700bh@gmail.com> Date: Mon, 3 Aug 2026 00:50:44 -0400 Subject: [PATCH 9/9] services/turnstiled: removed package.nix in favor of upstream package --- modules/services/turnstile/package.nix | 62 -------------------------- 1 file changed, 62 deletions(-) delete mode 100644 modules/services/turnstile/package.nix diff --git a/modules/services/turnstile/package.nix b/modules/services/turnstile/package.nix deleted file mode 100644 index 9829f0f..0000000 --- a/modules/services/turnstile/package.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - lib, - stdenv, - fetchFromGitHub, - pkg-config, - scdoc, - meson, - ninja, - pam, - dinitSupport ? true, - dinit, - runitSupport ? true, -}: - -stdenv.mkDerivation (finalAttrs: { - pname = "turnstile"; - version = "v0.1.11"; - - src = fetchFromGitHub { - owner = "chimera-linux"; - repo = "turnstile"; - rev = "${finalAttrs.version}"; - sha256 = "sha256-94J+w0RHxzw7wS70LcpEzMvgevAqAwl0EtiANUmdRYU="; - }; - - nativeBuildInputs = [ - pkg-config - scdoc - meson - ninja - ]; - - buildInputs = [ - pam - ]; - - postPatch = '' - substituteInPlace meson.build \ - --replace-fail "get_option('prefix'), get_option('sysconfdir'), 'turnstile'" "'/etc', 'turnstile'" - '' - + lib.optionalString dinitSupport '' - substituteInPlace backend/dinit \ - --replace-fail '/usr/bin/dinit-monitor' '${lib.getExe' dinit "dinit-monitor"}' - ''; - - mesonFlags = [ - "-Dlocalstatedir=/var" - "-Dpam_moddir=${placeholder "out"}/lib/security" - (lib.mesonEnable "dinit" dinitSupport) - (lib.mesonEnable "runit" runitSupport) - ]; - - meta = with lib; { - homepage = "https://github.com/chimera-linux/turnstile"; - description = "This program waits for user logins and then runs the associated user-service manager"; - license = licenses.bsd2; - maintainers = with maintainers; [ vitrial ]; - platforms = platforms.linux; - mainProgram = "turnstiled"; - }; - -})