Reformat changelog a little to follow arma rules on spacing
[tor.git] / src / common / procmon.c
blob0a49689e3af73c791b593e2dc8ccb5ff9987a167
1 /* Copyright (c) 2011-2013, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file procmon.c
6 * \brief Process-termination monitor functions
7 **/
9 #include "procmon.h"
11 #include "util.h"
13 #ifdef HAVE_EVENT2_EVENT_H
14 #include <event2/event.h>
15 #else
16 #include <event.h>
17 #endif
19 #ifdef HAVE_SIGNAL_H
20 #include <signal.h>
21 #endif
22 #ifdef HAVE_ERRNO_H
23 #include <errno.h>
24 #endif
26 #ifdef _WIN32
27 #include <windows.h>
28 #endif
30 #if (0 == SIZEOF_PID_T) && defined(_WIN32)
31 /* Windows does not define pid_t sometimes, but _getpid() returns an int.
32 * Everybody else needs to have a pid_t. */
33 typedef int pid_t;
34 #define PID_T_FORMAT "%d"
35 #elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT)
36 #define PID_T_FORMAT "%d"
37 #elif (SIZEOF_PID_T == SIZEOF_LONG)
38 #define PID_T_FORMAT "%ld"
39 #elif (SIZEOF_PID_T == SIZEOF_INT64_T)
40 #define PID_T_FORMAT I64_FORMAT
41 #else
42 #error Unknown: SIZEOF_PID_T
43 #endif
45 /* Define to 1 if process-termination monitors on this OS and Libevent
46 version must poll for process termination themselves. */
47 #define PROCMON_POLLS 1
48 /* Currently we need to poll in some way on all systems. */
50 #ifdef PROCMON_POLLS
51 static void tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
52 void *procmon_);
53 #endif
55 /* This struct may contain pointers into the original process
56 * specifier string, but it should *never* contain anything which
57 * needs to be freed. */
58 /* DOCDOC parsed_process_specifier_t */
59 struct parsed_process_specifier_t {
60 pid_t pid;
63 /** Parse the process specifier given in <b>process_spec</b> into
64 * *<b>ppspec</b>. Return 0 on success; return -1 and store an error
65 * message into *<b>msg</b> on failure. The caller must not free the
66 * returned error message. */
67 static int
68 parse_process_specifier(const char *process_spec,
69 struct parsed_process_specifier_t *ppspec,
70 const char **msg)
72 long pid_l;
73 int pid_ok = 0;
74 char *pspec_next;
76 /* If we're lucky, long will turn out to be large enough to hold a
77 * PID everywhere that Tor runs. */
78 pid_l = tor_parse_long(process_spec, 0, 1, LONG_MAX, &pid_ok, &pspec_next);
80 /* Reserve room in the ‘process specifier’ for additional
81 * (platform-specific) identifying information beyond the PID, to
82 * make our process-existence checks a bit less racy in a future
83 * version. */
84 if ((*pspec_next != 0) && (*pspec_next != ' ') && (*pspec_next != ':')) {
85 pid_ok = 0;
88 ppspec->pid = (pid_t)(pid_l);
89 if (!pid_ok || (pid_l != (long)(ppspec->pid))) {
90 *msg = "invalid PID";
91 goto err;
94 return 0;
95 err:
96 return -1;
99 /* DOCDOC tor_process_monitor_t */
100 struct tor_process_monitor_t {
101 /** Log domain for warning messages. */
102 log_domain_mask_t log_domain;
104 /** All systems: The best we can do in general is poll for the
105 * process's existence by PID periodically, and hope that the kernel
106 * doesn't reassign the same PID to another process between our
107 * polls. */
108 pid_t pid;
110 #ifdef _WIN32
111 /** Windows-only: Should we poll hproc? If false, poll pid
112 * instead. */
113 int poll_hproc;
115 /** Windows-only: Get a handle to the process (if possible) and
116 * periodically check whether the process we have a handle to has
117 * ended. */
118 HANDLE hproc;
119 /* XXX023 We can and should have Libevent watch hproc for us,
120 * if/when some version of Libevent 2.x can be told to do so. */
121 #endif
123 /* XXX023 On Linux, we can and should receive the 22nd
124 * (space-delimited) field (‘starttime’) of /proc/$PID/stat from the
125 * owning controller and store it, and poll once in a while to see
126 * whether it has changed -- if so, the kernel has *definitely*
127 * reassigned the owning controller's PID and we should exit. On
128 * FreeBSD, we can do the same trick using either the 8th
129 * space-delimited field of /proc/$PID/status on the seven FBSD
130 * systems whose admins have mounted procfs, or the start-time field
131 * of the process-information structure returned by kvmgetprocs() on
132 * any system. The latter is ickier. */
133 /* XXX023 On FreeBSD (and possibly other kqueue systems), we can and
134 * should arrange to receive EVFILT_PROC NOTE_EXIT notifications for
135 * pid, so we don't have to do such a heavyweight poll operation in
136 * order to avoid the PID-reassignment race condition. (We would
137 * still need to poll our own kqueue periodically until some version
138 * of Libevent 2.x learns to receive these events for us.) */
140 /** A Libevent event structure, to either poll for the process's
141 * existence or receive a notification when the process ends. */
142 struct event *e;
144 /** A callback to be called when the process ends. */
145 tor_procmon_callback_t cb;
146 void *cb_arg; /**< A user-specified pointer to be passed to cb. */
149 /** Verify that the process specifier given in <b>process_spec</b> is
150 * syntactically valid. Return 0 on success; return -1 and store an
151 * error message into *<b>msg</b> on failure. The caller must not
152 * free the returned error message. */
154 tor_validate_process_specifier(const char *process_spec,
155 const char **msg)
157 struct parsed_process_specifier_t ppspec;
159 tor_assert(msg != NULL);
160 *msg = NULL;
162 return parse_process_specifier(process_spec, &ppspec, msg);
165 #ifdef HAVE_EVENT2_EVENT_H
166 #define PERIODIC_TIMER_FLAGS EV_PERSIST
167 #else
168 #define PERIODIC_TIMER_FLAGS (0)
169 #endif
171 /* DOCDOC poll_interval_tv */
172 static struct timeval poll_interval_tv = {15, 0};
173 /* Note: If you port this file to plain Libevent 2, you can make
174 * poll_interval_tv const. It has to be non-const here because in
175 * libevent 1.x, event_add expects a pointer to a non-const struct
176 * timeval. */
178 /** Create a process-termination monitor for the process specifier
179 * given in <b>process_spec</b>. Return a newly allocated
180 * tor_process_monitor_t on success; return NULL and store an error
181 * message into *<b>msg</b> on failure. The caller must not free
182 * the returned error message.
184 * When the monitored process terminates, call
185 * <b>cb</b>(<b>cb_arg</b>).
187 tor_process_monitor_t *
188 tor_process_monitor_new(struct event_base *base,
189 const char *process_spec,
190 log_domain_mask_t log_domain,
191 tor_procmon_callback_t cb, void *cb_arg,
192 const char **msg)
194 tor_process_monitor_t *procmon = tor_malloc(sizeof(tor_process_monitor_t));
195 struct parsed_process_specifier_t ppspec;
197 tor_assert(msg != NULL);
198 *msg = NULL;
200 if (procmon == NULL) {
201 *msg = "out of memory";
202 goto err;
205 procmon->log_domain = log_domain;
207 if (parse_process_specifier(process_spec, &ppspec, msg))
208 goto err;
210 procmon->pid = ppspec.pid;
212 #ifdef _WIN32
213 procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
214 FALSE,
215 procmon->pid);
217 if (procmon->hproc != NULL) {
218 procmon->poll_hproc = 1;
219 log_info(procmon->log_domain, "Successfully opened handle to process "
220 PID_T_FORMAT"; "
221 "monitoring it.",
222 procmon->pid);
223 } else {
224 /* If we couldn't get a handle to the process, we'll try again the
225 * first time we poll. */
226 log_info(procmon->log_domain, "Failed to open handle to process "
227 PID_T_FORMAT"; will "
228 "try again later.",
229 procmon->pid);
231 #endif
233 procmon->cb = cb;
234 procmon->cb_arg = cb_arg;
236 #ifdef PROCMON_POLLS
237 procmon->e = tor_event_new(base, -1 /* no FD */, PERIODIC_TIMER_FLAGS,
238 tor_process_monitor_poll_cb, procmon);
239 /* Note: If you port this file to plain Libevent 2, check that
240 * procmon->e is non-NULL. We don't need to here because
241 * tor_evtimer_new never returns NULL. */
243 evtimer_add(procmon->e, &poll_interval_tv);
244 #else
245 #error OOPS?
246 #endif
248 return procmon;
249 err:
250 tor_process_monitor_free(procmon);
251 return NULL;
254 #ifdef PROCMON_POLLS
255 /** Libevent callback to poll for the existence of the process
256 * monitored by <b>procmon_</b>. */
257 static void
258 tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
259 void *procmon_)
261 tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
262 int its_dead_jim;
264 (void)unused1; (void)unused2;
266 tor_assert(procmon != NULL);
268 #ifdef _WIN32
269 if (procmon->poll_hproc) {
270 DWORD exit_code;
271 if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
272 char *errmsg = format_win32_error(GetLastError());
273 log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
274 "handle for monitored process "PID_T_FORMAT"; assuming "
275 "it's dead.",
276 errmsg, procmon->pid);
277 tor_free(errmsg);
278 its_dead_jim = 1;
279 } else {
280 its_dead_jim = (exit_code != STILL_ACTIVE);
282 } else {
283 /* All we can do is try to open the process, and look at the error
284 * code if it fails again. */
285 procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
286 FALSE,
287 procmon->pid);
289 if (procmon->hproc != NULL) {
290 log_info(procmon->log_domain, "Successfully opened handle to monitored "
291 "process "PID_T_FORMAT".",
292 procmon->pid);
293 its_dead_jim = 0;
294 procmon->poll_hproc = 1;
295 } else {
296 DWORD err_code = GetLastError();
297 char *errmsg = format_win32_error(err_code);
299 /* When I tested OpenProcess's error codes on Windows 7, I
300 * received error code 5 (ERROR_ACCESS_DENIED) for PIDs of
301 * existing processes that I could not open and error code 87
302 * (ERROR_INVALID_PARAMETER) for PIDs that were not in use.
303 * Since the nonexistent-process error code is sane, I'm going
304 * to assume that all errors other than ERROR_INVALID_PARAMETER
305 * mean that the process we are monitoring is still alive. */
306 its_dead_jim = (err_code == ERROR_INVALID_PARAMETER);
308 if (!its_dead_jim)
309 log_info(procmon->log_domain, "Failed to open handle to monitored "
310 "process "PID_T_FORMAT", and error code %lu (%s) is not "
311 "'invalid parameter' -- assuming the process is still alive.",
312 procmon->pid,
313 err_code, errmsg);
315 tor_free(errmsg);
318 #else
319 /* Unix makes this part easy, if a bit racy. */
320 its_dead_jim = kill(procmon->pid, 0);
321 its_dead_jim = its_dead_jim && (errno == ESRCH);
322 #endif
324 tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
325 procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.",
326 procmon->pid,
327 its_dead_jim ? "dead" : "still alive");
329 if (its_dead_jim) {
330 procmon->cb(procmon->cb_arg);
331 #ifndef HAVE_EVENT2_EVENT_H
332 } else {
333 evtimer_add(procmon->e, &poll_interval_tv);
334 #endif
337 #endif
339 /** Free the process-termination monitor <b>procmon</b>. */
340 void
341 tor_process_monitor_free(tor_process_monitor_t *procmon)
343 if (procmon == NULL)
344 return;
346 #ifdef _WIN32
347 if (procmon->hproc != NULL)
348 CloseHandle(procmon->hproc);
349 #endif
351 if (procmon->e != NULL)
352 tor_event_free(procmon->e);
354 tor_free(procmon);