Mercurial > hg-stable
annotate contrib/chg/chg.c @ 29016:94451300f3ec stable
chg: initialize sockdirfd to -1 instead of AT_FDCWD
As we don't use sockdirfd yet, this is the simplest workaround to compile chg
on old Unices where AT_FDCWD does not exist. Foozy pointed out Mac OS X 10.10
is required for AT_FDCWD as well as xxxat() functions.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 24 Apr 2016 21:35:30 +0900 |
parents | b89e4457fa86 |
children | bb3d5c20eaf6 |
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]; | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
34 char redirectsockname[UNIX_PATH_MAX]; |
28060 | 35 char lockfile[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; |
28852
7b5f5a1b4b41
chg: add sockdirfd to cmdserveropts
Jun Wu <quark@fb.com>
parents:
28851
diff
changeset
|
39 int sockdirfd; |
28060 | 40 }; |
41 | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
42 static void initcmdserveropts(struct cmdserveropts *opts) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
43 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
|
44 opts->lockfd = -1; |
29016
94451300f3ec
chg: initialize sockdirfd to -1 instead of AT_FDCWD
Yuya Nishihara <yuya@tcha.org>
parents:
28980
diff
changeset
|
45 opts->sockdirfd = -1; |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
46 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
47 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
48 static void freecmdserveropts(struct cmdserveropts *opts) { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
49 free(opts->args); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
50 opts->args = NULL; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
51 opts->argsize = 0; |
28853
d11548b4ae45
chg: check lockfd at freecmdserveropts
Jun Wu <quark@fb.com>
parents:
28852
diff
changeset
|
52 assert(opts->lockfd == -1 && "should be closed by unlockcmdserver()"); |
29016
94451300f3ec
chg: initialize sockdirfd to -1 instead of AT_FDCWD
Yuya Nishihara <yuya@tcha.org>
parents:
28980
diff
changeset
|
53 if (opts->sockdirfd >= 0) { |
28852
7b5f5a1b4b41
chg: add sockdirfd to cmdserveropts
Jun Wu <quark@fb.com>
parents:
28851
diff
changeset
|
54 close(opts->sockdirfd); |
29016
94451300f3ec
chg: initialize sockdirfd to -1 instead of AT_FDCWD
Yuya Nishihara <yuya@tcha.org>
parents:
28980
diff
changeset
|
55 opts->sockdirfd = -1; |
28852
7b5f5a1b4b41
chg: add sockdirfd to cmdserveropts
Jun Wu <quark@fb.com>
parents:
28851
diff
changeset
|
56 } |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
57 } |
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 /* |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
60 * 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
|
61 * 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
|
62 * 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
|
63 */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
64 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
|
65 { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
66 static const struct { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
67 const char *name; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
68 size_t narg; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
69 } flags[] = { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
70 {"--config", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
71 {"--cwd", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
72 {"--repo", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
73 {"--repository", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
74 {"--traceback", 0}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
75 {"-R", 1}, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
76 }; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
77 size_t i; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
78 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
|
79 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
|
80 size_t narg = flags[i].narg; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
81 if (memcmp(arg, flags[i].name, len) == 0) { |
28790 | 82 if (arg[len] == '\0') { |
83 /* --flag (value) */ | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
84 return narg + 1; |
28790 | 85 } else if (arg[len] == '=' && narg > 0) { |
86 /* --flag=value */ | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
87 return 1; |
28790 | 88 } else if (flags[i].name[1] != '-') { |
89 /* short flag */ | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
90 return 1; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
91 } |
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 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
94 return 0; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
95 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
96 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
97 /* |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
98 * 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
|
99 */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
100 static void setcmdserverargs(struct cmdserveropts *opts, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
101 int argc, const char *argv[]) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
102 { |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
103 size_t i, step; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
104 opts->argsize = 0; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
105 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
|
106 if (!argv[i]) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
107 continue; /* pass clang-analyse */ |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
108 if (strcmp(argv[i], "--") == 0) |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
109 break; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
110 size_t n = testsensitiveflag(argv[i]); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
111 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
|
112 continue; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
113 opts->args = reallocx(opts->args, |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
114 (n + opts->argsize) * sizeof(char *)); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
115 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
|
116 sizeof(char *) * n); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
117 opts->argsize += n; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
118 step = n; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
119 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
120 } |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
121 |
28060 | 122 static void preparesockdir(const char *sockdir) |
123 { | |
124 int r; | |
125 r = mkdir(sockdir, 0700); | |
126 if (r < 0 && errno != EEXIST) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
127 abortmsgerrno("cannot create sockdir %s", sockdir); |
28060 | 128 |
129 struct stat st; | |
130 r = lstat(sockdir, &st); | |
131 if (r < 0) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
132 abortmsgerrno("cannot stat %s", sockdir); |
28060 | 133 if (!S_ISDIR(st.st_mode)) |
134 abortmsg("cannot create sockdir %s (file exists)", sockdir); | |
135 if (st.st_uid != geteuid() || st.st_mode & 0077) | |
136 abortmsg("insecure sockdir %s", sockdir); | |
137 } | |
138 | |
139 static void setcmdserveropts(struct cmdserveropts *opts) | |
140 { | |
141 int r; | |
142 char sockdir[UNIX_PATH_MAX]; | |
143 const char *envsockname = getenv("CHGSOCKNAME"); | |
144 if (!envsockname) { | |
145 /* by default, put socket file in secure directory | |
146 * (permission of socket file may be ignored on some Unices) */ | |
147 const char *tmpdir = getenv("TMPDIR"); | |
148 if (!tmpdir) | |
149 tmpdir = "/tmp"; | |
150 r = snprintf(sockdir, sizeof(sockdir), "%s/chg%d", | |
151 tmpdir, geteuid()); | |
152 if (r < 0 || (size_t)r >= sizeof(sockdir)) | |
153 abortmsg("too long TMPDIR (r = %d)", r); | |
154 preparesockdir(sockdir); | |
155 } | |
156 | |
157 const char *basename = (envsockname) ? envsockname : sockdir; | |
158 const char *sockfmt = (envsockname) ? "%s" : "%s/server"; | |
159 const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock"; | |
160 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename); | |
161 if (r < 0 || (size_t)r >= sizeof(opts->sockname)) | |
162 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
163 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename); | |
164 if (r < 0 || (size_t)r >= sizeof(opts->lockfile)) | |
165 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
166 } | |
167 | |
168 /* | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
169 * 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
|
170 * 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
|
171 * explicit unlock. Will block if the lock is held by another process. |
28060 | 172 */ |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
173 static void lockcmdserver(struct cmdserveropts *opts) |
28060 | 174 { |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
175 if (opts->lockfd == -1) { |
28790 | 176 opts->lockfd = open(opts->lockfile, |
177 O_RDWR | O_CREAT | O_NOFOLLOW, 0600); | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
178 if (opts->lockfd == -1) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
179 abortmsgerrno("cannot create lock file %s", |
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
180 opts->lockfile); |
28856
0d530299acf2
chg: use fsetcloexec instead of closing lockfd manually
Jun Wu <quark@fb.com>
parents:
28853
diff
changeset
|
181 fsetcloexec(opts->lockfd); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
182 } |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
183 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
|
184 if (r == -1) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
185 abortmsgerrno("cannot acquire lock"); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
186 } |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
187 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
188 /* |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
189 * 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
|
190 * lockcmdserver is not called. |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
191 */ |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
192 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
|
193 { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
194 if (opts->lockfd == -1) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
195 return; |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
196 flock(opts->lockfd, LOCK_UN); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
197 close(opts->lockfd); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
198 opts->lockfd = -1; |
28060 | 199 } |
200 | |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
201 static const char *gethgcmd(void) |
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 static const char *hgcmd = NULL; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
204 if (!hgcmd) { |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
205 hgcmd = getenv("CHGHG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
206 if (!hgcmd || hgcmd[0] == '\0') |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
207 hgcmd = getenv("HG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
208 if (!hgcmd || hgcmd[0] == '\0') |
28605
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
209 #ifdef HGPATH |
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
210 hgcmd = (HGPATH); |
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
211 #else |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
212 hgcmd = "hg"; |
28605
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
213 #endif |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
214 } |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
215 return hgcmd; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
216 } |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
217 |
28060 | 218 static void execcmdserver(const struct cmdserveropts *opts) |
219 { | |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
220 const char *hgcmd = gethgcmd(); |
28060 | 221 |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
222 const char *baseargv[] = { |
28060 | 223 hgcmd, |
224 "serve", | |
225 "--cmdserver", "chgunix", | |
226 "--address", opts->sockname, | |
28453
8a7110e351ec
chg: use --daemon-postexec chdir:/ instead of --cwd /
Jun Wu <quark@fb.com>
parents:
28358
diff
changeset
|
227 "--daemon-postexec", "chdir:/", |
28060 | 228 "--config", "extensions.chgserver=", |
229 }; | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
230 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
|
231 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
|
232 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
233 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
|
234 memcpy(argv, baseargv, sizeof(baseargv)); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
235 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
|
236 argv[argsize - 1] = NULL; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
237 |
28261 | 238 if (putenv("CHGINTERNALMARK=") != 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
239 abortmsgerrno("failed to putenv"); |
28060 | 240 if (execvp(hgcmd, (char **)argv) < 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
241 abortmsgerrno("failed to exec cmdserver"); |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
242 free(argv); |
28060 | 243 } |
244 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
245 /* 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
|
246 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid) |
28060 | 247 { |
248 static const struct timespec sleepreq = {0, 10 * 1000000}; | |
249 int pst = 0; | |
250 | |
28769
222f482930c8
chg: make connect debug message less repetitive
Jun Wu <quark@fb.com>
parents:
28605
diff
changeset
|
251 debugmsg("try connect to %s repeatedly", opts->sockname); |
28060 | 252 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
|
253 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
|
254 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
255 return hgc; |
28060 | 256 |
257 if (pid > 0) { | |
258 /* 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
|
259 int r = waitpid(pid, &pst, WNOHANG); |
28060 | 260 if (r != 0) |
261 goto cleanup; | |
262 } | |
263 | |
264 nanosleep(&sleepreq, NULL); | |
265 } | |
266 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
267 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
|
268 return NULL; |
28060 | 269 |
270 cleanup: | |
271 if (WIFEXITED(pst)) { | |
28863
6e06fbee9244
chg: server exited with code 0 without being connectable is an error
Jun Wu <quark@fb.com>
parents:
28856
diff
changeset
|
272 if (WEXITSTATUS(pst) == 0) |
6e06fbee9244
chg: server exited with code 0 without being connectable is an error
Jun Wu <quark@fb.com>
parents:
28856
diff
changeset
|
273 abortmsg("could not connect to cmdserver " |
6e06fbee9244
chg: server exited with code 0 without being connectable is an error
Jun Wu <quark@fb.com>
parents:
28856
diff
changeset
|
274 "(exited with status 0)"); |
28477
194a6cd873cd
chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents:
28455
diff
changeset
|
275 debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst)); |
194a6cd873cd
chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents:
28455
diff
changeset
|
276 exit(WEXITSTATUS(pst)); |
28060 | 277 } else if (WIFSIGNALED(pst)) { |
278 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst)); | |
279 } else { | |
28851
584e0716c7af
chg: fix spelling in the error message about error waiting for cmdserver
Jun Wu <quark@fb.com>
parents:
28790
diff
changeset
|
280 abortmsg("error while waiting for cmdserver"); |
28060 | 281 } |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
282 return NULL; |
28060 | 283 } |
284 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
285 /* 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
|
286 static hgclient_t *connectcmdserver(struct cmdserveropts *opts) |
28060 | 287 { |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
288 const char *sockname = opts->redirectsockname[0] ? |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
289 opts->redirectsockname : opts->sockname; |
28769
222f482930c8
chg: make connect debug message less repetitive
Jun Wu <quark@fb.com>
parents:
28605
diff
changeset
|
290 debugmsg("try connect to %s", sockname); |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
291 hgclient_t *hgc = hgc_open(sockname); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
292 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
293 return hgc; |
28060 | 294 |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
295 lockcmdserver(opts); |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
296 hgc = hgc_open(sockname); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
297 if (hgc) { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
298 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
299 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
|
300 return hgc; |
28060 | 301 } |
302 | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
303 /* prevent us from being connected to an outdated server: we were |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
304 * told by a server to redirect to opts->redirectsockname and that |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
305 * address does not work. we do not want to connect to the server |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
306 * again because it will probably tell us the same thing. */ |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
307 if (sockname == opts->redirectsockname) |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
308 unlink(opts->sockname); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
309 |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
310 debugmsg("start cmdserver at %s", opts->sockname); |
28060 | 311 |
312 pid_t pid = fork(); | |
313 if (pid < 0) | |
314 abortmsg("failed to fork cmdserver process"); | |
315 if (pid == 0) { | |
316 execcmdserver(opts); | |
317 } else { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
318 hgc = retryconnectcmdserver(opts, pid); |
28060 | 319 } |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
320 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
321 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
322 return hgc; |
28060 | 323 } |
324 | |
28455 | 325 static void killcmdserver(const struct cmdserveropts *opts) |
28060 | 326 { |
28455 | 327 /* resolve config hash */ |
328 char *resolvedpath = realpath(opts->sockname, NULL); | |
329 if (resolvedpath) { | |
330 unlink(resolvedpath); | |
331 free(resolvedpath); | |
28060 | 332 } |
333 } | |
334 | |
335 static pid_t peerpid = 0; | |
336 | |
337 static void forwardsignal(int sig) | |
338 { | |
339 assert(peerpid > 0); | |
340 if (kill(peerpid, sig) < 0) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
341 abortmsgerrno("cannot kill %d", peerpid); |
28060 | 342 debugmsg("forward signal %d", sig); |
343 } | |
344 | |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
345 static void handlestopsignal(int sig) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
346 { |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
347 sigset_t unblockset, oldset; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
348 struct sigaction sa, oldsa; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
349 if (sigemptyset(&unblockset) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
350 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
351 if (sigaddset(&unblockset, sig) < 0) |
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 memset(&sa, 0, sizeof(sa)); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
354 sa.sa_handler = SIG_DFL; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
355 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
356 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
|
357 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
358 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
359 forwardsignal(sig); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
360 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
|
361 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
362 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
|
363 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
364 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
|
365 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
366 /* 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
|
367 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
|
368 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
369 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
|
370 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
371 return; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
372 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
373 error: |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
374 abortmsgerrno("failed to handle stop signal"); |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
375 } |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
376 |
28060 | 377 static void setupsignalhandler(pid_t pid) |
378 { | |
379 if (pid <= 0) | |
380 return; | |
381 peerpid = pid; | |
382 | |
383 struct sigaction sa; | |
384 memset(&sa, 0, sizeof(sa)); | |
385 sa.sa_handler = forwardsignal; | |
386 sa.sa_flags = SA_RESTART; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
387 if (sigemptyset(&sa.sa_mask) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
388 goto error; |
28060 | 389 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
390 if (sigaction(SIGHUP, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
391 goto error; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
392 if (sigaction(SIGINT, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
393 goto error; |
28060 | 394 |
395 /* terminate frontend by double SIGTERM in case of server freeze */ | |
396 sa.sa_flags |= SA_RESETHAND; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
397 if (sigaction(SIGTERM, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
398 goto error; |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
399 |
28980 | 400 /* notify the worker about window resize events */ |
401 sa.sa_flags = SA_RESTART; | |
402 if (sigaction(SIGWINCH, &sa, NULL) < 0) | |
403 goto error; | |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
404 /* 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
|
405 sa.sa_handler = forwardsignal; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
406 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
407 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
|
408 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
409 sa.sa_handler = handlestopsignal; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
410 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
411 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
|
412 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
413 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
414 return; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
415 |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
416 error: |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
417 abortmsgerrno("failed to set up signal handlers"); |
28060 | 418 } |
419 | |
420 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */ | |
421 static void setuppager(hgclient_t *hgc, const char *const args[], | |
422 size_t argsize) | |
423 { | |
424 const char *pagercmd = hgc_getpager(hgc, args, argsize); | |
425 if (!pagercmd) | |
426 return; | |
427 | |
428 int pipefds[2]; | |
429 if (pipe(pipefds) < 0) | |
430 return; | |
431 pid_t pid = fork(); | |
432 if (pid < 0) | |
433 goto error; | |
434 if (pid == 0) { | |
435 close(pipefds[0]); | |
436 if (dup2(pipefds[1], fileno(stdout)) < 0) | |
437 goto error; | |
438 if (isatty(fileno(stderr))) { | |
439 if (dup2(pipefds[1], fileno(stderr)) < 0) | |
440 goto error; | |
441 } | |
442 close(pipefds[1]); | |
443 hgc_attachio(hgc); /* reattach to pager */ | |
444 return; | |
445 } else { | |
446 dup2(pipefds[0], fileno(stdin)); | |
447 close(pipefds[0]); | |
448 close(pipefds[1]); | |
449 | |
450 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL); | |
451 if (r < 0) { | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
452 abortmsgerrno("cannot start pager '%s'", pagercmd); |
28060 | 453 } |
454 return; | |
455 } | |
456 | |
457 error: | |
458 close(pipefds[0]); | |
459 close(pipefds[1]); | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
460 abortmsgerrno("failed to prepare pager"); |
28060 | 461 } |
462 | |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
463 /* Run instructions sent from the server like unlink and set redirect path |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
464 * Return 1 if reconnect is needed, otherwise 0 */ |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
465 static int runinstructions(struct cmdserveropts *opts, const char **insts) |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
466 { |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
467 int needreconnect = 0; |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
468 if (!insts) |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
469 return needreconnect; |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
470 |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
471 assert(insts); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
472 opts->redirectsockname[0] = '\0'; |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
473 const char **pinst; |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
474 for (pinst = insts; *pinst; pinst++) { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
475 debugmsg("instruction: %s", *pinst); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
476 if (strncmp(*pinst, "unlink ", 7) == 0) { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
477 unlink(*pinst + 7); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
478 } else if (strncmp(*pinst, "redirect ", 9) == 0) { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
479 int r = snprintf(opts->redirectsockname, |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
480 sizeof(opts->redirectsockname), |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
481 "%s", *pinst + 9); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
482 if (r < 0 || r >= (int)sizeof(opts->redirectsockname)) |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
483 abortmsg("redirect path is too long (%d)", r); |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
484 needreconnect = 1; |
28516
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
485 } else if (strncmp(*pinst, "exit ", 5) == 0) { |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
486 int n = 0; |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
487 if (sscanf(*pinst + 5, "%d", &n) != 1) |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
488 abortmsg("cannot read the exit code"); |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
489 exit(n); |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
490 } else if (strcmp(*pinst, "reconnect") == 0) { |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
491 needreconnect = 1; |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
492 } else { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
493 abortmsg("unknown instruction: %s", *pinst); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
494 } |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
495 } |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
496 return needreconnect; |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
497 } |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
498 |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
499 /* |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
500 * 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
|
501 * 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
|
502 * 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
|
503 */ |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
504 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
|
505 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
506 enum { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
507 SERVE = 1, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
508 DAEMON = 2, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
509 SERVEDAEMON = SERVE | DAEMON, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
510 TIME = 4, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
511 }; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
512 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
|
513 int i; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
514 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
|
515 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
|
516 break; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
517 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
|
518 state |= SERVE; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
519 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
|
520 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
|
521 state |= DAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
522 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
|
523 state |= TIME; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
524 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
525 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
|
526 (state & SERVEDAEMON) == SERVEDAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
527 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
528 |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
529 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
|
530 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
531 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
|
532 if (execvp(gethgcmd(), (char **)argv) < 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
533 abortmsgerrno("failed to exec original hg"); |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
534 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
535 |
28060 | 536 int main(int argc, const char *argv[], const char *envp[]) |
537 { | |
538 if (getenv("CHGDEBUG")) | |
539 enabledebugmsg(); | |
540 | |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
541 if (!getenv("HGPLAIN") && isatty(fileno(stderr))) |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
542 enablecolor(); |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
543 |
28261 | 544 if (getenv("CHGINTERNALMARK")) |
545 abortmsg("chg started by chg detected.\n" | |
546 "Please make sure ${HG:-hg} is not a symlink or " | |
547 "wrapper to chg. Alternatively, set $CHGHG to the " | |
548 "path of real hg."); | |
549 | |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
550 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
|
551 execoriginalhg(argv); |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
552 |
28060 | 553 struct cmdserveropts opts; |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
554 initcmdserveropts(&opts); |
28060 | 555 setcmdserveropts(&opts); |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
556 setcmdserverargs(&opts, argc, argv); |
28060 | 557 |
558 if (argc == 2) { | |
28455 | 559 if (strcmp(argv[1], "--kill-chg-daemon") == 0) { |
560 killcmdserver(&opts); | |
28060 | 561 return 0; |
562 } | |
563 } | |
564 | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
565 hgclient_t *hgc; |
28358 | 566 size_t retry = 0; |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
567 while (1) { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
568 hgc = connectcmdserver(&opts); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
569 if (!hgc) |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
570 abortmsg("cannot open hg client"); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
571 hgc_setenv(hgc, envp); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
572 const char **insts = hgc_validate(hgc, argv + 1, argc - 1); |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
573 int needreconnect = runinstructions(&opts, insts); |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
574 free(insts); |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
575 if (!needreconnect) |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
576 break; |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
577 hgc_close(hgc); |
28358 | 578 if (++retry > 10) |
579 abortmsg("too many redirections.\n" | |
580 "Please make sure %s is not a wrapper which " | |
581 "changes sensitive environment variables " | |
582 "before executing hg. If you have to use a " | |
583 "wrapper, wrap chg instead of hg.", | |
584 gethgcmd()); | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
585 } |
28060 | 586 |
587 setupsignalhandler(hgc_peerpid(hgc)); | |
588 setuppager(hgc, argv + 1, argc - 1); | |
589 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); | |
590 hgc_close(hgc); | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
591 freecmdserveropts(&opts); |
28060 | 592 return exitcode; |
593 } |