procmon.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /**
  2. * \file procmon.c
  3. * \brief Process-termination monitor functions
  4. **/
  5. #include "procmon.h"
  6. #include "util.h"
  7. #ifdef HAVE_EVENT2_EVENT_H
  8. #include <event2/event.h>
  9. #else
  10. #include <event.h>
  11. #endif
  12. #ifdef HAVE_SIGNAL_H
  13. #include <signal.h>
  14. #endif
  15. #ifdef HAVE_ERRNO_H
  16. #include <errno.h>
  17. #endif
  18. #ifdef MS_WINDOWS
  19. #include <windows.h>
  20. /* Windows does not define pid_t, but _getpid() returns an int. */
  21. typedef int pid_t;
  22. #endif
  23. /* Define to 1 if process-termination monitors on this OS and Libevent
  24. version must poll for process termination themselves. */
  25. #define PROCMON_POLLS 1
  26. /* Currently we need to poll in some way on all systems. */
  27. #ifdef PROCMON_POLLS
  28. static void tor_process_monitor_poll_cb(int unused1, short unused2,
  29. void *procmon_);
  30. #endif
  31. /* This struct may contain pointers into the original process
  32. * specifier string, but it should *never* contain anything which
  33. * needs to be freed. */
  34. struct parsed_process_specifier_t {
  35. pid_t pid;
  36. };
  37. /** Parse the process specifier given in <b>process_spec</b> into
  38. * *<b>ppspec</b>. Return 0 on success; return -1 and store an error
  39. * message into *<b>msg</b> on failure. The caller must not free the
  40. * returned error message. */
  41. static int
  42. parse_process_specifier(const char *process_spec,
  43. struct parsed_process_specifier_t *ppspec,
  44. const char **msg)
  45. {
  46. long pid_l;
  47. int pid_ok = 0;
  48. char *pspec_next;
  49. /* If we're lucky, long will turn out to be large enough to hold a
  50. * PID everywhere that Tor runs. */
  51. pid_l = tor_parse_long(process_spec, 0, 1, LONG_MAX, &pid_ok, &pspec_next);
  52. /* Reserve room in the ‘process specifier’ for additional
  53. * (platform-specific) identifying information beyond the PID, to
  54. * make our process-existence checks a bit less racy in a future
  55. * version. */
  56. if ((*pspec_next != 0) && (*pspec_next != ' ') && (*pspec_next != ':')) {
  57. pid_ok = 0;
  58. }
  59. ppspec->pid = (pid_t)(pid_l);
  60. if (!pid_ok || (pid_l != (long)(ppspec->pid))) {
  61. *msg = "invalid PID";
  62. goto err;
  63. }
  64. return 0;
  65. err:
  66. return -1;
  67. }
  68. struct tor_process_monitor_t {
  69. /** Log domain for warning messages. */
  70. log_domain_mask_t log_domain;
  71. /** All systems: The best we can do in general is poll for the
  72. * process's existence by PID periodically, and hope that the kernel
  73. * doesn't reassign the same PID to another process between our
  74. * polls. */
  75. pid_t pid;
  76. #ifdef MS_WINDOWS
  77. /** Windows-only: Should we poll hproc? If false, poll pid
  78. * instead. */
  79. int poll_hproc;
  80. /** Windows-only: Get a handle to the process (if possible) and
  81. * periodically check whether the process we have a handle to has
  82. * ended. */
  83. HANDLE hproc;
  84. /* XXX023 We can and should have Libevent watch hproc for us,
  85. * if/when some version of Libevent 2.x can be told to do so. */
  86. #endif
  87. /* XXX023 On Linux, we can and should receive the 22nd
  88. * (space-delimited) field (‘starttime’) of /proc/$PID/stat from the
  89. * owning controller and store it, and poll once in a while to see
  90. * whether it has changed -- if so, the kernel has *definitely*
  91. * reassigned the owning controller's PID and we should exit. On
  92. * FreeBSD, we can do the same trick using either the 8th
  93. * space-delimited field of /proc/$PID/status on the seven FBSD
  94. * systems whose admins have mounted procfs, or the start-time field
  95. * of the process-information structure returned by kvmgetprocs() on
  96. * any system. The latter is ickier. */
  97. /* XXX023 On FreeBSD (and possibly other kqueue systems), we can and
  98. * should arrange to receive EVFILT_PROC NOTE_EXIT notifications for
  99. * pid, so we don't have to do such a heavyweight poll operation in
  100. * order to avoid the PID-reassignment race condition. (We would
  101. * still need to poll our own kqueue periodically until some version
  102. * of Libevent 2.x learns to receive these events for us.) */
  103. /** A Libevent event structure, to either poll for the process's
  104. * existence or receive a notification when the process ends. */
  105. struct event *e;
  106. /** A callback to be called when the process ends. */
  107. tor_procmon_callback_t cb;
  108. void *cb_arg; /**< A user-specified pointer to be passed to cb. */
  109. };
  110. /** Verify that the process specifier given in <b>process_spec</b> is
  111. * syntactically valid. Return 0 on success; return -1 and store an
  112. * error message into *<b>msg</b> on failure. The caller must not
  113. * free the returned error message. */
  114. int
  115. tor_validate_process_specifier(const char *process_spec,
  116. const char **msg)
  117. {
  118. struct parsed_process_specifier_t ppspec;
  119. tor_assert(msg != NULL);
  120. *msg = NULL;
  121. return parse_process_specifier(process_spec, &ppspec, msg);
  122. }
  123. #ifdef HAVE_EVENT2_EVENT_H
  124. #define PERIODIC_TIMER_FLAGS EV_PERSIST
  125. #else
  126. #define PERIODIC_TIMER_FLAGS (0)
  127. #endif
  128. static const struct timeval poll_interval_tv = {15, 0};
  129. /** Create a process-termination monitor for the process specifier
  130. * given in <b>process_spec</b>. Return a newly allocated
  131. * tor_process_monitor_t on success; return NULL and store an error
  132. * message into *<b>msg</b> on failure. The caller must not free
  133. * the returned error message.
  134. *
  135. * When the monitored process terminates, call
  136. * <b>cb</b>(<b>cb_arg</b>).
  137. */
  138. tor_process_monitor_t *
  139. tor_process_monitor_new(struct event_base *base,
  140. const char *process_spec,
  141. log_domain_mask_t log_domain,
  142. tor_procmon_callback_t cb, void *cb_arg,
  143. const char **msg)
  144. {
  145. tor_process_monitor_t *procmon = tor_malloc(sizeof(tor_process_monitor_t));
  146. struct parsed_process_specifier_t ppspec;
  147. tor_assert(msg != NULL);
  148. *msg = NULL;
  149. if (procmon == NULL) {
  150. *msg = "out of memory";
  151. goto err;
  152. }
  153. procmon->log_domain = log_domain;
  154. if (parse_process_specifier(process_spec, &ppspec, msg))
  155. goto err;
  156. procmon->pid = ppspec.pid;
  157. #ifdef MS_WINDOWS
  158. procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  159. FALSE,
  160. procmon->pid);
  161. if (procmon->hproc != NULL) {
  162. procmon->poll_hproc = 1;
  163. log_info(procmon->log_domain, "Successfully opened handle to process %d; "
  164. "monitoring it.",
  165. (int)(procmon->pid));
  166. } else {
  167. /* If we couldn't get a handle to the process, we'll try again the
  168. * first time we poll. */
  169. log_info(procmon->log_domain, "Failed to open handle to process %d; will "
  170. "try again later.",
  171. (int)(procmon->pid));
  172. }
  173. #endif
  174. procmon->cb = cb;
  175. procmon->cb_arg = cb_arg;
  176. #ifdef PROCMON_POLLS
  177. procmon->e = tor_event_new(base, -1 /* no FD */, PERIODIC_TIMER_FLAGS,
  178. tor_process_monitor_poll_cb, procmon);
  179. /* Note: If you port this file to plain Libevent 2, check that
  180. * procmon->e is non-NULL. We don't need to here because
  181. * tor_evtimer_new never returns NULL. */
  182. evtimer_add(procmon->e, &poll_interval_tv);
  183. #else
  184. #error OOPS?
  185. #endif
  186. return procmon;
  187. err:
  188. tor_process_monitor_free(procmon);
  189. return NULL;
  190. }
  191. #ifdef PROCMON_POLLS
  192. /** Libevent callback to poll for the existence of the process
  193. * monitored by <b>procmon_</b>. */
  194. static void
  195. tor_process_monitor_poll_cb(int unused1, short unused2, void *procmon_)
  196. {
  197. tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
  198. int its_dead_jim;
  199. (void)unused1; (void)unused2;
  200. tor_assert(procmon != NULL);
  201. #ifdef MS_WINDOWS
  202. if (procmon->poll_hproc) {
  203. DWORD exit_code;
  204. if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
  205. char *errmsg = format_win32_error(GetLastError());
  206. log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
  207. "handle for monitored process %d; assuming it's dead."
  208. errmsg, procmon->pid);
  209. tor_free(errmsg);
  210. its_dead_jim = 1;
  211. } else {
  212. its_dead_jim = (exit_code != STILL_ACTIVE);
  213. }
  214. } else {
  215. /* All we can do is try to open the process, and look at the error
  216. * code if it fails again. */
  217. procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  218. FALSE,
  219. procmon->pid);
  220. if (procmon->hproc != NULL) {
  221. log_info(procmon->log_domain, "Successfully opened handle to monitored "
  222. "process %d.",
  223. procmon->pid);
  224. its_dead_jim = 0;
  225. procmon->poll_hproc = 1;
  226. } else {
  227. DWORD err_code = GetLastError();
  228. char *errmsg = format_win32_error(err_code);
  229. /* When I tested OpenProcess's error codes on Windows 7, I
  230. * received error code 5 (ERROR_ACCESS_DENIED) for PIDs of
  231. * existing processes that I could not open and error code 87
  232. * (ERROR_INVALID_PARAMETER) for PIDs that were not in use.
  233. * Since the nonexistent-process error code is sane, I'm going
  234. * to assume that all errors other than ERROR_INVALID_PARAMETER
  235. * mean that the process we are monitoring is still alive. */
  236. its_dead_jim = (err_code == ERROR_INVALID_PARAMETER);
  237. if (!its_dead_jim)
  238. log_info(procmon->log_domain, "Failed to open handle to monitored "
  239. "process %d, and error code %d (%s) is not 'invalid "
  240. "parameter' -- assuming the process is still alive.",
  241. procmon->pid,
  242. err_code, err_msg);
  243. tor_free(err_msg);
  244. }
  245. }
  246. #else
  247. /* Unix makes this part easy, if a bit racy. */
  248. its_dead_jim = kill(procmon->pid, 0);
  249. its_dead_jim = its_dead_jim && (errno == ESRCH);
  250. #endif
  251. log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
  252. procmon->log_domain, "Monitored process %d is %s.",
  253. (int)procmon->pid,
  254. its_dead_jim ? "dead" : "still alive");
  255. if (its_dead_jim) {
  256. procmon->cb(procmon->cb_arg);
  257. #ifndef HAVE_EVENT2_EVENT_H
  258. } else {
  259. evtimer_add(procmon->e, &poll_interval_tv);
  260. #endif
  261. }
  262. }
  263. #endif
  264. /** Free the process-termination monitor <b>procmon</b>. */
  265. void
  266. tor_process_monitor_free(tor_process_monitor_t *procmon)
  267. {
  268. if (procmon == NULL)
  269. return;
  270. #ifdef MS_WINDOWS
  271. if (procmon->hproc != NULL)
  272. CloseHandle(procmon->hproc);
  273. #endif
  274. if (procmon->e != NULL)
  275. tor_event_free(procmon->e);
  276. tor_free(procmon);
  277. }