| 42 | } |
| 43 | |
| 44 | void execProgramInStore( |
| 45 | ref<Store> store, |
| 46 | UseLookupPath useLookupPath, |
| 47 | const std::string & program, |
| 48 | const Strings & args, |
| 49 | std::optional<std::string_view> system, |
| 50 | std::optional<StringMap> env) |
| 51 | { |
| 52 | logger->stop(); |
| 53 | |
| 54 | char ** envp; |
| 55 | Strings envStrs; |
| 56 | std::vector<char *> envCharPtrs; |
| 57 | if (env.has_value()) { |
| 58 | envStrs = toEnvp(env.value()); |
| 59 | envCharPtrs = stringsToCharPtrs(envStrs); |
| 60 | envp = envCharPtrs.data(); |
| 61 | } else { |
| 62 | envp = environ; |
| 63 | } |
| 64 | |
| 65 | restoreProcessContext(); |
| 66 | |
| 67 | /* If this is a diverted store (i.e. its "logical" location |
| 68 | (typically /nix/store) differs from its "physical" location |
| 69 | (e.g. /home/eelco/nix/store), then run the command in a |
| 70 | chroot. For non-root users, this requires running it in new |
| 71 | mount and user namespaces. Unfortunately, |
| 72 | unshare(CLONE_NEWUSER) doesn't work in a multithreaded program |
| 73 | (which "nix" is), so we exec() a single-threaded helper program |
| 74 | (chrootHelper() below) to do the work. */ |
| 75 | auto store2 = store.dynamic_pointer_cast<LocalFSStore>(); |
| 76 | |
| 77 | if (!store2) |
| 78 | throw Error( |
| 79 | "store '%s' is not a local store so it does not support command execution", |
| 80 | store->config.getHumanReadableURI()); |
| 81 | |
| 82 | if (store->storeDir != store2->getRealStoreDir()) { |
| 83 | Strings helperArgs = { |
| 84 | chrootHelperName, |
| 85 | store->storeDir, |
| 86 | store2->getRealStoreDir().string(), |
| 87 | std::string(system.value_or("")), |
| 88 | program}; |
| 89 | for (auto & arg : args) |
| 90 | helperArgs.push_back(arg); |
| 91 | |
| 92 | execve(getSelfExe().value_or("nix").string().c_str(), stringsToCharPtrs(helperArgs).data(), envp); |
| 93 | |
| 94 | throw SysError("could not execute chroot helper"); |
| 95 | } |
| 96 | |
| 97 | #ifdef __linux__ |
| 98 | if (system) |
| 99 | linux::setPersonality({ |
| 100 | .system = *system, |
| 101 | .impersonateLinux26 = settings.getLocalSettings().impersonateLinux26, |
no test coverage detected