Commit Diff


commit - b2f7af546d38b360167a7e30a795ea9f2e91ddf7
commit + 99437157b9e800c9893cc896f72c552613dd0cbd
blob - 0c2e16f0122e7333307b41c59b0e75ded7852697
blob + b0622d7e7922159864c1eb5833a27896e1480bad
--- got/got.c
+++ got/got.c
@@ -23,6 +23,7 @@
 #include <err.h>
 #include <errno.h>
 #include <locale.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -42,7 +43,23 @@
 #ifndef nitems
 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
 #endif
+
+static volatile sig_atomic_t sigint_received;
+static volatile sig_atomic_t sigpipe_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
+
+static void
+catch_sigpipe(int signo)
+{
+	sigpipe_received = 1;
+}
 
+
 struct cmd {
 	const char	 *cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[]);
@@ -111,6 +128,9 @@ main(int argc, char *argv[])
 	if (argc <= 0)
 		usage();
 
+	signal(SIGINT, catch_sigint);
+	signal(SIGPIPE, catch_sigpipe);
+
 	for (i = 0; i < nitems(got_commands); i++) {
 		const struct got_error *error;
 
@@ -166,6 +186,14 @@ checkout_progress(void *arg, const char *path)
 		path++;
 
 	printf("A  %s/%s\n", worktree_path, path);
+}
+
+static const struct got_error *
+checkout_cancel(void *arg)
+{
+	if (sigint_received || sigpipe_received)
+		return got_error(GOT_ERR_CANCELLED);
+	return NULL;
 }
 
 static const struct got_error *
@@ -256,7 +284,7 @@ cmd_checkout(int argc, char *argv[])
 		goto done;
 
 	error = got_worktree_checkout_files(worktree, head_ref, repo,
-	    checkout_progress, worktree_path);
+	    checkout_progress, worktree_path, checkout_cancel, NULL);
 	if (error != NULL)
 		goto done;
 
blob - 4376f1b7a87bae66bf181b0a5134e50a53b24b93
blob + 1a82e737da3bdb1b65c894d3ba816343eb9e0910
--- include/got_error.h
+++ include/got_error.h
@@ -62,6 +62,7 @@
 #define GOT_ERR_ITER_COMPLETED	46
 #define GOT_ERR_RANGE		47
 #define GOT_ERR_EXPECTED	48 /* for use in regress tests only */
+#define GOT_ERR_CANCELLED	49
 
 static const struct got_error {
 	int code;
@@ -112,6 +113,7 @@ static const struct got_error {
 	{ GOT_ERR_ITER_COMPLETED,"iteration completed" },
 	{ GOT_ERR_RANGE,	"value out of range" },
 	{ GOT_ERR_EXPECTED,	"expected an error but have no error" },
+	{ GOT_ERR_CANCELLED,	"operation in progress has been cancelled" },
 };
 
 /*
blob - f4b03a494564fac33bc5f2de11b332218ec37eed
blob + 806d598ff338396a2c65dc8d684657dde47f4316
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -51,6 +51,10 @@ char  *got_worktree_get_head_ref_name(struct got_workt
 /* A callback function which is invoked when a path is checked out. */
 typedef void (*got_worktree_checkout_cb)(void *, const char *);
 
+/* A callback function which is invoked at cancellation points.
+ * May return GOT_ERR_CANCELLED to abort the runing operation. */
+typedef const struct got_error *(*got_worktree_cancel_cb)(void *);
+
 /*
  * Attempt to check out files into a work tree from its associated repository
  * and path prefix, and update the work tree's file index accordingly.
@@ -61,4 +65,5 @@ typedef void (*got_worktree_checkout_cb)(void *, const
  */
 const struct got_error *got_worktree_checkout_files(struct got_worktree *,
     struct got_reference *, struct got_repository *,
-    got_worktree_checkout_cb progress, void *);
+    got_worktree_checkout_cb progress, void *,
+    got_worktree_cancel_cb, void *);
blob - d93818fe53197d1dd8f8e7737b6837d4411b46c6
blob + 20f110b3b35b2536e85df68f177a3d4dde90379c
--- lib/worktree.c
+++ lib/worktree.c
@@ -470,13 +470,15 @@ done:
 static const struct got_error *
 tree_checkout(struct got_worktree *, struct got_fileindex *,
     struct got_tree_object *, const char *, struct got_repository *,
-    got_worktree_checkout_cb progress_cb, void *progress_arg);
+    got_worktree_checkout_cb progress_cb, void *progress_arg,
+    got_worktree_cancel_cb cancel_cb, void *cancel_arg);
 
 static const struct got_error *
 tree_checkout_entry(struct got_worktree *worktree,
     struct got_fileindex *fileindex, struct got_tree_entry *te,
     const char *parent, struct got_repository *repo,
-    got_worktree_checkout_cb progress_cb, void *progress_arg)
+    got_worktree_checkout_cb progress_cb, void *progress_arg,
+    got_worktree_cancel_cb cancel_cb, void *cancel_arg)
 {
 	const struct got_error *err = NULL;
 	struct got_object *obj = NULL;
@@ -525,8 +527,9 @@ tree_checkout_entry(struct got_worktree *worktree,
 			if (err)
 				break;
 		}
+		/* XXX infinite recursion possible */
 		err = tree_checkout(worktree, fileindex, tree, path, repo,
-		    progress_cb, progress_arg);
+		    progress_cb, progress_arg, cancel_cb, cancel_arg);
 		break;
 	default:
 		break;
