[PATCH 3 of 3 V2] chg: pass sensitive command line flags to server

Jun Wu quark at fb.com
Wed Feb 17 10:08:59 EST 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1455721247 0
#      Wed Feb 17 15:00:47 2016 +0000
# Node ID f9a49a0f18b29248fb86f3b1b1693b77207ef4ac
# Parent  a87f14c869a38406eab0595b514b915e6b6391a6
chg: pass sensitive command line flags to server

We are going to make chgserver load repo config, remember what it is, and
load repo config again to detect config change. This is the first step that
passes config, repo, cwd options to server. Traceback is passed as well to
cover errors before hitting chgserver.runcommand.

diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c
--- a/contrib/chg/chg.c
+++ b/contrib/chg/chg.c
@@ -32,8 +32,75 @@
 	char sockname[UNIX_PATH_MAX];
 	char lockfile[UNIX_PATH_MAX];
 	char pidfile[UNIX_PATH_MAX];
+	size_t argsize;
+	const char **args;
 };
 
+static void initcmdserveropts(struct cmdserveropts *opts) {
+	memset(opts, 0, sizeof(struct cmdserveropts));
+}
+
+static void freecmdserveropts(struct cmdserveropts *opts) {
+	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 int testsensetiveflag(const char *arg)
+{
+	static const struct {
+		const char *name;
+		const size_t narg;
+	} flags[] = {
+		{"--config", 1},
+		{"--cwd", 1},
+		{"--repo", 1},
+		{"--repository", 1},
+		{"--traceback", 0},
+		{"-R", 1},
+	};
+	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) {
+			if (arg[len] == '\0') {  /* --flag (value) */
+				return narg + 1;
+			} else if (arg[len] == '=' && narg > 0) {  /* --flag=value */
+				return 1;
+			} else if (flags[i].name[1] != '-') {  /* short flag */
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Parse argv[] and put sensitive flags to opts->args
+ */
+static void setcmdserverargs(struct cmdserveropts *opts,
+	int argc, const char *argv[])
+{
+	int i, step;
+	opts->argsize = 0;
+	for (i = 0, step = 1; i < argc; i += step, step = 1) {
+		if (!argv[i]) continue;  /* pass clang-analyse */
+		if (strcmp(argv[i], "--") == 0) break;
+		int n = testsensetiveflag(argv[i]);
+		if (n == 0 || i + n > argc) continue;
+		opts->args = reallocx(opts->args, (n + opts->argsize) * sizeof(char*));
+		memcpy(opts->args + opts->argsize, argv + i, sizeof(char*) * n);
+		opts->argsize += n;
+		step = n;
+	}
+}
+
 static void preparesockdir(const char *sockdir)
 {
 	int r;
@@ -111,7 +178,7 @@
 	if (!hgcmd || hgcmd[0] == '\0')
 		hgcmd = "hg";
 
-	const char *argv[] = {
+	const char *baseargv[] = {
 		hgcmd,
 		"serve",
 		"--cwd", "/",
@@ -122,10 +189,18 @@
 		"--config", "extensions.chgserver=",
 		/* wrap root ui so that it can be disabled/enabled by config */
 		"--config", "progress.assume-tty=1",
-		NULL,
 	};
+	int baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
+	int argsize = baseargvsize + opts->argsize + 1;
+
+	const char **argv = mallocx(sizeof(char*) * argsize);
+	memcpy(argv, baseargv, sizeof(baseargv));
+	memcpy(argv + baseargvsize, opts->args, sizeof(char*) * opts->argsize);
+	argv[argsize - 1] = NULL;
+
 	if (execvp(hgcmd, (char **)argv) < 0)
 		abortmsg("failed to exec cmdserver (errno = %d)", errno);
+	free(argv);
 }
 
 /*
@@ -352,7 +427,9 @@
 		enabledebugmsg();
 
 	struct cmdserveropts opts;
+	initcmdserveropts(&opts);
 	setcmdserveropts(&opts);
+	setcmdserverargs(&opts, argc, argv);
 
 	if (argc == 2) {
 		int sig = 0;
@@ -379,5 +456,6 @@
 	setuppager(hgc, argv + 1, argc - 1);
 	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
 	hgc_close(hgc);
+	freecmdserveropts(&opts);
 	return exitcode;
 }


More information about the Mercurial-devel mailing list