123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- #include "procmon.h"
- #include "util.h"
- #ifdef HAVE_SIGNAL_H
- #include <signal.h>
- #endif
- #ifdef HAVE_ERRNO_H
- #include <errno.h>
- #endif
- #ifdef _WIN32
- #include <windows.h>
- #endif
- #if (0 == SIZEOF_PID_T) && defined(_WIN32)
- typedef int pid_t;
- #define PID_T_FORMAT "%d"
- #elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT)
- #define PID_T_FORMAT "%d"
- #elif (SIZEOF_PID_T == SIZEOF_LONG)
- #define PID_T_FORMAT "%ld"
- #elif (SIZEOF_PID_T == SIZEOF_INT64_T)
- #define PID_T_FORMAT I64_FORMAT
- #else
- #error Unknown: SIZEOF_PID_T
- #endif
- #define PROCMON_POLLS 1
- #ifdef PROCMON_POLLS
- static void tor_process_monitor_poll_cb(periodic_timer_t *ev,
- void *procmon_);
- #endif
- struct parsed_process_specifier_t {
- pid_t pid;
- };
- static int
- parse_process_specifier(const char *process_spec,
- struct parsed_process_specifier_t *ppspec,
- const char **msg)
- {
- long pid_l;
- int pid_ok = 0;
- char *pspec_next;
-
- pid_l = tor_parse_long(process_spec, 10, 1, LONG_MAX, &pid_ok, &pspec_next);
-
- if ((*pspec_next != 0) && (*pspec_next != ' ') && (*pspec_next != ':')) {
- pid_ok = 0;
- }
- ppspec->pid = (pid_t)(pid_l);
- if (!pid_ok || (pid_l != (long)(ppspec->pid))) {
- *msg = "invalid PID";
- goto err;
- }
- return 0;
- err:
- return -1;
- }
- struct tor_process_monitor_t {
-
- log_domain_mask_t log_domain;
-
- pid_t pid;
- #ifdef _WIN32
-
- int poll_hproc;
-
- HANDLE hproc;
-
- #endif
-
-
-
- periodic_timer_t *e;
-
- tor_procmon_callback_t cb;
- void *cb_arg;
- };
- int
- tor_validate_process_specifier(const char *process_spec,
- const char **msg)
- {
- struct parsed_process_specifier_t ppspec;
- tor_assert(msg != NULL);
- *msg = NULL;
- return parse_process_specifier(process_spec, &ppspec, msg);
- }
- static const struct timeval poll_interval_tv = {15, 0};
- tor_process_monitor_t *
- tor_process_monitor_new(struct event_base *base,
- const char *process_spec,
- log_domain_mask_t log_domain,
- tor_procmon_callback_t cb, void *cb_arg,
- const char **msg)
- {
- tor_process_monitor_t *procmon = tor_malloc_zero(
- sizeof(tor_process_monitor_t));
- struct parsed_process_specifier_t ppspec;
- tor_assert(msg != NULL);
- *msg = NULL;
- if (procmon == NULL) {
- *msg = "out of memory";
- goto err;
- }
- procmon->log_domain = log_domain;
- if (parse_process_specifier(process_spec, &ppspec, msg))
- goto err;
- procmon->pid = ppspec.pid;
- #ifdef _WIN32
- procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
- FALSE,
- procmon->pid);
- if (procmon->hproc != NULL) {
- procmon->poll_hproc = 1;
- log_info(procmon->log_domain, "Successfully opened handle to process "
- PID_T_FORMAT"; "
- "monitoring it.",
- procmon->pid);
- } else {
-
- log_info(procmon->log_domain, "Failed to open handle to process "
- PID_T_FORMAT"; will "
- "try again later.",
- procmon->pid);
- }
- #endif
- procmon->cb = cb;
- procmon->cb_arg = cb_arg;
- #ifdef PROCMON_POLLS
- procmon->e = periodic_timer_new(base,
- &poll_interval_tv,
- tor_process_monitor_poll_cb, procmon);
- #else
- #error OOPS?
- #endif
- return procmon;
- err:
- tor_process_monitor_free(procmon);
- return NULL;
- }
- #ifdef PROCMON_POLLS
- static void
- tor_process_monitor_poll_cb(periodic_timer_t *event, void *procmon_)
- {
- (void)event;
- tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
- int its_dead_jim;
- tor_assert(procmon != NULL);
- #ifdef _WIN32
- if (procmon->poll_hproc) {
- DWORD exit_code;
- if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
- char *errmsg = format_win32_error(GetLastError());
- log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
- "handle for monitored process "PID_T_FORMAT"; assuming "
- "it's dead.",
- errmsg, procmon->pid);
- tor_free(errmsg);
- its_dead_jim = 1;
- } else {
- its_dead_jim = (exit_code != STILL_ACTIVE);
- }
- } else {
-
- procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
- FALSE,
- procmon->pid);
- if (procmon->hproc != NULL) {
- log_info(procmon->log_domain, "Successfully opened handle to monitored "
- "process "PID_T_FORMAT".",
- procmon->pid);
- its_dead_jim = 0;
- procmon->poll_hproc = 1;
- } else {
- DWORD err_code = GetLastError();
- char *errmsg = format_win32_error(err_code);
-
- its_dead_jim = (err_code == ERROR_INVALID_PARAMETER);
- if (!its_dead_jim)
- log_info(procmon->log_domain, "Failed to open handle to monitored "
- "process "PID_T_FORMAT", and error code %lu (%s) is not "
- "'invalid parameter' -- assuming the process is still alive.",
- procmon->pid,
- err_code, errmsg);
- tor_free(errmsg);
- }
- }
- #else
-
- its_dead_jim = kill(procmon->pid, 0);
- its_dead_jim = its_dead_jim && (errno == ESRCH);
- #endif
- tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
- procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.",
- procmon->pid,
- its_dead_jim ? "dead" : "still alive");
- if (its_dead_jim) {
- procmon->cb(procmon->cb_arg);
- }
- }
- #endif
- void
- tor_process_monitor_free_(tor_process_monitor_t *procmon)
- {
- if (procmon == NULL)
- return;
- #ifdef _WIN32
- if (procmon->hproc != NULL)
- CloseHandle(procmon->hproc);
- #endif
- if (procmon->e != NULL)
- periodic_timer_free(procmon->e);
- tor_free(procmon);
- }
|