Merge remote-tracking branch 'origin/systemd'

This commit is contained in:
Eelco Dolstra 2013-01-21 12:45:50 +01:00
commit 1aaa726e75
152 changed files with 4123 additions and 3176 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*~
.version-suffix

View File

@ -1 +1 @@
0.1
0.2

View File

@ -0,0 +1,173 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-configuration">
<title>Configuring NixOS</title>
<para>This chapter describes how to configure various aspects of a
NixOS machine through the configuration file
<filename>/etc/nixos/configuration.nix</filename>. As described in
<xref linkend="sec-changing-config" />, changes to that file only take
effect after you run <command>nixos-rebuild</command>.</para>
<!--===============================================================-->
<section><title>Networking</title>
<section><title>Secure shell access</title>
<para>Secure shell (SSH) access to your machine can be enabled by
setting:
<programlisting>
services.openssh.enable = true;
</programlisting>
By default, root logins using a password are disallowed. They can be
disabled entirely by setting
<literal>services.openssh.permitRootLogin</literal> to
<literal>"no"</literal>.</para>
<para>You can declaratively specify authorised RSA/DSA public keys for
a user as follows:
<!-- FIXME: this might not work if the user is unmanaged. -->
<programlisting>
users.extraUsers.alice.openssh.authorizedKeys.keys =
[ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ];
</programlisting>
</para>
</section>
<section><title>IPv4 configuration</title>
<para>By default, NixOS uses DHCP (specifically,
(<command>dhcpcd</command>)) to automatically configure network
interfaces. However, you can configure an interface manually as
follows:
<programlisting>
networking.interfaces.eth0 = { ipAddress = "192.168.1.2"; prefixLength = 24; };
</programlisting>
(The network prefix can also be specified using the option
<literal>subnetMask</literal>,
e.g. <literal>"255.255.255.0"</literal>, but this is deprecated.)
Typically youll also want to set a default gateway and set of name
servers:
<programlisting>
networking.defaultGateway = "192.168.1.1";
networking.nameservers = [ "8.8.8.8" ];
</programlisting>
</para>
<note><para>Statically configured interfaces are set up by the systemd
service
<replaceable>interface-name</replaceable><literal>-cfg.service</literal>.
The default gateway and name server configuration is performed by
<literal>network-setup.service</literal>.</para></note>
<para>The host name is set using <option>networking.hostName</option>:
<programlisting>
networking.hostName = "cartman";
</programlisting>
The default host name is <literal>nixos</literal>. Set it to the
empty string (<literal>""</literal>) to allow the DHCP server to
provide the host name.</para>
</section>
<section><title>IPv6 configuration</title>
<para>IPv6 is enabled by default. Stateless address autoconfiguration
is used to automatically assign IPv6 addresses to all interfaces. You
can disable IPv6 support globally by setting:
<programlisting>
networking.enableIPv6 = false;
</programlisting>
</para>
</section>
<section><title>Firewall</title>
<para>NixOS has a simple stateful firewall that blocks incoming
connections and other unexpected packets. The firewall applies to
both IPv4 and IPv6 traffic. It can be enabled as follows:
<programlisting>
networking.firewall.enable = true;
</programlisting>
You can open specific TCP ports to the outside world:
<programlisting>
networking.firewall.allowedTCPPorts = [ 80 443 ];
</programlisting>
Note that TCP port 22 (ssh) is opened automatically if the SSH daemon
is enabled (<option>services.openssh.enable = true</option>). UDP
ports can be opened through
<option>networking.firewall.allowedUDPPorts</option>. Also of
interest is
<programlisting>
networking.firewall.allowPing = true;
</programlisting>
to allow the machine to respond to ping requests. (ICMPv6 pings are
always allowed.)</para>
</section>
<section><title>Wireless networks</title>
<para>TODO</para>
</section>
<section><title>Ad-hoc configuration</title>
<para>You can use <option>networking.localCommands</option> to specify
shell commands to be run at the end of
<literal>network-setup.service</literal>. This is useful for doing
network configuration not covered by the existing NixOS modules. For
instance, to statically configure an IPv6 address:
<programlisting>
networking.localCommands =
''
ip -6 addr add 2001:610:685:1::1/64 dev eth0
'';
</programlisting>
</para>
</section>
<!-- TODO: OpenVPN, NAT -->
</section>
<!-- TODO: declarative package installation; X11; user management;
Apache; libvirtd virtualisation -->
</chapter>

View File

