Beispiel #1
0
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;
    }
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}