From a9790a21302f47016a88ba9a2c904bed11efb388 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 29 Jan 2013 11:43:09 +0100 Subject: Make the p11-kit tool have distinct commands * Change the -l argument into the list-modules command. * Add proper functions for printing usage * Support for external commands in the path or /usr/share/p11-kit --- tools/Makefile.am | 9 +- tools/list.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++ tools/p11-kit.c | 273 ------------------------------------------- tools/tool.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/tool.h | 56 +++++++++ 5 files changed, 692 insertions(+), 275 deletions(-) create mode 100644 tools/list.c delete mode 100644 tools/p11-kit.c create mode 100644 tools/tool.c create mode 100644 tools/tool.h (limited to 'tools') diff --git a/tools/Makefile.am b/tools/Makefile.am index 44b8432..43adf56 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -6,17 +6,22 @@ INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/common \ -I$(top_srcdir)/p11-kit \ - -DSRCDIR=\"$(srcdir)\" + -DSRCDIR=\"$(srcdir)\" \ + -DPKGDATADIR=\"$(pkgdatadir)\" \ + -DP11_KIT_FUTURE_UNSTABLE_API \ + $(NULL) bin_PROGRAMS = \ p11-kit p11_kit_SOURCES = \ - p11-kit.c \ + list.c \ + tool.c tool.h \ $(NULL) p11_kit_LDADD = \ $(top_builddir)/p11-kit/libp11-kit.la \ + $(top_builddir)/common/libp11-library.la \ $(top_builddir)/common/libp11-compat.la \ $(LTLIBINTL) \ $(NULL) diff --git a/tools/list.c b/tools/list.c new file mode 100644 index 0000000..8430d78 --- /dev/null +++ b/tools/list.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "compat.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include + +#include "library.h" +#include "p11-kit.h" +#include "tool.h" +#include "uri.h" + +typedef int (*operation) (int argc, char *argv[]); +bool verbose = false; + +static const char HEXC_LOWER[] = "0123456789abcdef"; + +static char * +hex_encode (const unsigned char *data, + size_t n_data) +{ + char *result; + size_t i; + size_t o; + + result = malloc (n_data * 3 + 1); + if (result == NULL) + return NULL; + + for (i = 0, o = 0; i < n_data; i++) { + if (i > 0) + result[o++] = ':'; + result[o++] = HEXC_LOWER[data[i] >> 4 & 0xf]; + result[o++] = HEXC_LOWER[data[i] & 0xf]; + } + + result[o] = 0; + return result; +} + +static bool +is_ascii_string (const unsigned char *data, + size_t n_data) +{ + size_t i; + + for (i = 0; i < n_data; i++) { + if (!isascii (data[i]) && + (data[i] < 0x20 && !isspace (data[i]))) + return false; + } + + return true; +} + +static void +print_token_info (CK_FUNCTION_LIST_PTR module, CK_SLOT_ID slot_id) +{ + CK_TOKEN_INFO info; + char *value; + CK_RV rv; + + rv = (module->C_GetTokenInfo) (slot_id, &info); + if (rv != CKR_OK) { + p11_message ("couldn't load module info: %s", p11_kit_strerror (rv)); + return; + } + + value = p11_kit_space_strdup (info.label, sizeof (info.label)); + printf (" token: %s\n", value); + free (value); + + value = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID)); + printf (" manufacturer: %s\n", value); + free (value); + + value = p11_kit_space_strdup (info.model, sizeof (info.model)); + printf (" model: %s\n", value); + free (value); + + if (is_ascii_string (info.serialNumber, sizeof (info.serialNumber))) + value = p11_kit_space_strdup (info.serialNumber, sizeof (info.serialNumber)); + else + value = hex_encode (info.serialNumber, sizeof (info.serialNumber)); + printf (" serial-number: %s\n", value); + free (value); + + if (info.hardwareVersion.major || info.hardwareVersion.minor) + printf (" hardware-version: %d.%d\n", + info.hardwareVersion.major, + info.hardwareVersion.minor); + + if (info.firmwareVersion.major || info.firmwareVersion.minor) + printf (" firmware-version: %d.%d\n", + info.firmwareVersion.major, + info.firmwareVersion.minor); + + printf (" flags:\n"); + #define X(x, y) if (info.flags & (x)) printf (" %s\n", (y)) + X(CKF_RNG, "rng"); + X(CKF_WRITE_PROTECTED, "write-protected"); + X(CKF_LOGIN_REQUIRED, "login-required"); + X(CKF_USER_PIN_INITIALIZED, "user-pin-initialized"); + X(CKF_RESTORE_KEY_NOT_NEEDED, "restore-key-not-needed"); + X(CKF_CLOCK_ON_TOKEN, "clock-on-token"); + X(CKF_PROTECTED_AUTHENTICATION_PATH, "protected-authentication-path"); + X(CKF_DUAL_CRYPTO_OPERATIONS, "dual-crypto-operations"); + X(CKF_TOKEN_INITIALIZED, "token-initialized"); + X(CKF_SECONDARY_AUTHENTICATION, "secondary-authentication"); + X(CKF_USER_PIN_COUNT_LOW, "user-pin-count-low"); + X(CKF_USER_PIN_FINAL_TRY, "user-pin-final-try"); + X(CKF_USER_PIN_LOCKED, "user-pin-locked"); + X(CKF_USER_PIN_TO_BE_CHANGED, "user-pin-to-be-changed"); + X(CKF_SO_PIN_COUNT_LOW, "so-pin-count-low"); + X(CKF_SO_PIN_FINAL_TRY, "so-pin-final-try"); + X(CKF_SO_PIN_LOCKED, "so-pin-locked"); + X(CKF_SO_PIN_TO_BE_CHANGED, "so-pin-to-be-changed"); + #undef X +} + +static void +print_module_info (CK_FUNCTION_LIST_PTR module) +{ + CK_SLOT_ID slot_list[256]; + CK_ULONG i, count; + CK_INFO info; + char *value; + CK_RV rv; + + rv = (module->C_GetInfo) (&info); + if (rv != CKR_OK) { + p11_message ("couldn't load module info: %s", p11_kit_strerror (rv)); + return; + } + + value = p11_kit_space_strdup (info.libraryDescription, + sizeof (info.libraryDescription)); + printf (" library-description: %s\n", value); + free (value); + + value = p11_kit_space_strdup (info.manufacturerID, + sizeof (info.manufacturerID)); + printf (" library-manufacturer: %s\n", value); + free (value); + + printf (" library-version: %d.%d\n", + info.libraryVersion.major, + info.libraryVersion.minor); + + count = sizeof (slot_list) / sizeof (slot_list[0]); + rv = (module->C_GetSlotList) (CK_TRUE, slot_list, &count); + if (rv != CKR_OK) { + p11_message ("couldn't load module info: %s", p11_kit_strerror (rv)); + return; + } + + for (i = 0; i < count; i++) + print_token_info (module, slot_list[i]); +} + +static int +print_modules (void) +{ + CK_FUNCTION_LIST_PTR *module_list; + char *name; + char *path; + CK_RV rv; + int i; + + rv = p11_kit_initialize_registered (); + if (rv != CKR_OK) { + p11_message ("couldn't initialize registered modules: %s", + p11_kit_strerror (rv)); + return 1; + } + + module_list = p11_kit_registered_modules (); + for (i = 0; module_list[i]; i++) { + name = p11_kit_registered_module_to_name (module_list[i]); + path = p11_kit_registered_option (module_list[i], "module"); + + printf ("%s: %s\n", + name ? name : "(null)", + path ? path : "(null)"); + print_module_info (module_list[i]); + + free (name); + free (path); + } + free (module_list); + + p11_kit_finalize_registered (); + return 0; +} + +int +p11_tool_list_modules (int argc, + char *argv[]) +{ + int opt; + + enum { + opt_verbose = 'v', + opt_quiet = 'q', + opt_list = 'l', + opt_help = 'h', + }; + + struct option options[] = { + { "verbose", no_argument, NULL, opt_verbose }, + { "quiet", no_argument, NULL, opt_quiet }, + { "list", no_argument, NULL, opt_list }, + { "help", no_argument, NULL, opt_help }, + { 0 }, + }; + + p11_tool_desc usages[] = { + { 0, "usage: p11-kit list" }, + { opt_verbose, "show verbose debug output", }, + { opt_quiet, "supress command output", }, + { 0 }, + }; + + while ((opt = p11_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { + + /* Ignore these options, already handled */ + case opt_verbose: + case opt_quiet: + case opt_list: + break; + + case opt_help: + p11_tool_usage (usages, options); + return 0; + case '?': + return 2; + default: + assert_not_reached (); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc != 0) { + p11_message ("extra arguments specified"); + return 2; + } + + return print_modules (); +} diff --git a/tools/p11-kit.c b/tools/p11-kit.c deleted file mode 100644 index f789fb8..0000000 --- a/tools/p11-kit.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2011, Collabora Ltd. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Author: Stef Walter - */ - -#include "config.h" - -#include "compat.h" - -#include -#include -#include -#include -#include -#include - -#include "p11-kit/p11-kit.h" -#include "p11-kit/uri.h" - -typedef int (*operation) (int argc, char *argv[]); -bool verbose = false; - -static void -usage (void) -{ - fprintf (stderr, "usage: p11-kit [-v] -l\n"); - fprintf (stderr, " p11-kit -h\n"); - exit (2); -} - -static const char HEXC_LOWER[] = "0123456789abcdef"; - -static char * -hex_encode (const unsigned char *data, - size_t n_data) -{ - char *result; - size_t i; - size_t o; - - result = malloc (n_data * 3 + 1); - if (result == NULL) - return NULL; - - for (i = 0, o = 0; i < n_data; i++) { - if (i > 0) - result[o++] = ':'; - result[o++] = HEXC_LOWER[data[i] >> 4 & 0xf]; - result[o++] = HEXC_LOWER[data[i] & 0xf]; - } - - result[o] = 0; - return result; -} - -static bool -is_ascii_string (const unsigned char *data, - size_t n_data) -{ - size_t i; - - for (i = 0; i < n_data; i++) { - if (!isascii (data[i]) && - (data[i] < 0x20 && !isspace (data[i]))) - return false; - } - - return true; -} - -static void -print_token_info (CK_FUNCTION_LIST_PTR module, CK_SLOT_ID slot_id) -{ - CK_TOKEN_INFO info; - char *value; - CK_RV rv; - - rv = (module->C_GetTokenInfo) (slot_id, &info); - if (rv != CKR_OK) { - warnx ("couldn't load module info: %s", p11_kit_strerror (rv)); - return; - } - - value = p11_kit_space_strdup (info.label, sizeof (info.label)); - printf (" token: %s\n", value); - free (value); - - value = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID)); - printf (" manufacturer: %s\n", value); - free (value); - - value = p11_kit_space_strdup (info.model, sizeof (info.model)); - printf (" model: %s\n", value); - free (value); - - if (is_ascii_string (info.serialNumber, sizeof (info.serialNumber))) - value = p11_kit_space_strdup (info.serialNumber, sizeof (info.serialNumber)); - else - value = hex_encode (info.serialNumber, sizeof (info.serialNumber)); - printf (" serial-number: %s\n", value); - free (value); - - if (info.hardwareVersion.major || info.hardwareVersion.minor) - printf (" hardware-version: %d.%d\n", - info.hardwareVersion.major, - info.hardwareVersion.minor); - - if (info.firmwareVersion.major || info.firmwareVersion.minor) - printf (" firmware-version: %d.%d\n", - info.firmwareVersion.major, - info.firmwareVersion.minor); - - printf (" flags:\n"); - #define X(x, y) if (info.flags & (x)) printf (" %s\n", (y)) - X(CKF_RNG, "rng"); - X(CKF_WRITE_PROTECTED, "write-protected"); - X(CKF_LOGIN_REQUIRED, "login-required"); - X(CKF_USER_PIN_INITIALIZED, "user-pin-initialized"); - X(CKF_RESTORE_KEY_NOT_NEEDED, "restore-key-not-needed"); - X(CKF_CLOCK_ON_TOKEN, "clock-on-token"); - X(CKF_PROTECTED_AUTHENTICATION_PATH, "protected-authentication-path"); - X(CKF_DUAL_CRYPTO_OPERATIONS, "dual-crypto-operations"); - X(CKF_TOKEN_INITIALIZED, "token-initialized"); - X(CKF_SECONDARY_AUTHENTICATION, "secondary-authentication"); - X(CKF_USER_PIN_COUNT_LOW, "user-pin-count-low"); - X(CKF_USER_PIN_FINAL_TRY, "user-pin-final-try"); - X(CKF_USER_PIN_LOCKED, "user-pin-locked"); - X(CKF_USER_PIN_TO_BE_CHANGED, "user-pin-to-be-changed"); - X(CKF_SO_PIN_COUNT_LOW, "so-pin-count-low"); - X(CKF_SO_PIN_FINAL_TRY, "so-pin-final-try"); - X(CKF_SO_PIN_LOCKED, "so-pin-locked"); - X(CKF_SO_PIN_TO_BE_CHANGED, "so-pin-to-be-changed"); - #undef X -} - -static void -print_module_info (CK_FUNCTION_LIST_PTR module) -{ - CK_SLOT_ID slot_list[256]; - CK_ULONG i, count; - CK_INFO info; - char *value; - CK_RV rv; - - rv = (module->C_GetInfo) (&info); - if (rv != CKR_OK) { - warnx ("couldn't load module info: %s", p11_kit_strerror (rv)); - return; - } - - value = p11_kit_space_strdup (info.libraryDescription, - sizeof (info.libraryDescription)); - printf (" library-description: %s\n", value); - free (value); - - value = p11_kit_space_strdup (info.manufacturerID, - sizeof (info.manufacturerID)); - printf (" library-manufacturer: %s\n", value); - free (value); - - printf (" library-version: %d.%d\n", - info.libraryVersion.major, - info.libraryVersion.minor); - - count = sizeof (slot_list) / sizeof (slot_list[0]); - rv = (module->C_GetSlotList) (CK_TRUE, slot_list, &count); - if (rv != CKR_OK) { - warnx ("couldn't load module info: %s", p11_kit_strerror (rv)); - return; - } - - for (i = 0; i < count; i++) - print_token_info (module, slot_list[i]); -} - -static int -list_modules (int argc, char *argv[]) -{ - CK_FUNCTION_LIST_PTR *module_list; - char *name; - char *path; - CK_RV rv; - int i; - - if (argc != 0) - usage (); - - rv = p11_kit_initialize_registered (); - if (rv != CKR_OK) - errx (1, "couldn't initialize registered modules: %s", - p11_kit_strerror (rv)); - - module_list = p11_kit_registered_modules (); - for (i = 0; module_list[i]; i++) { - name = p11_kit_registered_module_to_name (module_list[i]); - path = p11_kit_registered_option (module_list[i], "module"); - - printf ("%s: %s\n", - name ? name : "(null)", - path ? path : "(null)"); - print_module_info (module_list[i]); - - free (name); - free (path); - } - free (module_list); - - p11_kit_finalize_registered (); - - return 0; -} - -int -main (int argc, char *argv[]) -{ - operation oper = NULL; - int opt; - - while ((opt = getopt (argc, argv, "hlv")) != -1) { - switch (opt) { - case 'l': - if (oper != NULL) - usage (); - oper = list_modules; - break; - case 'v': - verbose = true; - putenv ("P11_KIT_DEBUG=all"); - break; - case 'h': - case '?': - usage(); - break; - } - } - - if (!oper) - usage (); - - argc -= optind; - argv += optind; - - return (oper) (argc, argv); -} diff --git a/tools/tool.c b/tools/tool.c new file mode 100644 index 0000000..92c5e70 --- /dev/null +++ b/tools/tool.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "buffer.h" +#include "compat.h" +#include "debug.h" +#include "library.h" +#include "p11-kit.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "tool.h" + +struct { + const char *name; + int (*function) (int, char*[]); + const char *text; +} commands[] = { + { "list-modules", p11_tool_list_modules, "List modules and tokens"}, + { 0, } +}; + +static char +short_option (int opt) +{ + if (isalpha (opt) || isdigit (opt)) + return (char)opt; + return 0; +} + +static const struct option * +find_option (const struct option *longopts, + int opt) +{ + int i; + + for (i = 0; longopts[i].name != NULL; i++) { + if (longopts[i].val == opt) + return longopts + i; + } + + return NULL; +} + +void +p11_tool_usage (const p11_tool_desc *usages, + const struct option *longopts) +{ + const struct option *longopt; + const int indent = 22; + const char *long_name; + const char *description; + const char *next; + char short_name; + int spaces; + int len; + int i; + + for (i = 0; usages[i].text != NULL; i++) { + + /* If no option, then this is a heading */ + if (!usages[i].option) { + printf ("%s\n\n", usages[i].text); + continue; + } + + longopt = find_option (longopts, usages[i].option); + long_name = longopt ? longopt->name : NULL; + short_name = short_option (usages[i].option); + description = usages[i].text; + + if (short_name && long_name) + len = printf (" -%c, --%s", (int)short_name, long_name); + else if (long_name) + len = printf (" --%s", long_name); + else + len = printf (" -%c", (int)short_name); + if (longopt->has_arg) + len += printf ("%s<%s>", + long_name ? "=" : " ", + usages[i].arg ? usages[i].arg : "..."); + if (len < indent) { + spaces = indent - len; + } else { + printf ("\n"); + spaces = indent; + } + while (description) { + while (spaces-- > 0) + fputc (' ', stdout); + next = strchr (description, '\n'); + if (next) { + next += 1; + printf ("%.*s", (int)(next - description), description); + description = next; + spaces = indent; + } else { + printf ("%s\n", description); + break; + } + } + + } +} + +int +p11_tool_getopt (int argc, + char *argv[], + const struct option *longopts) +{ + p11_buffer buf; + int ret; + char opt; + int i; + + if (!p11_buffer_init_null (&buf, 64)) + return_val_if_reached (-1); + + for (i = 0; longopts[i].name != NULL; i++) { + opt = short_option (longopts[i].val); + if (opt != 0) { + p11_buffer_add (&buf, &opt, 1); + assert (longopts[i].has_arg != optional_argument); + if (longopts[i].has_arg == required_argument) + p11_buffer_add (&buf, ":", 1); + } + } + + ret = getopt_long (argc, argv, buf.data, longopts, NULL); + + p11_buffer_uninit (&buf); + + return ret; +} + +static void +command_usage (void) +{ + int i; + + printf ("usage: p11-kit command ...\n"); + printf ("\nCommon p11-kit commands are:\n"); + for (i = 0; commands[i].name != NULL; i++) + printf (" %-15s %s\n", commands[i].name, commands[i].text); + printf ("\nSee 'p11-kit --help' for more information\n"); +} + +static void +exec_external (const char *command, + int argc, + char *argv[]) +{ + char *filename; + const char *path; + char *env; + + if (!asprintf (&filename, "p11-kit-%s", command) < 0) + return_if_reached (); + + /* Add our libexec directory to the path */ + path = getenv ("PATH"); + if (!asprintf (&env, "PATH=%s%s%s", path ? path : "", path ? ":" : "", PKGDATADIR)) + return_if_reached (); + printf ("%s\n", env); + putenv (env); + + argv[0] = filename; + execvp (filename, argv); +} + +static void +verbose_arg (void) +{ + putenv ("P11_KIT_DEBUG=all"); + p11_kit_be_loud (); + p11_message_loud (); +} + +static void +quiet_arg (void) +{ + putenv ("P11_KIT_DEBUG="); + p11_kit_be_quiet (); + p11_message_quiet (); +} + +int +main (int argc, char *argv[]) +{ + char *command = NULL; + bool skip; + int in, out; + int i; + + /* + * Parse the global options. We rearrange the options as + * necessary, in order to pass relevant options through + * to the commands, but also have them take effect globally. + */ + + for (in = 1, out = 1; in < argc; in++, out++) { + skip = false; + + /* Already seen the command, keep the arguments */ + if (command) { + skip = false; + + /* The non-option is the command, take it out of the arguments */ + } else if (argv[in][0] != '-') { + skip = true; + command = argv[in]; + + /* The global long options */ + } else if (argv[in][1] == '-') { + skip = false; + + if (strcmp (argv[in], "--") == 0) { + p11_message ("no command specified"); + return 2; + + } else if (strcmp (argv[in], "--verbose") == 0) { + verbose_arg (); + + } else if (strcmp (argv[in], "--quiet") == 0) { + quiet_arg (); + + } else if (strcmp (argv[in], "--help") == 0) { + command_usage (); + return 0; + + } else { + p11_message ("unknown option: %s", argv[in]); + return 2; + } + + /* The global short options */ + } else { + skip = false; + + for (i = 1; argv[in][i] != '\0'; i++) { + switch (argv[in][i]) { + case 'h': + command_usage (); + return 0; + + /* Compatibility option */ + case 'l': + command = "list-modules"; + break; + + case 'v': + verbose_arg (); + break; + + case 'q': + quiet_arg (); + break; + + default: + p11_message ("unknown option: -%c", (int)argv[in][i]); + return 2; + } + } + } + + /* Skipping this argument? */ + if (skip) + out--; + else + argv[out] = argv[in]; + } + + if (command == NULL) { + /* As a special favor if someone just typed 'p11-kit', help them out */ + if (argc == 1) + command_usage (); + else + p11_message ("no command specified"); + return 2; + } + + argc = out; + + /* Look for the command */ + for (i = 0; commands[i].name != NULL; i++) { + if (strcmp (commands[i].name, command) == 0) { + argv[0] = command; + return (commands[i].function) (argc, argv); + } + } + + /* Got here because no command matched */ + exec_external (command, argc, argv); + + /* At this point we have no command */ + p11_message ("'%s' is not a valid p11-kit command. See 'p11-kit --help'", command); + return 2; +} diff --git a/tools/tool.h b/tools/tool.h new file mode 100644 index 0000000..709e668 --- /dev/null +++ b/tools/tool.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter + */ + +#ifndef P11_TOOL_H_ +#define P11_TOOL_H_ + +#include + +typedef struct { + int option; + const char *text; + const char *arg; +} p11_tool_desc; + +int p11_tool_getopt (int argc, + char *argv[], + const struct option *longopts); + +void p11_tool_usage (const p11_tool_desc *usages, + const struct option *longopts); + +int p11_tool_list_modules (int argc, + char *argv[]); + +#endif /* P11_TOOL_H_ */ -- cgit v1.1