blob: 1cccc3a0b9cfb2a14e9c87d5afc29234fa62adc4 [file] [log] [blame]
Jeff Kinge2770972011-12-10 05:34:14 -05001#include "cache.h"
2#include "credential.h"
3#include "string-list.h"
4#include "parse-options.h"
5#include "unix-socket.h"
6#include "run-command.h"
7
8#define FLAG_SPAWN 0x1
9#define FLAG_RELAY 0x2
10
11static int send_request(const char *socket, const struct strbuf *out)
12{
13 int got_data = 0;
14 int fd = unix_stream_connect(socket);
15
16 if (fd < 0)
17 return -1;
18
19 if (write_in_full(fd, out->buf, out->len) < 0)
20 die_errno("unable to write to cache daemon");
21 shutdown(fd, SHUT_WR);
22
23 while (1) {
24 char in[1024];
25 int r;
26
27 r = read_in_full(fd, in, sizeof(in));
Ramsay Jones1f180e52017-07-27 02:08:40 +010028 if (r == 0 || (r < 0 && errno == ECONNRESET))
Jeff Kinge2770972011-12-10 05:34:14 -050029 break;
30 if (r < 0)
31 die_errno("read error from cache daemon");
32 write_or_die(1, in, r);
33 got_data = 1;
34 }
Stefan Beller9c60d9f2016-03-31 17:35:46 -070035 close(fd);
Jeff Kinge2770972011-12-10 05:34:14 -050036 return got_data;
37}
38
39static void spawn_daemon(const char *socket)
40{
René Scharfed3180272014-08-19 21:09:35 +020041 struct child_process daemon = CHILD_PROCESS_INIT;
Jeff Kinge2770972011-12-10 05:34:14 -050042 const char *argv[] = { NULL, NULL, NULL };
43 char buf[128];
44 int r;
45
Jeff Kinge2770972011-12-10 05:34:14 -050046 argv[0] = "git-credential-cache--daemon";
47 argv[1] = socket;
48 daemon.argv = argv;
49 daemon.no_stdin = 1;
50 daemon.out = -1;
51
52 if (start_command(&daemon))
53 die_errno("unable to start cache daemon");
54 r = read_in_full(daemon.out, buf, sizeof(buf));
55 if (r < 0)
56 die_errno("unable to read result code from cache daemon");
57 if (r != 3 || memcmp(buf, "ok\n", 3))
58 die("cache daemon did not start: %.*s", r, buf);
59 close(daemon.out);
60}
61
62static void do_cache(const char *socket, const char *action, int timeout,
63 int flags)
64{
65 struct strbuf buf = STRBUF_INIT;
66
67 strbuf_addf(&buf, "action=%s\n", action);
68 strbuf_addf(&buf, "timeout=%d\n", timeout);
69 if (flags & FLAG_RELAY) {
70 if (strbuf_read(&buf, 0, 0) < 0)
71 die_errno("unable to relay credential");
72 }
73
Jeff King8ec6c8d2012-01-09 23:57:33 -050074 if (send_request(socket, &buf) < 0) {
Jeff King35a71f12012-01-17 01:02:32 -050075 if (errno != ENOENT && errno != ECONNREFUSED)
Clemens Buchacher98c29242012-01-07 12:54:36 +010076 die_errno("unable to connect to cache daemon");
Jeff King8ec6c8d2012-01-09 23:57:33 -050077 if (flags & FLAG_SPAWN) {
78 spawn_daemon(socket);
79 if (send_request(socket, &buf) < 0)
80 die_errno("unable to connect to cache daemon");
81 }
Jeff Kinge2770972011-12-10 05:34:14 -050082 }
83 strbuf_release(&buf);
84}
85
Devin Lehmacher60759ba2017-03-17 08:36:33 -040086static char *get_socket_path(void)
87{
88 struct stat sb;
89 char *old_dir, *socket;
Junio C Hamanoa2e2c042017-04-23 22:07:46 -070090 old_dir = expand_user_path("~/.git-credential-cache", 0);
Devin Lehmacher60759ba2017-03-17 08:36:33 -040091 if (old_dir && !stat(old_dir, &sb) && S_ISDIR(sb.st_mode))
92 socket = xstrfmt("%s/socket", old_dir);
93 else
94 socket = xdg_cache_home("credential/socket");
95 free(old_dir);
96 return socket;
97}
98
Jeff King3f2e2292016-07-01 01:58:58 -040099int cmd_main(int argc, const char **argv)
Jeff Kinge2770972011-12-10 05:34:14 -0500100{
101 char *socket_path = NULL;
102 int timeout = 900;
103 const char *op;
104 const char * const usage[] = {
Ralf Thielowd96a0312015-10-16 19:09:57 +0200105 "git credential-cache [<options>] <action>",
Jeff Kinge2770972011-12-10 05:34:14 -0500106 NULL
107 };
108 struct option options[] = {
109 OPT_INTEGER(0, "timeout", &timeout,
110 "number of seconds to cache credentials"),
111 OPT_STRING(0, "socket", &socket_path, "path",
112 "path of cache-daemon socket"),
113 OPT_END()
114 };
115
116 argc = parse_options(argc, argv, NULL, options, usage, 0);
117 if (!argc)
118 usage_with_options(usage, options);
119 op = argv[0];
120
121 if (!socket_path)
Devin Lehmacher60759ba2017-03-17 08:36:33 -0400122 socket_path = get_socket_path();
Jeff Kinge2770972011-12-10 05:34:14 -0500123 if (!socket_path)
124 die("unable to find a suitable socket path; use --socket");
125
126 if (!strcmp(op, "exit"))
127 do_cache(socket_path, op, timeout, 0);
128 else if (!strcmp(op, "get") || !strcmp(op, "erase"))
129 do_cache(socket_path, op, timeout, FLAG_RELAY);
130 else if (!strcmp(op, "store"))
131 do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN);
132 else
133 ; /* ignore unknown operation */
134
135 return 0;
136}