1 /*----------------------------------------------------------------------------*/
2 /* Xymon hosts.cfg file grep'er                                               */
3 /*                                                                            */
4 /* This tool will pick out the hosts from a hosts.cfg file that has one of    */
5 /* the tags given on the command line. This allows an extension script to     */
6 /* deal with only the relevant parts of the hosts.cfg file, instead of        */
7 /* having to parse the entire file.                                           */
8 /*                                                                            */
9 /* Copyright (C) 2003-2011 Henrik Storner <henrik@hswn.dk>                    */
10 /*                                                                            */
11 /* This program is released under the GNU General Public License (GPL),       */
12 /* version 2. See the file "COPYING" for details.                             */
13 /*                                                                            */
14 /*----------------------------------------------------------------------------*/
15 
16 static char rcsid[] = "$Id: xymongrep.c 7706 2015-10-19 21:54:16Z jccleaver $";
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 
23 #include "version.h"
24 #include "libxymon.h"
25 
26 static char *connstatus = NULL;
27 static char *teststatus = NULL;
28 static char *conncolumn = "conn";
29 static char *testcolumn = NULL;
30 
31 
load_hoststatus()32 static void load_hoststatus()
33 {
34 	int res;
35 	char msg[1024];
36 	sendreturn_t *sres;
37 
38 	sprintf(msg, "xymondboard fields=hostname,testname,color test=%s", conncolumn);
39 	sres = newsendreturnbuf(1, NULL);
40 	res = sendmessage(msg, NULL, XYMON_TIMEOUT, sres);
41 	if (res == XYMONSEND_OK) connstatus = getsendreturnstr(sres, 1);
42 
43 	if ((res == XYMONSEND_OK) && testcolumn) {
44 		sprintf(msg, "xymondboard fields=hostname,testname,color test=%s", testcolumn);
45 		res = sendmessage(msg, NULL, XYMON_TIMEOUT, sres);
46 		if (res == XYMONSEND_OK) teststatus = getsendreturnstr(sres, 1);
47 	}
48 
49 	if (res != XYMONSEND_OK) {
50 		errprintf("Cannot fetch Xymon status, ignoring --no-down\n");
51 		connstatus = NULL;
52 		teststatus = NULL;
53 	}
54 
55 	freesendreturnbuf(sres);
56 }
57 
58 
netok(char * netstring,char * curnet,int testuntagged)59 static int netok(char *netstring, char *curnet, int testuntagged)
60 {
61 	return ( (netstring == NULL) ||
62 		 (curnet && netstring && (strcmp(curnet, netstring) == 0)) ||
63 		 (testuntagged && (curnet == NULL)) );
64 }
65 
downok(char * hostname,int nodownhosts)66 static int downok(char *hostname, int nodownhosts)
67 {
68 	char *mark, *colorstr;
69 	int color;
70 
71 	if (!nodownhosts) return 1;
72 
73 	/* Check if the host is down (i.e. "conn" test is non-green) */
74 	if (!connstatus) return 1;
75 	mark = (char *)malloc(strlen(hostname) + strlen(conncolumn) + 4);
76 	sprintf(mark, "\n%s|%s|", hostname, conncolumn);
77 	colorstr = strstr(connstatus, mark);
78 	if (colorstr) {
79 		colorstr += strlen(mark);	/* Skip to the color data */
80 	}
81 	else if (strncmp(connstatus, mark+1, strlen(mark+1)) == 0) {
82 		colorstr = connstatus + strlen(mark+1);	/* First entry we get */
83 	}
84 	xfree(mark);
85 	color = (colorstr ? parse_color(colorstr) : COL_GREEN);
86 	if ((color == COL_RED) || (color == COL_BLUE)) return 0;
87 
88 	/* Check if the test is currently disabled */
89 	if (!teststatus) return 1;
90 	mark = (char *)malloc(strlen(hostname) + strlen(testcolumn) + 4);
91 	sprintf(mark, "\n%s|%s|", hostname, testcolumn);
92 	colorstr = strstr(teststatus, mark);
93 	if (colorstr) {
94 		colorstr += strlen(mark);	/* Skip to the color data */
95 	}
96 	else if (strncmp(teststatus, mark+1, strlen(mark+1)) == 0) {
97 		colorstr = teststatus + strlen(mark+1);	/* First entry we get */
98 	}
99 	xfree(mark);
100 	color = (colorstr ? parse_color(colorstr) : COL_GREEN);
101 	if ((color == COL_RED) || (color == COL_BLUE)) return 0;
102 
103 	return 1;
104 }
105 
main(int argc,char * argv[])106 int main(int argc, char *argv[])
107 {
108 	void *hwalk;
109 	char *hostsfn = NULL;
110 	char *netstring = NULL;
111 	char *include2 = NULL;
112 	int extras = 1;
113 	int testuntagged = 0;
114 	int nodownhosts = 0;
115 	int loadhostsfromxymond = 0;
116 	int onlypreferredentry = 0;
117 	char *p;
118 	char **lookv;
119 	int argi, lookc;
120 	strbuffer_t *wantedtags;
121 
122 	lookv = (char **)malloc(argc*sizeof(char *));
123 	lookc = 0;
124 
125 	conncolumn = xgetenv("PINGCOLUMN");
126 
127 	for (argi=1; (argi < argc); argi++) {
128 		if (strcmp(argv[argi], "--debug") == 0) {
129 			char *delim = strchr(argv[argi], '=');
130 			debug = 1;
131 			if (delim) set_debugfile(delim+1, 0);
132 		}
133 		else if (strcmp(argv[argi], "--help") == 0) {
134 			printf("Usage:\n%s [options] test1 [test2] [test3] ... \n", argv[0]);
135 			exit(1);
136 		}
137 		else if (strcmp(argv[argi], "--noextras") == 0) {
138 			extras = 0;
139 		}
140 		else if (strcmp(argv[argi], "--test-untagged") == 0) {
141 			testuntagged = 1;
142 		}
143 		else if (argnmatch(argv[argi], "--no-down")) {
144 			char *p;
145 			nodownhosts = 1;
146 			p = strchr(argv[argi], '=');
147 			if (p) testcolumn = strdup(p+1);
148 		}
149 		else if (strcmp(argv[argi], "--version") == 0) {
150 			printf("xymongrep version %s\n", VERSION);
151 			exit(0);
152 		}
153 		else if ((strcmp(argv[argi], "--net") == 0) || (strcmp(argv[argi], "--bbnet") == 0)) {
154 			include2 = "netinclude";
155 			onlypreferredentry = 0;
156 		}
157 		else if ((strcmp(argv[argi], "--web") == 0) || (strcmp(argv[argi], "--bbdisp") == 0)) {
158 			include2 = "dispinclude";
159 			onlypreferredentry = 1;
160 		}
161 		else if (argnmatch(argv[argi], "--hosts=")) {
162 			hostsfn = strchr(argv[argi], '=') + 1;
163 		}
164 		else if (strcmp(argv[argi], "--loadhostsfromxymond") == 0) {
165 			loadhostsfromxymond = 1;
166 		}
167 		else if ((*(argv[argi]) == '-') && (strlen(argv[argi]) > 1)) {
168 			fprintf(stderr, "Unknown option %s\n", argv[argi]);
169 		}
170 		else {
171 			lookv[lookc] = strdup(argv[argi]);
172 			lookc++;
173 		}
174 	}
175 	lookv[lookc] = NULL;
176 
177 	if ((hostsfn == NULL) || (strlen(hostsfn) == 0)) {
178 		hostsfn = strdup(xgetenv("HOSTSCFG"));
179 		if (!loadhostsfromxymond) {
180 			/* The default in load_hostnames is to try xymond first when */
181 			/* hostsfn = xgetenv("HOSTSCFG"), however we don't want that here */
182 			/* unless we're told to explicitly. Thus, copy xymond logic here. */
183 			hostsfn = (char *)realloc(hostsfn, strlen(hostsfn) + 2);
184 			memmove(hostsfn+1, hostsfn, strlen(hostsfn)+1);
185 			*hostsfn = '!';
186 		}
187 	}
188 	dbgprintf("Loading host configuration from %s%s\n", (loadhostsfromxymond ? "xymond, failing back to " : ""), hostsfn);
189 
190 	load_hostnames(hostsfn, include2, get_fqdn());
191 	if (first_host() == NULL) {
192 		errprintf("Cannot load %s, or file is empty\n", hostsfn);
193 		exit(3);
194 	}
195 
196 	/* If we must avoid downed or disabled hosts, let's find out what those are */
197 	if (nodownhosts) load_hoststatus();
198 
199 	/* Each network test tagged with NET:locationname */
200 	p = xgetenv("XYMONNETWORK");
201 	if ((p == NULL) || (strlen(p) == 0)) p = xgetenv("BBLOCATION");
202 	if (p && strlen(p)) netstring = strdup(p);
203 
204 	hwalk = first_host();
205 	wantedtags = newstrbuffer(0);
206 	while (hwalk) {
207 		char hostip[IP_ADDR_STRLEN];
208 		char *curnet = xmh_item(hwalk, XMH_NET);
209 		char *curname = xmh_item(hwalk, XMH_HOSTNAME);
210 
211 		/*
212 		 * Only look at the hosts whose NET: definition matches the wanted one.
213 		 * Must also check if the host is currently down (not responding to ping).
214 		 * And if the host is OK with knownhost(), because it may be time-limited.
215 		 */
216 		if (netok(netstring, curnet, testuntagged) && downok(curname, nodownhosts) && knownhost(curname, hostip, GH_IGNORE)) {
217 			char *item;
218 
219 			clearstrbuffer(wantedtags);
220 			for (item = xmh_item_walk(hwalk); (item); item = xmh_item_walk(NULL)) {
221 				int i;
222 				char *realitem = item + strspn(item, "!~?");
223 
224 				for (i=0; lookv[i]; i++) {
225 					char *outitem = NULL;
226 
227 					if (lookv[i][strlen(lookv[i])-1] == '*') {
228 						if (strncasecmp(realitem, lookv[i], strlen(lookv[i])-1) == 0) {
229 							outitem = (extras ? item : realitem);
230 						}
231 					}
232 					else if (strcasecmp(realitem, lookv[i]) == 0) {
233 						outitem = (extras ? item : realitem);
234 					}
235 
236 					if (outitem) {
237 						int needquotes = ((strchr(outitem, ' ') != NULL) || (strchr(outitem, '\t') != NULL));
238 						addtobuffer(wantedtags, " ");
239 						if (needquotes) addtobuffer(wantedtags, "\"");
240 						addtobuffer(wantedtags, outitem);
241 						if (needquotes) addtobuffer(wantedtags, "\"");
242 					}
243 				}
244 			}
245 
246 			if (STRBUF(wantedtags) && (*STRBUF(wantedtags) != '\0') && extras) {
247 				if (xmh_item(hwalk, XMH_FLAG_DIALUP)) addtobuffer(wantedtags, " dialup");
248 				if (xmh_item(hwalk, XMH_FLAG_TESTIP)) addtobuffer(wantedtags, " testip");
249 			}
250 
251 			if (STRBUF(wantedtags) && *STRBUF(wantedtags)) {
252 				printf("%s %s #%s\n", xmh_item(hwalk, XMH_IP), xmh_item(hwalk, XMH_HOSTNAME), STRBUF(wantedtags));
253 			}
254 		}
255 
256 		do { hwalk = next_host(hwalk, 1); } while (hwalk && onlypreferredentry && (strcmp(curname, xmh_item(hwalk, XMH_HOSTNAME)) == 0));
257 	}
258 
259 	return 0;
260 }
261 
262