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.
--- a/contrib/chg/chg.c Mon Dec 19 22:07:41 2016 +0000
+++ b/contrib/chg/chg.c Mon Dec 19 22:09:49 2016 +0000
@@ -31,6 +31,7 @@
struct cmdserveropts {
char sockname[UNIX_PATH_MAX];
+ char initsockname[UNIX_PATH_MAX];
char redirectsockname[UNIX_PATH_MAX];
char lockfile[UNIX_PATH_MAX];
size_t argsize;
@@ -163,6 +164,10 @@
r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename);
if (r < 0 || (size_t)r >= sizeof(opts->lockfile))
abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
+ r = snprintf(opts->initsockname, sizeof(opts->initsockname),
+ "%s.%u", opts->sockname, (unsigned)getpid());
+ if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
+ abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
}
/*
@@ -223,7 +228,7 @@
hgcmd,
"serve",
"--cmdserver", "chgunix",
- "--address", opts->sockname,
+ "--address", opts->initsockname,
"--daemon-postexec", "chdir:/",
};
size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
@@ -247,7 +252,7 @@
static const struct timespec sleepreq = {0, 10 * 1000000};
int pst = 0;
- debugmsg("try connect to %s repeatedly", opts->sockname);
+ debugmsg("try connect to %s repeatedly", opts->initsockname);
unsigned int timeoutsec = 60; /* default: 60 seconds */
const char *timeoutenv = getenv("CHGTIMEOUT");
@@ -255,9 +260,15 @@
sscanf(timeoutenv, "%u", &timeoutsec);
for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
- hgclient_t *hgc = hgc_open(opts->sockname);
- if (hgc)
+ hgclient_t *hgc = hgc_open(opts->initsockname);
+ if (hgc) {
+ debugmsg("rename %s to %s", opts->initsockname,
+ opts->sockname);
+ int r = rename(opts->initsockname, opts->sockname);
+ if (r != 0)
+ abortmsgerrno("cannot rename");
return hgc;
+ }
if (pid > 0) {
/* collect zombie if child process fails to start */
@@ -269,7 +280,7 @@
nanosleep(&sleepreq, NULL);
}
- abortmsg("timed out waiting for cmdserver %s", opts->sockname);
+ abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
return NULL;
cleanup:
@@ -312,7 +323,7 @@
if (sockname == opts->redirectsockname)
unlink(opts->sockname);
- debugmsg("start cmdserver at %s", opts->sockname);
+ debugmsg("start cmdserver at %s", opts->initsockname);
pid_t pid = fork();
if (pid < 0)
--- a/tests/test-chg.t Mon Dec 19 22:07:41 2016 +0000
+++ b/tests/test-chg.t Mon Dec 19 22:09:49 2016 +0000
@@ -46,7 +46,7 @@
warm up server:
$ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
- chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server
+ chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
new server should be started if extension modified:
@@ -55,7 +55,7 @@
$ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
chg: debug: instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
chg: debug: instruction: reconnect
- chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server
+ chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
old server will shut down, while new server should still be reachable:
@@ -77,7 +77,7 @@
(this test makes sure that old server shut down automatically)
$ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
- chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server
+ chg: debug: start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
shut down servers and restore environment: