{ config, lib, pkgs, ... }: with lib; let uid = config.ids.uids.gpsd; gid = config.ids.gids.gpsd; cfg = config.services.gpsd; in { # An attempt at creating a secure hotplug-capable gpsd configuration # TODO: for not running as root, chronys SHM segments have to be configured to be writable from chrony # (e.g. `refclock SHM 1:perm=0664 refid GPS2`, started with an appropriate group) # The same applies to crony .sock files (they are only writeable by root by default) # New service unit to use --sockfile feature systemd.services.gpsd = { serviceConfig = { ExecStart = "${pkgs.gpsd}/bin/gpsd --foreground --sockfile /run/gpsd/gpsd.sock --nowait --debug 0"; Type = "exec"; #User = "gpsd"; #Group = "gpsd"; ProtectSystem = "strict"; ProtectHome = true; ProtectControlGroups = true; CapabilityBoundingSet = "CAP_SYS_TIME CAP_IPC_LOCK CAP_SETUID CAP_SETGID"; RuntimeDirectory = "gpsd"; }; }; # Per-device service unit to load devices systemd.services."gpsd-add-device@" = { requires = [ "gpsd.service" ]; after = [ "gpsd.service" ]; serviceConfig = { ExecStartPre = "${pkgs.setserial}/bin/setserial /dev/%I low_latency"; ExecStart = "${pkgs.gpsd}/bin/gpsdctl add /dev/%I"; ExecStop = ''${pkgs.zsh}/bin/zsh -c "[[ -e /dev/%I ]] && ${pkgs.gpsd}/bin/gpsdctl remove /dev/%I"''; RemainAfterExit = true; Environment = "GPSD_SOCKET=/run/gpsd/gpsd.sock"; Type = "oneshot"; #User = "gpsd"; #Group = "gpsd"; ProtectSystem = "strict"; ProtectHome = true; ProtectKernelTunables = true; ProtectControlGroups = true; CapabilityBoundingSet = ""; }; }; services.udev.packages = lib.singleton (pkgs.writeTextFile { name = "gpsmouse-udev-rules"; destination = "/etc/udev/rules.d/90-gpsmouse.rules"; text = '' SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", GROUP="dialout", TAG+="systemd", ENV{SYSTEMD_WANTS}="gpsd-add-device@$name.service" ''; }); # User config replicated from nixpkgs gpsd.nix users.users.gpsd = { inherit uid; group = "gpsd"; description = "gpsd daemon user"; home = "/var/empty"; }; users.groups.gpsd = { inherit gid; }; }