commit 6242c45bf7571868b35d644cd0655d3b007d60c9 from: Omar Polo date: Mon Nov 14 22:56:04 2022 UTC got send: show server error Print the error message reported by the remote server when failing to update a branch (for e.g. because of a server-side check.) Reported by gonzalo@, with help and ok stsp@. commit - b18b22548b5f83b9ec2eaf63b161fa5f76febdbc commit + 6242c45bf7571868b35d644cd0655d3b007d60c9 blob - b444c533995567c4ece649cbcf950cd7f365361e blob + 63af2b9f40b9e8782cba105f307f72d0a7180caa --- got/got.c +++ got/got.c @@ -8763,7 +8763,8 @@ struct got_send_progress_arg { static const struct got_error * send_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, - int nobj_written, off_t bytes_sent, const char *refname, int success) + int nobj_written, off_t bytes_sent, const char *refname, + const char *errmsg, int success) { struct got_send_progress_arg *a = arg; char scaled_packsize[FMT_SCALED_STRSIZE]; @@ -8795,6 +8796,8 @@ send_progress(void *arg, int ncolored, int nfound, int if (a->printed_something) putchar('\n'); printf("Server has %s %s", status, refname); + if (errmsg) + printf(": %s", errmsg); a->printed_something = 1; return NULL; } blob - 19e9e4f116e70c354ec4bbff8ce7e5a1615acd1f blob + 038b51f30308b8ca6879fdbddcfd64c6c83b7594 --- include/got_send.h +++ include/got_send.h @@ -38,7 +38,7 @@ const struct got_error *got_send_connect(pid_t *, int typedef const struct got_error *(*got_send_progress_cb)(void *, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, off_t bytes_sent, - const char *refname, int success); + const char *refname, const char *, int success); /* * Attempt to generate a pack file and sent it to a server. blob - f84d920be3d90fdc2c9b6db77113efd0d7d87c62 blob + 37d537ab48623fa50dd909cf2725e58151958e35 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -481,7 +481,9 @@ struct got_imsg_send_remote_ref { struct got_imsg_send_ref_status { int success; size_t name_len; + size_t errmsg_len; /* Followed by name_len data bytes. */ + /* Followed by errmsg_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_IDXPACK_REQUEST data. */ @@ -702,7 +704,7 @@ const struct got_error *got_privsep_recv_send_remote_r struct got_pathlist_head *, struct imsgbuf *); const struct got_error *got_privsep_send_packfd(struct imsgbuf *, int); const struct got_error *got_privsep_recv_send_progress(int *, off_t *, - int *, char **, struct imsgbuf *); + int *, char **, char **, struct imsgbuf *); const struct got_error *got_privsep_get_imsg_obj(struct got_object **, struct imsg *, struct imsgbuf *); const struct got_error *got_privsep_recv_obj(struct got_object **, blob - 175c3a0c4138ebc26f9e5160af4f028ccf1f46e7 blob + 174d412f27d59a5180400ca4bbd33f6a4b8e5564 --- lib/privsep.c +++ lib/privsep.c @@ -964,7 +964,7 @@ got_privsep_send_packfd(struct imsgbuf *ibuf, int fd) const struct got_error * got_privsep_recv_send_progress(int *done, off_t *bytes_sent, - int *success, char **refname, struct imsgbuf *ibuf) + int *success, char **refname, char **errmsg, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; @@ -975,6 +975,7 @@ got_privsep_recv_send_progress(int *done, off_t *bytes *done = 0; *success = 0; *refname = NULL; + *errmsg = NULL; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) @@ -995,13 +996,18 @@ got_privsep_recv_send_progress(int *done, off_t *bytes break; } memcpy(&iref_status, imsg.data, sizeof(iref_status)); - if (datalen != sizeof(iref_status) + iref_status.name_len) { + if (datalen != sizeof(iref_status) + iref_status.name_len + + iref_status.errmsg_len) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } *success = iref_status.success; *refname = strndup(imsg.data + sizeof(iref_status), iref_status.name_len); + + if (iref_status.errmsg_len != 0) + *errmsg = strndup(imsg.data + sizeof(iref_status) + + iref_status.name_len, iref_status.errmsg_len); break; case GOT_IMSG_SEND_DONE: if (datalen != 0) { blob - f916422dab87523c5b073b161f9ba85ad2f970b2 blob + ade0d5069d9f6bac709c4e0f2ea1dac629315b46 --- lib/send.c +++ lib/send.c @@ -126,7 +126,7 @@ pack_progress(void *arg, int ncolored, int nfound, int err = a->progress_cb(a->progress_arg, ncolored, nfound, ntrees, packfile_size, ncommits, nobj_total, nobj_deltify, - nobj_written, 0, NULL, 0); + nobj_written, 0, NULL, NULL, 0); if (err) return err; @@ -670,13 +670,15 @@ got_send_pack(const char *remote_name, struct got_path while (!done) { int success = 0; char *refname = NULL; + char *errmsg = NULL; + if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) goto done; } err = got_privsep_recv_send_progress(&done, &bytes_sent, - &success, &refname, &sendibuf); + &success, &refname, &errmsg, &sendibuf); if (err) goto done; if (refname && got_ref_name_is_valid(refname) && success && @@ -700,14 +702,16 @@ got_send_pack(const char *remote_name, struct got_path ppa.nfound, ppa.ntrees, ppa.packfile_size, ppa.ncommits, ppa.nobj_total, ppa.nobj_deltify, ppa.nobj_written, bytes_sent, - refname, success); + refname, errmsg, success); if (err) { free(refname); + free(errmsg); goto done; } bytes_sent_cur = bytes_sent; } free(refname); + free(errmsg); } done: if (sendpid != -1) { blob - c773102729c2714c83c3b63b36a5ce9699aba978 blob + 07a27f7715950303cc9130d9ed1920c3bd9ec96c --- libexec/got-send-pack/Makefile +++ libexec/got-send-pack/Makefile @@ -5,7 +5,7 @@ PROG= got-send-pack SRCS= got-send-pack.c error.c inflate.c object_parse.c \ path.c privsep.c sha1.c pkt.c gitproto.c ratelimit.c \ - pollfd.c + pollfd.c reference_parse.c CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib blob - e4d0f25b9ed093ef2eedaffd7a65b3d05e786a3e blob + 7069d8b17d0928e260d85033e81ff7ac104c27dd --- libexec/got-send-pack/got-send-pack.c +++ libexec/got-send-pack/got-send-pack.c @@ -223,10 +223,11 @@ send_ref_status(struct imsgbuf *ibuf, const char *refn struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs) { struct ibuf *wbuf; - size_t len, reflen = strlen(refname); + size_t i, len, reflen, errmsglen = 0; struct got_pathlist_entry *pe; int ref_valid = 0; - char *eol; + char *eol, *sp; + const char *errmsg = ""; eol = strchr(refname, '\n'); if (eol == NULL) { @@ -234,7 +235,28 @@ send_ref_status(struct imsgbuf *ibuf, const char *refn "unexpected message from server"); } *eol = '\0'; + + sp = strchr(refname, ' '); + if (sp != NULL) { + *sp++ = '\0'; + errmsg = sp; + errmsglen = strlen(errmsg); + + for (i = 0; i < errmsglen; ++i) { + if (!isprint((unsigned char)errmsg[i])) { + return got_error_msg(GOT_ERR_BAD_PACKET, + "non-printable error message received " + "from the server"); + } + } + } + reflen = strlen(refname); + if (!got_ref_name_is_valid(refname)) { + return got_error_msg(GOT_ERR_BAD_PACKET, + "unexpected message from server"); + } + TAILQ_FOREACH(pe, refs, entry) { if (strcmp(refname, pe->path) == 0) { ref_valid = 1; @@ -254,7 +276,7 @@ send_ref_status(struct imsgbuf *ibuf, const char *refn "unexpected message from server"); } - len = sizeof(struct got_imsg_send_ref_status) + reflen; + len = sizeof(struct got_imsg_send_ref_status) + reflen + errmsglen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); @@ -268,8 +290,12 @@ send_ref_status(struct imsgbuf *ibuf, const char *refn return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); + if (imsg_add(wbuf, &errmsglen, sizeof(errmsglen)) == -1) + return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); + if (imsg_add(wbuf, errmsg, errmsglen) == -1) + return got_error_from_errno("imsg_add SEND_REF_STATUS"); wbuf->fd = -1; imsg_close(ibuf, wbuf); blob - f989b0dbd6a3ca710184d881f574e55a5eb83e78 blob + 2bfbfe22cdf4a0255e78921e2da2bfcc76ffb03c --- regress/cmdline/send.sh +++ regress/cmdline/send.sh @@ -1511,6 +1511,69 @@ EOF git_fsck "$testroot" "$testroot/repo-clone" ret=$? test_done "$testroot" "$ret" +} + +test_send_rejected() { + local testroot=`test_init send_rejected` + local testurl=ssh://127.0.0.1/$testroot + local commit_id=`git_show_head $testroot/repo` + + if ! got clone -q "$testurl/repo" "$testroot/repo-clone"; then + echo "got clone command failed unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + mkdir "$testroot/repo-clone/hooks" + cat <<'EOF' >$testroot/repo-clone/hooks/update +case "$1" in +*master*) + echo "rejecting push on master branch" + exit 1 + ;; +esac +exit 0 +EOF + chmod +x "$testroot/repo-clone/hooks/update" + + cat > $testroot/repo/.git/got.conf <$testroot/repo/alpha + git_commit "$testroot/repo" -m "modified alpha" + + got send -q -r "$testroot/repo" >$testroot/stdout 2>$testroot/stderr + ret=$? + if [ $ret -ne 0 ]; then + echo "got send command failed unexpectedly" >&2 + test_done "$testroot" $ret + return 1 + fi + + touch "$testroot/stdout.expected" + if ! cmp -s "$testroot/stdout.expected" "$testroot/stdout"; then + diff -u "$testroot/stdout.expected" "$testroot/stdout" + test_done "$testroot" 1 + return 1 + fi + + cat <$testroot/stderr.expected +rejecting push on master branch +error: hook declined to update refs/heads/master +EOF + + if ! cmp -s "$testroot/stderr.expected" "$testroot/stderr"; then + diff -u "$testroot/stderr.expected" "$testroot/stderr" + test_done "$testroot" 1 + return 1 + fi + + test_done "$testroot" 0 } test_parseargs "$@" @@ -1526,3 +1589,4 @@ run_test test_send_all_branches run_test test_send_to_empty_repo run_test test_send_and_fetch_config run_test test_send_config +run_test test_send_rejected