summaryrefslogtreecommitdiff
path: root/tools/gusb-main.c
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2011-08-11 12:48:21 +0200
committerRichard Hughes <richard@hughsie.com>2011-08-11 12:48:28 +0200
commit789e690e9916bd6cc44839a2cc9404476cb3f0f9 (patch)
tree985d32afa61aae3ded56d7096c58f99517313502 /tools/gusb-main.c
parent0eb4dbbbee5d76b885382f94096b873ca2e6e178 (diff)
downloadgusb-789e690e9916bd6cc44839a2cc9404476cb3f0f9.tar.gz
Add a debugging tool to exercise the API that is not installed
This adds the commands 'gusb show' and 'gusb watch' which are not designed to be useful to end users.
Diffstat (limited to 'tools/gusb-main.c')
-rw-r--r--tools/gusb-main.c386
1 files changed, 386 insertions, 0 deletions
diff --git a/tools/gusb-main.c b/tools/gusb-main.c
new file mode 100644
index 0000000..c58061e
--- /dev/null
+++ b/tools/gusb-main.c
@@ -0,0 +1,386 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <gusb/gusb.h>
+#include <string.h>
+
+/**
+ * gusb_log_ignore_cb:
+ **/
+static void
+gusb_log_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *message, gpointer user_data)
+{
+}
+
+/**
+ * gusb_log_handler_cb:
+ **/
+static void
+gusb_log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *message, gpointer user_data)
+{
+ gchar str_time[255];
+ time_t the_time;
+
+ /* header always in green */
+ time (&the_time);
+ strftime (str_time, 254, "%H:%M:%S", localtime (&the_time));
+ g_print ("%c[%dmTI:%s\t", 0x1B, 32, str_time);
+
+ /* critical is also in red */
+ if (log_level == G_LOG_LEVEL_CRITICAL ||
+ log_level == G_LOG_LEVEL_WARNING ||
+ log_level == G_LOG_LEVEL_ERROR) {
+ g_print ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0);
+ } else {
+ /* debug in blue */
+ g_print ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0);
+ }
+}
+
+typedef struct {
+ GOptionContext *context;
+ GUsbContext *usb_ctx;
+ GPtrArray *cmd_array;
+} GUsbCmdPrivate;
+
+typedef gboolean (*GUsbCmdPrivateCb) (GUsbCmdPrivate *cmd,
+ gchar **values,
+ GError **error);
+
+typedef struct {
+ gchar *name;
+ gchar *description;
+ GUsbCmdPrivateCb callback;
+} GUsbCmdItem;
+
+/**
+ * gusb_cmd_item_free:
+ **/
+static void
+gusb_cmd_item_free (GUsbCmdItem *item)
+{
+ g_free (item->name);
+ g_free (item->description);
+ g_free (item);
+}
+
+/*
+ * gusb_sort_command_name_cb:
+ */
+static gint
+gusb_sort_command_name_cb (GUsbCmdItem **item1, GUsbCmdItem **item2)
+{
+ return g_strcmp0 ((*item1)->name, (*item2)->name);
+}
+
+/**
+ * gusb_cmd_add:
+ **/
+static void
+gusb_cmd_add (GPtrArray *array, const gchar *name, const gchar *description, GUsbCmdPrivateCb callback)
+{
+ gchar **names;
+ guint i;
+ GUsbCmdItem *item;
+
+ /* add each one */
+ names = g_strsplit (name, ",", -1);
+ for (i=0; names[i] != NULL; i++) {
+ item = g_new0 (GUsbCmdItem, 1);
+ item->name = g_strdup (names[i]);
+ if (i == 0) {
+ item->description = g_strdup (description);
+ } else {
+ /* TRANSLATORS: this is a command alias */
+ item->description = g_strdup_printf ("Alias to %s",
+ names[0]);
+ }
+ item->callback = callback;
+ g_ptr_array_add (array, item);
+ }
+ g_strfreev (names);
+}
+
+/**
+ * gusb_cmd_get_descriptions:
+ **/
+static gchar *
+gusb_cmd_get_descriptions (GPtrArray *array)
+{
+ guint i;
+ guint j;
+ guint len;
+ guint max_len = 19;
+ GUsbCmdItem *item;
+ GString *string;
+
+ /* print each command */
+ string = g_string_new ("");
+ for (i=0; i<array->len; i++) {
+ item = g_ptr_array_index (array, i);
+ g_string_append (string, " ");
+ g_string_append (string, item->name);
+ g_string_append (string, " ");
+ len = strlen (item->name);
+ for (j=len; j<max_len+2; j++)
+ g_string_append_c (string, ' ');
+ g_string_append (string, item->description);
+ g_string_append_c (string, '\n');
+ }
+
+ /* remove trailing newline */
+ if (string->len > 0)
+ g_string_set_size (string, string->len - 1);
+
+ return g_string_free (string, FALSE);
+}
+
+/**
+ * gusb_device_list_added_cb:
+ **/
+static void
+gusb_device_list_added_cb (GUsbDeviceList *list,
+ GUsbDevice *device,
+ GUdevDevice *udev,
+ gpointer user_data)
+{
+ g_print ("device %s added %x:%x\n",
+ g_udev_device_get_name (udev),
+ g_usb_device_get_bus (device),
+ g_usb_device_get_address (device));
+}
+
+/**
+ * gusb_device_list_removed_cb:
+ **/
+static void
+gusb_device_list_removed_cb (GUsbDeviceList *list,
+ GUsbDevice *device,
+ GUdevDevice *udev,
+ gpointer user_data)
+{
+ g_print ("device %s removed %x:%x\n",
+ g_udev_device_get_name (udev),
+ g_usb_device_get_bus (device),
+ g_usb_device_get_address (device));
+}
+
+/**
+ * gusb_cmd_show:
+ **/
+static gboolean
+gusb_cmd_show (GUsbCmdPrivate *priv, gchar **values, GError **error)
+{
+ gboolean ret = TRUE;
+ GPtrArray *devices;
+ guint i;
+ GUsbDevice *device;
+ GUsbDeviceList *list;
+
+ list = g_usb_device_list_new (priv->usb_ctx);
+ g_usb_device_list_coldplug (list);
+ devices = g_usb_device_list_get_devices (list);
+ for (i=0; i<devices->len; i++) {
+ device = g_ptr_array_index (devices, i);
+ g_print ("device present %x:%x\n",
+ g_usb_device_get_bus (device),
+ g_usb_device_get_address (device));
+ }
+ g_ptr_array_unref (devices);
+ if (list != NULL)
+ g_object_unref (list);
+ return ret;
+}
+
+/**
+ * gusb_cmd_watch:
+ **/
+static gboolean
+gusb_cmd_watch (GUsbCmdPrivate *priv, gchar **values, GError **error)
+{
+ gboolean ret = TRUE;
+ GPtrArray *devices;
+ guint i;
+ GUsbDevice *device;
+ GUsbDeviceList *list;
+ GMainLoop *loop;
+
+ list = g_usb_device_list_new (priv->usb_ctx);
+ g_usb_device_list_coldplug (list);
+ devices = g_usb_device_list_get_devices (list);
+ for (i=0; i<devices->len; i++) {
+ device = g_ptr_array_index (devices, i);
+ g_print ("device already present %x:%x\n",
+ g_usb_device_get_bus (device),
+ g_usb_device_get_address (device));
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_signal_connect (list, "device-added",
+ G_CALLBACK (gusb_device_list_added_cb),
+ priv);
+ g_signal_connect (list, "device-removed",
+ G_CALLBACK (gusb_device_list_removed_cb),
+ priv);
+ g_main_loop_run (loop);
+
+ g_main_loop_unref (loop);
+ g_ptr_array_unref (devices);
+ if (list != NULL)
+ g_object_unref (list);
+ return ret;
+}
+
+/**
+ * gusb_cmd_run:
+ **/
+static gboolean
+gusb_cmd_run (GUsbCmdPrivate *priv, const gchar *command, gchar **values, GError **error)
+{
+ gboolean ret = FALSE;
+ guint i;
+ GUsbCmdItem *item;
+ GString *string;
+
+ /* find command */
+ for (i=0; i<priv->cmd_array->len; i++) {
+ item = g_ptr_array_index (priv->cmd_array, i);
+ if (g_strcmp0 (item->name, command) == 0) {
+ ret = item->callback (priv, values, error);
+ goto out;
+ }
+ }
+
+ /* not found */
+ string = g_string_new ("");
+ /* TRANSLATORS: error message */
+ g_string_append_printf (string, "%s\n", "Command not found, valid commands are:");
+ for (i=0; i<priv->cmd_array->len; i++) {
+ item = g_ptr_array_index (priv->cmd_array, i);
+ g_string_append_printf (string, " * %s\n", item->name);
+ }
+ g_set_error_literal (error, 1, 0, string->str);
+ g_string_free (string, TRUE);
+out:
+ return ret;
+}
+
+/**
+ * main:
+ **/
+int
+main (int argc, char *argv[])
+{
+ gboolean ret;
+ gboolean verbose = FALSE;
+ gchar *cmd_descriptions = NULL;
+ gchar *options_help = NULL;
+ GError *error = NULL;
+ gint retval = 0;
+ GUsbCmdPrivate *priv;
+
+ const GOptionEntry options[] = {
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Show extra debugging information", NULL },
+ { NULL}
+ };
+
+ /* create helper object */
+ priv = g_new0 (GUsbCmdPrivate, 1);
+
+ if (! g_thread_supported ())
+ g_thread_init (NULL);
+ g_type_init ();
+
+ priv->context = g_option_context_new ("GUSB Console Program");
+ g_option_context_add_main_entries (priv->context, options, NULL);
+ g_option_context_parse (priv->context, &argc, &argv, NULL);
+
+ /* verbose? */
+ if (verbose) {
+ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+ g_log_set_handler ("GUsb", G_LOG_LEVEL_ERROR |
+ G_LOG_LEVEL_CRITICAL |
+ G_LOG_LEVEL_DEBUG |
+ G_LOG_LEVEL_WARNING,
+ gusb_log_handler_cb, NULL);
+ } else {
+ /* hide all debugging */
+ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+ g_log_set_handler ("GUsb", G_LOG_LEVEL_DEBUG,
+ gusb_log_ignore_cb, NULL);
+ }
+
+ /* GUsbContext */
+ priv->usb_ctx = g_usb_context_new (NULL);
+
+ /* add commands */
+ priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) gusb_cmd_item_free);
+ gusb_cmd_add (priv->cmd_array,
+ "show",
+ "Show currently connected devices",
+ gusb_cmd_show);
+ gusb_cmd_add (priv->cmd_array,
+ "watch",
+ "Watch devices as they come and go",
+ gusb_cmd_watch);
+
+ /* sort by command name */
+ g_ptr_array_sort (priv->cmd_array,
+ (GCompareFunc) gusb_sort_command_name_cb);
+
+ /* get a list of the commands */
+ cmd_descriptions = gusb_cmd_get_descriptions (priv->cmd_array);
+ g_option_context_set_summary (priv->context, cmd_descriptions);
+
+ /* nothing specified */
+ if (argc < 2) {
+ options_help = g_option_context_get_help (priv->context, TRUE, NULL);
+ g_print ("%s", options_help);
+ goto out;
+ }
+
+ /* run the specified command */
+ ret = gusb_cmd_run (priv, argv[1], (gchar**) &argv[2], &error);
+ if (!ret) {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ retval = 1;
+ goto out;
+ }
+out:
+ if (priv != NULL) {
+ if (priv->usb_ctx != NULL)
+ g_object_unref (priv->usb_ctx);
+ g_option_context_free (priv->context);
+ g_free (priv);
+ }
+
+ /* free state */
+ g_free (options_help);
+ g_free (cmd_descriptions);
+ return retval;
+}