Commit 1decbc12 authored by Simon McVittie's avatar Simon McVittie

utils: Add --help, --version and GNU argument parsing to all tools

They now all take named options (including the -- pseudo-option) for
future expansion, and fail with an error if given too many positional
parameters.

When libcapsule tools are bundled with a larger project, this should
make it easier to check which ones they are.
Signed-off-by: Simon McVittie's avatarSimon McVittie <smcv@collabora.com>
parent 4932c006
......@@ -17,6 +17,7 @@
AUTOMAKE_OPTIONS = subdir-objects
ACLOCAL_AMFLAGS = -I m4 --install
AM_CPPFLAGS = -DHOST_PREFIX=\"$(HOST_PREFIX)\"
AM_CFLAGS = -fvisibility=hidden \
--std=c99 \
$(WARN_CFLAGS) \
......@@ -94,22 +95,23 @@ utils_libld_la_LIBADD = utils/libutils.la -ldl $(LIBELF_LIBS)
bin_PROGRAMS += capsule-elf-dump
capsule_elf_dump_SOURCES = utils/elf-dump.c utils/dump.c
capsule_elf_dump_SOURCES += utils/tools.c utils/tools.h
capsule_elf_dump_LDADD = utils/libutils.la -ldl
# This looks redundant, but it forces Automake to build separate
# instantiations of dump.o for elf-dump and libcapsule
capsule_elf_dump_CFLAGS = $(AM_CFLAGS)
capsule_elf_dump_LDFLAGS = $(AM_LDFLAGS) $(tools_ldflags)
capsule_capture_libs_SOURCES = utils/capture-libs.c
capsule_capture_libs_SOURCES = utils/capture-libs.c utils/tools.c utils/tools.h
capsule_capture_libs_LDADD = utils/libld.la
capsule_capture_libs_LDFLAGS = $(AM_LDFLAGS) $(tools_ldflags)
# now the rules for building our installables:
capsule_symbols_SOURCES = utils/print-libstubs.c
capsule_symbols_SOURCES = utils/print-libstubs.c utils/tools.c utils/tools.h
capsule_symbols_LDADD = utils/libld.la
capsule_symbols_LDFLAGS = $(AM_LDFLAGS) $(tools_ldflags)
capsule_version_SOURCES = utils/print-version.c
capsule_version_SOURCES = utils/print-version.c utils/tools.c utils/tools.h
capsule_version_LDADD = utils/libld.la
capsule_version_LDFLAGS = $(AM_LDFLAGS) $(tools_ldflags)
......
......@@ -32,6 +32,7 @@
#include "debug.h"
#include "ld-libs.h"
#include "tools.h"
#include "utils.h"
// We only really care about x86 here because that's the only thing
......@@ -92,6 +93,7 @@ enum
OPTION_PRINT_LD_SO,
OPTION_PROVIDER,
OPTION_RESOLVE_LD_SO,
OPTION_VERSION,
};
static const char * const *arg_patterns = NULL;
......@@ -111,6 +113,7 @@ static struct option long_options[] =
{ "print-ld.so", no_argument, NULL, OPTION_PRINT_LD_SO },
{ "provider", required_argument, NULL, OPTION_PROVIDER },
{ "resolve-ld.so", required_argument, NULL, OPTION_RESOLVE_LD_SO },
{ "version", no_argument, NULL, OPTION_VERSION },
{ NULL }
};
......@@ -1034,6 +1037,10 @@ main (int argc, char **argv)
option_glibc = false;
break;
case OPTION_VERSION:
_capsule_tools_print_version( "capsule-capture-libs" );
return 0;
case OPTION_RESOLVE_LD_SO:
{
char path[PATH_MAX] = { 0 };
......
......@@ -17,12 +17,48 @@
#include <dlfcn.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "dump.h"
#include "tools.h"
static void usage (int code) __attribute__((noreturn));
static void usage (int code)
{
FILE *fh;
if( code == 0 )
{
fh = stdout;
}
else
{
fh = stderr;
}
fprintf( fh, "Usage: %s SONAME\n",
program_invocation_short_name );
fprintf( fh, "SONAME is the machine-readable name of a shared library,\n"
"for example 'libz.so.1'.\n" );
exit( code );
}
enum
{
OPTION_HELP,
OPTION_VERSION,
};
static struct option long_options[] =
{
{ "help", no_argument, NULL, OPTION_HELP },
{ "version", no_argument, NULL, OPTION_VERSION },
{ NULL }
};
int main (int argc, char **argv)
{
......@@ -31,26 +67,49 @@ int main (int argc, char **argv)
set_debug_flags( getenv("CAPSULE_DEBUG") );
if( argc < 2 )
while( 1 )
{
fprintf( stderr, "usage: %s <ELF-DSO>\n", argv[0] );
exit( 1 );
int opt = getopt_long( argc, argv, "", long_options, NULL );
if( opt == -1 )
{
break;
}
switch( opt )
{
case '?':
default:
usage( 2 );
break; // not reached
case OPTION_HELP:
usage( 0 );
break; // not reached
case OPTION_VERSION:
_capsule_tools_print_version( "capsule-elf-dump" );
return 0;
}
}
handle = dlopen( argv[1], RTLD_LAZY );
if( argc != optind + 1 )
usage( 1 );
handle = dlopen( argv[optind], RTLD_LAZY );
if( !handle )
{
int e = errno;
const char *err = dlerror();
fprintf( stderr, "%s: dlopen failed (%s)\n", argv[0], err );
fprintf( stderr, "%s: dlopen failed (%s)\n", program_invocation_short_name, err );
return e ? e : ENOENT;
}
if( (libname = strrchr( argv[1], '/' )) )
if( (libname = strrchr( argv[optind], '/' )) )
libname = libname + 1;
else
libname = argv[1];
libname = argv[optind];
dump_elf_data( libname );
......
......@@ -16,6 +16,7 @@
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#include <dlfcn.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
......@@ -30,10 +31,33 @@
#include <link.h>
#include "tools.h"
#include "utils.h"
#include "ld-cache.h"
#include "ld-libs.h"
static void usage (int code) __attribute__((noreturn));
static void usage (int code)
{
FILE *fh;
if( code == 0 )
{
fh = stdout;
}
else
{
fh = stderr;
}
fprintf( fh, "Usage: %s SONAME [SYSROOT]\n",
program_invocation_short_name );
fprintf( fh, "SONAME is the machine-readable name of a shared library,\n"
"for example 'libz.so.1'.\n" );
fprintf( fh, "SYSROOT is the root directory where we look for SONAME.\n" );
exit( code );
}
typedef struct
{
size_t plen;
......@@ -288,6 +312,19 @@ dump_symbols (void *handle, const char *libname)
}
enum
{
OPTION_HELP,
OPTION_VERSION,
};
static struct option long_options[] =
{
{ "help", no_argument, NULL, OPTION_HELP },
{ "version", no_argument, NULL, OPTION_VERSION },
{ NULL }
};
int main (int argc, char **argv)
{
const char *libname;
......@@ -298,38 +335,61 @@ int main (int argc, char **argv)
Lmid_t ns = LM_ID_BASE;
void *handle;
if( argc < 2 )
while( 1 )
{
fprintf( stderr, "usage: %s <ELF-DSO> [/path/prefix]\n", argv[0] );
exit( 1 );
int opt = getopt_long( argc, argv, "", long_options, NULL );
if( opt == -1 )
{
break;
}
switch( opt )
{
case '?':
default:
usage( 2 );
break; // not reached
case OPTION_HELP:
usage( 0 );
break; // not reached
case OPTION_VERSION:
_capsule_tools_print_version( "capsule-symbols" );
return 0;
}
}
set_debug_flags( getenv("CAPSULE_DEBUG") );
if( argc < optind + 1 || argc > optind + 2)
usage( 1 );
if( argc > 2 )
prefix = argv[2];
if( argc > optind + 1 )
prefix = argv[optind + 1];
set_debug_flags( getenv("CAPSULE_DEBUG") );
if( !ld_libs_init( &ldlibs, NULL, prefix, 0, &error, &message ) )
{
fprintf( stderr, "%s: failed to initialize for prefix %s (%d: %s)\n",
argv[0], argv[2], error, message );
program_invocation_short_name, prefix, error, message );
exit( error ? error : ENOENT );
}
if( !ld_libs_set_target( &ldlibs, argv[1], &error, &message ) ||
if( !ld_libs_set_target( &ldlibs, argv[optind], &error, &message ) ||
!ld_libs_find_dependencies( &ldlibs, &error, &message ) )
{
fprintf( stderr, "%s: failed to open [%s]%s (%d: %s)\n",
argv[0], argv[2], argv[1], error, message );
program_invocation_short_name, prefix, argv[optind], error, message );
exit( error ? error : ENOENT );
}
if( ( handle = ld_libs_load( &ldlibs, &ns, 0, &error, &message ) ) )
{
if( (libname = strrchr( argv[1], '/' )) )
if( (libname = strrchr( argv[optind], '/' )) )
libname = libname + 1;
else
libname = argv[1];
libname = argv[optind];
// dl_iterate_phdr won't work with private dlmopen namespaces:
dump_symbols( handle, libname );
......@@ -337,7 +397,7 @@ int main (int argc, char **argv)
else
{
fprintf( stderr, "%s: failed to open [%s]%s (%d: %s)\n",
argv[0], argv[2], argv[1], error, message );
program_invocation_short_name, prefix, argv[optind], error, message );
exit(error ? error : ENOENT);
}
......
......@@ -16,6 +16,7 @@
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#include <dlfcn.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
......@@ -24,6 +25,42 @@
#include "debug.h"
#include "ld-cache.h"
#include "ld-libs.h"
#include "tools.h"
static void usage (int code) __attribute__((noreturn));
static void usage (int code)
{
FILE *fh;
if( code == 0 )
{
fh = stdout;
}
else
{
fh = stderr;
}
fprintf( fh, "Usage: %s SONAME [SYSROOT]\n",
program_invocation_short_name );
fprintf( fh, "SONAME is the machine-readable name of a shared library,\n"
"for example 'libz.so.1'.\n" );
fprintf( fh, "SYSROOT is the root directory where we look for SONAME.\n" );
exit( code );
}
enum
{
OPTION_HELP,
OPTION_VERSION,
};
static struct option long_options[] =
{
{ "help", no_argument, NULL, OPTION_HELP },
{ "version", no_argument, NULL, OPTION_VERSION },
{ NULL }
};
int main (int argc, char **argv)
{
......@@ -36,31 +73,54 @@ int main (int argc, char **argv)
set_debug_flags( getenv("CAPSULE_DEBUG") );
if( argc < 2 )
while( 1 )
{
fprintf( stderr, "usage: %s <ELF-DSO> [/path/prefix]\n", argv[0] );
exit( 1 );
int opt = getopt_long( argc, argv, "", long_options, NULL );
if( opt == -1 )
{
break;
}
switch( opt )
{
case '?':
default:
usage( 2 );
break; // not reached
case OPTION_HELP:
usage( 0 );
break; // not reached
case OPTION_VERSION:
_capsule_tools_print_version( "capsule-version" );
return 0;
}
}
if( argc > 2 )
prefix = argv[2];
if( argc < optind + 1 || argc > optind + 2)
usage( 1 );
if( argc > optind + 1 )
prefix = argv[optind + 1];
if( !ld_libs_init( &ldlibs, NULL, prefix, 0, &error, &message ) )
{
fprintf( stderr, "%s: failed to initialize for prefix %s (%d: %s)\n",
argv[0], argv[2], error, message );
program_invocation_short_name, prefix, error, message );
exit( error ? error : ENOENT );
}
if( ld_libs_set_target( &ldlibs, argv[1], &error, &message ) )
if( ld_libs_set_target( &ldlibs, argv[optind], &error, &message ) )
{
const char *path;
const char *buf;
if( (libname = strrchr( argv[1], '/' )) )
if( (libname = strrchr( argv[optind], '/' )) )
libname = libname + 1;
else
libname = argv[1];
libname = argv[optind];
path = &ldlibs.needed[0].path[0];
......@@ -85,7 +145,7 @@ int main (int argc, char **argv)
else
{
fprintf( stderr, "%s: failed to open [%s]%s (%d: %s)\n",
argv[0], argv[2], argv[1], error, message );
program_invocation_short_name, prefix, argv[optind], error, message );
exit( error ? error : ENOENT );
}
......
// Copyright © 2017-2019 Collabora Ltd
// This file is part of libcapsule.
// libcapsule is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
// libcapsule is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#include "tools.h"
#include <stdio.h>
void
_capsule_tools_print_version( const char *command )
{
/* This is actually valid/parseable YAML, so that it's both
* human-readable and machine-readable. Inspired by `docker version`
* and `ostree --version`. */
printf( "%s%s:\n", HOST_PREFIX, command );
printf( " Package: %s\n", PACKAGE_TARNAME );
printf( " Version: '%s'\n", PACKAGE_VERSION );
}
// Copyright © 2017-2019 Collabora Ltd
// This file is part of libcapsule.
// libcapsule is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
// libcapsule is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#pragma once
void _capsule_tools_print_version( const char *command );
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment