Blame clients/cli/nmcli.c

Packit Service 87a54e
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit 5756e2
/*
Packit 5756e2
 * Jiri Klimes <jklimes@redhat.com>
Packit 5756e2
 * Copyright (C) 2010 - 2018 Red Hat, Inc.
Packit 5756e2
 */
Packit 5756e2
Packit Service 2bceb2
#include "libnm/nm-default-client.h"
Packit 5756e2
Packit 5756e2
#include "nmcli.h"
Packit 5756e2
Packit 5756e2
#include <stdio.h>
Packit 5756e2
#include <stdlib.h>
Packit 5756e2
#include <signal.h>
Packit 5756e2
#include <termios.h>
Packit 5756e2
#include <unistd.h>
Packit 5756e2
#include <locale.h>
Packit 5756e2
#include <glib-unix.h>
Packit 5756e2
#include <readline/readline.h>
Packit 5756e2
#include <readline/history.h>
Packit 5756e2
Packit 5756e2
#include "nm-client-utils.h"
Packit 5756e2
Packit 5756e2
#include "polkit-agent.h"
Packit 5756e2
#include "utils.h"
Packit 5756e2
#include "common.h"
Packit 5756e2
#include "connections.h"
Packit 5756e2
#include "devices.h"
Packit 5756e2
#include "settings.h"
Packit 5756e2
Packit 5756e2
#if defined(NM_DIST_VERSION)
Packit Service a1bd4f
    #define NMCLI_VERSION NM_DIST_VERSION
Packit 5756e2
#else
Packit Service a1bd4f
    #define NMCLI_VERSION VERSION
Packit 5756e2
#endif
Packit 5756e2
Packit Service a1bd4f
#define _NMC_COLOR_PALETTE_INIT()                              \
Packit Service a1bd4f
    {                                                          \
Packit Service a1bd4f
        .ansi_seq = {                                          \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTION_ACTIVATED]     = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTION_ACTIVATING]    = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTION_DISCONNECTING] = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTION_INVISIBLE]     = "2",    \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTION_EXTERNAL]      = "32;2", \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTIVITY_FULL]        = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTIVITY_LIMITED]     = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTIVITY_NONE]        = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_CONNECTIVITY_PORTAL]      = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_ACTIVATED]         = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_ACTIVATING]        = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_DISCONNECTED]      = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_FIRMWARE_MISSING]  = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_PLUGIN_MISSING]    = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_UNAVAILABLE]       = "2",    \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_DISABLED]          = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_DEVICE_EXTERNAL]          = "32;2", \
Packit Service a1bd4f
            [NM_META_COLOR_MANAGER_RUNNING]          = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_MANAGER_STARTING]         = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_MANAGER_STOPPED]          = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_PERMISSION_AUTH]          = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_PERMISSION_NO]            = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_PERMISSION_YES]           = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_ASLEEP]             = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_CONNECTED_GLOBAL]   = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_CONNECTED_LOCAL]    = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_CONNECTED_SITE]     = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_CONNECTING]         = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_DISCONNECTED]       = "31",   \
Packit Service a1bd4f
            [NM_META_COLOR_STATE_DISCONNECTING]      = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_WIFI_SIGNAL_EXCELLENT]    = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_WIFI_SIGNAL_FAIR]         = "35",   \
Packit Service a1bd4f
            [NM_META_COLOR_WIFI_SIGNAL_GOOD]         = "33",   \
Packit Service a1bd4f
            [NM_META_COLOR_WIFI_SIGNAL_POOR]         = "36",   \
Packit Service a1bd4f
            [NM_META_COLOR_WIFI_SIGNAL_UNKNOWN]      = "2",    \
Packit Service a1bd4f
            [NM_META_COLOR_ENABLED]                  = "32",   \
Packit Service a1bd4f
            [NM_META_COLOR_DISABLED]                 = "31",   \
Packit Service a1bd4f
        },                                                     \
Packit Service a1bd4f
    }
Packit 5756e2
Packit 5756e2
static NmCli nm_cli = {
Packit Service a1bd4f
    .client = NULL,
Packit Service a1bd4f
Packit Service a1bd4f
    .return_value = NMC_RESULT_SUCCESS,
Packit Service a1bd4f
Packit Service a1bd4f
    .timeout = -1,
Packit Service a1bd4f
Packit Service a1bd4f
    .secret_agent = NULL,
Packit Service a1bd4f
    .pwds_hash    = NULL,
Packit Service a1bd4f
    .pk_listener  = NULL,
Packit Service a1bd4f
Packit Service a1bd4f
    .should_wait                 = 0,
Packit Service a1bd4f
    .nowait_flag                 = TRUE,
Packit Service a1bd4f
    .nmc_config.print_output     = NMC_PRINT_NORMAL,
Packit Service a1bd4f
    .nmc_config.multiline_output = FALSE,
Packit Service a1bd4f
    .mode_specified              = FALSE,
Packit Service a1bd4f
    .nmc_config.escape_values    = TRUE,
Packit Service a1bd4f
    .required_fields             = NULL,
Packit Service a1bd4f
    .ask                         = FALSE,
Packit Service a1bd4f
    .complete                    = FALSE,
Packit Service a1bd4f
    .nmc_config.show_secrets     = FALSE,
Packit Service a1bd4f
    .nmc_config.in_editor        = FALSE,
Packit Service a1bd4f
    .nmc_config.palette          = _NMC_COLOR_PALETTE_INIT(),
Packit Service a1bd4f
    .editor_status_line          = FALSE,
Packit Service a1bd4f
    .editor_save_confirmation    = TRUE,
Packit 5756e2
};
Packit 5756e2
Packit Service a1bd4f
const NmCli *const nm_cli_global_readline   = &nm_cli;
Packit 5756e2
const NmCli *const nmc_meta_environment_arg = &nm_cli;
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    NmCli *nmc;
Packit Service a1bd4f
    int    argc;
Packit Service a1bd4f
    char **argv;
