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 } |