about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc2
-rw-r--r--src/libexpr/nixexpr.cc4
-rw-r--r--src/libexpr/parser.cc2
-rw-r--r--src/libmain/shared.cc15
-rw-r--r--src/libstore/db.cc9
-rw-r--r--src/libstore/exec.cc4
-rw-r--r--src/libstore/normalise.cc6
-rw-r--r--src/libstore/pathlocks.cc7
-rw-r--r--src/libstore/references.cc3
-rw-r--r--src/libstore/store.cc2
-rw-r--r--src/libutil/archive.cc6
-rw-r--r--src/libutil/util.cc17
-rw-r--r--src/libutil/util.hh13
13 files changed, 86 insertions, 4 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index f6634e8921a5..0470deee9c0c 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -227,6 +227,8 @@ Expr evalExpr2(EvalState & state, Expr e)
 
 Expr evalExpr(EvalState & state, Expr e)
 {
+    checkInterrupt();
+    
     startNest(nest, lvlVomit,
         format("evaluating expression: %1%") % e);
 
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 816b39dc1ae3..dd0f5d58af27 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -87,6 +87,8 @@ string aterm2String(ATerm t)
 
 ATerm bottomupRewrite(TermFun & f, ATerm e)
 {
+    checkInterrupt();
+
     if (ATgetType(e) == AT_APPL) {
         AFun fun = ATgetAFun(e);
         int arity = ATgetArity(fun);
@@ -149,6 +151,8 @@ Expr makeAttrs(const ATermMap & attrs)
 
 Expr substitute(const ATermMap & subs, Expr e)
 {
+    checkInterrupt();
+
     ATMatcher m;
     string s;
 
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc
index b9e79e13d5f1..83b656342ff8 100644
--- a/src/libexpr/parser.cc
+++ b/src/libexpr/parser.cc
@@ -26,6 +26,8 @@ struct Cleanup : TermFun
 
     virtual ATerm operator () (ATerm e)
     {
+        checkInterrupt();
+        
         ATMatcher m;
         string s;
 
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 24bedb3fb63b..17d4dda6703a 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -12,6 +12,12 @@ extern "C" {
 #include "config.h"
 
 
+void sigintHandler(int signo)
+{
+    _isInterrupted = 1;
+}
+
+
 /* Initialize and reorder arguments, then call the actual argument
    processor. */
 static void initAndRun(int argc, char * * argv)
@@ -23,6 +29,15 @@ static void initAndRun(int argc, char * * argv)
     nixStateDir = (string) NIX_STATE_DIR;
     nixDBPath = (string) NIX_STATE_DIR + "/db";
 
+    /* Catch SIGINT. */
+    struct sigaction act, oact;
+    act.sa_handler = sigintHandler;
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    if (sigaction(SIGINT, &act, &oact))
+        throw SysError("installing handler for SIGINT");
+    printMsg(lvlError, "SIG HANDLER INSTALLED");
+
     /* Put the arguments in a vector. */
     Strings args, remaining;
     while (argc--) args.push_back(*argv++);
diff --git a/src/libstore/db.cc b/src/libstore/db.cc
index c89d6b197d7c..d2a0026384b0 100644
--- a/src/libstore/db.cc
+++ b/src/libstore/db.cc
@@ -80,6 +80,7 @@ void Transaction::moveTo(Transaction & t)
 
 void Database::requireEnv()
 {
+    checkInterrupt();
     if (!env) throw Error("database environment not open");
 }
 
@@ -310,6 +311,8 @@ TableId Database::openTable(const string & tableName)
 bool Database::queryString(const Transaction & txn, TableId table, 
     const string & key, string & data)
 {
+    checkInterrupt();
+
     try {
         Db * db = getDb(table);
 
@@ -367,6 +370,7 @@ bool Database::queryStrings(const Transaction & txn, TableId table,
 void Database::setString(const Transaction & txn, TableId table,
     const string & key, const string & data)
 {
+    checkInterrupt();
     try {
         Db * db = getDb(table);
         Dbt kt((void *) key.c_str(), key.length());
@@ -402,6 +406,7 @@ void Database::setStrings(const Transaction & txn, TableId table,
 void Database::delPair(const Transaction & txn, TableId table,
     const string & key)
 {
+    checkInterrupt();
     try {
         Db * db = getDb(table);
         Dbt kt((void *) key.c_str(), key.length());
@@ -423,9 +428,11 @@ void Database::enumTable(const Transaction & txn, TableId table,
         DestroyDbc destroyDbc(dbc);
 
         Dbt kt, dt;
-        while (dbc->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND)
+        while (dbc->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND) {
+            checkInterrupt();
             keys.push_back(
                 string((char *) kt.get_data(), kt.get_size()));
+        }
 
     } catch (DbException e) { rethrow(e); }
 }
diff --git a/src/libstore/exec.cc b/src/libstore/exec.cc
index b25423b4449a..01577143dc9e 100644
--- a/src/libstore/exec.cc
+++ b/src/libstore/exec.cc
@@ -108,7 +108,9 @@ void runProgram(const string & program,
     int status;
     if (waitpid(pid, &status, 0) != pid)
         throw Error("unable to wait for child");
-    
+
+    checkInterrupt();
+
     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
 	if (keepFailed) {
 	    printMsg(lvlTalkative, 
diff --git a/src/libstore/normalise.cc b/src/libstore/normalise.cc
index 7ef45e292352..51f90207ead3 100644
--- a/src/libstore/normalise.cc
+++ b/src/libstore/normalise.cc
@@ -96,6 +96,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
     for (PathSet::iterator i = ne.derivation.inputs.begin();
          i != ne.derivation.inputs.end(); i++)
     {
+        checkInterrupt();
         Path nfPath = normaliseStoreExpr(*i, pending);
         realiseClosure(nfPath, pending);
         /* !!! nfPath should be a root of the garbage collector while
@@ -193,6 +194,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
         for (Paths::iterator j = refPaths.begin();
 	     j != refPaths.end(); j++)
 	{
+            checkInterrupt();
 	    Path path = *j;
 	    elem.refs.insert(path);
             if (inClosures.find(path) != inClosures.end())
@@ -209,6 +211,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
     PathSet donePaths;
 
     while (!usedPaths.empty()) {
+        checkInterrupt();
 	PathSet::iterator i = usedPaths.begin();
 	Path path = *i;
 	usedPaths.erase(i);
@@ -291,6 +294,7 @@ void ensurePath(const Path & path, PathSet pending)
     for (Paths::iterator i = subPaths.begin(); 
          i != subPaths.end(); i++)
     {
+        checkInterrupt();
         try {
             normaliseStoreExpr(*i, pending);
             if (isValidPath(path)) return;
@@ -337,6 +341,8 @@ static void requisitesWorker(const Path & nePath,
     bool includeExprs, bool includeSuccessors,
     PathSet & paths, PathSet & doneSet)
 {
+    checkInterrupt();
+    
     if (doneSet.find(nePath) != doneSet.end()) return;
     doneSet.insert(nePath);
 
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 321e965bb34b..d4f980c6487c 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -19,11 +19,14 @@ bool lockFile(int fd, LockType lockType, bool wait)
     lock.l_len = 0; /* entire file */
 
     if (wait) {
-        while (fcntl(fd, F_SETLKW, &lock) != 0)
+        while (fcntl(fd, F_SETLKW, &lock) != 0) {
+            checkInterrupt();
             if (errno != EINTR)
                 throw SysError(format("acquiring/releasing lock"));
+        }
     } else {
         while (fcntl(fd, F_SETLK, &lock) != 0) {
+            checkInterrupt();
             if (errno == EACCES || errno == EAGAIN) return false;
             if (errno != EINTR) 
                 throw SysError(format("acquiring/releasing lock"));
@@ -55,6 +58,7 @@ PathLocks::PathLocks(const PathSet & _paths)
     
     /* Acquire the lock for each path. */
     for (Paths::iterator i = paths.begin(); i != paths.end(); i++) {
+        checkInterrupt();
         Path path = *i;
         Path lockPath = path + ".lock";
 
@@ -87,6 +91,7 @@ PathLocks::~PathLocks()
         close(*i);
 
     for (Paths::iterator i = paths.begin(); i != paths.end(); i++) {
+        checkInterrupt();
         if (deletePaths) {
             /* This is not safe in general! */
             unlink(i->c_str());
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 2daf4d4f4d0a..9b20b980a1b2 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -17,6 +17,7 @@ static void search(const string & s,
     for (Strings::iterator i = ids.begin();
          i != ids.end(); )
     {
+        checkInterrupt();
         if (s.find(*i) == string::npos)
             i++;
         else {
@@ -31,6 +32,8 @@ static void search(const string & s,
 void checkPath(const string & path,
     Strings & ids, Strings & seen)
 {
+    checkInterrupt();
+    
     struct stat st;
     if (lstat(path.c_str(), &st))
         throw SysError(format("getting attributes of path `%1%'") % path);
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index c1d95ab8c5b9..4cd77796ea36 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -133,7 +133,7 @@ void copyPath(const Path & src, const Path & dst)
             source.fd = fds[0];
             restorePath(dst, source);
             _exit(0);
-        }  catch (exception & e) {
+        } catch (exception & e) {
             cerr << "error: " << e.what() << endl;
         }
         _exit(1);        
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 90a039164b58..2b8fb2f10adb 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -83,6 +83,7 @@ static void dumpContents(const Path & path, unsigned int size,
     unsigned int total = 0;
     ssize_t n;
     while ((n = read(fd, buf, sizeof(buf)))) {
+        checkInterrupt();
         if (n == -1) throw SysError("reading file " + path);
         total += n;
         sink(buf, n);
@@ -200,6 +201,8 @@ static void restoreEntry(const Path & path, RestoreSource & source)
     if (s != "(") throw badArchive("expected open tag");
 
     while (1) {
+        checkInterrupt();
+
         s = readString(source);
 
         if (s == ")") {
@@ -224,6 +227,7 @@ static void restoreContents(int fd, const Path & path, RestoreSource & source)
     unsigned char buf[65536];
 
     while (left) {
+        checkInterrupt();
         unsigned int n = sizeof(buf);
         if (n > left) n = left;
         source(buf, n);
@@ -247,6 +251,8 @@ static void restore(const Path & path, RestoreSource & source)
     AutoCloseFD fd;
 
     while (1) {
+        checkInterrupt();
+
         s = readString(source);
 
         if (s == ")") {
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 28e276a329b3..5c8b7279c42d 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -132,6 +132,7 @@ Strings readDirectory(const Path & path)
 
     struct dirent * dirent;
     while (errno = 0, dirent = readdir(dir)) { /* sic */
+        checkInterrupt();
         string name = dirent->d_name;
         if (name == "." || name == "..") continue;
         names.push_back(name);
@@ -144,6 +145,8 @@ Strings readDirectory(const Path & path)
 
 void deletePath(const Path & path)
 {
+    checkInterrupt();
+
     printMsg(lvlVomit, format("deleting path `%1%'") % path);
 
     struct stat st;
@@ -170,6 +173,8 @@ void deletePath(const Path & path)
 
 void makePathReadOnly(const Path & path)
 {
+    checkInterrupt();
+
     struct stat st;
     if (lstat(path.c_str(), &st))
 	throw SysError(format("getting attributes of path `%1%'") % path);
@@ -199,6 +204,7 @@ static Path tempName()
 Path createTempDir()
 {
     while (1) {
+        checkInterrupt();
 	Path tmpDir = tempName();
 	if (mkdir(tmpDir.c_str(), 0777) == 0) return tmpDir;
 	if (errno != EEXIST)
@@ -246,6 +252,7 @@ void Nest::open(Verbosity level, const format & f)
 
 void printMsg_(Verbosity level, const format & f)
 {
+    checkInterrupt();
     if (level > verbosity) return;
     string spaces;
     for (int i = 0; i < nestingLevel; i++)
@@ -257,6 +264,7 @@ void printMsg_(Verbosity level, const format & f)
 void readFull(int fd, unsigned char * buf, size_t count)
 {
     while (count) {
+        checkInterrupt();
         ssize_t res = read(fd, (char *) buf, count);
         if (res == -1) throw SysError("reading from file");
         if (res == 0) throw Error("unexpected end-of-file");
@@ -269,6 +277,7 @@ void readFull(int fd, unsigned char * buf, size_t count)
 void writeFull(int fd, const unsigned char * buf, size_t count)
 {
     while (count) {
+        checkInterrupt();
         ssize_t res = write(fd, (char *) buf, count);
         if (res == -1) throw SysError("writing to file");
         count -= res;
@@ -344,3 +353,11 @@ AutoCloseDir::operator DIR *()
     return dir;
 }
 
+
+volatile sig_atomic_t _isInterrupted = 0;
+
+void _interrupted()
+{
+    _isInterrupted = 0;
+    throw Error("interrupted by the user");
+}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 5d27ac1bddb4..34fff003b88f 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <unistd.h>
+#include <signal.h>
 
 #include <boost/format.hpp>
 
@@ -179,4 +180,16 @@ public:
 };
 
 
+/* User interruption. */
+
+extern volatile sig_atomic_t _isInterrupted;
+
+void _interrupted();
+
+void inline checkInterrupt()
+{
+    if (_isInterrupted) _interrupted();
+}
+
+
 #endif /* !__UTIL_H */