Commit be703cf4 authored by hustlerone's avatar hustlerone Committed by ccicnce113424
Browse files

nixos/kmscon: run agetty under kmscon



Cherry-picked from NixOS/nixpkgs#391574

Co-authored-by: default avatarccicnce113424 <ccicnce113424@gmail.com>
parent b81e9cfd
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -132,6 +132,12 @@ in
  ###### implementation

  config = mkIf config.console.enable {
    assertions = [
      {
        assertion = cfg.loginOptions != null -> cfg.autologinUser == null;
        message = "services.getty.autoLoginUser has no effect when services.getty.loginOptions is set.";
      }
    ];
    # Note: this is set here rather than up there so that changing
    # nixos.label would not rebuild manual pages
    services.getty.greetingLine = mkDefault ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
+106 −36
Original line number Diff line number Diff line
@@ -17,28 +17,80 @@ let

  cfg = config.services.kmscon;

  autologinArg = lib.optionalString (cfg.autologinUser != null) "-f ${cfg.autologinUser}";
  gettyCfg = config.services.getty;

  configDir = pkgs.writeTextFile {
    name = "kmscon-config";
    destination = "/kmscon.conf";
    text = cfg.extraConfig;
  };

  baseLoginOptions = "-p -- \\u";

  agettyCmd =
    enableAutologin:
    "${lib.getExe' pkgs.util-linux "agetty"} ${
      lib.escapeShellArgs (
        [
          "--login-program"
          (toString gettyCfg.loginProgram)
          "--login-options"
          # these options are passed as a single parameter
          "${lib.optionalString enableAutologin "-f "}${baseLoginOptions}"
        ]
        ++ lib.optionals enableAutologin [
          "--autologin"
          gettyCfg.autologinUser
        ]
        ++ gettyCfg.extraArgs
        ++ [
          "--8bits"
          "--noclear"
          "--"
          "-"
        ]
      )
    } $TERM";

  loginScript = pkgs.writers.writeDash "kmscon-login" ''
    kms_tty=
    active_tty_file=/sys/class/tty/tty0/active
    if [ -f "$active_tty_file" ]; then
      read -r kms_tty < "$active_tty_file"
    fi

    ${lib.optionalString (gettyCfg.autologinUser != null && gettyCfg.autologinOnce) ''
      autologged="/run/kmscon.autologged"
      if [ "$kms_tty" = tty1 ] && [ ! -f "$autologged" ]; then
        touch "$autologged"
        exec ${agettyCmd true}
      fi
    ''}

    exec ${agettyCmd (gettyCfg.autologinUser != null && !gettyCfg.autologinOnce)}
  '';
