about summary refs log blame commit diff
path: root/third_party/nix/src/nix/main.cc
blob: 5536aac5329827838b590c804b0279d1958b3861 (plain) (tree)
1
2
3
4
5
6
7
8
9

                    
                         




                       
 








                                 
 

                                    
                                         
 

               
                                                                   

                            
 
                                

                

                                              
 

                                                       

               






                                                                            
                                                                             
                    
       
     
   
 
               

 

                        

















                                                                                
                                          
                                                            
           






































                                                                                

  






                                                                   
 

            
 
                        
                                                    
 

                                                                  


                                
   
 
                                
 
               
 
                                               
 


                           
 
                                       

                                                                

                        
 

                                                           


                                             
                                         
                                                                     
     


                                            
                                                     
                                          
     
   
 

                          

 
                   
 
                                  
                           

                                     

                                                                        
 
#include <algorithm>

#include <glog/logging.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

#include "libexpr/eval.hh"
#include "libmain/common-args.hh"
#include "libmain/shared.hh"
#include "libstore/download.hh"
#include "libstore/globals.hh"
#include "libstore/store-api.hh"
#include "libutil/finally.hh"
#include "nix/command.hh"
#include "nix/legacy.hh"

extern std::string chrootHelperName;

void chrootHelper(int argc, char** argv);

namespace nix {

/* Check if we have a non-loopback/link-local network interface. */
static bool haveInternet() {
  struct ifaddrs* addrs;

  if (getifaddrs(&addrs) != 0) {
    return true;
  }

  Finally free([&]() { freeifaddrs(addrs); });

  for (auto i = addrs; i != nullptr; i = i->ifa_next) {
    if (i->ifa_addr == nullptr) {
      continue;
    }
    if (i->ifa_addr->sa_family == AF_INET) {
      if (ntohl(((sockaddr_in*)i->ifa_addr)->sin_addr.s_addr) !=
          INADDR_LOOPBACK) {
        return true;
      }
    } else if (i->ifa_addr->sa_family == AF_INET6) {
      if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6*)i->ifa_addr)->sin6_addr) &&
          !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6*)i->ifa_addr)->sin6_addr)) {
        return true;
      }
    }
  }

  return false;
}

std::string programPath;

struct NixArgs : virtual MultiCommand, virtual MixCommonArgs {
  bool printBuildLogs = false;
  bool useNet = true;

  NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") {
    mkFlag()
        .longName("help")
        .description("show usage information")
        .handler([&]() { showHelpAndExit(); });

    mkFlag()
        .longName("help-config")
        .description("show configuration options")
        .handler([&]() {
          std::cout << "The following configuration options are available:\n\n";
          Table2 tbl;
          std::map<std::string, Config::SettingInfo> settings;
          globalConfig.getSettings(settings);
          for (const auto& s : settings) {
            tbl.emplace_back(s.first, s.second.description);
          }
          printTable(std::cout, tbl);
          throw Exit();
        });

    mkFlag()
        .longName("print-build-logs")
        .shortName('L')
        .description("print full build logs on stderr")
        .set(&printBuildLogs, true);

    mkFlag()
        .longName("version")
        .description("show version information")
        .handler([&]() { printVersion(programName); });

    mkFlag()
        .longName("no-net")
        .description(
            "disable substituters and consider all previously downloaded files "
            "up-to-date")
        .handler([&]() { useNet = false; });
  }

  void printFlags(std::ostream& out) override {
    Args::printFlags(out);
    std::cout << "\n"
                 "In addition, most configuration settings can be overriden "
                 "using '--<name> <value>'.\n"
                 "Boolean settings can be overriden using '--<name>' or "
                 "'--no-<name>'. See 'nix\n"
                 "--help-config' for a list of configuration settings.\n";
  }

  void showHelpAndExit() {
    printHelp(programName, std::cout);
    std::cout
        << "\nNote: this program is EXPERIMENTAL and subject to change.\n";
    throw Exit();
  }
};

void mainWrapped(int argc, char** argv) {
  /* The chroot helper needs to be run before any threads have been
     started. */
  if (argc > 0 && argv[0] == chrootHelperName) {
    chrootHelper(argc, argv);
    return;
  }

  initNix();
  initGC();

  programPath = argv[0];
  std::string programName = baseNameOf(programPath);

  {
    auto legacy = (*RegisterLegacyCommand::commands)[programName];
    if (legacy) {
      return legacy(argc, argv);
    }
  }

  settings.verboseBuild = false;

  NixArgs args;

  args.parseCmdline(argvToStrings(argc, argv));

  if (!args.command) {
    args.showHelpAndExit();
  }

  if (args.useNet && !haveInternet()) {
    LOG(WARNING) << "you don't have Internet access; "
                 << "disabling some network-dependent features";
    args.useNet = false;
  }

  if (!args.useNet) {
    // FIXME: should check for command line overrides only.
    if (!settings.useSubstitutes.overriden) {
      settings.useSubstitutes = false;
    }
    if (!settings.tarballTtl.overriden) {
      settings.tarballTtl = std::numeric_limits<unsigned int>::max();
    }
    if (!downloadSettings.tries.overriden) {
      downloadSettings.tries = 0;
    }
    if (!downloadSettings.connectTimeout.overriden) {
      downloadSettings.connectTimeout = 1;
    }
  }

  args.command->prepare();
  args.command->run();
}

}  // namespace nix

int main(int argc, char* argv[]) {
  FLAGS_logtostderr = true;
  google::InitGoogleLogging(argv[0]);

  return nix::handleExceptions(argv[0],
                               [&]() { nix::mainWrapped(argc, argv); });
}