summary refs log tree commit diff
diff options
context:
space:
mode:
authorMathijs Kwik <mathijs@bluescreen303.nl>2013-09-23 11:23:10 -0700
committerMathijs Kwik <mathijs@bluescreen303.nl>2013-09-23 11:23:10 -0700
commit3840e96e79205880ed32351986d4b47be75c5088 (patch)
treec49e21b04f288c31fbbcd342f5c7f2073121d52f
parentbfd86d4e744861011df558254c5354723c9eb51f (diff)
parentffa4b28dcec622c98c1491a09c9b254dc13b0741 (diff)
downloadnixlib-3840e96e79205880ed32351986d4b47be75c5088.tar
nixlib-3840e96e79205880ed32351986d4b47be75c5088.tar.gz
nixlib-3840e96e79205880ed32351986d4b47be75c5088.tar.bz2
nixlib-3840e96e79205880ed32351986d4b47be75c5088.tar.lz
nixlib-3840e96e79205880ed32351986d4b47be75c5088.tar.xz
nixlib-3840e96e79205880ed32351986d4b47be75c5088.tar.zst
nixlib-3840e96e79205880ed32351986d4b47be75c5088.zip
Merge pull request #256 from oxij/shells-environment
I tested the previous "version" and found my environment to be exactly the same.

Let's start discussing possible extensions/improvements somewhere else. For now it's a nice improvement.
-rw-r--r--modules/config/fonts/fontconfig.nix11
-rw-r--r--modules/config/i18n.nix5
-rw-r--r--modules/config/shells-environment.nix202
-rw-r--r--modules/config/shells.nix24
-rw-r--r--modules/config/timezone.nix7
-rw-r--r--modules/module-list.nix4
-rw-r--r--modules/profiles/installation-device.nix6
-rw-r--r--modules/programs/bash/bash.nix237
-rw-r--r--modules/programs/bash/bashrc.sh19
-rw-r--r--modules/programs/bash/command-not-found.nix2
-rw-r--r--modules/programs/bash/profile.sh119
-rw-r--r--modules/programs/environment.nix79
-rw-r--r--modules/programs/shadow.nix4
-rw-r--r--modules/programs/shell.nix70
-rw-r--r--modules/programs/zsh/zinputrc42
-rw-r--r--modules/programs/zsh/zsh.nix180
-rw-r--r--modules/rename.nix1
-rw-r--r--modules/security/ca.nix10
-rw-r--r--modules/services/misc/nix-daemon.nix11
-rw-r--r--modules/services/x11/desktop-managers/xfce.nix5
-rw-r--r--modules/services/x11/xserver.nix3
-rw-r--r--modules/system/boot/modprobe.nix5
22 files changed, 736 insertions, 310 deletions
diff --git a/modules/config/fonts/fontconfig.nix b/modules/config/fonts/fontconfig.nix
index d0478083ed3f..88643b41d838 100644
--- a/modules/config/fonts/fontconfig.nix
+++ b/modules/config/fonts/fontconfig.nix
@@ -46,13 +46,10 @@ with pkgs.lib;
         </fontconfig>
       '';
 
-    environment.shellInit =
-      ''
-        # FIXME: This variable is no longer needed, but we'll keep it
-        # around for a while for applications linked against old
-        # fontconfig builds.
-        export FONTCONFIG_FILE=/etc/fonts/fonts.conf
-      '';
+    # FIXME: This variable is no longer needed, but we'll keep it
+    # around for a while for applications linked against old
+    # fontconfig builds.
+    environment.variables.FONTCONFIG_FILE.value = "/etc/fonts/fonts.conf";
 
     environment.systemPackages = [ pkgs.fontconfig ];
 
diff --git a/modules/config/i18n.nix b/modules/config/i18n.nix
index 62b01c2221ec..15df0b3a12aa 100644
--- a/modules/config/i18n.nix
+++ b/modules/config/i18n.nix
@@ -69,10 +69,7 @@ in
 
     environment.systemPackages = [ glibcLocales ];
 
-    environment.shellInit =
-      ''
-        export LANG=${config.i18n.defaultLocale}
-      '';
+    environment.variables.LANG.value = config.i18n.defaultLocale;
 
     # ‘/etc/locale.conf’ is used by systemd.
     environment.etc = singleton
