blob: 6953672d060e5e8c51f4803600cf4797e505c95d [file] [log] [blame]
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* mmcli -- Control modem status & access information from the command line
*
* 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) 2011 Aleksander Morgado <aleksander@gnu.org>
* Copyright (C) 2011 Google, Inc.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#define _LIBMM_INSIDE_MMCLI
#include <libmm-glib.h>
#include "mmcli.h"
#include "mmcli-common.h"
#include "mmcli-output.h"
#define PROGRAM_NAME "mmcli"
#define PROGRAM_VERSION PACKAGE_VERSION
/* Globals */
static GMainLoop *loop;
static GCancellable *cancellable;
/* Context */
static gboolean output_keyvalue_flag;
static gboolean verbose_flag;
static gboolean version_flag;
static gboolean async_flag;
static gint timeout = 30; /* by default, use 30s for all operations */
static GOptionEntry main_entries[] = {
{ "output-keyvalue", 'K', 0, G_OPTION_ARG_NONE, &output_keyvalue_flag,
"Run action with machine-friendly key-value output",
NULL
},
{ "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
},
{ "async", 'a', 0, G_OPTION_ARG_NONE, &async_flag,
"Use asynchronous methods",
NULL
},
{ "timeout", 0, 0, G_OPTION_ARG_INT, &timeout,
"Timeout for the operation",
"[SECONDS]"
},
{ 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 (2011 - 2019) 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);
}
void
mmcli_async_operation_done (void)
{
if (cancellable) {
g_object_unref (cancellable);
cancellable = NULL;
}
g_main_loop_quit (loop);
}
void
mmcli_force_async_operation (void)
{
if (!async_flag) {
g_debug ("Forcing request to be run asynchronously");
async_flag = TRUE;
}
}
void
mmcli_force_sync_operation (void)
{
if (async_flag) {
g_debug ("Ignoring request to run asynchronously");
async_flag = FALSE;
}
}
void
mmcli_force_operation_timeout (GDBusProxy *proxy)
{
g_dbus_proxy_set_default_timeout (proxy, timeout * 1000);
}
gint
main (gint argc, gchar **argv)
{
GDBusConnection *connection;
GOptionContext *context;
GError *error = NULL;
setlocale (LC_ALL, "");
/* Setup option context, process it and destroy it */
context = g_option_context_new ("- Control and monitor the ModemManager");
g_option_context_add_group (context,
mmcli_manager_get_option_group ());
g_option_context_add_group (context,
mmcli_get_common_option_group ());
g_option_context_add_group (context,
mmcli_modem_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_3gpp_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_cdma_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_simple_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_location_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_messaging_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_voice_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_time_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_firmware_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_signal_get_option_group ());
g_option_context_add_group (context,
mmcli_modem_oma_get_option_group ());
g_option_context_add_group (context,
mmcli_sim_get_option_group ());
g_option_context_add_group (context,
mmcli_bearer_get_option_group ());
g_option_context_add_group (context,
mmcli_sms_get_option_group ());
g_option_context_add_group (context,
mmcli_call_get_option_group ());
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);
/* Setup output */
if (output_keyvalue_flag) {
if (verbose_flag) {
g_printerr ("error: cannot set verbose output in keyvalue output type\n");
exit (EXIT_FAILURE);
}
mmcli_output_set (MMC_OUTPUT_TYPE_KEYVALUE);
} else
mmcli_output_set (MMC_OUTPUT_TYPE_HUMAN);
/* Setup signals */
signal (SIGINT, signals_handler);
signal (SIGHUP, signals_handler);
signal (SIGTERM, signals_handler);
/* Setup dbus connection to use */
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (!connection) {
g_printerr ("error: couldn't get bus: %s\n",
error ? error->message : "unknown error");
exit (EXIT_FAILURE);
}
/* Create requirements for async options */
cancellable = g_cancellable_new ();
loop = g_main_loop_new (NULL, FALSE);
/* Manager options? */
if (mmcli_manager_options_enabled ()) {
/* Ensure options from different groups are not enabled */
if (mmcli_modem_options_enabled ()) {
g_printerr ("error: cannot use manager and modem options "
"at the same time\n");
exit (EXIT_FAILURE);
}
if (async_flag)
mmcli_manager_run_asynchronous (connection, cancellable);
else
mmcli_manager_run_synchronous (connection);
}
/* Sim options? */
else if (mmcli_sim_options_enabled ()) {
if (async_flag)
mmcli_sim_run_asynchronous (connection, cancellable);
else
mmcli_sim_run_synchronous (connection);
}
/* Bearer options? */
else if (mmcli_bearer_options_enabled ()) {
if (async_flag)
mmcli_bearer_run_asynchronous (connection, cancellable);
else
mmcli_bearer_run_synchronous (connection);
}
/* Sms options? */
else if (mmcli_sms_options_enabled ()) {
if (async_flag)
mmcli_sms_run_asynchronous (connection, cancellable);
else
mmcli_sms_run_synchronous (connection);
}
/* Call options? */
else if (mmcli_call_options_enabled ()) {
if (async_flag)
mmcli_call_run_asynchronous (connection, cancellable);
else
mmcli_call_run_synchronous (connection);
}
/* Modem 3GPP options? */
else if (mmcli_modem_3gpp_options_enabled ()) {
if (async_flag)
mmcli_modem_3gpp_run_asynchronous (connection, cancellable);
else
mmcli_modem_3gpp_run_synchronous (connection);
}
/* Modem CDMA options? */
else if (mmcli_modem_cdma_options_enabled ()) {
if (async_flag)
mmcli_modem_cdma_run_asynchronous (connection, cancellable);
else
mmcli_modem_cdma_run_synchronous (connection);
}
/* Modem Simple options? */
else if (mmcli_modem_simple_options_enabled ()) {
if (async_flag)
mmcli_modem_simple_run_asynchronous (connection, cancellable);
else
mmcli_modem_simple_run_synchronous (connection);
}
/* Modem Location options? */
else if (mmcli_modem_location_options_enabled ()) {
if (async_flag)
mmcli_modem_location_run_asynchronous (connection, cancellable);
else
mmcli_modem_location_run_synchronous (connection);
}
/* Modem Messaging options? */
else if (mmcli_modem_messaging_options_enabled ()) {
if (async_flag)
mmcli_modem_messaging_run_asynchronous (connection, cancellable);
else
mmcli_modem_messaging_run_synchronous (connection);
}
/* Voice options? */
else if (mmcli_modem_voice_options_enabled ()) {
if (async_flag)
mmcli_modem_voice_run_asynchronous (connection, cancellable);
else
mmcli_modem_voice_run_synchronous (connection);
}
/* Modem Time options? */
else if (mmcli_modem_time_options_enabled ()) {
if (async_flag)
mmcli_modem_time_run_asynchronous (connection, cancellable);
else
mmcli_modem_time_run_synchronous (connection);
}
/* Modem Firmware options? */
else if (mmcli_modem_firmware_options_enabled ()) {
if (async_flag)
mmcli_modem_firmware_run_asynchronous (connection, cancellable);
else
mmcli_modem_firmware_run_synchronous (connection);
}
/* Modem Signal options? */
else if (mmcli_modem_signal_options_enabled ()) {
if (async_flag)
mmcli_modem_signal_run_asynchronous (connection, cancellable);
else
mmcli_modem_signal_run_synchronous (connection);
}
/* Modem Oma options? */
else if (mmcli_modem_oma_options_enabled ()) {
if (async_flag)
mmcli_modem_oma_run_asynchronous (connection, cancellable);
else
mmcli_modem_oma_run_synchronous (connection);
}
/* Modem options?
* NOTE: let this check be always the last one, as other groups also need
* having a modem specified, and therefore if -m is set, modem options
* are always enabled. */
else if (mmcli_modem_options_enabled ()) {
if (async_flag)
mmcli_modem_run_asynchronous (connection, cancellable);
else
mmcli_modem_run_synchronous (connection);
}
/* No options? */
else {
g_printerr ("error: no actions specified\n");
exit (EXIT_FAILURE);
}
/* Run loop only in async operations */
if (async_flag)
g_main_loop_run (loop);
if (mmcli_manager_options_enabled ()) {
mmcli_manager_shutdown ();
} else if (mmcli_modem_3gpp_options_enabled ()) {
mmcli_modem_3gpp_shutdown ();
} else if (mmcli_modem_cdma_options_enabled ()) {
mmcli_modem_cdma_shutdown ();
} else if (mmcli_modem_simple_options_enabled ()) {
mmcli_modem_simple_shutdown ();
} else if (mmcli_modem_location_options_enabled ()) {
mmcli_modem_location_shutdown ();
} else if (mmcli_modem_messaging_options_enabled ()) {
mmcli_modem_messaging_shutdown ();
} else if (mmcli_modem_voice_options_enabled ()) {
mmcli_modem_voice_shutdown ();
} else if (mmcli_modem_time_options_enabled ()) {
mmcli_modem_time_shutdown ();
} else if (mmcli_modem_firmware_options_enabled ()) {
mmcli_modem_firmware_shutdown ();
} else if (mmcli_modem_signal_options_enabled ()) {
mmcli_modem_signal_shutdown ();
} else if (mmcli_modem_oma_options_enabled ()) {
mmcli_modem_oma_shutdown ();
} else if (mmcli_sim_options_enabled ()) {
mmcli_sim_shutdown ();
} else if (mmcli_bearer_options_enabled ()) {
mmcli_bearer_shutdown ();
} else if (mmcli_sms_options_enabled ()) {
mmcli_sms_shutdown ();
} else if (mmcli_call_options_enabled ()) {
mmcli_call_shutdown ();
} else if (mmcli_modem_options_enabled ()) {
mmcli_modem_shutdown ();
}
if (cancellable)
g_object_unref (cancellable);
g_main_loop_unref (loop);
g_object_unref (connection);
return EXIT_SUCCESS;
}