Packit 5756e2
} ArgsInfo;
Packit 5756e2
Packit 5756e2
/* --- Global variables --- */
Packit Service a1bd4f
GMainLoop *    loop = NULL;
Packit 5756e2
struct termios termios_orig;
Packit 5756e2
Packit Service a1bd4f
NM_CACHED_QUARK_FCN("nmcli-error-quark", nmcli_error_quark);
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
complete_field_setting(GHashTable *h, NMMetaSettingType setting_type)
Packit 5756e2
{
Packit Service a1bd4f
    const NMMetaSettingInfoEditor *setting_info = &nm_meta_setting_infos_editor[setting_type];
Packit Service a1bd4f
    guint                          i;
Packit Service a1bd4f
Packit Service a1bd4f
    for (i = 0; i < setting_info->properties_num; i++) {
Packit Service a1bd4f
        g_hash_table_add(h,
Packit Service a1bd4f
                         g_strdup_printf("%s.%s",
Packit Service a1bd4f
                                         setting_info->general->setting_name,
Packit Service a1bd4f
                                         setting_info->properties[i]->property_name));
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
complete_field(GHashTable *h, const NmcMetaGenericInfo *const *field)
Packit 5756e2
{
Packit Service a1bd4f
    int i;
Packit 5756e2
Packit Service a1bd4f
    for (i = 0; field[i]; i++)
Packit Service a1bd4f
        g_hash_table_add(h, g_strdup(field[i]->name));
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
complete_one(gpointer key, gpointer value, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    const char **option_with_value = user_data;
Packit Service a1bd4f
    const char * option            = option_with_value[0];
Packit Service a1bd4f
    const char * prefix            = option_with_value[1];
Packit Service a1bd4f
    const char * name              = key;
Packit Service a1bd4f
    const char * last;
Packit Service a1bd4f
Packit Service a1bd4f
    last = strrchr(prefix, ',');
Packit Service a1bd4f
    if (last)
Packit Service a1bd4f
        last++;
Packit Service a1bd4f
    else
Packit Service a1bd4f
        last = prefix;
Packit Service a1bd4f
Packit Service a1bd4f
    if ((!*last && !strchr(name, '.')) || matches(last, name)) {
Packit Service a1bd4f
        if (option != prefix) {
Packit Service a1bd4f
            /* value prefix was not a standalone argument,
Packit Service a1bd4f
             * it was part of --option=<value> argument.
Packit Service a1bd4f
             * Repeat the part leading to "=". */
Packit Service a1bd4f
            g_print("%s=", option);
Packit Service a1bd4f
        }
Packit Service a1bd4f
        g_print("%.*s%s%s\n",
Packit Service a1bd4f
                (int) (last - prefix),
Packit Service a1bd4f
                prefix,
Packit Service a1bd4f
                name,
Packit Service a1bd4f
                strcmp(last, name) == 0 ? "," : "");
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
complete_fields(const char *option, const char *prefix)
Packit 5756e2
{
Packit Service a1bd4f
    guint       i;
Packit Service a1bd4f
    GHashTable *h;
Packit Service a1bd4f
    const char *option_with_value[2] = {option, prefix};
Packit Service a1bd4f
Packit Service a1bd4f
    h = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL);
Packit Service a1bd4f
Packit Service a1bd4f
    complete_field(h, metagen_ip4_config);
Packit Service a1bd4f
    complete_field(h, metagen_dhcp_config);
Packit Service a1bd4f
    complete_field(h, metagen_ip6_config);
Packit Service a1bd4f
    complete_field(h, metagen_con_show);
Packit Service a1bd4f
    complete_field(h, metagen_con_active_general);
Packit Service a1bd4f
    complete_field(h, metagen_con_active_vpn);
Packit Service a1bd4f
    complete_field(h, nmc_fields_con_active_details_groups);
Packit Service a1bd4f
    complete_field(h, metagen_device_status);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_general);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_connections);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_capabilities);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_wired_properties);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_wifi_properties);
Packit Service a1bd4f
    complete_field(h, metagen_device_detail_wimax_properties);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_wifi_list);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_wimax_list);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_show_master_prop);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_show_team_prop);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_show_vlan_prop);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_show_bluetooth);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_show_sections);
Packit Service a1bd4f
    complete_field(h, nmc_fields_dev_lldp_list);
Packit Service a1bd4f
Packit Service a1bd4f
    for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++)
Packit Service a1bd4f
        complete_field_setting(h, i);
Packit Service a1bd4f
Packit Service a1bd4f
    g_hash_table_foreach(h, complete_one, (gpointer) &option_with_value[0]);
Packit Service a1bd4f
    g_hash_table_destroy(h);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
