LTP GCOV extension - code coverage report
Current view: directory - src/libstore - remote-store.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 253
Code covered: 64.0 % Executed lines: 162

       1                 : #include "serialise.hh"
       2                 : #include "util.hh"
       3                 : #include "remote-store.hh"
       4                 : #include "worker-protocol.hh"
       5                 : #include "archive.hh"
       6                 : #include "globals.hh"
       7                 : 
       8                 : #include <sys/types.h>
       9                 : #include <sys/stat.h>
      10                 : #include <sys/socket.h>
      11                 : #include <sys/un.h>
      12                 : #include <fcntl.h>
      13                 : 
      14                 : #include <iostream>
      15                 : #include <unistd.h>
      16                 : 
      17                 : 
      18                 : namespace nix {
      19                 : 
      20                 : 
      21             373 : Path readStorePath(Source & from)
      22                 : {
      23             373 :     Path path = readString(from);
      24             373 :     assertStorePath(path);
      25               0 :     return path;
      26                 : }
      27                 : 
      28                 : 
      29             137 : PathSet readStorePaths(Source & from)
      30                 : {
      31             137 :     PathSet paths = readStringSet(from);
      32             289 :     for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
      33             152 :         assertStorePath(*i);
      34               0 :     return paths;
      35                 : }
      36                 : 
      37                 : 
      38              92 : RemoteStore::RemoteStore()
      39                 : {
      40              92 :     string remoteMode = getEnv("NIX_REMOTE");
      41                 : 
      42             184 :     if (remoteMode == "slave")
      43                 :         /* Fork off a setuid worker to do the privileged work. */
      44              46 :         forkSlave();
      45              46 :     else if (remoteMode == "daemon")
      46                 :         /* Connect to a daemon that does the privileged work for
      47                 :            us. */
      48              46 :        connectToDaemon();
      49                 :     else
      50                 :          throw Error(format("invalid setting for NIX_REMOTE, `%1%'")
      51               0 :              % remoteMode);
      52                 :             
      53              92 :     from.fd = fdSocket;
      54              92 :     to.fd = fdSocket;
      55                 : 
      56                 :     /* Send the magic greeting, check for the reply. */
      57                 :     try {
      58              92 :         writeInt(WORKER_MAGIC_1, to);
      59              92 :         unsigned int magic = readInt(from);
      60              92 :         if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch");
      61                 : 
      62              92 :         daemonVersion = readInt(from);
      63              92 :         if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
      64               0 :             throw Error("Nix daemon protocol version not supported");
      65              92 :         writeInt(PROTOCOL_VERSION, to);
      66              92 :         processStderr();
      67                 : 
      68               0 :     } catch (Error & e) {
      69                 :         throw Error(format("cannot start worker (%1%)")
      70               0 :             % e.msg());
      71                 :     }
      72                 : 
      73             184 :     setOptions();
      74              92 : }
      75                 : 
      76                 : 
      77              46 : void RemoteStore::forkSlave()
      78                 : {
      79                 :     int sockets[2];
      80              46 :     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1)
      81               0 :         throw SysError("cannot create sockets");
      82                 : 
      83              46 :     fdSocket = sockets[0];
      84              46 :     AutoCloseFD fdChild = sockets[1];
      85                 : 
      86                 :     /* Start the worker. */
      87              46 :     Path worker = getEnv("NIX_WORKER");
      88              92 :     if (worker == "")
      89              46 :         worker = nixBinDir + "/nix-worker";
      90                 : 
      91              46 :     string verbosityArg = "-";
      92              46 :     for (int i = 1; i < verbosity; ++i)
      93               0 :         verbosityArg += "v";
      94                 : 
      95              46 :     child = fork();
      96                 :     
      97              92 :     switch (child) {
      98                 :         
      99                 :     case -1:
     100               0 :         throw SysError("unable to fork");
     101                 : 
     102                 :     case 0:
     103                 :         try { /* child */
     104                 :             
     105              46 :             if (dup2(fdChild, STDOUT_FILENO) == -1)
     106               0 :                 throw SysError("dupping write side");
     107                 : 
     108              46 :             if (dup2(fdChild, STDIN_FILENO) == -1)
     109               0 :                 throw SysError("dupping read side");
     110                 : 
     111              46 :             close(fdSocket);
     112              46 :             close(fdChild);
     113                 : 
     114                 :             execlp(worker.c_str(), worker.c_str(), "--slave",
     115                 :                 /* hacky - must be at the end */
     116                 :                 verbosityArg == "-" ? NULL : verbosityArg.c_str(),
     117              46 :                 NULL);
     118                 : 
     119               0 :             throw SysError(format("executing `%1%'") % worker);
     120                 :             
     121               0 :         } catch (std::exception & e) {
     122               0 :             std::cerr << format("child error: %1%\n") % e.what();
     123                 :         }
     124               0 :         quickExit(1);
     125                 :     }
     126                 : 
     127              46 :     fdChild.close();
     128                 : 
     129              46 : }
     130                 : 
     131                 : 
     132              46 : void RemoteStore::connectToDaemon()
     133                 : {
     134              46 :     fdSocket = socket(PF_UNIX, SOCK_STREAM, 0);
     135              46 :     if (fdSocket == -1)
     136               0 :         throw SysError("cannot create Unix domain socket");
     137                 : 
     138              46 :     string socketPath = nixStateDir + DEFAULT_SOCKET_PATH;
     139                 : 
     140                 :     /* Urgh, sockaddr_un allows path names of only 108 characters.  So
     141                 :        chdir to the socket directory so that we can pass a relative
     142                 :        path name.  !!! this is probably a bad idea in multi-threaded
     143                 :        applications... */
     144              46 :     AutoCloseFD fdPrevDir = open(".", O_RDONLY);
     145              46 :     if (fdPrevDir == -1) throw SysError("couldn't open current directory");
     146              46 :     chdir(dirOf(socketPath).c_str()); 
     147              46 :     Path socketPathRel = "./" + baseNameOf(socketPath);
     148                 :     
     149                 :     struct sockaddr_un addr;
     150              46 :     addr.sun_family = AF_UNIX;
     151              46 :     if (socketPathRel.size() >= sizeof(addr.sun_path))
     152               0 :         throw Error(format("socket path `%1%' is too long") % socketPathRel);
     153              46 :     strcpy(addr.sun_path, socketPathRel.c_str());
     154                 :     
     155              46 :     if (connect(fdSocket, (struct sockaddr *) &addr, sizeof(addr)) == -1)
     156               0 :         throw SysError(format("cannot connect to daemon at `%1%'") % socketPath);
     157                 : 
     158              46 :     if (fchdir(fdPrevDir) == -1)
     159               0 :         throw SysError("couldn't change back to previous directory");
     160              46 : }
     161                 : 
     162                 : 
     163              92 : RemoteStore::~RemoteStore()
     164                 : {
     165                 :     try {
     166              92 :         fdSocket.close();
     167              92 :         if (child != -1)
     168              46 :             child.wait(true);
     169               0 :     } catch (...) {
     170               0 :         ignoreException();
     171                 :     }
     172              92 : }
     173                 : 
     174                 : 
     175              92 : void RemoteStore::setOptions()
     176                 : {
     177              92 :     writeInt(wopSetOptions, to);
     178              92 :     writeInt(keepFailed, to);
     179              92 :     writeInt(keepGoing, to);
     180              92 :     writeInt(tryFallback, to);
     181              92 :     writeInt(verbosity, to);
     182              92 :     writeInt(maxBuildJobs, to);
     183              92 :     writeInt(maxSilentTime, to);
     184              92 :     if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
     185              92 :         writeInt(useBuildHook, to);
     186              92 :     if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) {
     187              92 :         writeInt(buildVerbosity, to);
     188              92 :         writeInt(logType, to);
     189              92 :         writeInt(printBuildTrace, to);
     190                 :     }
     191              92 :     processStderr();
     192              92 : }
     193                 : 
     194                 : 
     195              58 : bool RemoteStore::isValidPath(const Path & path)
     196                 : {
     197              58 :     writeInt(wopIsValidPath, to);
     198              58 :     writeString(path, to);
     199              58 :     processStderr();
     200              58 :     unsigned int reply = readInt(from);
     201              58 :     return reply != 0;
     202                 : }
     203                 : 
     204                 : 
     205               0 : PathSet RemoteStore::queryValidPaths()
     206                 : {
     207               0 :     throw Error("not implemented");
     208                 : }
     209                 : 
     210                 : 
     211              12 : bool RemoteStore::hasSubstitutes(const Path & path)
     212                 : {
     213              12 :     writeInt(wopHasSubstitutes, to);
     214              12 :     writeString(path, to);
     215              12 :     processStderr();
     216              12 :     unsigned int reply = readInt(from);
     217              12 :     return reply != 0;
     218                 : }
     219                 : 
     220                 : 
     221                 : bool RemoteStore::querySubstitutablePathInfo(const Path & path,
     222               0 :     SubstitutablePathInfo & info)
     223                 : {
     224               0 :     if (GET_PROTOCOL_MINOR(daemonVersion) < 3) return false;
     225               0 :     writeInt(wopQuerySubstitutablePathInfo, to);
     226               0 :     writeString(path, to);
     227               0 :     processStderr();
     228               0 :     unsigned int reply = readInt(from);
     229               0 :     if (reply == 0) return false;
     230               0 :     info.deriver = readString(from);
     231               0 :     if (info.deriver != "") assertStorePath(info.deriver);
     232               0 :     info.references = readStorePaths(from);
     233               0 :     info.downloadSize = readLongLong(from);
     234               0 :     return true;
     235                 : }
     236                 : 
     237                 : 
     238               0 : Hash RemoteStore::queryPathHash(const Path & path)
     239                 : {
     240               0 :     writeInt(wopQueryPathHash, to);
     241               0 :     writeString(path, to);
     242               0 :     processStderr();
     243               0 :     string hash = readString(from);
     244               0 :     return parseHash(htSHA256, hash);
     245                 : }
     246                 : 
     247                 : 
     248                 : void RemoteStore::queryReferences(const Path & path,
     249               0 :     PathSet & references)
     250                 : {
     251               0 :     writeInt(wopQueryReferences, to);
     252               0 :     writeString(path, to);
     253               0 :     processStderr();
     254               0 :     PathSet references2 = readStorePaths(from);
     255               0 :     references.insert(references2.begin(), references2.end());
     256               0 : }
     257                 : 
     258                 : 
     259                 : void RemoteStore::queryReferrers(const Path & path,
     260               0 :     PathSet & referrers)
     261                 : {
     262               0 :     writeInt(wopQueryReferrers, to);
     263               0 :     writeString(path, to);
     264               0 :     processStderr();
     265               0 :     PathSet referrers2 = readStorePaths(from);
     266               0 :     referrers.insert(referrers2.begin(), referrers2.end());
     267               0 : }
     268                 : 
     269                 : 
     270               0 : Path RemoteStore::queryDeriver(const Path & path)
     271                 : {
     272               0 :     writeInt(wopQueryDeriver, to);
     273               0 :     writeString(path, to);
     274               0 :     processStderr();
     275               0 :     Path drvPath = readString(from);
     276               0 :     if (drvPath != "") assertStorePath(drvPath);
     277               0 :     return drvPath;
     278                 : }
     279                 : 
     280                 : 
     281                 : Path RemoteStore::addToStore(const Path & _srcPath, bool fixed,
     282              42 :     bool recursive, string hashAlgo, PathFilter & filter)
     283                 : {
     284              42 :     Path srcPath(absPath(_srcPath));
     285                 :     
     286              42 :     writeInt(wopAddToStore, to);
     287              42 :     writeString(baseNameOf(srcPath), to);
     288              42 :     writeInt(fixed ? 1 : 0, to);
     289              42 :     writeInt(recursive ? 1 : 0, to);
     290              42 :     writeString(hashAlgo, to);
     291              42 :     dumpPath(srcPath, to, filter);
     292              42 :     processStderr();
     293              42 :     return readStorePath(from);
     294                 : }
     295                 : 
     296                 : 
     297                 : Path RemoteStore::addTextToStore(const string & suffix, const string & s,
     298              74 :     const PathSet & references)
     299                 : {
     300              74 :     writeInt(wopAddTextToStore, to);
     301              74 :     writeString(suffix, to);
     302              74 :     writeString(s, to);
     303              74 :     writeStringSet(references, to);
     304                 :     
     305              74 :     processStderr();
     306              74 :     return readStorePath(from);
     307                 : }
     308                 : 
     309                 : 
     310                 : void RemoteStore::exportPath(const Path & path, bool sign,
     311               0 :     Sink & sink)
     312                 : {
     313               0 :     writeInt(wopExportPath, to);
     314               0 :     writeString(path, to);
     315               0 :     writeInt(sign ? 1 : 0, to);
     316               0 :     processStderr(&sink); /* sink receives the actual data */
     317               0 :     readInt(from);
     318               0 : }
     319                 : 
     320                 : 
     321               0 : Path RemoteStore::importPath(bool requireSignature, Source & source)
     322                 : {
     323               0 :     writeInt(wopImportPath, to);
     324                 :     /* We ignore requireSignature, since the worker forces it to true
     325                 :        anyway. */
     326                 :     
     327               0 :     processStderr(0, &source);
     328               0 :     return readStorePath(from);
     329                 : }
     330                 : 
     331                 : 
     332              56 : void RemoteStore::buildDerivations(const PathSet & drvPaths)
     333                 : {
     334              56 :     writeInt(wopBuildDerivations, to);
     335              56 :     writeStringSet(drvPaths, to);
     336              56 :     processStderr();
     337              54 :     readInt(from);
     338              54 : }
     339                 : 
     340                 : 
     341              44 : void RemoteStore::ensurePath(const Path & path)
     342                 : {
     343              44 :     writeInt(wopEnsurePath, to);
     344              44 :     writeString(path, to);
     345              44 :     processStderr();
     346              44 :     readInt(from);
     347              44 : }
     348                 : 
     349                 : 
     350              26 : void RemoteStore::addTempRoot(const Path & path)
     351                 : {
     352              26 :     writeInt(wopAddTempRoot, to);
     353              26 :     writeString(path, to);
     354              26 :     processStderr();
     355              26 :     readInt(from);
     356              26 : }
     357                 : 
     358                 : 
     359               0 : void RemoteStore::addIndirectRoot(const Path & path)
     360                 : {
     361               0 :     writeInt(wopAddIndirectRoot, to);
     362               0 :     writeString(path, to);
     363               0 :     processStderr();
     364               0 :     readInt(from);
     365               0 : }
     366                 : 
     367                 : 
     368              26 : void RemoteStore::syncWithGC()
     369                 : {
     370              26 :     writeInt(wopSyncWithGC, to);
     371              26 :     processStderr();
     372              26 :     readInt(from);
     373              26 : }
     374                 : 
     375                 : 
     376              26 : Roots RemoteStore::findRoots()
     377                 : {
     378              26 :     writeInt(wopFindRoots, to);
     379              26 :     processStderr();
     380              26 :     unsigned int count = readInt(from);
     381              26 :     Roots result;
     382             112 :     while (count--) {
     383             112 :         Path link = readString(from);
     384             112 :         Path target = readStorePath(from);
     385             112 :         result[link] = target;
     386                 :     }
     387               0 :     return result;
     388                 : }
     389                 : 
     390                 : 
     391               2 : void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
     392                 : {
     393               2 :     writeInt(wopCollectGarbage, to);
     394               2 :     writeInt(options.action, to);
     395               2 :     writeStringSet(options.pathsToDelete, to);
     396               2 :     writeInt(options.ignoreLiveness, to);
     397               2 :     writeLongLong(options.maxFreed, to);
     398               2 :     writeInt(options.maxLinks, to);
     399                 :     
     400               2 :     processStderr();
     401                 :     
     402               2 :     results.paths = readStringSet(from);
     403               2 :     results.bytesFreed = readLongLong(from);
     404               2 :     results.blocksFreed = readLongLong(from);
     405               2 : }
     406                 : 
     407                 : 
     408             550 : void RemoteStore::processStderr(Sink * sink, Source * source)
     409                 : {
     410                 :     unsigned int msg;
     411            1354 :     while ((msg = readInt(from)) == STDERR_NEXT
     412                 :         || msg == STDERR_READ || msg == STDERR_WRITE) {
     413             254 :         if (msg == STDERR_WRITE) {
     414               0 :             string s = readString(from);
     415               0 :             if (!sink) throw Error("no sink");
     416               0 :             (*sink)((const unsigned char *) s.c_str(), s.size());
     417                 :         }
     418             254 :         else if (msg == STDERR_READ) {
     419               0 :             if (!source) throw Error("no source");
     420               0 :             unsigned int len = readInt(from);
     421               0 :             unsigned char * buf = new unsigned char[len];
     422               0 :             AutoDeleteArray<unsigned char> d(buf);
     423               0 :             (*source)(buf, len);
     424               0 :             writeString(string((const char *) buf, len), to);
     425                 :         }
     426                 :         else {
     427             254 :             string s = readString(from);
     428             254 :             writeToStderr((const unsigned char *) s.c_str(), s.size());
     429                 :         }
     430                 :     }
     431             550 :     if (msg == STDERR_ERROR)
     432               2 :         throw Error(readString(from));
     433             548 :     else if (msg != STDERR_LAST)
     434               0 :         throw Error("protocol error processing standard error");
     435             548 : }
     436                 : 
     437               0 : 
     438            1106 : }

Generated by: LTP GCOV extension version 1.6