Mercurial > hg
annotate contrib/chg/chg.c @ 28789:7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Since we have abortmsgerrno now, use it to show human friendly error messages
across platforms.
author | Jun Wu <quark@fb.com> |
---|---|
date | Tue, 05 Apr 2016 15:16:01 +0100 |
parents | ea86cdcd9b50 |
children | b0cc9652e8dc |
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; |
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) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
117 abortmsgerrno("cannot create sockdir %s", sockdir); |
28060 | 118 |
119 struct stat st; | |
120 r = lstat(sockdir, &st); | |
121 if (r < 0) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
122 abortmsgerrno("cannot stat %s", sockdir); |
28060 | 123 if (!S_ISDIR(st.st_mode)) |
124 abortmsg("cannot create sockdir %s (file exists)", sockdir); | |
125 if (st.st_uid != geteuid() || st.st_mode & 0077) | |
126 abortmsg("insecure sockdir %s", sockdir); | |
127 } | |
128 | |
129 static void setcmdserveropts(struct cmdserveropts *opts) | |
130 { | |
131 int r; | |
132 char sockdir[UNIX_PATH_MAX]; | |
133 const char *envsockname = getenv("CHGSOCKNAME"); | |
134 if (!envsockname) { | |
135 /* by default, put socket file in secure directory | |
136 * (permission of socket file may be ignored on some Unices) */ | |
137 const char *tmpdir = getenv("TMPDIR"); | |
138 if (!tmpdir) | |
139 tmpdir = "/tmp"; | |
140 r = snprintf(sockdir, sizeof(sockdir), "%s/chg%d", | |
141 tmpdir, geteuid()); | |
142 if (r < 0 || (size_t)r >= sizeof(sockdir)) | |
143 abortmsg("too long TMPDIR (r = %d)", r); | |
144 preparesockdir(sockdir); | |
145 } | |
146 | |
147 const char *basename = (envsockname) ? envsockname : sockdir; | |
148 const char *sockfmt = (envsockname) ? "%s" : "%s/server"; | |
149 const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock"; | |
150 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename); | |
151 if (r < 0 || (size_t)r >= sizeof(opts->sockname)) | |
152 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
153 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename); | |
154 if (r < 0 || (size_t)r >= sizeof(opts->lockfile)) | |
155 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); | |
156 } | |
157 | |
158 /* | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
159 * 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
|
160 * 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
|
161 * explicit unlock. Will block if the lock is held by another process. |
28060 | 162 */ |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
163 static void lockcmdserver(struct cmdserveropts *opts) |
28060 | 164 { |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
165 if (opts->lockfd == -1) { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
166 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
|
167 if (opts->lockfd == -1) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
168 abortmsgerrno("cannot create lock file %s", |
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
169 opts->lockfile); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
170 } |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
171 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
|
172 if (r == -1) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
173 abortmsgerrno("cannot acquire lock"); |
28196
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 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
176 /* |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
177 * 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
|
178 * lockcmdserver is not called. |
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 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
|
181 { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
182 if (opts->lockfd == -1) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
183 return; |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
184 flock(opts->lockfd, LOCK_UN); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
185 close(opts->lockfd); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
186 opts->lockfd = -1; |
28060 | 187 } |
188 | |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
189 static const char *gethgcmd(void) |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
190 { |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
191 static const char *hgcmd = NULL; |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
192 if (!hgcmd) { |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
193 hgcmd = getenv("CHGHG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
194 if (!hgcmd || hgcmd[0] == '\0') |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
195 hgcmd = getenv("HG"); |
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
196 if (!hgcmd || hgcmd[0] == '\0') |
28605
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
197 #ifdef HGPATH |
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
198 hgcmd = (HGPATH); |
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
199 #else |
28237
a3d73e069f8d
chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents:
28196
diff
changeset
|
200 hgcmd = "hg"; |
28605
baa073200ba2
chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents:
28555
diff
changeset
|
201 #endif |
28237
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 "--cmdserver", "chgunix", | |
214 "--address", opts->sockname, | |
28453
8a7110e351ec
chg: use --daemon-postexec chdir:/ instead of --cwd /
Jun Wu <quark@fb.com>
parents:
28358
diff
changeset
|
215 "--daemon-postexec", "chdir:/", |
28060 | 216 "--config", "extensions.chgserver=", |
217 }; | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
218 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
|
219 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
|
220 |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
221 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
|
222 memcpy(argv, baseargv, sizeof(baseargv)); |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
223 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
|
224 argv[argsize - 1] = NULL; |
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
225 |
28261 | 226 if (putenv("CHGINTERNALMARK=") != 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
227 abortmsgerrno("failed to putenv"); |
28060 | 228 if (execvp(hgcmd, (char **)argv) < 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
229 abortmsgerrno("failed to exec cmdserver"); |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
230 free(argv); |
28060 | 231 } |
232 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
233 /* 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
|
234 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid) |
28060 | 235 { |
236 static const struct timespec sleepreq = {0, 10 * 1000000}; | |
237 int pst = 0; | |
238 | |
28769
222f482930c8
chg: make connect debug message less repetitive
Jun Wu <quark@fb.com>
parents:
28605
diff
changeset
|
239 debugmsg("try connect to %s repeatedly", opts->sockname); |
28060 | 240 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
|
241 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
|
242 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
243 return hgc; |
28060 | 244 |
245 if (pid > 0) { | |
246 /* 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
|
247 int r = waitpid(pid, &pst, WNOHANG); |
28060 | 248 if (r != 0) |
249 goto cleanup; | |
250 } | |
251 | |
252 nanosleep(&sleepreq, NULL); | |
253 } | |
254 | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
255 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
|
256 return NULL; |
28060 | 257 |
258 cleanup: | |
259 if (WIFEXITED(pst)) { | |
28477
194a6cd873cd
chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents:
28455
diff
changeset
|
260 debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst)); |
194a6cd873cd
chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents:
28455
diff
changeset
|
261 exit(WEXITSTATUS(pst)); |
28060 | 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 { |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
273 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
|
274 opts->redirectsockname : opts->sockname; |
28769
222f482930c8
chg: make connect debug message less repetitive
Jun Wu <quark@fb.com>
parents:
28605
diff
changeset
|
275 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
|
276 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
|
277 if (hgc) |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
278 return hgc; |
28060 | 279 |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
280 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
|
281 hgc = hgc_open(sockname); |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
282 if (hgc) { |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
283 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
284 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
|
285 return hgc; |
28060 | 286 } |
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 /* 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
|
289 * 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
|
290 * 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
|
291 * 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
|
292 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
|
293 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
|
294 |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
295 debugmsg("start cmdserver at %s", opts->sockname); |
28060 | 296 |
297 pid_t pid = fork(); | |
298 if (pid < 0) | |
299 abortmsg("failed to fork cmdserver process"); | |
300 if (pid == 0) { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
301 /* 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
|
302 close(opts->lockfd); |
28060 | 303 execcmdserver(opts); |
304 } else { | |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
305 hgc = retryconnectcmdserver(opts, pid); |
28060 | 306 } |
28196
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
307 |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
308 unlockcmdserver(opts); |
87de4a22e8c2
chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents:
28194
diff
changeset
|
309 return hgc; |
28060 | 310 } |
311 | |
28455 | 312 static void killcmdserver(const struct cmdserveropts *opts) |
28060 | 313 { |
28455 | 314 /* resolve config hash */ |
315 char *resolvedpath = realpath(opts->sockname, NULL); | |
316 if (resolvedpath) { | |
317 unlink(resolvedpath); | |
318 free(resolvedpath); | |
28060 | 319 } |
320 } | |
321 | |
322 static pid_t peerpid = 0; | |
323 | |
324 static void forwardsignal(int sig) | |
325 { | |
326 assert(peerpid > 0); | |
327 if (kill(peerpid, sig) < 0) | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
328 abortmsgerrno("cannot kill %d", peerpid); |
28060 | 329 debugmsg("forward signal %d", sig); |
330 } | |
331 | |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
332 static void handlestopsignal(int sig) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
333 { |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
334 sigset_t unblockset, oldset; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
335 struct sigaction sa, oldsa; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
336 if (sigemptyset(&unblockset) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
337 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
338 if (sigaddset(&unblockset, sig) < 0) |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
339 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
340 memset(&sa, 0, sizeof(sa)); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
341 sa.sa_handler = SIG_DFL; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
342 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
343 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
|
344 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
345 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
346 forwardsignal(sig); |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
347 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
|
348 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
349 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
|
350 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
351 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
|
352 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
353 /* 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
|
354 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
|
355 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
356 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
|
357 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
358 return; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
359 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
360 error: |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
361 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
|
362 } |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
363 |
28060 | 364 static void setupsignalhandler(pid_t pid) |
365 { | |
366 if (pid <= 0) | |
367 return; | |
368 peerpid = pid; | |
369 | |
370 struct sigaction sa; | |
371 memset(&sa, 0, sizeof(sa)); | |
372 sa.sa_handler = forwardsignal; | |
373 sa.sa_flags = SA_RESTART; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
374 if (sigemptyset(&sa.sa_mask) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
375 goto error; |
28060 | 376 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
377 if (sigaction(SIGHUP, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
378 goto error; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
379 if (sigaction(SIGINT, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
380 goto error; |
28060 | 381 |
382 /* terminate frontend by double SIGTERM in case of server freeze */ | |
383 sa.sa_flags |= SA_RESETHAND; | |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
384 if (sigaction(SIGTERM, &sa, NULL) < 0) |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
385 goto error; |
28086
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
386 |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
387 /* 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
|
388 sa.sa_handler = forwardsignal; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
389 sa.sa_flags = SA_RESTART; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
390 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
|
391 goto error; |
65d24ca35496
chg: forward job control signals to worker process (issue5051)
Yuya Nishihara <yuya@tcha.org>
parents:
28085
diff
changeset
|
392 sa.sa_handler = handlestopsignal; |
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(SIGTSTP, &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 |
28085
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
397 return; |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
398 |
c0d1bf1b26b7
chg: verify return value of sigaction() and sigemptyset()
Yuya Nishihara <yuya@tcha.org>
parents:
28084
diff
changeset
|
399 error: |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
400 abortmsgerrno("failed to set up signal handlers"); |
28060 | 401 } |
402 | |
403 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */ | |
404 static void setuppager(hgclient_t *hgc, const char *const args[], | |
405 size_t argsize) | |
406 { | |
407 const char *pagercmd = hgc_getpager(hgc, args, argsize); | |
408 if (!pagercmd) | |
409 return; | |
410 | |
411 int pipefds[2]; | |
412 if (pipe(pipefds) < 0) | |
413 return; | |
414 pid_t pid = fork(); | |
415 if (pid < 0) | |
416 goto error; | |
417 if (pid == 0) { | |
418 close(pipefds[0]); | |
419 if (dup2(pipefds[1], fileno(stdout)) < 0) | |
420 goto error; | |
421 if (isatty(fileno(stderr))) { | |
422 if (dup2(pipefds[1], fileno(stderr)) < 0) | |
423 goto error; | |
424 } | |
425 close(pipefds[1]); | |
426 hgc_attachio(hgc); /* reattach to pager */ | |
427 return; | |
428 } else { | |
429 dup2(pipefds[0], fileno(stdin)); | |
430 close(pipefds[0]); | |
431 close(pipefds[1]); | |
432 | |
433 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL); | |
434 if (r < 0) { | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
435 abortmsgerrno("cannot start pager '%s'", pagercmd); |
28060 | 436 } |
437 return; | |
438 } | |
439 | |
440 error: | |
441 close(pipefds[0]); | |
442 close(pipefds[1]); | |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
443 abortmsgerrno("failed to prepare pager"); |
28060 | 444 } |
445 | |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
446 /* 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
|
447 * 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
|
448 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
|
449 { |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
450 int needreconnect = 0; |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
451 if (!insts) |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
452 return needreconnect; |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
453 |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
454 assert(insts); |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
455 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
|
456 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
|
457 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
|
458 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
|
459 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
|
460 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
|
461 } 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
|
462 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
|
463 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
|
464 "%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
|
465 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
|
466 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
|
467 needreconnect = 1; |
28516
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
468 } else if (strncmp(*pinst, "exit ", 5) == 0) { |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
469 int n = 0; |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
470 if (sscanf(*pinst + 5, "%d", &n) != 1) |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
471 abortmsg("cannot read the exit code"); |
3bf2892f685f
chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents:
28477
diff
changeset
|
472 exit(n); |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
473 } else if (strcmp(*pinst, "reconnect") == 0) { |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
474 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
|
475 } else { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
476 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
|
477 } |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
478 } |
28535
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
479 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
|
480 } |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
481 |
28260
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 * 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
|
484 * 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
|
485 * 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
|
486 */ |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
487 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
|
488 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
489 enum { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
490 SERVE = 1, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
491 DAEMON = 2, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
492 SERVEDAEMON = SERVE | DAEMON, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
493 TIME = 4, |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
494 }; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
495 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
|
496 int i; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
497 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
|
498 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
|
499 break; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
500 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
|
501 state |= SERVE; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
502 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
|
503 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
|
504 state |= DAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
505 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
|
506 state |= TIME; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
507 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
508 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
|
509 (state & SERVEDAEMON) == SERVEDAEMON; |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
510 } |
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 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
|
513 { |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
514 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
|
515 if (execvp(gethgcmd(), (char **)argv) < 0) |
28789
7f6e0a15189b
chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
516 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
|
517 } |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
518 |
28060 | 519 int main(int argc, const char *argv[], const char *envp[]) |
520 { | |
521 if (getenv("CHGDEBUG")) | |
522 enabledebugmsg(); | |
523 | |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
524 if (!getenv("HGPLAIN") && isatty(fileno(stderr))) |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
525 enablecolor(); |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28769
diff
changeset
|
526 |
28261 | 527 if (getenv("CHGINTERNALMARK")) |
528 abortmsg("chg started by chg detected.\n" | |
529 "Please make sure ${HG:-hg} is not a symlink or " | |
530 "wrapper to chg. Alternatively, set $CHGHG to the " | |
531 "path of real hg."); | |
532 | |
28260
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
533 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
|
534 execoriginalhg(argv); |
0a17cfbe5429
chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents:
28237
diff
changeset
|
535 |
28060 | 536 struct cmdserveropts opts; |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
537 initcmdserveropts(&opts); |
28060 | 538 setcmdserveropts(&opts); |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
539 setcmdserverargs(&opts, argc, argv); |
28060 | 540 |
541 if (argc == 2) { | |
28455 | 542 if (strcmp(argv[1], "--kill-chg-daemon") == 0) { |
543 killcmdserver(&opts); | |
28060 | 544 return 0; |
545 } | |
546 } | |
547 | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
548 hgclient_t *hgc; |
28358 | 549 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
|
550 while (1) { |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
551 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
|
552 if (!hgc) |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
553 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
|
554 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
|
555 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
|
556 int needreconnect = runinstructions(&opts, insts); |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
557 free(insts); |
aa082a8125da
chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents:
28516
diff
changeset
|
558 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
|
559 break; |
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
560 hgc_close(hgc); |
28358 | 561 if (++retry > 10) |
562 abortmsg("too many redirections.\n" | |
563 "Please make sure %s is not a wrapper which " | |
564 "changes sensitive environment variables " | |
565 "before executing hg. If you have to use a " | |
566 "wrapper, wrap chg instead of hg.", | |
567 gethgcmd()); | |
28357
2f0f352d4196
chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents:
28327
diff
changeset
|
568 } |
28060 | 569 |
570 setupsignalhandler(hgc_peerpid(hgc)); | |
571 setuppager(hgc, argv + 1, argc - 1); | |
572 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); | |
573 hgc_close(hgc); | |
28167
66f6dad20c19
chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents:
28086
diff
changeset
|
574 freecmdserveropts(&opts); |
28060 | 575 return exitcode; |
576 } |