* Synced with trunk @ 13663

svn path=/nixos/branches/modular-nixos/; revision=14945
This commit is contained in:
Nicolas Pierron 2009-04-08 13:32:37 +00:00
commit bb24373197
19 changed files with 361 additions and 82 deletions

View File

@ -138,6 +138,26 @@ fi
if test -n "$debug1devices"; then fail; fi if test -n "$debug1devices"; then fail; fi
# Return true if the machine is on AC power, or if we can't determine
# whether it's on AC power.
onACPower () {
if test -d "/proc/acpi/battery"; then
if ls /proc/acpi/battery/BAT[0-9]* > /dev/null 2>&1; then
if cat /proc/acpi/battery/BAT*/state \
| grep "^charging state" \
| grep -q "discharg" ; then
false
else
true
fi
else
true
fi
else
true
fi
}
# Function for mounting a file system. # Function for mounting a file system.
mountFS() { mountFS() {
local device="$1" local device="$1"
@ -158,6 +178,7 @@ mountFS() {
fi fi
if test -n "$mustCheck"; then if test -n "$mustCheck"; then
if onACPower; then
FSTAB_FILE="/etc/mtab" fsck -V -v -C -a "$device" FSTAB_FILE="/etc/mtab" fsck -V -v -C -a "$device"
fsckResult=$? fsckResult=$?
@ -176,6 +197,10 @@ mountFS() {
echo "fsck on $device failed." echo "fsck on $device failed."
fail fail
fi fi
else
# Don't run `fsck' if the machine is on battery power.
echo "on battery power, so \`fsck' not run on \`$device'"
fi
fi fi
# Mount read-writable. # Mount read-writable.

View File

@ -1,6 +1,6 @@
let let
fromEnv = name : default : fromEnv = name: default:
let env = builtins.getEnv name; in let env = builtins.getEnv name; in
if env == "" then default else env; if env == "" then default else env;
configuration = import (fromEnv "NIXOS_CONFIG" /etc/nixos/configuration.nix); configuration = import (fromEnv "NIXOS_CONFIG" /etc/nixos/configuration.nix);

View File

@ -38,6 +38,8 @@ let
${pkgs.docbook5_xsl}/xml/xsl/docbook/html/docbook.xsl \ ${pkgs.docbook5_xsl}/xml/xsl/docbook/html/docbook.xsl \
./manual.xml ./manual.xml
cp ${./style.css} $out/style.css cp ${./style.css} $out/style.css
ensureDir $out/nix-support
echo "doc manual $out" >> $out/nix-support/hydra-build-products
''; '';
}; };

View File

@ -15,6 +15,7 @@
<copyright> <copyright>
<year>2007</year> <year>2007</year>
<year>2008</year>
<holder>Eelco Dolstra</holder> <holder>Eelco Dolstra</holder>
</copyright> </copyright>

View File

@ -30,13 +30,12 @@ let
nssModulesPath = config.system.nssModules.path; nssModulesPath = config.system.nssModules.path;
wrapperDir = config.system.wrapperDir; wrapperDir = config.system.wrapperDir;
systemPath = config.system.path; systemPath = config.system.path;
binsh = config.system.build.binsh;
optional = pkgs.lib.optional; optional = pkgs.lib.optional;
# !!! ugh, these files shouldn't be created here. # !!! ugh, these files shouldn't be created here.
pamConsoleHandlers = pkgs.writeText "console.handlers" '' pamConsoleHandlers = pkgs.writeText "console.handlers" ''
console consoledevs /dev/tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] console consoledevs /dev/tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
${pkgs.pam_console}/sbin/pam_console_apply lock logfail wait -t tty -s -c ${pamConsolePerms} ${pkgs.pam_console}/sbin/pam_console_apply lock logfail wait -t tty -s -c ${pamConsolePerms}
@ -131,13 +130,27 @@ let
} }
{ # Nix configuration. { # Nix configuration.
source = pkgs.writeText "nix.conf" '' source =
let
# Tricky: if we're using a chroot for builds, then we need
# /bin/sh in the chroot (our own compromise to purity).
# However, since /bin/sh is a symlink to some path in the
# Nix store, which furthermore has runtime dependencies on
# other paths in the store, we need the closure of /bin/sh
# in `build-chroot-dirs' - otherwise any builder that uses
# /bin/sh won't work.
refs = pkgs.writeReferencesToFile binsh;
in
pkgs.runCommand "nix.conf" {} ''
binshDeps=$(for i in $(cat ${refs}); do if test -d $i; then echo $i; fi; done)
cat > $out <<END
# WARNING: this file is generated. # WARNING: this file is generated.
build-users-group = nixbld build-users-group = nixbld
build-max-jobs = ${toString (config.nix.maxJobs)} build-max-jobs = ${toString (config.nix.maxJobs)}
build-use-chroot = ${if config.nix.useChroot then "true" else "false"} build-use-chroot = ${if config.nix.useChroot then "true" else "false"}
build-chroot-dirs = /dev /dev/pts /proc /bin build-chroot-dirs = /dev /dev/pts /proc /bin $(echo $binshDeps)
${config.nix.extraOptions} ${config.nix.extraOptions}
END
''; '';
target = "nix.conf"; # will be symlinked from /nix/etc/nix/nix.conf in activate-configuration.sh. target = "nix.conf"; # will be symlinked from /nix/etc/nix/nix.conf in activate-configuration.sh.
} }
@ -209,7 +222,6 @@ let
"shadow" "shadow"
"sshd" "sshd"
"lshd" "lshd"
"lsh-pam-checkpw"
"useradd" "useradd"
"chsh" "chsh"
"xlock" "xlock"

