/* Copyright (C) 2001 Ulric Eriksson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #define CFG ETCDIR "/dwatch.conf" #define TIMEOUT 5 static int foreground = 1; static int debuglevel = 0; static int verboselevel = 0; static char *cfg = CFG; static int timeout = TIMEOUT; static void debug(char *fmt, ...) { char b[4096]; va_list ap; va_start(ap, fmt); vsnprintf(b, sizeof b, fmt, ap); if (foreground) { fprintf(stderr, "%s\n", b); } else { openlog("pen", LOG_CONS, LOG_USER); syslog(LOG_DEBUG, "%s\n", b); closelog(); } va_end(ap); } static void error(char *fmt, ...) { char b[4096]; va_list ap; va_start(ap, fmt); vsnprintf(b, sizeof b, fmt, ap); if (foreground) { fprintf(stderr, "%s\n", b); } else { openlog("pen", LOG_CONS, LOG_USER); syslog(LOG_ERR, "%s\n", b); closelog(); } va_end(ap); exit(1); } static void usage(void) { printf("usage:\n" " dwatch [-d] [-f conf]\n" "\n" " -d debugging on\n" " -v verbose\n" " -f conf alternate configuration file [%s]\n", CFG); exit(0); } static void options(int argc, char **argv) { int c; while ((c = getopt(argc, argv, "f:dv")) != EOF) { switch (c) { case 'd': debuglevel++; break; case 'f': cfg = optarg; break; case 'v': verboselevel++; break; default: usage(); break; } } } static int try_process(char *p) { FILE *fp; char b[1024]; if (debuglevel) debug("Scanning for process '%s'", p); fp = popen(PS, "r"); if (fp == NULL) error("Can't run ps"); while (fgets(b, sizeof b, fp)) { if (strstr(b, p)) { pclose(fp); return 0; } } pclose(fp); return -1; } static void tcp_alarm(int dummy) { ; } static int try_tcp(char *p) { struct sockaddr_in serv_addr; int upfd; char *addr = strtok(p, ":"), *port = strtok(NULL, ":"); struct hostent *h = gethostbyname(addr); struct in_addr a; struct servent *s = getservbyname(port, "tcp"); int po; if (h == NULL) { if ((a.s_addr = inet_addr(addr)) == -1) { error("unknown or invalid address [%s]\n", addr); } } else { memcpy(&a, h->h_addr, h->h_length); } if (s == NULL) { po = atoi(port); } else { po = ntohs(s->s_port); } if (debuglevel) debug("Connecting to %s", p); upfd = socket(AF_INET, SOCK_STREAM, 0); if (upfd < 0) error("Error opening socket"); memset(&serv_addr, 0, sizeof serv_addr); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = a.s_addr; if (debuglevel) debug("Port '%s' = %d", port, po); serv_addr.sin_port = htons(po); signal(SIGALRM, tcp_alarm); alarm(timeout); if (connect(upfd, (struct sockaddr *) &serv_addr, sizeof serv_addr) == -1) { if (debuglevel) debug("Connect failed"); close(upfd); return -1; } if (debuglevel) debug("Successful connect"); close(upfd); return 0; } int main(int argc, char **argv) { char b[1024], directive[1024], argument[1024], command[1024]; int n; FILE *fp; options(argc, argv); fp = fopen(cfg, "r"); if (fp == NULL) error("Can't open configuration file '%s'", cfg); while (fgets(b, sizeof b, fp)) { if (b[0] == '#') continue; n = sscanf(b, "%s \"%[^\"]\" %[^\n]", directive, argument, command); if (n != 3) { if (debuglevel) debug("Bogus conf line '%s'", b); continue; } if (debuglevel) { debug("directive: '%s'", directive); debug("argument: '%s'", argument); debug("command: '%s'", command); } switch (directive[0]) { case 'P': if (try_process(argument)) { if (debuglevel) debug("Running '%s'", command); if (verboselevel) { printf("No process '%s'; running '%s'\n", argument, command); } system(command); sleep(10); } break; case 'T': if (try_tcp(argument)) { if (debuglevel) debug("Running '%s'", command); if (verboselevel) { printf("No listener on %s, running '%s'\n", argument, command); } system(command); sleep(10); } break; default: error("Bogus directive '%s'", directive); break; } } return 0; }