@@ -547,7 +550,8 @@ static const struct got_error *
 tree_checkout(struct got_worktree *worktree,
     struct got_fileindex *fileindex, struct got_tree_object *tree,
     const char *path, struct got_repository *repo,
-    got_worktree_checkout_cb progress_cb, void *progress_arg)
+    got_worktree_checkout_cb progress_cb, void *progress_arg,
+    got_worktree_cancel_cb cancel_cb, void *cancel_arg)
 {
 	const struct got_error *err = NULL;
 	const struct got_tree_entries *entries;
@@ -561,8 +565,13 @@ tree_checkout(struct got_worktree *worktree,
 
 	entries = got_object_tree_get_entries(tree);
 	SIMPLEQ_FOREACH(te, &entries->head, entry) {
+		if (cancel_cb) {
+			err = (*cancel_cb)(cancel_arg);
+			if (err)
+				break;
+		}
 		err = tree_checkout_entry(worktree, fileindex, te, path, repo,
-		    progress_cb, progress_arg);
+		    progress_cb, progress_arg, cancel_cb, cancel_arg);
 		if (err)
 			break;
 	}
@@ -573,7 +582,8 @@ tree_checkout(struct got_worktree *worktree,
 const struct got_error *
 got_worktree_checkout_files(struct got_worktree *worktree,
     struct got_reference *head_ref, struct got_repository *repo,
-    got_worktree_checkout_cb progress_cb, void *progress_arg)
+    got_worktree_checkout_cb progress_cb, void *progress_arg,
+    got_worktree_cancel_cb cancel_cb, void *cancel_arg)
 {
 	const struct got_error *err = NULL, *unlockerr;
 	struct got_object_id *commit_id = NULL;
@@ -637,7 +647,7 @@ got_worktree_checkout_files(struct got_worktree *workt
 		goto done;
 
 	err = tree_checkout(worktree, fileindex, tree, "/", repo,
-	    progress_cb, progress_arg);
+	    progress_cb, progress_arg, cancel_cb, cancel_arg);
 	if (err)
 		goto done;
 
blob - 071331070dc68817f9f11f2dee7249493215e227
blob + d33d70db40ff1313b717c0429c1b3ac7209086d0
--- libexec/got-read-blob/got-read-blob.c
+++ libexec/got-read-blob/got-read-blob.c
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <imsg.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +39,14 @@
 #include "got_lib_object_parse.h"
 #include "got_lib_privsep.h"
 
+static volatile sig_atomic_t sigint_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -45,6 +54,8 @@ main(int argc, char *argv[])
 	struct imsgbuf ibuf;
 	size_t datalen;
 
+	signal(SIGINT, catch_sigint);
+
 	imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
 
 #ifndef PROFILE
@@ -66,6 +77,11 @@ main(int argc, char *argv[])
 		memset(&imsg_outfd, 0, sizeof(imsg_outfd));
 		imsg_outfd.fd = -1;
 
+		if (sigint_received) {
+			err = got_error(GOT_ERR_CANCELLED);
+			break;
+		}
+
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
 			if (err->code == GOT_ERR_PRIVSEP_PIPE)
@@ -136,18 +152,16 @@ done:
 			close(imsg_outfd.fd);
 		imsg_free(&imsg);
 		imsg_free(&imsg_outfd);
-		if (err) {
-			if (err->code == GOT_ERR_PRIVSEP_PIPE)
-				err = NULL;
-			else
-				got_privsep_send_error(&ibuf, err);
+		if (err)
 			break;
-		}
 	}
 
 	imsg_clear(&ibuf);
-	if (err)
+	if (err) {
 		fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+		if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE)
+			got_privsep_send_error(&ibuf, err);
+	}
 	close(GOT_IMSG_FD_CHILD);
 	return err ? 1 : 0;
 }