View File

@ -1,4 +0,0 @@
auth include common
account include common
password include common
session include common

View File

@ -70,4 +70,5 @@ in
"" ""
["nix-reduce-build" "nix-http-export.cgi"] ["nix-reduce-build" "nix-http-export.cgi"]
["--with-docbook-xsl=\\\${pkgs.docbook5_xsl}/xml/xsl/docbook/"]; ["--with-docbook-xsl=\\\${pkgs.docbook5_xsl}/xml/xsl/docbook/"];
extraInitrdKernelModules = ["usb_storage" "ehci_hcd" "ohci_hcd" "iso9660" "ext3"];
}).rescueCD }).rescueCD

View File

@ -153,7 +153,6 @@ rec {
kernelModules = bootKernelModules; kernelModules = bootKernelModules;
extraModulePackages = ((extraModulePackages pkgs) extraModulePackages = ((extraModulePackages pkgs)
++(if aufs then [(kernelPackages pkgs).aufs] else []) ++(if aufs then [(kernelPackages pkgs).aufs] else [])
++(pkgs.lib.optional intel3945FWEnable (kernelPackages pkgs).iwlwifi)
); );
}; };

View File

@ -220,18 +220,12 @@ rec {
"; ";
# Put the current directory in a tarball (making sure to filter # Put the current directory in a tarball.
# out crap like the .svn directories). nixosTarball = makeTarball "nixos.tar.bz2" ../..;
nixosTarball = makeTarball "nixos.tar.bz2" (builtins.filterSource svnFilter ./../..);
svnFilter = name: type:
let base = baseNameOf (toString name);
in base != ".svn" && base != "result";
# Put Nixpkgs in a tarball # Put Nixpkgs in a tarball.
nixpkgsTarball = makeTarball "nixpkgs.tar.bz2" nixpkgsTarball = makeTarball "nixpkgs.tar.bz2" nixpkgsPath;
(builtins.filterSource svnFilter nixpkgsPath);
# The configuration file for Grub. # The configuration file for Grub.

75
release.nix Normal file
View File

@ -0,0 +1,75 @@
let
jobs = rec {
tarball =
{ nixosSrc ? {path = ./.; rev = 1234;}
, nixpkgs ? {path = ../nixpkgs-wc;}
, officialRelease ? false
}:
with import nixpkgs.path {};
releaseTools.makeSourceTarball {
name = "nixos-tarball";
src = nixosSrc;
inherit officialRelease;
distPhase = ''
releaseName=nixos-$(cat $src/VERSION)$VERSION_SUFFIX
ensureDir "$out/tarballs"
mkdir ../$releaseName
cp -prd . ../$releaseName
cd ..
tar cfvj $out/tarballs/$releaseName.tar.bz2 $releaseName
''; # */
};
manual =
{ nixosSrc ? {path = ./.; rev = 1234;}
, nixpkgs ? {path = ../nixpkgs-wc;}
, officialRelease ? false
}:
import "${nixosSrc.path}/doc/manual" {
nixpkgsPath = nixpkgs.path;
};
iso =
{ nixosSrc ? {path = ./.; rev = 1234;}
, nixpkgs ? {path = ../nixpkgs-wc;}
, officialRelease ? false
, system ? "i686-linux"
}:
with import nixpkgs.path {inherit system;};
let
iso = (import "${nixosSrc.path}/installer/cd-dvd/rescue-cd.nix" {
platform = system;
compressImage = true;
nixpkgsPath = nixpkgs.path;
}).rescueCD;
in
# Declare the ISO as a build product so that it shows up in Hydra.
runCommand "nixos-iso"
{ meta = {
description = "NixOS installation CD ISO image for ${system}";
};
}
''
ensureDir $out/nix-support
echo "file iso" ${iso}/iso/*.iso* >> $out/nix-support/hydra-build-products
''; # */
};
in jobs

View File

@ -301,7 +301,6 @@ in
kernel = kernelPackages.kernel; kernel = kernelPackages.kernel;
in in
[ kernel ] [ kernel ]
++ pkgs.lib.optional ((config.networking.enableIntel3945ABGFirmware || config.networking.enableIntel4965AGNFirmware) && !kernel.features ? iwlwifi) kernelPackages.iwlwifi
++ pkgs.lib.optional config.hardware.enableGo7007 kernelPackages.wis_go7007 ++ pkgs.lib.optional config.hardware.enableGo7007 kernelPackages.wis_go7007
++ config.boot.extraModulePackages ++ config.boot.extraModulePackages
# should only keep this one, other have to be set by the option owners. # should only keep this one, other have to be set by the option owners.
@ -818,6 +817,13 @@ in
<command>no</command> <command>no</command>
"; ";
}; };
gatewayPorts = mkOption {
default = "no";
description = "
Specifies whether remote hosts are allowed to connect to ports forwarded for the client. See man sshd_conf.
";
};
}; };
lshd = { lshd = {
@ -1255,9 +1261,11 @@ in
default = []; default = [];
example = [ "proxy_connect" { name = "php5_module"; path = "${pkgs.php}/modules/libphp5.so"; } ]; example = [ "proxy_connect" { name = "php5_module"; path = "${pkgs.php}/modules/libphp5.so"; } ];
description = '' description = ''
Loads additional modules either beeing distributed with apache. Specifies additional Apache modules. These can be specified
If the module is contained in a foreign package (such as php5_module) as a string in the case of modules distributed with Apache,
kse an attrset as given in the example. or as an attribute set specifying the
<varname>name</varname> and <varname>path</varname> of the
module.
''; '';
}; };
@ -1996,25 +2004,29 @@ in
example = [ { type = "svn"; url = "https://svn.nixos.org/repos/nix/nixos/branches/stdenv-updates"; target = "/etc/nixos/nixos-stdenv-updates"; } example = [ { type = "svn"; url = "https://svn.nixos.org/repos/nix/nixos/branches/stdenv-updates"; target = "/etc/nixos/nixos-stdenv-updates"; }
{ type = "git"; initialize = ''git clone git://mawercer.de/nixos $target''; update = "git pull origin"; target = "/etc/nixos/nixos-git"; } { type = "git"; initialize = ''git clone git://mawercer.de/nixos $target''; update = "git pull origin"; target = "/etc/nixos/nixos-git"; }
]; ];
description = "The NixOS repository from which the system will be build. description = ''
nixos-checkout will update all working copies of the given repositories, The NixOS repository from which the system will be built.
nixos-rebuild will use the first item which has <command>nixos-checkout</command> will update all working
the attribute default = true falling back to the copies of the given repositories,
first item. The type defines the repository tool added <command>nixos-rebuild</command> will use the first item
to the path. It also defines a \"valid\" repository. which has the attribute <literal>default = true</literal>
If the target directory already exists and it's not falling back to the first item. The type defines the
valid it will be moved to the backup location repository tool added to the path. It also defines a "valid"
<filename>\${dir}-date</filename>. repository. If the target directory already exists and it's
not valid it will be moved to the backup location
<filename><replaceable>dir</replaceable>-date</filename>.
For svn the default target and repositories are For svn the default target and repositories are
<filename>/etc/nixos/nixos</filename> and <filename>/etc/nixos/nixos</filename> and
<filename>https://svn.nixos.org/repos/nix/nixos/trunk</filename>. <filename>https://svn.nixos.org/repos/nix/nixos/trunk</filename>.
For git repositories update is called after For git repositories update is called after initialization
initialization when the repo is initialized. when the repo is initialized. The initialize code is run
The initialize code is run from working directory from working directory dirname
dirname \$target and should create the directory <replaceable>target</replaceable> and should create the
<filename>\$target<filename>. (<command>git clone url nixos/nixpkgs/services</command> should do) directory
For the executables beeing used see <option>repoTypes</option> <filename><replaceable>dir</replaceable></filename>. (<command>git
"; clone url nixos/nixpkgs/services</command> should do) For
the executables used see <option>repoTypes</option>.
'';
}; };
nixpkgs = mkOption { nixpkgs = mkOption {
@ -2033,8 +2045,13 @@ in
svn = { valid = "[ -d .svn ]"; env = [ pkgs.coreutils pkgs.subversion ]; }; svn = { valid = "[ -d .svn ]"; env = [ pkgs.coreutils pkgs.subversion ]; };
git = { valid = "[ -d .git ]"; env = [ pkgs.coreutils pkgs.git pkgs.gnused /* FIXME: use full path to sed in nix-pull */ ]; }; git = { valid = "[ -d .git ]"; env = [ pkgs.coreutils pkgs.git pkgs.gnused /* FIXME: use full path to sed in nix-pull */ ]; };
}; };
description = "defines PATH environment and when directory is considered beeing a valid repository. description = ''
If it's not it's moved to a backup directory"; Defines, for each supported version control system
(e.g. <literal>git</literal>), the dependencies for the
mechanism, as well as a test used to determine whether a
directory is a checkout created by that version control
system.
'';
}; };
manifests = mkOption { manifests = mkOption {
@ -2423,6 +2440,7 @@ in
(import ../upstart-jobs/zabbix-server.nix) (import ../upstart-jobs/zabbix-server.nix)
(import ../upstart-jobs/disnix.nix) (import ../upstart-jobs/disnix.nix)
(import ../upstart-jobs/cron.nix) (import ../upstart-jobs/cron.nix)
(import ../upstart-jobs/fcron.nix)
(import ../upstart-jobs/cron/locate.nix) (import ../upstart-jobs/cron/locate.nix)
# fonts # fonts

View File

@ -88,6 +88,10 @@ in
]; ];
system = { system = {
build = {
binsh = pkgs.bashInteractive;
};
activationScripts = { activationScripts = {
systemConfig = noDepEntry '' systemConfig = noDepEntry ''
systemConfig="$1" systemConfig="$1"
@ -122,7 +126,7 @@ in
# Create the required /bin/sh symlink; otherwise lots of things # Create the required /bin/sh symlink; otherwise lots of things
# (notably the system() function) won't work. # (notably the system() function) won't work.
mkdir -m 0755 -p $mountPoint/bin mkdir -m 0755 -p $mountPoint/bin
ln -sfn ${pkgs.bash}/bin/sh $mountPoint/bin/sh ln -sfn ${config.system.build.binsh}/bin/sh $mountPoint/bin/sh
'' [ '' [
activateLib.defaultPath # path to ln & mkdir activateLib.defaultPath # path to ln & mkdir
activateLib.stdio # ? activateLib.stdio # ?

View File

@ -184,6 +184,9 @@ rec {
# at boot time (such as start `init'). # at boot time (such as start `init').
activateConfiguration = config.system.activationScripts.script; activateConfiguration = config.system.activationScripts.script;
# The shell that we want to use for /bin/sh.
binsh = pkgs.bashInteractive;
# The init script of boot stage 2, which is supposed to do # The init script of boot stage 2, which is supposed to do
# everything else to bring up the system. # everything else to bring up the system.

View File

@ -19,7 +19,8 @@ let
default = false; default = false;
description = '' description = ''
Whether to make /var/spool/at{jobs,spool} writeable Whether to make /var/spool/at{jobs,spool} writeable
by everyone (and sticky). by everyone (and sticky). This is normally not needed since
the `at' commands are setuid/setgid `atd'.
''; '';
}; };
}; };
@ -74,7 +75,7 @@ start script
if [ ! -f "$etcdir"/at.deny ] if [ ! -f "$etcdir"/at.deny ]
then then
touch "$etcdir"/at.deny && \ touch "$etcdir"/at.deny && \
chown root:root "$etcdir"/at.deny && \ chown root:atd "$etcdir"/at.deny && \
chmod 640 "$etcdir"/at.deny chmod 640 "$etcdir"/at.deny
fi fi
if [ ! -f "$jobdir"/.SEQ ] if [ ! -f "$jobdir"/.SEQ ]
@ -107,9 +108,13 @@ mkIf cfg.enable {
]; ];
security = { security = {
extraSetuidPrograms = [ setuidOwners = map (program: {
"at" "atq" "atrm" inherit program;
]; owner = "atd";
group = "atd";
setuid = true;
setgid = true;
}) [ "at" "atq" "atrm" ];
}; };
environment = { environment = {

View File

@ -150,7 +150,7 @@ let
firmwareDirs = firmwareDirs =
pkgs.lib.optional config.networking.enableIntel2200BGFirmware pkgs.ipw2200fw pkgs.lib.optional config.networking.enableIntel2200BGFirmware pkgs.ipw2200fw
++ pkgs.lib.optional config.networking.enableIntel3945ABGFirmware pkgs.iwlwifi3945ucode ++ pkgs.lib.optional config.networking.enableIntel3945ABGFirmware pkgs.iwlwifi3945ucode
++ pkgs.lib.optional config.networking.enableIntel4965AGNFirmware pkgs.iwlwifi4965ucode ++ pkgs.lib.optional config.networking.enableIntel4965AGNFirmware kernelPackages.iwlwifi4965ucode
++ pkgs.lib.optional config.networking.enableZydasZD1211Firmware pkgs.zd1211fw ++ pkgs.lib.optional config.networking.enableZydasZD1211Firmware pkgs.zd1211fw
++ pkgs.lib.optional config.hardware.enableGo7007 "${kernelPackages.wis_go7007}/firmware" ++ pkgs.lib.optional config.hardware.enableGo7007 "${kernelPackages.wis_go7007}/firmware"
++ config.services.udev.addFirmware; ++ config.services.udev.addFirmware;
@ -239,9 +239,7 @@ let
inherit (pkgs) writeText openssh glibc; inherit (pkgs) writeText openssh glibc;
inherit (pkgs.xorg) xauth; inherit (pkgs.xorg) xauth;
inherit nssModulesPath; inherit nssModulesPath;
forwardX11 = config.services.sshd.forwardX11; inherit (config.services.sshd) forwardX11 allowSFTP permitRootLogin gatewayPorts;
allowSFTP = config.services.sshd.allowSFTP;
permitRootLogin = config.services.sshd.permitRootLogin;
}) })
# GNU lshd SSH2 deamon. # GNU lshd SSH2 deamon.

