diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-04-19 18:35:56 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-07-03 15:47:21 +0200 |
commit | 06bccb357d7ed27e6790a6ad60b36e39eedcfdea (patch) | |
tree | 71ecac6866a157d0145d162e5b12a36575b91488 | |
parent | 8a812bcb15348ee8d4b80f27455d7673203bf013 (diff) | |
download | external_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.zip external_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.tar.gz external_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.tar.bz2 |
cli: new `qmicli' command line utility
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | cli/Makefile.am | 14 | ||||
-rw-r--r-- | cli/qmicli.c | 274 | ||||
-rw-r--r-- | configure.ac | 11 |
5 files changed, 303 insertions, 2 deletions
@@ -38,3 +38,7 @@ src/qmi-error-types.c src/qmi-error-types.h src/qmi-enum-types.h src/qmi-enum-types.c + +cli/.deps +cli/.libs +cli/qmicli diff --git a/Makefile.am b/Makefile.am index 57a3b87..2bbf885 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . build-aux src +SUBDIRS = . build-aux src cli ACLOCAL_AMFLAGS = -I m4 diff --git a/cli/Makefile.am b/cli/Makefile.am new file mode 100644 index 0000000..dca3dde --- /dev/null +++ b/cli/Makefile.am @@ -0,0 +1,14 @@ +bin_PROGRAMS = qmicli + +qmicli_CPPFLAGS = \ + $(QMICLI_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src + +qmicli_SOURCES = \ + qmicli.c + +qmicli_LDADD = \ + $(QMICLI_LIBS) \ + $(top_builddir)/src/libqmi-glib.la diff --git a/cli/qmicli.c b/cli/qmicli.c new file mode 100644 index 0000000..6afc8fa --- /dev/null +++ b/cli/qmicli.c @@ -0,0 +1,274 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * qmicli -- Command line interface to control QMI devices + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Copyright (C) 2012 Aleksander Morgado <aleksander@lanedo.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <locale.h> +#include <string.h> + +#include <glib.h> +#include <gio/gio.h> + +#include <libqmi-glib.h> + +#define PROGRAM_NAME "qmicli" +#define PROGRAM_VERSION PACKAGE_VERSION + +/* Globals */ +static GMainLoop *loop; +static GCancellable *cancellable; + +/* Main options */ +static gchar *device_str; +static gboolean verbose_flag; +static gboolean version_flag; + +static GOptionEntry main_entries[] = { + { "device", 'd', 0, G_OPTION_ARG_STRING, &device_str, + "Specify device path", + "[PATH]" + }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_flag, + "Run action with verbose logs", + NULL + }, + { "version", 'V', 0, G_OPTION_ARG_NONE, &version_flag, + "Print version", + NULL + }, + { NULL } +}; + +static void +signals_handler (int signum) +{ + if (cancellable) { + /* Ignore consecutive requests of cancellation */ + if (!g_cancellable_is_cancelled (cancellable)) { + g_printerr ("%s\n", + "cancelling the operation...\n"); + g_cancellable_cancel (cancellable); + } + return; + } + + if (loop && + g_main_loop_is_running (loop)) { + g_printerr ("%s\n", + "cancelling the main loop...\n"); + g_main_loop_quit (loop); + } +} + +static void +log_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + const gchar *log_level_str; + time_t now; + gchar time_str[64]; + struct tm *local_time; + + now = time ((time_t *) NULL); + local_time = localtime (&now); + strftime (time_str, 64, "%d %b %Y, %H:%M:%S", local_time); + + switch (log_level) { + case G_LOG_LEVEL_WARNING: + log_level_str = "-Warning **"; + break; + + case G_LOG_LEVEL_CRITICAL: + case G_LOG_FLAG_FATAL: + case G_LOG_LEVEL_ERROR: + log_level_str = "-Error **"; + break; + + case G_LOG_LEVEL_DEBUG: + log_level_str = "[Debug]"; + break; + + default: + log_level_str = ""; + break; + } + + g_print ("[%s] %s %s\n", time_str, log_level_str, message); +} + +static void +print_version_and_exit (void) +{ + g_print ("\n" + PROGRAM_NAME " " PROGRAM_VERSION "\n" + "Copyright (2012) Aleksander Morgado\n" + "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" + "\n"); + exit (EXIT_SUCCESS); +} + +/*****************************************************************************/ +/* Running asynchronously */ + +static void +async_operation_done (void) +{ + if (cancellable) { + g_object_unref (cancellable); + cancellable = NULL; + } + + g_main_loop_quit (loop); +} + +typedef struct { + GCancellable *cancellable; + QmiDevice *device; +} AsyncRunContext; + +static void +async_run_context_complete_and_free (AsyncRunContext *ctx) +{ + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + if (ctx->device) + g_object_unref (ctx->device); + g_slice_free (AsyncRunContext, ctx); + + async_operation_done (); +} + +static void +device_open_ready (QmiDevice *device, + GAsyncResult *res, + AsyncRunContext *ctx) +{ + GError *error = NULL; + + if (!qmi_device_open_finish (device, res, &error)) { + g_printerr ("error: couldn't open the QmiDevice: %s\n", + error->message); + exit (EXIT_FAILURE); + } + + if (!qmi_device_close (ctx->device, &error)) { + g_printerr ("error: couldn't close the QmiDevice: %s\n", + error->message); + exit (EXIT_FAILURE); + } + + /* All done */ + async_run_context_complete_and_free (ctx); +} + +static void +device_new_ready (GObject *unused, + GAsyncResult *res, + AsyncRunContext *ctx) +{ + GError *error = NULL; + + ctx->device = qmi_device_new_finish (res, &error); + if (!ctx->device) { + g_printerr ("error: couldn't create QmiDevice: %s\n", + error->message); + exit (EXIT_FAILURE); + } + + /* Open the device */ + qmi_device_open (ctx->device, + ctx->cancellable, + (GAsyncReadyCallback)device_open_ready, + ctx); +} + +static void +run (GFile *file, + GCancellable *cancellable) +{ + AsyncRunContext *ctx; + + ctx = g_slice_new0 (AsyncRunContext); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + qmi_device_new (file, + cancellable, + (GAsyncReadyCallback)device_new_ready, + ctx); +} + +/*****************************************************************************/ + +int main (int argc, char **argv) +{ + GFile *file; + GOptionContext *context; + GOptionGroup *group; + + setlocale (LC_ALL, ""); + + g_type_init (); + + /* Setup option context, process it and destroy it */ + context = g_option_context_new ("- Control QMI devices"); + g_option_context_add_main_entries (context, main_entries, NULL); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + if (version_flag) + print_version_and_exit (); + + if (verbose_flag) + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, log_handler, NULL); + + /* No device path given? */ + if (!device_str) { + g_printerr ("error: no device path specified\n"); + exit (EXIT_FAILURE); + } + + /* Build new GFile from the commandline arg */ + file = g_file_new_for_commandline_arg (device_str); + + /* Setup signals */ + signal (SIGINT, signals_handler); + signal (SIGHUP, signals_handler); + signal (SIGTERM, signals_handler); + + /* Create requirements for async options */ + cancellable = g_cancellable_new (); + loop = g_main_loop_new (NULL, FALSE); + + run (file, cancellable); + g_main_loop_run (loop); + + if (cancellable) + g_object_unref (cancellable); + g_main_loop_unref (loop); + g_object_unref (file); + + return EXIT_SUCCESS; +} diff --git a/configure.ac b/configure.ac index 1611c24..22b8c1a 100644 --- a/configure.ac +++ b/configure.ac @@ -31,12 +31,21 @@ PKG_CHECK_MODULES(LIBQMI_GLIB, AC_SUBST(LIBQMI_GLIB_CFLAGS) AC_SUBST(LIBQMI_GLIB_LIBS) +dnl General cli dependencies +PKG_CHECK_MODULES(QMICLI, + glib-2.0 >= 2.22 + gobject-2.0 + gio-2.0) +AC_SUBST(QMICLI_CFLAGS) +AC_SUBST(QMICLI_LIBS) + GLIB_MKENUMS=`pkg-config --variable=glib_mkenums glib-2.0` AC_SUBST(GLIB_MKENUMS) AC_CONFIG_FILES([Makefile build-aux/Makefile - src/Makefile]) + src/Makefile + cli/Makefile]) AC_OUTPUT echo " |