/* * Service monitor. * * Nickolai Zeldovich * February 2002 */ #include #include #include #include "svcmon.h" static str confpath; int check_timeout = 30; static int check_period = 60; static int status_port = -1; static int webstat_port = 8080; static vec services; struct notify_type { str name; cbnotify cb; }; static struct notify_type notify_types[] = { { "console", wrap (¬ify_cons) }, { "zephyr", wrap (¬ify_zephyr) }, { NULL, NULL }, }; void net_write (int fd, strbuf sb, cbb cb) { fdcb (fd, selwrite, NULL); suio *s = sb.tosuio (); if (s->resid ()) { int res = s->output (fd); if (res < 0) { cb (false); return; } } if (s->resid ()) fdcb (fd, selwrite, wrap (&net_write, fd, sb, cb)); else cb (true); } static void start_check () { for (unsigned int i = 0; i < services.size (); i++) { service *svc = services[i]; svc->start (); } delaycb (check_period, 0, wrap (&start_check)); } static cbnotify find_notify (str type) { for (int i = 0; notify_types[i].cb != NULL; i++) if (notify_types[i].name == type) return notify_types[i].cb; return NULL; } static checker * make_checker (str type, str param) { if (type == "http") return New http_checker (param); if (type == "tcp") { rxx tcp_param ("^([\\w\\.-]+):(\\d{1,6})"); str host; int port; if (!tcp_param.match (param)) return NULL; host = tcp_param[1]; convertint (tcp_param[2].cstr (), &port); return New tcp_checker (host, port); } if (type == "pksd") { rxx pksd_param ("^([\\w\\.-]+):(\\d{1,6})/0x([\\dABCDEF]{8})"); str host; int port; str key; if (!pksd_param.match (param)) return NULL; host = pksd_param[1]; key = pksd_param[3]; convertint (pksd_param[2].cstr (), &port); return New pksd_checker (host, port, key); } if (type == "news") { rxx news_param ("^([\\w\\.-]+):(\\d{1,6}),(\\S*)"); str host; int port; str group; if (!news_param.match (param)) return NULL; host = news_param[1]; group = news_param[3]; convertint (news_param[2].cstr (), &port); return New news_checker (host, port, group); } if (type == "sshd") { rxx sshd_param ("^([\\w\\.-]+)"); str host; if (!sshd_param.match (param)) return NULL; host = sshd_param[1]; return New sshd_checker (host); } if (type == "smtp") { rxx smtp_param ("^([\\w\\.-]+)"); str host; if (!smtp_param.match (param)) return NULL; host = smtp_param[1]; return New smtp_checker (host); } return NULL; } static void load_config (str cf) { parseargs pa (cf); bool errors = false; int line; vec av; while (pa.getline (&av, &line)) { if (!strcasecmp (av[0], "recheck")) { if (av.size () != 2 || !convertint (av[1], &check_period)) { errors = true; warn << cf << ":" << line << ": usage: recheck \n"; } } else if (!strcasecmp (av[0], "timeout")) { if (av.size () != 2 || !convertint (av[1], &check_timeout)) { errors = true; warn << cf << ":" << line << ": usage: timeout \n"; } } else if (!strcasecmp (av[0], "statusport")) { if (av.size () != 2 || !convertint (av[1], &status_port)) { errors = true; warn << cf << ":" << line << ": usage: statusport \n"; } } else if (!strcasecmp (av[0], "webstatport")) { if (av.size () != 2 || !convertint (av[1], &webstat_port)) { errors = true; warn << cf << ":" << line << ": usage: webstatport \n"; } } else if (!strcasecmp (av[0], "service")) { if (av.size () != 3) { errors = true; warn << cf << ":" << line << ": usage: service \n"; } else { str type, param; checker *c = NULL; type = av[1]; param = av[2]; c = make_checker (type, param); if (!c) { errors = true; warn << cf << ":" << line << ": bad type or args: " << type << ", " << param << "\n"; } else { service *svc = New service (c); services.push_back (svc); svc->add_notify (find_notify ("zephyr")); } } } else { errors = true; warn << cf << ":" << line << ": unknown directive: " << av[0] << "\n"; } } if (errors) fatal << "errors in config file\n"; } int main (int ac, char **av) { if (ac != 2) fatal << "Usage: " << av[0] << " config-file\n"; confpath = av[1]; load_config (confpath); delaycb (0, wrap (&start_check)); if (status_port > 0) status_init (status_port, services); if (webstat_port > 0) web_status_init (webstat_port, services); amain (); }