complete_option_with_value(const char *option, const char *prefix, ...)
Packit 5756e2
{
Packit Service a1bd4f
    va_list     args;
Packit Service a1bd4f
    const char *candidate;
Packit Service a1bd4f
Packit Service a1bd4f
    va_start(args, prefix);
Packit Service a1bd4f
    while ((candidate = va_arg(args, const char *))) {
Packit Service a1bd4f
        if (!*prefix || matches(prefix, candidate)) {
Packit Service a1bd4f
            if (option != prefix) {
Packit Service a1bd4f
                /* value prefix was not a standalone argument,
Packit Service a1bd4f
                 * it was part of --option=<value> argument.
Packit Service a1bd4f
                 * Repeat the part leading to "=". */
Packit Service a1bd4f
                g_print("%s=", option);
Packit Service a1bd4f
            }
Packit Service a1bd4f
            g_print("%s\n", candidate);
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
    va_end(args);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
usage(void)
Packit 5756e2
{
Packit Service a1bd4f
    g_printerr(_(
Packit Service a1bd4f
        "Usage: nmcli [OPTIONS] OBJECT { COMMAND | help }\n"
Packit Service a1bd4f
        "\n"
Packit Service a1bd4f
        "OPTIONS\n"
Packit Service a1bd4f
        "  -a, --ask                                ask for missing parameters\n"
Packit Service a1bd4f
        "  -c, --colors auto|yes|no                 whether to use colors in output\n"
Packit Service a1bd4f
        "  -e, --escape yes|no                      escape columns separators in values\n"
Packit Service a1bd4f
        "  -f, --fields <field,...>|all|common      specify fields to output\n"
Packit Service a1bd4f
        "  -g, --get-values <field,...>|all|common  shortcut for -m tabular -t -f\n"
Packit Service a1bd4f
        "  -h, --help                               print this help\n"
Packit Service a1bd4f
        "  -m, --mode tabular|multiline             output mode\n"
Packit Service a1bd4f
        "  -o, --overview                           overview mode\n"
Packit Service a1bd4f
        "  -p, --pretty                             pretty output\n"
Packit Service a1bd4f
        "  -s, --show-secrets                       allow displaying passwords\n"
Packit Service a1bd4f
        "  -t, --terse                              terse output\n"
Packit Service a1bd4f
        "  -v, --version                            show program version\n"
Packit Service a1bd4f
        "  -w, --wait <seconds>                     set timeout waiting for finishing operations\n"
Packit Service a1bd4f
        "\n"
Packit Service a1bd4f
        "OBJECT\n"
Packit Service a1bd4f
        "  g[eneral]       NetworkManager's general status and operations\n"
Packit Service a1bd4f
        "  n[etworking]    overall networking control\n"
Packit Service a1bd4f
        "  r[adio]         NetworkManager radio switches\n"
Packit Service a1bd4f
        "  c[onnection]    NetworkManager's connections\n"
Packit Service a1bd4f
        "  d[evice]        devices managed by NetworkManager\n"
Packit Service a1bd4f
        "  a[gent]         NetworkManager secret agent or polkit agent\n"
Packit Service a1bd4f
        "  m[onitor]       monitor NetworkManager changes\n"
Packit Service a1bd4f
        "\n"));
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
matches_arg(NmCli *nmc, int *argc, const char *const **argv, const char *pattern, char **arg)
Packit 5756e2
{
Packit Service a1bd4f
    gs_free char *opt_free = NULL;
Packit Service a1bd4f
    const char *  opt      = (*argv)[0];
Packit Service a1bd4f
    gs_free char *arg_tmp  = NULL;
Packit Service a1bd4f
    const char *  s;
Packit Service a1bd4f
Packit Service a1bd4f
    nm_assert(opt);
Packit Service a1bd4f
    nm_assert(opt[0] == '-');
Packit Service a1bd4f
    nm_assert(!arg || !*arg);
Packit Service a1bd4f
Packit Service a1bd4f
    if (nmc->return_value != NMC_RESULT_SUCCESS) {
Packit Service a1bd4f
        /* Don't process further matches if there has been an error. */
Packit Service a1bd4f
        return FALSE;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (opt[1] == '-') {
Packit Service a1bd4f
        /* We know one '-' was already seen by the caller.
Packit Service a1bd4f
         * Skip it if there's a second one*/
Packit Service a1bd4f
        opt++;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (arg) {
Packit Service a1bd4f
        /* If there's a "=" separator, replace it with NUL so that matches()
Packit Service a1bd4f
         * works and consider the part after it to be the argument's value. */
Packit Service a1bd4f
        s = strchr(opt, '=');
Packit Service a1bd4f
        if (s) {
Packit Service a1bd4f
            opt     = nm_strndup_a(300, opt, s - opt, &opt_free);
Packit Service a1bd4f
            arg_tmp = g_strdup(&s[1]);
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!matches(opt, pattern))
Packit Service a1bd4f
        return FALSE;
Packit Service a1bd4f
Packit Service a1bd4f
    if (arg) {
Packit Service a1bd4f
        if (arg_tmp)
Packit Service a1bd4f
            *arg = g_steal_pointer(&arg_tmp);
Packit Service a1bd4f
        else {
Packit Service a1bd4f
            /* We need a value, but the option didn't contain a "=<value>" part.
Packit Service a1bd4f
             * Proceed to the next argument. */
Packit Service a1bd4f
            if (*argc <= 1) {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: missing argument for '%s' option."),
Packit Service a1bd4f
                                opt);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
            (*argc)--;
Packit Service a1bd4f
            (*argv)++;
Packit Service a1bd4f
            *arg = g_strdup(*argv[0]);
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return TRUE;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
/*************************************************************************************/
Packit 5756e2
Packit 5756e2
typedef enum {
Packit Service a1bd4f
    NMC_USE_COLOR_AUTO,
Packit Service a1bd4f
    NMC_USE_COLOR_YES,
Packit Service a1bd4f
    NMC_USE_COLOR_NO,
Packit 5756e2
} NmcColorOption;
Packit 5756e2
Packit 5756e2
static char *
Packit Service a1bd4f
check_colors_construct_filename(const char *base_dir,
Packit Service a1bd4f
                                const char *name,
Packit Service a1bd4f
                                const char *term,
Packit Service a1bd4f
                                const char *type)
Packit 5756e2
{
Packit Service a1bd4f
    return g_strdup_printf("%s/terminal-colors.d/%s%s%s%s%s",
Packit Service a1bd4f
                           base_dir,
Packit Service a1bd4f
                           name ? name : "",
Packit Service a1bd4f
                           term ? "@" : "",
Packit Service a1bd4f
                           term ? term : "",
Packit Service a1bd4f
                           (name || term) ? "." : "",
Packit Service a1bd4f
                           type);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static NmcColorOption
Packit Service a1bd4f
check_colors_check_enabled_one_file(const char *base_dir, const char *name, const char *term)
Packit 5756e2
{
Packit Service a1bd4f
    gs_free char *filename_e = NULL;
Packit Service a1bd4f
    gs_free char *filename_d = NULL;
Packit 5756e2
Packit Service a1bd4f
    filename_e = check_colors_construct_filename(base_dir, name, term, "enable");
Packit Service a1bd4f
    if (g_file_test(filename_e, G_FILE_TEST_EXISTS))
Packit Service a1bd4f
        return NMC_USE_COLOR_YES;
Packit 5756e2
Packit Service a1bd4f
    filename_d = check_colors_construct_filename(base_dir, name, term, "disable");
Packit Service a1bd4f
    if (g_file_test(filename_d, G_FILE_TEST_EXISTS))
Packit Service a1bd4f
        return NMC_USE_COLOR_NO;
Packit 5756e2
Packit Service a1bd4f
    return NMC_USE_COLOR_AUTO;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static char *
Packit Service a1bd4f
check_colors_check_palette_one_file(const char *base_dir, const char *name, const char *term)
Packit 5756e2
{
Packit Service a1bd4f
    static const char *const extensions[] = {
Packit Service a1bd4f
        "scheme",
Packit Service a1bd4f
        "schem",
Packit Service a1bd4f
    };
Packit Service a1bd4f
    guint i;
Packit Service a1bd4f
Packit Service a1bd4f
    for (i = 0; i < G_N_ELEMENTS(extensions); i++) {
Packit Service a1bd4f
        gs_free char *filename = NULL;
Packit Service a1bd4f
        char *        contents;
Packit Service a1bd4f
Packit Service a1bd4f
        filename = check_colors_construct_filename(base_dir, name, term, extensions[i]);
Packit Service a1bd4f
        if (g_file_get_contents(filename, &contents, NULL, NULL))
Packit Service a1bd4f
            return contents;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return NULL;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
check_colors_check_enabled(const char *base_dir_1,
Packit Service a1bd4f
                           const char *base_dir_2,
Packit Service a1bd4f
                           const char *name,
Packit Service a1bd4f
                           const char *term)
Packit 5756e2
{
Packit Service a1bd4f
    int i;
Packit Service a1bd4f
Packit Service a1bd4f
    if (term && strchr(term, '/'))
Packit Service a1bd4f
        term = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
#define CHECK_AND_RETURN(cmd)                          \
Packit Service a1bd4f
    G_STMT_START                                       \
Packit Service a1bd4f
    {                                                  \
Packit Service a1bd4f
        NmcColorOption _color_option;                  \
Packit Service a1bd4f
                                                       \
Packit Service a1bd4f
        _color_option = (cmd);                         \
Packit Service a1bd4f
        if (_color_option != NMC_USE_COLOR_AUTO)       \
Packit Service a1bd4f
            return _color_option == NMC_USE_COLOR_YES; \
Packit Service a1bd4f
    }                                                  \
Packit Service a1bd4f
    G_STMT_END
Packit Service a1bd4f
Packit Service a1bd4f
    for (i = 0; i < 2; i++) {
Packit Service a1bd4f
        const char *base_dir = (i == 0 ? base_dir_1 : base_dir_2);
Packit Service a1bd4f
Packit Service a1bd4f
        if (!base_dir)
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
        if (name && term)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_enabled_one_file(base_dir, name, term));
Packit Service a1bd4f
        if (name)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_enabled_one_file(base_dir, name, NULL));
Packit Service a1bd4f
        if (term)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_enabled_one_file(base_dir, NULL, term));
Packit Service a1bd4f
        if (TRUE)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_enabled_one_file(base_dir, NULL, NULL));
Packit Service a1bd4f
    }
Packit 5756e2
#undef CHECK_AND_RETURN
Packit Service a1bd4f
    return TRUE;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static char *
Packit Service a1bd4f
check_colors_check_palette(const char *base_dir_1,
Packit Service a1bd4f
                           const char *base_dir_2,
Packit Service a1bd4f
                           const char *name,
Packit Service a1bd4f
                           const char *term)
Packit 5756e2
{
Packit Service a1bd4f
    int i;
Packit 5756e2
Packit Service a1bd4f
    if (term && strchr(term, '/'))
Packit Service a1bd4f
        term = NULL;
Packit 5756e2
Packit 5756e2
#define CHECK_AND_RETURN(cmd) \
Packit Service a1bd4f
    G_STMT_START              \
Packit Service a1bd4f
    {                         \
Packit Service a1bd4f
        char *_palette;       \
Packit Service a1bd4f
                              \
Packit Service a1bd4f
        _palette = (cmd);     \
Packit Service a1bd4f
        if (_palette)         \
Packit Service a1bd4f
            return _palette;  \
Packit Service a1bd4f
    }                         \
Packit Service a1bd4f
    G_STMT_END
Packit Service a1bd4f
Packit Service a1bd4f
    for (i = 0; i < 2; i++) {
Packit Service a1bd4f
        const char *base_dir = (i == 0 ? base_dir_1 : base_dir_2);
Packit Service a1bd4f
Packit Service a1bd4f
        if (!base_dir)
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
        if (name && term)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_palette_one_file(base_dir, name, term));
Packit Service a1bd4f
        if (name)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_palette_one_file(base_dir, name, NULL));
Packit Service a1bd4f
        if (term)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_palette_one_file(base_dir, NULL, term));
Packit Service a1bd4f
        if (TRUE)
Packit Service a1bd4f
            CHECK_AND_RETURN(check_colors_check_palette_one_file(base_dir, NULL, NULL));
Packit Service a1bd4f
    }
Packit 5756e2
#undef CHECK_AND_RETURN
Packit Service a1bd4f
    return NULL;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
check_colors(NmcColorOption color_option, char **out_palette_str)
Packit 5756e2
{
Packit Service a1bd4f
    const char *      base_dir_1, *base_dir_2;
Packit Service a1bd4f
    const char *const NAME = "nmcli";
Packit Service a1bd4f
    const char *      term;
Packit 5756e2
Packit Service a1bd4f
    *out_palette_str = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!NM_IN_SET(color_option, NMC_USE_COLOR_AUTO, NMC_USE_COLOR_YES)) {
Packit Service a1bd4f
        /* nothing to do. Colors are disabled. */
Packit Service a1bd4f
        return FALSE;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (color_option == NMC_USE_COLOR_AUTO && g_getenv("NO_COLOR")) {
Packit Service a1bd4f
        /* https://no-color.org/ */
Packit Service a1bd4f
        return FALSE;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    term = g_getenv("TERM");
Packit Service a1bd4f
Packit Service a1bd4f
    if (color_option == NMC_USE_COLOR_AUTO) {
Packit Service a1bd4f
        if (nm_streq0(term, "dumb") || !isatty(STDOUT_FILENO))
Packit Service a1bd4f
            return FALSE;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    base_dir_1 = g_get_user_config_dir();
Packit Service a1bd4f
    base_dir_2 = "" SYSCONFDIR;
Packit Service a1bd4f
Packit Service a1bd4f
    if (base_dir_1) {
Packit Service a1bd4f
        if (nm_streq(base_dir_1, base_dir_2) || !g_file_test(base_dir_1, G_FILE_TEST_EXISTS))
Packit Service a1bd4f
            base_dir_1 = NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
    if (!g_file_test(base_dir_2, G_FILE_TEST_EXISTS))
Packit Service a1bd4f
        base_dir_2 = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (color_option == NMC_USE_COLOR_AUTO
Packit Service a1bd4f
        && !check_colors_check_enabled(base_dir_1, base_dir_2, NAME, term))
Packit Service a1bd4f
        return FALSE;
Packit Service a1bd4f
Packit Service a1bd4f
    *out_palette_str = check_colors_check_palette(base_dir_1, base_dir_2, NAME, term);
Packit Service a1bd4f
    return TRUE;
Packit 5756e2
}
Packit 5756e2
Packit Service a1bd4f
static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
Packit Service a1bd4f
    _resolve_color_alias,
Packit Service a1bd4f
    const char *,
Packit Service a1bd4f
    { nm_assert(name); },
Packit Service a1bd4f
    { return NULL; },
Packit Service a1bd4f
    {"black", "30"},
Packit Service a1bd4f
    {"blink", "5"},
Packit Service a1bd4f
    {"blue", "34"},
Packit Service a1bd4f
    {"bold", "1"},
Packit Service a1bd4f
    {"brown", "33"},
Packit Service a1bd4f
    {"cyan", "36"},
Packit Service a1bd4f
    {"darkgray", "90"},
Packit Service a1bd4f
    {"gray", "37"},
Packit Service a1bd4f
    {"green", "32"},
Packit Service a1bd4f
    {"halfbright", "2"},
Packit Service a1bd4f
    {"lightblue", "94"},
Packit Service a1bd4f
    {"lightcyan", "96"},
Packit Service a1bd4f
    {"lightgray", "97"},
Packit Service a1bd4f
    {"lightgreen", "92"},
Packit Service a1bd4f
    {"lightmagenta", "95"},
Packit Service a1bd4f
    {"lightred", "91"},
Packit Service a1bd4f
    {"magenta", "35"},
Packit Service a1bd4f
    {"red", "31"},
Packit Service a1bd4f
    {"reset", "0"},
Packit Service a1bd4f
    {"reverse", "7"},
Packit Service a1bd4f
    {"underscore", "4"},
Packit Service a1bd4f
    {"white", "1;37"},
Packit Service a1bd4f
    {"yellow", "33" /* well, yellow */}, );
Packit Service a1bd4f
Packit Service a1bd4f
static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
Packit Service a1bd4f
    _nm_meta_color_from_name,
Packit Service a1bd4f
    NMMetaColor,
Packit Service a1bd4f
    { nm_assert(name); },
Packit Service a1bd4f
    { return NM_META_COLOR_NONE; },
Packit Service a1bd4f
    {"connection-activated", NM_META_COLOR_CONNECTION_ACTIVATED},
Packit Service a1bd4f
    {"connection-activating", NM_META_COLOR_CONNECTION_ACTIVATING},
Packit Service a1bd4f
    {"connection-disconnecting", NM_META_COLOR_CONNECTION_DISCONNECTING},
Packit Service a1bd4f
    {"connection-external", NM_META_COLOR_CONNECTION_EXTERNAL},
Packit Service a1bd4f
    {"connection-invisible", NM_META_COLOR_CONNECTION_INVISIBLE},
Packit Service a1bd4f
    {"connection-unknown", NM_META_COLOR_CONNECTION_UNKNOWN},
Packit Service a1bd4f
    {"connectivity-full", NM_META_COLOR_CONNECTIVITY_FULL},
Packit Service a1bd4f
    {"connectivity-limited", NM_META_COLOR_CONNECTIVITY_LIMITED},
Packit Service a1bd4f
    {"connectivity-none", NM_META_COLOR_CONNECTIVITY_NONE},
Packit Service a1bd4f
    {"connectivity-portal", NM_META_COLOR_CONNECTIVITY_PORTAL},
Packit Service a1bd4f
    {"connectivity-unknown", NM_META_COLOR_CONNECTIVITY_UNKNOWN},
Packit Service a1bd4f
    {"device-activated", NM_META_COLOR_DEVICE_ACTIVATED},
Packit Service a1bd4f
    {"device-activating", NM_META_COLOR_DEVICE_ACTIVATING},
Packit Service a1bd4f
    {"device-disabled", NM_META_COLOR_DEVICE_DISABLED},
Packit Service a1bd4f
    {"device-disconnected", NM_META_COLOR_DEVICE_DISCONNECTED},
Packit Service a1bd4f
    {"device-external", NM_META_COLOR_DEVICE_EXTERNAL},
Packit Service a1bd4f
    {"device-firmware-missing", NM_META_COLOR_DEVICE_FIRMWARE_MISSING},
Packit Service a1bd4f
    {"device-plugin-missing", NM_META_COLOR_DEVICE_PLUGIN_MISSING},
Packit Service a1bd4f
    {"device-unavailable", NM_META_COLOR_DEVICE_UNAVAILABLE},
Packit Service a1bd4f
    {"device-unknown", NM_META_COLOR_DEVICE_UNKNOWN},
Packit Service a1bd4f
    {"disabled", NM_META_COLOR_DISABLED},
Packit Service a1bd4f
    {"enabled", NM_META_COLOR_ENABLED},
Packit Service a1bd4f
    {"manager-running", NM_META_COLOR_MANAGER_RUNNING},
Packit Service a1bd4f
    {"manager-starting", NM_META_COLOR_MANAGER_STARTING},
Packit Service a1bd4f
    {"manager-stopped", NM_META_COLOR_MANAGER_STOPPED},
Packit Service a1bd4f
    {"permission-auth", NM_META_COLOR_PERMISSION_AUTH},
Packit Service a1bd4f
    {"permission-no", NM_META_COLOR_PERMISSION_NO},
Packit Service a1bd4f
    {"permission-unknown", NM_META_COLOR_PERMISSION_UNKNOWN},
Packit Service a1bd4f
    {"permission-yes", NM_META_COLOR_PERMISSION_YES},
Packit Service a1bd4f
    {"prompt", NM_META_COLOR_PROMPT},
Packit Service a1bd4f
    {"state-asleep", NM_META_COLOR_STATE_ASLEEP},
Packit Service a1bd4f
    {"state-connected-global", NM_META_COLOR_STATE_CONNECTED_GLOBAL},
Packit Service a1bd4f
    {"state-connected-local", NM_META_COLOR_STATE_CONNECTED_LOCAL},
Packit Service a1bd4f
    {"state-connected-site", NM_META_COLOR_STATE_CONNECTED_SITE},
Packit Service a1bd4f
    {"state-connecting", NM_META_COLOR_STATE_CONNECTING},
Packit Service a1bd4f
    {"state-disconnected", NM_META_COLOR_STATE_DISCONNECTED},
Packit Service a1bd4f
    {"state-disconnecting", NM_META_COLOR_STATE_DISCONNECTING},
Packit Service a1bd4f
    {"state-unknown", NM_META_COLOR_STATE_UNKNOWN},
Packit Service a1bd4f
    {"wifi-signal-excellent", NM_META_COLOR_WIFI_SIGNAL_EXCELLENT},
Packit Service a1bd4f
    {"wifi-signal-fair", NM_META_COLOR_WIFI_SIGNAL_FAIR},
Packit Service a1bd4f
    {"wifi-signal-good", NM_META_COLOR_WIFI_SIGNAL_GOOD},
Packit Service a1bd4f
    {"wifi-signal-poor", NM_META_COLOR_WIFI_SIGNAL_POOR},
Packit Service a1bd4f
    {"wifi-signal-unknown", NM_META_COLOR_WIFI_SIGNAL_UNKNOWN}, );
Packit Service a1bd4f
Packit 5756e2
static gboolean
Packit Service a1bd4f
parse_color_scheme(char *palette_buffer, NmcColorPalette *out_palette, GError **error)
Packit 5756e2
{
Packit Service a1bd4f
    char *p = palette_buffer;
Packit Service a1bd4f
Packit Service a1bd4f
    nm_assert(out_palette);
Packit Service a1bd4f
Packit Service a1bd4f
    *out_palette = (NmcColorPalette) _NMC_COLOR_PALETTE_INIT();
Packit Service a1bd4f
Packit Service a1bd4f
    /* This reads through the raw color scheme file contents, identifying the
Packit Service a1bd4f
     * color names and sequences, putting in terminating NULs in place, so that
Packit Service a1bd4f
     * pointers into the buffer can readily be used as strings in the palette. */
Packit Service a1bd4f
    while (1) {
Packit Service a1bd4f
        NMMetaColor name_idx;
Packit Service a1bd4f
        const char *name;
Packit Service a1bd4f
        const char *color;
Packit Service a1bd4f
Packit Service a1bd4f
        /* Leading whitespace. */
Packit Service a1bd4f
        while (nm_utils_is_separator(*p) || *p == '\n')
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
Packit Service a1bd4f
        if (*p == '\0')
Packit Service a1bd4f
            break;
Packit Service a1bd4f
Packit Service a1bd4f
        /* Comments. */
Packit Service a1bd4f
        if (*p == '#') {
Packit Service a1bd4f
            while (*p != '\n' && *p != '\0')
Packit Service a1bd4f
                p++;
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        /* Color name. */
Packit Service a1bd4f
        name = p;
Packit Service a1bd4f
        while (g_ascii_isgraph(*p))
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
        if (*p == '\0') {
Packit Service a1bd4f
            g_set_error(error, NMCLI_ERROR, 0, _("Unexpected end of file following '%s'\n"), name);
Packit Service a1bd4f
            return FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        /* Separating whitespace. */
Packit Service a1bd4f
        if (!nm_utils_is_separator(*p)) {
Packit Service a1bd4f
            *p = '\0';
Packit Service a1bd4f
            g_set_error(error, NMCLI_ERROR, 0, _("Expected whitespace following '%s'\n"), name);
Packit Service a1bd4f
            return FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
        while (nm_utils_is_separator(*p)) {
Packit Service a1bd4f
            *p = '\0';
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        /* Color sequence. */
Packit Service a1bd4f
        color = p;
Packit Service a1bd4f
        if (!g_ascii_isgraph(*p)) {
Packit Service a1bd4f
            g_set_error(error, NMCLI_ERROR, 0, _("Expected a value for '%s'\n"), name);
Packit Service a1bd4f
            return FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
        while (g_ascii_isgraph(*p))
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
Packit Service a1bd4f
        /* Trailing whitespace. */
Packit Service a1bd4f
        while (nm_utils_is_separator(*p)) {
Packit Service a1bd4f
            *p = '\0';
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
        }
Packit Service a1bd4f
        if (*p != '\0') {
Packit Service a1bd4f
            if (*p != '\n') {
Packit Service a1bd4f
                g_set_error(error,
Packit Service a1bd4f
                            NMCLI_ERROR,
Packit Service a1bd4f
                            0,
Packit Service a1bd4f
                            _("Expected a line break following '%s'\n"),
Packit Service a1bd4f
                            color);
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
            *p = '\0';
Packit Service a1bd4f
            p++;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        name_idx = _nm_meta_color_from_name(name);
Packit Service a1bd4f
        if (name_idx == NM_META_COLOR_NONE) {
Packit Service a1bd4f
            g_debug("Ignoring an unrecognized color: '%s'\n", name);
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        out_palette->ansi_seq[name_idx] = _resolve_color_alias(color) ?: color;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return TRUE;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
set_colors(NmcColorOption   color_option,
Packit Service a1bd4f
           bool *           out_use_colors,
Packit Service a1bd4f
           char **          out_palette_buffer,
Packit Service a1bd4f
           NmcColorPalette *out_palette)
Packit 5756e2
{
Packit Service a1bd4f
    gs_free char *palette_str = NULL;
Packit Service a1bd4f
    gboolean      use_colors;
Packit Service a1bd4f
    gboolean      palette_set = FALSE;
Packit 5756e2
Packit Service a1bd4f
    nm_assert(out_use_colors);
Packit Service a1bd4f
    nm_assert(out_palette);
Packit Service a1bd4f
    nm_assert(out_palette_buffer && !*out_palette_buffer);
Packit 5756e2
Packit Service a1bd4f
    use_colors = check_colors(color_option, &palette_str);
Packit 5756e2
Packit Service a1bd4f
    *out_use_colors = use_colors;
Packit Service a1bd4f
Packit Service a1bd4f
    if (use_colors && palette_str) {
Packit Service a1bd4f
        gs_free_error GError *error = NULL;
Packit Service a1bd4f
        NmcColorPalette       palette;
Packit Service a1bd4f
Packit Service a1bd4f
        if (!parse_color_scheme(palette_str, &palette, &error))
Packit Service a1bd4f
            g_debug("Error parsing color scheme: %s", error->message);
Packit Service a1bd4f
        else {
Packit Service a1bd4f
            *out_palette_buffer = g_steal_pointer(&palette_str);
Packit Service a1bd4f
            *out_palette        = palette;
Packit Service a1bd4f
            palette_set         = TRUE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!palette_set)
Packit Service a1bd4f
        *out_palette = (NmcColorPalette) _NMC_COLOR_PALETTE_INIT();
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
/*************************************************************************************/
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
process_command_line(NmCli *nmc, int argc, char **argv_orig)
Packit 5756e2
{
Packit Service a1bd4f
    static const NMCCommand nmcli_cmds[] = {
Packit Service a1bd4f
        {"general", nmc_command_func_general, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {"monitor", nmc_command_func_monitor, NULL, TRUE, FALSE},
Packit Service a1bd4f
        {"networking", nmc_command_func_networking, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {"radio", nmc_command_func_radio, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {"connection", nmc_command_func_connection, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {"device", nmc_command_func_device, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {"agent", nmc_command_func_agent, NULL, FALSE, FALSE},
Packit Service a1bd4f
        {NULL, nmc_command_func_overview, usage, TRUE, TRUE},
Packit Service a1bd4f
    };
Packit Service a1bd4f
    NmcColorOption     colors = NMC_USE_COLOR_AUTO;
Packit Service a1bd4f
    const char *       base;
Packit Service a1bd4f
    const char *const *argv;
Packit Service a1bd4f
Packit Service a1bd4f
    base = strrchr(argv_orig[0], '/');
Packit Service a1bd4f
    if (base == NULL)
Packit Service a1bd4f
        base = argv_orig[0];
Packit Service a1bd4f
    else
Packit Service a1bd4f
        base++;
Packit Service a1bd4f
Packit Service a1bd4f
    if (argc > 1 && nm_streq(argv_orig[1], "--complete-args")) {
Packit Service a1bd4f
        nmc->complete = TRUE;
Packit Service a1bd4f
        argv_orig[1]  = argv_orig[0];
Packit Service a1bd4f
        argc--;
Packit Service a1bd4f
        argv_orig++;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    argv = (const char *const *) argv_orig;
Packit Service a1bd4f
Packit Service a1bd4f
    next_arg(nmc, &argc, &argv, NULL);
Packit Service a1bd4f
Packit Service a1bd4f
    /* parse options */
Packit Service a1bd4f
    while (argc) {
Packit Service a1bd4f
        gs_free char *value = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
        if (argv[0][0] != '-')
Packit Service a1bd4f
            break;
Packit Service a1bd4f
Packit Service a1bd4f
        if (argc == 1 && nmc->complete) {
Packit Service a1bd4f
            nmc_complete_strings(argv[0],
Packit Service a1bd4f
                                 "--terse",
Packit Service a1bd4f
                                 "--pretty",
Packit Service a1bd4f
                                 "--mode",
Packit Service a1bd4f
                                 "--overview",
Packit Service a1bd4f
                                 "--colors",
Packit Service a1bd4f
                                 "--escape",
Packit Service a1bd4f
                                 "--fields",
Packit Service a1bd4f
                                 "--nocheck",
Packit Service a1bd4f
                                 "--get-values",
Packit Service a1bd4f
                                 "--wait",
Packit Service a1bd4f
                                 "--version",
Packit Service a1bd4f
                                 "--help");
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        if (argv[0][1] == '-' && argv[0][2] == '\0') {
Packit Service a1bd4f
            /* '--' ends options */
Packit Service a1bd4f
            next_arg(nmc, &argc, &argv, NULL);
Packit Service a1bd4f
            break;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        if (matches_arg(nmc, &argc, &argv, "-overview", NULL)) {
Packit Service a1bd4f
            nmc->nmc_config_mutable.overview = TRUE;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-terse", NULL)) {
Packit Service a1bd4f
            if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: Option '--terse' is specified the second time."));
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            } else if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
Packit Service a1bd4f
                g_string_printf(
Packit Service a1bd4f
                    nmc->return_text,
Packit Service a1bd4f
                    _("Error: Option '--terse' is mutually exclusive with '--pretty'."));
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            } else
Packit Service a1bd4f
                nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-pretty", NULL)) {
Packit Service a1bd4f
            if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: Option '--pretty' is specified the second time."));
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            } else if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
Packit Service a1bd4f
                g_string_printf(
Packit Service a1bd4f
                    nmc->return_text,
Packit Service a1bd4f
                    _("Error: Option '--pretty' is mutually exclusive with '--terse'."));
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            } else
Packit Service a1bd4f
                nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-mode", &value)) {
Packit Service a1bd4f
            nmc->mode_specified = TRUE;
Packit Service a1bd4f
            if (argc == 1 && nmc->complete)
Packit Service a1bd4f
                complete_option_with_value(argv[0], value, "tabular", "multiline", NULL);
Packit Service a1bd4f
            if (matches(value, "tabular"))
Packit Service a1bd4f
                nmc->nmc_config_mutable.multiline_output = FALSE;
Packit Service a1bd4f
            else if (matches(value, "multiline"))
Packit Service a1bd4f
                nmc->nmc_config_mutable.multiline_output = TRUE;
Packit Service a1bd4f
            else {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: '%s' is not a valid argument for '%s' option."),
Packit Service a1bd4f
                                value,
Packit Service a1bd4f
                                argv[0]);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-colors", &value)) {
Packit Service a1bd4f
            if (argc == 1 && nmc->complete)
Packit Service a1bd4f
                complete_option_with_value(argv[0], value, "yes", "no", "auto", NULL);
Packit Service a1bd4f
            if (matches(value, "auto"))
Packit Service a1bd4f
                colors = NMC_USE_COLOR_AUTO;
Packit Service a1bd4f
            else if (matches(value, "yes"))
Packit Service a1bd4f
                colors = NMC_USE_COLOR_YES;
Packit Service a1bd4f
            else if (matches(value, "no"))
Packit Service a1bd4f
                colors = NMC_USE_COLOR_NO;
Packit Service a1bd4f
            else {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: '%s' is not valid argument for '%s' option."),
Packit Service a1bd4f
                                value,
Packit Service a1bd4f
                                argv[0]);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-escape", &value)) {
Packit Service a1bd4f
            if (argc == 1 && nmc->complete)
Packit Service a1bd4f
                complete_option_with_value(argv[0], value, "yes", "no", NULL);
Packit Service a1bd4f
            if (matches(value, "yes"))
Packit Service a1bd4f
                nmc->nmc_config_mutable.escape_values = TRUE;
Packit Service a1bd4f
            else if (matches(value, "no"))
Packit Service a1bd4f
                nmc->nmc_config_mutable.escape_values = FALSE;
Packit Service a1bd4f
            else {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: '%s' is not valid argument for '%s' option."),
Packit Service a1bd4f
                                value,
Packit Service a1bd4f
                                argv[0]);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-fields", &value)) {
Packit Service a1bd4f
            if (argc == 1 && nmc->complete)
Packit Service a1bd4f
                complete_fields(argv[0], value);
Packit Service a1bd4f
            nmc->required_fields = g_strdup(value);
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-get-values", &value)) {
Packit Service a1bd4f
            if (argc == 1 && nmc->complete)
Packit Service a1bd4f
                complete_fields(argv[0], value);
Packit Service a1bd4f
            nmc->required_fields                 = g_strdup(value);
Packit Service a1bd4f
            nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
Packit Service a1bd4f
            /* We want fixed tabular mode here, but just set the mode specified and rely on defaults:
Packit Service a1bd4f
             * in this way we allow use of "-m multiline" to swap the output mode also if placed
Packit Service a1bd4f
             * before the "-g <field>" option (-g may be still more practical and easy to remember than -t -f).
Packit Service a1bd4f
             */
Packit Service a1bd4f
            nmc->mode_specified = TRUE;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-nocheck", NULL)) {
Packit Service a1bd4f
            /* ignore for backward compatibility */
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-wait", &value)) {
Packit Service a1bd4f
            unsigned long timeout;
Packit Service a1bd4f
Packit Service a1bd4f
            if (!nmc_string_to_uint(value, TRUE, 0, G_MAXINT, &timeout)) {
Packit Service a1bd4f
                g_string_printf(nmc->return_text, _("Error: '%s' is not a valid timeout."), value);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
                return FALSE;
Packit Service a1bd4f
            }
Packit Service a1bd4f
            nmc->timeout = (int) timeout;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-version", NULL)) {
Packit Service a1bd4f
            if (!nmc->complete)
Packit Service a1bd4f
                g_print(_("nmcli tool, version %s\n"), NMCLI_VERSION);
Packit Service a1bd4f
            return NMC_RESULT_SUCCESS;
Packit Service a1bd4f
        } else if (matches_arg(nmc, &argc, &argv, "-help", NULL)) {
Packit Service a1bd4f
            if (!nmc->complete)
Packit Service a1bd4f
                usage();
Packit Service a1bd4f
            return NMC_RESULT_SUCCESS;
Packit Service a1bd4f
        } else {
Packit Service a1bd4f
            if (nmc->return_value == NMC_RESULT_SUCCESS) {
Packit Service a1bd4f
                g_string_printf(nmc->return_text,
Packit Service a1bd4f
                                _("Error: Option '%s' is unknown, try 'nmcli -help'."),
Packit Service a1bd4f
                                argv[0]);
Packit Service a1bd4f
                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
Packit Service a1bd4f
            }
Packit Service a1bd4f
            return FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        next_arg(nmc, &argc, &argv, NULL);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    /* Ignore --overview when fields are set explicitly */
Packit Service a1bd4f
    if (nmc->required_fields)
Packit Service a1bd4f
        nmc->nmc_config_mutable.overview = FALSE;
Packit Service a1bd4f
Packit Service a1bd4f
    set_colors(colors,
Packit Service a1bd4f
               &nmc->nmc_config_mutable.use_colors,
Packit Service a1bd4f
               &nmc->palette_buffer,
Packit Service a1bd4f
               &nmc->nmc_config_mutable.palette);
Packit Service a1bd4f
Packit Service a1bd4f
    /* Now run the requested command */
Packit Service a1bd4f
    nmc_do_cmd(nmc, nmcli_cmds, *argv, argc, argv);
Packit Service a1bd4f
Packit Service a1bd4f
    return TRUE;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean nmcli_sigint = FALSE;
Packit 5756e2
Packit 5756e2
gboolean
Packit Service a1bd4f
nmc_seen_sigint(void)
Packit 5756e2
{
Packit Service a1bd4f
    return nmcli_sigint;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
void
Packit Service a1bd4f
nmc_clear_sigint(void)
Packit 5756e2
{
Packit Service a1bd4f
    nmcli_sigint = FALSE;
Packit 5756e2
}
Packit 5756e2
Packit Service a1bd4f
void
Packit Service a1bd4f
nmc_exit(void)
Packit 5756e2
{
Packit Service a1bd4f
    tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_orig);
Packit Service a1bd4f
    nmc_cleanup_readline();
Packit Service a1bd4f
    exit(1);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
signal_handler(gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    int signo = GPOINTER_TO_INT(user_data);
Packit Service a1bd4f
Packit Service a1bd4f
    switch (signo) {
Packit Service a1bd4f
    case SIGINT:
Packit Service a1bd4f
        if (nmc_get_in_readline()) {
Packit Service a1bd4f
            nmcli_sigint = TRUE;
Packit Service a1bd4f
        } else {
Packit Service a1bd4f
            nm_cli.return_value = 0x80 + signo;
Packit Service a1bd4f
            g_string_printf(nm_cli.return_text,
Packit Service a1bd4f
                            _("Error: nmcli terminated by signal %s (%d)"),
Packit Service a1bd4f
                            strsignal(signo),
Packit Service a1bd4f
                            signo);
Packit Service a1bd4f
            g_main_loop_quit(loop);
Packit Service a1bd4f
        }
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    case SIGTERM:
Packit Service a1bd4f
        nm_cli.return_value = 0x80 + signo;
Packit Service a1bd4f
        g_string_printf(nm_cli.return_text,
Packit Service a1bd4f
                        _("Error: nmcli terminated by signal %s (%d)"),
Packit Service a1bd4f
                        strsignal(signo),
Packit Service a1bd4f
                        signo);
Packit Service a1bd4f
        nmc_exit();
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return G_SOURCE_CONTINUE;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
void
Packit Service a1bd4f
nm_cli_spawn_pager(const NmcConfig *nmc_config, NmcPagerData *pager_data)
Packit 5756e2
{
Packit Service a1bd4f
    if (pager_data->pid != 0)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    pager_data->pid = nmc_terminal_spawn_pager(nmc_config);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
nmc_cleanup(NmCli *nmc)
Packit 5756e2
{
Packit Service a1bd4f
    pid_t ret;
Packit 5756e2
Packit Service a1bd4f
    g_clear_object(&nmc->client);
Packit 5756e2
Packit Service a1bd4f
    if (nmc->return_text)
Packit Service a1bd4f
        g_string_free(g_steal_pointer(&nmc->return_text), TRUE);
Packit 5756e2
Packit Service a1bd4f
    if (nmc->secret_agent) {
Packit Service a1bd4f
        nm_secret_agent_old_unregister(NM_SECRET_AGENT_OLD(nmc->secret_agent), NULL, NULL);
Packit Service a1bd4f
        g_clear_object(&nmc->secret_agent);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    nm_clear_pointer(&nmc->pwds_hash, g_hash_table_destroy);
Packit 5756e2
Packit Service a1bd4f
    nm_clear_g_free(&nmc->required_fields);
Packit 5756e2
Packit Service a1bd4f
    if (nmc->pager_data.pid != 0) {
Packit Service a1bd4f
        pid_t pid = nm_steal_int(&nmc->pager_data.pid);
Packit 5756e2
Packit Service a1bd4f
        fclose(stdout);
Packit Service a1bd4f
        fclose(stderr);
Packit Service a1bd4f
        do {
Packit Service a1bd4f
            ret = waitpid(pid, NULL, 0);
Packit Service a1bd4f
        } while (ret == -1 && errno == EINTR);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    nm_clear_g_free(&nmc->palette_buffer);
Packit 5756e2
Packit Service a1bd4f
    nmc_polkit_agent_fini(nmc);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
int
Packit Service a1bd4f
main(int argc, char *argv[])
Packit 5756e2
{
Packit Service a1bd4f
    /* Set locale to use environment variables */
Packit Service a1bd4f
    setlocale(LC_ALL, "");
Packit 5756e2
Packit 5756e2
#ifdef GETTEXT_PACKAGE
Packit Service a1bd4f
    /* Set i18n stuff */
Packit Service a1bd4f
    bindtextdomain(GETTEXT_PACKAGE, NMLOCALEDIR);
Packit Service a1bd4f
    bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
Packit Service a1bd4f
    textdomain(GETTEXT_PACKAGE);
Packit 5756e2
#endif
Packit 5756e2
Packit Service a1bd4f
    /* Save terminal settings */
Packit Service a1bd4f
    tcgetattr(STDIN_FILENO, &termios_orig);
Packit 5756e2
Packit Service a1bd4f
    nm_cli.return_text = g_string_new(_("Success"));
Packit Service a1bd4f
    loop               = g_main_loop_new(NULL, FALSE);
Packit 5756e2
Packit Service a1bd4f
    g_unix_signal_add(SIGTERM, signal_handler, GINT_TO_POINTER(SIGTERM));
Packit Service a1bd4f
    g_unix_signal_add(SIGINT, signal_handler, GINT_TO_POINTER(SIGINT));
Packit 5756e2
Packit Service a1bd4f
    if (process_command_line(&nm_cli, argc, argv))
Packit Service a1bd4f
        g_main_loop_run(loop);
Packit 5756e2
Packit Service a1bd4f
    if (nm_cli.complete) {
Packit Service a1bd4f
        /* Remove error statuses from command completion runs. */
Packit Service a1bd4f
        if (nm_cli.return_value < NMC_RESULT_COMPLETE_FILE)
Packit Service a1bd4f
            nm_cli.return_value = NMC_RESULT_SUCCESS;
Packit Service a1bd4f
    } else if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
Packit Service a1bd4f
        /* Print result descripting text */
Packit Service a1bd4f
        g_printerr("%s\n", nm_cli.return_text->str);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    nmc_cleanup(&nm_cli);
Packit Service a1bd4f
    g_main_loop_unref(loop);
Packit 5756e2
Packit Service a1bd4f
    return nm_cli.return_value;
Packit 5756e2
}