| 1 | #pragma once |
| 2 | |
| 3 | #include "hash.hh" |
| 4 | #include "serialise.hh" |
| 5 | |
| 6 | #include <string> |
| 7 | #include <map> |
| 8 | #include <memory> |
| 9 | |
| 10 | |
| 11 | namespace nix { |
| 12 | |
| 13 | |
| 14 | typedef std::map<Path, Path> Roots; |
| 15 | |
| 16 | |
| 17 | struct GCOptions |
| 18 | { |
| 19 | /* Garbage collector operation: |
| 20 | |
| 21 | - `gcReturnLive': return the set of paths reachable from |
| 22 | (i.e. in the closure of) the roots. |
| 23 | |
| 24 | - `gcReturnDead': return the set of paths not reachable from |
| 25 | the roots. |
| 26 | |
| 27 | - `gcDeleteDead': actually delete the latter set. |
| 28 | |
| 29 | - `gcDeleteSpecific': delete the paths listed in |
| 30 | `pathsToDelete', insofar as they are not reachable. |
| 31 | */ |
| 32 | typedef enum { |
| 33 | gcReturnLive, |
| 34 | gcReturnDead, |
| 35 | gcDeleteDead, |
| 36 | gcDeleteSpecific, |
| 37 | } GCAction; |
| 38 | |
| 39 | GCAction action; |
| 40 | |
| 41 | /* If `ignoreLiveness' is set, then reachability from the roots is |
| 42 | ignored (dangerous!). However, the paths must still be |
| 43 | unreferenced *within* the store (i.e., there can be no other |
| 44 | store paths that depend on them). */ |
| 45 | bool ignoreLiveness; |
| 46 | |
| 47 | /* For `gcDeleteSpecific', the paths to delete. */ |
| 48 | PathSet pathsToDelete; |
| 49 | |
| 50 | /* Stop after at least `maxFreed' bytes have been freed. */ |
| 51 | unsigned long long maxFreed; |
| 52 | |
| 53 | GCOptions(); |
| 54 | }; |
| 55 | |
| 56 | |
| 57 | struct GCResults |
| 58 | { |
| 59 | /* Depending on the action, the GC roots, or the paths that would |
| 60 | be or have been deleted. */ |
| 61 | PathSet paths; |
| 62 | |
| 63 | /* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the |
| 64 | number of bytes that would be or was freed. */ |
| 65 | unsigned long long bytesFreed; |
| 66 | |
| 67 | GCResults() |
| 68 | { |
| 69 | bytesFreed = 0; |
| 70 | } |
| 71 | }; |
| 72 | |
| 73 | |
| 74 | struct SubstitutablePathInfo |
| 75 | { |
| 76 | Path deriver; |
| 77 | PathSet references; |
| 78 | unsigned long long downloadSize; /* 0 = unknown or inapplicable */ |
| 79 | unsigned long long narSize; /* 0 = unknown */ |
| 80 | }; |
| 81 | |
| 82 | typedef std::map<Path, SubstitutablePathInfo> SubstitutablePathInfos; |
| 83 | |
| 84 | |
| 85 | struct ValidPathInfo |
| 86 | { |
| 87 | Path path; |
| 88 | Path deriver; |
| 89 | Hash hash; |
| 90 | PathSet references; |
| 91 | time_t registrationTime = 0; |
| 92 | uint64_t narSize = 0; // 0 = unknown |
| 93 | uint64_t id; // internal use only |
| 94 | |
| 95 | bool operator == (const ValidPathInfo & i) const |
| 96 | { |
| 97 | return |
| 98 | path == i.path |
| 99 | && hash == i.hash |
| 100 | && references == i.references; |
| 101 | } |
| 102 | }; |
| 103 | |
| 104 | typedef list<ValidPathInfo> ValidPathInfos; |
| 105 | |
| 106 | |
| 107 | enum BuildMode { bmNormal, bmRepair, bmCheck }; |
| 108 | |
| 109 | struct BuildResult |
| 110 | { |
| 111 | enum Status { |
| 112 | Built = 0, |
| 113 | Substituted, |
| 114 | AlreadyValid, |
| 115 | PermanentFailure, |
| 116 | InputRejected, |
| 117 | OutputRejected, |
| 118 | TransientFailure, // possibly transient |
| 119 | CachedFailure, |
| 120 | TimedOut, |
| 121 | MiscFailure, |
| 122 | DependencyFailed, |
| 123 | LogLimitExceeded, |
| 124 | NotDeterministic, |
| 125 | } status = MiscFailure; |
| 126 | std::string errorMsg; |
| 127 | //time_t startTime = 0, stopTime = 0; |
| 128 | bool success() { |
| 129 | return status == Built || status == Substituted || status == AlreadyValid; |
| 130 | } |
| 131 | }; |
| 132 | |
| 133 | |
| 134 | class StoreAPI |
| 135 | { |
| 136 | public: |
| 137 | |
| 138 | virtual ~StoreAPI() { } |
| 139 | |
| 140 | /* Check whether a path is valid. */ |
| 141 | virtual bool isValidPath(const Path & path) = 0; |
| 142 | |
| 143 | /* Query which of the given paths is valid. */ |
| 144 | virtual PathSet queryValidPaths(const PathSet & paths) = 0; |
| 145 | |
| 146 | /* Query the set of all valid paths. */ |
| 147 | virtual PathSet queryAllValidPaths() = 0; |
| 148 | |
| 149 | /* Query information about a valid path. */ |
| 150 | virtual ValidPathInfo queryPathInfo(const Path & path) = 0; |
| 151 | |
| 152 | /* Query the hash of a valid path. */ |
| 153 | virtual Hash queryPathHash(const Path & path) = 0; |
| 154 | |
| 155 | /* Query the set of outgoing FS references for a store path. The |
| 156 | result is not cleared. */ |
| 157 | virtual void queryReferences(const Path & path, |
| 158 | PathSet & references) = 0; |
| 159 | |
| 160 | /* Queries the set of incoming FS references for a store path. |
| 161 | The result is not cleared. */ |
| 162 | virtual void queryReferrers(const Path & path, |
| 163 | PathSet & referrers) = 0; |
| 164 | |
| 165 | /* Query the deriver of a store path. Return the empty string if |
| 166 | no deriver has been set. */ |
| 167 | virtual Path queryDeriver(const Path & path) = 0; |
| 168 | |
| 169 | /* Return all currently valid derivations that have `path' as an |
| 170 | output. (Note that the result of `queryDeriver()' is the |
| 171 | derivation that was actually used to produce `path', which may |
| 172 | not exist anymore.) */ |
| 173 | virtual PathSet queryValidDerivers(const Path & path) = 0; |
| 174 | |
| 175 | /* Query the outputs of the derivation denoted by `path'. */ |
| 176 | virtual PathSet queryDerivationOutputs(const Path & path) = 0; |
| 177 | |
| 178 | /* Query the output names of the derivation denoted by `path'. */ |
| 179 | virtual StringSet queryDerivationOutputNames(const Path & path) = 0; |
| 180 | |
| 181 | /* Query the full store path given the hash part of a valid store |
| 182 | path, or "" if the path doesn't exist. */ |
| 183 | virtual Path queryPathFromHashPart(const string & hashPart) = 0; |
| 184 | |
| 185 | /* Query which of the given paths have substitutes. */ |
| 186 | virtual PathSet querySubstitutablePaths(const PathSet & paths) = 0; |
| 187 | |
| 188 | /* Query substitute info (i.e. references, derivers and download |
| 189 | sizes) of a set of paths. If a path does not have substitute |
| 190 | info, it's omitted from the resulting ‘infos’ map. */ |
| 191 | virtual void querySubstitutablePathInfos(const PathSet & paths, |
| 192 | SubstitutablePathInfos & infos) = 0; |
| 193 | |
| 194 | /* Copy the contents of a path to the store and register the |
| 195 | validity the resulting path. The resulting path is returned. |
| 196 | The function object `filter' can be used to exclude files (see |
| 197 | libutil/archive.hh). */ |
| 198 | virtual Path addToStore(const string & name, const Path & srcPath, |
| 199 | bool recursive = true, HashType hashAlgo = htSHA256, |
| 200 | PathFilter & filter = defaultPathFilter, bool repair = false) = 0; |
| 201 | |
| 202 | /* Like addToStore, but the contents written to the output path is |
| 203 | a regular file containing the given string. */ |
| 204 | virtual Path addTextToStore(const string & name, const string & s, |
| 205 | const PathSet & references, bool repair = false) = 0; |
| 206 | |
| 207 | /* Export a store path, that is, create a NAR dump of the store |
| 208 | path and append its references and its deriver. Optionally, a |
| 209 | cryptographic signature (created by OpenSSL) of the preceding |
| 210 | data is attached. */ |
| 211 | virtual void exportPath(const Path & path, bool sign, |
| 212 | Sink & sink) = 0; |
| 213 | |
| 214 | /* Import a sequence of NAR dumps created by exportPaths() into |
| 215 | the Nix store. */ |
| 216 | virtual Paths importPaths(bool requireSignature, Source & source) = 0; |
| 217 | |
| 218 | /* For each path, if it's a derivation, build it. Building a |
| 219 | derivation means ensuring that the output paths are valid. If |
| 220 | they are already valid, this is a no-op. Otherwise, validity |
| 221 | can be reached in two ways. First, if the output paths is |
| 222 | substitutable, then build the path that way. Second, the |
| 223 | output paths can be created by running the builder, after |
| 224 | recursively building any sub-derivations. For inputs that are |
| 225 | not derivations, substitute them. */ |
| 226 | virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal) = 0; |
| 227 | |
| 228 | /* Ensure that a path is valid. If it is not currently valid, it |
| 229 | may be made valid by running a substitute (if defined for the |
| 230 | path). */ |
| 231 | virtual void ensurePath(const Path & path) = 0; |
| 232 | |
| 233 | /* Add a store path as a temporary root of the garbage collector. |
| 234 | The root disappears as soon as we exit. */ |
| 235 | virtual void addTempRoot(const Path & path) = 0; |
| 236 | |
| 237 | /* Add an indirect root, which is merely a symlink to `path' from |
| 238 | /nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed |
| 239 | to be a symlink to a store path. The garbage collector will |
| 240 | automatically remove the indirect root when it finds that |
| 241 | `path' has disappeared. */ |
| 242 | virtual void addIndirectRoot(const Path & path) = 0; |
| 243 | |
| 244 | /* Acquire the global GC lock, then immediately release it. This |
| 245 | function must be called after registering a new permanent root, |
| 246 | but before exiting. Otherwise, it is possible that a running |
| 247 | garbage collector doesn't see the new root and deletes the |
| 248 | stuff we've just built. By acquiring the lock briefly, we |
| 249 | ensure that either: |
| 250 | |
| 251 | - The collector is already running, and so we block until the |
| 252 | collector is finished. The collector will know about our |
| 253 | *temporary* locks, which should include whatever it is we |
| 254 | want to register as a permanent lock. |
| 255 | |
| 256 | - The collector isn't running, or it's just started but hasn't |
| 257 | acquired the GC lock yet. In that case we get and release |
| 258 | the lock right away, then exit. The collector scans the |
| 259 | permanent root and sees our's. |
| 260 | |
| 261 | In either case the permanent root is seen by the collector. */ |
| 262 | virtual void syncWithGC() = 0; |
| 263 | |
| 264 | /* Find the roots of the garbage collector. Each root is a pair |
| 265 | (link, storepath) where `link' is the path of the symlink |
| 266 | outside of the Nix store that point to `storePath'. */ |
| 267 | virtual Roots findRoots() = 0; |
| 268 | |
| 269 | /* Perform a garbage collection. */ |
| 270 | virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0; |
| 271 | |
| 272 | /* Return the set of paths that have failed to build.*/ |
| 273 | virtual PathSet queryFailedPaths() = 0; |
| 274 | |
| 275 | /* Clear the "failed" status of the given paths. The special |
| 276 | value `*' causes all failed paths to be cleared. */ |
| 277 | virtual void clearFailedPaths(const PathSet & paths) = 0; |
| 278 | |
| 279 | /* Return a string representing information about the path that |
| 280 | can be loaded into the database using `nix-store --load-db' or |
| 281 | `nix-store --register-validity'. */ |
| 282 | string makeValidityRegistration(const PathSet & paths, |
| 283 | bool showDerivers, bool showHash); |
| 284 | |
| 285 | /* Optimise the disk space usage of the Nix store by hard-linking files |
| 286 | with the same contents. */ |
| 287 | virtual void optimiseStore() = 0; |
| 288 | |
| 289 | /* Check the integrity of the Nix store. Returns true if errors |
| 290 | remain. */ |
| 291 | virtual bool verifyStore(bool checkContents, bool repair) = 0; |
| 292 | }; |
| 293 | |
| 294 | |
| 295 | /* !!! These should be part of the store API, I guess. */ |
| 296 | |
| 297 | /* Throw an exception if `path' is not directly in the Nix store. */ |
| 298 | void assertStorePath(const Path & path); |
| 299 | |
| 300 | bool isInStore(const Path & path); |
| 301 | bool isStorePath(const Path & path); |
| 302 | |
| 303 | /* Extract the name part of the given store path. */ |
| 304 | string storePathToName(const Path & path); |
| 305 | |
| 306 | void checkStoreName(const string & name); |
| 307 | |
| 308 | |
| 309 | /* Chop off the parts after the top-level store name, e.g., |
| 310 | /nix/store/abcd-foo/bar => /nix/store/abcd-foo. */ |
| 311 | Path toStorePath(const Path & path); |
| 312 | |
| 313 | |
| 314 | /* Follow symlinks until we end up with a path in the Nix store. */ |
| 315 | Path followLinksToStore(const Path & path); |
| 316 | |
| 317 | |
| 318 | /* Same as followLinksToStore(), but apply toStorePath() to the |
| 319 | result. */ |
| 320 | Path followLinksToStorePath(const Path & path); |
| 321 | |
| 322 | |
| 323 | /* Constructs a unique store path name. */ |
| 324 | Path makeStorePath(const string & type, |
| 325 | const Hash & hash, const string & name); |
| 326 | |
| 327 | Path makeOutputPath(const string & id, |
| 328 | const Hash & hash, const string & name); |
| 329 | |
| 330 | Path makeFixedOutputPath(bool recursive, |
| 331 | HashType hashAlgo, Hash hash, string name); |
| 332 | |
| 333 | |
| 334 | /* This is the preparatory part of addToStore() and addToStoreFixed(); |
| 335 | it computes the store path to which srcPath is to be copied. |
| 336 | Returns the store path and the cryptographic hash of the |
| 337 | contents of srcPath. */ |
| 338 | std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, |
| 339 | bool recursive = true, HashType hashAlgo = htSHA256, |
| 340 | PathFilter & filter = defaultPathFilter); |
| 341 | |
| 342 | /* Preparatory part of addTextToStore(). |
| 343 | |
| 344 | !!! Computation of the path should take the references given to |
| 345 | addTextToStore() into account, otherwise we have a (relatively |
| 346 | minor) security hole: a caller can register a source file with |
| 347 | bogus references. If there are too many references, the path may |
| 348 | not be garbage collected when it has to be (not really a problem, |
| 349 | the caller could create a root anyway), or it may be garbage |
| 350 | collected when it shouldn't be (more serious). |
| 351 | |
| 352 | Hashing the references would solve this (bogus references would |
| 353 | simply yield a different store path, so other users wouldn't be |
| 354 | affected), but it has some backwards compatibility issues (the |
| 355 | hashing scheme changes), so I'm not doing that for now. */ |
| 356 | Path computeStorePathForText(const string & name, const string & s, |
| 357 | const PathSet & references); |
| 358 | |
| 359 | |
| 360 | /* Remove the temporary roots file for this process. Any temporary |
| 361 | root becomes garbage after this point unless it has been registered |
| 362 | as a (permanent) root. */ |
| 363 | void removeTempRoots(); |
| 364 | |
| 365 | |
| 366 | /* Register a permanent GC root. */ |
| 367 | Path addPermRoot(StoreAPI & store, const Path & storePath, |
| 368 | const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false); |
| 369 | |
| 370 | |
| 371 | /* Sort a set of paths topologically under the references relation. |
| 372 | If p refers to q, then p preceeds q in this list. */ |
| 373 | Paths topoSortPaths(StoreAPI & store, const PathSet & paths); |
| 374 | |
| 375 | |
| 376 | /* For now, there is a single global store API object, but we'll |
| 377 | purify that in the future. */ |
| 378 | extern std::shared_ptr<StoreAPI> store; |
| 379 | |
| 380 | |
| 381 | /* Factory method: open the Nix database, either through the local or |
| 382 | remote implementation. */ |
| 383 | std::shared_ptr<StoreAPI> openStore(bool reserveSpace = true); |
| 384 | |
| 385 | |
| 386 | /* Display a set of paths in human-readable form (i.e., between quotes |
| 387 | and separated by commas). */ |
| 388 | string showPaths(const PathSet & paths); |
| 389 | |
| 390 | |
| 391 | ValidPathInfo decodeValidPathInfo(std::istream & str, |
| 392 | bool hashGiven = false); |
| 393 | |
| 394 | |
| 395 | /* Export multiple paths in the format expected by ‘nix-store |
| 396 | --import’. */ |
| 397 | void exportPaths(StoreAPI & store, const Paths & paths, |
| 398 | bool sign, Sink & sink); |
| 399 | |
| 400 | |
| 401 | MakeError(SubstError, Error) |
| 402 | MakeError(BuildError, Error) /* denotes a permanent build failure */ |
| 403 | |
| 404 | |
| 405 | } |