procmon.c 11 KB

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