Example #1
0
static RbtHandle findrec(char *key)
{
	RbtHandle handle;

	handle = rbtFind(rbconf, key);
	if (handle == rbtEnd(rbconf)) {
		/* Check if there's a clone pointer record */
		char *clonekey, *p;

		clonekey = strdup(key);
		p = strchr(clonekey, '|'); 
		if (p && *(p+1)) { *p = '='; *(p+1) = '\0'; }
		handle = rbtFind(rbconf, clonekey);
		xfree(clonekey);

		if (handle != rbtEnd(rbconf)) {
			void *k1, *k2;
			char *pointsto;
			char *service;

			/* Get the origin record for this cloned record, using the same service name */
			rbtKeyValue(rbconf, handle, &k1, &k2);
			pointsto = (char *)k2;
			service = strchr(key, '|'); if (service) service++;
			clonekey = (char *)malloc(strlen(pointsto) + strlen(service) + 2);
			sprintf(clonekey, "%s|%s", pointsto, service);

			handle = rbtFind(rbconf, clonekey);
			xfree(clonekey);
		}
	}

	return handle;
}
Example #2
0
char *knownhost(char *hostname, char *hostip, int ghosthandling)
{
	/*
	 * ghosthandling = 0 : Default BB method (case-sensitive, no logging, keep ghosts)
	 * ghosthandling = 1 : Case-insensitive, no logging, drop ghosts
	 * ghosthandling = 2 : Case-insensitive, log ghosts, drop ghosts
	 */
	RbtIterator hosthandle;
	namelist_t *walk = NULL;
	static char *result = NULL;
	void *k1, *k2;
	time_t now = getcurrenttime(NULL);

	if (result) xfree(result);
	result = NULL;

	/* Find the host in the normal hostname list */
	hosthandle = rbtFind(rbhosts, hostname);
	if (hosthandle != rbtEnd(rbhosts)) {
		rbtKeyValue(rbhosts, hosthandle, &k1, &k2);
		walk = (namelist_t *)k2;
	}
	else {
		/* Not found - lookup in the client alias list */
		hosthandle = rbtFind(rbclients, hostname);
		if (hosthandle != rbtEnd(rbclients)) {
			rbtKeyValue(rbclients, hosthandle, &k1, &k2);
			walk = (namelist_t *)k2;
		}
	}

	if (walk) {
		/*
		 * Force our version of the hostname. Done here so CLIENT works always.
		 */
		strcpy(hostip, walk->ip);
		result = strdup(walk->bbhostname);
	}
	else {
		*hostip = '\0';
		result = strdup(hostname);
	}

	/* If default method, just say yes */
	if (ghosthandling == 0) return result;

	/* Allow all summaries */
	if (strcmp(hostname, "summary") == 0) return result;

	if (walk && ( ((walk->notbefore > now) || (walk->notafter < now)) )) walk = NULL;
	return (walk ? result : NULL);
}
Example #3
0
void print_colheaders(FILE *output, RbtHandle rbcolumns)
{
	int colcount;
	RbtIterator colhandle;

	colcount = 1;	/* Remember the hostname column */

	/* Group column headings */
	fprintf(output, "<TR>");
	fprintf(output, "<TD ROWSPAN=2>&nbsp;</TD>\n");	/* For the prio column - in both row headers+dash rows */
	fprintf(output, "<TD ROWSPAN=2>&nbsp;</TD>\n");	/* For the host column - in both row headers+dash rows */
	for (colhandle = rbtBegin(rbcolumns); (colhandle != rbtEnd(rbcolumns)); colhandle = rbtNext(rbcolumns, colhandle)) {
		void *k1, *k2;
		char *colname;

	        rbtKeyValue(rbcolumns, colhandle, &k1, &k2);
		colname = (char *)k1;
		colcount++;

		fprintf(output, " <TD ALIGN=CENTER VALIGN=BOTTOM WIDTH=45>\n");
		fprintf(output, " <A HREF=\"%s\"><FONT %s><B>%s</B></FONT></A> </TD>\n",
			columnlink(colname), xgetenv("XYMONPAGECOLFONT"), colname);
	}
	fprintf(output, "</TR>\n");
	fprintf(output, "<TR><TD COLSPAN=%d><HR WIDTH=\"100%%\"></TD></TR>\n\n", colcount);
}
Example #4
0
void print_oneprio(FILE *output, RbtHandle rbstate, RbtHandle rbcolumns, int prio)
{
	RbtIterator hhandle;
	int firsthost = 1;
	char *curhost = "";

	/* Then output each host and their column status */
	for (hhandle = rbtBegin(rbstate); (hhandle != rbtEnd(rbstate)); hhandle = rbtNext(rbstate, hhandle)) {
		void *k1, *k2;
		hstatus_t *itm;

	        rbtKeyValue(rbstate, hhandle, &k1, &k2);
		itm = (hstatus_t *)k2;

		if (itm->config->priority != prio) continue;
		if (strcmp(curhost, itm->hostname) == 0) continue;

		/* New host */
		curhost = itm->hostname;
		print_hoststatus(output, itm, rbcolumns, prio, firsthost);
		firsthost = 0;
	}

	/* If we did output any hosts, make some room for the next priority */
	if (!firsthost) fprintf(output, "<TR><TD>&nbsp;</TD></TR>\n");
}
Example #5
0
static void locator_updatecache(enum locator_servicetype_t svc, char *key, char *resp)
{
	RbtIterator handle;
	cacheitm_t *newitm;

	if (!havecache[svc]) return;

	handle = rbtFind(locatorcache[svc], key);
	if (handle == rbtEnd(locatorcache[svc])) {
		newitm = (cacheitm_t *)calloc(1, sizeof(cacheitm_t));
		newitm->key = strdup(key);
		newitm->resp = strdup(resp);
		if (rbtInsert(locatorcache[svc], newitm->key, newitm) != RBT_STATUS_OK) {
			xfree(newitm->key);
			xfree(newitm->resp);
			xfree(newitm);
		}
	}
	else {
		newitm = (cacheitm_t *)gettreeitem(locatorcache[svc], handle);
		if (newitm->resp) xfree(newitm->resp);
		newitm->resp = strdup(resp);
		newitm->tstamp = getcurrenttime(NULL);
	}
}
Example #6
0
static link_t *find_link(char *key)
{
	link_t *l = NULL;
	RbtIterator handle;

	handle = rbtFind(linkstree, key);
	if (handle != rbtEnd(linkstree)) l = (link_t *)gettreeitem(linkstree, handle);

	return l;
}
Example #7
0
int delete_nkconfig(char *dropkey, int evenifcloned)
{
	RbtHandle handle;
	void *k1, *k2;

	handle = rbtFind(rbconf, dropkey);
	if (handle == rbtEnd(rbconf)) return 0;

	if (!evenifcloned) {
		/* Check if this record has any clones attached to it */
		char *hostname, *p;

		hostname = strdup(dropkey);
		p = strchr(hostname, '|'); if (p) *p = '\0';

		handle = rbtBegin(rbconf);

		while (handle != rbtEnd(rbconf)) {
			void *k1, *k2;
			char *key, *ptr;

			rbtKeyValue(rbconf, handle, &k1, &k2);
			key = (char *)k1; ptr = (char *)k2;
			if ((*(key + strlen(key) - 1) == '=') && (strcmp(hostname, ptr) == 0)) {
				xfree(hostname);
				return 1;
			}

			handle = rbtNext(rbconf, handle);
		}

		xfree(hostname);
	}

	handle = rbtFind(rbconf, dropkey);
	if (handle != rbtEnd(rbconf)) {
		rbtKeyValue(rbconf, handle, &k1, &k2);
		rbtErase(rbconf, handle);
		flushrec(k1, k2);
	}

	return 0;
}
Example #8
0
void addclone_nkconfig(char *origin, char *newclone)
{
	char *newkey;
	RbtHandle handle;

	newkey = (char *)malloc(strlen(newclone) + 2);
	sprintf(newkey, "%s=", newclone);
	handle = rbtFind(rbconf, newkey);
	if (handle != rbtEnd(rbconf)) dropclone_nkconfig(newclone);
	rbtInsert(rbconf, newkey, strdup(origin));
}
Example #9
0
void locator_flushcache(enum locator_servicetype_t svc, char *key)
{
	RbtIterator handle;

	if (!havecache[svc]) return;

	if (key) {
		handle = rbtFind(locatorcache[svc], key);
		if (handle != rbtEnd(locatorcache[svc])) {
			cacheitm_t *itm = (cacheitm_t *)gettreeitem(locatorcache[svc], handle);
			itm->tstamp = 0;
		}
	}
	else {
		for (handle = rbtBegin(locatorcache[svc]); (handle != rbtEnd(locatorcache[svc])); handle = rbtNext(locatorcache[svc], handle)) {
			cacheitm_t *itm = (cacheitm_t *)gettreeitem(locatorcache[svc], handle);
			itm->tstamp = 0;
		}
	}
}
Example #10
0
static char *locator_querycache(enum locator_servicetype_t svc, char *key)
{
	RbtIterator handle;
	cacheitm_t *itm;

	if (!havecache[svc]) return NULL;

	handle = rbtFind(locatorcache[svc], key);
	if (handle == rbtEnd(locatorcache[svc])) return NULL;

	itm = (cacheitm_t *)gettreeitem(locatorcache[svc], handle);
	return (itm->tstamp + cachetimeout[svc]) > getcurrenttime(NULL) ? itm->resp : NULL;
}
Example #11
0
void generate_critpage(FILE *output, char *hfprefix)
{
	RbtIterator hhandle;
	int color = COL_GREEN;
	int maxprio = 0;

	/* Determine background color and max. priority */
	for (hhandle = rbtBegin(rbstate); (hhandle != rbtEnd(rbstate)); hhandle = rbtNext(rbstate, hhandle)) {
		void *k1, *k2;
		hstatus_t *itm;

	        rbtKeyValue(rbstate, hhandle, &k1, &k2);
		itm = (hstatus_t *)k2;

		if (itm->color > color) color = itm->color;
		if (itm->config->priority > maxprio) maxprio = itm->config->priority;
	}

        headfoot(output, hfprefix, "", "header", color);
        fprintf(output, "<center>\n");

        if (color != COL_GREEN) {
		RbtHandle rbcolumns;
		int prio;

		rbcolumns = columnlist(rbstate);

		fprintf(output, "<TABLE BORDER=0 CELLPADDING=4 SUMMARY=\"Critical status display\">\n");
		print_colheaders(output, rbcolumns);

		for (prio = 1; (prio <= maxprio); prio++) {
			print_oneprio(output, rbstate, rbcolumns, prio);
		}

		fprintf(output, "</TABLE>\n");
		rbtDelete(rbcolumns);
        }
        else {
                /* "All Monitored Systems OK */
		fprintf(output, "%s", xgetenv("XYMONALLOKTEXT"));
        }

        fprintf(output, "</center>\n");
        headfoot(output, hfprefix, "", "footer", color);
}
Example #12
0
void dropclone_nkconfig(char *drop)
{
	RbtHandle handle;
	char *key;
	void *k1, *k2;
	char *dropkey, *dropsrc;

	key = (char *)malloc(strlen(drop) + 2);
	sprintf(key, "%s=", drop);
	handle = rbtFind(rbconf, key);
	if (handle == rbtEnd(rbconf)) return;

	rbtKeyValue(rbconf, handle, &k1, &k2);
	dropkey = k1; dropsrc = k2;
	rbtErase(rbconf, handle);
	xfree(dropkey); xfree(dropsrc);

	xfree(key);
}
Example #13
0
RbtHandle columnlist(RbtHandle statetree)
{
	RbtHandle rbcolumns;
	RbtIterator hhandle;

	rbcolumns = rbtNew(name_compare);
	for (hhandle = rbtBegin(statetree); (hhandle != rbtEnd(statetree)); hhandle = rbtNext(statetree, hhandle)) {
		void *k1, *k2;
		hstatus_t *itm;
		RbtStatus status;

	        rbtKeyValue(statetree, hhandle, &k1, &k2);
		itm = (hstatus_t *)k2;

		status = rbtInsert(rbcolumns, itm->testname, NULL);
	}

	return rbcolumns;
}
Example #14
0
void *hostinfo(char *hostname)
{
	RbtIterator hosthandle;
	namelist_t *result = NULL;
	time_t now = getcurrenttime(NULL);

	if (!configloaded) load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());

	hosthandle = rbtFind(rbhosts, hostname);
	if (hosthandle != rbtEnd(rbhosts)) {
		void *k1, *k2;

		rbtKeyValue(rbhosts, hosthandle, &k1, &k2);
		result = (namelist_t *)k2;

		if ((result->notbefore > now) || (result->notafter < now)) return NULL;
	}

	return result;
}
Example #15
0
int load_hostnames(char *bbhostsfn, char *extrainclude, int fqdn)
{
	/* Return value: 0 for load OK, 1 for "No files changed since last load", -1 for error (file not found) */
	static void *bbhfiles = NULL;
	FILE *bbhosts;
	int ip1, ip2, ip3, ip4, groupid, pageidx;
	char hostname[4096];
	strbuffer_t *inbuf;
	pagelist_t *curtoppage, *curpage, *pgtail;
	namelist_t *nametail = NULL;
	RbtHandle htree;

	/* First check if there were no modifications at all */
	if (bbhfiles) {
		if (!stackfmodified(bbhfiles)){
			dbgprintf("No files modified, skipping reload of %s\n", bbhostsfn);
			return 1;
		}
		else {
			stackfclist(&bbhfiles);
			bbhfiles = NULL;
		}
	}

	MEMDEFINE(hostname);
	MEMDEFINE(l);

	configloaded = 1;
	initialize_hostlist();
	curpage = curtoppage = pgtail = pghead;
	pageidx = groupid = 0;

	bbhosts = stackfopen(bbhostsfn, "r", &bbhfiles);
	if (bbhosts == NULL) return -1;

	inbuf = newstrbuffer(0);
	htree = rbtNew(name_compare);
	while (stackfgets(inbuf, extrainclude)) {
		sanitize_input(inbuf, 0, 0);

		if (strncmp(STRBUF(inbuf), "page", 4) == 0) {
			pagelist_t *newp;
			char *name, *title;

			pageidx = groupid = 0;
			if (get_page_name_title(STRBUF(inbuf), "page", &name, &title) == 0) {
				newp = (pagelist_t *)malloc(sizeof(pagelist_t));
				newp->pagepath = strdup(name);
				newp->pagetitle = (title ? strdup(title) : NULL);
				newp->next = NULL;

				pgtail->next = newp;
				pgtail = newp;

				curpage = curtoppage = newp;
			}
		}
		else if (strncmp(STRBUF(inbuf), "subpage", 7) == 0) {
			pagelist_t *newp;
			char *name, *title;

			pageidx = groupid = 0;
			if (get_page_name_title(STRBUF(inbuf), "subpage", &name, &title) == 0) {
				newp = (pagelist_t *)malloc(sizeof(pagelist_t));
				newp->pagepath = malloc(strlen(curtoppage->pagepath) + strlen(name) + 2);
				sprintf(newp->pagepath, "%s/%s", curtoppage->pagepath, name);
				newp->pagetitle = malloc(strlen(curtoppage->pagetitle) + strlen(title) + 2);
				sprintf(newp->pagetitle, "%s/%s", curtoppage->pagetitle, title);
				newp->next = NULL;

				pgtail->next = newp;
				pgtail = newp;

				curpage = newp;
			}
		}
		else if (strncmp(STRBUF(inbuf), "subparent", 9) == 0) {
			pagelist_t *newp, *parent;
			char *pname, *name, *title;

			pageidx = groupid = 0;
			parent = NULL;
			if (get_page_name_title(STRBUF(inbuf), "subparent", &pname, &title) == 0) {
				for (parent = pghead; (parent && !pagematch(parent, pname)); parent = parent->next);
			}

			if (parent && (get_page_name_title(title, "", &name, &title) == 0)) {
				newp = (pagelist_t *)malloc(sizeof(pagelist_t));
				newp->pagepath = malloc(strlen(parent->pagepath) + strlen(name) + 2);
				sprintf(newp->pagepath, "%s/%s", parent->pagepath, name);
				newp->pagetitle = malloc(strlen(parent->pagetitle) + strlen(title) + 2);
				sprintf(newp->pagetitle, "%s/%s", parent->pagetitle, title);
				newp->next = NULL;

				pgtail->next = newp;
				pgtail = newp;

				curpage = newp;
			}
		}
		else if (strncmp(STRBUF(inbuf), "group", 5) == 0) {
			groupid++;
		}
		else if (sscanf(STRBUF(inbuf), "%d.%d.%d.%d %s", &ip1, &ip2, &ip3, &ip4, hostname) == 5) {
			char *startoftags, *tag, *delim;
			int elemidx, elemsize;
			char clientname[4096];
			char downtime[4096];
			char groupidstr[10];
			RbtIterator handle;

			namelist_t *newitem = calloc(1, sizeof(namelist_t));
			namelist_t *iwalk, *iprev;

			MEMDEFINE(clientname);
			MEMDEFINE(downtime);

			/* Hostname beginning with '@' are "no-display" hosts. But we still want them. */
			if (*hostname == '@') memmove(hostname, hostname+1, strlen(hostname));

			if (!fqdn) {
				/* Strip any domain from the hostname */
				char *p = strchr(hostname, '.');
				if (p) *p = '\0';
			}

			sprintf(newitem->ip, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
			sprintf(groupidstr, "%d", groupid);
			newitem->groupid = strdup(groupidstr);
			newitem->pageindex = pageidx++;

			newitem->bbhostname = strdup(hostname);
			if (ip1 || ip2 || ip3 || ip4) newitem->preference = 1; else newitem->preference = 0;
			newitem->logname = strdup(newitem->bbhostname);
			{ char *p = newitem->logname; while ((p = strchr(p, '.')) != NULL) { *p = '_'; } }
			newitem->page = curpage;
			newitem->defaulthost = defaulthost;

			clientname[0] = downtime[0] = '\0';
			startoftags = strchr(STRBUF(inbuf), '#');
			if (startoftags == NULL) startoftags = ""; else startoftags++;
			startoftags += strspn(startoftags, " \t\r\n");
			newitem->allelems = strdup(startoftags);
			elemsize = 5;
			newitem->elems = (char **)malloc((elemsize+1)*sizeof(char *));

			tag = newitem->allelems; elemidx = 0;
			while (tag && *tag) {
				if (elemidx == elemsize) {
					elemsize += 5;
					newitem->elems = (char **)realloc(newitem->elems, (elemsize+1)*sizeof(char *));
				}
				newitem->elems[elemidx] = tag;

				/* Skip until we hit a whitespace or a quote */
				tag += strcspn(tag, " \t\r\n\"");
				if (*tag == '"') {
					delim = tag;

					/* Hit a quote - skip until the next matching quote */
					tag = strchr(tag+1, '"');
					if (tag != NULL) { 
						/* Found end-quote, NULL the item here and move on */
						*tag = '\0'; tag++; 
					}

					/* Now move quoted data one byte down (including the NUL) to kill quotechar */
					memmove(delim, delim+1, strlen(delim));
				}
				else if (*tag) {
					/* Normal end of item, NULL it and move on */
					*tag = '\0'; tag++;
				}
				else {
					/* End of line - no more to do. */
					tag = NULL;
				}

				/* 
				 * If we find a "noconn", drop preference value to 0.
				 * If we find a "prefer", up reference value to 2.
				 */
				if ((newitem->preference == 1) && (strcmp(newitem->elems[elemidx], "noconn") == 0))
					newitem->preference = 0;
				else if (strcmp(newitem->elems[elemidx], "prefer") == 0)
					newitem->preference = 2;

				/* Skip whitespace until start of next tag */
				if (tag) tag += strspn(tag, " \t\r\n");
				elemidx++;
			}

			newitem->elems[elemidx] = NULL;

			/* See if this host is defined before */
			handle = rbtFind(htree, newitem->bbhostname);
			if (strcasecmp(newitem->bbhostname, ".default.") == 0) {
				/* The pseudo DEFAULT host */
				newitem->next = NULL;
				defaulthost = newitem;
			}
			else if (handle == rbtEnd(htree)) {
				/* New item, so add to end of list */
				newitem->next = NULL;
				if (namehead == NULL) 
					namehead = nametail = newitem;
				else {
					nametail->next = newitem;
					nametail = newitem;
				}
				rbtInsert(htree, newitem->bbhostname, newitem);
			}
			else {
				/* Find the existing record - compare the record pointer instead of the name */
				namelist_t *existingrec = (namelist_t *)gettreeitem(htree, handle);
				for (iwalk = namehead, iprev = NULL; ((iwalk != existingrec) && iwalk); iprev = iwalk, iwalk = iwalk->next) ;
 				if (newitem->preference <= iwalk->preference) {
					/* Add after the existing (more preferred) entry */
					newitem->next = iwalk->next;
					iwalk->next = newitem;
				}
				else {
					/* New item has higher preference, so add before the iwalk item (i.e. after iprev) */
					if (iprev == NULL) {
						newitem->next = namehead;
						namehead = newitem;
					}
					else {
						newitem->next = iprev->next;
						iprev->next = newitem;
					}
				}
			}

			newitem->clientname = bbh_find_item(newitem, BBH_CLIENTALIAS);
			if (newitem->clientname == NULL) newitem->clientname = newitem->bbhostname;
			newitem->downtime = bbh_find_item(newitem, BBH_DOWNTIME);

			MEMUNDEFINE(clientname);
			MEMUNDEFINE(downtime);
		}
	}
	stackfclose(bbhosts);
	freestrbuffer(inbuf);
	rbtDelete(htree);

	MEMUNDEFINE(hostname);
	MEMUNDEFINE(l);

	build_hosttree();

	return 0;
}
Example #16
0
int addmessage(char *inbuf)
{
	RbtIterator phandle;
	xymon_peer_t *peer;
	int bcastmsg = 0;
	int inlen = strlen(inbuf);

	if (locatorbased) {
		char *hostname, *hostend, *peerlocation;

		/* xymond sends us messages with the KEY in the first field, between a '/' and a '|' */
		hostname = inbuf + strcspn(inbuf, "/|\r\n");
		if (*hostname != '/') {
			errprintf("No key field in message, dropping it\n");
			return -1; /* Malformed input */
		}
		hostname++;
		bcastmsg = (*hostname == '*');
		if (!bcastmsg) {
			/* Lookup which server handles this host */
			hostend = hostname + strcspn(hostname, "|\r\n");
			if (*hostend != '|') {
				errprintf("No delimiter found in input, dropping it\n");
				return -1; /* Malformed input */
			}
			*hostend = '\0';
			peerlocation = locator_query(hostname, locatorservice, NULL);

			/*
			 * If we get no response, or an empty response, 
			 * then there is no server capable of handling this
			 * request.
			 */
			if (!peerlocation || (*peerlocation == '\0')) {
				errprintf("No response from locator for %s/%s, dropping it\n",
					  servicetype_names[locatorservice], hostname);
				return -1;
			}

			*hostend = '|';
			phandle = rbtFind(peers, peerlocation);
			if (phandle == rbtEnd(peers)) {
				/* New peer - register it */
				addnetpeer(peerlocation);
				phandle = rbtFind(peers, peerlocation);
			}
		}
	}
	else {
		phandle = rbtFind(peers, "");
	}

	if (bcastmsg) {
		for (phandle = rbtBegin(peers); (phandle != rbtEnd(peers)); phandle = rbtNext(peers, phandle)) {
			peer = (xymon_peer_t *)gettreeitem(peers, phandle);

			addmessage_onepeer(peer, inbuf, inlen);
		}
	}
	else {
		if (phandle == rbtEnd(peers)) {
			errprintf("No peer found to handle message, dropping it\n");
			return -1;
		}
		peer = (xymon_peer_t *)gettreeitem(peers, phandle);

		addmessage_onepeer(peer, inbuf, inlen);
	}

	return 0;
}
Example #17
0
int main(int argc, char *argv[])
{
	int argi;
	struct sigaction sa;
	namelist_t *hostwalk;
	time_t nexttimeout;

	for (argi=1; (argi < argc); argi++) {
		if (argnmatch(argv[argi], "--server=")) {
			char *p = strchr(argv[argi], '=');
			serverip = strdup(p+1);
		}
		else if (argnmatch(argv[argi], "--interval=")) {
			char *p = strchr(argv[argi], '=');
			pollinterval = atoi(p+1);
		}
		else if (argnmatch(argv[argi], "--log-interval=")) {
			char *p = strchr(argv[argi], '=');
			errorloginterval = atoi(p+1);
		}
		else if (argnmatch(argv[argi], "--id=")) {
			char *p = strchr(argv[argi], '=');
			serverid = atoi(p+1);
		}
		else if (strcmp(argv[argi], "--debug") == 0) {
			debug = 1;
		}
	}

	setup_signalhandler("hobbitfetch");
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sigmisc_handler;
	sigaction(SIGHUP, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
	sigaction(SIGUSR1, &sa, NULL);	/* SIGUSR1 triggers logging of active requests */

	clients = rbtNew(name_compare);
	nexttimeout = time(NULL) + 60;

	{
		/* Seed the random number generator */
		struct timeval tv;
		struct timezone tz;

		gettimeofday(&tv, &tz);
		srandom(tv.tv_usec);
	}

	do {
		RbtIterator handle;
		conn_t *connwalk, *cprev;
		fd_set fdread, fdwrite;
		int n, maxfd;
		struct timeval tmo;
		time_t now;
		
		now = time(NULL);
		if (now > reloadtime) {
			/* Time to reload the bb-hosts file */
			reloadtime = now + 600;

			load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());
			for (hostwalk = first_host(); (hostwalk); hostwalk = hostwalk->next) {
				char *hname;
				clients_t *newclient;

				if (!bbh_item(hostwalk, BBH_FLAG_PULLDATA)) continue;

				hname = bbh_item(hostwalk, BBH_HOSTNAME);
				handle = rbtFind(clients, hname);
				if (handle == rbtEnd(clients)) {
					newclient = (clients_t *)calloc(1, sizeof(clients_t));
					newclient->hostname = strdup(hname);
					rbtInsert(clients, newclient->hostname, newclient);
					whentoqueue = now;
				}
			}
		}

		now = time(NULL);
		if (now > nexttimeout) {
			/* Check for connections that have timed out */
			nexttimeout = now + 60;

			for (connwalk = chead; (connwalk); connwalk = connwalk->next) {
				if ((connwalk->tstamp + 60) < now) {
					if (debug || (connwalk->client->nexterrortxt < now)) {
						errprintf("Timeout while talking to %s (req %lu): Aborting session\n",
							  addrstring(&connwalk->caddr), connwalk->seq);
						connwalk->client->nexterrortxt = now + errorloginterval;
					}
					flag_cleanup(connwalk);
				}
			}
		}

		if (needcleanup) {
			/* Remove any finished requests */
			needcleanup = 0;
			connwalk = chead; cprev = NULL;
			dbgprintf("Doing cleanup\n");

			while (connwalk) {
				conn_t *zombie;

				if ((connwalk->action == C_READING) || (connwalk->action == C_WRITING)) {
					/* Active connection - skip to the next conn_t record */
					cprev = connwalk;
					connwalk = connwalk->next;
					continue;
				}

				if (connwalk->action == C_CLEANUP) {
					if (connwalk->ctype == C_CLIENT) {
						/* 
						 * Finished getting data from a client, 
						 * flag idle and set next poll time.
						 */
						connwalk->client->busy = 0;
						set_polltime(connwalk->client);
					}
					else if (connwalk->ctype == C_SERVER) {
						/* Nothing needed for server cleanups */
					}
				}

				/* Unlink the request from the list of active connections */
				zombie = connwalk;
				if (cprev == NULL) {
					chead = zombie->next;
					connwalk = chead;
					cprev = NULL;
				}
				else {
					cprev->next = zombie->next;
					connwalk = zombie->next;
				}

				/* Purge the zombie */
				dbgprintf("Request completed: req %lu, peer %s, action was %d, type was %d\n", 
					zombie->seq, addrstring(&zombie->caddr), 
					zombie->action, zombie->ctype);
				close(zombie->sockfd);
				freestrbuffer(zombie->msgbuf);
				xfree(zombie);
			}

			/* Set the tail pointer correctly */
			ctail = chead;
			if (ctail) { while (ctail->next) ctail = ctail->next; }
		}

		if (dumpsessions) {
			/* Set by SIGUSR1 - dump the list of active requests */
			dumpsessions = 0;
			for (connwalk = chead; (connwalk); connwalk = connwalk->next) {
				char *ctypestr, *actionstr;
				char timestr[30];

				switch (connwalk->ctype) {
				  case C_CLIENT: ctypestr = "client"; break;
				  case C_SERVER: ctypestr = "server"; break;
				}

				switch (connwalk->action) {
				  case C_READING: actionstr = "reading"; break;
				  case C_WRITING: actionstr = "writing"; break;
				  case C_CLEANUP: actionstr = "cleanup"; break;
				}

				strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S",
					 localtime(&connwalk->tstamp));

				errprintf("Request %lu: state %s/%s, peer %s, started %s (%lu secs ago)\n",
					  connwalk->seq, ctypestr, actionstr, addrstring(&connwalk->caddr),
					  timestr, (now - connwalk->tstamp));
			}
		}

		now = time(NULL);
		if (now >= whentoqueue) {
			/* Scan host-tree for clients we need to contact */
			for (handle = rbtBegin(clients); (handle != rbtEnd(clients)); handle = rbtNext(clients, handle)) {
				clients_t *clientwalk;
				char msgline[100];
				strbuffer_t *request;
				char *pullstr, *ip;
				int port;

				clientwalk = (clients_t *)gettreeitem(clients, handle);
				if (clientwalk->busy) continue;
				if (clientwalk->nextpoll > now) continue;

				/* Deleted hosts stay in our tree - but should disappear from the known hosts */
				hostwalk = hostinfo(clientwalk->hostname); if (!hostwalk) continue;
				pullstr = bbh_item(hostwalk, BBH_FLAG_PULLDATA); if (!pullstr) continue;

				ip = strchr(pullstr, '=');
				port = atoi(xgetenv("BBPORT"));

				if (!ip) {
					ip = strdup(bbh_item(hostwalk, BBH_IP));
				}
				else {
					/* There is an explicit IP setting in the pulldata tag */
					char *p;

					ip++; /* Skip the '=' */
					ip = strdup(ip);
					p = strchr(ip, ':');
					if (p) { *p = '\0'; port = atoi(p+1); }

					if (*ip == '\0') {
						/* No IP given, just a port number */
						xfree(ip);
						ip = strdup(bbh_item(hostwalk, BBH_IP));
					}
				}

				if (strcmp(ip, "0.0.0.0") == 0) {
					struct hostent *hent;

					xfree(ip); ip = NULL;
					hent = gethostbyname(clientwalk->hostname);
					if (hent) {
						struct in_addr addr;

						memcpy(&addr, *(hent->h_addr_list), sizeof(addr));
						ip = strdup(inet_ntoa(addr));
					}
				}

				if (!ip) continue;

				/* 
				 * Build the "pullclient" request, which includes the latest
				 * clientdata config we got from the server. Keep the clientdata
				 * here - we send "pullclient" requests more often that we actually
				 * contact the server, but we should provide the config data always.
				 */
				request = newstrbuffer(0);
				sprintf(msgline, "pullclient %d\n", serverid);
				addtobuffer(request, msgline);
				if (clientwalk->clientdata) addtobuffer(request, clientwalk->clientdata);

				/* Put the request on the connection queue */
				addrequest(C_CLIENT, ip, port, request, clientwalk);
				clientwalk->busy = 1;

				xfree(ip);
			}
		}

		/* Handle request queue */
		FD_ZERO(&fdread);
		FD_ZERO(&fdwrite);
		maxfd = -1;
		for (connwalk = chead; (connwalk); connwalk = connwalk->next) {
			switch (connwalk->action) {
			  case C_READING: 
				FD_SET(connwalk->sockfd, &fdread);
				if (connwalk->sockfd > maxfd) maxfd = connwalk->sockfd;
				break;

			  case C_WRITING: 
				FD_SET(connwalk->sockfd, &fdwrite);
				if (connwalk->sockfd > maxfd) maxfd = connwalk->sockfd;
				break;

			  case C_CLEANUP:
				break;
			}
		}

		/* Do select with a 1 second timeout */
		tmo.tv_sec = 1;
		tmo.tv_usec = 0;
		n = select(maxfd+1, &fdread, &fdwrite, NULL, &tmo);

		if (n == -1) {
			if (errno == EINTR) continue;	/* Interrupted, e.g. a SIGHUP */

			/* This is a "cannot-happen" failure. Bail out */
			errprintf("select failure: %s\n", strerror(errno));
			return 0;
		}

		if (n == 0) continue;	/* Timeout */

		for (connwalk = chead; (connwalk); connwalk = connwalk->next) {
			switch (connwalk->action) {
			  case C_READING: 
				if (FD_ISSET(connwalk->sockfd, &fdread)) grabdata(connwalk);
				break;

			  case C_WRITING: 
				if (FD_ISSET(connwalk->sockfd, &fdwrite)) senddata(connwalk);
				break;

			  case C_CLEANUP:
				break;
			}
		}

	} while (running);

	return 0;
}
Example #18
0
nkconf_t *get_nkconfig(char *key, int flags, char **resultkey)
{
	static RbtHandle handle;
	static char *realkey = NULL;
	void *k1, *k2;
	nkconf_t *result = NULL;
	int isclone;

	if (resultkey) *resultkey = NULL;

	switch (flags) {
	  case NKCONF_TIMEFILTER:
		handle = findrec(key);
		/* We may have hit a cloned record, so use the real key for further searches */
		if (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = k1;
		}

		while (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			result = (nkconf_t *)k2;
			if (timecheck(result->starttime, result->endtime, result->nktime)) return result;

			/* Go to the next */
			handle = rbtNext(rbconf, handle);
			if (handle != rbtEnd(rbconf)) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				if (strncmp(realkey, ((nkconf_t *)k2)->key, strlen(realkey)) != 0) handle=rbtEnd(rbconf);
			}
		}
		realkey = NULL;
		break;

	  case NKCONF_FIRSTMATCH:
		handle = findrec(key);
		realkey = NULL;
		if (handle != rbtEnd(rbconf)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = (char *)k1;
		}
		break;

	  case NKCONF_FIRST:
		realkey = NULL;
		handle = rbtBegin(rbconf);
		if (handle == rbtEnd(rbconf)) return NULL;
		do {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			realkey = (char *)k1;
			isclone = (*(realkey + strlen(realkey) - 1) == '=');
			if (isclone) handle = rbtNext(rbconf, handle);
		} while (isclone && (handle != rbtEnd(rbconf)));
		break;


	  case NKCONF_NEXT:
		if (!realkey || (handle == rbtEnd(rbconf))) return NULL;
		isclone = 1;
		while (isclone && (handle != rbtEnd(rbconf))) {
			handle = rbtNext(rbconf, handle);
			if (handle) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				realkey = (char *)k1;
				isclone = (*(realkey + strlen(realkey) - 1) == '=');
			}
		}
		break;

	  case NKCONF_RAW_FIRST:
		handle = rbtBegin(rbconf);
		realkey = NULL;
		break;

	  case NKCONF_RAW_NEXT:
		handle = rbtNext(rbconf, handle);
		realkey = NULL;
		break;

	  case NKCONF_FIRSTHOSTMATCH:
		do {
			int found = 0;
			char *delim;

			realkey = NULL;
			handle = rbtBegin(rbconf);
			while (!found && (handle != rbtEnd(rbconf))) {
				rbtKeyValue(rbconf, handle, &k1, &k2);
				realkey = (char *)k1;
				delim = realkey + strlen(key); /* OK even if past end of realkey */
				found = ((strncmp(realkey, key, strlen(key)) == 0) &&
					((*delim == '|') || (*delim == '=')));
				if (!found) { handle = rbtNext(rbconf, handle); realkey = NULL; }
			}

			if ((handle != rbtEnd(rbconf)) && (*(realkey + strlen(realkey) - 1) == '=')) {
				key = (char *)k2;
				isclone = 1;
			}
			else isclone = 0;

		} while (isclone && (handle != rbtEnd(rbconf)));
		break;
	}

	if (handle == rbtEnd(rbconf)) { realkey = NULL; return NULL; }

	rbtKeyValue(rbconf, handle, &k1, &k2);
	if (resultkey) *resultkey = (char *)k1;
	result = (nkconf_t *)k2;

	return result;
}
Example #19
0
int do_la_rrd(char *hostname, char *testname, char *msg, time_t tstamp)
{
	static char *la_params[]          = { "rrdcreate", rrdfn, "DS:la:GAUGE:600:0:U", rra1, rra2, rra3, rra4, NULL };
	static char *la_tpl               = NULL;

	static pcre *as400_exp = NULL;
	static pcre *zVM_exp = NULL;
	static time_t starttime = 0;

	char *p, *eoln = NULL;
	int gotusers=0, gotprocs=0, gotload=0, gotclock=0;
	int users=0, procs=0, load=0, clockdiff=0;
	time_t now = time(NULL);

	if (la_tpl == NULL) la_tpl = setup_template(la_params);
	if (starttime == 0) starttime = now;

	if (strstr(msg, "bb-xsnmp") || strstr(msg, "netapp.pl")) {
		/*
		 * bb-xsnmp.pl script output.
		 *
		 * green Tue Apr  5 12:57:37 2005 up: 254.58 days, CPU Usage=  9%
		 *
		 * &green  CPU Time in Busy Mode:   9%
		 * &green  CPU Time in Idle Mode:  91%
		 *
		 * &yellow CPU Usage Threshold: 90%
		 * &red CPU Usage Threshold: 95%
		 *
		 * <!-- Enterprise: netapp , Version: 6.42 -->
		 * bb-xsnmp.pl Version: 1.78
		 */

		p = strstr(msg, "CPU Usage=");
		if (p) {
			p += strlen("CPU Usage=");
			gotload = 1;
			load = atoi(p);
		}

		goto done_parsing;
	}
	else if (strstr(msg, "z/VM") || strstr(msg, "VSE/ESA") || strstr(msg, "z/VSE")) {
		/* z/VM cpu message. Looks like this, from Rich Smrcina:
		 * green 5 Apr 2005 20:07:34  CPU Utilization  7% z/VM Version 4 Release 4.0, service level 0402 (32-bit) AVGPROC-007% 01
		 * VSE/ESA or z/VSE cpu message. Looks like this, from Rich Smrcina:
		 * VSE/ESA 2.7.2 cr IPLed on ...
		 * or
		 * z/VSE 3.1.1 cr IPLed on ...
		 */

		int ovector[30];
		char w[100];
		int res;

		if (zVM_exp == NULL) {
			const char *errmsg = NULL;
			int errofs = 0;

			zVM_exp = pcre_compile(".* CPU Utilization *([0-9]+)%", PCRE_CASELESS, &errmsg, &errofs, NULL);
		}

		res = pcre_exec(zVM_exp, NULL, msg, strlen(msg), 0, 0, ovector, (sizeof(ovector)/sizeof(int)));
		if (res >= 0) {
			/* We have a match - pick up the data. */
			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 1, w, sizeof(w));
			if (strlen(w)) {
				load = atoi(w); gotload = 1;
			}
		}

		goto done_parsing;
	}

	eoln = strchr(msg, '\n'); if (eoln) *eoln = '\0';
	p = strstr(msg, "up: ");
	if (!p) p = strstr(msg, "Uptime:");	/* Netapp filerstats2bb script */
	if (!p) p = strstr(msg, "uptime:");
	if (p) {
		/* First line of cpu report, contains "up: 159 days, 1 users, 169 procs, load=21" */
		p = strchr(p, ',');
		if (p) {
			gotusers = (sscanf(p, ", %d users", &users) == 1);
			p = strchr(p+1, ',');
		}

		if (p) {
			gotprocs = (sscanf(p, ", %d procs", &procs) == 1);
			p = strchr(p+1, ',');
		}

		/*
		 * Load can be either 
		 * -  "load=xx%"   (Windows)
		 * -  "load=xx.xx" (Unix, DISPREALLOADAVG=TRUE)
		 * -  "load=xx"    (Unix, DISPREALLOADAVG=FALSE)
		 *
		 * We want the load in percent (Windows), or LA*100 (Unix).
		 */
		p = strstr(msg, "load="); 
		if (p) { 
			p += 5;
			if (strchr(p, '%')) {
				gotload = 1; 
				load = atoi(p);
			}
			else if (strchr(p, '.')) {
				gotload = 1; 
				load = 100*atoi(p);
				/* Find the decimal part, and cut off at 2 decimals */
				p = strchr(p, '.'); if (strlen(p) > 3) *(p+3) = '\0';
				load += atoi(p+1);
			}
			else {
				gotload = 1; 
				load = atoi(p);
			}
		}
	}
	else {
		/* 
		 * No "uptime" in message - could be from an AS/400. They look like this:
		 * green March 21, 2005 12:33:24 PM EST deltacdc 108 users 45525 jobs(126 batch,0 waiting for message), load=26%
		 */
		int ovector[30];
		char w[100];
		int res;

		if (as400_exp == NULL) {
			const char *errmsg = NULL;
			int errofs = 0;

			as400_exp = pcre_compile(".* ([0-9]+) users ([0-9]+) jobs.* load=([0-9]+)\\%", 
						 PCRE_CASELESS, &errmsg, &errofs, NULL);
		}

		res = pcre_exec(as400_exp, NULL, msg, strlen(msg), 0, 0, ovector, (sizeof(ovector)/sizeof(int)));
		if (res >= 0) {
			/* We have a match - pick up the AS/400 data. */
			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 1, w, sizeof(w));
			if (strlen(w)) {
				users = atoi(w); gotusers = 1;
			}

			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 3, w, sizeof(w));
			if (strlen(w)) {
				load = atoi(w); gotload = 1;
			}
		}
	}