diff --git a/modules/config/shells-environment.nix b/modules/config/shells-environment.nix
new file mode 100644
index 000000000000..116c5f11e1f2
--- /dev/null
+++ b/modules/config/shells-environment.nix
@@ -0,0 +1,202 @@
+# This module defines a global environment configuration and
+# a common configuration for all shells.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.environment;
+
+  environOpts = { name, config, ... }: {
+
+    options = {
+
+      value = mkOption {
+        example = "/foo/bin";
+        description =
+          ''
+            Variable value.
+            Exactly one of this or <option>list</option> must be set.
+          '';
+        type = types.uniq types.string;
+      };
+
+      list = mkOption {
+        default = null;
+        example = [ "/foo/bin" "/bar/bin" ];
+        description =
+          ''
+            Variable value.
+            Exactly one of this or <option>value</option> must be set.
+          '';
+        type = types.nullOr (types.listOf types.string);
+      };
+
+    };
+
+    config = {
+      value = mkIf (config.list != null)
+        (concatStringsSep ":" config.list);
+    };
+
+  };
+
+in
+
+{
+
+  options = {
+
+    environment.variables = mkOption {
+      default = {};
+      description = ''
+        A set of environment variables used in the global environment.
+      '';
+      type = types.attrsOf types.optionSet;
+      options = [ environOpts ];
+    };
+
+    environment.profiles = mkOption {
+      default = [];
+      description = ''
+        A list of profiles used to setup the global environment.
+      '';
+      type = types.listOf types.string;
+    };
+
+    environment.profileVariables = mkOption {
+      default = (p: {});
+      description = ''
+        A function which given a profile path should give back
+        a set of environment variables for that profile.
+      '';
+      # !!! this should be of the following type:
+      #type = types.functionTo (types.attrsOf (types.optionSet envVar));
+      # and envVar should be changed to something more like environOpts.
+      # Having unique `value' _or_ multiple `list' is much more useful
+      # than just sticking everything together with ':' unconditionally.
+      # Anyway, to have this type mentioned above
+      # types.optionSet needs to be transformed into a type constructor
+      # (it has a !!! mark on that in nixpkgs)
+      # for now we hack all this to be
+      type = types.functionTo (types.attrsOf (types.listOf types.string));
+    };
+
+    # !!! isn't there a better way?
+    environment.extraInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during global environment initialisation
+        after all variables and profileVariables have been set.
+        This code is asumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.shellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during shell initialisation.
+        This code is asumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.loginShellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during login shell initialisation.
+        This code is asumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.interactiveShellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during interactive shell initialisation.
+        This code is asumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.shellAliases = mkOption {
+      default = {};
+      example = { ll = "ls -l"; };
+      description = ''
+        An attribute set that maps aliases (the top level attribute names in
+        this option) to command strings or directly to build outputs. The
+        aliases are added to all users' shells.
+      '';
+      type = types.attrs; # types.attrsOf types.stringOrPath;
+    };
+
+    environment.binsh = mkOption {
+      default = "${config.system.build.binsh}/bin/sh";
+      example = "\${pkgs.dash}/bin/dash";
+      type = with pkgs.lib.types; path;
+      description = ''
+        The shell executable that is linked system-wide to
+        <literal>/bin/sh</literal>. Please note that NixOS assumes all
+        over the place that shell to be Bash, so override the default
+        setting only if you know exactly what you're doing.
+      '';
+    };
+
+    environment.shells = mkOption {
+      default = [];
+      example = [ "/run/current-system/sw/bin/zsh" ];
+      description = ''
+        A list of permissible login shells for user accounts.
+        No need to mention <literal>/bin/sh</literal>
+        here, it is placed into this list implicitly.
+      '';
+      type = types.listOf types.path;
+    };
+
+  };
+
+  config = {
+
+    system.build.binsh = pkgs.bashInteractive;
+
+    environment.etc."shells".text =
+      ''
+        ${concatStringsSep "\n" cfg.shells}
+        /bin/sh
+      '';
+
+    environment.etc."environment".text =
+       ''
+         ${concatStringsSep "\n" (
+           (mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'')
+             # This line is a kind of a hack because of !!! note above
+             (fold (mergeAttrsWithFunc concat) {} ([ (mapAttrs (n: v: [ v.value ]) cfg.variables) ] ++ map cfg.profileVariables cfg.profiles))))}
+
+         ${cfg.extraInit}
+
+         # The setuid wrappers override other bin directories.
+         export PATH="${config.security.wrapperDir}:$PATH"
+
+         # ~/bin if it exists overrides other bin directories.
+         export PATH="$HOME/bin:$PATH"
+       '';
+
+    system.activationScripts.binsh = stringAfter [ "stdio" ]
+      ''
+        # Create the required /bin/sh symlink; otherwise lots of things
+        # (notably the system() function) won't work.
+        mkdir -m 0755 -p /bin
+        ln -sfn "${cfg.binsh}" /bin/.sh.tmp
+        mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
+      '';
+
+  };
+
+}
diff --git a/modules/config/shells.nix b/modules/config/shells.nix
deleted file mode 100644
index b0a946a8e6ec..000000000000
--- a/modules/config/shells.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-# This module creates /etc/shells, the file that defines the list of
-# permissible login shells for user accounts.
-
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-{
-
-  config = {
-
-    environment.etc = singleton
-      { target = "shells";
-        source = pkgs.writeText "shells"
-          ''
-            /run/current-system/sw/bin/bash
-            /var/run/current-system/sw/bin/bash
-            /bin/sh
-          '';
-      };
-
-  };
-
-}
diff --git a/modules/config/timezone.nix b/modules/config/timezone.nix
index 81536725501f..68b785601faf 100644
--- a/modules/config/timezone.nix
+++ b/modules/config/timezone.nix
@@ -24,11 +24,8 @@ with pkgs.lib;
 
   config = {
 
-    environment.shellInit =
-      ''
-        export TZDIR=/etc/zoneinfo
-        export TZ=${config.time.timeZone}
-      '';
+    environment.variables.TZDIR.value = "/etc/zoneinfo";
+    environment.variables.TZ.value = config.time.timeZone;
 
     environment.etc.localtime.source = "${pkgs.tzdata}/share/zoneinfo/${config.time.timeZone}";
 
diff --git a/modules/module-list.nix b/modules/module-list.nix
index 08acd213355e..9f1563c0768d 100644
--- a/modules/module-list.nix
+++ b/modules/module-list.nix
@@ -13,7 +13,7 @@
   ./config/nsswitch.nix
   ./config/power-management.nix
   ./config/pulseaudio.nix
-  ./config/shells.nix
+  ./config/shells-environment.nix
   ./config/swap.nix
   ./config/sysctl.nix
   ./config/system-path.nix
@@ -45,6 +45,7 @@
   ./programs/bash/bash.nix
   ./programs/bash/command-not-found.nix
   ./programs/blcr.nix
+  ./programs/environment.nix
   ./programs/info.nix
   ./programs/shadow.nix
   ./programs/shell.nix
@@ -52,6 +53,7 @@
   ./programs/ssmtp.nix
   ./programs/venus.nix
   ./programs/wvdial.nix
+  ./programs/zsh/zsh.nix
   ./rename.nix
   ./security/apparmor.nix
   ./security/apparmor-suid.nix
diff --git a/modules/profiles/installation-device.nix b/modules/profiles/installation-device.nix
index 5a92789e5d90..cfb2eb3f9cb1 100644
--- a/modules/profiles/installation-device.nix
+++ b/modules/profiles/installation-device.nix
@@ -50,9 +50,7 @@ with pkgs.lib;
     # Tell the Nix evaluator to garbage collect more aggressively.
     # This is desirable in memory-constrained environments that don't
     # (yet) have swap set up.
-    environment.shellInit =
-      ''
-        export GC_INITIAL_HEAP_SIZE=100000
-      '';
+    environment.variables.GC_INITIAL_HEAP_SIZE.value = "100000";
+
   };
 }
