comparison contrib/chg/chg.c @ 30620:937c52f06709

chg: start server at a unique address See the previous patch for motivation. Previously, the server is started at a globally shared address. This patch appends pid to the address so it becomes unique. Note: with Linux pid namespace, the address may be non-unique, but it does not affect correctness of chg - chg client will receive an redirection and that's it.
author Jun Wu <quark@fb.com>
date Mon, 19 Dec 2016 22:09:49 +0000
parents ff7df4bb75de
children d7875bfbfccb
comparison
equal deleted inserted replaced
30619:88efb4fb1975 30620:937c52f06709
29 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path)) 29 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path))
30 #endif 30 #endif
31 31
32 struct cmdserveropts { 32 struct cmdserveropts {
33 char sockname[UNIX_PATH_MAX]; 33 char sockname[UNIX_PATH_MAX];
34 char initsockname[UNIX_PATH_MAX];
34 char redirectsockname[UNIX_PATH_MAX]; 35 char redirectsockname[UNIX_PATH_MAX];
35 char lockfile[UNIX_PATH_MAX]; 36 char lockfile[UNIX_PATH_MAX];
36 size_t argsize; 37 size_t argsize;
37 const char **args; 38 const char **args;
38 int lockfd; 39 int lockfd;
161 if (r < 0 || (size_t)r >= sizeof(opts->sockname)) 162 if (r < 0 || (size_t)r >= sizeof(opts->sockname))
162 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); 163 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
163 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename); 164 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename);
164 if (r < 0 || (size_t)r >= sizeof(opts->lockfile)) 165 if (r < 0 || (size_t)r >= sizeof(opts->lockfile))
165 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); 166 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
167 r = snprintf(opts->initsockname, sizeof(opts->initsockname),
168 "%s.%u", opts->sockname, (unsigned)getpid());
169 if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
170 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
166 } 171 }
167 172
168 /* 173 /*
169 * Acquire a file lock that indicates a client is trying to start and connect 174 * Acquire a file lock that indicates a client is trying to start and connect
170 * to a server, before executing a command. The lock is released upon exit or 175 * to a server, before executing a command. The lock is released upon exit or
221 226
222 const char *baseargv[] = { 227 const char *baseargv[] = {
223 hgcmd, 228 hgcmd,
224 "serve", 229 "serve",
225 "--cmdserver", "chgunix", 230 "--cmdserver", "chgunix",
226 "--address", opts->sockname, 231 "--address", opts->initsockname,
227 "--daemon-postexec", "chdir:/", 232 "--daemon-postexec", "chdir:/",
228 }; 233 };
229 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]); 234 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
230 size_t argsize = baseargvsize + opts->argsize + 1; 235 size_t argsize = baseargvsize + opts->argsize + 1;
231 236
245 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid) 250 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid)
246 { 251 {
247 static const struct timespec sleepreq = {0, 10 * 1000000}; 252 static const struct timespec sleepreq = {0, 10 * 1000000};
248 int pst = 0; 253 int pst = 0;
249 254
250 debugmsg("try connect to %s repeatedly", opts->sockname); 255 debugmsg("try connect to %s repeatedly", opts->initsockname);
251 256
252 unsigned int timeoutsec = 60; /* default: 60 seconds */ 257 unsigned int timeoutsec = 60; /* default: 60 seconds */
253 const char *timeoutenv = getenv("CHGTIMEOUT"); 258 const char *timeoutenv = getenv("CHGTIMEOUT");
254 if (timeoutenv) 259 if (timeoutenv)
255 sscanf(timeoutenv, "%u", &timeoutsec); 260 sscanf(timeoutenv, "%u", &timeoutsec);
256 261
257 for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) { 262 for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
258 hgclient_t *hgc = hgc_open(opts->sockname); 263 hgclient_t *hgc = hgc_open(opts->initsockname);
259 if (hgc) 264 if (hgc) {
265 debugmsg("rename %s to %s", opts->initsockname,
266 opts->sockname);
267 int r = rename(opts->initsockname, opts->sockname);
268 if (r != 0)
269 abortmsgerrno("cannot rename");
260 return hgc; 270 return hgc;
271 }
261 272
262 if (pid > 0) { 273 if (pid > 0) {
263 /* collect zombie if child process fails to start */ 274 /* collect zombie if child process fails to start */
264 int r = waitpid(pid, &pst, WNOHANG); 275 int r = waitpid(pid, &pst, WNOHANG);
265 if (r != 0) 276 if (r != 0)
267 } 278 }
268 279
269 nanosleep(&sleepreq, NULL); 280 nanosleep(&sleepreq, NULL);
270 } 281 }
271 282
272 abortmsg("timed out waiting for cmdserver %s", opts->sockname); 283 abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
273 return NULL; 284 return NULL;
274 285
275 cleanup: 286 cleanup:
276 if (WIFEXITED(pst)) { 287 if (WIFEXITED(pst)) {
277 if (WEXITSTATUS(pst) == 0) 288 if (WEXITSTATUS(pst) == 0)
310 * address does not work. we do not want to connect to the server 321 * address does not work. we do not want to connect to the server
311 * again because it will probably tell us the same thing. */ 322 * again because it will probably tell us the same thing. */
312 if (sockname == opts->redirectsockname) 323 if (sockname == opts->redirectsockname)
313 unlink(opts->sockname); 324 unlink(opts->sockname);
314 325
315 debugmsg("start cmdserver at %s", opts->sockname); 326 debugmsg("start cmdserver at %s", opts->initsockname);
316 327
317 pid_t pid = fork(); 328 pid_t pid = fork();
318 if (pid < 0) 329 if (pid < 0)
319 abortmsg("failed to fork cmdserver process"); 330 abortmsg("failed to fork cmdserver process");
320 if (pid == 0) { 331 if (pid == 0) {