gdmaps_t* gdmaps_test_init(const char* config_path) { dmn_init_log(); dmn_assert(config_path); const vscf_data_t* cfg_root = conf_load(config_path); conf_options(cfg_root); gdnsd_set_cfdir(config_path); const vscf_data_t* maps_cfg = conf_get_maps(cfg_root); gdmaps_t* gdmaps = gdmaps_new(maps_cfg); vscf_destroy(cfg_root); gdmaps_load_geoip_databases(gdmaps); gdmaps_setup_geoip_watcher_paths(gdmaps); gdmaps_setup_geoip_watchers(gdmaps); return gdmaps; }
int main(int argc, char** argv) { dmn_init_log("gdnsd_extmon_helper", true); // start up syslog IFF it appears the daemon // was *not* started via "startfg". Regular // start/restart would have /dev/null'd the // standard descriptors before forking us off. if(!isatty(0)) dmn_start_syslog(); // Bail out early if we don't have the right argument // count, and try to tell the user not to run us // if stderr happens to be hooked up to a terminal if(argc != 5) { fprintf(stderr, "This binary is not for human execution!\n"); abort(); } // open stderr logging connection using passed fd dmn_log_set_alt_stderr(atoi(argv[2])); // regardless, we seal off stdin now. We don't need it, // and this way we don't have to deal with it when // execv()-ing child commands later. if(!freopen("/dev/null", "r", stdin)) dmn_log_fatal("Cannot open /dev/null: %s", dmn_strerror(errno)); if(!strcmp(argv[1], "Y")) dmn_set_debug(true); else if(!strcmp(argv[1], "N")) dmn_set_debug(false); else log_fatal("Invalid debug argument on cmdline: '%s'!", argv[1]); // these are the main communication pipes to the daemon/plugin plugin_read_fd = atoi(argv[3]); plugin_write_fd = atoi(argv[4]); if(plugin_read_fd < 3 || plugin_read_fd > 1000 || plugin_write_fd < 3 || plugin_write_fd > 1000) log_fatal("Invalid pipe descriptors!"); // CLOEXEC the direct lines to the main plugin/daemon, // so that child scripts can't screw with them. if(fcntl(plugin_read_fd, F_SETFD, FD_CLOEXEC)) log_fatal("Failed to set FD_CLOEXEC on plugin read fd: %s", dmn_strerror(errno)); if(fcntl(plugin_write_fd, F_SETFD, FD_CLOEXEC)) log_fatal("Failed to set FD_CLOEXEC on plugin write fd: %s", dmn_strerror(errno)); if(emc_read_exact(plugin_read_fd, "HELO")) log_fatal("Failed to read HELO from plugin"); if(emc_write_string(plugin_write_fd, "HELO_ACK", 8)) log_fatal("Failed to write HELO_ACK to plugin"); uint8_t ccount_buf[7]; if(emc_read_nbytes(plugin_read_fd, 7, ccount_buf) || strncmp((char*)ccount_buf, "CMDS:", 5)) log_fatal("Failed to read command count from plugin"); num_mons = ((unsigned)ccount_buf[5] << 8) + ccount_buf[6]; if(!num_mons) log_fatal("Received command count of zero from plugin"); mons = calloc(num_mons, sizeof(mon_t)); if(emc_write_string(plugin_write_fd, "CMDS_ACK", 8)) log_fatal("Failed to write CMDS_ACK to plugin"); // Note, it's merely a happy coincidence that our mons[] // indices exactly match cmd->idx numbers. Always use // the cmd->idx numbers as the official index when talking // to the main daemon! for(unsigned i = 0; i < num_mons; i++) { mons[i].cmd = emc_read_command(plugin_read_fd); if(!mons[i].cmd) log_fatal("Failed to read command %u from plugin", i); if(i != mons[i].cmd->idx) log_fatal("BUG: plugin index issues, %u vs %u", i, mons[i].cmd->idx); if(emc_write_string(plugin_write_fd, "CMD_ACK", 7)) log_fatal("Failed to write CMD_ACK for command %u to plugin", i); } if(emc_read_exact(plugin_read_fd, "END_CMDS")) log_fatal("Failed to read END_CMDS from plugin"); if(emc_write_string(plugin_write_fd, "END_CMDS_ACK", 12)) log_fatal("Failed to write END_CMDS_ACK to plugin"); // done with the serial setup, close the readpipe and go nonblocking on write for eventloop... close(plugin_read_fd); if(unlikely(fcntl(plugin_write_fd, F_SETFL, (fcntl(plugin_write_fd, F_GETFL, 0)) | O_NONBLOCK) == -1)) log_fatal("Failed to set O_NONBLOCK on pipe: %s", logf_errno()); // init results-sending queue sendq_init(); // Set up libev error callback ev_set_syserr_cb(&syserr_for_ev); // Construct the default loop for the main thread struct ev_loop* def_loop = ev_default_loop(EVFLAG_AUTO); if(!def_loop) log_fatal("Could not initialize the default libev loop"); ev_set_timeout_collect_interval(def_loop, 0.1); ev_set_io_collect_interval(def_loop, 0.01); // set up primary read/write watchers on the pipe to the daemon's plugin plugin_read_watcher = malloc(sizeof(ev_io)); plugin_write_watcher = malloc(sizeof(ev_io)); ev_io_init(plugin_write_watcher, plugin_write_cb, plugin_write_fd, EV_WRITE); ev_set_priority(plugin_write_watcher, 1); // set up interval watchers for each monitor, initially for immediate firing // for the daemon's monitoring init cycle, then repeating every interval. for(unsigned i = 0; i < num_mons; i++) { mon_t* this_mon = &mons[i]; this_mon->interval_timer = malloc(sizeof(ev_timer)); ev_timer_init(this_mon->interval_timer, mon_interval_cb, 0., this_mon->cmd->interval); this_mon->interval_timer->data = this_mon; ev_set_priority(this_mon->interval_timer, 0); ev_timer_start(def_loop, this_mon->interval_timer); // initialize the other watchers in the mon_t here as well, // but do not start them (the interval callback starts them each interval) this_mon->cmd_timeout = malloc(sizeof(ev_timer)); ev_timer_init(this_mon->cmd_timeout, mon_timeout_cb, 0, 0); ev_set_priority(this_mon->cmd_timeout, -1); this_mon->cmd_timeout->data = this_mon; this_mon->child_watcher = malloc(sizeof(ev_child)); ev_child_init(this_mon->child_watcher, mon_child_cb, 0, 0); this_mon->child_watcher->data = this_mon; } log_info("gdnsd_extmon_helper running"); // shut off stderr output from here out... dmn_log_close_alt_stderr(); ev_run(def_loop, 0); log_info("gdnsd_extmon_helper terminating"); // kill -9 on any extant child procs for(unsigned i = 0; i < num_mons; i++) if(mons[i].cmd_pid) kill(mons[i].cmd_pid, SIGKILL); // Bye! exit(0); }