12 #include <sys/socket.h>
14 #include <sys/types.h>
17 #include <stdarg.h> /* for microhttpd.h (bug in there) */
18 #include <stdint.h> /* for microhttpd.h (bug in there) */
22 #include "state_defs.h"
24 static int auto_db_port
;
25 static char auto_arg_port
[10];
27 static char *auto_arg_mongod
[] = {
29 "--port", auto_arg_port
,
30 "--dbpath", AUTO_DIR_DB
,
31 /* "--fork", */ /* chdirs god knows where, we cannot use this. */
32 /* "--logpath", AUTO_MONGOD_LOG, */ /* required by --fork */
34 "--pidfilepath", "mongo.pid",
38 /* The --quiet option in mongod is useless, so redirect instead. */
39 static char *auto_arg_mongod_quiet
[] = {
41 "--port", auto_arg_port
,
42 "--dbpath", AUTO_DIR_DB
,
43 "--logpath", AUTO_MONGOD_LOG
,
44 "--pidfilepath", "mongo.pid",
48 static int auto_pid_mongod
;
51 auto_mkdir (const char *name
)
55 if (mkdir(name
, 0777) < 0) {
56 if (errno
== EEXIST
) {
57 if (stat(name
, &statb
) < 0) {
58 error (0, errno
, "stat %s failed", name
);
61 if (!S_ISDIR(statb
.st_mode
)) {
62 error (0, 0, "path %s is not a directory",name
);
67 error(0, errno
, "Cannot create %s", name
);
74 auto_prepare_area (void)
77 if (auto_mkdir(AUTO_DIR_FS
) < 0) {
80 if (auto_mkdir(AUTO_DIR_DB
) < 0) {
87 auto_kill_mongod (int sig
)
89 if (auto_pid_mongod
) {
90 kill(auto_pid_mongod
, sig
);
95 auto_spawn (const char *prog
, char *argv
[])
101 * The stat check is purely so that common errors, such as ENOENT
102 * if the program is not available, were printed before the fork.
103 * This serves no security purpose but only makes stderr more tidy.
105 if (stat(prog
, &statb
) < 0) {
106 error (0, errno
, "stat %s failed", prog
);
109 if (!S_ISREG(statb
.st_mode
)) {
110 error (0, 0, "path %s is not a regular file", prog
);
116 error (0, errno
, "fork failed");
122 error (EXIT_FAILURE
, errno
, "failed to run command %s", prog
);
126 * This is where you'd normally run waitpid for your daemon, so that
127 * argument check failures were caught at least. In case of mongod,
128 * daemonizing it is a whole can of worms, so we do not. On the
129 * upside, it stays on our session (and process group) and dies
130 * cleanly on keyboard interrupt.
137 auto_test_mongod(void)
140 struct sockaddr_in a4
;
147 * We hardcode IPv4 because Mongo often listens on IPv4 only.
149 memset(&addr
, 0, sizeof(addr
));
150 addr
.a4
.sin_family
= AF_INET
;
151 addr
.a4
.sin_port
= htons(auto_db_port
);
152 addr
.a4
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
154 DPRINTF("trying to connect to mongod (host 127.0.0.1 port %u) ...\n",
157 sfd
= socket(addr
.a
.sa_family
, SOCK_STREAM
, 0);
159 error(0, errno
, "socket");
163 rc
= connect(sfd
, &addr
.a
, sizeof(addr
.a4
));
165 DPRINTF("connect: %s\n", strerror(errno
));
175 auto_wait_mongod(void)
181 start_time
= time(NULL
);
183 rc
= auto_test_mongod();
186 if (time(NULL
) >= start_time
+ 20) {
187 error(0, 0, "failed to verify mongod using port %s",
194 nanosleep(&ts
, NULL
);
196 DPRINTF("mongod went up after %ld s\n", (long)time(NULL
) - start_time
);
202 auto_action (int sig
, siginfo_t
*info
, void *uctx
)
207 if (sig
== SIGSEGV
|| sig
== SIGILL
|| sig
== SIGFPE
|| sig
== SIGBUS
) {
208 auto_kill_mongod(SIGTERM
);
211 auto_kill_mongod(info
->si_signo
);
218 struct sigaction actb
;
220 memset(&actb
, 0, sizeof(struct sigaction
));
221 actb
.sa_flags
|= SA_SIGINFO
;
222 actb
.sa_sigaction
= auto_action
;
224 /* Not trapping SIGINT or SIGHUP since mongo is in our session. */
225 if (sigaction(SIGTERM
, &actb
, NULL
) ||
226 sigaction(SIGSEGV
, &actb
, NULL
) ||
227 sigaction(SIGILL
, &actb
, NULL
) ||
228 sigaction(SIGFPE
, &actb
, NULL
) ||
229 sigaction(SIGBUS
, &actb
, NULL
) ||
230 sigaction(SIGABRT
, &actb
, NULL
)) {
231 error(0, errno
, "sigaction");
240 auto_kill_mongod(SIGTERM
);
244 auto_start (int dbport
)
250 auto_db_port
= dbport
;
251 snprintf(auto_arg_port
, sizeof(auto_arg_port
), "%u", dbport
);
253 if (auto_prepare_area() < 0)
256 rc
= auto_test_mongod();
261 * This is a trick. The auto_test_mongod() merely connects to a TCP
262 * port, and does not execute a NO-OP in Mongo. Therefore, it succeeds
263 * if a foreign application is listening on our private port.
264 * We abort because we do not want anyone listening there.
267 error (0, 0, "something is listening on port %s,"
268 " not auto-starting Mongo", auto_arg_port
);
272 DPRINTF("auto-starting mongod\n");
273 earg
= verbose
? auto_arg_mongod
: auto_arg_mongod_quiet
;
274 pid
= auto_spawn(AUTO_BIN_MONGOD
, earg
);
277 auto_pid_mongod
= pid
;
278 if (auto_wait_mongod() < 0) {
279 auto_kill_mongod(SIGTERM
);
283 if (auto_set_sig() < 0) {
284 auto_kill_mongod(SIGTERM
);
287 if (atexit(auto_stop
) != 0) {
288 error (0, 0, "atexit failed for auto_stop");
289 auto_kill_mongod(SIGTERM
);
293 DPRINTF("mongod listens on port %u\n", dbport
);