1 /*
2 Copyright (C) 2001 Ulric Eriksson <ulric@siag.nu>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17 MA 02111-1307, USA.
18 */
19
20 #include <sys/types.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <signal.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #include <syslog.h>
31 #include <sys/socket.h>
32
33 #define CFG ETCDIR "/dwatch.conf"
34 #define TIMEOUT 5
35
36 static int foreground = 1;
37 static int debuglevel = 0;
38 static int verboselevel = 0;
39 static char *cfg = CFG;
40 static int timeout = TIMEOUT;
41
debug(char * fmt,...)42 static void debug(char *fmt, ...)
43 {
44 char b[4096];
45 va_list ap;
46 va_start(ap, fmt);
47 vsnprintf(b, sizeof b, fmt, ap);
48 if (foreground) {
49 fprintf(stderr, "%s\n", b);
50 } else {
51 openlog("pen", LOG_CONS, LOG_USER);
52 syslog(LOG_DEBUG, "%s\n", b);
53 closelog();
54 }
55 va_end(ap);
56 }
57
error(char * fmt,...)58 static void error(char *fmt, ...)
59 {
60 char b[4096];
61 va_list ap;
62 va_start(ap, fmt);
63 vsnprintf(b, sizeof b, fmt, ap);
64 if (foreground) {
65 fprintf(stderr, "%s\n", b);
66 } else {
67 openlog("pen", LOG_CONS, LOG_USER);
68 syslog(LOG_ERR, "%s\n", b);
69 closelog();
70 }
71 va_end(ap);
72 exit(1);
73 }
74
usage(void)75 static void usage(void)
76 {
77 printf("usage:\n"
78 " dwatch [-d] [-f conf]\n"
79 "\n"
80 " -d debugging on\n"
81 " -v verbose\n"
82 " -f conf alternate configuration file [%s]\n",
83 CFG);
84
85 exit(0);
86 }
87
options(int argc,char ** argv)88 static void options(int argc, char **argv)
89 {
90 int c;
91
92 while ((c = getopt(argc, argv, "f:dv")) != EOF) {
93 switch (c) {
94 case 'd':
95 debuglevel++;
96 break;
97 case 'f':
98 cfg = optarg;
99 break;
100 case 'v':
101 verboselevel++;
102 break;
103 default:
104 usage();
105 break;
106 }
107 }
108 }
109
try_process(char * p)110 static int try_process(char *p)
111 {
112 FILE *fp;
113 char b[1024];
114 if (debuglevel) debug("Scanning for process '%s'", p);
115 fp = popen(PS, "r");
116 if (fp == NULL) error("Can't run ps");
117 while (fgets(b, sizeof b, fp)) {
118 if (strstr(b, p)) {
119 pclose(fp);
120 return 0;
121 }
122 }
123 pclose(fp);
124 return -1;
125 }
126
tcp_alarm(int dummy)127 static void tcp_alarm(int dummy)
128 {
129 ;
130 }
131
try_tcp(char * p)132 static int try_tcp(char *p)
133 {
134 struct sockaddr_in serv_addr;
135 int upfd;
136 char *addr = strtok(p, ":"), *port = strtok(NULL, ":");
137 struct hostent *h = gethostbyname(addr);
138 struct in_addr a;
139 struct servent *s = getservbyname(port, "tcp");
140 int po;
141
142 if (h == NULL) {
143 if ((a.s_addr = inet_addr(addr)) == -1) {
144 error("unknown or invalid address [%s]\n", addr);
145 }
146 } else {
147 memcpy(&a, h->h_addr, h->h_length);
148 }
149
150 if (s == NULL) {
151 po = atoi(port);
152 } else {
153 po = ntohs(s->s_port);
154 }
155
156 if (debuglevel) debug("Connecting to %s", p);
157 upfd = socket(AF_INET, SOCK_STREAM, 0);
158 if (upfd < 0) error("Error opening socket");
159 memset(&serv_addr, 0, sizeof serv_addr);
160 serv_addr.sin_family = AF_INET;
161 serv_addr.sin_addr.s_addr = a.s_addr;
162 if (debuglevel) debug("Port '%s' = %d", port, po);
163 serv_addr.sin_port = htons(po);
164 signal(SIGALRM, tcp_alarm);
165 alarm(timeout);
166 if (connect(upfd, (struct sockaddr *) &serv_addr,
167 sizeof serv_addr) == -1) {
168 if (debuglevel) debug("Connect failed");
169 close(upfd);
170 return -1;
171 }
172 if (debuglevel) debug("Successful connect");
173 close(upfd);
174 return 0;
175 }
176
main(int argc,char ** argv)177 int main(int argc, char **argv)
178 {
179 char b[1024], directive[1024], argument[1024], command[1024];
180 int n;
181 FILE *fp;
182
183 options(argc, argv);
184 fp = fopen(cfg, "r");
185 if (fp == NULL) error("Can't open configuration file '%s'", cfg);
186 while (fgets(b, sizeof b, fp)) {
187 if (b[0] == '#') continue;
188 n = sscanf(b, "%s \"%[^\"]\" %[^\n]",
189 directive, argument, command);
190 if (n != 3) {
191 if (debuglevel) debug("Bogus conf line '%s'", b);
192 continue;
193 }
194 if (debuglevel) {
195 debug("directive: '%s'", directive);
196 debug("argument: '%s'", argument);
197 debug("command: '%s'", command);
198 }
199 switch (directive[0]) {
200 case 'P':
201 if (try_process(argument)) {
202 if (debuglevel) debug("Running '%s'", command);
203 if (verboselevel) {
204 printf("No process '%s'; running '%s'\n",
205 argument, command);
206 }
207 system(command);
208 sleep(10);
209 }
210 break;
211 case 'T':
212 if (try_tcp(argument)) {
213 if (debuglevel) debug("Running '%s'", command);
214 if (verboselevel) {
215 printf("No listener on %s, running '%s'\n",
216 argument, command);
217 }
218 system(command);
219 sleep(10);
220 }
221 break;
222 default:
223 error("Bogus directive '%s'", directive);
224 break;
225 }
226 }
227 return 0;
228 }
229
230