···100100 in if isDerivation res then res else toDerivation res;
101101 };
102102103103+ shellPackage = package // {
104104+ check = x: (package.check x) && (hasAttr "shellPath" x);
105105+ };
106106+103107 path = mkOptionType {
104108 name = "path";
105109 # Hacky: there is no ‘isPath’ primop.
+6
nixos/lib/utils.nix
···88 replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"]
99 (if hasPrefix "/" s then substring 1 (stringLength s) s else s);
10101111+ # Returns a system path for a given shell package
1212+ toShellPath = shell:
1313+ if types.shellPackage.check shell then
1414+ "/run/current-system/sw${shell.shellPath}"
1515+ else
1616+ shell;
1117}
+4-4
nixos/modules/config/shells-environment.nix
···11# This module defines a global environment configuration and
22# a common configuration for all shells.
3344-{ config, lib, pkgs, ... }:
44+{ config, lib, utils, pkgs, ... }:
5566with lib;
77···135135136136 environment.shells = mkOption {
137137 default = [];
138138- example = [ "/run/current-system/sw/bin/zsh" ];
138138+ example = literalExample "[ pkgs.bashInteractive pkgs.zsh ]";
139139 description = ''
140140 A list of permissible login shells for user accounts.
141141 No need to mention <literal>/bin/sh</literal>
142142 here, it is placed into this list implicitly.
143143 '';
144144- type = types.listOf types.path;
144144+ type = types.listOf (types.either types.shellPackage types.path);
145145 };
146146147147 };
···158158159159 environment.etc."shells".text =
160160 ''
161161- ${concatStringsSep "\n" cfg.shells}
161161+ ${concatStringsSep "\n" (map utils.toShellPath cfg.shells)}
162162 /bin/sh
163163 '';
164164
+18-7
nixos/modules/config/users-groups.nix
···11-{ config, lib, pkgs, ... }:
11+{ config, lib, utils, pkgs, ... }:
2233with lib;
4455let
66-76 ids = config.ids;
87 cfg = config.users;
98···103102 };
104103105104 home = mkOption {
106106- type = types.str;
105105+ type = types.path;
107106 default = "/var/empty";
108107 description = "The user's home directory.";
109108 };
···118117 };
119118120119 shell = mkOption {
121121- type = types.str;
122122- default = "/run/current-system/sw/bin/nologin";
120120+ type = types.either types.shellPackage types.path;
121121+ default = pkgs.nologin;
122122+ defaultText = "pkgs.nologin";
123123+ example = literalExample "pkgs.bashInteractive";
123124 description = "The path to the user's shell.";
124125 };
125126···359360360361 spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
361362 inherit (cfg) mutableUsers;
362362- users = mapAttrsToList (n: u:
363363+ users = mapAttrsToList (_: u:
363364 { inherit (u)
364364- name uid group description home shell createHome isSystemUser
365365+ name uid group description home createHome isSystemUser
365366 password passwordFile hashedPassword
366367 initialPassword initialHashedPassword;
368368+ shell = utils.toShellPath u.shell;
367369 }) cfg.users;
368370 groups = mapAttrsToList (n: g:
369371 { inherit (g) name gid;
···372374 ));
373375 }) cfg.groups;
374376 });
377377+378378+ systemShells =
379379+ let
380380+ shells = mapAttrsToList (_: u: u.shell) cfg.users;
381381+ in
382382+ filter types.shellPackage.check shells;
375383376384in {
377385···476484 group = "nogroup";
477485 };
478486 };
487487+488488+ # Install all the user shells
489489+ environment.systemPackages = systemShells;
479490480491 users.groups = {
481492 root.gid = ids.gids.root;
···11# Configuration for the pwdutils suite of tools: passwd, useradd, etc.
2233-{ config, lib, pkgs, ... }:
33+{ config, lib, utils, pkgs, ... }:
4455with lib;
66···4343 users.defaultUserShell = lib.mkOption {
4444 description = ''
4545 This option defines the default shell assigned to user
4646- accounts. This must not be a store path, since the path is
4646+ accounts. This can be either a full system path or a shell package.
4747+4848+ This must not be a store path, since the path is
4749 used outside the store (in particular in /etc/passwd).
4848- Rather, it should be the path of a symlink that points to the
4949- actual shell in the Nix store.
5050 '';
5151- example = "/run/current-system/sw/bin/zsh";
5252- type = types.path;
5151+ example = literalExample "pkgs.zsh";
5252+ type = types.either types.path types.shellPackage;
5353 };
54545555 };
···6060 config = {
61616262 environment.systemPackages =
6363- lib.optional config.users.mutableUsers pkgs.shadow;
6363+ lib.optional config.users.mutableUsers pkgs.shadow ++
6464+ lib.optional (types.shellPackage.check config.users.defaultUserShell)
6565+ config.users.defaultUserShell;
64666567 environment.etc =
6668 [ { # /etc/login.defs: global configuration for pwdutils. You
···7476 ''
7577 GROUP=100
7678 HOME=/home
7777- SHELL=${config.users.defaultUserShell}
7979+ SHELL=${utils.toShellPath config.users.defaultUserShell}
7880 '';
7981 target = "default/useradd";
8082 }
+3
pkgs/os-specific/linux/shadow/default.nix
···5353 meta = {
5454 homepage = http://pkg-shadow.alioth.debian.org/;
5555 description = "Suite containing authentication-related tools such as passwd and su";
5656+ passthru = {
5757+ shellPath = "/bin/nologin";
5858+ };
5659 };
5760}
+4
pkgs/shells/dash/default.nix
···1313 description = "A POSIX-compliant implementation of /bin/sh that aims to be as small as possible";
1414 hydraPlatforms = stdenv.lib.platforms.linux;
1515 };
1616+1717+ passthru = {
1818+ shellPath = "/bin/dash";
1919+ };
1620}