Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • steamrt/steam-runtime-tools
1 result
Show changes
Commits on Source (26)
steam-runtime-tools (0.20240805.0) UNRELEASED; urgency=medium
steam-runtime-tools (0.20240806.0) UNRELEASED; urgency=medium
[ Simon McVittie ]
* pressure-vessel:
- Update libcapsule to 0.20240806.0
+ Always rewrite the symlink target, fixing a regression on NixOS
(steam-runtime#684)
+ Improve consistency of capsule-capture-libs diagnostic messages
* SteamLinuxRuntime 1.0:
- Update fallback code path to account for changes in the Steam client
since May 2024 (steamrt/tasks#490)
[ Ryan Gonzalez, Simon McVittie ]
* srt-logger:
- Avoid reopening log file unnecessarily, fixing a regression in
0.20240805.0 (steamrt/tasks#487)
-- Simon McVittie <smcv@collabora.com> Tue, 06 Aug 2024 13:57:41 +0100
steam-runtime-tools (0.20240805.0) steamrt; urgency=medium
[ Simon McVittie ]
* pv-runtime:
......@@ -11,7 +30,7 @@ steam-runtime-tools (0.20240805.0) UNRELEASED; urgency=medium
by a developer wanting to clear out old logs before reproducing
an issue (steamrt/tasks#487)
-- Simon McVittie <smcv@collabora.com> Mon, 05 Aug 2024 13:42:47 +0100
-- Simon McVittie <smcv@collabora.com> Mon, 05 Aug 2024 19:11:13 +0100
steam-runtime-tools (0.20240802.0) steamrt; urgency=medium
......
......@@ -23,7 +23,7 @@
project(
'steam-runtime-tools', 'c',
version : '0.20240802.0',
version : '0.20240805.0',
default_options: [
'c_std=c99',
'warning_level=2',
......@@ -33,7 +33,7 @@ project(
api_major = '0'
abi_major = '0'
abi_minor = '20240802.0'
abi_minor = '20240805.0'
gnome = import('gnome')
pkg = import('pkgconfig')
......
......@@ -450,6 +450,10 @@ _srt_logger_setup (SrtLogger *self,
if (self->filename == NULL)
return glnx_throw (error,
"Providing a log fd requires a filename");
if (fstat (self->file_fd, &self->file_stat) < 0)
return glnx_throw_errno_prefix (error,
"Unable to stat \"%s\"",
self->filename);
}
else if (self->use_file)
{
......@@ -1093,7 +1097,7 @@ _srt_logger_try_rotate (SrtLogger *self,
glnx_close_fd (&self->file_fd);
self->file_fd = g_steal_fd (&new_fd);
memcpy (&self->file_stat, &new_stat, sizeof (new_stat));
self->file_stat = new_stat;
ret = TRUE;
out:
......@@ -1216,17 +1220,26 @@ logger_process_complete_line (SrtLogger *self,
{
if (self->filename != NULL)
{
gboolean log_file_still_exists = FALSE;
const char *reason_to_reopen = NULL;
struct stat current_stat;
if (TEMP_FAILURE_RETRY (stat (self->filename, &current_stat)) == 0)
log_file_still_exists = _srt_is_same_stat (&current_stat,
&self->file_stat);
else if (errno != ENOENT)
_srt_log_warning ("Unable to stat log file: %s",
g_strerror (errno));
{
if (!_srt_is_same_stat (&current_stat, &self->file_stat))
reason_to_reopen = "File replaced";
}
else
{
int saved_errno = errno;
if (saved_errno != ENOENT)
_srt_log_warning ("Unable to stat log file \"%s\": %s",
self->filename, g_strerror (saved_errno));
reason_to_reopen = g_strerror (saved_errno);
}
if (!log_file_still_exists)
if (reason_to_reopen != NULL)
{
/* The log file is either deleted or replaced, probably by a
* developer who wanted to clear the logs out. Re-create it now
......@@ -1234,17 +1247,35 @@ logger_process_complete_line (SrtLogger *self,
glnx_autofd int new_fd = -1;
g_autoptr(GError) local_error = NULL;
g_info ("Re-opening \"%s\" because: %s",
self->filename, reason_to_reopen);
new_fd = TEMP_FAILURE_RETRY (open (self->filename,
OPEN_FLAGS,
0644));
if (new_fd < 0)
_srt_log_warning ("Unable to re-open log file: %s",
g_strerror (errno));
{
_srt_log_warning ("Unable to re-open log file: \"%s\": %s",
self->filename, g_strerror (errno));
}
/* Reuse current_stat (which might or might not be populated)
* for the device and inode of the replacement file */
else if (fstat (new_fd, &current_stat) < 0)
{
_srt_log_warning ("Unable to stat log file \"%s\": %s",
self->filename, g_strerror (errno));
}
else if (!lock_output_file (self->filename, new_fd, &local_error))
_srt_log_warning ("Unable to re-lock log file: %s",
local_error->message);
{
_srt_log_warning ("Unable to re-lock log file \"%s\": %s",
self->filename, local_error->message);
}
else
self->file_fd = glnx_steal_fd (&new_fd);
{
g_info ("Successfully re-opened \"%s\"", self->filename);
self->file_fd = glnx_steal_fd (&new_fd);
self->file_stat = current_stat;
}
}
else if (self->max_bytes > 0
&& (current_stat.st_size + len) > self->max_bytes)
......
......@@ -155,9 +155,9 @@ main () {
if [ "$theirs_should_be" != "$ours" ]; then
# Recover by unpacking a copy locally.
log "Recovering by unpacking $src.tar.xz* into ${here}/var/unpack..."
log "Recovering by unpacking $src.tar.xz into ${here}/var/unpack..."
mkdir -p "${here}/var/unpack"
cat "$src.tar.xz".* | tar -C "${here}/var/unpack" -Jxf-
tar -C "${here}/var/unpack" -Jxf "$src.tar.xz"
echo "$theirs_should_be" > "${here}/var/unpack/steam-runtime/checksum"
fi
......
# Contributing and maintenance
<!-- This file:
Copyright 2019-2020 Collabora Ltd.
Copyright 2019-2024 Collabora Ltd.
SPDX-License-Identifier: MIT
-->
......
libcapsule (0.20240806.0-0co1) upstream; urgency=medium
* capsule-capture-libs: Never undo our rewriting of the symlink target,
fixing a regression on NixOS (steam-runtime#684)
* capsule-capture-libs: Add --level-prefix option, which prepends a
severity indicator compatible with `systemd-cat --level-prefix=true`
(steamrt/tasks#444)
* capsule-capture-libs: Add "quiet:" pattern to suppress non-fatal
warnings for a particular library (steamrt/tasks#488)
* utils: Prepend basename of argv[0] to diagnostic messages
* utils: Consistently add error: or warning: prefix where appropriate
* tests: Improve coverage
-- Simon McVittie <smcv@collabora.com> Tue, 06 Aug 2024 13:37:16 +0100
libcapsule (0.20240520.0-0co1) upstream; urgency=medium
* utils: Allocate ld_libs on the heap, avoiding a segfault with
......
......@@ -42,6 +42,7 @@ our @EXPORT = qw(
run_verbose
skip_all_unless_bwrap
skip_all_unless_nm
$CAPSULE_CAPTURE_LIBS_BASENAME
$CAPSULE_CAPTURE_LIBS_TOOL
$CAPSULE_INIT_PROJECT_TOOL
$CAPSULE_SYMBOLS_TOOL
......@@ -86,6 +87,15 @@ if (! length $CAPSULE_CAPTURE_LIBS_TOOL) {
chomp $CAPSULE_CAPTURE_LIBS_TOOL;
}
=item $CAPSULE_CAPTURE_LIBS_BASENAME
The last path component of C<$CAPSULE_CAPTURE_LIBS_TOOL>.
=cut
our $CAPSULE_CAPTURE_LIBS_BASENAME = $CAPSULE_CAPTURE_LIBS_TOOL;
$CAPSULE_CAPTURE_LIBS_BASENAME =~ s{.*/}{};
=item $CAPSULE_INIT_PROJECT_TOOL
The B<capsule-init-project>(1) development tool.
......
......@@ -218,8 +218,10 @@ run_ok([$CAPSULE_CAPTURE_LIBS_TOOL, '--remap-link-prefix=/opt/=/OPT/',
$target = readlink "$libdir/libc.so.6";
diag("Expecting: $libdir/libc.so.6 -> $LIBDIR/libc.so.6");
diag("Actual: $libdir/libc.so.6 -> $target");
like($target, qr{^$LIBDIR/libc\.so\.6$},
"$libdir/libc.so.6 is a symlink to the real libc.so.6");
like($target, $libc_re,
"$libdir/libc.so.6 is a symlink to the real libc.so.6 in some form");
is(abs_path("$libdir/libc.so.6"), $libc_realpath,
"$libdir/libc.so.6 canonicalizes to $libc_realpath");
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
......@@ -514,6 +516,8 @@ SKIP: {
SKIP: {
my $multiarch;
my $other_multiarch;
my $stdout;
my $stderr;
# For simplicity, we only consider this case on x86.
skip "$ENV{CAPSULE_TESTS_GNU_HOST} not x86_64 or i386", 1
......@@ -538,9 +542,11 @@ SKIP: {
$CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/',
"--dest=$libdir", "--provider=$host",
"path:/usr/lib/$other_multiarch/libxml2.so.2"],
'>&2');
'>', \$stdout, '2>', \$stderr);
ok(! $result, 'library of wrong ABI yields an error');
ok(! -e "$libdir/libxml2.so.2");
is($stdout, '', 'no machine-readable output');
like($stderr, qr{^\Q$CAPSULE_CAPTURE_LIBS_BASENAME\E: error: }m, 'stderr shows error message');
# ... but when we're dealing with a glob match, other ABIs are silently
# ignored.
......@@ -568,6 +574,23 @@ SKIP: {
'>&2');
ok($result, 'library of wrong ABI ignored when using if-same-abi');
ok(! -e "$libdir/libxml2.so.2");
# If we use --level-prefix and repeat the failing case, there's a
# marker for the severity level
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
$result = run_verbose([qw(bwrap --ro-bind / / --ro-bind /), $host,
'--bind', $libdir, $libdir,
qw(--dev-bind /dev /dev),
$CAPSULE_CAPTURE_LIBS_TOOL,
'--level-prefix', '--link-target=/',
"--dest=$libdir", "--provider=$host",
"path:/usr/lib/$other_multiarch/libxml2.so.2"],
'>', \$stdout, '2>', \$stderr);
ok(! $result, 'library of wrong ABI yields an error');
ok(! -e "$libdir/libxml2.so.2");
is($stdout, '', 'no machine-readable output');
like($stderr, qr{^<3>\Q$CAPSULE_CAPTURE_LIBS_BASENAME\E: error: }m, 'stderr has severity prefix');
};
SKIP: {
......@@ -770,34 +793,46 @@ SKIP: {
'/run/host/opt/libunversionedsymbols.so.1.0.0',
"should take provider's version, even if the DT_SONAME is the unexpected libunversionedsymbols.so.1");
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
$result = run_verbose([qw(bwrap --ro-bind / /),
'--tmpfs', $host,
bind_usr('/', $host),
'--tmpfs', "$host/more",
'--tmpfs', $container,
bind_usr('/', $container),
'--ro-bind', $version1, "$host/opt",
'--ro-bind', $version2, "$container/opt",
'--symlink', "$host/opt/libunversionedsymbols.so.1", "$host/more/libunversionedsymbols.so.0",
'--bind', $libdir, $libdir,
qw(--dev-bind /dev /dev),
'env', 'CAPSULE_DEBUG=all',
"LD_LIBRARY_PATH=/opt:/more",
$CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/run/host',
"--dest=$libdir", "--provider=$host",
"--container=$container",
'if-exists:exact-soname:libunversionedsymbols.so.0',
'if-exists:exact-soname:libunversionedsymbols.so.1'],
'2>', \$stderr, '>&2');
diag $stderr;
ok($result);
ok (! -l "$libdir/libunversionedsymbols.so.0",
"should not take provider's version because the DT_SONAME is not the expected value");
is(tolerant_readlink("$libdir/libunversionedsymbols.so.1"),
'/run/host/opt/libunversionedsymbols.so.1.0.0',
"should take provider's version by default if name is the same");
foreach my $quiet_prefix ("", "quiet:") {
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
$result = run_verbose([qw(bwrap --ro-bind / /),
'--tmpfs', $host,
bind_usr('/', $host),
'--tmpfs', "$host/more",
'--tmpfs', $container,
bind_usr('/', $container),
'--ro-bind', $version1, "$host/opt",
'--ro-bind', $version2, "$container/opt",
'--symlink', "$host/opt/libunversionedsymbols.so.1", "$host/more/libunversionedsymbols.so.0",
'--bind', $libdir, $libdir,
qw(--dev-bind /dev /dev),
'env', 'CAPSULE_DEBUG=all',
"LD_LIBRARY_PATH=/opt:/more",
$CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/run/host',
"--dest=$libdir", "--provider=$host",
"--container=$container",
"${quiet_prefix}if-exists:exact-soname:libunversionedsymbols.so.0",
'if-exists:exact-soname:libunversionedsymbols.so.1'],
'2>', \$stderr, '>&2');
diag $stderr;
ok($result);
ok (! -l "$libdir/libunversionedsymbols.so.0",
"should not take provider's version because the DT_SONAME is not the expected value");
is(tolerant_readlink("$libdir/libunversionedsymbols.so.1"),
'/run/host/opt/libunversionedsymbols.so.1.0.0',
"should take provider's version by default if name is the same");
if ($quiet_prefix eq '') {
like($stderr,
qr{^\Q$CAPSULE_CAPTURE_LIBS_BASENAME\E: warning: libunversionedsymbols\.so\.0 has an unexpected DT_SONAME, ignoring: libunversionedsymbols\.so\.1$}m,
'stderr shows expected warning message');
}
else {
unlike($stderr, qr{warning:.*unexpected DT_SONAME, ignoring}m,
'"quiet:" de-escalates warning message to debug');
}
}
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
......@@ -817,12 +852,15 @@ SKIP: {
$CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/run/host',
"--dest=$libdir", "--provider=$host",
"--container=$container",
'exact-soname:libunversionedsymbols.so.0'],
"quiet:exact-soname:libunversionedsymbols.so.0"],
'2>', \$stderr, '>&2');
diag $stderr;
ok(! $result, 'library with the wrong DT_SONAME yields an error');
ok (! -l "$libdir/libunversionedsymbols.so.0",
"should not take provider's version because the DT_SONAME is not the expected value");
like($stderr,
qr{^\Q$CAPSULE_CAPTURE_LIBS_BASENAME\E: error: code [0-9]+: libunversionedsymbols\.so\.0 has an unexpected DT_SONAME: libunversionedsymbols\.so\.1$}m,
'"quiet:" does not suppress fatal error messages');
}
my $testlibs = "$builddir/tests";
......
......@@ -17,7 +17,6 @@
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
......@@ -112,6 +111,7 @@ enum
OPTION_COMPARE_BY,
OPTION_CONTAINER,
OPTION_DEST,
OPTION_LEVEL_PREFIX,
OPTION_LIBRARY_KNOWLEDGE,
OPTION_LINK_TARGET,
OPTION_NO_GLIBC,
......@@ -141,6 +141,7 @@ static struct option long_options[] =
{ "container", required_argument, NULL, OPTION_CONTAINER },
{ "dest", required_argument, NULL, OPTION_DEST },
{ "help", no_argument, NULL, 'h' },
{ "level-prefix", no_argument, NULL, OPTION_LEVEL_PREFIX },
{ "library-knowledge", required_argument, NULL, OPTION_LIBRARY_KNOWLEDGE },
{ "link-target", required_argument, NULL, OPTION_LINK_TARGET },
{ "no-glibc", no_argument, NULL, OPTION_NO_GLIBC },
......@@ -250,6 +251,8 @@ static void usage (int code)
"\tdeciding which libraries are needed [default: /]\n" );
fprintf( fh, "--dest=LIBDIR\n"
"\tCreate symlinks in LIBDIR [default: .]\n" );
fprintf( fh, "--level-prefix\n"
"\tAdd severity prefixes such as <3> to output\n" );
fprintf( fh, "--library-knowledge=FILE\n"
"\tLoad information about known libraries from a"
"\t.desktop-style file at FILE, overriding --compare-by.\n" );
......@@ -295,6 +298,8 @@ static void usage (int code)
fprintf( fh, "even-if-older:PATTERN\n"
"\tCapture PATTERN, even if the version in CONTAINER\n"
"\tappears newer\n" );
fprintf( fh, "quiet:PATTERN\n"
"\tCapture PATTERN, but don't warn for non-fatal issues\n" );
fprintf( fh, "gl:\n"
"\tShortcut for even-if-older:if-exists:soname:libGL.so.1,\n"
"\teven-if-older:if-exists:soname-match:libGLX_*.so.0, and\n"
......@@ -325,8 +330,33 @@ typedef enum
CAPTURE_FLAG_DEPENDENCIES = ( 1 << 3 ),
CAPTURE_FLAG_IF_SAME_ABI = ( 1 << 4 ),
CAPTURE_FLAG_IF_EXACT_SONAME = ( 1 << 5 ),
CAPTURE_FLAG_QUIET = ( 1 << 6 ),
} capture_flags;
static void maybe_warn( capture_flags flags, const char *fmt, ... ) __attribute__((__format__(__printf__, 2, 3)));
static void
maybe_warn( capture_flags flags, const char *fmt, ... )
{
va_list ap;
va_start( ap, fmt );
if( flags & CAPTURE_FLAG_QUIET )
{
if( debug_flags & DEBUG_TOOL )
{
capsule_logv( LOG_DEBUG, fmt, ap );
}
}
else
{
capsule_logv( LOG_WARNING, fmt, ap );
}
va_end( ap );
}
typedef struct
{
capture_flags flags;
......@@ -454,8 +484,9 @@ capture_one( const char *soname, const capture_options *options,
{
if( ( options->flags & CAPTURE_FLAG_IF_EXISTS ) )
{
warnx( "warning: Unable to obtain the library %s DT_SONAME, ignoring",
soname );
maybe_warn( options->flags,
"Unable to obtain the library %s DT_SONAME, ignoring",
soname );
return true;
}
......@@ -470,8 +501,9 @@ capture_one( const char *soname, const capture_options *options,
{
if( ( options->flags & CAPTURE_FLAG_IF_EXISTS ) )
{
warnx( "warning: %s has an unexpected DT_SONAME, ignoring: %s",
soname, dt_soname );
maybe_warn( options->flags,
"%s has an unexpected DT_SONAME, ignoring: %s",
soname, dt_soname );
return true;
}
......@@ -487,8 +519,9 @@ capture_one( const char *soname, const capture_options *options,
{
if( ( options->flags & CAPTURE_FLAG_IF_EXISTS ) && local_code == ENOENT )
{
warnx( "warning: Dependencies of %s not found, ignoring: %s",
soname, local_message );
maybe_warn( options->flags,
"Dependencies of %s not found, ignoring: %s",
soname, local_message );
_capsule_clear( &local_message );
return true;
}
......@@ -505,7 +538,6 @@ capture_one( const char *soname, const capture_options *options,
const char *needed_name = provider->needed[i].name;
const char *needed_path_in_provider = provider->needed[i].path;
const char *needed_basename;
bool remapped_prefix = false;
if( !needed_name )
{
......@@ -709,8 +741,8 @@ capture_one( const char *soname, const capture_options *options,
if( strncmp( path, option_provider, prefix_len ) != 0 ||
path[prefix_len] != '/' )
{
warnx( "warning: \"%s\" is not within prefix \"%s\"",
path, option_provider );
capsule_warn( "\"%s\" is not within prefix \"%s\"",
path, option_provider );
continue;
}
......@@ -730,18 +762,14 @@ capture_one( const char *soname, const capture_options *options,
target + strlen( remap_prefix[j].from ) );
free( target );
target = tmp;
remapped_prefix = true;
}
}
}
// If we don't have the link target option and we didn't remap the
// prefix, we just set the target to the needed path in provider
// without following the eventual link chain
if( !remapped_prefix && option_link_target == NULL )
else
{
if( target != NULL )
free( target );
/* No need to remap anything or canonicalize the path,
* because we're going to use it from the same view of the
* filesystem that we're currently in. */
target = xstrdup( needed_path_in_provider );
}
......@@ -752,8 +780,8 @@ capture_one( const char *soname, const capture_options *options,
if( symlinkat( target, dest_fd, needed_basename ) < 0 )
{
warn( "warning: cannot create symlink %s/%s",
option_dest, needed_basename );
capsule_warn( "cannot create symlink %s/%s: %s",
option_dest, needed_basename, strerror( errno ) );
}
if( strcmp( needed_basename, "libc.so.6" ) == 0 )
......@@ -802,7 +830,7 @@ cache_foreach_cb (const char *name, int flag, unsigned int osv,
if( !name || !*name )
{
warnx( "warning: empty name found in ld.so.cache" );
capsule_warn( "empty name found in ld.so.cache" );
return 0;
}
......@@ -1121,6 +1149,15 @@ capture_pattern( const char *pattern, const capture_options *options,
&new_options, code, message );
}
if( strstarts( pattern, "quiet:" ) )
{
capture_options new_options = *options;
new_options.flags |= CAPTURE_FLAG_QUIET;
return capture_pattern( pattern + strlen( "quiet:" ),
&new_options, code, message );
}
if( strcmp( pattern, "gl:" ) == 0 )
{
// Useful information:
......@@ -1348,7 +1385,7 @@ main (int argc, char **argv)
case OPTION_LIBRARY_KNOWLEDGE:
if( option_library_knowledge != NULL )
errx( 1, "--library-knowledge can only be used once" );
capsule_err( 1, "--library-knowledge can only be used once" );
option_library_knowledge = optarg;
break;
......@@ -1357,6 +1394,10 @@ main (int argc, char **argv)
option_link_target = optarg;
break;
case OPTION_LEVEL_PREFIX:
capsule_level_prefix = 1;
break;
case OPTION_PRINT_LD_SO:
puts( LD_SO );
goto out;
......@@ -1375,7 +1416,7 @@ main (int argc, char **argv)
case OPTION_REMAP_LINK_PREFIX:
if( strchr( optarg, '=' ) == NULL )
errx( 1, "--remap-link-prefix value must follow the FROM=TO pattern" );
capsule_err( 1, "--remap-link-prefix value must follow the FROM=TO pattern" );
ptr_list_push_ptr( remap_list, xstrdup( optarg ) );
break;
......@@ -1388,7 +1429,7 @@ main (int argc, char **argv)
if( !resolve_ld_so( optarg, path, &within_prefix,
&code, &message ) )
{
errx( 1, "code %d: %s", code, message );
capsule_err( 1, "code %d: %s", code, message );
}
puts( within_prefix );
......@@ -1400,7 +1441,7 @@ main (int argc, char **argv)
if( optind >= argc )
{
warnx( "One or more patterns must be provided" );
capsule_warn( "One or more patterns must be provided" );
usage( 2 );
}
......@@ -1417,7 +1458,7 @@ main (int argc, char **argv)
{
free( buf );
free_strv_full( remap_array );
errx( 1, "--remap-link-prefix value must follow the FROM=TO pattern" );
capsule_err( 1, "--remap-link-prefix value must follow the FROM=TO pattern" );
}
*equals = '\0';
remap_prefix[i].from = buf;
......@@ -1433,7 +1474,7 @@ main (int argc, char **argv)
mkdir( option_dest, 0755 ) < 0 &&
errno != EEXIST )
{
err( 1, "creating \"%s\"", option_dest );
capsule_err( 1, "creating \"%s\": %s", option_dest, strerror( errno ) );
}
options.comparators = library_cmp_list_from_string( option_compare_by, ",",
......@@ -1441,7 +1482,7 @@ main (int argc, char **argv)
if( options.comparators == NULL )
{
errx( 1, "code %d: %s", code, message );
capsule_err( 1, "code %d: %s", code, message );
}
if( option_library_knowledge != NULL )
......@@ -1450,14 +1491,14 @@ main (int argc, char **argv)
if( fh == NULL)
{
err( 1, "opening \"%s\"", option_library_knowledge );
capsule_err( 1, "opening \"%s\": %s", option_library_knowledge, strerror( errno ) );
}
if( !library_knowledge_load_from_stream( &options.knowledge,
fh, option_library_knowledge,
&code, &message ) )
{
errx( 1, "code %d: %s", code, message );
capsule_err( 1, "code %d: %s", code, message );
}
fclose( fh );
......@@ -1467,12 +1508,12 @@ main (int argc, char **argv)
if( dest_fd < 0 )
{
err( 1, "opening \"%s\"", option_dest );
capsule_err( 1, "opening \"%s\": %s", option_dest, strerror( errno ) );
}
if( !capture_patterns( arg_patterns, &options, &code, &message ) )
{
errx( 1, "code %d: %s", code, message );
capsule_err( 1, "code %d: %s", code, message );
}
close( dest_fd );
......
......@@ -18,6 +18,9 @@
#pragma once
#include <stdarg.h>
#include <syslog.h>
enum
{
DEBUG_NONE = 0,
......@@ -36,11 +39,24 @@ enum
#define LDLIB_DEBUG(ldl, flags, fmt, args...) \
if( ldl->debug && (ldl->debug & (flags)) ) \
fprintf( stderr, "%s:" fmt "\n", __PRETTY_FUNCTION__, ##args )
capsule_log( LOG_DEBUG, "%s:" fmt, __PRETTY_FUNCTION__, ##args )
#define DEBUG(flags, fmt, args...) \
if( debug_flags && (debug_flags & (flags)) ) \
fprintf( stderr, "%s:" fmt "\n", __PRETTY_FUNCTION__, ##args )
capsule_log( LOG_DEBUG, "%s:" fmt, __PRETTY_FUNCTION__, ##args )
extern unsigned long debug_flags;
void set_debug_flags (const char *control);
extern int capsule_level_prefix;
void capsule_log (int log_level, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
void capsule_logv (int log_level, const char *fmt, va_list ap) __attribute__((__format__(__printf__, 2, 0)));
#define capsule_err(status, fmt, args...) \
do { \
capsule_log( LOG_ERR, fmt, ##args ); \
exit (status); \
} while (0)
#define capsule_warn(fmt, args...) \
capsule_log( LOG_WARNING, fmt, ##args )
......@@ -18,7 +18,6 @@
#include "library-cmp.h"
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
......@@ -1134,8 +1133,8 @@ library_cmp_filter_list( char ** const filters,
if( fnmatch( filters[j] + 1, element, 0 ) == 0 )
{
if( guessing )
warnx( "warning: we are assuming \"%s\" to be private, but it's just a guess",
element );
capsule_warn( "we are assuming \"%s\" to be private, but it's just a guess",
element );
else
DEBUG( DEBUG_TOOL,
"Ignoring \"%s\" because it has been declared as private",
......@@ -1148,8 +1147,8 @@ library_cmp_filter_list( char ** const filters,
if( fnmatch( filters[j], element, 0 ) == 0 )
{
if( guessing )
warnx( "warning: we are assuming \"%s\" to be public, but it's just a guess",
element );
capsule_warn( "we are assuming \"%s\" to be public, but it's just a guess",
element );
ptr_list_push_ptr( filtered_list, xstrdup( list[i] ) );
break;
......@@ -1158,8 +1157,8 @@ library_cmp_filter_list( char ** const filters,
}
/* If we checked all the patterns and didn't have a match */
if( filters[j] == NULL )
warnx( "warning: \"%s\" does not have a match in the given filters, treating it as private",
token );
capsule_warn( "\"%s\" does not have a match in the given filters, treating it as private",
token );
}
free( buf );
......@@ -1219,8 +1218,8 @@ library_cmp_by_symbols( const library_details *details,
if( container_symbols == NULL )
{
warnx( "failed to get container versions for %s (%d): %s",
details->name, code, message );
capsule_warn( "failed to get container versions for %s (%d): %s",
details->name, code, message );
goto out;
}
......@@ -1256,8 +1255,8 @@ library_cmp_by_symbols( const library_details *details,
if( provider_symbols == NULL )
{
warnx( "failed to get provider versions for %s (%d): %s",
details->name, code, message );
capsule_warn( "failed to get provider versions for %s (%d): %s",
details->name, code, message );
goto out;
}
......@@ -1375,8 +1374,8 @@ library_cmp_by_versions( const library_details *details,
if( container_versions == NULL )
{
warnx( "failed to get container versions for %s (%d): %s",
details->name, code, message );
capsule_warn( "failed to get container versions for %s (%d): %s",
details->name, code, message );
goto out;
}
......@@ -1412,8 +1411,8 @@ library_cmp_by_versions( const library_details *details,
if( provider_versions == NULL )
{
warnx( "failed to get provider versions for %s (%d): %s",
details->name, code, message );
capsule_warn( "failed to get provider versions for %s (%d): %s",
details->name, code, message );
goto out;
}
......
......@@ -17,6 +17,7 @@
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#include <assert.h>
#include <errno.h>
#include <sys/param.h>
#include <unistd.h>
#include <fcntl.h>
......@@ -27,6 +28,7 @@
#include "debug.h"
#include "utils.h"
int capsule_level_prefix = 0;
unsigned long debug_flags;
// ==========================================================================
......@@ -725,3 +727,61 @@ _capsule_basename (const char *path)
assert( ret[0] == '/' );
return ret + 1;
}
/*
* capsule_logv:
* @severity: A `syslog.h` severity constant such as `LOG_ERR`
* @fmt: A printf-style format string
* @ap: Arguments for @fmt
*
* Log the message @fmt, substituting the given arguments.
* If enabled globally, a severity prefix compatible with
* `systemd-cat --level-prefix=true` is prepended.
* The basename of argv[0] is prepended, similar to warnx().
* If the severity is `LOG_WARNING` or more serious (numerically smaller),
* `error: ` or `warning: ` is prepended and should not be included in @fmt.
* A newline is appended automatically and should not be included in @fmt.
*
* Unlike `errx()` and `g_error()`, this does not immediately exit,
* even if the severity indicates a fatal error (the caller must do that,
* if desired).
*/
void
capsule_logv( int severity, const char *fmt, va_list ap )
{
/* libcapsule tools are single-threaded, so it's an acceptable
* simplification that we do not emit the whole message atomically. */
if( capsule_level_prefix )
fprintf( stderr, "<%d>", severity );
fprintf( stderr, "%s: ", program_invocation_short_name );
/* This looks wrong, but is the right way round: more serious errors
* are numerically smaller. */
if( severity <= LOG_ERR )
fprintf( stderr, "error: " );
else if( severity == LOG_WARNING )
fprintf( stderr, "warning: " );
vfprintf( stderr, fmt, ap );
fputc( '\n', stderr );
}
/*
* capsule_log:
* @severity: A `syslog.h` severity constant such as `LOG_ERR`
* @fmt: A printf-style format string
* @...: Arguments for @fmt
*
* Same as capsule_logv(), but with varargs.
*/
void
capsule_log( int severity, const char *fmt, ... )
{
va_list ap;
va_start( ap, fmt );
capsule_logv( severity, fmt, ap );
va_end( ap );
}