static int statuscolor_by_set(testedhost_t *h, long status, char *okcodes, char *badcodes) { int result = -1; char codestr[10]; pcre *ptn; /* Use code 999 to indicate we could not fetch the URL */ sprintf(codestr, "%ld", (status ? status : 999)); if (okcodes) { ptn = compileregex(okcodes); if (matchregex(codestr, ptn)) result = COL_GREEN; else result = COL_RED; freeregex(ptn); } if (badcodes) { ptn = compileregex(badcodes); if (matchregex(codestr, ptn)) result = COL_RED; else result = COL_GREEN; freeregex(ptn); } if (result == -1) result = statuscolor(h, status); dbgprintf("Host %s status %s [%s:%s] -> color %s\n", h->hostname, codestr, (okcodes ? okcodes : "<null>"), (badcodes ? badcodes : "<null>"), colorname(result)); return result; }
int main(int argc, char *argv[]) { int argi; char *envarea = NULL; int obeycookies = 1; char *accessfn = NULL; for (argi = 1; (argi < argc); argi++) { 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 (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else if (strcmp(argv[argi], "--no-pin") == 0) { nopin = 1; } else if (strcmp(argv[argi], "--no-cookies") == 0) { obeycookies = 0; } else if (argnmatch(argv[argi], "--access=")) { char *p = strchr(argv[argi], '='); accessfn = strdup(p+1); } } redirect_cgilog("ack"); cgidata = cgi_request(); if ( (nopin && (cgi_method == CGI_GET)) || (!nopin && (cgidata == NULL)) ) { /* Present the query form */ sethostenv("", "", "", colorname(COL_RED), NULL); printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); if (!nopin) { showform(stdout, "acknowledge", "acknowledge_form", COL_RED, getcurrenttime(NULL), NULL, NULL); } else { char *cmd; char *respbuf = NULL; char *hostname, *pagename; int gotfilter = 0, filtererror = 0; sendreturn_t *sres = NULL; int col, firstcolor = 1, alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE))); headfoot(stdout, "acknowledge", "", "header", COL_RED); cmd = (char *)malloc(1024); strcpy(cmd, "xymondboard fields=hostname,testname,cookie color="); for (col = 0; (col < COL_COUNT); col++) { if ((1 << col) & alertcolors) { if (!firstcolor) strcat(cmd, ","); strcat(cmd, colorname(col)); firstcolor = 0; } } // printf("<!-- cmd = %s -->\n", cmd); if (obeycookies && !gotfilter && ((hostname = get_cookie("host")) != NULL)) { if (*hostname) { pcre *dummy; char *re; re = (char *)malloc(3+strlen(hostname)); sprintf(re, "^%s$", hostname); dummy = compileregex(re); if (dummy) { /* Valid expression */ freeregex(dummy); cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); sprintf(cmd + strlen(cmd), " host=%s", re); gotfilter = 1; } else { filtererror = 1; printf("<p align=\"center\">Invalid hostname filter</p>\n"); } } } if (obeycookies && !gotfilter && ((pagename = get_cookie("pagepath")) != NULL)) { if (*pagename) { pcre *dummy; char *re; re = (char *)malloc(8 + strlen(pagename)*2); sprintf(re, "%s$|^%s/.+", pagename, pagename); dummy = compileregex(re); if (dummy) { /* Valid expression */ freeregex(dummy); cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); sprintf(cmd + strlen(cmd), " page=%s", re); gotfilter = 1; } else { filtererror = 1; printf("<p align=\"center\">Invalid pagename filter</p>\n"); } } } sres = newsendreturnbuf(1, NULL); if (!filtererror && (sendmessage(cmd, NULL, XYMON_TIMEOUT, sres) == XYMONSEND_OK)) { char *bol, *eoln; int first = 1; respbuf = getsendreturnstr(sres, 1); bol = respbuf; while (bol) { char *hname, *tname, *ackcode; eoln = strchr(bol, '\n'); if (eoln) *eoln = '\0'; hname = tname = ackcode = NULL; hname = strtok(bol, "|"); if (hname) tname = strtok(NULL, "|"); if (tname) ackcode = strtok(NULL, "|"); if (hname && tname && ackcode && (strcmp(hname, "summary") != 0)) { if (first) { fprintf(stdout, "<form method=\"POST\" ACTION=\"%s\">\n", getenv("SCRIPT_NAME")); fprintf(stdout, "<center><table cellpadding=5 summary=\"Ack data\">\n"); fprintf(stdout, "<tr><th align=left>Host</th><th align=left>Test</th><th align=left>Duration</th><th align=left>Cause</th><th>Ack</th><th>Ack Multiple</tr>\n"); first = 0; } generate_ackline(stdout, hname, tname, ackcode); } if (eoln) bol = eoln+1; else bol = NULL; } if (first) { fprintf(stdout, "<center><font size=\"+1\"><b>No active alerts</b></font></center>\n"); } else { generate_ackline(stdout, NULL, NULL, NULL); fprintf(stdout, "</table></center>\n"); fprintf(stdout, "</form>\n"); } } freesendreturnbuf(sres); headfoot(stdout, "acknowledge", "", "footer", COL_RED); } } else if ( (nopin && (cgi_method == CGI_POST)) || (!nopin && (cgidata != NULL)) ) { char *xymonmsg; char *acking_user = ""; acklist_t *awalk; strbuffer_t *response = newstrbuffer(0); int count = 0; /* We only want to accept posts from certain pages */ { char cgisource[1024]; char *p; p = csp_header("acknowledge"); if (p) fprintf(stdout, "%s", p); snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "acknowledge"); if (!cgi_refererok(cgisource)) { fprintf(stdout, "Location: %s.sh?\n\n", cgisource); return 0; } } parse_query(); if (getenv("REMOTE_USER")) { char *remaddr = getenv("REMOTE_ADDR"); acking_user = (char *)malloc(1024 + strlen(getenv("REMOTE_USER")) + (remaddr ? strlen(remaddr) : 0)); sprintf(acking_user, "\nAcked by: %s", getenv("REMOTE_USER")); if (remaddr) sprintf(acking_user + strlen(acking_user), " (%s)", remaddr); } /* Load the host data (for access control) */ if (accessfn) { load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn()); load_web_access_config(accessfn); } addtobuffer(response, "<center>\n"); for (awalk = ackhead; (awalk); awalk = awalk->next) { char *msgline = (char *)malloc(1024 + (awalk->hostname ? strlen(awalk->hostname) : 0) + (awalk->testname ? strlen(awalk->testname) : 0)); if (!awalk->checked) continue; if (accessfn && (!web_access_allowed(getenv("REMOTE_USER"), awalk->hostname, awalk->testname, WEB_ACCESS_CONTROL))) continue; if ((reqtype == ACK_ONE) && (awalk->id != sendnum)) continue; if (reqtype == ACK_MANY) { if (!awalk->ackmsg) awalk->ackmsg = ackmsgall; if (!awalk->validity && validityall) awalk->validity = durationvalue(validityall); if (periodall) awalk->period = periodall; } if (strncmp(awalk->period, "hour", 4) == 0) awalk->validity *= 60; else if (strncmp(awalk->period, "day", 4) == 0) awalk->validity *= 60*24; count++; if (!awalk->ackmsg || !awalk->validity || !awalk->acknum) { if (awalk->hostname && awalk->testname) { sprintf(msgline, "<b>NO ACK</b> sent for host %s / test %s", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "<b>NO ACK</b> sent for item %d", awalk->id); } addtobuffer(response, msgline); addtobuffer(response, ": Duration or message not set<br>\n"); continue; } xymonmsg = (char *)malloc(1024 + strlen(awalk->ackmsg) + strlen(acking_user)); sprintf(xymonmsg, "xymondack %d %d %s %s", awalk->acknum, awalk->validity, awalk->ackmsg, acking_user); if (sendmessage(xymonmsg, NULL, XYMON_TIMEOUT, NULL) == XYMONSEND_OK) { if (awalk->hostname && awalk->testname) { sprintf(msgline, "Acknowledge sent for host %s / test %s<br>\n", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "Acknowledge sent for code %d<br>\n", awalk->acknum); } } else { if (awalk->hostname && awalk->testname) { sprintf(msgline, "Failed to send acknowledge for host %s / test %s<br>\n", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "Failed to send acknowledge for code %d<br>\n", awalk->acknum); } } addtobuffer(response, msgline); xfree(xymonmsg); } if (count == 0) addtobuffer(response, "<b>No acks requested</b>\n"); addtobuffer(response, "</center>\n"); fprintf(stdout, "Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); headfoot(stdout, "acknowledge", "", "header", COL_RED); fprintf(stdout, "%s", STRBUF(response)); headfoot(stdout, "acknowledge", "", "footer", COL_RED); } return 0; }
int main(int argc, char *argv[]) { char *envarea = NULL; char *server = NULL; char *cookie, *pagefilter = ""; char *filter = NULL; char *heading = NULL; int showcolors = 1; int showcolumn = 0; int addlink = 0; int allhosts = 0; int summary = 0; int embedded = 0; char *req, *board, *l; int argi, res; sendreturn_t *sres; init_timestamp(); for (argi=1; (argi < argc); argi++) { 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 (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else if ( argnmatch(argv[argi], "--column=") || argnmatch(argv[argi], "--test=")) { char *p = strchr(argv[argi], '='); int needed; needed = 10 + strlen(p); if (filter) needed += strlen(filter); filter = (char *)(filter ? realloc(filter, needed) : calloc(1, needed)); sprintf(filter + strlen(filter), " test=%s", p+1); if (!heading) { heading = (char *)malloc(1024 + strlen(p) + strlen(timestamp)); sprintf(heading, "%s report on %s", p+1, timestamp); } } else if (argnmatch(argv[argi], "--filter=")) { char *p = strchr(argv[argi], '='); int needed; needed = 10 + strlen(p); if (filter) needed += strlen(filter); filter = (char *)(filter ? realloc(filter, needed) : calloc(1, needed)); sprintf(filter + strlen(filter), " %s", p+1); } else if (argnmatch(argv[argi], "--heading=")) { char *p = strchr(argv[argi], '='); heading = strdup(p+1); } else if (strcmp(argv[argi], "--show-column") == 0) { showcolumn = 1; } else if (strcmp(argv[argi], "--show-test") == 0) { showcolumn = 1; } else if (strcmp(argv[argi], "--show-colors") == 0) { showcolors = 1; } else if (strcmp(argv[argi], "--show-summary") == 0) { summary = 1; } else if (strcmp(argv[argi], "--show-message") == 0) { summary = 0; } else if (strcmp(argv[argi], "--link") == 0) { addlink = 1; } else if (strcmp(argv[argi], "--no-colors") == 0) { showcolors = 0; } else if (strcmp(argv[argi], "--all") == 0) { allhosts = 1; } else if (strcmp(argv[argi], "--embedded") == 0) { embedded = 1; } } if (!allhosts) { /* Setup the filter we use for the report */ cookie = get_cookie("pagepath"); if (cookie && *cookie) { pcre *dummy; char *re = (char *)malloc(8 + 2*strlen(cookie)); sprintf(re, "^%s$|^%s/.+", cookie, cookie); dummy = compileregex(re); if (dummy) { freeregex(dummy); pagefilter = malloc(10 + strlen(re)); sprintf(pagefilter, "page=%s", re); } } } sres = newsendreturnbuf(1, NULL); req = malloc(1024 + strlen(pagefilter) + strlen(filter)); sprintf(req, "xymondboard fields=hostname,testname,color,msg %s %s", pagefilter, filter); res = sendmessage(req, server, XYMON_TIMEOUT, sres); board = getsendreturnstr(sres, 1); freesendreturnbuf(sres); if (res != XYMONSEND_OK) return 1; if (!embedded) { printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); printf("<html><head><title>%s</title></head>\n", htmlquoted(heading)); printf("<body>"); printf("<table border=1 cellpadding=5><tr><th>%s</th><th align=left>Status</th></tr>\n", (showcolumn ? "Host/Column" : "Host")); } l = board; while (l && *l) { char *hostname, *testname = NULL, *colorstr = NULL, *msg = NULL, *p; char *eoln = strchr(l, '\n'); if (eoln) *eoln = '\0'; hostname = l; p = strchr(l, '|'); if (p) { *p = '\0'; l = testname = p+1; } p = strchr(l, '|'); if (p) { *p = '\0'; l = colorstr = p+1; } p = strchr(l, '|'); if (p) { *p = '\0'; l = msg = p+1; } if (hostname && testname && colorstr && msg) { char *msgeol; nldecode(msg); msgeol = strchr(msg, '\n'); if (msgeol) { /* Skip the first status line */ msg = msgeol + 1; } printf("<tr><td align=left valign=top><b>"); if (addlink) printf("<a href=\"%s\">%s</a>", hostsvcurl(hostname, xgetenv("INFOCOLUMN"), 1), htmlquoted(hostname)); else printf("%s", htmlquoted(hostname)); if (showcolumn) { printf("<br>"); if (addlink) printf("<a href=\"%s\">%s</a>", hostsvcurl(hostname, testname, 1), htmlquoted(testname)); else printf("%s", htmlquoted(testname)); } if (showcolors) printf(" - %s", colorstr); printf("</b></td>\n"); printf("<td><pre>\n"); if (summary) { int firstline = 1; char *bol, *eol; bol = msg; while (bol) { eol = strchr(bol, '\n'); if (eol) *eol = '\0'; if (firstline) { if (!isspace((int)*bol)) { printf("%s\n", bol); firstline = 0; } } else if ((*bol == '&') && (strncmp(bol, "&green", 6) != 0)) { printf("%s\n", bol); } bol = (eol ? eol+1 : NULL); } } else { printf("%s", msg); } printf("</pre></td></tr>\n"); } if (eoln) l = eoln+1; else l = NULL; } if (!embedded) printf("</table></body></html>\n"); return 0; }
int do_ifstat_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *msg, time_t tstamp) { static int pcres_compiled = 0; static pcre **ifstat_linux_pcres = NULL; static pcre **ifstat_freebsd_pcres = NULL; static pcre **ifstat_freebsdV8_pcres = NULL; static pcre **ifstat_openbsd_pcres = NULL; static pcre **ifstat_netbsd_pcres = NULL; static pcre **ifstat_darwin_pcres = NULL; static pcre **ifstat_solaris_pcres = NULL; static pcre **ifstat_aix_pcres = NULL; static pcre **ifstat_hpux_pcres = NULL; static pcre **ifstat_sco_sv_pcres = NULL; static pcre **ifstat_bbwin_pcres = NULL; enum ostype_t ostype; char *datapart = msg; char *bol, *eoln, *ifname, *rxstr, *txstr, *dummy; int dmatch; void *xmh; pcre *ifname_filter_pcre = NULL; xmh = hostinfo(hostname); if (xmh) { char *ifname_filter_expr = xmh_item(xmh, XMH_INTERFACES); if (ifname_filter_expr && *ifname_filter_expr) ifname_filter_pcre = compileregex(ifname_filter_expr); } if (pcres_compiled == 0) { pcres_compiled = 1; ifstat_linux_pcres = compile_exprs("LINUX", ifstat_linux_exprs, (sizeof(ifstat_linux_exprs) / sizeof(ifstat_linux_exprs[0]))); ifstat_freebsd_pcres = compile_exprs("FREEBSD", ifstat_freebsd_exprs, (sizeof(ifstat_freebsd_exprs) / sizeof(ifstat_freebsd_exprs[0]))); ifstat_freebsdV8_pcres = compile_exprs("FREEBSD", ifstat_freebsdV8_exprs, (sizeof(ifstat_freebsdV8_exprs) / sizeof(ifstat_freebsdV8_exprs[0]))); ifstat_openbsd_pcres = compile_exprs("OPENBSD", ifstat_openbsd_exprs, (sizeof(ifstat_openbsd_exprs) / sizeof(ifstat_openbsd_exprs[0]))); ifstat_netbsd_pcres = compile_exprs("NETBSD", ifstat_netbsd_exprs, (sizeof(ifstat_netbsd_exprs) / sizeof(ifstat_netbsd_exprs[0]))); ifstat_darwin_pcres = compile_exprs("DARWIN", ifstat_darwin_exprs, (sizeof(ifstat_darwin_exprs) / sizeof(ifstat_darwin_exprs[0]))); ifstat_solaris_pcres = compile_exprs("SOLARIS", ifstat_solaris_exprs, (sizeof(ifstat_solaris_exprs) / sizeof(ifstat_solaris_exprs[0]))); ifstat_aix_pcres = compile_exprs("AIX", ifstat_aix_exprs, (sizeof(ifstat_aix_exprs) / sizeof(ifstat_aix_exprs[0]))); ifstat_hpux_pcres = compile_exprs("HPUX", ifstat_hpux_exprs, (sizeof(ifstat_hpux_exprs) / sizeof(ifstat_hpux_exprs[0]))); ifstat_sco_sv_pcres = compile_exprs("SCO_SV", ifstat_sco_sv_exprs, (sizeof(ifstat_sco_sv_exprs) / sizeof(ifstat_sco_sv_exprs[0]))); ifstat_bbwin_pcres = compile_exprs("BBWIN", ifstat_bbwin_exprs, (sizeof(ifstat_bbwin_exprs) / sizeof(ifstat_bbwin_exprs[0]))); } if (ifstat_tpl == NULL) ifstat_tpl = setup_template(ifstat_params); if ((strncmp(msg, "status", 6) == 0) || (strncmp(msg, "data", 4) == 0)) { /* Skip the first line of full status- and data-messages. */ datapart = strchr(msg, '\n'); if (datapart) datapart++; else datapart = msg; } ostype = get_ostype(datapart); datapart = strchr(datapart, '\n'); if (datapart) { datapart++; } else { errprintf("Too few lines in ifstat report from %s\n", hostname); return -1; } dmatch = 0; ifname = rxstr = txstr = dummy = NULL; bol = datapart; while (bol) { eoln = strchr(bol, '\n'); if (eoln) *eoln = '\0'; switch (ostype) { case OS_LINUX22: case OS_LINUX: case OS_RHEL3: case OS_ZVM: case OS_ZVSE: case OS_ZOS: if (pickdata(bol, ifstat_linux_pcres[0], 1, &ifname)) { /* * Linux' netif aliases mess up things. * Clear everything when we see an interface name. * But we dont want to track the "lo" interface. */ /* Strip off the last character if it is a colon (:) */ if (ifname[strlen(ifname)-1] == ':') ifname[strlen(ifname)-1] = '\0'; if (strcmp(ifname, "lo") == 0) { xfree(ifname); ifname = NULL; } else { dmatch = 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } } else if (pickdata(bol, ifstat_linux_pcres[1], 1, &rxstr, &txstr)) dmatch |= 6; else if (pickdata(bol, ifstat_linux_pcres[2], 1, &rxstr)) dmatch |= 2; else if (pickdata(bol, ifstat_linux_pcres[3], 1, &txstr)) dmatch |= 4; break; case OS_FREEBSD: /* * FreeBSD 8 added an "Idrop" counter in the middle of the data. * See if we match this expression, and if not then fall back to * the old regex without that field. */ if (pickdata(bol, ifstat_freebsdV8_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; else if (pickdata(bol, ifstat_freebsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_OPENBSD: if (pickdata(bol, ifstat_openbsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_NETBSD: if (pickdata(bol, ifstat_netbsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_SOLARIS: if (pickdata(bol, ifstat_solaris_pcres[0], 0, &ifname, &txstr)) dmatch |= 1; else if (pickdata(bol, ifstat_solaris_pcres[1], 0, &dummy, &rxstr)) dmatch |= 6; if (ifname && dummy && (strcmp(ifname, dummy) != 0)) { /* They must match, drop the data */ errprintf("Host %s has weird ifstat data - device name mismatch %s:%s\n", hostname, ifname, dummy); xfree(ifname); xfree(txstr); xfree(rxstr); xfree(dummy); dmatch = 0; } /* Ignore "mac" and "wrsmd" entries - these are for sub-devices for multiple nic's aggregated into one */ /* See http://www.xymon.com/archive/2009/06/msg00204.html for more info */ if (ifname && ((strcmp(ifname, "mac") == 0) || (strcmp(ifname, "wrsmd") == 0)) ) { xfree(ifname); xfree(txstr); dmatch = 0; } if (dummy && ((strcmp(dummy, "mac") == 0) || (strcmp(dummy, "wrsmd") == 0)) ) { xfree(dummy); xfree(rxstr); dmatch = 0; } break; case OS_AIX: if (pickdata(bol, ifstat_aix_pcres[0], 1, &ifname)) { /* Interface names comes first, so any rx/tx data is discarded */ dmatch |= 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } else if (pickdata(bol, ifstat_aix_pcres[1], 1, &txstr, &rxstr)) dmatch |= 6; break; case OS_HPUX: if (pickdata(bol, ifstat_hpux_pcres[0], 1, &ifname)) { /* Interface names comes first, so any rx/tx data is discarded */ dmatch |= 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } else if (pickdata(bol, ifstat_hpux_pcres[1], 1, &rxstr)) dmatch |= 2; else if (pickdata(bol, ifstat_hpux_pcres[2], 1, &txstr)) dmatch |= 4; break; case OS_DARWIN: if (pickdata(bol, ifstat_darwin_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_SCO_SV: if (pickdata(bol, ifstat_sco_sv_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_WIN32_BBWIN: if (pickdata(bol, ifstat_bbwin_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; default: break; } if ((dmatch == 7) && ifname && rxstr && txstr) { if (!ifname_filter_pcre || matchregex(ifname, ifname_filter_pcre)) { setupfn2("%s.%s.rrd", "ifstat", ifname); snprintf(rrdvalues, sizeof(rrdvalues), "%d:%s:%s", (int)tstamp, txstr, rxstr); create_and_update_rrd(hostname, testname, classname, pagepaths, ifstat_params, ifstat_tpl); } xfree(ifname); xfree(rxstr); xfree(txstr); if (dummy) xfree(dummy); ifname = rxstr = txstr = dummy = NULL; dmatch = 0; } if (eoln) { *eoln = '\n'; bol = eoln+1; if (*bol == '\0') bol = NULL; } else { bol = NULL; } } if (ifname_filter_pcre) freeregex(ifname_filter_pcre); if (ifname) xfree(ifname); if (rxstr) xfree(rxstr); if (txstr) xfree(txstr); if (dummy) xfree(dummy); return 0; }