done_parsing:
	if (eoln) *eoln = '\n';

	p = strstr(msg, "System clock is ");
	if (p) {
		if (sscanf(p, "System clock is %d seconds off", &clockdiff) == 1) gotclock = 1;
	}

	if (!gotload) {
		/* See if it's a report from the ciscocpu.pl script. */
		p = strstr(msg, "<br>CPU 5 min average:");
		if (p) {
			/* It reports in % cpu utilization */
			p = strchr(p, ':');
			load = atoi(p+1);
			gotload = 1;
		}
	}

	if (gotload) {
		sprintf(rrdfn, "la.rrd");
		sprintf(rrdvalues, "%d:%d", (int)tstamp, load);
		create_and_update_rrd(hostname, rrdfn, la_params, la_tpl);
	}

	if (gotprocs) {
		sprintf(rrdfn, "procs.rrd");
		sprintf(rrdvalues, "%d:%d", (int)tstamp, procs);
		create_and_update_rrd(hostname, rrdfn, la_params, la_tpl);
	}

	if (gotusers) {
		sprintf(rrdfn, "users.rrd");
		sprintf(rrdvalues, "%d:%d", (int)tstamp, users);
		create_and_update_rrd(hostname, rrdfn, la_params, la_tpl);
	}

	if (gotclock) {
		sprintf(rrdfn, "clock.rrd");
		sprintf(rrdvalues, "%d:%d", (int)tstamp, clockdiff);
		create_and_update_rrd(hostname, rrdfn, la_params, la_tpl);
	}

	/*
	 * If we have run for less than 6 minutes, drop the memory updates here.
	 * We want to be sure not to use memory statistics from the CPU report
	 * if there is a memory add-on sending a separate memory statistics
	 */
	if ((now - starttime) < 360) return 0;

	if (!memhosts_init || (rbtFind(memhosts, hostname) == rbtEnd(memhosts))) {
		/* Pick up memory statistics */
		int found, overflow, realuse, swapuse;
		long long phystotal, physavail, pagetotal, pageavail;

		found = overflow = realuse = swapuse = 0;
		phystotal = physavail = pagetotal = pageavail = 0;

		p = strstr(msg, "Total Physical memory:");
		if (p) { 
			phystotal = str2ll(strchr(p, ':') + 1, NULL); 
			if (phystotal != LONG_MAX) found++; else overflow++;
		}

		if (found == 1) {
			p = strstr(msg, "Available Physical memory:");
			if (p) { 
				physavail = str2ll(strchr(p, ':') + 1, NULL); 
				if (physavail != LONG_MAX) found++; else overflow++;
			}
		}

		if (found == 2) {
			p = strstr(msg, "Total PageFile size:"); 
			if (p) { 
				pagetotal = str2ll(strchr(p, ':') + 1, NULL); 
				if (pagetotal != LONG_MAX) found++; else overflow++;
			}
		}

		if (found == 3) {
			p = strstr(msg, "Available PageFile size:"); 
			if (p) { 
				pageavail = str2ll(strchr(p, ':') + 1, NULL); 
				if (pageavail != LONG_MAX) found++; else overflow++;
			}
		}

		if (found == 4) {
			phystotal = phystotal / 100;
			pagetotal = pagetotal / 100;
			realuse = 100 - (physavail / phystotal);
			swapuse = 100 - (pageavail / pagetotal);
			do_memory_rrd_update(tstamp, hostname, realuse, swapuse, -1);
		}
		else if (overflow) {
			errprintf("Host %s cpu report overflows in memory usage calculation\n", hostname);
		}
	}

	return 0;
}
Example #20
0
int update_nkconfig(nkconf_t *rec)
{
	char *bakfn;
	FILE *bakfd;
	unsigned char buf[8192];
	int n;
	struct stat st;
	struct utimbuf ut;

	RbtHandle handle;
	FILE *fd;
	int result = 0;

	/* First, copy the old file */
	bakfn = (char *)malloc(strlen(configfn) + 5);
	sprintf(bakfn, "%s.bak", configfn);
	if (stat(configfn, &st) == 0) {
		ut.actime = st.st_atime;
		ut.modtime = st.st_mtime;
	}
	else ut.actime = ut.modtime = getcurrenttime(NULL);
	fd = fopen(configfn, "r");
	if (fd) {
		bakfd = fopen(bakfn, "w");
		if (bakfd) {
			while ((n = fread(buf, 1, sizeof(buf), fd)) > 0) fwrite(buf, 1, n, bakfd);
			fclose(bakfd);
			utime(bakfn, &ut);
		}
		fclose(fd);
	}
	xfree(bakfn);

	fd = fopen(configfn, "w");
	if (fd == NULL) {
		errprintf("Cannot open output file %s\n", configfn);
		return 1;
	}

	if (rec) {
		handle = rbtFind(rbconf, rec->key);
		if (handle == rbtEnd(rbconf)) rbtInsert(rbconf, rec->key, rec);
	}

	handle = rbtBegin(rbconf);
	while (handle != rbtEnd(rbconf)) {
		void *k1, *k2;
		char *onekey;

		rbtKeyValue(rbconf, handle, &k1, &k2);
		onekey = (char *)k1;

		if (*(onekey + strlen(onekey) - 1) == '=') {
			char *pointsto = (char *)k2;
			char *hostname;
			
			hostname = strdup(onekey);
			*(hostname + strlen(hostname) - 1) = '\0';
			fprintf(fd, "%s|=%s\n", hostname, pointsto);
		}
		else {
			nkconf_t *onerec = (nkconf_t *)k2;
			char startstr[20], endstr[20];

			*startstr = *endstr = '\0';
			if (onerec->starttime > 0) sprintf(startstr, "%d", (int)onerec->starttime);
			if (onerec->endtime > 0) sprintf(endstr, "%d", (int)onerec->endtime);

			fprintf(fd, "%s|%s|%s|%s|%d|%s|%s|%s\n",
				onekey, 
				startstr, endstr,
				(onerec->nktime ? onerec->nktime : ""),
				onerec->priority, 
				(onerec->ttgroup ? onerec->ttgroup : ""), 
				(onerec->ttextra ? onerec->ttextra : ""),
				(onerec->updinfo ? onerec->updinfo : ""));
		}

		handle = rbtNext(rbconf, handle);
	}

	fclose(fd);

	return result;
}
Example #21
0
int main(int argc, char *argv[])
{
	int daemonize = 0;
	char *pidfile = NULL;
	char *envarea = NULL;
	int cnid = -1;
	pcre *msgfilter = NULL;
	pcre *stdfilter = NULL;

	int argi;
	struct sigaction sa;
	RbtIterator handle;


	/* Dont save the error buffer */
	save_errbuf = 0;

	/* Create the peer container */
	peers = rbtNew(name_compare);

	for (argi=1; (argi < argc); argi++) {
		if (argnmatch(argv[argi], "--debug")) {
			debug = 1;
		}
		else if (argnmatch(argv[argi], "--channel=")) {
			char *cn = strchr(argv[argi], '=') + 1;

			for (cnid = C_STATUS; (channelnames[cnid] && strcmp(channelnames[cnid], cn)); cnid++) ;
			if (channelnames[cnid] == NULL) cnid = -1;
		}
		else if (argnmatch(argv[argi], "--daemon")) {
			daemonize = 1;
		}
		else if (argnmatch(argv[argi], "--no-daemon")) {
			daemonize = 0;
		}
		else if (argnmatch(argv[argi], "--pidfile=")) {
			char *p = strchr(argv[argi], '=');
			pidfile = strdup(p+1);
		}
		else if (argnmatch(argv[argi], "--log=")) {
			char *p = strchr(argv[argi], '=');
			logfn = strdup(p+1);
		}
		else if (argnmatch(argv[argi], "--env=")) {
			char *p = strchr(argv[argi], '=');
			loadenv(p+1, envarea);
		}
		else if (argnmatch(argv[argi], "--area=")) {
			char *p = strchr(argv[argi], '=');
			envarea = strdup(p+1);
		}
		else if (argnmatch(argv[argi], "--locator=")) {
			char *p = strchr(argv[argi], '=');
			locator_init(p+1);
			locatorbased = 1;
		}
		else if (argnmatch(argv[argi], "--service=")) {
			char *p = strchr(argv[argi], '=');
			locatorservice = get_servicetype(p+1);
		}
		else if (argnmatch(argv[argi], "--filter=")) {
			char *p = strchr(argv[argi], '=');
			msgfilter = compileregex(p+1);
			if (!msgfilter) {
				errprintf("Invalid filter (bad expression): %s\n", p+1);
			}
			else {
				stdfilter = compileregex("^@@(logrotate|shutdown|drophost|droptest|renamehost|renametest)");
			}
		}
		else {
			char *childcmd;
			char **childargs;
			int i = 0;

			childcmd = argv[argi];
			childargs = (char **) calloc((1 + argc - argi), sizeof(char *));
			while (argi < argc) { childargs[i++] = argv[argi++]; }
			addlocalpeer(childcmd, childargs);
		}
	}

	/* Sanity checks */
	if (cnid == -1) {
		errprintf("No channel/unknown channel specified\n");
		return 1;
	}
	if (locatorbased && (locatorservice == ST_MAX)) {
		errprintf("Must specify --service when using locator\n");
		return 1;
	}
	if (!locatorbased && (rbtBegin(peers) == rbtEnd(peers))) {
		errprintf("Must specify command for local worker\n");
		return 1;
	}

	/* Do cache responses to avoid doing too many lookups */
	if (locatorbased) locator_prepcache(locatorservice, 0);

	/* Go daemon */
	if (daemonize) {
		/* Become a daemon */
		pid_t daemonpid = fork();
		if (daemonpid < 0) {
			/* Fork failed */
			errprintf("Could not fork child\n");
			exit(1);
		}
		else if (daemonpid > 0) {
			/* Parent creates PID file and exits */
			FILE *fd = NULL;
			if (pidfile) fd = fopen(pidfile, "w");
			if (fd) {
				fprintf(fd, "%d\n", (int)daemonpid);
				fclose(fd);
			}
			exit(0);
		}
		/* Child (daemon) continues here */
		setsid();
	}

	/* Catch signals */
	setup_signalhandler("xymond_channel");
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sig_handler;
	sigaction(SIGINT, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
	sigaction(SIGCHLD, &sa, NULL);
	signal(SIGALRM, SIG_IGN);

	/* Switch stdout/stderr to the logfile, if one was specified */
	freopen("/dev/null", "r", stdin);	/* xymond_channel's stdin is not used */
	if (logfn) {
		freopen(logfn, "a", stdout);
		freopen(logfn, "a", stderr);
	}

	/* Attach to the channel */
	channel = setup_channel(cnid, CHAN_CLIENT);
	if (channel == NULL) {
		errprintf("Channel not available\n");
		running = 0;
	}

	while (running) {
		/* 
		 * Wait for GOCLIENT to go up.
		 *
		 * Note that we use IPC_NOWAIT if there are messages in the
		 * queue, because then we just want to pick up a message if
		 * there is one, and if not we want to continue pushing the
		 * queued data to the worker.
		 */
		struct sembuf s;
		int n;

		s.sem_num = GOCLIENT; s.sem_op  = -1; s.sem_flg = ((pendingcount > 0) ? IPC_NOWAIT : 0);
		n = semop(channel->semid, &s, 1);

		if (n == 0) {
			/*
			 * GOCLIENT went high, and so we got alerted about a new
			 * message arriving. Copy the message to our own buffer queue.
			 */
			char *inbuf = NULL;

			if (!msgfilter || matchregex(channel->channelbuf, msgfilter) || matchregex(channel->channelbuf, stdfilter)) {
				inbuf = strdup(channel->channelbuf);
			}

			/* 
			 * Now we have safely stored the new message in our buffer.
			 * Wait until any other clients on the same channel have picked up 
			 * this message (GOCLIENT reaches 0).
			 *
			 * We wrap this into an alarm handler, because it can occasionally
			 * fail, causing the whole system to lock up. We dont want that....
			 * We'll set the alarm to trigger after 1 second. Experience shows
			 * that we'll either succeed in a few milliseconds, or fail completely
			 * and wait the full alarm-timer duration.
			 */
			gotalarm = 0; signal(SIGALRM, sig_handler); alarm(2); 
			do {
				s.sem_num = GOCLIENT; s.sem_op  = 0; s.sem_flg = 0;
				n = semop(channel->semid, &s, 1);
			} while ((n == -1) && (errno == EAGAIN) && running && (!gotalarm));
			signal(SIGALRM, SIG_IGN);

			if (gotalarm) {
				errprintf("Gave up waiting for GOCLIENT to go low.\n");
			}

			/* 
			 * Let master know we got it by downing BOARDBUSY.
			 * This should not block, since BOARDBUSY is upped
			 * by the master just before he ups GOCLIENT.
			 */
			do {
				s.sem_num = BOARDBUSY; s.sem_op  = -1; s.sem_flg = IPC_NOWAIT;
				n = semop(channel->semid, &s, 1);
			} while ((n == -1) && (errno == EINTR));
			if (n == -1) {
				errprintf("Tried to down BOARDBUSY: %s\n", strerror(errno));
			}

			if (inbuf) {
				/*
				 * See if they want us to rotate logs. We pass this on to
				 * the worker module as well, but must handle our own logfile.
				 */
				if (strncmp(inbuf, "@@logrotate", 11) == 0) {
					freopen(logfn, "a", stdout);
					freopen(logfn, "a", stderr);
				}

				/*
				 * Put the new message on our outbound queue.
				 */
				if (addmessage(inbuf) != 0) {
					/* Failed to queue message, free the buffer */
					xfree(inbuf);
				}
			}
		}
		else {
			if (errno != EAGAIN) {
				dbgprintf("Semaphore wait aborted: %s\n", strerror(errno));
				continue;
			}
		}

		/* 
		 * We've picked up messages from the master. Now we 
		 * must push them to the worker process. Since there 
		 * is no way to hang off both a semaphore and select(),
		 * we'll just push as much data as possible into the 
		 * pipe. If we get to a point where we would block,
		 * then wait a teeny bit of time and restart the 
		 * whole loop with checking for new messages from the
		 * master etc.
		 *
		 * In theory, this could become an almost busy-wait loop.
		 * In practice, however, the queue will be empty most
		 * of the time because we'll just shove the data to the
		 * worker child.
		 */
		for (handle = rbtBegin(peers); (handle != rbtEnd(peers)); handle = rbtNext(peers, handle)) {
			int canwrite = 1, hasfailed = 0;
			xymon_peer_t *pwalk;
			time_t msgtimeout = gettimer() - MSGTIMEOUT;
			int flushcount = 0;

			pwalk = (xymon_peer_t *) gettreeitem(peers, handle);
			if (pwalk->msghead == NULL) continue; /* Ignore peers with nothing queued */

			switch (pwalk->peerstatus) {
			  case P_UP:
				canwrite = 1;
				break;

			  case P_DOWN:
				openconnection(pwalk);
				canwrite = (pwalk->peerstatus == P_UP);
				break;

			  case P_FAILED:
				canwrite = 0;
				break;
			}

			/* See if we have stale messages queued */
			while (pwalk->msghead && (pwalk->msghead->tstamp < msgtimeout)) {
				flushmessage(pwalk);
				flushcount++;
			}

			if (flushcount) {
				errprintf("Flushed %d stale messages for %s:%d\n",
					  flushcount,
				  	  inet_ntoa(pwalk->peeraddr.sin_addr), 
					  ntohs(pwalk->peeraddr.sin_port));
			}

			while (pwalk->msghead && canwrite) {
				fd_set fdwrite;
				struct timeval tmo;

				/* Check that this peer is ready for writing. */
				FD_ZERO(&fdwrite); FD_SET(pwalk->peersocket, &fdwrite);
				tmo.tv_sec = 0; tmo.tv_usec = 2000;
				n = select(pwalk->peersocket+1, NULL, &fdwrite, NULL, &tmo);
				if (n == -1) {
					errprintf("select() failed: %s\n", strerror(errno));
					canwrite = 0; 
					hasfailed = 1;
					continue;
				}
				else if ((n == 0) || (!FD_ISSET(pwalk->peersocket, &fdwrite))) {
					canwrite = 0;
					continue;
				}

				n = write(pwalk->peersocket, pwalk->msghead->bufp, pwalk->msghead->buflen);
				if (n >= 0) {
					pwalk->msghead->bufp += n;
					pwalk->msghead->buflen -= n;
					if (pwalk->msghead->buflen == 0) flushmessage(pwalk);
				}
				else if (errno == EAGAIN) {
					/*
					 * Write would block ... stop for now. 
					 */
					canwrite = 0;
				}
				else {
					hasfailed = 1;
				}

				if (hasfailed) {
					/* Write failed, or message grew stale */
					errprintf("Peer at %s:%d failed: %s\n",
						  inet_ntoa(pwalk->peeraddr.sin_addr), ntohs(pwalk->peeraddr.sin_port),
						  strerror(errno));
					canwrite = 0;
					shutdownconnection(pwalk);
					if (pwalk->peertype == P_NET) locator_serverdown(pwalk->peername, locatorservice);
					pwalk->peerstatus = P_FAILED;
				}
			}
		}
	}

	/* Detach from channels */
	close_channel(channel, CHAN_CLIENT);

	/* Close peer connections */
	for (handle = rbtBegin(peers); (handle != rbtEnd(peers)); handle = rbtNext(peers, handle)) {
		xymon_peer_t *pwalk = (xymon_peer_t *) gettreeitem(peers, handle);
		shutdownconnection(pwalk);
	}

	/* Remove the PID file */
	if (pidfile) unlink(pidfile);

	return 0;
}
Example #22
0
void print_hoststatus(FILE *output, hstatus_t *itm, RbtHandle columns, int prio, int firsthost)
{
	void *hinfo;
	char *dispname, *ip, *key;
	time_t now;
	RbtIterator colhandle;

	now = getcurrenttime(NULL);
	hinfo = hostinfo(itm->hostname);
	dispname = xmh_item(hinfo, XMH_DISPLAYNAME);
	ip = xmh_item(hinfo, XMH_IP);

	fprintf(output, "<TR>\n");

	/* Print the priority */
	fprintf(output, "<TD ALIGN=LEFT VALIGN=TOP WIDTH=25%% NOWRAP>");
	if (firsthost) 
		fprintf(output, "<FONT %s>PRIO %d</FONT>", xgetenv("XYMONPAGEROWFONT"), prio);
	else 
		fprintf(output, "&nbsp;");
	fprintf(output, "</TD>\n");

	/* Print the hostname with a link to the critical systems info page */
	fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", hostnamehtml(itm->hostname, NULL, usetooltips));

	key = (char *)malloc(strlen(itm->hostname) + 1024);
	for (colhandle = rbtBegin(columns); (colhandle != rbtEnd(columns)); colhandle = rbtNext(columns, colhandle)) {
		void *k1, *k2;
		char *colname;
		RbtIterator sthandle;

		fprintf(output, "<TD ALIGN=CENTER>");

		rbtKeyValue(columns, colhandle, &k1, &k2);
		colname = (char *)k1;
		sprintf(key, "%s|%s", itm->hostname, colname);
		sthandle = rbtFind(rbstate, key);
		if (sthandle == rbtEnd(rbstate)) {
			fprintf(output, "-");
		}
		else {
			hstatus_t *column;
			char *htmlalttag;
			char *htmlackstr;

			rbtKeyValue(rbstate, sthandle, &k1, &k2);
			column = (hstatus_t *)k2;
			if (column->config->priority != prio) 
				fprintf(output, "-");
			else {
				time_t age = now - column->lastchange;
				char *htmlgroupstr;
				char *htmlextrastr;

				htmlalttag = alttag(colname, column->color, 0, 1, agestring(age));
				htmlackstr = (column->ackmsg ? column->ackmsg : "");
				htmlgroupstr = strdup(urlencode(column->config->ttgroup ? column->config->ttgroup : ""));
				htmlextrastr = strdup(urlencode(column->config->ttextra ? column->config->ttextra : ""));
				fprintf(output, "<A HREF=\"%s&amp;NKPRIO=%d&amp;NKTTGROUP=%s&amp;NKTTEXTRA=%s\">",
					hostsvcurl(itm->hostname, colname, 1),
					prio, 
					htmlgroupstr, htmlextrastr);
				fprintf(output, "<IMG SRC=\"%s/%s\" ALT=\"%s\" TITLE=\"%s %s\" HEIGHT=\"%s\" WIDTH=\"%s\" BORDER=0></A>",
					xgetenv("XYMONSKIN"), 
					dotgiffilename(column->color, (column->acktime > 0), (age > oldlimit)),
					colorname(column->color), htmlalttag, htmlackstr,
					xgetenv("DOTHEIGHT"), xgetenv("DOTWIDTH"));
				xfree(htmlgroupstr);
				xfree(htmlextrastr);
			}
		}

		fprintf(output, "</TD>\n");
	}
	xfree(key);

	fprintf(output, "</TR>\n");
}
Example #23
0
int load_nkconfig(char *fn)
{
	static void *configfiles = NULL;
	static int firsttime = 1;
	FILE *fd;
	strbuffer_t *inbuf;

	/* Setup the default configuration filename */
	if (!fn) {
		if (!defaultfn) {
			char *bbhome = xgetenv("BBHOME");
			defaultfn = (char *)malloc(strlen(bbhome) + strlen(DEFAULTCONFIG) + 2);
			sprintf(defaultfn, "%s/%s", bbhome, DEFAULTCONFIG);
		}
		fn = defaultfn;
	}

	if (configfn) xfree(configfn);
	configfn = strdup(fn);

	/* First check if there were no modifications at all */
	if (configfiles) {
		if (!stackfmodified(configfiles)){
			dbgprintf("No files modified, skipping reload of %s\n", fn);
			return 0;
		}
		else {
			stackfclist(&configfiles);
			configfiles = NULL;
		}
	}

	if (!firsttime) {
		/* Clean up existing datatree */
		RbtHandle handle;
		void *k1, *k2;

		for (handle = rbtBegin(rbconf); (handle != rbtEnd(rbconf)); handle = rbtNext(rbconf, handle)) {
			rbtKeyValue(rbconf, handle, &k1, &k2);
			flushrec(k1, k2);
		}

		rbtDelete(rbconf);
	}

	firsttime = 0;
	rbconf = rbtNew(name_compare);

	fd = stackfopen(fn, "r", &configfiles);
	if (fd == NULL) return 1;

	inbuf = newstrbuffer(0);
	while (stackfgets(inbuf, NULL)) {
		/* Full record : Host  service  START  END  TIMESPEC  TTPrio TTGroup TTExtra */
		/* Clone record: Host  =HOST */
		char *ehost, *eservice, *estart, *eend, *etime, *ttgroup, *ttextra, *updinfo;
		int ttprio = 0;
		nkconf_t *newitem;
		RbtStatus status;
		int idx = 0;

		ehost = gettok(STRBUF(inbuf), "|\n"); if (!ehost) continue;
		eservice = gettok(NULL, "|\n"); if (!eservice) continue;

		if (*eservice == '=') {
			char *key = (char *)malloc(strlen(ehost) + 2);
			char *pointsto = strdup(eservice+1);

			sprintf(key, "%s=", ehost);
			status = rbtInsert(rbconf, key, pointsto);
		}
		else {
			estart = gettok(NULL, "|\n"); if (!estart) continue;
			eend = gettok(NULL, "|\n"); if (!eend) continue;
			etime = gettok(NULL, "|\n"); if (!etime) continue;
			ttprio = atoi(gettok(NULL, "|\n")); if (ttprio == 0) continue;
			ttgroup = gettok(NULL, "|\n");
			ttextra = gettok(NULL, "|\n");
			updinfo = gettok(NULL, "|\n");

			newitem = (nkconf_t *)malloc(sizeof(nkconf_t));
			newitem->key = (char *)malloc(strlen(ehost) + strlen(eservice) + 15);
			sprintf(newitem->key, "%s|%s", ehost, eservice);
			newitem->starttime= ((estart && *estart) ? atoi(estart) : 0);
			newitem->endtime  = ((eend && *eend) ? atoi(eend) : 0);
			newitem->nktime   = ((etime && *etime) ? strdup(etime) : NULL);
			newitem->priority = ttprio;
			newitem->ttgroup  = strdup(ttgroup);
			newitem->ttextra  = strdup(ttextra);
			newitem->updinfo  = strdup(updinfo);

			status = rbtInsert(rbconf, newitem->key, newitem);
			while (status == RBT_STATUS_DUPLICATE_KEY) {
				idx++;
				sprintf(newitem->key, "%s|%s|%d", ehost, eservice, idx);
				status = rbtInsert(rbconf, newitem->key, newitem);
			}
		}
	}

	stackfclose(fd);
	freestrbuffer(inbuf);

	if (debug) {
		RbtHandle handle;

		handle = rbtBegin(rbconf);
		while (handle != rbtEnd(rbconf)) {
			void *k1, *k2;
			rbtKeyValue(rbconf, handle, &k1, &k2);
			printf("%s\n", (char *)k1);
			handle = rbtNext(rbconf, handle);
		}
	}

	return 0;
}