scripts: Buffer output in non-journal case, prefix print with id

In the server-side `compose tree` case, this makes it obvious which package is
causing error spew. No particular burning reason, this was just bothering me.

Closes: #1235
Approved by: jlebon
This commit is contained in:
Colin Walters 2018-02-06 22:00:45 -05:00 committed by Atomic Bot
parent f26dcd59a2
commit f1e9f53480

View File

@ -207,6 +207,57 @@ script_child_setup (gpointer opaque)
err (1, "dup2(stderr)"); err (1, "dup2(stderr)");
} }
/* Print the output of a script, with each line prefixed with
* the script identifier (e.g. foo.post: bla bla bla).
*/
static gboolean
dump_buffered_output (const char *prefix,
GLnxTmpfile *tmpf,
GError **error)
{
/* The tmpf won't be initialized in the journal case */
if (!tmpf->initialized)
return TRUE;
if (lseek (tmpf->fd, 0, SEEK_SET) < 0)
return glnx_throw_errno_prefix (error, "lseek");
g_autoptr(FILE) buf = fdopen (tmpf->fd, "r");
if (!buf)
return glnx_throw_errno_prefix (error, "fdopen");
tmpf->fd = -1; /* Ownership of fd was transferred */
while (TRUE)
{
size_t len = 0;
ssize_t bytes_read = 0;
g_autofree char *line = NULL;
errno = 0;
if ((bytes_read = getline (&line, &len, buf)) == -1)
{
if (errno != 0)
return glnx_throw_errno_prefix (error, "getline");
else
break;
}
printf ("%s: %s", prefix, line);
if (bytes_read > 0 && line[bytes_read-1] != '\n')
fputc ('\n', stdout);
}
return TRUE;
}
/* Since it doesn't make sense to fatally error if printing output fails, catch
* any errors there and print.
*/
static void
dump_buffered_output_noerr (const char *prefix,
GLnxTmpfile *tmpf)
{
g_autoptr(GError) local_error = NULL;
if (!dump_buffered_output (prefix, tmpf, &local_error))
g_printerr ("While writing output: %s\n", local_error->message);
}
/* Lowest level script handler in this file; create a bwrap instance and run it /* Lowest level script handler in this file; create a bwrap instance and run it
* synchronously. * synchronously.
*/ */
@ -297,6 +348,7 @@ run_script_in_bwrap_container (int rootfs_fd,
* is where other output will go. * is where other output will go.
*/ */
const char *id = glnx_strjoina ("rpm-ostree(", pkg_script, ")"); const char *id = glnx_strjoina ("rpm-ostree(", pkg_script, ")");
GLnxTmpfile buffered_output = { 0, };
if (rpmostree_stdout_is_journal ()) if (rpmostree_stdout_is_journal ())
{ {
data.stdout_fd = stdout_fd = sd_journal_stream_fd (id, LOG_INFO, 0); data.stdout_fd = stdout_fd = sd_journal_stream_fd (id, LOG_INFO, 0);
@ -313,6 +365,13 @@ run_script_in_bwrap_container (int rootfs_fd,
goto out; goto out;
} }
} }
else
{
/* In the non-journal case we buffer so we can prefix output */
if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, &buffered_output, error))
return FALSE;
data.stdout_fd = data.stderr_fd = buffered_output.fd;
}
data.all_fds_initialized = TRUE; data.all_fds_initialized = TRUE;
rpmostree_bwrap_set_child_setup (bwrap, script_child_setup, &data); rpmostree_bwrap_set_child_setup (bwrap, script_child_setup, &data);
@ -325,6 +384,7 @@ run_script_in_bwrap_container (int rootfs_fd,
if (!rpmostree_bwrap_run (bwrap, cancellable, error)) if (!rpmostree_bwrap_run (bwrap, cancellable, error))
{ {
dump_buffered_output_noerr (pkg_script, &buffered_output);
/* If errors go to the journal, help the user/admin find them there */ /* If errors go to the journal, help the user/admin find them there */
if (error && rpmostree_stdout_is_journal ()) if (error && rpmostree_stdout_is_journal ())
{ {
@ -335,9 +395,12 @@ run_script_in_bwrap_container (int rootfs_fd,
} }
goto out; goto out;
} }
else
dump_buffered_output_noerr (pkg_script, &buffered_output);
ret = TRUE; ret = TRUE;
out: out:
glnx_tmpfile_clear (&buffered_output);
(void) unlinkat (rootfs_fd, postscript_path_host, 0); (void) unlinkat (rootfs_fd, postscript_path_host, 0);
if (created_var_tmp) if (created_var_tmp)
(void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR); (void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR);