aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-04-19 18:35:56 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-07-03 15:47:21 +0200
commit06bccb357d7ed27e6790a6ad60b36e39eedcfdea (patch)
tree71ecac6866a157d0145d162e5b12a36575b91488
parent8a812bcb15348ee8d4b80f27455d7673203bf013 (diff)
downloadexternal_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.zip
external_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.tar.gz
external_libqmi-06bccb357d7ed27e6790a6ad60b36e39eedcfdea.tar.bz2
cli: new `qmicli' command line utility
-rw-r--r--.gitignore4
-rw-r--r--Makefile.am2
-rw-r--r--cli/Makefile.am14
-rw-r--r--cli/qmicli.c274
-rw-r--r--configure.ac11
5 files changed, 303 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index f424e58..e972e69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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 "