summaryrefslogtreecommitdiff
path: root/src/libeinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libeinfo.c')
-rw-r--r--src/libeinfo.c324
1 files changed, 115 insertions, 209 deletions
diff --git a/src/libeinfo.c b/src/libeinfo.c
index 9355021..a6c0a2a 100644
--- a/src/libeinfo.c
+++ b/src/libeinfo.c
@@ -8,6 +8,7 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -32,6 +33,7 @@ hidden_proto(eerror)
hidden_proto(eerrorn)
hidden_proto(eerrorx)
hidden_proto(eflush)
+hidden_proto(eclose)
hidden_proto(eindent)
hidden_proto(eindentv)
hidden_proto(einfo)
@@ -118,6 +120,11 @@ static const char *color_terms[] = {
NULL
};
+/* We use this array to save the stdout/stderr fd's for buffering */
+static int stdfd[2] = {-1, -1};
+static FILE *ebfp = NULL;
+static char ebfile[PATH_MAX] = { '\0' };
+
static bool is_env (const char *var, const char *val)
{
char *v;
@@ -177,194 +184,125 @@ static int get_term_columns (void)
return (DEFAULT_COLS);
}
-static int ebuffer (const char *cmd, int retval, const char *fmt, va_list ap)
+void ebuffer (const char *file)
{
- char *file = getenv ("RC_EBUFFER");
- FILE *fp;
- char buffer[RC_LINEBUFFER];
- int l = 1;
+ /* Don't ebuffer if we don't have a file or we already are */
+ if (! file || stdfd[0] >= 0 || ! isatty (fileno (stdout)))
+ return;
- if (! file || ! cmd || strlen (cmd) < 4)
- return (0);
+ /* Save the current fd's */
+ stdfd[0] = dup (fileno (stdout));
+ stdfd[1] = dup (fileno (stderr));
- if (! (fp = fopen (file, "a"))) {
+ if (! (ebfp = fopen (file, "w+"))) {
fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno));
- return (0);
+ return;
}
- fprintf (fp, "%s %d ", cmd, retval);
+ snprintf (ebfile, sizeof (ebfile), "%s", file);
- if (fmt) {
- va_list apc;
- va_copy (apc, ap);
- l = vsnprintf (buffer, sizeof (buffer), fmt, apc);
- fprintf (fp, "%d %s\n", l, buffer);
- va_end (apc);
- } else
- fprintf (fp, "0\n");
-
- fclose (fp);
- return (l);
-}
-
-typedef struct func
-{
- const char *name;
- int (*efunc) (const char *fmt, ...);
- int (*eefunc) (int retval, const char *fmt, ...);
- void (*eind) (void);
-} func_t;
-
-static const func_t funcmap[] = {
- { "einfon", &einfon, NULL, NULL },
- { "ewarnn", &ewarnn, NULL, NULL},
- { "eerrorn", &eerrorn, NULL, NULL},
- { "einfo", &einfo, NULL, NULL },
- { "ewarn", &ewarn, NULL, NULL },
- { "eerror", &eerror, NULL, NULL },
- { "ebegin", &ebegin, NULL, NULL },
- { "eend", NULL, &eend, NULL },
- { "ewend", NULL, &ewend, NULL },
- { "eindent", NULL, NULL, &eindent },
- { "eoutdent", NULL, NULL, &eoutdent },
- { "einfovn", &einfovn, NULL, NULL },
- { "ewarnvn", &ewarnvn, NULL, NULL },
- { "einfov", &einfov, NULL, NULL },
- { "ewarnv", &ewarnv, NULL, NULL },
- { "ebeginv", &ebeginv, NULL, NULL },
- { "eendv", NULL, &eendv, NULL },
- { "ewendv", NULL, &ewendv, NULL },
- { "eindentv" ,NULL, NULL, &eindentv },
- { "eoutdentv", NULL, NULL, &eoutdentv },
- { NULL, NULL, NULL, NULL },
-};
+ fflush (stdout);
+ fflush (stderr);
+
+ /* Now redirect stdout and stderr */
+ if ((dup2 (fileno (ebfp), fileno (stdout))) < 0)
+ fprintf (stderr, "dup2: %s", strerror (errno));
+ if ((dup2 (fileno (ebfp), fileno (stderr))) < 0)
+ fprintf (stderr, "dup2: %s", strerror (errno));
-void eflush (void)
+ /* Store the filename in our environment so scripts can tell if we're
+ * buffering or not */
+ unsetenv ("RC_EBUFFER");
+ setenv ("RC_EBUFFER", file, 1);
+
+ return;
+}
+
+static void _eflush (bool reopen)
{
- FILE *fp;
- char *file = getenv ("RC_EBUFFER");
char buffer[RC_LINEBUFFER];
- char *cmd;
- int retval = 0;
- int length = 0;
- char *token;
- char *p;
- struct stat buf;
- pid_t pid;
- char newfile[PATH_MAX];
- int i = 1;
-
- if (! file|| (stat (file, &buf) != 0)) {
- errno = 0;
- return;
- }
-
- /* Find a unique name for our file */
- while (true) {
- snprintf (newfile, sizeof (newfile), "%s.%d", file, i);
- if (stat (newfile, &buf) != 0) {
- if (rename (file, newfile))
- fprintf (stderr, "rename `%s' `%s': %s\n", file, newfile,
- strerror (errno));
- break;
- }
- i++;
+ int serrno = errno;
+
+ /* eflush called from an init script? */
+ if (! ebfp) {
+ char *file = getenv ("RC_EBUFFER");
+ if (file)
+ ebfp = fopen (file, "a+");
}
- /* We fork a child process here so we don't hold anything up */
- if ((pid = fork ()) == -1) {
- fprintf (stderr, "fork: %s", strerror (errno));
+ if (! ebfp)
return;
- }
- if (pid != 0)
- return;
+ fflush (stdout);
+ fflush (stderr);
+
+ /* Restore stdout and stderr now */
+ if (stdfd[0] >= 0) {
+ dup2 (stdfd[0], fileno (stdout));
+ dup2 (stdfd[1], fileno (stderr));
+ } else {
+ char *tty = getenv ("RC_TTY");
+ if (tty) {
+ freopen (tty, "w+", stdout);
+ dup2 (fileno (stdout), fileno (stderr));
+ }
+ }
/* Spin until we can lock the ebuffer */
while (true) {
struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 20000;
- select (0, NULL, NULL, NULL, &tv);
errno = 0;
- if (link (newfile, EBUFFER_LOCK) == 0)
+ if (mkfifo (EBUFFER_LOCK, 0700) == 0)
break;
if (errno != EEXIST)
- fprintf (stderr, "link `%s' `%s': %s\n", newfile, EBUFFER_LOCK,
- strerror (errno));
- }
-
- if (! (fp = fopen (newfile, "r"))) {
- fprintf (stderr, "fopen `%s': %s\n", newfile, strerror (errno));
- return;
+ eerror ("mkfifo `%s': %s\n", EBUFFER_LOCK, strerror (errno));
+ tv.tv_sec = 0;
+ tv.tv_usec = 20000;
+ select (0, NULL, NULL, NULL, &tv);
}
+ errno = serrno;
- unsetenv ("RC_EBUFFER");
-
+ /* Dump the file to stdout */
memset (buffer, 0, RC_LINEBUFFER);
- while (fgets (buffer, RC_LINEBUFFER, fp)) {
- i = strlen (buffer) - 1;
- if (i < 1)
- continue;
-
- if (buffer[i] == '\n')
- buffer[i] = 0;
-
- p = buffer;
- cmd = strsep (&p, " ");
- token = strsep (&p, " ");
- if (sscanf (token, "%d", &retval) != 1) {
- fprintf (stderr, "eflush `%s': not a number", token);
- continue;
- }
- token = strsep (&p, " ");
- if (sscanf (token, "%d", &length) != 1) {
- fprintf (stderr, "eflush `%s': not a number", token);
- continue;
- }
-
- i = 0;
- while (funcmap[i].name) {
- if (strcmp (funcmap[i].name, cmd) == 0) {
- if (funcmap[i].efunc) {
- if (p)
- funcmap[i].efunc ("%s", p);
- else
- funcmap[i].efunc (NULL, NULL);
- } else if (funcmap[i].eefunc) {
- if (p)
- funcmap[i].eefunc (retval, "%s", p);
- else
- funcmap[i].eefunc (retval, NULL, NULL);
- } else if (funcmap[i].eind)
- funcmap[i].eind ();
- else
- fprintf (stderr, "eflush `%s': no function defined\n", cmd);
- break;
- }
- i++;
- }
-
- if (! funcmap[i].name)
- fprintf (stderr, "eflush `%s': invalid function\n", cmd);
+ if (fseek (ebfp, (off_t) 0, SEEK_SET) < 0)
+ eerror ("fseek: %s", strerror (errno));
+ else {
+ while (fgets (buffer, RC_LINEBUFFER, ebfp))
+ printf ("%s", buffer);
}
- fclose (fp);
-
+ fflush (stdout);
+ fflush (stderr);
+
if (unlink (EBUFFER_LOCK))
- fprintf (stderr, "unlink `%s': %s", EBUFFER_LOCK, strerror (errno));
+ eerror ("unlink `%s': %s", EBUFFER_LOCK, strerror (errno));
+
+ if (reopen) {
+ ftruncate (fileno (ebfp), (off_t) 0);
+ fseek (ebfp, (off_t) 0, SEEK_SET);
+ dup2 (fileno (ebfp), fileno (stdout));
+ dup2 (fileno (ebfp), fileno (stderr));
+ } else {
+ stdfd[0] = -1;
+ stdfd[1] = -1;
+ fclose (ebfp);
+ ebfp = NULL;
+ unlink (ebfile);
+ ebfile[0] = '\0';
+ unsetenv ("RC_EBUFFER");
+ }
- if (unlink (newfile))
- fprintf (stderr, "unlink `%s': %s", newfile, strerror (errno));
+ return;
+}
- _exit (EXIT_SUCCESS);
+void eflush () {
+ _eflush (true);
}
hidden_def(eflush)
-#define EBUFFER(_cmd, _retval, _fmt, _ap) { \
- int _i = ebuffer (_cmd, _retval, _fmt, _ap); \
- if (_i) \
- return (_i); \
+void eclose () {
+ _eflush (false);
}
+hidden_def(eclose)
static void elog (int level, const char *fmt, va_list ap)
{
@@ -401,7 +339,6 @@ static int _eindent (FILE *stream)
/* Terminate it */
memset (indent + amount, 0, 1);
-
return (fprintf (stream, "%s", indent));
}
@@ -486,8 +423,7 @@ int einfon (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("einfon", 0, fmt, ap)))
- retval = _einfovn (fmt, ap);
+ retval = _einfovn (fmt, ap);
va_end (ap);
return (retval);
@@ -503,8 +439,7 @@ int ewarnn (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("ewarnn", 0, fmt, ap)))
- retval = _ewarnvn (fmt, ap);
+ retval = _ewarnvn (fmt, ap);
va_end (ap);
return (retval);
@@ -517,8 +452,7 @@ int eerrorn (const char *fmt, ...)
va_list ap;
va_start (ap, fmt);
- if (! (retval = ebuffer ("eerrorn", 0, fmt, ap)))
- retval = _eerrorvn (fmt, ap);
+ retval = _eerrorvn (fmt, ap);
va_end (ap);
return (retval);
@@ -534,10 +468,8 @@ int einfo (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("einfo", 0, fmt, ap))) {
- retval = _einfovn (fmt, ap);
- retval += printf ("\n");
- }
+ retval = _einfovn (fmt, ap);
+ retval += printf ("\n");
va_end (ap);
return (retval);
@@ -554,10 +486,8 @@ int ewarn (const char *fmt, ...)
va_start (ap, fmt);
elog (LOG_WARNING, fmt, ap);
- if (! (retval = ebuffer ("ewarn", 0, fmt, ap))) {
- retval = _ewarnvn (fmt, ap);
- retval += printf ("\n");
- }
+ retval = _ewarnvn (fmt, ap);
+ retval += printf ("\n");
va_end (ap);
return (retval);
@@ -569,6 +499,7 @@ void ewarnx (const char *fmt, ...)
int retval;
va_list ap;
+ eclose ();
if (fmt && ! is_env ("RC_QUIET", "yes")) {
va_start (ap, fmt);
elog (LOG_WARNING, fmt, ap);
@@ -594,6 +525,7 @@ int eerror (const char *fmt, ...)
va_end (ap);
retval += fprintf (stderr, "\n");
+ eflush ();
return (retval);
}
hidden_def(eerror)
@@ -602,6 +534,7 @@ void eerrorx (const char *fmt, ...)
{
va_list ap;
+ eclose ();
if (fmt) {
va_start (ap, fmt);
elog (LOG_ERR, fmt, ap);
@@ -609,6 +542,7 @@ void eerrorx (const char *fmt, ...)
va_end (ap);
printf ("\n");
}
+
exit (EXIT_FAILURE);
}
hidden_def(eerrorx)
@@ -622,11 +556,6 @@ int ebegin (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if ((retval = ebuffer ("ebegin", 0, fmt, ap))) {
- va_end (ap);
- return (retval);
- }
-
retval = _einfovn (fmt, ap);
va_end (ap);
retval += printf (" ...");
@@ -667,15 +596,6 @@ static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
int col = 0;
FILE *fp;
va_list apc;
- int eb;
-
- if (fmt) {
- va_copy (apc, ap);
- eb = ebuffer (cmd, retval, fmt, apc);
- va_end (apc);
- if (eb)
- return (retval);
- }
if (fmt && retval != 0) {
va_copy (apc, ap);
@@ -739,9 +659,6 @@ void eindent (void)
int amount = 0;
char num[10];
- if (ebuffer ("eindent", 0, NULL, NULL))
- return;
-
if (env) {
errno = 0;
amount = strtol (env, NULL, 0);
@@ -764,9 +681,6 @@ void eoutdent (void)
int amount = 0;
char num[10];
- if (ebuffer ("eoutdent", 0, NULL, NULL))
- return;
-
if (! env)
return;
@@ -797,8 +711,7 @@ int einfovn (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("einfovn", 0, fmt, ap)))
- retval = _einfovn (fmt, ap);
+ retval = _einfovn (fmt, ap);
va_end (ap);
return (retval);
@@ -816,8 +729,7 @@ int ewarnvn (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("ewarnvn", 0, fmt, ap)))
- retval = _ewarnvn (fmt, ap);
+ retval = _ewarnvn (fmt, ap);
va_end (ap);
return (retval);
@@ -835,10 +747,8 @@ int einfov (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("einfov", 0, fmt, ap))) {
- retval = _einfovn (fmt, ap);
- retval += printf ("\n");
- }
+ retval = _einfovn (fmt, ap);
+ retval += printf ("\n");
va_end (ap);
return (retval);
@@ -856,10 +766,8 @@ int ewarnv (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("ewarnv", 0, fmt, ap))) {
- retval = _ewarnvn (fmt, ap);
- retval += printf ("\n");
- }
+ retval = _ewarnvn (fmt, ap);
+ retval += printf ("\n");
va_end (ap);
return (retval);
@@ -877,12 +785,10 @@ int ebeginv (const char *fmt, ...)
return (0);
va_start (ap, fmt);
- if (! (retval = ebuffer ("ebeginv", 0, fmt, ap))) {
- retval = _einfovn (fmt, ap);
- retval += printf (" ...");
- if (colour_terminal ())
- retval += printf ("\n");
- }
+ retval = _einfovn (fmt, ap);
+ retval += printf (" ...");
+ if (colour_terminal ())
+ retval += printf ("\n");
va_end (ap);
return (retval);