Compare commits
139 Commits
master
...
1.11-maint
Author | SHA1 | Date |
---|---|---|
Eelco Dolstra | 33d58a1904 | |
Eelco Dolstra | c6e15c4322 | |
Eelco Dolstra | 7487debaf5 | |
Eelco Dolstra | a18c085af8 | |
Graham Christensen | 6b887844d6 | |
Graham Christensen | c32bdf0548 | |
Eelco Dolstra | e462fa746b | |
Eelco Dolstra | 3454356001 | |
Danylo Hlynskyi | c7c806ec21 | |
Eelco Dolstra | 76431e0a26 | |
Shea Levy | 3c52567b3e | |
Anthony Cowley | b03066835c | |
Eelco Dolstra | aa57c32318 | |
Eelco Dolstra | f217acd9e7 | |
Falco Peijnenburg | b3ad7c5052 | |
Eelco Dolstra | e8235c4f3e | |
Sergei Trofimovich | 41352d50db | |
Eelco Dolstra | b3a616e860 | |
Eelco Dolstra | 617dab1515 | |
Eelco Dolstra | 35f541a7a0 | |
Eelco Dolstra | 23795d47fb | |
Graham Christensen | d07697de5f | |
Domen Kožar | 3afb744185 | |
Eelco Dolstra | 04532ee2c8 | |
Eelco Dolstra | 24883645a6 | |
Graham Christensen | 9a04bc6f5e | |
Eelco Dolstra | 0ec723375b | |
Graham Christensen | 4b45f94b5c | |
Eelco Dolstra | 16daed49dc | |
Graham Christensen | 41f0a08a31 | |
Graham Christensen | e4831a4412 | |
Graham Christensen | 6ba624f25a | |
Graham Christensen | 6b6d4b69c1 | |
Graham Christensen | b01eaa6114 | |
Eelco Dolstra | 04e071a5e4 | |
Domen Kožar | 44f51a5dd2 | |
Eelco Dolstra | e135db704f | |
Graham Christensen | c82126790d | |
Graham Christensen | 85acfcd6bd | |
Graham Christensen | b2917c8246 | |
Graham Christensen | a31347d6ec | |
Graham Christensen | c4f349d572 | |
Graham Christensen | 163d93125e | |
Graham Christensen | 302e820660 | |
Graham Christensen | 2442c4684d | |
Graham Christensen | d4f128352e | |
Graham Christensen | 0c13077d83 | |
Graham Christensen | 661daed683 | |
Graham Christensen | 262a08c0e2 | |
Graham Christensen | 3ebd25a644 | |
Graham Christensen | 218978154a | |
Graham Christensen | 799f5adf79 | |
Eelco Dolstra | 84d10d248e | |
Robert Vollmert | 758a3044f1 | |
Matthew Bauer | 5a7d00ced8 | |
Eelco Dolstra | 9943f98c35 | |
Eelco Dolstra | b59788fc48 | |
Eelco Dolstra | 7577d35895 | |
Shea Levy | 2a0112a370 | |
Graham Christensen | 3e0a503bf7 | |
Eelco Dolstra | 026f4f9ae8 | |
Eelco Dolstra | 11dd08f02e | |
Shea Levy | 3e574c3691 | |
Eelco Dolstra | 5ac7088726 | |
Eelco Dolstra | 35ea3d62dc | |
Joel Rivera | 7917494c45 | |
Eelco Dolstra | 1e4885e316 | |
Eelco Dolstra | 36f363b8f0 | |
Eelco Dolstra | c33854513a | |
Eelco Dolstra | 0be5b949d3 | |
Eelco Dolstra | c20641ce56 | |
Eelco Dolstra | 0fb60e4e0f | |
Eelco Dolstra | 3414f3804c | |
Eelco Dolstra | 8e298e8ad9 | |
Eelco Dolstra | f534627929 | |
Eelco Dolstra | 0ca9502264 | |
Eelco Dolstra | bcc21744df | |
Eelco Dolstra | 833aae4509 | |
Eelco Dolstra | aabe20bf78 | |
Eelco Dolstra | c48697d617 | |
Eelco Dolstra | 4be5a65b39 | |
Eelco Dolstra | 634d117ede | |
Eelco Dolstra | 66618dbad5 | |
Eelco Dolstra | 1e0f1dab1e | |
Eelco Dolstra | 17da82e04d | |
Eelco Dolstra | a2cf0f1018 | |
Eelco Dolstra | e296b8884e | |
Guillaume Maudoux | a8d13e66ee | |
Guillaume Maudoux | a10bd3355a | |
Eelco Dolstra | 26f7e8305b | |
Eelco Dolstra | 5d59ec86d4 | |
Eelco Dolstra | 1ab5cc0f5a | |
Dan Peebles | ad9e6037a4 | |
Neil Mayhew | de4e706776 | |
Shea Levy | eb6f3d5159 | |
Shea Levy | 967f231981 | |
Daiderd Jordan | 773313591f | |
Eelco Dolstra | 206b61b074 | |
Eelco Dolstra | 201ad43d1a | |
Vladimír Čunát | 9504bcf03c | |
Eelco Dolstra | d8638ae6b4 | |
Shea Levy | a437b8c5d2 | |
Shea Levy | 37bdb9d7f2 | |
Domen Kožar | 13fe83dc8e | |
Eelco Dolstra | 697b5755e4 | |
Dmitry Kalinkin | 06b46f646d | |
Eelco Dolstra | 2936a8d1ca | |
Eelco Dolstra | 142c777112 | |
Eelco Dolstra | 41230dd463 | |
Eelco Dolstra | 8ca944e009 | |
Eelco Dolstra | 1fa2c86db5 | |
Eelco Dolstra | 0085fc6d3e | |
Tuomas Tynkkynen | a4ad1ffa25 | |
Scott R. Parish | 0c67498be9 | |
Eelco Dolstra | d39f51fa34 | |
Dmitry Kalinkin | 5bf9689e0c | |
Shea Levy | 612c77a399 | |
Eelco Dolstra | 2eb840eefa | |
Shea Levy | fd9fc15c0c | |
Shea Levy | 8bddc3d406 | |
Eelco Dolstra | fb577a431f | |
Eelco Dolstra | 8c353ea698 | |
Eelco Dolstra | a566927003 | |
Dan Peebles | f2495212b1 | |
Eelco Dolstra | 7ead75ca85 | |
Eelco Dolstra | f668fdb026 | |
aszlig | 16e88f0b5a | |
Eelco Dolstra | 2179dd3e5b | |
Eelco Dolstra | efa2e451fb | |
Shea Levy | dea9de79b7 | |
Shea Levy | 2ac966a464 | |
Eelco Dolstra | 6a493a7c44 | |
Shea Levy | 7bb4d028a8 | |
Shea Levy | 66151dc154 | |
Domen Kožar | 0eb8bbb31e | |
Eelco Dolstra | 437d3cdc7a | |
Alex Cruice | 0322c92560 | |
Brian McKenna | 1852f7dbf3 | |
Eelco Dolstra | 08500066ea |
|
@ -34,6 +34,7 @@ Makefile.config
|
|||
|
||||
# /scripts/
|
||||
/scripts/nix-profile.sh
|
||||
/scripts/nix-profile-daemon.sh
|
||||
/scripts/nix-pull
|
||||
/scripts/nix-push
|
||||
/scripts/nix-switch
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
os: osx
|
||||
script: ./tests/install-darwin.sh
|
|
@ -200,6 +200,13 @@ AC_SUBST(HAVE_SODIUM, [$have_sodium])
|
|||
PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"])
|
||||
|
||||
|
||||
# Look for libseccomp, required for Linux sandboxing.
|
||||
if test "$sys_name" = linux; then
|
||||
PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
|
||||
[CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
|
||||
fi
|
||||
|
||||
|
||||
# Whether to use the Boehm garbage collector.
|
||||
AC_ARG_ENABLE(gc, AC_HELP_STRING([--enable-gc],
|
||||
[enable garbage collection in the Nix expression evaluator (requires Boehm GC) [default=no]]),
|
||||
|
|
|
@ -268,7 +268,12 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
|
|||
to mount a path in a different location in the sandbox; for
|
||||
instance, <literal>/bin=/nix-bin</literal> will mount the path
|
||||
<literal>/nix-bin</literal> as <literal>/bin</literal> inside the
|
||||
sandbox.</para>
|
||||
sandbox. If <replaceable>source</replaceable> is followed by
|
||||
<literal>?</literal>, then it is not an error if
|
||||
<replaceable>source</replaceable> does not exist; for example,
|
||||
<literal>/dev/nvidiactl?</literal> specifies that
|
||||
<filename>/dev/nvidiactl</filename> will only be mounted in the
|
||||
sandbox if it exists in the host filesystem.</para>
|
||||
|
||||
<para>Depending on how Nix was built, the default value for this option
|
||||
may be empty or provide <filename>/bin/sh</filename> as a
|
||||
|
@ -452,6 +457,29 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
|
|||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>netrc-file</literal></term>
|
||||
|
||||
<listitem><para>If set to an absolute path to a <filename>netrc</filename>
|
||||
file, Nix will use the HTTP authentication credentials in this file when
|
||||
trying to download from a remote host through HTTP or HTTPS. Defaults to
|
||||
<filename>$NIX_CONF_DIR/netrc</filename>.</para>
|
||||
|
||||
<para>The <filename>netrc</filename> file consists of a list of
|
||||
accounts in the following format:
|
||||
|
||||
<screen>
|
||||
machine <replaceable>my-machine</replaceable>
|
||||
login <replaceable>my-username</replaceable>
|
||||
password <replaceable>my-password</replaceable>
|
||||
</screen>
|
||||
|
||||
For the exact syntax, see <link
|
||||
xlink:href="https://ec.haxx.se/usingcurl-netrc.html">the
|
||||
<literal>curl</literal> documentation.</link></para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>system</literal></term>
|
||||
|
||||
<listitem><para>This option specifies the canonical Nix system
|
||||
|
|
|
@ -22,12 +22,6 @@
|
|||
<arg><option>--delete-old</option></arg>
|
||||
<arg><option>-d</option></arg>
|
||||
<arg><option>--delete-older-than</option> <replaceable>period</replaceable></arg>
|
||||
<group choice='opt'>
|
||||
<arg choice='plain'><option>--print-roots</option></arg>
|
||||
<arg choice='plain'><option>--print-live</option></arg>
|
||||
<arg choice='plain'><option>--print-dead</option></arg>
|
||||
<arg choice='plain'><option>--delete</option></arg>
|
||||
</group>
|
||||
<arg><option>--max-freed</option> <replaceable>bytes</replaceable></arg>
|
||||
<arg><option>--dry-run</option></arg>
|
||||
</cmdsynopsis>
|
||||
|
|
|
@ -367,6 +367,10 @@ number of possible ways:
|
|||
linkend="rsec-nix-store-realise">realised</link> and
|
||||
installed.</para></listitem>
|
||||
|
||||
<listitem><para>By default all outputs are installed for each derivation.
|
||||
That can be reduced by setting <literal>meta.outputsToInstall</literal>.
|
||||
</para></listitem> <!-- TODO: link nixpkgs docs on the ability to override those. -->
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
|
|
@ -43,7 +43,8 @@
|
|||
<arg choice='plain'><option>-E</option></arg>
|
||||
</group>
|
||||
<arg choice='plain' rep='repeat'><replaceable>files</replaceable></arg>
|
||||
<sbr/>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>nix-instantiate</command>
|
||||
<arg choice='plain'><option>--find-file</option></arg>
|
||||
<arg choice='plain' rep='repeat'><replaceable>files</replaceable></arg>
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
<title>Building and Testing</title>
|
||||
|
||||
<para>You can now try to build Hello. Of course, you could do
|
||||
<literal>nix-env -f pkgs/top-level/all-packages.nix -i hello</literal>,
|
||||
but you may not want to install a possibly broken package just yet.
|
||||
The best way to test the package is by using the command <command
|
||||
linkend="sec-nix-build">nix-build</command>, which builds a Nix
|
||||
expression and creates a symlink named <filename>result</filename> in
|
||||
the current directory:
|
||||
<literal>nix-env -i hello</literal>, but you may not want to install a
|
||||
possibly broken package just yet. The best way to test the package is by
|
||||
using the command <command linkend="sec-nix-build">nix-build</command>,
|
||||
which builds a Nix expression and creates a symlink named
|
||||
<filename>result</filename> in the current directory:
|
||||
|
||||
<screen>
|
||||
$ nix-build pkgs/top-level/all-packages.nix -A hello
|
||||
$ nix-build -A hello
|
||||
building path `/nix/store/632d2b22514d...-hello-2.1.1'
|
||||
hello-2.1.1/
|
||||
hello-2.1.1/intl/
|
||||
|
@ -29,8 +28,7 @@ $ ./result/bin/hello
|
|||
Hello, world!</screen>
|
||||
|
||||
The <link linkend='opt-attr'><option>-A</option></link> option selects
|
||||
the <literal>hello</literal> attribute from
|
||||
<filename>all-packages.nix</filename>. This is faster than using the
|
||||
the <literal>hello</literal> attribute. This is faster than using the
|
||||
symbolic package name specified by the <literal>name</literal>
|
||||
attribute (which also happens to be <literal>hello</literal>) and is
|
||||
unambiguous (there can be multiple packages with the symbolic name
|
||||
|
@ -69,7 +67,7 @@ block (or perform other derivations if available) until the build
|
|||
finishes:
|
||||
|
||||
<screen>
|
||||
$ nix-build pkgs/top-level/all-packages.nix -A hello
|
||||
$ nix-build -A hello
|
||||
waiting for lock on `/nix/store/0h5b7hp8d4hqfrw8igvx97x1xawrjnac-hello-2.1.1x'</screen>
|
||||
|
||||
So it is always safe to run multiple instances of Nix in parallel
|
||||
|
|
|
@ -10,7 +10,7 @@ XSLTPROC = $(xsltproc) --nonet $(xmlflags) \
|
|||
--stringparam generate.toc "book toc" \
|
||||
--param keep.relative.image.uris 0
|
||||
|
||||
docbookxsl = http://docbook.sourceforge.net/release/xsl-ns/1.78.1
|
||||
docbookxsl = http://docbook.sourceforge.net/release/xsl-ns/current
|
||||
docbookrng = http://docbook.org/xml/5.0/rng/docbook.rng
|
||||
|
||||
MANUAL_SRCS := $(call rwildcard, $(d), *.xml)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
</partintro>
|
||||
-->
|
||||
|
||||
<xi:include href="rl-1.11.10.xml" />
|
||||
<xi:include href="rl-1.11.xml" />
|
||||
<xi:include href="rl-1.10.xml" />
|
||||
<xi:include href="rl-1.9.xml" />
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ssec-relnotes-1.11.10">
|
||||
|
||||
<title>Release 1.11.10 (2017-06-12)</title>
|
||||
|
||||
<para>This release fixes a security bug in Nix’s “build user” build
|
||||
isolation mechanism. Previously, Nix builders had the ability to
|
||||
create setuid binaries owned by a <literal>nixbld</literal>
|
||||
user. Such a binary could then be used by an attacker to assume a
|
||||
<literal>nixbld</literal> identity and interfere with subsequent
|
||||
builds running under the same UID.</para>
|
||||
|
||||
<para>To prevent this issue, Nix now disallows builders to create
|
||||
setuid and setgid binaries. On Linux, this is done using a seccomp BPF
|
||||
filter. Note that this imposes a small performance penalty (e.g. 1%
|
||||
when building GNU Hello). Using seccomp, we now also prevent the
|
||||
creation of extended attributes and POSIX ACLs since these cannot be
|
||||
represented in the NAR format and (in the case of POSIX ACLs) allow
|
||||
bypassing regular Nix store permissions. On macOS, the restriction is
|
||||
implemented using the existing sandbox mechanism, which now uses a
|
||||
minimal “allow all except the creation of setuid/setgid binaries”
|
||||
profile when regular sandboxing is disabled. On other platforms, the
|
||||
“build user” mechanism is now disabled.</para>
|
||||
|
||||
<para>Thanks go to Linus Heckemann for discovering and reporting this
|
||||
bug.</para>
|
||||
|
||||
</section>
|
|
@ -13,11 +13,11 @@ RUN set -x \
|
|||
ONBUILD ENV \
|
||||
ENV=/etc/profile \
|
||||
PATH=/root/.nix-profile/bin:/root/.nix-profile/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
|
||||
GIT_SSL_CAINFO=/root/.nix-profile/etc/ca-bundle.crt \
|
||||
SSL_CERT_FILE=/root/.nix-profile/etc/ca-bundle.crt
|
||||
GIT_SSL_CAINFO=/root/.nix-profile/etc/ssl/certs/ca-bundle.crt \
|
||||
NIX_SSL_CERT_FILE=/root/.nix-profile/etc/ssl/certs/ca-bundle.crt
|
||||
|
||||
ENV \
|
||||
ENV=/etc/profile \
|
||||
PATH=/root/.nix-profile/bin:/root/.nix-profile/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
|
||||
GIT_SSL_CAINFO=/root/.nix-profile/etc/ca-bundle.crt \
|
||||
SSL_CERT_FILE=/root/.nix-profile/etc/ca-bundle.crt
|
||||
GIT_SSL_CAINFO=/root/.nix-profile/etc/ssl/certs/ca-bundle.crt \
|
||||
NIX_SSL_CERT_FILE=/root/.nix-profile/etc/ssl/certs/ca-bundle.crt
|
||||
|
|
|
@ -12,5 +12,10 @@
|
|||
<string>/var/log/nix-daemon.log</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/dev/null</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>NIX_SSL_CERT_FILE</key>
|
||||
<string>/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -24,9 +24,11 @@ Requires: perl-DBD-SQLite
|
|||
Requires: bzip2
|
||||
Requires: gzip
|
||||
Requires: xz
|
||||
Requires: libseccomp
|
||||
BuildRequires: bzip2-devel
|
||||
BuildRequires: sqlite-devel
|
||||
BuildRequires: libcurl-devel
|
||||
BuildRequires: libseccomp-devel
|
||||
|
||||
# Hack to make that shitty RPM scanning hack shut up.
|
||||
Provides: perl(Nix::SSH)
|
||||
|
@ -178,6 +180,7 @@ systemctl start nix-daemon.socket
|
|||
%{_mandir}/man5/*.5*
|
||||
%{_mandir}/man8/*.8*
|
||||
%config(noreplace) %{_sysconfdir}/profile.d/nix.sh
|
||||
%config(noreplace) %{_sysconfdir}/profile.d/nix-daemon.sh
|
||||
/nix
|
||||
|
||||
%files devel
|
||||
|
|
|
@ -12,6 +12,12 @@ $logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix";
|
|||
$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix";
|
||||
$storeDir = $ENV{"NIX_STORE_DIR"} || "@storedir@";
|
||||
|
||||
$caBundle = $ENV{"NIX_SSL_CERT_FILE"} // $ENV{"SSL_CERT_FILE"} // $ENV{"CURL_CA_BUNDLE"} // $ENV{"OPENSSL_X509_CERT_FILE"};
|
||||
$caBundle = "/etc/ssl/certs/ca-bundle.crt" if !$caBundle && -f "/etc/ssl/certs/ca-bundle.crt";
|
||||
$caBundle = "/etc/ssl/certs/ca-certificates.crt" if !$caBundle && -f "/etc/ssl/certs/ca-certificates.crt";
|
||||
|
||||
$curlCaFlag = defined $caBundle ? "--cacert $caBundle" : "";
|
||||
|
||||
$bzip2 = "@bzip2@";
|
||||
$xz = "@xz@";
|
||||
$curl = "@curl@";
|
||||
|
|
83
release.nix
83
release.nix
|
@ -7,7 +7,7 @@ let
|
|||
|
||||
pkgs = import <nixpkgs> {};
|
||||
|
||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" /* "x86_64-freebsd" "i686-freebsd" */ ];
|
||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" /* "x86_64-freebsd" "i686-freebsd" */ ];
|
||||
|
||||
|
||||
jobs = rec {
|
||||
|
@ -27,7 +27,8 @@ let
|
|||
[ curl bison flex perl libxml2 libxslt bzip2 xz
|
||||
dblatex (dblatex.tex or tetex) nukeReferences pkgconfig sqlite libsodium
|
||||
docbook5 docbook5_xsl
|
||||
] ++ lib.optional (!lib.inNixShell) git;
|
||||
] ++ lib.optional stdenv.isLinux libseccomp
|
||||
++ lib.optional (!lib.inNixShell) git;
|
||||
|
||||
configureFlags = ''
|
||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||
|
@ -77,8 +78,7 @@ let
|
|||
|
||||
build = pkgs.lib.genAttrs systems (system:
|
||||
|
||||
# FIXME: temporarily use a different branch for the Darwin build.
|
||||
with import (if system == "x86_64-darwin" then <nixpkgs-darwin> else <nixpkgs>) { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.nixBuild {
|
||||
name = "nix";
|
||||
|
@ -86,7 +86,8 @@ let
|
|||
|
||||
buildInputs =
|
||||
[ curl perl bzip2 xz openssl pkgconfig sqlite boehmgc ]
|
||||
++ lib.optional stdenv.isLinux libsodium;
|
||||
++ lib.optional stdenv.isLinux libseccomp
|
||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium;
|
||||
|
||||
configureFlags = ''
|
||||
--disable-init-state
|
||||
|
@ -113,7 +114,7 @@ let
|
|||
binaryTarball = pkgs.lib.genAttrs systems (system:
|
||||
|
||||
# FIXME: temporarily use a different branch for the Darwin build.
|
||||
with import (if system == "x86_64-darwin" then <nixpkgs-darwin> else <nixpkgs>) { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
let
|
||||
toplevel = builtins.getAttr system jobs.build;
|
||||
|
@ -122,7 +123,7 @@ let
|
|||
|
||||
runCommand "nix-binary-tarball-${version}"
|
||||
{ exportReferencesGraph = [ "closure1" toplevel "closure2" cacert ];
|
||||
buildInputs = [ perl ];
|
||||
buildInputs = [ perl /* shellcheck */ ];
|
||||
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
|
||||
}
|
||||
''
|
||||
|
@ -131,7 +132,15 @@ let
|
|||
substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
|
||||
--subst-var-by nix ${toplevel} \
|
||||
--subst-var-by cacert ${cacert}
|
||||
substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user \
|
||||
--subst-var-by nix ${toplevel} \
|
||||
--subst-var-by cacert ${cacert}
|
||||
|
||||
#shellcheck -e SC1090 $TMPDIR/install
|
||||
#shellcheck -e SC1091,SC2002 $TMPDIR/install-darwin-multi-user
|
||||
|
||||
chmod +x $TMPDIR/install
|
||||
chmod +x $TMPDIR/install-darwin-multi-user
|
||||
dir=nix-${version}-${system}
|
||||
fn=$out/$dir.tar.bz2
|
||||
mkdir -p $out/nix-support
|
||||
|
@ -143,7 +152,7 @@ let
|
|||
--transform "s,$TMPDIR/install,$dir/install," \
|
||||
--transform "s,$TMPDIR/reginfo,$dir/.reginfo," \
|
||||
--transform "s,$NIX_STORE,$dir/store,S" \
|
||||
$TMPDIR/install $TMPDIR/reginfo $storePaths
|
||||
$TMPDIR/install $TMPDIR/install-darwin-multi-user $TMPDIR/reginfo $storePaths
|
||||
'');
|
||||
|
||||
|
||||
|
@ -155,7 +164,7 @@ let
|
|||
src = tarball;
|
||||
|
||||
buildInputs =
|
||||
[ curl perl bzip2 openssl pkgconfig sqlite xz libsodium
|
||||
[ curl perl bzip2 openssl pkgconfig sqlite xz libsodium libseccomp
|
||||
# These are for "make check" only:
|
||||
graphviz libxml2 libxslt
|
||||
];
|
||||
|
@ -180,8 +189,6 @@ let
|
|||
};
|
||||
|
||||
|
||||
rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) [];
|
||||
rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) [];
|
||||
rpm_fedora19i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora19i386) [];
|
||||
rpm_fedora19x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora19x86_64) [];
|
||||
rpm_fedora20i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora20i386) [];
|
||||
|
@ -190,23 +197,19 @@ let
|
|||
rpm_fedora21x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora21x86_64) [ "libsodium-devel" ];
|
||||
|
||||
|
||||
deb_debian7i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian7i386) [];
|
||||
deb_debian7x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian7x86_64) [];
|
||||
deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ];
|
||||
deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ];
|
||||
deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||
deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||
|
||||
deb_ubuntu1210i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1210i386) [];
|
||||
deb_ubuntu1210x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1210x86_64) [];
|
||||
deb_ubuntu1304i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1304i386) [];
|
||||
deb_ubuntu1304x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1304x86_64) [];
|
||||
deb_ubuntu1310i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1310i386) [];
|
||||
deb_ubuntu1310x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1310x86_64) [];
|
||||
deb_ubuntu1404i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1404i386) [];
|
||||
deb_ubuntu1404x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1404x86_64) [];
|
||||
deb_ubuntu1410i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1410i386) [];
|
||||
deb_ubuntu1410x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1410x86_64) [];
|
||||
deb_ubuntu1504i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1504i386) [ "libsodium-dev" ];
|
||||
deb_ubuntu1504x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1504x86_64) [ "libsodium-dev" ];
|
||||
deb_ubuntu1404i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1404i386) [] [];
|
||||
deb_ubuntu1404x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1404x86_64) [] [];
|
||||
deb_ubuntu1410i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1410i386) [] [];
|
||||
deb_ubuntu1410x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1410x86_64) [] [];
|
||||
deb_ubuntu1504i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1504i386) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||
deb_ubuntu1504x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1504x86_64) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||
deb_ubuntu1510i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1510i386) [ "libsodium-dev" ] [ "libsodium13"];
|
||||
deb_ubuntu1510x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1510x86_64) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||
deb_ubuntu1604i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1604i386) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||
deb_ubuntu1604x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1604x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||
|
||||
|
||||
# System tests.
|
||||
|
@ -218,6 +221,11 @@ let
|
|||
nix = build.x86_64-linux; system = "x86_64-linux";
|
||||
});
|
||||
|
||||
tests.setuid = pkgs.lib.genAttrs (pkgs.lib.filter (pkgs.lib.hasSuffix "-linux") systems) (system:
|
||||
import ./tests/setuid.nix rec {
|
||||
nix = build.${system}; inherit system;
|
||||
});
|
||||
|
||||
tests.binaryTarball =
|
||||
with import <nixpkgs> { system = "x86_64-linux"; };
|
||||
vmTools.runInLinuxImage (runCommand "nix-binary-tarball-test"
|
||||
|
@ -226,13 +234,15 @@ let
|
|||
''
|
||||
useradd -m alice
|
||||
su - alice -c 'tar xf ${binaryTarball.x86_64-linux}/*.tar.*'
|
||||
mount -t tmpfs none /nix # Provide a writable /nix.
|
||||
mkdir /dest-nix
|
||||
mount -o bind /dest-nix /nix # Provide a writable /nix.
|
||||
chown alice /nix
|
||||
su - alice -c '_NIX_INSTALLER_TEST=1 ./nix-*/install'
|
||||
su - alice -c 'nix-store --verify'
|
||||
su - alice -c 'nix-store -qR ${build.x86_64-linux}'
|
||||
su - alice -c 'PAGER= nix-store -qR ${build.x86_64-linux}'
|
||||
mkdir -p $out/nix-support
|
||||
touch $out/nix-support/hydra-build-products
|
||||
umount /nix
|
||||
''); # */
|
||||
|
||||
tests.evalNixpkgs =
|
||||
|
@ -272,8 +282,8 @@ let
|
|||
binaryTarball.x86_64-darwin
|
||||
#binaryTarball.x86_64-freebsd
|
||||
binaryTarball.x86_64-linux
|
||||
deb_debian7i386
|
||||
deb_debian7x86_64
|
||||
deb_debian8i386
|
||||
deb_debian8x86_64
|
||||
deb_ubuntu1404i386 # LTS
|
||||
deb_ubuntu1404x86_64 # LTS
|
||||
deb_ubuntu1504i386
|
||||
|
@ -306,7 +316,7 @@ let
|
|||
src = jobs.tarball;
|
||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||
{ extraPackages =
|
||||
[ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "perl-WWW-Curl" "libcurl-devel" "openssl-devel" "xz-devel" ]
|
||||
[ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "perl-WWW-Curl" "libcurl-devel" "openssl-devel" "xz-devel" "libseccomp-devel" ]
|
||||
++ extraPackages; };
|
||||
memSize = 1024;
|
||||
meta.schedulingPriority = 50;
|
||||
|
@ -318,7 +328,7 @@ let
|
|||
makeDeb_x86_64 = makeDeb "x86_64-linux";
|
||||
|
||||
makeDeb =
|
||||
system: diskImageFun: extraPackages:
|
||||
system: diskImageFun: extraPackages: extraDebPackages:
|
||||
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
|
@ -327,14 +337,15 @@ let
|
|||
src = jobs.tarball;
|
||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||
{ extraPackages =
|
||||
[ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" "libwww-curl-perl" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" ]
|
||||
[ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" "libwww-curl-perl" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" "libseccomp-dev" ]
|
||||
++ extraPackages; };
|
||||
memSize = 1024;
|
||||
meta.schedulingPriority = 50;
|
||||
postInstall = "make installcheck";
|
||||
configureFlags = "--sysconfdir=/etc";
|
||||
debRequires =
|
||||
[ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" "libssl1.0.0" "liblzma5" ]
|
||||
++ lib.optionals (lib.elem "libsodium-dev" extraPackages) [ "libsodium13" ] ;
|
||||
[ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" "libssl1.0.0" "liblzma5" "libseccomp2" ]
|
||||
++ extraDebPackages;
|
||||
debMaintainer = "Eelco Dolstra <eelco.dolstra@logicblox.com>";
|
||||
doInstallCheck = true;
|
||||
};
|
||||
|
|
|
@ -41,9 +41,6 @@ my $activeRequests = 0;
|
|||
my $curlIdCount = 1;
|
||||
my %requests;
|
||||
my %scheduled;
|
||||
my $caBundle = $ENV{"SSL_CERT_FILE"} // $ENV{"CURL_CA_BUNDLE"} // $ENV{"OPENSSL_X509_CERT_FILE"};
|
||||
$caBundle = "/etc/ssl/certs/ca-bundle.crt" if !$caBundle && -f "/etc/ssl/certs/ca-bundle.crt";
|
||||
$caBundle = "/etc/ssl/certs/ca-certificates.crt" if !$caBundle && -f "/etc/ssl/certs/ca-certificates.crt";
|
||||
|
||||
my $userName = getpwuid($<) || $ENV{"USER"} or die "cannot figure out user name";
|
||||
|
||||
|
@ -65,6 +62,8 @@ my $curlConnectTimeout = int(
|
|||
$Nix::Config::config{"connect-timeout"} //
|
||||
$ENV{"NIX_CONNECT_TIMEOUT"} // 0);
|
||||
|
||||
my $netrcFile = $Nix::Config::config{"netrc-file"} //
|
||||
"$Nix::Config::confDir/netrc";
|
||||
|
||||
sub addRequest {
|
||||
my ($storePath, $url, $head) = @_;
|
||||
|
@ -79,7 +78,7 @@ sub addRequest {
|
|||
open (my $fh, ">", \$requests{$curlId}->{content});
|
||||
$curl->setopt(CURLOPT_WRITEDATA, $fh);
|
||||
$curl->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||
$curl->setopt(CURLOPT_CAINFO, $caBundle) if defined $caBundle;
|
||||
$curl->setopt(CURLOPT_CAINFO, $Nix::Config::caBundle) if defined $Nix::Config::caBundle;
|
||||
|
||||
unless (isTrue($Nix::Config::config{"verify-https-binary-caches"} // "1")) {
|
||||
$curl->setopt(CURLOPT_SSL_VERIFYPEER, 0);
|
||||
|
@ -91,6 +90,8 @@ sub addRequest {
|
|||
$curl->setopt(CURLOPT_FAILONERROR, 1);
|
||||
$curl->setopt(CURLOPT_CONNECTTIMEOUT, $curlConnectTimeout);
|
||||
$curl->setopt(CURLOPT_TIMEOUT, 20 * 60);
|
||||
$curl->setopt(CURLOPT_NETRC_FILE, $netrcFile);
|
||||
$curl->setopt(CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
|
||||
if ($activeRequests >= $maxParallelRequests) {
|
||||
$scheduled{$curlId} = 1;
|
||||
|
@ -566,7 +567,7 @@ sub downloadBinary {
|
|||
die if $requireSignedBinaryCaches && !defined $info->{signedBy};
|
||||
print STDERR "\n*** Downloading ‘$url’ ", ($requireSignedBinaryCaches ? "(signed by ‘$info->{signedBy}’) " : ""), "to ‘$storePath’...\n";
|
||||
checkURL $url;
|
||||
if (system("$Nix::Config::curl --fail --location --connect-timeout $curlConnectTimeout -A '$userAgent' '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
|
||||
if (system("$Nix::Config::curl --fail --location --netrc-file $netrcFile --netrc-optional --connect-timeout $curlConnectTimeout -A '$userAgent' $Nix::Config::curlCaFlag '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
|
||||
warn "download of ‘$url’ failed" . ($! ? ": $!" : "") . "\n";
|
||||
next;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ my $logFile = "$Nix::Config::logDir/downloads";
|
|||
# estimating the expected download size.
|
||||
my $fast = 1;
|
||||
|
||||
my $curl = "$Nix::Config::curl --fail --location";
|
||||
my $curl = "$Nix::Config::curl $Nix::Config::curlCaFlag --fail --location";
|
||||
|
||||
|
||||
# Open the manifest cache and update it if necessary.
|
||||
|
|
|
@ -0,0 +1,845 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
# Sourced from:
|
||||
# - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh
|
||||
# - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0
|
||||
# - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh
|
||||
# - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh
|
||||
# - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a
|
||||
#
|
||||
# however tracking which bits came from which would be impossible.
|
||||
|
||||
readonly ESC='\033[0m'
|
||||
readonly BOLD='\033[38;1m'
|
||||
readonly BLUE='\033[38;34m'
|
||||
readonly BLUE_UL='\033[38;4;34m'
|
||||
readonly GREEN='\033[38;32m'
|
||||
readonly GREEN_UL='\033[38;4;32m'
|
||||
readonly RED='\033[38;31m'
|
||||
readonly RED_UL='\033[38;4;31m'
|
||||
readonly YELLOW='\033[38;33m'
|
||||
readonly YELLOW_UL='\033[38;4;33m'
|
||||
|
||||
readonly CORES=$(sysctl -n hw.ncpu)
|
||||
readonly NIX_USER_COUNT="$CORES"
|
||||
readonly NIX_BUILD_GROUP_ID="30000"
|
||||
readonly NIX_BUILD_GROUP_NAME="nixbld"
|
||||
readonly NIX_FIRST_BUILD_UID="30001"
|
||||
# Please don't change this. We don't support it, because the
|
||||
# default shell profile that comes with Nix doesn't support it.
|
||||
readonly NIX_ROOT="/nix"
|
||||
readonly PLIST_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist
|
||||
|
||||
readonly PROFILE_TARGETS=("/etc/profile" "/etc/bashrc" "/etc/zshrc")
|
||||
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
|
||||
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
|
||||
|
||||
readonly NIX_INSTALLED_NIX="@nix@"
|
||||
readonly NIX_INSTALLED_CACERT="@cacert@"
|
||||
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
|
||||
|
||||
readonly ROOT_HOME="/var/root"
|
||||
|
||||
if [ -t 0 ]; then
|
||||
readonly IS_HEADLESS='no'
|
||||
else
|
||||
readonly IS_HEADLESS='yes'
|
||||
fi
|
||||
|
||||
headless() {
|
||||
if [ "$IS_HEADLESS" = "yes" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
contactme() {
|
||||
echo "We'd love to help if you need it."
|
||||
echo ""
|
||||
echo "If you can, open an issue at https://github.com/nixos/nix/issues"
|
||||
echo ""
|
||||
echo "Or feel free to contact the team,"
|
||||
echo " - on IRC #nixos on irc.freenode.net"
|
||||
echo " - on twitter @nixos_org"
|
||||
}
|
||||
|
||||
uninstall_directions() {
|
||||
subheader "Uninstalling nix:"
|
||||
local step=0
|
||||
|
||||
if [ -e "$PLIST_DEST" ]; then
|
||||
step=$((step + 1))
|
||||
cat <<EOF
|
||||
$step. Delete $PLIST_DEST
|
||||
|
||||
sudo launchctl unload $PLIST_DEST
|
||||
sudo rm $PLIST_DEST
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||
if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
|
||||
step=$((step + 1))
|
||||
cat <<EOF
|
||||
$step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target
|
||||
|
||||
sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
|
||||
|
||||
(after this one, you may need to re-open any terminals that were
|
||||
opened while it existed.)
|
||||
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
|
||||
step=$((step + 1))
|
||||
cat <<EOF
|
||||
$step. Delete the files Nix added to your system:
|
||||
|
||||
sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels
|
||||
|
||||
and that is it.
|
||||
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
nix_user_for_core() {
|
||||
printf "nixbld%d" "$1"
|
||||
}
|
||||
|
||||
nix_uid_for_core() {
|
||||
echo $((NIX_FIRST_BUILD_UID + $1 - 1))
|
||||
}
|
||||
|
||||
dsclattr() {
|
||||
/usr/bin/dscl . -read "$1" \
|
||||
| awk "/$2/ { print \$2 }"
|
||||
}
|
||||
|
||||
_textout() {
|
||||
echo -en "$1"
|
||||
shift
|
||||
if [ "$*" = "" ]; then
|
||||
cat
|
||||
else
|
||||
echo "$@"
|
||||
fi
|
||||
echo -en "$ESC"
|
||||
}
|
||||
|
||||
header() {
|
||||
follow="---------------------------------------------------------"
|
||||
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
|
||||
echo ""
|
||||
_textout "$BLUE" "$header"
|
||||
}
|
||||
|
||||
warningheader() {
|
||||
follow="---------------------------------------------------------"
|
||||
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
|
||||
echo ""
|
||||
_textout "$RED" "$header"
|
||||
}
|
||||
|
||||
subheader() {
|
||||
echo ""
|
||||
_textout "$BLUE_UL" "$*"
|
||||
}
|
||||
|
||||
row() {
|
||||
printf "$BOLD%s$ESC:\t%s\n" "$1" "$2"
|
||||
}
|
||||
|
||||
task() {
|
||||
echo ""
|
||||
ok "~~> $1"
|
||||
}
|
||||
|
||||
bold() {
|
||||
echo "$BOLD$*$ESC"
|
||||
}
|
||||
|
||||
ok() {
|
||||
_textout "$GREEN" "$@"
|
||||
}
|
||||
|
||||
warning() {
|
||||
warningheader "warning!"
|
||||
cat
|
||||
echo ""
|
||||
}
|
||||
|
||||
failure() {
|
||||
header "oh no!"
|
||||
_textout "$RED" "$@"
|
||||
echo ""
|
||||
_textout "$RED" "$(contactme)"
|
||||
trap finish_cleanup EXIT
|
||||
exit 1
|
||||
}
|
||||
|
||||
ui_confirm() {
|
||||
_textout "$GREEN$GREEN_UL" "$1"
|
||||
|
||||
if headless; then
|
||||
echo "No TTY, assuming you would say yes :)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local prompt="[y/n] "
|
||||
echo -n "$prompt"
|
||||
while read -r y; do
|
||||
if [ "$y" = "y" ]; then
|
||||
echo ""
|
||||
return 0
|
||||
elif [ "$y" = "n" ]; then
|
||||
echo ""
|
||||
return 1
|
||||
else
|
||||
_textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n"
|
||||
echo -n "$prompt"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
return 1
|
||||
}
|
||||
|
||||
__sudo() {
|
||||
local expl="$1"
|
||||
local cmd="$2"
|
||||
shift
|
||||
header "sudo execution"
|
||||
|
||||
echo "I am executing:"
|
||||
echo ""
|
||||
printf " $ sudo %s\n" "$cmd"
|
||||
echo ""
|
||||
echo "$expl"
|
||||
echo ""
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_sudo() {
|
||||
local expl="$1"
|
||||
shift
|
||||
if ! headless; then
|
||||
__sudo "$expl" "$*"
|
||||
fi
|
||||
sudo "$@"
|
||||
}
|
||||
|
||||
|
||||
readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX)
|
||||
function finish_cleanup {
|
||||
rm -rf "$SCRATCH"
|
||||
}
|
||||
|
||||
function finish_fail {
|
||||
finish_cleanup
|
||||
|
||||
failure <<EOF
|
||||
Jeeze, something went wrong. If you can take all the output and open
|
||||
an issue, we'd love to fix the problem so nobody else has this issue.
|
||||
|
||||
:(
|
||||
EOF
|
||||
}
|
||||
trap finish_fail EXIT
|
||||
|
||||
function finish_success {
|
||||
finish_cleanup
|
||||
|
||||
ok "Alright! We're done!"
|
||||
cat <<EOF
|
||||
|
||||
Before Nix will work in your existing shells, you'll need to either
|
||||
run:
|
||||
|
||||
$ source $PROFILE_NIX_FILE
|
||||
|
||||
or close them and open them again. Other than that, you should be
|
||||
ready to go.
|
||||
|
||||
Try it! Open a new terminal, and type:
|
||||
|
||||
$ nix-shell -p nix-info --run "nix-info -m"
|
||||
|
||||
Thank you for using this installer. If you have any feedback, don't
|
||||
hesitate:
|
||||
|
||||
$(contactme)
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
validate_starting_assumptions() {
|
||||
if [ "$(uname -s)" != "Darwin" ]; then
|
||||
failure "This script is for use with macOS!"
|
||||
fi
|
||||
|
||||
if [ $EUID -eq 0 ]; then
|
||||
failure <<EOF
|
||||
Please do not run this script with root privileges. We will call sudo
|
||||
when we need to.
|
||||
EOF
|
||||
fi
|
||||
|
||||
if type nix-env 2> /dev/null >&2; then
|
||||
failure <<EOF
|
||||
Nix already appears to be installed, and this tool assumes it is
|
||||
_not_ yet installed.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
|
||||
if pgrep nix-daemon 2> /dev/null >&2; then
|
||||
failure <<EOF
|
||||
Nix seems to be partially installed, because the nix-daemon is
|
||||
currently running. It may be in a launchd service. Please stop the
|
||||
the old nix-daemon, and try again.
|
||||
|
||||
If you have an existing launchd plist for nix-daemon, please delete
|
||||
it.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "${NIX_REMOTE:-}" != "" ]; then
|
||||
failure <<EOF
|
||||
For some reason, \$NIX_REMOTE is set. It really should not be set
|
||||
before this installer runs, and it hints that Nix is currently
|
||||
installed. Please delete the old Nix installation and start again.
|
||||
|
||||
Note: You might need to close your shell window and open a new shell
|
||||
to clear the variable.
|
||||
EOF
|
||||
fi
|
||||
|
||||
if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then
|
||||
failure <<EOF
|
||||
It looks like \$SSL_CERT_FILE is set to a path that used to be part of
|
||||
the old Nix installation. Please unset that variable and try again:
|
||||
|
||||
$ unset SSL_CERT_FILE
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do
|
||||
if [ -f "$file" ]; then
|
||||
if grep -l "^[^#].*.nix-profile" "$file"; then
|
||||
failure <<EOF
|
||||
I found a reference to a ".nix-profile" in $file.
|
||||
This has a high chance of breaking a new nix installation. It was most
|
||||
likely put there by a previous Nix installer.
|
||||
|
||||
Please remove this reference and try running this again. You should
|
||||
also look for similar references in:
|
||||
|
||||
- ~/.bash_profile
|
||||
- ~/.bash_login
|
||||
- ~/.profile
|
||||
|
||||
or other shell init files that you may have.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -d /nix ]; then
|
||||
failure <<EOF
|
||||
There are some relics of a previous installation of Nix at /nix, and
|
||||
this scripts assumes Nix is _not_ yet installed. Please delete the old
|
||||
Nix installation and start again.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ -d /etc/nix ]; then
|
||||
failure <<EOF
|
||||
There are some relics of a previous installation of Nix at /etc/nix, and
|
||||
this scripts assumes Nix is _not_ yet installed. Please delete the old
|
||||
Nix installation and start again.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
|
||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||
if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
|
||||
failure <<EOF
|
||||
When this script runs, it backs up the current $profile_target to
|
||||
$profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though.
|
||||
|
||||
Please follow these instructions to clean up the old backup file:
|
||||
|
||||
1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just
|
||||
in case.
|
||||
|
||||
2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like
|
||||
it has anything nix-related in it. If it does, something is probably
|
||||
quite wrong. Please open an issue or get in touch immediately.
|
||||
|
||||
3. Take care to make sure that $profile_target doesn't look like it has
|
||||
anything nix-related in it. If it does, and $profile_target _did not_,
|
||||
run:
|
||||
|
||||
$ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
|
||||
|
||||
and try again.
|
||||
EOF
|
||||
fi
|
||||
|
||||
if grep -qi "nix" "$profile_target"; then
|
||||
failure <<EOF
|
||||
It looks like $profile_target already has some Nix configuration in
|
||||
there. There should be no reason to run this again. If you're having
|
||||
trouble, please open an issue.
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
|
||||
danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile")
|
||||
for danger_path in "${danger_paths[@]}"; do
|
||||
if _sudo "making sure that $danger_path doesn't exist" \
|
||||
test -e "$danger_path"; then
|
||||
failure <<EOF
|
||||
I found a file at $danger_path, which is a relic of a previous
|
||||
installation. You must first delete this file before continuing.
|
||||
|
||||
$(uninstall_directions)
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
setup_report() {
|
||||
header "hardware report"
|
||||
row " Cores" "$CORES"
|
||||
|
||||
header "Nix config report"
|
||||
row " Temp Dir" "$SCRATCH"
|
||||
row " Nix Root" "$NIX_ROOT"
|
||||
row " Build Users" "$NIX_USER_COUNT"
|
||||
row " Build Group ID" "$NIX_BUILD_GROUP_ID"
|
||||
row "Build Group Name" "$NIX_BUILD_GROUP_NAME"
|
||||
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then
|
||||
row "Preexisting Install" "Allowed"
|
||||
fi
|
||||
|
||||
subheader "build users:"
|
||||
|
||||
row " Username" "UID"
|
||||
for i in $(seq 1 "$NIX_USER_COUNT"); do
|
||||
row " $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
create_build_group() {
|
||||
local primary_group_id
|
||||
|
||||
task "Setting up the build group $NIX_BUILD_GROUP_NAME"
|
||||
if ! /usr/bin/dscl . -read "/Groups/$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1; then
|
||||
_sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \
|
||||
/usr/sbin/dseditgroup -o create \
|
||||
-r "Nix build group for nix-daemon" \
|
||||
-i "$NIX_BUILD_GROUP_ID" \
|
||||
"$NIX_BUILD_GROUP_NAME" >&2
|
||||
row " Created" "Yes"
|
||||
else
|
||||
primary_group_id=$(dsclattr "/Groups/$NIX_BUILD_GROUP_NAME" "PrimaryGroupID")
|
||||
if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then
|
||||
failure <<EOF
|
||||
It seems the build group $NIX_BUILD_GROUP_NAME already exists, but
|
||||
with the UID $primary_group_id. This script can't really handle
|
||||
that right now, so I'm going to give up.
|
||||
|
||||
You can fix this by editing this script and changing the
|
||||
NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID
|
||||
to $primary_group_id and re-run.
|
||||
EOF
|
||||
else
|
||||
row " Exists" "Yes"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
create_build_user_for_core() {
|
||||
local coreid
|
||||
local username
|
||||
local uid
|
||||
|
||||
coreid="$1"
|
||||
username=$(nix_user_for_core "$coreid")
|
||||
uid=$(nix_uid_for_core "$coreid")
|
||||
dsclpath="/Users/$username"
|
||||
|
||||
task "Setting up the build user $username"
|
||||
|
||||
if ! /usr/bin/dscl . -read "$dsclpath" > /dev/null 2>&1; then
|
||||
_sudo "Creating the Nix build user, $username" \
|
||||
/usr/bin/dscl . create "$dsclpath" \
|
||||
UniqueID "${uid}"
|
||||
row " Created" "Yes"
|
||||
else
|
||||
actual_uid=$(dsclattr "$dsclpath" "UniqueID")
|
||||
if [ "$actual_uid" -ne "$uid" ]; then
|
||||
failure <<EOF
|
||||
It seems the build user $username already exists, but with the UID
|
||||
with the UID $actual_uid. This script can't really handle that right
|
||||
now, so I'm going to give up.
|
||||
|
||||
If you already created the users and you know they start from
|
||||
$actual_uid and go up from there, you can edit this script and change
|
||||
NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try
|
||||
again.
|
||||
EOF
|
||||
else
|
||||
row " Exists" "Yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$(dsclattr "$dsclpath" "IsHidden")" = "1" ]; then
|
||||
row " IsHidden" "Yes"
|
||||
else
|
||||
_sudo "in order to make $username a hidden user" \
|
||||
/usr/bin/dscl . -create "$dsclpath" "IsHidden" "1"
|
||||
row " IsHidden" "Yes"
|
||||
fi
|
||||
|
||||
if [ "$(dsclattr "$dsclpath" "NFSHomeDirectory")" = "/var/empty" ]; then
|
||||
row " NFSHomeDirectory" "/var/empty"
|
||||
else
|
||||
_sudo "in order to give $username a safe home directory" \
|
||||
/usr/bin/dscl . -create "$dsclpath" "NFSHomeDirectory" "/var/empty"
|
||||
row " NFSHomeDirectory" "/var/empty"
|
||||
fi
|
||||
|
||||
if [ "$(dsclattr "$dsclpath" "RealName")" = "Nix build user $coreid" ]; then
|
||||
row " RealName" "Nix build user $coreid"
|
||||
else
|
||||
_sudo "in order to give $username a useful name" \
|
||||
/usr/bin/dscl . -create "$dsclpath" "RealName" "Nix build user $coreid"
|
||||
row " RealName" "Nix build user $coreid"
|
||||
fi
|
||||
|
||||
if [ "$(dsclattr "$dsclpath" "UserShell")" = "/sbin/nologin" ]; then
|
||||
row " Logins Disabled" "Yes"
|
||||
else
|
||||
_sudo "in order to prevent $username from logging in" \
|
||||
/usr/bin/dscl . -create "$dsclpath" "UserShell" "/sbin/nologin"
|
||||
row " Logins Disabled" "Yes"
|
||||
fi
|
||||
|
||||
if dseditgroup -o checkmember -m "$username" "$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1 ; then
|
||||
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
|
||||
else
|
||||
_sudo "Add $username to the $NIX_BUILD_GROUP_NAME group"\
|
||||
/usr/sbin/dseditgroup -o edit -t user \
|
||||
-a "$username" "$NIX_BUILD_GROUP_NAME"
|
||||
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
|
||||
fi
|
||||
|
||||
if [ "$(dsclattr "$dsclpath" "PrimaryGroupID")" = "$NIX_BUILD_GROUP_ID" ]; then
|
||||
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
|
||||
else
|
||||
_sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \
|
||||
/usr/bin/dscl . -create "$dsclpath" "PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
|
||||
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
create_build_users() {
|
||||
for i in $(seq 1 "$NIX_USER_COUNT"); do
|
||||
create_build_user_for_core "$i"
|
||||
done
|
||||
}
|
||||
|
||||
create_directories() {
|
||||
_sudo "to make the basic directory structure of Nix (part 1)" \
|
||||
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}
|
||||
|
||||
_sudo "to make the basic directory structure of Nix (part 2)" \
|
||||
mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user
|
||||
|
||||
_sudo "to make the basic directory structure of Nix (part 3)" \
|
||||
mkdir -pv -m 1775 /nix/store
|
||||
|
||||
_sudo "to make the basic directory structure of Nix (part 4)" \
|
||||
chgrp "$NIX_BUILD_GROUP_NAME" /nix/store
|
||||
|
||||
_sudo "to set up the root user's profile (part 1)" \
|
||||
mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root
|
||||
|
||||
_sudo "to set up the root user's profile (part 2)" \
|
||||
mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"
|
||||
|
||||
_sudo "to place the default nix daemon configuration (part 1)" \
|
||||
mkdir -pv -m 0555 /etc/nix
|
||||
}
|
||||
|
||||
place_channel_configuration() {
|
||||
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels"
|
||||
_sudo "to set up the default system channel (part 1)" \
|
||||
install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"
|
||||
}
|
||||
|
||||
welcome_to_nix() {
|
||||
ok "Welcome to the Multi-User Nix Installation"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
This installation tool will set up your computer with the Nix package
|
||||
manager. This will happen in a few stages:
|
||||
|
||||
1. Make sure your computer doesn't already have Nix. If it does, I
|
||||
will show you instructions on how to clean up your old one.
|
||||
|
||||
2. Show you what we are going to install and where. Then we will ask
|
||||
if you are ready to continue.
|
||||
|
||||
3. Create the system users and groups that the Nix daemon uses to run
|
||||
builds.
|
||||
|
||||
4. Perform the basic installation of the Nix files daemon.
|
||||
|
||||
5. Configure your shell to import special Nix Profile files, so you
|
||||
can use Nix.
|
||||
|
||||
6. Start the Nix daemon.
|
||||
|
||||
EOF
|
||||
|
||||
if ui_confirm "Would you like to see a more detailed list of what we will do?"; then
|
||||
cat <<EOF
|
||||
|
||||
We will:
|
||||
|
||||
- make sure your computer doesn't already have Nix files
|
||||
(if it does, I will tell you how to clean them up.)
|
||||
- create local users (see the list above for the users we'll make)
|
||||
- create a local group ($NIX_BUILD_GROUP_NAME)
|
||||
- install Nix in to $NIX_ROOT
|
||||
- create a configuration file in /etc/nix
|
||||
- set up the "default profile" by creating some Nix-related files in
|
||||
$ROOT_HOME
|
||||
EOF
|
||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||
if [ -e "$profile_target" ]; then
|
||||
cat <<EOF
|
||||
- back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX
|
||||
- update $profile_target to include some Nix configuration
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
cat <<EOF
|
||||
- load and start a LaunchDaemon (at $PLIST_DEST) for nix-daemon
|
||||
|
||||
EOF
|
||||
if ! ui_confirm "Ready to continue?"; then
|
||||
failure <<EOF
|
||||
Okay, maybe you would like to talk to the team.
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
chat_about_sudo() {
|
||||
header "let's talk about sudo"
|
||||
|
||||
if headless; then
|
||||
cat <<EOF
|
||||
This script is going to call sudo a lot. Normally, it would show you
|
||||
exactly what commands it is running and why. However, the script is
|
||||
run in a headless fashion, like this:
|
||||
|
||||
$ curl https://nixos.org/nix/install | sh
|
||||
|
||||
or maybe in a CI pipeline. Because of that, we're going to skip the
|
||||
verbose output in the interest of brevity.
|
||||
|
||||
If you would like to
|
||||
see the output, try like this:
|
||||
|
||||
$ curl -o install-nix https://nixos.org/nix/install
|
||||
$ sh ./install-nix
|
||||
|
||||
EOF
|
||||
return 0
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
This script is going to call sudo a lot. Every time we do, it'll
|
||||
output exactly what it'll do, and why.
|
||||
|
||||
Just like this:
|
||||
EOF
|
||||
|
||||
__sudo "to demonstrate how our sudo prompts look" \
|
||||
echo "this is a sudo prompt"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
This might look scary, but everything can be undone by running just a
|
||||
few commands. We used to ask you to confirm each time sudo ran, but it
|
||||
was too many times. Instead, I'll just ask you this one time:
|
||||
|
||||
EOF
|
||||
if ui_confirm "Can we use sudo?"; then
|
||||
ok "Yay! Thanks! Let's get going!"
|
||||
else
|
||||
failure <<EOF
|
||||
That is okay, but we can't install.
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
install_from_extracted_nix() {
|
||||
(
|
||||
cd "$EXTRACTED_NIX_PATH"
|
||||
|
||||
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
|
||||
rsync -rlpt "$(pwd)/store/" "$NIX_ROOT/store/"
|
||||
|
||||
if [ -d "$NIX_INSTALLED_NIX" ]; then
|
||||
echo " Alright! We have our first nix at $NIX_INSTALLED_NIX"
|
||||
else
|
||||
failure <<EOF
|
||||
Something went wrong, and I didn't find Nix installed at
|
||||
$NIX_INSTALLED_NIX.
|
||||
EOF
|
||||
fi
|
||||
|
||||
_sudo "to initialize the Nix Database" \
|
||||
$NIX_INSTALLED_NIX/bin/nix-store --init
|
||||
|
||||
cat ./.reginfo \
|
||||
| _sudo "to load data for the first time in to the Nix Database" \
|
||||
"$NIX_INSTALLED_NIX/bin/nix-store" --load-db
|
||||
|
||||
echo " Just finished getting the nix database ready."
|
||||
)
|
||||
}
|
||||
|
||||
shell_source_lines() {
|
||||
cat <<EOF
|
||||
|
||||
# Nix
|
||||
if [ -e '$PROFILE_NIX_FILE' ]; then
|
||||
. '$PROFILE_NIX_FILE'
|
||||
fi
|
||||
# End Nix
|
||||
|
||||
EOF
|
||||
}
|
||||
configure_shell_profile() {
|
||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||
if [ -e "$profile_target" ]; then
|
||||
_sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \
|
||||
cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX"
|
||||
|
||||
shell_source_lines \
|
||||
| _sudo "extend your $profile_target with nix-daemon settings" \
|
||||
tee -a "$profile_target"
|
||||
fi
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
setup_default_profile() {
|
||||
_sudo "to installing a bootstrapping Nix in to the default Profile" \
|
||||
HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX"
|
||||
|
||||
_sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \
|
||||
HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT"
|
||||
|
||||
_sudo "to update the default channel in the default profile" \
|
||||
HOME=$ROOT_HOME NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs
|
||||
}
|
||||
|
||||
|
||||
place_nix_configuration() {
|
||||
cat <<EOF > "$SCRATCH/nix.conf"
|
||||
build-users-group = $NIX_BUILD_GROUP_NAME
|
||||
|
||||
build-max-jobs = $NIX_USER_COUNT
|
||||
build-cores = 1
|
||||
build-use-sandbox = false
|
||||
|
||||
binary-caches = https://cache.nixos.org/
|
||||
trusted-binary-caches =
|
||||
binary-cache-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
|
||||
signed-binary-caches = *
|
||||
|
||||
trusted-users = root
|
||||
allowed-users = *
|
||||
EOF
|
||||
_sudo "to place the default nix daemon configuration (part 2)" \
|
||||
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
|
||||
}
|
||||
|
||||
configure_nix_daemon_plist() {
|
||||
_sudo "to set up the nix-daemon as a LaunchDaemon" \
|
||||
ln -sfn "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST"
|
||||
|
||||
_sudo "to load the LaunchDaemon plist for nix-daemon" \
|
||||
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist
|
||||
|
||||
_sudo "to start the nix-daemon" \
|
||||
launchctl start org.nixos.nix-daemon
|
||||
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
welcome_to_nix
|
||||
chat_about_sudo
|
||||
|
||||
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then
|
||||
validate_starting_assumptions
|
||||
fi
|
||||
|
||||
setup_report
|
||||
|
||||
if ! ui_confirm "Ready to continue?"; then
|
||||
ok "Alright, no changes have been made :)"
|
||||
contactme
|
||||
trap finish_cleanup EXIT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
create_build_group
|
||||
create_build_users
|
||||
create_directories
|
||||
place_channel_configuration
|
||||
install_from_extracted_nix
|
||||
|
||||
configure_shell_profile
|
||||
|
||||
set +eu
|
||||
. /etc/profile
|
||||
set -eu
|
||||
|
||||
setup_default_profile
|
||||
place_nix_configuration
|
||||
configure_nix_daemon_plist
|
||||
|
||||
trap finish_success EXIT
|
||||
}
|
||||
|
||||
|
||||
main
|
|
@ -7,7 +7,7 @@ self="$(dirname "$0")"
|
|||
nix="@nix@"
|
||||
cacert="@cacert@"
|
||||
|
||||
if ! [ -e $self/.reginfo ]; then
|
||||
if ! [ -e "$self/.reginfo" ]; then
|
||||
echo "$0: incomplete installer (.reginfo is missing)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
@ -17,6 +17,23 @@ if [ -z "$USER" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$HOME" ]; then
|
||||
echo "$0: \$HOME is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# macOS support for 10.10 or higher
|
||||
if [[ "$(uname -s)" = "Darwin" ]]; then
|
||||
if [[ $(($(sw_vers -productVersion | cut -d '.' -f 2))) -lt 10 ]]; then
|
||||
echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.10 or higher"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '\e[1;31mSwitching to the Multi-User Darwin Installer\e[0m\n'
|
||||
exec "$self/install-darwin-multi-user"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
printf '\e[1;31mwarning: installing Nix as root is not supported by this script!\e[0m\n'
|
||||
fi
|
||||
|
@ -41,7 +58,7 @@ mkdir -p $dest/store
|
|||
|
||||
echo -n "copying Nix to $dest/store..." >&2
|
||||
|
||||
for i in $(cd $self/store >/dev/null && echo *); do
|
||||
for i in $(cd "$self/store" >/dev/null && echo ./*); do
|
||||
echo -n "." >&2
|
||||
i_tmp="$dest/store/$i.$$"
|
||||
if [ -e "$i_tmp" ]; then
|
||||
|
@ -55,47 +72,47 @@ done
|
|||
echo "" >&2
|
||||
|
||||
echo "initialising Nix database..." >&2
|
||||
if ! $nix/bin/nix-store --init; then
|
||||
if ! "$nix/bin/nix-store" --init; then
|
||||
echo "$0: failed to initialize the Nix database" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! $nix/bin/nix-store --load-db < $self/.reginfo; then
|
||||
if ! "$nix/bin/nix-store" --load-db < "$self/.reginfo"; then
|
||||
echo "$0: unable to register valid paths" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. $nix/etc/profile.d/nix.sh
|
||||
. "$nix/etc/profile.d/nix.sh"
|
||||
|
||||
if ! $nix/bin/nix-env -i "$nix"; then
|
||||
if ! "$nix/bin/nix-env" -i "$nix"; then
|
||||
echo "$0: unable to install Nix into your default profile" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install an SSL certificate bundle.
|
||||
if [ -z "$SSL_CERT_FILE" -o ! -f "$SSL_CERT_FILE" ]; then
|
||||
$nix/bin/nix-env -i "$cacert"
|
||||
export SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
|
||||
if [ -z "$NIX_SSL_CERT_FILE" ] || [ ! -f "$NIX_SSL_CERT_FILE" ]; then
|
||||
"$nix/bin/nix-env" -i "$cacert"
|
||||
export NIX_SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
|
||||
fi
|
||||
|
||||
# Subscribe the user to the Nixpkgs channel and fetch it.
|
||||
if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
|
||||
$nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
||||
if ! "$nix/bin/nix-channel" --list | grep -q "^nixpkgs "; then
|
||||
"$nix/bin/nix-channel" --add https://nixos.org/channels/nixpkgs-unstable
|
||||
fi
|
||||
if [ -z "$_NIX_INSTALLER_TEST" ]; then
|
||||
$nix/bin/nix-channel --update nixpkgs
|
||||
"$nix/bin/nix-channel" --update nixpkgs
|
||||
fi
|
||||
|
||||
# Make the shell source nix.sh during login.
|
||||
p=$NIX_LINK/etc/profile.d/nix.sh
|
||||
p="$NIX_LINK/etc/profile.d/nix.sh"
|
||||
|
||||
added=
|
||||
for i in .bash_profile .bash_login .profile; do
|
||||
fn="$HOME/$i"
|
||||
if [ -e "$fn" ]; then
|
||||
if [ -w "$fn" ]; then
|
||||
if ! grep -q "$p" "$fn"; then
|
||||
echo "modifying $fn..." >&2
|
||||
echo "if [ -e $p ]; then . $p; fi # added by Nix installer" >> $fn
|
||||
echo "if [ -e $p ]; then . $p; fi # added by Nix installer" >> "$fn"
|
||||
fi
|
||||
added=1
|
||||
break
|
||||
|
|
|
@ -20,6 +20,7 @@ nix_noinst_scripts := \
|
|||
$(d)/resolve-system-dependencies.pl \
|
||||
$(d)/nix-http-export.cgi \
|
||||
$(d)/nix-profile.sh \
|
||||
$(d)/nix-profile-daemon.sh \
|
||||
$(d)/nix-reduce-build \
|
||||
$(nix_substituters)
|
||||
|
||||
|
@ -28,6 +29,7 @@ noinst-scripts += $(nix_noinst_scripts)
|
|||
profiledir = $(sysconfdir)/profile.d
|
||||
|
||||
$(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644))
|
||||
$(eval $(call install-file-as, $(d)/nix-profile-daemon.sh, $(profiledir)/nix-daemon.sh, 0644))
|
||||
$(eval $(call install-program-in, $(d)/find-runtime-roots.pl, $(libexecdir)/nix))
|
||||
$(eval $(call install-program-in, $(d)/build-remote.pl, $(libexecdir)/nix))
|
||||
$(eval $(call install-program-in, $(d)/resolve-system-dependencies.pl, $(libexecdir)/nix))
|
||||
|
|
|
@ -11,13 +11,16 @@ use Cwd;
|
|||
|
||||
binmode STDERR, ":encoding(utf8)";
|
||||
|
||||
Nix::Config::readConfig;
|
||||
|
||||
my $dryRun = 0;
|
||||
my $verbose = 0;
|
||||
my $runEnv = $0 =~ /nix-shell$/;
|
||||
my $pure = 0;
|
||||
my $fromArgs = 0;
|
||||
my $packages = 0;
|
||||
my $interactive = 1;
|
||||
# Same condition as bash uses for interactive shells
|
||||
my $interactive = -t STDIN && -t STDERR;
|
||||
|
||||
my @instArgs = ();
|
||||
my @buildArgs = ();
|
||||
|
@ -57,7 +60,7 @@ if ($runEnv && defined $ARGV[0] && $ARGV[0] !~ /nix-shell/) {
|
|||
while (<SCRIPT>) {
|
||||
chomp;
|
||||
if (/^\#\!\s*nix-shell (.*)$/) {
|
||||
push @ARGV, shellwords(/ /, $1);
|
||||
push @ARGV, shellwords($1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +226,7 @@ die "$0: ‘-p’ and ‘-E’ are mutually exclusive\n" if $packages && $fromAr
|
|||
if ($packages) {
|
||||
push @instArgs, "--expr";
|
||||
@exprs = (
|
||||
'with import <nixpkgs> { }; runCommand "shell" { buildInputs = [ '
|
||||
'with import <nixpkgs> { }; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ '
|
||||
. (join " ", map { "($_)" } @exprs) . ']; } ""');
|
||||
} elsif (!$fromArgs) {
|
||||
@exprs = ("shell.nix") if scalar @exprs == 0 && $runEnv && -e "shell.nix";
|
||||
|
@ -278,6 +281,9 @@ foreach my $expr (@exprs) {
|
|||
}
|
||||
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} = $ENV{'TEMPDIR'} = $ENV{'TMP'} = $ENV{'TEMP'} = $tmp;
|
||||
$ENV{'NIX_STORE'} = $Nix::Config::storeDir;
|
||||
if (defined $Nix::Config::config{"build-cores"}) {
|
||||
$ENV{'NIX_BUILD_CORES'} = $Nix::Config::config{"build-cores"};
|
||||
}
|
||||
$ENV{$_} = $drv->{env}->{$_} foreach keys %{$drv->{env}};
|
||||
|
||||
# Run a shell using the derivation's environment. For
|
||||
|
@ -288,7 +294,6 @@ foreach my $expr (@exprs) {
|
|||
writeFile(
|
||||
$rcfile,
|
||||
"rm -rf '$tmpDir'; " .
|
||||
'unset BASH_ENV; ' .
|
||||
'[ -n "$PS1" ] && [ -e ~/.bashrc ] && source ~/.bashrc; ' .
|
||||
($pure ? '' : 'p=$PATH; ' ) .
|
||||
'dontAddDisableDepTrack=1; ' .
|
||||
|
@ -302,7 +307,6 @@ foreach my $expr (@exprs) {
|
|||
'shopt -u nullglob; ' .
|
||||
'unset TZ; ' . (defined $ENV{'TZ'} ? "export TZ='${ENV{'TZ'}}'; " : '') .
|
||||
$envCommand);
|
||||
$ENV{BASH_ENV} = $rcfile;
|
||||
my @args = ($ENV{NIX_BUILD_SHELL} // "bash");
|
||||
push @args, "--rcfile" if $interactive;
|
||||
push @args, $rcfile;
|
||||
|
|
|
@ -32,6 +32,9 @@ mkpath(dirname $profile, 0, 0755);
|
|||
|
||||
my %channels;
|
||||
|
||||
my $netrcFile = $Nix::Config::config{"netrc-file"} //
|
||||
"$Nix::Config::confDir/netrc";
|
||||
|
||||
|
||||
# Reads the list of channels.
|
||||
sub readChannels {
|
||||
|
@ -104,7 +107,7 @@ sub update {
|
|||
# definition from a consistent location if the redirect changes mid-download.
|
||||
my $tmpdir = tempdir( CLEANUP => 1 );
|
||||
my $filename;
|
||||
($url, $filename) = `cd $tmpdir && $Nix::Config::curl --silent --write-out '%{url_effective}\n%{filename_effective}' -L '$url' -O`;
|
||||
($url, $filename) = `cd $tmpdir && $Nix::Config::curl $Nix::Config::curlCaFlag --netrc-file $netrcFile --netrc-optional --silent --write-out '%{url_effective}\n%{filename_effective}' -L '$url' -O`;
|
||||
chomp $url;
|
||||
die "$0: unable to check ‘$url’\n" if $? != 0;
|
||||
|
||||
|
@ -131,7 +134,7 @@ sub update {
|
|||
my $extraAttrs = "";
|
||||
if ($ret != 0) {
|
||||
# Check if the channel advertises a binary cache.
|
||||
my $binaryCacheURL = `$Nix::Config::curl --silent '$url'/binary-cache-url`;
|
||||
my $binaryCacheURL = `$Nix::Config::curl $Nix::Config::curlCaFlag --netrc-file $netrcFile --netrc-optional --silent '$url'/binary-cache-url`;
|
||||
my $getManifest = ($Nix::Config::config{"force-manifest"} // "false") eq "true";
|
||||
if ($? == 0 && $binaryCacheURL ne "") {
|
||||
$extraAttrs .= "binaryCacheURL = \"$binaryCacheURL\"; ";
|
||||
|
@ -151,7 +154,7 @@ sub update {
|
|||
|
||||
# Download the channel tarball.
|
||||
my $fullURL = "$url/nixexprs.tar.xz";
|
||||
system("$Nix::Config::curl --fail --silent --head '$fullURL' > /dev/null") == 0 or
|
||||
system("$Nix::Config::curl $Nix::Config::curlCaFlag --netrc-file $netrcFile --netrc-optional --fail --silent --head '$fullURL' > /dev/null") == 0 or
|
||||
$fullURL = "$url/nixexprs.tar.bz2";
|
||||
print STDERR "downloading Nix expressions from ‘$fullURL’...\n";
|
||||
(my $hash, $path) = `PRINT_PATH=1 QUIET=1 $Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
|
||||
|
|
|
@ -7,8 +7,10 @@ use Nix::Config;
|
|||
use Nix::Store;
|
||||
use Nix::CopyClosure;
|
||||
use List::Util qw(sum);
|
||||
use IO::Handle;
|
||||
|
||||
binmode STDERR, ":encoding(utf8)";
|
||||
STDERR->autoflush(1);
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
print STDERR <<EOF
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# Only execute this file once per shell.
|
||||
if [ -n "$__ETC_PROFILE_NIX_SOURCED" ]; then return; fi
|
||||
__ETC_PROFILE_NIX_SOURCED=1
|
||||
|
||||
# Set up secure multi-user builds: non-root users build through the
|
||||
# Nix daemon.
|
||||
if [ "$USER" != root -o ! -w @localstatedir@/nix/db ]; then
|
||||
export NIX_REMOTE=daemon
|
||||
fi
|
||||
|
||||
export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"
|
||||
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||
|
||||
# Set up the per-user profile.
|
||||
mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
|
||||
if ! test -O "$NIX_USER_PROFILE_DIR"; then
|
||||
echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
|
||||
fi
|
||||
|
||||
if test -w $HOME; then
|
||||
if ! test -L $HOME/.nix-profile; then
|
||||
if test "$USER" != root; then
|
||||
ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
|
||||
else
|
||||
# Root installs in the system-wide profile by default.
|
||||
ln -s @localstatedir@/nix/profiles/default $HOME/.nix-profile
|
||||
fi
|
||||
fi
|
||||
|
||||
# Subscribe the root user to the NixOS channel by default.
|
||||
if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
|
||||
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
|
||||
fi
|
||||
|
||||
# Create the per-user garbage collector roots directory.
|
||||
NIX_USER_GCROOTS_DIR=@localstatedir@/nix/gcroots/per-user/$USER
|
||||
mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
|
||||
if ! test -O "$NIX_USER_GCROOTS_DIR"; then
|
||||
echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
|
||||
fi
|
||||
|
||||
# Set up a default Nix expression from which to install stuff.
|
||||
if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
|
||||
rm -f $HOME/.nix-defexpr
|
||||
mkdir -p $HOME/.nix-defexpr
|
||||
if [ "$USER" != root ]; then
|
||||
ln -s @localstatedir@/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
export NIX_SSL_CERT_FILE="@localstatedir@/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
export NIX_PATH="@localstatedir@/nix/profiles/per-user/root/channels"
|
||||
export PATH="$HOME/.nix-profile/bin:$HOME/.nix-profile/sbin:$HOME/.nix-profile/lib/kde4/libexec:@localstatedir@/nix/profiles/default/bin:@localstatedir@/nix/profiles/default/sbin:@localstatedir@/nix/profiles/default/lib/kde4/libexec:$PATH"
|
|
@ -20,16 +20,18 @@ if [ -n "$HOME" ]; then
|
|||
# channel.
|
||||
export NIX_PATH=${NIX_PATH:+$NIX_PATH:}nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs
|
||||
|
||||
# Set $SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
elif [ -e /etc/ssl/ca-bundle.pem ]; then # openSUSE Tumbleweed
|
||||
export NIX_SSL_CERT_FILE=/etc/ssl/ca-bundle.pem
|
||||
elif [ -e /etc/ssl/certs/ca-bundle.crt ]; then # Old NixOS
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
|
||||
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
|
||||
elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS
|
||||
export SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt
|
||||
export NIX_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt
|
||||
elif [ -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" ]; then # fall back to cacert in Nix profile
|
||||
export SSL_CERT_FILE="$NIX_LINK/etc/ssl/certs/ca-bundle.crt"
|
||||
export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ssl/certs/ca-bundle.crt"
|
||||
elif [ -e "$NIX_LINK/etc/ca-bundle.crt" ]; then # old cacert in Nix profile
|
||||
export SSL_CERT_FILE="$NIX_LINK/etc/ca-bundle.crt"
|
||||
export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ca-bundle.crt"
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -8,7 +8,8 @@ use Nix::Manifest;
|
|||
binmode STDERR, ":encoding(utf8)";
|
||||
|
||||
my $manifestDir = $Nix::Config::manifestDir;
|
||||
|
||||
my $netrcFile = $Nix::Config::config{"netrc-file"} //
|
||||
"$Nix::Config::confDir/netrc";
|
||||
|
||||
# Prevent access problems in shared-stored installations.
|
||||
umask 0022;
|
||||
|
@ -51,7 +52,7 @@ sub processURL {
|
|||
my $origUrl = $ENV{'NIX_ORIG_URL'} || $url;
|
||||
|
||||
# First see if a bzipped manifest is available.
|
||||
if (system("$Nix::Config::curl --fail --silent --location --head '$url'.bz2 > /dev/null") == 0) {
|
||||
if (system("$Nix::Config::curl $Nix::Config::curlCaFlag --netrc-file $netrcFile --netrc-optional --fail --silent --location --head '$url'.bz2 > /dev/null") == 0) {
|
||||
print "fetching list of Nix archives at ‘$url.bz2’...\n";
|
||||
$manifest = downloadFile "$url.bz2";
|
||||
}
|
||||
|
|
|
@ -273,7 +273,7 @@ EvalState::EvalState(const Strings & _searchPath)
|
|||
|
||||
/* Initialise the Nix expression search path. */
|
||||
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
|
||||
for (auto & i : _searchPath) addToSearchPath(i, true);
|
||||
for (auto & i : _searchPath) addToSearchPath(i);
|
||||
for (auto & i : paths) addToSearchPath(i);
|
||||
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
|
||||
|
||||
|
@ -296,11 +296,15 @@ Path EvalState::checkSourcePath(const Path & path_)
|
|||
if (!restricted) return path_;
|
||||
|
||||
/* Resolve symlinks. */
|
||||
debug(format("checking access to ‘%s’") % path_);
|
||||
Path path = canonPath(path_, true);
|
||||
|
||||
for (auto & i : searchPath)
|
||||
if (path == i.second || isInDir(path, i.second))
|
||||
for (auto & i : searchPath) {
|
||||
auto r = resolveSearchPathElem(i);
|
||||
if (!r.first) continue;
|
||||
if (path == r.second || isInDir(path, r.second))
|
||||
return path;
|
||||
}
|
||||
|
||||
/* To support import-from-derivation, allow access to anything in
|
||||
the store. FIXME: only allow access to paths that have been
|
||||
|
@ -946,11 +950,18 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
|
|||
if (fun.type == tAttrs) {
|
||||
auto found = fun.attrs->find(sFunctor);
|
||||
if (found != fun.attrs->end()) {
|
||||
/* fun may be allocated on the stack of the calling function,
|
||||
* but for functors we may keep a reference, so heap-allocate
|
||||
* a copy and use that instead.
|
||||
*/
|
||||
auto & fun2 = *allocValue();
|
||||
fun2 = fun;
|
||||
/* !!! Should we use the attr pos here? */
|
||||
forceValue(*found->value, pos);
|
||||
Value * v2 = allocValue();
|
||||
callFunction(*found->value, fun, *v2, pos);
|
||||
forceValue(*v2, pos);
|
||||
return callFunction(*v2, arg, v, pos);
|
||||
Value v2;
|
||||
callFunction(*found->value, fun2, v2, pos);
|
||||
forceValue(v2, pos);
|
||||
return callFunction(v2, arg, v, pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ typedef std::map<Path, Path> SrcToStore;
|
|||
std::ostream & operator << (std::ostream & str, const Value & v);
|
||||
|
||||
|
||||
typedef list<std::pair<string, Path> > SearchPath;
|
||||
typedef std::pair<std::string, std::string> SearchPathElem;
|
||||
typedef std::list<SearchPathElem> SearchPath;
|
||||
|
||||
|
||||
/* Initialise the Boehm GC, if applicable. */
|
||||
|
@ -95,12 +96,14 @@ private:
|
|||
|
||||
SearchPath searchPath;
|
||||
|
||||
std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
|
||||
|
||||
public:
|
||||
|
||||
EvalState(const Strings & _searchPath);
|
||||
~EvalState();
|
||||
|
||||
void addToSearchPath(const string & s, bool warn = false);
|
||||
void addToSearchPath(const string & s);
|
||||
|
||||
Path checkSourcePath(const Path & path);
|
||||
|
||||
|
@ -122,6 +125,9 @@ public:
|
|||
Path findFile(const string & path);
|
||||
Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos);
|
||||
|
||||
/* If the specified search path element is a URI, download it. */
|
||||
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
|
||||
|
||||
/* Evaluate an expression to normal form, storing the result in
|
||||
value `v'. */
|
||||
void eval(Expr * e, Value & v);
|
||||
|
|
|
@ -30,7 +30,7 @@ string DrvInfo::queryOutPath()
|
|||
}
|
||||
|
||||
|
||||
DrvInfo::Outputs DrvInfo::queryOutputs()
|
||||
DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
||||
{
|
||||
if (outputs.empty()) {
|
||||
/* Get the ‘outputs’ list. */
|
||||
|
@ -55,7 +55,23 @@ DrvInfo::Outputs DrvInfo::queryOutputs()
|
|||
} else
|
||||
outputs["out"] = queryOutPath();
|
||||
}
|
||||
return outputs;
|
||||
if (!onlyOutputsToInstall || !attrs)
|
||||
return outputs;
|
||||
|
||||
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
||||
const Value * outTI = queryMeta("outputsToInstall");
|
||||
if (!outTI) return outputs;
|
||||
const auto errMsg = Error("this derivation has bad ‘meta.outputsToInstall’");
|
||||
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
||||
if (!outTI->isList()) throw errMsg;
|
||||
Outputs result;
|
||||
for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) {
|
||||
if ((*i)->type != tString) throw errMsg;
|
||||
auto out = outputs.find((*i)->string.s);
|
||||
if (out == outputs.end()) throw errMsg;
|
||||
result.insert(*out);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,8 +193,8 @@ typedef set<Bindings *> Done;
|
|||
|
||||
|
||||
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
|
||||
then put information about it in `drvs' (unless it's already in
|
||||
`doneExprs'). The result boolean indicates whether it makes sense
|
||||
then put information about it in `drvs' (unless it's already in `done').
|
||||
The result boolean indicates whether it makes sense
|
||||
for the caller to recursively search for derivations in `v'. */
|
||||
static bool getDerivation(EvalState & state, Value & v,
|
||||
const string & attrPath, DrvInfos & drvs, Done & done,
|
||||
|
|
|
@ -42,7 +42,8 @@ public:
|
|||
string queryDrvPath();
|
||||
string queryOutPath();
|
||||
string queryOutputName();
|
||||
Outputs queryOutputs();
|
||||
/** Return the list of outputs. The "outputs to install" are determined by `mesa.outputsToInstall`. */
|
||||
Outputs queryOutputs(bool onlyOutputsToInstall = false);
|
||||
|
||||
StringSet queryMetaNames();
|
||||
Value * queryMeta(const string & name);
|
||||
|
|
|
@ -14,7 +14,7 @@ static void skipWhitespace(const char * & s)
|
|||
|
||||
#if HAVE_BOEHMGC
|
||||
typedef std::vector<Value *, gc_allocator<Value *> > ValueVector;
|
||||
typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap;
|
||||
typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<std::pair<const Symbol, Value *> > > ValueMap;
|
||||
#else
|
||||
typedef std::vector<Value *> ValueVector;
|
||||
typedef std::map<Symbol, Value *> ValueMap;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
%x STRING
|
||||
%x IND_STRING
|
||||
%x INSIDE_DOLLAR_CURLY
|
||||
|
||||
|
||||
%{
|
||||
|
@ -93,6 +94,8 @@ URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~
|
|||
|
||||
%%
|
||||
|
||||
<INITIAL,INSIDE_DOLLAR_CURLY>{
|
||||
|
||||
|
||||
if { return IF; }
|
||||
then { return THEN; }
|
||||
|
@ -124,29 +127,42 @@ or { return OR_KW; }
|
|||
return INT;
|
||||
}
|
||||
|
||||
\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||
\{ { PUSH_STATE(INITIAL); return '{'; }
|
||||
\} { POP_STATE(); return '}'; }
|
||||
\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
|
||||
}
|
||||
|
||||
\" { PUSH_STATE(STRING); return '"'; }
|
||||
\} { return '}'; }
|
||||
<INSIDE_DOLLAR_CURLY>\} { POP_STATE(); return '}'; }
|
||||
\{ { return '{'; }
|
||||
<INSIDE_DOLLAR_CURLY>\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return '{'; }
|
||||
|
||||
<INITIAL,INSIDE_DOLLAR_CURLY>\" {
|
||||
PUSH_STATE(STRING); return '"';
|
||||
}
|
||||
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)*\$/\" |
|
||||
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)+ {
|
||||
/* It is impossible to match strings ending with '$' with one
|
||||
regex because trailing contexts are only valid at the end
|
||||
of a rule. (A sane but undocumented limitation.) */
|
||||
yylval->e = unescapeStr(data->symbols, yytext);
|
||||
return STR;
|
||||
}
|
||||
<STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||
<STRING>\" { POP_STATE(); return '"'; }
|
||||
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
||||
/* It is impossible to match strings ending with '$' with one
|
||||
regex because trailing contexts are only valid at the end
|
||||
of a rule. (A sane but undocumented limitation.) */
|
||||
yylval->e = unescapeStr(data->symbols, yytext);
|
||||
return STR;
|
||||
}
|
||||
<STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
|
||||
<STRING>\" { POP_STATE(); return '"'; }
|
||||
<STRING>\$|\\|\$\\ {
|
||||
/* This can only occur when we reach EOF, otherwise the above
|
||||
(...|\$[^\{\"\\]|\\.|\$\\.)+ would have triggered.
|
||||
This is technically invalid, but we leave the problem to the
|
||||
parser who fails with exact location. */
|
||||
return STR;
|
||||
}
|
||||
|
||||
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
|
||||
<INITIAL,INSIDE_DOLLAR_CURLY>\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
|
||||
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
||||
yylval->e = new ExprIndStr(yytext);
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\$ {
|
||||
<IND_STRING>\'\'\$ |
|
||||
<IND_STRING>\$ {
|
||||
yylval->e = new ExprIndStr("$");
|
||||
return IND_STR;
|
||||
}
|
||||
|
@ -158,13 +174,14 @@ or { return OR_KW; }
|
|||
yylval->e = unescapeStr(data->symbols, yytext + 2);
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||
<IND_STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
|
||||
<IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; }
|
||||
<IND_STRING>\' {
|
||||
yylval->e = new ExprIndStr("'");
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
||||
|
||||
<INITIAL,INSIDE_DOLLAR_CURLY>{
|
||||
|
||||
{PATH} { yylval->path = strdup(yytext); return PATH; }
|
||||
{HPATH} { yylval->path = strdup(yytext); return HPATH; }
|
||||
|
@ -177,6 +194,7 @@ or { return OR_KW; }
|
|||
|
||||
. return yytext[0];
|
||||
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
|
|
|
@ -590,7 +590,7 @@ Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
|
|||
}
|
||||
|
||||
|
||||
void EvalState::addToSearchPath(const string & s, bool warn)
|
||||
void EvalState::addToSearchPath(const string & s)
|
||||
{
|
||||
size_t pos = s.find('=');
|
||||
string prefix;
|
||||
|
@ -602,16 +602,7 @@ void EvalState::addToSearchPath(const string & s, bool warn)
|
|||
path = string(s, pos + 1);
|
||||
}
|
||||
|
||||
if (isUri(path))
|
||||
path = downloadFileCached(path, true);
|
||||
|
||||
path = absPath(path);
|
||||
if (pathExists(path)) {
|
||||
debug(format("adding path ‘%1%’ to the search path") % path);
|
||||
/* Resolve symlinks in the path to support restricted mode. */
|
||||
searchPath.push_back(std::pair<string, Path>(prefix, canonPath(path, true)));
|
||||
} else if (warn)
|
||||
printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ does not exist, ignoring") % path);
|
||||
searchPath.emplace_back(prefix, path);
|
||||
}
|
||||
|
||||
|
||||
|
@ -624,17 +615,19 @@ Path EvalState::findFile(const string & path)
|
|||
Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos & pos)
|
||||
{
|
||||
for (auto & i : searchPath) {
|
||||
assert(!isUri(i.second));
|
||||
Path res;
|
||||
std::string suffix;
|
||||
if (i.first.empty())
|
||||
res = i.second + "/" + path;
|
||||
suffix = "/" + path;
|
||||
else {
|
||||
if (path.compare(0, i.first.size(), i.first) != 0 ||
|
||||
(path.size() > i.first.size() && path[i.first.size()] != '/'))
|
||||
auto s = i.first.size();
|
||||
if (path.compare(0, s, i.first) != 0 ||
|
||||
(path.size() > s && path[s] != '/'))
|
||||
continue;
|
||||
res = i.second +
|
||||
(path.size() == i.first.size() ? "" : "/" + string(path, i.first.size()));
|
||||
suffix = path.size() == s ? "" : "/" + string(path, s);
|
||||
}
|
||||
auto r = resolveSearchPathElem(i);
|
||||
if (!r.first) continue;
|
||||
Path res = r.second + suffix;
|
||||
if (pathExists(res)) return canonPath(res);
|
||||
}
|
||||
format f = format(
|
||||
|
@ -645,4 +638,35 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
|
|||
}
|
||||
|
||||
|
||||
std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathElem & elem)
|
||||
{
|
||||
auto i = searchPathResolved.find(elem.second);
|
||||
if (i != searchPathResolved.end()) return i->second;
|
||||
|
||||
std::pair<bool, std::string> res;
|
||||
|
||||
if (isUri(elem.second)) {
|
||||
try {
|
||||
res = { true, downloadFileCached(elem.second, true) };
|
||||
} catch (DownloadError & e) {
|
||||
printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ cannot be downloaded, ignoring") % elem.second);
|
||||
res = { false, "" };
|
||||
}
|
||||
} else {
|
||||
auto path = absPath(elem.second);
|
||||
if (pathExists(path))
|
||||
res = { true, path };
|
||||
else {
|
||||
printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ does not exist, ignoring") % elem.second);
|
||||
res = { false, "" };
|
||||
}
|
||||
}
|
||||
|
||||
debug(format("resolved search path element ‘%s’ to ‘%s’") % elem.second % res.second);
|
||||
|
||||
searchPathResolved[elem.second] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,45 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args
|
|||
}
|
||||
|
||||
|
||||
/* Execute a program and parse its output */
|
||||
static void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos);
|
||||
auto elems = args[0]->listElems();
|
||||
auto count = args[0]->listSize();
|
||||
if (count == 0) {
|
||||
throw EvalError(format("at least one argument to 'exec' required, at %1%") % pos);
|
||||
}
|
||||
PathSet context;
|
||||
auto program = state.coerceToString(pos, *elems[0], context, false, false);
|
||||
Strings commandArgs;
|
||||
for (unsigned int i = 1; i < args[0]->listSize(); ++i) {
|
||||
commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
|
||||
}
|
||||
try {
|
||||
realiseContext(context);
|
||||
} catch (InvalidPathError & e) {
|
||||
throw EvalError(format("cannot execute ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||
% program % e.path % pos);
|
||||
}
|
||||
|
||||
auto output = runProgram(program, true, commandArgs);
|
||||
Expr * parsed;
|
||||
try {
|
||||
parsed = state.parseExprFromString(output, pos.file);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("While parsing the output from ‘%1%’, at %2%\n") % program % pos);
|
||||
throw;
|
||||
}
|
||||
try {
|
||||
state.eval(parsed, v);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("While evaluating the output from ‘%1%’, at %2%\n") % program % pos);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return a string representing the type of the expression. */
|
||||
static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
|
@ -765,7 +804,6 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
|
||||
SearchPath searchPath;
|
||||
|
||||
PathSet context;
|
||||
for (unsigned int n = 0; n < args[0]->listSize(); ++n) {
|
||||
Value & v2(*args[0]->listElems()[n]);
|
||||
state.forceAttrs(v2, pos);
|
||||
|
@ -778,21 +816,23 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
i = v2.attrs->find(state.symbols.create("path"));
|
||||
if (i == v2.attrs->end())
|
||||
throw EvalError(format("attribute ‘path’ missing, at %1%") % pos);
|
||||
string path = state.coerceToPath(pos, *i->value, context);
|
||||
|
||||
searchPath.push_back(std::pair<string, Path>(prefix, state.checkSourcePath(path)));
|
||||
PathSet context;
|
||||
string path = state.coerceToString(pos, *i->value, context, false, false);
|
||||
|
||||
try {
|
||||
realiseContext(context);
|
||||
} catch (InvalidPathError & e) {
|
||||
throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||
% path % e.path % pos);
|
||||
}
|
||||
|
||||
searchPath.emplace_back(prefix, path);
|
||||
}
|
||||
|
||||
string path = state.forceStringNoCtx(*args[1], pos);
|
||||
|
||||
try {
|
||||
realiseContext(context);
|
||||
} catch (InvalidPathError & e) {
|
||||
throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||
% path % e.path % pos);
|
||||
}
|
||||
|
||||
mkPath(v, state.findFile(searchPath, path, pos).c_str());
|
||||
mkPath(v, state.checkSourcePath(state.findFile(searchPath, path, pos)).c_str());
|
||||
}
|
||||
|
||||
/* Read a directory (without . or ..) */
|
||||
|
@ -1657,6 +1697,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
|||
if (state.restricted) throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
|
||||
|
||||
string url;
|
||||
string name;
|
||||
|
||||
state.forceValue(*args[0]);
|
||||
|
||||
|
@ -1665,9 +1706,11 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
|||
state.forceAttrs(*args[0], pos);
|
||||
|
||||
for (auto & attr : *args[0]->attrs) {
|
||||
string name(attr.name);
|
||||
if (name == "url")
|
||||
string n(attr.name);
|
||||
if (n == "url")
|
||||
url = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||
else if (n == "name")
|
||||
name = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||
else
|
||||
throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
|
||||
}
|
||||
|
@ -1678,7 +1721,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
|||
} else
|
||||
url = state.forceStringNoCtx(*args[0], pos);
|
||||
|
||||
Path res = downloadFileCached(url, unpack);
|
||||
Path res = downloadFileCached(url, unpack, name);
|
||||
mkString(v, res, PathSet({res}));
|
||||
}
|
||||
|
||||
|
@ -1746,8 +1789,10 @@ void EvalState::createBaseEnv()
|
|||
mkApp(v, *baseEnv.values[baseEnvDispl - 1], *v2);
|
||||
forceValue(v);
|
||||
addConstant("import", v);
|
||||
if (settings.enableImportNative)
|
||||
if (settings.enableNativeCode) {
|
||||
addPrimOp("__importNative", 2, prim_importNative);
|
||||
addPrimOp("__exec", 1, prim_exec);
|
||||
}
|
||||
addPrimOp("__typeOf", 1, prim_typeOf);
|
||||
addPrimOp("isNull", 1, prim_isNull);
|
||||
addPrimOp("__isFunction", 1, prim_isFunction);
|
||||
|
|
|
@ -162,6 +162,14 @@ void initNix()
|
|||
|
||||
if (char *pack = getenv("_NIX_OPTIONS"))
|
||||
settings.unpack(pack);
|
||||
|
||||
/* On macOS, don't use the per-session TMPDIR (as set e.g. by
|
||||
sshd). This breaks build users because they don't have access
|
||||
to the TMPDIR, in particular in ‘nix-store --serve’. */
|
||||
#if __APPLE__
|
||||
if (getuid() == 0 && hasPrefix(getEnv("TMPDIR"), "/var/folders/"))
|
||||
unsetenv("TMPDIR");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
|
|||
bool haveSP = true;
|
||||
char * sp = 0;
|
||||
#if defined(__x86_64__) && defined(REG_RSP)
|
||||
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_RSP];
|
||||
sp = (char *) ((ucontext_t *) ctx)->uc_mcontext.gregs[REG_RSP];
|
||||
#elif defined(REG_ESP)
|
||||
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_ESP];
|
||||
sp = (char *) ((ucontext_t *) ctx)->uc_mcontext.gregs[REG_ESP];
|
||||
#else
|
||||
haveSP = false;
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "archive.hh"
|
||||
#include "affinity.hh"
|
||||
#include "builtins.hh"
|
||||
#include "finally.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
@ -54,6 +55,7 @@
|
|||
#include <sys/mount.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/fs.h>
|
||||
#include <seccomp.h>
|
||||
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
||||
#endif
|
||||
|
||||
|
@ -761,7 +763,14 @@ private:
|
|||
GoalState state;
|
||||
|
||||
/* Stuff we need to pass to initChild(). */
|
||||
typedef map<Path, Path> DirsInChroot; // maps target path to source path
|
||||
struct ChrootPath {
|
||||
Path source;
|
||||
bool optional;
|
||||
ChrootPath(Path source = "", bool optional = false)
|
||||
: source(source), optional(optional)
|
||||
{ }
|
||||
};
|
||||
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
|
||||
DirsInChroot dirsInChroot;
|
||||
typedef map<string, string> Environment;
|
||||
Environment env;
|
||||
|
@ -769,7 +778,6 @@ private:
|
|||
#if __APPLE__
|
||||
typedef string SandboxProfile;
|
||||
SandboxProfile additionalSandboxProfile;
|
||||
AutoDelete autoDelSandbox;
|
||||
#endif
|
||||
|
||||
/* Hash rewriting. */
|
||||
|
@ -1063,8 +1071,10 @@ void DerivationGoal::outputsSubstituted()
|
|||
{
|
||||
trace("all outputs substituted (maybe)");
|
||||
|
||||
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback)
|
||||
throw Error(format("some substitutes for the outputs of derivation ‘%1%’ failed (usually happens due to networking issues); try ‘--fallback’ to build derivation from source ") % drvPath);
|
||||
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
|
||||
done(BuildResult::TransientFailure, (format("some substitutes for the outputs of derivation ‘%1%’ failed (usually happens due to networking issues); try ‘--fallback’ to build derivation from source ") % drvPath).str());
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the substitutes form an incomplete closure, then we should
|
||||
build the dependencies of this derivation, but after that, we
|
||||
|
@ -1884,7 +1894,13 @@ void DerivationGoal::startBuilder()
|
|||
/* If `build-users-group' is not empty, then we have to build as
|
||||
one of the members of that group. */
|
||||
if (settings.buildUsersGroup != "") {
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
buildUser.acquire();
|
||||
#else
|
||||
/* Don't know how to block the creation of setuid/setgid
|
||||
binaries on this platform. */
|
||||
throw Error("build users are not supported on this platform for security reasons");
|
||||
#endif
|
||||
assert(buildUser.getUID() != 0);
|
||||
assert(buildUser.getGID() != 0);
|
||||
|
||||
|
@ -1922,20 +1938,30 @@ void DerivationGoal::startBuilder()
|
|||
|
||||
dirsInChroot.clear();
|
||||
|
||||
for (auto & i : dirs) {
|
||||
for (auto i : dirs) {
|
||||
if (i.empty()) continue;
|
||||
bool optional = false;
|
||||
if (i[i.size() - 1] == '?') {
|
||||
optional = true;
|
||||
i.pop_back();
|
||||
}
|
||||
size_t p = i.find('=');
|
||||
if (p == string::npos)
|
||||
dirsInChroot[i] = i;
|
||||
dirsInChroot[i] = {i, optional};
|
||||
else
|
||||
dirsInChroot[string(i, 0, p)] = string(i, p + 1);
|
||||
dirsInChroot[string(i, 0, p)] = {string(i, p + 1), optional};
|
||||
}
|
||||
dirsInChroot[tmpDirInSandbox] = tmpDir;
|
||||
|
||||
/* Add the closure of store paths to the chroot. */
|
||||
PathSet closure;
|
||||
for (auto & i : dirsInChroot)
|
||||
if (isInStore(i.second))
|
||||
computeFSClosure(worker.store, toStorePath(i.second), closure);
|
||||
try {
|
||||
if (isInStore(i.second.source))
|
||||
computeFSClosure(worker.store, toStorePath(i.second.source), closure);
|
||||
} catch (Error & e) {
|
||||
throw Error(format("while processing ‘build-sandbox-paths’: %s") % e.what());
|
||||
}
|
||||
for (auto & i : closure)
|
||||
dirsInChroot[i] = i;
|
||||
|
||||
|
@ -2094,7 +2120,7 @@ void DerivationGoal::startBuilder()
|
|||
}
|
||||
}
|
||||
|
||||
if (settings.preBuildHook != "") {
|
||||
if (useChroot && settings.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
|
||||
printMsg(lvlChatty, format("executing pre-build hook ‘%1%’")
|
||||
% settings.preBuildHook);
|
||||
auto args = useChroot ? Strings({drvPath, chrootRootDir}) :
|
||||
|
@ -2232,6 +2258,55 @@ void DerivationGoal::startBuilder()
|
|||
}
|
||||
|
||||
|
||||
void setupSeccomp()
|
||||
{
|
||||
#if __linux__
|
||||
scmp_filter_ctx ctx;
|
||||
|
||||
if (!(ctx = seccomp_init(SCMP_ACT_ALLOW)))
|
||||
throw SysError("unable to initialize seccomp mode 2");
|
||||
|
||||
Finally cleanup([&]() {
|
||||
seccomp_release(ctx);
|
||||
});
|
||||
|
||||
if (settings.thisSystem == "x86_64-linux" &&
|
||||
seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0)
|
||||
throw SysError("unable to add 32-bit seccomp architecture");
|
||||
|
||||
if (settings.thisSystem == "x86_64-linux" &&
|
||||
seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
|
||||
throw SysError("unable to add X32 seccomp architecture");
|
||||
|
||||
/* Prevent builders from creating setuid/setgid binaries. */
|
||||
for (int perm : { S_ISUID, S_ISGID }) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(chmod), 1,
|
||||
SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0)
|
||||
throw SysError("unable to add seccomp rule");
|
||||
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmod), 1,
|
||||
SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0)
|
||||
throw SysError("unable to add seccomp rule");
|
||||
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmodat), 1,
|
||||
SCMP_A2(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0)
|
||||
throw SysError("unable to add seccomp rule");
|
||||
}
|
||||
|
||||
/* Prevent builders from creating EAs or ACLs. Not all filesystems
|
||||
support these, and they're not allowed in the Nix store because
|
||||
they're not representable in the NAR serialisation. */
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(setxattr), 0) != 0 ||
|
||||
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(lsetxattr), 0) != 0 ||
|
||||
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
|
||||
throw SysError("unable to add seccomp rule");
|
||||
|
||||
if (seccomp_load(ctx) != 0)
|
||||
throw SysError("unable to load seccomp BPF program");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DerivationGoal::runChild()
|
||||
{
|
||||
/* Warning: in the child we should absolutely not make any SQLite
|
||||
|
@ -2243,6 +2318,12 @@ void DerivationGoal::runChild()
|
|||
|
||||
commonChildInit(builderOut);
|
||||
|
||||
try {
|
||||
setupSeccomp();
|
||||
} catch (...) {
|
||||
if (buildUser.enabled()) throw;
|
||||
}
|
||||
|
||||
#if __linux__
|
||||
if (useChroot) {
|
||||
|
||||
|
@ -2326,12 +2407,16 @@ void DerivationGoal::runChild()
|
|||
environment. */
|
||||
for (auto & i : dirsInChroot) {
|
||||
struct stat st;
|
||||
Path source = i.second;
|
||||
Path source = i.second.source;
|
||||
Path target = chrootRootDir + i.first;
|
||||
if (source == "/proc") continue; // backwards compatibility
|
||||
debug(format("bind mounting ‘%1%’ to ‘%2%’") % source % target);
|
||||
if (stat(source.c_str(), &st) == -1)
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % source);
|
||||
if (stat(source.c_str(), &st) == -1) {
|
||||
if (i.second.optional && errno == ENOENT)
|
||||
continue;
|
||||
else
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % source);
|
||||
}
|
||||
if (S_ISDIR(st.st_mode))
|
||||
createDirs(target);
|
||||
else {
|
||||
|
@ -2456,46 +2541,100 @@ void DerivationGoal::runChild()
|
|||
|
||||
const char *builder = "invalid";
|
||||
|
||||
string sandboxProfile;
|
||||
if (isBuiltin(*drv)) {
|
||||
;
|
||||
}
|
||||
#if __APPLE__
|
||||
} else if (useChroot) {
|
||||
/* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */
|
||||
PathSet ancestry;
|
||||
else if (getEnv("_NIX_TEST_NO_SANDBOX") == "") {
|
||||
/* This has to appear before import statements. */
|
||||
std::string sandboxProfile = "(version 1)\n";
|
||||
|
||||
/* We build the ancestry before adding all inputPaths to the store because we know they'll
|
||||
all have the same parents (the store), and there might be lots of inputs. This isn't
|
||||
particularly efficient... I doubt it'll be a bottleneck in practice */
|
||||
for (auto & i : dirsInChroot) {
|
||||
Path cur = i.first;
|
||||
while (cur.compare("/") != 0) {
|
||||
cur = dirOf(cur);
|
||||
ancestry.insert(cur);
|
||||
if (useChroot) {
|
||||
|
||||
/* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */
|
||||
PathSet ancestry;
|
||||
|
||||
/* We build the ancestry before adding all inputPaths to the store because we know they'll
|
||||
all have the same parents (the store), and there might be lots of inputs. This isn't
|
||||
particularly efficient... I doubt it'll be a bottleneck in practice */
|
||||
for (auto & i : dirsInChroot) {
|
||||
Path cur = i.first;
|
||||
while (cur.compare("/") != 0) {
|
||||
cur = dirOf(cur);
|
||||
ancestry.insert(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* And we want the store in there regardless of how empty dirsInChroot. We include the innermost
|
||||
path component this time, since it's typically /nix/store and we care about that. */
|
||||
Path cur = settings.nixStore;
|
||||
while (cur.compare("/") != 0) {
|
||||
ancestry.insert(cur);
|
||||
cur = dirOf(cur);
|
||||
}
|
||||
/* And we want the store in there regardless of how empty dirsInChroot. We include the innermost
|
||||
path component this time, since it's typically /nix/store and we care about that. */
|
||||
Path cur = settings.nixStore;
|
||||
while (cur.compare("/") != 0) {
|
||||
ancestry.insert(cur);
|
||||
cur = dirOf(cur);
|
||||
}
|
||||
|
||||
/* Add all our input paths to the chroot */
|
||||
for (auto & i : inputPaths)
|
||||
dirsInChroot[i] = i;
|
||||
/* Add all our input paths to the chroot */
|
||||
for (auto & i : inputPaths)
|
||||
dirsInChroot[i] = i;
|
||||
|
||||
/* This has to appear before import statements */
|
||||
sandboxProfile += "(version 1)\n";
|
||||
/* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */
|
||||
if (settings.get("darwin-log-sandbox-violations", false)) {
|
||||
sandboxProfile += "(deny default)\n";
|
||||
} else {
|
||||
sandboxProfile += "(deny default (with no-log))\n";
|
||||
}
|
||||
|
||||
/* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */
|
||||
if (settings.get("darwin-log-sandbox-violations", false)) {
|
||||
sandboxProfile += "(deny default)\n";
|
||||
} else {
|
||||
sandboxProfile += "(deny default (with no-log))\n";
|
||||
}
|
||||
/* Our rwx outputs */
|
||||
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
||||
for (auto & i : missingPaths) {
|
||||
sandboxProfile += (format("\t(subpath \"%1%\")\n") % i.c_str()).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
/* Our inputs (transitive dependencies and any impurities computed above)
|
||||
|
||||
without file-write* allowed, access() incorrectly returns EPERM
|
||||
*/
|
||||
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
||||
for (auto & i : dirsInChroot) {
|
||||
if (i.first != i.second.source)
|
||||
throw Error(format(
|
||||
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin")
|
||||
% i.first % i.second.source);
|
||||
|
||||
string path = i.first;
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st)) {
|
||||
if (i.second.optional && errno == ENOENT)
|
||||
continue;
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
||||
}
|
||||
if (S_ISDIR(st.st_mode))
|
||||
sandboxProfile += (format("\t(subpath \"%1%\")\n") % path).str();
|
||||
else
|
||||
sandboxProfile += (format("\t(literal \"%1%\")\n") % path).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
/* Allow file-read* on full directory hierarchy to self. Allows realpath() */
|
||||
sandboxProfile += "(allow file-read*\n";
|
||||
for (auto & i : ancestry) {
|
||||
sandboxProfile += (format("\t(literal \"%1%\")\n") % i.c_str()).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
sandboxProfile += additionalSandboxProfile;
|
||||
} else
|
||||
sandboxProfile += "(allow default)\n";
|
||||
|
||||
sandboxProfile += "(deny file-write-setugid)\n";
|
||||
|
||||
debug("Generated sandbox profile:");
|
||||
debug(sandboxProfile);
|
||||
|
||||
Path sandboxFile = tmpDir + "/.sandbox.sb";
|
||||
|
||||
writeFile(sandboxFile, sandboxProfile);
|
||||
|
||||
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
|
||||
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
|
||||
|
@ -2504,53 +2643,6 @@ void DerivationGoal::runChild()
|
|||
/* They don't like trailing slashes on subpath directives */
|
||||
if (globalTmpDir.back() == '/') globalTmpDir.pop_back();
|
||||
|
||||
/* Our rwx outputs */
|
||||
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
||||
for (auto & i : missingPaths) {
|
||||
sandboxProfile += (format("\t(subpath \"%1%\")\n") % i.c_str()).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
/* Our inputs (transitive dependencies and any impurities computed above)
|
||||
|
||||
without file-write* allowed, access() incorrectly returns EPERM
|
||||
*/
|
||||
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
||||
for (auto & i : dirsInChroot) {
|
||||
if (i.first != i.second)
|
||||
throw Error(format(
|
||||
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin")
|
||||
% i.first % i.second);
|
||||
|
||||
string path = i.first;
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
||||
if (S_ISDIR(st.st_mode))
|
||||
sandboxProfile += (format("\t(subpath \"%1%\")\n") % path).str();
|
||||
else
|
||||
sandboxProfile += (format("\t(literal \"%1%\")\n") % path).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
/* Allow file-read* on full directory hierarchy to self. Allows realpath() */
|
||||
sandboxProfile += "(allow file-read*\n";
|
||||
for (auto & i : ancestry) {
|
||||
sandboxProfile += (format("\t(literal \"%1%\")\n") % i.c_str()).str();
|
||||
}
|
||||
sandboxProfile += ")\n";
|
||||
|
||||
sandboxProfile += additionalSandboxProfile;
|
||||
|
||||
debug("Generated sandbox profile:");
|
||||
debug(sandboxProfile);
|
||||
|
||||
Path sandboxFile = drvPath + ".sb";
|
||||
if (pathExists(sandboxFile)) deletePath(sandboxFile);
|
||||
autoDelSandbox.reset(sandboxFile, false);
|
||||
|
||||
writeFile(sandboxFile, sandboxProfile);
|
||||
|
||||
builder = "/usr/bin/sandbox-exec";
|
||||
args.push_back("sandbox-exec");
|
||||
args.push_back("-f");
|
||||
|
@ -2558,8 +2650,9 @@ void DerivationGoal::runChild()
|
|||
args.push_back("-D");
|
||||
args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir);
|
||||
args.push_back(drv->builder);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
else {
|
||||
builder = drv->builder.c_str();
|
||||
string builderBasename = baseNameOf(drv->builder);
|
||||
args.push_back(builderBasename);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "globals.hh"
|
||||
#include "hash.hh"
|
||||
#include "store-api.hh"
|
||||
#include "pathlocks.hh"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
@ -114,6 +115,10 @@ struct Curl
|
|||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback_);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *) &curl);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
/* If no file exist in the specified path, curl continues to work
|
||||
* anyway as if netrc support was disabled. */
|
||||
curl_easy_setopt(curl, CURLOPT_NETRC_FILE, settings.netrcFile.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
}
|
||||
|
||||
~Curl()
|
||||
|
@ -129,7 +134,8 @@ struct Curl
|
|||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
|
||||
if (options.verifyTLS)
|
||||
curl_easy_setopt(curl, CURLOPT_CAINFO, getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt").c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_CAINFO,
|
||||
getEnv("NIX_SSL_CERT_FILE", getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt")).c_str());
|
||||
else {
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
|
@ -188,7 +194,7 @@ DownloadResult downloadFile(string url, const DownloadOptions & options)
|
|||
}
|
||||
|
||||
|
||||
Path downloadFileCached(const string & url, bool unpack)
|
||||
Path downloadFileCached(const string & url, bool unpack, string name)
|
||||
{
|
||||
Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
|
||||
createDirs(cacheDir);
|
||||
|
@ -198,6 +204,8 @@ Path downloadFileCached(const string & url, bool unpack)
|
|||
Path dataFile = cacheDir + "/" + urlHash + ".info";
|
||||
Path fileLink = cacheDir + "/" + urlHash + "-file";
|
||||
|
||||
PathLocks lock({fileLink}, (format("waiting for lock on ‘%1%’...") % fileLink).str());
|
||||
|
||||
Path storePath;
|
||||
|
||||
string expectedETag;
|
||||
|
@ -223,9 +231,10 @@ Path downloadFileCached(const string & url, bool unpack)
|
|||
storePath = "";
|
||||
}
|
||||
|
||||
string name;
|
||||
auto p = url.rfind('/');
|
||||
if (p != string::npos) name = string(url, p + 1);
|
||||
if (name == "") {
|
||||
auto p = url.rfind('/');
|
||||
if (p != string::npos) name = string(url, p + 1);
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
|
||||
|
@ -249,6 +258,7 @@ Path downloadFileCached(const string & url, bool unpack)
|
|||
|
||||
if (unpack) {
|
||||
Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
|
||||
PathLocks lock({unpackedLink}, (format("waiting for lock on ‘%1%’...") % unpackedLink).str());
|
||||
Path unpackedStorePath;
|
||||
if (pathExists(unpackedLink)) {
|
||||
unpackedStorePath = readLink(unpackedLink);
|
||||
|
|
|
@ -20,7 +20,7 @@ struct DownloadResult
|
|||
|
||||
DownloadResult downloadFile(string url, const DownloadOptions & options);
|
||||
|
||||
Path downloadFileCached(const string & url, bool unpack);
|
||||
Path downloadFileCached(const string & url, bool unpack, string name = "");
|
||||
|
||||
MakeError(DownloadError, Error)
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ Settings::Settings()
|
|||
envKeepDerivations = false;
|
||||
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
|
||||
showTrace = false;
|
||||
enableImportNative = false;
|
||||
enableNativeCode = false;
|
||||
netrcFile = (format("%1%/%2%") % nixConfDir % "netrc").str();
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,9 +186,12 @@ void Settings::update()
|
|||
_get(sshSubstituterHosts, "ssh-substituter-hosts");
|
||||
_get(useSshSubstituter, "use-ssh-substituter");
|
||||
_get(logServers, "log-servers");
|
||||
_get(enableImportNative, "allow-unsafe-native-code-during-evaluation");
|
||||
_get(enableNativeCode, "allow-unsafe-native-code-during-evaluation");
|
||||
_get(useCaseHack, "use-case-hack");
|
||||
_get(preBuildHook, "pre-build-hook");
|
||||
_get(keepGoing, "keep-going");
|
||||
_get(keepFailed, "keep-failed");
|
||||
_get(netrcFile, "netrc-file");
|
||||
|
||||
string subs = getEnv("NIX_SUBSTITUTERS", "default");
|
||||
if (subs == "default") {
|
||||
|
|
|
@ -203,13 +203,17 @@ struct Settings {
|
|||
/* A list of URL prefixes that can return Nix build logs. */
|
||||
Strings logServers;
|
||||
|
||||
/* Whether the importNative primop should be enabled */
|
||||
bool enableImportNative;
|
||||
/* Whether native-code enabling primops should be enabled */
|
||||
bool enableNativeCode;
|
||||
|
||||
/* The hook to run just before a build to set derivation-specific
|
||||
build settings */
|
||||
Path preBuildHook;
|
||||
|
||||
/* Path to the netrc file used to obtain usernames/passwords for
|
||||
downloads. */
|
||||
Path netrcFile;
|
||||
|
||||
private:
|
||||
SettingsMap settings, overrides;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <sys/statvfs.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
@ -225,6 +226,7 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||
schemaPath = settings.nixDBPath + "/schema";
|
||||
|
||||
if (settings.readOnlyMode) {
|
||||
curSchema = getSchema();
|
||||
openDB(false);
|
||||
return;
|
||||
}
|
||||
|
@ -309,6 +311,7 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||
} catch (SysError & e) {
|
||||
if (e.errNo != EACCES) throw;
|
||||
settings.readOnlyMode = true;
|
||||
curSchema = getSchema();
|
||||
openDB(false);
|
||||
return;
|
||||
}
|
||||
|
@ -320,8 +323,8 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||
|
||||
/* Check the current database schema and if necessary do an
|
||||
upgrade. */
|
||||
int curSchema = getSchema();
|
||||
if (curSchema > nixSchemaVersion)
|
||||
curSchema = getSchema();
|
||||
if (curSchema >= 0x100)
|
||||
throw Error(format("current Nix store schema is version %1%, but I only support %2%")
|
||||
% curSchema % nixSchemaVersion);
|
||||
|
||||
|
@ -470,16 +473,18 @@ void LocalStore::openDB(bool create)
|
|||
"select path from Refs join ValidPaths on referrer = id where reference = (select id from ValidPaths where path = ?);");
|
||||
stmtInvalidatePath.create(db,
|
||||
"delete from ValidPaths where path = ?;");
|
||||
stmtRegisterFailedPath.create(db,
|
||||
"insert or ignore into FailedPaths (path, time) values (?, ?);");
|
||||
stmtHasPathFailed.create(db,
|
||||
"select time from FailedPaths where path = ?;");
|
||||
stmtQueryFailedPaths.create(db,
|
||||
"select path from FailedPaths;");
|
||||
// If the path is a derivation, then clear its outputs.
|
||||
stmtClearFailedPath.create(db,
|
||||
"delete from FailedPaths where ?1 = '*' or path = ?1 "
|
||||
"or path in (select d.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where v.path = ?1);");
|
||||
if (curSchema < 9) {
|
||||
stmtRegisterFailedPath.create(db,
|
||||
"insert or ignore into FailedPaths (path, time) values (?, ?);");
|
||||
stmtHasPathFailed.create(db,
|
||||
"select time from FailedPaths where path = ?;");
|
||||
stmtQueryFailedPaths.create(db,
|
||||
"select path from FailedPaths;");
|
||||
// If the path is a derivation, then clear its outputs.
|
||||
stmtClearFailedPath.create(db,
|
||||
"delete from FailedPaths where ?1 = '*' or path = ?1 "
|
||||
"or path in (select d.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where v.path = ?1);");
|
||||
}
|
||||
stmtAddDerivationOutput.create(db,
|
||||
"insert or replace into DerivationOutputs (drv, id, path) values (?, ?, ?);");
|
||||
stmtQueryValidDerivers.create(db,
|
||||
|
@ -566,6 +571,16 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
|
|||
{
|
||||
checkInterrupt();
|
||||
|
||||
#if __APPLE__
|
||||
/* Remove flags, in particular UF_IMMUTABLE which would prevent
|
||||
the file from being garbage-collected. FIXME: Use
|
||||
setattrlist() to remove other attributes as well. */
|
||||
if (lchflags(path.c_str(), 0)) {
|
||||
if (errno != ENOTSUP)
|
||||
throw SysError(format("clearing flags of path ‘%1%’") % path);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
||||
|
@ -574,6 +589,29 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
|
|||
if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)))
|
||||
throw Error(format("file ‘%1%’ has an unsupported type") % path);
|
||||
|
||||
#if __linux__
|
||||
/* Remove extended attributes / ACLs. */
|
||||
ssize_t eaSize = llistxattr(path.c_str(), nullptr, 0);
|
||||
|
||||
if (eaSize < 0) {
|
||||
if (errno != ENOTSUP)
|
||||
throw SysError(format("querying extended attributes of ‘%s’") % path);
|
||||
} else if (eaSize > 0) {
|
||||
std::vector<char> eaBuf(eaSize);
|
||||
|
||||
if ((eaSize = llistxattr(path.c_str(), eaBuf.data(), eaBuf.size())) < 0)
|
||||
throw SysError(format("querying extended attributes of ‘%s’") % path);
|
||||
|
||||
for (auto & eaName: tokenizeString<Strings>(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) {
|
||||
/* Ignore SELinux security labels since these cannot be
|
||||
removed even by root. */
|
||||
if (eaName == "security.selinux") continue;
|
||||
if (lremovexattr(path.c_str(), eaName.c_str()) == -1)
|
||||
throw SysError(format("removing extended attribute ‘%s’ from ‘%s’") % eaName % path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fail if the file is not owned by the build user. This prevents
|
||||
us from messing up the ownership/permissions of files
|
||||
hard-linked into the output (e.g. "ln /etc/shadow $out/foo").
|
||||
|
@ -742,6 +780,7 @@ void LocalStore::addReference(unsigned long long referrer, unsigned long long re
|
|||
|
||||
void LocalStore::registerFailedPath(const Path & path)
|
||||
{
|
||||
if (curSchema >= 9) return;
|
||||
retry_sqlite {
|
||||
SQLiteStmtUse use(stmtRegisterFailedPath);
|
||||
stmtRegisterFailedPath.bind(path);
|
||||
|
@ -754,6 +793,7 @@ void LocalStore::registerFailedPath(const Path & path)
|
|||
|
||||
bool LocalStore::hasPathFailed(const Path & path)
|
||||
{
|
||||
if (curSchema >= 9) return false;
|
||||
retry_sqlite {
|
||||
SQLiteStmtUse use(stmtHasPathFailed);
|
||||
stmtHasPathFailed.bind(path);
|
||||
|
@ -767,6 +807,8 @@ bool LocalStore::hasPathFailed(const Path & path)
|
|||
|
||||
PathSet LocalStore::queryFailedPaths()
|
||||
{
|
||||
if (curSchema >= 9) return {};
|
||||
|
||||
retry_sqlite {
|
||||
SQLiteStmtUse use(stmtQueryFailedPaths);
|
||||
|
||||
|
@ -788,6 +830,8 @@ PathSet LocalStore::queryFailedPaths()
|
|||
|
||||
void LocalStore::clearFailedPaths(const PathSet & paths)
|
||||
{
|
||||
if (curSchema >= 9) return;
|
||||
|
||||
retry_sqlite {
|
||||
SQLiteTxn txn(db);
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ private:
|
|||
|
||||
Path linksDir;
|
||||
|
||||
int curSchema = 0;
|
||||
|
||||
public:
|
||||
|
||||
/* Initialise the local store, upgrading the schema if
|
||||
|
|
|
@ -14,6 +14,10 @@ ifeq ($(OS), SunOS)
|
|||
libstore_LDFLAGS += -lsocket
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Linux)
|
||||
libstore_LDFLAGS += -lseccomp
|
||||
endif
|
||||
|
||||
libstore_CXXFLAGS = \
|
||||
-DNIX_PREFIX=\"$(prefix)\" \
|
||||
-DNIX_STORE_DIR=\"$(storedir)\" \
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <regex>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
@ -97,6 +98,19 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
|
|||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
||||
|
||||
#if __APPLE__
|
||||
/* HFS/OS X has some undocumented security feature disabling hardlinking for
|
||||
special files within .app dirs. *.app/Contents/PkgInfo and
|
||||
*.app/Contents/Resources/\*.lproj seem to be the only paths affected. See
|
||||
https://github.com/NixOS/nix/issues/1443 for more discussion. */
|
||||
|
||||
if (std::regex_search(path, std::regex("\\.app/Contents/PkgInfo$")) ||
|
||||
std::regex_search(path, std::regex("\\.app/Contents/Resources/.+\\.lproj$"))) {
|
||||
debug(format("‘%1%’ is not allowed to be linked in OS X") % path);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
Strings names = readDirectoryIgnoringInodes(path, inodeHash);
|
||||
for (auto & i : names)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
/* A trivial class to run a function at the end of a scope. */
|
||||
class Finally
|
||||
{
|
||||
private:
|
||||
std::function<void()> fun;
|
||||
|
||||
public:
|
||||
Finally(std::function<void()> fun) : fun(fun) { }
|
||||
~Finally() { fun(); }
|
||||
};
|
|
@ -205,7 +205,7 @@ static void start(HashType ht, Ctx & ctx)
|
|||
|
||||
|
||||
static void update(HashType ht, Ctx & ctx,
|
||||
const unsigned char * bytes, unsigned int len)
|
||||
const unsigned char * bytes, size_t len)
|
||||
{
|
||||
if (ht == htMD5) MD5_Update(&ctx.md5, bytes, len);
|
||||
else if (ht == htSHA1) SHA1_Update(&ctx.sha1, bytes, len);
|
||||
|
|
|
@ -327,10 +327,11 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
|
|||
bytesFreed += st.st_blocks * 512;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* Make the directory writable. */
|
||||
if (!(st.st_mode & S_IWUSR)) {
|
||||
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
||||
throw SysError(format("making ‘%1%’ writable") % path);
|
||||
/* Make the directory accessible. */
|
||||
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
|
||||
if ((st.st_mode & PERM_MASK) != PERM_MASK) {
|
||||
if (chmod(path.c_str(), st.st_mode | PERM_MASK) == -1)
|
||||
throw SysError(format("chmod ‘%1%’") % path);
|
||||
}
|
||||
|
||||
for (auto & i : readDirectory(path))
|
||||
|
@ -430,12 +431,21 @@ void createSymlink(const Path & target, const Path & link)
|
|||
|
||||
void replaceSymlink(const Path & target, const Path & link)
|
||||
{
|
||||
Path tmp = canonPath(dirOf(link) + "/.new_" + baseNameOf(link));
|
||||
for (unsigned int n = 0; true; n++) {
|
||||
Path tmp = canonPath((format("%s/.%d_%s") % dirOf(link) % n % baseNameOf(link)).str());
|
||||
|
||||
createSymlink(target, tmp);
|
||||
try {
|
||||
createSymlink(target, tmp);
|
||||
} catch (SysError & e) {
|
||||
if (e.errNo == EEXIST) continue;
|
||||
throw;
|
||||
}
|
||||
|
||||
if (rename(tmp.c_str(), link.c_str()) != 0)
|
||||
throw SysError(format("renaming ‘%1%’ to ‘%2%’") % tmp % link);
|
||||
if (rename(tmp.c_str(), link.c_str()) != 0)
|
||||
throw SysError(format("renaming ‘%1%’ to ‘%2%’") % tmp % link);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1170,6 +1180,12 @@ bool statusOk(int status)
|
|||
}
|
||||
|
||||
|
||||
bool hasPrefix(const string & s, const string & suffix)
|
||||
{
|
||||
return s.compare(0, suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
|
||||
bool hasSuffix(const string & s, const string & suffix)
|
||||
{
|
||||
return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
|
||||
|
|
|
@ -365,6 +365,10 @@ template<class N> bool string2Int(const string & s, N & n)
|
|||
}
|
||||
|
||||
|
||||
/* Return true iff `s' starts with `prefix'. */
|
||||
bool hasPrefix(const string & s, const string & prefix);
|
||||
|
||||
|
||||
/* Return true iff `s' ends in `suffix'. */
|
||||
bool hasSuffix(const string & s, const string & suffix);
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
if (drvPath != "")
|
||||
mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath());
|
||||
|
||||
// Copy each output.
|
||||
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||
// Copy each output meant for installation.
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
||||
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
|
||||
state.mkList(vOutputs, outputs.size());
|
||||
unsigned int m = 0;
|
||||
|
|
|
@ -16,6 +16,10 @@ export NIX_DB_DIR=$TEST_ROOT/db
|
|||
export NIX_CONF_DIR=$TEST_ROOT/etc
|
||||
export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests
|
||||
export _NIX_TEST_SHARED=$TEST_ROOT/shared
|
||||
if [[ -n $NIX_STORE ]]; then
|
||||
export _NIX_TEST_NO_SANDBOX=1
|
||||
fi
|
||||
export _NIX_IN_TEST=$TEST_ROOT/shared
|
||||
export NIX_REMOTE=$NIX_REMOTE_
|
||||
|
||||
export PATH=@bindir@:$PATH
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
cleanup() {
|
||||
PLIST="/Library/LaunchDaemons/org.nixos.nix-daemon.plist"
|
||||
if sudo launchctl list | grep -q nix-daemon; then
|
||||
sudo launchctl unload "$PLIST"
|
||||
fi
|
||||
|
||||
if [ -f "$PLIST" ]; then
|
||||
sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist
|
||||
fi
|
||||
|
||||
profiles=(/etc/profile /etc/bashrc /etc/zshrc)
|
||||
for profile in "${profiles[@]}"; do
|
||||
if [ -f "${profile}.backup-before-nix" ]; then
|
||||
sudo mv "${profile}.backup-before-nix" "${profile}"
|
||||
fi
|
||||
done
|
||||
|
||||
for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do
|
||||
if [ -e "$file" ]; then
|
||||
cat "$file" | grep -v nix-profile > "$file.next"
|
||||
mv "$file.next" "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
for i in $(seq 1 $(sysctl -n hw.ncpu)); do
|
||||
sudo /usr/bin/dscl . -delete "/Users/nixbld$i" || true
|
||||
done
|
||||
sudo /usr/bin/dscl . -delete "/Groups/nixbld" || true
|
||||
|
||||
sudo rm -rf /etc/nix \
|
||||
/nix \
|
||||
/var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels \
|
||||
"$USER/.nix-profile" "$USER/.nix-defexpr" "$USER/.nix-channels"
|
||||
}
|
||||
|
||||
verify() {
|
||||
set +e
|
||||
output=$(echo "nix-shell -p bash --run 'echo toow | rev'" | bash -l)
|
||||
set -e
|
||||
|
||||
test "$output" = "woot"
|
||||
}
|
||||
|
||||
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
|
||||
function finish {
|
||||
rm -rf "$scratch"
|
||||
}
|
||||
trap finish EXIT
|
||||
|
||||
# First setup Nix
|
||||
cleanup
|
||||
curl -o install https://nixos.org/nix/install
|
||||
yes | bash ./install
|
||||
verify
|
||||
|
||||
|
||||
(
|
||||
set +e
|
||||
(
|
||||
echo "cd $(pwd)"
|
||||
echo nix-build ./release.nix -A binaryTarball.x86_64-darwin
|
||||
) | bash -l
|
||||
set -e
|
||||
cp ./result/nix-*.tar.bz2 $scratch/nix.tar.bz2
|
||||
)
|
||||
|
||||
(
|
||||
cd $scratch
|
||||
tar -xf ./nix.tar.bz2
|
||||
|
||||
cd nix-*
|
||||
|
||||
set -eux
|
||||
|
||||
cleanup
|
||||
|
||||
yes | ./install
|
||||
verify
|
||||
cleanup
|
||||
|
||||
echo -n "" | ./install
|
||||
verify
|
||||
cleanup
|
||||
|
||||
sudo mkdir -p /nix/store
|
||||
sudo touch /nix/store/.silly-hint
|
||||
echo -n "" | ALLOW_PREEXISTING_INSTALLATION=true ./install
|
||||
verify
|
||||
test -e /nix/store/.silly-hint
|
||||
|
||||
cleanup
|
||||
)
|
|
@ -1 +1 @@
|
|||
"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\n"
|
||||
"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n"
|
||||
|
|
|
@ -117,4 +117,12 @@ let
|
|||
bar
|
||||
'';
|
||||
|
||||
in s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15
|
||||
# Regression test: accept $'.
|
||||
s16 = ''
|
||||
cut -d $'\t' -f 1
|
||||
'';
|
||||
|
||||
# Accept dollars at end of strings
|
||||
s17 = ''ending dollar $'' + ''$'' + "\n";
|
||||
|
||||
in s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s16 + s17
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
let const = a: "const"; in
|
||||
''${ const { x = "q"; }}''
|
|
@ -0,0 +1,3 @@
|
|||
source common.sh
|
||||
|
||||
nix-instantiate --eval ./lexer.nix
|
|
@ -11,7 +11,7 @@ nix_tests = \
|
|||
binary-patching.sh timeout.sh secure-drv-outputs.sh nix-channel.sh \
|
||||
multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
|
||||
binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \
|
||||
check-reqs.sh pass-as-file.sh tarball.sh
|
||||
check-reqs.sh pass-as-file.sh tarball.sh lexer.sh
|
||||
# parallel.sh
|
||||
|
||||
install-tests += $(foreach x, $(nix_tests), tests/$(x))
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
with import <nixpkgs/nixos/lib/testing.nix> { inherit system; };
|
||||
|
||||
makeTest (let pkgA = pkgs.aterm; pkgB = pkgs.wget; pkgC = pkgs.hello; in {
|
||||
makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in {
|
||||
|
||||
nodes =
|
||||
{ client =
|
||||
|
|
|
@ -14,7 +14,7 @@ let
|
|||
{ services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
nix.package = nix;
|
||||
nix.useChroot = true;
|
||||
nix.useSandbox = true;
|
||||
};
|
||||
|
||||
# Trivial Nix expression to build remotely.
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# Verify that Linux builds cannot create setuid or setgid binaries.
|
||||
|
||||
{ system, nix }:
|
||||
|
||||
with import <nixpkgs/nixos/lib/testing.nix> { inherit system; };
|
||||
|
||||
makeTest {
|
||||
|
||||
machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
nix.package = nix;
|
||||
nix.binaryCaches = [ ];
|
||||
nix.nixPath = [ "nixpkgs=${lib.cleanSource pkgs.path}" ];
|
||||
virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ];
|
||||
};
|
||||
|
||||
testScript = { nodes }:
|
||||
''
|
||||
startAll;
|
||||
|
||||
# Copying to /tmp should succeed.
|
||||
$machine->succeed('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
# Creating a setuid binary should fail.
|
||||
$machine->fail('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 4755 /tmp/id
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
# Creating a setgid binary should fail.
|
||||
$machine->fail('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
# The checks should also work on 32-bit binaries.
|
||||
$machine->fail('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
# The tests above use fchmodat(). Test chmod() as well.
|
||||
$machine->succeed('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 0666, qw(/tmp/id) or die\"
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 666 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
$machine->fail('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 04755, qw(/tmp/id) or die\"
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
# And test fchmod().
|
||||
$machine->succeed('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\"
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
|
||||
$machine->fail('nix-build --option build-use-sandbox false -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\"
|
||||
")\' ');
|
||||
|
||||
$machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');
|
||||
|
||||
$machine->succeed("rm /tmp/id");
|
||||
'';
|
||||
|
||||
}
|
|
@ -16,8 +16,14 @@ tarball=$TEST_ROOT/tarball.tar.xz
|
|||
|
||||
nix-env -f file://$tarball -qa --out-path | grep -q dependencies
|
||||
|
||||
nix-build file://$tarball
|
||||
nix-build -o $TEST_ROOT/result file://$tarball
|
||||
|
||||
nix-build '<foo>' -I foo=file://$tarball
|
||||
nix-build -o $TEST_ROOT/result '<foo>' -I foo=file://$tarball
|
||||
|
||||
nix-build -E "import (fetchTarball file://$tarball)"
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"
|
||||
|
||||
nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar.xz
|
||||
nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball.tar.xz
|
||||
(! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball.tar.xz)
|
||||
|
||||
nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball.tar.xz -I fnord=.
|
||||
|
|
Loading…
Reference in New Issue