@ -59,7 +59,7 @@ in rec {
mkdir -p $dst/images/callouts
cp ${pkgs.docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/
cp ${./style.css} $dst/style.css
ensureDir $out/nix-support

View File

@ -1,7 +1,7 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Installation</title>
<title>Installing NixOS</title>
<!--===============================================================-->
@ -58,7 +58,7 @@ Wiki</link>.</para>
<listitem><para>For partitioning:
<command>fdisk</command>.</para></listitem>
<listitem><para>For initialising Ext4 partitions:
<command>mkfs.ext4</command>. It is recommended that you assign a
unique symbolic label to the file system using the option
@ -70,13 +70,13 @@ Wiki</link>.</para>
<command>mkswap</command>. Again its recommended to assign a
label to the swap partition: <option>-L
<replaceable>label</replaceable></option>.</para></listitem>
<listitem><para>For creating LVM volumes, the LVM commands, e.g.,
<screen>
$ pvcreate /dev/sda1 /dev/sdb1
$ vgcreate MyVolGroup /dev/sda1 /dev/sdb1
$ lvcreate --size 2G --name bigdisk MyVolGroup
$ lvcreate --size 2G --name bigdisk MyVolGroup
$ lvcreate --size 1G --name smalldisk MyVolGroup</screen>
</para></listitem>
@ -87,7 +87,7 @@ $ lvcreate --size 1G --name smalldisk MyVolGroup</screen>
</itemizedlist>
</para></listitem>
<listitem><para>Mount the target file system on which NixOS should
be installed on <filename>/mnt</filename>.</para></listitem>
@ -138,7 +138,7 @@ $ nixos-option --install</screen>
xlink:href="https://nixos.org/repos/nix/configurations/trunk/"/>.</para>
</listitem>
<listitem><para>If your machine has a limited amount of memory, you
may want to activate swap devices now (<command>swapon
<replaceable>device</replaceable></command>). The installer (or
@ -230,15 +230,11 @@ $ reboot</screen>
{
boot.loader.grub.device = "/dev/sda";
fileSystems =
[ { mountPoint = "/";
device = "/dev/disk/by-label/nixos";
}
];
fileSystems."/".device = "/dev/disk/by-label/nixos";
swapDevices =
[ { device = "/dev/disk/by-label/swap"; } ];
services.sshd.enable = true;
}</screen>
</example>
@ -264,7 +260,7 @@ to build the new configuration, make it the default configuration for
booting, and try to realise the configuration in the running system
(e.g., by restarting system services).</para>
<para>You can also do
<para>You can also do
<screen>
$ nixos-rebuild test</screen>
@ -274,7 +270,7 @@ without making it the boot default. So if (say) the configuration
locks up your machine, you can just reboot to get back to a working
configuration.</para>
<para>There is also
<para>There is also
<screen>
$ nixos-rebuild boot</screen>
@ -283,7 +279,7 @@ to build the configuration and make it the boot default, but not
switch to it now (so it will only take effect after the next
reboot).</para>
<para>Finally, you can do
<para>Finally, you can do
<screen>
$ nixos-rebuild build</screen>
@ -333,7 +329,7 @@ You can then upgrade NixOS to the latest version in the channel by
running
<screen>
$ nix-channel --update
$ nix-channel --update nixos
</screen>
and running the <command>nixos-rebuild</command> command as described

View File

@ -24,16 +24,16 @@
<year>2007-2012</year>
<holder>Eelco Dolstra</holder>
</copyright>
</info>
<preface>
<title>Preface</title>
<para>This manual describes NixOS, a Linux distribution based on
the purely functional package management system Nix.</para>
<para>NixOS is rather bleeding edge, and this manual is
correspondingly sketchy and quite possibly out of date. It gives
basic information on how to get NixOS up and running, but since
@ -45,11 +45,13 @@
mailing list or on <link
xlink:href="irc://irc.freenode.net/#nixos">the
<literal>#nixos</literal> channel on Freenode.</link>.</para>
</preface>
<xi:include href="installation.xml" />
<xi:include href="configuration.xml" />
<xi:include href="running.xml" />
<!-- <xi:include href="userconfiguration.xml" /> -->
<xi:include href="troubleshooting.xml" />
<xi:include href="development.xml" />

288
doc/manual/running.xml Normal file
View File

@ -0,0 +1,288 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-running">
<title>Running NixOS</title>
<para>This chapter describes various aspects of managing a running
NixOS system, such as how to use the <command>systemd</command>
service manager.</para>
<!--===============================================================-->
<section><title>Service management</title>
<para>In NixOS, all system services are started and monitored using
the systemd program. Systemd is the “init” process of the system
(i.e. PID 1), the parent of all other processes. It manages a set of
so-called “units”, which can be things like system services
(programs), but also mount points, swap files, devices, targets
(groups of units) and more. Units can have complex dependencies; for
instance, one unit can require that another unit must be succesfully
started before the first unit can be started. When the system boots,
it starts a unit named <literal>default.target</literal>; the
dependencies of this unit cause all system services to be started,
filesystems to be mounted, swap files to be activated, and so
on.</para>
<para>The command <command>systemctl</command> is the main way to
interact with <command>systemd</command>. Without any arguments, it
shows the status of active units:
<screen>
$ systemctl
-.mount loaded active mounted /
swapfile.swap loaded active active /swapfile
sshd.service loaded active running SSH Daemon
graphical.target loaded active active Graphical Interface
<replaceable>...</replaceable>
</screen>
</para>
<para>You can ask for detailed status information about a unit, for
instance, the PostgreSQL database service:
<screen>
$ systemctl status postgresql.service
postgresql.service - PostgreSQL Server
Loaded: loaded (/nix/store/pn3q73mvh75gsrl8w7fdlfk3fq5qm5mw-unit/postgresql.service)
Active: active (running) since Mon, 2013-01-07 15:55:57 CET; 9h ago
Main PID: 2390 (postgres)
CGroup: name=systemd:/system/postgresql.service
├─2390 postgres
├─2418 postgres: writer process
├─2419 postgres: wal writer process
├─2420 postgres: autovacuum launcher process
├─2421 postgres: stats collector process
└─2498 postgres: zabbix zabbix [local] idle
Jan 07 15:55:55 hagbard postgres[2394]: [1-1] LOG: database system was shut down at 2013-01-07 15:55:05 CET
Jan 07 15:55:57 hagbard postgres[2390]: [1-1] LOG: database system is ready to accept connections
Jan 07 15:55:57 hagbard postgres[2420]: [1-1] LOG: autovacuum launcher started
Jan 07 15:55:57 hagbard systemd[1]: Started PostgreSQL Server.
</screen>
Note that this shows the status of the unit (active and running), all
the processes belonging to the service, as well as the most recent log
messages from the service.
</para>
<para>Units can be stopped, started or restarted:
<screen>
$ systemctl stop postgresql.service
$ systemctl start postgresql.service
$ systemctl restart postgresql.service
</screen>
These operations are synchronous: they wait until the service has
finished starting or stopping (or has failed). Starting a unit will
cause the dependencies of that unit to be started as well (if
necessary).</para>
<!-- - cgroups: each service and user session is a cgroup
- cgroup resource management -->
</section>
<!--===============================================================-->
<section><title>Rebooting and shutting down</title>
<para>The system can be shut down (and automatically powered off) by
doing:
<screen>
$ shutdown
</screen>
This is equivalent to running <command>systemctl poweroff</command>.
Likewise, <command>reboot</command> (a.k.a. <command>systemctl
reboot</command>) will reboot the system.</para>
<para>The machine can be suspended to RAM (if supported) using
<command>systemctl suspend</command>, and suspended to disk using
<command>systemctl hibernate</command>.</para>
<para>These commands can be run by any user who is logged in locally,
i.e. on a virtual console or in X11; otherwise, the user is asked for
authentication.</para>
</section>
<!--===============================================================-->
<section><title>User sessions</title>
<para>Systemd keeps track of all users who are logged into the system
(e.g. on a virtual console or remotely via SSH). The command
<command>loginctl</command> allows quering and manipulating user
sessions. For instance, to list all user sessions:
<screen>
$ loginctl
SESSION UID USER SEAT
c1 500 eelco seat0
c3 0 root seat0
c4 500 alice
</screen>
This shows that two users are logged in locally, while another is
logged in remotely. (“Seats” are essentially the combinations of
displays and input devices attached to the system; usually, there is
only one seat.) To get information about a session:
<screen>
$ loginctl session-status c3
c3 - root (0)
Since: Tue, 2013-01-08 01:17:56 CET; 4min 42s ago
Leader: 2536 (login)
Seat: seat0; vc3
TTY: /dev/tty3
Service: login; type tty; class user
State: online
CGroup: name=systemd:/user/root/c3
├─ 2536 /nix/store/10mn4xip9n7y9bxqwnsx7xwx2v2g34xn-shadow-4.1.5.1/bin/login --
├─10339 -bash
└─10355 w3m nixos.org
</screen>
This shows that the user is logged in on virtual console 3. It also
lists the processes belonging to this session. Since systemd keeps
track of this, you can terminate a session in a way that ensures that
all the sessions processes are gone:
<screen>
$ loginctl terminate-session c3
</screen>
</para>
</section>
<!--===============================================================-->
<section><title>Control groups</title>
<para>To keep track of the processes in a running system, systemd uses
<emphasis>control groups</emphasis> (cgroups). A control group is a
set of processes used to allocate resources such as CPU, memory or I/O
bandwidth. There can be multiple control group hierarchies, allowing
each kind of resource to be managed independently.</para>
<para>The command <command>systemd-cgls</command> lists all control
groups in the <literal>systemd</literal> hierarchy, which is what
systemd uses to keep track of the processes belonging to each service
or user session:
<screen>
$ systemd-cgls
├─user
│ └─eelco
│ └─c1
│ ├─ 2567 -:0
│ ├─ 2682 kdeinit4: kdeinit4 Running...
│ ├─ <replaceable>...</replaceable>
│ └─10851 sh -c less -R
└─system
├─httpd.service
│ ├─2444 httpd -f /nix/store/3pyacby5cpr55a03qwbnndizpciwq161-httpd.conf -DNO_DETACH
│ └─<replaceable>...</replaceable>
├─dhcpcd.service
│ └─2376 dhcpcd --config /nix/store/f8dif8dsi2yaa70n03xir8r653776ka6-dhcpcd.conf
└─ <replaceable>...</replaceable>
</screen>
Similarly, <command>systemd-cgls cpu</command> shows the cgroups in
the CPU hierarchy, which allows per-cgroup CPU scheduling priorities.
By default, every systemd service gets its own CPU cgroup, while all
user sessions are in the top-level CPU cgroup. This ensures, for
instance, that a thousand run-away processes in the
<literal>httpd.service</literal> cgroup cannot starve the CPU for one
process in the <literal>postgresql.service</literal> cgroup. (By
contrast, it they were in the same cgroup, then the PostgreSQL process
would get 1/1001 of the cgroups CPU time.) You can limit a services
CPU share in <filename>configuration.nix</filename>:
<programlisting>
systemd.services.httpd.serviceConfig.CPUShares = 512;
</programlisting>
By default, every cgroup has 1024 CPU shares, so this will halve the
CPU allocation of the <literal>httpd.service</literal> cgroup.</para>
<para>There also is a <literal>memory</literal> hierarchy that
controls memory allocation limits; by default, all processes are in
the top-level cgroup, so any service or session can exhaust all
available memory. Per-cgroup memory limits can be specified in
<filename>configuration.nix</filename>; for instance, to limit
<literal>httpd.service</literal> to 512 MiB of RAM (excluding swap)
and 640 MiB of RAM (including swap):
<programlisting>
systemd.services.httpd.serviceConfig.MemoryLimit = "512M";
systemd.services.httpd.serviceConfig.ControlGroupAttribute = [ "memory.memsw.limit_in_bytes 640M" ];
</programlisting>
</para>
<para>The command <command>systemd-cgtop</command> shows a
continuously updated list of all cgroups with their CPU and memory
usage.</para>
</section>
<!--===============================================================-->
<section><title>Logging</title>
<para>System-wide logging is provided by systemds
<emphasis>journal</emphasis>, which subsumes traditional logging
daemons such as syslogd and klogd. Log entries are kept in binary
files in <filename>/var/log/journal/</filename>. The command
<literal>journalctl</literal> allows you to see the contents of the
journal. For example,
<screen>
$ journalctl -b
</screen>
shows all journal entries since the last reboot. (The output of
<command>journalctl</command> is piped into <command>less</command> by
default.) You can use various options and match operators to restrict
output to messages of interest. For instance, to get all messages
from PostgreSQL:
<screen>
$ journalctl _SYSTEMD_UNIT=postgresql.service
-- Logs begin at Mon, 2013-01-07 13:28:01 CET, end at Tue, 2013-01-08 01:09:57 CET. --
...
Jan 07 15:44:14 hagbard postgres[2681]: [2-1] LOG: database system is shut down
-- Reboot --
Jan 07 15:45:10 hagbard postgres[2532]: [1-1] LOG: database system was shut down at 2013-01-07 15:44:14 CET
Jan 07 15:45:13 hagbard postgres[2500]: [1-1] LOG: database system is ready to accept connections
</screen>
Or to get all messages since the last reboot that have at least a
“critical” severity level:
<screen>
$ journalctl -b -p crit
Dec 17 21:08:06 mandark sudo[3673]: pam_unix(sudo:auth): auth could not identify password for [alice]
Dec 29 01:30:22 mandark kernel[6131]: [1053513.909444] CPU6: Core temperature above threshold, cpu clock throttled (total events = 1)
</screen>
</para>
</section>
</chapter>

View File

@ -4,60 +4,81 @@
<title>Troubleshooting</title>
<section>
<title>Debugging the boot process</title>
<section><title>Boot problems</title>
<para>To get a Stage 1 shell (i.e., a shell in the initial ramdisk),
add <literal>debug1</literal> to the kernel command line. The shell
gets started before anything useful has been done. That is, no
modules have been loaded and no file systems have been mounted, except
for <filename>/proc</filename> and <filename>/sys</filename>.</para>
<para>If NixOS fails to boot, there are a number of kernel command
line parameters that may help you to identify or fix the issue. You
can add these parameters in the GRUB boot menu by pressing “e” to
modify the selected boot entry and editing the line starting with
<literal>linux</literal>. The following are some useful kernel command
line parameters that are recognised by the NixOS boot scripts or by
systemd:
<para>To get a Stage 2 shell (i.e., a shell in the actual root file
system), add <literal>debug2</literal> to the kernel command
line. This shell is started right after stage 1 calls the stage 2
<literal>init</literal> script, so the root file system is there but
no services have been started.</para>
<variablelist>
</section>
<varlistentry><term><literal>boot.shell_on_fail</literal></term>
<listitem><para>Start a root shell if something goes wrong in
stage 1 of the boot process (the initial ramdisk). This is
disabled by default because there is no authentication for the
root shell.</para></listitem>
</varlistentry>
<varlistentry><term><literal>boot.debug1</literal></term>
<listitem><para>Start an interactive shell in stage 1 before
anything useful has been done. That is, no modules have been
loaded and no file systems have been mounted, except for
<filename>/proc</filename> and
<filename>/sys</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>boot.trace</literal></term>
<listitem><para>Print every shell command executed by the stage 1
and 2 boot scripts.</para></listitem>
</varlistentry>
<section>
<title>Safe mode</title>
<varlistentry><term><literal>single</literal></term>
<listitem><para>Boot into rescue mode (a.k.a. single user mode).
This will cause systemd to start nothing but the unit
<literal>rescue.target</literal>, which runs
<command>sulogin</command> to prompt for the root password and
start a root login shell. Exiting the shell causes the system to
continue with the normal boot process.</para></listitem>
</varlistentry>
<para>If the hardware autodetection (in
<filename>upstart-jobs/hardware-scan</filename>) causes problems, add
<literal>safemode</literal> to the kernel command line. This will
disable auto-loading of modules for your PCI devices. However, you
will probably need to explicitly add modules to
<option>boot.kernelModules</option> to get network support etc.</para>
<varlistentry><term><literal>systemd.log_level=debug systemd.log_target=console</literal></term>
<listitem><para>Make systemd very verbose and send log messages to
the console instead of the journal.</para></listitem>
</varlistentry>
</variablelist>
For more parameters recognised by systemd, see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<para>If no login prompts or X11 login screens appear (e.g. due to
hanging dependencies), you can press Alt+ArrowUp. If youre lucky,
this will start rescue mode (described above). (Also note that since
most units have a 90-second timeout before systemd gives up on them,
the <command>agetty</command> login prompts should appear eventually
unless something is very wrong.)</para>
</section>
<section>
<title>Maintenance mode</title>
<para>You can go to maintenance mode by doing
<para>You can enter rescue mode by running:
<screen>
$ shutdown now</screen>
$ systemctl rescue</screen>
This will eventually give you a single-user root shell.
To get out of maintenance mode, do
<screen>
$ initctl emit startup</screen>
</para>
This will eventually give you a single-user root shell. Systemd will
stop (almost) all system services. To get out of maintenance mode,
just exit from the rescue shell.</para>
</section>
</chapter>

View File

@ -2,7 +2,7 @@
let pkgs = import <nixpkgs> { config = {}; inherit system; }; in
with pkgs;
with pkgs.lib;
with import ../lib/qemu-flags.nix;
rec {
@ -15,7 +15,7 @@ rec {
# hostname and `configX' is a NixOS system configuration. Each
# machine is given an arbitrary IP address in the virtual network.
buildVirtualNetwork =
nodes: let nodesOut = lib.mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
nodes: let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
buildVM =
@ -27,7 +27,7 @@ rec {
[ ../modules/virtualisation/qemu-vm.nix
../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
{ key = "no-manual"; services.nixosManual.enable = false; }
] ++ lib.optional minimal ../modules/testing/minimal-kernel.nix;
] ++ optional minimal ../modules/testing/minimal-kernel.nix;
extraArgs = { inherit nodes; };
};
@ -39,51 +39,49 @@ rec {
let
machines = lib.attrNames nodes;
machines = attrNames nodes;
machinesNumbered = lib.zipTwoLists machines (lib.range 1 254);
machinesNumbered = zipTwoLists machines (range 1 254);
nodes_ = lib.flip map machinesNumbered (m: lib.nameValuePair m.first
nodes_ = flip map machinesNumbered (m: nameValuePair m.first
[ ( { config, pkgs, nodes, ... }:
let
interfacesNumbered = lib.zipTwoLists config.virtualisation.vlans (lib.range 1 255);
interfaces =
lib.flip map interfacesNumbered ({ first, second }:
{ name = "eth${toString second}";
ipAddress = "192.168.${toString first}.${toString m.second}";
interfacesNumbered = zipTwoLists config.virtualisation.vlans (range 1 255);
interfaces = flip map interfacesNumbered ({ first, second }:
nameValuePair "eth${toString second}"
{ ipAddress = "192.168.${toString first}.${toString m.second}";
subnetMask = "255.255.255.0";
}
);
});
in
{ key = "ip-address";
config =
{ networking.hostName = m.first;
networking.interfaces = interfaces;
networking.interfaces = listToAttrs interfaces;
networking.primaryIPAddress =
lib.optionalString (interfaces != []) (lib.head interfaces).ipAddress;
optionalString (interfaces != []) (head interfaces).value.ipAddress;
# Put the IP addresses of all VMs in this machine's
# /etc/hosts file. If a machine has multiple
# interfaces, use the IP address corresponding to
# the first interface (i.e. the first network in its
# virtualisation.vlans option).
networking.extraHosts = lib.flip lib.concatMapStrings machines
(m: let config = (lib.getAttr m nodes).config; in
lib.optionalString (config.networking.primaryIPAddress != "")
networking.extraHosts = flip concatMapStrings machines
(m: let config = (getAttr m nodes).config; in
optionalString (config.networking.primaryIPAddress != "")
("${config.networking.primaryIPAddress} " +
"${config.networking.hostName}\n"));
virtualisation.qemu.options =
lib.flip map interfacesNumbered
flip map interfacesNumbered
({ first, second }: qemuNICFlags second first m.second);
};
}
)
(lib.getAttr m.first nodes)
(getAttr m.first nodes)
] );
in lib.listToAttrs nodes_;
in listToAttrs nodes_;
}

View File

@ -31,7 +31,7 @@ rec {
inherit pkgs modules baseModules;
modulesPath = ../modules;
pkgs_i686 = import <nixpkgs> { system = "i686-linux"; };
utils = {}; # forward compatibility
utils = import ./utils.nix pkgs;
};
# Import Nixpkgs, allowing the NixOS option nixpkgs.config to

View File

@ -58,6 +58,7 @@ sub new {
stateDir => "$tmpDir/vm-state-$name",
monitor => undef,
log => $args->{log},
redirectSerial => $args->{redirectSerial} // 1,
};
mkdir $self->{stateDir}, 0700;
@ -125,10 +126,12 @@ sub start {
close $serialP;
close $monitorS;
close $shellS;
open NUL, "</dev/null" or die;
dup2(fileno(NUL), fileno(STDIN));
dup2(fileno($serialC), fileno(STDOUT));
dup2(fileno($serialC), fileno(STDERR));
if ($self->{redirectSerial}) {
open NUL, "</dev/null" or die;
dup2(fileno(NUL), fileno(STDIN));
dup2(fileno($serialC), fileno(STDOUT));
dup2(fileno($serialC), fileno(STDERR));
}
$ENV{TMPDIR} = $self->{stateDir};
$ENV{SHARED_DIR} = $sharedDir;
$ENV{USE_TMPDIR} = 1;
@ -349,18 +352,39 @@ sub mustFail {
}
# Wait for an Upstart job to reach the "running" state.
sub waitForJob {
my ($self, $jobName) = @_;
$self->nest("waiting for job $jobName", sub {
sub getUnitInfo {
my ($self, $unit) = @_;
my ($status, $lines) = $self->execute("systemctl --no-pager show '$unit'");
return undef if $status != 0;
my $info = {};
foreach my $line (split '\n', $lines) {
$line =~ /^([^=]+)=(.*)$/ or next;
$info->{$1} = $2;
}
return $info;
}
# Wait for a systemd unit to reach the "active" state.
sub waitForUnit {
my ($self, $unit) = @_;
$self->nest("waiting for unit $unit", sub {
retry sub {
my ($status, $out) = $self->execute("initctl status $jobName");
return 1 if $out =~ /start\/running/;
my $info = $self->getUnitInfo($unit);
my $state = $info->{ActiveState};
die "unit $unit reached state $state\n" if $state eq "failed";
return 1 if $state eq "active";
};
});
}
sub waitForJob {
my ($self, $jobName) = @_;
return $self->waitForUnit($jobName);
}
# Wait until the specified file exists.
sub waitForFile {
my ($self, $fileName) = @_;
@ -374,16 +398,13 @@ sub waitForFile {
sub startJob {
my ($self, $jobName) = @_;
$self->execute("initctl start $jobName");
my ($status, $out) = $self->execute("initctl status $jobName");
die "failed to start $jobName" unless $out =~ /start\/running/;
$self->execute("systemctl stop $jobName");
# FIXME: check result
}
sub stopJob {
my ($self, $jobName) = @_;
$self->execute("initctl stop $jobName");
my ($status, $out) = $self->execute("initctl status $jobName");
die "failed to stop $jobName" unless $out =~ /stop\/waiting/;
$self->execute("systemctl stop $jobName");
}
@ -413,7 +434,7 @@ sub shutdown {
my ($self) = @_;
return unless $self->{booted};
$self->execute("poweroff");
print { $self->{socket} } ("poweroff\n");
$self->waitForShutdown;
}

View File

@ -50,7 +50,7 @@ my $context = "";
sub createMachine {
my ($args) = @_;
my $vm = Machine->new({%{$args}, log => $log});
my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"});
$vms{$vm->name} = $vm;
return $vm;
}

View File

@ -158,7 +158,8 @@ rec {
wrapProgram $out/bin/nixos-run-vms \
--add-flags "$vms" \
--set tests '"startAll; joinAll;"' \
--set VLANS '"${toString vlans}"'
--set VLANS '"${toString vlans}"' \
${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
''; # "
test = runTests driver;

10
lib/utils.nix Normal file
View File

@ -0,0 +1,10 @@
pkgs: with pkgs.lib;
rec {
# Escape a path according to the systemd rules, e.g. /dev/xyzzy
# becomes dev-xyzzy. FIXME: slow.
escapeSystemdPath = s:
replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] (substring 1 (stringLength s) s);
}

View File

@ -32,10 +32,16 @@ f.write('''{{
'''.format(args.region, key_name, ebs_size))
f.close()
depl = deployment.Deployment("./ebs-creator.json", create=True, nix_exprs=["./ebs-creator.nix", "./ebs-creator-config.nix"])
depl.load_state()
if not args.keep: depl.destroy_vms()
depl.deploy()
db = deployment.open_database("./ebs-creator.charon")
try:
depl = deployment.open_deployment(db, "ebs-creator")
except Exception:
depl = deployment.create_deployment(db)
depl.name = "ebs-creator"
depl.auto_response = "y"
depl.nix_exprs = ["./ebs-creator.nix", "./ebs-creator-config.nix"]
if not args.keep: depl.destroy_resources()
depl.deploy(allow_reboot=True)
m = depl.machines['machine']
@ -52,15 +58,23 @@ m.run_command("mkdir -p /mnt")
m.run_command("mount {0} /mnt".format(device))
m.run_command("touch /mnt/.ebs")
m.run_command("mkdir -p /mnt/etc/nixos")
m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
m.run_command("nix-channel --update")
# Kind of hacky until the nixos channel is updated to systemd
#m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
#m.run_command("nix-channel --update")
m.run_command("mkdir unpack")
m.run_command("cd unpack; (curl -L http://hydra.nixos.org/job/nixos/systemd/channel/latest/download | bzcat | tar xv)")
m.run_command("mkdir nixos")
m.run_command("mv unpack/*/* nixos")
m.run_command("mv nixos unpack/*")
m.run_command("nix-env -p /nix/var/nix/profiles/per-user/root/channels -i $(nix-store --add unpack/*)")
m.run_command("rm -fR unpack")
m.run_command("nixos-rebuild switch")
version = m.run_command("nixos-version", capture_stdout=True).replace('"', '').rstrip()
print >> sys.stderr, "NixOS version is {0}".format(version)
m.run_command("cp -f $(nix-instantiate --find-file nixos/modules/virtualisation/amazon-config.nix) /mnt/etc/nixos/configuration.nix")
m.run_command("nixos-install")
if args.hvm:
m.run_command('cp /nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
m.run_command('cp /mnt/nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
m.run_command('sed -i "s|hd0|hd0,0|" /mnt/boot/grub/menu.lst')
m.run_command('echo "(hd1) /dev/xvdg" > device.map')
m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch')
@ -84,12 +98,12 @@ def check():
return status == '100%'
m.connect()
volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m._instance_id, 'attachment.device': "/dev/sdg"})[0]
volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
if args.hvm:
instance = m._conn.run_instances( image_id="ami-6a9e4503"
, instance_type=instance_type
, key_name=key_name
, placement=m._zone
, placement=m.zone
, security_groups=["eelco-test"]).instances[0]
charon.util.check_wait(lambda: instance.update() == 'running', max_tries=120)
instance.stop()
@ -117,7 +131,7 @@ else:
m._conn.create_tags([snapshot.id], {'Name': ami_name})
if not args.keep: depl.destroy_vms()
if not args.keep: depl.destroy_resources()
# Register the image.
aki = m._conn.get_all_images(filters={'manifest-location': '*pv-grub-hd0_1.03-x86_64*'})[0]
@ -163,11 +177,15 @@ f.write(
'''.format(args.region, ami_id, instance_type, key_name))
f.close()
test_depl = deployment.Deployment("./ebs-test.json", create=True, nix_exprs=["./ebs-test.nix"])
test_depl.load_state()
test_depl = deployment.create_deployment(db)
test_depl.auto_response = "y"
test_depl.name = "ebs-creator-test"
test_depl.nix_exprs = [ "./ebs-test.nix" ]
test_depl.deploy(create_only=True)
test_depl.machines['machine'].run_command("nixos-version")
if not args.keep: test_depl.destroy_vms()
if not args.keep:
test_depl.destroy_resources()
test_depl.delete()
# Log the AMI ID.
f = open("{0}.ebs.ami-id".format(args.region), "w")

View File

@ -1,6 +1,7 @@
#! /bin/sh -e
revision=$(svnversion "$NIXOS")
nixos=$(nix-instantiate --find-file nixos)
revision=$(cd $nixos; git rev-parse --short HEAD)
echo "NixOS revision is $revision"
buildAndUploadFor() {
@ -8,7 +9,7 @@ buildAndUploadFor() {
arch="$2"
echo "building $system image..."
NIXOS_CONFIG=$NIXOS/modules/virtualisation/amazon-config.nix nix-build "$NIXOS" \
NIXOS_CONFIG=$nixos/modules/virtualisation/amazon-config.nix nix-build "$nixos" \
-A config.system.build.amazonImage --argstr system "$system" -o ec2-ami
ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \

View File

@ -1,8 +1,10 @@
{pkgs, config, ...}:
{ config, pkgs, ... }:
with pkgs.lib;
###### interface
let
inherit (pkgs.lib) mkOption mkIf;
options = {
i18n = {
@ -45,16 +47,15 @@ let
The keyboard mapping table for the virtual consoles.
";
};
};
};
in
###### implementation
let
glibcLocales = pkgs.glibcLocales.override {
allLocales = pkgs.lib.any (x: x == "all") config.i18n.supportedLocales;
allLocales = any (x: x == "all") config.i18n.supportedLocales;
locales = config.i18n.supportedLocales;
};
@ -63,10 +64,19 @@ in
{
require = options;
environment.systemPackages = [glibcLocales];
environment.systemPackages = [ glibcLocales ];
environment.shellInit =
''
export LANG=${config.i18n.defaultLocale}
'';
# /etc/locale.conf is used by systemd.
environment.etc = singleton
{ target = "locale.conf";
source = pkgs.writeText "locale.conf"
''
LANG=${config.i18n.defaultLocale}
'';
};
}

View File

@ -3,7 +3,9 @@
{config, pkgs, ...}:
with pkgs.lib;
let
cfg = config.networking;
options = {
@ -55,7 +57,9 @@ in
source = pkgs.writeText "hosts"
''
127.0.0.1 localhost
::1 localhost
${optionalString cfg.enableIPv6 ''
::1 localhost
''}
${cfg.extraHosts}
'';
target = "hosts";
@ -71,7 +75,7 @@ in
'' + optionalString config.services.nscd.enable ''
# Invalidate the nscd cache whenever resolv.conf is
# regenerated.
libc_restart='${pkgs.upstart}/sbin/start invalidate-nscd'
libc_restart='${pkgs.systemd}/bin/systemctl reload --no-block nscd.service'
'' + optionalString cfg.dnsSingleRequest ''
# only send one DNS request at a time
resolv_conf_options='single-request'
@ -82,4 +86,10 @@ in
target = "resolvconf.conf";
}
];
systemd.units."ip-up.target".text =
''
[Unit]
Description=Services Requiring IP Connectivity
'';
}

View File

@ -7,7 +7,7 @@
example = true;
description = ''
Switch off the options in the default configuration that require X libraries.
Currently this includes: ssh X11 forwarding, dbus, hal, fonts.enableCoreFonts,
Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts,
fonts.enableFontConfig
'';
};
@ -16,7 +16,6 @@
programs.ssh.setXAuthLocation = false;
services = {
dbus.enable = false;
hal.enable = false;
};
fonts = {
enableCoreFonts = false;

View File

@ -6,21 +6,6 @@ let
cfg = config.powerManagement;
sleepHook = pkgs.writeScript "sleep-hook.sh"
''
#! ${pkgs.stdenv.shell}
action="$1"
case "$action" in
hibernate|suspend)
${cfg.powerDownCommands}
;;
thaw|resume)
${cfg.resumeCommands}
${cfg.powerUpCommands}
;;
esac
'';
in
{
@ -32,7 +17,7 @@ in
powerManagement = {
enable = mkOption {
default = false;
default = true;
description =
''
Whether to enable power management. This includes support
@ -79,13 +64,6 @@ in
# Enable the ACPI daemon. Not sure whether this is essential.
services.acpid.enable = true;
environment.systemPackages = [ pkgs.pmutils ];
environment.etc = singleton
{ source = sleepHook;
target = "pm/sleep.d/00sleep-hook";
};
boot.kernelModules =
[ "acpi_cpufreq" "powernow-k8" "cpufreq_performance" "cpufreq_powersave" "cpufreq_ondemand"
"cpufreq_conservative"
@ -93,7 +71,46 @@ in
powerManagement.cpuFreqGovernor = mkDefault "ondemand";
powerManagement.scsiLinkPolicy = mkDefault "min_power";
# Service executed before suspending/hibernating.
systemd.services."pre-sleep" =
{ description = "Pre-Sleep Actions";
wantedBy = [ "sleep.target" ];
before = [ "sleep.target" ];
script =
''
${cfg.powerDownCommands}
'';
serviceConfig.Type = "oneshot";
};
# Service executed before suspending/hibernating. There doesn't
# seem to be a good way to hook in a service to be executed after
# both suspend *and* hibernate, so have a separate one for each.
systemd.services."post-suspend" =
{ description = "Post-Suspend Actions";
wantedBy = [ "suspend.target" ];
after = [ "systemd-suspend.service" ];
script =
''
${cfg.resumeCommands}
${cfg.powerUpCommands}
'';
serviceConfig.Type = "oneshot";
};
systemd.services."post-hibernate" =
{ description = "Post-Hibernate Actions";
wantedBy = [ "hibernate.target" ];
after = [ "systemd-hibernate.service" ];
script =
''
${cfg.resumeCommands}
${cfg.powerUpCommands}
'';
serviceConfig.Type = "oneshot";
};
};
}

View File

@ -1,6 +1,7 @@
{ config, pkgs, ... }:
{ config, pkgs, utils, ... }:
with pkgs.lib;
with utils;
{
@ -74,9 +75,39 @@ with pkgs.lib;
};
config = mkIf ((length config.swapDevices) != 0) {
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isYes "SWAP")
];
# Create missing swapfiles.
# FIXME: support changing the size of existing swapfiles.
systemd.services =
let
createSwapDevice = sw:
assert sw.device != "";
let device' = escapeSystemdPath sw.device; in
nameValuePair "mkswap-${escapeSystemdPath sw.device}"
{ description = "Initialisation of Swapfile ${sw.device}";
wantedBy = [ "${device'}.swap" ];
before = [ "${device'}.swap" ];
path = [ pkgs.utillinux ];
script =
''
if [ ! -e "${sw.device}" ]; then
fallocate -l ${toString sw.size}M "${sw.device}" ||
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
mkswap ${sw.device}
fi
'';
unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
serviceConfig.Type = "oneshot";
};
in listToAttrs (map createSwapDevice (filter (sw: sw.size != null) config.swapDevices));
};
}

View File

@ -16,9 +16,7 @@ let
'';
requiredPackages =
[ config.system.sbin.modprobe # must take precedence over module_init_tools
config.system.build.upstart
config.environment.nix
[ config.environment.nix
pkgs.acl
pkgs.attr
pkgs.bashInteractive # bash with ncurses support
@ -39,7 +37,6 @@ let
pkgs.less
pkgs.libcap
pkgs.man
pkgs.module_init_tools
pkgs.nano
pkgs.ncurses
pkgs.netcat
@ -50,12 +47,10 @@ let
pkgs.procps
pkgs.rsync
pkgs.strace
pkgs.sysklogd
pkgs.sysvtools
pkgs.time
pkgs.udev
pkgs.usbutils
pkgs.utillinuxCurses
pkgs.utillinux
extraManpages
];

View File

@ -8,74 +8,74 @@ let
users = config.users;
userOpts = { name, config, ... }: {
options = {
name = mkOption {
type = with types; uniq string;
description = "The name of the user account. If undefined, the name of the attribute set will be used.";
};
description = mkOption {
type = with types; uniq string;
default = "";
description = "A short description of the user account.";
};
uid = mkOption {
type = with types; uniq (nullOr int);
default = null;
description = "The account UID. If undefined, NixOS will select a free UID.";
};
group = mkOption {
type = with types; uniq string;
default = "nogroup";
description = "The user's primary group.";
};
extraGroups = mkOption {
type = types.listOf types.string;
default = [];
description = "The user's auxiliary groups.";
};
home = mkOption {
type = with types; uniq string;
default = "/var/empty";
description = "The user's home directory.";
};
shell = mkOption {
type = with types; uniq string;
default = "/run/current-system/sw/sbin/nologin";
description = "The path to the user's shell.";
};
createHome = mkOption {
type = types.bool;
default = false;
description = "If true, the home directory will be created automatically.";
};
useDefaultShell = mkOption {
type = types.bool;
default = false;
description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>.";
};
password = mkOption {
type = with types; uniq (nullOr string);
default = null;
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
};
isSystemUser = mkOption {
type = types.bool;
default = true;
description = "Indicates if the user is a system user or not.";
};
createUser = mkOption {
type = types.bool;
default = true;
@ -85,7 +85,13 @@ let
then not modify any of the basic properties for the user account.
";
};
isAlias = mkOption {
type = types.bool;
default = false;
description = "If true, the UID of this user is not required to be unique and can thus alias another user.";
};
};
config = {
@ -93,41 +99,41 @@ let
uid = mkDefault (attrByPath [name] null ids.uids);
shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
};
};
groupOpts = { name, config, ... }: {
options = {
name = mkOption {
type = with types; uniq string;
description = "The name of the group. If undefined, the name of the attribute set will be used.";
};
gid = mkOption {
type = with types; uniq (nullOr int);
default = null;
description = "The GID of the group. If undefined, NixOS will select a free GID.";
};
};
config = {
name = mkDefault name;
gid = mkDefault (attrByPath [name] null ids.gids);
};
};
# Note: the 'X' in front of the password is to distinguish between
# having an empty password, and not having a password.
serializedUser = userName: let u = getAttr userName config.users.extraUsers; in "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${if u.createUser then "yes" else "no"}\n";
serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n";
# keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
usersFile = pkgs.writeText "users" (
concatMapStrings serializedUser (attrNames config.users.extraUsers)
);
let
p = partition (u: u.isAlias) (attrValues config.users.extraUsers);
in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right));
in
@ -208,6 +214,7 @@ in
users = { };
nixbld = { };
utmp = { };
adm = { }; # expected by journald
};
system.activationScripts.rootPasswd = stringAfter [ "etc" ]
@ -242,8 +249,9 @@ in
read password
read isSystemUser
read createUser
read isAlias
if ! test "$createUser" = "yes"; then
if [ -z "$createUser" ]; then
continue
fi
@ -256,6 +264,7 @@ in
--home "$home" \
--shell "$shell" \
''${createHome:+--create-home} \
''${isAlias:+--non-unique} \
"$name"
if test "''${password:0:1}" = 'X'; then
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"

View File

@ -87,7 +87,7 @@ let
# The Grub image.
grubImage = pkgs.runCommand "grub_eltorito" {}
''
${pkgs.grub2}/bin/grub-mkimage -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain vbe png jpeg echo test normal
${pkgs.grub2}/bin/grub-mkimage -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain png jpeg echo gfxmenu reboot
cat ${pkgs.grub2}/lib/grub/*/cdboot.img tmp > $out
''; # */
@ -184,27 +184,15 @@ in
# Note that /dev/root is a symlink to the actual root device
# specified on the kernel command line, created in the stage 1 init
# script.
fileSystems =
[ { mountPoint = "/";
device = "/dev/root";
}
{ mountPoint = "/nix/store";
fsType = "squashfs";
device = "/nix-store.squashfs";
options = "loop";
neededForBoot = true;
}
];
fileSystems."/".device = "/dev/root";
# We need squashfs in the initrd to mount the compressed Nix store,
# and aufs to make the root filesystem appear writable.
boot.extraModulePackages =
if config.boot.kernelPackages.aufs == null then
abort "This kernel doesn't have aufs enabled"
else
[ config.boot.kernelPackages.aufs ];
fileSystems."/nix/store" =
{ fsType = "squashfs";
device = "/nix-store.squashfs";
options = "loop";
};
boot.initrd.availableKernelModules = [ "aufs" "squashfs" "iso9660" ];
boot.initrd.availableKernelModules = [ "squashfs" "iso9660" ];
boot.initrd.kernelModules = [ "loop" ];
@ -214,16 +202,20 @@ in
# /nix/store (the squashfs image) to make this a live CD.
boot.initrd.postMountCommands =
''
mkdir /mnt-root-tmpfs
mount -t tmpfs -o "mode=755" none /mnt-root-tmpfs
mkdir -p /unionfs-chroot/ro-root
mount --rbind $targetRoot /unionfs-chroot/ro-root
mkdir /unionfs-chroot/rw-root
mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-root
mkdir /mnt-root-union
mount -t aufs -o dirs=/mnt-root-tmpfs=rw:$targetRoot=ro none /mnt-root-union
unionfs -o allow_other,cow,chroot=/unionfs-chroot /rw-root=RW:/ro-root=RO /mnt-root-union
oldTargetRoot=$targetRoot
targetRoot=/mnt-root-union
mkdir /mnt-store-tmpfs
mount -t tmpfs -o "mode=755" none /mnt-store-tmpfs
mkdir -p $targetRoot/nix/store
mount -t aufs -o dirs=/mnt-store-tmpfs=rw:/mnt-root/nix/store=ro none /mnt-root-union/nix/store
mkdir /unionfs-chroot/rw-store
mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-store
mkdir -p $oldTargetRoot/nix/store
unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot /rw-store=RW:/ro-root/nix/store=RO /mnt-root-union/nix/store
'';
# Closures to be copied to the Nix store on the CD, namely the init
@ -315,7 +307,7 @@ in
'';
# Add vfat support to the initrd to enable people to copy the
# contents of the CD to a bootable USB stick.
boot.initrd.supportedFilesystems = [ "vfat" ];
# contents of the CD to a bootable USB stick. Need unionfs-fuse for union mounts
boot.initrd.supportedFilesystems = [ "vfat" "unionfs-fuse" ];
}

View File

@ -0,0 +1,29 @@
getVersion() {
local dir="$1"
rev=
if [ -e "$dir/.git" ]; then
if [ -z "$(type -P git)" ]; then
echo "warning: Git not found; cannot figure out revision of $dir" >&2
return
fi
cd "$dir"
rev=$(git rev-parse --short HEAD)
if git describe --always --dirty | grep -q dirty; then
rev+=M
fi
fi
}
if nixos=$(nix-instantiate --find-file nixos "$@"); then
getVersion $nixos
if [ -n "$rev" ]; then
suffix="pre-$rev"
if nixpkgs=$(nix-instantiate --find-file nixpkgs "$@"); then
getVersion $nixpkgs
if [ -n "$rev" ]; then
suffix+="-$rev"
fi
fi
echo $suffix
fi
fi

View File

@ -16,7 +16,7 @@ if test -z "$mountPoint"; then
fi
if test -z "$NIXOS_CONFIG"; then
NIXOS_CONFIG=/mnt/etc/nixos/configuration.nix
NIXOS_CONFIG=/etc/nixos/configuration.nix
fi
if ! test -e "$mountPoint"; then
@ -28,32 +28,41 @@ if ! grep -F -q " $mountPoint " /proc/mounts; then
echo "$mountPoint doesn't appear to be a mount point"
exit 1
fi
if ! test -e "$NIXOS_CONFIG"; then
if ! test -e "$mountPoint/$NIXOS_CONFIG"; then
echo "configuration file $NIXOS_CONFIG doesn't exist"
exit 1
fi
# Mount some stuff in the target root directory. We bind-mount /etc
# into the chroot because we need networking and the nixbld user
# accounts in /etc/passwd. But we do need the target's /etc/nixos.
mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/mnt $mountPoint/etc
mount --rbind /dev $mountPoint/dev
mount --rbind /proc $mountPoint/proc
mount --rbind /sys $mountPoint/sys
mount --rbind / $mountPoint/mnt
mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/mnt $mountPoint/mnt2 $mountPoint/etc /etc/nixos
mount --make-private / # systemd makes / shared, which is annoying
mount --bind / $mountPoint/mnt
mount --bind /nix/store $mountPoint/mnt/nix/store
mount --bind /dev $mountPoint/dev
mount --bind /dev/shm $mountPoint/dev/shm
mount --bind /proc $mountPoint/proc
mount --bind /sys $mountPoint/sys
mount --bind $mountPoint/etc/nixos $mountPoint/mnt2
mount --bind /etc $mountPoint/etc
mount --bind $mountPoint/mnt/$mountPoint/etc/nixos $mountPoint/etc/nixos
mount --bind $mountPoint/mnt2 $mountPoint/etc/nixos
cleanup() {
set +e
umount -l $mountPoint/mnt
umount -l $mountPoint/dev
umount -l $mountPoint/proc
umount -l $mountPoint/sys
mountpoint -q $mountPoint/etc && umount -l $mountPoint/etc
mountpoint -q $mountPoint/etc/nixos && umount $mountPoint/etc/nixos
mountpoint -q $mountPoint/etc && umount $mountPoint/etc
umount $mountPoint/mnt2
umount $mountPoint/sys
umount $mountPoint/proc
umount $mountPoint/dev/shm
umount $mountPoint/dev
umount $mountPoint/mnt/nix/store
umount $mountPoint/mnt
rmdir $mountPoint/mnt $mountPoint/mnt2
}
trap "cleanup" EXIT
@ -144,7 +153,7 @@ srcs=$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-nam
# Build the specified Nix expression in the target store and install
# it into the system configuration profile.
echo "building the system configuration..."
NIX_PATH="/mnt$srcs/nixos:nixos-config=/mnt$NIXOS_CONFIG" NIXOS_CONFIG= \
NIX_PATH="/mnt$srcs/nixos:nixos-config=$NIXOS_CONFIG" NIXOS_CONFIG= \
chroot $mountPoint @nix@/bin/nix-env \
-p /nix/var/nix/profiles/system -f '<nixos>' --set -A system --show-trace

View File

@ -239,17 +239,14 @@ if $generate; then
# Add filesystem entries for each partition that you want to see
# mounted at boot time. This should include at least the root
# filesystem.
fileSystems =
[ # { mountPoint = "/";
# device = "/dev/disk/by-label/nixos";
# }
# { mountPoint = "/data"; # where you want to mount the device
# device = "/dev/sdb"; # the device
# fsType = "ext3"; # the type of the partition
# options = "data=journal";
# }
];
# fileSystems."/".device = "/dev/disk/by-label/nixos";
# fileSystems."/data" = # where you want to mount the device
# { device = "/dev/sdb"; # the device
# fsType = "ext3"; # the type of the partition
# options = "data=journal";
# };
# List swap partitions activated at boot time.
swapDevices =

View File

@ -44,13 +44,13 @@ EOF
# Parse the command line.
extraBuildFlags=
extraBuildFlags=()
action=
buildNix=1
rollback=
upgrade=
while test "$#" -gt 0; do
while [ "$#" -gt 0 ]; do
i="$1"; shift 1
case "$i" in
--help)
@ -72,20 +72,20 @@ while test "$#" -gt 0; do
upgrade=1
;;
--show-trace|--no-build-hook|--keep-failed|-K|--keep-going|-k|--verbose|-v|--fallback)
extraBuildFlags="$extraBuildFlags $i"
extraBuildFlags+=("$i")
;;
--max-jobs|-j|--cores|-I)
j="$1"; shift 1
extraBuildFlags="$extraBuildFlags $i $j"
extraBuildFlags+=("$i" "$j")
;;
--option)
j="$1"; shift 1
k="$1"; shift 1
extraBuildFlags="$extraBuildFlags $i $j $k"
extraBuildFlags+=("$i" "$j" "$k")
;;
--fast)
buildNix=
extraBuildFlags="$extraBuildFlags --show-trace"
extraBuildFlags+=(--show-trace)
;;
*)
echo "$0: unknown option \`$i'"
@ -94,13 +94,9 @@ while test "$#" -gt 0; do
esac
done
if test -z "$action"; then showSyntax; fi
if [ -z "$action" ]; then showSyntax; fi
if test "$action" = dry-run; then
extraBuildFlags="$extraBuildFlags --dry-run"
fi
if test -n "$rollback"; then
if [ -n "$rollback" ]; then
buildNix=
fi
@ -115,7 +111,7 @@ trap 'rm -rf "$tmpDir"' EXIT
# This matters if the new Nix in Nixpkgs has a schema change. It
# would upgrade the schema, which should only happen once we actually
# switch to the new configuration.
if initctl status nix-daemon 2>&1 | grep -q 'running'; then
if systemctl show nix-daemon.socket nix-daemon.service | grep -q ActiveState=active; then
export NIX_REMOTE=${NIX_REMOTE:-daemon}
fi
@ -129,42 +125,57 @@ fi
# First build Nix, since NixOS may require a newer version than the
# current one. Of course, the same goes for Nixpkgs, but Nixpkgs is
# more conservative.
if [ -n "$buildNix" ]; then
if [ "$action" != dry-run -a -n "$buildNix" ]; then
echo "building Nix..." >&2
if ! nix-build '<nixos>' -A config.environment.nix -o $tmpDir/nix $extraBuildFlags > /dev/null; then
if ! nix-build '<nixos>' -A nixFallback -o $tmpDir/nix $extraBuildFlags > /dev/null; then
nix-build '<nixpkgs>' -A nixUnstable -o $tmpDir/nix $extraBuildFlags > /dev/null
if ! nix-build '<nixos>' -A config.environment.nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
if ! nix-build '<nixos>' -A nixFallback -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
nix-build '<nixpkgs>' -A nixUnstable -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null
fi
fi
PATH=$tmpDir/nix/bin:$PATH
fi
# Update the version suffix if we're building from Git (so that
# nixos-version shows something useful).
if nixos=$(nix-instantiate --find-file nixos "${extraBuildFlags[@]}"); then
suffix=$($SHELL $nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}")
if [ -n "$suffix" ]; then
echo -n "$suffix" > "$nixos/.version-suffix"
fi
fi
if [ "$action" = dry-run ]; then
extraBuildFlags+=(--dry-run)
fi
# Either upgrade the configuration in the system profile (for "switch"
# or "boot"), or just build it and create a symlink "result" in the
# current directory (for "build" and "test").
if test -z "$rollback"; then
if [ -z "$rollback" ]; then
echo "building the system configuration..." >&2
if test "$action" = switch -o "$action" = boot; then
nix-env $extraBuildFlags -p /nix/var/nix/profiles/system -f '<nixos>' --set -A system
if [ "$action" = switch -o "$action" = boot ]; then
nix-env "${extraBuildFlags[@]}" -p /nix/var/nix/profiles/system -f '<nixos>' --set -A system
pathToConfig=/nix/var/nix/profiles/system
elif test "$action" = test -o "$action" = build -o "$action" = dry-run; then
nix-build '<nixos>' -A system -K -k $extraBuildFlags > /dev/null
elif [ "$action" = test -o "$action" = build -o "$action" = dry-run ]; then
nix-build '<nixos>' -A system -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
elif [ "$action" = build-vm ]; then
nix-build '<nixos>' -A vm -K -k $extraBuildFlags > /dev/null
nix-build '<nixos>' -A vm -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
elif [ "$action" = build-vm-with-bootloader ]; then
nix-build '<nixos>' -A vmWithBootLoader -K -k $extraBuildFlags > /dev/null
nix-build '<nixos>' -A vmWithBootLoader -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
else
showSyntax
fi
else # test -n "$rollback"
if test "$action" = switch -o "$action" = boot; then
else # [ -n "$rollback" ]
if [ "$action" = switch -o "$action" = boot ]; then
nix-env --rollback -p /nix/var/nix/profiles/system
pathToConfig=/nix/var/nix/profiles/system
elif test "$action" = test -o "$action" = build; then
elif [ "$action" = test -o "$action" = build ]; then
systemNumber=$(
nix-env -p /nix/var/nix/profiles/system --list-generations |
sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h'
@ -179,7 +190,7 @@ fi
# If we're not just building, then make the new configuration the boot
# default and/or activate it now.
if test "$action" = switch -o "$action" = boot -o "$action" = test; then
if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
# Just in case the new configuration hangs the system, do a sync now.
sync
@ -187,7 +198,7 @@ if test "$action" = switch -o "$action" = boot -o "$action" = test; then
fi
if test "$action" = build-vm; then
if [ "$action" = build-vm ]; then
cat >&2 <<EOF
Done. The virtual machine can be started by running $(echo $pathToConfig/bin/run-*-vm).

View File

@ -70,4 +70,18 @@ in
};
};
config = {
# FIXME
nixpkgs.config.packageOverrides = pkgs: {
#udev = pkgs.systemd;
slim = pkgs.slim.override (args: if args ? consolekit then { consolekit = null; } else { });
lvm2 = pkgs.lvm2.override { udev = pkgs.systemd; };
upower = pkgs.upower.override { useSystemd = true; };
polkit = pkgs.polkit.override { useSystemd = true; };
consolekit = null;
};
};
}

View File

@ -5,18 +5,27 @@ with pkgs.lib;
{
options = {
system.nixosVersion = mkOption {
default =
builtins.readFile ../../.version
+ (if builtins.pathExists ../../.version-suffix then builtins.readFile ../../.version-suffix else "pre-git");
type = types.uniq types.string;
description = "NixOS version.";
};
system.nixosVersionSuffix = mkOption {
type = types.uniq types.string;
description = "NixOS version suffix.";
};
};
config = {
system.nixosVersion =
mkDefault (builtins.readFile ../../.version + config.system.nixosVersionSuffix);
system.nixosVersionSuffix =
mkDefault (if builtins.pathExists ../../.version-suffix then builtins.readFile ../../.version-suffix else "pre-git");
# Generate /etc/os-release. See
# http://0pointer.de/public/systemd-man/os-release.html for the
# format.
@ -32,7 +41,7 @@ with pkgs.lib;
'';
target = "os-release";
};
};
}

View File

@ -46,11 +46,10 @@
./rename.nix
./security/apparmor.nix
./security/ca.nix
./security/consolekit.nix
./security/pam.nix
./security/pam_usb.nix
./security/policykit.nix
./security/polkit.nix
./security/rngd.nix
./security/rtkit.nix
./security/setuid-wrappers.nix
./security/sudo.nix
@ -73,7 +72,6 @@
./services/games/ghost-one.nix
./services/hardware/acpid.nix
./services/hardware/bluetooth.nix
./services/hardware/hal.nix
./services/hardware/nvidia-optimus.nix
./services/hardware/pcscd.nix
./services/hardware/pommed.nix
@ -102,6 +100,7 @@
./services/misc/rogue.nix
./services/misc/svnserve.nix
./services/misc/synergy.nix
./services/monitoring/dd-agent.nix
./services/monitoring/monit.nix
./services/monitoring/nagios/default.nix
./services/monitoring/smartd.nix
@ -166,13 +165,12 @@
./services/security/tor.nix
./services/security/torify.nix
./services/security/torsocks.nix
./services/system/cgroups.nix
./services/system/dbus.nix
./services/system/kerberos.nix
./services/system/nscd.nix
./services/system/uptimed.nix
./services/ttys/gpm.nix
./services/ttys/mingetty.nix
./services/ttys/agetty.nix
./services/web-servers/apache-httpd/default.nix
./services/web-servers/jboss/default.nix
./services/web-servers/tomcat.nix
@ -206,12 +204,11 @@
./system/boot/loader/init-script/init-script.nix
./system/boot/luksroot.nix
./system/boot/modprobe.nix
./system/boot/shutdown.nix
./system/boot/stage-1.nix
./system/boot/stage-2.nix
./system/boot/systemd.nix
./system/etc/etc.nix
./system/upstart-events/control-alt-delete.nix
./system/upstart-events/runlevel.nix
./system/upstart-events/shutdown.nix
./system/upstart/upstart.nix
./tasks/cpu-freq.nix
./tasks/filesystems.nix
@ -219,6 +216,7 @@
./tasks/filesystems/ext.nix
./tasks/filesystems/nfs.nix
./tasks/filesystems/reiserfs.nix
./tasks/filesystems/unionfs-fuse.nix
./tasks/filesystems/vfat.nix
./tasks/filesystems/xfs.nix
./tasks/kbd.nix

View File

@ -10,19 +10,11 @@ with pkgs.lib;
boot.vesa = false;
boot.initrd.enableSplashScreen = false;
services.ttyBackgrounds.enable = false;
services.mingetty.ttys = [ ];
# Don't start a tty on the serial consoles.
systemd.services."serial-getty@ttyS0".enable = false;
systemd.services."serial-getty@hvc0".enable = false;
# Since we can't manually respond to a panic, just reboot.
boot.kernelParams = [ "panic=1" "stage1panic=1" ];
# Since we don't have an (interactive) console, disable the
# emergency shell (started if mountall fails).
jobs."mount-failed".script = mkOverride 50
''
${pkgs.utillinux}/bin/logger -p user.emerg -t mountall "filesystem $DEVICE could not be mounted on $MOUNTPOINT"
'';
# Likewise, redirect mountall output from the console to the default
# Upstart job log file.
jobs."mountall".console = mkOverride 50 "";
boot.kernelParams = [ "panic=1" "boot.panic_on_fail" ];
}

View File

@ -31,20 +31,48 @@ let
options = {
environment.promptInit = mkOption {
default = ''
# Provide a nice prompt.
PROMPT_COLOR="1;31m"
let $UID && PROMPT_COLOR="1;32m"
PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
if test "$TERM" = "xterm"; then
PS1="\[\033]2;\h:\u:\w\007\]$PS1"
fi
'';
description = "
Script used to initialized shell prompt.
";
type = with pkgs.lib.types; string;
};
environment.shellInit = mkOption {
default = "";
example = ''export PATH=/godi/bin/:$PATH'';
description = "
Script used to initialized user shell environments.
";
type = with pkgs.lib.types; string;
};
default = "";
example = ''export PATH=/godi/bin/:$PATH'';
description = "
Script used to initialized user shell environments.
";
type = with pkgs.lib.types; string;
};
environment.enableBashCompletion = mkOption {
default = false;
description = "Enable bash-completion for all interactive shells.";
type = with pkgs.lib.types; bool;
};
default = false;
description = "Enable bash-completion for all interactive shells.";
type = with pkgs.lib.types; bool;
};
environment.binsh = mkOption {
default = "${config.system.build.binsh}/bin/sh";
example = "\${pkgs.dash}/bin/dash";
type = with pkgs.lib.types; path;
description = ''
Select the shell executable that is linked system-wide to
<literal>/bin/sh</literal>. Please note that NixOS assumes all
over the place that shell to be Bash, so override the default
setting only if you know exactly what you're doing.
'';
};
};
@ -68,6 +96,7 @@ in
# configured properly.
source = pkgs.substituteAll {
src = ./bashrc.sh;
inherit (config.environment) promptInit;
inherit initBashCompletion shellAliases;
};
target = "bashrc";
@ -79,12 +108,12 @@ in
}
];
environment.shellAliases = {
ls = "ls --color=tty";
ll = "ls -l";
l = "ls -alh";
which = "type -P";
};
environment.shellAliases =
{ ls = "ls --color=tty";
ll = "ls -l";
l = "ls -alh";
which = "type -P";
};
system.build.binsh = pkgs.bashInteractive;
@ -93,7 +122,7 @@ in
# Create the required /bin/sh symlink; otherwise lots of things
# (notably the system() function) won't work.
mkdir -m 0755 -p /bin
ln -sfn ${config.system.build.binsh}/bin/sh /bin/.sh.tmp
ln -sfn "${config.environment.binsh}" /bin/.sh.tmp
mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
'';

View File

@ -19,14 +19,6 @@ if [ -z "$PS1" ]; then return; fi
# Check the window size after every command.
shopt -s checkwinsize
# Provide a nice prompt.
PROMPT_COLOR="1;31m"
let $UID && PROMPT_COLOR="1;32m"
PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
if test "$TERM" = "xterm"; then
PS1="\[\033]2;\h:\u:\w\007\]$PS1"
fi
@promptInit@
@initBashCompletion@
@shellAliases@

View File

@ -1,6 +1,6 @@
# Configuration for the pwdutils suite of tools: passwd, useradd, etc.
{config, pkgs, ...}:
{ config, pkgs, ... }:
let
@ -27,6 +27,7 @@ let
# Uncomment this to allow non-root users to change their account
#information. This should be made configurable.
#CHFN_RESTRICT frwh
'';
in
@ -90,7 +91,7 @@ in
{ name = "groupmod"; rootOK = true; }
{ name = "groupmems"; rootOK = true; }
{ name = "groupdel"; rootOK = true; }
{ name = "login"; ownDevices = true; allowNullPassword = true; }
{ name = "login"; startSession = true; allowNullPassword = true; showMotd = true; }
];
security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ];

View File

@ -38,7 +38,7 @@ in
};
};
assertions = [{ assertion = if cfg.forwardX11 then cfg.setXAuthLocation else true;
assertions = [{ assertion = if cfg.forwardX11 then cfg.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";}];
config = {
@ -46,14 +46,11 @@ in
[ { # SSH configuration. Slight duplication of the sshd_config
# generation in the sshd service.
source = pkgs.writeText "ssh_config" ''
AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
${optionalString cfg.setXAuthLocation ''
XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
''}
${if cfg.forwardX11 then ''
ForwardX11 yes
'' else ''
ForwardX11 no
''}
ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
'';
target = "ssh/ssh_config";
}

View File

@ -10,26 +10,32 @@ let virtualbox = config.boot.kernelPackages.virtualbox; in
environment.systemPackages = [ virtualbox ];
users.extraGroups = singleton { name = "vboxusers"; };
services.udev.extraRules =
''
KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660"
KERNEL=="vboxnetctl", OWNER="root", GROUP="root", MODE="0600"
KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
KERNEL=="vboxnetctl", OWNER="root", GROUP="root", MODE="0600", TAG+="systemd"
'';
# Since we lack the right setuid binaries, set up a host-only network by default.
jobs."create-vboxnet0" =
{ task = true;
jobs."vboxnet0" =
{ description = "VirtualBox vboxnet0 Interface";
requires = [ "dev-vboxnetctl.device" ];
after = [ "dev-vboxnetctl.device" ];
wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
path = [ virtualbox ];
startOn = "starting network-interfaces";
script =
preStart =
''
if ! [ -e /sys/class/net/vboxnet0 ]; then
VBoxManage hostonlyif create
fi
'';
postStop =
''
VBoxManage hostonlyif remove vboxnet0
'';
};
networking.interfaces = [ { name = "vboxnet0"; ipAddress = "192.168.56.1"; subnetMask = "255.255.255.0"; } ];
networking.interfaces.vboxnet0 = { ipAddress = "192.168.56.1"; prefixLength = 24; };
}

View File

@ -71,6 +71,11 @@ in zipModules ([]
++ rename obsolete "networking.enableWLAN" "networking.wireless.enable"
++ rename obsolete "networking.enableRT73Firmware" "networking.enableRalinkFirmware"
# FIXME: Remove these eventually.
++ rename obsolete "boot.systemd.sockets" "systemd.sockets"
++ rename obsolete "boot.systemd.targets" "systemd.targets"
++ rename obsolete "boot.systemd.services" "systemd.services"
# Old Grub-related options.
++ rename obsolete "boot.copyKernels" "boot.loader.grub.copyKernels"
++ rename obsolete "boot.extraGrubEntries" "boot.loader.grub.extraEntries"

View File

@ -21,7 +21,6 @@ with pkgs.lib;
''
export OPENSSL_X509_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
# !!! Remove the following as soon as OpenSSL 1.0.0e is the default.
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt
export GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt
'';

View File

@ -1,60 +0,0 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
# `pam_console' maintains the set of locally logged in users in
# /var/run/console. This is obsolete, but D-Bus still uses it for
# its `at_console' feature. So maintain it using a ConsoleKit
# session script. Borrowed from
# http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/sys-auth/consolekit/files/pam-foreground-compat.ck
updateVarRunConsole = pkgs.writeTextFile {
name = "var-run-console.ck";
destination = "/etc/ConsoleKit/run-session.d/var-run-console.ck";
executable = true;
text =
''
#! ${pkgs.stdenv.shell} -e
PATH=${pkgs.coreutils}/bin:${pkgs.gnused}/bin:${pkgs.glibc}/bin
TAGDIR=/var/run/console
[ -n "$CK_SESSION_USER_UID" ] || exit 1
TAGFILE="$TAGDIR/`getent passwd $CK_SESSION_USER_UID | cut -f 1 -d:`"
if [ "$1" = "session_added" ]; then
mkdir -p "$TAGDIR"
echo "$CK_SESSION_ID" >> "$TAGFILE"
fi
if [ "$1" = "session_removed" ] && [ -e "$TAGFILE" ]; then
sed -i "\%^$CK_SESSION_ID\$%d" "$TAGFILE"
[ -s "$TAGFILE" ] || rm -f "$TAGFILE"
fi
'';
};
in
{
config = {
environment.systemPackages = [ pkgs.consolekit ];
services.dbus.packages = [ pkgs.consolekit ];
environment.etc = singleton
{ source = (pkgs.buildEnv {
name = "consolekit-config";
pathsToLink = [ "/etc/ConsoleKit" ];
paths = [ pkgs.consolekit pkgs.udev updateVarRunConsole ];
}) + "/etc/ConsoleKit";
target = "ConsoleKit";
};
};
}

View File

@ -31,6 +31,8 @@ let
concatStringsSep " " [ domain type item value ])
limits));
motd = pkgs.writeText "motd" config.users.motd;
makePAMService =
{ name
, # If set, root doesn't need to authenticate (e.g. for the "chsh"
@ -43,9 +45,10 @@ let
# against the keys in the calling user's ~/.ssh/authorized_keys.
# This is useful for "sudo" on password-less remote systems.
sshAgentAuth ? false
, # If set, use ConsoleKit's PAM connector module to claim
# ownership of audio devices etc.
ownDevices ? false
, # If set, the service will register a new session with systemd's
# login manager. If the service is running locally, this will
# give the user ownership of audio devices etc.
startSession ? false
, # Whether to forward XAuth keys between users. Mostly useful
# for "su".
forwardXAuth ? false
@ -59,6 +62,8 @@ let
allowNullPassword ? false
, # The limits, as per limits.conf(5).
limits ? config.security.pam.loginLimits
, # Whether to show the message of the day.
showMotd ? false
}:
{ source = pkgs.writeText "${name}.pam"
@ -77,7 +82,7 @@ let
${optionalString rootOK
"auth sufficient pam_rootok.so"}
${optionalString (config.security.pam.enableSSHAgentAuth && sshAgentAuth)
"auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys"}
"auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
${optionalString usbAuth
"auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
auth sufficient pam_unix.so ${optionalString allowNullPassword "nullok"} likeauth
@ -105,12 +110,14 @@ let
"session optional ${pam_ldap}/lib/security/pam_ldap.so"}
${optionalString config.krb5.enable
"session optional ${pam_krb5}/lib/security/pam_krb5.so"}
${optionalString ownDevices
"session optional ${pkgs.consolekit}/lib/security/pam_ck_connector.so"}
${optionalString startSession
"session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
${optionalString forwardXAuth
"session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"}
${optionalString (limits != [])
"session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf limits}"}
${optionalString (showMotd && config.users.motd != null)
"session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
'';
target = "pam.d/${name}";
};
@ -152,7 +159,7 @@ in
default = [];
example = [
{ name = "chsh"; rootOK = true; }
{ name = "login"; ownDevices = true; allowNullPassword = true;
{ name = "login"; startSession = true; allowNullPassword = true;
limits = [
{ domain = "ftp";
type = "hard";
@ -173,13 +180,13 @@ in
the name of the service. The attribute
<varname>rootOK</varname> specifies whether the root user is
allowed to use this service without authentication. The
attribute <varname>ownDevices</varname> specifies whether
ConsoleKit's PAM connector module should be used to give the
user ownership of devices such as audio and CD-ROM drives.
The attribute <varname>forwardXAuth</varname> specifies
whether X authentication keys should be passed from the
calling user to the target user (e.g. for
<command>su</command>).
attribute <varname>startSession</varname> specifies whether
systemd's PAM connector module should be used to start a new
session; for local sessions, this will give the user
ownership of devices such as audio and CD-ROM drives. The
attribute <varname>forwardXAuth</varname> specifies whether
X authentication keys should be passed from the calling user
to the target user (e.g. for <command>su</command>).
The attribute <varname>limits</varname> defines resource limits
that should apply to users or groups for the service. Each item in
@ -202,6 +209,13 @@ in
'';
};
users.motd = mkOption {
default = null;
example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
type = types.nullOr types.string;
description = "Message of the day shown to users when they log in.";
};
};
@ -238,7 +252,6 @@ in
{ name = "lshd"; }
{ name = "samba"; }
{ name = "screen"; }
{ name = "sshd"; }
{ name = "vlock"; }
{ name = "xlock"; }
{ name = "xscreensaver"; }

View File

@ -1,80 +0,0 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
conf = pkgs.writeText "PolicyKit.conf"
''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pkconfig PUBLIC "-//freedesktop//DTD PolicyKit Configuration 1.0//EN"
"http://hal.freedesktop.org/releases/PolicyKit/1.0/config.dtd">
<config version="0.1">
</config>
'';
in
{
options = {
security.policykit.enable = mkOption {
default = false;
description = "Enable PolicyKit (obsolete).";
};
};
config = mkIf config.security.policykit.enable {
environment.systemPackages = [ pkgs.policykit ];
services.dbus.packages = [ pkgs.policykit ];
security.pam.services = [ { name = "polkit"; } ];
users.extraUsers = singleton
{ name = "polkituser";
uid = config.ids.uids.polkituser;
description = "PolicyKit user";
};
users.extraGroups = singleton
{ name = "polkituser";
gid = config.ids.gids.polkituser;
};
environment.etc =
[ { source = conf;
target = "PolicyKit/PolicyKit.conf";
}
{ source = (pkgs.buildEnv {
name = "PolicyKit-policies";
pathsToLink = [ "/share/PolicyKit/policy" ];
paths = [ pkgs.policykit pkgs.consolekit pkgs.hal ];
}) + "/share/PolicyKit/policy";
target = "PolicyKit/policy";
}
];
system.activationScripts.policyKit = stringAfter [ "users" ]
''
mkdir -m 0770 -p /var/run/PolicyKit
chown root:polkituser /var/run/PolicyKit
mkdir -m 0770 -p /var/lib/PolicyKit
chown root:polkituser /var/lib/PolicyKit
mkdir -p /var/lib/misc
touch /var/lib/misc/PolicyKit.reload
chmod 0664 /var/lib/misc/PolicyKit.reload
chown polkituser:polkituser /var/lib/misc/PolicyKit.reload
'';
};
}

37
modules/security/rngd.nix Normal file
View File

@ -0,0 +1,37 @@
{ config, pkgs, ... }:
with pkgs.lib;
{
options = {
security.rngd.enable = mkOption {
default = true;
description = ''
Whether to enable the rng daemon, which adds entropy from
hardware sources of randomness to the kernel entropy pool when
available.
'';
};
};
config = mkIf config.security.rngd.enable {
services.udev.extraRules = ''
KERNEL=="random", TAG+="systemd"
SUBSYSTEM=="cpu", ENV{MODALIAS}=="x86cpu:*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
KERNEL=="hw_random", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
KERNEL=="tmp0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
'';
systemd.services.rngd = {
bindsTo = [ "dev-random.device" ];
after = [ "dev-random.device" ];
description = "Hardware RNG Entropy Gatherer Daemon";
serviceConfig.ExecStart = "${pkgs.rng_tools}/sbin/rngd -f";
restartTriggers = [ pkgs.rng_tools ];
};
};
}

View File

@ -37,25 +37,6 @@ in
security.sudo.configFile = mkOption {
# Note: if syntax errors are detected in this file, the NixOS
# configuration will fail to build.
default =
''
# Don't edit this file. Set the NixOS option security.sudo.configFile instead.
# Environment variables to keep for root and %wheel.
Defaults:root,%wheel env_keep+=LOCALE_ARCHIVE
Defaults:root,%wheel env_keep+=NIX_CONF_DIR
Defaults:root,%wheel env_keep+=NIX_PATH
Defaults:root,%wheel env_keep+=TERMINFO_DIRS
# Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
Defaults env_keep+=SSH_AUTH_SOCK
# "root" is allowed to do anything.
root ALL=(ALL) SETENV: ALL
# Users in the "wheel" group can do anything.
%wheel ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
'';
description =
''
This string contains the contents of the
@ -69,6 +50,26 @@ in
config = mkIf cfg.enable {
security.sudo.configFile =
''
# Don't edit this file. Set the NixOS option security.sudo.configFile instead.
# Environment variables to keep for root and %wheel.
Defaults:root,%wheel env_keep+=LOCALE_ARCHIVE
Defaults:root,%wheel env_keep+=NIX_CONF_DIR
Defaults:root,%wheel env_keep+=NIX_PATH
Defaults:root,%wheel env_keep+=TERMINFO_DIRS
# Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
Defaults env_keep+=SSH_AUTH_SOCK
# "root" is allowed to do anything.
root ALL=(ALL) SETENV: ALL
# Users in the "wheel" group can do anything.
%wheel ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
'';
security.setuidPrograms = [ "sudo" ];
environment.systemPackages = [ sudo ];

View File

@ -29,9 +29,9 @@ in
enableOSSEmulation = mkOption {
default = true;
description = ''
Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).
'';
description = ''
Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).
'';
};
};
@ -45,25 +45,18 @@ in
environment.systemPackages = [ alsaUtils ];
# ALSA provides a udev rule for restoring volume settings.
services.udev.packages = [ alsaUtils ];
boot.kernelModules = optional config.sound.enableOSSEmulation "snd_pcm_oss";
jobs.alsa =
{ startOn = "stopped udevtrigger";
preStart =
''
mkdir -m 0755 -p $(dirname ${soundState})
# Try to restore the sound state.
${alsaUtils}/sbin/alsactl --ignore init || true
${alsaUtils}/sbin/alsactl --ignore -f ${soundState} restore || true
'';
postStop =
''
# Save the sound state.
${alsaUtils}/sbin/alsactl --ignore -f ${soundState} store
'';
systemd.services."alsa-store" =
{ description = "Store Sound Card State";
wantedBy = [ "shutdown.target" ];
before = [ "shutdown.target" ];
unitConfig.DefaultDependencies = "no";
serviceConfig.Type = "oneshot";
serviceConfig.ExecStart = "${alsaUtils}/sbin/alsactl store --ignore";
};
};

View File

@ -97,17 +97,16 @@ in
users.extraUsers = singleton
{ name = cfg.user;
shell = "/bin/sh";
description = "MongoDB server user";
};
environment.systemPackages = [mongodb];
environment.systemPackages = [ mongodb ];
jobs.mongodb =
systemd.services.mongodb =
{ description = "MongoDB server";
daemonType = "daemon";
startOn = "filesystem";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart =
''
@ -117,11 +116,10 @@ in
fi
'';
path = [mongodb];
exec = "mongod --config ${mongoCnf} --fork";
setuid = cfg.user;
extraConfig = "kill timeout 10";
serviceConfig = {
ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf}";
User = cfg.user;
};
};
};

View File

@ -91,6 +91,7 @@ in
description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
};
# FIXME: remove this option; it's a really bad idea.
rootPassword = mkOption {
default = null;
description = "Path to a file containing the root password, modified on the first startup. Not specifying a root password will leave the root password empty.";
@ -140,10 +141,12 @@ in
environment.systemPackages = [mysql];
jobs.mysql =
{ description = "MySQL server";
systemd.services.mysql =
{ description = "MySQL Server";
startOn = "filesystem";
wantedBy = [ "multi-user.target" ];
unitConfig.RequiresMountsFor = "${cfg.dataDir}";
preStart =
''
@ -156,9 +159,12 @@ in
mkdir -m 0700 -p ${cfg.pidDir}
chown -R ${cfg.user} ${cfg.pidDir}
${mysql}/libexec/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions} &
'';
serviceConfig.ExecStart = "${mysql}/libexec/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
postStart =
''
# Wait until the MySQL server is available for use
count=0
while [ ! -e /tmp/mysql.sock ]
@ -183,7 +189,7 @@ in
echo "Creating initial database: ${database.name}"
( echo "create database ${database.name};"
echo "use ${database.name};"
if [ -f "${database.schema}" ]
then
cat ${database.schema}
@ -204,7 +210,7 @@ in
${optionalString (cfg.rootPassword != null)
''
# Change root password
( echo "use mysql;"
echo "update user set Password=password('$(cat ${cfg.rootPassword})') where User='root';"
echo "flush privileges;"
@ -213,14 +219,10 @@ in
rm /tmp/mysql_init
fi
'';
''; # */
postStop = "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
# !!! Need a postStart script to wait until mysqld is ready to
# accept connections.
extraConfig = "kill timeout 60";
serviceConfig.ExecStop =
"${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
};
};

View File

@ -84,6 +84,7 @@ in
description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
};
# FIXME: remove this option; it's a really bad idea.
rootPassword = mkOption {
default = null;
description = "Path to a file containing the root password, modified on the first startup. Not specifying a root password will leave the root password empty.";
@ -133,10 +134,12 @@ in
environment.systemPackages = [mysql];
jobs.mysql =
{ description = "MySQL server";
systemd.services.mysql =
{ description = "MySQL Server";
startOn = "filesystem";
wantedBy = [ "multi-user.target" ];
unitConfig.RequiresMountsFor = "${cfg.dataDir}";
preStart =
''
@ -149,9 +152,12 @@ in
mkdir -m 0700 -p ${cfg.pidDir}
chown -R ${cfg.user} ${cfg.pidDir}
${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions} &
'';
serviceConfig.ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
postStart =
''
# Wait until the MySQL server is available for use
count=0
while [ ! -e /tmp/mysql.sock ]
@ -176,7 +182,7 @@ in
echo "Creating initial database: ${database.name}"
( echo "create database ${database.name};"
echo "use ${database.name};"
if [ -f "${database.schema}" ]
then
cat ${database.schema}
@ -207,7 +213,7 @@ in
${optionalString (cfg.rootPassword != null)
''
# Change root password
( echo "use mysql;"
echo "update user set Password=password('$(cat ${cfg.rootPassword})') where User='root';"
echo "flush privileges;"
@ -216,14 +222,10 @@ in
rm /tmp/mysql_init
fi
'';
''; # */
postStop = "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
# !!! Need a postStart script to wait until mysqld is ready to
# accept connections.
extraConfig = "kill timeout 60";
serviceConfig.ExecStop =
"${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
};
};

View File

@ -22,8 +22,6 @@ let
postgresql = postgresqlAndPlugins cfg.package;
run = "su -s ${pkgs.stdenv.shell} postgres";
flags = optional cfg.enableTCPIP "-i";
# The main PostgreSQL configuration file.
@ -36,7 +34,7 @@ let
'';
pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4";
in
{
@ -146,7 +144,7 @@ in
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'';
users.extraUsers = singleton
{ name = "postgres";
description = "PostgreSQL server user";
@ -157,10 +155,11 @@ in
environment.systemPackages = [postgresql];
jobs.postgresql =
{ description = "PostgreSQL server";
systemd.services.postgresql =
{ description = "PostgreSQL Server";
startOn = "started network-interfaces and filesystem";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment =
{ TZ = config.time.timeZone;
@ -175,34 +174,38 @@ in
if ! test -e ${cfg.dataDir}; then
mkdir -m 0700 -p ${cfg.dataDir}
chown -R postgres ${cfg.dataDir}
${run} -c 'initdb -U root'
su -s ${pkgs.stdenv.shell} postgres -c 'initdb -U root'
rm -f ${cfg.dataDir}/*.conf
fi
ln -sfn ${configFile} ${cfg.dataDir}/postgresql.conf
''; # */
exec = "${run} -c 'postgres ${toString flags}'";
serviceConfig =
{ ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}";
User = "postgres";
Group = "postgres";
PermissionsStartOnly = true;
# Shut down Postgres using SIGINT ("Fast Shutdown mode"). See
# http://www.postgresql.org/docs/current/static/server-shutdown.html
KillSignal = "SIGINT";
# Give Postgres a decent amount of time to clean up after
# receiving systemd's SIGINT.
TimeoutSec = 60;
};
# Wait for PostgreSQL to be ready to accept connections.
postStart =
''
while ! psql postgres -c ""; do
stop_check
sleep 1
while ! psql postgres -c "" 2> /dev/null; do
if ! kill -0 "$MAINPID"; then exit 1; fi
sleep 0.1
done
'';
extraConfig =
''
# Shut down Postgres using SIGINT ("Fast Shutdown mode"). See
# http://www.postgresql.org/docs/current/static/server-shutdown.html
kill signal INT
# Give Postgres a decent amount of time to clean up after
# receiving Upstart's SIGINT.
kill timeout 60
'';
unitConfig.RequiresMountsFor = "${cfg.dataDir}";
};
};

View File

@ -95,15 +95,18 @@ in
config = mkIf config.services.acpid.enable {
jobs.acpid =
{ description = "ACPI daemon";
{ description = "ACPI Daemon";
startOn = "stopped udevtrigger and started syslogd";
wantedBy = [ "multi-user.target" ];
after = [ "systemd-udev-settle.service" ];
path = [ pkgs.acpid ];
daemonType = "fork";
exec = "acpid --confdir ${acpiConfDir}";
unitConfig.ConditionPathExists = [ "/proc/acpi" ];
};
};

View File

@ -1,117 +0,0 @@
# HAL daemon.
{ config, pkgs, ... }:
with pkgs.lib;
let
cfg = config.services.hal;
inherit (pkgs) hal;
fdi = pkgs.buildEnv {
name = "hal-fdi";
pathsToLink = [ "/share/hal/fdi" ];
paths = cfg.packages;
};
in
{
###### interface
options = {
services.hal = {
enable = mkOption {
default = false;
description = ''
Whether to start the HAL daemon.
'';
};
packages = mkOption {
default = [];
description = ''
Packages containing additional HAL configuration data.
'';
};
};
};
###### implementation
config = mkIf cfg.enable {
environment.systemPackages = [ hal ];
services.hal.packages = [ hal pkgs.hal_info ];
security.policykit.enable = true;
users.extraUsers = singleton
{ name = "haldaemon";
uid = config.ids.uids.haldaemon;
description = "HAL daemon user";
};
users.extraGroups = singleton
{ name = "haldaemon";
gid = config.ids.gids.haldaemon;
};
jobs.hal =
{ description = "HAL daemon";
startOn = "started dbus" + optionalString config.services.acpid.enable " and started acpid";
environment =
{ # !!! HACK? These environment variables manipulated inside
# 'src'/hald/mmap_cache.c are used for testing the daemon.
HAL_FDI_SOURCE_PREPROBE = "${fdi}/share/hal/fdi/preprobe";
HAL_FDI_SOURCE_INFORMATION = "${fdi}/share/hal/fdi/information";
HAL_FDI_SOURCE_POLICY = "${fdi}/share/hal/fdi/policy";
# Stuff needed by the shell scripts run by HAL (in particular pm-utils).
HALD_RUNNER_PATH = concatStringsSep ":"
[ "${pkgs.coreutils}/bin"
"${pkgs.gnugrep}/bin"
"${pkgs.dbus_tools}/bin"
"${pkgs.procps}/bin"
"${pkgs.procps}/sbin"
"${config.system.sbin.modprobe}/sbin"
"${pkgs.module_init_tools}/bin"
"${pkgs.module_init_tools}/sbin"
"${pkgs.kbd}/bin"
];
};
preStart =
''
mkdir -m 0755 -p /var/cache/hald
mkdir -m 0755 -p /var/run/hald
rm -f /var/cache/hald/fdi-cache
'';
daemonType = "fork";
# The `PATH=' works around a bug in HAL: it concatenates
# its libexec directory to $PATH, but using a 512-byte
# buffer. So if $PATH is too long it fails.
script = "PATH= exec ${hal}/sbin/hald --use-syslog";
};
services.udev.packages = [hal];
services.dbus.enable = true;
services.dbus.packages = [hal];
};
}

View File

@ -4,7 +4,9 @@ with pkgs.lib;
let
inherit (pkgs) stdenv writeText udev procps;
inherit (pkgs) stdenv writeText procps;
udev = config.systemd.package;
cfg = config.services.udev;
@ -24,20 +26,16 @@ let
udevRules = stdenv.mkDerivation {
name = "udev-rules";
buildCommand = ''
ensureDir $out
mkdir -p $out
shopt -s nullglob
# Set a reasonable $PATH for programs called by udev rules.
echo 'ENV{PATH}="${udevPath}/bin:${udevPath}/sbin"' > $out/00-path.rules
# Set the firmware search path so that the firmware.sh helper
# called by 50-firmware.rules works properly.
echo 'ENV{FIRMWARE_DIRS}="/root/test-firmware ${toString config.hardware.firmware}"' >> $out/00-path.rules
# Add the udev rules from other packages.
for i in ${toString cfg.packages}; do
echo "Adding rules for package $i"
for j in $i/*/udev/rules.d/*; do
for j in $i/{etc,lib}/udev/rules.d/*; do
echo "Copying $j to $out/$(basename $j)"
echo "# Copied from $j" > $out/$(basename $j)
cat $j >> $out/$(basename $j)
@ -53,12 +51,7 @@ let
--replace \"/bin/mount \"${pkgs.utillinux}/bin/mount
done
# If auto-configuration is disabled, then remove
# udev's 80-drivers.rules file, which contains rules for
# automatically calling modprobe.
${if !config.boot.hardwareScan then "rm $out/80-drivers.rules" else ""}
echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev ... "
echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... "
import_progs=$(grep 'IMPORT{program}="[^/$]' $out/* |
sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="[^/$]' |
@ -72,7 +65,7 @@ let
done
echo "OK"
echo -n "Checking that all programs call by absolute paths in udev rules exist ... "
echo -n "Checking that all programs called by absolute paths in udev rules exist... "
import_progs=$(grep 'IMPORT{program}="\/' $out/* |
sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="/' |
@ -90,24 +83,9 @@ let
for i in ${toString cfg.packages}; do
grep -l '\(RUN+\|IMPORT{program}\)="\(/usr\)\?/s\?bin' $i/*/udev/rules.d/* || true
done
# Use the persistent device rules (naming for CD/DVD and
# network devices) stored in
# /var/lib/udev/rules.d/70-persistent-{cd,net}.rules. These are
# modified by the write_{cd,net}_rules helpers called from
# 75-cd-aliases-generator.rules and
# 75-persistent-net-generator.rules.
ln -sv /var/lib/udev/rules.d/70-persistent-cd.rules $out/
ln -sv /var/lib/udev/rules.d/70-persistent-net.rules $out/
''; # */
};
# The udev configuration file.
conf = writeText "udev.conf" ''
udev_rules="${udevRules}"
#udev_log="debug"
'';
# Udev has a 512-character limit for ENV{PATH}, so create a symlink
# tree to work around this.
udevPath = pkgs.buildEnv {
@ -207,61 +185,15 @@ in
services.udev.extraRules = nixosRules;
services.udev.packages = [ pkgs.udev extraUdevRules ];
services.udev.packages = [ extraUdevRules ];
services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux pkgs.udev ];
services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
jobs.udev =
{ startOn = "startup";
environment = { UDEV_CONFIG_FILE = conf; };
path = [ udev ];
preStart =
''
echo "" > /proc/sys/kernel/hotplug || true
mkdir -p /var/lib/udev/rules.d
touch /var/lib/udev/rules.d/70-persistent-cd.rules /var/lib/udev/rules.d/70-persistent-net.rules
mkdir -p /dev/.udev # !!! bug in udev?
'';
daemonType = "fork";
exec = "udevd --daemon";
postStart =
''
# Do the loading of additional stage 2 kernel modules.
# This needs to be done while udevd is running, because
# the modules may call upon udev's firmware loading rule.
for i in ${toString config.boot.kernelModules}; do
echo "loading kernel module $i..."
${config.system.sbin.modprobe}/sbin/modprobe $i || true
done
'';
};
jobs.udevtrigger =
{ startOn = "started udev";
task = true;
path = [ udev ];
script =
''
# Let udev create device nodes for all modules that have already
# been loaded into the kernel (or for which support is built into
# the kernel).
udevadm trigger --action=add
udevadm settle || true # wait for udev to finish
initctl emit -n new-devices
'';
};
environment.etc =
[ { source = udevRules;
target = "udev/rules.d";
}
];
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isEnabled "UNIX")

View File

@ -35,11 +35,30 @@ with pkgs.lib;
services.udev.packages = [ pkgs.upower ];
systemd.services.upower =
{ description = "Power Management Daemon";
path = [ pkgs.glib ]; # needed for gdbus
serviceConfig =
{ Type = "dbus";
BusName = "org.freedesktop.UPower";
ExecStart = "@${pkgs.upower}/libexec/upowerd upowerd";
};
};
system.activationScripts.upower =
''
mkdir -m 0755 -p /var/lib/upower
'';
# The upower daemon seems to get stuck after doing a suspend
# (i.e. subsequent suspend requests will say "Sleep has already
# been requested and is pending"). So as a workaround, restart
# the daemon.
powerManagement.resumeCommands =
''
${config.systemd.package}/bin/systemctl try-restart upower
'';
};
}

View File

@ -1,19 +1,42 @@
{ config, pkgs, ... }:
###### implementation
with pkgs.lib;
{
###### interface
jobs.klogd =
{ description = "Kernel log daemon";
options = {
startOn = "started syslogd";
path = [ pkgs.sysklogd ];
exec =
"klogd -c 1 -2 -n " +
"-k $(dirname $(readlink -f /run/booted-system/kernel))/System.map";
services.klogd.enable = mkOption {
type = types.bool;
default = versionOlder (getVersion config.boot.kernelPackages.kernel) "3.5";
description = ''
Whether to enable klogd, the kernel log message processing
daemon. Since systemd handles logging of kernel messages on
Linux 3.5 and later, this is only useful if you're running an
older kernel.
'';
};
};
###### implementation
config = mkIf config.services.klogd.enable {
jobs.klogd =
{ description = "Kernel Log Daemon";
wantedBy = [ "multi-user.target" ];
path = [ pkgs.sysklogd ];
exec =
"klogd -c 1 -2 -n " +
"-k $(dirname $(readlink -f /run/booted-system/kernel))/System.map";
};
};
}

View File

@ -136,12 +136,11 @@ in
mkNameValuePairs = mergeConfigs;
};
} ( mkIf cfg.enable {
# Always log to stdout
services.logstash.outputConfig = { stdout = {}; };
jobs.logstash = with pkgs; {
systemd.services.logstash = with pkgs; {
description = "Logstash daemon";
startOn = "started networking and filesystem";
wantedBy = [ "multi-user.target" ];
environment.TZ = config.time.timeZone;
path = [ jre ];
@ -157,7 +156,7 @@ in
output {
${exprToConfig cfg.outputConfig}
}
''}";
''} &> /var/log/logstash.log";
};
})];
}

View File

@ -36,6 +36,15 @@ in
services.syslogd = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable syslogd. Note that systemd also logs
syslog messages, so you normally don't need to run syslogd.
'';
};
tty = mkOption {
type = types.uniq types.string;
default = "tty10";
@ -89,22 +98,27 @@ in
###### implementation
config = {
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.sysklogd ];
services.syslogd.extraParams = optional cfg.enableNetworkInput "-r";
jobs.syslogd =
{ description = "Syslog daemon";
# FIXME: restarting syslog seems to break journal logging.
systemd.services.syslog =
{ description = "Syslog Daemon";
startOn = "started udev";
requires = [ "syslog.socket" ];
environment = { TZ = config.time.timeZone; };
wantedBy = [ "multi-user.target" "syslog.target" ];
daemonType = "fork";
environment.TZ = config.time.timeZone;
path = [ pkgs.sysklogd ];
exec = "syslogd ${toString cfg.extraParams} -f ${syslogConf}";
serviceConfig =
{ ExecStart = "${pkgs.sysklogd}/sbin/syslogd ${toString cfg.extraParams} -f ${syslogConf} -n";
# Prevent syslogd output looping back through journald.
StandardOutput = "null";
};
};
};

View File

@ -364,22 +364,13 @@ in
# accurate way is unlikely to be better.
{ description = "Postfix mail server";
startOn = "started networking and filesystem";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
daemonType = "none";
respawn = true;
daemonType = "fork";
environment.TZ = config.time.timeZone;
script = ''
while ${pkgs.procps}/bin/ps `${pkgs.coreutils}/bin/cat /var/postfix/queue/pid/master.pid` |
grep -q postfix
do
${pkgs.coreutils}/bin/sleep 1m
done
'';
preStart =
''
if ! [ -d /var/spool/postfix ]; then
@ -402,11 +393,11 @@ in
${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
exec ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
'';
preStop = ''
exec ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
'';
};

View File

@ -4,6 +4,8 @@ with pkgs.lib;
let
cfg = config.nix;
inherit (config.environment) nix;
makeNixBuildUser = nr:
@ -74,9 +76,7 @@ in
gc-keep-outputs = true
gc-keep-derivations = true
";
description = "
This option allows to append lines to nix.conf.
";
description = "Additional text appended to <filename>nix.conf</filename>.";
};
distributedBuilds = mkOption {
@ -169,11 +169,9 @@ in
# actually a shell script.
envVars = mkOption {
internal = true;
default = "";
type = types.string;
description = "
Environment variables used by Nix.
";
default = {};
type = types.attrs;
description = "Environment variables used by Nix.";
};
nrBuildUsers = mkOption {
@ -186,6 +184,16 @@ in
'';
};
readOnlyStore = mkOption {
default = false;
description = ''
If set, NixOS will enforce the immutability of the Nix store
by making <filename>/nix/store</filename> a read-only bind
mount. Nix will automatically make the store writable when
needed.
'';
};
binaryCaches = mkOption {
default = [ http://nixos.org/binary-cache ];
type = types.list types.string;
@ -231,16 +239,16 @@ in
# /bin/sh won't work.
binshDeps = pkgs.writeReferencesToFile config.system.build.binsh;
in
pkgs.runCommand "nix.conf" {extraOptions = config.nix.extraOptions; } ''
pkgs.runCommand "nix.conf" {extraOptions = cfg.extraOptions; } ''
extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done)
cat > $out <<END
# WARNING: this file is generated.
build-users-group = nixbld
build-max-jobs = ${toString (config.nix.maxJobs)}
build-use-chroot = ${if config.nix.useChroot then "true" else "false"}
build-chroot-dirs = ${toString config.nix.chrootDirs} $(echo $extraPaths)
binary-caches = ${toString config.nix.binaryCaches}
trusted-binary-caches = ${toString config.nix.trustedBinaryCaches}
build-max-jobs = ${toString (cfg.maxJobs)}
build-use-chroot = ${if cfg.useChroot then "true" else "false"}
build-chroot-dirs = ${toString cfg.chrootDirs} $(echo $extraPaths)
binary-caches = ${toString cfg.binaryCaches}
trusted-binary-caches = ${toString cfg.trustedBinaryCaches}
$extraOptions
END
'';
@ -248,7 +256,7 @@ in
}
]
++ optional (config.nix.distributedBuilds && !config.nix.manualNixMachines)
++ optional (cfg.distributedBuilds && !cfg.manualNixMachines)
{ # List of machines for distributed Nix builds in the format expected
# by build-remote.pl.
source = pkgs.writeText "nix.machines"
@ -258,37 +266,61 @@ in
+ " ${machine.sshKey} ${toString machine.maxJobs} "
+ (if machine ? speedFactor then toString machine.speedFactor else "1" )
+ "\n"
) config.nix.buildMachines));
) cfg.buildMachines));
target = "nix.machines";
};
jobs.nixDaemon =
{ name = "nix-daemon";
systemd.sockets."nix-daemon" =
{ description = "Nix Daemon Socket";
wantedBy = [ "sockets.target" ];
before = [ "multi-user.target" ];
socketConfig.ListenStream = "/nix/var/nix/daemon-socket/socket";
};
startOn = "startup";
systemd.services."nix-daemon" =
{ description = "Nix Daemon";
path = [ nix pkgs.openssl pkgs.utillinux ]
++ optionals config.nix.distributedBuilds [ pkgs.openssh pkgs.gzip ];
++ optionals cfg.distributedBuilds [ pkgs.openssh pkgs.gzip ];
script =
''
${config.nix.envVars}
exec \
nice -n ${builtins.toString config.nix.daemonNiceLevel} \
ionice -n ${builtins.toString config.nix.daemonIONiceLevel} \
nix-worker --daemon > /dev/null 2>&1
'';
environment = cfg.envVars;
extraConfig =
''
limit nofile 4096 4096
'';
serviceConfig =
{ ExecStart = "@${nix}/bin/nix-daemon nix-daemon";
KillMode = "process";
Nice = cfg.daemonNiceLevel;
IOSchedulingPriority = cfg.daemonIONiceLevel;
LimitNOFILE = 4096;
};
};
nix.envVars =
{ NIX_CONF_DIR = "/etc/nix";
# Enable the copy-from-other-stores substituter, which allows builds
# to be sped up by copying build results from remote Nix stores. To
# do this, mount the remote file system on a subdirectory of
# /var/run/nix/remote-stores.
NIX_OTHER_STORES = "/var/run/nix/remote-stores/*/nix";
}
// optionalAttrs cfg.distributedBuilds {
NIX_BUILD_HOOK = "${config.environment.nix}/libexec/nix/build-remote.pl";
NIX_REMOTE_SYSTEMS = "/etc/nix.machines";
NIX_CURRENT_LOAD = "/var/run/nix/current-load";
}
# !!! These should not be defined here, but in some general proxy configuration module!
// optionalAttrs (cfg.proxy != "") {
http_proxy = cfg.proxy;
https_proxy = cfg.proxy;
ftp_proxy = cfg.proxy;
};
environment.shellInit =
''
# Set up the environment variables for running Nix.
${config.nix.envVars}
${concatMapStrings (n: "export ${n}=\"${getAttr n cfg.envVars}\"\n") (attrNames cfg.envVars)}
# Set up secure multi-user builds: non-root users build through the
# Nix daemon.
@ -299,36 +331,10 @@ in
fi
'';
nix.envVars =
''
export NIX_CONF_DIR=/etc/nix
# Enable the copy-from-other-stores substituter, which allows builds
# to be sped up by copying build results from remote Nix stores. To
# do this, mount the remote file system on a subdirectory of
# /var/run/nix/remote-stores.
export NIX_OTHER_STORES=/var/run/nix/remote-stores/*/nix
'' # */
+ optionalString config.nix.distributedBuilds ''
export NIX_BUILD_HOOK=${config.environment.nix}/libexec/nix/build-remote.pl
export NIX_REMOTE_SYSTEMS=/etc/nix.machines
export NIX_CURRENT_LOAD=/var/run/nix/current-load
''
# !!! These should not be defined here, but in some general proxy configuration module!
+ optionalString (config.nix.proxy != "") ''
export http_proxy=${config.nix.proxy}
export https_proxy=${config.nix.proxy}
export ftp_proxy=${config.nix.proxy}
'';
users.extraUsers = map makeNixBuildUser (range 1 config.nix.nrBuildUsers);
users.extraUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers);
system.activationScripts.nix = stringAfter [ "etc" "users" ]
''
# Set up Nix.
chown root:nixbld /nix/store
chmod 1775 /nix/store
# Nix initialisation.
mkdir -m 0755 -p \
/nix/var/nix/gcroots \
@ -340,9 +346,10 @@ in
/nix/var/log/nix/drvs \
/nix/var/nix/channel-cache \
/nix/var/nix/chroots
mkdir -m 1777 -p /nix/var/nix/gcroots/per-user
mkdir -m 1777 -p /nix/var/nix/profiles/per-user
mkdir -m 1777 -p /nix/var/nix/gcroots/tmp
mkdir -m 1777 -p \
/nix/var/nix/gcroots/per-user \
/nix/var/nix/profiles/per-user \
/nix/var/nix/gcroots/tmp
ln -sf /nix/var/nix/profiles /nix/var/nix/gcroots/
ln -sf /nix/var/nix/manifests /nix/var/nix/gcroots/

View File

@ -3,7 +3,6 @@
with pkgs.lib;
let
nix = config.environment.nix;
cfg = config.nix.gc;
in
@ -16,7 +15,7 @@ in
automatic = mkOption {
default = false;
example = true;
type = types.bool;
description = "
Automatically run the garbage collector at specified dates.
";
@ -24,6 +23,7 @@ in
dates = mkOption {
default = "15 03 * * *";
type = types.string;
description = "
Run the garbage collector at specified dates to avoid full
hard-drives.
@ -33,6 +33,7 @@ in
options = mkOption {
default = "";
example = "--max-freed $((64 * 1024**3))";
type = types.string;
description = "
Options given to <filename>nix-collect-garbage</filename> when the
garbage collector is run automatically.
@ -45,10 +46,17 @@ in
###### implementation
config = mkIf cfg.automatic {
services.cron.systemCronJobs = [
"${cfg.dates} root ${nix}/bin/nix-collect-garbage ${cfg.options} > /var/log/gc.log 2>&1"
];
config = {
services.cron.systemCronJobs = mkIf cfg.automatic (singleton
"${cfg.dates} root ${config.systemd.package}/bin/systemctl start nix-gc.service");
systemd.services."nix-gc" =
{ description = "Nix Garbage Collector";
path = [ config.environment.nix ];
script = "exec nix-collect-garbage ${cfg.options}";
};
};
}

View File

@ -16,6 +16,17 @@ let
inherit pkgs options;
};
entry = "${manual.manual}/share/doc/nixos/manual.html";
help = pkgs.writeScriptBin "nixos-help"
''
#! ${pkgs.stdenv.shell} -e
if ! ''${BROWSER:-w3m} ${entry}; then
echo "$0: unable to start a web browser; please set \$BROWSER or install w3m"
exit 1
fi
'';
in
{
@ -69,23 +80,23 @@ in
system.build.manual = manual;
environment.systemPackages = [ manual.manpages ];
environment.systemPackages = [ manual.manpages help ];
boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"];
jobs = mkIf cfg.showManual
{ nixosManual =
{ name = "nixos-manual";
description = "NixOS manual";
startOn = "started udev";
exec =
''
${cfg.browser} ${manual.manual}/share/doc/nixos/manual.html \
< /dev/tty${toString cfg.ttyNumber} > /dev/tty${toString cfg.ttyNumber} 2>&1
'';
systemd.services = optionalAttrs cfg.showManual
{ "nixos-manual" =
{ description = "NixOS Manual";
wantedBy = [ "multi-user.target" ];
serviceConfig =
{ ExecStart = "${cfg.browser} ${entry}";
StandardInput = "tty";
StandardOutput = "tty";
TTYPath = "/dev/tty${cfg.ttyNumber}";
TTYReset = true;
TTYVTDisallocate = true;
Restart = "always";
};
};
};

View File

@ -40,14 +40,18 @@ in
boot.extraTTYs = [ cfg.tty ];
jobs.rogue =
systemd.services.rogue =
{ description = "Rogue dungeon crawling game";
startOn = "started udev";
extraConfig = "chdir /root";
exec = "${pkgs.rogue}/bin/rogue < /dev/${cfg.tty} > /dev/${cfg.tty} 2>&1";
wantedBy = [ "multi-user.target" ];
serviceConfig =
{ ExecStart = "${pkgs.rogue}/bin/rogue";
StandardInput = "tty";
StandardOutput = "tty";
TTYPath = "/dev/${cfg.tty}";
TTYReset = true;
TTYVTDisallocate = true;
Restart = "always";
};
};
services.ttyBackgrounds.specificThemes = singleton

View File

@ -0,0 +1,58 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
cfg = config.services.dd-agent;
datadog-conf = pkgs.runCommand "datadog.conf" {} ''
sed -e 's|^api_key:|api_key: ${cfg.api_key}|' ${optionalString (cfg.hostname != null)
"-e 's|^#hostname: mymachine.mydomain|hostname: ${cfg.hostname}|'"
} ${pkgs.dd-agent}/etc/dd-agent/datadog.conf.example > $out
'';
in {
options.services.dd-agent = {
enable = mkOption {
description = "Whether to enable the dd-agent montioring service";
default = false;
type = types.bool;
};
# !!! This gets stored in the store (world-readable), wish we had https://github.com/NixOS/nix/issues/8
api_key = mkOption {
description = "The Datadog API key to associate the agent with your account";
example = "ae0aa6a8f08efa988ba0a17578f009ab";
type = types.uniq types.string;
};
hostname = mkOption {
description = "The hostname to show in the Datadog dashboard (optional)";
default = null;
example = "mymachine.mydomain";
type = types.uniq (types.nullOr types.string);
};
};
config = mkIf cfg.enable {
environment.etc = [ { source = datadog-conf; target = "dd-agent/datadog.conf"; } ];
systemd.services.dd-agent = {
description = "Datadog agent monitor";
path = [ pkgs.sysstat pkgs.procps ];
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.dd-agent}/bin/dd-agent foreground";
restartTriggers = [ pkgs.dd-agent ];
};
};
}

View File

@ -159,12 +159,7 @@ in
environment.systemPackages = [ pkgs.nagios ];
jobs.nagios =
{ # Run `nagios -v' to check the validity of the configuration file so
# that a nixos-rebuild fails *before* we kill the running Nagios
# daemon.
buildHook = "${pkgs.nagios}/bin/nagios -v ${nagiosCfgFile}";
description = "Nagios monitoring daemon";
{ description = "Nagios monitoring daemon";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";

View File

@ -57,7 +57,7 @@ in
description = ''
Additional options for each device that is monitored. The example
turns on SMART Automatic Offline Testing on startup, and schedules short
self-tests daily, and long self-tests weekly.
self-tests daily, and long self-tests weekly.
'';
};
@ -81,17 +81,15 @@ in
config = mkIf cfg.enable {
jobs.smartd = {
description = "S.M.A.R.T. Daemon";
systemd.services.smartd = {
description = "S.M.A.R.T. Daemon";
environment.TZ = config.time.timeZone;
environment.TZ = config.time.timeZone;
startOn = "started syslogd";
wantedBy = [ "multi-user.target" ];
path = [ pkgs.smartmontools ];
exec = "smartd --no-fork --pidfile=/var/run/smartd.pid ${smartdFlags}";
};
serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork ${smartdFlags}";
};
};

View File

@ -73,15 +73,12 @@ in
description = "Zabbix daemon user";
};
jobs.zabbix_agent =
{ name = "zabbix-agent";
systemd.services."zabbix-agent" =
{ description = "Zabbix Agent";
description = "Zabbix agent daemon";
wantedBy = [ "multi-user.target" ];
startOn = "ip-up";
stopOn = "stopping network-interfaces";
path = [ pkgs.zabbix.agent ];
path = [ pkgs.nettools ];
preStart =
''
@ -89,30 +86,11 @@ in
chown zabbix ${stateDir} ${logDir}
'';
# Zabbix doesn't have an option not to daemonize, and doesn't
# daemonize in a way that allows Upstart to track it. So to
# make sure that we notice when it goes down, we start Zabbix
# with an open connection to a fifo, with a `cat' on the other
# side. If Zabbix dies, then `cat' will exit as well, so we
# just monitor `cat'.
script =
''
export PATH=${pkgs.nettools}/bin:$PATH
rm -f ${stateDir}/dummy2
mkfifo ${stateDir}/dummy2
cat ${stateDir}/dummy2 &
pid=$!
zabbix_agentd --config ${configFile} 100>${stateDir}/dummy2
wait "$pid"
'';
postStop =
''
pid=$(cat ${pidFile} 2> /dev/null || true)
(test -n "$pid" && kill "$pid") || true
# Wait until they're really gone.
while ${pkgs.procps}/bin/pgrep -u zabbix zabbix_agentd > /dev/null; do sleep 1; done
'';
serviceConfig.ExecStart = "@${pkgs.zabbix.agent}/sbin/zabbix_agentd zabbix_agentd --config ${configFile}";
serviceConfig.Type = "forking";
serviceConfig.RemainAfterExit = true;
serviceConfig.Restart = "always";
serviceConfig.RestartSec = 2;
};
environment.systemPackages = [ pkgs.zabbix.agent ];

View File

@ -73,12 +73,11 @@ in
description = "Zabbix daemon user";
};
jobs.zabbix_server =
{ name = "zabbix-server";
systemd.services."zabbix-server" =
{ description = "Zabbix Server";
description = "Zabbix server daemon";
startOn = "filesystem";
wantedBy = [ "multi-user.target" ];
after = optional (cfg.dbServer == "localhost") "postgresql.service";
preStart =
''
@ -95,31 +94,12 @@ in
fi
'';
path = [ pkgs.nettools pkgs.zabbix.server ];
path = [ pkgs.nettools ];
# Zabbix doesn't have an option not to daemonize, and doesn't
# daemonize in a way that allows Upstart to track it. So to
# make sure that we notice when it goes down, we start Zabbix
# with an open connection to a fifo, with a `cat' on the other
# side. If Zabbix dies, then `cat' will exit as well, so we
# just monitor `cat'.
script =
''
rm -f ${stateDir}/dummy
mkfifo ${stateDir}/dummy
cat ${stateDir}/dummy &
pid=$!
zabbix_server --config ${configFile} 100>${stateDir}/dummy
wait "$pid"
'';
postStop =
''
pid=$(cat ${pidFile} 2> /dev/null || true)
(test -n "$pid" && kill "$pid") || true
# Wait until they're really gone.
while ${pkgs.procps}/bin/pkill -u zabbix zabbix_server; do true; done
'';
serviceConfig.ExecStart = "@${pkgs.zabbix.server}/sbin/zabbix_server zabbix_server --config ${configFile}";
serviceConfig.Type = "forking";
serviceConfig.Restart = "always";
serviceConfig.RestartSec = 2;
};
};

View File

@ -80,44 +80,44 @@ in
boot.kernelModules = [ "nfsd" ];
jobs.nfsd =
{ description = "Kernel NFS server";
systemd.services.nfsd =
{ description = "NFS Server";
startOn = "started networking";
wantedBy = [ "multi-user.target" ];
requires = [ "rpcbind.service" "mountd.service" ];
after = [ "rpcbind.service" "mountd.service" "statd.service" ];
path = [ pkgs.nfsUtils ];
preStart =
script =
''
ensure rpcbind
ensure mountd
# Create a state directory required by NFSv4.
mkdir -p /var/lib/nfs/v4recovery
rpc.nfsd \
${if cfg.hostName != null then "-H ${cfg.hostName}" else ""} \
${builtins.toString cfg.nproc}
sm-notify -d
'';
postStop = "rpc.nfsd 0";
postStart =
''
ensure statd
ensure idmapd
'';
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
};
jobs.mountd =
{ description = "Kernel NFS server - mount daemon";
systemd.services.mountd =
{ description = "NFSv3 Mount Daemon";
requires = [ "rpcbind.service" ];
after = [ "rpcbind.service" ];
path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
preStart =
''
ensure rpcbind
mkdir -p /var/lib/nfs
touch /var/lib/nfs/rmtab
@ -133,14 +133,14 @@ in
''
}
# exports file is ${exports}
# keep this comment so that this job is restarted whenever exports changes!
exportfs -ra
'';
daemonType = "fork";
restartTriggers = [ exports ];
exec = "rpc.mountd -f /etc/exports";
serviceConfig.Type = "forking";
serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.mountd rpc.mountd -f /etc/exports";
serviceConfig.Restart = "always";
};
};

View File

@ -26,18 +26,14 @@ let
mkdir -p /var/samba/locks /var/samba/cores/nmbd /var/samba/cores/smbd /var/samba/cores/winbindd
fi
passwdFile="$(sed -n 's/^.*smb[ ]\+passwd[ ]\+file[ ]\+=[ ]\+\(.*\)/\1/p' ${configFile})"
passwdFile="$(${pkgs.gnused}/bin/sed -n 's/^.*smb[ ]\+passwd[ ]\+file[ ]\+=[ ]\+\(.*\)/\1/p' ${configFile})"
if [ -n "$passwdFile" ]; then
echo 'INFO: creating directory containing passwd file'
echo 'INFO: [samba] creating directory containing passwd file'
mkdir -p "$(dirname "$passwdFile")"
fi
mkdir -p ${logDir}
mkdir -p ${privateDir}
# The following line is to trigger a restart of the daemons when
# the configuration changes:
# ${configFile}
'';
configFile = pkgs.writeText "smb.conf"
@ -60,12 +56,11 @@ let
# This may include nss_ldap, needed for samba if it has to use ldap.
nssModulesPath = config.system.nssModules.path;
daemonJob = appName: args:
{ name = "samba-${appName}";
description = "Samba Service daemon ${appName}";
daemonService = appName: args:
{ description = "Samba Service daemon ${appName}";
startOn = "started samba";
stopOn = "stopping samba";
wantedBy = [ "samba.target" ];
partOf = [ "samba.target" ];
environment = {
LD_LIBRARY_PATH = nssModulesPath;
@ -73,9 +68,12 @@ let
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};
daemonType = "fork";
serviceConfig = {
ExecStart = "${samba}/sbin/${appName} ${args}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
};
exec = "${samba}/sbin/${appName} ${args}";
restartTriggers = [ configFile ];
};
in
@ -202,22 +200,26 @@ in
};
# Dummy job to start the real Samba daemons (nmbd, smbd, winbindd).
jobs.sambaControl =
{ name = "samba";
systemd = {
targets.samba = {
description = "Samba server";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
preStart = setupScript;
requires = [ "samba-setup.service" ];
after = [ "samba-setup.service" "network.target" ];
wantedBy = [ "multi-user.target" ];
};
jobs.nmbd = daemonJob "nmbd" "-D";
services = {
"samba-nmbd" = daemonService "nmbd" "-F";
"samba-smbd" = daemonService "smbd" "-F";
"samba-winbindd" = daemonService "winbindd" "-F";
"samba-setup" = {
description = "Samba setup task";
script = setupScript;
unitConfig.RequiresMountsFor = "/home/smbd /var/samba /var/log/samba";
};
};
};
jobs.smbd = daemonJob "smbd" "-D";
jobs.winbindd = daemonJob "winbindd" "-D";
})
];

View File

@ -9,7 +9,7 @@ let
# Don't start dhclient on explicitly configured interfaces or on
# interfaces that are part of a bridge.
ignoredInterfaces =
map (i: i.name) (filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces)
map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
++ config.networking.dhcpcd.denyInterfaces;
@ -52,20 +52,19 @@ let
''}
if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then
# Restart ntpd. (The "ip-up" event below will trigger the
# restart.) We need to restart it to make sure that it will
# actually do something: if ntpd cannot resolve the server
# hostnames in its config file, then it will never do
# Restart ntpd. We need to restart it to make sure that it
# will actually do something: if ntpd cannot resolve the
# server hostnames in its config file, then it will never do
# anything ever again ("couldn't resolve ..., giving up on
# it"), so we silently lose time synchronisation.
${config.system.build.upstart}/sbin/initctl stop ntpd
${config.systemd.package}/bin/systemctl try-restart ntpd.service
${config.system.build.upstart}/sbin/initctl emit -n ip-up $params
${config.systemd.package}/bin/systemctl start ip-up.target
fi
if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
${config.system.build.upstart}/sbin/initctl emit -n ip-down $params
fi
#if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
# ${config.systemd.package}/bin/systemctl start ip-down.target
#fi
'';
in
@ -93,12 +92,27 @@ in
config = mkIf config.networking.useDHCP {
jobs.dhcpcd =
{ startOn = "started network-interfaces";
systemd.services.dhcpcd =
{ description = "DHCP Client";
wantedBy = [ "network.target" ];
after = [ "systemd-udev-settle.service" ];
# Stopping dhcpcd during a reconfiguration is undesirable
# because it brings down the network interfaces configured by
# dhcpcd. So do a "systemctl restart" instead.
stopIfChanged = false;
path = [ dhcpcd pkgs.nettools pkgs.openresolv ];
exec = "dhcpcd --config ${dhcpcdConf} --nobackground";
serviceConfig =
{ Type = "forking";
PIDFile = "/run/dhcpcd.pid";
ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --config ${dhcpcdConf}";
ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind";
StandardError = "null";
Restart = "always";
};
};
environment.systemPackages = [ dhcpcd ];
@ -112,8 +126,7 @@ in
powerManagement.resumeCommands =
''
# Tell dhcpcd to rebind its interfaces if it's running.
status="$(${config.system.build.upstart}/sbin/status dhcpcd)"
[[ "$status" =~ start/running ]] && ${dhcpcd}/sbin/dhcpcd --rebind
${config.systemd.package}/bin/systemctl reload dhcpcd.service
'';
};

View File

@ -236,14 +236,15 @@ in
];
jobs.firewall =
{ startOn = "started network-interfaces";
{ description = "Firewall";
startOn = "started network-interfaces";
path = [ pkgs.iptables ];
preStart =
''
${helpers}
set -x
# Flush the old firewall rules. !!! Ideally, updating the
# firewall would be atomic. Apparently that's possible

View File

@ -56,22 +56,31 @@ in
config = mkIf cfg.enable {
boot.kernelModules = [ "tun" ];
# environment.systemPackages = [pkgs.gogoclient];
networking.enableIPv6 = true;
jobs.gogoclient = {
name = "gogoclient";
systemd.services.gogoclient = {
description = "ipv6 tunnel";
startOn = optionalString cfg.autorun "starting networking";
stopOn = "stopping network-interfaces";
preStart = ''
mkdir -p /var/lib/gogoc
chmod 700 /var/lib/gogoc
cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | ${pkgs.gnused}/bin/sed -e "s|^userid=|&${cfg.username}|;s|^passwd=|&${if cfg.password == "" then "" else "$(cat ${cfg.password})"}|;s|^server=.*|server=${cfg.server}|;s|^auth_method=.*|auth_method=${if cfg.password == "" then "anonymous" else "any"}|;s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf
after = [ "network.target" ];
requires = [ "network.target" ];
unitConfig.RequiresMountsFor = "/var/lib/gogoc";
script = let authMethod = if cfg.password == "" then "anonymous" else "any"; in ''
mkdir -p -m 700 /var/lib/gogoc
cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | \
${pkgs.gnused}/bin/sed \
-e "s|^userid=|&${cfg.username}|" \
-e "s|^passwd=|&${optionalString (cfg.password != "") "$(cat ${cfg.password})"}|" \
-e "s|^server=.*|server=${cfg.server}|" \
-e "s|^auth_method=.*|auth_method=${authMethod}|" \
-e "s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf
cd /var/lib/gogoc
exec ${pkgs.gogoclient}/bin/gogoc -y -f /var/lib/gogoc/gogoc.conf
'';
script = "cd /var/lib/gogoc; exec gogoc -y -f ./gogoc.conf";
path = [pkgs.gogoclient];
} // optionalAttrs cfg.autorun {
wantedBy = [ "ip-up.target" ];
partOf = [ "ip-up.target" ];
};
};

View File

@ -1,13 +1,14 @@
{ config, pkgs, ... }:
with pkgs.lib;
with pkgs;
let
cfg = config.networking.networkmanager;
stateDirs = "/var/lib/NetworkManager /var/lib/dhclient";
configFile = pkgs.writeText "NetworkManager.conf" ''
configFile = writeText "NetworkManager.conf" ''
[main]
plugins=keyfile
@ -36,10 +37,10 @@ let
ResultActive=yes
'';
ipUpScript = pkgs.writeScript "01nixos-ip-up" ''
ipUpScript = writeScript "01nixos-ip-up" ''
#!/bin/sh
if test "$2" = "up"; then
${pkgs.upstart}/sbin/initctl emit ip-up "IFACE=$1"
${config.systemd.package}/bin/systemctl start ip-up.target
fi
'';
@ -67,7 +68,7 @@ in {
Extra packages that provide NetworkManager plugins.
'';
merge = mergeListOption;
apply = list: [ pkgs.networkmanager pkgs.modemmanager ] ++ list;
apply = list: [ networkmanager modemmanager wpa_supplicant ] ++ list;
};
};
@ -76,10 +77,14 @@ in {
config = mkIf cfg.enable {
environment.etc = singleton {
source = ipUpScript;
target = "NetworkManager/dispatcher.d/01nixos-ip-up";
};
environment.etc = [
{ source = ipUpScript;
target = "NetworkManager/dispatcher.d/01nixos-ip-up";
}
{ source = configFile;
target = "NetworkManager/NetworkManager.conf";
}
];
environment.systemPackages = cfg.packages;
@ -88,24 +93,31 @@ in {
gid = config.ids.gids.networkmanager;
};
jobs.networkmanager = {
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
systemd.packages = cfg.packages;
path = [ pkgs.networkmanager ];
preStart = ''
mkdir -m 755 -p /etc/NetworkManager
# Create an initialisation service that both starts
# NetworkManager when network.target is reached,
# and sets up necessary directories for NM.
systemd.services."networkmanager-init" = {
description = "NetworkManager initialisation";
wantedBy = [ "network.target" ];
partOf = [ "NetworkManager.service" ];
wants = [ "NetworkManager.service" ];
before = [ "NetworkManager.service" ];
script = ''
mkdir -m 700 -p /etc/NetworkManager/system-connections
mkdir -m 755 -p ${stateDirs}
'';
exec = "NetworkManager --config=${configFile} --no-daemon";
serviceConfig = {
Type = "oneshot";
};
};
networking.useDHCP = false;
networking.wireless.enable = true;
# Turn off NixOS' network management
networking = {
useDHCP = false;
wireless.enable = false;
};
security.polkit.permissions = polkitConf;

View File

@ -66,9 +66,10 @@ in
};
jobs.ntpd =
{ description = "NTP daemon";
{ description = "NTP Daemon";
startOn = "ip-up";
wantedBy = [ "ip-up.target" ];
partOf = [ "ip-up.target" ];
path = [ ntp ];

View File

@ -11,8 +11,8 @@ let
makeOpenVPNJob = cfg: name:
let
path = (getAttr "openvpn-${name}" config.jobs).path;
path = (getAttr "openvpn-${name}" config.systemd.services).path;
upScript = ''
#! /bin/sh
exec > /var/log/openvpn-${name}-up 2>&1
@ -28,17 +28,17 @@ let
fi
fi
done
${cfg.up}
'';
downScript = ''
#! /bin/sh
exec > /var/log/openvpn-${name}-down 2>&1
export PATH=${path}
${cfg.down}
'';
configFile = pkgs.writeText "openvpn-config-${name}"
''
${optionalString (cfg.up != "" || cfg.down != "") "script-security 2"}
@ -46,7 +46,7 @@ let
${optionalString (cfg.up != "") "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
${optionalString (cfg.down != "") "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
'';
in {
description = "OpenVPN instance ${name}";
@ -76,7 +76,7 @@ in
default = {};
example = {
server = {
config = ''
# Simplest server configuration: http://openvpn.net/index.php/documentation/miscellaneous/static-key-mini-howto.html.
@ -88,7 +88,7 @@ in
up = "ip route add ...";
down = "ip route del ...";
};
client = {
config = ''
client
@ -103,7 +103,7 @@ in
up = "echo nameserver $nameserver | ${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev";
down = "${pkgs.openresolv}/sbin/resolvconf -d $dev";
};
};
description = ''
@ -116,7 +116,7 @@ in
'';
type = types.attrsOf types.optionSet;
options = {
config = mkOption {
@ -158,9 +158,9 @@ in
jobs = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers);
environment.systemPackages = [ openvpn ];
boot.kernelModules = [ "tun" ];
};
}

View File

@ -29,6 +29,8 @@ let
'';
};
check = mkAssert (!(config.services.rpcbind.enable && config.services.portmap.enable))
"Portmap and rpcbind cannot both be enabled.";
in
@ -57,24 +59,26 @@ in
###### implementation
config = mkIf config.services.rpcbind.enable {
config = mkIf config.services.rpcbind.enable (check {
environment.etc = [netconfigFile];
environment.systemPackages = [ pkgs.rpcbind ];
jobs.rpcbind =
{ description = "ONC RPC rpcbind";
environment.etc = [ netconfigFile ];
startOn = "started network-interfaces";
stopOn = "";
systemd.services.rpcbind =
{ description = "ONC RPC Directory Service";
daemonType = "fork";
wantedBy = [ "multi-user.target" ];
exec =
''
${pkgs.rpcbind}/bin/rpcbind
'';
requires = [ "basic.target" ];
after = [ "basic.target" ];
unitConfig.DefaultDependencies = false; # don't stop during shutdown
serviceConfig.Type = "forking";
serviceConfig.ExecStart = "@${pkgs.rpcbind}/bin/rpcbind rpcbind";
};
};
});
}

View File

@ -39,6 +39,7 @@ let
);
userOptions = {
openssh.authorizedKeys = {
keys = mkOption {
type = types.listOf types.string;
@ -63,6 +64,7 @@ let
'';
};
};
};
authKeysFiles = let
@ -114,14 +116,13 @@ in
};
permitRootLogin = mkOption {
default = "yes";
default = "without-password";
check = permitRootLoginCheck;
description = ''
Whether the root user can login using ssh. Valid values are
<literal>yes</literal>, <literal>without-password</literal>,
<literal>forced-commands-only</literal> or
<literal>no</literal>.
If without-password doesn't work try <literal>yes</literal>.
'';
};
@ -261,20 +262,18 @@ in
}
];
jobs.sshd = {
systemd.services.sshd =
{ description = "SSH Daemon";
description = "OpenSSH server";
wantedBy = [ "multi-user.target" ];
startOn = "started network-interfaces";
environment = {
LD_LIBRARY_PATH = nssModulesPath;
# Duplicated from bashrc. OpenSSH needs a patch for this.
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};
stopIfChanged = false;
path = [ pkgs.openssh ];
environment.LD_LIBRARY_PATH = nssModulesPath;
environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
preStart =
''
mkdir -m 0755 -p /etc/ssh
@ -284,22 +283,28 @@ in
fi
'';
daemonType = "fork";
exec =
''
${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} \
-f ${pkgs.writeText "sshd_config" cfg.extraConfig}
'';
serviceConfig =
{ ExecStart =
"${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} " +
"-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
Restart = "always";
Type = "forking";
KillMode = "process";
PIDFile = "/run/sshd.pid";
};
};
networking.firewall.allowedTCPPorts = cfg.ports;
security.pam.services = optional cfg.usePAM { name = "sshd"; startSession = true; showMotd = true; };
services.openssh.authorizedKeysFiles =
[ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
services.openssh.extraConfig =
''
PidFile /run/sshd.pid
Protocol 2
UsePAM ${if cfg.usePAM then "yes" else "no"}
@ -328,11 +333,14 @@ in
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"}
PrintMotd no # handled by pam_motd
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
'';
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";}];
};
}

View File

@ -45,15 +45,15 @@ in
description = ''
The interfaces <command>wpa_supplicant</command> will use. If empty, it will
automatically use all wireless interfaces. (Note that auto-detection is currently
broken on Linux 3.4.x kernels. See http://github.com/NixOS/nixos/issues/10 for
further details.)
broken on Linux 3.4.x kernels. See http://github.com/NixOS/nixos/issues/10 for
further details.)
'';
};
driver = mkOption {
default = "";
example = "nl80211";
description = "force a specific wpa_supplicant driver";
description = "Force a specific wpa_supplicant driver.";
};
userControlled = {
@ -66,7 +66,7 @@ in
When you want to use this, make sure ${configFile} doesn't exist.
It will be created for you.
Currently it is also necesarry to explicitly specify networking.wireless.interfaces
Currently it is also necessary to explicitly specify networking.wireless.interfaces.
'';
};
@ -74,7 +74,7 @@ in
default = "wheel";
example = "network";
type = types.string;
description = "members of this group can control wpa_supplicant";
description = "Members of this group can control wpa_supplicant.";
};
};
};
@ -90,8 +90,10 @@ in
services.dbus.packages = [ pkgs.wpa_supplicant ];
jobs.wpa_supplicant =
{ startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
{ description = "WPA Supplicant";
wantedBy = [ "network.target" ];
after = [ "systemd-udev-settle.service" ];
path = [ pkgs.wpa_supplicant ];
@ -122,7 +124,7 @@ in
powerManagement.resumeCommands =
''
${config.system.build.upstart}/sbin/restart wpa_supplicant
${config.systemd.package}/bin/systemctl try-restart wpa_supplicant
'';
assertions = [{ assertion = !cfg.userControlled.enable || cfg.interfaces != [];

View File

@ -118,7 +118,7 @@ in
boot.blacklistedKernelModules = [ "usblp" ];
jobs.cupsd =
{ description = "CUPS printing daemon";
{ description = "CUPS Printing Daemon";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";

View File

@ -64,7 +64,7 @@ in
};
jobs.atd =
{ description = "at daemon (atd)";
{ description = "Job Execution Daemon (atd)";
startOn = "stopped udevtrigger";

View File

@ -86,7 +86,7 @@ in
environment.systemPackages = [ cronNixosPkg ];
jobs.cron =
{ description = "Cron daemon";
{ description = "Cron Daemon";
startOn = "startup";

View File

@ -1,146 +0,0 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
cfg = config.services.cgroups;
cgconfigConf = pkgs.writeText "cgconfig.conf" cfg.groups;
cgrulesConf = pkgs.writeText "cgrules.conf" cfg.rules;
in
{
###### interface
options = {
services.cgroups.enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable support for control groups, a Linux kernel
feature for resource management. It allows you to assign
processes to groups that share certain resource limits (e.g.,
CPU or memory). The <command>cgrulesengd</command> daemon
automatically assigns processes to the right cgroup depending
on the rules defined in
<option>services.cgroups.rules</option>.
'';
};
services.cgroups.groups = mkOption {
type = types.string;
default =
''
mount {
cpu = /sys/fs/cgroup/cpu;
}
'';
example =
''
mount {
cpu = /sys/fs/cgroup/cpu;
cpuacct = /sys/fs/cgroup/cpuacct;
}
# Create a "www" cgroup with a lower share of the CPU (the
# default is 1024).
group www {
cpu {
cpu.shares = "500";
}
}
'';
description = ''
The contents of the <filename>cgconfig.conf</filename>
configuration file, which defines the cgroups.
'';
};
services.cgroups.rules = mkOption {
type = types.string;
default = "";
example =
''
# All processes executed by the "wwwrun" uid should be
# assigned to the "www" CPU cgroup.
wwwrun cpu www
'';
description = ''
The contents of the <filename>cgrules.conf</filename>
configuration file, which determines to which cgroups
processes should be assigned by the
<command>cgrulesengd</command> daemon.
'';
};
};
###### implementation
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.libcgroup ];
environment.etc =
[ { source = cgconfigConf;
target = "cgconfig.conf";
}
{ source = cgrulesConf;
target = "cgrules.conf";
}
];
# The daemon requires the userspace<->kernelspace netlink
# connector.
boot.kernelModules = [ "cn" ];
jobs.cgroups =
{ startOn = "startup";
description = "Control groups daemon";
path = [ pkgs.libcgroup pkgs.procps pkgs.utillinux ];
preStart =
''
if [ -d /sys/fs/cgroup ]; then
if ! mountpoint -q /sys/fs/cgroup; then
mount -t tmpfs -o mode=755 /dev/cgroup /sys/fs/cgroup
fi
fi
cgclear || true
# Mount the cgroup hierarchies. Note: we refer to the
# store path of cgconfig.conf here to ensure that the job
# gets reloaded if the configuration changes.
cgconfigparser -l ${cgconfigConf}
# Move existing processes to the right cgroup.
cgclassify --cancel-sticky $(ps --no-headers -eL o tid) || true
# Force a restart if the rules change:
# ${cgrulesConf}
'';
# Run the daemon that moves new processes to the right cgroup.
exec = "cgrulesengd";
daemonType = "fork";
postStop =
''
cgclear
'';
};
};
}

View File

@ -116,6 +116,33 @@ in
gid = config.ids.gids.messagebus;
};
# FIXME: these are copied verbatim from the dbus source tree. We
# should install and use the originals.
systemd.units."dbus.socket".text =
''
[Unit]
Description=D-Bus System Message Bus Socket
[Socket]
ListenStream=/var/run/dbus/system_bus_socket
'';
systemd.units."dbus.service".text =
''
[Unit]
Description=D-Bus System Message Bus
Requires=dbus.socket
After=syslog.target
[Service]
ExecStartPre=${pkgs.dbus_tools}/bin/dbus-uuidgen --ensure
ExecStartPre=-${pkgs.coreutils}/bin/rm -f /var/run/dbus/pid
ExecStart=${pkgs.dbus_daemon}/bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation
ExecReload=${pkgs.dbus_tools}/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
OOMScoreAdjust=-900
'';
/*
jobs.dbus =
{ startOn = "started udev and started syslogd";
@ -138,15 +165,6 @@ in
exec = "dbus-daemon --system";
/*
postStart =
''
# Signal Upstart to connect to the system bus. This
# allows initctl to work for non-root users.
kill -USR1 1
'';
*/
postStop =
''
# !!! Hack: doesn't belong here.
@ -157,6 +175,7 @@ in
fi
'';
};
*/
security.setuidOwners = singleton
{ program = "dbus-daemon-launch-helper";

View File

@ -20,15 +20,14 @@ in
enable = mkOption {
default = true;
description = "
Whether to enable the Name Service Cache Daemon.
";
description = "Whether to enable the Name Service Cache Daemon.";
};
};
};
###### implementation
config = mkIf config.services.nscd.enable {
@ -39,37 +38,31 @@ in
description = "Name service cache daemon user";
};
jobs.nscd =
systemd.services.nscd =
{ description = "Name Service Cache Daemon";
startOn = "startup";
wantedBy = [ "nss-lookup.target" "nss-user-lookup.target" ];
environment = { LD_LIBRARY_PATH = nssModulesPath; };
preStart =
''
mkdir -m 0755 -p /var/run/nscd
mkdir -m 0755 -p /run/nscd
rm -f /run/nscd/nscd.pid
mkdir -m 0755 -p /var/db/nscd
'';
path = [ pkgs.glibc ];
exec = "nscd -f ${./nscd.conf} -d 2> /dev/null";
};
# Flush nscd's hosts database when the network comes up or the
# system configuration changes to get rid of any negative entries.
jobs.invalidate_nscd =
{ name = "invalidate-nscd";
description = "Invalidate NSCD cache";
startOn = "ip-up or config-changed";
task = true;
path = [ pkgs.glibc ];
script = ''
nscd --invalidate=passwd
nscd --invalidate=group
nscd --invalidate=hosts
'';
serviceConfig =
{ ExecStart = "@${pkgs.glibc}/sbin/nscd nscd -f ${./nscd.conf}";
Type = "forking";
PIDFile = "/run/nscd/nscd.pid";
Restart = "always";
ExecReload =
[ "${pkgs.glibc}/sbin/nscd --invalidate passwd"
"${pkgs.glibc}/sbin/nscd --invalidate group"
"${pkgs.glibc}/sbin/nscd --invalidate hosts"
];
};
};
};

View File

@ -0,0 +1,127 @@
{ config, pkgs, ... }:
with pkgs.lib;
{
###### interface
options = {
services.mingetty = {
greetingLine = mkOption {
default = ''<<< Welcome to NixOS ${config.system.nixosVersion} (\m) - \l >>>'';
description = ''
Welcome line printed by mingetty.
'';
};
helpLine = mkOption {
default = "";
description = ''
Help line printed by mingetty below the welcome line.
Used by the installation CD to give some hints on
how to proceed.
'';
};
};
};
###### implementation
config = {
# FIXME: these are mostly copy/pasted from the systemd sources,
# which some small modifications, which is annoying.
# Generate a separate job for each tty.
systemd.units."getty@.service".text =
''
[Unit]
Description=Getty on %I
Documentation=man:agetty(8)
After=systemd-user-sessions.service plymouth-quit-wait.service
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes
ConditionPathExists=/dev/tty0
[Service]
Environment=TERM=linux
Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes # set to no to prevent clearing the screen
KillMode=process
IgnoreSIGPIPE=no
# Some login implementations ignore SIGTERM, so we send SIGHUP
# instead, to ensure that login terminates cleanly.
KillSignal=SIGHUP
X-RestartIfChanged=false
'';
systemd.units."serial-getty@.service".text =
''
[Unit]
Description=Serial Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
BindsTo=dev-%i.device
After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes
[Service]
Environment=TERM=linux
Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login %I 115200,38400,9600
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
# Some login implementations ignore SIGTERM, so we send SIGHUP
# instead, to ensure that login terminates cleanly.
KillSignal=SIGHUP
X-RestartIfChanged=false
'';
environment.etc = singleton
{ # Friendly greeting on the virtual consoles.
source = pkgs.writeText "issue" ''
${config.services.mingetty.greetingLine}
${config.services.mingetty.helpLine}
'';
target = "issue";
};
};
}

View File

@ -1,90 +0,0 @@
{ config, pkgs, ... }:
with pkgs.lib;
{
###### interface
options = {
services.mingetty = {
ttys = mkOption {
default =
if pkgs.stdenv.isArm
then [ "ttyS0" ] # presumably an embedded platform such as a plug
else [ "tty1" "tty2" "tty3" "tty4" "tty5" "tty6" ];
description = ''
The list of tty devices on which to start a login prompt.
'';
};
waitOnMounts = mkOption {
default = false;
description = ''
Whether the login prompts on the virtual consoles will be
started before or after all file systems have been mounted. By
default we don't wait, but if for example your /home is on a
separate partition, you may want to turn this on.
'';
};
greetingLine = mkOption {
default = ''<<< Welcome to NixOS ${config.system.nixosVersion} (\m) - \l >>>'';
description = ''
Welcome line printed by mingetty.
'';
};
helpLine = mkOption {
default = "";
description = ''
Help line printed by mingetty below the welcome line.
Used by the installation CD to give some hints on
how to proceed.
'';
};
};
};
###### implementation
config = {
# Generate a separate job for each tty.
jobs = listToAttrs (map (tty: nameValuePair tty {
startOn =
# On tty1 we should always wait for mountall, since it may
# start an emergency-shell job.
if config.services.mingetty.waitOnMounts || tty == "tty1"
then "stopped udevtrigger and filesystem"
else "stopped udevtrigger"; # !!! should start as soon as the tty device is created
path = [ pkgs.mingetty ];
exec = "mingetty --loginprog=${pkgs.shadow}/bin/login --noclear ${tty}";
restartIfChanged = false;
environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
}) config.services.mingetty.ttys);
environment.etc = singleton
{ # Friendly greeting on the virtual consoles.
source = pkgs.writeText "issue" ''
${config.services.mingetty.greetingLine}
${config.services.mingetty.helpLine}
'';
target = "issue";
};
};
}

View File

@ -601,26 +601,12 @@ in
date.timezone = "${config.time.timeZone}"
'';
jobs.httpd =
{ # Statically verify the syntactic correctness of the generated
# httpd.conf. !!! this is impure! It doesn't just check for
# syntax, but also whether the Apache user/group exist,
# whether SSL keys exist, etc.
buildHook =
''
echo
echo '=== Checking the generated Apache configuration file ==='
${httpd}/bin/httpd -f ${httpdConf} -t || true
'';
systemd.services.httpd =
{ description = "Apache HTTPD";
description = "Apache HTTPD";
startOn = "started networking and filesystem"
# Hacky. Some subservices depend on Postgres
# (e.g. Mediawiki), but they don't have a way to declare
# that dependency. So just start httpd after postgresql if
# the latter is enabled.
+ optionalString config.services.postgresql.enable " and started postgresql";
wantedBy = [ "multi-user.target" ];
requires = [ "keys.target" ];
after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ];
path =
[ httpd pkgs.coreutils pkgs.gnugrep ]
@ -632,9 +618,7 @@ in
environment =
{ PHPRC = if enablePHP then phpIni else "";
TZ = config.time.timeZone;
} // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices));
preStart =
@ -668,12 +652,9 @@ in
done
'';
exec = "httpd -f ${httpdConf} -DNO_DETACH";
preStop =
''
${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop
'';
serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf} -DNO_DETACH";
serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
serviceConfig.Restart = "always";
};
};

View File

@ -158,7 +158,7 @@ in
services.udisks.enable = true;
services.upower = mkIf config.powerManagement.enable { enable = true; };
security.pam.services = [ { name = "kde"; allowNullPassword = true; } ];
security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
};

View File

@ -41,16 +41,11 @@ in
config = mkIf cfg.enable {
services.xserver.displayManager.slim.enable = false;
services.xserver.displayManager.job =
{ execCmd =
''
exec ${pkgs.xorg.xinit}/bin/xinit \
${pkgs.su}/bin/su -c ${dmcfg.session.script} ${cfg.user} \
-- ${dmcfg.xserverBin} ${dmcfg.xserverArgs}
'';
};
services.xserver.displayManager.slim = {
enable = true;
autoLogin = true;
defaultUser = cfg.user;
};
};

View File

@ -21,6 +21,7 @@ let
''
#! /bin/sh
. /etc/profile
cd "$HOME"
# The first argument of this script is the session type.
@ -31,6 +32,13 @@ let
exec > ~/.xsession-errors 2>&1
''}
# Stop systemd from handling the power button and lid switch,
# since presumably the desktop environment will handle these.
if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then
export _INHIBITION_LOCK_TAKEN=1
exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key "$0" "$sessionType"
fi
${optionalString cfg.startOpenSSHAgent ''
if test -z "$SSH_AUTH_SOCK"; then
# Restart this script as a child of the SSH agent. (It is
@ -53,12 +61,6 @@ let
fi
''}
# Start a ConsoleKit session so that we get ownership of various
# devices.
if test -z "$XDG_SESSION_COOKIE"; then
exec ${pkgs.consolekit}/bin/ck-launch-session "$0" "$sessionType"
fi
# Handle being called by kdm.
if test "''${1:0:1}" = /; then eval exec "$1"; fi

View File

@ -12,8 +12,8 @@ let
defaultConfig =
''
[Shutdown]
HaltCmd=${config.system.build.upstart}/sbin/halt
RebootCmd=${config.system.build.upstart}/sbin/reboot
HaltCmd=${config.systemd.package}/sbin/shutdown -h now
RebootCmd=${config.systemd.package}/sbin/shutdown -r now
${optionalString (config.system.boot.loader.id == "grub") ''
BootManager=${if config.boot.loader.grub.version == 2 then "Grub2" else "Grub"}
''}
@ -111,7 +111,7 @@ in
logsXsession = true;
};
security.pam.services = [ { name = "kde"; allowNullPassword = true; } ];
security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
users.extraUsers = singleton
{ name = "kdm";

View File

@ -14,10 +14,9 @@ let
xserver_arguments ${dmcfg.xserverArgs}
sessions ${pkgs.lib.concatStringsSep "," (dmcfg.session.names ++ ["custom"])}
login_cmd exec ${pkgs.stdenv.shell} ${dmcfg.session.script} "%session"
halt_cmd ${config.system.build.upstart}/sbin/shutdown -h now
reboot_cmd ${config.system.build.upstart}/sbin/shutdown -r now
halt_cmd ${config.systemd.package}/sbin/shutdown -h now
reboot_cmd ${config.systemd.package}/sbin/shutdown -r now
${optionalString (cfg.defaultUser != "") ("default_user " + cfg.defaultUser)}
${optionalString cfg.hideCursor "hidecursor true"}
${optionalString cfg.autoLogin "auto_login yes"}
'';
@ -76,14 +75,6 @@ in
'';
};
hideCursor = mkOption {
default = false;
example = true;
description = ''
Hide the mouse cursor on the login screen.
'';
};
autoLogin = mkOption {
default = false;
example = true;
@ -115,7 +106,7 @@ in
# Allow null passwords so that the user can login as root on the
# installation CD.
security.pam.services = [ { name = "slim"; allowNullPassword = true; } ];
security.pam.services = [ { name = "slim"; allowNullPassword = true; startSession = true; } ];
};

View File

@ -434,15 +434,14 @@ in
environment.pathsToLink =
[ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
jobs."xserver-start-check" =
{ startOn = if cfg.autorun then "filesystem and stopped udevtrigger" else "";
stopOn = "";
task = true;
script = "grep -qv noX11 /proc/cmdline && start xserver || true";
};
systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
jobs.xserver =
{ restartIfChanged = false;
systemd.services."display-manager" =
{ description = "X11 Server";
after = [ "systemd-udev-settle.service" "local-fs.target" ];
restartIfChanged = false;
environment =
{ FONTCONFIG_FILE = "/etc/fonts/fonts.conf"; # !!! cleanup

View File

@ -116,9 +116,8 @@ in
# jobs. Used to determine which jobs need to be restarted
# when switching to a new configuration.
mkdir -m 0700 -p /var/run/upstart-jobs
mkdir -m 0755 -p /var/log
mkdir -m 0755 -p /var/log/upstart
touch /var/log/wtmp # must exist
chmod 644 /var/log/wtmp
@ -146,9 +145,9 @@ in
system.activationScripts.tmpfs =
''
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" /dev
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" /dev/shm
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" /run
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
'';
};

View File

@ -0,0 +1,345 @@
#! @perl@
use strict;
use warnings;
use File::Basename;
use File::Slurp;
use Cwd 'abs_path';
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")) {
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
EOF
exit 1;
}
die "This is not a NixOS installation (/etc/NIXOS is missing)!\n" unless -f "/etc/NIXOS";
# Install or update the bootloader.
if ($action eq "switch" || $action eq "boot") {
system("@installBootLoader@ @out@") == 0 or exit 1;
exit 0 if $action eq "boot";
}
# Check if we can activate the new configuration.
my $oldVersion = read_file("/run/current-system/init-interface-version", err_mode => 'quiet') // "";
my $newVersion = read_file("@out@/init-interface-version");
if ($newVersion ne $oldVersion) {
print STDERR <<EOF;
Warning: the new NixOS configuration has an init that is
incompatible with the current configuration. The new configuration
won\'t take effect until you reboot the system.
EOF
exit 100;
}
# 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";
sub getActiveUnits {
# FIXME: use D-Bus or whatever to query this, since parsing the
# output of list-units is likely to break.
my $lines = `@systemd@/bin/systemctl list-units --full`;
my $res = {};
foreach my $line (split '\n', $lines) {
chomp $line;
last if $line eq "";
$line =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s/ or next;
next if $1 eq "UNIT";
$res->{$1} = { load => $2, state => $3, substate => $4 };
}
return $res;
}
sub parseFstab {
my ($filename) = @_;
my ($fss, $swaps);
foreach my $line (read_file($filename, err_mode => 'quiet')) {
chomp $line;
$line =~ s/#.*//;
next if $line =~ /^\s*$/;
my @xs = split / /, $line;
if ($xs[2] eq "swap") {
$swaps->{$xs[0]} = { options => $xs[3] // "" };
} else {
$fss->{$xs[1]} = { device => $xs[0], fsType => $xs[2], options => $xs[3] // "" };
}
}
return ($fss, $swaps);
}
sub parseUnit {
my ($filename) = @_;
my $info = {};
foreach my $line (read_file($filename)) {
# FIXME: not quite correct.
$line =~ /^([^=]+)=(.*)$/ or next;
$info->{$1} = $2;
}
return $info;
}
sub boolIsTrue {
my ($s) = @_;
return $s eq "yes" || $s eq "true";
}
# Stop all services that no longer exist or have changed in the new
# configuration.
my (@unitsToStop, @unitsToSkip);
my $activePrev = getActiveUnits;
while (my ($unit, $state) = each %{$activePrev}) {
my $baseUnit = $unit;
# Recognise template instances.
$baseUnit = "$1\@.$2" if $unit =~ /^(.*)@[^\.]*\.(.*)$/;
my $prevUnitFile = "/etc/systemd/system/$baseUnit";
my $newUnitFile = "@out@/etc/systemd/system/$baseUnit";
my $baseName = $baseUnit;
$baseName =~ s/\.[a-z]*$//;
if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
if (! -e $newUnitFile) {
push @unitsToStop, $unit;
}
elsif ($unit =~ /\.target$/) {
my $unitInfo = parseUnit($newUnitFile);
# Cause all active target units to be restarted below.
# This should start most changed units we stop here as
# well as any new dependencies (including new mounts and
# swap devices). FIXME: the suspend target is sometimes
# active after the system has resumed, which probably
# should not be the case. Just ignore it.
if ($unit ne "suspend.target" && $unit ne "hibernate.target") {
unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) {
write_file($startListFile, { append => 1 }, "$unit\n");
}
}
# Stop targets that have X-StopOnReconfiguration set.
# This is necessary to respect dependency orderings
# involving targets: if unit X starts after target Y and
# target Y starts after unit Z, then if X and Z have both
# changed, then X should be restarted after Z. However,
# if target Y is in the "active" state, X and Z will be
# restarted at the same time because X's dependency on Y
# is already satisfied. Thus, we need to stop Y first.
# Stopping a target generally has no effect on other units
# (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;
}
}
elsif (abs_path($prevUnitFile) ne abs_path($newUnitFile)) {
if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
# 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");
} elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/) {
# FIXME: do something?
} else {
my $unitInfo = parseUnit($newUnitFile);
if (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes")) {
push @unitsToSkip, $unit;
} else {
# If this unit is socket-activated, then stop the
# socket unit(s) as well, and restart the
# socket(s) instead of the service.
my $socketActivated = 0;
if ($unit =~ /\.service$/) {
my @sockets = split / /, ($unitInfo->{Sockets} // "");
if (scalar @sockets == 0) {
@sockets = ("$baseName.socket");
}
foreach my $socket (@sockets) {
if (defined $activePrev->{$socket}) {
push @unitsToStop, $socket;
write_file($startListFile, { append => 1 }, "$socket\n");
$socketActivated = 1;
}
}
}
if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
# This unit should be restarted instead of
# stopped and started.
write_file($restartListFile, { append => 1 }, "$unit\n");
} else {
# If the unit is not socket-activated, record
# that this unit needs to be started below.
# 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");
}
push @unitsToStop, $unit;
}
}
}
}
}
}
sub pathToUnitName {
my ($path) = @_;
die unless substr($path, 0, 1) eq "/";
return "-" if $path eq "/";
$path = substr($path, 1);
$path =~ s/\//-/g;
# FIXME: handle - and unprintable characters.
return $path;
}
sub unique {
my %seen;
my @res;
foreach my $name (@_) {
next if $seen{$name};
$seen{$name} = 1;
push @res, $name;
}
return @res;
}
# Compare the previous and new fstab to figure out which filesystems
# need a remount or need to be unmounted. New filesystems are mounted
# automatically by starting local-fs.target. FIXME: might be nicer if
# we generated units for all mounts; then we could unify this with the
# unit checking code above.
my ($prevFss, $prevSwaps) = parseFstab "/etc/fstab";
my ($newFss, $newSwaps) = parseFstab "@out@/etc/fstab";
foreach my $mountPoint (keys %$prevFss) {
my $prev = $prevFss->{$mountPoint};
my $new = $newFss->{$mountPoint};
my $unit = pathToUnitName($mountPoint) . ".mount";
if (!defined $new) {
# Filesystem entry disappeared, so unmount it.
push @unitsToStop, $unit;
} 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;
} elsif ($prev->{options} ne $new->{options}) {
# Mount options changes, so remount it.
write_file($reloadListFile, { append => 1 }, "$unit\n");
}
}
# Also handles swap devices.
foreach my $device (keys %$prevSwaps) {
my $prev = $prevSwaps->{$device};
my $new = $newSwaps->{$device};
if (!defined $new) {
# Swap entry disappeared, so turn it off. Can't use
# "systemctl stop" here because systemd has lots of alias
# units that prevent a stop from actually calling
# "swapoff".
print STDERR "stopping swap device: $device\n";
system("@utillinux@/sbin/swapoff", $device);
}
# 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("@systemd@/bin/systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors?
}
print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n"
if scalar @unitsToSkip > 0;
# Activate the new configuration (i.e., update /etc, make accounts,
# and so on).
my $res = 0;
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")) {
print STDERR "restarting systemd...\n";
system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2;
}
# Forget about previously failed services.
system("@systemd@/bin/systemctl", "reset-failed");
# Make systemd reload its units.
system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
# 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;
unlink($restartListFile);
}
# Start all active targets, as well as changed units we stopped above.
# The latter is necessary because some may not be dependencies of the
# targets (i.e., they were manually started). FIXME: detect units
# 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", 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;
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;
unlink($reloadListFile);
}
# Signal dbus to reload its configuration.
system("@systemd@/bin/systemctl", "reload", "dbus.service");
# Print failed and new units.
my (@failed, @new, @restarting);
my $activeNew = getActiveUnits;
while (my ($unit, $state) = each %{$activeNew}) {
push @failed, $unit if $state->{state} eq "failed" || $state->{substate} eq "auto-restart";
push @new, $unit if $state->{state} ne "failed" && !defined $activePrev->{$unit};
}
print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n"
if scalar @new > 0;
if (scalar @failed > 0) {
print STDERR "warning: the following units failed: ", join(", ", sort(@failed)), "\n";
foreach my $unit (@failed) {
print STDERR "\n";
system("COLUMNS=1000 @systemd@/bin/systemctl status --no-pager '$unit' >&2");
}
$res = 4;
}
exit $res;

View File

@ -1,135 +0,0 @@
#! @shell@
set -e
export PATH=/empty
for i in @path@; do PATH=$PATH:$i/bin:$i/sbin; done
action="$1"
if ! test -e /etc/NIXOS; then
echo "This is not a NixOS installation (/etc/NIXOS) is missing!"
exit 1
fi
if test -z "$action"; then
cat <<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
EOF
exit 1
fi
# Install or update the bootloader.
if [ "$action" = "switch" -o "$action" = "boot" ]; then
@installBootLoader@ @out@
fi
# Activate the new configuration.
if [ "$action" != switch -a "$action" != test ]; then exit 0; fi
oldVersion=$(cat /run/current-system/upstart-interface-version 2> /dev/null || echo 0)
newVersion=$(cat @out@/upstart-interface-version 2> /dev/null || echo 0)
if test "$oldVersion" -ne "$newVersion"; then
cat <<EOF
Warning: the new NixOS configuration has an Upstart version that is
incompatible with the current version. The new configuration won't
take effect until you reboot the system.
EOF
exit 1
fi
# Ignore SIGHUP so that we're not killed if we're running on (say)
# virtual console 1 and we restart the "tty1" job.
trap "" SIGHUP
jobsDir=$(readlink -f @out@/etc/init)
# Stop all currently running jobs that are not in the new Upstart
# configuration. (Here "running" means all jobs that are not in the
# stop/waiting state.)
for job in $(initctl list | sed -e '/ stop\/waiting/ d; /^[^a-z]/ d; s/^\([^ ]\+\).*/\1/' | sort); do
if ! [ -e "$jobsDir/$job.conf" ] ; then
echo "stopping obsolete job $job..."
stop --quiet "$job" || true
fi
done
# Activate the new configuration (i.e., update /etc, make accounts,
# and so on).
echo "activating the configuration..."
@out@/activate @out@
# Make Upstart reload its jobs.
initctl reload-configuration
# Allow Upstart jobs to react intelligently to a config change.
initctl emit config-changed
declare -A tasks=(@tasks@)
declare -A noRestartIfChanged=(@noRestartIfChanged@)
start_() {
local job="$1"
if start --quiet "$job"; then
# Handle services that cancel themselves.
if ! [ -n "${tasks[$job]}" ]; then
local status=$(status "$job")
[[ "$status" =~ start/running ]] || echo "job $job failed to start!"
fi
fi
}
log() {
echo "$@" >&2 || true
}
# Restart all running jobs that have changed. (Here "running" means
# all jobs that don't have a "stop" goal.) We use the symlinks in
# /var/run/upstart-jobs (created by each job's pre-start script) to
# determine if a job has changed.
for job in @jobs@; do
status=$(status "$job")
if ! [[ "$status" =~ start/ ]]; then continue; fi
if [ "$(readlink -f "$jobsDir/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ]; then continue; fi
if [ -n "${noRestartIfChanged[$job]}" ]; then
log "not restarting changed service $job"
continue
fi
log "restarting changed service $job..."
# Note: can't use "restart" here, since that only restarts the
# job's main process.
stop --quiet "$job" || true
start_ "$job" || true
done
# Start all jobs that are not running but should be. The "should be"
# criterion is tricky: the intended semantics is that we end up with
# the same jobs as after a reboot. If it's a task, start it if it
# differs from the previous instance of the same task; if it wasn't
# previously run, don't run it. If it's a service, only start it if
# it has a "start on" condition.
for job in @jobs@; do
status=$(status "$job")
if ! [[ "$status" =~ stop/ ]]; then continue; fi
if [ -n "${tasks[$job]}" ]; then
if [ ! -e "/var/run/upstart-jobs/$job" -o \
"$(readlink -f "$jobsDir/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ];
then continue; fi
if [ -n "${noRestartIfChanged[$job]}" ]; then continue; fi
log "starting task $job..."
start --quiet "$job" || true
else
if ! grep -q "^start on" "$jobsDir/$job.conf"; then continue; fi
log "starting service $job..."
start_ "$job" || true
fi
done
# Signal dbus to reload its configuration.
dbusPid=$(initctl status dbus 2> /dev/null | sed -e 's/.*process \([0-9]\+\)/\1/;t;d')
[ -n "$dbusPid" ] && kill -HUP "$dbusPid"

View File

@ -115,12 +115,12 @@ let
ln -s ${config.system.build.etc}/etc $out/etc
ln -s ${config.system.path} $out/sw
ln -s ${config.system.build.upstart} $out/upstart
ln -s "$systemd" $out/systemd
ln -s ${config.hardware.firmware} $out/firmware
echo -n "$kernelParams" > $out/kernel-params
echo -n "$configurationName" > $out/configuration-name
echo -n "${toString config.system.build.upstart.interfaceVersion}" > $out/upstart-interface-version
echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version
echo -n "$nixosVersion" > $out/nixos-version
mkdir $out/fine-tune
@ -131,7 +131,7 @@ let
done
mkdir $out/bin
substituteAll ${./switch-to-configuration.sh} $out/bin/switch-to-configuration
substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration
chmod +x $out/bin/switch-to-configuration
${config.system.extraSystemBuilderCmds}
@ -147,6 +147,10 @@ let
name = "nixos-${config.system.nixosVersion}";
preferLocalBuild = true;
buildCommand = systemBuilder;
inherit (pkgs) utillinux;
systemd = config.systemd.package;
inherit children;
kernelParams =
config.boot.kernelParams ++ config.boot.extraKernelParams;
@ -165,17 +169,10 @@ let
# to the activation script.
noRestartIfChanged = attrValues (mapAttrs (n: v: if v.restartIfChanged then [] else ["[${v.name}]=1"]) config.jobs);
# Most of these are needed by grub-install.
path =
[ pkgs.coreutils
pkgs.gnused
pkgs.gnugrep
pkgs.findutils
pkgs.diffutils
config.system.build.upstart # for initctl
];
configurationName = config.boot.loader.grub.configurationName;
# Needed by switch-to-configuration.
perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
};

View File

@ -2,7 +2,16 @@
with pkgs.lib;
let kernel = config.boot.kernelPackages.kernel; in
let
kernel = config.boot.kernelPackages.kernel;
kernelModulesConf = pkgs.writeText "nixos.conf"
''
${concatStringsSep "\n" config.boot.kernelModules}
'';
in
{
@ -41,7 +50,7 @@ let kernel = config.boot.kernelPackages.kernel; in
boot.extraKernelParams = mkOption {
default = [ ];
example = [ "debugtrace" ];
example = [ "boot.trace" ];
description = "Additional user-defined kernel parameters.";
};
@ -55,7 +64,7 @@ let kernel = config.boot.kernelPackages.kernel; in
boot.extraModulePackages = mkOption {
default = [];
# !!! example = [pkgs.aufs pkgs.nvidia_x11];
# !!! example = [pkgs.nvidia_x11];
description = "A list of additional packages supplying kernel modules.";
};
@ -191,6 +200,40 @@ let kernel = config.boot.kernelPackages.kernel; in
# The Linux kernel >= 2.6.27 provides firmware.
hardware.firmware = [ "${kernel}/lib/firmware" ];
# Create /etc/modules-load.d/nixos.conf, which is read by
# systemd-modules-load.service to load required kernel modules.
# FIXME: ensure that systemd-modules-load.service is restarted if
# this file changes.
environment.etc = singleton
{ target = "modules-load.d/nixos.conf";
source = kernelModulesConf;
};
# Sigh. This overrides systemd's systemd-modules-load.service
# just so we can set a restart trigger. Also make
# multi-user.target pull it in so that it gets started if it
# failed earlier.
systemd.services."systemd-modules-load" =
{ description = "Load Kernel Modules";
wantedBy = [ "sysinit.target" "multi-user.target" ];
before = [ "sysinit.target" "shutdown.target" ];
unitConfig =
{ DefaultDependencies = "no";
Conflicts = "shutdown.target";
};
serviceConfig =
{ Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${config.systemd.package}/lib/systemd/systemd-modules-load";
# Ignore failed module loads. Typically some of the
# modules in boot.kernelModules are "nice to have but
# not required" (e.g. acpi-cpufreq), so we don't want to
# barf on those.
SuccessExitStatus = "0 1";
};
restartTriggers = [ kernelModulesConf ];
};
lib.kernelConfig = {
isYes = option: {
assertion = config: config.isYes option;
@ -240,4 +283,5 @@ let kernel = config.boot.kernelPackages.kernel; in
) config.system.requiredKernelConfig;
};
}

View File

@ -19,6 +19,7 @@ let
version extraConfig extraPerEntryConfig extraEntries
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
default devices;
path = makeSearchPath "bin" [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils ];
});
in

View File

@ -39,6 +39,7 @@ my $configurationLimit = int(get("configurationLimit"));
my $copyKernels = get("copyKernels") eq "true";
my $timeout = int(get("timeout"));
my $defaultEntry = int(get("default"));
$ENV{'PATH'} = get("path");
die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;

View File

@ -5,7 +5,7 @@
with pkgs.lib;
let
isEnabled = config.boot.loader.grub.memtest86;
memtest86 = pkgs.memtest86;
memtest86 = pkgs.memtest86plus;
in
{
options = {

Some files were not shown because too many files have changed in this diff Show More