in
{
  imports = [
    (lib.mkRemovedOptionModule [ "services" "kmscon" "autologinUser" ] ''
      Autologin is now handled by the agetty module.

      Check `services.getty.autologinUser` instead.
    '')
  ];

  options = {
    services.kmscon = {
      enable = mkEnableOption ''
        kmscon as the virtual console instead of gettys.
        kmscon is a kms/dri-based userspace virtual terminal implementation.
        It supports a richer feature set than the standard linux console VT,
        including full unicode support, and when the video card supports drm
        should be much faster
        Use kmscon instead of autovt.

        Kmscon is a simple terminal emulator based on linux kernel mode setting (KMS).
        It is an attempt to replace the in-kernel VT implementation with a userspace console.
      '';

      package = mkPackageOption pkgs "kmscon" { };

      hwRender = mkEnableOption "3D hardware acceleration to render the console";
      hwRender = mkEnableOption "hardware acceleration + DRM backend";

      fonts = mkOption {
        description = "Fonts used by kmscon, in order of priority.";
@@ -63,8 +115,13 @@ in
          nullOr (nonEmptyListOf fontType);
      };

      useXkbConfig = mkEnableOption "" // {
        description = "Whether to configure keymap from xserver keyboard settings.";
      useXkbConfig = mkEnableOption "configure keymap from xserver keyboard settings.";

      term = mkOption {
        description = "Value for the TERM environment variable.";
        type = types.nullOr types.str;
        default = null;
        example = "xterm-256color";
      };

      extraConfig = mkOption {
@@ -80,33 +137,39 @@ in
        default = "";
        example = "--term xterm-256color";
      };

      autologinUser = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = ''
          Username of the account that will be automatically logged in at the console.
          If unspecified, a login prompt is shown as usual.
        '';
      };
    };
  };

  config = mkIf cfg.enable {
    assertions = [
      {
        assertion = gettyCfg.loginOptions == null;
        message = "services.getty.loginOptions is not supported when services.kmscon is enabled.";
      }
    ];

    environment.systemPackages = [ cfg.package ];
    systemd.packages = [ cfg.package ];

    systemd.services."kmsconvt@" = {
      after = [
        "systemd-logind.service"
        "systemd-vconsole-setup.service"
      ];
      requires = [ "systemd-logind.service" ];

      serviceConfig.ExecStart = [
        ""
        ''
          ${cfg.package}/bin/kmscon "--vt=%I" ${cfg.extraOptions} --seats=seat0 --no-switchvt --configdir ${configDir} --login -- ${pkgs.shadow}/bin/login -p ${autologinArg}
        ''
        "" # override upstream default with an empty ExecStart
        (builtins.concatStringsSep " " (
          [
            "${cfg.package}/bin/kmscon"
            "--configdir"
            configDir
            "--vt=%I"
            "--no-switchvt"
            "--login"
          ]
          ++ lib.optional (cfg.extraOptions != "") cfg.extraOptions
          ++ [
            "--"
            loginScript
          ]

        ))
      ];

      restartIfChanged = false;
@@ -115,9 +178,6 @@ in

    systemd.suppressedSystemUnits = [ "autovt@.service" ];

    systemd.services.systemd-vconsole-setup.enable = false;
    systemd.services.reload-systemd-vconsole-setup.enable = false;

    services.kmscon.extraConfig =
      let
        xkb = optionals cfg.useXkbConfig (
@@ -134,15 +194,20 @@ in
            ) config.services.xserver.xkb
          )
        );
        render = optionals cfg.hwRender [
        render =
          if cfg.hwRender then
            [
              "drm"
              "hwaccel"
        ];
            ]
          else
            [ "no-drm" ];
        fonts =
          optional (cfg.fonts != null)
            "font-name=${lib.concatMapStringsSep ", " (f: f.name) cfg.fonts}";
        term = optional (cfg.term != null) "term=${cfg.term}";
      in
      lib.concatLines (xkb ++ render ++ fonts);
      lib.concatLines (xkb ++ render ++ fonts ++ term);

    hardware.graphics.enable = mkIf cfg.hwRender true;

@@ -151,4 +216,9 @@ in
      packages = map (f: f.package) cfg.fonts;
    };
  };

  meta.maintainers = with lib.maintainers; [
    hustlerone
    ccicnce113424
  ];
}
+4 −8
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@
  nodes.machine =
    {
      pkgs,
      lib,
      ...
    }:
    {
@@ -13,6 +12,8 @@
        ./common/user-account.nix
      ];

      services.getty.autologinUser = "alice";

      services.kmscon = {
        enable = true;
        hwRender = true;
@@ -22,6 +23,7 @@
            package = pkgs.nerd-fonts.jetbrains-mono;
          }
        ];
        term = "xterm-256color";
        package = pkgs.kmscon;
      };
    };
@@ -29,15 +31,9 @@
  enableOCR = true;

  testScript = ''
    machine.wait_for_unit("multi-user.target")
    machine.start()

    with subtest("ensure we can open a tty"):
      machine.wait_for_text("machine login:")

      machine.send_chars("alice\n")
      machine.wait_for_text("Password:")

      machine.send_chars("foobar\n")
      machine.wait_for_text("alice@machine")

      machine.send_chars("echo $TERM | tee /tmp/term.txt\n")