diff options
| author | William Hubbs <w.d.hubbs@gmail.com> | 2013-09-22 20:23:56 -0500 | 
|---|---|---|
| committer | William Hubbs <w.d.hubbs@gmail.com> | 2013-09-26 22:18:21 -0500 | 
| commit | de88aff0a839844526ae262f8961ec4372fed238 (patch) | |
| tree | 74c98ab41e7a03456d3c2a52c8cfb2fe3d39b915 /src/rc | |
| parent | 9e989227ab51cd880405958a0b11c63fa461ea7e (diff) | |
| download | openrc-de88aff0a839844526ae262f8961ec4372fed238.tar.xz | |
Make einfo routines private
The libeinfo library has no consumers other than OpenRC, so there is no
reason for it to be maintained as a library. The einfo routines are now
an object that links with the rc binary.
Diffstat (limited to 'src/rc')
| -rw-r--r-- | src/rc/Makefile | 27 | ||||
| -rw-r--r-- | src/rc/einfo.c | 1016 | ||||
| -rw-r--r-- | src/rc/einfo.h | 130 | 
3 files changed, 1166 insertions, 7 deletions
| diff --git a/src/rc/Makefile b/src/rc/Makefile index a2e638e8..6490826e 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -1,8 +1,21 @@  PROG=		rc -SRCS=		checkpath.c fstabinfo.c mountinfo.c start-stop-daemon.c \ -		rc-applets.c rc-depend.c rc-logger.c \ -		rc-misc.c rc-plugin.c rc-service.c rc-status.c rc-update.c \ -		runscript.c rc.c swclock.c +SRCS=	\ +	checkpath.c \ +	einfo.c \ +	fstabinfo.c \ +	mountinfo.c \ +	rc-applets.c \ +	rc-depend.c \ +	rc-logger.c \ +	rc-misc.c \ +	rc-plugin.c \ +	rc-service.c \ +	rc-status.c \ +	rc-update.c \ +	rc.c \ +	runscript.c \ +	start-stop-daemon.c \ +	swclock.c  CLEANFILES=	version.h @@ -30,9 +43,9 @@ RC_SBINLINKS=	mark_service_starting mark_service_started \  ALL_LINKS=	${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS}  CLEANFILES+=	${ALL_LINKS} -CPPFLAGS+=	-I../includes -I../librc -I../libeinfo -LDFLAGS+=	-L../librc -L../libeinfo -LDADD+=		-lutil -lrc -leinfo +CPPFLAGS+=	-I../includes -I../librc +LDFLAGS+=	-L../librc +LDADD+=		-lutil -lrc  include ../../Makefile.inc  MK=		../../mk diff --git a/src/rc/einfo.c b/src/rc/einfo.c new file mode 100644 index 00000000..306e7885 --- /dev/null +++ b/src/rc/einfo.c @@ -0,0 +1,1016 @@ +/* +  einfo.c +  Informational functions +*/ + +/* + * Copyright (c) 2007-2008 Roy Marples <roy@marples.name> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#ifdef HAVE_TERMCAP +# include <termcap.h> +#endif +#include <unistd.h> + +#include "einfo.h" +#include "helpers.h" + +/* Incase we cannot work out how many columns from ioctl, supply a default */ +#define DEFAULT_COLS		 80 + +#define OK			"ok" +#define NOT_OK			"!!" + +/* Number of spaces for an indent */ +#define INDENT_WIDTH		2 + +/* How wide can the indent go? */ +#define INDENT_MAX		40 + +/* Default colours */ +#define GOOD                    2 +#define WARN                    3 +#define BAD                     1 +#define HILITE                  6 +#define BRACKET                 4 + +/* We fallback to these escape codes if termcap isn't available + * like say /usr isn't mounted */ +#define AF "\033[3%dm" +#define CE "\033[K" +#define CH "\033[%dC" +#define MD "\033[1m" +#define ME "\033[m" +#define UP "\033[A" + +#define _GET_CAP(_d, _c) strlcpy(_d, tgoto(_c, 0, 0), sizeof(_d)); +#define _ASSIGN_CAP(_v) do {						      \ +		_v = p;							      \ +		p += strlcpy(p, tmp, sizeof(ebuffer) - (p - ebuffer)) + 1;    \ +	} while (0) + +/* A pointer to a string to prefix to einfo/ewarn/eerror messages */ +static const char *_eprefix = NULL; + +/* Buffers and structures to hold the final colours */ +static char ebuffer[100]; +struct ecolor { +	ECOLOR color; +	int def; +	const char *name; +}; +static char nullstr = '\0'; + +static const struct ecolor ecolors[] = { +	{ ECOLOR_GOOD,    GOOD,    "good"    }, +	{ ECOLOR_WARN,    WARN,    "warn"    }, +	{ ECOLOR_BAD,     BAD,     "bad"     }, +	{ ECOLOR_HILITE,  HILITE,  "hilite"  }, +	{ ECOLOR_BRACKET, BRACKET, "bracket" }, +	{ ECOLOR_NORMAL,  0,       NULL      }, +}; +static const char *ecolors_str[ARRAY_SIZE(ecolors)]; + +static char *flush = NULL; +static char *up = NULL; +static char *goto_column = NULL; + +static const char *term = NULL; +static bool term_is_cons25 = false; + +/* Termcap buffers and pointers + * Static buffers suck hard, but some termcap implementations require them */ +#ifdef HAVE_TERMCAP +static char termcapbuf[2048]; +static char tcapbuf[512]; +#else +/* No curses support, so we hardcode a list of colour capable terms + * Only terminals without "color" in the name need to be explicitly listed */ +static const char *const color_terms[] = { +	"Eterm", +	"ansi", +	"con132x25", +	"con132x30", +	"con132x43", +	"con132x60", +	"con80x25", +	"con80x28", +	"con80x30", +	"con80x43", +	"con80x50", +	"con80x60", +	"cons25", +	"console", +	"cygwin", +	"dtterm", +	"gnome", +	"konsole", +	"kterm", +	"linux", +	"linux-c", +	"mlterm", +	"putty", +	"rxvt", +	"rxvt-cygwin", +	"rxvt-cygwin-native", +	"rxvt-unicode", +	"screen", +	"screen-bce", +	"screen-w", +	"screen.linux", +	"vt100", +	"vt220", +	"wsvt25", +	"xterm", +	"xterm-debian", +	NULL +}; +#endif + +/* strlcat and strlcpy are nice, shame glibc does not define them */ +#ifdef __GLIBC__ +#  if ! defined (__UCLIBC__) && ! defined (__dietlibc__) +static size_t +strlcat(char *dst, const char *src, size_t size) +{ +	char *d = dst; +	const char *s = src; +	size_t src_n = size; +	size_t dst_n; + +	while (src_n-- != 0 && *d != '\0') +		d++; +	dst_n = d - dst; +	src_n = size - dst_n; + +	if (src_n == 0) +		return dst_n + strlen(src); + +	while (*s != '\0') { +		if (src_n != 1) { +			*d++ = *s; +			src_n--; +		} +		s++; +	} +	*d = '\0'; + +	return dst_n + (s - src); +} +#  endif +#endif + +static bool +yesno(const char *value) +{ +	if (!value) { +		errno = ENOENT; +		return false; +	} + +	if (strcasecmp(value, "yes") == 0 || +	    strcasecmp(value, "y") == 0 || +	    strcasecmp(value, "true") == 0 || +	    strcasecmp(value, "on") == 0 || +	    strcasecmp(value, "1") == 0) +		return true; + +	if (strcasecmp(value, "no") != 0 && +	    strcasecmp(value, "n") != 0 && +	    strcasecmp(value, "false") != 0 && +	    strcasecmp(value, "off") != 0 && +	    strcasecmp(value, "0") != 0) +		errno = EINVAL; + +	return false; +} + +static bool +noyes(const char *value) +{ +	int serrno = errno; +	bool retval; + +	errno = 0; +	retval = yesno(value); +	if (errno == 0) { +		retval = !retval; +		errno = serrno; +	} + +	return retval; +} + +static bool +is_quiet(void) +{ +	return yesno(getenv("EINFO_QUIET")); +} + +static bool +is_really_quiet(void) +{ +	return yesno(getenv("EERROR_QUIET")); +} + +static bool +is_verbose(void) +{ +	return yesno(getenv ("EINFO_VERBOSE")); +} + +/* Fake tgoto call - very crapy, but works for our needs */ +#ifndef HAVE_TERMCAP +static char * +tgoto(const char *cap, int col, int line) +{ +	static char buf[20]; +	char *p, *e, c, dbuf[6]; +	int oncol = 0, which = line, i; + +	p = buf; +	e = p + sizeof(buf); +	while ((c = *cap++)) { +		if (c != '%' || ((c = *cap++) == '%')) { +			*p++ = c; +			if (p >= e) { +				errno = E2BIG; +				return NULL; +			} +			continue; +		} +		switch (c) { +		case '3': +		case '2': +		case 'd': +			i = 0; +			do +				dbuf[i++] = which % 10 | '0'; +			while ((which /= 10)); +			if (c != 'd') { +				c -= '0'; +				if (i > c) { +					errno = EINVAL; +					return NULL; +				} +				while (i < c) +					dbuf[i++] = '0'; +			} +			if (p + i >= e) { +				errno = E2BIG; +				return NULL; +			} +			do +				*p++ = dbuf[--i]; +			while (i); +			break; +		case 'r': +			oncol = 0; +			break; +		case 'i': +			col++; +			line++; +			which++; +			continue; +		default: +			errno = EINVAL; +			return NULL; +		} + +		oncol = 1 - oncol; +		which = oncol ? col : line; +	} +	*p = '\0'; +	return buf; +} +#endif + +static bool +colour_terminal(FILE *f) +{ +	static int in_colour = -1; +	char *e, *ee, *end, *d, *p; +	int c; +	const char *_af = NULL, *_ce = NULL, *_ch = NULL; +	const char *_md = NULL, *_me = NULL, *_up = NULL; +	const char *bold; +	char tmp[100]; +	unsigned int i = 0; +#ifdef HAVE_TERMCAP +	char *bp; +#endif + +	if (f && !isatty(fileno(f))) +		return false; + +	if (noyes(getenv("EINFO_COLOR"))) +		return false; + +	if (in_colour == 0) +		return false; +	if (in_colour == 1) +		return true; + +	term_is_cons25 = false; +	if (!term) { +		term = getenv("TERM"); +		if (!term) +			return false; +	} +	if (strcmp(term, "cons25") == 0) +		term_is_cons25 = true; + +#ifdef HAVE_TERMCAP +	/* Check termcap to see if we can do colour or not */ +	if (tgetent(termcapbuf, term) == 1) { +		bp = tcapbuf; +		_af = tgetstr("AF", &bp); +		_ce = tgetstr("ce", &bp); +		_ch = tgetstr("ch", &bp); +		/* Our ch use also works with RI .... for now */ +		if (!_ch) +			_ch = tgetstr("RI", &bp); +		_md = tgetstr("md", &bp); +		_me = tgetstr("me", &bp); +		_up = tgetstr("up", &bp); +	} + +	/* Cheat here as vanilla BSD has the whole termcap info in /usr +	 * which is not available to us when we boot */ +	if (term_is_cons25 || strcmp(term, "wsvt25") == 0) { +#else +		if (strstr(term, "color")) +			in_colour = 1; + +		while (color_terms[i] && in_colour != 1) { +			if (strcmp(color_terms[i], term) == 0) { +				in_colour = 1; +			} +			i++; +		} + +		if (in_colour != 1) { +			in_colour = 0; +			return false; +		} +#endif +		if (!_af) +			_af = AF; +		if (!_ce) +			_ce = CE; +		if (!_ch) +			_ch = CH; +		if (!_md) +			_md = MD; +		if (!_me) +			_me = ME; +		if (!_up) +			_up = UP; +#ifdef HAVE_TERMCAP +	} + +	if (!_af || !_ce || !_me || !_md || !_up) { +		in_colour = 0; +		return false; +	} + +	/* Many termcap databases don't have ch or RI even though they +	 * do work */ +	if (!_ch) +		_ch = CH; +#endif + +	/* Now setup our colours */ +	p = ebuffer; +	for (i = 0; i < ARRAY_SIZE(ecolors); ++i) { +		tmp[0] = '\0'; +		if (ecolors[i].name) { +			bold = _md; +			c = ecolors[i].def; + +			/* See if the user wants to override the colour +			 * We use a :col;bold: format like 2;1: for bold green +			 * and 1;0: for a normal red */ +			if ((e = getenv("EINFO_COLOR"))) { +				ee = strstr(e, ecolors[i].name); +				if (ee) +					ee += strlen(ecolors[i].name); + +				if (ee && *ee == '=') { +					d = strdup(ee + 1); +					if (d) { +						end = strchr(d, ':'); +						if (end) +							*end = '\0'; +						c = atoi(d); +						end = strchr(d, ';'); +						if (end && *++end == '0') +							bold = _me; +						free(d); +					} +				} +			} +			strlcpy(tmp, tgoto(bold, 0, 0), sizeof(tmp)); +			strlcat(tmp, tgoto(_af, 0, c & 0x07), sizeof(tmp)); +		} else +			_GET_CAP(tmp, _me); + +		if (tmp[0]) +			_ASSIGN_CAP(ecolors_str[i]); +		else +			ecolors_str[i] = &nullstr; +	} + +	_GET_CAP(tmp, _ce); +	_ASSIGN_CAP(flush); +	_GET_CAP(tmp, _up); +	_ASSIGN_CAP(up); +	strlcpy(tmp, _ch, sizeof(tmp)); +	_ASSIGN_CAP(goto_column); + +	in_colour = 1; +	return true; +} + +static int +get_term_columns(FILE *stream) +{ +	struct winsize ws; +	char *env = getenv("COLUMNS"); +	char *p; +	int i; + +	if (env) { +		i = strtoimax(env, &p, 10); +		if (!*p) +			return i; +	} + +	if (ioctl(fileno(stream), TIOCGWINSZ, &ws) == 0) +		return ws.ws_col; + +	return DEFAULT_COLS; +} + +void +eprefix(const char *prefix) +{ +	_eprefix = prefix; +} + +static void EINFO_PRINTF(2, 0) +elogv(int level, const char *fmt, va_list ap) +{ +	char *e = getenv("EINFO_LOG"); +	va_list apc; + +	if (fmt && e) { +		closelog(); +		openlog(e, LOG_PID, LOG_DAEMON); +		va_copy(apc, ap); +		vsyslog(level, fmt, apc); +		va_end(apc); +		closelog(); +	} +} + +void +elog(int level, const char *fmt, ...) +{ +	va_list ap; + +	va_start(ap, fmt); +	elogv(level, fmt, ap); +	va_end(ap); +} + +static int +_eindent(FILE *stream) +{ +	char *env = getenv("EINFO_INDENT"); +	int amount = 0; +	char indent[INDENT_MAX]; + +	if (env) { +		errno = 0; +		amount = strtoimax(env, NULL, 0); +		if (errno != 0 || amount < 0) +			amount = 0; +		else if (amount > INDENT_MAX) +			amount = INDENT_MAX; + +		if (amount > 0) +			memset(indent, ' ', (size_t)amount); +	} + +	/* Terminate it */ +	memset(indent + amount, 0, 1); +	return fprintf(stream, "%s", indent); +} + +static const char * +_ecolor(FILE *f, ECOLOR color) +{ +	unsigned int i; + +	if (!colour_terminal(f)) +		return ""; + +	for (i = 0; i < ARRAY_SIZE(ecolors); ++i) +		if (ecolors[i].color == color) +			return ecolors_str[i]; +	return ""; +} + +const char * +ecolor(ECOLOR color) +{ +	FILE *f = stdout; + +	/* Try and guess a valid tty */ +	if (!isatty(fileno(f))) { +		f = stderr; +		if (!isatty(fileno(f))) { +			f = stdin; +			if (!isatty(fileno(f))) +				f = NULL; +		} +	} + +	return _ecolor(f, color); +} + +#define LASTCMD(_cmd) {							      \ +		unsetenv("EINFO_LASTCMD");				      \ +		setenv("EINFO_LASTCMD", _cmd, 1);			      \ +	} + +static int EINFO_PRINTF(3, 0) +	_einfo(FILE *f, ECOLOR color, const char *fmt, va_list va) +{ +	int retval = 0; +	char *last = getenv("EINFO_LASTCMD"); +	va_list ap; + +	if (last && +	    !colour_terminal(f) && +	    strcmp(last, "ewarn") != 0 && +	    last[strlen(last) - 1] == 'n') +		fprintf(f, "\n"); +	if (_eprefix) +		fprintf(f, "%s%s%s|", _ecolor(f, color), _eprefix, _ecolor(f, ECOLOR_NORMAL)); +	fprintf(f, " %s*%s ", _ecolor(f, color), _ecolor(f, ECOLOR_NORMAL)); +	retval += _eindent(f); +	va_copy(ap, va); +	retval += vfprintf(f, fmt, ap) + 3; +	va_end(ap); \ +	if (colour_terminal(f)) +		fprintf(f, "%s", flush); +	return retval; +} + +#define _einfovn(fmt, ap) _einfo(stdout, ECOLOR_GOOD, fmt, ap) +#define _ewarnvn(fmt, ap) _einfo(stderr, ECOLOR_WARN, fmt, ap) +#define _eerrorvn(fmt, ap) _einfo(stderr, ECOLOR_BAD, fmt, ap) + +int +einfon(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_quiet()) +		return 0; +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	va_end(ap); +	LASTCMD("einfon"); +	return retval; +} + +int +ewarnn(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_quiet()) +		return 0; +	va_start(ap, fmt); +	retval = _ewarnvn(fmt, ap); +	va_end(ap); +	LASTCMD("ewarnn"); +	return retval; +} + +int +eerrorn(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_really_quiet()) +		return 0; +	va_start(ap, fmt); +	retval = _eerrorvn(fmt, ap); +	va_end(ap); +	LASTCMD("errorn"); +	return retval; +} + +int +einfo(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_quiet()) +		return 0; +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	retval += printf("\n"); +	va_end(ap); +	LASTCMD("einfo"); +	return retval; +} + +int +ewarn(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_quiet()) +		return 0; +	va_start(ap, fmt); +	elogv(LOG_WARNING, fmt, ap); +	retval = _ewarnvn(fmt, ap); +	retval += fprintf(stderr, "\n"); +	va_end(ap); +	LASTCMD("ewarn"); +	return retval; +} + +void +ewarnx(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (fmt && !is_quiet()) { +		va_start(ap, fmt); +		elogv(LOG_WARNING, fmt, ap); +		retval = _ewarnvn(fmt, ap); +		va_end(ap); +		retval += fprintf(stderr, "\n"); +	} +	exit(EXIT_FAILURE); +} + +int +eerror(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_really_quiet()) +		return 0; +	va_start(ap, fmt); +	elogv(LOG_ERR, fmt, ap); +	retval = _eerrorvn(fmt, ap); +	va_end(ap); +	retval += fprintf(stderr, "\n"); +	LASTCMD("eerror"); +	return retval; +} + +void +eerrorx(const char *fmt, ...) +{ +	va_list ap; + +	if (fmt && !is_really_quiet()) { +		va_start(ap, fmt); +		elogv(LOG_ERR, fmt, ap); +		_eerrorvn(fmt, ap); +		va_end(ap); +		fprintf(stderr, "\n"); +	} +	exit(EXIT_FAILURE); +} + +int +ebegin(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || is_quiet()) +		return 0; +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	va_end(ap); +	retval += printf(" ..."); +	if (colour_terminal(stdout)) +		retval += printf("\n"); +	LASTCMD("ebegin"); +	return retval; +} + +static void +_eend(FILE *fp, int col, ECOLOR color, const char *msg) +{ +	int i; +	int cols; + +	if (!msg) +		return; + +	cols = get_term_columns(fp) - (strlen(msg) + 5); + +	/* cons25 is special - we need to remove one char, otherwise things +	 * do not align properly at all. */ +	if (!term) { +		term = getenv("TERM"); +		if (term && strcmp(term, "cons25") == 0) +			term_is_cons25 = true; +		else +			term_is_cons25 = false; +	} +	if (term_is_cons25) +		cols--; + +	if (cols > 0 && colour_terminal(fp)) { +		fprintf(fp, "%s%s %s[%s %s %s]%s\n", up, tgoto(goto_column, 0, cols), +		    ecolor(ECOLOR_BRACKET), ecolor(color), msg, +		    ecolor(ECOLOR_BRACKET), ecolor(ECOLOR_NORMAL)); +	} else { +		if (col > 0) +			for (i = 0; i < cols - col; i++) +				fprintf(fp, " "); +		fprintf(fp, " [ %s ]\n", msg); +	} +} + +static int EINFO_PRINTF(3, 0) +_do_eend(const char *cmd, int retval, +    const char *fmt, va_list ap) +{ +	int col = 0; +	FILE *fp = stdout; +	va_list apc; + +	if (fmt && *fmt != '\0' && retval != 0) { +		fp = stderr; +		va_copy(apc, ap); +		if (strcmp(cmd, "ewend") == 0) +			col = _ewarnvn(fmt, apc); +		else +			col = _eerrorvn(fmt, apc); +		col += fprintf(fp, "\n"); +		va_end(apc); +	} +	_eend(fp, col, +	    retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD, +	    retval == 0 ? OK : NOT_OK); +	return retval; +} + +int +eend(int retval, const char *fmt, ...) +{ +	va_list ap; + +	if (is_quiet()) +		return retval; +	va_start(ap, fmt); +	_do_eend("eend", retval, fmt, ap); +	va_end(ap); +	LASTCMD("eend"); +	return retval; +} + +int +ewend(int retval, const char *fmt, ...) +{ +	va_list ap; + +	if (is_quiet()) +		return retval; +	va_start(ap, fmt); +	_do_eend("ewend", retval, fmt, ap); +	va_end(ap); +	LASTCMD("ewend"); +	return retval; +} + +void +ebracket(int col, ECOLOR color, const char *msg) +{ +	_eend(stdout, col, color, msg); +} + +void +eindent(void) +{ +	char *env = getenv("EINFO_INDENT"); +	int amount = 0; +	char num[10]; + +	if (env) { +		errno = 0; +		amount = strtoimax(env, NULL, 0); +		if (errno != 0) +			amount = 0; +	} +	amount += INDENT_WIDTH; +	if (amount > INDENT_MAX) +		amount = INDENT_MAX; +	snprintf(num, 10, "%08d", amount); +	setenv("EINFO_INDENT", num, 1); +} + +void eoutdent(void) +{ +	char *env = getenv("EINFO_INDENT"); +	int amount = 0; +	char num[10]; +	int serrno = errno; + +	if (!env) +		return; +	errno = 0; +	amount = strtoimax(env, NULL, 0); +	if (errno != 0) +		amount = 0; +	else +		amount -= INDENT_WIDTH; +	if (amount <= 0) +		unsetenv("EINFO_INDENT"); +	else { +		snprintf(num, 10, "%08d", amount); +		setenv("EINFO_INDENT", num, 1); +	} +	errno = serrno; +} + +int +einfovn(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || !is_verbose()) +		return 0; +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	va_end(ap); +	LASTCMD("einfovn"); +	return retval; +} + +int +ewarnvn(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || !is_verbose()) +		return 0; +	va_start(ap, fmt); +	retval = _ewarnvn(fmt, ap); +	va_end(ap); +	LASTCMD("ewarnvn"); +	return retval; +} + +int +einfov(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || !is_verbose()) +		return 0; +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	retval += printf("\n"); +	va_end(ap); +	LASTCMD("einfov"); +	return retval; +} + +int +ewarnv(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || !is_verbose()) +		return 0; +	va_start(ap, fmt); +	retval = _ewarnvn(fmt, ap); +	retval += printf("\n"); +	va_end(ap); +	LASTCMD("ewarnv"); +	return retval; +} + +int +ebeginv(const char *fmt, ...) +{ +	int retval; +	va_list ap; + +	if (!fmt || !is_verbose()) +		return 0; + +	va_start(ap, fmt); +	retval = _einfovn(fmt, ap); +	retval += printf(" ..."); +	if (colour_terminal(stdout)) +		retval += printf("\n"); +	va_end(ap); +	LASTCMD("ebeginv"); +	return retval; +} + +int +eendv(int retval, const char *fmt, ...) +{ +	va_list ap; + +	if (!is_verbose()) +		return 0; +	va_start(ap, fmt); +	_do_eend("eendv", retval, fmt, ap); +	va_end(ap); +	LASTCMD("eendv"); +	return retval; +} + +int +ewendv(int retval, const char *fmt, ...) +{ +	va_list ap; + +	if (!is_verbose()) +		return 0; +	va_start(ap, fmt); +	_do_eend("ewendv", retval, fmt, ap); +	va_end(ap); +	LASTCMD("ewendv"); +	return retval; +} + +void +eindentv(void) +{ +	if (is_verbose()) +		eindent(); +} + +void +eoutdentv(void) +{ +	if (is_verbose()) +		eoutdent(); +} diff --git a/src/rc/einfo.h b/src/rc/einfo.h new file mode 100644 index 00000000..57645695 --- /dev/null +++ b/src/rc/einfo.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2007-2008 Roy Marples <roy@marples.name> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __EINFO_H__ +#define __EINFO_H__ + +#if defined(__GNUC__) +# define EINFO_PRINTF(a, b)  __attribute__((__format__(__printf__, a, b))) +# define EINFO_XPRINTF(a, b) __attribute__((__noreturn__,__format__(__printf__, a, b))) +#else +# define EINFO_PRINTF(a, b) +# define EINFO_XPRINTF(a, b) +#endif + +#include <sys/types.h> +#include <stdbool.h> + +/*! @brief Color types to use */ +typedef enum +{ +	ECOLOR_NORMAL	= 1, +	ECOLOR_GOOD	= 2, +	ECOLOR_WARN	= 3, +	ECOLOR_BAD	= 4, +	ECOLOR_HILITE	= 5, +	ECOLOR_BRACKET	= 6 +} ECOLOR; + +/*! @brief Returns the ASCII code for the color */ +const char *ecolor(ECOLOR); + +/*! @brief Writes to syslog. */ +void elog(int, const char *, ...) EINFO_PRINTF(2, 3); + +/*! + * @brief Display informational messages. + * + * The einfo family of functions display messages in a consistent manner + * Basically they prefix the message with " * ". + * If the terminal can handle color then we color the * based on + * the command used. Otherwise we are identical to the printf function. + * + * - einfo  - green + * - ewarn  - yellow + * - eerror - red + * + * The n suffix denotes that no new line should be printed. + * The v suffix means only print if EINFO_VERBOSE is yes. + */ +/*@{*/ +int einfon(const char *, ...) EINFO_PRINTF(1, 2); +int ewarnn(const char *, ...) EINFO_PRINTF(1, 2); +int eerrorn(const char *, ...) EINFO_PRINTF(1, 2); +int einfo(const char *, ...) EINFO_PRINTF(1, 2); +int ewarn(const char *, ...) EINFO_PRINTF(1, 2); +void ewarnx(const char *, ...) EINFO_XPRINTF(1, 2); +int eerror(const char *, ...) EINFO_PRINTF(1, 2); +void eerrorx(const char *, ...) EINFO_XPRINTF(1, 2); + +int einfovn(const char *, ...) EINFO_PRINTF(1, 2); +int ewarnvn(const char * , ...) EINFO_PRINTF(1, 2); +int ebeginvn(const char *, ...) EINFO_PRINTF(1, 2); +int eendvn(int, const char *, ...) EINFO_PRINTF(2, 3); +int ewendvn(int, const char *, ...) EINFO_PRINTF(2, 3); +int einfov(const char *, ...) EINFO_PRINTF(1, 2); +int ewarnv(const char *, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup ebegin + * @brief Display informational messages that may take some time. + * + * Similar to einfo, but we add ... to the end of the message */ +/*@{*/ +int ebeginv(const char *, ...) EINFO_PRINTF(1, 2); +int ebegin(const char *, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup eend + * @brief End an ebegin. + * + * If you ebegin, you should eend also. + * eend places [ ok ] or [ !! ] at the end of the terminal line depending on + * retval (0 or ok, anything else for !!) + * + * ebracket allows you to specifiy the position, color and message */ +/*@{*/ +int eend(int, const char *, ...) EINFO_PRINTF(2, 3); +int ewend(int, const char *, ...) EINFO_PRINTF(2, 3); +void ebracket(int, ECOLOR, const char *); + +int eendv(int, const char *, ...) EINFO_PRINTF(2, 3); +int ewendv(int, const char *, ...) EINFO_PRINTF(2, 3); +/*@}*/ + +/*! @ingroup eindent + * @brief Indents the einfo lines. + * + * For each indent you should outdent when done */ +/*@{*/ +void eindent(void); +void eoutdent(void); +void eindentv(void); +void eoutdentv(void); + +/*! @brief Prefix each einfo line with something */ +void eprefix(const char *); + +#endif | 
