{"thread":{"id":"1904","subject":"[PATCH] Verbose git-daemon logging","startedAt":"2005-09-21T21:39:33Z","lastAt":"2005-09-23T12:08:02Z","messageCount":6,"participants":["Petr Baudis","Junio C Hamano","Linus Torvalds","Morten Welinder"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"9073","messageId":"20050921213933.GB10575@pasky.or.cz","threadId":"1904","inReplyTo":null,"subject":"[PATCH] Verbose git-daemon logging","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-09-21T21:39:33Z","receivedAt":"2005-09-21T21:39:33Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"This patch makes git-daemon --verbose log some useful things on stderr -\nin particular connects, disconnects and upload requests, and in such a\nway to be able to trace a particular session. Some more errors are now\nalso logged (even when --verbose is not passed). It is still not perfect\nsince messages produced by the non-daemon-specific code are obviously\nnot formatted properly.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n\n---\ncommit 419408cb9545495cd542d18219598c318f91007d\ntree da6735878367946edae024c76e6f8165f82cfe07\nparent ff0b3368b45a07ac080574eb721a607892413b99\nauthor Petr Baudis <pasky@suse.cz> Wed, 21 Sep 2005 23:36:20 +0200\ncommitter Petr Baudis <xpasky@machine.(none)> Wed, 21 Sep 2005 23:36:20 +0200\n\n daemon.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 74 insertions(+), 4 deletions(-)\n\ndiff --git a/daemon.c b/daemon.c\n--- a/daemon.c\n+++ b/daemon.c\n@@ -6,13 +6,54 @@\n #include <sys/time.h>\n #include <netdb.h>\n #include <netinet/in.h>\n+#include <arpa/inet.h>\n+\n+static int verbose;\n+\n+static const char daemon_usage[] = \"git-daemon [--verbose] [--inetd | --port=n]\";\n+\n+\n+static void logreport(const char *err, va_list params)\n+{\n+\t/* We should do a single write so that it is atomic and output\n+\t * of several threads does not get intermangled. */\n+\tchar buf[1024];\n+\tint buflen;\n+\n+\tbuflen = snprintf(buf, 1024, \"[%d] \", getpid());\n+\tbuflen += vsnprintf(buf + buflen, 1024 - buflen, err, params);\n+\tbuf[buflen++] = '\\n';\n+\tbuf[buflen] = '\\0';\n+\n+\tfputs(buf, stderr);\n+}\n+\n+void logerror(const char *err, ...)\n+{\n+\tva_list params;\n+\tva_start(params, err);\n+\tlogreport(err, params);\n+\tva_end(params);\n+}\n+\n+void lognotice(const char *err, ...)\n+{\n+\tva_list params;\n+\tif (!verbose)\n+\t\treturn;\n+\tva_start(params, err);\n+\tlogreport(err, params);\n+\tva_end(params);\n+}\n \n-static const char daemon_usage[] = \"git-daemon [--inetd | --port=n]\";\n \n static int upload(char *dir, int dirlen)\n {\n-\tif (chdir(dir) < 0)\n+\tlognotice(\"Request for '%s'\", dir);\n+\tif (chdir(dir) < 0) {\n+\t\tlogerror(\"Cannot chdir('%s'): %s\", dir, strerror(errno));\n \t\treturn -1;\n+\t}\n \tchdir(\".git\");\n \n \t/*\n@@ -24,8 +65,10 @@ static int upload(char *dir, int dirlen)\n \t */\n \tif (access(\"git-daemon-export-ok\", F_OK) ||\n \t    access(\"objects/00\", X_OK) ||\n-\t    access(\"HEAD\", R_OK))\n+\t    access(\"HEAD\", R_OK)) {\n+\t\tlogerror(\"Not a valid gitd-enabled repository: '%s'\", dir);\n \t\treturn -1;\n+\t}\n \n \t/*\n \t * We'll ignore SIGTERM from now on, we have a\n@@ -51,7 +94,7 @@ static int execute(void)\n \tif (!strncmp(\"git-upload-pack /\", line, 17))\n \t\treturn upload(line + 16, len - 16);\n \n-\tfprintf(stderr, \"got bad connection '%s'\\n\", line);\n+\tlogerror(\"Protocol error: '%s'\", line);\n \treturn -1;\n }\n \n@@ -181,6 +224,8 @@ static void check_max_connections(void)\n static void handle(int incoming, struct sockaddr *addr, int addrlen)\n {\n \tpid_t pid = fork();\n+\tchar addrbuf[256] = \"\";\n+\tint port = -1;\n \n \tif (pid) {\n \t\tunsigned idx;\n@@ -200,6 +245,24 @@ static void handle(int incoming, struct \n \tdup2(incoming, 0);\n \tdup2(incoming, 1);\n \tclose(incoming);\n+\n+\tif (addr->sa_family == AF_INET) {\n+\t\tstruct sockaddr_in *sin_addr = (void *) addr;\n+\t\tinet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));\n+\t\tport = sin_addr->sin_port;\n+\n+\t} else if (addr->sa_family == AF_INET6) {\n+\t\tstruct sockaddr_in6 *sin6_addr = (void *) addr;\n+\n+\t\tchar *buf = addrbuf;\n+\t\t*buf++ = '['; *buf = '\\0'; /* stpcpy() is cool */\n+\t\tinet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);\n+\t\tstrcat(buf, \"]\");\n+\n+\t\tport = sin6_addr->sin6_port;\n+\t}\n+\tlognotice(\"Connection from %s:%d\", addrbuf, port);\n+\n \texit(execute());\n }\n \n@@ -212,6 +275,9 @@ static void child_handler(int signo)\n \t\t\tunsigned reaped = children_reaped;\n \t\t\tdead_child[reaped % MAX_CHILDREN] = pid;\n \t\t\tchildren_reaped = reaped + 1;\n+\t\t\t/* XXX: Custom logging, since we don't wanna getpid() */\n+\t\t\tif (verbose)\n+\t\t\t\tfprintf(stderr, \"[%d] Disconnected\\n\", pid);\n \t\t\tcontinue;\n \t\t}\n \t\tbreak;\n@@ -349,6 +415,10 @@ int main(int argc, char **argv)\n \t\t\tinetd_mode = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--verbose\")) {\n+\t\t\tverbose = 1;\n+\t\t\tcontinue;\n+\t\t}\n \n \t\tusage(daemon_usage);\n \t}\n\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"9090","messageId":"7vwtl9mqm5.fsf@assigned-by-dhcp.cox.net","threadId":"1904","inReplyTo":"20050921213933.GB10575@pasky.or.cz","subject":"Re: [PATCH] Verbose git-daemon logging","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-09-22T08:52:18Z","receivedAt":"2005-09-22T08:52:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Overall looks very informative to me.  Couple of points,\nalthough your patch was not directly addressed to me... ;-).\n\n> +static void logreport(const char *err, va_list params)\n> +{\n> +\t/* We should do a single write so that it is atomic and output\n> +\t * of several threads does not get intermangled. */\n\n\"threads\"?  Nevertheless yes it is nicer to do a single write.\n\n> +\tchar buf[1024];\n> +\tint buflen;\n> +\n> +\tbuflen = snprintf(buf, 1024, \"[%d] \", getpid());\n\nsizeof(buf)?\n\n> +\tbuflen += vsnprintf(buf + buflen, 1024 - buflen, err, params);\n\nvsnprintf() would return number of characters that would have\nbeen written if the buffer were sufficiently long, so buflen can\ngrow outside buf[].  I could ask for a deeeeeeeeeeep directory\nto git-daemon, have it say \"Request for 'diiiiiiiiiiiiii....r'\",\nand have this code\n\n> +\tbuf[buflen++] = '\\n';\n> +\tbuf[buflen] = '\\0';\n\noverwrite the stack with these two bytes; overwriting with\nconstant bytes may or may not be exploitable, though.\n\nAlso the man page says glibc 2.0.6 returned -1 upon output\ntruncation.  Do we care?\n\n> @@ -212,6 +275,9 @@ static void child_handler(int signo)\n>  \t\t\tunsigned reaped = children_reaped;\n>  \t\t\tdead_child[reaped % MAX_CHILDREN] = pid;\n>  \t\t\tchildren_reaped = reaped + 1;\n> +\t\t\t/* XXX: Custom logging, since we don't wanna getpid() */\n> +\t\t\tif (verbose)\n> +\t\t\t\tfprintf(stderr, \"[%d] Disconnected\\n\", pid);\n\n\"we don't wanna getpid()\" because the guy reporting is the\nparent?  I would presume knowing parent PID would also useful,\nso maybe we could say \"[1012] child 1014 disconnected\\n\" for\nparent 1012 reaping chilid 1014? \n"},{"id":"9091","messageId":"20050922092528.GB21019@pasky.or.cz","threadId":"1904","inReplyTo":"7vwtl9mqm5.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Verbose git-daemon logging","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-09-22T09:25:28Z","receivedAt":"2005-09-22T09:25:28Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Sep 22, 2005 at 10:52:18AM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> told me that...\n> > +static void logreport(const char *err, va_list params)\n> > +{\n> > +\t/* We should do a single write so that it is atomic and output\n> > +\t * of several threads does not get intermangled. */\n> \n> \"threads\"?  Nevertheless yes it is nicer to do a single write.\n\nOk, perhaps the \"threads\" name is not so appropriate after all. It\nlooked so cute in the sentence... ;-)\n\n> > +\tchar buf[1024];\n> > +\tint buflen;\n> > +\n> > +\tbuflen = snprintf(buf, 1024, \"[%d] \", getpid());\n> \n> sizeof(buf)?\n\nAck.\n\n> > +\tbuflen += vsnprintf(buf + buflen, 1024 - buflen, err, params);\n> \n> vsnprintf() would return number of characters that would have\n> been written if the buffer were sufficiently long, so buflen can\n> grow outside buf[].  I could ask for a deeeeeeeeeeep directory\n> to git-daemon, have it say \"Request for 'diiiiiiiiiiiiii....r'\",\n> and have this code\n> \n> > +\tbuf[buflen++] = '\\n';\n> > +\tbuf[buflen] = '\\0';\n> \n> overwrite the stack with these two bytes; overwriting with\n> constant bytes may or may not be exploitable, though.\n\nWhoops.\n\nHm, the vsnprintf() code ended up more complicated that I'd have liked.\nWell, I hope I got it right now. :-)\n\n> Also the man page says glibc 2.0.6 returned -1 upon output\n> truncation.  Do we care?\n\nIf we do, there seems to be like 10 other places in the code where we\nneed to fix that.\n\n> > @@ -212,6 +275,9 @@ static void child_handler(int signo)\n> >  \t\t\tunsigned reaped = children_reaped;\n> >  \t\t\tdead_child[reaped % MAX_CHILDREN] = pid;\n> >  \t\t\tchildren_reaped = reaped + 1;\n> > +\t\t\t/* XXX: Custom logging, since we don't wanna getpid() */\n> > +\t\t\tif (verbose)\n> > +\t\t\t\tfprintf(stderr, \"[%d] Disconnected\\n\", pid);\n> \n> \"we don't wanna getpid()\" because the guy reporting is the\n> parent?  I would presume knowing parent PID would also useful,\n> so maybe we could say \"[1012] child 1014 disconnected\\n\" for\n> parent 1012 reaping chilid 1014? \n\nWhat would be knowing parent PID be useful for? (It's not really the PID\nnumber that's useful anyway (at least mostly), it's just a good unique\nidentifier to distinguish between several simultaneous sessions.)\n\nThe way it is now, it is consistent and all messages concerning lifetime\nof one session have that session ID prepended. Otherwise not only a\nmechanical parser would be more complicated, but also visual inspection\nwould be more demanding.\n\n\nFixed up patch follows.\n\n--\n\n[PATCH] Verbose git-daemon logging\n\nThis patch makes git-daemon --verbose log some useful things on stderr -\nin particular connects, disconnects and upload requests, and in such a\nway to be able to trace a particular session. Some more errors are now\nalso logged (even when --verbose is not passed). It is still not perfect\nsince messages produced by the non-daemon-specific code are obviously\nnot formatted properly.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n\n---\ncommit ebb97336b876ebc56b60fe8381c8d0145c0e47d0\ntree e2234a568608743889a36750ae11ea4d00e9a7b4\nparent ff0b3368b45a07ac080574eb721a607892413b99\nauthor Petr Baudis <pasky@suse.cz> Thu, 22 Sep 2005 11:24:07 +0200\ncommitter Petr Baudis <xpasky@machine.(none)> Thu, 22 Sep 2005 11:24:07 +0200\n\n daemon.c |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 83 insertions(+), 4 deletions(-)\n\ndiff --git a/daemon.c b/daemon.c\n--- a/daemon.c\n+++ b/daemon.c\n@@ -6,13 +6,63 @@\n #include <sys/time.h>\n #include <netdb.h>\n #include <netinet/in.h>\n+#include <arpa/inet.h>\n+\n+static int verbose;\n+\n+static const char daemon_usage[] = \"git-daemon [--verbose] [--inetd | --port=n]\";\n+\n+\n+static void logreport(const char *err, va_list params)\n+{\n+\t/* We should do a single write so that it is atomic and output\n+\t * of several processes does not get intermangled. */\n+\tchar buf[1024];\n+\tint buflen;\n+\tint maxlen, msglen;\n+\n+\tbuflen = snprintf(buf, sizeof(buf), \"[%d] \", getpid());\n+\n+\tmaxlen = sizeof(buf) - buflen - 1;\n+\tmsglen = vsnprintf(buf + buflen, maxlen, err, params);\n+\tif (msglen > maxlen)\n+\t\tmsglen = maxlen;\n+\telse if (msglen < 0)\n+\t\tmsglen = -1; /* Protect against weird return values. */\n+\tbuflen += msglen;\n+\n+\tbuf[buflen++] = '\\n';\n+\tbuf[buflen] = '\\0';\n+\n+\tfputs(buf, stderr);\n+}\n+\n+void logerror(const char *err, ...)\n+{\n+\tva_list params;\n+\tva_start(params, err);\n+\tlogreport(err, params);\n+\tva_end(params);\n+}\n+\n+void lognotice(const char *err, ...)\n+{\n+\tva_list params;\n+\tif (!verbose)\n+\t\treturn;\n+\tva_start(params, err);\n+\tlogreport(err, params);\n+\tva_end(params);\n+}\n \n-static const char daemon_usage[] = \"git-daemon [--inetd | --port=n]\";\n \n static int upload(char *dir, int dirlen)\n {\n-\tif (chdir(dir) < 0)\n+\tlognotice(\"Request for '%s'\", dir);\n+\tif (chdir(dir) < 0) {\n+\t\tlogerror(\"Cannot chdir('%s'): %s\", dir, strerror(errno));\n \t\treturn -1;\n+\t}\n \tchdir(\".git\");\n \n \t/*\n@@ -24,8 +74,10 @@ static int upload(char *dir, int dirlen)\n \t */\n \tif (access(\"git-daemon-export-ok\", F_OK) ||\n \t    access(\"objects/00\", X_OK) ||\n-\t    access(\"HEAD\", R_OK))\n+\t    access(\"HEAD\", R_OK)) {\n+\t\tlogerror(\"Not a valid gitd-enabled repository: '%s'\", dir);\n \t\treturn -1;\n+\t}\n \n \t/*\n \t * We'll ignore SIGTERM from now on, we have a\n@@ -51,7 +103,7 @@ static int execute(void)\n \tif (!strncmp(\"git-upload-pack /\", line, 17))\n \t\treturn upload(line + 16, len - 16);\n \n-\tfprintf(stderr, \"got bad connection '%s'\\n\", line);\n+\tlogerror(\"Protocol error: '%s'\", line);\n \treturn -1;\n }\n \n@@ -181,6 +233,8 @@ static void check_max_connections(void)\n static void handle(int incoming, struct sockaddr *addr, int addrlen)\n {\n \tpid_t pid = fork();\n+\tchar addrbuf[256] = \"\";\n+\tint port = -1;\n \n \tif (pid) {\n \t\tunsigned idx;\n@@ -200,6 +254,24 @@ static void handle(int incoming, struct \n \tdup2(incoming, 0);\n \tdup2(incoming, 1);\n \tclose(incoming);\n+\n+\tif (addr->sa_family == AF_INET) {\n+\t\tstruct sockaddr_in *sin_addr = (void *) addr;\n+\t\tinet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));\n+\t\tport = sin_addr->sin_port;\n+\n+\t} else if (addr->sa_family == AF_INET6) {\n+\t\tstruct sockaddr_in6 *sin6_addr = (void *) addr;\n+\n+\t\tchar *buf = addrbuf;\n+\t\t*buf++ = '['; *buf = '\\0'; /* stpcpy() is cool */\n+\t\tinet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);\n+\t\tstrcat(buf, \"]\");\n+\n+\t\tport = sin6_addr->sin6_port;\n+\t}\n+\tlognotice(\"Connection from %s:%d\", addrbuf, port);\n+\n \texit(execute());\n }\n \n@@ -212,6 +284,9 @@ static void child_handler(int signo)\n \t\t\tunsigned reaped = children_reaped;\n \t\t\tdead_child[reaped % MAX_CHILDREN] = pid;\n \t\t\tchildren_reaped = reaped + 1;\n+\t\t\t/* XXX: Custom logging, since we don't wanna getpid() */\n+\t\t\tif (verbose)\n+\t\t\t\tfprintf(stderr, \"[%d] Disconnected\\n\", pid);\n \t\t\tcontinue;\n \t\t}\n \t\tbreak;\n@@ -349,6 +424,10 @@ int main(int argc, char **argv)\n \t\t\tinetd_mode = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--verbose\")) {\n+\t\t\tverbose = 1;\n+\t\t\tcontinue;\n+\t\t}\n \n \t\tusage(daemon_usage);\n \t}\n\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"9146","messageId":"7vd5n0lle8.fsf@assigned-by-dhcp.cox.net","threadId":"1904","inReplyTo":"20050922092528.GB21019@pasky.or.cz","subject":"Re: [PATCH] Verbose git-daemon logging","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-09-22T23:42:39Z","receivedAt":"2005-09-22T23:42:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> What would be knowing parent PID be useful for? (It's not really the PID\n> number that's useful anyway (at least mostly), it's just a good unique\n> identifier to distinguish between several simultaneous sessions.)\n\nMaybe running two daemons serving two sets of repos?  But anyway\nwhat you have look more consistent so let's keep that.\n\n> Fixed up patch follows.\n\nThanks.\n\n> +static void logreport(const char *err, va_list params)\n> +{\n> +\t/* We should do a single write so that it is atomic and output\n> +\t * of several processes does not get intermangled. */\n> +\tchar buf[1024];\n> +\tint buflen;\n> +\tint maxlen, msglen;\n> +\n> +\tbuflen = snprintf(buf, sizeof(buf), \"[%d] \", getpid());\n> +\n> +\tmaxlen = sizeof(buf) - buflen - 1;\n> +\tmsglen = vsnprintf(buf + buflen, maxlen, err, params);\n> +\tif (msglen > maxlen)\n> +\t\tmsglen = maxlen;\n> +\telse if (msglen < 0)\n> +\t\tmsglen = -1; /* Protect against weird return values. */\n> +\tbuflen += msglen;\n> +\n> +\tbuf[buflen++] = '\\n';\n> +\tbuf[buflen] = '\\0';\n> +\n> +\tfputs(buf, stderr);\n> +}\n\nThe tail part still looks odd here.  Maybe something like this?\n\n+static void logreport(const char *err, va_list params)\n+{\n+\t/* We should do a single write so that it is atomic and output\n+\t * of several processes does not get intermangled. */\n+\tchar buf[1024];\n+\tint buflen;\n+\tint maxlen, msglen;\n+\n+\t/* sizeof(buf) should be big enough for \"[pid] \\n\" */\n+\tbuflen = snprintf(buf, sizeof(buf), \"[%d] \", getpid());\n+\n+\tmaxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */\n+\tmsglen = vsnprintf(buf + buflen, maxlen, err, params);\n+\n+\t/* maxlen counted our own LF but also counts space given to\n+\t * vsnprintf for the terminating NUL.  We want to make sure that\n+\t * we have space for our own LF and NUL after the \"meat\" of the\n+\t * message, so truncate it at maxlen - 1.\n+\t */\n+\tif (msglen > maxlen - 1)\n+\t\tmsglen = maxlen - 1;\n+\telse if (msglen < 0)\n+\t\tmsglen = 0; /* Protect against weird return values. */\n+\tbuflen += msglen;\n+\n+\tbuf[buflen++] = '\\n';\n+\tbuf[buflen] = '\\0';\n+\n+\tfputs(buf, stderr);\n+}\n"},{"id":"9147","messageId":"Pine.LNX.4.58.0509221651000.2553@g5.osdl.org","threadId":"1904","inReplyTo":"7vd5n0lle8.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Verbose git-daemon logging","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-09-22T23:58:32Z","receivedAt":"2005-09-22T23:58:32Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 22 Sep 2005, Junio C Hamano wrote:\n> \n> The tail part still looks odd here.  Maybe something like this?\n\nAnd if you actually want it to be more reliable, don't use fputs. That \ncan still split lines, and even if it doesn't, it doesn't help.\n\n> +\tbuf[buflen++] = '\\n';\n> +\tbuf[buflen] = '\\0';\n> +\n> +\tfputs(buf, stderr);\n\nWhy use \"fputs()\", when you migth as well do write()?\n\nAlso, it would probably be nice if you allow the use of syslog().. \n\n\t\tLinus\n"},{"id":"9172","messageId":"118833cc05092305083757bd9b@mail.gmail.com","threadId":"1904","inReplyTo":"20050921213933.GB10575@pasky.or.cz","subject":"Re: [PATCH] Verbose git-daemon logging","fromName":"Morten Welinder","fromEmail":"mwelinder@gmail.com","sentAt":"2005-09-23T12:08:02Z","receivedAt":"2005-09-23T12:08:02Z","isPatch":true,"sender":{"key":"mwelinder@gmail.com","avatar":null},"body":"> +       buflen = snprintf(buf, 1024, \"[%d] \", getpid());\n\npid_t is not int.\n\nPlease cast it to int, or use %ld and cast it to long int.\n\nMorten\n"}]}