commit 99437157b9e800c9893cc896f72c552613dd0cbd from: Stefan Sperling date: Sun Nov 11 11:52:59 2018 UTC abort checkout operations cleanly when Ctrl-C is hit commit - b2f7af546d38b360167a7e30a795ea9f2e91ddf7 commit + 99437157b9e800c9893cc896f72c552613dd0cbd blob - 0c2e16f0122e7333307b41c59b0e75ded7852697 blob + b0622d7e7922159864c1eb5833a27896e1480bad --- got/got.c +++ got/got.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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;