{ config, pkgs, lib, ... }: let cfg = config.services.netatalk; settingsFormat = pkgs.formats.ini { }; afpConfFile = settingsFormat.generate "afp.conf" cfg.settings; in { options = { services.netatalk = { enable = lib.mkEnableOption "the Netatalk AFP fileserver"; port = lib.mkOption { type = lib.types.port; default = 548; description = "TCP port to be used for AFP."; }; settings = lib.mkOption { inherit (settingsFormat) type; default = { }; example = { Global = { "uam list" = "uams_guest.so"; }; Homes = { path = "afp-data"; "basedir regex" = "/home"; }; example-volume = { path = "/srv/volume"; "read only" = true; }; }; description = '' Configuration for Netatalk. See {manpage}`afp.conf(5)`. ''; }; extmap = lib.mkOption { type = lib.types.lines; default = ""; description = '' File name extension mappings. See {manpage}`extmap.conf(5)`. for more information. ''; }; }; }; imports = (map (option: lib.mkRemovedOptionModule [ "services" "netatalk" option ] "This option was removed in favor of `services.netatalk.settings`.") [ "extraConfig" "homes" "volumes" ]); config = lib.mkIf cfg.enable { services.netatalk.settings.Global = { "afp port" = toString cfg.port; "extmap file" = "${pkgs.writeText "extmap.conf" cfg.extmap}"; }; systemd.services.netatalk = { description = "Netatalk AFP fileserver for Macintosh clients"; unitConfig.Documentation = "man:afp.conf(5) man:netatalk(8) man:afpd(8) man:cnid_metad(8) man:cnid_dbd(8)"; after = [ "network.target" "avahi-daemon.service" ]; wantedBy = [ "multi-user.target" ]; path = [ pkgs.netatalk ]; serviceConfig = { Type = "forking"; GuessMainPID = "no"; PIDFile = "/run/lock/netatalk"; ExecStart = "${pkgs.netatalk}/sbin/netatalk -F ${afpConfFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID"; Restart = "always"; RestartSec = 1; StateDirectory = [ "netatalk/CNID" ]; }; }; security.pam.services.netatalk.unixAuth = true; }; }