##// END OF EJS Templates
copies: fix the changeset based algorithm regarding merge...
copies: fix the changeset based algorithm regarding merge In 99ebde4fec99, we changed the list of files stored into the `files` field. This lead to the changeset centric copy algorithm to break in various merge situation involving merge. Older information could reach the merge through `p1`, and while information from `p2` was strictly fresher, it would get overwritten anyway. We update the situation with more details about which revision introduces rename information. This help use making the right decision in case of merge. We are now running a more comprehensive suite of test with include this kind of situation. The behavior differ slightly from the filelog based in a couple of instance. There is mostly two distinct cases: 1) there are conflicting rename information in a merge (different rename history on each side). In this case the filelog based implementation arbitrarily pick a side based on the file-revision-number. So it depends on a local factor. The changeset centric algorithm will use a deterministic approach, by picking the information coming from the first parent of the merge. This is stable across different clone. 2) rename information related to file that exist in both source and destination. The filelog based implementation do not even try to detect these, however the changeset centric one get them for "free" (it is simpler to detect them than not). The new implementation focus on correctness. Performance improvement will come later. Differential Revision: https://phab.mercurial-scm.org/D8244

File last commit:

r45107:1e459ac4 default
r45252:45f3f35c default
Show More
chg.c
470 lines | 12.5 KiB | text/x-c | CLexer
Yuya Nishihara
chg: import frontend sources...
r28060 /*
* A fast client for Mercurial command server
*
* Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2 or any later version.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Jun Wu
chg: hold a lock file before connected to server...
r28196 #include <sys/file.h>
Yuya Nishihara
chg: import frontend sources...
r28060 #include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "hgclient.h"
Jun Wu
chg: add procutil.h...
r30693 #include "procutil.h"
Yuya Nishihara
chg: import frontend sources...
r28060 #include "util.h"
Jun Wu
chg: support long socket path...
r30677 #ifndef PATH_MAX
#define PATH_MAX 4096
Yuya Nishihara
chg: import frontend sources...
r28060 #endif
struct cmdserveropts {
Jun Wu
chg: support long socket path...
r30677 char sockname[PATH_MAX];
char initsockname[PATH_MAX];
char redirectsockname[PATH_MAX];
Jun Wu
chg: pass sensitive command line flags to server...
r28167 size_t argsize;
const char **args;
Yuya Nishihara
chg: import frontend sources...
r28060 };
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 static void initcmdserveropts(struct cmdserveropts *opts)
{
Jun Wu
chg: pass sensitive command line flags to server...
r28167 memset(opts, 0, sizeof(struct cmdserveropts));
}
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 static void freecmdserveropts(struct cmdserveropts *opts)
{
Jun Wu
chg: pass sensitive command line flags to server...
r28167 free(opts->args);
opts->args = NULL;
opts->argsize = 0;
}
/*
* Test if an argument is a sensitive flag that should be passed to the server.
* Return 0 if not, otherwise the number of arguments starting from the current
* one that should be passed to the server.
*/
static size_t testsensitiveflag(const char *arg)
{
static const struct {
const char *name;
size_t narg;
} flags[] = {
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 {"--config", 1}, {"--cwd", 1}, {"--repo", 1},
{"--repository", 1}, {"--traceback", 0}, {"-R", 1},
Jun Wu
chg: pass sensitive command line flags to server...
r28167 };
size_t i;
for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
size_t len = strlen(flags[i].name);
size_t narg = flags[i].narg;
if (memcmp(arg, flags[i].name, len) == 0) {
Jun Wu
chg: wrap line at 80 chars...
r28790 if (arg[len] == '\0') {
/* --flag (value) */
Jun Wu
chg: pass sensitive command line flags to server...
r28167 return narg + 1;
Jun Wu
chg: wrap line at 80 chars...
r28790 } else if (arg[len] == '=' && narg > 0) {
/* --flag=value */
Jun Wu
chg: pass sensitive command line flags to server...
r28167 return 1;
Jun Wu
chg: wrap line at 80 chars...
r28790 } else if (flags[i].name[1] != '-') {
/* short flag */
Jun Wu
chg: pass sensitive command line flags to server...
r28167 return 1;
}
}
}
return 0;
}
/*
* Parse argv[] and put sensitive flags to opts->args
*/
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 static void setcmdserverargs(struct cmdserveropts *opts, int argc,
const char *argv[])
Jun Wu
chg: pass sensitive command line flags to server...
r28167 {
size_t i, step;
opts->argsize = 0;
for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
if (!argv[i])
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 continue; /* pass clang-analyse */
Jun Wu
chg: pass sensitive command line flags to server...
r28167 if (strcmp(argv[i], "--") == 0)
break;
size_t n = testsensitiveflag(argv[i]);
if (n == 0 || i + n > (size_t)argc)
continue;
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 opts->args =
reallocx(opts->args, (n + opts->argsize) * sizeof(char *));
Jun Wu
chg: pass sensitive command line flags to server...
r28167 memcpy(opts->args + opts->argsize, argv + i,
sizeof(char *) * n);
opts->argsize += n;
step = n;
}
}
Yuya Nishihara
chg: import frontend sources...
r28060 static void preparesockdir(const char *sockdir)
{
int r;
r = mkdir(sockdir, 0700);
if (r < 0 && errno != EEXIST)
Jun Wu
chg: replace abortmsg showing errno with abortmsgerrno...
r28789 abortmsgerrno("cannot create sockdir %s", sockdir);
Yuya Nishihara
chg: import frontend sources...
r28060
struct stat st;
r = lstat(sockdir, &st);
if (r < 0)
Jun Wu
chg: replace abortmsg showing errno with abortmsgerrno...
r28789 abortmsgerrno("cannot stat %s", sockdir);
Yuya Nishihara
chg: import frontend sources...
r28060 if (!S_ISDIR(st.st_mode))
abortmsg("cannot create sockdir %s (file exists)", sockdir);
if (st.st_uid != geteuid() || st.st_mode & 0077)
abortmsg("insecure sockdir %s", sockdir);
}
Jun Wu
chg: verify XDG_RUNTIME_DIR...
r30884 /*
* Check if a socket directory exists and is only owned by the current user.
* Return 1 if so, 0 if not. This is used to check if XDG_RUNTIME_DIR can be
* used or not. According to the specification [1], XDG_RUNTIME_DIR should be
* ignored if the directory is not owned by the user with mode 0700.
* [1]: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*/
static int checkruntimedir(const char *sockdir)
{
struct stat st;
int r = lstat(sockdir, &st);
if (r < 0) /* ex. does not exist */
return 0;
if (!S_ISDIR(st.st_mode)) /* ex. is a file, not a directory */
return 0;
return st.st_uid == geteuid() && (st.st_mode & 0777) == 0700;
}
Jun Wu
chg: make "get default sockdir" a separate method...
r30680 static void getdefaultsockdir(char sockdir[], size_t size)
{
/* by default, put socket file in secure directory
Jun Wu
chg: respect XDG_RUNTIME_DIR...
r30681 * (${XDG_RUNTIME_DIR}/chg, or /${TMPDIR:-tmp}/chg$UID)
Jun Wu
chg: make "get default sockdir" a separate method...
r30680 * (permission of socket file may be ignored on some Unices) */
Jun Wu
chg: respect XDG_RUNTIME_DIR...
r30681 const char *runtimedir = getenv("XDG_RUNTIME_DIR");
int r;
Jun Wu
chg: verify XDG_RUNTIME_DIR...
r30884 if (runtimedir && checkruntimedir(runtimedir)) {
Jun Wu
chg: respect XDG_RUNTIME_DIR...
r30681 r = snprintf(sockdir, size, "%s/chg", runtimedir);
} else {
const char *tmpdir = getenv("TMPDIR");
if (!tmpdir)
tmpdir = "/tmp";
r = snprintf(sockdir, size, "%s/chg%d", tmpdir, geteuid());
}
Jun Wu
chg: make "get default sockdir" a separate method...
r30680 if (r < 0 || (size_t)r >= size)
abortmsg("too long TMPDIR (r = %d)", r);
}
Yuya Nishihara
chg: import frontend sources...
r28060 static void setcmdserveropts(struct cmdserveropts *opts)
{
int r;
Jun Wu
chg: support long socket path...
r30677 char sockdir[PATH_MAX];
Yuya Nishihara
chg: import frontend sources...
r28060 const char *envsockname = getenv("CHGSOCKNAME");
if (!envsockname) {
Jun Wu
chg: make "get default sockdir" a separate method...
r30680 getdefaultsockdir(sockdir, sizeof(sockdir));
Yuya Nishihara
chg: import frontend sources...
r28060 preparesockdir(sockdir);
}
const char *basename = (envsockname) ? envsockname : sockdir;
const char *sockfmt = (envsockname) ? "%s" : "%s/server";
r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
if (r < 0 || (size_t)r >= sizeof(opts->sockname))
abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 r = snprintf(opts->initsockname, sizeof(opts->initsockname), "%s.%u",
opts->sockname, (unsigned)getpid());
Jun Wu
chg: start server at a unique address...
r30620 if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: extract gethgcmd logic to a function...
r28237 static const char *gethgcmd(void)
{
static const char *hgcmd = NULL;
if (!hgcmd) {
hgcmd = getenv("CHGHG");
if (!hgcmd || hgcmd[0] == '\0')
hgcmd = getenv("HG");
if (!hgcmd || hgcmd[0] == '\0')
Jun Wu
chg: allows default hg path to be overridden...
r28605 #ifdef HGPATH
hgcmd = (HGPATH);
#else
Jun Wu
chg: extract gethgcmd logic to a function...
r28237 hgcmd = "hg";
Jun Wu
chg: allows default hg path to be overridden...
r28605 #endif
Jun Wu
chg: extract gethgcmd logic to a function...
r28237 }
return hgcmd;
}
Yuya Nishihara
chg: import frontend sources...
r28060 static void execcmdserver(const struct cmdserveropts *opts)
{
Jun Wu
chg: extract gethgcmd logic to a function...
r28237 const char *hgcmd = gethgcmd();
Yuya Nishihara
chg: import frontend sources...
r28060
Jun Wu
chg: pass sensitive command line flags to server...
r28167 const char *baseargv[] = {
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 hgcmd,
"serve",
"--cmdserver",
"chgunix",
"--address",
opts->initsockname,
"--daemon-postexec",
"chdir:/",
Yuya Nishihara
chg: import frontend sources...
r28060 };
Jun Wu
chg: pass sensitive command line flags to server...
r28167 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
size_t argsize = baseargvsize + opts->argsize + 1;
const char **argv = mallocx(sizeof(char *) * argsize);
memcpy(argv, baseargv, sizeof(baseargv));
Jun Wu
chg: fix an undefined behavior about memcpy...
r38256 if (opts->args) {
size_t size = sizeof(char *) * opts->argsize;
memcpy(argv + baseargvsize, opts->args, size);
}
Jun Wu
chg: pass sensitive command line flags to server...
r28167 argv[argsize - 1] = NULL;
Kyle Lippincott
chg: force-set LC_CTYPE on server start to actual value from the environment...
r44733 const char *lc_ctype_env = getenv("LC_CTYPE");
if (lc_ctype_env == NULL) {
if (putenv("CHG_CLEAR_LC_CTYPE=") != 0)
abortmsgerrno("failed to putenv CHG_CLEAR_LC_CTYPE");
} else {
if (setenv("CHGORIG_LC_CTYPE", lc_ctype_env, 1) != 0) {
abortmsgerrno("failed to setenv CHGORIG_LC_CTYYPE");
}
}
Jun Wu
chg: detect chg started by chg...
r28261 if (putenv("CHGINTERNALMARK=") != 0)
Jun Wu
chg: replace abortmsg showing errno with abortmsgerrno...
r28789 abortmsgerrno("failed to putenv");
Yuya Nishihara
chg: import frontend sources...
r28060 if (execvp(hgcmd, (char **)argv) < 0)
Jun Wu
chg: replace abortmsg showing errno with abortmsgerrno...
r28789 abortmsgerrno("failed to exec cmdserver");
Jun Wu
chg: pass sensitive command line flags to server...
r28167 free(argv);
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: hold a lock file before connected to server...
r28196 /* Retry until we can connect to the server. Give up after some time. */
static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid)
Yuya Nishihara
chg: import frontend sources...
r28060 {
static const struct timespec sleepreq = {0, 10 * 1000000};
int pst = 0;
Jun Wu
chg: start server at a unique address...
r30620 debugmsg("try connect to %s repeatedly", opts->initsockname);
Jun Wu
chg: make timeout adjustable...
r29345
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 unsigned int timeoutsec = 60; /* default: 60 seconds */
Jun Wu
chg: make timeout adjustable...
r29345 const char *timeoutenv = getenv("CHGTIMEOUT");
if (timeoutenv)
sscanf(timeoutenv, "%u", &timeoutsec);
for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
Jun Wu
chg: start server at a unique address...
r30620 hgclient_t *hgc = hgc_open(opts->initsockname);
if (hgc) {
debugmsg("rename %s to %s", opts->initsockname,
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 opts->sockname);
Jun Wu
chg: start server at a unique address...
r30620 int r = rename(opts->initsockname, opts->sockname);
if (r != 0)
abortmsgerrno("cannot rename");
Jun Wu
chg: hold a lock file before connected to server...
r28196 return hgc;
Jun Wu
chg: start server at a unique address...
r30620 }
Yuya Nishihara
chg: import frontend sources...
r28060
if (pid > 0) {
/* collect zombie if child process fails to start */
Jun Wu
chg: hold a lock file before connected to server...
r28196 int r = waitpid(pid, &pst, WNOHANG);
Yuya Nishihara
chg: import frontend sources...
r28060 if (r != 0)
goto cleanup;
}
nanosleep(&sleepreq, NULL);
}
Jun Wu
chg: start server at a unique address...
r30620 abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
Jun Wu
chg: hold a lock file before connected to server...
r28196 return NULL;
Yuya Nishihara
chg: import frontend sources...
r28060
cleanup:
if (WIFEXITED(pst)) {
Jun Wu
chg: server exited with code 0 without being connectable is an error...
r28863 if (WEXITSTATUS(pst) == 0)
abortmsg("could not connect to cmdserver "
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 "(exited with status 0)");
Jun Wu
chg: silently inherit server exit code...
r28477 debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
exit(WEXITSTATUS(pst));
Yuya Nishihara
chg: import frontend sources...
r28060 } else if (WIFSIGNALED(pst)) {
abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
} else {
Jun Wu
chg: fix spelling in the error message about error waiting for cmdserver...
r28851 abortmsg("error while waiting for cmdserver");
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: hold a lock file before connected to server...
r28196 return NULL;
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: hold a lock file before connected to server...
r28196 /* Connect to a cmdserver. Will start a new server on demand. */
static hgclient_t *connectcmdserver(struct cmdserveropts *opts)
Yuya Nishihara
chg: import frontend sources...
r28060 {
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 const char *sockname =
opts->redirectsockname[0] ? opts->redirectsockname : opts->sockname;
Jun Wu
chg: make connect debug message less repetitive...
r28769 debugmsg("try connect to %s", sockname);
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 hgclient_t *hgc = hgc_open(sockname);
Jun Wu
chg: hold a lock file before connected to server...
r28196 if (hgc)
return hgc;
Yuya Nishihara
chg: import frontend sources...
r28060
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 /* prevent us from being connected to an outdated server: we were
* told by a server to redirect to opts->redirectsockname and that
* address does not work. we do not want to connect to the server
* again because it will probably tell us the same thing. */
if (sockname == opts->redirectsockname)
unlink(opts->sockname);
Jun Wu
chg: start server at a unique address...
r30620 debugmsg("start cmdserver at %s", opts->initsockname);
Yuya Nishihara
chg: import frontend sources...
r28060
pid_t pid = fork();
if (pid < 0)
abortmsg("failed to fork cmdserver process");
if (pid == 0) {
execcmdserver(opts);
} else {
Jun Wu
chg: hold a lock file before connected to server...
r28196 hgc = retryconnectcmdserver(opts, pid);
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: hold a lock file before connected to server...
r28196
return hgc;
Yuya Nishihara
chg: import frontend sources...
r28060 }
Jun Wu
chg: do not write pidfile...
r28455 static void killcmdserver(const struct cmdserveropts *opts)
Yuya Nishihara
chg: import frontend sources...
r28060 {
Jun Wu
chg: do not write pidfile...
r28455 /* resolve config hash */
char *resolvedpath = realpath(opts->sockname, NULL);
if (resolvedpath) {
unlink(resolvedpath);
free(resolvedpath);
Yuya Nishihara
chg: import frontend sources...
r28060 }
}
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 /* Run instructions sent from the server like unlink and set redirect path
* Return 1 if reconnect is needed, otherwise 0 */
static int runinstructions(struct cmdserveropts *opts, const char **insts)
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 {
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 int needreconnect = 0;
if (!insts)
return needreconnect;
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 assert(insts);
opts->redirectsockname[0] = '\0';
const char **pinst;
for (pinst = insts; *pinst; pinst++) {
debugmsg("instruction: %s", *pinst);
if (strncmp(*pinst, "unlink ", 7) == 0) {
unlink(*pinst + 7);
} else if (strncmp(*pinst, "redirect ", 9) == 0) {
int r = snprintf(opts->redirectsockname,
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 sizeof(opts->redirectsockname), "%s",
*pinst + 9);
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 if (r < 0 || r >= (int)sizeof(opts->redirectsockname))
abortmsg("redirect path is too long (%d)", r);
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 needreconnect = 1;
Jun Wu
chgserver: handle ParseError during validate...
r28516 } else if (strncmp(*pinst, "exit ", 5) == 0) {
int n = 0;
if (sscanf(*pinst + 5, "%d", &n) != 1)
abortmsg("cannot read the exit code");
exit(n);
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 } else if (strcmp(*pinst, "reconnect") == 0) {
needreconnect = 1;
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 } else {
abortmsg("unknown instruction: %s", *pinst);
}
}
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 return needreconnect;
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 }
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 /*
* Test whether the command is unsupported or not. This is not designed to
Pulkit Goyal
chg: be stricter about checking invocation of `serve` command...
r45107 * cover all cases. But it's fast, does not depend on the server.
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 */
static int isunsupported(int argc, const char *argv[])
{
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 enum { SERVE = 1,
DAEMON = 2,
SERVEDAEMON = SERVE | DAEMON,
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 };
unsigned int state = 0;
int i;
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--") == 0)
break;
Pulkit Goyal
chg: be stricter about checking invocation of `serve` command...
r45107 /*
* there can be false positives but no false negative
* we cannot assume `serve` will always be first argument
* because global options can be passed before the command name
*/
if (strcmp("serve", argv[i]) == 0)
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 state |= SERVE;
else if (strcmp("-d", argv[i]) == 0 ||
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 strcmp("--daemon", argv[i]) == 0)
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 state |= DAEMON;
}
Yuya Nishihara
chg: just forward --time to command server...
r34532 return (state & SERVEDAEMON) == SERVEDAEMON;
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 }
static void execoriginalhg(const char *argv[])
{
debugmsg("execute original hg");
if (execvp(gethgcmd(), (char **)argv) < 0)
Jun Wu
chg: replace abortmsg showing errno with abortmsgerrno...
r28789 abortmsgerrno("failed to exec original hg");
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 }
Yuya Nishihara
chg: import frontend sources...
r28060 int main(int argc, const char *argv[], const char *envp[])
{
if (getenv("CHGDEBUG"))
enabledebugmsg();
Jun Wu
chg: use color in debug/error messages conditionally...
r28787 if (!getenv("HGPLAIN") && isatty(fileno(stderr)))
enablecolor();
Jun Wu
chg: detect chg started by chg...
r28261 if (getenv("CHGINTERNALMARK"))
abortmsg("chg started by chg detected.\n"
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 "Please make sure ${HG:-hg} is not a symlink or "
"wrapper to chg. Alternatively, set $CHGHG to the "
"path of real hg.");
Jun Wu
chg: detect chg started by chg...
r28261
Jun Wu
chg: fallback to original hg for some unsupported commands or flags...
r28260 if (isunsupported(argc - 1, argv + 1))
execoriginalhg(argv);
Yuya Nishihara
chg: import frontend sources...
r28060 struct cmdserveropts opts;
Jun Wu
chg: pass sensitive command line flags to server...
r28167 initcmdserveropts(&opts);
Yuya Nishihara
chg: import frontend sources...
r28060 setcmdserveropts(&opts);
Jun Wu
chg: pass sensitive command line flags to server...
r28167 setcmdserverargs(&opts, argc, argv);
Yuya Nishihara
chg: import frontend sources...
r28060
if (argc == 2) {
Jun Wu
chg: do not write pidfile...
r28455 if (strcmp(argv[1], "--kill-chg-daemon") == 0) {
killcmdserver(&opts);
Yuya Nishihara
chg: import frontend sources...
r28060 return 0;
}
}
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 hgclient_t *hgc;
Jun Wu
chg: limit reconnect attempts...
r28358 size_t retry = 0;
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 while (1) {
hgc = connectcmdserver(&opts);
if (!hgc)
abortmsg("cannot open hg client");
hgc_setenv(hgc, envp);
const char **insts = hgc_validate(hgc, argv + 1, argc - 1);
Jun Wu
chgserver: add an explicit "reconnect" instruction to validate...
r28535 int needreconnect = runinstructions(&opts, insts);
free(insts);
if (!needreconnect)
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 break;
hgc_close(hgc);
Jun Wu
chg: limit reconnect attempts...
r28358 if (++retry > 10)
abortmsg("too many redirections.\n"
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 "Please make sure %s is not a wrapper which "
"changes sensitive environment variables "
"before executing hg. If you have to use a "
"wrapper, wrap chg instead of hg.",
gethgcmd());
Jun Wu
chg: use validate to make sure the server is up to date...
r28357 }
Yuya Nishihara
chg: import frontend sources...
r28060
Jun Wu
chg: decouple hgclient from setupsignalhandler...
r30690 setupsignalhandler(hgc_peerpid(hgc), hgc_peerpgid(hgc));
Jun Wu
chg: always wait for pager...
r31890 atexit(waitpager);
Yuya Nishihara
chg: import frontend sources...
r28060 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
Yuya Nishihara
chg: reset signal handlers to default before waiting pager...
r29369 restoresignalhandler();
Yuya Nishihara
chg: import frontend sources...
r28060 hgc_close(hgc);
Jun Wu
chg: pass sensitive command line flags to server...
r28167 freecmdserveropts(&opts);
Jun Wu
chg: exec pager in child process...
r29344
Yuya Nishihara
chg: import frontend sources...
r28060 return exitcode;
}