aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2007-04-24 11:29:19 +0000
committerRoy Marples <roy@marples.name>2007-04-24 11:29:19 +0000
commita44abb9577a3ccb9202b84765d4b4c1746e6963d (patch)
tree9d0a3df13709385b55dc407a23d3ce94a2b52308 /src
parentc965f74f46b266987ed635e65fafc9562a7ccff5 (diff)
We now buffer stdout and stderr to a file and flush that when running in parallel. RC_PARALLEL_STARTUP has been renamed to RC_PARALLEL.
Diffstat (limited to 'src')
-rw-r--r--src/einfo.h10
-rw-r--r--src/libeinfo.c324
-rw-r--r--src/librc-misc.c14
-rw-r--r--src/rc.c12
-rw-r--r--src/runscript.c16
5 files changed, 149 insertions, 227 deletions
diff --git a/src/einfo.h b/src/einfo.h
index a99af240..e1953772 100644
--- a/src/einfo.h
+++ b/src/einfo.h
@@ -64,8 +64,12 @@ int ewendv (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
void eindentv (void);
void eoutdentv (void);
-/* If RC_EBUFFER is set, then we buffer all the above commands.
- As such, we need to flush the buffer when done. */
-void eflush(void);
+/* Handy utils to buffer stdout and stderr so our output is always
+ * sane when forking around.
+ * Don't depend on these being here though as we may take a different
+ * approach at a later date. */
+void ebuffer (const char *file);
+void eflush (void);
+void eclose (void);
#endif
diff --git a/src/libeinfo.c b/src/libeinfo.c
index 9355021c..a6c0a2a1 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);
diff --git a/src/librc-misc.c b/src/librc-misc.c
index 0700863e..a2b38b4a 100644
--- a/src/librc-misc.c
+++ b/src/librc-misc.c
@@ -644,6 +644,20 @@ char **rc_config_env (char **env)
} else
env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
+ /* Store the name of the tty that stdout is connected to
+ * We do this so our init scripts can call eflush without any knowledge
+ * of our fd's */
+ if (isatty (fileno (stdout))) {
+ if ((p = rc_xstrdup (ttyname (fileno (stdout))))) {
+ i = strlen ("RC_TTY=") + strlen (p) + 1;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_TTY=%s", p);
+ env = rc_strlist_add (env, line);
+ free (p);
+ free (line);
+ }
+ }
+
memset (sys, 0, sizeof (sys));
/* Linux can run some funky stuff like Xen, VServer, UML, etc
diff --git a/src/rc.c b/src/rc.c
index 12ce4382..c533a18b 100644
--- a/src/rc.c
+++ b/src/rc.c
@@ -462,13 +462,7 @@ static void set_ksoftlevel (const char *runlevel)
static void wait_for_services ()
{
int status = 0;
- struct timeval tv;
while (wait (&status) != -1);
-
- /* Wait for a little bit to flush our ebuffer */
- tv.tv_usec = 50000;
- tv.tv_sec = 0;
- select (0, NULL, NULL, NULL, &tv);
}
static void add_pid (pid_t pid)
@@ -1077,7 +1071,7 @@ int main (int argc, char **argv)
/* We always stop the service when in these runlevels */
if (going_down) {
pid_t pid = rc_stop_service (service);
- if (pid > 0 && ! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
rc_waitpid (pid);
}
@@ -1141,7 +1135,7 @@ int main (int argc, char **argv)
/* After all that we can finally stop the blighter! */
if (! found) {
pid_t pid = rc_stop_service (service);
- if (pid > 0 && ! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
rc_waitpid (pid);
}
}
@@ -1227,7 +1221,7 @@ interactive_option:
if ((pid = rc_start_service (service)))
add_pid (pid);
- if (! rc_is_env ("RC_PARALLEL_STARTUP", "yes")) {
+ if (! rc_is_env ("RC_PARALLEL", "yes")) {
rc_waitpid (pid);
remove_pid (pid);
}
diff --git a/src/runscript.c b/src/runscript.c
index 45f83433..e1d880b5 100644
--- a/src/runscript.c
+++ b/src/runscript.c
@@ -199,7 +199,7 @@ static void uncoldplug (char *service)
static void cleanup (void)
{
/* Flush our buffered output if any */
- eflush ();
+ eclose ();
if (hook_out)
rc_plugin_run (hook_out, applet);
@@ -267,6 +267,10 @@ static bool svc_exec (const char *service, const char *arg1, const char *arg2)
{
bool retval;
+ /* To ensure any output has hit our ebuffer */
+ fflush (stdout);
+ fflush (stderr);
+
/* We need to disable our child signal handler now so we block
until our script returns. */
signal (SIGCHLD, NULL);
@@ -466,7 +470,7 @@ static void svc_start (const char *service, bool deps)
STRLIST_FOREACH (services, svc, i)
if (rc_service_state (svc, rc_service_stopped)) {
pid_t pid = rc_start_service (svc);
- if (! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ if (! rc_is_env ("RC_PARALLEL", "yes"))
rc_waitpid (pid);
}
@@ -670,7 +674,7 @@ static void svc_stop (const char *service, bool deps)
rc_service_state (svc, rc_service_inactive))
{
pid_t pid = rc_stop_service (svc);
- if (! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ if (! rc_is_env ("RC_PARALLEL", "yes"))
rc_waitpid (pid);
tmplist = rc_strlist_add (tmplist, svc);
}
@@ -883,7 +887,7 @@ int main (int argc, char **argv)
softlevel = rc_get_runlevel ();
/* If not called from RC or another service then don't be parallel */
- unsetenv ("RC_PARALLEL_STARTUP");
+ unsetenv ("RC_PARALLEL");
}
setenv ("RC_ELOG", service, 1);
@@ -895,13 +899,13 @@ int main (int argc, char **argv)
snprintf (pid, sizeof (pid), "%d", (int) getpid ());
setenv ("RC_RUNSCRIPT_PID", pid, 1);
- if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) {
+ if (rc_is_env ("RC_PARALLEL", "yes")) {
char ebname[PATH_MAX];
char *eb;
snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
- setenv ("RC_EBUFFER", eb, 1);
+ ebuffer (eb);
free (eb);
}