diff --git a/modules/config/power-management.nix b/modules/config/power-management.nix new file mode 100644 index 00000000000..dd241e4e815 --- /dev/null +++ b/modules/config/power-management.nix @@ -0,0 +1,75 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.powerManagement; + + sleepHook = pkgs.writeScript "sleep-hook.sh" + '' + #! ${pkgs.stdenv.shell} + action="$1" + if [ "$action" = "resume" ]; then + ${cfg.resumeCommands} + ${cfg.powerUpCommands} + fi + ''; + +in + +{ + + ###### interface + + options = { + + powerManagement = { + + enable = mkOption { + default = false; + description = + '' + Whether to enable power management. This includes support + for suspend-to-RAM and powersave features on laptops. + ''; + }; + + resumeCommands = mkOption { + default = ""; + description = "Commands executed after the system resumes from suspend-to-RAM."; + }; + + powerUpCommands = mkOption { + default = ""; + example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda"; + description = + '' + Commands executed when the machine powers up. That is, + they're executed both when the system first boots and when + it resumes from suspend or hibernation. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + # 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"; + }; + + }; + +} diff --git a/modules/config/system-path.nix b/modules/config/system-path.nix index c2605d0963e..50617ec91da 100644 --- a/modules/config/system-path.nix +++ b/modules/config/system-path.nix @@ -10,6 +10,7 @@ let requiredPackages = [ config.system.sbin.modprobe # must take precedence over module_init_tools config.system.sbin.mount # must take precedence over util-linux + config.system.build.upstart config.environment.nix pkgs.acl pkgs.attr @@ -53,7 +54,6 @@ let pkgs.sysvtools pkgs.time pkgs.udev - pkgs.upstart pkgs.usbutils pkgs.utillinux ]; diff --git a/modules/installer/cd-dvd/installation-cd-base.nix b/modules/installer/cd-dvd/installation-cd-base.nix index 3ec4f3a63de..0fb1156dc71 100644 --- a/modules/installer/cd-dvd/installation-cd-base.nix +++ b/modules/installer/cd-dvd/installation-cd-base.nix @@ -1,20 +1,22 @@ # This module contains the basic configuration for building a NixOS # installation CD. -{config, pkgs, ...}: +{ config, pkgs, ... }: + +with pkgs.lib; let options = { - system.nixosVersion = pkgs.lib.mkOption { + system.nixosVersion = mkOption { default = "${builtins.readFile ../../../VERSION}"; description = '' NixOS version number. ''; }; - installer.configModule = pkgs.lib.mkOption { + installer.configModule = mkOption { example = "./nixos/modules/installer/cd-dvd/installation-cd.nix"; description = '' Filename of the configuration module that builds the CD @@ -38,10 +40,12 @@ let ''; # Put the current directory in a tarball. - nixosTarball = makeTarball "nixos.tar.bz2" (pkgs.lib.cleanSource ../../..); + nixosTarball = makeTarball "nixos.tar.bz2" (cleanSource ../../..); # Put Nixpkgs in a tarball. - nixpkgsTarball = makeTarball "nixpkgs.tar.bz2" (pkgs.lib.cleanSource pkgs.path); + nixpkgsTarball = makeTarball "nixpkgs.tar.bz2" (cleanSource pkgs.path); + + includeSources = true; # A dummy /etc/nixos/configuration.nix in the booted CD that @@ -169,12 +173,14 @@ in # Provide the NixOS/Nixpkgs sources in /etc/nixos. This is required # for nixos-install. - echo "unpacking the NixOS/Nixpkgs sources..." - mkdir -p /etc/nixos/nixos - tar xjf ${nixosTarball}/nixos.tar.bz2 -C /etc/nixos/nixos - mkdir -p /etc/nixos/nixpkgs - tar xjf ${nixpkgsTarball}/nixpkgs.tar.bz2 -C /etc/nixos/nixpkgs - chown -R root.root /etc/nixos + ${optionalString includeSources '' + echo "unpacking the NixOS/Nixpkgs sources..." + mkdir -p /etc/nixos/nixos + tar xjf ${nixosTarball}/nixos.tar.bz2 -C /etc/nixos/nixos + mkdir -p /etc/nixos/nixpkgs + tar xjf ${nixpkgsTarball}/nixpkgs.tar.bz2 -C /etc/nixos/nixpkgs + chown -R root.root /etc/nixos + ''} # Provide a configuration for the CD/DVD itself, to allow users # to run nixos-rebuild to change the configuration of the diff --git a/modules/installer/cd-dvd/iso-image.nix b/modules/installer/cd-dvd/iso-image.nix index 2a0ac4f0e28..6c1151ca217 100644 --- a/modules/installer/cd-dvd/iso-image.nix +++ b/modules/installer/cd-dvd/iso-image.nix @@ -2,20 +2,22 @@ # configuration. The derivation for the ISO image will be placed in # config.system.build.isoImage. -{config, pkgs, ...}: +{ config, pkgs, ... }: + +with pkgs.lib; let options = { - isoImage.isoName = pkgs.lib.mkOption { + isoImage.isoName = mkOption { default = "cd.iso"; description = '' Name of the generated ISO image file. ''; }; - isoImage.compressImage = pkgs.lib.mkOption { + isoImage.compressImage = mkOption { default = false; description = '' Whether the ISO image should be compressed using @@ -23,7 +25,7 @@ let ''; }; - isoImage.volumeID = pkgs.lib.mkOption { + isoImage.volumeID = mkOption { default = "NIXOS_BOOT_CD"; description = '' Specifies the label or volume ID of the generated ISO image. @@ -32,7 +34,7 @@ let ''; }; - isoImage.contents = pkgs.lib.mkOption { + isoImage.contents = mkOption { example = [ { source = pkgs.memtest86 + "/memtest.bin"; target = "boot/memtest.bin"; @@ -44,7 +46,7 @@ let ''; }; - isoImage.storeContents = pkgs.lib.mkOption { + isoImage.storeContents = mkOption { example = [pkgs.stdenv]; description = '' This option lists additional derivations to be included in the @@ -55,14 +57,38 @@ let }; + # The Grub image. + grubImage = pkgs.runCommand "grub_eltorito" {} + '' + ${pkgs.grub2}/bin/grub-mkimage -o tmp biosdisk iso9660 help linux linux16 sh chain gfxterm vbe png jpeg + cat ${pkgs.grub2}/lib/grub/*/cdboot.img tmp > $out + ''; # */ + + # The configuration file for Grub. grubCfg = '' - default 0 - timeout 10 - splashimage /boot/background.xpm.gz + set default=0 + set timeout=10 - ${config.boot.extraGrubEntries} + if loadfont /boot/grub/unicode.pf2; then + set gfxmode=640x480 + insmod gfxterm + insmod vbe + terminal_output.gfxterm + + insmod png + if background_image /boot/grub/splash.png; then + set color_normal=white/black + set color_highlight=black/white + else + set menu_color_normal=cyan/blue + set menu_color_highlight=white/blue + fi + + fi + + ${config.boot.loader.grub.extraEntries} ''; in @@ -70,6 +96,17 @@ in { require = options; + boot.loader.grub.version = 2; + + # Don't build the GRUB menu builder script, since we don't need it + # here and it causes a cyclic dependency. + boot.loader.grub.enable = false; + + # !!! Hack - attributes expected by other modules. + system.build.menuBuilder = "true"; + system.boot.loader.kernelFile = "vmlinuz"; + environment.systemPackages = [ pkgs.grub2 ]; + # In stage 1 of the boot, mount the CD/DVD as the root FS by label # so that we don't need to know its device. fileSystems = @@ -86,7 +123,7 @@ in # We need squashfs in the initrd to mount the compressed Nix store, # and aufs to make the root filesystem appear writable. - boot.extraModulePackages = (pkgs.lib.optional + boot.extraModulePackages = (optional (! config.boot.kernelPackages.kernel.features ? aufs) config.boot.kernelPackages.aufs); boot.initrd.extraKernelModules = ["aufs" "squashfs"]; @@ -112,11 +149,11 @@ in # Individual files to be included on the CD, outside of the Nix # store on the CD. isoImage.contents = - [ { source = "${pkgs.grub}/lib/grub/${if pkgs.stdenv.system == "i686-linux" then "i386-pc" else "x86_64-unknown"}/stage2_eltorito"; - target = "/boot/grub/stage2_eltorito"; + [ { source = grubImage; + target = "/boot/grub/grub_eltorito"; } - { source = pkgs.writeText "menu.lst" grubCfg; - target = "/boot/grub/menu.lst"; + { source = pkgs.writeText "grub.cfg" grubCfg; + target = "/boot/grub/grub.cfg"; } { source = config.boot.kernelPackages.kernel + "/vmlinuz"; target = "/boot/vmlinuz"; @@ -124,8 +161,11 @@ in { source = config.system.build.initialRamdisk + "/initrd"; target = "/boot/initrd"; } - { source = config.boot.grubSplashImage; - target = "/boot/background.xpm.gz"; + { source = "${pkgs.grub2}/share/grub/unicode.pf2"; + target = "/boot/grub/unicode.pf2"; + } + { source = config.boot.loader.grub.splashImage; + target = "/boot/grub/splash.png"; } { source = config.system.build.squashfsStore; target = "/nix-store.squashfs"; @@ -134,31 +174,20 @@ in source = pkgs.runCommand "empty" {} "ensureDir $out"; target = "/nix/store"; } - { # Another quick hack: the kernel needs a systemConfig - # parameter in menu.lst, but the system config depends on - # menu.lst. Break the cyclic dependency by having a /system - # symlink on the CD, and having menu.lst refer to /system. - source = pkgs.runCommand "system" {} - "ln -s ${config.system.build.toplevel} $out"; - target = "/system"; - } - { # Idem for the stage-2 init script. - source = pkgs.runCommand "system" {} - "ln -s ${config.system.build.bootStage2} $out"; - target = "/init"; - } ]; # The Grub menu. - boot.extraGrubEntries = + boot.loader.grub.extraEntries = '' - title Boot from hard disk - root (hd0) + menuentry "Boot from hard disk" { + set root=(hd0) chainloader +1 + } - title NixOS Installer / Rescue - kernel /boot/vmlinuz init=/init systemConfig=/system ${toString config.boot.kernelParams} + menuentry "NixOS Installer / Rescue" { + linux /boot/vmlinuz init=${config.system.build.bootStage2} systemConfig=${config.system.build.toplevel} ${toString config.boot.kernelParams} initrd /boot/initrd + } ''; # Create the ISO image. @@ -168,7 +197,7 @@ in inherit (config.isoImage) isoName compressImage volumeID contents; bootable = true; - bootImage = "/boot/grub/stage2_eltorito"; + bootImage = "/boot/grub/grub_eltorito"; }; boot.postBootCommands = diff --git a/modules/installer/cd-dvd/memtest.nix b/modules/installer/cd-dvd/memtest.nix index fb3aa817855..2ec35dcc8fb 100644 --- a/modules/installer/cd-dvd/memtest.nix +++ b/modules/installer/cd-dvd/memtest.nix @@ -10,10 +10,11 @@ let in { - boot.extraGrubEntries = + boot.loader.grub.extraEntries = '' - title Memtest86+ - kernel ${memtestPath} + menuentry "Memtest86+" { + linux16 ${memtestPath} + } ''; isoImage.contents = diff --git a/modules/installer/grub/grub.nix b/modules/installer/grub/grub.nix index cb716a2a84e..9fe65a7bceb 100644 --- a/modules/installer/grub/grub.nix +++ b/modules/installer/grub/grub.nix @@ -98,10 +98,7 @@ in sha256 = "14kqdx2lfqvh40h6fjjzqgff1mwk74dmbjvmqphi6azzra7z8d59"; } # GRUB 1.97 doesn't support gzipped XPMs. - else pkgs.fetchurl { - url = http://www.gnu.org/graphics/winkler-gnu-blue.png; - sha256 = "0y8fvxalwxyid4k438k7c21bnv728qjsb92rqfapsmpv2bcj7f6k"; - }; + else ./winkler-gnu-blue-640x480.png; example = null; description = '' Background image used for GRUB. It must be a 640x480, diff --git a/modules/installer/grub/winkler-gnu-blue-640x480.png b/modules/installer/grub/winkler-gnu-blue-640x480.png new file mode 100644 index 00000000000..35bbb57b51e Binary files /dev/null and b/modules/installer/grub/winkler-gnu-blue-640x480.png differ diff --git a/modules/installer/grub/winkler-gnu-blue.README b/modules/installer/grub/winkler-gnu-blue.README new file mode 100644 index 00000000000..9616362dce2 --- /dev/null +++ b/modules/installer/grub/winkler-gnu-blue.README @@ -0,0 +1,6 @@ +This is a resized version of + + http://www.gnu.org/graphics/winkler-gnu-blue.png + +by Kyle Winkler and released under the Free Art License +(http://artlibre.org/licence.php/lalgb.html). diff --git a/modules/module-list.nix b/modules/module-list.nix index f6480537abf..f80d4d6a586 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -5,6 +5,7 @@ ./config/networking.nix ./config/no-x-libs.nix ./config/nsswitch.nix + ./config/power-management.nix ./config/system-path.nix ./config/timezone.nix ./config/unix-odbc-drivers.nix @@ -128,9 +129,9 @@ ./system/boot/stage-1.nix ./system/boot/stage-2.nix ./system/etc/etc.nix - ./system/upstart-events/ctrl-alt-delete.nix - ./system/upstart-events/halt.nix - ./system/upstart-events/maintenance-shell.nix + ./system/upstart-events/control-alt-delete.nix + ./system/upstart-events/runlevel.nix + ./system/upstart-events/shutdown.nix ./system/upstart/upstart.nix ./tasks/filesystems.nix ./tasks/kbd.nix diff --git a/modules/services/audio/alsa.nix b/modules/services/audio/alsa.nix index 5f463f8d8cd..78d6a004418 100644 --- a/modules/services/audio/alsa.nix +++ b/modules/services/audio/alsa.nix @@ -46,7 +46,7 @@ in }; jobs.alsa = - { startOn = "udev"; + { startOn = "started udev"; preStart = '' diff --git a/modules/services/audio/pulseaudio.nix b/modules/services/audio/pulseaudio.nix index 5a8ffbd30a1..f48cdd49c83 100644 --- a/modules/services/audio/pulseaudio.nix +++ b/modules/services/audio/pulseaudio.nix @@ -66,7 +66,6 @@ in { description = "PulseAudio system-wide server"; startOn = "startup"; - stopOn = "shutdown"; preStart = '' diff --git a/modules/services/databases/mysql.nix b/modules/services/databases/mysql.nix index 5d16ebe0af4..31d5676b8d7 100644 --- a/modules/services/databases/mysql.nix +++ b/modules/services/databases/mysql.nix @@ -55,7 +55,15 @@ in default = "/var/run/mysql"; description = "Location of the file which stores the PID of the MySQL server"; }; - + + initialDatabases = mkOption { + default = []; + description = "List of database names and their initial schemas that should be used to create databases on the first startup of MySQL"; + example = [ + { name = "foodatabase"; schema = ./foodatabase.sql; } + { name = "bardatabase"; schema = ./bardatabase.sql; } + ]; + }; }; }; @@ -75,8 +83,7 @@ in jobs.mysql = { description = "MySQL server"; - startOn = "filesystems"; - stopOn = "shutdown"; + startOn = "started network-interfaces"; preStart = '' @@ -90,14 +97,49 @@ in chown -R ${cfg.user} ${cfg.pidDir} ''; - exec = "${mysql}/bin/mysqld ${mysqldOptions}"; + exec = "${mysql}/libexec/mysqld ${mysqldOptions}"; + + postStart = + '' + # Wait until the MySQL server is available for use + count=0 + while [ ! -e /tmp/mysql.sock ] + do + if [ $count -eq 30 ] + then + echo "Tried 30 times, giving up..." + exit 1 + fi - postStop = - '' - pid=$(cat ${pidFile}) - kill "$pid" - ${mysql}/bin/mysql_waitpid "$pid" 1000 - ''; + echo "MySQL daemon not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + + # Create initial databases + + ${concatMapStrings (database: + '' + if ! test -e "${cfg.dataDir}/${database.name}"; then + echo "Creating initial database: ${database.name}" + ( echo "create database ${database.name};" + echo "use ${database.name};" + if [ -f "${database.schema}" ] + then + cat ${database.schema} + elif [ -d "${database.schema}" ] + then + cat ${database.schema}/mysql-databases/*.sql + fi + ) | ${mysql}/bin/mysql -u root -N + fi + '') cfg.initialDatabases} + ''; + + # !!! Need a postStart script to wait until mysqld is ready to + # accept connections. + + extraConfig = "kill timeout 60"; }; }; diff --git a/modules/services/databases/postgresql.nix b/modules/services/databases/postgresql.nix index b463e39c725..1e96483662e 100644 --- a/modules/services/databases/postgresql.nix +++ b/modules/services/databases/postgresql.nix @@ -116,20 +116,40 @@ in jobs.postgresql = { description = "PostgreSQL server"; - startOn = "${startDependency}/started"; - stopOn = "shutdown"; + startOn = "started ${startDependency}"; + + environment = + { TZ = config.time.timeZone; + PGDATA = cfg.dataDir; + }; preStart = '' + # Initialise the database. if ! test -e ${cfg.dataDir}; then mkdir -m 0700 -p ${cfg.dataDir} chown -R postgres ${cfg.dataDir} - ${run} -c '${postgresql}/bin/initdb -D ${cfg.dataDir} -U root' + ${run} -c '${postgresql}/bin/initdb -U root' fi + cp -f ${pkgs.writeText "pg_hba.conf" cfg.authentication} ${cfg.dataDir}/pg_hba.conf + + # We'd like to use the `-w' flag here to wait until the + # database is up, but it requires a `postgres' user to + # exist. And we can't call `createuser' before the + # database is running. + ${run} -c '${postgresql}/bin/pg_ctl start -o "${toString flags}"' + + # So wait until the server is running. + while ! ${run} -c '${postgresql}/bin/pg_ctl status'; do + sleep 1 + done ''; - exec = "${run} -c '${postgresql}/bin/postgres -D ${cfg.dataDir} ${toString flags}'"; + postStop = + '' + ${run} -c '${postgresql}/bin/pg_ctl stop -m fast' + ''; }; }; diff --git a/modules/services/hardware/acpid.nix b/modules/services/hardware/acpid.nix index ebb2f2a6a05..e9fd8e46dc9 100644 --- a/modules/services/hardware/acpid.nix +++ b/modules/services/hardware/acpid.nix @@ -60,11 +60,11 @@ in options = { - powerManagement = { + services.acpid = { enable = mkOption { default = false; - description = "Whether to enable power management (ACPI daemon)"; + description = "Whether to enable the ACPI daemon."; }; }; @@ -74,13 +74,12 @@ in ###### implementation - config = mkIf config.powerManagement.enable { + config = mkIf config.services.acpid.enable { jobs.acpid = { description = "ACPI daemon"; - startOn = "udev"; - stopOn = "shutdown"; + startOn = "started udev"; exec = "${pkgs.acpid}/sbin/acpid --foreground --confdir ${acpiConfDir}"; }; diff --git a/modules/services/hardware/hal.nix b/modules/services/hardware/hal.nix index 11cda8d4cc4..25a24ce5e34 100644 --- a/modules/services/hardware/hal.nix +++ b/modules/services/hardware/hal.nix @@ -48,10 +48,9 @@ in config = mkIf cfg.enable { - # !!! move pmutils somewhere else - environment.systemPackages = [hal pkgs.pmutils]; + environment.systemPackages = [ hal ]; - services.hal.packages = [hal pkgs.hal_info]; + services.hal.packages = [ hal pkgs.hal_info ]; users.extraUsers = singleton { name = "haldaemon"; @@ -67,10 +66,7 @@ in jobs.hal = { description = "HAL daemon"; - # !!! TODO: make sure that HAL starts after acpid, - # otherwise hald-addon-acpi will grab /proc/acpi/event. - startOn = if config.powerManagement.enable then "acpid" else "dbus"; - stopOn = "shutdown"; + startOn = "started dbus" + optionalString config.services.acpid.enable " and started acpid"; environment = { # !!! HACK? These environment variables manipulated inside @@ -99,23 +95,14 @@ in mkdir -m 0755 -p /var/run/hald rm -f /var/cache/hald/fdi-cache - - # For some weird reason HAL sometimes fails to start at - # boot time, which seems to be timing-dependent. As a - # temporary workaround, sleep for a while here. - sleep 2 - - # !!! Hack: start the daemon here to make sure it's - # running when the Upstart job reaches the "running" - # state. Should be fixable in Upstart 0.6. - ${hal}/sbin/hald --use-syslog # --verbose=yes ''; - postStop = - '' - pid=$(cat /var/run/hald/pid || true) - test -n "$pid" && kill "$pid" - ''; + 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]; @@ -125,4 +112,4 @@ in }; -} \ No newline at end of file +} diff --git a/modules/services/hardware/udev.nix b/modules/services/hardware/udev.nix index 105f8a2b54f..798b9a4e381 100644 --- a/modules/services/hardware/udev.nix +++ b/modules/services/hardware/udev.nix @@ -159,7 +159,6 @@ in jobs.udev = { startOn = "startup"; - stopOn = "shutdown"; environment = { UDEV_CONFIG_FILE = conf; }; @@ -169,9 +168,6 @@ in mkdir -p /var/lib/udev/rules.d - # Get rid of possible old udev processes. - ${procps}/bin/pkill -u root "^udevd$" || true - # Do the loading of additional stage 2 kernel modules. # Maybe this isn't the best place... for i in ${toString config.boot.kernelModules}; do @@ -179,32 +175,24 @@ in ${modprobe}/sbin/modprobe $i || true done - # Start udev. mkdir -p /dev/.udev # !!! bug in udev? - ${udev}/sbin/udevd --daemon + ''; + daemonType = "fork"; + + exec = "${udev}/sbin/udevd --daemon"; + + postStart = + '' # 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). ${udev}/sbin/udevadm trigger ${udev}/sbin/udevadm settle # wait for udev to finish - # Kill udev, let Upstart restart and monitor it. (This is nasty, - # but we have to run `udevadm trigger' first. Maybe we can use - # Upstart's `binary' keyword, but it isn't implemented yet.) - if ! ${procps}/bin/pkill -u root "^udevd$"; then - echo "couldn't stop udevd" - fi - - while ${procps}/bin/pgrep -u root "^udevd$"; do - sleep 1 - done - - initctl emit new-devices + initctl emit -n new-devices ''; - - exec = "${udev}/sbin/udevd"; - + }; }; diff --git a/modules/services/logging/klogd.nix b/modules/services/logging/klogd.nix index 0b2e3d9ddc7..2b8a6a64d99 100644 --- a/modules/services/logging/klogd.nix +++ b/modules/services/logging/klogd.nix @@ -2,28 +2,16 @@ ###### implementation -let - - klogdCmd = "${pkgs.sysklogd}/sbin/klogd -c 1 -2 -k $(dirname $(readlink -f /var/run/booted-system/kernel))/System.map"; - -in - { jobs.klogd = { description = "Kernel log daemon"; - startOn = "syslogd"; - stopOn = "shutdown"; + startOn = "started syslogd"; - preStart = - '' - # !!! this hangs for some reason (it blocks reading from - # /proc/kmsg). - #${klogdCmd} -o - ''; - - exec = "${klogdCmd} -n"; + exec = + "${pkgs.sysklogd}/sbin/klogd -c 1 -2 -n " + + "-k $(dirname $(readlink -f /var/run/booted-system/kernel))/System.map"; }; } diff --git a/modules/services/logging/syslogd.nix b/modules/services/logging/syslogd.nix index bc6b6eb4389..7c3e54cadb0 100644 --- a/modules/services/logging/syslogd.nix +++ b/modules/services/logging/syslogd.nix @@ -50,12 +50,13 @@ in jobs.syslogd = { description = "Syslog daemon"; - startOn = "udev"; - stopOn = "shutdown"; + startOn = "started udev"; environment = { TZ = config.time.timeZone; }; - exec = "${pkgs.sysklogd}/sbin/syslogd -n -f ${syslogConf}"; + daemonType = "fork"; + + exec = "${pkgs.sysklogd}/sbin/syslogd -f ${syslogConf}"; }; }; diff --git a/modules/services/mail/dovecot.nix b/modules/services/mail/dovecot.nix index 8ddbe5bfd7b..a41bd9eaad7 100644 --- a/modules/services/mail/dovecot.nix +++ b/modules/services/mail/dovecot.nix @@ -116,7 +116,7 @@ in jobs.dovecot = { description = "Dovecot IMAP/POP3 server"; - startOn = "${startingDependency}/started"; + startOn = "started ${startingDependency}"; preStart = '' diff --git a/modules/services/mail/postfix.nix b/modules/services/mail/postfix.nix index b5ed10d957b..ae85dd43f23 100644 --- a/modules/services/mail/postfix.nix +++ b/modules/services/mail/postfix.nix @@ -283,7 +283,7 @@ in # accurate way is unlikely to be better. { description = "Postfix mail server"; - startOn = "${startingDependency}/started"; + startOn = "started ${startingDependency}"; script = '' diff --git a/modules/services/misc/autofs.nix b/modules/services/misc/autofs.nix index b9936d0249d..079c684d086 100644 --- a/modules/services/misc/autofs.nix +++ b/modules/services/misc/autofs.nix @@ -75,8 +75,8 @@ in jobs.autofs = { description = "Filesystem automounter"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; environment = { PATH = "${pkgs.nfsUtils}/sbin:${config.system.sbin.modprobe}/sbin"; diff --git a/modules/services/misc/disnix.nix b/modules/services/misc/disnix.nix index 225762813ee..886c86e7fab 100644 --- a/modules/services/misc/disnix.nix +++ b/modules/services/misc/disnix.nix @@ -39,8 +39,7 @@ in jobs.disnix = { description = "Disnix server"; - startOn = "dbus"; - stopOn = "shutdown"; + startOn = "started dbus"; script = '' diff --git a/modules/services/misc/gpsd.nix b/modules/services/misc/gpsd.nix index 98feef68231..83cc6bae1d5 100644 --- a/modules/services/misc/gpsd.nix +++ b/modules/services/misc/gpsd.nix @@ -88,8 +88,8 @@ in jobs.gpsd = { description = "GPSD daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = '' diff --git a/modules/services/misc/nixos-manual.nix b/modules/services/misc/nixos-manual.nix index 04fc34c94fa..ed2972e5b5b 100644 --- a/modules/services/misc/nixos-manual.nix +++ b/modules/services/misc/nixos-manual.nix @@ -78,8 +78,7 @@ in description = "NixOS manual"; - startOn = "udev"; - stopOn = "shutdown"; + startOn = "started udev"; exec = '' diff --git a/modules/services/misc/rogue.nix b/modules/services/misc/rogue.nix index 43f43ae5bad..8760ce12510 100644 --- a/modules/services/misc/rogue.nix +++ b/modules/services/misc/rogue.nix @@ -43,8 +43,7 @@ in jobs.rogue = { description = "Rogue dungeon crawling game"; - startOn = "udev"; - stopOn = "shutdown"; + startOn = "started udev"; extraConfig = "chdir /root"; diff --git a/modules/services/misc/synergy.nix b/modules/services/misc/synergy.nix index 72eaf640ea8..96616fa7a73 100644 --- a/modules/services/misc/synergy.nix +++ b/modules/services/misc/synergy.nix @@ -76,8 +76,8 @@ in description = "Synergy client"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stopped"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = "${pkgs.synergy}/bin/synergyc ${if cfgS.screenName == "" then "" else "-n ${cfgS.screenName}" }"; }; @@ -89,8 +89,8 @@ in description = "Synergy server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stopped"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = '' diff --git a/modules/services/monitoring/nagios/default.nix b/modules/services/monitoring/nagios/default.nix index 78e6a276fc8..6b1b3163d26 100644 --- a/modules/services/monitoring/nagios/default.nix +++ b/modules/services/monitoring/nagios/default.nix @@ -166,8 +166,8 @@ in description = "Nagios monitoring daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/monitoring/zabbix-agent.nix b/modules/services/monitoring/zabbix-agent.nix index 9fbcad78c68..3691405e1e2 100644 --- a/modules/services/monitoring/zabbix-agent.nix +++ b/modules/services/monitoring/zabbix-agent.nix @@ -69,8 +69,8 @@ in description = "Zabbix agent daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/monitoring/zabbix-server.nix b/modules/services/monitoring/zabbix-server.nix index 9b006ed8ec2..d38e955ed4f 100644 --- a/modules/services/monitoring/zabbix-server.nix +++ b/modules/services/monitoring/zabbix-server.nix @@ -56,8 +56,8 @@ in description = "Zabbix server daemon"; - startOn = "postgresql"; - stopOn = "shutdown"; + startOn = "started postgresql"; + stopOn = "stopping postgresql"; preStart = '' diff --git a/modules/services/network-filesystems/nfs-kernel.nix b/modules/services/network-filesystems/nfs-kernel.nix index 1f67d584b89..2f6904457b2 100644 --- a/modules/services/network-filesystems/nfs-kernel.nix +++ b/modules/services/network-filesystems/nfs-kernel.nix @@ -81,8 +81,8 @@ in description = "Kernel NFS server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' @@ -111,8 +111,8 @@ in description = "Kernel NFS server"; - startOn = "nfs-kernel-exports/started"; - stopOn = "nfs-kernel-exports/stop"; + startOn = "started nfs-kernel-exports"; + stopOn = "stopping nfs-kernel-exports"; exec = "${pkgs.nfsUtils}/sbin/rpc.nfsd ${if cfg.hostName != null then "-H ${cfg.hostName}" else ""} ${builtins.toString cfg.nproc}"; }; @@ -122,8 +122,8 @@ in description = "Kernel NFS server - mount daemon"; - startOn = "nfs-kernel-nfsd/started"; - stopOn = "nfs-kernel-exports/stop"; + startOn = "started nfs-kernel-nfsd"; + stopOn = "stopping nfs-kernel-exports"; exec = "${pkgs.nfsUtils}/sbin/rpc.mountd -F -f ${exports}"; }; @@ -133,8 +133,8 @@ in description = "Kernel NFS server - Network Status Monitor"; - startOn = "nfs-kernel-nfsd/started"; - stopOn = "nfs-kernel-exports/stop"; + startOn = "started nfs-kernel-nfsd"; + stopOn = "stopping nfs-kernel-exports"; preStart = '' diff --git a/modules/services/network-filesystems/samba.nix b/modules/services/network-filesystems/samba.nix index 9b7937ac4a1..814ca7e2316 100644 --- a/modules/services/network-filesystems/samba.nix +++ b/modules/services/network-filesystems/samba.nix @@ -56,8 +56,8 @@ let { name = "samba-${appName}"; description = "Samba Service daemon ${appName}"; - startOn = "samba/started"; - stopOn = "samba-control/stop"; + startOn = "started samba"; + stopOn = "stopping samba-control"; exec = "${samba}/sbin/${appName} ${args}"; }; @@ -168,8 +168,8 @@ in { name = "samba"; description = "Samba server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = setupScript; }; diff --git a/modules/services/networking/avahi-daemon.nix b/modules/services/networking/avahi-daemon.nix index f3033e8a408..82693c7399e 100644 --- a/modules/services/networking/avahi-daemon.nix +++ b/modules/services/networking/avahi-daemon.nix @@ -118,8 +118,8 @@ in jobs.avahi_daemon = { name = "avahi-daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; script = '' diff --git a/modules/services/networking/bitlbee.nix b/modules/services/networking/bitlbee.nix index 2aa51603d05..f61227e0984 100644 --- a/modules/services/networking/bitlbee.nix +++ b/modules/services/networking/bitlbee.nix @@ -67,8 +67,8 @@ in jobs.bitlbee = { description = "BitlBee IRC to other chat networks gateway"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/networking/ddclient.nix b/modules/services/networking/ddclient.nix index b5bffa83cd7..575386c8579 100644 --- a/modules/services/networking/ddclient.nix +++ b/modules/services/networking/ddclient.nix @@ -114,7 +114,6 @@ in { name = "ddclient"; startOn = "startup"; - stopOn = "shutdown"; preStart = '' diff --git a/modules/services/networking/dhclient.nix b/modules/services/networking/dhclient.nix index 9696c8b14aa..a714562444e 100644 --- a/modules/services/networking/dhclient.nix +++ b/modules/services/networking/dhclient.nix @@ -26,13 +26,13 @@ let # 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. - ${pkgs.upstart}/sbin/initctl stop ntpd + ${config.system.build.upstart}/sbin/initctl stop ntpd - ${pkgs.upstart}/sbin/initctl emit ip-up + ${config.system.build.upstart}/sbin/initctl emit -n ip-up fi if test "$reason" = EXPIRE -o "$reason" = RELEASE; then - ${pkgs.upstart}/sbin/initctl emit ip-down + ${config.system.build.upstart}/sbin/initctl emit -n ip-down fi ''; @@ -62,8 +62,8 @@ in config = mkIf config.networking.useDHCP { jobs.dhclient = - { startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + { startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' @@ -103,6 +103,22 @@ in } ]; + powerManagement.resumeCommands = + '' + export PATH=${config.system.build.upstart}/sbin:$PATH + + restart() { + local job="$1" + if initctl status "$job" 2> /dev/null | grep -q 'running'; then + initctl stop "$job" + initctl start "$job" + fi + } + + restart wpa_supplicant + restart dhclient + ''; + }; } diff --git a/modules/services/networking/dhcpd.nix b/modules/services/networking/dhcpd.nix index 6daa0c073b8..43e0843cb97 100644 --- a/modules/services/networking/dhcpd.nix +++ b/modules/services/networking/dhcpd.nix @@ -111,8 +111,8 @@ in jobs.dhcpd = { description = "DHCP server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; script = '' diff --git a/modules/services/networking/ejabberd.nix b/modules/services/networking/ejabberd.nix index 4dce0926364..b85dc26d2fc 100644 --- a/modules/services/networking/ejabberd.nix +++ b/modules/services/networking/ejabberd.nix @@ -41,6 +41,11 @@ in description = "Virtualhosts that ejabberd should host. Hostnames are surrounded with doublequotes and separated by commas"; }; + loadDumps = mkOption { + default = []; + description = "Configuration dump that should be loaded on the first startup"; + example = [ ./myejabberd.dump ]; + }; }; }; @@ -54,8 +59,12 @@ in jobs.ejabberd = { description = "EJabberd server"; - startOn = "network-interface/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + environment = { + PATH = "$PATH:${pkgs.ejabberd}/sbin:${pkgs.ejabberd}/bin:${pkgs.coreutils}/bin:${pkgs.bash}/bin:${pkgs.gnused}/bin"; + }; preStart = '' @@ -64,6 +73,7 @@ in if ! test -d ${cfg.spoolDir} then + initialize=1 cp -av ${pkgs.ejabberd}/var/lib/ejabberd /var/lib fi @@ -73,13 +83,50 @@ in cp ${pkgs.ejabberd}/etc/ejabberd/* ${cfg.confDir} sed -e 's|{hosts, \["localhost"\]}.|{hosts, \[${cfg.virtualHosts}\]}.|' ${pkgs.ejabberd}/etc/ejabberd/ejabberd.cfg > ${cfg.confDir}/ejabberd.cfg fi - ''; + + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} start + + ${if cfg.loadDumps == [] then "" else + '' + if [ "$initialize" = "1" ] + then + # Wait until the ejabberd server is available for use + count=0 + while ! ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} status + do + if [ $count -eq 30 ] + then + echo "Tried 30 times, giving up..." + exit 1 + fi - exec = "${pkgs.bash}/bin/sh -c 'export PATH=$PATH:${pkgs.ejabberd}/sbin:${pkgs.coreutils}/bin:${pkgs.bash}/bin; ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} start; sleep 1d'"; + echo "Ejabberd daemon not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + + ${concatMapStrings (dump: + '' + echo "Importing dump: ${dump}" + + if [ -f ${dump} ] + then + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load ${dump} + elif [ -d ${dump} ] + then + for i in ${dump}/ejabberd-dump/* + do + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load $i + done + fi + '') cfg.loadDumps} + fi + ''} + ''; postStop = '' - ${pkgs.ejabberd}/sbin/ejabberdctl stop + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} stop ''; }; diff --git a/modules/services/networking/firewall.nix b/modules/services/networking/firewall.nix index 0b8a8d93061..28c43ef3370 100644 --- a/modules/services/networking/firewall.nix +++ b/modules/services/networking/firewall.nix @@ -79,7 +79,7 @@ in environment.systemPackages = [pkgs.iptables]; jobs.firewall = - { startOn = "network-interfaces/started"; + { startOn = "started network-interfaces"; preStart = '' diff --git a/modules/services/networking/gnunet.nix b/modules/services/networking/gnunet.nix index e35dfbcd1a8..53223f1df22 100644 --- a/modules/services/networking/gnunet.nix +++ b/modules/services/networking/gnunet.nix @@ -194,8 +194,8 @@ in jobs.gnunetd = { description = "The GNUnet Daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/networking/gvpe.nix b/modules/services/networking/gvpe.nix index 72b45df26af..102de2bca2d 100644 --- a/modules/services/networking/gvpe.nix +++ b/modules/services/networking/gvpe.nix @@ -56,13 +56,13 @@ in ''; }; startOn = mkOption { - default = "network-interfaces/started"; + default = "started network-interfaces"; description = '' Condition to start GVPE ''; }; stopOn = mkOption { - default = "network-interfaces/stop"; + default = "stopping network-interfaces"; description = '' Condition to stop GVPE ''; diff --git a/modules/services/networking/gw6c.nix b/modules/services/networking/gw6c.nix index 143fe57979a..eaf84c5f70f 100644 --- a/modules/services/networking/gw6c.nix +++ b/modules/services/networking/gw6c.nix @@ -6,10 +6,12 @@ let cfg = config.services.gw6c; + # !!! Move this from the services tree to the nixos tree. gw6cService = import (servicesPath + /gw6c) { inherit (pkgs) stdenv gw6c coreutils - procps upstart iputils gnused + procps iputils gnused gnugrep seccure writeScript; + upstart = config.system.build.upstart; username = cfg.username; password = cfg.password; server = cfg.server; @@ -132,8 +134,8 @@ in jobs.gw6c = { description = "Gateway6 client"; - startOn = if cfg.autorun then "network-interfaces/started" else ""; - stopOn = "network-interfaces/stop"; + startOn = if cfg.autorun then "started network-interfaces" else ""; + stopOn = "stopping network-interfaces"; exec = "${gw6cService}/bin/control start"; }; diff --git a/modules/services/networking/ifplugd.nix b/modules/services/networking/ifplugd.nix index 85eda29f5a2..6ec71849ca3 100644 --- a/modules/services/networking/ifplugd.nix +++ b/modules/services/networking/ifplugd.nix @@ -16,7 +16,6 @@ let #! ${pkgs.stdenv.shell} if test "$2" = up; then initctl stop dhclient - sleep 1 initctl start dhclient fi ''; @@ -58,8 +57,8 @@ in jobs.ifplugd = { description = "Network interface connectivity monitor"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = '' diff --git a/modules/services/networking/ircd-hybrid.nix b/modules/services/networking/ircd-hybrid.nix index aea5fbd6550..34c3b13d82d 100644 --- a/modules/services/networking/ircd-hybrid.nix +++ b/modules/services/networking/ircd-hybrid.nix @@ -122,8 +122,8 @@ in description = "IRCD Hybrid server"; - startOn = "${startingDependency}/started"; - stopOn = "${startingDependency}/stop"; + startOn = "started ${startingDependency}"; + stopOn = "stopping ${startingDependency}"; exec = "${ircdService}/bin/control start"; }; diff --git a/modules/services/networking/ntpd.nix b/modules/services/networking/ntpd.nix index 159c8022442..eaf5b5532ac 100644 --- a/modules/services/networking/ntpd.nix +++ b/modules/services/networking/ntpd.nix @@ -82,7 +82,7 @@ in chown ${ntpUser} ${stateDir} # Needed to run ntpd as an unprivileged user. - ${modprobe}/sbin/modprobe capability || true + ${modprobe}/sbin/modprobe --quiet capability || true # !!! This can hang indefinitely if the network is down or # the servers are unreachable. This is particularly bad diff --git a/modules/services/networking/openfire.nix b/modules/services/networking/openfire.nix index 67e2558b22a..a46b4fa4294 100644 --- a/modules/services/networking/openfire.nix +++ b/modules/services/networking/openfire.nix @@ -52,8 +52,7 @@ in jobs.openfire = { description = "OpenFire XMPP server"; - startOn = "${startDependency}/started"; - stopOn = "shutdown"; + startOn = "started ${startDependency}"; script = '' diff --git a/modules/services/networking/portmap.nix b/modules/services/networking/portmap.nix index 0fcbf63d799..5a51836efad 100644 --- a/modules/services/networking/portmap.nix +++ b/modules/services/networking/portmap.nix @@ -66,8 +66,8 @@ in jobs.portmap = { description = "ONC RPC portmap"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = '' diff --git a/modules/services/networking/privoxy.nix b/modules/services/networking/privoxy.nix index f2350f4c462..eee020a1f0e 100644 --- a/modules/services/networking/privoxy.nix +++ b/modules/services/networking/privoxy.nix @@ -81,7 +81,6 @@ in { name = "privoxy"; startOn = "startup"; - stopOn = "shutdown"; preStart = '' diff --git a/modules/services/networking/ssh/lshd.nix b/modules/services/networking/ssh/lshd.nix index c3a14ba17e8..f5d52c82101 100644 --- a/modules/services/networking/ssh/lshd.nix +++ b/modules/services/networking/ssh/lshd.nix @@ -119,8 +119,8 @@ in jobs.lshd = { description = "GNU lshd SSH2 daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; environment = { LD_LIBRARY_PATH = config.system.nssModules.path; }; diff --git a/modules/services/networking/ssh/sshd.nix b/modules/services/networking/ssh/sshd.nix index 8c18a560748..87cb942f2f9 100644 --- a/modules/services/networking/ssh/sshd.nix +++ b/modules/services/networking/ssh/sshd.nix @@ -112,8 +112,7 @@ in description = "OpenSSH server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; environment = { LD_LIBRARY_PATH = nssModulesPath; }; @@ -126,7 +125,9 @@ in fi ''; - exec = "${openssh}/sbin/sshd -D -h /etc/ssh/ssh_host_dsa_key -f ${sshdConfig}"; + daemonType = "fork"; + + exec = "${openssh}/sbin/sshd -h /etc/ssh/ssh_host_dsa_key -f ${sshdConfig}"; }; networking.firewall.allowedTCPPorts = [22]; diff --git a/modules/services/networking/vsftpd.nix b/modules/services/networking/vsftpd.nix index b98a9aa3f7d..4c6b6f411cd 100644 --- a/modules/services/networking/vsftpd.nix +++ b/modules/services/networking/vsftpd.nix @@ -102,8 +102,8 @@ in jobs.vsftpd = { description = "vsftpd server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/networking/wpa_supplicant.nix b/modules/services/networking/wpa_supplicant.nix index 37b5923421f..93450f8eac1 100644 --- a/modules/services/networking/wpa_supplicant.nix +++ b/modules/services/networking/wpa_supplicant.nix @@ -38,8 +38,8 @@ in environment.systemPackages = [pkgs.wpa_supplicant]; jobs.wpa_supplicant = - { startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + { startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/networking/xinetd.nix b/modules/services/networking/xinetd.nix index be9e5712e7d..4729ba9d2e4 100644 --- a/modules/services/networking/xinetd.nix +++ b/modules/services/networking/xinetd.nix @@ -122,8 +122,8 @@ in jobs.xinetd = { description = "xinetd server"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; exec = "${xinetd}/sbin/xinetd -syslog daemon -dontfork -stayalive -f ${configFile}"; }; diff --git a/modules/services/printing/cupsd.nix b/modules/services/printing/cupsd.nix index 149055d74c5..546eb7be396 100644 --- a/modules/services/printing/cupsd.nix +++ b/modules/services/printing/cupsd.nix @@ -160,8 +160,8 @@ in jobs.cupsd = { description = "CUPS printing daemon"; - startOn = "network-interfaces/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' diff --git a/modules/services/scheduling/atd.nix b/modules/services/scheduling/atd.nix index fb579dbf0b2..19fda42928a 100644 --- a/modules/services/scheduling/atd.nix +++ b/modules/services/scheduling/atd.nix @@ -67,7 +67,6 @@ in { description = "at daemon (atd)"; startOn = "startup"; - stopOn = "shutdown"; preStart = '' @@ -97,12 +96,12 @@ in chown atd:atd "$jobdir"/.SEQ && \ chmod 600 "$jobdir"/.SEQ fi - - # `atd' doesn't have a no-fork flag, so start it here. !!! - # Fix this once we have Upstart 0.6. - ${at}/sbin/atd ''; + daemonType = "fork"; + + exec = "${at}/sbin/atd"; + postStop = '' test -e /var/run/atd.pid && kill $(cat /var/run/atd.pid) diff --git a/modules/services/scheduling/cron.nix b/modules/services/scheduling/cron.nix index 8408fe6e003..478a9800c77 100644 --- a/modules/services/scheduling/cron.nix +++ b/modules/services/scheduling/cron.nix @@ -70,7 +70,6 @@ in { description = "Cron daemon"; startOn = "startup"; - stopOn = "shutdown"; # Needed to interpret times in the local timezone. environment = { TZ = config.time.timeZone; }; diff --git a/modules/services/scheduling/fcron.nix b/modules/services/scheduling/fcron.nix index b38a70b932a..fbd1288a55f 100644 --- a/modules/services/scheduling/fcron.nix +++ b/modules/services/scheduling/fcron.nix @@ -101,7 +101,6 @@ in { description = "fcron daemon"; startOn = "startup"; - stopOn = "shutdown"; environment = { PATH = "/var/run/current-system/sw/bin"; diff --git a/modules/services/system/dbus.nix b/modules/services/system/dbus.nix index 8e1d9bd4d10..b0c8dc66ae5 100644 --- a/modules/services/system/dbus.nix +++ b/modules/services/system/dbus.nix @@ -113,8 +113,7 @@ in }; jobs.dbus = - { startOn = "udev"; - stopOn = "shutdown"; + { startOn = "started udev"; preStart = '' @@ -125,24 +124,19 @@ in ${dbus.tools}/bin/dbus-uuidgen --ensure rm -f ${homeDir}/pid - # !!! hack - dbus should be running once this job is - # considered "running"; should be fixable once we have - # Upstart 0.6. - ${dbus}/bin/dbus-daemon --config-file=${configDir}/system.conf ''; + daemonType = "fork"; + + exec = "${dbus}/bin/dbus-daemon --config-file=${configDir}/system.conf"; + postStop = '' - pid=$(cat ${homeDir}/pid) - if test -n "$pid"; then - kill $pid - fi - # !!! Hack: doesn't belong here. - pid=$(cat /var/run/ConsoleKit/pid) + pid=$(cat /var/run/ConsoleKit/pid || true) if test -n "$pid"; then - kill $pid - rm /var/run/ConsoleKit/pid + kill $pid || true + rm -f /var/run/ConsoleKit/pid fi ''; }; diff --git a/modules/services/system/nscd.nix b/modules/services/system/nscd.nix index a14215c70d1..1e3a4ff75c9 100644 --- a/modules/services/system/nscd.nix +++ b/modules/services/system/nscd.nix @@ -21,7 +21,6 @@ in { description = "Name Service Cache Daemon"; startOn = "startup"; - stopOn = "shutdown"; environment = { LD_LIBRARY_PATH = nssModulesPath; }; diff --git a/modules/services/system/uptimed.nix b/modules/services/system/uptimed.nix index 3749358ac20..fd4c1652bd3 100644 --- a/modules/services/system/uptimed.nix +++ b/modules/services/system/uptimed.nix @@ -53,7 +53,6 @@ in { description = "Uptimed daemon"; startOn = "startup"; - stopOn = "shutdown"; preStart = '' diff --git a/modules/services/ttys/gpm.nix b/modules/services/ttys/gpm.nix index 026ed4a299f..256fe8d2380 100644 --- a/modules/services/ttys/gpm.nix +++ b/modules/services/ttys/gpm.nix @@ -41,8 +41,7 @@ in jobs.gpm = { description = "General purpose mouse"; - startOn = "udev"; - stopOn = "shutdown"; + startOn = "started udev"; exec = "${pkgs.gpm}/sbin/gpm -m /dev/input/mice -t ${cfg.protocol} -D &>/dev/null"; }; diff --git a/modules/services/ttys/mingetty.nix b/modules/services/ttys/mingetty.nix index 6c793ffa112..5f6b1d0f14c 100644 --- a/modules/services/ttys/mingetty.nix +++ b/modules/services/ttys/mingetty.nix @@ -55,7 +55,7 @@ with pkgs.lib; # Generate a separate job for each tty. jobs = listToAttrs (map (tty: nameValuePair tty { - startOn = "udev"; + startOn = "started udev"; exec = "${pkgs.mingetty}/sbin/mingetty --loginprog=${pkgs.pam_login}/bin/login --noclear ${tty}"; diff --git a/modules/services/web-servers/apache-httpd/default.nix b/modules/services/web-servers/apache-httpd/default.nix index 55902f9e5e0..c70d99db964 100644 --- a/modules/services/web-servers/apache-httpd/default.nix +++ b/modules/services/web-servers/apache-httpd/default.nix @@ -582,8 +582,7 @@ in description = "Apache HTTPD"; - startOn = "${startingDependency}/started"; - stopOn = "shutdown"; + startOn = "started ${startingDependency}"; environment = { # !!! This should be added in test-instrumentation.nix. It @@ -613,7 +612,14 @@ in done ''; - exec = "${httpd}/bin/httpd -f ${httpdConf} -DNO_DETACH"; + daemonType = "fork"; + + exec = "${httpd}/bin/httpd -f ${httpdConf}"; + + preStop = + '' + ${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop + ''; }; }; diff --git a/modules/services/web-servers/tomcat.nix b/modules/services/web-servers/tomcat.nix index 331653ba929..ef569a8fedf 100644 --- a/modules/services/web-servers/tomcat.nix +++ b/modules/services/web-servers/tomcat.nix @@ -100,12 +100,12 @@ in description = "Tomcat user"; home = "/homeless-shelter"; }; - + jobs.tomcat = { description = "Apache Tomcat server"; - startOn = "network-interface/started"; - stopOn = "network-interfaces/stop"; + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; preStart = '' @@ -215,6 +215,7 @@ in then for j in $i/conf/Catalina/* do + mkdir -p ${cfg.baseDir}/conf/Catalina/localhost ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j` done fi @@ -251,6 +252,7 @@ in then for j in $i/conf/Catalina/* do + mkdir -p ${cfg.baseDir}/conf/Catalina/${virtualHost.name} ln -sfn $j ${cfg.baseDir}/conf/Catalina/${virtualHost.name}/`basename $j` done fi @@ -304,13 +306,10 @@ in done '' else ""} - ''; # */ - exec = - '' - ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${pkgs.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${pkgs.tomcat6}/bin/startup.sh; sleep 1000d' + ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${pkgs.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${pkgs.tomcat6}/bin/startup.sh' ''; - + postStop = '' echo "Stopping tomcat..." diff --git a/modules/services/x11/display-managers/kdm.nix b/modules/services/x11/display-managers/kdm.nix index 349fd19adfe..18a6623eb85 100644 --- a/modules/services/x11/display-managers/kdm.nix +++ b/modules/services/x11/display-managers/kdm.nix @@ -12,8 +12,8 @@ let defaultConfig = '' [Shutdown] - HaltCmd=${pkgs.upstart}/sbin/halt - RebootCmd=${pkgs.upstart}/sbin/reboot + HaltCmd=${config.system.build.upstart}/sbin/halt + RebootCmd=${config.system.build.upstart}/sbin/reboot ${optionalString (config.system.boot.loader.id == "grub") '' BootManager=Grub ''} @@ -26,6 +26,8 @@ let [X-:*-Core] ServerCmd=${dmcfg.xserverBin} ${dmcfg.xserverArgs} + # The default timeout (15) is too short in a heavily loaded boot process. + ServerTimeout=60 # Needed to prevent the X server from dying on logout and not coming back: TerminateServer=true diff --git a/modules/services/x11/display-managers/slim.nix b/modules/services/x11/display-managers/slim.nix index af15e0df5e6..ad767e199a1 100644 --- a/modules/services/x11/display-managers/slim.nix +++ b/modules/services/x11/display-managers/slim.nix @@ -14,8 +14,8 @@ let xserver_arguments ${dmcfg.xserverArgs} sessions ${pkgs.lib.concatStringsSep "," (dmcfg.session.names ++ ["custom"])} login_cmd exec ${pkgs.stdenv.bash}/bin/sh ${dmcfg.session.script} "%session" - halt_cmd ${pkgs.upstart}/sbin/shutdown -h now - reboot_cmd ${pkgs.upstart}/sbin/shutdown -r now + halt_cmd ${config.system.build.upstart}/sbin/shutdown -h now + reboot_cmd ${config.system.build.upstart}/sbin/shutdown -r now ${if cfg.defaultUser != "" then "default_user " + cfg.defaultUser else ""} ${if cfg.hideCursor then "hidecursor true" else ""} ''; diff --git a/modules/services/x11/xfs.nix b/modules/services/x11/xfs.nix index 860d5823be3..f2b7108debc 100644 --- a/modules/services/x11/xfs.nix +++ b/modules/services/x11/xfs.nix @@ -43,8 +43,7 @@ in jobs.xfs = { description = "X Font Server"; - startOn = "${startingDependency}/started"; - stopOn = "shutdown"; + startOn = "started ${startingDependency}"; exec = "${pkgs.xorg.xfs}/bin/xfs -config ${configFile}"; }; diff --git a/modules/services/x11/xserver.nix b/modules/services/x11/xserver.nix index 3afad9d7615..4ceb5579533 100644 --- a/modules/services/x11/xserver.nix +++ b/modules/services/x11/xserver.nix @@ -385,7 +385,7 @@ in optional (elem "virtualbox" driverNames) kernelPackages.virtualboxGuestAdditions; jobs.xserver = - { startOn = if cfg.autorun then "hal" else "never"; + { startOn = if cfg.autorun then "started udev and started hal" else ""; environment = { FONTCONFIG_FILE = "/etc/fonts/fonts.conf"; # !!! cleanup @@ -401,14 +401,6 @@ in preStart = '' - # Ugly hack: wait until udev has started since the X server - # needs various devices. This would more properly be - # expressed as an Upstart dependency, but AFAIK in "start - # on" we can't express a logical AND. - while ! initctl status udev 2>&1 | grep -q running; do - sleep 1 - done - rm -f /var/run/opengl-driver ${# !!! The OpenGL driver depends on what's detected at runtime. if elem "nvidia" driverNames then '' diff --git a/modules/system/activation/activation-script.nix b/modules/system/activation/activation-script.nix index a62120363f2..df3806b834b 100644 --- a/modules/system/activation/activation-script.nix +++ b/modules/system/activation/activation-script.nix @@ -84,6 +84,16 @@ let mkdir -m 0755 -p /var/run/nix/current-load # for distributed builds mkdir -m 0700 -p /var/run/nix/remote-stores + # Use a tmpfs for /var/run/nscd to ensure that / or /var can be + # unmounted or at least remounted read-only during shutdown. + # (Upstart 0.6 apparently uses nscd to do some name lookups, + # resulting in it holding some mmap mapping to deleted files in + # /var/run/nscd.) + if [ ! -e /var/run/nscd ]; then + mkdir -p /var/run/nscd + ${pkgs.utillinux}/bin/mount -t tmpfs -o "mode=755" none /var/run/nscd + fi + mkdir -m 0755 -p /var/log touch /var/log/wtmp # must exist diff --git a/modules/system/activation/switch-to-configuration.sh b/modules/system/activation/switch-to-configuration.sh index 802b57a31af..18a0664daa7 100644 --- a/modules/system/activation/switch-to-configuration.sh +++ b/modules/system/activation/switch-to-configuration.sh @@ -54,27 +54,24 @@ EOF exit 1 fi - oldEvents=$(readlink -f /etc/event.d || true) - newEvents=$(readlink -f @out@/etc/event.d) + oldJobs=$(readlink -f /etc/static/init) + newJobs=$(readlink -f @out@/etc/init) - #echo "old: $oldEvents" - #echo "new: $newEvents" + echo "old: $oldJobs" + echo "new: $newJobs" stopJob() { local job=$1 - initctl stop "$job" - while ! initctl status "$job" 2>&1 | grep -q "(stop) waiting"; do - echo "waiting for $job to stop..." - sleep 1 - done + initctl stop "$job" || true } # Stop all services that are not in the new Upstart # configuration. - for event in $(cd $oldEvents && ls); do - if ! test -e "$newEvents/$event"; then - echo "stopping $event..." - stopJob $event + for job in $(cd $oldJobs && ls *.conf); do + job=$(basename $job .conf) + if ! test -e "$newJobs/$job.conf"; then + echo "stopping $job..." + stopJob $job fi done @@ -83,26 +80,27 @@ EOF echo "activating the configuration..." @out@/activate @out@ - # Make Upstart reload its events. !!! Should wait until it has - # finished processing its stop events. - kill -TERM 1 + # Make Upstart reload its jobs. + initctl reload-configuration # Start all new services and restart all changed services. - for event in $(cd $newEvents && ls); do + for job in $(cd $newJobs && ls *.conf); do - # Hack: skip the sys-* and ctrl-alt-delete events. + job=$(basename $job .conf) + + # Hack: skip the shutdown and control-alt-delete jobs. # Another hack: don't restart the X server (that would kill all the clients). # And don't restart dbus, since that causes ConsoleKit to # forget about current sessions. - if echo "$event" | grep -q "^sys-\|^ctrl-\|^xserver$\|^dbus$"; then continue; fi - - if ! test -e "$oldEvents/$event"; then - echo "starting $event..." - initctl start "$event" - elif test "$(readlink "$oldEvents/$event")" != "$(readlink "$newEvents/$event")"; then - echo "restarting $event..." - stopJob $event - initctl start "$event" + if echo "$job" | grep -q "^shutdown$\|^control-alt-delete$\|^xserver$\|^dbus$"; then continue; fi + + if ! test -e "$oldJobs/$job.conf"; then + echo "starting $job..." + initctl start "$job" || true + elif test "$(readlink "$oldJobs/$job.conf")" != "$(readlink "$newJobs/$job.conf")"; then + echo "restarting $job..." + stopJob $job + initctl start "$job" || true fi done fi diff --git a/modules/system/activation/top-level.nix b/modules/system/activation/top-level.nix index bb1cacfa78a..1d1fef29902 100644 --- a/modules/system/activation/top-level.nix +++ b/modules/system/activation/top-level.nix @@ -76,11 +76,11 @@ let ln -s ${config.system.activationScripts.script} $out/activate ln -s ${config.system.build.etc}/etc $out/etc ln -s ${config.system.path} $out/sw - ln -s ${pkgs.upstart} $out/upstart + ln -s ${config.system.build.upstart} $out/upstart echo "$kernelParams" > $out/kernel-params echo "$configurationName" > $out/configuration-name - echo "${toString pkgs.upstart.interfaceVersion}" > $out/upstart-interface-version + echo "${toString config.system.build.upstart.interfaceVersion}" > $out/upstart-interface-version mkdir $out/fine-tune childCount=0; @@ -114,7 +114,7 @@ let pkgs.gnugrep pkgs.findutils pkgs.diffutils - pkgs.upstart # for initctl + config.system.build.upstart # for initctl ]; # Boot loaders diff --git a/modules/system/boot/stage-1-init.sh b/modules/system/boot/stage-1-init.sh index 58bf218428b..182fe7e98e1 100644 --- a/modules/system/boot/stage-1-init.sh +++ b/modules/system/boot/stage-1-init.sh @@ -39,7 +39,7 @@ trap 'fail' ERR # Print a greeting. echo -echo "<<< NixOS Stage 1 >>>" +echo "<<< NixOS Stage 1 >>>" echo diff --git a/modules/system/boot/stage-2-init.sh b/modules/system/boot/stage-2-init.sh index 0cc09caebba..5343aa9eae9 100644 --- a/modules/system/boot/stage-2-init.sh +++ b/modules/system/boot/stage-2-init.sh @@ -5,7 +5,7 @@ # Print a greeting. echo -echo "<<< NixOS Stage 2 >>>" +echo -e "\e[1;32m<<< NixOS Stage 2 >>>\e[0m" echo @@ -27,7 +27,7 @@ setPath "@path@" # Mount special file systems. mkdir -m 0755 -p /etc test -e /etc/fstab || touch /etc/fstab # to shut up mount -[ -s /etc/mtab ] && rm /etc/mtab # while installing a symlink is created (see man mount), if it's still there for whateever reason remove it +test -s /etc/mtab && rm /etc/mtab # while installing a symlink is created (see man mount), if it's still there for whateever reason remove it rm -f /etc/mtab* # not that we care about stale locks mkdir -m 0755 -p /proc mount -n -t proc none /proc @@ -100,15 +100,12 @@ rm -rf /var/lock # gone, of course. rm -rf /nix/var/nix/chroots # recreated in activate-configuration.sh -if test -n "$safeMode"; then - mkdir -m 0755 -p /var/run - touch /var/run/safemode -fi - -# Create the minimal device nodes needed before we run udev. +# Create the minimal device nodes needed for the activation scripts +# and Upstart. mknod -m 0666 /dev/null c 1 3 mknod -m 0644 /dev/urandom c 1 9 # needed for passwd +mknod -m 0644 /dev/console c 5 1 # Clear the resume device. @@ -136,12 +133,9 @@ export MODULE_DIR=@kernel@/lib/modules/ # Run any user-specified commands. @shell@ @postBootCommands@ -echo "starting Upstart..." +# For debugging Upstart. +#@shell@ --login < /dev/console > /dev/console 2>&1 & -# Start Upstart's init. We start it through the -# /var/run/current-system symlink indirection so that we can upgrade -# init in a running system by changing the symlink and sending init a -# HUP signal. -export UPSTART_CFG_DIR=/etc/event.d -setPath "@upstartPath@" -exec /var/run/current-system/upstart/sbin/init +# Start Upstart's init. +echo "starting Upstart..." +PATH=/var/run/current-system/upstart/sbin exec init diff --git a/modules/system/boot/stage-2.nix b/modules/system/boot/stage-2.nix index 440ff70965f..5c3c3560be3 100644 --- a/modules/system/boot/stage-2.nix +++ b/modules/system/boot/stage-2.nix @@ -15,30 +15,25 @@ let }; - inherit (pkgs) substituteAll writeText coreutils utillinux udev upstart; + inherit (pkgs) substituteAll writeText coreutils utillinux udev; kernel = config.boot.kernelPackages.kernel; activateConfiguration = config.system.activationScripts.script; - # Path for Upstart jobs. Should be quite minimal. - upstartPath = - [ pkgs.coreutils - pkgs.findutils - pkgs.gnugrep - pkgs.gnused - pkgs.upstart - ]; - bootStage2 = substituteAll { src = ./stage-2-init.sh; isExecutable = true; - inherit kernel upstart activateConfiguration upstartPath; + inherit kernel activateConfiguration; + upstart = config.system.build.upstart; path = [ coreutils utillinux udev - upstart ]; - postBootCommands = writeText "local-cmds" config.boot.postBootCommands; + postBootCommands = writeText "local-cmds" + '' + ${config.boot.postBootCommands} + ${config.powerManagement.powerUpCommands} + ''; }; in diff --git a/modules/system/upstart-events/ctrl-alt-delete.nix b/modules/system/upstart-events/control-alt-delete.nix similarity index 62% rename from modules/system/upstart-events/ctrl-alt-delete.nix rename to modules/system/upstart-events/control-alt-delete.nix index ae1ba2e342e..5fa2bd87eb9 100644 --- a/modules/system/upstart-events/ctrl-alt-delete.nix +++ b/modules/system/upstart-events/control-alt-delete.nix @@ -3,10 +3,10 @@ ###### implementation { - jobs.ctrl_alt_delete = - { name = "ctrl-alt-delete"; + jobs.control_alt_delete = + { name = "control-alt-delete"; - startOn = "ctrlaltdel"; + startOn = "control-alt-delete"; task = true; diff --git a/modules/system/upstart-events/maintenance-shell.nix b/modules/system/upstart-events/maintenance-shell.nix deleted file mode 100644 index a8eceb93158..00000000000 --- a/modules/system/upstart-events/maintenance-shell.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ config, pkgs, ... }: - -###### implementation - -{ - jobs.maintenance_shell = - { name = "maintenance-shell"; - - startOn = [ "maintenance" "stalled" ]; - - task = true; - - script = - '' - exec < /dev/tty1 > /dev/tty1 2>&1 - echo \ - echo "<<< MAINTENANCE SHELL >>>" - echo "" - exec ${pkgs.bash}/bin/sh - ''; - }; -} diff --git a/modules/system/upstart-events/runlevel.nix b/modules/system/upstart-events/runlevel.nix new file mode 100644 index 00000000000..750d9a07f50 --- /dev/null +++ b/modules/system/upstart-events/runlevel.nix @@ -0,0 +1,25 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + jobs.runlevel = + { name = "runlevel"; + + startOn = "runlevel [0123456S]"; + + task = true; + + script = + '' + case "$RUNLEVEL" in + 0) initctl start shutdown MODE=poweroff;; + 1) initctl start shutdown MODE=maintenance;; + 6) initctl start shutdown MODE=reboot;; + *) echo "Unsupported runlevel: $RUNLEVEL";; + esac + ''; + }; + +} diff --git a/modules/system/upstart-events/halt.nix b/modules/system/upstart-events/shutdown.nix similarity index 69% rename from modules/system/upstart-events/halt.nix rename to modules/system/upstart-events/shutdown.nix index 36efc3fe2cf..fa264979c6c 100644 --- a/modules/system/upstart-events/halt.nix +++ b/modules/system/upstart-events/shutdown.nix @@ -2,29 +2,33 @@ with pkgs.lib; -###### implementation +{ -let - - inherit (pkgs) bash utillinux; - - jobFun = event: - { startOn = event; + jobs.shutdown = + { name = "shutdown"; task = true; + environment = { MODE = "poweroff"; }; + script = '' set +e # continue in case of errors + + ${pkgs.kbd}/bin/chvt 1 - exec < /dev/tty1 > /dev/tty1 2>&1 + exec < /dev/console > /dev/console 2>&1 echo "" - echo "<<< SYSTEM SHUTDOWN >>>" + if test "$MODE" = maintenance; then + echo "<<< Entering maintenance mode >>>" + else + echo "<<< System shutdown >>>" + fi echo "" - export PATH=${utillinux}/bin:${utillinux}/sbin:$PATH - + export PATH=${pkgs.utillinux}/bin:${pkgs.utillinux}/sbin:$PATH + # Set the hardware clock to the system time. echo "setting the hardware clock..." hwclock --systohc --utc @@ -32,6 +36,15 @@ let # Do an initial sync just in case. sync + + + # Stop all Upstart jobs. + initctl list | while IFS=", " read jobName status rest; do + if test "$jobName" != shutdown -a "$status" != "stop/waiting"; then + echo "stopping $jobName..." + stop "$jobName" + fi + done # Kill all remaining processes except init and this one. @@ -42,7 +55,20 @@ let echo "sending the KILL signal to all processes..." kill -KILL -1 - + + + # If maintenance mode is requested, start a root shell, and + # afterwards emit the "startup" event to bring everything + # back up. + if test "$MODE" = maintenance; then + echo "" + echo "<<< Maintenance shell >>>" + echo "" + while ! ${pkgs.bash}/bin/bash --login; do true; done + initctl emit -n startup + exit 0 + fi + # Unmount helper functions. getMountPoints() { @@ -99,9 +125,8 @@ let sync - # Either reboot or power-off the system. Note that the "halt" - # event also does a power-off. - if test ${event} = reboot; then + # Either reboot or power-off the system. + if test "$MODE" = reboot; then echo "rebooting..." sleep 1 exec reboot -f @@ -113,9 +138,4 @@ let ''; }; -in - -{ - jobs = listToAttrs (map (n: nameValuePair "sys-${n}" (jobFun n)) - [ "reboot" "halt" "system-halt" "power-off" ] ); -} +} \ No newline at end of file diff --git a/modules/system/upstart/upstart.nix b/modules/system/upstart/upstart.nix index bb6a4f9a117..f7c9eaaa6ef 100644 --- a/modules/system/upstart/upstart.nix +++ b/modules/system/upstart/upstart.nix @@ -4,6 +4,19 @@ with pkgs.lib; let + upstart = pkgs.upstart06; + + + # Path for Upstart jobs. Should be quite minimal. + upstartPath = + [ pkgs.coreutils + pkgs.findutils + pkgs.gnugrep + pkgs.gnused + upstart + ]; + + # From a job description, generate an Upstart job file. makeJob = job: @@ -15,23 +28,25 @@ let description "${job.description}" + console output + ${if isList job.startOn then - # This is a hack to support or-dependencies on Upstart 0.3. - concatMapStrings (x: "start on ${x}\n") job.startOn + "start on ${concatStringsSep " or " job.startOn}" else if job.startOn != "" then "start on ${job.startOn}" else "" } - ${if job.stopOn != "" then "stop on ${job.stopOn}" else ""} + ${optionalString (job.stopOn != "") "stop on ${job.stopOn}"} + env PATH=${makeSearchPath "bin" upstartPath}:${makeSearchPath "sbin" upstartPath} ${concatMapStrings (n: "env ${n}=${getAttr n job.environment}\n") (attrNames job.environment)} - ${if job.preStart != "" then '' - start script + ${optionalString (job.preStart != "") '' + pre-start script ${job.preStart} end script - '' else ""} + ''} ${if job.script != "" && job.exec != "" then abort "Job ${job.name} has both a `script' and `exec' attribute." @@ -45,189 +60,218 @@ let '' exec ${job.exec} '' - else - # Simulate jobs without a main process (which Upstart 0.3 - # doesn't support) using a semi-infinite sleep. - '' - exec sleep 1e100 - '' + else "" } - ${if job.respawn && !job.task then "respawn" else ""} + ${optionalString (job.postStart != "") '' + post-start script + ${job.postStart} + end script + ''} + + ${optionalString job.task "task"} + ${optionalString job.respawn "respawn"} - ${if job.postStop != "" then '' - stop script + ${optionalString (job.preStop != "") '' + pre-stop script + ${job.preStop} + end script + ''} + + ${optionalString (job.postStop != "") '' + post-stop script ${job.postStop} end script - '' else ""} + ''} + + ${optionalString (!job.task) ( + if job.daemonType == "fork" then "expect fork" else + if job.daemonType == "daemon" then "expect daemon" else + if job.daemonType == "stop" then "expect stop" else + if job.daemonType == "none" then "" else + throw "invalid daemon type `${job.daemonType}'" + )} ${job.extraConfig} ''; in - pkgs.runCommand ("upstart-" + job.name) + pkgs.runCommand ("upstart-" + job.name + ".conf") { inherit (job) buildHook; inherit jobText; } '' eval "$buildHook" - ensureDir $out/etc/event.d - echo "$jobText" > $out/etc/event.d/${job.name} + echo "$jobText" > $out ''; - jobs = - [pkgs.upstart] # for the built-in logd job - ++ map (job: job.upstartPkg) (attrValues config.jobs); - - # Create an etc/event.d directory containing symlinks to the - # specified list of Upstart job files. - jobsDir = pkgs.runCommand "upstart-jobs" {inherit jobs;} - '' - ensureDir $out/etc/event.d - for i in $jobs; do - if ln -s $i . ; then - if test -d $i; then - ln -s $i/etc/event.d/* $out/etc/event.d/ - fi - else - echo Duplicate entry: $i; - fi; - done - ''; # */ - - # !! remove extra indentations. + jobOptions = { - name = mkOption { - # !!! The type should ensure that this could be a filename. - type = types.string; - example = "sshd"; - description = '' - Name of the Upstart job. - ''; - }; + name = mkOption { + # !!! The type should ensure that this could be a filename. + type = types.string; + example = "sshd"; + description = '' + Name of the Upstart job. + ''; + }; - buildHook = mkOption { - type = types.string; - default = "true"; - description = '' - Command run while building the Upstart job. Can be used - to perform simple regression tests (e.g., the Apache - Upstart job uses it to check the syntax of the generated - httpd.conf. - ''; - }; + buildHook = mkOption { + type = types.string; + default = "true"; + description = '' + Command run while building the Upstart job. Can be used + to perform simple regression tests (e.g., the Apache + Upstart job uses it to check the syntax of the generated + httpd.conf. + ''; + }; - description = mkOption { - type = types.string; - default = "(no description given)"; - description = '' - A short description of this job. - ''; - }; + description = mkOption { + type = types.string; + default = "(no description given)"; + description = '' + A short description of this job. + ''; + }; - startOn = mkOption { - # !!! Re-enable this once we're on Upstart >= 0.6. - #type = types.string; - default = ""; - description = '' - The Upstart event that triggers this job to be started. - If empty, the job will not start automatically. - ''; - }; + startOn = mkOption { + # !!! Re-enable this once we're on Upstart >= 0.6. + #type = types.string; + default = ""; + description = '' + The Upstart event that triggers this job to be started. + If empty, the job will not start automatically. + ''; + }; - stopOn = mkOption { - type = types.string; - default = "shutdown"; - description = '' - The Upstart event that triggers this job to be stopped. - ''; - }; + stopOn = mkOption { + type = types.string; + default = "shutdown"; + description = '' + The Upstart event that triggers this job to be stopped. + ''; + }; - preStart = mkOption { - type = types.string; - default = ""; - description = '' - Shell commands executed before the job is started - (i.e. before the job's main process is started). - ''; - }; + preStart = mkOption { + type = types.string; + default = ""; + description = '' + Shell commands executed before the job is started + (i.e. before the job's main process is started). + ''; + }; - postStop = mkOption { - type = types.string; - default = ""; - description = '' - Shell commands executed after the job has stopped - (i.e. after the job's main process has terminated). - ''; - }; + postStart = mkOption { + type = types.string; + default = ""; + description = '' + Shell commands executed after the job is started (i.e. after + the job's main process is started), but before the job is + considered “running”. + ''; + }; - exec = mkOption { - type = types.string; - default = ""; - description = '' - Command to start the job's main process. If empty, the - job has no main process, but can still have pre/post-start - and pre/post-stop scripts, and is considered "running" - until it is stopped. - ''; - }; + preStop = mkOption { + type = types.string; + default = ""; + description = '' + Shell commands executed before the job is stopped + (i.e. before Upstart kills the job's main process). This can + be used to cleanly shut down a daemon. + ''; + }; - script = mkOption { - type = types.string; - default = ""; - description = '' - Shell commands executed as the job's main process. Can be - specified instead of the exec attribute. - ''; - }; + postStop = mkOption { + type = types.string; + default = ""; + description = '' + Shell commands executed after the job has stopped + (i.e. after the job's main process has terminated). + ''; + }; - respawn = mkOption { - type = types.bool; - default = true; - description = '' - Whether to restart the job automatically if its process - ends unexpectedly. - ''; - }; + exec = mkOption { + type = types.string; + default = ""; + description = '' + Command to start the job's main process. If empty, the + job has no main process, but can still have pre/post-start + and pre/post-stop scripts, and is considered “running” + until it is stopped. + ''; + }; - task = mkOption { - type = types.bool; - default = false; - description = '' - Whether this job is a task rather than a service. Tasks - are executed only once, while services are restarted when - they exit. - ''; - }; + script = mkOption { + type = types.string; + default = ""; + description = '' + Shell commands executed as the job's main process. Can be + specified instead of the exec attribute. + ''; + }; - environment = mkOption { - type = types.attrs; - default = {}; - example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; }; - description = '' - Environment variables passed to the job's processes. - ''; - }; + respawn = mkOption { + type = types.bool; + default = true; + description = '' + Whether to restart the job automatically if its process + ends unexpectedly. + ''; + }; - extraConfig = mkOption { - type = types.string; - default = ""; - example = "limit nofile 4096 4096"; - description = '' - Additional Upstart stanzas not otherwise supported. - ''; - }; + task = mkOption { + type = types.bool; + default = false; + description = '' + Whether this job is a task rather than a service. Tasks + are executed only once, while services are restarted when + they exit. + ''; + }; - }; + environment = mkOption { + type = types.attrs; + default = {}; + example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; }; + description = '' + Environment variables passed to the job's processes. + ''; + }; + daemonType = mkOption { + type = types.string; + default = "none"; + description = '' + Determines how Upstart detects when a daemon should be + considered “running”. The value none means + that the daemon is considered ready immediately. The value + fork means that the daemon will fork once. + The value daemon means that the daemon will + fork twice. The value stop means that the + daemon will raise the SIGSTOP signal to indicate readiness. + ''; + }; + + extraConfig = mkOption { + type = types.string; + default = ""; + example = "limit nofile 4096 4096"; + description = '' + Additional Upstart stanzas not otherwise supported. + ''; + }; + + }; + + upstartJob = {name, config, ...}: { options = { - upstartPkg = mkOption { + jobDrv = mkOption { default = makeJob config; type = types.uniq types.package; description = '' - Upstart package which contains upstart events inside - /etc/event.d/. The default value is - generated from other options. + Derivation that builds the Upstart job file. The default + value is generated from other options. ''; }; }; @@ -275,19 +319,26 @@ in config = { + system.build.upstart = upstart; + environment.etc = - [ { # The Upstart events defined above. - source = "${jobsDir}/etc/event.d"; - target = "event.d"; - } - ]; + flip map (attrValues config.jobs) (job: + { source = job.jobDrv; + target = "init/${job.name}.conf"; + } ); + + # Upstart can listen on the system bus, allowing normal users to + # do status queries. + services.dbus.packages = [ upstart ]; # !!! fix this + /* tests.upstartJobs = { recurseForDerivations = true; } // builtins.listToAttrs (map (job: { name = removePrefix "upstart-" job.name; value = job; }) jobs); + */ }; diff --git a/modules/tasks/kbd.nix b/modules/tasks/kbd.nix index 9ba7f973cf3..8ed4b44f91b 100644 --- a/modules/tasks/kbd.nix +++ b/modules/tasks/kbd.nix @@ -59,9 +59,11 @@ in jobs.kbd = { description = "Keyboard / console initialisation"; - startOn = "udev"; + startOn = "started udev"; - preStart = '' + task = true; + + script = '' export LANG=${defaultLocale} export LOCALE_ARCHIVE=/var/run/current-system/sw/lib/locale/locale-archive export PATH=${pkgs.gzip}/bin:$PATH # Needed by setfont diff --git a/modules/tasks/lvm.nix b/modules/tasks/lvm.nix index 4da517deae1..4aebb33767e 100644 --- a/modules/tasks/lvm.nix +++ b/modules/tasks/lvm.nix @@ -7,7 +7,7 @@ config = { jobs.lvm = - { startOn = " udev"; # !!! or on new-devices + { startOn = "started udev or new-devices"; script = '' @@ -23,7 +23,7 @@ # make them appear in /dev. ${pkgs.lvm2}/sbin/vgchange --available y - initctl emit new-devices + initctl emit -n new-devices ''; task = true; diff --git a/modules/tasks/network-interfaces.nix b/modules/tasks/network-interfaces.nix index 4b53da876da..2868c251fca 100644 --- a/modules/tasks/network-interfaces.nix +++ b/modules/tasks/network-interfaces.nix @@ -135,7 +135,7 @@ in jobs.networkInterfaces = { name = "network-interfaces"; - startOn = "udev"; + startOn = "started udev"; preStart = '' @@ -178,6 +178,11 @@ in # Run any user-specified commands. ${pkgs.stdenv.shell} ${pkgs.writeText "local-net-cmds" cfg.localCommands} || true + + # Emit the ip-up event (e.g. to start ntpd). + ${optionalString (cfg.interfaces != []) '' + initctl emit -n ip-up + ''} ''; postStop = diff --git a/modules/tasks/swraid.nix b/modules/tasks/swraid.nix index 6e29062f0a9..b9465822601 100644 --- a/modules/tasks/swraid.nix +++ b/modules/tasks/swraid.nix @@ -13,7 +13,7 @@ in { jobs.swraid = - { startOn = "udev"; # !!! or on "new-devices" + { startOn = "started udev or new-devices"; script = '' @@ -25,11 +25,13 @@ in # Scan /proc/partitions for RAID devices. ${mdadm}/sbin/mdadm --examine --brief --scan -c partitions > ${tempConf} + + if ! test -s ${tempConf}; then exit 0; fi # Activate each device found. ${mdadm}/sbin/mdadm --assemble -c ${tempConf} --scan - initctl emit new-devices + initctl emit -n new-devices ''; task = true; diff --git a/modules/tasks/tty-backgrounds.nix b/modules/tasks/tty-backgrounds.nix index d15365fab9d..5f557ac7f5c 100644 --- a/modules/tasks/tty-backgrounds.nix +++ b/modules/tasks/tty-backgrounds.nix @@ -105,7 +105,7 @@ in jobs.ttyBackgrounds = { name = "tty-backgrounds"; - startOn = "udev"; + startOn = "started udev"; preStart = '' diff --git a/modules/virtualisation/qemu-vm.nix b/modules/virtualisation/qemu-vm.nix index 87138ed5c52..68ba340e6c2 100644 --- a/modules/virtualisation/qemu-vm.nix +++ b/modules/virtualisation/qemu-vm.nix @@ -9,6 +9,8 @@ {config, pkgs, ...}: +with pkgs.lib; + let vmName = config.networking.hostName; @@ -16,7 +18,7 @@ let options = { virtualisation.diskImage = - pkgs.lib.mkOption { + mkOption { default = "./${vmName}.qcow2"; description = '' @@ -90,7 +92,7 @@ in # where the regular value for the `fileSystems' attribute should be # disregarded for the purpose of building a VM test image (since # those filesystems don't exist in the VM). - fileSystems = pkgs.lib.mkOverride 50 {} + fileSystems = mkOverride 50 {} [ { mountPoint = "/"; device = "/dev/vda"; } @@ -119,6 +121,13 @@ in networking.defaultGateway = "10.0.2.2"; + networking.nameservers = [ "10.0.2.3" ]; + + networking.interfaces = singleton + { name = "eth0"; + ipAddress = "10.0.2.15"; + }; + system.build.vm = pkgs.runCommand "nixos-vm" {} '' ensureDir $out/bin @@ -135,11 +144,11 @@ in # When building a regular system configuration, override whatever # video driver the host uses. - services.xserver.videoDriver = pkgs.lib.mkOverride 50 {} null; - services.xserver.videoDrivers = pkgs.lib.mkOverride 50 {} [ "cirrus" "vesa" ]; - services.xserver.defaultDepth = pkgs.lib.mkOverride 50 {} 0; - services.xserver.resolutions = pkgs.lib.mkOverride 50 {} []; + services.xserver.videoDriver = mkOverride 50 {} null; + services.xserver.videoDrivers = mkOverride 50 {} [ "cirrus" "vesa" ]; + services.xserver.defaultDepth = mkOverride 50 {} 0; + services.xserver.resolutions = mkOverride 50 {} []; # Wireless won't work in the VM. - networking.enableWLAN = pkgs.lib.mkOverride 50 {} false; + networking.enableWLAN = mkOverride 50 {} false; } diff --git a/release.nix b/release.nix index 8d00c826806..9520ac02698 100644 --- a/release.nix +++ b/release.nix @@ -30,10 +30,11 @@ let description = "NixOS installation CD (${description}) - ISO image for ${system}"; maintainers = map (x: lib.getAttr x lib.maintainers) maintainers; }; + inherit iso; } '' ensureDir $out/nix-support - echo "file iso" ${iso}/iso/*.iso* >> $out/nix-support/hydra-build-products + echo "file iso" $iso/iso/*.iso* >> $out/nix-support/hydra-build-products ''; # */