uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead
https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948 this can do it nicely. Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
commit
56de2bcd43
30691 changed files with 3076956 additions and 0 deletions
12
nixos/modules/system/etc/etc-activation.nix
Normal file
12
nixos/modules/system/etc/etc-activation.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) stringAfter;
|
||||
in {
|
||||
|
||||
imports = [ ./etc.nix ];
|
||||
|
||||
config = {
|
||||
system.activationScripts.etc =
|
||||
stringAfter [ "users" "groups" ] config.system.build.etcActivationCommands;
|
||||
};
|
||||
}
|
||||
201
nixos/modules/system/etc/etc.nix
Normal file
201
nixos/modules/system/etc/etc.nix
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
# Management of static files in /etc.
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
etc' = filter (f: f.enable) (attrValues config.environment.etc);
|
||||
|
||||
etc = pkgs.runCommandLocal "etc" {
|
||||
# This is needed for the systemd module
|
||||
passthru.targets = map (x: x.target) etc';
|
||||
} /* sh */ ''
|
||||
set -euo pipefail
|
||||
|
||||
makeEtcEntry() {
|
||||
src="$1"
|
||||
target="$2"
|
||||
mode="$3"
|
||||
user="$4"
|
||||
group="$5"
|
||||
|
||||
if [[ "$src" = *'*'* ]]; then
|
||||
# If the source name contains '*', perform globbing.
|
||||
mkdir -p "$out/etc/$target"
|
||||
for fn in $src; do
|
||||
ln -s "$fn" "$out/etc/$target/"
|
||||
done
|
||||
else
|
||||
|
||||
mkdir -p "$out/etc/$(dirname "$target")"
|
||||
if ! [ -e "$out/etc/$target" ]; then
|
||||
ln -s "$src" "$out/etc/$target"
|
||||
else
|
||||
echo "duplicate entry $target -> $src"
|
||||
if [ "$(readlink "$out/etc/$target")" != "$src" ]; then
|
||||
echo "mismatched duplicate entry $(readlink "$out/etc/$target") <-> $src"
|
||||
ret=1
|
||||
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$mode" != symlink ]; then
|
||||
echo "$mode" > "$out/etc/$target.mode"
|
||||
echo "$user" > "$out/etc/$target.uid"
|
||||
echo "$group" > "$out/etc/$target.gid"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "$out/etc"
|
||||
${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
|
||||
"makeEtcEntry"
|
||||
# Force local source paths to be added to the store
|
||||
"${etcEntry.source}"
|
||||
etcEntry.target
|
||||
etcEntry.mode
|
||||
etcEntry.user
|
||||
etcEntry.group
|
||||
]) etc'}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
imports = [ ../build.nix ];
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
environment.etc = mkOption {
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{ example-configuration-file =
|
||||
{ source = "/nix/store/.../etc/dir/file.conf.example";
|
||||
mode = "0440";
|
||||
};
|
||||
"default/useradd".text = "GROUP=100 ...";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Set of files that have to be linked in <filename>/etc</filename>.
|
||||
'';
|
||||
|
||||
type = with types; attrsOf (submodule (
|
||||
{ name, config, options, ... }:
|
||||
{ options = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether this /etc file should be generated. This
|
||||
option allows specific /etc files to be disabled.
|
||||
'';
|
||||
};
|
||||
|
||||
target = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Name of symlink (relative to
|
||||
<filename>/etc</filename>). Defaults to the attribute
|
||||
name.
|
||||
'';
|
||||
};
|
||||
|
||||
text = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.lines;
|
||||
description = "Text of the file.";
|
||||
};
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = "Path of the source file.";
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.str;
|
||||
default = "symlink";
|
||||
example = "0600";
|
||||
description = ''
|
||||
If set to something else than <literal>symlink</literal>,
|
||||
the file is copied instead of symlinked, with the given
|
||||
file mode.
|
||||
'';
|
||||
};
|
||||
|
||||
uid = mkOption {
|
||||
default = 0;
|
||||
type = types.int;
|
||||
description = ''
|
||||
UID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
gid = mkOption {
|
||||
default = 0;
|
||||
type = types.int;
|
||||
description = ''
|
||||
GID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
default = "+${toString config.uid}";
|
||||
type = types.str;
|
||||
description = ''
|
||||
User name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over <literal>uid</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
default = "+${toString config.gid}";
|
||||
type = types.str;
|
||||
description = ''
|
||||
Group name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over <literal>gid</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
target = mkDefault name;
|
||||
source = mkIf (config.text != null) (
|
||||
let name' = "etc-" + baseNameOf name;
|
||||
in mkDerivedConfig options.text (pkgs.writeText name')
|
||||
);
|
||||
};
|
||||
|
||||
}));
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = {
|
||||
|
||||
system.build.etc = etc;
|
||||
system.build.etcActivationCommands =
|
||||
''
|
||||
# Set up the statically computed bits of /etc.
|
||||
echo "setting up /etc..."
|
||||
${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl ${./setup-etc.pl} ${etc}/etc
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
||||
146
nixos/modules/system/etc/setup-etc.pl
Normal file
146
nixos/modules/system/etc/setup-etc.pl
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
use strict;
|
||||
use File::Find;
|
||||
use File::Copy;
|
||||
use File::Path;
|
||||
use File::Basename;
|
||||
use File::Slurp;
|
||||
|
||||
my $etc = $ARGV[0] or die;
|
||||
my $static = "/etc/static";
|
||||
|
||||
sub atomicSymlink {
|
||||
my ($source, $target) = @_;
|
||||
my $tmp = "$target.tmp";
|
||||
unlink $tmp;
|
||||
symlink $source, $tmp or return 0;
|
||||
rename $tmp, $target or return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# Atomically update /etc/static to point at the etc files of the
|
||||
# current configuration.
|
||||
atomicSymlink $etc, $static or die;
|
||||
|
||||
# Returns 1 if the argument points to the files in /etc/static. That
|
||||
# means either argument is a symlink to a file in /etc/static or a
|
||||
# directory with all children being static.
|
||||
sub isStatic {
|
||||
my $path = shift;
|
||||
|
||||
if (-l $path) {
|
||||
my $target = readlink $path;
|
||||
return substr($target, 0, length "/etc/static/") eq "/etc/static/";
|
||||
}
|
||||
|
||||
if (-d $path) {
|
||||
opendir DIR, "$path" or return 0;
|
||||
my @names = readdir DIR or die;
|
||||
closedir DIR;
|
||||
|
||||
foreach my $name (@names) {
|
||||
next if $name eq "." || $name eq "..";
|
||||
unless (isStatic("$path/$name")) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Remove dangling symlinks that point to /etc/static. These are
|
||||
# configuration files that existed in a previous configuration but not
|
||||
# in the current one. For efficiency, don't look under /etc/nixos
|
||||
# (where all the NixOS sources live).
|
||||
sub cleanup {
|
||||
if ($File::Find::name eq "/etc/nixos") {
|
||||
$File::Find::prune = 1;
|
||||
return;
|
||||
}
|
||||
if (-l $_) {
|
||||
my $target = readlink $_;
|
||||
if (substr($target, 0, length $static) eq $static) {
|
||||
my $x = "/etc/static/" . substr($File::Find::name, length "/etc/");
|
||||
unless (-l $x) {
|
||||
print STDERR "removing obsolete symlink ‘$File::Find::name’...\n";
|
||||
unlink "$_";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
find(\&cleanup, "/etc");
|
||||
|
||||
|
||||
# Use /etc/.clean to keep track of copied files.
|
||||
my @oldCopied = read_file("/etc/.clean", chomp => 1, err_mode => 'quiet');
|
||||
open CLEAN, ">>/etc/.clean";
|
||||
|
||||
|
||||
# For every file in the etc tree, create a corresponding symlink in
|
||||
# /etc to /etc/static. The indirection through /etc/static is to make
|
||||
# switching to a new configuration somewhat more atomic.
|
||||
my %created;
|
||||
my @copied;
|
||||
|
||||
sub link {
|
||||
my $fn = substr $File::Find::name, length($etc) + 1 or next;
|
||||
my $target = "/etc/$fn";
|
||||
File::Path::make_path(dirname $target);
|
||||
$created{$fn} = 1;
|
||||
|
||||
# Rename doesn't work if target is directory.
|
||||
if (-l $_ && -d $target) {
|
||||
if (isStatic $target) {
|
||||
rmtree $target or warn;
|
||||
} else {
|
||||
warn "$target directory contains user files. Symlinking may fail.";
|
||||
}
|
||||
}
|
||||
|
||||
if (-e "$_.mode") {
|
||||
my $mode = read_file("$_.mode"); chomp $mode;
|
||||
if ($mode eq "direct-symlink") {
|
||||
atomicSymlink readlink("$static/$fn"), $target or warn;
|
||||
} else {
|
||||
my $uid = read_file("$_.uid"); chomp $uid;
|
||||
my $gid = read_file("$_.gid"); chomp $gid;
|
||||
copy "$static/$fn", "$target.tmp" or warn;
|
||||
$uid = getpwnam $uid unless $uid =~ /^\+/;
|
||||
$gid = getgrnam $gid unless $gid =~ /^\+/;
|
||||
chown int($uid), int($gid), "$target.tmp" or warn;
|
||||
chmod oct($mode), "$target.tmp" or warn;
|
||||
rename "$target.tmp", $target or warn;
|
||||
}
|
||||
push @copied, $fn;
|
||||
print CLEAN "$fn\n";
|
||||
} elsif (-l "$_") {
|
||||
atomicSymlink "$static/$fn", $target or warn;
|
||||
}
|
||||
}
|
||||
|
||||
find(\&link, $etc);
|
||||
|
||||
|
||||
# Delete files that were copied in a previous version but not in the
|
||||
# current.
|
||||
foreach my $fn (@oldCopied) {
|
||||
if (!defined $created{$fn}) {
|
||||
$fn = "/etc/$fn";
|
||||
print STDERR "removing obsolete file ‘$fn’...\n";
|
||||
unlink "$fn";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Rewrite /etc/.clean.
|
||||
close CLEAN;
|
||||
write_file("/etc/.clean", map { "$_\n" } @copied);
|
||||
|
||||
# Create /etc/NIXOS tag if not exists.
|
||||
# When /etc is not on a persistent filesystem, it will be wiped after reboot,
|
||||
# so we need to check and re-create it during activation.
|
||||
open TAG, ">>/etc/NIXOS";
|
||||
close TAG;
|
||||
70
nixos/modules/system/etc/test.nix
Normal file
70
nixos/modules/system/etc/test.nix
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{ lib
|
||||
, coreutils
|
||||
, fakechroot
|
||||
, fakeroot
|
||||
, evalMinimalConfig
|
||||
, pkgsModule
|
||||
, runCommand
|
||||
, util-linux
|
||||
, vmTools
|
||||
, writeText
|
||||
}:
|
||||
let
|
||||
node = evalMinimalConfig ({ config, ... }: {
|
||||
imports = [ pkgsModule ../etc/etc.nix ];
|
||||
environment.etc."passwd" = {
|
||||
text = passwdText;
|
||||
};
|
||||
environment.etc."hosts" = {
|
||||
text = hostsText;
|
||||
mode = "0751";
|
||||
};
|
||||
});
|
||||
passwdText = ''
|
||||
root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash
|
||||
'';
|
||||
hostsText = ''
|
||||
127.0.0.1 localhost
|
||||
::1 localhost
|
||||
# testing...
|
||||
'';
|
||||
in
|
||||
lib.recurseIntoAttrs {
|
||||
test-etc-vm =
|
||||
vmTools.runInLinuxVM (runCommand "test-etc-vm" { } ''
|
||||
mkdir -p /etc
|
||||
${node.config.system.build.etcActivationCommands}
|
||||
set -x
|
||||
[[ -L /etc/passwd ]]
|
||||
diff /etc/passwd ${writeText "expected-passwd" passwdText}
|
||||
[[ 751 = $(stat --format %a /etc/hosts) ]]
|
||||
diff /etc/hosts ${writeText "expected-hosts" hostsText}
|
||||
set +x
|
||||
touch $out
|
||||
'');
|
||||
|
||||
# fakeroot is behaving weird
|
||||
test-etc-fakeroot =
|
||||
runCommand "test-etc"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
fakeroot
|
||||
fakechroot
|
||||
# for chroot
|
||||
coreutils
|
||||
# fakechroot needs getopt, which is provided by util-linux
|
||||
util-linux
|
||||
];
|
||||
fakeRootCommands = ''
|
||||
mkdir -p /etc
|
||||
${node.config.system.build.etcActivationCommands}
|
||||
diff /etc/hosts ${writeText "expected-hosts" hostsText}
|
||||
touch $out
|
||||
'';
|
||||
} ''
|
||||
mkdir fake-root
|
||||
export FAKECHROOT_EXCLUDE_PATH=/dev:/proc:/sys:${builtins.storeDir}:$out
|
||||
fakechroot fakeroot chroot $PWD/fake-root bash -c 'source $stdenv/setup; eval "$fakeRootCommands"'
|
||||
'';
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue