/* * dnsutl - utilities to make DNS easier to configure * Copyright (C) 1991-1993, 1995, 1999, 2000, 2006, 2007 Peter Miller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include #include #include #include #include #include #include #include #include static char *huge_buffer; static void make_huge_buffer(void) { static int entry_count; if (huge_buffer) return; entry_count++; if (entry_count != 1) { static char small_buffer[100]; /* just enuf for "out of memory" message */ huge_buffer = small_buffer; } else { huge_buffer = malloc(100000L); if (!huge_buffer) fatal("can't alloc buffer for error messages"); } entry_count--; } /* * NAME * wrap - wrap s string over lines * * SYNOPSIS * void wrap(char *); * * DESCRIPTION * The wrap function is used to print error messages onto stderr * wrapping ling lines. * * CAVEATS * Line length is assumed to be 80 characters. */ #define PAGE_WIDTH 79 static void wrap(const char *s) { static char escapes[] = "\rr\nn\ff\bb\tt"; char tmp[PAGE_WIDTH + 2]; int first_line; char *tp; int bomb_later; /* * Flush stdout so that errors are in sync with the output. * If you get an error doing this, whinge about it _after_ reporting * the originating error. Also, clear the error on stdout to * avoid getting caught in an infinite loop. */ if (fflush(stdout) || ferror(stdout)) { bomb_later = errno; clearerr(stdout); } else bomb_later = 0; first_line = 1; while (*s) { const char *ep; int ocol; /* * Work out how many characters fit on the line. */ if (first_line) ocol = strlen(progname) + 2; else ocol = 8; for (ep = s; *ep; ++ep) { int cw; int c; c = (unsigned char)*ep; if (isprint(c)) cw = 1 + (c == '\\'); else cw = (strchr(escapes, c) ? 2 : 4); if (ocol + cw > PAGE_WIDTH) break; ocol += cw; } /* * see if there is a better place to break the line */ if (*ep && *ep != ' ') { const char *mp; for (mp = ep; mp > s; --mp) { if (strchr(" /", mp[-1])) { ep = mp; break; } } } /* * ignore trailing blanks */ while (ep > s && ep[-1] == ' ') ep--; /* * print the line */ if (first_line) sprintf(tmp, "%s: ", progname); else strcpy(tmp, " "); tp = tmp + strlen(tmp); while (s < ep) { int c; c = (unsigned char)*s++; if (isprint(c)) { if (c == '\\') *tp++ = '\\'; *tp++ = c; } else { char *esc; esc = strchr(escapes, c); if (esc) { *tp++ = '\\'; *tp++ = esc[1]; } else { sprintf(tp, "\\%3.3o", c); tp += strlen(tp); } } } *tp++ = '\n'; *tp = 0; fputs(tmp, stderr); if (ferror(stderr)) break; /* * skip leading spaces for subsequent lines */ while (*s == ' ') s++; first_line = 0; } if (fflush(stderr) || ferror(stderr)) { /* don't print why, there is no point! */ exit(1); } if (bomb_later) { errno = bomb_later; nfatal("(stdout)"); } } /* * NAME * error - place a message on the error stream * * SYNOPSIS * void error(char *s, ...); * * DESCRIPTION * Error places a message on the error output stream. * The first argument is a printf-like format string, * optionally followed by other arguments. * The message will be prefixed by the program name and a colon, * and will be terminated with a newline, automatically. * * CAVEAT * Things like "error(filename)" blow up if the filename * contains a '%' character. */ void error(const char *s, ...) { va_list ap; va_start(ap, s); make_huge_buffer(); vsprintf(huge_buffer, s, ap); va_end(ap); wrap(huge_buffer); } /* * NAME * nerror - place a system fault message on the error stream * * SYNOPSIS * void nerror(char *s, ...); * * DESCRIPTION * Nerror places a message on the error output stream. * The first argument is a printf-like format string, * optionally followed by other arguments. * The message will be prefixed by the program name and a colon, * and will be terminated with a text description of the error * indicated by the 'errno' global variable, automatically. * * CAVEAT * Things like "nerror(filename)" blow up if the filename * contains a '%' character. */ void nerror(const char *s, ...) { va_list ap; int n; va_start(ap, s); n = errno; make_huge_buffer(); vsprintf(huge_buffer, s, ap); va_end(ap); strcat(huge_buffer, ": "); strcat(huge_buffer, strerror(n)); wrap(huge_buffer); } /* * NAME * nfatal - place a system fault message on the error stream and exit * * SYNOPSIS * void nfatal(char *s, ...); * * DESCRIPTION * Nfatal places a message on the error output stream and exits. * The first argument is a printf-like format string, * optionally followed by other arguments. * The message will be prefixed by the program name and a colon, * and will be terminated with a text description of the error * indicated by the 'errno' global variable, automatically. * * CAVEAT * Things like "nfatal(filename)" blow up if the filename * contains a '%' character. * * This function does NOT return. */ void nfatal(const char *s, ...) { va_list ap; int n; va_start(ap, s); n = errno; make_huge_buffer(); vsprintf(huge_buffer, s, ap); va_end(ap); strcat(huge_buffer, ": "); strcat(huge_buffer, strerror(n)); wrap(huge_buffer); exit(1); } /* * NAME * fatal - place a message on the error stream and exit * * SYNOPSIS * void fatal(char *s, ...); * * DESCRIPTION * Fatal places a message on the error output stream and exits. * The first argument is a printf-like format string, * optionally followed by other arguments. * The message will be prefixed by the program name and a colon, * and will be terminated with a newline, automatically. * * CAVEAT * Things like "error(filename)" blow up if the filename * contains a '%' character. * * This function does NOT return. */ void fatal(const char *s, ...) { va_list ap; va_start(ap, s); make_huge_buffer(); vsprintf(huge_buffer, s, ap); va_end(ap); wrap(huge_buffer); exit(1); } /* * NAME * assert - make an assertion * * SYNOPSIS * void assert(int condition); * * DESCRIPTION * Assert is a handy tool for a programmer to guarantee the internal * consistency of their program. If "-DDEBUG" is specified on * the compiler's command line, then assert will generate code to verify * the assertios made. If no DEBUG is defined, assertions will generate * no code. * * CAVEAT * If the assertion fails, a fatal diagnostic is issued. * * The #define's which control the compilation may be found in "error.h". * */ void cook_assert(int c, const char *s, const char *file, int line) { if (c) return; error("%s: %d: assertion \"%s\" failed (bug)", file, line, s); abort(); }