Mercurial > hg
annotate contrib/chg/chg.c @ 28260:0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
There are some known unsupported commands or flags for chg, such as hg serve -d
and hg foo --time. This patch detects these situations and transparently fall
back to the original hg. So the users won't bother remembering what chg can and
cannot do by themselves.
The current detection is not 100% accurate since we do not have an equivalent
command line parser in C. But it tries not to cause false positives that
prevents people from using chg for legit cases. In the future we may want to
implement a more accurate "unsupported" check server-side.
author | Jun Wu <quark@fb.com> |
---|---|
date | Fri, 26 Feb 2016 14:17:59 +0000 |
parents | a3d73e069f8d |
children | 2ab59ac06b76 |
rev | line source |
---|---|
28060 | 1 /* |
2 * A fast client for Mercurial command server | |
3 * | |
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org> | |
5 * | |
6 * This software may be used and distributed according to the terms of the | |
7 * GNU General Public License version 2 or any later version. | |
8 */ | |
9 | |
10 #include <assert.h> | |
11 #include <errno.h> | |
12 #include <fcntl.h> | |
13 #include <signal.h> | |
14 #include <stdio.h> | |
15 #include <stdlib.h> | |
16 #include <string.h> | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
17 #include <sys/file.h> |
28060 | 18 #include <sys/stat.h> |
19 #include <sys/types.h> | |
20 #include <sys/un.h> | |
21 #include <sys/wait.h> | |
22 #include <time.h> | |
23 #include <unistd.h> | |
24 | |
25 #include "hgclient.h" | |
26 #include "util.h" | |
27 | |
28 #ifndef UNIX_PATH_MAX | |
29 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path)) | |
30 #endif | |
31 | |
32 struct cmdserveropts { | |
33 char sockname[UNIX_PATH_MAX]; | |
34 char lockfile[UNIX_PATH_MAX]; | |
35 char pidfile[UNIX_PATH_MAX]; | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
36 size_t argsize; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
37 const char **args; |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
38 int lockfd; |
28060 | 39 }; |
40 | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
41 static void initcmdserveropts(struct cmdserveropts *opts) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
42 memset(opts, 0, sizeof(struct cmdserveropts)); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
43 opts->lockfd = -1; |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
44 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
45 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
46 static void freecmdserveropts(struct cmdserveropts *opts) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
47 free(opts->args); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
48 opts->args = NULL; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
49 opts->argsize = 0; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
50 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
51 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
52 /* |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
53 * Test if an argument is a sensitive flag that should be passed to the server. |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
54 * Return 0 if not, otherwise the number of arguments starting from the current |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
55 * one that should be passed to the server. |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
56 */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
57 static size_t testsensitiveflag(const char *arg) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
58 { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
59 static const struct { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
60 const char *name; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
61 size_t narg; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
62 } flags[] = { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
63 {"--config", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
64 {"--cwd", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
65 {"--repo", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
66 {"--repository", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
67 {"--traceback", 0}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
68 {"-R", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
69 }; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
70 size_t i; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
71 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
72 size_t len = strlen(flags[i].name); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
73 size_t narg = flags[i].narg; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
74 if (memcmp(arg, flags[i].name, len) == 0) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
75 if (arg[len] == '\0') { /* --flag (value) */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
76 return narg + 1; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
77 } else if (arg[len] == '=' && narg > 0) { /* --flag=value */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
78 return 1; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
79 } else if (flags[i].name[1] != '-') { /* short flag */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
80 return 1; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
81 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
82 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
83 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
84 return 0; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
85 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
86 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
87 /* |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
88 * Parse argv[] and put sensitive flags to opts->args |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
89 */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
90 static void setcmdserverargs(struct cmdserveropts *opts, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
91 int argc, const char *argv[]) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
92 { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
93 size_t i, step; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
94 opts->argsize = 0; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
95 for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
96 if (!argv[i]) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
97 continue; /* pass clang-analyse */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
98 if (strcmp(argv[i], "--") == 0) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
99 break; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
100 size_t n = testsensitiveflag(argv[i]); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
101 if (n == 0 || i + n > (size_t)argc) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
102 continue; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
103 opts->args = reallocx(opts->args, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
104 (n + opts->argsize) * sizeof(char *)); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
105 memcpy(opts->args + opts->argsize, argv + i, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
106 sizeof(char *) * n); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
107 opts->argsize += n; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
108 step = n; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
109 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
110 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
111 |
28060 | 112 static void preparesockdir(const char *sockdir) |
113 { | |
114 int r; | |
115 r = mkdir(sockdir, 0700); | |
116 if (r < 0 && errno != EEXIST) | |
117 abortmsg("cannot create sockdir %s (errno = %d)", | |
118 sockdir, errno); | |
119 | |
120 struct stat st; | |
121 r = lstat(sockdir, &st); | |
122 if (r < 0) | |
123 abortmsg("cannot stat %s (errno = %d)", sockdir, errno); | |
124 if (!S_ISDIR(st.st_mode)) | |
125 abortmsg("cannot create sockdir %s (file exists)", sockdir); | |
126 if (st.st_uid != geteuid() || st.st_mode & 0077) | |
127 abortmsg("insecure sockdir %s", sockdir); | |
128 } | |
129 | |
130 static void setcmdserveropts(struct cmdserveropts *opts) | |
131 { | |
132 int r; | |
133 char sockdir[UNIX_PATH_MAX]; | |
134 const char *envsockname = getenv("CHGSOCKNAME"); | |
135 if (!envsockname) { | |
136 /* by default, put socket file in secure directory | |
137 * (permission of socket file may be ignored on some Unices) */ | |
138 const char *tmpdir = getenv("TMPDIR"); | |
139 if (!tmpdir) | |
140 tmpdir = "/tmp"; | |
141 r = snprintf(sockdir, sizeof(sockdir), "%s/chg%d", | |
142 tmpdir, geteuid()); | |
143 if (r < 0 || (size_t)r >= sizeof(sockdir)) | |
144 abortmsg("too long TMPDIR (r = %d)", r); | |
145 preparesockdir(sockdir); | |
146 } | |
147 | |
148 const char *basename = (envsockname) ? envsockname : sockdir; | |
149 const char *sockfmt = (envsockname) ? "%s" : "%s/server"; | |
150 const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock"; | |
151 const char *pidfmt = (envsockname) ? "%s.pid" : "%s/pid"; | |
152 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename); | |
153 if (r < 0 || (size_t)r >= sizeof(opts->sockname)) | |
154 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
155 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename); | |
156 if (r < 0 || (size_t)r >= sizeof(opts->lockfile)) | |
157 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
158 r = snprintf(opts->pidfile, sizeof(opts->pidfile), pidfmt, basename); | |
159 if (r < 0 || (size_t)r >= sizeof(opts->pidfile)) | |
160 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
161 } | |
162 | |
163 /* | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
164 * Acquire a file lock that indicates a client is trying to start and connect |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
165 * to a server, before executing a command. The lock is released upon exit or |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
166 * explicit unlock. Will block if the lock is held by another process. |
28060 | 167 */ |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
168 static void lockcmdserver(struct cmdserveropts *opts) |
28060 | 169 { |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
170 if (opts->lockfd == -1) { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
171 opts->lockfd = open(opts->lockfile, O_RDWR | O_CREAT | O_NOFOLLOW, 0600); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
172 if (opts->lockfd == -1) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
173 abortmsg("cannot create lock file %s", opts->lockfile); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
174 } |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
175 int r = flock(opts->lockfd, LOCK_EX); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
176 if (r == -1) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
177 abortmsg("cannot acquire lock"); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
178 } |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
179 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
180 /* |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
181 * Release the file lock held by calling lockcmdserver. Will do nothing if |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
182 * lockcmdserver is not called. |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
183 */ |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
184 static void unlockcmdserver(struct cmdserveropts *opts) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
185 { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
186 if (opts->lockfd == -1) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
187 return; |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
188 flock(opts->lockfd, LOCK_UN); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
189 close(opts->lockfd); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
190 opts->lockfd = -1; |
28060 | 191 } |
192 | |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
193 static const char *gethgcmd(void) |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
194 { |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
195 static const char *hgcmd = NULL; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
196 if (!hgcmd) { |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
197 hgcmd = getenv("CHGHG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
198 if (!hgcmd || hgcmd[0] == '\0') |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
199 hgcmd = getenv("HG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
200 if (!hgcmd || hgcmd[0] == '\0') |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
201 hgcmd = "hg"; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
202 } |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
203 return hgcmd; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
204 } |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
205 |
28060 | 206 static void execcmdserver(const struct cmdserveropts *opts) |
207 { | |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
208 const char *hgcmd = gethgcmd(); |
28060 | 209 |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
210 const char *baseargv[] = { |
28060 | 211 hgcmd, |
212 "serve", | |
213 "--cwd", "/", | |
214 "--cmdserver", "chgunix", | |
215 "--address", opts->sockname, | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
216 "--daemon-postexec", "none", |
28060 | 217 "--pid-file", opts->pidfile, |
218 "--config", "extensions.chgserver=", | |
219 /* wrap root ui so that it can be disabled/enabled by config */ | |
220 "--config", "progress.assume-tty=1", | |
221 }; | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
222 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
223 size_t argsize = baseargvsize + opts->argsize + 1; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
224 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
225 const char **argv = mallocx(sizeof(char *) * argsize); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
226 memcpy(argv, baseargv, sizeof(baseargv)); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
227 memcpy(argv + baseargvsize, opts->args, sizeof(char *) * opts->argsize); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
228 argv[argsize - 1] = NULL; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
229 |
28060 | 230 if (execvp(hgcmd, (char **)argv) < 0) |
231 abortmsg("failed to exec cmdserver (errno = %d)", errno); | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
232 free(argv); |
28060 | 233 } |
234 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
235 /* Retry until we can connect to the server. Give up after some time. */ |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
236 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid) |
28060 | 237 { |
238 static const struct timespec sleepreq = {0, 10 * 1000000}; | |
239 int pst = 0; | |
240 | |
241 for (unsigned int i = 0; i < 10 * 100; i++) { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
242 hgclient_t *hgc = hgc_open(opts->sockname); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
243 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
244 return hgc; |
28060 | 245 |
246 if (pid > 0) { | |
247 /* collect zombie if child process fails to start */ | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
248 int r = waitpid(pid, &pst, WNOHANG); |
28060 | 249 if (r != 0) |
250 goto cleanup; | |
251 } | |
252 | |
253 nanosleep(&sleepreq, NULL); | |
254 } | |
255 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
256 abortmsg("timed out waiting for cmdserver %s", opts->sockname); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
257 return NULL; |
28060 | 258 |
259 cleanup: | |
260 if (WIFEXITED(pst)) { | |
261 abortmsg("cmdserver exited with status %d", WEXITSTATUS(pst)); | |
262 } else if (WIFSIGNALED(pst)) { | |
263 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst)); | |
264 } else { | |
265 abortmsg("error white waiting cmdserver"); | |
266 } | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
267 return NULL; |
28060 | 268 } |
269 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
270 /* Connect to a cmdserver. Will start a new server on demand. */ |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
271 static hgclient_t *connectcmdserver(struct cmdserveropts *opts) |
28060 | 272 { |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
273 hgclient_t *hgc = hgc_open(opts->sockname); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
274 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
275 return hgc; |
28060 | 276 |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
277 lockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
278 hgc = hgc_open(opts->sockname); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
279 if (hgc) { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
280 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
281 debugmsg("cmdserver is started by another process"); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
282 return hgc; |
28060 | 283 } |
284 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
285 debugmsg("start cmdserver at %s", opts->sockname); |
28060 | 286 |
287 pid_t pid = fork(); | |
288 if (pid < 0) | |
289 abortmsg("failed to fork cmdserver process"); | |
290 if (pid == 0) { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
291 /* do not leak lockfd to hg */ |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
292 close(opts->lockfd); |
28060 | 293 /* bypass uisetup() of pager extension */ |
294 int nullfd = open("/dev/null", O_WRONLY); | |
295 if (nullfd >= 0) { | |
296 dup2(nullfd, fileno(stdout)); | |
297 close(nullfd); | |
298 } | |
299 execcmdserver(opts); | |
300 } else { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
301 hgc = retryconnectcmdserver(opts, pid); |
28060 | 302 } |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
303 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
304 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
305 return hgc; |
28060 | 306 } |
307 | |
308 static void killcmdserver(const struct cmdserveropts *opts, int sig) | |
309 { | |
310 FILE *fp = fopen(opts->pidfile, "r"); | |
311 if (!fp) | |
312 abortmsg("cannot open %s (errno = %d)", opts->pidfile, errno); | |
313 int pid = 0; | |
314 int n = fscanf(fp, "%d", &pid); | |
315 fclose(fp); | |
316 if (n != 1 || pid <= 0) | |
317 abortmsg("cannot read pid from %s", opts->pidfile); | |
318 | |
319 if (kill((pid_t)pid, sig) < 0) { | |
320 if (errno == ESRCH) | |
321 return; | |
322 abortmsg("cannot kill %d (errno = %d)", pid, errno); | |
323 } | |
324 } | |
325 | |
326 static pid_t peerpid = 0; | |
327 | |
328 static void forwardsignal(int sig) | |
329 { | |
330 assert(peerpid > 0); | |
331 if (kill(peerpid, sig) < 0) | |
332 abortmsg("cannot kill %d (errno = %d)", peerpid, errno); | |
333 debugmsg("forward signal %d", sig); | |
334 } | |
335 | |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
336 static void handlestopsignal(int sig) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
337 { |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
338 sigset_t unblockset, oldset; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
339 struct sigaction sa, oldsa; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
340 if (sigemptyset(&unblockset) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
341 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
342 if (sigaddset(&unblockset, sig) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
343 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
344 memset(&sa, 0, sizeof(sa)); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
345 sa.sa_handler = SIG_DFL; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
346 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
347 if (sigemptyset(&sa.sa_mask) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
348 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
349 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
350 forwardsignal(sig); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
351 if (raise(sig) < 0) /* resend to self */ |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
352 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
353 if (sigaction(sig, &sa, &oldsa) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
354 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
355 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
356 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
357 /* resent signal will be handled before sigprocmask() returns */ |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
358 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
359 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
360 if (sigaction(sig, &oldsa, NULL) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
361 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
362 return; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
363 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
364 error: |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
365 abortmsg("failed to handle stop signal (errno = %d)", errno); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
366 } |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
367 |
28060 | 368 static void setupsignalhandler(pid_t pid) |
369 { | |
370 if (pid <= 0) | |
371 return; | |
372 peerpid = pid; | |
373 | |
374 struct sigaction sa; | |
375 memset(&sa, 0, sizeof(sa)); | |
376 sa.sa_handler = forwardsignal; | |
377 sa.sa_flags = SA_RESTART; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
378 if (sigemptyset(&sa.sa_mask) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
379 goto error; |
28060 | 380 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
381 if (sigaction(SIGHUP, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
382 goto error; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
383 if (sigaction(SIGINT, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
384 goto error; |
28060 | 385 |
386 /* terminate frontend by double SIGTERM in case of server freeze */ | |
387 sa.sa_flags |= SA_RESETHAND; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
388 if (sigaction(SIGTERM, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
389 goto error; |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
390 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
391 /* propagate job control requests to worker */ |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
392 sa.sa_handler = forwardsignal; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
393 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
394 if (sigaction(SIGCONT, &sa, NULL) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
395 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
396 sa.sa_handler = handlestopsignal; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
397 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
398 if (sigaction(SIGTSTP, &sa, NULL) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
399 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
400 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
401 return; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
402 |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
403 error: |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
404 abortmsg("failed to set up signal handlers (errno = %d)", errno); |
28060 | 405 } |
406 | |
407 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */ | |
408 static void setuppager(hgclient_t *hgc, const char *const args[], | |
409 size_t argsize) | |
410 { | |
411 const char *pagercmd = hgc_getpager(hgc, args, argsize); | |
412 if (!pagercmd) | |
413 return; | |
414 | |
415 int pipefds[2]; | |
416 if (pipe(pipefds) < 0) | |
417 return; | |
418 pid_t pid = fork(); | |
419 if (pid < 0) | |
420 goto error; | |
421 if (pid == 0) { | |
422 close(pipefds[0]); | |
423 if (dup2(pipefds[1], fileno(stdout)) < 0) | |
424 goto error; | |
425 if (isatty(fileno(stderr))) { | |
426 if (dup2(pipefds[1], fileno(stderr)) < 0) | |
427 goto error; | |
428 } | |
429 close(pipefds[1]); | |
430 hgc_attachio(hgc); /* reattach to pager */ | |
431 return; | |
432 } else { | |
433 dup2(pipefds[0], fileno(stdin)); | |
434 close(pipefds[0]); | |
435 close(pipefds[1]); | |
436 | |
437 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL); | |
438 if (r < 0) { | |
439 abortmsg("cannot start pager '%s' (errno = %d)", | |
440 pagercmd, errno); | |
441 } | |
442 return; | |
443 } | |
444 | |
445 error: | |
446 close(pipefds[0]); | |
447 close(pipefds[1]); | |
448 abortmsg("failed to prepare pager (errno = %d)", errno); | |
449 } | |
450 | |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
451 /* |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
452 * Test whether the command is unsupported or not. This is not designed to |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
453 * cover all cases. But it's fast, does not depend on the server and does |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
454 * not return false positives. |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
455 */ |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
456 static int isunsupported(int argc, const char *argv[]) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
457 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
458 enum { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
459 SERVE = 1, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
460 DAEMON = 2, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
461 SERVEDAEMON = SERVE | DAEMON, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
462 TIME = 4, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
463 }; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
464 unsigned int state = 0; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
465 int i; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
466 for (i = 0; i < argc; ++i) { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
467 if (strcmp(argv[i], "--") == 0) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
468 break; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
469 if (i == 0 && strcmp("serve", argv[i]) == 0) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
470 state |= SERVE; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
471 else if (strcmp("-d", argv[i]) == 0 || |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
472 strcmp("--daemon", argv[i]) == 0) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
473 state |= DAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
474 else if (strcmp("--time", argv[i]) == 0) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
475 state |= TIME; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
476 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
477 return (state & TIME) == TIME || |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
478 (state & SERVEDAEMON) == SERVEDAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
479 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
480 |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
481 static void execoriginalhg(const char *argv[]) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
482 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
483 debugmsg("execute original hg"); |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
484 if (execvp(gethgcmd(), (char **)argv) < 0) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
485 abortmsg("failed to exec original hg (errno = %d)", errno); |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
486 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
487 |
28060 | 488 int main(int argc, const char *argv[], const char *envp[]) |
489 { | |
490 if (getenv("CHGDEBUG")) | |
491 enabledebugmsg(); | |
492 | |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
493 if (isunsupported(argc - 1, argv + 1)) |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
494 execoriginalhg(argv); |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
495 |
28060 | 496 struct cmdserveropts opts; |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
497 initcmdserveropts(&opts); |
28060 | 498 setcmdserveropts(&opts); |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
499 setcmdserverargs(&opts, argc, argv); |
28060 | 500 |
501 if (argc == 2) { | |
502 int sig = 0; | |
503 if (strcmp(argv[1], "--kill-chg-daemon") == 0) | |
504 sig = SIGTERM; | |
505 if (strcmp(argv[1], "--reload-chg-daemon") == 0) | |
506 sig = SIGHUP; | |
507 if (sig > 0) { | |
508 killcmdserver(&opts, sig); | |
509 return 0; | |
510 } | |
511 } | |
512 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
513 hgclient_t *hgc = connectcmdserver(&opts); |
28060 | 514 if (!hgc) |
515 abortmsg("cannot open hg client"); | |
516 | |
517 setupsignalhandler(hgc_peerpid(hgc)); | |
518 hgc_setenv(hgc, envp); | |
519 setuppager(hgc, argv + 1, argc - 1); | |
520 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); | |
521 hgc_close(hgc); | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
522 freecmdserveropts(&opts); |
28060 | 523 return exitcode; |
524 } |