summary refs log tree commit diff
path: root/nixos/modules/programs
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/programs')
-rw-r--r--nixos/modules/programs/atop.nix36
-rw-r--r--nixos/modules/programs/bash/bash.nix217
-rw-r--r--nixos/modules/programs/bash/command-not-found.nix51
-rw-r--r--nixos/modules/programs/bash/command-not-found.pl48
-rw-r--r--nixos/modules/programs/bash/inputrc36
-rw-r--r--nixos/modules/programs/blcr.nix27
-rw-r--r--nixos/modules/programs/environment.nix79
-rw-r--r--nixos/modules/programs/info.nix36
-rw-r--r--nixos/modules/programs/shadow.nix103
-rw-r--r--nixos/modules/programs/shell.nix64
-rw-r--r--nixos/modules/programs/ssh.nix68
-rw-r--r--nixos/modules/programs/ssmtp.nix111
-rw-r--r--nixos/modules/programs/venus.nix174
-rw-r--r--nixos/modules/programs/virtualbox.nix47
-rw-r--r--nixos/modules/programs/wvdial.nix71
-rw-r--r--nixos/modules/programs/zsh/zinputrc42
-rw-r--r--nixos/modules/programs/zsh/zsh.nix180
17 files changed, 1390 insertions, 0 deletions
diff --git a/nixos/modules/programs/atop.nix b/nixos/modules/programs/atop.nix
new file mode 100644
index 00000000000..7fdaab9d67d
--- /dev/null
+++ b/nixos/modules/programs/atop.nix
@@ -0,0 +1,36 @@
+# Global configuration for atop.
+
+{config, pkgs, ...}:
+
+with pkgs.lib;
+
+let cfg = config.programs.atop;
+
+in
+{
+  ###### interface
+
+  options = {
+
+    programs.atop = {
+
+      settings = mkOption {
+        type = types.attrs;
+        default = {};
+        example = {
+          flags = "a1f";
+          interval = 5;
+        };
+        description = ''
+          Parameters to be written to <filename>/etc/atoprc</filename>
+        '';
+      };
+
+    };
+  };
+
+  config = mkIf (cfg.settings != {}) {
+    environment.etc."atoprc".text =
+      concatStrings (mapAttrsToList (n: v: "${n} ${toString v}\n") cfg.settings);
+  };
+}
diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix
new file mode 100644
index 00000000000..8cfe3f990ad
--- /dev/null
+++ b/nixos/modules/programs/bash/bash.nix
@@ -0,0 +1,217 @@
+# This module defines global configuration for the Bash shell, in
+# particular /etc/bashrc and /etc/profile.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfge = config.environment;
+
+  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).
+    if shopt -q progcomp &>/dev/null; then
+      . "${pkgs.bashCompletion}/etc/profile.d/bash_completion.sh"
+      nullglobStatus=$(shopt -p nullglob)
+      shopt -s nullglob
+      for p in $NIX_PROFILES; do
+        for m in "$p/etc/bash_completion.d/"* "$p/share/bash-completion/completions/"*; do
+          . $m
+        done
+      done
+      eval "$nullglobStatus"
+      unset nullglobStatus p m
+    fi
+  '';
+
+  bashAliases = concatStringsSep "\n" (
+    mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases
+  );
+
+in
+
+{
+  options = {
+
+    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;
+      };
+
+      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;
+      };
+
+      shellInit = mkOption {
+        default = "";
+        description = ''
+          Shell script code called during bash shell initialisation.
+        '';
+        type = types.lines;
+      };
+
+      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;
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    programs.bash = {
+
+      shellInit = ''
+        . ${config.system.build.setEnvironment}
+
+        ${cfge.shellInit}
+      '';
+
+      loginShellInit = cfge.loginShellInit;
+
+      interactiveShellInit = ''
+        ${cfge.interactiveShellInit}
+
+        # Check the window size after every command.
+        shopt -s checkwinsize
+
+        # Disable hashing (i.e. caching) of command lookups.
+        set +h
+
+        ${cfg.promptInit}
+        ${bashCompletion}
+        ${bashAliases}
+      '';
+
+    };
+
+    environment.etc."profile".text =
+      ''
+        # /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
+
+        # Prevent this file from being sourced by interactive non-login child shells.
+        export __ETC_PROFILE_DONE=1
+
+        ${cfg.shellInit}
+        ${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.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 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 [ -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.pathsToLink = optionals cfg.enableCompletion [
+      "/etc/bash_completion.d"
+      "/share/bash-completion"
+    ];
+
+    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/nixos/modules/programs/bash/command-not-found.nix b/nixos/modules/programs/bash/command-not-found.nix
new file mode 100644
index 00000000000..502320446a3
--- /dev/null
+++ b/nixos/modules/programs/bash/command-not-found.nix
@@ -0,0 +1,51 @@
+# This module provides suggestions of packages to install if the user
+# tries to run a missing command in Bash.  This is implemented using a
+# SQLite database that maps program names to Nix package names (e.g.,
+# "pdflatex" is mapped to "tetex").
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  commandNotFound = pkgs.substituteAll {
+    name = "command-not-found";
+    dir = "bin";
+    src = ./command-not-found.pl;
+    isExecutable = true;
+    inherit (pkgs) perl;
+    perlFlags = concatStrings (map (path: "-I ${path}/lib/perl5/site_perl ")
+      [ pkgs.perlPackages.DBI pkgs.perlPackages.DBDSQLite ]);
+  };
+
+in
+
+{
+
+  programs.bash.interactiveShellInit =
+    ''
+      # This function is called whenever a command is not found.
+      command_not_found_handle() {
+        local p=/run/current-system/sw/bin/command-not-found
+        if [ -x $p -a -f /nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite ]; then
+          # Run the helper program.
+          $p "$1"
+          # Retry the command if we just installed it.
+          if [ $? = 126 ]; then
+            "$@"
+          else
+            return 127
+          fi
+        else
+          echo "$1: command not found" >&2
+          return 127
+        fi
+      }
+    '';
+
+  environment.systemPackages = [ commandNotFound ];
+
+  # TODO: tab completion for uninstalled commands! :-)
+
+}
diff --git a/nixos/modules/programs/bash/command-not-found.pl b/nixos/modules/programs/bash/command-not-found.pl
new file mode 100644
index 00000000000..916649059d3
--- /dev/null
+++ b/nixos/modules/programs/bash/command-not-found.pl
@@ -0,0 +1,48 @@
+#! @perl@/bin/perl -w @perlFlags@
+
+use strict;
+use DBI;
+use DBD::SQLite;
+use Config;
+
+my $program = $ARGV[0];
+
+my $dbPath = "/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite";
+
+my $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
+    or die "cannot open database `$dbPath'";
+$dbh->{RaiseError} = 0;
+$dbh->{PrintError} = 0;
+
+my $system = $ENV{"NIX_SYSTEM"} // $Config{myarchname};
+
+my $res = $dbh->selectall_arrayref(
+    "select package from Programs where system = ? and name = ?",
+    { Slice => {} }, $system, $program);
+
+if (!defined $res || scalar @$res == 0) {
+    print STDERR "$program: command not found\n";
+} elsif (scalar @$res == 1) {
+    my $package = @$res[0]->{package};
+    if ($ENV{"NIX_AUTO_INSTALL"} // "") {
+        print STDERR <<EOF;
+The program ‘$program’ is currently not installed. It is provided by
+the package ‘$package’, which I will now install for you.
+EOF
+        ;
+        exit 126 if system("nix-env", "-i", $package) == 0;
+    } else {
+        print STDERR <<EOF;
+The program ‘$program’ is currently not installed. You can install it by typing:
+  nix-env -i $package
+EOF
+    }
+} else {
+    print STDERR <<EOF;
+The program ‘$program’ is currently not installed. It is provided by
+several packages. You can install it by typing one of the following:
+EOF
+    print STDERR "  nix-env -i $_->{package}\n" foreach @$res;
+}
+
+exit 127;
diff --git a/nixos/modules/programs/bash/inputrc b/nixos/modules/programs/bash/inputrc
new file mode 100644
index 00000000000..e4eabc052c5
--- /dev/null
+++ b/nixos/modules/programs/bash/inputrc
@@ -0,0 +1,36 @@
+# inputrc borrowed from CentOS (RHEL).
+
+set bell-style none
+
+set meta-flag on
+set input-meta on
+set convert-meta off
+set output-meta on
+
+#set mark-symlinked-directories on
+
+$if mode=emacs
+
+# for linux console and RH/Debian xterm
+"\e[1~": beginning-of-line
+"\e[4~": end-of-line
+"\e[5~": beginning-of-history
+"\e[6~": end-of-history
+"\e[3~": delete-char
+"\e[2~": quoted-insert
+"\e[5C": forward-word
+"\e[5D": backward-word
+"\e[1;5C": forward-word
+"\e[1;5D": backward-word
+
+# for rxvt
+"\e[8~": end-of-line
+
+# for non RH/Debian xterm, can't hurt for RH/DEbian xterm
+"\eOH": beginning-of-line
+"\eOF": end-of-line
+
+# for freebsd console
+"\e[H": beginning-of-line
+"\e[F": end-of-line
+$endif
diff --git a/nixos/modules/programs/blcr.nix b/nixos/modules/programs/blcr.nix
new file mode 100644
index 00000000000..e1e31b4a56a
--- /dev/null
+++ b/nixos/modules/programs/blcr.nix
@@ -0,0 +1,27 @@
+{ config, pkgs, ... }:
+
+let
+  inherit (pkgs.lib) mkOption mkIf;
+  cfg = config.environment.blcr;
+  blcrPkg = config.boot.kernelPackages.blcr;
+in
+
+{
+  ###### interface
+
+  options = {
+    environment.blcr.enable = mkOption {
+      default = false;
+      description =
+        "Whether to enable support for the BLCR checkpointing tool.";
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    boot.kernelModules = [ "blcr" "blcr_imports" ];
+    boot.extraModulePackages = [ blcrPkg ];
+    environment.systemPackages = [ blcrPkg ];
+  };
+}
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
new file mode 100644
index 00000000000..f42df351422
--- /dev/null
+++ b/nixos/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 = "/run/current-system/sw/lib/locale/locale-archive";
+        LOCATE_PATH = "/var/cache/locatedb";
+        NIXPKGS_CONFIG = "/etc/nix/nixpkgs-config.nix";
+        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"
+          ];
+        PAGER = "less -R";
+        EDITOR = "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/nixos/modules/programs/info.nix b/nixos/modules/programs/info.nix
new file mode 100644
index 00000000000..30c25cf3420
--- /dev/null
+++ b/nixos/modules/programs/info.nix
@@ -0,0 +1,36 @@
+{config, pkgs, ...}:
+
+let
+
+  # Quick hack to make the `info' command work properly.  `info' needs
+  # a "dir" file containing all the installed Info files, which we
+  # don't have (it would be impure to have a package installation
+  # update some global "dir" file).  So this wrapper script around
+  # "info" builds a temporary "dir" file on the fly.  This is a bit
+  # slow (on a cold cache) but not unacceptably so.
+  infoWrapper = pkgs.writeScriptBin "info"
+    ''
+      #! ${pkgs.stdenv.shell}
+
+      dir=$(mktemp --tmpdir -d "info.dir.XXXXXX")
+
+      if test -z "$dir"; then exit 1; fi
+
+      trap 'rm -rf "$dir"' EXIT
+
+      shopt -s nullglob
+
+      for i in $(IFS=:; echo $INFOPATH); do
+          for j in $i/*.info; do
+              ${pkgs.texinfo}/bin/install-info --quiet $j $dir/dir
+          done
+      done
+
+      INFOPATH=$dir:$INFOPATH ${pkgs.texinfo}/bin/info "$@"
+    ''; # */
+
+in
+
+{
+  environment.systemPackages = [ infoWrapper pkgs.texinfo ];
+}
diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
new file mode 100644
index 00000000000..695c0b6620f
--- /dev/null
+++ b/nixos/modules/programs/shadow.nix
@@ -0,0 +1,103 @@
+# Configuration for the pwdutils suite of tools: passwd, useradd, etc.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  loginDefs =
+    ''
+      DEFAULT_HOME yes
+
+      SYS_UID_MIN  100
+      SYS_UID_MAX  499
+      UID_MIN      1000
+      UID_MAX      29999
+
+      SYS_GID_MIN  100
+      SYS_GID_MAX  499
+      GID_MIN      1000
+      GID_MAX      29999
+
+      TTYGROUP     tty
+      TTYPERM      0620
+
+      # Ensure privacy for newly created home directories.
+      UMASK        077
+
+      # Uncomment this to allow non-root users to change their account
+      #information.  This should be made configurable.
+      #CHFN_RESTRICT frwh
+
+    '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    users.defaultUserShell = pkgs.lib.mkOption {
+      description = ''
+        This option defines the default shell assigned to user
+        accounts.  This must not be a store path, since the path is
+        used outside the store (in particular in /etc/passwd).
+        Rather, it should be the path of a symlink that points to the
+        actual shell in the Nix store.
+      '';
+      type = types.uniq types.path;
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    environment.systemPackages = [ pkgs.shadow ];
+
+    environment.etc =
+      [ { # /etc/login.defs: global configuration for pwdutils.  You
+          # cannot login without it!
+          source = pkgs.writeText "login.defs" loginDefs;
+          target = "login.defs";
+        }
+
+        { # /etc/default/useradd: configuration for useradd.
+          source = pkgs.writeText "useradd"
+            ''
+              GROUP=100
+              HOME=/home
+              SHELL=${config.users.defaultUserShell}
+            '';
+          target = "default/useradd";
+        }
+      ];
+
+    security.pam.services =
+      [ { name = "chsh"; rootOK = true; }
+        { name = "chfn"; rootOK = true; }
+        { name = "su"; rootOK = true; forwardXAuth = true; }
+        { name = "passwd"; }
+        # Note: useradd, groupadd etc. aren't setuid root, so it
+        # doesn't really matter what the PAM config says as long as it
+        # lets root in.
+        { name = "useradd"; rootOK = true; }
+        { name = "usermod"; rootOK = true; }
+        { name = "userdel"; rootOK = true; }
+        { name = "groupadd"; rootOK = true; }
+        { name = "groupmod"; rootOK = true; }
+        { name = "groupmems"; rootOK = true; }
+        { name = "groupdel"; rootOK = true; }
+        { name = "login"; startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; }
+      ];
+
+    security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ];
+
+  };
+
+}
diff --git a/nixos/modules/programs/shell.nix b/nixos/modules/programs/shell.nix
new file mode 100644
index 00000000000..679c4979dfa
--- /dev/null
+++ b/nixos/modules/programs/shell.nix
@@ -0,0 +1,64 @@
+# This module defines a standard configuration for NixOS shells.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.environment;
+
+in
+
+{
+
+  config = {
+
+    environment.shellAliases =
+      { ls = "ls --color=tty";
+        ll = "ls -l";
+        l  = "ls -alh";
+      };
+
+    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
+            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
+            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
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
new file mode 100644
index 00000000000..5ec32376b60
--- /dev/null
+++ b/nixos/modules/programs/ssh.nix
@@ -0,0 +1,68 @@
+# Global configuration for the SSH client.
+
+{config, pkgs, ...}:
+
+with pkgs.lib;
+
+let cfg  = config.programs.ssh;
+    cfgd = config.services.openssh;
+
+in
+{
+  ###### interface
+
+  options = {
+
+    programs.ssh = {
+
+      forwardX11 = mkOption {
+        default = false;
+        description = ''
+          Whether to request X11 forwarding on outgoing connections by default.
+          This is useful for running graphical programs on the remote machine and have them display to your local X11 server.
+          Historically, this value has depended on the value used by the local sshd daemon, but there really isn't a relation between the two.
+          Note: there are some security risks to forwarding an X11 connection.
+          NixOS's X server is built with the SECURITY extension, which prevents some obvious attacks.
+          To enable or disable forwarding on a per-connection basis, see the -X and -x options to ssh.
+          The -Y option to ssh enables trusted forwarding, which bypasses the SECURITY extension.
+        '';
+      };
+
+      setXAuthLocation = mkOption {
+        default = true;
+        description = ''
+          Whether to set the path to xauth for X11-forwarded connections.
+          Pulls in X11 dependency.
+        '';
+      };
+
+      extraConfig = mkOption {
+        default = "";
+        description = ''
+          Extra configuration text appended to <filename>ssh_config</filename>.
+          See the ssh_config(5) man page for help.
+        '';
+      };
+    };
+  };
+
+  assertions = [{ assertion = if cfg.forwardX11 then cfg.setXAuthLocation else true;
+                  message = "cannot enable X11 forwarding without setting xauth location";}];
+
+  config = {
+    environment.etc =
+      [ { # SSH configuration.  Slight duplication of the sshd_config
+          # generation in the sshd service.
+          source = pkgs.writeText "ssh_config" ''
+            AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
+            ${optionalString cfg.setXAuthLocation ''
+              XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
+            ''}
+            ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
+            ${cfg.extraConfig}
+          '';
+          target = "ssh/ssh_config";
+        }
+      ];
+  };
+}
diff --git a/nixos/modules/programs/ssmtp.nix b/nixos/modules/programs/ssmtp.nix
new file mode 100644
index 00000000000..904989d57a0
--- /dev/null
+++ b/nixos/modules/programs/ssmtp.nix
@@ -0,0 +1,111 @@
+# Configuration for `ssmtp', a trivial mail transfer agent that can
+# replace sendmail/postfix on simple systems.  It delivers email
+# directly to an SMTP server defined in its configuration file, wihout
+# queueing mail locally.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.networking.defaultMailServer;
+
+in
+
+{
+
+  options = {
+
+    networking.defaultMailServer = {
+
+      directDelivery = mkOption {
+        default = false;
+        example = true;
+        description = ''
+          Use the trivial Mail Transfer Agent (MTA)
+          <command>ssmtp</command> package to allow programs to send
+          e-mail.  If you don't want to run a “real” MTA like
+          <command>sendmail</command> or <command>postfix</command> on
+          your machine, set this option to <literal>true</literal>, and
+          set the option
+          <option>networking.defaultMailServer.hostName</option> to the
+          host name of your preferred mail server.
+        '';
+      };
+
+      hostName = mkOption {
+        example = "mail.example.org";
+        description = ''
+          The host name of the default mail server to use to deliver
+          e-mail.
+        '';
+      };
+
+      domain = mkOption {
+        default = "";
+        example = "example.org";
+        description = ''
+          The domain from which mail will appear to be sent.
+        '';
+      };
+
+      useTLS = mkOption {
+        default = false;
+        example = true;
+        description = ''
+          Whether TLS should be used to connect to the default mail
+          server.
+        '';
+      };
+
+      useSTARTTLS = mkOption {
+        default = false;
+        example = true;
+        description = ''
+          Whether the STARTTLS should be used to connect to the default
+          mail server.  (This is needed for TLS-capable mail servers
+          running on the default SMTP port 25.)
+        '';
+      };
+
+      authUser = mkOption {
+        default = "";
+        example = "foo@example.org";
+        description = ''
+          Username used for SMTP auth. Leave blank to disable.
+        '';
+      };
+
+      authPass = mkOption {
+        default = "";
+        example = "correctHorseBatteryStaple";
+        description = ''
+          Password used for SMTP auth. (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)
+        '';
+      };
+
+    };
+
+  };
+
+
+  config = mkIf cfg.directDelivery {
+
+    environment.etc."ssmtp/ssmtp.conf".text =
+      ''
+        MailHub=${cfg.hostName}
+        FromLineOverride=YES
+        ${if cfg.domain != "" then "rewriteDomain=${cfg.domain}" else ""}
+        UseTLS=${if cfg.useTLS then "YES" else "NO"}
+        UseSTARTTLS=${if cfg.useSTARTTLS then "YES" else "NO"}
+        #Debug=YES
+        ${if cfg.authUser != "" then "AuthUser=${cfg.authUser}" else ""}
+        ${if cfg.authPass != "" then "AuthPass=${cfg.authPass}" else ""}
+      '';
+
+    environment.systemPackages = [pkgs.ssmtp];
+
+  };
+
+}
diff --git a/nixos/modules/programs/venus.nix b/nixos/modules/programs/venus.nix
new file mode 100644
index 00000000000..2b3bfbc6c18
--- /dev/null
+++ b/nixos/modules/programs/venus.nix
@@ -0,0 +1,174 @@
+{config, pkgs, ...}:
+
+with pkgs.lib;
+let
+  cfg = config.services.venus;
+
+  configFile = pkgs.writeText "venus.ini"
+    ''
+      [Planet]
+      name = ${cfg.name}
+      link = ${cfg.link}
+      owner_name = ${cfg.ownerName}
+      owner_email = ${cfg.ownerEmail}
+      output_theme = ${cfg.cacheDirectory}/theme
+      output_dir = ${cfg.outputDirectory}
+      cache_directory = ${cfg.cacheDirectory}
+      items_per_page = ${toString cfg.itemsPerPage}
+      ${(concatStringsSep "\n\n"
+            (map ({ name, feedUrl, homepageUrl }:
+            ''
+              [${feedUrl}]
+              name = ${name}
+              link = ${homepageUrl}
+            '') cfg.feeds))}
+    '';
+
+in
+{
+
+  options = {
+    services.venus = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Planet Venus is an awesome ‘river of news’ feed reader. It downloads
+          news feeds published by web sites and aggregates their content
+          together into a single combined feed, latest news first.
+        '';
+      };
+
+      dates = mkOption {
+        default = "*:0,15,30,45";
+        type = types.string;
+        description = ''
+          Specification (in the format described by
+          <citerefentry><refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>) of the time at
+          which the Venus will collect feeds.
+        '';
+      };
+
+      user = mkOption {
+        default = "root";
+        type = types.string;
+        description = ''
+          User for running venus script.
+        '';
+      };
+
+      group = mkOption {
+        default = "root";
+        type = types.string;
+        description = ''
+          Group for running venus script.
+        '';
+      };
+
+      name = mkOption {
+        default = "NixOS Planet";
+        type = types.string;
+        description = ''
+          Your planet's name.
+        '';
+      };
+
+      link = mkOption {
+        default = "http://planet.nixos.org";
+        type = types.string;
+        description = ''
+          Link to the main page.
+        '';
+      };
+
+      ownerName = mkOption {
+        default = "Rok Garbas";
+        type = types.string;
+        description = ''
+          Your name.
+        '';
+      };
+
+      ownerEmail = mkOption {
+        default = "some@example.com";
+        type = types.string;
+        description = ''
+          Your e-mail address.
+        '';
+      };
+
+      outputTheme = mkOption {
+        default = "${pkgs.venus}/themes/classic_fancy";
+        type = types.path;
+        description = ''
+          Directory containing a config.ini file which is merged with this one.
+          This is typically used to specify templating and bill of material
+          information.
+        '';
+      };
+
+      outputDirectory = mkOption {
+        type = types.path;
+        description = ''
+          Directory to place output files.
+        '';
+      };
+
+      cacheDirectory = mkOption {
+        default = "/var/cache/venus";
+        type = types.path;
+        description = ''
+            Where cached feeds are stored.
+        '';
+      };
+
+      itemsPerPage = mkOption {
+        default = 15;
+        type = types.int;
+        description = ''
+          How many items to put on each page.
+        '';
+      };
+
+      feeds = mkOption {
+        default = [];
+        example = [
+          {
+            name = "Rok Garbas";
+            feedUrl= "http://url/to/rss/feed.xml";
+            homepageUrl = "http://garbas.si";
+          }
+        ];
+        description = ''
+          List of feeds.
+        '';
+      };
+
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    system.activationScripts.venus =
+      ''
+        mkdir -p ${cfg.outputDirectory}
+        chown ${cfg.user}:${cfg.group} ${cfg.outputDirectory} -R
+        rm -rf ${cfg.cacheDirectory}/theme
+        mkdir -p ${cfg.cacheDirectory}/theme
+        cp -R ${cfg.outputTheme}/* ${cfg.cacheDirectory}/theme
+        chown ${cfg.user}:${cfg.group} ${cfg.cacheDirectory} -R
+      '';
+
+    systemd.services.venus =
+      { description = "Planet Venus, an awesome ‘river of news’ feed reader";
+        path  = [ pkgs.venus ];
+        script = "exec venus-planet ${configFile}";
+        serviceConfig.User = "${cfg.user}";
+        serviceConfig.Group = "${cfg.group}";
+        environment.OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
+        startOn = cfg.dates;
+      };
+
+  };
+}
diff --git a/nixos/modules/programs/virtualbox.nix b/nixos/modules/programs/virtualbox.nix
new file mode 100644
index 00000000000..340fec0496a
--- /dev/null
+++ b/nixos/modules/programs/virtualbox.nix
@@ -0,0 +1,47 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let virtualbox = config.boot.kernelPackages.virtualbox; in
+
+{
+  boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
+  boot.extraModulePackages = [ virtualbox ];
+  environment.systemPackages = [ virtualbox ];
+
+  users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers;
+
+  services.udev.extraRules =
+    ''
+      KERNEL=="vboxdrv",    OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+      KERNEL=="vboxnetctl", OWNER="root", GROUP="root",      MODE="0600", TAG+="systemd"
+      SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
+      SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
+      SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
+      SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
+    '';
+
+  # Since we lack the right setuid binaries, set up a host-only network by default.
+
+  systemd.services."vboxnet0" =
+    { description = "VirtualBox vboxnet0 Interface";
+      requires = [ "dev-vboxnetctl.device" ];
+      after = [ "dev-vboxnetctl.device" ];
+      wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
+      path = [ virtualbox ];
+      serviceConfig.RemainAfterExit = true;
+      serviceConfig.Type = "oneshot";
+      script =
+        ''
+          if ! [ -e /sys/class/net/vboxnet0 ]; then
+            VBoxManage hostonlyif create
+          fi
+        '';
+      postStop =
+        ''
+          VBoxManage hostonlyif remove vboxnet0
+        '';
+    };
+
+  networking.interfaces.vboxnet0 = { ipAddress = "192.168.56.1"; prefixLength = 24; };
+}
diff --git a/nixos/modules/programs/wvdial.nix b/nixos/modules/programs/wvdial.nix
new file mode 100644
index 00000000000..da3f7dce98a
--- /dev/null
+++ b/nixos/modules/programs/wvdial.nix
@@ -0,0 +1,71 @@
+# Global configuration for wvdial.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  configFile = ''
+    [Dialer Defaults]
+    PPPD PATH = ${pkgs.ppp}/sbin/pppd
+    ${config.environment.wvdial.dialerDefaults}
+  '';
+
+  cfg = config.environment.wvdial;
+
+in
+{
+  ###### interface
+
+  options = {
+
+    environment.wvdial = {
+
+      dialerDefaults = mkOption {
+        default = "";
+        type = types.string;
+        example = ''Init1 = AT+CGDCONT=1,"IP","internet.t-mobile"'';
+        description = ''
+          Contents of the "Dialer Defaults" section of
+          <filename>/etc/wvdial.conf</filename>.
+        '';
+      };
+
+      pppDefaults = mkOption {
+        default = ''
+          noipdefault
+          usepeerdns
+          defaultroute
+          persist
+          noauth
+        '';
+        type = types.string;
+        description = "Default ppp settings for wvdial.";
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf (cfg.dialerDefaults != "") {
+
+    environment = {
+
+      etc =
+      [
+        { source = pkgs.writeText "wvdial.conf" configFile;
+          target = "wvdial.conf";
+        }
+        { source = pkgs.writeText "wvdial" cfg.pppDefaults;
+          target = "ppp/peers/wvdial";
+        }
+      ];
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/programs/zsh/zinputrc b/nixos/modules/programs/zsh/zinputrc
new file mode 100644
index 00000000000..6121f3e21f1
--- /dev/null
+++ b/nixos/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/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix
new file mode 100644
index 00000000000..cff751934d7
--- /dev/null
+++ b/nixos/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 = ''
+        . ${config.system.build.setEnvironment}
+
+        ${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"
+      ];
+
+  };
+
+}