Unstable channel breaks systemd automatic login service

For a while I’ve been using the config at this guide to automatically log in a user on a NixOS setup running on a Raspberry Pi. Switching from stable 21.05 to unstable makes it stop working. journalctl -u shows the exact same things it normally does (“Started Autologin at the TTY1.”, “pam_unix(login:session): session opened for user nixos(uid=1000) by LOGIN(uid=0)”), but instead of automatically logging in I simply get a normal login prompt. systemctl status gives the following on unstable

● autovt@tty1.service - Autologin at the TTY1
     Loaded: loaded (/etc/systemd/system/autovt@tty1.service; enabled; vendor preset: enabled)
    Drop-In: /nix/store/dqggadk7jwkaxhbz1hnywliv3ggi9c5f-system-units/autovt@.service.d
             └─overrides.conf
     Active: active (running) since Thu 2021-09-30 22:30:39 UTC; 27s ago
   Main PID: 829 (login)
         IP: 0B in, 0B out
         IO: 1.5M read, 0B written
      Tasks: 0 (limit: 9537)
     Memory: 2.0M
        CPU: 17ms
     CGroup: /system.slice/system-autovt.slice/autovt@tty1.service
             ‣ 829 /nix/store/3srhn7p8d5h7w2jz19nz75qvqbwc76ln-shadow-4.8.1/bin/login -- "" "" "" "" "" ""

when the same configuration on 21.05 gives the following

● autovt@tty1.service - Autologin at the TTY1
     Loaded: loaded (/nix/store/d1iky3cy9q58rn8y8gpv3wx3xvidzkps-unit-autovt-tty1.service/autovt@tty1.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2021-09-30 22:26:57 UTC; 1min 13s ago
   Main PID: 838 (login)
         IP: 0B in, 0B out
         IO: 1.5M read, 4.0K written
      Tasks: 0 (limit: 9542)
     Memory: 2.0M
        CPU: 7ms
     CGroup: /system.slice/system-autovt.slice/autovt@tty1.service
             ‣ 838 /nix/store/61z6l8p3f14hgz29j607bg1d37sn5d86-shadow-4.8.1/bin/login -f

It seems to me like the issue might be caused by 21.05 generating autovt@tty1 as a service all its own, while unstable creates it as a “drop-in” override for the standard autovt service, or that the issue might be caused by 21.05 correctly generating the .service’s Exec line, while the unstable fails to compile the arguments the .nix gives it.

I’m able to reproduce this with a minimal configuration.nix in a virtual machine, so it’s not any RPi specific weirdness. The .nix files I used for that test are below. util-linux is version 2.36.2 on both 21.05 and unstable, and the same goes for shadow (v 4.8.1). Was there a change to systemd or how nix compiles the configuration that makes this method no longer work?

configuration.nix

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # This is the autologin service
  systemd.services."autovt@tty1".description = "Autologin at the TTY1";
  systemd.services."autovt@tty1".after = [ "systemd-logind.service" ];  # without it user session not started and xorg can't be run from this tty
  systemd.services."autovt@tty1".wantedBy = [ "multi-user.target" ];
  systemd.services."autovt@tty1".serviceConfig =
  { ExecStart = [
      ""  # override upstream default with an empty ExecStart
      "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login --autologin nixos --noclear %I $TERM"
    ];
    Restart = "always";
    Type = "idle";
  };

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  boot.loader.grub.device = "/dev/vda"; # or "nodev" for efi only

  # The global useDHCP flag is deprecated, therefore explicitly set to false here.
  # Per-interface useDHCP will be mandatory in the future, so this generated config
  # replicates the default behaviour.
  networking.useDHCP = false;
  networking.interfaces.enp1s0.useDHCP = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.nixos = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
  };

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It‘s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "21.05"; # Did you read the comment?
}

hardware-configuration.nix

# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/profiles/qemu-guest.nix")
    ];

  boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/c6444cd7-2265-43e8-be39-c9a3cc9c717d";
      fsType = "ext4";
    };

  swapDevices = [ ];

}

Why don’t you use services.getty.autologinUser?

Because that automatically logs in on all ttys, while this only automatically logs in on tty1. On the Pi that’s not a big deal since switching it to unstable was only a test and I actually could use getty.autologinUser there, but I discovered this issue when I tried to switch from SDDM to the same setup the Pi uses on my desktop, which does run unstable (and where getty.autologinUser would be unsuitable).

My reasoning is that it’s silly to launch X (SDDM), only for that to automatically close itself and launch a wayland session. This setup would have gone directly from terminal to wayland. Yes, that’s how bored I have been this past month.

But this systemd service does actually serve a purpose. A setup could be to boot the machine, automatically log in, automatically launch a plasma session, and automatically start the screen lock. The desktop will load while you enter the password, rather than only after. I suppose it is pretty niche, but in my university days at least I wasn’t alone in doing it that way. A DM, after all, only really serves any purpose on multiuser machines, which are pretty rare these days.

Ah, that makes sense. I don’t have any insights into why this changed, unfortunately, but I’d suggest opening an issue against nixpkgs instead of here - if you browse the history of the relevant modules and link maintainers and/or whoever recently changed how it works into an issue you’re more likely to get a useful response.

It probably also makes sense to write and upstream an option for your use case, rather than hacking this with downstream systemd units. Then you could add a test and ensure the behavior doesn’t change again in the future.

Personally, I also use them for lock screens that don’t leave my desktop unlocked if the application crashes due to a buffer overflow in the password prompt or such (sadly most non-DM lock screen implementations are vulnerable to such things), and for easier handling of hardware token login, but I agree it’s a bit silly to launch X to then launch wayland.

Technically the wayland protocol supports being used as a DM, hopefully someone eventually implements that for the various “window managers” we have today, obsoleting this kind of hackery.

I think that’s a side effect of universities messing with the screen lock system to keep students from hogging PCs, rather than a deliberate choice for any other reason, but it is indeed something we should support :slight_smile:

If I knew how to do any of that, I would have. I haven’t even been able to find where the thing that turns the systemd stuff in my .nix into an actual systemd unit file is located. :grinning_face_with_smiling_eyes: Oh well, I have nothing planned this weekend, it’s about time I learn github.

Oh, heh, if you visit your options on the search website (e.g. services.getty.autologinUser) there’s a “declared in” link that will show you the exact file where your option is declared. That, with a bit of sleuthing, can usually help you find what you need :slight_smile:

GitHub is fairly straightforward, the most useful buttons are the file history and “blame” buttons - the former tells you the history of the file, the latter tells you who changed what.

And if you don’t find what you need that way, cloning the repository and searching it with grep and find should usually get you there :slight_smile:

If you need help, feel free to ask, I’ve gotten pretty adept at this and am happy to research, just might take me a little while to find time.

I think I found something that might have caused the issue (big commit with a systemd version bump that touches a lot of services related to getty and autovt), and I wrote an issue report about it. Thank you for all your help.