1 /*
2 * qstat
3 * by Steve Jankowski
4 * steve@activesw.com
5 * http://www.activesw.com/people/steve/qstat.html
6 *
7 * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk)
8 * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net)
9 * Thanks to Scott MacFiggen for the quicksort code (smf@activesw.com)
10 *
11 * Inspired by QuakePing by Len Norton
12 *
13 * Copyright 1996,1997,1998,1999 by Steve Jankowski
14 *
15 * Licensed under the Artistic License, see LICENSE.txt for license terms
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include "qstat.h"
25 #include "debug.h"
26
27 #ifndef _WIN32
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 #endif
34
35 #ifdef _WIN32
36 #include <winsock.h>
37 #endif
38
39 #ifdef __hpux
40 #define STATIC static
41 #else
42 #define STATIC
43 #endif
44
45 #ifndef INADDR_NONE
46 #define INADDR_NONE ~0
47 #endif
48
49 typedef struct _cache_entry {
50 unsigned long ipaddr;
51 char *hostname[5];
52 } cache_entry;
53
54 static cache_entry *hcache;
55 static int n_entry;
56 static int max_entry;
57 static char *last_filename;
58 static int n_changes;
59
60 static void write_file(FILE *file);
61 static cache_entry *init_entry(unsigned long ipaddr, char *hostname,
62 cache_entry *known);
63 static cache_entry *find_entry(unsigned long ipaddr);
64 static void free_entry(cache_entry *entry);
65 static cache_entry *validate_entry(cache_entry *entry);
66 static cache_entry *find_host_entry(char *hostname);
67 static void add_hostname(cache_entry *entry, const char *hostname);
68
69 int
hcache_open(char * filename,int update)70 hcache_open(char *filename, int update)
71 {
72 FILE *file;
73 char line[500], ipstr[500], hostname[500];
74 char *l;
75 int line_no, end;
76 unsigned long ip1, ip2, ip3, ip4, ipaddr;
77 cache_entry *entry;
78
79 file = fopen(filename, update ? "r+" : "r");
80 if (file == NULL) {
81 if (errno == ENOENT) {
82 debug(2, "Creating new host cache \"%s\"\n", filename);
83 last_filename = filename;
84 return (0);
85 }
86 perror(filename);
87 return (-1);
88 }
89 last_filename = filename;
90
91 for (line_no = 1; fgets(line, sizeof(line), file) != NULL; line_no++) {
92 if (strlen(line) < 2) {
93 continue;
94 }
95 if (line[strlen(line) - 1] != '\n') {
96 printf("%d: line too long\n", line_no);
97 continue;
98 }
99 l = line;
100 while (isspace((unsigned char)*l)) {
101 l++;
102 }
103 if ((*l == '#') || (*l == '\0')) {
104 continue;
105 }
106 if (sscanf(l, "%s%n", ipstr, &end) != 1) {
107 printf("%d: parse error\n", line_no);
108 continue;
109 }
110 if (sscanf(ipstr, "%lu.%lu.%lu.%lu", &ip1, &ip2, &ip3, &ip4) != 4) {
111 init_entry(0, ipstr, NULL);
112 continue;
113 }
114
115 if ((ip1 & 0xffffff00) || (ip2 & 0xffffff00) ||
116 (ip3 & 0xffffff00) || (ip4 & 0xffffff00)) {
117 printf("%d: invalid IP address \"%s\"\n", line_no, ipstr);
118 continue;
119 }
120 ipaddr = (ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4;
121
122 entry = init_entry(ipaddr, NULL, NULL);
123 while (1) {
124 l += end;
125 while (isspace((unsigned char)*l)) {
126 l++;
127 }
128 if ((*l == '#') || (*l == '\0')) {
129 break;
130 }
131 hostname[0] = '\0';
132 if (sscanf(l, "%s%n", hostname, &end) != 1) {
133 printf("%d: parse error\n", line_no);
134 continue;
135 }
136 init_entry(ipaddr, hostname, entry);
137 }
138 }
139 fclose(file);
140 return (0);
141 }
142
143
144 STATIC cache_entry *
init_entry(unsigned long ipaddr,char * hostname,cache_entry * known)145 init_entry(unsigned long ipaddr, char *hostname, cache_entry *known)
146 {
147 cache_entry *entry;
148 int e = 0, h;
149
150 if (n_entry == max_entry) {
151 if (max_entry == 0) {
152 max_entry = 50;
153 hcache = (cache_entry *)malloc(sizeof(cache_entry) * max_entry * 2);
154 } else {
155 hcache = (cache_entry *)realloc(hcache,
156 sizeof(cache_entry) * max_entry * 2);
157 }
158 memset(hcache + n_entry, 0, sizeof(cache_entry) * max_entry *
159 (n_entry == 0 ? 2 : 1));
160 max_entry *= 2;
161 }
162
163 if (ipaddr == 0) {
164 entry = find_host_entry(hostname);
165 if (entry == NULL) {
166 hcache[n_entry].hostname[0] = strdup(hostname);
167 return (&hcache[n_entry++]);
168 }
169 return (entry);
170 }
171
172 if (known != NULL) {
173 entry = known;
174 } else {
175 for (e = 0; e < n_entry; e++) {
176 if (hcache[e].ipaddr == ipaddr) {
177 break;
178 }
179 }
180 entry = &hcache[e];
181 entry->ipaddr = ipaddr;
182 }
183
184 if (hostname && (hostname[0] != '\0')) {
185 for (h = 0; h < 5; h++) {
186 if (entry->hostname[h] == NULL) {
187 entry->hostname[h] = strdup(hostname);
188 break;
189 }
190 }
191 }
192 if (e == n_entry) {
193 n_entry++;
194 }
195 return (entry);
196 }
197
198
199 STATIC cache_entry *
find_host_entry(char * hostname)200 find_host_entry(char *hostname)
201 {
202 cache_entry *entry = &hcache[0];
203 char **ehost;
204 int e, h;
205 char first = *hostname;
206
207 for (e = 0; e < n_entry; e++, entry++) {
208 ehost = &entry->hostname[0];
209 for (h = 0; h < 5; h++, ehost++) {
210 if (*ehost && (first == **ehost) && (strcmp(hostname, *ehost) == 0)) {
211 return (entry);
212 }
213 }
214 }
215 return (NULL);
216 }
217
218
219 void
hcache_write_file(char * filename)220 hcache_write_file(char *filename)
221 {
222 FILE *file;
223
224 if (filename != NULL) {
225 file = fopen(filename, "w");
226 } else {
227 file = stdout;
228 }
229 if (file == NULL) {
230 perror(filename);
231 return;
232 }
233 write_file(file);
234 }
235
236
237 void
hcache_update_file()238 hcache_update_file()
239 {
240 FILE *file;
241
242 if ((last_filename == NULL) || (n_changes == 0)) {
243 return;
244 }
245
246 file = fopen(last_filename, "w");
247 if (file == NULL) {
248 perror(last_filename);
249 return;
250 }
251 write_file(file);
252 }
253
254
255 STATIC void
write_file(FILE * file)256 write_file(FILE *file)
257 {
258 int e, h;
259
260 for (e = 0; e < n_entry; e++) {
261 unsigned long ipaddr = hcache[e].ipaddr;
262 if (ipaddr == 0) {
263 continue;
264 }
265 fprintf(file, "%lu.%lu.%lu.%lu", (ipaddr & 0xff000000) >> 24,
266 (ipaddr & 0xff0000) >> 16, (ipaddr & 0xff00) >> 8, ipaddr & 0xff);
267 if (hcache[e].hostname[0]) {
268 for (h = 0; h < 5; h++) {
269 if (hcache[e].hostname[h] != NULL) {
270 fprintf(file, "%c%s", h ? ' ' : '\t', hcache[e].hostname[h]);
271 }
272 }
273 }
274 fprintf(file, "\n");
275 }
276 fclose(file);
277 }
278
279
280 void
hcache_invalidate()281 hcache_invalidate()
282 {
283 int e;
284
285 for (e = 0; e < n_entry; e++) {
286 if (hcache[e].ipaddr != 0) {
287 memset(&hcache[e].hostname[0], 0, sizeof(hcache[e].hostname));
288 }
289 }
290 }
291
292
293 void
hcache_validate()294 hcache_validate()
295 {
296 int e;
297 char **alias;
298 struct hostent *ent;
299 unsigned long ipaddr;
300 cache_entry *entry;
301
302 for (e = 0; e < n_entry; e++) {
303 fprintf(stderr, "\r%d / %d validating ", e, n_entry);
304 if (hcache[e].ipaddr != 0) {
305 ipaddr = hcache[e].ipaddr;
306 fprintf(stderr, "%lu.%lu.%lu.%lu", (ipaddr & 0xff000000) >> 24,
307 (ipaddr & 0xff0000) >> 16, (ipaddr & 0xff00) >> 8, ipaddr & 0xff);
308 ipaddr = htonl(ipaddr);
309 ent = gethostbyaddr((char *)&ipaddr, sizeof(unsigned long),
310 AF_INET);
311 } else if (hcache[e].hostname[0] != NULL) {
312 fprintf(stderr, "%s", hcache[e].hostname[0]);
313 ent = gethostbyname(hcache[e].hostname[0]);
314 if (ent != NULL) {
315 memcpy(&ipaddr, ent->h_addr_list[0], sizeof(ipaddr));
316 ipaddr = ntohl(ipaddr);
317 if ((entry = find_entry(ipaddr)) != NULL) {
318 add_hostname(entry, hcache[e].hostname[0]);
319 free_entry(&hcache[e]);
320 } else {
321 hcache[e].ipaddr = ipaddr;
322 }
323 }
324 } else {
325 continue;
326 }
327 if (ent == NULL) {
328 continue;
329 }
330
331 if (ent->h_name && (ent->h_name[0] != '\0')) {
332 add_hostname(&hcache[e], ent->h_name);
333 }
334 printf("h_name %s\n", ent->h_name ? ent->h_name : "NULL");
335 alias = ent->h_aliases;
336 while (*alias) {
337 add_hostname(&hcache[e], *alias);
338 printf("h_aliases %s\n", *alias);
339 alias++;
340 }
341 }
342 }
343
344
345 STATIC cache_entry *
validate_entry(cache_entry * entry)346 validate_entry(cache_entry *entry)
347 {
348 struct hostent *ent;
349 char **alias;
350 cache_entry *tmp;
351 unsigned long ipaddr;
352
353 if (entry->ipaddr != 0) {
354 ipaddr = htonl(entry->ipaddr);
355
356 /* fprintf( stderr, "%u.%u.%u.%u", (ipaddr&0xff000000)>>24,
357 * (ipaddr&0xff0000)>>16, (ipaddr&0xff00)>>8, ipaddr&0xff);
358 */
359 ent = gethostbyaddr((char *)&ipaddr, sizeof(unsigned long), AF_INET);
360 } else if (entry->hostname[0] != NULL) {
361 /* fprintf( stderr, "%s", entry->hostname[0]);
362 */
363 ent = gethostbyname(entry->hostname[0]);
364 if (ent != NULL) {
365 memcpy(&ipaddr, ent->h_addr_list[0], sizeof(ipaddr));
366 ipaddr = ntohl(ipaddr);
367 if ((tmp = find_entry(ipaddr)) != NULL) {
368 add_hostname(tmp, entry->hostname[0]);
369 free_entry(entry);
370 entry = tmp;
371 } else {
372 entry->ipaddr = ipaddr;
373 }
374 }
375 } else {
376 return (NULL);
377 }
378
379 if (ent == NULL) {
380 return (NULL);
381 }
382
383 if (ent->h_name && (ent->h_name[0] != '\0')) {
384 add_hostname(entry, ent->h_name);
385 }
386 alias = ent->h_aliases;
387 while (*alias) {
388 add_hostname(entry, *alias);
389 alias++;
390 }
391 return (entry);
392 }
393
394
395 unsigned long
hcache_lookup_hostname(char * hostname)396 hcache_lookup_hostname(char *hostname)
397 {
398 cache_entry *entry;
399 int e, h;
400
401 debug(1, "looking up %s\n", hostname);
402 for (e = 0; e < n_entry; e++) {
403 for (h = 0; h < 5; h++) {
404 if (hcache[e].hostname[h] &&
405 (strcmp(hostname, hcache[e].hostname[h]) == 0)) {
406 return (hcache[e].ipaddr);
407 }
408 }
409 }
410 entry = init_entry(0, hostname, NULL);
411 if (entry->ipaddr == 0) {
412 debug(2, "validating %s\n", hostname);
413 entry = validate_entry(entry);
414 n_changes++;
415 }
416 if ((entry != NULL) && entry->ipaddr) {
417 debug(2, "returning %lx\n", entry->ipaddr);
418 return (entry->ipaddr);
419 }
420
421 return (INADDR_NONE);
422 }
423
424
425 char *
hcache_lookup_ipaddr(unsigned long ipaddr)426 hcache_lookup_ipaddr(unsigned long ipaddr)
427 {
428 cache_entry *entry;
429 int e;
430
431 for (e = 0; e < n_entry; e++) {
432 if (hcache[e].ipaddr == ipaddr) {
433 return (hcache[e].hostname[0]);
434 }
435 }
436 entry = init_entry(ipaddr, 0, NULL);
437 debug(1, "validating %lx\n", ipaddr);
438 validate_entry(entry);
439 n_changes++;
440 return (entry ? entry->hostname[0] : NULL);
441 }
442
443
444 STATIC cache_entry *
find_entry(unsigned long ipaddr)445 find_entry(unsigned long ipaddr)
446 {
447 int e;
448
449 for (e = 0; e < n_entry; e++) {
450 if (hcache[e].ipaddr == ipaddr) {
451 return (&hcache[e]);
452 }
453 }
454 return (NULL);
455 }
456
457
458 STATIC void
free_entry(cache_entry * entry)459 free_entry(cache_entry *entry)
460 {
461 int h;
462
463 for (h = 0; h < 5; h++) {
464 if (entry->hostname[h] != NULL) {
465 free(entry->hostname[h]);
466 }
467 }
468 memset(entry, 0, sizeof(*entry));
469 }
470
471
472 STATIC void
add_hostname(cache_entry * entry,const char * hostname)473 add_hostname(cache_entry *entry, const char *hostname)
474 {
475 int h;
476
477 for (h = 0; h < 5; h++) {
478 if (entry->hostname[h] == NULL) {
479 break;
480 }
481 if (strcmp(entry->hostname[h], hostname) == 0) {
482 return;
483 }
484 }
485 if (h < 5) {
486 entry->hostname[h] = strdup(hostname);
487 }
488 }
489
490
491 /*
492 * main(int argc, char *argv[])
493 * {
494 * hcache_open( argv[1], 0);
495 * hcache_write(NULL);
496 *
497 * hcache_invalidate();
498 * printf( "invalidate\n");
499 * hcache_write(NULL);
500 * hcache_validate();
501 * printf( "validate\n");
502 * hcache_write( "/tmp/qhcache.out");
503 * }
504 *
505 */
506