138
upstart-jobs/fcron.nix Normal file
View File

@ -0,0 +1,138 @@
{pkgs, config}:
###### interface
let
inherit (pkgs.lib) mkOption concatStringsSep;
inherit (pkgs) writeText;
options = {
services = {
fcron = {
enable = mkOption {
default = false;
description = ''Whether to enable the `fcron' daemon.
From its docs: "fcron does both the job of Vixie Cron and anacron, but does even more and better".
It can trigger actions even if the event has passed due to shutdown for example.
TODO: add supoprt for fcron.allow and fcron.deny
Of course on cron daemon is enough.. So if fcron works fine there should be a system option systemCron="fcron or cron"
There are (or have been) some security issues.
I haven't yet checked wether they have been resolved.
For now you should trust the users registering crontab files.
I think gentoo has them listed.
'';
};
allow = mkOption {
default = [];
description = ''
Users allowed to use fcrontab and fcrondyn (one name per line, special name "all" acts for everyone)
nix adds username "root" for you.
'';
};
deny = mkOption {
default = [];
description = " same as allow but deny ";
};
maxSerialJobs = mkOption {
default = 1;
description = "maximum number of serial jobs which can run simultaneously (-m)";
};
queuelen = mkOption {
default = "";
description = "number of jobs the serial queue and the lavg queue can contain - empty to net set this number (-q)";
};
systab = mkOption {
default = "";
description = ''
The "system" crontab contents..
'';
};
};
};
};
in
###### implementation
let
# Put all the system cronjobs together.
# TODO allow using fcron only..
#systemCronJobs =
# config.services.cron.systemCronJobs;
cfg = config.services.fcron;
ifEnabled = if cfg.enable then pkgs.lib.id else (x : []);
queuelen = if cfg.queuelen == "" then "" else "-q ${toString cfg.queuelen}";
# shell is set to /sh in config..
# ${pkgs.lib.concatStrings (map (job: job + "\n") systemCronJobs)}
systemCronJobsFile = pkgs.writeText "fcron-systab" ''
SHELL=${pkgs.bash}/bin/sh
PATH=${pkgs.coreutils}/bin:${pkgs.findutils}/bin:${pkgs.gnused}/bin
'';
allowdeny = target: users : {
source = writeText "fcron.${target}" (concatStringsSep "\n" users);
target = "fcron.${target}";
mode = "600"; # fcron has some security issues.. So I guess this is most safe
};
in
{
require = [
# (import ../upstart-jobs/default.nix) # config.services.extraJobs
# (import ?) # config.time.timeZone
# (import ?) # config.environment.etc
# (import ?) # config.environment.extraPackages
# (import ?) # config.environment.cleanStart
options
];
environment = {
etc = ifEnabled [
(allowdeny "allow" (["root"] ++ cfg.allow))
(allowdeny "deny" cfg.deny)
# see man 5 fcron.conf
{ source = writeText "fcon.conf" ''
fcrontabs = /var/spool/fcron
pidfile = /var/run/fcron.pid
fifofile = /var/run/fcron.fifo
fcronallow = /etc/fcron.allow
fcrondeny = /etc/fcron.deny
shell = /bin/sh
sendmail = /var/setuid-wrappers/sendmail
editor = /var/run/current-system/sw/bin/vi
'';
target = "fcron.conf";
mode = "0600"; # max allowed is 644
}
];
extraPackages = ifEnabled (
pkgs.lib.optional
(!config.environment.cleanStart)
pkgs.fcron);
};
services = {
extraJobs = ifEnabled [{
name = "fcron";
job = ''
description "fcron daemon"
start on startup
stop on shutdown
env PATH=/var/run/current-system/sw/bin
start script
${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/spool/fcron
# load system crontab file
${pkgs.fcron}/bin/fcrontab -u systab ${writeText "systab" cfg.systab}
end script
respawn ${pkgs.fcron}/sbin/fcron -f -m ${toString cfg.maxSerialJobs} ${queuelen}
'';
}];
};
}

View File

@ -31,6 +31,7 @@ start script
end script end script
respawn ${lsh}/sbin/lshd --daemonic \ respawn ${lsh}/sbin/lshd --daemonic \
--password-helper="${lsh}/sbin/lsh-pam-checkpw" \
-p ${toString portNumber} \ -p ${toString portNumber} \
${if interfaces == [] then "" ${if interfaces == [] then ""
else (concatStrings (map (i: "--interface=\"${i}\"") else (concatStrings (map (i: "--interface=\"${i}\"")

View File

@ -1,6 +1,6 @@
{ writeText, openssh, glibc, xauth { writeText, openssh, glibc, xauth
, nssModulesPath , nssModulesPath
, forwardX11, allowSFTP, permitRootLogin , forwardX11, allowSFTP, permitRootLogin, gatewayPorts
}: }:
assert permitRootLogin == "yes" || assert permitRootLogin == "yes" ||
@ -29,6 +29,7 @@ let
"} "}
PermitRootLogin ${permitRootLogin} PermitRootLogin ${permitRootLogin}
GatewayPorts ${gatewayPorts}
''; '';

View File

@ -183,6 +183,10 @@ let
default = "0.12"; default = "0.12";
description = "Cursor speed factor for highest-speed finger motion"; description = "Cursor speed factor for highest-speed finger motion";
}; };
twoFingerScroll = mkOption {
default = false;
description = "Whether to enable two-finger drag-scrolling";
};
}; };
layout = mkOption { layout = mkOption {
@ -413,6 +417,8 @@ let
Option "TapButton1" "1" Option "TapButton1" "1"
Option "TapButton2" "2" Option "TapButton2" "2"
Option "TapButton3" "3" Option "TapButton3" "3"
Option "VertTwoFingerScroll" "${if cfg.synaptics.twoFingerScroll then "1" else "0"}"
Option "HorizTwoFingerScroll" "${if cfg.synaptics.twoFingerScroll then "1" else "0"}"
EndSection EndSection
'' else ""; '' else "";