biscuit

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

qmi-nmea.c (21286B)


      1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3  * qmi-nmea -- enable location services and print NMEA strings
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  *
     18  * This program started life as qmicli, which is
     19  *
     20  * Copyright (C) 2012-2023 Aleksander Morgado <aleksander@aleksander.es>
     21  * Copyright (c) 2022 Qualcomm Innovation Center, Inc.
     22  *
     23  * Changes Copyright (C) 2024 Daniel Barlow
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <locale.h>
     31 #include <string.h>
     32 
     33 #include <glib.h>
     34 #include <glib/gprintf.h>
     35 #include <gio/gio.h>
     36 #include <glib-unix.h>
     37 
     38 #include <libqmi-glib.h>
     39 
     40 #if QMI_MBIM_QMUX_SUPPORTED
     41 #include <libmbim-glib.h>
     42 #endif
     43 
     44 #include "qmicli.h"
     45 
     46 #define PROGRAM_NAME    "qmi-nmea"
     47 #define PROGRAM_VERSION PACKAGE_VERSION
     48 
     49 /* Globals */
     50 static GMainLoop *loop;
     51 static GCancellable *cancellable;
     52 static QmiDevice *device;
     53 static QmiClient *client;
     54 static QmiService service;
     55 static gboolean operation_status;
     56 static gboolean expect_indications;
     57 #if QMI_QRTR_SUPPORTED
     58 static QrtrBus *qrtr_bus;
     59 #endif
     60 
     61 /* Main options */
     62 static gchar *device_str;
     63 static gboolean get_service_version_info_flag;
     64 static gchar *device_set_instance_id_str;
     65 static gboolean device_open_version_info_flag;
     66 static gboolean device_open_sync_flag;
     67 static gchar *device_open_net_str;
     68 #if QMI_MBIM_QMUX_SUPPORTED
     69 static gboolean device_open_qmi_flag;
     70 static gboolean device_open_mbim_flag;
     71 static gboolean device_open_auto_flag;
     72 #endif
     73 static gchar *client_cid_str;
     74 static gboolean client_no_release_cid_flag;
     75 static gboolean verbose_flag;
     76 static gboolean verbose_full_flag;
     77 static gboolean silent_flag;
     78 static gboolean version_flag;
     79 
     80 static GOptionEntry main_entries[] = {
     81     { "device", 'd', 0, G_OPTION_ARG_STRING, &device_str,
     82 #if QMI_QRTR_SUPPORTED
     83       "Specify device path or QRTR URI (e.g. qrtr://0)",
     84       "[PATH|URI]"
     85 #else
     86       "Specify device path",
     87       "[PATH]"
     88 #endif
     89     },
     90 #if QMI_MBIM_QMUX_SUPPORTED
     91     { "device-open-qmi", 0, 0, G_OPTION_ARG_NONE, &device_open_qmi_flag,
     92       "Open a cdc-wdm device explicitly in QMI mode",
     93       NULL
     94     },
     95     { "device-open-mbim", 0, 0, G_OPTION_ARG_NONE, &device_open_mbim_flag,
     96       "Open a cdc-wdm device explicitly in MBIM mode",
     97       NULL
     98     },
     99     { "device-open-auto", 0, 0, G_OPTION_ARG_NONE, &device_open_auto_flag,
    100       "Open a cdc-wdm device in either QMI or MBIM mode (default)",
    101       NULL
    102     },
    103 #endif
    104     { "client-cid", 0, 0, G_OPTION_ARG_STRING, &client_cid_str,
    105       "Use the given CID, don't allocate a new one",
    106       "[CID]"
    107     },
    108     { "client-no-release-cid", 0, 0, G_OPTION_ARG_NONE, &client_no_release_cid_flag,
    109       "Do not release the CID when exiting",
    110       NULL
    111     },
    112     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_flag,
    113       "Run action with verbose logs, including the debug ones",
    114       NULL
    115     },
    116     { "verbose-full", 0, 0, G_OPTION_ARG_NONE, &verbose_full_flag,
    117       "Run action with verbose logs, including the debug ones and personal info",
    118       NULL
    119     },
    120     { NULL, 0, 0, 0, NULL, NULL, NULL }
    121 };
    122 
    123 static gboolean
    124 signals_handler (void)
    125 {
    126     if (cancellable) {
    127         /* Ignore consecutive requests of cancellation */
    128         if (!g_cancellable_is_cancelled (cancellable)) {
    129             g_printerr ("cancelling the operation...\n");
    130             g_cancellable_cancel (cancellable);
    131             /* Re-set the signal handler to allow main loop cancellation on
    132              * second signal */
    133             return G_SOURCE_CONTINUE;
    134         }
    135     }
    136 
    137     if (loop && g_main_loop_is_running (loop)) {
    138         g_printerr ("cancelling the main loop...\n");
    139         g_idle_add ((GSourceFunc) g_main_loop_quit, loop);
    140     }
    141     return G_SOURCE_REMOVE;
    142 }
    143 
    144 static void
    145 log_handler (const gchar *log_domain,
    146              GLogLevelFlags log_level,
    147              const gchar *message,
    148              gpointer user_data)
    149 {
    150     const gchar *log_level_str;
    151     time_t now;
    152     gchar time_str[64];
    153     struct tm *local_time;
    154     gboolean err;
    155 
    156     /* Nothing to do if we're silent */
    157     if (silent_flag)
    158         return;
    159 
    160     now = time ((time_t *) NULL);
    161     local_time = localtime (&now);
    162     strftime (time_str, 64, "%d %b %Y, %H:%M:%S", local_time);
    163     err = FALSE;
    164 
    165     switch (log_level) {
    166     case G_LOG_LEVEL_WARNING:
    167         log_level_str = "-Warning **";
    168         err = TRUE;
    169         break;
    170 
    171     case G_LOG_LEVEL_CRITICAL:
    172     case G_LOG_LEVEL_ERROR:
    173         log_level_str = "-Error **";
    174         err = TRUE;
    175         break;
    176 
    177     case G_LOG_LEVEL_DEBUG:
    178         log_level_str = "[Debug]";
    179         break;
    180 
    181     case G_LOG_LEVEL_MESSAGE:
    182     case G_LOG_LEVEL_INFO:
    183         log_level_str = "";
    184         break;
    185 
    186     case G_LOG_FLAG_FATAL:
    187     case G_LOG_LEVEL_MASK:
    188     case G_LOG_FLAG_RECURSION:
    189     default:
    190         g_assert_not_reached ();
    191     }
    192 
    193     if (!verbose_flag && !verbose_full_flag && !err)
    194         return;
    195 
    196     g_fprintf (err ? stderr : stdout,
    197                "[%s] %s %s\n",
    198                time_str,
    199                log_level_str,
    200                message);
    201 }
    202 
    203 G_GNUC_NORETURN
    204 static void
    205 print_version_and_exit (void)
    206 {
    207     g_print ("qmi-nmea\n\n"
    208              "Copyright (C) 2012-2023 Aleksander Morgado, 2024 Daniel Barlow\n"
    209              "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\n"
    210              "This is free software: you are free to change and redistribute it.\n"
    211              "There is NO WARRANTY, to the extent permitted by law.\n"
    212              "\n");
    213     exit (EXIT_SUCCESS);
    214 }
    215 
    216 static gboolean
    217 generic_options_enabled (void)
    218 {
    219     static guint n_actions = 0;
    220     static gboolean checked = FALSE;
    221 
    222     if (checked)
    223         return !!n_actions;
    224 
    225     n_actions = (!!device_set_instance_id_str +
    226                  get_service_version_info_flag);
    227 
    228     if (n_actions > 1) {
    229         g_printerr ("error: too many generic actions requested\n");
    230         exit (EXIT_FAILURE);
    231     }
    232 
    233     checked = TRUE;
    234     return !!n_actions;
    235 }
    236 
    237 /*****************************************************************************/
    238 /* Report that indications are expected */
    239 
    240 void
    241 qmicli_expect_indications (void)
    242 {
    243     expect_indications = TRUE;
    244 }
    245 
    246 /*****************************************************************************/
    247 /* Running asynchronously */
    248 
    249 static void
    250 close_ready (QmiDevice    *dev,
    251              GAsyncResult *res)
    252 {
    253     GError *error = NULL;
    254 
    255     if (!qmi_device_close_finish (dev, res, &error)) {
    256         g_printerr ("error: couldn't close: %s\n", error->message);
    257         g_error_free (error);
    258     } else
    259         g_debug ("Closed");
    260 
    261     g_main_loop_quit (loop);
    262 }
    263 
    264 static void
    265 release_client_ready (QmiDevice *dev,
    266                       GAsyncResult *res)
    267 {
    268     GError *error = NULL;
    269 
    270     if (!qmi_device_release_client_finish (dev, res, &error)) {
    271         g_printerr ("error: couldn't release client: %s\n", error->message);
    272         g_error_free (error);
    273     } else
    274         g_debug ("Client released");
    275 
    276     qmi_device_close_async (dev, 10, NULL, (GAsyncReadyCallback) close_ready, NULL);
    277 }
    278 
    279 static guint8 saved_cid = QMI_CID_NONE;
    280 
    281 void
    282 qmicli_async_operation_done (gboolean reported_operation_status,
    283                              gboolean skip_cid_release)
    284 {
    285     QmiDeviceReleaseClientFlags flags = QMI_DEVICE_RELEASE_CLIENT_FLAGS_NONE;
    286 
    287     /* Keep the result of the operation */
    288     operation_status = reported_operation_status;
    289 
    290     /* Cleanup cancellation */
    291     g_clear_object (&cancellable);
    292 
    293     /* If no client was allocated (e.g. generic action), just quit */
    294     if (!client) {
    295         g_main_loop_quit (loop);
    296         return;
    297     }
    298 
    299     if (skip_cid_release) {
    300         g_debug ("Skipped CID release");
    301         saved_cid = qmi_client_get_cid (client);
    302     }
    303     else if (!client_no_release_cid_flag)
    304         flags |= QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID;
    305     else
    306         g_print ("[%s] Client ID not released:\n"
    307                  "\tService: '%s'\n"
    308                  "\t    CID: '%u'\n",
    309                  qmi_device_get_path_display (device),
    310                  qmi_service_get_string (service),
    311                  qmi_client_get_cid (client));
    312 
    313     qmi_device_release_client (device,
    314                                client,
    315                                flags,
    316                                10,
    317                                NULL,
    318                                (GAsyncReadyCallback)release_client_ready,
    319                                NULL);
    320 }
    321 
    322 static void
    323 allocate_client_ready (QmiDevice *dev,
    324                        GAsyncResult *res)
    325 {
    326     GError *error = NULL;
    327 
    328     client = qmi_device_allocate_client_finish (dev, res, &error);
    329     if (!client) {
    330         g_printerr ("error: couldn't create client for the '%s' service: %s\n",
    331                     qmi_service_get_string (service),
    332                     error->message);
    333         exit (EXIT_FAILURE);
    334     }
    335 
    336     /* Run the service-specific action */
    337     switch (service) {
    338     case QMI_SERVICE_LOC:
    339 #if defined HAVE_QMI_SERVICE_LOC
    340         qmicli_loc_run (dev, QMI_CLIENT_LOC (client), cancellable);
    341         return;
    342 #else
    343         break;
    344 #endif
    345     default:
    346         break;
    347     }
    348     g_assert_not_reached ();
    349 }
    350 
    351 static void
    352 device_allocate_client (QmiDevice *dev)
    353 {
    354     guint8 cid = QMI_CID_NONE;
    355 
    356     if (client_cid_str) {
    357         guint32 cid32;
    358 
    359         cid32 = atoi (client_cid_str);
    360         if (!cid32 || cid32 > G_MAXUINT8) {
    361             g_printerr ("error: invalid CID given '%s'\n",
    362                         client_cid_str);
    363             exit (EXIT_FAILURE);
    364         }
    365 
    366         cid = (guint8)cid32;
    367         g_debug ("Reusing CID '%u'", cid);
    368     }
    369     if (saved_cid != QMI_CID_NONE) {
    370         cid = saved_cid;
    371         g_debug ("Using saved CID '%u'", cid);
    372     }
    373 
    374     /* As soon as we get the QmiDevice, create a client for the requested
    375      * service */
    376     qmi_device_allocate_client (dev,
    377                                 service,
    378                                 cid,
    379                                 10,
    380                                 cancellable,
    381                                 (GAsyncReadyCallback)allocate_client_ready,
    382                                 NULL);
    383 }
    384 
    385 static void
    386 set_instance_id_ready (QmiDevice *dev,
    387                        GAsyncResult *res)
    388 {
    389     GError *error = NULL;
    390     guint16 link_id;
    391 
    392     if (!qmi_device_set_instance_id_finish (dev, res, &link_id, &error)) {
    393         g_printerr ("error: couldn't set instance ID: %s\n",
    394                     error->message);
    395         exit (EXIT_FAILURE);
    396     }
    397 
    398     g_print ("[%s] Instance ID set:\n"
    399              "\tLink ID: '%" G_GUINT16_FORMAT "'\n",
    400              qmi_device_get_path_display (dev),
    401              link_id);
    402 
    403     /* We're done now */
    404     qmicli_async_operation_done (TRUE, FALSE);
    405 }
    406 
    407 static void
    408 device_set_instance_id (QmiDevice *dev)
    409 {
    410     gint instance_id;
    411 
    412     if (g_str_equal (device_set_instance_id_str, "0"))
    413         instance_id = 0;
    414     else {
    415         instance_id = atoi (device_set_instance_id_str);
    416         if (instance_id == 0) {
    417             g_printerr ("error: invalid instance ID given: '%s'\n", device_set_instance_id_str);
    418             exit (EXIT_FAILURE);
    419         } else if (instance_id < 0 || instance_id > G_MAXUINT8) {
    420             g_printerr ("error: given instance ID is out of range [0,%u]: '%s'\n",
    421                         G_MAXUINT8,
    422                         device_set_instance_id_str);
    423             exit (EXIT_FAILURE);
    424         }
    425     }
    426 
    427     g_debug ("Setting instance ID '%d'...", instance_id);
    428     qmi_device_set_instance_id (dev,
    429                                 (guint8)instance_id,
    430                                 10,
    431                                 cancellable,
    432                                 (GAsyncReadyCallback)set_instance_id_ready,
    433                                 NULL);
    434 }
    435 
    436 static void
    437 get_service_version_info_ready (QmiDevice *dev,
    438                                 GAsyncResult *res)
    439 {
    440     GError *error = NULL;
    441     GArray *services;
    442     guint i;
    443 
    444     services = qmi_device_get_service_version_info_finish (dev, res, &error);
    445     if (!services) {
    446         g_printerr ("error: couldn't get service version info: %s\n",
    447                     error->message);
    448         exit (EXIT_FAILURE);
    449     }
    450 
    451     g_print ("[%s] Supported versions:\n",
    452              qmi_device_get_path_display (dev));
    453     for (i = 0; i < services->len; i++) {
    454         QmiDeviceServiceVersionInfo *info;
    455         const gchar *service_str;
    456 
    457         info = &g_array_index (services, QmiDeviceServiceVersionInfo, i);
    458         service_str = qmi_service_get_string (info->service);
    459         if (service_str)
    460             g_print ("\t%s (%u.%u)\n",
    461                      service_str,
    462                      info->major_version,
    463                      info->minor_version);
    464         else
    465             g_print ("\tunknown [0x%02x] (%u.%u)\n",
    466                      info->service,
    467                      info->major_version,
    468                      info->minor_version);
    469     }
    470     g_array_unref (services);
    471 
    472     /* We're done now */
    473     qmicli_async_operation_done (TRUE, FALSE);
    474 }
    475 
    476 static void
    477 device_get_service_version_info (QmiDevice *dev)
    478 {
    479     g_debug ("Getting service version info...");
    480     qmi_device_get_service_version_info (dev,
    481                                          10,
    482                                          cancellable,
    483                                          (GAsyncReadyCallback)get_service_version_info_ready,
    484                                          NULL);
    485 }
    486 
    487 static void
    488 device_open_ready (QmiDevice *dev,
    489                    GAsyncResult *res)
    490 {
    491     GError *error = NULL;
    492 
    493     if (!qmi_device_open_finish (dev, res, &error)) {
    494         g_printerr ("error: couldn't open the QmiDevice: %s\n",
    495                     error->message);
    496         exit (EXIT_FAILURE);
    497     }
    498 
    499     g_debug ("QMI Device at '%s' ready",
    500              qmi_device_get_path_display (dev));
    501 
    502     if (device_set_instance_id_str)
    503         device_set_instance_id (dev);
    504     else if (get_service_version_info_flag)
    505         device_get_service_version_info (dev);
    506     else
    507         device_allocate_client (dev);
    508 }
    509 
    510 static void
    511 device_new_ready (GObject *unused,
    512                   GAsyncResult *res)
    513 {
    514     QmiDeviceOpenFlags open_flags = QMI_DEVICE_OPEN_FLAGS_NONE;
    515     GError *error = NULL;
    516 
    517     device = qmi_device_new_finish (res, &error);
    518     if (!device) {
    519         g_printerr ("error: couldn't create QmiDevice: %s\n",
    520                     error->message);
    521         exit (EXIT_FAILURE);
    522     }
    523 
    524 #if QMI_MBIM_QMUX_SUPPORTED
    525     if (device_open_mbim_flag + device_open_qmi_flag + device_open_auto_flag > 1) {
    526         g_printerr ("error: cannot specify multiple mode flags to open device\n");
    527         exit (EXIT_FAILURE);
    528     }
    529 #endif
    530 
    531     /* Setup device open flags */
    532     if (device_open_version_info_flag)
    533         open_flags |= QMI_DEVICE_OPEN_FLAGS_VERSION_INFO;
    534     if (device_open_sync_flag)
    535         open_flags |= QMI_DEVICE_OPEN_FLAGS_SYNC;
    536     open_flags |= QMI_DEVICE_OPEN_FLAGS_PROXY;
    537 #if QMI_MBIM_QMUX_SUPPORTED
    538     if (device_open_mbim_flag)
    539         open_flags |= QMI_DEVICE_OPEN_FLAGS_MBIM;
    540     if (device_open_auto_flag || (!device_open_qmi_flag && !device_open_mbim_flag))
    541         open_flags |= QMI_DEVICE_OPEN_FLAGS_AUTO;
    542 #endif
    543     if (expect_indications)
    544         open_flags |= QMI_DEVICE_OPEN_FLAGS_EXPECT_INDICATIONS;
    545     if (device_open_net_str) {
    546         if (!qmicli_read_device_open_flags_from_string (device_open_net_str, &open_flags) ||
    547             !qmicli_validate_device_open_flags (open_flags))
    548             exit (EXIT_FAILURE);
    549     }
    550 
    551     /* Open the device */
    552     qmi_device_open (device,
    553                      open_flags,
    554                      15,
    555                      cancellable,
    556                      (GAsyncReadyCallback)device_open_ready,
    557                      NULL);
    558 }
    559 
    560 #if QMI_QRTR_SUPPORTED
    561 
    562 static void
    563 bus_new_ready (GObject      *source,
    564                GAsyncResult *res,
    565                gpointer      user_data)
    566 {
    567     g_autoptr(GError)  error = NULL;
    568     guint              node_id;
    569     QrtrNode          *node;
    570 
    571     node_id = GPOINTER_TO_UINT (user_data);
    572 
    573     qrtr_bus = qrtr_bus_new_finish (res, &error);
    574     if (!qrtr_bus) {
    575         g_printerr ("error: couldn't access QRTR bus: %s\n", error->message);
    576         exit (EXIT_FAILURE);
    577     }
    578 
    579     node = qrtr_bus_peek_node (qrtr_bus, node_id);
    580     if (!node) {
    581         g_printerr ("error: node with id %u not found in QRTR bus\n", node_id);
    582         exit (EXIT_FAILURE);
    583     }
    584 
    585     qmi_device_new_from_node (node,
    586                               cancellable,
    587                               (GAsyncReadyCallback)device_new_ready,
    588                               NULL);
    589 }
    590 
    591 #endif
    592 
    593 static gboolean
    594 make_device (GFile *file)
    595 {
    596     g_autofree gchar *id = NULL;
    597 
    598     id = g_file_get_path (file);
    599     if (id) {
    600         /* Describes a local device file. */
    601         qmi_device_new (file,
    602                         cancellable,
    603                         (GAsyncReadyCallback)device_new_ready,
    604                         NULL);
    605         return TRUE;
    606     }
    607 
    608 #if QMI_QRTR_SUPPORTED
    609     {
    610         guint32 node_id;
    611 
    612         id = g_file_get_uri (file);
    613         if (qrtr_get_node_for_uri (id, &node_id)) {
    614             qrtr_bus_new (1000, /* ms */
    615                           cancellable,
    616                           (GAsyncReadyCallback)bus_new_ready,
    617                           GUINT_TO_POINTER (node_id));
    618             return TRUE;
    619         }
    620 
    621         g_printerr ("error: URI is neither a local file path nor a QRTR node: %s\n", id);
    622         return FALSE;
    623     }
    624 #else
    625     g_printerr ("error: URI is not a local file path: %s\n", id);
    626     return FALSE;
    627 #endif
    628 }
    629 
    630 /*****************************************************************************/
    631 
    632 static void
    633 parse_actions (void)
    634 {
    635     guint actions_enabled = 0;
    636 
    637     qmicli_loc_options_enabled ();
    638     service = QMI_SERVICE_LOC;
    639 
    640     /* Go on! */
    641 }
    642 
    643 int main (int argc, char **argv)
    644 {
    645     GError *error = NULL;
    646     GFile *file;
    647     GOptionContext *context;
    648 
    649     setlocale (LC_ALL, "");
    650 
    651     /* Setup option context, process it and destroy it */
    652     context = g_option_context_new ("- Control QMI devices");
    653 #if defined HAVE_QMI_SERVICE_LOC
    654     g_option_context_add_group (context, qmicli_loc_get_option_group ());
    655 #endif
    656     g_option_context_add_main_entries (context, main_entries, NULL);
    657     if (!g_option_context_parse (context, &argc, &argv, &error)) {
    658         g_printerr ("error: %s\n",
    659                     error->message);
    660         exit (EXIT_FAILURE);
    661     }
    662     g_option_context_free (context);
    663 
    664     if (version_flag)
    665         print_version_and_exit ();
    666 
    667     g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, NULL);
    668     g_log_set_handler ("Qmi", G_LOG_LEVEL_MASK, log_handler, NULL);
    669 
    670     if (verbose_flag && verbose_full_flag) {
    671         g_printerr ("error: cannot specify --verbose and --verbose-full at the same time\n");
    672         exit (EXIT_FAILURE);
    673     } else if (verbose_flag) {
    674         qmi_utils_set_traces_enabled (TRUE);
    675         qmi_utils_set_show_personal_info (FALSE);
    676     } else if (verbose_full_flag) {
    677         qmi_utils_set_traces_enabled (TRUE);
    678         qmi_utils_set_show_personal_info (TRUE);
    679     }
    680 
    681 #if QMI_MBIM_QMUX_SUPPORTED
    682     /* libmbim logging */
    683     g_log_set_handler ("Mbim", G_LOG_LEVEL_MASK, log_handler, NULL);
    684     if (verbose_flag) {
    685         mbim_utils_set_traces_enabled (TRUE);
    686 #if MBIM_CHECK_VERSION(1,27,6)
    687         mbim_utils_set_show_personal_info (FALSE);
    688 #endif
    689     } else if (verbose_full_flag) {
    690         mbim_utils_set_traces_enabled (TRUE);
    691 #if MBIM_CHECK_VERSION(1,27,6)
    692         mbim_utils_set_show_personal_info (TRUE);
    693 #endif
    694     }
    695 #endif
    696 
    697 #if QMI_QRTR_SUPPORTED
    698     /* libqrtr-glib logging */
    699     g_log_set_handler ("Qrtr", G_LOG_LEVEL_MASK, log_handler, NULL);
    700 #endif
    701 
    702     /* No device path given? */
    703     if (!device_str) {
    704         g_printerr ("error: no device path specified\n");
    705         exit (EXIT_FAILURE);
    706     }
    707 
    708     /* Build new GFile from the commandline arg */
    709     file = g_file_new_for_commandline_arg (device_str);
    710 
    711     parse_actions ();
    712 
    713     for(int i=0; i<2; i++){
    714         /* Create requirements for async options */
    715         cancellable = g_cancellable_new ();
    716         loop = g_main_loop_new (NULL, FALSE);
    717 
    718         /* Setup signals */
    719         g_unix_signal_add (SIGINT,  (GSourceFunc) signals_handler, NULL);
    720         g_unix_signal_add (SIGHUP,  (GSourceFunc) signals_handler, NULL);
    721         g_unix_signal_add (SIGTERM, (GSourceFunc) signals_handler, NULL);
    722 
    723         /* Launch QmiDevice creation */
    724         if (!make_device (file))
    725             return EXIT_FAILURE;
    726 
    727         g_main_loop_run (loop);
    728         if (cancellable)
    729             g_object_unref (cancellable);
    730         if (client)
    731             g_object_unref (client);
    732         if (device)
    733             g_object_unref (device);
    734         g_main_loop_unref (loop);
    735     }
    736 
    737     g_object_unref (file);
    738 
    739     return (operation_status ? EXIT_SUCCESS : EXIT_FAILURE);
    740 }