diff --git a/modules/programs/bash/bash.nix b/modules/programs/bash/bash.nix
index 0d751d1d0d39..2324164316df 100644
--- a/modules/programs/bash/bash.nix
+++ b/modules/programs/bash/bash.nix
@@ -7,9 +7,11 @@ with pkgs.lib;
 
 let
 
-  cfg = config.environment;
+  cfge = config.environment;
 
-  initBashCompletion = optionalString cfg.enableBashCompletion ''
+  cfg = config.programs.bash;
+
+  bashCompletion = optionalString cfg.enableCompletion ''
     # Check whether we're running a version of Bash that has support for
     # programmable completion. If we do, enable all modules installed in
     # the system (and user profile).
@@ -27,7 +29,7 @@ let
     fi
   '';
 
-  shellAliases = concatStringsSep "\n" (
+  bashAliases = concatStringsSep "\n" (
     mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases
   );
 
@@ -36,118 +38,173 @@ in
 {
   options = {
 
-    environment.promptInit = mkOption {
-      default = ''
-        # Provide a nice prompt.
-        PROMPT_COLOR="1;31m"
-        let $UID && PROMPT_COLOR="1;32m"
-        PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
-        if test "$TERM" = "xterm"; then
-          PS1="\[\033]2;\h:\u:\w\007\]$PS1"
-        fi
-      '';
-      description = ''
-        Shell script code used to initialise the shell prompt.
-      '';
-      type = types.lines;
-    };
+    programs.bash = {
+
+      enable = mkOption {
+        default = true;
+        description = ''
+          Whenever to configure Bash as an interactive shell.
+          Note that this tries to make Bash the default
+          <option>users.defaultUserShell</option>,
+          which in turn means that you might need to explicitly
+          set this variable if you have another shell configured
+          with NixOS.
+        '';
+        type = types.bool;
+      };
 
-    environment.shellInit = mkOption {
-      default = "";
-      example = ''export PATH=/godi/bin/:$PATH'';
-      description = ''
-        Shell script code called during login shell initialisation.
-      '';
-      type = types.lines;
-    };
+      shellAliases = mkOption {
+        default = config.environment.shellAliases // { which = "type -P"; };
+        description = ''
+          Set of aliases for bash shell. See <option>environment.shellAliases</option>
+          for an option format description.
+        '';
+        type = types.attrs; # types.attrsOf types.stringOrPath;
+      };
 
-    environment.interactiveShellInit = mkOption {
-      default = "";
-      example = ''export PATH=/godi/bin/:$PATH'';
-      description = ''
-        Shell script code called during interactive shell initialisation.
-      '';
-      type = types.lines;
-    };
+      shellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during bash shell initialisation.
+        '';
+        type = types.lines;
+      };
 
-    environment.enableBashCompletion = mkOption {
-      default = false;
-      description = "Enable Bash completion for all interactive shells.";
-      type = types.bool;
-    };
+      loginShellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during login bash shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      interactiveShellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during interactive bash shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      promptInit = mkOption {
+        default = ''
+          # Provide a nice prompt.
+          PROMPT_COLOR="1;31m"
+          let $UID && PROMPT_COLOR="1;32m"
+          PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
+          if test "$TERM" = "xterm"; then
+            PS1="\[\033]2;\h:\u:\w\007\]$PS1"
+          fi
+        '';
+        description = ''
+          Shell script code used to initialise the bash prompt.
+        '';
+        type = types.lines;
+      };
+
+      enableCompletion = mkOption {
+        default = false;
+        description = ''
+          Enable Bash completion for all interactive bash shells.
+        '';
+        type = types.bool;
+      };
 
-    environment.binsh = mkOption {
-      default = "${config.system.build.binsh}/bin/sh";
-      example = "\${pkgs.dash}/bin/dash";
-      type = types.path;
-      description = ''
-        Select the shell executable that is linked system-wide to
-        <literal>/bin/sh</literal>. Please note that NixOS assumes all
-        over the place that shell to be Bash, so override the default
-        setting only if you know exactly what you're doing.
-      '';
     };
 
   };
 
+  config = mkIf cfg.enable {
 
-  config = {
+    programs.bash = {
 
-    # Script executed when the shell starts as a login shell.
-    environment.etc."profile".source =
-      pkgs.substituteAll {
-        src = ./profile.sh;
-        wrapperDir = config.security.wrapperDir;
-        inherit (cfg) shellInit;
-      };
+      shellInit = ''
+        . /etc/environment
 
-    # /etc/bashrc: executed every time an interactive bash
-    # starts. Sources /etc/profile to ensure that the system
-    # environment is configured properly.
-    environment.etc."bashrc".source =
-      pkgs.substituteAll {
-        src = ./bashrc.sh;
-        inherit (cfg) interactiveShellInit;
-      };
+        ${cfge.shellInit}
+      '';
 
-    # Configuration for readline in bash.
-    environment.etc."inputrc".source = ./inputrc;
+      loginShellInit = cfge.loginShellInit;
 
-    environment.shellAliases =
-      { ls = "ls --color=tty";
-        ll = "ls -l";
-        l = "ls -alh";
-        which = "type -P";
-      };
+      interactiveShellInit = ''
+        ${cfge.interactiveShellInit}
 
-    environment.interactiveShellInit =
-      ''
         # Check the window size after every command.
         shopt -s checkwinsize
 
-        ${cfg.promptInit}
-        ${initBashCompletion}
-        ${shellAliases}
-
         # Disable hashing (i.e. caching) of command lookups.
         set +h
+
+        ${cfg.promptInit}
+        ${bashCompletion}
+        ${bashAliases}
       '';
 
-    system.build.binsh = pkgs.bashInteractive;
+    };
 
-    system.activationScripts.binsh = stringAfter [ "stdio" ]
+    environment.etc."profile".text =
       ''
-        # Create the required /bin/sh symlink; otherwise lots of things
-        # (notably the system() function) won't work.
-        mkdir -m 0755 -p /bin
-        ln -sfn "${cfg.binsh}" /bin/.sh.tmp
-        mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
+        # /etc/profile: DO NOT EDIT -- this file has been generated automatically.
+        # This file is read for login shells.
+
+        # Only execute this file once per shell.
+        if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi
+        __ETC_PROFILE_SOURCED=1
+
+        if [ -z "$__BASH_SHELL_INIT_DONE" ]; then
+          __BASH_SHELL_INIT_DONE=1
+          ${cfg.shellInit}
+        fi
+
+        ${cfg.loginShellInit}
+
+        # Read system-wide modifications.
+        if test -f /etc/profile.local; then
+          . /etc/profile.local
+        fi
+
+        if [ -n "''${BASH_VERSION:-}" ]; then
+          . /etc/bashrc
+        fi
       '';
 
-    environment.pathsToLink = optionals cfg.enableBashCompletion [
-      "/etc/bash_completion.d"
-      "/share/bash-completion"
-    ];
+    environment.etc."bashrc".text =
+      ''
+        # /etc/bashrc: DO NOT EDIT -- this file has been generated automatically.
+
+        # Only execute this file once per shell.
+        if [ -n "$__ETC_BASHRC_SOURCED" -o -n "$NOSYSBASHRC" ]; then return; fi
+        __ETC_BASHRC_SOURCED=1
+
+        if [ -z "$__BASH_SHELL_INIT_DONE" ]; then
+          __BASH_SHELL_INIT_DONE=1
+          ${cfg.shellInit}
+        fi
+
+        # We are not always an interactive shell.
+        if [ -n "$PS1" ]; then
+          ${cfg.interactiveShellInit}
+        fi
+
+        # Read system-wide modifications.
+        if test -f /etc/bashrc.local; then
+          . /etc/bashrc.local
+        fi
+      '';
+
+    # Configuration for readline in bash.
+    environment.etc."inputrc".source = ./inputrc;
+
+    users.defaultUserShell = mkDefault "/run/current-system/sw/bin/bash";
+
+    environment.shells =
+      [ "/run/current-system/sw/bin/bash"
+        "/var/run/current-system/sw/bin/bash"
+        "/run/current-system/sw/bin/sh"
+        "/var/run/current-system/sw/bin/sh"
+        "${pkgs.bashInteractive}/bin/bash"
+        "${pkgs.bashInteractive}/bin/sh"
+      ];
 
   };
 
diff --git a/modules/programs/bash/bashrc.sh b/modules/programs/bash/bashrc.sh
deleted file mode 100644
index 98b0907a06b3..000000000000
--- a/modules/programs/bash/bashrc.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-# /etc/bashrc: DO NOT EDIT -- this file has been generated automatically.
-
-# This file is read for interactive non-login shells.
-
-# Only execute this file once per shell.
-if [ -n "$__ETC_BASHRC_SOURCED" -o -n "$NOSYSBASHRC" ]; then return; fi
-__ETC_BASHRC_SOURCED=1
-
-# If the profile was not loaded in a parent process, source it.  But
-# otherwise don't do it because we don't want to clobber overridden
-# values of $PATH, etc.
-if [ -z "$__ETC_PROFILE_DONE" ]; then
-    . /etc/profile
-fi
-
-# We are not always an interactive shell.
-if [ -z "$PS1" ]; then return; fi
-
-@interactiveShellInit@
diff --git a/modules/programs/bash/command-not-found.nix b/modules/programs/bash/command-not-found.nix
index 6549ba86810a..502320446a37 100644
--- a/modules/programs/bash/command-not-found.nix
+++ b/modules/programs/bash/command-not-found.nix
@@ -23,7 +23,7 @@ in
 
 {
 
-  environment.interactiveShellInit =
+  programs.bash.interactiveShellInit =
     ''
       # This function is called whenever a command is not found.
       command_not_found_handle() {
diff --git a/modules/programs/bash/profile.sh b/modules/programs/bash/profile.sh
deleted file mode 100644
index 92fb06581890..000000000000
--- a/modules/programs/bash/profile.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-# /etc/profile: DO NOT EDIT -- this file has been generated automatically.
-
-# This file is read for (interactive) login shells.  Any
-# initialisation specific to interactive shells should be put in
-# /etc/bashrc, which is sourced from here.
-
-# Only execute this file once per shell.
-if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi
-__ETC_PROFILE_SOURCED=1
-
-# Prevent this file from being sourced by interactive non-login child shells.
-export __ETC_PROFILE_DONE=1
-
-# Initialise a bunch of environment variables.
-export LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
-export LD_LIBRARY_PATH=/run/opengl-driver/lib:/run/opengl-driver-32/lib # !!! only set if needed
-export NIXPKGS_CONFIG=/etc/nix/nixpkgs-config.nix
-export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixpkgs=/etc/nixos/nixpkgs:nixos=/etc/nixos/nixos:nixos-config=/etc/nixos/configuration.nix:services=/etc/nixos/services
-export PAGER="less -R"
-export EDITOR=nano
-export LOCATE_PATH=/var/cache/locatedb
-
-# Include the various profiles in the appropriate environment variables.
-export NIX_USER_PROFILE_DIR=/nix/var/nix/profiles/per-user/$USER
-export NIX_PROFILES="/run/current-system/sw /nix/var/nix/profiles/default $HOME/.nix-profile"
-
-unset PATH INFOPATH PKG_CONFIG_PATH PERL5LIB ALSA_PLUGIN_DIRS GST_PLUGIN_PATH KDEDIRS
-unset QT_PLUGIN_PATH QTWEBKIT_PLUGIN_PATH STRIGI_PLUGIN_PATH XDG_CONFIG_DIRS XDG_DATA_DIRS
-unset MOZ_PLUGIN_PATH TERMINFO_DIRS
-
-for i in $NIX_PROFILES; do # !!! reverse
-    # We have to care not leaving an empty PATH element, because that means '.' to Linux
-    export PATH=$i/bin:$i/sbin:$i/lib/kde4/libexec${PATH:+:}$PATH
-    export INFOPATH=$i/info:$i/share/info${INFOPATH:+:}$INFOPATH
-    export PKG_CONFIG_PATH="$i/lib/pkgconfig${PKG_CONFIG_PATH:+:}$PKG_CONFIG_PATH"
-
-    # terminfo and reset TERM with new TERMINFO available
-    export TERMINFO_DIRS=$i/share/terminfo${TERMINFO_DIRS:+:}$TERMINFO_DIRS
-    export TERM=$TERM
-
-    export PERL5LIB="$i/lib/perl5/site_perl${PERL5LIB:+:}$PERL5LIB"
-
-    # ALSA plugins
-    export ALSA_PLUGIN_DIRS="$i/lib/alsa-lib${ALSA_PLUGIN_DIRS:+:}$ALSA_PLUGIN_DIRS"
-
-    # GStreamer.
-    export GST_PLUGIN_PATH="$i/lib/gstreamer-0.10${GST_PLUGIN_PATH:+:}$GST_PLUGIN_PATH"
-
-    # KDE/Gnome stuff.
-    export KDEDIRS=$i${KDEDIRS:+:}$KDEDIRS
-    export STRIGI_PLUGIN_PATH=$i/lib/strigi/${STRIGI_PLUGIN_PATH:+:}$STRIGI_PLUGIN_PATH
-    export QT_PLUGIN_PATH=$i/lib/qt4/plugins:$i/lib/kde4/plugins${QT_PLUGIN_PATH:+:}:$QT_PLUGIN_PATH
-    export QTWEBKIT_PLUGIN_PATH=$i/lib/mozilla/plugins/${QTWEBKIT_PLUGIN_PATH:+:}$QTWEBKIT_PLUGIN_PATH
-    export XDG_CONFIG_DIRS=$i/etc/xdg${XDG_CONFIG_DIRS:+:}$XDG_CONFIG_DIRS
-    export XDG_DATA_DIRS=$i/share${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS
-
-    # Mozilla plugins.
-    export MOZ_PLUGIN_PATH=$i/lib/mozilla/plugins${MOZ_PLUGIN_PATH:+:}$MOZ_PLUGIN_PATH
-
-    # Search directory for Aspell dictionaries.
-    if [ -d "$i/lib/aspell" ]; then
-        export ASPELL_CONF="dict-dir $i/lib/aspell"
-    fi
-done
-
-# The setuid wrappers override other bin directories.
-export PATH=@wrapperDir@:$PATH
-
-# ~/bin if it exists overrides other bin directories.
-export PATH=$HOME/bin:$PATH
-
-# Set up the per-user profile.
-mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
-if test "$(stat --printf '%u' $NIX_USER_PROFILE_DIR)" != "$(id -u)"; then
-    echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
-fi
-
-if ! test -L $HOME/.nix-profile; then
-    echo "creating $HOME/.nix-profile" >&2
-    if test "$USER" != root; then
-        ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
-    else
-        # Root installs in the system-wide profile by default.
-        ln -s /nix/var/nix/profiles/default $HOME/.nix-profile
-    fi
-fi
-
-# Subscribe the root user to the NixOS channel by default.
-if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
-    echo "http://nixos.org/channels/nixos-unstable nixos" > $HOME/.nix-channels
-fi
-
-# Create the per-user garbage collector roots directory.
-NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER
-mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
-if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then
-    echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
-fi
-
-# Set up a default Nix expression from which to install stuff.
-if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
-    echo "creating $HOME/.nix-defexpr" >&2
-    rm -f $HOME/.nix-defexpr
-    mkdir $HOME/.nix-defexpr
-    if [ "$USER" != root ]; then
-        ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
-    fi
-fi
-
-@shellInit@
-
-# Read system-wide modifications.
-if test -f /etc/profile.local; then
-    . /etc/profile.local
-fi
-
-if [ -n "${BASH_VERSION:-}" ]; then
-    . /etc/bashrc
-fi
diff --git a/modules/programs/environment.nix b/modules/programs/environment.nix
new file mode 100644
index 000000000000..8f2df7e4a531
--- /dev/null
+++ b/modules/programs/environment.nix
@@ -0,0 +1,79 @@
+# This module defines a standard configuration for NixOS global environment.
+
+# Most of the stuff here should probably be moved elsewhere sometime.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.environment;
+
+in
+
+{
+
+  config = {
+
+    environment.variables =
+      { LOCALE_ARCHIVE.value = "/run/current-system/sw/lib/locale/locale-archive";
+        LOCATE_PATH.value = "/var/cache/locatedb";
+        NIXPKGS_CONFIG.value = "/etc/nix/nixpkgs-config.nix";
+        NIX_PATH.list =
+          [ "/nix/var/nix/profiles/per-user/root/channels/nixos"
+            "nixpkgs=/etc/nixos/nixpkgs"
+            "nixos=/etc/nixos/nixos"
+            "nixos-config=/etc/nixos/configuration.nix"
+            "services=/etc/nixos/services"
+          ];
+        PAGER.value = "less -R";
+        EDITOR.value = "nano";
+      };
+
+    environment.profiles =
+      [ "$HOME/.nix-profile"
+        "/nix/var/nix/profiles/default"
+        "/run/current-system/sw"
+      ];
+
+    # !!! fix environment.profileVariables definition and then move
+    # most of these elsewhere
+    environment.profileVariables = (i:
+      { PATH = [ "${i}/bin" "${i}/sbin" "${i}/lib/kde4/libexec" ];
+        MANPATH = [ "${i}/man" "${i}/share/man" ];
+        INFOPATH = [ "${i}/info" "${i}/share/info" ];
+        PKG_CONFIG_PATH = [ "${i}/lib/pkgconfig" ];
+        TERMINFO_DIRS = [ "${i}/share/terminfo" ];
+        PERL5LIB = [ "${i}/lib/perl5/site_perl" ];
+        ALSA_PLUGIN_DIRS = [ "${i}/lib/alsa-lib" ];
+        GST_PLUGIN_PATH = [ "${i}/lib/gstreamer-0.10" ];
+        KDEDIRS = [ "${i}" ];
+        STRIGI_PLUGIN_PATH = [ "${i}/lib/strigi/" ];
+        QT_PLUGIN_PATH = [ "${i}/lib/qt4/plugins" "${i}/lib/kde4/plugins" ];
+        QTWEBKIT_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins/" ];
+        GTK_PATH = [ "${i}/lib/gtk-2.0" ];
+        XDG_CONFIG_DIRS = [ "${i}/etc/xdg" ];
+        XDG_DATA_DIRS = [ "${i}/share" ];
+        MOZ_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins" ];
+      });
+
+    environment.extraInit =
+      ''
+         # reset TERM with new TERMINFO available (if any)
+         export TERM=$TERM
+
+         unset ASPELL_CONF
+         for i in ${concatStringsSep " " (reverseList cfg.profiles)} ; do
+           if [ -d "$i/lib/aspell" ]; then
+             export ASPELL_CONF="dict-dir $i/lib/aspell"
+           fi
+         done
+
+         export NIX_USER_PROFILE_DIR="/nix/var/nix/profiles/per-user/$USER"
+         export NIX_PROFILES="${concatStringsSep " " (reverseList cfg.profiles)}"
+      '';
+
+  };
+
+}
diff --git a/modules/programs/shadow.nix b/modules/programs/shadow.nix
index e4310dae986b..695c0b6620f7 100644
--- a/modules/programs/shadow.nix
+++ b/modules/programs/shadow.nix
@@ -2,6 +2,8 @@
 
 { config, pkgs, ... }:
 
+with pkgs.lib;
+
 let
 
   loginDefs =
@@ -39,7 +41,6 @@ in
   options = {
 
     users.defaultUserShell = pkgs.lib.mkOption {
-      default = "/run/current-system/sw/bin/bash";
       description = ''
         This option defines the default shell assigned to user
         accounts.  This must not be a store path, since the path is
@@ -47,6 +48,7 @@ in
         Rather, it should be the path of a symlink that points to the
         actual shell in the Nix store.
       '';
+      type = types.uniq types.path;
     };
 
   };
diff --git a/modules/programs/shell.nix b/modules/programs/shell.nix
index 8348c4c25a1c..d5f43a86a942 100644
--- a/modules/programs/shell.nix
+++ b/modules/programs/shell.nix
@@ -1,25 +1,67 @@
-# This module defines global configuration for the shells.
+# This module defines a standard configuration for NixOS shells.
 
 { config, pkgs, ... }:
 
 with pkgs.lib;
 
+let
+
+  cfg = config.environment;
+
+in
+
 {
-  options = {
-    environment.shellAliases = mkOption {
-      type = types.attrs; # types.attrsOf types.stringOrPath;
-      default = {};
-      example = {
-        ll = "ls -lh";
+
+  config = {
+
+    environment.shellAliases =
+      { ls = "ls --color=tty";
+        ll = "ls -l";
+        l  = "ls -alh";
       };
-      description = ''
-        An attribute set that maps aliases (the top level attribute names in
-        this option) to command strings or directly to build outputs. The
-        aliases are added to all users' shells.
+
+    environment.shellInit =
+      ''
+        # Set up the per-user profile.
+        mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
+        if test "$(stat --printf '%u' $NIX_USER_PROFILE_DIR)" != "$(id -u)"; then
+            echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
+        fi
+
+        if ! test -L $HOME/.nix-profile; then
+            echo "creating $HOME/.nix-profile" >&2
+            if test "$USER" != root; then
+                ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
+            else
+                # Root installs in the system-wide profile by default.
+                ln -s /nix/var/nix/profiles/default $HOME/.nix-profile
+            fi
+        fi
+
+        # Subscribe the root user to the NixOS channel by default.
+        if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
+            echo "creating $HOME/.nix-channels with nixos-unstable subscription" >&2
+            echo "http://nixos.org/channels/nixos-unstable nixos" > $HOME/.nix-channels
+        fi
+
+        # Create the per-user garbage collector roots directory.
+        NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER
+        mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
+        if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then
+            echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
+        fi
+
+        # Set up a default Nix expression from which to install stuff.
+        if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
+            echo "creating $HOME/.nix-defexpr" >&2
+            rm -f $HOME/.nix-defexpr
+            mkdir $HOME/.nix-defexpr
+            if [ "$USER" != root ]; then
+                ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
+            fi
+        fi
       '';
-    };
-  };
 
-  config = {
   };
+
 }
diff --git a/modules/programs/zsh/zinputrc b/modules/programs/zsh/zinputrc
new file mode 100644
index 000000000000..6121f3e21f16
--- /dev/null
+++ b/modules/programs/zsh/zinputrc
@@ -0,0 +1,42 @@
+# Stolen from ArchWiki
+
+# create a zkbd compatible hash;
+# to add other keys to this hash, see: man 5 terminfo
+typeset -A key
+
+key[Home]=${terminfo[khome]}
+
+key[End]=${terminfo[kend]}
+key[Insert]=${terminfo[kich1]}
+key[Delete]=${terminfo[kdch1]}
+key[Up]=${terminfo[kcuu1]}
+key[Down]=${terminfo[kcud1]}
+key[Left]=${terminfo[kcub1]}
+key[Right]=${terminfo[kcuf1]}
+key[PageUp]=${terminfo[kpp]}
+key[PageDown]=${terminfo[knp]}
+
+# setup key accordingly
+[[ -n "${key[Home]}"     ]]  && bindkey  "${key[Home]}"     beginning-of-line
+[[ -n "${key[End]}"      ]]  && bindkey  "${key[End]}"      end-of-line
+[[ -n "${key[Insert]}"   ]]  && bindkey  "${key[Insert]}"   overwrite-mode
+[[ -n "${key[Delete]}"   ]]  && bindkey  "${key[Delete]}"   delete-char
+[[ -n "${key[Up]}"       ]]  && bindkey  "${key[Up]}"       up-line-or-history
+[[ -n "${key[Down]}"     ]]  && bindkey  "${key[Down]}"     down-line-or-history
+[[ -n "${key[Left]}"     ]]  && bindkey  "${key[Left]}"     backward-char
+[[ -n "${key[Right]}"    ]]  && bindkey  "${key[Right]}"    forward-char
+[[ -n "${key[PageUp]}"   ]]  && bindkey  "${key[PageUp]}"   beginning-of-buffer-or-history
+[[ -n "${key[PageDown]}" ]]  && bindkey  "${key[PageDown]}" end-of-buffer-or-history
+
+# Finally, make sure the terminal is in application mode, when zle is
+# active. Only then are the values from $terminfo valid.
+if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
+    function zle-line-init () {
+        printf '%s' "${terminfo[smkx]}"
+    }
+    function zle-line-finish () {
+        printf '%s' "${terminfo[rmkx]}"
+    }
+    zle -N zle-line-init
+    zle -N zle-line-finish
+fi
diff --git a/modules/programs/zsh/zsh.nix b/modules/programs/zsh/zsh.nix
new file mode 100644
index 000000000000..97e7a49e5765
--- /dev/null
+++ b/modules/programs/zsh/zsh.nix
@@ -0,0 +1,180 @@
+# This module defines global configuration for the zshell.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfge = config.environment;
+
+  cfg = config.programs.zsh;
+
+  zshAliases = concatStringsSep "\n" (
+    mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases
+  );
+
+in
+
+{
+
+  options = {
+
+    programs.zsh = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whenever to configure Zsh as an interactive shell.
+          Note that this tries to make Zsh the default
+          <option>users.defaultUserShell</option>,
+          which in turn means that you might need to explicitly
+          set this variable if you have another shell configured
+          with NixOS.
+        '';
+        type = types.bool;
+      };
+
+      shellAliases = mkOption {
+        default = config.environment.shellAliases;
+        description = ''
+          Set of aliases for zsh shell. See <option>environment.shellAliases</option>
+          for an option format description.
+        '';
+        type = types.attrs; # types.attrsOf types.stringOrPath;
+      };
+
+      shellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during zsh shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      loginShellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during zsh login shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      interactiveShellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during interactive zsh shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      promptInit = mkOption {
+        default = ''
+          autoload -U promptinit && promptinit && prompt walters
+        '';
+        description = ''
+          Shell script code used to initialise the zsh prompt.
+        '';
+        type = types.lines;
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    programs.zsh = {
+
+      shellInit = ''
+        . /etc/environment
+
+        ${cfge.shellInit}
+      '';
+
+      loginShellInit = cfge.loginShellInit;
+
+      interactiveShellInit = ''
+        ${cfge.interactiveShellInit}
+
+        ${cfg.promptInit}
+        ${zshAliases}
+
+        # Some sane history defaults
+        export SAVEHIST=2000
+        export HISTSIZE=2000
+        export HISTFILE=$HOME/.zsh_history
+
+        setopt HIST_IGNORE_DUPS SHARE_HISTORY
+      '';
+
+    };
+
+    environment.etc."zshenv".text =
+      ''
+        # /etc/zshenv: DO NOT EDIT -- this file has been generated automatically.
+        # This file is read for all shells.
+
+        # Only execute this file once per shell.
+        if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi
+        __ETC_ZSHENV_SOURCED=1
+
+        ${cfg.shellInit}
+
+        # Read system-wide modifications.
+        if test -f /etc/zshenv.local; then
+          . /etc/zshenv.local
+        fi
+      '';
+
+    environment.etc."zprofile".text =
+      ''
+        # /etc/zprofile: DO NOT EDIT -- this file has been generated automatically.
+        # This file is read for login shells.
+
+        # Only execute this file once per shell.
+        if [ -n "$__ETC_ZPROFILE_SOURCED" ]; then return; fi
+        __ETC_ZPROFILE_SOURCED=1
+
+        ${cfg.loginShellInit}
+
+        # Read system-wide modifications.
+        if test -f /etc/zprofile.local; then
+          . /etc/zprofile.local
+        fi
+      '';
+
+    environment.etc."zshrc".text =
+      ''
+        # /etc/zshrc: DO NOT EDIT -- this file has been generated automatically.
+        # This file is read for interactive shells.
+
+        # Only execute this file once per shell.
+        if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi
+        __ETC_ZSHRC_SOURCED=1
+
+        . /etc/zinputrc
+
+        ${cfg.interactiveShellInit}
+
+        # Read system-wide modifications.
+        if test -f /etc/zshrc.local; then
+          . /etc/zshrc.local
+        fi
+      '';
+
+    environment.etc."zinputrc".source = ./zinputrc;
+
+    environment.systemPackages = [ pkgs.zsh ];
+
+    users.defaultUserShell = mkDefault "/run/current-system/sw/bin/zsh";
+
+    environment.shells =
+      [ "/run/current-system/sw/bin/zsh"
+        "/var/run/current-system/sw/bin/zsh"
+        "${pkgs.zsh}/bin/zsh"
+      ];
+
+  };
+
+}
diff --git a/modules/rename.nix b/modules/rename.nix
index bc0ebf1f0919..ef86befe9e75 100644
--- a/modules/rename.nix
+++ b/modules/rename.nix
@@ -66,6 +66,7 @@ in zipModules ([]
 # usage example:
 # ++ rename alias "services.xserver.slim.theme" "services.xserver.displayManager.slim.theme"
 ++ rename obsolete "environment.extraPackages" "environment.systemPackages"
+++ rename obsolete "environment.enableBashCompletion" "programs.bash.enableCompletion"
 
 ++ rename obsolete "security.extraSetuidPrograms" "security.setuidPrograms"
 ++ rename obsolete "networking.enableWLAN" "networking.wireless.enable"
diff --git a/modules/security/ca.nix b/modules/security/ca.nix
index e42f5ffe3b89..f0897630eac7 100644
--- a/modules/security/ca.nix
+++ b/modules/security/ca.nix
@@ -17,13 +17,9 @@ with pkgs.lib;
         }
       ];
 
-    environment.shellInit =
-      ''
-        export OPENSSL_X509_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
-
-        export CURL_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt
-        export GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt
-      '';
+    environment.variables.OPENSSL_X509_CERT_FILE.value = "/etc/ssl/certs/ca-bundle.crt";
+    environment.variables.CURL_CA_BUNDLE.value = "/etc/ssl/certs/ca-bundle.crt";
+    environment.variables.GIT_SSL_CAINFO.value = "/etc/ssl/certs/ca-bundle.crt";
 
   };
 
diff --git a/modules/services/misc/nix-daemon.nix b/modules/services/misc/nix-daemon.nix
index 6ae96028979b..9dd58fbab20a 100644
--- a/modules/services/misc/nix-daemon.nix
+++ b/modules/services/misc/nix-daemon.nix
@@ -198,8 +198,7 @@ in
         example = "http://127.0.0.1:3128";
       };
 
-      # Environment variables for running Nix.  !!! Misnomer - it's
-      # actually a shell script.
+      # Environment variables for running Nix.
       envVars = mkOption {
         internal = true;
         default = {};
@@ -328,11 +327,11 @@ in
         ftp_proxy = cfg.proxy;
       };
 
-    environment.shellInit =
-      ''
-        # Set up the environment variables for running Nix.
-        ${concatMapStrings (n: "export ${n}=\"${getAttr n cfg.envVars}\"\n") (attrNames cfg.envVars)}
+    # Set up the environment variables for running Nix.
+    environment.variables = mapAttrs (n: v: { value = v; }) cfg.envVars;
 
+    environment.extraInit =
+      ''
         # Set up secure multi-user builds: non-root users build through the
         # Nix daemon.
         if test "$USER" != root; then
diff --git a/modules/services/x11/desktop-managers/xfce.nix b/modules/services/x11/desktop-managers/xfce.nix
index e22e6a121308..6197a7e10aa7 100644
--- a/modules/services/x11/desktop-managers/xfce.nix
+++ b/modules/services/x11/desktop-managers/xfce.nix
@@ -79,10 +79,7 @@ in
     environment.pathsToLink =
       [ "/share/xfce4" "/share/themes" "/share/mime" "/share/desktop-directories" "/share/gtksourceview-2.0" ];
 
-    environment.shellInit =
-      ''
-        export GIO_EXTRA_MODULES=${pkgs.xfce.gvfs}/lib/gio/modules
-      '';
+    environment.variables.GIO_EXTRA_MODULES.value = "${pkgs.xfce.gvfs}/lib/gio/modules";
 
     # Enable helpful DBus services.
     services.udisks2.enable = true;
diff --git a/modules/services/x11/xserver.nix b/modules/services/x11/xserver.nix
index 40da6a743891..2c76361ea4bf 100644
--- a/modules/services/x11/xserver.nix
+++ b/modules/services/x11/xserver.nix
@@ -409,6 +409,9 @@ in
     boot.blacklistedKernelModules =
       optionals (elem "nvidia" driverNames) [ "nouveau" "nvidiafb" ];
 
+    environment.variables.LD_LIBRARY_PATH.list =
+      [ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ];
+
     environment.etc =
       (optionals cfg.exportConfiguration
         [ { source = "${configFile}";
diff --git a/modules/system/boot/modprobe.nix b/modules/system/boot/modprobe.nix
index 62ac3009d101..c1c65bed64f4 100644
--- a/modules/system/boot/modprobe.nix
+++ b/modules/system/boot/modprobe.nix
@@ -105,10 +105,7 @@ with pkgs.lib;
         echo ${config.system.sbin.modprobe}/sbin/modprobe > /proc/sys/kernel/modprobe
       '';
 
-    environment.shellInit =
-      ''
-        export MODULE_DIR=/run/current-system/kernel-modules/lib/modules
-      '';
+    environment.variables.MODULE_DIR.value = "/run/current-system/kernel-modules/lib/modules";
 
   };