{"thread":{"id":"9249","subject":"[PATCH] Make verify-tag a builtin.","startedAt":"2007-07-27T04:07:34Z","lastAt":"2007-07-28T18:02:09Z","messageCount":5,"participants":["Carlos Rica","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"48750","messageId":"46A96F86.2030704@gmail.com","threadId":"9249","inReplyTo":null,"subject":"[PATCH] Make verify-tag a builtin.","fromName":"Carlos Rica","fromEmail":"jasampler@gmail.com","sentAt":"2007-07-27T04:07:34Z","receivedAt":"2007-07-27T04:07:34Z","isPatch":true,"sender":{"key":"jasampler@gmail.com","avatar":null},"body":"This replaces \"git-verify-tag.sh\" with \"builtin-verify-tag.c\".\n\nTesting relies on the \"git tag -v\" tests calling this command.\n\nA temporary file is needed when calling to gpg, because git is\nalready creating detached signatures (gpg option -b) to sign tags\n(instead of leaving gpg to add the signature to the file by itself),\nand those signatures need to be supplied in a separate file to be\nverified by gpg.\n\nThe program uses git_mkstemp to create that temporary file needed by\ngpg, instead of the previously used \"$GIT_DIR/.tmp-vtag\", in order to\nallow the command to be used in read-only repositories, and also\nprevent other instances of git to read or remove the same file.\n\nSignal SIGPIPE is ignored because the program sometimes was\nterminated because that signal when writing the input for gpg.\n\nThe command now can receive many tag names to be verified.\nDocumentation is also updated here to reflect this new behaviour.\n\nSigned-off-by: Carlos Rica <jasampler@gmail.com>\n---\n\n   This resend is addressing the questions commented in:\n   http://thread.gmane.org/gmane.comp.version-control.git/53376\n\n   Function verify_tag is designed to be easily reused in the\n   upcoming \"builtin-tag.c\", although it is declared static now.\n\n Documentation/git-verify-tag.txt                   |    4 +-\n Makefile                                           |    3 +-\n builtin-verify-tag.c                               |  111 ++++++++++++++++++++\n builtin.h                                          |    1 +\n .../examples/git-verify-tag.sh                     |    0\n git.c                                              |    1 +\n 6 files changed, 117 insertions(+), 3 deletions(-)\n create mode 100644 builtin-verify-tag.c\n rename git-verify-tag.sh => contrib/examples/git-verify-tag.sh (100%)\n\ndiff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt\nindex 48d17fd..ac7fb19 100644\n--- a/Documentation/git-verify-tag.txt\n+++ b/Documentation/git-verify-tag.txt\n@@ -3,11 +3,11 @@ git-verify-tag(1)\n\n NAME\n ----\n-git-verify-tag - Check the GPG signature of tag\n+git-verify-tag - Check the GPG signature of tags\n\n SYNOPSIS\n --------\n-'git-verify-tag' <tag>\n+'git-verify-tag' <tag>...\n\n DESCRIPTION\n -----------\ndiff --git a/Makefile b/Makefile\nindex 73b487f..c6ed79f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -206,7 +206,7 @@ SCRIPT_SH = \\\n \tgit-pull.sh git-rebase.sh git-rebase--interactive.sh \\\n \tgit-repack.sh git-request-pull.sh git-reset.sh \\\n \tgit-sh-setup.sh \\\n-\tgit-tag.sh git-verify-tag.sh \\\n+\tgit-tag.sh \\\n \tgit-am.sh \\\n \tgit-merge.sh git-merge-stupid.sh git-merge-octopus.sh \\\n \tgit-merge-resolve.sh git-merge-ours.sh \\\n@@ -367,6 +367,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-update-ref.o \\\n \tbuiltin-upload-archive.o \\\n \tbuiltin-verify-pack.o \\\n+\tbuiltin-verify-tag.o \\\n \tbuiltin-write-tree.o \\\n \tbuiltin-show-ref.o \\\n \tbuiltin-pack-refs.o\ndiff --git a/builtin-verify-tag.c b/builtin-verify-tag.c\nnew file mode 100644\nindex 0000000..11b971e\n--- /dev/null\n+++ b/builtin-verify-tag.c\n@@ -0,0 +1,111 @@\n+/*\n+ * Builtin \"git verify-tag\"\n+ *\n+ * Copyright (c) 2007 Carlos Rica <jasampler@gmail.com>\n+ *\n+ * Based on git-verify-tag.sh\n+ */\n+#include \"cache.h\"\n+#include \"builtin.h\"\n+#include \"tag.h\"\n+#include \"run-command.h\"\n+#include <signal.h>\n+\n+static const char builtin_verify_tag_usage[] =\n+\t\t\"git-verify-tag [-v|--verbose] <tag>...\";\n+\n+#define PGP_SIGNATURE \"-----BEGIN PGP SIGNATURE-----\"\n+\n+static int run_gpg_verify(const char *buf, unsigned long size, int verbose)\n+{\n+\tstruct child_process gpg;\n+\tconst char *args_gpg[] = {\"gpg\", \"--verify\", \"FILE\", \"-\", NULL};\n+\tchar path[PATH_MAX], *eol;\n+\tsize_t len;\n+\tint fd, ret;\n+\n+\tfd = git_mkstemp(path, PATH_MAX, \".git_vtag_tmpXXXXXX\");\n+\tif (fd < 0)\n+\t\treturn error(\"could not create temporary file '%s': %s\",\n+\t\t\t\t\t\tpath, strerror(errno));\n+\tif (write_in_full(fd, buf, size) < 0)\n+\t\treturn error(\"failed writing temporary file '%s': %s\",\n+\t\t\t\t\t\tpath, strerror(errno));\n+\tclose(fd);\n+\n+\t/* find the length without signature */\n+\tlen = 0;\n+\twhile (len < size && prefixcmp(buf + len, PGP_SIGNATURE \"\\n\")) {\n+\t\teol = memchr(buf + len, '\\n', size - len);\n+\t\tlen += eol ? eol - (buf + len) + 1 : size - len;\n+\t}\n+\tif (verbose)\n+\t\twrite_in_full(1, buf, len);\n+\n+\tmemset(&gpg, 0, sizeof(gpg));\n+\tgpg.argv = args_gpg;\n+\tgpg.in = -1;\n+\tgpg.out = 1;\n+\targs_gpg[2] = path;\n+\tif (start_command(&gpg))\n+\t\treturn error(\"could not run gpg.\");\n+\n+\twrite_in_full(gpg.in, buf, len);\n+\tclose(gpg.in);\n+\tgpg.close_in = 0;\n+\tret = finish_command(&gpg);\n+\n+\tunlink(path);\n+\tfree(path);\n+\n+\treturn ret;\n+}\n+\n+static int verify_tag(const char *name, int verbose)\n+{\n+\tenum object_type type;\n+\tunsigned char sha1[20];\n+\tchar *buf;\n+\tunsigned long size;\n+\tint ret;\n+\n+\tif (get_sha1(name, sha1))\n+\t\treturn error(\"tag '%s' not found.\", name);\n+\n+\ttype = sha1_object_info(sha1, NULL);\n+\tif (type != OBJ_TAG)\n+\t\treturn error(\"%s: cannot verify a non-tag object of type %s.\",\n+\t\t\t\tname, typename(type));\n+\n+\tbuf = read_sha1_file(sha1, &type, &size);\n+\tif (!buf)\n+\t\treturn error(\"%s: unable to read file.\", name);\n+\n+\tret = run_gpg_verify(buf, size, verbose);\n+\n+\tfree(buf);\n+\treturn ret;\n+}\n+\n+int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n+{\n+\tint i = 1, verbose = 0, had_error = 0;\n+\n+\tgit_config(git_default_config);\n+\n+\tif (argc == 1)\n+\t\tusage(builtin_verify_tag_usage);\n+\n+\tif (!strcmp(argv[i], \"-v\") || !strcmp(argv[i], \"--verbose\")) {\n+\t\tverbose = 1;\n+\t\ti++;\n+\t}\n+\n+\t/* sometimes the program was terminated because this signal\n+\t * was received in the process of writing the gpg input: */\n+\tsignal(SIGPIPE, SIG_IGN);\n+\twhile (i < argc)\n+\t\tif (verify_tag(argv[i++], verbose))\n+\t\t\thad_error = 1;\n+\treturn had_error;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 4cc228d..cb860a0 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -76,6 +76,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix);\n extern int cmd_update_ref(int argc, const char **argv, const char *prefix);\n extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);\n extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);\n+extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);\n extern int cmd_version(int argc, const char **argv, const char *prefix);\n extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);\n extern int cmd_write_tree(int argc, const char **argv, const char *prefix);\ndiff --git a/git-verify-tag.sh b/contrib/examples/git-verify-tag.sh\nsimilarity index 100%\nrename from git-verify-tag.sh\nrename to contrib/examples/git-verify-tag.sh\ndiff --git a/git.c b/git.c\nindex a647f9c..1dfe120 100644\n--- a/git.c\n+++ b/git.c\n@@ -368,6 +368,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"update-index\", cmd_update_index, RUN_SETUP },\n \t\t{ \"update-ref\", cmd_update_ref, RUN_SETUP },\n \t\t{ \"upload-archive\", cmd_upload_archive },\n+\t\t{ \"verify-tag\", cmd_verify_tag, RUN_SETUP },\n \t\t{ \"version\", cmd_version },\n \t\t{ \"whatchanged\", cmd_whatchanged, RUN_SETUP | USE_PAGER },\n \t\t{ \"write-tree\", cmd_write_tree, RUN_SETUP },\n-- \n1.5.0\n"},{"id":"48776","messageId":"7vr6mu2uo0.fsf@assigned-by-dhcp.cox.net","threadId":"9249","inReplyTo":"46A96F86.2030704@gmail.com","subject":"Re: [PATCH] Make verify-tag a builtin.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T07:05:35Z","receivedAt":"2007-07-27T07:05:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlos Rica <jasampler@gmail.com> writes:\n\n> This replaces \"git-verify-tag.sh\" with \"builtin-verify-tag.c\".\n\nThis is better overall, but you need to drop free(path) as you\nare using git_mkstemp() now on a on-stack buffer.\n\n> Signal SIGPIPE is ignored because the program sometimes was\n> terminated because that signal when writing the input for gpg.\n\nThis \"sometimes\" does not give confidence to readers, I am\nafraid.\n\nWhat is happening is perfectly normal, not \"sometimes it gets\nthe signal mysteriously, so we need to paper it over by ignoring\nit\".\n\nYou invoke gpg, giving it a file that is supposed to contain a\ndetached signature, and start feeding the payload that ought to\nverify Ok with the signature.  If the tag is not signed, after\ngpg has read the detached signature, it already knows that the\nsignature will not verify and it can exit without reading the\npayload from its standard input.  When you try to write the\npayload to the pipe, you would get SIGPIPE.\n\nAnyway, I'll replace the tip of cr/tag topic with this version,\nand merge it to 'next'.\n"},{"id":"48832","messageId":"1b46aba20707271251g7cf968a6o3840739dec548408@mail.gmail.com","threadId":"9249","inReplyTo":"7vr6mu2uo0.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Make verify-tag a builtin.","fromName":"Carlos Rica","fromEmail":"jasampler@gmail.com","sentAt":"2007-07-27T19:51:41Z","receivedAt":"2007-07-27T19:51:41Z","isPatch":true,"sender":{"key":"jasampler@gmail.com","avatar":null},"body":"2007/7/27, Junio C Hamano <gitster@pobox.com>:\n> Carlos Rica <jasampler@gmail.com> writes:\n> > Signal SIGPIPE is ignored because the program sometimes was\n> > terminated because that signal when writing the input for gpg.\n>\n> This \"sometimes\" does not give confidence to readers, I am\n> afraid.\n>\n> What is happening is perfectly normal, not \"sometimes it gets\n> the signal mysteriously, so we need to paper it over by ignoring\n> it\".\n>\n> You invoke gpg, giving it a file that is supposed to contain a\n> detached signature, and start feeding the payload that ought to\n> verify Ok with the signature.  If the tag is not signed, after\n> gpg has read the detached signature, it already knows that the\n> signature will not verify and it can exit without reading the\n> payload from its standard input.  When you try to write the\n> payload to the pipe, you would get SIGPIPE.\n\nBy using \"sometimes\" I was requesting an answer to this strange\nbehaviour (for me) to you and the mailing list. Now I could reproduce it\nremoving the call to signal and running this:\n\n#!/bin/sh\necho \"creating vtag1...\"\ngit tag -s -m \"a signed tag\" vtag1\necho \"creating vtag2...\"\ngit tag -m \"an annotated non-signed tag\" vtag2\necho \"creating vtag3...\"\ngit tag -m \"another annotated non-signed tag is \" vtag3\n# 141 returned sometimes when gpg got\n# a non-signed file as detached signature:\n# (it refuses to read from the input when\n# no signature is given, sometimes)\nfor i in 1 2 3 4 5 6 7 8 9 10\ndo\n        ./git verify-tag vtag1 vtag2 vtag3\n        echo \"git verify-tag vtag1 vtag2 vtag3 exit code: $?\"\n        echo\ndone\ngit tag -d vtag1\ngit tag -d vtag2\ngit tag -d vtag3\n\nIn my system, some of the tests give 141 and others give 1 as exit code.\nDscho said that it could depend on the CPU current load of the computer,\nsince he got always 141 as you said, so perhaps it's me.\n"},{"id":"48842","messageId":"7vtzrpwo44.fsf@assigned-by-dhcp.cox.net","threadId":"9249","inReplyTo":"1b46aba20707271251g7cf968a6o3840739dec548408@mail.gmail.com","subject":"Re: [PATCH] Make verify-tag a builtin.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T21:08:59Z","receivedAt":"2007-07-27T21:08:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Carlos Rica\" <jasampler@gmail.com> writes:\n\n> In my system, some of the tests give 141 and others give 1 as exit code.\n> Dscho said that it could depend on the CPU current load of the computer,\n> since he got always 141 as you said, so perhaps it's me.\n\nThis is expected.  It depends on how processess are scheduled.\n\nWhat is happening is:\n\n 1. Your process prepares the whole thing in vtag-tmp, to hand\n    to gpg;\n\n 2. You make a pipe and start gpg with the above file telling it\n    \"here is a detached signature file, the payload will be fed\n    through your stdin\";\n\n 3-a. You feed the payload to the pipe, expecting gpg to read it.\n\n 3-b. gpg reads the detached signature file, finds no signature in\n    the vtag-tmp file because the tag in question is not signed,\n    and exits without reading a single byte from the pipe;\n\nNow, 3-a and 3-b run in parallel.  If 3-a is scheduled before\n3-b happens, because payload is very often much smaller than the\nin-kernel pipe buffer, your write(2) succeeds before gpg gives up\nand exits without reading from the pipe.  If 3-b is scheduled\nbefore 3-a, then gpg exits and when 3-a gets around to write(2)\nto the pipe, write notices that there is nobody on the other end\nof the pipe, and you get SIGPIPE.\n"},{"id":"48917","messageId":"1b46aba20707281102j6d519125y176fd11e3ab53fab@mail.gmail.com","threadId":"9249","inReplyTo":"7vtzrpwo44.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Make verify-tag a builtin.","fromName":"Carlos Rica","fromEmail":"jasampler@gmail.com","sentAt":"2007-07-28T18:02:09Z","receivedAt":"2007-07-28T18:02:09Z","isPatch":true,"sender":{"key":"jasampler@gmail.com","avatar":null},"body":"Your explanation about the I/O in parallel sounds much better to me,\nnow I understand, thank you Junio.\n\n2007/7/27, Junio C Hamano <gitster@pobox.com>:\n> What is happening is:\n>\n>  1. Your process prepares the whole thing in vtag-tmp, to hand\n>     to gpg;\n>\n>  2. You make a pipe and start gpg with the above file telling it\n>     \"here is a detached signature file, the payload will be fed\n>     through your stdin\";\n>\n>  3-a. You feed the payload to the pipe, expecting gpg to read it.\n>\n>  3-b. gpg reads the detached signature file, finds no signature in\n>     the vtag-tmp file because the tag in question is not signed,\n>     and exits without reading a single byte from the pipe;\n>\n> Now, 3-a and 3-b run in parallel.  If 3-a is scheduled before\n> 3-b happens, because payload is very often much smaller than the\n> in-kernel pipe buffer, your write(2) succeeds before gpg gives up\n> and exits without reading from the pipe.  If 3-b is scheduled\n> before 3-a, then gpg exits and when 3-a gets around to write(2)\n> to the pipe, write notices that there is nobody on the other end\n> of the pipe, and you get SIGPIPE.\n"}]}