static void mon_child_cb(struct ev_loop* loop, ev_child* w, int revents V_UNUSED) { dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_CHILD); ev_child_stop(loop, w); // always single-shot mon_t* this_mon = w->data; ev_timer_stop(loop, this_mon->cmd_timeout); this_mon->cmd_pid = 0; bool failed = true; int status = w->rstatus; if(WIFEXITED(status)) { if(!WEXITSTATUS(status)) failed = false; } else { if(WIFSIGNALED(status)) dmn_log_warn("Monitor child process for '%s' terminated by signal %u", this_mon->cmd->desc, WTERMSIG(status)); else dmn_log_warn("Monitor child process for '%s' terminated abnormally...", this_mon->cmd->desc); } // If timeout already sent a failure, don't double-send // here when we reap the SIGKILL'd child if(this_mon->result_pending) { if(!killed_by) { sendq_enq(emc_encode_mon(this_mon->cmd->idx, failed)); ev_io_start(loop, plugin_write_watcher); } if (num_proc > 0) { num_proc--; } this_mon->result_pending = false; } }
static void mon_timeout_cb(struct ev_loop* loop, ev_timer* w, int revents V_UNUSED) { dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_TIMER); mon_t* this_mon = w->data; dmn_assert(this_mon->result_pending); dmn_log_warn("Monitor child process for '%s' timed out after %u seconds. Marking failed and sending SIGKILL...", this_mon->cmd->desc, this_mon->cmd->timeout); kill(this_mon->cmd_pid, SIGKILL); // note we don't stop the child_watcher because we still // wait to reap the status below. I suppose technically // if SIGKILL doesn't work (e.g. stupid blocking NFS thing // in child proc), eventually we'll hit a new interval // and restart the child watcher for a new child, effectively // giving up on waitpid() of this child. Not much else we // could do in that case anyways. sendq_enq(emc_encode_mon(this_mon->cmd->idx, true)); ev_io_start(loop, plugin_write_watcher); this_mon->result_pending = false; }
static geoip2_t* geoip2_new(const char* pathname, const char* map_name, dclists_t* dclists, const dcmap_t* dcmap, const bool city_auto_mode, const bool city_no_region) { dmn_assert(pathname); dmn_assert(map_name); dmn_assert(dclists); geoip2_t* db = xcalloc(1, sizeof(*db)); int status = MMDB_open(pathname, MMDB_MODE_MMAP, &db->mmdb); if(status != MMDB_SUCCESS) { dmn_log_err("plugin_geoip: map '%s': Failed to open GeoIP2 database '%s': %s", map_name, pathname, MMDB_strerror(status)); free(db); return NULL; } MMDB_metadata_s* meta = &db->mmdb.metadata; if(!geoip2_mmdb_log_meta(meta, map_name, pathname)) { geoip2_destroy(db); return NULL; } // The database format spec indicates that minor version bumps // should be backwards compatible, so we only need to check // the major version here. if(meta->binary_format_major_version != 2U) { dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has" " unsupported binfmt major version %" PRIu16, map_name, pathname, meta->binary_format_major_version ); geoip2_destroy(db); return NULL; } // Both our own code and the current libmaxminddb seem to have // built-in assumptions based on record_size of 32 or less, // yet the spec allows for larger in the future. if(meta->record_size > 32U) { dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has" " unsupported record_size %" PRIu16, map_name, pathname, meta->record_size ); geoip2_destroy(db); return NULL; } if(meta->ip_version != 4U && meta->ip_version != 6U) { dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has" " unsupported ip_version %" PRIu16, map_name, pathname, meta->ip_version ); geoip2_destroy(db); return NULL; } // The check for /City/ is how the official Perl API detects // the City-level data model, so it's probably a reliable bet. // We assume anything that didn't match /City/ is a Country-level // database. This will technically "work" for GeoIP2 if there is no // Country-level info, but everything will default. So, warn about the // Country defaulting if the database_type does not match /Country/. db->is_city = !!strstr(meta->database_type, "City"); if(!db->is_city) { if(city_auto_mode) { dmn_log_err("plugin_geoip: map '%s': GeoIP2 DB '%s' is not a City-level" " database and this map uses auto_dc_coords", map_name, pathname); geoip2_destroy(db); return NULL; } if(!strstr(meta->database_type, "Country")) dmn_log_warn("plugin_geoip: map '%s': Assuming GeoIP2 database '%s'" " has standard MaxMind Country data, but type is actually '%s'", map_name, pathname, meta->database_type ); } db->is_v4 = meta->ip_version == 4U; db->city_auto_mode = city_auto_mode; db->city_no_region = city_no_region; db->pathname = strdup(pathname); db->map_name = strdup(map_name); db->dclists = dclists; db->dcmap = dcmap; return db; }