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