git

Форк
0
/
sub-process.c 
217 строк · 5.6 Кб
1
/*
2
 * Generic implementation of background process infrastructure.
3
 */
4
#include "git-compat-util.h"
5
#include "sub-process.h"
6
#include "sigchain.h"
7
#include "pkt-line.h"
8

9
int cmd2process_cmp(const void *cmp_data UNUSED,
10
		    const struct hashmap_entry *eptr,
11
		    const struct hashmap_entry *entry_or_key,
12
		    const void *keydata UNUSED)
13
{
14
	const struct subprocess_entry *e1, *e2;
15

16
	e1 = container_of(eptr, const struct subprocess_entry, ent);
17
	e2 = container_of(entry_or_key, const struct subprocess_entry, ent);
18

19
	return strcmp(e1->cmd, e2->cmd);
20
}
21

22
struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
23
{
24
	struct subprocess_entry key;
25

26
	hashmap_entry_init(&key.ent, strhash(cmd));
27
	key.cmd = cmd;
28
	return hashmap_get_entry(hashmap, &key, ent, NULL);
29
}
30

31
int subprocess_read_status(int fd, struct strbuf *status)
32
{
33
	struct strbuf **pair;
34
	char *line;
35
	int len;
36

37
	for (;;) {
38
		len = packet_read_line_gently(fd, NULL, &line);
39
		if ((len < 0) || !line)
40
			break;
41
		pair = strbuf_split_str(line, '=', 2);
42
		if (pair[0] && pair[0]->len && pair[1]) {
43
			/* the last "status=<foo>" line wins */
44
			if (!strcmp(pair[0]->buf, "status=")) {
45
				strbuf_reset(status);
46
				strbuf_addbuf(status, pair[1]);
47
			}
48
		}
49
		strbuf_list_free(pair);
50
	}
51

52
	return (len < 0) ? len : 0;
53
}
54

55
void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
56
{
57
	if (!entry)
58
		return;
59

60
	entry->process.clean_on_exit = 0;
61
	kill(entry->process.pid, SIGTERM);
62
	finish_command(&entry->process);
63

64
	hashmap_remove(hashmap, &entry->ent, NULL);
65
}
66

67
static void subprocess_exit_handler(struct child_process *process)
68
{
69
	sigchain_push(SIGPIPE, SIG_IGN);
70
	/* Closing the pipe signals the subprocess to initiate a shutdown. */
71
	close(process->in);
72
	close(process->out);
73
	sigchain_pop(SIGPIPE);
74
	/* Finish command will wait until the shutdown is complete. */
75
	finish_command(process);
76
}
77

78
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
79
	subprocess_start_fn startfn)
80
{
81
	int err;
82
	struct child_process *process;
83

84
	entry->cmd = cmd;
85
	process = &entry->process;
86

87
	child_process_init(process);
88
	strvec_push(&process->args, cmd);
89
	process->use_shell = 1;
90
	process->in = -1;
91
	process->out = -1;
92
	process->clean_on_exit = 1;
93
	process->clean_on_exit_handler = subprocess_exit_handler;
94
	process->trace2_child_class = "subprocess";
95

96
	err = start_command(process);
97
	if (err) {
98
		error("cannot fork to run subprocess '%s'", cmd);
99
		return err;
100
	}
101

102
	hashmap_entry_init(&entry->ent, strhash(cmd));
103

104
	err = startfn(entry);
105
	if (err) {
106
		error("initialization for subprocess '%s' failed", cmd);
107
		subprocess_stop(hashmap, entry);
108
		return err;
109
	}
110

111
	hashmap_add(hashmap, &entry->ent);
112
	return 0;
113
}
114

115
static int handshake_version(struct child_process *process,
116
			     const char *welcome_prefix, int *versions,
117
			     int *chosen_version)
118
{
119
	int version_scratch;
120
	int i;
121
	char *line;
122
	const char *p;
123

124
	if (!chosen_version)
125
		chosen_version = &version_scratch;
126

127
	if (packet_write_fmt_gently(process->in, "%s-client\n",
128
				    welcome_prefix))
129
		return error("Could not write client identification");
130
	for (i = 0; versions[i]; i++) {
131
		if (packet_write_fmt_gently(process->in, "version=%d\n",
132
					    versions[i]))
133
			return error("Could not write requested version");
134
	}
135
	if (packet_flush_gently(process->in))
136
		return error("Could not write flush packet");
137

138
	if (!(line = packet_read_line(process->out, NULL)) ||
139
	    !skip_prefix(line, welcome_prefix, &p) ||
140
	    strcmp(p, "-server"))
141
		return error("Unexpected line '%s', expected %s-server",
142
			     line ? line : "<flush packet>", welcome_prefix);
143
	if (!(line = packet_read_line(process->out, NULL)) ||
144
	    !skip_prefix(line, "version=", &p) ||
145
	    strtol_i(p, 10, chosen_version))
146
		return error("Unexpected line '%s', expected version",
147
			     line ? line : "<flush packet>");
148
	if ((line = packet_read_line(process->out, NULL)))
149
		return error("Unexpected line '%s', expected flush", line);
150

151
	/* Check to make sure that the version received is supported */
152
	for (i = 0; versions[i]; i++) {
153
		if (versions[i] == *chosen_version)
154
			break;
155
	}
156
	if (!versions[i])
157
		return error("Version %d not supported", *chosen_version);
158

159
	return 0;
160
}
161

162
static int handshake_capabilities(struct child_process *process,
163
				  struct subprocess_capability *capabilities,
164
				  unsigned int *supported_capabilities)
165
{
166
	int i;
167
	char *line;
168

169
	for (i = 0; capabilities[i].name; i++) {
170
		if (packet_write_fmt_gently(process->in, "capability=%s\n",
171
					    capabilities[i].name))
172
			return error("Could not write requested capability");
173
	}
174
	if (packet_flush_gently(process->in))
175
		return error("Could not write flush packet");
176

177
	while ((line = packet_read_line(process->out, NULL))) {
178
		const char *p;
179
		if (!skip_prefix(line, "capability=", &p))
180
			continue;
181

182
		for (i = 0;
183
		     capabilities[i].name && strcmp(p, capabilities[i].name);
184
		     i++)
185
			;
186
		if (capabilities[i].name) {
187
			if (supported_capabilities)
188
				*supported_capabilities |= capabilities[i].flag;
189
		} else {
190
			die("subprocess '%s' requested unsupported capability '%s'",
191
			    process->args.v[0], p);
192
		}
193
	}
194

195
	return 0;
196
}
197

198
int subprocess_handshake(struct subprocess_entry *entry,
199
			 const char *welcome_prefix,
200
			 int *versions,
201
			 int *chosen_version,
202
			 struct subprocess_capability *capabilities,
203
			 unsigned int *supported_capabilities)
204
{
205
	int retval;
206
	struct child_process *process = &entry->process;
207

208
	sigchain_push(SIGPIPE, SIG_IGN);
209

210
	retval = handshake_version(process, welcome_prefix, versions,
211
				   chosen_version) ||
212
		 handshake_capabilities(process, capabilities,
213
					supported_capabilities);
214

215
	sigchain_pop(SIGPIPE);
216
	return retval;
217
}
218

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.