blob - f6b5435605333d42433c5981a64efdc3cb4b18e6
blob + 56aac6aa18b45fe6f13d9723d5bfbdb18fc6024a
--- libexec/got-read-commit/got-read-commit.c
+++ libexec/got-read-commit/got-read-commit.c
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <imsg.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +39,14 @@
 #include "got_lib_object_parse.h"
 #include "got_lib_privsep.h"
 
+static volatile sig_atomic_t sigint_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
+
 static const struct got_error *
 read_commit_object(struct got_commit_object **commit, struct got_object *obj,
     FILE *f)
@@ -74,6 +83,8 @@ main(int argc, char *argv[])
 	struct imsgbuf ibuf;
 	size_t datalen;
 
+	signal(SIGINT, catch_sigint);
+
 	imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
 
 #ifndef PROFILE
@@ -90,6 +101,11 @@ main(int argc, char *argv[])
 		struct got_imsg_object iobj;
 		FILE *f = NULL;
 		struct got_object *obj = NULL;
+
+		if (sigint_received) {
+			err = got_error(GOT_ERR_CANCELLED);
+			break;
+		}
 	
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
@@ -152,18 +168,16 @@ done:
 		imsg_free(&imsg);
 		if (obj)
 			got_object_close(obj);
-		if (err) {
-			if (err->code == GOT_ERR_PRIVSEP_PIPE)
-				err = NULL;
-			else
-				got_privsep_send_error(&ibuf, err);
+		if (err)
 			break;
-		}
 	}
 
 	imsg_clear(&ibuf);
-	if (err)
+	if (err) {
 		fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+		if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE)
+			got_privsep_send_error(&ibuf, err);
+	}
 	close(GOT_IMSG_FD_CHILD);
 	return err ? 1 : 0;
 }
blob - baca7732ad9c42e87766cbc54a518a7321fb69ea
blob + 8f4ccd362c7963a8af97740e51adb99adef55a5f
--- libexec/got-read-object/got-read-object.c
+++ libexec/got-read-object/got-read-object.c
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <imsg.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -45,6 +46,14 @@
 #define GOT_OBJ_TAG_TREE	"tree"
 #define GOT_OBJ_TAG_BLOB	"blob"
 
+static volatile sig_atomic_t sigint_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
+
 static const struct got_error *
 parse_object_header(struct got_object **obj, char *buf, size_t len)
 {
@@ -154,6 +163,8 @@ main(int argc, char *argv[])
 	struct imsgbuf ibuf;
 	size_t datalen;
 
+	signal(SIGINT, catch_sigint);
+
 	imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
 
 #ifndef PROFILE
@@ -166,6 +177,11 @@ main(int argc, char *argv[])
 #endif
 
 	while (1) {
+		if (sigint_received) {
+			err = got_error(GOT_ERR_CANCELLED);
+			break;
+		}
+
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
 			if (err->code == GOT_ERR_PRIVSEP_PIPE)
@@ -197,18 +213,16 @@ done:
 		imsg_free(&imsg);
 		if (obj)
 			got_object_close(obj);
-		if (err) {
-			if (err->code == GOT_ERR_PRIVSEP_PIPE)
-				err = NULL;
-			else
-				got_privsep_send_error(&ibuf, err);
+		if (err)
 			break;
-		}
 	}
 
 	imsg_clear(&ibuf);
-	if (err)
+	if (err) {
 		fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+		if(!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE)
+			got_privsep_send_error(&ibuf, err);
+	}
 	close(GOT_IMSG_FD_CHILD);
 	return err ? 1 : 0;
 }
