diff options
| -rw-r--r-- | config-daemon.ac | 2 | ||||
| -rw-r--r-- | nix/libstore/build.cc | 171 | ||||
| -rw-r--r-- | nix/libstore/gc.cc | 6 | ||||
| -rw-r--r-- | nix/libstore/local-store.cc | 31 | ||||
| -rw-r--r-- | nix/libstore/local-store.hh | 2 | ||||
| -rw-r--r-- | nix/libstore/optimise-store.cc | 1 | ||||
| -rw-r--r-- | nix/libstore/pathlocks.cc | 2 | ||||
| -rw-r--r-- | nix/libstore/remote-store.cc | 17 | ||||
| -rw-r--r-- | nix/libstore/remote-store.hh | 29 | ||||
| -rw-r--r-- | nix/libstore/store-api.hh | 24 | ||||
| -rw-r--r-- | nix/libstore/worker-protocol.hh | 3 | ||||
| -rw-r--r-- | nix/libutil/hash.cc | 101 | ||||
| -rw-r--r-- | nix/libutil/util.cc | 62 | ||||
| -rw-r--r-- | nix/libutil/util.hh | 6 | ||||
| -rw-r--r-- | nix/nix-daemon/nix-daemon.cc | 34 |
15 files changed, 256 insertions, 235 deletions
diff --git a/config-daemon.ac b/config-daemon.ac index a6cf29ca426..f96cc8f7ac1 100644 --- a/config-daemon.ac +++ b/config-daemon.ac | |||
| @@ -76,7 +76,7 @@ if test "x$guix_build_daemon" = "xyes"; then | |||
| 76 | 76 | ||
| 77 | dnl Chroot support. | 77 | dnl Chroot support. |
| 78 | AC_CHECK_FUNCS([chroot unshare]) | 78 | AC_CHECK_FUNCS([chroot unshare]) |
| 79 | AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h tr1/unordered_set]) | 79 | AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h]) |
| 80 | 80 | ||
| 81 | if test "x$ac_cv_func_chroot" != "xyes"; then | 81 | if test "x$ac_cv_func_chroot" != "xyes"; then |
| 82 | AC_MSG_ERROR(['chroot' function missing, bailing out]) | 82 | AC_MSG_ERROR(['chroot' function missing, bailing out]) |
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index 009fcb2c0c1..85a818ba94f 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #if HAVE_SYS_MOUNT_H | 38 | #if HAVE_SYS_MOUNT_H |
| 39 | #include <sys/mount.h> | 39 | #include <sys/mount.h> |
| 40 | #endif | 40 | #endif |
| 41 | #if HAVE_SYS_SYSCALL_H | ||
| 42 | #include <sys/syscall.h> | ||
| 43 | #endif | ||
| 41 | #if HAVE_SCHED_H | 44 | #if HAVE_SCHED_H |
| 42 | #include <sched.h> | 45 | #include <sched.h> |
| 43 | #endif | 46 | #endif |
| @@ -48,7 +51,7 @@ | |||
| 48 | #include <linux/fs.h> | 51 | #include <linux/fs.h> |
| 49 | #endif | 52 | #endif |
| 50 | 53 | ||
| 51 | #define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE) && defined(CLONE_NEWNS) | 54 | #define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE) && defined(CLONE_NEWNS) && defined(SYS_pivot_root) |
| 52 | 55 | ||
| 53 | #if CHROOT_ENABLED | 56 | #if CHROOT_ENABLED |
| 54 | #include <sys/socket.h> | 57 | #include <sys/socket.h> |
| @@ -414,19 +417,6 @@ static void commonChildInit(Pipe & logPipe) | |||
| 414 | close(fdDevNull); | 417 | close(fdDevNull); |
| 415 | } | 418 | } |
| 416 | 419 | ||
| 417 | |||
| 418 | /* Convert a string list to an array of char pointers. Careful: the | ||
| 419 | string list should outlive the array. */ | ||
| 420 | const char * * strings2CharPtrs(const Strings & ss) | ||
| 421 | { | ||
| 422 | const char * * arr = new const char * [ss.size() + 1]; | ||
| 423 | const char * * p = arr; | ||
| 424 | foreach (Strings::const_iterator, i, ss) *p++ = i->c_str(); | ||
| 425 | *p = 0; | ||
| 426 | return arr; | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 430 | /* Restore default handling of SIGPIPE, otherwise some programs will | 420 | /* Restore default handling of SIGPIPE, otherwise some programs will |
| 431 | randomly say "Broken pipe". */ | 421 | randomly say "Broken pipe". */ |
| 432 | static void restoreSIGPIPE() | 422 | static void restoreSIGPIPE() |
| @@ -764,7 +754,7 @@ private: | |||
| 764 | typedef void (DerivationGoal::*GoalState)(); | 754 | typedef void (DerivationGoal::*GoalState)(); |
| 765 | GoalState state; | 755 | GoalState state; |
| 766 | 756 | ||
| 767 | /* Stuff we need to pass to initChild(). */ | 757 | /* Stuff we need to pass to runChild(). */ |
| 768 | typedef map<Path, Path> DirsInChroot; // maps target path to source path | 758 | typedef map<Path, Path> DirsInChroot; // maps target path to source path |
| 769 | DirsInChroot dirsInChroot; | 759 | DirsInChroot dirsInChroot; |
| 770 | typedef map<string, string> Environment; | 760 | typedef map<string, string> Environment; |
| @@ -828,8 +818,8 @@ private: | |||
| 828 | /* Start building a derivation. */ | 818 | /* Start building a derivation. */ |
| 829 | void startBuilder(); | 819 | void startBuilder(); |
| 830 | 820 | ||
| 831 | /* Initialise the builder's process. */ | 821 | /* Run the builder's process. */ |
| 832 | void initChild(); | 822 | void runChild(); |
| 833 | 823 | ||
| 834 | friend int childEntry(void *); | 824 | friend int childEntry(void *); |
| 835 | 825 | ||
| @@ -1612,7 +1602,7 @@ void chmod_(const Path & path, mode_t mode) | |||
| 1612 | 1602 | ||
| 1613 | int childEntry(void * arg) | 1603 | int childEntry(void * arg) |
| 1614 | { | 1604 | { |
| 1615 | ((DerivationGoal *) arg)->initChild(); | 1605 | ((DerivationGoal *) arg)->runChild(); |
| 1616 | return 1; | 1606 | return 1; |
| 1617 | } | 1607 | } |
| 1618 | 1608 | ||
| @@ -1759,37 +1749,11 @@ void DerivationGoal::startBuilder() | |||
| 1759 | 1749 | ||
| 1760 | /* Change ownership of the temporary build directory. */ | 1750 | /* Change ownership of the temporary build directory. */ |
| 1761 | if (chown(tmpDir.c_str(), buildUser.getUID(), buildUser.getGID()) == -1) | 1751 | if (chown(tmpDir.c_str(), buildUser.getUID(), buildUser.getGID()) == -1) |
| 1762 | throw SysError(format("cannot change ownership of `%1%'") % tmpDir); | 1752 | throw SysError(format("cannot change ownership of '%1%'") % tmpDir); |
| 1753 | } | ||
| 1763 | 1754 | ||
| 1764 | /* Check that the Nix store has the appropriate permissions, | ||
| 1765 | i.e., owned by root and mode 1775 (sticky bit on so that | ||
| 1766 | the builder can create its output but not mess with the | ||
| 1767 | outputs of other processes). */ | ||
| 1768 | struct stat st; | ||
| 1769 | if (stat(settings.nixStore.c_str(), &st) == -1) | ||
| 1770 | throw SysError(format("cannot stat `%1%'") % settings.nixStore); | ||
| 1771 | if (!(st.st_mode & S_ISVTX) || | ||
| 1772 | ((st.st_mode & S_IRWXG) != S_IRWXG) || | ||
| 1773 | (st.st_gid != buildUser.getGID())) | ||
| 1774 | throw Error(format( | ||
| 1775 | "builder does not have write permission to `%2%'; " | ||
| 1776 | "try `chgrp %1% %2%; chmod 1775 %2%'") | ||
| 1777 | % buildUser.getGID() % settings.nixStore); | ||
| 1778 | } | ||
| 1779 | |||
| 1780 | |||
| 1781 | /* Are we doing a chroot build? Note that fixed-output | ||
| 1782 | derivations are never done in a chroot, mainly so that | ||
| 1783 | functions like fetchurl (which needs a proper /etc/resolv.conf) | ||
| 1784 | work properly. Purity checking for fixed-output derivations | ||
| 1785 | is somewhat pointless anyway. */ | ||
| 1786 | useChroot = settings.useChroot; | 1755 | useChroot = settings.useChroot; |
| 1787 | 1756 | ||
| 1788 | if (fixedOutput) useChroot = false; | ||
| 1789 | |||
| 1790 | /* Hack to allow derivations to disable chroot builds. */ | ||
| 1791 | if (get(drv.env, "__noChroot") == "1") useChroot = false; | ||
| 1792 | |||
| 1793 | if (useChroot) { | 1757 | if (useChroot) { |
| 1794 | #if CHROOT_ENABLED | 1758 | #if CHROOT_ENABLED |
| 1795 | /* Create a temporary directory in which we set up the chroot | 1759 | /* Create a temporary directory in which we set up the chroot |
| @@ -1804,6 +1768,12 @@ void DerivationGoal::startBuilder() | |||
| 1804 | 1768 | ||
| 1805 | printMsg(lvlChatty, format("setting up chroot environment in `%1%'") % chrootRootDir); | 1769 | printMsg(lvlChatty, format("setting up chroot environment in `%1%'") % chrootRootDir); |
| 1806 | 1770 | ||
| 1771 | if (mkdir(chrootRootDir.c_str(), 0750) == -1) | ||
| 1772 | throw SysError(format("cannot create ‘%1%’") % chrootRootDir); | ||
| 1773 | |||
| 1774 | if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1) | ||
| 1775 | throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir); | ||
| 1776 | |||
| 1807 | /* Create a writable /tmp in the chroot. Many builders need | 1777 | /* Create a writable /tmp in the chroot. Many builders need |
| 1808 | this. (Of course they should really respect $TMPDIR | 1778 | this. (Of course they should really respect $TMPDIR |
| 1809 | instead.) */ | 1779 | instead.) */ |
| @@ -1830,7 +1800,8 @@ void DerivationGoal::startBuilder() | |||
| 1830 | % (buildUser.enabled() ? buildUser.getGID() : getgid())).str()); | 1800 | % (buildUser.enabled() ? buildUser.getGID() : getgid())).str()); |
| 1831 | 1801 | ||
| 1832 | /* Create /etc/hosts with localhost entry. */ | 1802 | /* Create /etc/hosts with localhost entry. */ |
| 1833 | writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n"); | 1803 | if (!fixedOutput) |
| 1804 | writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n"); | ||
| 1834 | 1805 | ||
| 1835 | /* Bind-mount a user-configurable set of directories from the | 1806 | /* Bind-mount a user-configurable set of directories from the |
| 1836 | host file system. */ | 1807 | host file system. */ |
| @@ -1853,8 +1824,12 @@ void DerivationGoal::startBuilder() | |||
| 1853 | can be bind-mounted). !!! As an extra security | 1824 | can be bind-mounted). !!! As an extra security |
| 1854 | precaution, make the fake Nix store only writable by the | 1825 | precaution, make the fake Nix store only writable by the |
| 1855 | build user. */ | 1826 | build user. */ |
| 1856 | createDirs(chrootRootDir + settings.nixStore); | 1827 | Path chrootStoreDir = chrootRootDir + settings.nixStore; |
| 1857 | chmod_(chrootRootDir + settings.nixStore, 01777); | 1828 | createDirs(chrootStoreDir); |
| 1829 | chmod_(chrootStoreDir, 01775); | ||
| 1830 | |||
| 1831 | if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1) | ||
| 1832 | throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir); | ||
| 1858 | 1833 | ||
| 1859 | foreach (PathSet::iterator, i, inputPaths) { | 1834 | foreach (PathSet::iterator, i, inputPaths) { |
| 1860 | struct stat st; | 1835 | struct stat st; |
| @@ -1963,14 +1938,17 @@ void DerivationGoal::startBuilder() | |||
| 1963 | */ | 1938 | */ |
| 1964 | #if CHROOT_ENABLED | 1939 | #if CHROOT_ENABLED |
| 1965 | if (useChroot) { | 1940 | if (useChroot) { |
| 1966 | char stack[32 * 1024]; | 1941 | char stack[32 * 1024]; |
| 1967 | pid = clone(childEntry, stack + sizeof(stack) - 8, | 1942 | int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD; |
| 1968 | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD, this); | 1943 | if (!fixedOutput) flags |= CLONE_NEWNET; |
| 1944 | pid = clone(childEntry, stack + sizeof(stack) - 8, flags, this); | ||
| 1945 | if (pid == -1) | ||
| 1946 | throw SysError("cloning builder process"); | ||
| 1969 | } else | 1947 | } else |
| 1970 | #endif | 1948 | #endif |
| 1971 | { | 1949 | { |
| 1972 | pid = fork(); | 1950 | pid = fork(); |
| 1973 | if (pid == 0) initChild(); | 1951 | if (pid == 0) runChild(); |
| 1974 | } | 1952 | } |
| 1975 | 1953 | ||
| 1976 | if (pid == -1) throw SysError("unable to fork"); | 1954 | if (pid == -1) throw SysError("unable to fork"); |
| @@ -1993,7 +1971,7 @@ void DerivationGoal::startBuilder() | |||
| 1993 | } | 1971 | } |
| 1994 | 1972 | ||
| 1995 | 1973 | ||
| 1996 | void DerivationGoal::initChild() | 1974 | void DerivationGoal::runChild() |
| 1997 | { | 1975 | { |
| 1998 | /* Warning: in the child we should absolutely not make any SQLite | 1976 | /* Warning: in the child we should absolutely not make any SQLite |
| 1999 | calls! */ | 1977 | calls! */ |
| @@ -2022,9 +2000,11 @@ void DerivationGoal::initChild() | |||
| 2022 | 2000 | ||
| 2023 | /* Set the hostname etc. to fixed values. */ | 2001 | /* Set the hostname etc. to fixed values. */ |
| 2024 | char hostname[] = "localhost"; | 2002 | char hostname[] = "localhost"; |
| 2025 | sethostname(hostname, sizeof(hostname)); | 2003 | if (sethostname(hostname, sizeof(hostname)) == -1) |
| 2004 | throw SysError("cannot set host name"); | ||
| 2026 | char domainname[] = "(none)"; // kernel default | 2005 | char domainname[] = "(none)"; // kernel default |
| 2027 | setdomainname(domainname, sizeof(domainname)); | 2006 | if (setdomainname(domainname, sizeof(domainname)) == -1) |
| 2007 | throw SysError("cannot set domain name"); | ||
| 2028 | 2008 | ||
| 2029 | /* Make all filesystems private. This is necessary | 2009 | /* Make all filesystems private. This is necessary |
| 2030 | because subtrees may have been mounted as "shared" | 2010 | because subtrees may have been mounted as "shared" |
| @@ -2042,12 +2022,17 @@ void DerivationGoal::initChild() | |||
| 2042 | throw SysError(format("unable to make filesystem `%1%' private") % fs); | 2022 | throw SysError(format("unable to make filesystem `%1%' private") % fs); |
| 2043 | } | 2023 | } |
| 2044 | 2024 | ||
| 2025 | /* Bind-mount chroot directory to itself, to treat it as a | ||
| 2026 | different filesystem from /, as needed for pivot_root. */ | ||
| 2027 | if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, MS_BIND, 0) == -1) | ||
| 2028 | throw SysError(format("unable to bind mount ‘%1%’") % chrootRootDir); | ||
| 2029 | |||
| 2045 | /* Set up a nearly empty /dev, unless the user asked to | 2030 | /* Set up a nearly empty /dev, unless the user asked to |
| 2046 | bind-mount the host /dev. */ | 2031 | bind-mount the host /dev. */ |
| 2032 | Strings ss; | ||
| 2047 | if (dirsInChroot.find("/dev") == dirsInChroot.end()) { | 2033 | if (dirsInChroot.find("/dev") == dirsInChroot.end()) { |
| 2048 | createDirs(chrootRootDir + "/dev/shm"); | 2034 | createDirs(chrootRootDir + "/dev/shm"); |
| 2049 | createDirs(chrootRootDir + "/dev/pts"); | 2035 | createDirs(chrootRootDir + "/dev/pts"); |
| 2050 | Strings ss; | ||
| 2051 | ss.push_back("/dev/full"); | 2036 | ss.push_back("/dev/full"); |
| 2052 | #ifdef __linux__ | 2037 | #ifdef __linux__ |
| 2053 | if (pathExists("/dev/kvm")) | 2038 | if (pathExists("/dev/kvm")) |
| @@ -2058,13 +2043,24 @@ void DerivationGoal::initChild() | |||
| 2058 | ss.push_back("/dev/tty"); | 2043 | ss.push_back("/dev/tty"); |
| 2059 | ss.push_back("/dev/urandom"); | 2044 | ss.push_back("/dev/urandom"); |
| 2060 | ss.push_back("/dev/zero"); | 2045 | ss.push_back("/dev/zero"); |
| 2061 | foreach (Strings::iterator, i, ss) dirsInChroot[*i] = *i; | ||
| 2062 | createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd"); | 2046 | createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd"); |
| 2063 | createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin"); | 2047 | createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin"); |
| 2064 | createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout"); | 2048 | createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout"); |
| 2065 | createSymlink("/proc/self/fd/2", chrootRootDir + "/dev/stderr"); | 2049 | createSymlink("/proc/self/fd/2", chrootRootDir + "/dev/stderr"); |
| 2066 | } | 2050 | } |
| 2067 | 2051 | ||
| 2052 | /* Fixed-output derivations typically need to access the | ||
| 2053 | network, so give them access to /etc/resolv.conf and so | ||
| 2054 | on. */ | ||
| 2055 | if (fixedOutput) { | ||
| 2056 | ss.push_back("/etc/resolv.conf"); | ||
| 2057 | ss.push_back("/etc/nsswitch.conf"); | ||
| 2058 | ss.push_back("/etc/services"); | ||
| 2059 | ss.push_back("/etc/hosts"); | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | for (auto & i : ss) dirsInChroot[i] = i; | ||
| 2063 | |||
| 2068 | /* Bind-mount all the directories from the "host" | 2064 | /* Bind-mount all the directories from the "host" |
| 2069 | filesystem that we want in the chroot | 2065 | filesystem that we want in the chroot |
| 2070 | environment. */ | 2066 | environment. */ |
| @@ -2114,13 +2110,26 @@ void DerivationGoal::initChild() | |||
| 2114 | chmod_(chrootRootDir + "/dev/pts/ptmx", 0666); | 2110 | chmod_(chrootRootDir + "/dev/pts/ptmx", 0666); |
| 2115 | } | 2111 | } |
| 2116 | 2112 | ||
| 2117 | /* Do the chroot(). Below we do a chdir() to the | 2113 | /* Do the chroot(). */ |
| 2118 | temporary build directory to make sure the current | 2114 | if (chdir(chrootRootDir.c_str()) == -1) |
| 2119 | directory is in the chroot. (Actually the order | 2115 | throw SysError(format("cannot change directory to '%1%'") % chrootRootDir); |
| 2120 | doesn't matter, since due to the bind mount tmpDir and | 2116 | |
| 2121 | tmpRootDit/tmpDir are the same directories.) */ | 2117 | if (mkdir("real-root", 0) == -1) |
| 2122 | if (chroot(chrootRootDir.c_str()) == -1) | 2118 | throw SysError("cannot create real-root directory"); |
| 2123 | throw SysError(format("cannot change root directory to `%1%'") % chrootRootDir); | 2119 | |
| 2120 | #define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old)) | ||
| 2121 | if (pivot_root(".", "real-root") == -1) | ||
| 2122 | throw SysError(format("cannot pivot old root directory onto '%1%'") % (chrootRootDir + "/real-root")); | ||
| 2123 | #undef pivot_root | ||
| 2124 | |||
| 2125 | if (chroot(".") == -1) | ||
| 2126 | throw SysError(format("cannot change root directory to '%1%'") % chrootRootDir); | ||
| 2127 | |||
| 2128 | if (umount2("real-root", MNT_DETACH) == -1) | ||
| 2129 | throw SysError("cannot unmount real root filesystem"); | ||
| 2130 | |||
| 2131 | if (rmdir("real-root") == -1) | ||
| 2132 | throw SysError("cannot remove real-root directory"); | ||
| 2124 | } | 2133 | } |
| 2125 | #endif | 2134 | #endif |
| 2126 | 2135 | ||
| @@ -2159,11 +2168,7 @@ void DerivationGoal::initChild() | |||
| 2159 | Strings envStrs; | 2168 | Strings envStrs; |
| 2160 | foreach (Environment::const_iterator, i, env) | 2169 | foreach (Environment::const_iterator, i, env) |
| 2161 | envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp)); | 2170 | envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp)); |
| 2162 | const char * * envArr = strings2CharPtrs(envStrs); | 2171 | auto envArr = stringsToCharPtrs(envStrs); |
| 2163 | |||
| 2164 | Path program = drv.builder.c_str(); | ||
| 2165 | std::vector<const char *> args; /* careful with c_str()! */ | ||
| 2166 | string user; /* must be here for its c_str()! */ | ||
| 2167 | 2172 | ||
| 2168 | /* If we are running in `build-users' mode, then switch to the | 2173 | /* If we are running in `build-users' mode, then switch to the |
| 2169 | user we allocated above. Make sure that we drop all root | 2174 | user we allocated above. Make sure that we drop all root |
| @@ -2189,29 +2194,25 @@ void DerivationGoal::initChild() | |||
| 2189 | } | 2194 | } |
| 2190 | 2195 | ||
| 2191 | /* Fill in the arguments. */ | 2196 | /* Fill in the arguments. */ |
| 2197 | Strings args; | ||
| 2192 | string builderBasename = baseNameOf(drv.builder); | 2198 | string builderBasename = baseNameOf(drv.builder); |
| 2193 | args.push_back(builderBasename.c_str()); | 2199 | args.push_back(builderBasename); |
| 2194 | foreach (Strings::iterator, i, drv.args) { | 2200 | foreach (Strings::iterator, i, drv.args) |
| 2195 | auto re = rewriteHashes(*i, rewritesToTmp); | 2201 | args.push_back(rewriteHashes(*i, rewritesToTmp)); |
| 2196 | auto cstr = new char[re.length()+1]; | 2202 | auto argArr = stringsToCharPtrs(args); |
| 2197 | std::strcpy(cstr, re.c_str()); | ||
| 2198 | |||
| 2199 | args.push_back(cstr); | ||
| 2200 | } | ||
| 2201 | args.push_back(0); | ||
| 2202 | 2203 | ||
| 2203 | restoreSIGPIPE(); | 2204 | restoreSIGPIPE(); |
| 2204 | 2205 | ||
| 2205 | /* Indicate that we managed to set up the build environment. */ | 2206 | /* Indicate that we managed to set up the build environment. */ |
| 2206 | writeToStderr("\n"); | 2207 | writeFull(STDERR_FILENO, "\n"); |
| 2207 | 2208 | ||
| 2208 | /* Execute the program. This should not return. */ | 2209 | /* Execute the program. This should not return. */ |
| 2209 | execve(program.c_str(), (char * *) &args[0], (char * *) envArr); | 2210 | execve(drv.builder.c_str(), (char * *) &argArr[0], (char * *) &envArr[0]); |
| 2210 | 2211 | ||
| 2211 | throw SysError(format("executing `%1%'") % drv.builder); | 2212 | throw SysError(format("executing `%1%'") % drv.builder); |
| 2212 | 2213 | ||
| 2213 | } catch (std::exception & e) { | 2214 | } catch (std::exception & e) { |
| 2214 | writeToStderr("while setting up the build environment: " + string(e.what()) + "\n"); | 2215 | writeFull(STDERR_FILENO, "while setting up the build environment: " + string(e.what()) + "\n"); |
| 2215 | _exit(1); | 2216 | _exit(1); |
| 2216 | } | 2217 | } |
| 2217 | 2218 | ||
| @@ -2526,7 +2527,7 @@ void DerivationGoal::handleChildOutput(int fd, const string & data) | |||
| 2526 | BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size()); | 2527 | BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size()); |
| 2527 | if (err != BZ_OK) throw Error(format("cannot write to compressed log file (BZip2 error = %1%)") % err); | 2528 | if (err != BZ_OK) throw Error(format("cannot write to compressed log file (BZip2 error = %1%)") % err); |
| 2528 | } else if (fdLogFile != -1) | 2529 | } else if (fdLogFile != -1) |
| 2529 | writeFull(fdLogFile, (unsigned char *) data.data(), data.size()); | 2530 | writeFull(fdLogFile, data); |
| 2530 | } | 2531 | } |
| 2531 | 2532 | ||
| 2532 | if (hook && fd == hook->fromHook.readSide) | 2533 | if (hook && fd == hook->fromHook.readSide) |
| @@ -2836,7 +2837,7 @@ void SubstitutionGoal::tryToRun() | |||
| 2836 | args.push_back("--substitute"); | 2837 | args.push_back("--substitute"); |
| 2837 | args.push_back(storePath); | 2838 | args.push_back(storePath); |
| 2838 | args.push_back(destPath); | 2839 | args.push_back(destPath); |
| 2839 | const char * * argArr = strings2CharPtrs(args); | 2840 | auto argArr = stringsToCharPtrs(args); |
| 2840 | 2841 | ||
| 2841 | /* Fork the substitute program. */ | 2842 | /* Fork the substitute program. */ |
| 2842 | pid = startProcess([&]() { | 2843 | pid = startProcess([&]() { |
| @@ -2846,7 +2847,7 @@ void SubstitutionGoal::tryToRun() | |||
| 2846 | if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1) | 2847 | if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1) |
| 2847 | throw SysError("cannot dup output pipe into stdout"); | 2848 | throw SysError("cannot dup output pipe into stdout"); |
| 2848 | 2849 | ||
| 2849 | execv(sub.c_str(), (char * *) argArr); | 2850 | execv(sub.c_str(), (char * *) &argArr[0]); |
| 2850 | 2851 | ||
| 2851 | throw SysError(format("executing `%1%'") % sub); | 2852 | throw SysError(format("executing `%1%'") % sub); |
| 2852 | }); | 2853 | }); |
diff --git a/nix/libstore/gc.cc b/nix/libstore/gc.cc index f98e02c1e21..34768324c26 100644 --- a/nix/libstore/gc.cc +++ b/nix/libstore/gc.cc | |||
| @@ -96,7 +96,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, | |||
| 96 | "(are you running nix-build inside the store?)") % gcRoot); | 96 | "(are you running nix-build inside the store?)") % gcRoot); |
| 97 | 97 | ||
| 98 | if (indirect) { | 98 | if (indirect) { |
| 99 | /* Don't clobber the the link if it already exists and doesn't | 99 | /* Don't clobber the link if it already exists and doesn't |
| 100 | point to the Nix store. */ | 100 | point to the Nix store. */ |
| 101 | if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) | 101 | if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) |
| 102 | throw Error(format("cannot create symlink `%1%'; already exists") % gcRoot); | 102 | throw Error(format("cannot create symlink `%1%'; already exists") % gcRoot); |
| @@ -191,7 +191,7 @@ void LocalStore::addTempRoot(const Path & path) | |||
| 191 | lockFile(fdTempRoots, ltWrite, true); | 191 | lockFile(fdTempRoots, ltWrite, true); |
| 192 | 192 | ||
| 193 | string s = path + '\0'; | 193 | string s = path + '\0'; |
| 194 | writeFull(fdTempRoots, (const unsigned char *) s.data(), s.size()); | 194 | writeFull(fdTempRoots, s); |
| 195 | 195 | ||
| 196 | /* Downgrade to a read lock. */ | 196 | /* Downgrade to a read lock. */ |
| 197 | debug(format("downgrading to read lock on `%1%'") % fnTempRoots); | 197 | debug(format("downgrading to read lock on `%1%'") % fnTempRoots); |
| @@ -231,7 +231,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds) | |||
| 231 | if (lockFile(*fd, ltWrite, false)) { | 231 | if (lockFile(*fd, ltWrite, false)) { |
| 232 | printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path); | 232 | printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path); |
| 233 | unlink(path.c_str()); | 233 | unlink(path.c_str()); |
| 234 | writeFull(*fd, (const unsigned char *) "d", 1); | 234 | writeFull(*fd, "d"); |
| 235 | continue; | 235 | continue; |
| 236 | } | 236 | } |
| 237 | 237 | ||
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc index a115f658475..630cb80c413 100644 --- a/nix/libstore/local-store.cc +++ b/nix/libstore/local-store.cc | |||
| @@ -254,22 +254,25 @@ LocalStore::LocalStore(bool reserveSpace) | |||
| 254 | Path perUserDir = profilesDir + "/per-user"; | 254 | Path perUserDir = profilesDir + "/per-user"; |
| 255 | createDirs(perUserDir); | 255 | createDirs(perUserDir); |
| 256 | if (chmod(perUserDir.c_str(), 01777) == -1) | 256 | if (chmod(perUserDir.c_str(), 01777) == -1) |
| 257 | throw SysError(format("could not set permissions on `%1%' to 1777") % perUserDir); | 257 | throw SysError(format("could not set permissions on '%1%' to 1777") % perUserDir); |
| 258 | |||
| 259 | mode_t perm = 01775; | ||
| 258 | 260 | ||
| 259 | struct group * gr = getgrnam(settings.buildUsersGroup.c_str()); | 261 | struct group * gr = getgrnam(settings.buildUsersGroup.c_str()); |
| 260 | if (!gr) | 262 | if (!gr) |
| 261 | throw Error(format("the group `%1%' specified in `build-users-group' does not exist") | 263 | throw Error(format("the group `%1%' specified in `build-users-group' does not exist") |
| 262 | % settings.buildUsersGroup); | 264 | % settings.buildUsersGroup); |
| 263 | 265 | else { | |
| 264 | struct stat st; | 266 | struct stat st; |
| 265 | if (stat(settings.nixStore.c_str(), &st)) | 267 | if (stat(settings.nixStore.c_str(), &st)) |
| 266 | throw SysError(format("getting attributes of path `%1%'") % settings.nixStore); | 268 | throw SysError(format("getting attributes of path '%1%'") % settings.nixStore); |
| 267 | 269 | ||
| 268 | if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != 01775) { | 270 | if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) { |
| 269 | if (chown(settings.nixStore.c_str(), 0, gr->gr_gid) == -1) | 271 | if (chown(settings.nixStore.c_str(), 0, gr->gr_gid) == -1) |
| 270 | throw SysError(format("changing ownership of path `%1%'") % settings.nixStore); | 272 | throw SysError(format("changing ownership of path '%1%'") % settings.nixStore); |
| 271 | if (chmod(settings.nixStore.c_str(), 01775) == -1) | 273 | if (chmod(settings.nixStore.c_str(), perm) == -1) |
| 272 | throw SysError(format("changing permissions on path `%1%'") % settings.nixStore); | 274 | throw SysError(format("changing permissions on path '%1%'") % settings.nixStore); |
| 275 | } | ||
| 273 | } | 276 | } |
| 274 | } | 277 | } |
| 275 | 278 | ||
| @@ -499,7 +502,7 @@ void LocalStore::makeStoreWritable() | |||
| 499 | if (unshare(CLONE_NEWNS) == -1) | 502 | if (unshare(CLONE_NEWNS) == -1) |
| 500 | throw SysError("setting up a private mount namespace"); | 503 | throw SysError("setting up a private mount namespace"); |
| 501 | 504 | ||
| 502 | if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1) | 505 | if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1) |
| 503 | throw SysError(format("remounting %1% writable") % settings.nixStore); | 506 | throw SysError(format("remounting %1% writable") % settings.nixStore); |
| 504 | } | 507 | } |
| 505 | #endif | 508 | #endif |
| @@ -1404,7 +1407,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name, | |||
| 1404 | } | 1407 | } |
| 1405 | 1408 | ||
| 1406 | 1409 | ||
| 1407 | Path LocalStore::addToStore(const Path & _srcPath, | 1410 | Path LocalStore::addToStore(const string & name, const Path & _srcPath, |
| 1408 | bool recursive, HashType hashAlgo, PathFilter & filter, bool repair) | 1411 | bool recursive, HashType hashAlgo, PathFilter & filter, bool repair) |
| 1409 | { | 1412 | { |
| 1410 | Path srcPath(absPath(_srcPath)); | 1413 | Path srcPath(absPath(_srcPath)); |
| @@ -1419,7 +1422,7 @@ Path LocalStore::addToStore(const Path & _srcPath, | |||
| 1419 | else | 1422 | else |
| 1420 | sink.s = readFile(srcPath); | 1423 | sink.s = readFile(srcPath); |
| 1421 | 1424 | ||
| 1422 | return addToStoreFromDump(sink.s, baseNameOf(srcPath), recursive, hashAlgo, repair); | 1425 | return addToStoreFromDump(sink.s, name, recursive, hashAlgo, repair); |
| 1423 | } | 1426 | } |
| 1424 | 1427 | ||
| 1425 | 1428 | ||
diff --git a/nix/libstore/local-store.hh b/nix/libstore/local-store.hh index e0aabdba420..819f59327a2 100644 --- a/nix/libstore/local-store.hh +++ b/nix/libstore/local-store.hh | |||
| @@ -130,7 +130,7 @@ public: | |||
| 130 | void querySubstitutablePathInfos(const PathSet & paths, | 130 | void querySubstitutablePathInfos(const PathSet & paths, |
| 131 | SubstitutablePathInfos & infos); | 131 | SubstitutablePathInfos & infos); |
| 132 | 132 | ||
| 133 | Path addToStore(const Path & srcPath, | 133 | Path addToStore(const string & name, const Path & srcPath, |
| 134 | bool recursive = true, HashType hashAlgo = htSHA256, | 134 | bool recursive = true, HashType hashAlgo = htSHA256, |
| 135 | PathFilter & filter = defaultPathFilter, bool repair = false); | 135 | PathFilter & filter = defaultPathFilter, bool repair = false); |
| 136 | 136 | ||
diff --git a/nix/libstore/optimise-store.cc b/nix/libstore/optimise-store.cc index 8ba9d1a2637..c62b8e451b4 100644 --- a/nix/libstore/optimise-store.cc +++ b/nix/libstore/optimise-store.cc | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include "local-store.hh" | 4 | #include "local-store.hh" |
| 5 | #include "globals.hh" | 5 | #include "globals.hh" |
| 6 | 6 | ||
| 7 | #include <cstdlib> | ||
| 7 | #include <sys/types.h> | 8 | #include <sys/types.h> |
| 8 | #include <sys/stat.h> | 9 | #include <sys/stat.h> |
| 9 | #include <unistd.h> | 10 | #include <unistd.h> |
diff --git a/nix/libstore/pathlocks.cc b/nix/libstore/pathlocks.cc index b858ed238de..830858ff8d9 100644 --- a/nix/libstore/pathlocks.cc +++ b/nix/libstore/pathlocks.cc | |||
| @@ -33,7 +33,7 @@ void deleteLockFile(const Path & path, int fd) | |||
| 33 | other processes waiting on this lock that the lock is stale | 33 | other processes waiting on this lock that the lock is stale |
| 34 | (deleted). */ | 34 | (deleted). */ |
| 35 | unlink(path.c_str()); | 35 | unlink(path.c_str()); |
| 36 | writeFull(fd, (const unsigned char *) "d", 1); | 36 | writeFull(fd, "d"); |
| 37 | /* Note that the result of unlink() is ignored; removing the lock | 37 | /* Note that the result of unlink() is ignored; removing the lock |
| 38 | file is an optimisation, not a necessity. */ | 38 | file is an optimisation, not a necessity. */ |
| 39 | } | 39 | } |
diff --git a/nix/libstore/remote-store.cc b/nix/libstore/remote-store.cc index 448d9b6bc1d..0539bbe1270 100644 --- a/nix/libstore/remote-store.cc +++ b/nix/libstore/remote-store.cc | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <sys/stat.h> | 10 | #include <sys/stat.h> |
| 11 | #include <sys/socket.h> | 11 | #include <sys/socket.h> |
| 12 | #include <sys/un.h> | 12 | #include <sys/un.h> |
| 13 | #include <errno.h> | ||
| 13 | #include <fcntl.h> | 14 | #include <fcntl.h> |
| 14 | 15 | ||
| 15 | #include <iostream> | 16 | #include <iostream> |
| @@ -109,7 +110,7 @@ void RemoteStore::connectToDaemon() | |||
| 109 | applications... */ | 110 | applications... */ |
| 110 | AutoCloseFD fdPrevDir = open(".", O_RDONLY); | 111 | AutoCloseFD fdPrevDir = open(".", O_RDONLY); |
| 111 | if (fdPrevDir == -1) throw SysError("couldn't open current directory"); | 112 | if (fdPrevDir == -1) throw SysError("couldn't open current directory"); |
| 112 | chdir(dirOf(socketPath).c_str()); | 113 | if (chdir(dirOf(socketPath).c_str()) == -1) throw SysError(format("couldn't change to directory of ‘%1%’") % socketPath); |
| 113 | Path socketPathRel = "./" + baseNameOf(socketPath); | 114 | Path socketPathRel = "./" + baseNameOf(socketPath); |
| 114 | 115 | ||
| 115 | struct sockaddr_un addr; | 116 | struct sockaddr_un addr; |
| @@ -384,7 +385,7 @@ Path RemoteStore::queryPathFromHashPart(const string & hashPart) | |||
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | 387 | ||
| 387 | Path RemoteStore::addToStore(const Path & _srcPath, | 388 | Path RemoteStore::addToStore(const string & name, const Path & _srcPath, |
| 388 | bool recursive, HashType hashAlgo, PathFilter & filter, bool repair) | 389 | bool recursive, HashType hashAlgo, PathFilter & filter, bool repair) |
| 389 | { | 390 | { |
| 390 | if (repair) throw Error("repairing is not supported when building through the Nix daemon"); | 391 | if (repair) throw Error("repairing is not supported when building through the Nix daemon"); |
| @@ -394,7 +395,7 @@ Path RemoteStore::addToStore(const Path & _srcPath, | |||
| 394 | Path srcPath(absPath(_srcPath)); | 395 | Path srcPath(absPath(_srcPath)); |
| 395 | 396 | ||
| 396 | writeInt(wopAddToStore, to); | 397 | writeInt(wopAddToStore, to); |
| 397 | writeString(baseNameOf(srcPath), to); | 398 | writeString(name, to); |
| 398 | /* backwards compatibility hack */ | 399 | /* backwards compatibility hack */ |
| 399 | writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to); | 400 | writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to); |
| 400 | writeInt(recursive ? 1 : 0, to); | 401 | writeInt(recursive ? 1 : 0, to); |
| @@ -584,6 +585,16 @@ void RemoteStore::optimiseStore() | |||
| 584 | readInt(from); | 585 | readInt(from); |
| 585 | } | 586 | } |
| 586 | 587 | ||
| 588 | bool RemoteStore::verifyStore(bool checkContents, bool repair) | ||
| 589 | { | ||
| 590 | openConnection(); | ||
| 591 | writeInt(wopVerifyStore, to); | ||
| 592 | writeInt(checkContents, to); | ||
| 593 | writeInt(repair, to); | ||
| 594 | processStderr(); | ||
| 595 | return readInt(from) != 0; | ||
| 596 | } | ||
| 597 | |||
| 587 | void RemoteStore::processStderr(Sink * sink, Source * source) | 598 | void RemoteStore::processStderr(Sink * sink, Source * source) |
| 588 | { | 599 | { |
| 589 | to.flush(); | 600 | to.flush(); |
diff --git a/nix/libstore/remote-store.hh b/nix/libstore/remote-store.hh index 98774c10b3d..030120db406 100644 --- a/nix/libstore/remote-store.hh +++ b/nix/libstore/remote-store.hh | |||
| @@ -21,15 +21,15 @@ public: | |||
| 21 | RemoteStore(); | 21 | RemoteStore(); |
| 22 | 22 | ||
| 23 | ~RemoteStore(); | 23 | ~RemoteStore(); |
| 24 | 24 | ||
| 25 | /* Implementations of abstract store API methods. */ | 25 | /* Implementations of abstract store API methods. */ |
| 26 | 26 | ||
| 27 | bool isValidPath(const Path & path); | 27 | bool isValidPath(const Path & path); |
| 28 | 28 | ||
| 29 | PathSet queryValidPaths(const PathSet & paths); | 29 | PathSet queryValidPaths(const PathSet & paths); |
| 30 | 30 | ||
| 31 | PathSet queryAllValidPaths(); | 31 | PathSet queryAllValidPaths(); |
| 32 | 32 | ||
| 33 | ValidPathInfo queryPathInfo(const Path & path); | 33 | ValidPathInfo queryPathInfo(const Path & path); |
| 34 | 34 | ||
| 35 | Hash queryPathHash(const Path & path); | 35 | Hash queryPathHash(const Path & path); |
| @@ -39,21 +39,21 @@ public: | |||
| 39 | void queryReferrers(const Path & path, PathSet & referrers); | 39 | void queryReferrers(const Path & path, PathSet & referrers); |
| 40 | 40 | ||
| 41 | Path queryDeriver(const Path & path); | 41 | Path queryDeriver(const Path & path); |
| 42 | 42 | ||
| 43 | PathSet queryValidDerivers(const Path & path); | 43 | PathSet queryValidDerivers(const Path & path); |
| 44 | 44 | ||
| 45 | PathSet queryDerivationOutputs(const Path & path); | 45 | PathSet queryDerivationOutputs(const Path & path); |
| 46 | 46 | ||
| 47 | StringSet queryDerivationOutputNames(const Path & path); | 47 | StringSet queryDerivationOutputNames(const Path & path); |
| 48 | 48 | ||
| 49 | Path queryPathFromHashPart(const string & hashPart); | 49 | Path queryPathFromHashPart(const string & hashPart); |
| 50 | 50 | ||
| 51 | PathSet querySubstitutablePaths(const PathSet & paths); | 51 | PathSet querySubstitutablePaths(const PathSet & paths); |
| 52 | 52 | ||
| 53 | void querySubstitutablePathInfos(const PathSet & paths, | 53 | void querySubstitutablePathInfos(const PathSet & paths, |
| 54 | SubstitutablePathInfos & infos); | 54 | SubstitutablePathInfos & infos); |
| 55 | 55 | ||
| 56 | Path addToStore(const Path & srcPath, | 56 | Path addToStore(const string & name, const Path & srcPath, |
| 57 | bool recursive = true, HashType hashAlgo = htSHA256, | 57 | bool recursive = true, HashType hashAlgo = htSHA256, |
| 58 | PathFilter & filter = defaultPathFilter, bool repair = false); | 58 | PathFilter & filter = defaultPathFilter, bool repair = false); |
| 59 | 59 | ||
| @@ -64,7 +64,7 @@ public: | |||
| 64 | Sink & sink); | 64 | Sink & sink); |
| 65 | 65 | ||
| 66 | Paths importPaths(bool requireSignature, Source & source); | 66 | Paths importPaths(bool requireSignature, Source & source); |
| 67 | 67 | ||
| 68 | void buildPaths(const PathSet & paths, BuildMode buildMode); | 68 | void buildPaths(const PathSet & paths, BuildMode buildMode); |
| 69 | 69 | ||
| 70 | void ensurePath(const Path & path); | 70 | void ensurePath(const Path & path); |
| @@ -72,19 +72,20 @@ public: | |||
| 72 | void addTempRoot(const Path & path); | 72 | void addTempRoot(const Path & path); |
| 73 | 73 | ||
| 74 | void addIndirectRoot(const Path & path); | 74 | void addIndirectRoot(const Path & path); |
| 75 | 75 | ||
| 76 | void syncWithGC(); | 76 | void syncWithGC(); |
| 77 | 77 | ||
| 78 | Roots findRoots(); | 78 | Roots findRoots(); |
| 79 | 79 | ||
| 80 | void collectGarbage(const GCOptions & options, GCResults & results); | 80 | void collectGarbage(const GCOptions & options, GCResults & results); |
| 81 | 81 | ||
| 82 | PathSet queryFailedPaths(); | 82 | PathSet queryFailedPaths(); |
| 83 | 83 | ||
| 84 | void clearFailedPaths(const PathSet & paths); | 84 | void clearFailedPaths(const PathSet & paths); |
| 85 | 85 | ||
| 86 | void optimiseStore(); | 86 | void optimiseStore(); |
| 87 | 87 | ||
| 88 | bool verifyStore(bool checkContents, bool repair); | ||
| 88 | private: | 89 | private: |
| 89 | AutoCloseFD fdSocket; | 90 | AutoCloseFD fdSocket; |
| 90 | FdSink to; | 91 | FdSink to; |
diff --git a/nix/libstore/store-api.hh b/nix/libstore/store-api.hh index 3109f100ef9..3764f3e5424 100644 --- a/nix/libstore/store-api.hh +++ b/nix/libstore/store-api.hh | |||
| @@ -54,7 +54,7 @@ struct GCOptions | |||
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | 56 | ||
| 57 | struct GCResults | 57 | struct GCResults |
| 58 | { | 58 | { |
| 59 | /* Depending on the action, the GC roots, or the paths that would | 59 | /* Depending on the action, the GC roots, or the paths that would |
| 60 | be or have been deleted. */ | 60 | be or have been deleted. */ |
| @@ -82,7 +82,7 @@ struct SubstitutablePathInfo | |||
| 82 | typedef std::map<Path, SubstitutablePathInfo> SubstitutablePathInfos; | 82 | typedef std::map<Path, SubstitutablePathInfo> SubstitutablePathInfos; |
| 83 | 83 | ||
| 84 | 84 | ||
| 85 | struct ValidPathInfo | 85 | struct ValidPathInfo |
| 86 | { | 86 | { |
| 87 | Path path; | 87 | Path path; |
| 88 | Path deriver; | 88 | Path deriver; |
| @@ -100,13 +100,13 @@ typedef list<ValidPathInfo> ValidPathInfos; | |||
| 100 | enum BuildMode { bmNormal, bmRepair, bmCheck }; | 100 | enum BuildMode { bmNormal, bmRepair, bmCheck }; |
| 101 | 101 | ||
| 102 | 102 | ||
| 103 | class StoreAPI | 103 | class StoreAPI |
| 104 | { | 104 | { |
| 105 | public: | 105 | public: |
| 106 | 106 | ||
| 107 | virtual ~StoreAPI() { } | 107 | virtual ~StoreAPI() { } |
| 108 | 108 | ||
| 109 | /* Check whether a path is valid. */ | 109 | /* Check whether a path is valid. */ |
| 110 | virtual bool isValidPath(const Path & path) = 0; | 110 | virtual bool isValidPath(const Path & path) = 0; |
| 111 | 111 | ||
| 112 | /* Query which of the given paths is valid. */ | 112 | /* Query which of the given paths is valid. */ |
| @@ -118,7 +118,7 @@ public: | |||
| 118 | /* Query information about a valid path. */ | 118 | /* Query information about a valid path. */ |
| 119 | virtual ValidPathInfo queryPathInfo(const Path & path) = 0; | 119 | virtual ValidPathInfo queryPathInfo(const Path & path) = 0; |
| 120 | 120 | ||
| 121 | /* Query the hash of a valid path. */ | 121 | /* Query the hash of a valid path. */ |
| 122 | virtual Hash queryPathHash(const Path & path) = 0; | 122 | virtual Hash queryPathHash(const Path & path) = 0; |
| 123 | 123 | ||
| 124 | /* Query the set of outgoing FS references for a store path. The | 124 | /* Query the set of outgoing FS references for a store path. The |
| @@ -150,7 +150,7 @@ public: | |||
| 150 | /* Query the full store path given the hash part of a valid store | 150 | /* Query the full store path given the hash part of a valid store |
| 151 | path, or "" if the path doesn't exist. */ | 151 | path, or "" if the path doesn't exist. */ |
| 152 | virtual Path queryPathFromHashPart(const string & hashPart) = 0; | 152 | virtual Path queryPathFromHashPart(const string & hashPart) = 0; |
| 153 | 153 | ||
| 154 | /* Query which of the given paths have substitutes. */ | 154 | /* Query which of the given paths have substitutes. */ |
| 155 | virtual PathSet querySubstitutablePaths(const PathSet & paths) = 0; | 155 | virtual PathSet querySubstitutablePaths(const PathSet & paths) = 0; |
| 156 | 156 | ||
| @@ -159,12 +159,12 @@ public: | |||
| 159 | info, it's omitted from the resulting ‘infos’ map. */ | 159 | info, it's omitted from the resulting ‘infos’ map. */ |
| 160 | virtual void querySubstitutablePathInfos(const PathSet & paths, | 160 | virtual void querySubstitutablePathInfos(const PathSet & paths, |
| 161 | SubstitutablePathInfos & infos) = 0; | 161 | SubstitutablePathInfos & infos) = 0; |
| 162 | 162 | ||
| 163 | /* Copy the contents of a path to the store and register the | 163 | /* Copy the contents of a path to the store and register the |
| 164 | validity the resulting path. The resulting path is returned. | 164 | validity the resulting path. The resulting path is returned. |
| 165 | The function object `filter' can be used to exclude files (see | 165 | The function object `filter' can be used to exclude files (see |
| 166 | libutil/archive.hh). */ | 166 | libutil/archive.hh). */ |
| 167 | virtual Path addToStore(const Path & srcPath, | 167 | virtual Path addToStore(const string & name, const Path & srcPath, |
| 168 | bool recursive = true, HashType hashAlgo = htSHA256, | 168 | bool recursive = true, HashType hashAlgo = htSHA256, |
| 169 | PathFilter & filter = defaultPathFilter, bool repair = false) = 0; | 169 | PathFilter & filter = defaultPathFilter, bool repair = false) = 0; |
| 170 | 170 | ||
| @@ -254,6 +254,10 @@ public: | |||
| 254 | /* Optimise the disk space usage of the Nix store by hard-linking files | 254 | /* Optimise the disk space usage of the Nix store by hard-linking files |
| 255 | with the same contents. */ | 255 | with the same contents. */ |
| 256 | virtual void optimiseStore() = 0; | 256 | virtual void optimiseStore() = 0; |
| 257 | |||
| 258 | /* Check the integrity of the Nix store. Returns true if errors | ||
| 259 | remain. */ | ||
| 260 | virtual bool verifyStore(bool checkContents, bool repair) = 0; | ||
| 257 | }; | 261 | }; |
| 258 | 262 | ||
| 259 | 263 | ||
| @@ -267,7 +271,7 @@ bool isStorePath(const Path & path); | |||
| 267 | 271 | ||
| 268 | /* Extract the name part of the given store path. */ | 272 | /* Extract the name part of the given store path. */ |
| 269 | string storePathToName(const Path & path); | 273 | string storePathToName(const Path & path); |
| 270 | 274 | ||
| 271 | void checkStoreName(const string & name); | 275 | void checkStoreName(const string & name); |
| 272 | 276 | ||
| 273 | 277 | ||
| @@ -288,7 +292,7 @@ Path followLinksToStorePath(const Path & path); | |||
| 288 | /* Constructs a unique store path name. */ | 292 | /* Constructs a unique store path name. */ |
| 289 | Path makeStorePath(const string & type, | 293 | Path makeStorePath(const string & type, |
| 290 | const Hash & hash, const string & name); | 294 | const Hash & hash, const string & name); |
| 291 | 295 | ||
| 292 | Path makeOutputPath(const string & id, | 296 | Path makeOutputPath(const string & id, |
| 293 | const Hash & hash, const string & name); | 297 | const Hash & hash, const string & name); |
| 294 | 298 | ||
diff --git a/nix/libstore/worker-protocol.hh b/nix/libstore/worker-protocol.hh index 4b040b77ce6..d037d7402ed 100644 --- a/nix/libstore/worker-protocol.hh +++ b/nix/libstore/worker-protocol.hh | |||
| @@ -42,7 +42,8 @@ typedef enum { | |||
| 42 | wopQueryValidPaths = 31, | 42 | wopQueryValidPaths = 31, |
| 43 | wopQuerySubstitutablePaths = 32, | 43 | wopQuerySubstitutablePaths = 32, |
| 44 | wopQueryValidDerivers = 33, | 44 | wopQueryValidDerivers = 33, |
| 45 | wopOptimiseStore = 34 | 45 | wopOptimiseStore = 34, |
| 46 | wopVerifyStore = 35 | ||
| 46 | } WorkerOp; | 47 | } WorkerOp; |
| 47 | 48 | ||
| 48 | 49 | ||
diff --git a/nix/libutil/hash.cc b/nix/libutil/hash.cc index 050446610f0..2da00a53de0 100644 --- a/nix/libutil/hash.cc +++ b/nix/libutil/hash.cc | |||
| @@ -84,7 +84,7 @@ string printHash(const Hash & hash) | |||
| 84 | return string(buf, hash.hashSize * 2); | 84 | return string(buf, hash.hashSize * 2); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | 87 | ||
| 88 | Hash parseHash(HashType ht, const string & s) | 88 | Hash parseHash(HashType ht, const string & s) |
| 89 | { | 89 | { |
| 90 | Hash hash(ht); | 90 | Hash hash(ht); |
| @@ -92,7 +92,7 @@ Hash parseHash(HashType ht, const string & s) | |||
| 92 | throw Error(format("invalid hash `%1%'") % s); | 92 | throw Error(format("invalid hash `%1%'") % s); |
| 93 | for (unsigned int i = 0; i < hash.hashSize; i++) { | 93 | for (unsigned int i = 0; i < hash.hashSize; i++) { |
| 94 | string s2(s, i * 2, 2); | 94 | string s2(s, i * 2, 2); |
| 95 | if (!isxdigit(s2[0]) || !isxdigit(s2[1])) | 95 | if (!isxdigit(s2[0]) || !isxdigit(s2[1])) |
| 96 | throw Error(format("invalid hash `%1%'") % s); | 96 | throw Error(format("invalid hash `%1%'") % s); |
| 97 | std::istringstream str(s2); | 97 | std::istringstream str(s2); |
| 98 | int n; | 98 | int n; |
| @@ -103,24 +103,6 @@ Hash parseHash(HashType ht, const string & s) | |||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | 105 | ||
| 106 | static unsigned char divMod(unsigned char * bytes, unsigned char y) | ||
| 107 | { | ||
| 108 | unsigned int borrow = 0; | ||
| 109 | |||
| 110 | int pos = Hash::maxHashSize - 1; | ||
| 111 | while (pos >= 0 && !bytes[pos]) --pos; | ||
| 112 | |||
| 113 | for ( ; pos >= 0; --pos) { | ||
| 114 | unsigned int s = bytes[pos] + (borrow << 8); | ||
| 115 | unsigned int d = s / y; | ||
| 116 | borrow = s % y; | ||
| 117 | bytes[pos] = d; | ||
| 118 | } | ||
| 119 | |||
| 120 | return borrow; | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | unsigned int hashLength32(const Hash & hash) | 106 | unsigned int hashLength32(const Hash & hash) |
| 125 | { | 107 | { |
| 126 | return (hash.hashSize * 8 - 1) / 5 + 1; | 108 | return (hash.hashSize * 8 - 1) / 5 + 1; |
| @@ -136,19 +118,19 @@ string printHash32(const Hash & hash) | |||
| 136 | Hash hash2(hash); | 118 | Hash hash2(hash); |
| 137 | unsigned int len = hashLength32(hash); | 119 | unsigned int len = hashLength32(hash); |
| 138 | 120 | ||
| 139 | const char * chars = base32Chars.data(); | 121 | string s; |
| 140 | 122 | s.reserve(len); | |
| 141 | string s(len, '0'); | 123 | |
| 142 | 124 | for (int n = len - 1; n >= 0; n--) { | |
| 143 | int pos = len - 1; | 125 | unsigned int b = n * 5; |
| 144 | while (pos >= 0) { | 126 | unsigned int i = b / 8; |
| 145 | unsigned char digit = divMod(hash2.hash, 32); | 127 | unsigned int j = b % 8; |
| 146 | s[pos--] = chars[digit]; | 128 | unsigned char c = |
| 129 | (hash.hash[i] >> j) | ||
| 130 | | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j)); | ||
| 131 | s.push_back(base32Chars[c & 0x1f]); | ||
| 147 | } | 132 | } |
| 148 | 133 | ||
| 149 | for (unsigned int i = 0; i < hash2.maxHashSize; ++i) | ||
| 150 | assert(hash2.hash[i] == 0); | ||
| 151 | |||
| 152 | return s; | 134 | return s; |
| 153 | } | 135 | } |
| 154 | 136 | ||
| @@ -159,51 +141,24 @@ string printHash16or32(const Hash & hash) | |||
| 159 | } | 141 | } |
| 160 | 142 | ||
| 161 | 143 | ||
| 162 | static bool mul(unsigned char * bytes, unsigned char y, int maxSize) | ||
| 163 | { | ||
| 164 | unsigned char carry = 0; | ||
| 165 | |||
| 166 | for (int pos = 0; pos < maxSize; ++pos) { | ||
| 167 | unsigned int m = bytes[pos] * y + carry; | ||
| 168 | bytes[pos] = m & 0xff; | ||
| 169 | carry = m >> 8; | ||
| 170 | } | ||
| 171 | |||
| 172 | return carry; | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
| 176 | static bool add(unsigned char * bytes, unsigned char y, int maxSize) | ||
| 177 | { | ||
| 178 | unsigned char carry = y; | ||
| 179 | |||
| 180 | for (int pos = 0; pos < maxSize; ++pos) { | ||
| 181 | unsigned int m = bytes[pos] + carry; | ||
| 182 | bytes[pos] = m & 0xff; | ||
| 183 | carry = m >> 8; | ||
| 184 | if (carry == 0) break; | ||
| 185 | } | ||
| 186 | |||
| 187 | return carry; | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | Hash parseHash32(HashType ht, const string & s) | 144 | Hash parseHash32(HashType ht, const string & s) |
| 192 | { | 145 | { |
| 193 | Hash hash(ht); | 146 | Hash hash(ht); |
| 147 | unsigned int len = hashLength32(ht); | ||
| 148 | assert(s.size() == len); | ||
| 194 | 149 | ||
| 195 | const char * chars = base32Chars.data(); | 150 | for (unsigned int n = 0; n < len; ++n) { |
| 196 | 151 | char c = s[len - n - 1]; | |
| 197 | for (unsigned int i = 0; i < s.length(); ++i) { | ||
| 198 | char c = s[i]; | ||
| 199 | unsigned char digit; | 152 | unsigned char digit; |
| 200 | for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */ | 153 | for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */ |
| 201 | if (chars[digit] == c) break; | 154 | if (base32Chars[digit] == c) break; |
| 202 | if (digit >= 32) | 155 | if (digit >= 32) |
| 203 | throw Error(format("invalid base-32 hash `%1%'") % s); | 156 | throw Error(format("invalid base-32 hash '%1%'") % s); |
| 204 | if (mul(hash.hash, 32, hash.hashSize) || | 157 | unsigned int b = n * 5; |
| 205 | add(hash.hash, digit, hash.hashSize)) | 158 | unsigned int i = b / 8; |
| 206 | throw Error(format("base-32 hash `%1%' is too large") % s); | 159 | unsigned int j = b % 8; |
| 160 | hash.hash[i] |= digit << j; | ||
| 161 | if (i < hash.hashSize - 1) hash.hash[i + 1] |= digit >> (8 - j); | ||
| 207 | } | 162 | } |
| 208 | 163 | ||
| 209 | return hash; | 164 | return hash; |
| @@ -299,7 +254,7 @@ Hash hashFile(HashType ht, const Path & path) | |||
| 299 | if (n == -1) throw SysError(format("reading file `%1%'") % path); | 254 | if (n == -1) throw SysError(format("reading file `%1%'") % path); |
| 300 | update(ht, ctx, buf, n); | 255 | update(ht, ctx, buf, n); |
| 301 | } | 256 | } |
| 302 | 257 | ||
| 303 | finish(ht, ctx, hash.hash); | 258 | finish(ht, ctx, hash.hash); |
| 304 | return hash; | 259 | return hash; |
| 305 | } | 260 | } |
| @@ -311,7 +266,7 @@ HashSink::HashSink(HashType ht) : ht(ht) | |||
| 311 | bytes = 0; | 266 | bytes = 0; |
| 312 | start(ht, *ctx); | 267 | start(ht, *ctx); |
| 313 | } | 268 | } |
| 314 | 269 | ||
| 315 | HashSink::~HashSink() | 270 | HashSink::~HashSink() |
| 316 | { | 271 | { |
| 317 | bufPos = 0; | 272 | bufPos = 0; |
| @@ -369,7 +324,7 @@ HashType parseHashType(const string & s) | |||
| 369 | else return htUnknown; | 324 | else return htUnknown; |
| 370 | } | 325 | } |
| 371 | 326 | ||
| 372 | 327 | ||
| 373 | string printHashType(HashType ht) | 328 | string printHashType(HashType ht) |
| 374 | { | 329 | { |
| 375 | if (ht == htMD5) return "md5"; | 330 | if (ht == htMD5) return "md5"; |
| @@ -378,5 +333,5 @@ string printHashType(HashType ht) | |||
| 378 | else throw Error("cannot print unknown hash type"); | 333 | else throw Error("cannot print unknown hash type"); |
| 379 | } | 334 | } |
| 380 | 335 | ||
| 381 | 336 | ||
| 382 | } | 337 | } |
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc index a4a1ddb12a0..dab4235b04f 100644 --- a/nix/libutil/util.cc +++ b/nix/libutil/util.cc | |||
| @@ -19,6 +19,10 @@ | |||
| 19 | #include <sys/syscall.h> | 19 | #include <sys/syscall.h> |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #ifdef __linux__ | ||
| 23 | #include <sys/prctl.h> | ||
| 24 | #endif | ||
| 25 | |||
| 22 | 26 | ||
| 23 | extern char * * environ; | 27 | extern char * * environ; |
| 24 | 28 | ||
| @@ -189,8 +193,12 @@ Path readLink(const Path & path) | |||
| 189 | if (!S_ISLNK(st.st_mode)) | 193 | if (!S_ISLNK(st.st_mode)) |
| 190 | throw Error(format("`%1%' is not a symlink") % path); | 194 | throw Error(format("`%1%' is not a symlink") % path); |
| 191 | char buf[st.st_size]; | 195 | char buf[st.st_size]; |
| 192 | if (readlink(path.c_str(), buf, st.st_size) != st.st_size) | 196 | ssize_t rlsize = readlink(path.c_str(), buf, st.st_size); |
| 193 | throw SysError(format("reading symbolic link `%1%'") % path); | 197 | if (rlsize == -1) |
| 198 | throw SysError(format("reading symbolic link '%1%'") % path); | ||
| 199 | else if (rlsize > st.st_size) | ||
| 200 | throw Error(format("symbolic link ‘%1%’ size overflow %2% > %3%") | ||
| 201 | % path % rlsize % st.st_size); | ||
| 194 | return string(buf, st.st_size); | 202 | return string(buf, st.st_size); |
| 195 | } | 203 | } |
| 196 | 204 | ||
| @@ -260,8 +268,8 @@ void writeFile(const Path & path, const string & s) | |||
| 260 | { | 268 | { |
| 261 | AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666); | 269 | AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666); |
| 262 | if (fd == -1) | 270 | if (fd == -1) |
| 263 | throw SysError(format("opening file `%1%'") % path); | 271 | throw SysError(format("opening file '%1%'") % path); |
| 264 | writeFull(fd, (unsigned char *) s.data(), s.size()); | 272 | writeFull(fd, s); |
| 265 | } | 273 | } |
| 266 | 274 | ||
| 267 | 275 | ||
| @@ -288,7 +296,7 @@ string readLine(int fd) | |||
| 288 | void writeLine(int fd, string s) | 296 | void writeLine(int fd, string s) |
| 289 | { | 297 | { |
| 290 | s += '\n'; | 298 | s += '\n'; |
| 291 | writeFull(fd, (const unsigned char *) s.data(), s.size()); | 299 | writeFull(fd, s); |
| 292 | } | 300 | } |
| 293 | 301 | ||
| 294 | 302 | ||
| @@ -478,18 +486,13 @@ void warnOnce(bool & haveWarned, const FormatOrString & fs) | |||
| 478 | } | 486 | } |
| 479 | 487 | ||
| 480 | 488 | ||
| 481 | static void defaultWriteToStderr(const unsigned char * buf, size_t count) | ||
| 482 | { | ||
| 483 | writeFull(STDERR_FILENO, buf, count); | ||
| 484 | } | ||
| 485 | |||
| 486 | |||
| 487 | void writeToStderr(const string & s) | 489 | void writeToStderr(const string & s) |
| 488 | { | 490 | { |
| 489 | try { | 491 | try { |
| 490 | auto p = _writeToStderr; | 492 | if (_writeToStderr) |
| 491 | if (!p) p = defaultWriteToStderr; | 493 | _writeToStderr((const unsigned char *) s.data(), s.size()); |
| 492 | p((const unsigned char *) s.data(), s.size()); | 494 | else |
| 495 | writeFull(STDERR_FILENO, s); | ||
| 493 | } catch (SysError & e) { | 496 | } catch (SysError & e) { |
| 494 | /* Ignore failing writes to stderr if we're in an exception | 497 | /* Ignore failing writes to stderr if we're in an exception |
| 495 | handler, otherwise throw an exception. We need to ignore | 498 | handler, otherwise throw an exception. We need to ignore |
| @@ -501,7 +504,7 @@ void writeToStderr(const string & s) | |||
| 501 | } | 504 | } |
| 502 | 505 | ||
| 503 | 506 | ||
| 504 | void (*_writeToStderr) (const unsigned char * buf, size_t count) = defaultWriteToStderr; | 507 | void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0; |
| 505 | 508 | ||
| 506 | 509 | ||
| 507 | void readFull(int fd, unsigned char * buf, size_t count) | 510 | void readFull(int fd, unsigned char * buf, size_t count) |
| @@ -535,6 +538,12 @@ void writeFull(int fd, const unsigned char * buf, size_t count) | |||
| 535 | } | 538 | } |
| 536 | 539 | ||
| 537 | 540 | ||
| 541 | void writeFull(int fd, const string & s) | ||
| 542 | { | ||
| 543 | writeFull(fd, (const unsigned char *) s.data(), s.size()); | ||
| 544 | } | ||
| 545 | |||
| 546 | |||
| 538 | string drainFD(int fd) | 547 | string drainFD(int fd) |
| 539 | { | 548 | { |
| 540 | string result; | 549 | string result; |
| @@ -867,6 +876,10 @@ pid_t startProcess(std::function<void()> fun, | |||
| 867 | if (pid == 0) { | 876 | if (pid == 0) { |
| 868 | _writeToStderr = 0; | 877 | _writeToStderr = 0; |
| 869 | try { | 878 | try { |
| 879 | #if __linux__ | ||
| 880 | if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) | ||
| 881 | throw SysError("setting death signal"); | ||
| 882 | #endif | ||
| 870 | restoreAffinity(); | 883 | restoreAffinity(); |
| 871 | fun(); | 884 | fun(); |
| 872 | } catch (std::exception & e) { | 885 | } catch (std::exception & e) { |
| @@ -884,16 +897,19 @@ pid_t startProcess(std::function<void()> fun, | |||
| 884 | } | 897 | } |
| 885 | 898 | ||
| 886 | 899 | ||
| 900 | std::vector<const char *> stringsToCharPtrs(const Strings & ss) | ||
| 901 | { | ||
| 902 | std::vector<const char *> res; | ||
| 903 | for (auto & s : ss) res.push_back(s.c_str()); | ||
| 904 | res.push_back(0); | ||
| 905 | return res; | ||
| 906 | } | ||
| 907 | |||
| 908 | |||
| 887 | string runProgram(Path program, bool searchPath, const Strings & args) | 909 | string runProgram(Path program, bool searchPath, const Strings & args) |
| 888 | { | 910 | { |
| 889 | checkInterrupt(); | 911 | checkInterrupt(); |
| 890 | 912 | ||
| 891 | std::vector<const char *> cargs; /* careful with c_str()! */ | ||
| 892 | cargs.push_back(program.c_str()); | ||
| 893 | for (Strings::const_iterator i = args.begin(); i != args.end(); ++i) | ||
| 894 | cargs.push_back(i->c_str()); | ||
| 895 | cargs.push_back(0); | ||
| 896 | |||
| 897 | /* Create a pipe. */ | 913 | /* Create a pipe. */ |
| 898 | Pipe pipe; | 914 | Pipe pipe; |
| 899 | pipe.create(); | 915 | pipe.create(); |
| @@ -903,6 +919,10 @@ string runProgram(Path program, bool searchPath, const Strings & args) | |||
| 903 | if (dup2(pipe.writeSide, STDOUT_FILENO) == -1) | 919 | if (dup2(pipe.writeSide, STDOUT_FILENO) == -1) |
| 904 | throw SysError("dupping stdout"); | 920 | throw SysError("dupping stdout"); |
| 905 | 921 | ||
| 922 | Strings args_(args); | ||
| 923 | args_.push_front(program); | ||
| 924 | auto cargs = stringsToCharPtrs(args_); | ||
| 925 | |||
| 906 | if (searchPath) | 926 | if (searchPath) |
| 907 | execvp(program.c_str(), (char * *) &cargs[0]); | 927 | execvp(program.c_str(), (char * *) &cargs[0]); |
| 908 | else | 928 | else |
diff --git a/nix/libutil/util.hh b/nix/libutil/util.hh index 0ad0026711e..6a84ed88518 100644 --- a/nix/libutil/util.hh +++ b/nix/libutil/util.hh | |||
| @@ -171,6 +171,7 @@ extern void (*_writeToStderr) (const unsigned char * buf, size_t count); | |||
| 171 | requested number of bytes. */ | 171 | requested number of bytes. */ |
| 172 | void readFull(int fd, unsigned char * buf, size_t count); | 172 | void readFull(int fd, unsigned char * buf, size_t count); |
| 173 | void writeFull(int fd, const unsigned char * buf, size_t count); | 173 | void writeFull(int fd, const unsigned char * buf, size_t count); |
| 174 | void writeFull(int fd, const string & s); | ||
| 174 | 175 | ||
| 175 | MakeError(EndOfFile, Error) | 176 | MakeError(EndOfFile, Error) |
| 176 | 177 | ||
| @@ -280,6 +281,11 @@ string runProgram(Path program, bool searchPath = false, | |||
| 280 | 281 | ||
| 281 | MakeError(ExecError, Error) | 282 | MakeError(ExecError, Error) |
| 282 | 283 | ||
| 284 | /* Convert a list of strings to a null-terminated vector of char | ||
| 285 | *'s. The result must not be accessed beyond the lifetime of the | ||
| 286 | list of strings. */ | ||
| 287 | std::vector<const char *> stringsToCharPtrs(const Strings & ss); | ||
| 288 | |||
| 283 | /* Close all file descriptors except stdin, stdout, stderr, and those | 289 | /* Close all file descriptors except stdin, stdout, stderr, and those |
| 284 | listed in the given set. Good practice in child processes. */ | 290 | listed in the given set. Good practice in child processes. */ |
| 285 | void closeMostFDs(const set<int> & exceptions); | 291 | void closeMostFDs(const set<int> & exceptions); |
diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc index e42d602a3af..2b89190dbe0 100644 --- a/nix/nix-daemon/nix-daemon.cc +++ b/nix/nix-daemon/nix-daemon.cc | |||
| @@ -641,11 +641,23 @@ static void performOp(bool trusted, unsigned int clientVersion, | |||
| 641 | } | 641 | } |
| 642 | 642 | ||
| 643 | case wopOptimiseStore: | 643 | case wopOptimiseStore: |
| 644 | startWork(); | 644 | startWork(); |
| 645 | store->optimiseStore(); | 645 | store->optimiseStore(); |
| 646 | stopWork(); | 646 | stopWork(); |
| 647 | writeInt(1, to); | 647 | writeInt(1, to); |
| 648 | break; | 648 | break; |
| 649 | |||
| 650 | case wopVerifyStore: { | ||
| 651 | bool checkContents = readInt(from) != 0; | ||
| 652 | bool repair = readInt(from) != 0; | ||
| 653 | startWork(); | ||
| 654 | if (repair && !trusted) | ||
| 655 | throw Error("you are not privileged to repair paths"); | ||
| 656 | bool errors = store->verifyStore(checkContents, repair); | ||
| 657 | stopWork(); | ||
| 658 | writeInt(errors, to); | ||
| 659 | break; | ||
| 660 | } | ||
| 649 | 661 | ||
| 650 | default: | 662 | default: |
| 651 | throw Error(format("invalid operation %1%") % op); | 663 | throw Error(format("invalid operation %1%") % op); |
| @@ -743,6 +755,8 @@ static void processConnection(bool trusted) | |||
| 743 | assert(!canSendStderr); | 755 | assert(!canSendStderr); |
| 744 | }; | 756 | }; |
| 745 | 757 | ||
| 758 | canSendStderr = false; | ||
| 759 | _isInterrupted = false; | ||
| 746 | printMsg(lvlDebug, format("%1% operations") % opCount); | 760 | printMsg(lvlDebug, format("%1% operations") % opCount); |
| 747 | } | 761 | } |
| 748 | 762 | ||
| @@ -791,6 +805,9 @@ bool matchUser(const string & user, const string & group, const Strings & users) | |||
| 791 | 805 | ||
| 792 | static void daemonLoop() | 806 | static void daemonLoop() |
| 793 | { | 807 | { |
| 808 | if (chdir("/") == -1) | ||
| 809 | throw SysError("cannot change current directory"); | ||
| 810 | |||
| 794 | /* Get rid of children automatically; don't let them become | 811 | /* Get rid of children automatically; don't let them become |
| 795 | zombies. */ | 812 | zombies. */ |
| 796 | setSigChldAction(true); | 813 | setSigChldAction(true); |
| @@ -819,7 +836,8 @@ static void daemonLoop() | |||
| 819 | /* Urgh, sockaddr_un allows path names of only 108 characters. | 836 | /* Urgh, sockaddr_un allows path names of only 108 characters. |
| 820 | So chdir to the socket directory so that we can pass a | 837 | So chdir to the socket directory so that we can pass a |
| 821 | relative path name. */ | 838 | relative path name. */ |
| 822 | chdir(dirOf(socketPath).c_str()); | 839 | if (chdir(dirOf(socketPath).c_str()) == -1) |
| 840 | throw SysError("cannot change current directory"); | ||
| 823 | Path socketPathRel = "./" + baseNameOf(socketPath); | 841 | Path socketPathRel = "./" + baseNameOf(socketPath); |
| 824 | 842 | ||
| 825 | struct sockaddr_un addr; | 843 | struct sockaddr_un addr; |
| @@ -839,7 +857,8 @@ static void daemonLoop() | |||
| 839 | if (res == -1) | 857 | if (res == -1) |
| 840 | throw SysError(format("cannot bind to socket `%1%'") % socketPath); | 858 | throw SysError(format("cannot bind to socket `%1%'") % socketPath); |
| 841 | 859 | ||
| 842 | chdir("/"); /* back to the root */ | 860 | if (chdir("/") == -1) /* back to the root */ |
| 861 | throw SysError("cannot change current directory"); | ||
| 843 | 862 | ||
| 844 | if (listen(fdSocket, 5) == -1) | 863 | if (listen(fdSocket, 5) == -1) |
| 845 | throw SysError(format("cannot listen on socket `%1%'") % socketPath); | 864 | throw SysError(format("cannot listen on socket `%1%'") % socketPath); |
| @@ -943,7 +962,6 @@ void run(Strings args) | |||
| 943 | if (arg == "--daemon") /* ignored for backwards compatibility */; | 962 | if (arg == "--daemon") /* ignored for backwards compatibility */; |
| 944 | } | 963 | } |
| 945 | 964 | ||
| 946 | chdir("/"); | ||
| 947 | daemonLoop(); | 965 | daemonLoop(); |
| 948 | } | 966 | } |
| 949 | 967 | ||
