contrib/chg/chg.c
changeset 28167 66f6dad20c19
parent 28086 65d24ca35496
child 28194 7623ba92af72
equal deleted inserted replaced
28166:c6e0c2533e5f 28167:66f6dad20c19
    30 
    30 
    31 struct cmdserveropts {
    31 struct cmdserveropts {
    32 	char sockname[UNIX_PATH_MAX];
    32 	char sockname[UNIX_PATH_MAX];
    33 	char lockfile[UNIX_PATH_MAX];
    33 	char lockfile[UNIX_PATH_MAX];
    34 	char pidfile[UNIX_PATH_MAX];
    34 	char pidfile[UNIX_PATH_MAX];
       
    35 	size_t argsize;
       
    36 	const char **args;
    35 };
    37 };
       
    38 
       
    39 static void initcmdserveropts(struct cmdserveropts *opts) {
       
    40 	memset(opts, 0, sizeof(struct cmdserveropts));
       
    41 }
       
    42 
       
    43 static void freecmdserveropts(struct cmdserveropts *opts) {
       
    44 	free(opts->args);
       
    45 	opts->args = NULL;
       
    46 	opts->argsize = 0;
       
    47 }
       
    48 
       
    49 /*
       
    50  * Test if an argument is a sensitive flag that should be passed to the server.
       
    51  * Return 0 if not, otherwise the number of arguments starting from the current
       
    52  * one that should be passed to the server.
       
    53  */
       
    54 static size_t testsensitiveflag(const char *arg)
       
    55 {
       
    56 	static const struct {
       
    57 		const char *name;
       
    58 		size_t narg;
       
    59 	} flags[] = {
       
    60 		{"--config", 1},
       
    61 		{"--cwd", 1},
       
    62 		{"--repo", 1},
       
    63 		{"--repository", 1},
       
    64 		{"--traceback", 0},
       
    65 		{"-R", 1},
       
    66 	};
       
    67 	size_t i;
       
    68 	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
       
    69 		size_t len = strlen(flags[i].name);
       
    70 		size_t narg = flags[i].narg;
       
    71 		if (memcmp(arg, flags[i].name, len) == 0) {
       
    72 			if (arg[len] == '\0') {  /* --flag (value) */
       
    73 				return narg + 1;
       
    74 			} else if (arg[len] == '=' && narg > 0) {  /* --flag=value */
       
    75 				return 1;
       
    76 			} else if (flags[i].name[1] != '-') {  /* short flag */
       
    77 				return 1;
       
    78 			}
       
    79 		}
       
    80 	}
       
    81 	return 0;
       
    82 }
       
    83 
       
    84 /*
       
    85  * Parse argv[] and put sensitive flags to opts->args
       
    86  */
       
    87 static void setcmdserverargs(struct cmdserveropts *opts,
       
    88 			     int argc, const char *argv[])
       
    89 {
       
    90 	size_t i, step;
       
    91 	opts->argsize = 0;
       
    92 	for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
       
    93 		if (!argv[i])
       
    94 			continue;  /* pass clang-analyse */
       
    95 		if (strcmp(argv[i], "--") == 0)
       
    96 			break;
       
    97 		size_t n = testsensitiveflag(argv[i]);
       
    98 		if (n == 0 || i + n > (size_t)argc)
       
    99 			continue;
       
   100 		opts->args = reallocx(opts->args,
       
   101 				      (n + opts->argsize) * sizeof(char *));
       
   102 		memcpy(opts->args + opts->argsize, argv + i,
       
   103 		       sizeof(char *) * n);
       
   104 		opts->argsize += n;
       
   105 		step = n;
       
   106 	}
       
   107 }
    36 
   108 
    37 static void preparesockdir(const char *sockdir)
   109 static void preparesockdir(const char *sockdir)
    38 {
   110 {
    39 	int r;
   111 	int r;
    40 	r = mkdir(sockdir, 0700);
   112 	r = mkdir(sockdir, 0700);
   109 	if (!hgcmd || hgcmd[0] == '\0')
   181 	if (!hgcmd || hgcmd[0] == '\0')
   110 		hgcmd = getenv("HG");
   182 		hgcmd = getenv("HG");
   111 	if (!hgcmd || hgcmd[0] == '\0')
   183 	if (!hgcmd || hgcmd[0] == '\0')
   112 		hgcmd = "hg";
   184 		hgcmd = "hg";
   113 
   185 
   114 	const char *argv[] = {
   186 	const char *baseargv[] = {
   115 		hgcmd,
   187 		hgcmd,
   116 		"serve",
   188 		"serve",
   117 		"--cwd", "/",
   189 		"--cwd", "/",
   118 		"--cmdserver", "chgunix",
   190 		"--cmdserver", "chgunix",
   119 		"--address", opts->sockname,
   191 		"--address", opts->sockname,
   120 		"--daemon-pipefds", opts->lockfile,
   192 		"--daemon-pipefds", opts->lockfile,
   121 		"--pid-file", opts->pidfile,
   193 		"--pid-file", opts->pidfile,
   122 		"--config", "extensions.chgserver=",
   194 		"--config", "extensions.chgserver=",
   123 		/* wrap root ui so that it can be disabled/enabled by config */
   195 		/* wrap root ui so that it can be disabled/enabled by config */
   124 		"--config", "progress.assume-tty=1",
   196 		"--config", "progress.assume-tty=1",
   125 		NULL,
       
   126 	};
   197 	};
       
   198 	size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
       
   199 	size_t argsize = baseargvsize + opts->argsize + 1;
       
   200 
       
   201 	const char **argv = mallocx(sizeof(char *) * argsize);
       
   202 	memcpy(argv, baseargv, sizeof(baseargv));
       
   203 	memcpy(argv + baseargvsize, opts->args, sizeof(char *) * opts->argsize);
       
   204 	argv[argsize - 1] = NULL;
       
   205 
   127 	if (execvp(hgcmd, (char **)argv) < 0)
   206 	if (execvp(hgcmd, (char **)argv) < 0)
   128 		abortmsg("failed to exec cmdserver (errno = %d)", errno);
   207 		abortmsg("failed to exec cmdserver (errno = %d)", errno);
       
   208 	free(argv);
   129 }
   209 }
   130 
   210 
   131 /*
   211 /*
   132  * Sleep until lock file is deleted, i.e. cmdserver process starts listening.
   212  * Sleep until lock file is deleted, i.e. cmdserver process starts listening.
   133  * If pid is given, it also checks if the child process fails to start.
   213  * If pid is given, it also checks if the child process fails to start.
   350 {
   430 {
   351 	if (getenv("CHGDEBUG"))
   431 	if (getenv("CHGDEBUG"))
   352 		enabledebugmsg();
   432 		enabledebugmsg();
   353 
   433 
   354 	struct cmdserveropts opts;
   434 	struct cmdserveropts opts;
       
   435 	initcmdserveropts(&opts);
   355 	setcmdserveropts(&opts);
   436 	setcmdserveropts(&opts);
       
   437 	setcmdserverargs(&opts, argc, argv);
   356 
   438 
   357 	if (argc == 2) {
   439 	if (argc == 2) {
   358 		int sig = 0;
   440 		int sig = 0;
   359 		if (strcmp(argv[1], "--kill-chg-daemon") == 0)
   441 		if (strcmp(argv[1], "--kill-chg-daemon") == 0)
   360 			sig = SIGTERM;
   442 			sig = SIGTERM;
   377 	setupsignalhandler(hgc_peerpid(hgc));
   459 	setupsignalhandler(hgc_peerpid(hgc));
   378 	hgc_setenv(hgc, envp);
   460 	hgc_setenv(hgc, envp);
   379 	setuppager(hgc, argv + 1, argc - 1);
   461 	setuppager(hgc, argv + 1, argc - 1);
   380 	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
   462 	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
   381 	hgc_close(hgc);
   463 	hgc_close(hgc);
       
   464 	freecmdserveropts(&opts);
   382 	return exitcode;
   465 	return exitcode;
   383 }
   466 }