credential-cache: close stderr in daemon process

If the stderr of "git credential-cache" is redirected to a pipe, the reader on the other end of a pipe may be surprised that the pipe remains open long after the process exits. This happens because we may auto-spawn a daemon which is long-lived, and which keeps stderr open. We can solve this by redirecting the daemon's stderr to /dev/null once we are ready to go into our event loop. We would not want to do so before then, because we may want to report errors about the setup (e.g., failure to establish the listening socket). This does mean that we will not report errors we encounter for specific clients. That's acceptable, as such errors should be rare (e.g., clients sending buggy requests). However, we also provide an escape hatch: if you want to see these later messages, you can provide the "--debug" option to keep stderr open. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Sep 14, 2014 at 03:35 UTC f5e3c0b9d050ebdaf96d3910b01b01695e3ea1a2
2 files changed +26 -5
Documentation/git-credential-cache--daemon.txt
+5 -1
@@ -8,7 +8,7 @@ git-credential-cache--daemon - Temporarily store user credentials in memory
8 SYNOPSIS
9 --------
10 [verse]
11 -git credential-cache--daemon <socket>
11 +git credential-cache--daemon [--debug] <socket>
12
13 DESCRIPTION
14 -----------
@@ -21,6 +21,10 @@ for `git-credential-cache` clients. Clients may store and retrieve
21 credentials. Each credential is held for a timeout specified by the
22 client; once no credentials are held, the daemon exits.
23
24 +If the `--debug` option is specified, the daemon does not close its
25 +stderr stream, and may output extra diagnostics to it even after it has
26 +begun listening for clients.
27 +
28 GIT
29 ---
30 Part of the linkgit:git[1] suite
credential-cache--daemon.c
+21 -4
@@ -2,6 +2,7 @@
2 #include "credential.h"
3 #include "unix-socket.h"
4 #include "sigchain.h"
5 +#include "parse-options.h"
6
7 static const char *socket_path;
8
@@ -201,7 +202,7 @@ static int serve_cache_loop(int fd)
202 return 1;
203 }
204
204 -static void serve_cache(const char *socket_path)
205 +static void serve_cache(const char *socket_path, int debug)
206 {
207 int fd;
208
@@ -211,6 +212,10 @@ static void serve_cache(const char *socket_path)
212
213 printf("ok\n");
214 fclose(stdout);
215 + if (!debug) {
216 + if (!freopen("/dev/null", "w", stderr))
217 + die_errno("unable to point stderr to /dev/null");
218 + }
219
220 while (serve_cache_loop(fd))
221 ; /* nothing */
@@ -252,16 +257,28 @@ static void check_socket_directory(const char *path)
257
258 int main(int argc, const char **argv)
259 {
255 - socket_path = argv[1];
260 + static const char *usage[] = {
261 + "git-credential-cache--daemon [opts] <socket_path>",
262 + NULL
263 + };
264 + int debug = 0;
265 + const struct option options[] = {
266 + OPT_BOOL(0, "debug", &debug,
267 + N_("print debugging messages to stderr")),
268 + OPT_END()
269 + };
270 +
271 + argc = parse_options(argc, argv, NULL, options, usage, 0);
272 + socket_path = argv[0];
273
274 if (!socket_path)
258 - die("usage: git-credential-cache--daemon <socket_path>");
275 + usage_with_options(usage, options);
276 check_socket_directory(socket_path);
277
278 atexit(cleanup_socket);
279 sigchain_push_common(cleanup_socket_on_signal);
280
264 - serve_cache(socket_path);
281 + serve_cache(socket_path, debug);
282
283 return 0;
284 }