LTP GCOV extension - code coverage report
Current view: directory - src/libmain - shared.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 171
Code covered: 78.9 % Executed lines: 135

       1                 : #include "config.h"
       2                 : 
       3                 : #include "shared.hh"
       4                 : #include "globals.hh"
       5                 : #include "store-api.hh"
       6                 : #include "util.hh"
       7                 : #include "misc.hh"
       8                 : 
       9                 : #include <iostream>
      10                 : #include <cctype>
      11                 : #include <exception>
      12                 : 
      13                 : #include <sys/stat.h>
      14                 : #include <unistd.h>
      15                 : 
      16                 : #include <aterm2.h>
      17                 : 
      18                 : 
      19                 : namespace nix {
      20                 : 
      21                 : 
      22                 : volatile sig_atomic_t blockInt = 0;
      23                 : 
      24                 : 
      25               0 : static void sigintHandler(int signo)
      26                 : {
      27               0 :     if (!blockInt) {
      28               0 :         _isInterrupted = 1;
      29               0 :         blockInt = 1;
      30                 :     }
      31               0 : }
      32                 : 
      33                 : 
      34              18 : Path makeRootName(const Path & gcRoot, int & counter)
      35                 : {
      36              18 :     counter++;
      37              18 :     if (counter == 1)
      38              18 :         return gcRoot;
      39                 :     else
      40               0 :         return (format("%1%-%2%") % gcRoot % counter).str();
      41                 : }
      42                 : 
      43                 : 
      44              74 : void printGCWarning()
      45                 : {
      46                 :     static bool haveWarned = false;
      47                 :     warnOnce(haveWarned, 
      48                 :         "you did not specify `--add-root'; "
      49              74 :         "the result might be removed by the garbage collector");
      50              74 : }
      51                 : 
      52                 : 
      53              64 : void printMissing(const PathSet & paths)
      54                 : {
      55                 :     unsigned long long downloadSize;
      56              64 :     PathSet willBuild, willSubstitute, unknown;
      57              64 :     queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize);
      58                 : 
      59              64 :     if (!willBuild.empty()) {
      60              44 :         printMsg(lvlInfo, format("the following derivations will be built:"));
      61             133 :         foreach (PathSet::iterator, i, willBuild)
      62              89 :             printMsg(lvlInfo, format("  %1%") % *i);
      63                 :     }
      64                 : 
      65              64 :     if (!willSubstitute.empty()) {
      66               6 :         printMsg(lvlInfo, format("the following paths will be downloaded/copied (%.2f MiB):") %
      67                 :             (downloadSize / (1024.0 * 1024.0)));
      68              14 :         foreach (PathSet::iterator, i, willSubstitute)
      69               8 :             printMsg(lvlInfo, format("  %1%") % *i);
      70                 :     }
      71                 : 
      72              64 :     if (!unknown.empty()) {
      73               1 :         printMsg(lvlInfo, format("don't know how to build the following paths%1%:")
      74                 :             % (readOnlyMode ? " (may be caused by read-only store access)" : ""));
      75               2 :         foreach (PathSet::iterator, i, unknown)
      76               1 :             printMsg(lvlInfo, format("  %1%") % *i);
      77              64 :     }
      78              64 : }
      79                 : 
      80                 : 
      81               1 : static void setLogType(string lt)
      82                 : {
      83               1 :     if (lt == "pretty") logType = ltPretty;
      84               1 :     else if (lt == "escapes") logType = ltEscapes;
      85               0 :     else if (lt == "flat") logType = ltFlat;
      86               0 :     else throw UsageError("unknown log type");
      87               1 : }
      88                 : 
      89                 : 
      90                 : unsigned long long getIntArg(const string & opt,
      91               2 :     Strings::iterator & i, const Strings::iterator & end)
      92                 : {
      93               2 :     ++i;
      94               2 :     if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
      95                 :     long long n;
      96               2 :     if (!string2Int(*i, n) || n < 0)
      97               0 :         throw UsageError(format("`%1%' requires a non-negative integer") % opt);
      98               2 :     return n;
      99                 : }
     100                 : 
     101                 : 
     102                 : void initDerivationsHelpers();
     103                 : 
     104                 : 
     105               0 : static void closeStore()
     106                 : {
     107                 :     try {
     108               0 :         throw;
     109               0 :     } catch (std::exception & e) {
     110               0 :         printMsg(lvlError,
     111                 :             format("FATAL: unexpected exception (closing store and aborting): %1%") % e.what());
     112                 :     }
     113                 :     try {
     114               0 :         store.reset((StoreAPI *) 0);
     115               0 :     } catch (...) {
     116               0 :         ignoreException();
     117                 :     }
     118               0 :     abort();
     119                 : }
     120                 : 
     121                 : 
     122             639 : RemoveTempRoots::~RemoveTempRoots()
     123                 : {
     124             639 :     removeTempRoots();
     125             639 : }
     126                 : 
     127                 : 
     128                 : /* Initialize and reorder arguments, then call the actual argument
     129                 :    processor. */
     130             553 : static void initAndRun(int argc, char * * argv)
     131                 : {
     132                 :     /* Setup Nix paths. */
     133             553 :     nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR)));
     134            1106 :     nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
     135            1106 :     nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
     136            1106 :     nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
     137            1106 :     nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
     138            1106 :     nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
     139            1106 :     nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
     140            1106 :     nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
     141            1106 :     nixChrootsDir = canonPath(getEnv("NIX_CHROOTS_DIR", nixStateDir + "/chroots"));
     142                 : 
     143            1106 :     string subs = getEnv("NIX_SUBSTITUTERS", "default");
     144            1106 :     if (subs == "default") {
     145             549 :         substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl");
     146             549 :         substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl");
     147                 :     } else
     148               4 :         substituters = tokenizeString(subs, ":");
     149                 : 
     150                 :     /* Get some settings from the configuration file. */
     151             553 :     thisSystem = querySetting("system", SYSTEM);
     152            1106 :     maxBuildJobs = queryIntSetting("build-max-jobs", 1);
     153            1106 :     maxSilentTime = queryIntSetting("build-max-silent-time", 0);
     154                 : 
     155                 :     /* Catch SIGINT. */
     156                 :     struct sigaction act, oact;
     157             553 :     act.sa_handler = sigintHandler;
     158             553 :     sigfillset(&act.sa_mask);
     159             553 :     act.sa_flags = 0;
     160             553 :     if (sigaction(SIGINT, &act, &oact))
     161               0 :         throw SysError("installing handler for SIGINT");
     162             553 :     if (sigaction(SIGTERM, &act, &oact))
     163               0 :         throw SysError("installing handler for SIGTERM");
     164             553 :     if (sigaction(SIGHUP, &act, &oact))
     165               0 :         throw SysError("installing handler for SIGHUP");
     166                 : 
     167                 :     /* Ignore SIGPIPE. */
     168             553 :     act.sa_handler = SIG_IGN;
     169             553 :     act.sa_flags = 0;
     170             553 :     if (sigaction(SIGPIPE, &act, &oact))
     171               0 :         throw SysError("ignoring SIGPIPE");
     172                 : 
     173                 :     /* There is no privacy in the Nix system ;-)  At least not for
     174                 :        now.  In particular, store objects should be readable by
     175                 :        everybody.  This prevents nasty surprises when using a shared
     176                 :        store (with the setuid() hack). */
     177             553 :     umask(0022);
     178                 : 
     179                 :     /* Process the NIX_LOG_TYPE environment variable. */
     180             553 :     string lt = getEnv("NIX_LOG_TYPE");
     181            1106 :     if (lt != "") setLogType(lt);
     182                 : 
     183                 :     /* ATerm stuff.  !!! find a better place to put this */
     184             553 :     initDerivationsHelpers();
     185                 :     
     186                 :     /* Put the arguments in a vector. */
     187             553 :     Strings args, remaining;
     188            2274 :     while (argc--) args.push_back(*argv++);
     189             553 :     args.erase(args.begin());
     190                 :     
     191                 :     /* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
     192                 :        ignore options for the ATerm library. */
     193            2274 :     for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
     194            1721 :         string arg = *i;
     195            1721 :         if (string(arg, 0, 4) == "-at-") ;
     196            1721 :         else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') {
     197             408 :             for (unsigned int j = 1; j < arg.length(); j++)
     198             156 :                 if (isalpha(arg[j]))
     199             154 :                     remaining.push_back((string) "-" + arg[j]);
     200                 :                 else {
     201               2 :                     remaining.push_back(string(arg, j));
     202               2 :                     break;
     203                 :                 }
     204            1671 :         } else remaining.push_back(arg);
     205                 :     }
     206             553 :     args = remaining;
     207             553 :     remaining.clear();
     208                 : 
     209                 :     /* Process default options. */
     210             553 :     for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
     211            1824 :         string arg = *i;
     212            1824 :         if (arg == "--verbose" || arg == "-v")
     213             102 :             verbosity = (Verbosity) ((int) verbosity + 1);
     214            1722 :         else if (arg == "--log-type") {
     215               1 :             ++i;
     216               1 :             if (i == args.end()) throw UsageError("`--log-type' requires an argument");
     217               1 :             setLogType(*i);
     218                 :         }
     219            1721 :         else if (arg == "--build-output" || arg == "-B")
     220                 :             ; /* !!! obsolete - remove eventually */
     221            1721 :         else if (arg == "--no-build-output" || arg == "-Q")
     222               0 :             buildVerbosity = lvlVomit;
     223            1721 :         else if (arg == "--print-build-trace")
     224               0 :             printBuildTrace = true;
     225            1721 :         else if (arg == "--help") {
     226               4 :             printHelp();
     227               5 :             return;
     228                 :         }
     229            1717 :         else if (arg == "--version") {
     230               1 :             std::cout << format("%1% (Nix) %2%") % programId % NIX_VERSION << std::endl;
     231                 :             return;
     232                 :         }
     233            1716 :         else if (arg == "--keep-failed" || arg == "-K")
     234               0 :             keepFailed = true;
     235            1716 :         else if (arg == "--keep-going" || arg == "-k")
     236               0 :             keepGoing = true;
     237            1716 :         else if (arg == "--fallback")
     238               2 :             tryFallback = true;
     239            1714 :         else if (arg == "--max-jobs" || arg == "-j")
     240               2 :             maxBuildJobs = getIntArg(arg, i, args.end());
     241            1712 :         else if (arg == "--readonly-mode")
     242               1 :             readOnlyMode = true;
     243            1711 :         else if (arg == "--max-silent-time")
     244               0 :             maxSilentTime = getIntArg(arg, i, args.end());
     245            1711 :         else if (arg == "--no-build-hook")
     246               1 :             useBuildHook = false;
     247            1710 :         else remaining.push_back(arg);
     248                 :     }
     249                 : 
     250                 :     /* Automatically clean up the temporary roots file when we
     251                 :        exit. */
     252                 :     RemoveTempRoots removeTempRoots __attribute__((unused));
     253                 : 
     254                 :     /* Make sure that the database gets closed properly, even if
     255                 :        terminate() is called (which happens sometimes due to bugs in
     256                 :        destructor/exceptions interaction, but that needn't preclude a
     257                 :        clean shutdown of the database). */
     258             548 :     std::set_terminate(closeStore);
     259                 :     
     260             548 :     run(remaining);
     261                 : 
     262                 :     /* Close the Nix database. */
     263             492 :     store.reset((StoreAPI *) 0);
     264                 : }
     265                 : 
     266                 : 
     267                 : bool setuidMode = false;
     268                 : 
     269                 : 
     270             553 : static void setuidInit()
     271                 : {
     272                 :     /* Don't do anything if this is not a setuid binary. */
     273             553 :     if (getuid() == geteuid() && getgid() == getegid()) return;
     274                 : 
     275               0 :     uid_t nixUid = geteuid();
     276               0 :     gid_t nixGid = getegid();
     277                 :     
     278               0 :     setuidCleanup();
     279                 : 
     280                 :     /* Don't trust the current directory. */
     281               0 :     if (chdir("/") == -1) abort();
     282                 : 
     283                 :     /* Set the real (and preferably also the save) uid/gid to the
     284                 :        effective uid/gid.  This matters mostly when we're not using
     285                 :        build-users (bad!), since some builders (like Perl) complain
     286                 :        when real != effective.
     287                 : 
     288                 :        On systems where setresuid is unavailable, we can't drop the
     289                 :        saved uid/gid.  This means that we could go back to the
     290                 :        original real uid (i.e., the uid of the caller).  That's not
     291                 :        really a problem, except maybe when we execute a builder and
     292                 :        we're not using build-users.  In that case, the builder may be
     293                 :        able to switch to the uid of the caller and possibly do bad
     294                 :        stuff.  But note that when not using build-users, the builder
     295                 :        could also modify the Nix executables (say, replace them by a
     296                 :        Trojan horse), so the problem is already there. */
     297                 : 
     298                 : #if HAVE_SETRESUID
     299               0 :     if (setresuid(nixUid, nixUid, nixUid)) abort();
     300               0 :     if (setresgid(nixGid, nixGid, nixGid)) abort();
     301                 : #elif HAVE_SETREUID
     302                 :     /* Note: doesn't set saved uid/gid! */
     303                 :     fprintf(stderr, "warning: cannot set saved uid\n");
     304                 :     if (setreuid(nixUid, nixUid)) abort();
     305                 :     if (setregid(nixGid, nixGid)) abort();
     306                 : #else
     307                 :     /* Note: doesn't set real and saved uid/gid! */
     308                 :     fprintf(stderr, "warning: cannot set real and saved uids\n");
     309                 :     if (setuid(nixUid)) abort();
     310                 :     if (setgid(nixGid)) abort();
     311                 : #endif
     312                 : 
     313               0 :     setuidMode = true;
     314                 : }
     315                 : 
     316                 : 
     317                 : }
     318                 : 
     319                 : 
     320                 : static char buf[1024];
     321                 : 
     322             553 : int main(int argc, char * * argv)
     323                 : {
     324                 :     using namespace nix;
     325                 : 
     326                 :     /* If we're setuid, then we need to take some security precautions
     327                 :        right away. */
     328             553 :     if (argc == 0) abort();
     329             553 :     setuidInit();
     330                 :     
     331                 :     /* ATerm setup. */
     332                 :     ATerm bottomOfStack;
     333             553 :     ATinit(argc, argv, &bottomOfStack);
     334                 : 
     335                 :     /* Turn on buffering for cerr. */
     336                 : #if HAVE_PUBSETBUF
     337             553 :     std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
     338                 : #endif
     339                 : 
     340             553 :     std::ios::sync_with_stdio(false);
     341                 : 
     342                 :     try {
     343                 :         try {
     344             553 :             initAndRun(argc, argv);
     345             110 :         } catch (...) {
     346                 :             /* Subtle: we have to make sure that any `interrupted'
     347                 :                condition is discharged before we reach printMsg()
     348                 :                below, since otherwise it will throw an (uncaught)
     349                 :                exception. */
     350              55 :             blockInt = 1; /* ignore further SIGINTs */
     351              55 :             _isInterrupted = 0;
     352              55 :             throw;
     353                 :         }
     354               4 :     } catch (UsageError & e) {
     355               2 :         printMsg(lvlError, 
     356                 :             format(
     357                 :                 "error: %1%\n"
     358                 :                 "Try `%2% --help' for more information.")
     359                 :             % e.what() % programId);
     360               4 :         return 1;
     361             106 :     } catch (BaseError & e) {
     362              53 :         printMsg(lvlError, format("error: %1%") % e.msg());
     363             106 :         return 1;
     364               0 :     } catch (std::exception & e) {
     365               0 :         printMsg(lvlError, format("error: %1%") % e.what());
     366               0 :         return 1;
     367                 :     }
     368                 : 
     369             497 :     return 0;
     370            1106 : }
     371             553 : 
     372                 :  

Generated by: LTP GCOV extension version 1.6