diff options
Diffstat (limited to 'nixos')
57 files changed, 1056 insertions, 336 deletions
diff --git a/nixos/doc/manual/administration/declarative-containers.xml b/nixos/doc/manual/administration/declarative-containers.xml index 177ebdd8db175..228c45b0c1fec 100644 --- a/nixos/doc/manual/administration/declarative-containers.xml +++ b/nixos/doc/manual/administration/declarative-containers.xml @@ -49,4 +49,8 @@ on container networking.)</para> switch</literal>. Note that this will not delete the root directory of the container in <literal>/var/lib/containers</literal>.</para> -</section> \ No newline at end of file +<para>Declarative containers can be started and stopped using the +corresponding systemd service, e.g. <literal>systemctl start +container@database</literal>.</para> + +</section> diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml index 2a58ff25941c1..b613c7f06cc89 100644 --- a/nixos/doc/manual/configuration/config-file.xml +++ b/nixos/doc/manual/configuration/config-file.xml @@ -68,7 +68,7 @@ instance, if you try to define an option that doesn’t exist (that is, doesn’t have a corresponding <emphasis>option declaration</emphasis>), <command>nixos-rebuild</command> will give an error like: <screen> -The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist. +The option `services.httpd.enable' defined in `/etc/nixos/configuration.nix' does not exist. </screen> Likewise, values in option definitions must have a correct type. For instance, <option>services.httpd.enable</option> must be a Boolean diff --git a/nixos/doc/manual/configuration/network-manager.xml b/nixos/doc/manual/configuration/network-manager.xml index ceac40b7a1f66..b7e47b8729f32 100644 --- a/nixos/doc/manual/configuration/network-manager.xml +++ b/nixos/doc/manual/configuration/network-manager.xml @@ -10,7 +10,7 @@ use NetworkManager. You can enable NetworkManager by setting: <programlisting> -services.networkmanager.enable = true; +networking.networkmanager.enable = true; </programlisting> some desktop managers (e.g., GNOME) enable NetworkManager @@ -19,8 +19,8 @@ automatically for you.</para> <para>All users that should have permission to change network settings must belong to the <code>networkmanager</code> group.</para> -<note><para><code>services.networkmanager</code> and -<code>services.wireless</code> can not be enabled at the same time: +<note><para><code>networking.networkmanager</code> and +<code>networking.wireless</code> can not be enabled at the same time: you can still connect to the wireless networks using NetworkManager.</para></note> diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml index afc159dbd5d76..c529737c3bf3d 100644 --- a/nixos/doc/manual/man-nixos-rebuild.xml +++ b/nixos/doc/manual/man-nixos-rebuild.xml @@ -1,7 +1,7 @@ <refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"> - + <refmeta> <refentrytitle><command>nixos-rebuild</command></refentrytitle> <manvolnum>8</manvolnum> @@ -22,7 +22,8 @@ <arg choice='plain'><option>boot</option></arg> <arg choice='plain'><option>test</option></arg> <arg choice='plain'><option>build</option></arg> - <arg choice='plain'><option>dry-run</option></arg> + <arg choice='plain'><option>dry-build</option></arg> + <arg choice='plain'><option>dry-activate</option></arg> <arg choice='plain'><option>build-vm</option></arg> <arg choice='plain'><option>build-vm-with-bootloader</option></arg> </group> @@ -114,10 +115,22 @@ $ nix-build /path/to/nixpkgs/nixos -A system </varlistentry> <varlistentry> - <term><option>dry-run</option></term> + <term><option>dry-build</option></term> + <listitem> + <para>Show what store paths would be built or downloaded by any + of the operations above, but otherwise do nothing.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>dry-activate</option></term> <listitem> - <para>Simply show what store paths would be built or downloaded - by any of the operations above.</para> + <para>Build the new configuration, but instead of activating it, + show what changes would be performed by the activation (i.e. by + <command>nixos-rebuild test</command>). For + instance, this command will print which systemd units would be + restarted. The list of changes is not guaranteed to be + complete.</para> </listitem> </varlistentry> diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index 549e731f3b08a..a39c2895bf84d 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -8,6 +8,7 @@ let inherit (config.services.avahi) nssmdns; inherit (config.services.samba) nsswins; + ldap = config.users.ldap.enable; in @@ -40,9 +41,9 @@ in # should define an option used by this module. environment.etc."nsswitch.conf".text = '' - passwd: files ldap - group: files ldap - shadow: files ldap + passwd: files ${optionalString ldap "ldap"} + group: files ${optionalString ldap "ldap"} + shadow: files ${optionalString ldap "ldap"} hosts: files ${optionalString nssmdns "mdns_minimal [NOTFOUND=return]"} dns ${optionalString nssmdns "mdns"} ${optionalString nsswins "wins"} myhostname mymachines networks: files dns ethers: files diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index d35ecb754bdb0..de73de91629b0 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -174,12 +174,12 @@ foreach my $u (@{$spec->{users}}) { } elsif (defined $u->{initialHashedPassword}) { $u->{hashedPassword} = $u->{initialHashedPassword}; } + } - # Create a home directory. - if ($u->{createHome}) { - make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home}; - chown $u->{uid}, $u->{gid}, $u->{home}; - } + # Create a home directory. + if ($u->{createHome} && ! -e $u->{home}) { + make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home}; + chown $u->{uid}, $u->{gid}, $u->{home}; } if (defined $u->{passwordFile}) { diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index f585a27747994..db87f9fd0b1a5 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -489,6 +489,7 @@ in { utmp.gid = ids.gids.utmp; adm.gid = ids.gids.adm; grsecurity.gid = ids.gids.grsecurity; + input.gid = ids.gids.input; }; system.activationScripts.users = stringAfter [ "etc" ] diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 2b20dc7395af9..209310bec9991 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -47,6 +47,15 @@ in boot.extraModulePackages = [ nvidia_x11 ]; + # nvidia-uvm is required by CUDA applications. + boot.kernelModules = [ "nvidia-uvm" ]; + + # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. + services.udev.extraRules = + '' + KERNEL=="nvidia_uvm", RUN+="${pkgs.stdenv.shell} -c 'mknod -m 666 /dev/nvidia-uvm c $(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" + ''; + boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ]; services.acpid.enable = true; diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh index 8157f8fc7da5d..1d6df8cb3f71a 100644 --- a/nixos/modules/installer/tools/nixos-rebuild.sh +++ b/nixos/modules/installer/tools/nixos-rebuild.sh @@ -26,7 +26,8 @@ while [ "$#" -gt 0 ]; do --help) showSyntax ;; - switch|boot|test|build|dry-run|build-vm|build-vm-with-bootloader) + switch|boot|test|build|dry-build|dry-run|dry-activate|build-vm|build-vm-with-bootloader) + if [ "$i" = dry-run ]; then i=dry-build; fi action="$i" ;; --install-grub) @@ -137,7 +138,7 @@ fi # First build Nix, since NixOS may require a newer version than the # current one. -if [ -n "$rollback" -o "$action" = dry-run ]; then +if [ -n "$rollback" -o "$action" = dry-build ]; then buildNix= fi @@ -180,7 +181,7 @@ if [ -n "$canRun" ]; then fi -if [ "$action" = dry-run ]; then +if [ "$action" = dry-build ]; then extraBuildFlags+=(--dry-run) fi @@ -193,7 +194,7 @@ if [ -z "$rollback" ]; then if [ "$action" = switch -o "$action" = boot ]; then nix-env "${extraBuildFlags[@]}" -p "$profile" -f '<nixpkgs/nixos>' --set -A system pathToConfig="$profile" - elif [ "$action" = test -o "$action" = build -o "$action" = dry-run ]; then + elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then nix-build '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}" > /dev/null pathToConfig=./result elif [ "$action" = build-vm ]; then @@ -224,7 +225,7 @@ fi # If we're not just building, then make the new configuration the boot # default and/or activate it now. -if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then +if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then if ! $pathToConfig/bin/switch-to-configuration "$action"; then echo "warning: error(s) occured while switching to the new configuration" >&2 exit 1 diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 0c863ec8de1cc..158609dcf7931 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -180,6 +180,7 @@ panamax = 170; marathon = 171; exim = 172; + sddm = 175; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -301,8 +302,6 @@ mlmmj = 135; riemann = 137; riemanndash = 138; - hbase = 139; - opentsdb = 140; uhub = 142; mailpile = 146; redmine = 147; @@ -313,14 +312,18 @@ systemd-resolve = 153; systemd-timesync = 154; liquidsoap = 155; - fleet = 159; + hbase = 158; + opentsdb = 159; scollector = 160; bosun = 161; kubernetes = 162; gitlab = 165; - nylon = 166; + nylon = 168; panamax = 170; exim = 172; + fleet = 173; + input = 174; + sddm = 175; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c41ae69c1ace6..de86f11c6bbe0 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -228,6 +228,7 @@ ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba.nix ./services/network-filesystems/diod.nix + ./services/network-filesystems/u9fs.nix ./services/network-filesystems/yandex-disk.nix ./services/networking/amuled.nix ./services/networking/atftpd.nix @@ -352,12 +353,14 @@ ./services/web-servers/varnish/default.nix ./services/web-servers/winstone.nix ./services/web-servers/zope2.nix + ./services/x11/unclutter.nix ./services/x11/desktop-managers/default.nix ./services/x11/display-managers/auto.nix ./services/x11/display-managers/default.nix ./services/x11/display-managers/gdm.nix ./services/x11/display-managers/kdm.nix ./services/x11/display-managers/lightdm.nix + ./services/x11/display-managers/sddm.nix ./services/x11/display-managers/slim.nix ./services/x11/hardware/multitouch.nix ./services/x11/hardware/synaptics.nix @@ -432,5 +435,5 @@ ./virtualisation/openvswitch.nix ./virtualisation/parallels-guest.nix ./virtualisation/virtualbox-guest.nix - #./virtualisation/xen-dom0.nix + ./virtualisation/xen-dom0.nix ] diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 796740ea636ac..bd9b897158dc1 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -4,8 +4,19 @@ with lib; -let cfg = config.programs.ssh; - cfgd = config.services.openssh; +let + + cfg = config.programs.ssh; + cfgd = config.services.openssh; + + askPassword = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass"; + + askPasswordWrapper = pkgs.writeScript "ssh-askpass-wrapper" + '' + #! ${pkgs.stdenv.shell} -e + export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')" + exec ${askPassword} + ''; in { @@ -117,6 +128,11 @@ in Restart = "on-failure"; SuccessExitStatus = "0 2"; }; + # Allow ssh-agent to ask for confirmation. This requires the + # unit to know about the user's $DISPLAY (via ‘systemctl + # import-environment’). + environment.SSH_ASKPASS = optionalString config.services.xserver.enable askPasswordWrapper; + environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS }; environment.extraInit = optionalString cfg.startAgent @@ -126,5 +142,10 @@ in fi ''; + environment.interactiveShellInit = optionalString config.services.xserver.enable + '' + export SSH_ASKPASS=${askPassword} + ''; + }; } diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix index fc25ba6f9694c..4bf2f9a175716 100644 --- a/nixos/modules/programs/uim.nix +++ b/nixos/modules/programs/uim.nix @@ -7,14 +7,16 @@ let in { options = { + uim = { enable = mkOption { type = types.bool; default = false; example = true; - description = "enable UIM input method"; + description = "Enable UIM input method"; }; }; + }; config = mkIf cfg.enable { diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 1efc278aeb224..e820b2cb9ce48 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -112,6 +112,9 @@ in zipModules ([] # VirtualBox ++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ] +# Tarsnap +++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ] + # proxy ++ obsolete [ "nix" "proxy" ] [ "networking" "proxy" "default" ] diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix index d0c7fa6ec288f..66eeab7503db3 100644 --- a/nixos/modules/security/grsecurity.nix +++ b/nixos/modules/security/grsecurity.nix @@ -286,10 +286,11 @@ in systemd.services.grsec-lock = mkIf cfg.config.sysctl { description = "grsecurity sysctl-lock Service"; - requires = [ "sysctl.service" ]; + requires = [ "systemd-sysctl.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = "yes"; + unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock"; script = '' locked=`cat /proc/sys/kernel/grsecurity/grsec_lock` if [ "$locked" == "0" ]; then diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 65761865859f1..e81278a95d5c5 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -63,6 +63,14 @@ let ''; }; + oathAuth = mkOption { + default = config.security.pam.enableOATH; + type = types.bool; + description = '' + If set, the OATH Toolkit will be used. + ''; + }; + sshAgentAuth = mkOption { default = false; type = types.bool; @@ -203,9 +211,13 @@ let ${optionalString cfg.usbAuth "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"} ${optionalString cfg.unixAuth - "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"} + "auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"} + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} ${optionalString cfg.otpwAuth "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"} + ${optionalString cfg.oathAuth + "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} ${optionalString config.users.ldap.enable "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"} ${optionalString config.krb5.enable '' @@ -213,9 +225,11 @@ let auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass ''} - auth required pam_deny.so + ${optionalString (! config.security.pam.enableEcryptfs) "auth required pam_deny.so"} # Password management. + ${optionalString config.security.pam.enableEcryptfs + "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} password requisite pam_unix.so nullok sha512 ${optionalString config.users.ldap.enable "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"} @@ -235,12 +249,16 @@ let "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=/etc/skel umask=0022"} ${optionalString cfg.updateWtmp "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"} + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} ${optionalString config.users.ldap.enable "session optional ${pam_ldap}/lib/security/pam_ldap.so"} ${optionalString config.krb5.enable "session optional ${pam_krb5}/lib/security/pam_krb5.so"} ${optionalString cfg.otpwAuth "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"} + ${optionalString cfg.oathAuth + "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} ${optionalString cfg.startSession "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"} ${optionalString cfg.forwardXAuth @@ -338,6 +356,20 @@ in ''; }; + security.pam.enableOATH = mkOption { + default = false; + description = '' + Enable the OATH (one-time password) PAM module. + ''; + }; + + security.pam.enableEcryptfs = mkOption { + default = false; + description = '' + Enable eCryptfs PAM module (mounting ecryptfs home directory on login). + ''; + }; + users.motd = mkOption { default = null; example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178."; @@ -357,7 +389,12 @@ in [ pkgs.pam ] ++ optional config.users.ldap.enable pam_ldap ++ optionals config.krb5.enable [pam_krb5 pam_ccreds] - ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]; + ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] + ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ] + ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; + + security.setuidPrograms = + optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ]; environment.etc = mapAttrsToList (n: v: makePAMService v) config.security.pam.services; diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index b79052337597e..9abfb41087b71 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -15,6 +15,8 @@ let state_file "${cfg.dataDir}/state" sticker_file "${cfg.dataDir}/sticker.sql" log_file "syslog" + user "${cfg.user}" + group "${cfg.group}" ${if cfg.network.host != "any" then "bind_to_address ${cfg.network.host}" else ""} ${if cfg.network.port != 6600 then @@ -40,8 +42,7 @@ in { musicDirectory = mkOption { default = "${cfg.dataDir}/music"; description = '' - Extra configuration added to the end of MPD's - configuration file, mpd.conf. + The directory where mpd reads music from. ''; }; @@ -62,6 +63,16 @@ in { ''; }; + user = mkOption { + default = "mpd"; + description = "User account under which MPD runs."; + }; + + group = mkOption { + default = "mpd"; + description = "Group account under which MPD runs."; + }; + network = { host = mkOption { @@ -96,7 +107,7 @@ in { description = "Music Player Daemon"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.mpd ]; - preStart = "mkdir -p ${cfg.dataDir} && chown -R mpd:mpd ${cfg.dataDir}"; + preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}"; script = "exec mpd --no-daemon ${mpdConf}"; serviceConfig = { User = "mpd"; @@ -104,16 +115,18 @@ in { }; }; - users.extraUsers.mpd = { + users.extraUsers = optionalAttrs (cfg.user == "mpd") (singleton { inherit uid; - group = "mpd"; + name = "mpd"; + group = cfg.group; extraGroups = [ "audio" ]; description = "Music Player Daemon user"; home = "${cfg.dataDir}"; - }; - - users.extraGroups.mpd.gid = gid; + }); + users.extraGroups = optionalAttrs (cfg.group == "mpd") (singleton { + gid = gid; + }); }; } diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index 1b0bcadca1515..155161945cd90 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -12,6 +12,7 @@ let keyfile ${config.services.tarsnap.keyfile} ${optionalString cfg.nodump "nodump"} ${optionalString cfg.printStats "print-stats"} + ${optionalString cfg.printStats "humanize-numbers"} ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes} ${optionalString cfg.aggressiveNetworking "aggressive-networking"} ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)} @@ -27,46 +28,39 @@ in type = types.bool; default = false; description = '' - If enabled, NixOS will periodically create backups of the - specified directories using the <literal>tarsnap</literal> - backup service. This installs a <literal>systemd</literal> - service called <literal>tarsnap-backup</literal> which is - periodically run by cron, or you may run it on-demand. - - See the Tarsnap <link - xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting - Started</link> page. + Enable periodic tarsnap backups. ''; }; keyfile = mkOption { - type = types.path; + type = types.str; default = "/root/tarsnap.key"; description = '' - Path to the keyfile which identifies the machine - associated with your Tarsnap account. This file can - be created using the - <literal>tarsnap-keygen</literal> utility, and - providing your Tarsnap login credentials. + The keyfile which associates this machine with your tarsnap + account. + Create the keyfile with <command>tarsnap-keygen</command>. + + The keyfile name should be given as a string and not a path, to + avoid the key being copied into the Nix store. ''; }; cachedir = mkOption { - type = types.path; + type = types.nullOr types.path; default = "/var/cache/tarsnap"; description = '' - Tarsnap operations use a "cache directory" which - allows Tarsnap to identify which blocks of data have - been previously stored; this directory is specified - via the <literal>cachedir</literal> option. If the - cache directory is lost or out of date, tarsnap - creation/deletion operations will exit with an error - message instructing you to run <literal>tarsnap - --fsck</literal> to regenerate the cache directory. + The cache allows tarsnap to identify previously stored data + blocks, reducing archival time and bandwidth usage. + + Should the cache become desynchronized or corrupted, tarsnap + will refuse to run until you manually rebuild the cache with + <command>tarsnap --fsck</command>. + + Set to <literal>null</literal> to disable caching. ''; }; - config = mkOption { + archives = mkOption { type = types.attrsOf (types.submodule ( { options = { @@ -74,41 +68,44 @@ in type = types.bool; default = true; description = '' - If set to <literal>true</literal>, then don't - archive files which have the - <literal>nodump</literal> flag set. + Exclude files with the <literal>nodump</literal> flag. ''; }; printStats = mkOption { type = types.bool; default = true; - description = "Print statistics when creating archives."; + description = '' + Print global archive statistics upon completion. + The output is available via + <command>systemctl status tarsnap@archive-name</command>. + ''; }; checkpointBytes = mkOption { type = types.nullOr types.str; - default = "1G"; + default = "1GB"; description = '' - Create a checkpoint per a particular amount of - uploaded data. By default, Tarsnap will create - checkpoints once per GB of data uploaded. At - minimum, <literal>checkpointBytes</literal> must be - 1GB. - - Can also be set to <literal>null</literal> to - disable checkpointing. + Create a checkpoint every <literal>checkpointBytes</literal> + of uploaded data (optionally specified using an SI prefix). + + 1GB is the minimum value. A higher value is recommended, + as checkpointing is expensive. + + Set to <literal>null</literal> to disable checkpointing. ''; }; period = mkOption { type = types.str; - default = "15 01 * * *"; + default = "01:15"; + example = "hourly"; description = '' - This option defines (in the format used by cron) - when tarsnap is run for backups. The default is to - backup the specified paths at 01:15 at night every - day. + Create archive at this interval. + + The format is described in + <citerefentry><refentrytitle>systemd.time</refentrytitle> + <manvolnum>7</manvolnum></citerefentry>. ''; }; @@ -116,11 +113,11 @@ in type = types.bool; default = false; description = '' - Aggressive network behaviour: Use multiple TCP - connections when writing archives. Use of this - option is recommended only in cases where TCP - congestion control is known to be the limiting - factor in upload performance. + Upload data over multiple TCP connections, potentially + increasing tarsnap's bandwidth utilisation at the cost + of slowing down all other network traffic. Not + recommended unless TCP congestion is the dominant + limiting factor. ''; }; @@ -134,8 +131,7 @@ in type = types.listOf types.str; default = []; description = '' - Exclude files and directories matching the specified - patterns. + Exclude files and directories matching these patterns. ''; }; @@ -143,12 +139,10 @@ in type = types.listOf types.str; default = []; description = '' - Include only files and directories matching the - specified patterns. + Include only files and directories matching these + patterns (the empty list includes everything). - Note that exclusions specified via - <literal>excludes</literal> take precedence over - inclusions. + Exclusions have precedence over inclusions. ''; }; @@ -156,10 +150,10 @@ in type = types.bool; default = false; description = '' - Attempt to reduce tarsnap memory consumption. This - option will slow down the process of creating - archives, but may help on systems where the average - size of files being backed up is less than 1 MB. + Reduce memory consumption by not caching small files. + Possibly beneficial if the average file size is smaller + than 1 MB and the number of files is lower than the + total amount of RAM in KB. ''; }; @@ -167,11 +161,9 @@ in type = types.bool; default = false; description = '' - Try even harder to reduce tarsnap memory - consumption. This can significantly slow down - tarsnap, but reduces its memory usage by an - additional factor of 2 beyond what the - <literal>lowmem</literal> option does. + Reduce memory consumption by a factor of 2 beyond what + <literal>lowmem</literal> does, at the cost of significantly + slowing down the archiving process. ''; }; }; @@ -188,25 +180,22 @@ in gamedata = { directories = [ "/var/lib/minecraft "]; - period = "*/30 * * * *"; + period = "*:30"; }; } ''; description = '' - Configuration of a Tarsnap archive. In the example, your - machine will have two tarsnap archives: - <literal>gamedata</literal> (backed up every 30 minutes) and - <literal>nixos</literal> (backed up at 1:15 AM every night by - default). You can control individual archive backups using - <literal>systemctl</literal>, using the - <literal>tarsnap@nixos</literal> or - <literal>tarsnap@gamedata</literal> units. For example, - <literal>systemctl start tarsnap@nixos</literal> will - immediately create a new NixOS archive. By default, archives - are suffixed with the timestamp of when they were started, - down to second resolution. This means you can use GNU - <literal>sort</literal> to sort output easily. + Tarsnap archive configurations. Each attribute names an archive + to be created at a given time interval, according to the options + associated with it. When uploading to the tarsnap server, + archive names are suffixed by a 1 second resolution timestamp. + + For each member of the set is created a timer which triggers the + instanced <literal>tarsnap@</literal> service unit. You may use + <command>systemctl start tarsnap@archive-name</command> to + manually trigger creation of <literal>archive-name</literal> at + any time. ''; }; }; @@ -216,38 +205,45 @@ in assertions = (mapAttrsToList (name: cfg: { assertion = cfg.directories != []; - message = "Must specify directories for Tarsnap to back up"; - }) cfg.config) ++ + message = "Must specify paths for tarsnap to back up"; + }) cfg.archives) ++ (mapAttrsToList (name: cfg: - { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem); + { assertion = !(cfg.lowmem && cfg.verylowmem); message = "You cannot set both lowmem and verylowmem"; - }) cfg.config); + }) cfg.archives); systemd.services."tarsnap@" = { - description = "Tarsnap Backup of '%i'"; + description = "Tarsnap archive '%i'"; requires = [ "network.target" ]; path = [ pkgs.tarsnap pkgs.coreutils ]; scriptArgs = "%i"; script = '' - mkdir -p -m 0755 $(dirname ${cfg.cachedir}) - mkdir -p -m 0600 ${cfg.cachedir} + mkdir -p -m 0755 ${dirOf cfg.cachedir} + mkdir -p -m 0700 ${cfg.cachedir} DIRS=`cat /etc/tarsnap/$1.dirs` exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS ''; + + serviceConfig = { + IOSchedulingClass = "idle"; + NoNewPrivileges = "true"; + CapabilityBoundingSet = "CAP_DAC_READ_SEARCH"; + }; }; - services.cron.systemCronJobs = mapAttrsToList (name: cfg: - "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap@${name}" - ) cfg.config; + systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}" + { timerConfig.OnCalendar = cfg.period; + wantedBy = [ "timers.target" ]; + }) cfg.archives; environment.etc = (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf" { text = configFile cfg; - }) cfg.config) // + }) cfg.archives) // (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs" { text = concatStringsSep " " cfg.directories; - }) cfg.config); + }) cfg.archives); environment.systemPackages = [ pkgs.tarsnap ]; }; diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix index e1fe6be6f6a36..2b1d07c355ef8 100644 --- a/nixos/modules/services/databases/couchdb.nix +++ b/nixos/modules/services/databases/couchdb.nix @@ -131,8 +131,8 @@ in { type = types.string; default = "/var/lib/couchdb/couchdb.ini"; description = '' - Custom configuration file. File needs to be readable and writable - from couchdb user/group. + Configuration file for persisting runtime changes. File + needs to be readable and writable from couchdb user/group. ''; }; @@ -157,12 +157,15 @@ in { mkdir -p ${cfg.databaseDir}; mkdir -p ${cfg.viewIndexDir}; touch ${cfg.configFile} + touch -a ${cfg.logFile} if [ "$(id -u)" = 0 ]; then - chown ${cfg.user}:${cfg.group} ${cfg.uriFile} + chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`; + (-f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true chown ${cfg.user}:${cfg.group} ${cfg.databaseDir} chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir} chown ${cfg.user}:${cfg.group} ${cfg.configFile} + chown ${cfg.user}:${cfg.group} ${cfg.logFile} fi ''; diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix index 02e44ad887049..14ffdad9217d2 100644 --- a/nixos/modules/services/databases/mongodb.nix +++ b/nixos/modules/services/databases/mongodb.nix @@ -120,6 +120,7 @@ in }; preStart = '' + rm ${cfg.dbpath}/mongod.lock || true if ! test -e ${cfg.dbpath}; then install -d -m0700 -o ${cfg.user} ${cfg.dbpath} fi diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index b91c389e90a2d..f2612d0b43b94 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -201,7 +201,7 @@ in environment.systemPackages = [ cfg.package ]; systemd.services.redis_init = - { description = "Redis server initialisation"; + { description = "Redis Server Initialisation"; wantedBy = [ "redis.service" ]; before = [ "redis.service" ]; @@ -216,7 +216,7 @@ in }; systemd.services.redis = - { description = "Redis server"; + { description = "Redis Server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix index 219c7ed958749..48bb9e4293e79 100644 --- a/nixos/modules/services/misc/disnix.nix +++ b/nixos/modules/services/misc/disnix.nix @@ -132,7 +132,7 @@ in restartIfChanged = false; - path = [ pkgs.nix pkgs.disnix dysnomia ]; + path = [ pkgs.nix pkgs.disnix dysnomia "/run/current-system/sw" ]; environment = { HOME = "/root"; diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index f231998d8f479..2da84c031a789 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -20,6 +20,8 @@ let extraGroups = [ "nixbld" ]; }; + nixbldUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers); + nixConf = let # If we're using a chroot for builds, then provide /bin/sh in @@ -357,7 +359,9 @@ in nix.nrBuildUsers = mkDefault (lib.max 10 cfg.maxJobs); - users.extraUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers); + users.extraUsers = nixbldUsers; + + services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers; system.activationScripts.nix = stringAfter [ "etc" "users" ] '' diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 8c79bf663d15d..d6babb8e9a51d 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -27,7 +27,7 @@ let [ global ] security = ${cfg.securityType} passwd program = /var/setuid-wrappers/passwd %u - pam password change = ${toString cfg.syncPasswordsByPam} + pam password change = ${if cfg.syncPasswordsByPam then "yes" else "no"} invalid users = ${toString cfg.invalidUsers} ${cfg.extraConfig} diff --git a/nixos/modules/services/network-filesystems/u9fs.nix b/nixos/modules/services/network-filesystems/u9fs.nix new file mode 100644 index 0000000000000..648097274641c --- /dev/null +++ b/nixos/modules/services/network-filesystems/u9fs.nix @@ -0,0 +1,75 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.u9fs; +in +{ + + options = { + + services.u9fs = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to run the u9fs 9P server for Unix."; + }; + + listenStreams = mkOption { + type = types.listOf types.str; + default = [ "564" ]; + example = [ "192.168.16.1:564" ]; + description = '' + Sockets to listen for clients on. + See <command>man 5 systemd.socket</command> for socket syntax. + ''; + }; + + extraArgs = mkOption { + type = types.str; + default = ""; + example = "-a none -u nobody"; + description = + '' + Extra arguments to pass on invocation, + see <command>man 4 u9fs</command> + ''; + }; + + fsroot = mkOption { + type = types.path; + default = "/"; + example = "/srv"; + description = "File system root to serve to clients."; + }; + + }; + + }; + + config = mkIf cfg.enable { + + systemd = { + sockets.u9fs = { + description = "U9fs Listening Socket"; + wantedBy = [ "sockets.target" ]; + inherit (cfg) listenStreams; + socketConfig.Accept = "yes"; + }; + services."u9fs@" = { + description = "9P Protocol Server"; + reloadIfChanged = true; + requires = [ "u9fs.socket" ]; + serviceConfig = + { ExecStart = "-${pkgs.u9fs}/bin/u9fs ${cfg.extraArgs} ${cfg.fsroot}"; + StandardInput = "socket"; + StandardError = "journal"; + }; + }; + }; + + }; + +} diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 3ae010e810704..5308fd9950855 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -178,7 +178,7 @@ in ExecReload = "${pkgs.consul}/bin/consul reload"; PermissionsStartOnly = true; User = if cfg.dropPrivileges then "consul" else null; - TimeoutStartSec = "${toString (20 + (3 * cfg.joinRetries))}s"; + TimeoutStartSec = "0"; } // (optionalAttrs (cfg.leaveOnStop) { ExecStop = "${pkgs.consul}/bin/consul leave"; }); @@ -209,13 +209,14 @@ in echo "$ADDR" } echo "{" > /etc/consul-addrs.json + delim=" " '' + concatStrings (flip mapAttrsToList cfg.interface (name: i: optionalString (i != null) '' - echo " \"${name}_addr\": \"$(getAddr "${i}")\"," >> /etc/consul-addrs.json + echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json + delim="," '')) + '' - echo " \"\": \"\"" >> /etc/consul-addrs.json echo "}" >> /etc/consul-addrs.json ''; postStart = '' diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index fbb211911f1ce..7ddabf73106e0 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -82,7 +82,7 @@ in systemd.services.dnsmasq = { description = "dnsmasq daemon"; - after = [ "network.target" "systemd-resolved.conf" ]; + after = [ "network.target" "systemd-resolved.service" ]; wantedBy = [ "multi-user.target" ]; path = [ dnsmasq ]; preStart = '' diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index f72c7fb39d6c5..3a64d3f09e025 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -71,6 +71,13 @@ let ${coreutils}/bin/rm -f $tmp $tmp.ns ''; + # pre-up and pre-down hooks were added in NM 0.9.10, but we still use 0.9.0 + dispatcherTypesSubdirMap = { + "basic" = ""; + /*"pre-up" = "pre-up.d/"; + "pre-down" = "pre-down.d/";*/ + }; + in { ###### interface @@ -118,6 +125,30 @@ in { ''; }; + dispatcherScripts = mkOption { + type = types.listOf (types.submodule { + options = { + source = mkOption { + type = types.str; + description = '' + A script source. + ''; + }; + + type = mkOption { + type = types.enum (attrNames dispatcherTypesSubdirMap); + default = "basic"; + description = '' + Dispatcher hook type. Only basic hooks are currently available. + ''; + }; + }; + }); + default = []; + description = '' + A list of scripts which will be executed in response to network events. + ''; + }; }; }; @@ -155,7 +186,11 @@ in { ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == []) { source = overrideNameserversScript; target = "NetworkManager/dispatcher.d/02overridedns"; - }; + } + ++ lib.imap (i: s: { + text = s.source; + target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; + }) cfg.dispatcherScripts; environment.systemPackages = cfg.packages ++ [ networkmanager_openvpn diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index c0ad9e17c4130..b11f996c63cf9 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -195,12 +195,14 @@ in default = [ { path = "/etc/ssh/ssh_host_dsa_key"; type = "dsa"; - bits = 1024; } { path = "/etc/ssh/ssh_host_ecdsa_key"; type = "ecdsa"; bits = 521; } + { path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } ]; description = '' NixOS can automatically generate SSH host keys. This option @@ -323,7 +325,7 @@ in ${flip concatMapStrings cfg.hostKeys (k: '' if ! [ -f "${k.path}" ]; then - ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" + ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N "" fi '')} ''; @@ -379,6 +381,8 @@ in UsePAM yes + UsePrivilegeSeparation sandbox + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} ${concatMapStrings (port: '' Port ${toString port} diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix index c40f41e07d4fc..6288b1b3ba863 100644 --- a/nixos/modules/services/security/fail2ban.nix +++ b/nixos/modules/services/security/fail2ban.nix @@ -95,7 +95,7 @@ in environment.etc."fail2ban/filter.d".source = "${pkgs.fail2ban}/etc/fail2ban/filter.d/*.conf"; systemd.services.fail2ban = - { description = "Fail2ban intrusion prevention system"; + { description = "Fail2ban Intrusion Prevention System"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 1b38ea3b679be..135113b3ceb14 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -9,28 +9,16 @@ let homeDir = "/var/lib/transmission"; downloadDir = "${homeDir}/Downloads"; incompleteDir = "${homeDir}/.incomplete"; + settingsDir = "${homeDir}/.config/transmission-daemon"; - settingsFile = "${settingsDir}/settings.json"; + settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings); # Strings must be quoted, ints and bools must not (for settings.json). toOption = x: if x == true then "true" else if x == false then "false" else if isInt x then toString x - else toString ''\"${x}\"''; - - # All lines in settings.json end with a ',' (comma), except for the last - # line. This is standard JSON. But a comma can also appear *inside* some - # fields, notably the "rpc-whitelist" field. This is difficult to handle in - # sed so we simply ignore it and say that if you want to change the option at - # the last line of settings.json, you have to do it manually. At this time of - # writing, the last option is "utp-enable":true. - attrsToSedArgs = as: - concatStrings (concatLists (mapAttrsToList (name: value: - #map (x: '' -e 's=\(\"${name}\":\)[^,]*\(.*\)=\1 ${toOption x}\2=' '') # breaks if comma inside value field - map (x: '' -e 's=\(\"${name}\":\).*=\1 ${toOption x},=' '') # always append ',' (breaks last line in settings.json) - (if isList value then value else [value])) - as)); + else toString ''"${x}"''; # for users in group "transmission" to have access to torrents fullSettings = cfg.settings // { umask = 2; }; @@ -73,7 +61,7 @@ in boolean values must not. See https://trac.transmissionbt.com/wiki/EditConfigFiles for - documentation and/or look at ${settingsFile}. + documentation. ''; }; @@ -95,7 +83,7 @@ in # 1) Only the "transmission" user and group have access to torrents. # 2) Optionally update/force specific fields into the configuration file. serviceConfig.ExecStartPre = '' - ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && ${pkgs.transmission}/bin/transmission-daemon -d |& sed ${attrsToSedArgs fullSettings} > ${settingsFile}.tmp && mv ${settingsFile}.tmp ${settingsFile}" + ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && rm -f ${settingsDir}/settings.json && cp -f ${settingsFile} ${settingsDir}/settings.json" ''; serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port}"; serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 6a830827fd783..2b5cba68d457a 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -171,6 +171,9 @@ let SSLRandomSeed startup builtin SSLRandomSeed connect builtin + + SSLProtocol All -SSLv2 -SSLv3 + SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!EXP ''; diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix index 7e91e7b60eef3..2c5e433003c8c 100644 --- a/nixos/modules/services/web-servers/fcgiwrap.nix +++ b/nixos/modules/services/web-servers/fcgiwrap.nix @@ -4,7 +4,6 @@ with lib; let cfg = config.services.fcgiwrap; - in { options = { @@ -21,29 +20,53 @@ in { description = "Number of processes to prefork."; }; - bindSocket = mkOption { - type = types.string; - default = "unix:/run/fcgiwrap.sock"; - description = '' - Socket to bind to. Valid socket URLs are: - unix:/path/to/socket for Unix sockets - tcp:dot.ted.qu.ad:port for IPv4 sockets - tcp6:[ipv6_addr]:port for IPv6 sockets - ''; + socketType = mkOption { + type = types.addCheck types.str (t: t == "unix" || t == "tcp" || t == "tcp6"); + default = "unix"; + description = "Socket type: 'unix', 'tcp' or 'tcp6'."; + }; + + socketAddress = mkOption { + type = types.str; + default = "/run/fcgiwrap.sock"; + example = "1.2.3.4:5678"; + description = "Socket address. In case of a UNIX socket, this should be its filesystem path."; + }; + + user = mkOption { + type = types.nullOr types.str; + default = null; + description = "User permissions for the socket."; + }; + + group = mkOption { + type = types.nullOr types.str; + default = null; + description = "Group permissions for the socket."; }; }; }; config = mkIf cfg.enable { - systemd.services.fcgiwrap = { after = [ "nss-user-lookup.target" ]; - wantedBy = [ "multi-user.target" ]; + wantedBy = optional (cfg.socketType != "unix") "multi-user.target"; serviceConfig = { - ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} -s ${cfg.bindSocket}"; - }; + ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} ${ + if (cfg.socketType != "unix") then "-s ${cfg.socketType}:${cfg.socketAddress}" else "" + }"; + } // (if cfg.user != null && cfg.group != null then { + User = cfg.user; + Group = cfg.group; + } else { } ); }; + systemd.sockets = if (cfg.socketType == "unix") then { + fcgiwrap = { + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = cfg.socketAddress; + }; + } else { }; }; } diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 601971d27b69f..c5012dbb5e304 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -89,6 +89,10 @@ let ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1" ''} + # Tell systemd about our $DISPLAY. This is needed by the + # ssh-agent unit. + ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY + # Load X defaults. ${xorg.xrdb}/bin/xrdb -merge ${xresourcesXft} if test -e ~/.Xresources; then @@ -204,6 +208,14 @@ in description = "Shell commands executed just before the window or desktop manager is started."; }; + hiddenUsers = mkOption { + type = types.listOf types.str; + default = [ "nobody" ]; + description = '' + A list of users which will not be shown in the display manager. + ''; + }; + desktopManagerHandlesLidAndPower = mkOption { type = types.bool; default = true; diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index b3da0cda04a30..a7ebafa28b38a 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -95,15 +95,23 @@ in auth required pam_succeed_if.so uid >= 1000 quiet auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so - auth sufficient pam_unix.so nullok likeauth - auth required pam_deny.so + auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} + + ${optionalString (! config.security.pam.enableEcryptfs) + "auth required pam_deny.so"} account sufficient pam_unix.so password requisite pam_unix.so nullok sha512 + ${optionalString config.security.pam.enableEcryptfs + "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_env.so envfile=${config.system.build.pamEnvironment} session required pam_unix.so + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_loginuid.so session optional ${pkgs.systemd}/lib/security/pam_systemd.so session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start @@ -115,15 +123,22 @@ in auth required pam_succeed_if.so uid >= 1000 quiet auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so - auth sufficient pam_unix.so nullok likeauth - auth required pam_deny.so + auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} + ${optionalString (! config.security.pam.enableEcryptfs) + "auth required pam_deny.so"} account sufficient pam_unix.so password requisite pam_unix.so nullok sha512 + ${optionalString config.security.pam.enableEcryptfs + "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_env.so envfile=${config.system.build.pamEnvironment} session required pam_unix.so + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_loginuid.so session optional ${pkgs.systemd}/lib/security/pam_systemd.so session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix index 42eaacfe84afd..d0b69c5452c2c 100644 --- a/nixos/modules/services/x11/display-managers/kdm.nix +++ b/nixos/modules/services/x11/display-managers/kdm.nix @@ -38,7 +38,7 @@ let ''} [X-*-Greeter] - HiddenUsers=root,nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10 + HiddenUsers=root,${concatStringsSep "," dmcfg.hiddenUsers} PluginsLogin=${kdebase_workspace}/lib/kde4/kgreet_classic.so ${optionalString (cfg.themeDirectory != null) '' diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 98e3fd6d6a5d1..e7ddb7ff254dc 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -18,6 +18,9 @@ let exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} ''; + theme = pkgs.gnome3.gnome_themes_standard; + icons = pkgs.gnome3.gnome_icon_theme; + # The default greeter provided with this expression is the GTK greeter. # Again, we need a few things in the environment for the greeter to run with # fonts/icons. @@ -26,19 +29,16 @@ let buildInputs = [ pkgs.makeWrapper ]; buildCommand = '' - mkdir -p $out/gtk-3.0/ - - # This wrapper ensures that we actually get ?? (fonts should be OK now) + # This wrapper ensures that we actually get themes makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \ $out/greeter \ - --set XDG_DATA_DIRS ${pkgs.gnome2.gnome_icon_theme}/share \ - --set XDG_CONFIG_HOME $out/ - - # We need this to ensure that it actually tries to find icons from gnome-icon-theme - cat - > $out/gtk-3.0/settings.ini << EOF - [Settings] - gtk-icon-theme-name=gnome - EOF + --prefix PATH : "${pkgs.glibc}/bin" \ + --set GDK_PIXBUF_MODULE_FILE "$(find ${theme} -name loaders.cache)" \ + --set GTK_PATH "${theme}:${pkgs.gtk3}" \ + --set GTK_EXE_PREFIX "${theme}" \ + --set GTK_DATA_PREFIX "${theme}" \ + --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \ + --set XDG_CONFIG_HOME "${theme}/share" cat - > $out/lightdm-gtk-greeter.desktop << EOF [Desktop Entry] @@ -50,6 +50,14 @@ let ''; }; + usersConf = writeText "users.conf" + '' + [UserList] + minimum-uid=500 + hidden-users=${concatStringsSep " " dmcfg.hiddenUsers} + hidden-shells=/run/current-system/sw/sbin/nologin + ''; + lightdmConf = writeText "lightdm.conf" '' [LightDM] @@ -63,10 +71,19 @@ let greeter-session = ${cfg.greeter.name} ''; + gtkGreeterConf = writeText "lightdm-gtk-greeter.conf" + '' + [greeter] + theme-name = Adwaita + icon-theme-name = Adwaita + background = ${cfg.background} + ''; + in { options = { services.xserver.displayManager.lightdm = { + enable = mkOption { default = false; description = '' @@ -84,6 +101,14 @@ in package = wrappedGtkGreeter; }; }; + + background = mkOption { + default = "${pkgs.nixos-artwork}/gnome/Gnome_Dark.png"; + description = '' + The background image or color to use. + ''; + }; + }; }; @@ -97,10 +122,14 @@ in # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH execCmd = '' export PATH=${lightdm}/sbin:$PATH - ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run --config=${lightdmConf} + exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run ''; }; + environment.etc."lightdm/lightdm-gtk-greeter.conf".source = gtkGreeterConf; + environment.etc."lightdm/lightdm.conf".source = lightdmConf; + environment.etc."lightdm/users.conf".source = usersConf; + services.dbus.enable = true; services.dbus.packages = [ lightdm ]; @@ -109,7 +138,7 @@ in users.extraUsers.lightdm = { createHome = true; - home = "/var/lib/lightdm"; + home = "/var/lib/lightdm-data"; group = "lightdm"; uid = config.ids.uids.lightdm; }; diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix new file mode 100644 index 0000000000000..c14c13b1cba90 --- /dev/null +++ b/nixos/modules/services/x11/display-managers/sddm.nix @@ -0,0 +1,110 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + xcfg = config.services.xserver; + dmcfg = xcfg.displayManager; + cfg = dmcfg.sddm; + xEnv = config.systemd.services."display-manager".environment; + + xserverWrapper = pkgs.writeScript "xserver-wrapper" '' + #!/bin/sh + ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)} + exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} "$@" + ''; + + cfgFile = pkgs.writeText "sddm.conf" '' + [General] + HaltCommand=${pkgs.systemd}/bin/systemctl poweroff + RebootCommand=${pkgs.systemd}/bin/systemctl reboot + + [Theme] + Current=${cfg.theme} + + [Users] + MaximumUid=${toString config.ids.uids.nixbld} + HideUsers=${concatStringsSep "," dmcfg.hiddenUsers} + HideShells=/run/current-system/sw/sbin/nologin + + [XDisplay] + MinimumVT=${toString xcfg.tty} + ServerPath=${xserverWrapper} + XephyrPath=${pkgs.xorg.xorgserver}/bin/Xephyr + SessionCommand=${dmcfg.session.script} + SessionDir=${dmcfg.session.desktops} + XauthPath=${pkgs.xorg.xauth}/bin/xauth + ''; + +in +{ + options = { + + services.xserver.displayManager.sddm = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable sddm as the display manager. + ''; + }; + + theme = mkOption { + type = types.str; + default = "maui"; + description = '' + Greeter theme to use. + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + + services.xserver.displayManager.slim.enable = false; + + services.xserver.displayManager.job = { + logsXsession = true; + + #execCmd = "${pkgs.sddm}/bin/sddm"; + execCmd = "exec ${pkgs.sddm}/bin/sddm"; + }; + + security.pam.services = { + sddm = { + allowNullPassword = true; + startSession = true; + }; + + sddm-greeter.text = '' + auth required pam_succeed_if.so audit quiet_success user = sddm + auth optional pam_permit.so + + account required pam_succeed_if.so audit quiet_success user = sddm + account sufficient pam_unix.so + + password required pam_deny.so + + session required pam_succeed_if.so audit quiet_success user = sddm + session required pam_env.so envfile=${config.system.build.pamEnvironment} + session optional ${pkgs.systemd}/lib/security/pam_systemd.so + session optional pam_keyinit.so force revoke + session optional pam_permit.so + ''; + }; + + users.extraUsers.sddm = { + createHome = true; + home = "/var/lib/sddm"; + group = "sddm"; + uid = config.ids.uids.sddm; + }; + + environment.etc."sddm.conf".source = cfgFile; + + users.extraGroups.sddm.gid = config.ids.gids.sddm; + + }; +} diff --git a/nixos/modules/services/x11/hardware/multitouch.nix b/nixos/modules/services/x11/hardware/multitouch.nix index 6e6e88e672180..f8386b5e333bf 100644 --- a/nixos/modules/services/x11/hardware/multitouch.nix +++ b/nixos/modules/services/x11/hardware/multitouch.nix @@ -2,9 +2,15 @@ with lib; -let cfg = config.services.xserver.multitouch; in - -{ +let cfg = config.services.xserver.multitouch; + disabledTapConfig = '' + Option "MaxTapTime" "0" + Option "MaxTapMove" "0" + Option "TapButton1" "0" + Option "TapButton2" "0" + Option "TapButton3" "0" + ''; +in { options = { @@ -30,6 +36,33 @@ let cfg = config.services.xserver.multitouch; in description = "Whether to ignore touches detected as being the palm (i.e when typing)"; }; + tapButtons = mkOption { + type = types.bool; + default = true; + example = false; + description = "Whether to enable tap buttons."; + }; + + buttonsMap = mkOption { + type = types.listOf types.int; + default = [3 2 0]; + example = [1 3 2]; + description = "Remap touchpad buttons."; + apply = map toString; + }; + + additionalOptions = mkOption { + type = types.str; + default = ""; + example = '' + Option "ScaleDistance" "50" + Option "RotateDistance" "60" + ''; + description = '' + Additional options for mtrack touchpad driver. + ''; + }; + }; }; @@ -46,12 +79,17 @@ let cfg = config.services.xserver.multitouch; in Identifier "Touchpads" Driver "mtrack" Option "IgnorePalm" "${if cfg.ignorePalm then "true" else "false"}" + Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}" + Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}" + Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}" + ${optionalString (!cfg.tapButtons) disabledTapConfig} ${optionalString cfg.invertScroll '' Option "ScrollUpButton" "5" Option "ScrollDownButton" "4" Option "ScrollLeftButton" "7" Option "ScrollRightButton" "6" ''} + ${cfg.additionalOptions} EndSection ''; diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix new file mode 100644 index 0000000000000..556d9e187fddf --- /dev/null +++ b/nixos/modules/services/x11/unclutter.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: +with lib; +let cfg = config.services.unclutter; +in { + options = { + services.unclutter.enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable unclutter to hide your mouse cursor when inactive"; + }; + + services.unclutter.arguments = mkOption { + description = "Arguments to pass to unclutter command"; + default = "-idle 1"; + type = types.uniq types.string; + }; + }; + + config = mkIf cfg.enable { + systemd.services.unclutter = { + description = "unclutter"; + requires = [ "display-manager.service" ]; + after = [ "display-manager.service" ]; + wantedBy = [ "graphical.target" ]; + serviceConfig.ExecStart = '' + ${pkgs.unclutter}/bin/unclutter ${cfg.arguments} + ''; + environment = { DISPLAY = ":0"; }; + serviceConfig.Restart = "always"; + }; + }; +} diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 628d475c96842..97cc198137c41 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -8,8 +8,10 @@ in { imports = [ + ./afterstep.nix ./bspwm.nix ./compiz.nix + ./fluxbox.nix ./herbstluftwm.nix ./i3.nix ./metacity.nix diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index dbe13c022f09e..ce36bac2bdcf8 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -9,19 +9,21 @@ use Cwd 'abs_path'; my $out = "@out@"; +# To be robust against interruption, record what units need to be started etc. my $startListFile = "/run/systemd/start-list"; my $restartListFile = "/run/systemd/restart-list"; my $reloadListFile = "/run/systemd/reload-list"; my $action = shift @ARGV; -if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test")) { +if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) { print STDERR <<EOF; Usage: $0 [switch|boot|test] -switch: make the configuration the boot default and activate now -boot: make the configuration the boot default -test: activate the configuration, but don\'t make it the boot default +switch: make the configuration the boot default and activate now +boot: make the configuration the boot default +test: activate the configuration, but don\'t make it the boot default +dry-activate: show what would be done if this configuration were activated EOF exit 1; } @@ -56,8 +58,6 @@ EOF exit 100; } -syslog(LOG_NOTICE, "switching to system configuration $out"); - # Ignore SIGHUP so that we're not killed if we're running on (say) # virtual console 1 and we restart the "tty1" unit. $SIG{PIPE} = "IGNORE"; @@ -116,6 +116,11 @@ sub boolIsTrue { return $s eq "yes" || $s eq "true"; } +sub recordUnit { + my ($fn, $unit) = @_; + write_file($fn, { append => 1 }, "$unit\n") if $action ne "dry-activate"; +} + # As a fingerprint for determining whether a unit has changed, we use # its absolute path. If it has an override file, we append *its* # absolute path as well. @@ -124,9 +129,20 @@ sub fingerprintUnit { return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : ""); } -# Stop all services that no longer exist or have changed in the new -# configuration. -my (@unitsToStop, @unitsToSkip); +# Figure out what units need to be stopped, started, restarted or reloaded. +my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload); + +my %unitsToFilter; # units not shown + +$unitsToStart{$_} = 1 foreach + split('\n', read_file($startListFile, err_mode => 'quiet') // ""); + +$unitsToRestart{$_} = 1 foreach + split('\n', read_file($restartListFile, err_mode => 'quiet') // ""); + +$unitsToReload{$_} = 1 foreach + split '\n', read_file($reloadListFile, err_mode => 'quiet') // ""; + my $activePrev = getActiveUnits; while (my ($unit, $state) = each %{$activePrev}) { my $baseUnit = $unit; @@ -141,7 +157,7 @@ while (my ($unit, $state) = each %{$activePrev}) { if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) { if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") { - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } elsif ($unit =~ /\.target$/) { @@ -155,7 +171,10 @@ while (my ($unit, $state) = each %{$activePrev}) { # should not be the case. Just ignore it. if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") { unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) { - write_file($startListFile, { append => 1 }, "$unit\n"); + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); + # Don't spam the user with target units that always get started. + $unitsToFilter{$unit} = 1; } } @@ -171,7 +190,7 @@ while (my ($unit, $state) = each %{$activePrev}) { # (unless there is a PartOf dependency), so this is just a # bookkeeping thing to get systemd to do the right thing. if (boolIsTrue($unitInfo->{'X-StopOnReconfiguration'} // "no")) { - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } } @@ -180,16 +199,18 @@ while (my ($unit, $state) = each %{$activePrev}) { # Do nothing. These cannot be restarted directly. } elsif ($unit =~ /\.mount$/) { # Reload the changed mount unit to force a remount. - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) { # FIXME: do something? } else { my $unitInfo = parseUnit($newUnitFile); if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) { - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") ) { - push @unitsToSkip, $unit; + $unitsToSkip{$unit} = 1; } else { # If this unit is socket-activated, then stop the # socket unit(s) as well, and restart the @@ -202,8 +223,9 @@ while (my ($unit, $state) = each %{$activePrev}) { } foreach my $socket (@sockets) { if (defined $activePrev->{$socket}) { - push @unitsToStop, $socket; - write_file($startListFile, { append => 1 }, "$socket\n"); + $unitsToStop{$unit} = 1; + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $socket); $socketActivated = 1; } } @@ -213,7 +235,8 @@ while (my ($unit, $state) = each %{$activePrev}) { # This unit should be restarted instead of # stopped and started. - write_file($restartListFile, { append => 1 }, "$unit\n"); + $unitsToRestart{$unit} = 1; + recordUnit($restartListFile, $unit); } else { @@ -222,10 +245,11 @@ while (my ($unit, $state) = each %{$activePrev}) { # We write this to a file to ensure that the # service gets restarted if we're interrupted. if (!$socketActivated) { - write_file($startListFile, { append => 1 }, "$unit\n"); + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); } - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } } @@ -268,14 +292,16 @@ foreach my $mountPoint (keys %$prevFss) { my $unit = pathToUnitName($mountPoint) . ".mount"; if (!defined $new) { # Filesystem entry disappeared, so unmount it. - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) { # Filesystem type or device changed, so unmount and mount it. - write_file($startListFile, { append => 1 }, "$unit\n"); - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); } elsif ($prev->{options} ne $new->{options}) { # Mount options changes, so remount it. - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } } @@ -294,14 +320,51 @@ foreach my $device (keys %$prevSwaps) { # FIXME: update swap options (i.e. its priority). } -if (scalar @unitsToStop > 0) { - @unitsToStop = unique(@unitsToStop); - print STDERR "stopping the following units: ", join(", ", sort(@unitsToStop)), "\n"; - system("systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors? + +# Should we have systemd re-exec itself? +my $restartSystemd = abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd"); + + +sub filterUnits { + my ($units) = @_; + my @res; + foreach my $unit (sort(keys %{$units})) { + push @res, $unit if !defined $unitsToFilter{$unit}; + } + return @res; +} + +my @unitsToStopFiltered = filterUnits(\%unitsToStop); +my @unitsToStartFiltered = filterUnits(\%unitsToStart); + + +# Show dry-run actions. +if ($action eq "dry-activate") { + print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n" + if scalar @unitsToStopFiltered > 0; + print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" + if scalar(keys %unitsToSkip) > 0; + print STDERR "would restart systemd\n" if $restartSystemd; + print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n" + if scalar(keys %unitsToRestart) > 0; + print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n" + if scalar @unitsToStartFiltered; + print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" + if scalar(keys %unitsToReload) > 0; + exit 0; +} + + +syslog(LOG_NOTICE, "switching to system configuration $out"); + +if (scalar (keys %unitsToStop) > 0) { + print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n" + if scalar @unitsToStopFiltered; + system("systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors? } -print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n" - if scalar @unitsToSkip > 0; +print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" + if scalar(keys %unitsToSkip) > 0; # Activate the new configuration (i.e., update /etc, make accounts, # and so on). @@ -310,7 +373,7 @@ print STDERR "activating the configuration...\n"; system("$out/activate", "$out") == 0 or $res = 2; # Restart systemd if necessary. -if (abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd")) { +if ($restartSystemd) { print STDERR "restarting systemd...\n"; system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2; } @@ -327,10 +390,9 @@ system("@systemd@/bin/systemctl", "reload-or-restart", "dbus.service"); # Restart changed services (those that have to be restarted rather # than stopped and started). -my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // "")); -if (scalar @restart > 0) { - print STDERR "restarting the following units: ", join(", ", sort(@restart)), "\n"; - system("@systemd@/bin/systemctl", "restart", "--", @restart) == 0 or $res = 4; +if (scalar(keys %unitsToRestart) > 0) { + print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"; + system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4; unlink($restartListFile); } @@ -340,17 +402,16 @@ if (scalar @restart > 0) { # that are symlinks to other units. We shouldn't start both at the # same time because we'll get a "Failed to add path to set" error from # systemd. -my @start = unique("default.target", "timers.target", "sockets.target", split('\n', read_file($startListFile, err_mode => 'quiet') // "")); -print STDERR "starting the following units: ", join(", ", sort(@start)), "\n"; -system("@systemd@/bin/systemctl", "start", "--", @start) == 0 or $res = 4; +print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n" + if scalar @unitsToStartFiltered; +system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4; unlink($startListFile); # Reload units that need it. This includes remounting changed mount # units. -my @reload = unique(split '\n', read_file($reloadListFile, err_mode => 'quiet') // ""); -if (scalar @reload > 0) { - print STDERR "reloading the following units: ", join(", ", sort(@reload)), "\n"; - system("@systemd@/bin/systemctl", "reload", "--", @reload) == 0 or $res = 4; +if (scalar(keys %unitsToReload) > 0) { + print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n"; + system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4; unlink($reloadListFile); } diff --git a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix index 4b5e84f53c1ac..6153578612c11 100644 --- a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix +++ b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix @@ -24,6 +24,7 @@ in enable = mkOption { default = false; + type = types.bool; description = '' Whether to create symlinks to the system generations under <literal>/boot</literal>. When enabled, @@ -42,6 +43,7 @@ in copyKernels = mkOption { default = false; + type = types.bool; description = " Whether copy the necessary boot files into /boot, so /nix/store is not needed by the boot loader. diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index a166709d39a32..585c8854feecc 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -179,6 +179,7 @@ in }; splashImage = mkOption { + type = types.nullOr types.path; example = literalExample "./my-background.png"; description = '' Background image used for GRUB. It must be a 640x480, diff --git a/nixos/modules/system/boot/loader/init-script/init-script.nix b/nixos/modules/system/boot/loader/init-script/init-script.nix index 3b33d42b4ae4e..374d9524ff1ee 100644 --- a/nixos/modules/system/boot/loader/init-script/init-script.nix +++ b/nixos/modules/system/boot/loader/init-script/init-script.nix @@ -23,6 +23,7 @@ in enable = mkOption { default = false; + type = types.bool; description = '' Some systems require a /sbin/init script which is started. Or having it makes starting NixOS easier. diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix index d3f32418a64c4..1ea3ddd8867c3 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix @@ -21,6 +21,7 @@ in boot.loader.raspberryPi.enable = mkOption { default = false; + type = types.bool; description = '' Whether to create files with the system generations in <literal>/boot</literal>. diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index a34a136026506..5af644279e5f4 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -177,20 +177,24 @@ fi if test -e /sys/power/resume -a -e /sys/power/disk; then if test -n "@resumeDevice@"; then resumeDev="@resumeDevice@" + resumeInfo="$(udevadm info -q property "$resumeDev" )" else for sd in @resumeDevices@; do # Try to detect resume device. According to Ubuntu bug: # https://bugs.launchpad.net/ubuntu/+source/pm-utils/+bug/923326/comments/1 # When there are multiple swap devices, we can't know where will hibernate # image reside. We can check all of them for swsuspend blkid. - if [ "$(udevadm info -q property "$sd" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then + resumeInfo="$(udevadm info -q property "$sd" )" + if [ "$(echo "$resumeInfo" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then resumeDev="$sd" break fi done fi - if test -n "$resumeDev"; then - readlink -f "$resumeDev" > /sys/power/resume 2> /dev/null || echo "failed to resume..." + if test -e "$resumeDev"; then + resumeMajor="$(echo "$resumeInfo" | sed -n 's/^MAJOR=//p')" + resumeMinor="$(echo "$resumeInfo" | sed -n 's/^MINOR=//p')" + echo "$resumeMajor:$resumeMinor" > /sys/power/resume 2> /dev/null || echo "failed to resume..." fi fi diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix index 03c42404e5d55..8d26998021d33 100644 --- a/nixos/modules/tasks/kbd.nix +++ b/nixos/modules/tasks/kbd.nix @@ -22,6 +22,7 @@ in # FIXME: still needed? boot.extraTTYs = mkOption { default = []; + type = types.listOf types.string; example = ["tty8" "tty9"]; description = '' Tty (virtual console) devices, in addition to the consoles on diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 70158fc7252b0..8223c5a4941e5 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -35,7 +35,10 @@ in assertions = [ { assertion = cfg.defaultGatewayWindowSize == null; message = "networking.defaultGatewayWindowSize is not supported by networkd."; - } ]; + } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { + assertion = !rstp; + message = "networking.bridges.${n}.rstp is not supported by networkd."; + }); systemd.services.dhcpcd.enable = mkDefault false; diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index c461cf8c00cb8..da39dda853535 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -10,6 +10,7 @@ let isExecutable = true; src = ./nixos-container.pl; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; + su = "${pkgs.shadow.su}/bin/su"; inherit (pkgs) utillinux; }; @@ -202,7 +203,7 @@ in script = '' mkdir -p -m 0755 "$root/etc" "$root/var/lib" - mkdir -p -m 0700 "$root/var/lib/private" "$root/root" + mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/containers if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -211,7 +212,7 @@ in "/nix/var/nix/profiles/per-container/$INSTANCE" \ "/nix/var/nix/gcroots/per-container/$INSTANCE" - cp -f /etc/resolv.conf "$root/etc/resolv.conf" + cp --remove-destination /etc/resolv.conf "$root/etc/resolv.conf" if [ "$PRIVATE_NETWORK" = 1 ]; then extraFlags+=" --network-veth" @@ -260,11 +261,21 @@ in ip route add $LOCAL_ADDRESS dev $ifaceHost fi fi + + # Get the leader PID so that we can signal it in + # preStop. We can't use machinectl there because D-Bus + # might be shutting down. FIXME: in systemd 219 we can + # just signal systemd-nspawn to do a clean shutdown. + machinectl show "$INSTANCE" | sed 's/Leader=\(.*\)/\1/;t;d' > "/run/containers/$INSTANCE.pid" ''; preStop = '' - machinectl poweroff "$INSTANCE" || true + pid="$(cat /run/containers/$INSTANCE.pid)" + if [ -n "$pid" ]; then + kill -RTMIN+4 "$pid" + fi + rm -f "/run/containers/$INSTANCE.pid" ''; restartIfChanged = false; diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 4d493b3896f24..98985d2d2c57c 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -129,10 +129,10 @@ in wantedBy = [ "sshd.service" ]; before = [ "sshd.service" ]; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; + after = [ "network-online.target" "ip-up.target" ]; + wants = [ "network-online.target" "ip-up.target" ]; - script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 6 --waitretry=10"; in + script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; in '' # When dealing with cryptographic keys, we want to keep things private. umask 077 @@ -140,7 +140,7 @@ in if ! [ -e /root/.ssh/authorized_keys ]; then echo "obtaining SSH key..." mkdir -m 0700 -p /root/.ssh - ${wget} -O /root/authorized-keys-metadata http://metadata/0.1/meta-data/authorized-keys + ${wget} -O /root/authorized-keys-metadata http://metadata.google.internal/0.1/meta-data/authorized-keys if [ $? -eq 0 -a -e /root/authorized-keys-metadata ]; then cat /root/authorized-keys-metadata | cut -d: -f2- > /root/key.pub if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then @@ -156,7 +156,7 @@ in ${flip concatMapStrings config.services.openssh.hostKeys (k : let kName = baseNameOf k.path; in '' echo "trying to obtain SSH private host key ${kName}" - ${wget} -O /root/${kName} http://metadata/0.1/meta-data/attributes/${kName} && : + ${wget} -O /root/${kName} http://metadata.google.internal/0.1/meta-data/attributes/${kName} && : if [ $? -eq 0 -a -e /root/${kName} ]; then countKeys=$((countKeys+1)) mv -f /root/${kName} ${k.path} diff --git a/nixos/modules/virtualisation/lxc.nix b/nixos/modules/virtualisation/lxc.nix index 10d3a6575fb9b..22da012e4141e 100644 --- a/nixos/modules/virtualisation/lxc.nix +++ b/nixos/modules/virtualisation/lxc.nix @@ -32,7 +32,9 @@ in default = ""; description = '' - This is the system-wide LXC config. See lxc.system.conf(5). + This is the system-wide LXC config. See + <citerefentry><refentrytitle>lxc.system.conf</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. ''; }; @@ -43,7 +45,8 @@ in description = '' Default config (default.conf) for new containers, i.e. for - network config. See lxc.container.conf(5). + network config. See <citerefentry><refentrytitle>lxc.container.conf + </refentrytitle><manvolnum>5</manvolnum></citerefentry>. ''; }; @@ -54,7 +57,9 @@ in description = '' This is the config file for managing unprivileged user network - administration access in LXC. See lxc-user-net(5). + administration access in LXC. See <citerefentry> + <refentrytitle>lxc-user-net</refentrytitle><manvolnum>5</manvolnum> + </citerefentry>. ''; }; diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl index 94edfb37948a3..1455f7143f131 100644 --- a/nixos/modules/virtualisation/nixos-container.pl +++ b/nixos/modules/virtualisation/nixos-container.pl @@ -8,6 +8,7 @@ use Fcntl ':flock'; use Getopt::Long qw(:config gnu_getopt); my $nsenter = "@utillinux@/bin/nsenter"; +my $su = "@su@"; # Ensure a consistent umask. umask 0022; @@ -271,14 +272,14 @@ elsif ($action eq "login") { } elsif ($action eq "root-login") { - runInContainer("su", "root", "-l"); + runInContainer("@su@", "root", "-l"); } elsif ($action eq "run") { shift @ARGV; shift @ARGV; # Escape command. my $s = join(' ', map { s/'/'\\''/g; "'$_'" } @ARGV); - runInContainer("su", "root", "-l", "-c", "exec " . $s); + runInContainer("@su@", "root", "-l", "-c", "exec " . $s); } elsif ($action eq "show-ip") { diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index f3a24c5cf25bc..ea9f61aad6a68 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -5,18 +5,8 @@ with lib; let - cfg = config.virtualisation.xen; - xen = pkgs.xen; - - xendConfig = pkgs.writeText "xend-config.sxp" - '' - (loglevel DEBUG) - (network-script network-bridge) - (vif-script vif-bridge) - ''; - in { @@ -58,23 +48,62 @@ in ''; }; + virtualisation.xen.bridge = + mkOption { + default = "xenbr0"; + description = + '' + Create a bridge for the Xen domUs to connect to. + ''; + }; + + virtualisation.xen.stored = + mkOption { + type = types.path; + description = + '' + Xen Store daemon to use. Defaults to oxenstored of the xen package. + ''; + }; + + virtualisation.xen.trace = + mkOption { + default = false; + description = + '' + Enable Xen tracing. + ''; + }; }; ###### implementation config = mkIf cfg.enable { + assertions = [ { + assertion = pkgs.stdenv.isx86_64; + message = "Xen currently not supported on ${pkgs.stdenv.system}"; + } { + assertion = config.boot.loader.grub.enable && (config.boot.loader.grub.efiSupport == false); + message = "Xen currently does not support EFI boot"; + } ]; + + virtualisation.xen.stored = mkDefault "${xen}/bin/oxenstored"; environment.systemPackages = [ xen ]; - # Domain 0 requires a pvops-enabled kernel. - boot.kernelPackages = pkgs.linuxPackages_3_2_xen; + # Make sure Domain 0 gets the required configuration + #boot.kernelPackages = pkgs.boot.kernelPackages.override { features={xen_dom0=true;}; }; boot.kernelModules = - [ "xen_evtchn" "xen_gntdev" "xen_blkback" "xen_netback" "xen_pciback" - "blktap" "tun" + [ "xen-evtchn" "xen-gntdev" "xen-gntalloc" "xen-blkback" "xen-netback" + "xen-pciback" "evtchn" "gntdev" "netbk" "blkbk" "xen-scsibk" + "usbbk" "pciback" "xen-acpi-processor" "blktap2" "tun" "netxen_nic" + "xen_wdt" "xen-acpi-processor" "xen-privcmd" "xen-scsiback" + "xenfs" ]; + # The radeonfb kernel module causes the screen to go black as soon # as it's loaded, so don't load it. boot.blacklistedKernelModules = [ "radeonfb" ]; @@ -87,8 +116,8 @@ in options loop max_loop=64 ''; - virtualisation.xen.bootParams = - [ "loglvl=all" "guest_loglvl=all" ] ++ + virtualisation.xen.bootParams = [] ++ + optionals cfg.trace [ "loglvl=all" "guest_loglvl=all" ] ++ optional (cfg.domain0MemorySize != 0) "dom0_mem=${toString cfg.domain0MemorySize}M"; system.extraSystemBuilderCmds = @@ -101,71 +130,36 @@ in system.activationScripts.xen = '' if [ -d /proc/xen ]; then - ${pkgs.sysvtools}/bin/mountpoint -q /proc/xen || \ + ${pkgs.kmod}/bin/modprobe xenfs 2> /dev/null + ${pkgs.utillinux}/bin/mountpoint -q /proc/xen || \ ${pkgs.utillinux}/bin/mount -t xenfs none /proc/xen fi ''; - jobs.xend = - { description = "Xen Control Daemon"; - - startOn = "stopped udevtrigger"; - - path = - [ pkgs.bridge-utils pkgs.gawk pkgs.iproute pkgs.nettools - pkgs.utillinux pkgs.bash xen pkgs.pciutils pkgs.procps - ]; - - environment.XENCONSOLED_TRACE = "hv"; - - preStart = - '' - mkdir -p /var/log/xen/console -m 0700 - - ${xen}/sbin/xend start - - # Wait until Xend is running. - for ((i = 0; i < 60; i++)); do echo "waiting for xend..."; ${xen}/sbin/xend status && break; done - - ${xen}/sbin/xend status || exit 1 - ''; - - postStop = "${xen}/sbin/xend stop"; - }; - - jobs.xendomains = - { description = "Automatically starts, saves and restores Xen domains on startup/shutdown"; - - startOn = "started xend"; - - stopOn = "starting shutdown and stopping xend"; - - restartIfChanged = false; - - path = [ pkgs.xen ]; - - environment.XENDOM_CONFIG = "${xen}/etc/sysconfig/xendomains"; - - preStart = - '' - mkdir -p /var/lock/subsys -m 755 - ${xen}/etc/init.d/xendomains start - ''; - - postStop = "${xen}/etc/init.d/xendomains stop"; - }; + # Domain 0 requires a pvops-enabled kernel. + system.requiredKernelConfig = with config.lib.kernelConfig; + [ (isYes "XEN") + (isYes "X86_IO_APIC") + (isYes "ACPI") + (isYes "XEN_DOM0") + (isYes "PCI_XEN") + (isYes "XEN_DEV_EVTCHN") + (isYes "XENFS") + (isYes "XEN_COMPAT_XENFS") + (isYes "XEN_SYS_HYPERVISOR") + (isYes "XEN_GNTDEV") + (isYes "XEN_BACKEND") + (isModule "XEN_NETDEV_BACKEND") + (isModule "XEN_BLKDEV_BACKEND") + (isModule "XEN_PCIDEV_BACKEND") + (isYes "XEN_BALLOON") + (isYes "XEN_SCRUB_PAGES") + ]; - # To prevent a race between dhcpcd and xend's bridge setup script - # (which renames eth* to peth* and recreates eth* as a virtual - # device), start dhcpcd after xend. - jobs.dhcpcd.startOn = mkOverride 50 "started xend"; environment.etc = - [ { source = xendConfig; - target = "xen/xend-config.sxp"; - } - { source = "${xen}/etc/xen/scripts"; - target = "xen/scripts"; + [ { source = "${xen}/etc/xen/xl.conf"; + target = "xen/xl.conf"; } ]; @@ -174,6 +168,125 @@ in services.udev.path = [ pkgs.bridge-utils pkgs.iproute ]; + systemd.services.xen-store = { + description = "Xen Store Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "xen-store.socket" ]; + requires = [ "xen-store.socket" ]; + preStart = '' + export XENSTORED_ROOTDIR="/var/lib/xenstored" + rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null + + mkdir -p /var/run + ${optionalString cfg.trace "mkdir -p /var/log/xen"} + grep -q control_d /proc/xen/capabilities + ''; + serviceConfig.ExecStart = '' + ${cfg.stored}${optionalString cfg.trace " -T /var/log/xen/xenstored-trace.log"} --no-fork + ''; + postStart = '' + time=0 + timeout=30 + # Wait for xenstored to actually come up, timing out after 30 seconds + while [ $time -lt $timeout ] && ! `${pkgs.xen}/bin/xenstore-read -s / >/dev/null 2>&1` ; do + time=$(($time+1)) + sleep 1 + done + + # Exit if we timed out + if ! [ $time -lt $timeout ] ; then + echo "Could not start Xenstore Daemon" + exit 1 + fi + + ${pkgs.xen}/bin/xenstore-write "/local/domain/0/name" "Domain-0" + ${pkgs.xen}/bin/xenstore-write "/local/domain/0/domid" 0 + ''; + }; + + systemd.sockets.xen-store = { + description = "XenStore Socket for userspace API"; + wantedBy = [ "sockets.target" ]; + socketConfig = { + ListenStream = [ "/var/run/xenstored/socket" "/var/run/xenstored/socket_ro" ]; + SocketMode = "0660"; + SocketUser = "root"; + SocketGroup = "root"; + }; + }; + + + systemd.services.xen-console = { + description = "Xen Console Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-store.service" ]; + preStart = '' + mkdir -p /var/run/xen + ${optionalString cfg.trace "mkdir -p /var/log/xen"} + grep -q control_d /proc/xen/capabilities + ''; + serviceConfig = { + ExecStart = '' + ${pkgs.xen}/bin/xenconsoled${optionalString cfg.trace " --log=all --log-dir=/var/log/xen"} + ''; + }; + }; + + + systemd.services.xen-qemu = { + description = "Xen Qemu Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-console.service" ]; + serviceConfig.ExecStart = '' + ${pkgs.xen}/lib/xen/bin/qemu-system-i386 -xen-domid 0 -xen-attach -name dom0 -nographic -M xenpv \ + -monitor /dev/null -serial /dev/null -parallel /dev/null + ''; + }; + + + systemd.services.xen-watchdog = { + description = "Xen Watchdog Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-qemu.service" ]; + serviceConfig.ExecStart = "${pkgs.xen}/bin/xenwatchdogd 30 15"; + serviceConfig.Type = "forking"; + serviceConfig.RestartSec = "1"; + serviceConfig.Restart = "on-failure"; + }; + + + systemd.services.xen-bridge = { + description = "Xen bridge"; + wantedBy = [ "multi-user.target" ]; + before = [ "xen-domains.service" ]; + serviceConfig.RemainAfterExit = "yes"; + serviceConfig.ExecStart = '' + ${pkgs.bridge-utils}/bin/brctl addbr ${cfg.bridge} + ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} up + ''; + serviceConfig.ExecStop = '' + ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} down + ${pkgs.bridge-utils}/bin/brctl delbr ${cfg.bridge} + ''; + }; + + systemd.services.xen-domains = { + description = "Xen domains - automatically starts, saves and restores Xen domains"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-bridge.service" "xen-qemu.service" ]; + ## To prevent a race between dhcpcd and xend's bridge setup script + ## (which renames eth* to peth* and recreates eth* as a virtual + ## device), start dhcpcd after xend. + before = [ "dhcpd.service" ]; + restartIfChanged = false; + serviceConfig.RemainAfterExit = "yes"; + path = [ pkgs.xen ]; + environment.XENDOM_CONFIG = "${pkgs.xen}/etc/sysconfig/xendomains"; + preStart = "mkdir -p /var/lock/subsys -m 755"; + serviceConfig.ExecStart = "${pkgs.xen}/etc/init.d/xendomains start"; + serviceConfig.ExecStop = "${pkgs.xen}/etc/init.d/xendomains stop"; + }; + }; } diff --git a/nixos/modules/virtualisation/xen-domU.nix b/nixos/modules/virtualisation/xen-domU.nix index 4835896693456..2db3190ad139d 100644 --- a/nixos/modules/virtualisation/xen-domU.nix +++ b/nixos/modules/virtualisation/xen-domU.nix @@ -9,7 +9,10 @@ boot.loader.grub.device = "nodev"; boot.loader.grub.extraPerEntryConfig = "root (hd0)"; - boot.initrd.kernelModules = [ "xen-blkfront" ]; + boot.initrd.kernelModules = + [ "xen-blkfront" "xen-tpmfront" "xen-kbdfront" "xen-fbfront" + "xen-netfront" "xen-pcifront" "xen-scsifront" + ]; # Send syslog messages to the Xen console. services.syslogd.tty = "hvc0"; diff --git a/nixos/release.nix b/nixos/release.nix index 1bd3ec5773189..cc451f7fe15bc 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -244,7 +244,7 @@ in rec { tests.blivet = callTest tests/blivet.nix {}; tests.cadvisor = scrubDrv (import tests/cadvisor.nix { system = "x86_64-linux"; }); tests.chromium = callTest tests/chromium.nix {}; - tests.cjdns = callTest tests/cjdns.nix {}; + #tests.cjdns = callTest tests/cjdns.nix {}; tests.containers = callTest tests/containers.nix {}; tests.docker = scrubDrv (import tests/docker.nix { system = "x86_64-linux"; }); tests.dockerRegistry = scrubDrv (import tests/docker-registry.nix { system = "x86_64-linux"; }); @@ -254,6 +254,7 @@ in rec { tests.fleet = scrubDrv (import tests/fleet.nix { system = "x86_64-linux"; }); #tests.gitlab = callTest tests/gitlab.nix {}; tests.gnome3 = callTest tests/gnome3.nix {}; + tests.i3wm = callTest tests/i3wm.nix {}; tests.installer.grub1 = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).grub1.test); tests.installer.lvm = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).lvm.test); tests.installer.rebuildCD = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).rebuildCD.test); diff --git a/nixos/tests/i3wm.nix b/nixos/tests/i3wm.nix new file mode 100644 index 0000000000000..0966dba8a3c89 --- /dev/null +++ b/nixos/tests/i3wm.nix @@ -0,0 +1,28 @@ +import ./make-test.nix { + name = "i3wm"; + + machine = { lib, pkgs, ... }: { + imports = [ ./common/x11.nix ./common/user-account.nix ]; + services.xserver.displayManager.auto.user = "alice"; + services.xserver.windowManager.default = lib.mkForce "i3"; + services.xserver.windowManager.i3.enable = true; + }; + + testScript = { nodes, ... }: '' + $machine->waitForX; + $machine->waitForWindow(qr/first configuration/); + $machine->sleep(1); + $machine->screenshot("started"); + $machine->sendKeys("ret"); + $machine->sleep(1); + $machine->sendKeys("alt"); + $machine->sleep(1); + $machine->screenshot("configured"); + $machine->sendKeys("ret"); + $machine->sleep(2); + $machine->sendKeys("alt-ret"); + $machine->waitForWindow(qr/machine.*alice/); + $machine->sleep(1); + $machine->screenshot("terminal"); + ''; +} |