blob - 010b14b5519db260c50522b9ffb8d93182af1675
blob + debf11401b6553196d83b1b302a0426e77b030a6
--- libexec/got-read-pack/got-read-pack.c
+++ libexec/got-read-pack/got-read-pack.c
@@ -23,6 +23,7 @@
 #include <sys/mman.h>
 
 #include <limits.h>
+#include <signal.h>
 #include <stdint.h>
 #include <imsg.h>
 #include <stdio.h>
@@ -42,6 +43,14 @@
 #include "got_lib_privsep.h"
 #include "got_lib_pack.h"
 
+static volatile sig_atomic_t sigint_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
+
 static const struct got_error *
 object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
     struct got_packidx *packidx, struct got_object_cache *objcache)
@@ -412,6 +421,8 @@ main(int argc, char *argv[])
 	//static int attached;
 	//while (!attached) sleep(1);
 
+	signal(SIGINT, catch_sigint);
+
 	imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
 
 	err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
@@ -444,6 +455,11 @@ main(int argc, char *argv[])
 
 	while (1) {
 		imsg.fd = -1;
+
+		if (sigint_received) {
+			err = got_error(GOT_ERR_CANCELLED);
+			break;
+		}
 
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
@@ -480,13 +496,8 @@ main(int argc, char *argv[])
 		if (imsg.fd != -1)
 			close(imsg.fd);
 		imsg_free(&imsg);
-		if (err) {
-			if (err->code == GOT_ERR_PRIVSEP_PIPE)
-				err = NULL;
-			else
-				got_privsep_send_error(&ibuf, err);
+		if (err)
 			break;
-		}
 	}
 
 	if (packidx)
@@ -495,8 +506,11 @@ main(int argc, char *argv[])
 		got_pack_close(pack);
 	got_object_cache_close(&objcache);
 	imsg_clear(&ibuf);
-	if (err)
+	if (err) {
 		fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+		if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE)
+			got_privsep_send_error(&ibuf, err);
+	}
 	close(GOT_IMSG_FD_CHILD);
 	return err ? 1 : 0;
 }
blob - 5abd5641f7bf4ae26e07d409b477b3de8140d6bf
blob + 176d429702fa94a803327cbdae31975f748bf235
--- libexec/got-read-tree/got-read-tree.c
+++ libexec/got-read-tree/got-read-tree.c
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <imsg.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +39,13 @@
 #include "got_lib_object_parse.h"
 #include "got_lib_privsep.h"
 
+static volatile sig_atomic_t sigint_received;
+
+static void
+catch_sigint(int signo)
+{
+	sigint_received = 1;
+}
 static const struct got_error *
 read_tree_object(struct got_tree_object **tree, struct got_object *obj, FILE *f)
 {
@@ -73,6 +81,8 @@ main(int argc, char *argv[])
 	struct imsgbuf ibuf;
 	size_t datalen;
 
+	signal(SIGINT, catch_sigint);
+
 	imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
 
 #ifndef PROFILE
@@ -89,6 +99,11 @@ main(int argc, char *argv[])
 		struct got_imsg_object iobj;
 		FILE *f = NULL;
 		struct got_object *obj = NULL;
+
+		if (sigint_received) {
+			err = got_error(GOT_ERR_CANCELLED);
+			break;
+		}
 	
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
@@ -151,18 +166,16 @@ done:
 		imsg_free(&imsg);
 		if (obj)
 			got_object_close(obj);
-		if (err) {
-			if (err->code == GOT_ERR_PRIVSEP_PIPE)
-				err = NULL;
-			else
-				got_privsep_send_error(&ibuf, err);
+		if (err)
 			break;
-		}
 	}
 
 	imsg_clear(&ibuf);
-	if (err)
+	if (err) {
 		fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+		if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE)
+			got_privsep_send_error(&ibuf, err);
+	}
 	close(GOT_IMSG_FD_CHILD);
 	return err ? 1 : 0;
 }
blob - 1b97298bec1b9a653524d535083509cbe7aa0d27
blob + f5e074fbbd708429bf097a89be6a2ad5af0605aa
--- regress/worktree/worktree_test.c
+++ regress/worktree/worktree_test.c
@@ -335,7 +335,7 @@ worktree_checkout(const char *repo_path)
 		goto done;
 
 	err = got_worktree_checkout_files(worktree, head_ref, repo,
-	    process_cb, NULL);
+	    process_cb, NULL, NULL, NULL);
 	if (err != NULL)
 		goto done;