
Many func implementations are asynchronous, that means, they cannot return right away. Instead, they record the return value in nmc->result_value. The return value from the command functions was thus redundant. In the best case, the return value agrees with the cached result in nmc->result_value, in which it was unnecessary. In the worst case, they disagree, and overwrite each other. nmc->result_value is state. Tracking state is hard, and there should be fewer places where the state gets mutated. Also, the rules how that happened should be clearer. Drop the redundant, conflicting mechanism.
1542 lines
48 KiB
C
1542 lines
48 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2010 - 2018 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "nm-libnm-core-intern/nm-common-macros.h"
|
|
|
|
#include "nm-client-utils.h"
|
|
|
|
#include "polkit-agent.h"
|
|
#include "utils.h"
|
|
#include "common.h"
|
|
#include "common.h"
|
|
#include "devices.h"
|
|
#include "connections.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void permission_changed (GObject *gobject,
|
|
GParamSpec *pspec,
|
|
NmCli *nmc);
|
|
|
|
/*****************************************************************************/
|
|
|
|
static
|
|
NM_UTILS_LOOKUP_STR_DEFINE (nm_state_to_string, NMState,
|
|
NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_ASLEEP, N_("asleep")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTING, N_("connecting")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_LOCAL, N_("connected (local only)")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_SITE, N_("connected (site only)")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_GLOBAL, N_("connected")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_DISCONNECTING, N_("disconnecting")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_STATE_DISCONNECTED, N_("disconnected")),
|
|
NM_UTILS_LOOKUP_ITEM_IGNORE (NM_STATE_UNKNOWN),
|
|
);
|
|
|
|
static NMMetaColor
|
|
state_to_color (NMState state)
|
|
{
|
|
switch (state) {
|
|
case NM_STATE_CONNECTING:
|
|
return NM_META_COLOR_STATE_CONNECTING;
|
|
case NM_STATE_CONNECTED_LOCAL:
|
|
return NM_META_COLOR_STATE_CONNECTED_LOCAL;
|
|
case NM_STATE_CONNECTED_SITE:
|
|
return NM_META_COLOR_STATE_CONNECTED_SITE;
|
|
case NM_STATE_CONNECTED_GLOBAL:
|
|
return NM_META_COLOR_STATE_CONNECTED_GLOBAL;
|
|
case NM_STATE_DISCONNECTING:
|
|
return NM_META_COLOR_STATE_DISCONNECTING;
|
|
case NM_STATE_ASLEEP:
|
|
return NM_META_COLOR_STATE_ASLEEP;
|
|
case NM_STATE_DISCONNECTED:
|
|
return NM_META_COLOR_STATE_DISCONNECTED;
|
|
default:
|
|
return NM_META_COLOR_STATE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static NMMetaColor
|
|
connectivity_to_color (NMConnectivityState connectivity)
|
|
{
|
|
switch (connectivity) {
|
|
case NM_CONNECTIVITY_NONE:
|
|
return NM_META_COLOR_CONNECTIVITY_NONE;
|
|
case NM_CONNECTIVITY_PORTAL:
|
|
return NM_META_COLOR_CONNECTIVITY_PORTAL;
|
|
case NM_CONNECTIVITY_LIMITED:
|
|
return NM_META_COLOR_CONNECTIVITY_LIMITED;
|
|
case NM_CONNECTIVITY_FULL:
|
|
return NM_META_COLOR_CONNECTIVITY_FULL;
|
|
default:
|
|
return NM_META_COLOR_CONNECTIVITY_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static const char *
|
|
permission_to_string (NMClientPermission perm)
|
|
{
|
|
return nm_auth_permission_to_string (perm)
|
|
?: _("unknown");
|
|
}
|
|
|
|
static
|
|
NM_UTILS_LOOKUP_STR_DEFINE (permission_result_to_string, NMClientPermissionResult,
|
|
NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, N_("yes")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, N_("no")),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, N_("auth")),
|
|
NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN),
|
|
);
|
|
|
|
static
|
|
NM_UTILS_LOOKUP_DEFINE (permission_result_to_color, NMClientPermissionResult, NMMetaColor,
|
|
NM_UTILS_LOOKUP_DEFAULT (NM_META_COLOR_PERMISSION_UNKNOWN),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, NM_META_COLOR_PERMISSION_YES),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, NM_META_COLOR_PERMISSION_NO),
|
|
NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, NM_META_COLOR_PERMISSION_AUTH),
|
|
NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN),
|
|
);
|
|
|
|
/*****************************************************************************/
|
|
|
|
static const NmcMetaGenericInfo *const metagen_general_status[];
|
|
|
|
static gconstpointer
|
|
_metagen_general_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
|
|
{
|
|
NmCli *nmc = target;
|
|
const char *value;
|
|
gboolean v_bool;
|
|
NMState state;
|
|
NMConnectivityState connectivity;
|
|
|
|
switch (info->info_type) {
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING:
|
|
NMC_HANDLE_COLOR (NM_META_COLOR_NONE);
|
|
value = N_("running");
|
|
goto translate_and_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION:
|
|
NMC_HANDLE_COLOR (NM_META_COLOR_NONE);
|
|
value = nm_client_get_version (nmc->client);
|
|
goto clone_and_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE:
|
|
state = nm_client_get_state (nmc->client);
|
|
NMC_HANDLE_COLOR (state_to_color (state));
|
|
value = nm_state_to_string (state);
|
|
goto translate_and_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP:
|
|
v_bool = nm_client_get_startup (nmc->client);
|
|
NMC_HANDLE_COLOR (v_bool ? NM_META_COLOR_MANAGER_STARTING : NM_META_COLOR_MANAGER_RUNNING);
|
|
value = v_bool ? N_("starting") : N_("started");
|
|
goto translate_and_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY:
|
|
connectivity = nm_client_get_connectivity (nmc->client);
|
|
NMC_HANDLE_COLOR (connectivity_to_color (connectivity));
|
|
value = nm_connectivity_to_string (connectivity);
|
|
goto translate_and_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING:
|
|
v_bool = nm_client_networking_get_enabled (nmc->client);
|
|
goto enabled_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW:
|
|
v_bool = nm_client_wireless_hardware_get_enabled (nmc->client);
|
|
goto enabled_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI:
|
|
v_bool = nm_client_wireless_get_enabled (nmc->client);
|
|
goto enabled_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW:
|
|
v_bool = nm_client_wwan_hardware_get_enabled (nmc->client);
|
|
goto enabled_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN:
|
|
v_bool = nm_client_wwan_get_enabled (nmc->client);
|
|
goto enabled_out;
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW:
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX:
|
|
/* deprecated fields. Don't return anything. */
|
|
return NULL;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
enabled_out:
|
|
NMC_HANDLE_COLOR (v_bool ? NM_META_COLOR_ENABLED : NM_META_COLOR_DISABLED);
|
|
value = v_bool ? N_("enabled") : N_("disabled");
|
|
goto translate_and_out;
|
|
|
|
clone_and_out:
|
|
return (*out_to_free = g_strdup (value));
|
|
|
|
translate_and_out:
|
|
if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
|
|
return _(value);
|
|
return value;
|
|
}
|
|
|
|
static const NmcMetaGenericInfo *const metagen_general_status[_NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NUM + 1] = {
|
|
#define _METAGEN_GENERAL_STATUS(type, name) \
|
|
[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_status_get_fcn)
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING, "RUNNING"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION, "VERSION"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE, "STATE"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP, "STARTUP"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY, "CONNECTIVITY"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING, "NETWORKING"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW, "WIFI-HW"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI, "WIFI"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW, "WWAN-HW"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN, "WWAN"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW, "WIMAX-HW"),
|
|
_METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX, "WIMAX"),
|
|
};
|
|
#define NMC_FIELDS_NM_STATUS_ALL "RUNNING,VERSION,STATE,STARTUP,CONNECTIVITY,NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
|
|
#define NMC_FIELDS_NM_STATUS_SWITCH "NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
|
|
#define NMC_FIELDS_NM_STATUS_RADIO "WIFI-HW,WIFI,WWAN-HW,WWAN"
|
|
#define NMC_FIELDS_NM_STATUS_COMMON "STATE,CONNECTIVITY,WIFI-HW,WIFI,WWAN-HW,WWAN"
|
|
#define NMC_FIELDS_NM_NETWORKING "NETWORKING"
|
|
#define NMC_FIELDS_NM_WIFI "WIFI"
|
|
#define NMC_FIELDS_NM_WWAN "WWAN"
|
|
#define NMC_FIELDS_NM_WIMAX "WIMAX"
|
|
#define NMC_FIELDS_NM_CONNECTIVITY "CONNECTIVITY"
|
|
|
|
/*****************************************************************************/
|
|
|
|
static gconstpointer
|
|
_metagen_general_permissions_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
|
|
{
|
|
NMClientPermission perm = GPOINTER_TO_UINT (target);
|
|
NmCli *nmc = environment_user_data;
|
|
NMClientPermissionResult perm_result;
|
|
const char *s;
|
|
|
|
switch (info->info_type) {
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION:
|
|
NMC_HANDLE_COLOR (NM_META_COLOR_NONE);
|
|
return permission_to_string (perm);
|
|
case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE:
|
|
perm_result = nm_client_get_permission_result (nmc->client, perm);
|
|
NMC_HANDLE_COLOR (permission_result_to_color (perm_result));
|
|
s = permission_result_to_string (perm_result);
|
|
if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
|
|
return _(s);
|
|
return s;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_return_val_if_reached (NULL);
|
|
}
|
|
|
|
static const NmcMetaGenericInfo *const metagen_general_permissions[_NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_NUM + 1] = {
|
|
#define _METAGEN_GENERAL_PERMISSIONS(type, name) \
|
|
[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_permissions_get_fcn)
|
|
_METAGEN_GENERAL_PERMISSIONS (NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION, "PERMISSION"),
|
|
_METAGEN_GENERAL_PERMISSIONS (NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE, "VALUE"),
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
typedef struct {
|
|
bool initialized;
|
|
char **level;
|
|
char **domains;
|
|
} GetGeneralLoggingData;
|
|
|
|
static gconstpointer
|
|
_metagen_general_logging_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
|
|
{
|
|
NmCli *nmc = environment_user_data;
|
|
GetGeneralLoggingData *d = target;
|
|
|
|
nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM);
|
|
|
|
NMC_HANDLE_COLOR (NM_META_COLOR_NONE);
|
|
|
|
if (!d->initialized) {
|
|
d->initialized = TRUE;
|
|
if (!nm_client_get_logging (nmc->client,
|
|
d->level,
|
|
d->domains,
|
|
NULL))
|
|
return NULL;
|
|
}
|
|
|
|
if (info->info_type == NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_LEVEL)
|
|
return *d->level;
|
|
else
|
|
return *d->domains;
|
|
}
|
|
|
|
static const NmcMetaGenericInfo *const metagen_general_logging[_NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM + 1] = {
|
|
#define _METAGEN_GENERAL_LOGGING(type, name) \
|
|
[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_logging_get_fcn)
|
|
_METAGEN_GENERAL_LOGGING (NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_LEVEL, "LEVEL"),
|
|
_METAGEN_GENERAL_LOGGING (NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_DOMAINS, "DOMAINS"),
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
usage_general (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general { COMMAND | help }\n\n"
|
|
"COMMAND := { status | hostname | permissions | logging }\n\n"
|
|
" status\n\n"
|
|
" hostname [<hostname>]\n\n"
|
|
" permissions\n\n"
|
|
" logging [level <log level>] [domains <log domains>]\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_general_status (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general status { help }\n"
|
|
"\n"
|
|
"Show overall status of NetworkManager.\n"
|
|
"'status' is the default action, which means 'nmcli gen' calls 'nmcli gen status'\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_general_hostname (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general hostname { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [<hostname>]\n"
|
|
"\n"
|
|
"Get or change persistent system hostname.\n"
|
|
"With no arguments, this prints currently configured hostname. When you pass\n"
|
|
"a hostname, NetworkManager will set it as the new persistent system hostname.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_general_permissions (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general permissions { help }\n"
|
|
"\n"
|
|
"Show caller permissions for authenticated operations.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_general_reload (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general reload { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [<flag>[,<flag>...]]\n"
|
|
"\n"
|
|
"Reload NetworkManager's configuration and perform certain updates, like\n"
|
|
"flushing caches or rewriting external state to disk. This is similar to\n"
|
|
"sending SIGHUP to NetworkManager but it allows for more fine-grained\n"
|
|
"control over what to reload through the flags argument. It also allows\n"
|
|
"non-root access via PolicyKit and contrary to signals it is synchronous.\n"
|
|
"\n"
|
|
"Available flags are:\n"
|
|
"\n"
|
|
" 'conf' Reload the NetworkManager.conf configuration from\n"
|
|
" disk. Note that this does not include connections, which\n"
|
|
" can be reloaded through 'nmcli connection reload' instead.\n"
|
|
"\n"
|
|
" 'dns-rc' Update DNS configuration, which usually involves writing\n"
|
|
" /etc/resolv.conf anew.\n"
|
|
"\n"
|
|
" 'dns-full' Restart the DNS plugin. This is for example useful when\n"
|
|
" using dnsmasq plugin, which uses additional configuration\n"
|
|
" in /etc/NetworkManager/dnsmasq.d. If you edit those files,\n"
|
|
" you can restart the DNS plugin. This action shortly\n"
|
|
" interrupts name resolution.\n"
|
|
"\n"
|
|
"With no flags, everything that is supported is reloaded, which is\n"
|
|
"identical to sending a SIGHUP.\n"));
|
|
}
|
|
|
|
static void
|
|
usage_general_logging (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli general logging { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [level <log level>] [domains <log domains>]\n"
|
|
"\n"
|
|
"Get or change NetworkManager logging level and domains.\n"
|
|
"Without any argument current logging level and domains are shown. In order to\n"
|
|
"change logging state, provide level and/or domain. Please refer to the man page\n"
|
|
"for the list of possible logging domains.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_networking (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli networking { COMMAND | help }\n\n"
|
|
"COMMAND := { [ on | off | connectivity ] }\n\n"
|
|
" on\n\n"
|
|
" off\n\n"
|
|
" connectivity [check]\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_networking_on (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli networking on { help }\n"
|
|
"\n"
|
|
"Switch networking on.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_networking_off (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli networking off { help }\n"
|
|
"\n"
|
|
"Switch networking off.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_networking_connectivity (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli networking connectivity { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [check]\n"
|
|
"\n"
|
|
"Get network connectivity state.\n"
|
|
"The optional 'check' argument makes NetworkManager re-check the connectivity.\n\n"));
|
|
|
|
}
|
|
|
|
static void
|
|
usage_radio (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli radio { COMMAND | help }\n\n"
|
|
"COMMAND := { all | wifi | wwan }\n\n"
|
|
" all | wifi | wwan [ on | off ]\n\n"
|
|
));
|
|
}
|
|
|
|
static void
|
|
usage_radio_all (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli radio all { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [on | off]\n"
|
|
"\n"
|
|
"Get status of all radio switches, or turn them on/off.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_radio_wifi (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli radio wifi { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [on | off]\n"
|
|
"\n"
|
|
"Get status of Wi-Fi radio switch, or turn it on/off.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_radio_wwan (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli radio wwan { ARGUMENTS | help }\n"
|
|
"\n"
|
|
"ARGUMENTS := [on | off]\n"
|
|
"\n"
|
|
"Get status of mobile broadband radio switch, or turn it on/off.\n\n"));
|
|
}
|
|
|
|
static void
|
|
usage_monitor (void)
|
|
{
|
|
g_printerr (_("Usage: nmcli monitor\n"
|
|
"\n"
|
|
"Monitor NetworkManager changes.\n"
|
|
"Prints a line whenever a change occurs in NetworkManager\n\n"));
|
|
}
|
|
|
|
static void
|
|
quit (void)
|
|
{
|
|
g_main_loop_quit (loop);
|
|
}
|
|
|
|
static gboolean
|
|
show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_flds)
|
|
{
|
|
gs_free_error GError *error = NULL;
|
|
const char *fields_str;
|
|
const char *fields_all = print_flds ?: NMC_FIELDS_NM_STATUS_ALL;
|
|
const char *fields_common = print_flds ?: NMC_FIELDS_NM_STATUS_COMMON;
|
|
|
|
if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
|
|
fields_str = fields_common;
|
|
else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0)
|
|
fields_str = fields_all;
|
|
else
|
|
fields_str = nmc->required_fields;
|
|
|
|
if (!nmc_print (&nmc->nmc_config,
|
|
(gpointer[]) { nmc, NULL },
|
|
NULL,
|
|
pretty_header_name ?: N_("NetworkManager status"),
|
|
(const NMMetaAbstractInfo *const*) metagen_general_status,
|
|
fields_str,
|
|
&error)) {
|
|
g_string_printf (nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
do_general_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
show_nm_status (nmc, NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
timeout_cb (gpointer user_data)
|
|
{
|
|
NmCli *nmc = (NmCli *) user_data;
|
|
|
|
g_signal_handlers_disconnect_by_func (nmc->client,
|
|
G_CALLBACK (permission_changed),
|
|
nmc);
|
|
|
|
g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
|
|
nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
|
|
quit ();
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
print_permissions (void *user_data)
|
|
{
|
|
NmCli *nmc = user_data;
|
|
gs_free_error GError *error = NULL;
|
|
const char *fields_str = NULL;
|
|
gpointer permissions[G_N_ELEMENTS (nm_auth_permission_sorted) + 1];
|
|
gboolean is_running;
|
|
int i;
|
|
|
|
is_running = nm_client_get_nm_running (nmc->client);
|
|
|
|
if ( is_running
|
|
&& nm_client_get_permissions_state (nmc->client) != NM_TERNARY_TRUE) {
|
|
/* wait longer. Permissions are not up to date. */
|
|
return;
|
|
}
|
|
|
|
g_signal_handlers_disconnect_by_func (nmc->client,
|
|
G_CALLBACK (permission_changed),
|
|
nmc);
|
|
|
|
if (!is_running) {
|
|
/* NetworkManager quit while we were waiting. */
|
|
g_string_printf (nmc->return_text, _("NetworkManager is not running."));
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
|
quit ();
|
|
return;
|
|
}
|
|
|
|
if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
|
|
} else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
|
|
} else
|
|
fields_str = nmc->required_fields;
|
|
|
|
for (i = 0; i < (int) G_N_ELEMENTS (nm_auth_permission_sorted); i++)
|
|
permissions[i] = GINT_TO_POINTER (nm_auth_permission_sorted[i]);
|
|
permissions[i] = NULL;
|
|
|
|
nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
|
|
|
|
if (!nmc_print (&nmc->nmc_config,
|
|
permissions,
|
|
NULL,
|
|
_("NetworkManager permissions"),
|
|
(const NMMetaAbstractInfo *const*) metagen_general_permissions,
|
|
fields_str,
|
|
&error)) {
|
|
g_string_printf (nmc->return_text, _("Error: 'general permissions': %s"), error->message);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
}
|
|
|
|
quit ();
|
|
}
|
|
|
|
static void
|
|
permission_changed (GObject *gobject,
|
|
GParamSpec *pspec,
|
|
NmCli *nmc)
|
|
{
|
|
if (NM_IN_STRSET (pspec->name, NM_CLIENT_NM_RUNNING,
|
|
NM_CLIENT_PERMISSIONS_STATE))
|
|
print_permissions (nmc);
|
|
}
|
|
|
|
static gboolean
|
|
show_nm_permissions (NmCli *nmc)
|
|
{
|
|
NMClientInstanceFlags instance_flags;
|
|
|
|
instance_flags = nm_client_get_instance_flags (nmc->client);
|
|
instance_flags &= ~NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS;
|
|
|
|
g_object_set (nmc->client,
|
|
NM_CLIENT_INSTANCE_FLAGS, (guint) instance_flags,
|
|
NULL);
|
|
|
|
g_signal_connect (nmc->client,
|
|
"notify",
|
|
G_CALLBACK (permission_changed),
|
|
nmc);
|
|
|
|
if (nmc->timeout == -1)
|
|
nmc->timeout = 10;
|
|
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
|
|
|
|
nmc->should_wait++;
|
|
|
|
print_permissions (nmc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
do_general_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
gs_unref_variant GVariant *result = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
gs_free const char **values = NULL;
|
|
gs_free char *err_token = NULL;
|
|
gs_free char *joined = NULL;
|
|
int flags = 0;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
if (nmc->complete) {
|
|
if (argc == 0)
|
|
return;
|
|
|
|
if (argc == 1) {
|
|
values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
|
|
NM_MANAGER_RELOAD_FLAG_CONF,
|
|
NM_MANAGER_RELOAD_FLAG_ALL);
|
|
nmc_complete_strv (*argv, -1, values);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (argc > 0) {
|
|
if (!nm_utils_enum_from_str (nm_manager_reload_flags_get_type (), *argv, &flags, &err_token)) {
|
|
values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
|
|
NM_MANAGER_RELOAD_FLAG_CONF,
|
|
NM_MANAGER_RELOAD_FLAG_ALL);
|
|
joined = g_strjoinv (",", (char **) values);
|
|
g_string_printf (nmc->return_text,
|
|
_("Error: invalid reload flag '%s'. Allowed flags are: %s"),
|
|
err_token,
|
|
joined);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (argc > 0) {
|
|
g_string_printf (nmc->return_text, _("Error: extra argument '%s'"), *argv);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return;
|
|
}
|
|
|
|
result = nmc_dbus_call_sync (nmc,
|
|
"/org/freedesktop/NetworkManager",
|
|
"org.freedesktop.NetworkManager",
|
|
"Reload",
|
|
g_variant_new ("(u)", flags),
|
|
G_VARIANT_TYPE("()"),
|
|
&error);
|
|
|
|
if (error) {
|
|
g_string_printf (nmc->return_text,
|
|
_("Error: failed to reload: %s"),
|
|
nmc_error_get_simple_message (error));
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_general_permissions (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
show_nm_permissions (nmc);
|
|
}
|
|
|
|
static void
|
|
show_general_logging (NmCli *nmc)
|
|
{
|
|
gs_free char *level_cache = NULL;
|
|
gs_free char *domains_cache = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
const char *fields_str = NULL;
|
|
GetGeneralLoggingData d = {
|
|
.level = &level_cache,
|
|
.domains = &domains_cache,
|
|
};
|
|
|
|
if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
|
|
} else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
|
|
} else
|
|
fields_str = nmc->required_fields;
|
|
|
|
if (!nmc_print (&nmc->nmc_config,
|
|
(gpointer const []) { &d, NULL },
|
|
NULL,
|
|
_("NetworkManager logging"),
|
|
(const NMMetaAbstractInfo *const*) metagen_general_logging,
|
|
fields_str,
|
|
&error)) {
|
|
g_string_printf (nmc->return_text, _("Error: 'general logging': %s"), error->message);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmc_complete_strings_nocase (const char *prefix, ...)
|
|
{
|
|
va_list args;
|
|
const char *candidate;
|
|
int len;
|
|
|
|
len = strlen (prefix);
|
|
|
|
va_start (args, prefix);
|
|
while ((candidate = va_arg (args, const char *))) {
|
|
if (strncasecmp (prefix, candidate, len) == 0)
|
|
g_print ("%s\n", candidate);
|
|
}
|
|
va_end (args);
|
|
}
|
|
|
|
static void
|
|
_set_logging_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
|
{
|
|
NmCli *nmc = user_data;
|
|
gs_unref_variant GVariant *res = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
res = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
|
|
if (!res) {
|
|
g_dbus_error_strip_remote_error (error);
|
|
g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
|
|
nmc_error_get_simple_message (error));
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
quit ();
|
|
}
|
|
|
|
static void
|
|
do_general_logging (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (argc == 0) {
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
show_general_logging (nmc);
|
|
} else {
|
|
/* arguments provided -> set logging level and domains */
|
|
const char *level = NULL;
|
|
const char *domains = NULL;
|
|
|
|
do {
|
|
if (argc == 1 && nmc->complete)
|
|
nmc_complete_strings (*argv, "level", "domains");
|
|
|
|
if (matches (*argv, "level")) {
|
|
argc--;
|
|
argv++;
|
|
if (!argc) {
|
|
g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return;
|
|
}
|
|
if (argc == 1 && nmc->complete) {
|
|
nmc_complete_strings_nocase (*argv, "TRACE", "DEBUG", "INFO", "WARN",
|
|
"ERR", "OFF", "KEEP", NULL);
|
|
}
|
|
level = *argv;
|
|
} else if (matches (*argv, "domains")) {
|
|
argc--;
|
|
argv++;
|
|
if (!argc) {
|
|
g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return;
|
|
}
|
|
if (argc == 1 && nmc->complete) {
|
|
nmc_complete_strings_nocase (*argv, "PLATFORM", "RFKILL", "ETHER", "WIFI", "BT",
|
|
"MB", "DHCP4", "DHCP6", "PPP", "WIFI_SCAN", "IP4",
|
|
"IP6", "AUTOIP4", "DNS", "VPN", "SHARING", "SUPPLICANT",
|
|
"AGENTS", "SETTINGS", "SUSPEND", "CORE", "DEVICE", "OLPC",
|
|
"INFINIBAND", "FIREWALL", "ADSL", "BOND", "VLAN", "BRIDGE",
|
|
"DBUS_PROPS", "TEAM", "CONCHECK", "DCB", "DISPATCH", "AUDIT",
|
|
"SYSTEMD", "VPN_PLUGIN", "PROXY", "TC", NULL);
|
|
}
|
|
domains = *argv;
|
|
} else {
|
|
g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return;
|
|
}
|
|
} while (next_arg (nmc, &argc, &argv, NULL) == 0);
|
|
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
nmc->should_wait++;
|
|
nm_client_dbus_call (nmc->client,
|
|
NM_DBUS_PATH,
|
|
NM_DBUS_INTERFACE,
|
|
"SetLogging",
|
|
g_variant_new ("(ss)",
|
|
level ?: "",
|
|
domains ?: ""),
|
|
G_VARIANT_TYPE ("()"),
|
|
-1,
|
|
NULL,
|
|
_set_logging_cb,
|
|
nmc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
|
{
|
|
NmCli *nmc = user_data;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
nm_client_save_hostname_finish (NM_CLIENT (object), result, &error);
|
|
if (error) {
|
|
g_string_printf (nmc->return_text, _("Error: failed to set hostname: %s"),
|
|
error->message);
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
|
|
quit ();
|
|
}
|
|
|
|
static void
|
|
do_general_hostname (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
const char *hostname;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
if (argc == 0) {
|
|
/* no arguments -> get hostname */
|
|
gs_free char *s = NULL;
|
|
|
|
g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &s, NULL);
|
|
if (s)
|
|
g_print ("%s\n", s);
|
|
return;
|
|
}
|
|
|
|
hostname = *argv;
|
|
if (next_arg (nmc, &argc, &argv, NULL) == 0)
|
|
g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
|
|
|
|
nmc->should_wait++;
|
|
nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
|
|
}
|
|
|
|
void
|
|
nmc_command_func_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
static const NMCCommand cmds[] = {
|
|
{ "status", do_general_status, usage_general_status, TRUE, TRUE },
|
|
{ "hostname", do_general_hostname, usage_general_hostname, TRUE, TRUE },
|
|
{ "permissions", do_general_permissions, usage_general_permissions, TRUE, TRUE },
|
|
{ "logging", do_general_logging, usage_general_logging, TRUE, TRUE },
|
|
{ "reload", do_general_reload, usage_general_reload, FALSE, FALSE },
|
|
{ NULL, do_general_status, usage_general, TRUE, TRUE },
|
|
};
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nmc_do_cmd (nmc, cmds, *argv, argc, argv);
|
|
}
|
|
|
|
static gboolean
|
|
nmc_switch_show (NmCli *nmc, const char *switch_name, const char *header)
|
|
{
|
|
g_return_val_if_fail (nmc != NULL, FALSE);
|
|
g_return_val_if_fail (switch_name != NULL, FALSE);
|
|
|
|
if (nmc->required_fields && g_ascii_strcasecmp (nmc->required_fields, switch_name) != 0) {
|
|
g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"),
|
|
nmc->required_fields, switch_name);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return FALSE;
|
|
}
|
|
if (nmc->nmc_config.print_output == NMC_PRINT_NORMAL)
|
|
nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
|
|
|
|
if (!nmc->required_fields)
|
|
nmc->required_fields = g_strdup (switch_name);
|
|
return show_nm_status (nmc, header, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
nmc_switch_parse_on_off (NmCli *nmc, const char *arg1, const char *arg2, gboolean *res)
|
|
{
|
|
g_return_val_if_fail (nmc != NULL, FALSE);
|
|
g_return_val_if_fail (arg1 && arg2, FALSE);
|
|
g_return_val_if_fail (res != NULL, FALSE);
|
|
|
|
if (!strcmp (arg2, "on"))
|
|
*res = TRUE;
|
|
else if (!strcmp (arg2, "off"))
|
|
*res = FALSE;
|
|
else {
|
|
g_string_printf (nmc->return_text, _("Error: invalid '%s' argument: '%s' (use on/off)."), arg1, arg2);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_do_networking_on_off_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
|
{
|
|
NmCli *nmc = user_data;
|
|
gs_unref_variant GVariant *ret = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
ret = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
|
|
if (!ret) {
|
|
if (g_error_matches (error,
|
|
NM_MANAGER_ERROR,
|
|
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED)) {
|
|
/* This is fine. Be quiet about it. */
|
|
} else {
|
|
g_dbus_error_strip_remote_error (error);
|
|
g_string_printf (nmc->return_text, _("Error: failed to set networking: %s"),
|
|
nmc_error_get_simple_message (error));
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
}
|
|
quit ();
|
|
}
|
|
|
|
static void
|
|
do_networking_on_off (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
gboolean enable = nm_streq (cmd->cmd, "on");
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nmc->should_wait++;
|
|
nm_client_dbus_call (nmc->client,
|
|
NM_DBUS_PATH,
|
|
NM_DBUS_INTERFACE,
|
|
"Enable",
|
|
g_variant_new ("(b)", enable),
|
|
G_VARIANT_TYPE ("()"),
|
|
-1,
|
|
NULL,
|
|
_do_networking_on_off_cb,
|
|
nmc);
|
|
}
|
|
|
|
static void
|
|
do_networking_connectivity (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (nmc->complete) {
|
|
if (argc == 1)
|
|
nmc_complete_strings (*argv, "check");
|
|
return;
|
|
}
|
|
|
|
if (!argc) {
|
|
/* no arguments -> get current state */
|
|
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
|
|
} else if (matches (*argv, "check")) {
|
|
gs_free_error GError *error = NULL;
|
|
|
|
/* Register polkit agent */
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nm_client_check_connectivity (nmc->client, NULL, &error);
|
|
if (error) {
|
|
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
} else
|
|
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
|
|
} else {
|
|
usage_networking ();
|
|
g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_networking_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking"));
|
|
}
|
|
|
|
void
|
|
nmc_command_func_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
static const NMCCommand cmds[] = {
|
|
{ "on", do_networking_on_off, usage_networking_on, TRUE, TRUE },
|
|
{ "off", do_networking_on_off, usage_networking_off, TRUE, TRUE },
|
|
{ "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE },
|
|
{ NULL, do_networking_show, usage_networking, TRUE, TRUE },
|
|
};
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
nmc_do_cmd (nmc, cmds, *argv, argc, argv);
|
|
}
|
|
|
|
static void
|
|
do_radio_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
gboolean enable_flag;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (argc == 0) {
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
/* no argument, show all radio switches */
|
|
show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
|
|
} else {
|
|
if (nmc->complete) {
|
|
if (argc == 1)
|
|
nmc_complete_bool (*argv);
|
|
return;
|
|
}
|
|
|
|
if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
|
|
return;
|
|
|
|
nm_client_wireless_set_enabled (nmc->client, enable_flag);
|
|
nm_client_wimax_set_enabled (nmc->client, enable_flag);
|
|
nm_client_wwan_set_enabled (nmc->client, enable_flag);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_do_radio_wifi_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
|
{
|
|
NmCli *nmc = user_data;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
if (!nm_client_dbus_set_property_finish (NM_CLIENT (object), result, &error)) {
|
|
g_dbus_error_strip_remote_error (error);
|
|
g_string_printf (nmc->return_text, _("Error: failed to set Wi-Fi radio: %s"),
|
|
nmc_error_get_simple_message (error));
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
quit ();
|
|
}
|
|
|
|
static void
|
|
do_radio_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
gboolean enable_flag;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (argc == 0) {
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
/* no argument, show current Wi-Fi state */
|
|
nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch"));
|
|
} else {
|
|
if (nmc->complete) {
|
|
if (argc == 1)
|
|
nmc_complete_bool (*argv);
|
|
return;
|
|
}
|
|
if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
|
|
return;
|
|
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nmc->should_wait++;
|
|
nm_client_dbus_set_property (nmc->client,
|
|
NM_DBUS_PATH,
|
|
NM_DBUS_INTERFACE,
|
|
"WirelessEnabled",
|
|
g_variant_new_boolean (enable_flag),
|
|
-1,
|
|
NULL,
|
|
_do_radio_wifi_cb,
|
|
nmc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_radio_wwan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
gboolean enable_flag;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
if (argc == 0) {
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
/* no argument, show current WWAN (mobile broadband) state */
|
|
nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch"));
|
|
} else {
|
|
if (nmc->complete) {
|
|
if (argc == 1)
|
|
nmc_complete_bool (*argv);
|
|
return;
|
|
}
|
|
if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
|
|
return;
|
|
|
|
nm_client_wwan_set_enabled (nmc->client, enable_flag);
|
|
}
|
|
}
|
|
|
|
void
|
|
nmc_command_func_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
static const NMCCommand cmds[] = {
|
|
{ "all", do_radio_all, usage_radio_all, TRUE, TRUE },
|
|
{ "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE },
|
|
{ "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE },
|
|
{ NULL, do_radio_all, usage_radio, TRUE, TRUE },
|
|
};
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nmc_do_cmd (nmc, cmds, *argv, argc, argv);
|
|
}
|
|
|
|
static void
|
|
networkmanager_running (NMClient *client, GParamSpec *param, NmCli *nmc)
|
|
{
|
|
gboolean running;
|
|
char *str;
|
|
|
|
running = nm_client_get_nm_running (client);
|
|
str = nmc_colorize (&nmc->nmc_config,
|
|
running ? NM_META_COLOR_MANAGER_RUNNING : NM_META_COLOR_MANAGER_STOPPED,
|
|
running ? _("NetworkManager has started") : _("NetworkManager has stopped"));
|
|
g_print ("%s\n", str);
|
|
g_free (str);
|
|
}
|
|
|
|
static void
|
|
client_hostname (NMClient *client, GParamSpec *param, NmCli *nmc)
|
|
{
|
|
const char *hostname;
|
|
|
|
g_object_get (client, NM_CLIENT_HOSTNAME, &hostname, NULL);
|
|
g_print (_("Hostname set to '%s'\n"), hostname);
|
|
}
|
|
|
|
static void
|
|
client_primary_connection (NMClient *client, GParamSpec *param, NmCli *nmc)
|
|
{
|
|
NMActiveConnection *primary;
|
|
const char *id;
|
|
|
|
primary = nm_client_get_primary_connection (client);
|
|
if (primary) {
|
|
id = nm_active_connection_get_id (primary);
|
|
if (!id)
|
|
id = nm_active_connection_get_uuid (primary);
|
|
|
|
g_print (_("'%s' is now the primary connection\n"), id);
|
|
} else {
|
|
g_print (_("There's no primary connection\n"));
|
|
}
|
|
}
|
|
|
|
static void
|
|
client_connectivity (NMClient *client, GParamSpec *param, NmCli *nmc)
|
|
{
|
|
NMConnectivityState connectivity;
|
|
char *str;
|
|
|
|
g_object_get (client, NM_CLIENT_CONNECTIVITY, &connectivity, NULL);
|
|
str = nmc_colorize (&nmc->nmc_config, connectivity_to_color (connectivity),
|
|
_("Connectivity is now '%s'\n"),
|
|
gettext (nm_connectivity_to_string (connectivity)));
|
|
g_print ("%s", str);
|
|
g_free (str);
|
|
}
|
|
|
|
static void
|
|
client_state (NMClient *client, GParamSpec *param, NmCli *nmc)
|
|
{
|
|
NMState state;
|
|
char *str;
|
|
|
|
g_object_get (client, NM_CLIENT_STATE, &state, NULL);
|
|
str = nmc_colorize (&nmc->nmc_config, state_to_color (state),
|
|
_("Networkmanager is now in the '%s' state\n"),
|
|
gettext (nm_state_to_string (state)));
|
|
g_print ("%s", str);
|
|
g_free (str);
|
|
}
|
|
|
|
static void
|
|
device_overview (NmCli *nmc, NMDevice *device)
|
|
{
|
|
GString *outbuf = g_string_sized_new (80);
|
|
char *tmp;
|
|
const GPtrArray *activatable;
|
|
|
|
activatable = nm_device_get_available_connections (device);
|
|
|
|
g_string_append_printf (outbuf, "%s", nm_device_get_type_description (device));
|
|
|
|
if (nm_device_get_state (device) == NM_DEVICE_STATE_DISCONNECTED) {
|
|
if (activatable) {
|
|
if (activatable->len == 1)
|
|
g_print ("\t%d %s\n", activatable->len, _("connection available"));
|
|
else if (activatable->len > 1)
|
|
g_print ("\t%d %s\n", activatable->len, _("connections available"));
|
|
}
|
|
}
|
|
|
|
if ( nm_device_get_driver (device)
|
|
&& strcmp (nm_device_get_driver (device), "")
|
|
&& strcmp (nm_device_get_driver (device), nm_device_get_type_description (device))) {
|
|
g_string_append_printf (outbuf, " (%s)", nm_device_get_driver (device));
|
|
}
|
|
|
|
g_string_append_printf (outbuf, ", ");
|
|
|
|
if ( nm_device_get_hw_address (device)
|
|
&& strcmp (nm_device_get_hw_address (device), "")) {
|
|
g_string_append_printf (outbuf, "%s, ", nm_device_get_hw_address (device));
|
|
}
|
|
|
|
if (!nm_device_get_autoconnect (device))
|
|
g_string_append_printf (outbuf, "%s, ", _("autoconnect"));
|
|
if (nm_device_get_firmware_missing (device)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_FIRMWARE_MISSING, _("fw missing"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
if (nm_device_get_nm_plugin_missing (device)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_PLUGIN_MISSING, _("plugin missing"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
|
|
switch (nm_device_get_device_type (device)) {
|
|
case NM_DEVICE_TYPE_WIFI:
|
|
case NM_DEVICE_TYPE_OLPC_MESH:
|
|
case NM_DEVICE_TYPE_WIFI_P2P:
|
|
if (!nm_client_wireless_get_enabled (nmc->client)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("sw disabled"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
if (!nm_client_wireless_hardware_get_enabled (nmc->client)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("hw disabled"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
break;
|
|
case NM_DEVICE_TYPE_MODEM:
|
|
if ( nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device))
|
|
& (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) {
|
|
if (!nm_client_wwan_get_enabled (nmc->client)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("sw disabled"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
if (!nm_client_wwan_hardware_get_enabled (nmc->client)) {
|
|
tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("hw disabled"));
|
|
g_string_append_printf (outbuf, "%s, ", tmp);
|
|
g_free (tmp);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (nm_device_is_software (device))
|
|
g_string_append_printf (outbuf, "%s, ", _("sw"));
|
|
else
|
|
g_string_append_printf (outbuf, "%s, ", _("hw"));
|
|
|
|
if (!NM_IN_STRSET (nm_device_get_ip_iface (device),
|
|
NULL,
|
|
nm_device_get_iface (device)))
|
|
g_string_append_printf (outbuf, "%s %s, ", _("iface"), nm_device_get_ip_iface (device));
|
|
|
|
if (nm_device_get_physical_port_id (device))
|
|
g_string_append_printf (outbuf, "%s %s, ", _("port"), nm_device_get_physical_port_id (device));
|
|
|
|
if (nm_device_get_mtu (device))
|
|
g_string_append_printf (outbuf, "%s %d, ", _("mtu"), nm_device_get_mtu (device));
|
|
|
|
if (outbuf->len >= 2) {
|
|
g_string_truncate (outbuf, outbuf->len - 2);
|
|
g_print ("\t%s\n", outbuf->str);
|
|
}
|
|
|
|
g_string_free (outbuf, TRUE);
|
|
}
|
|
|
|
static void
|
|
ac_overview (NmCli *nmc, NMActiveConnection *ac)
|
|
{
|
|
GString *outbuf = g_string_sized_new (80);
|
|
NMIPConfig *ip;
|
|
|
|
if (nm_active_connection_get_master (ac)) {
|
|
g_string_append_printf (outbuf, "%s %s, ", _("master"),
|
|
nm_device_get_iface (nm_active_connection_get_master (ac)));
|
|
}
|
|
if (nm_active_connection_get_vpn (ac))
|
|
g_string_append_printf (outbuf, "%s, ", _("VPN"));
|
|
if (nm_active_connection_get_default (ac))
|
|
g_string_append_printf (outbuf, "%s, ", _("ip4 default"));
|
|
if (nm_active_connection_get_default6 (ac))
|
|
g_string_append_printf (outbuf, "%s, ", _("ip6 default"));
|
|
if (outbuf->len >= 2) {
|
|
g_string_truncate (outbuf, outbuf->len - 2);
|
|
g_print ("\t%s\n", outbuf->str);
|
|
}
|
|
|
|
ip = nm_active_connection_get_ip4_config (ac);
|
|
if (ip) {
|
|
const GPtrArray *p;
|
|
int i;
|
|
|
|
p = nm_ip_config_get_addresses (ip);
|
|
for (i = 0; i < p->len; i++) {
|
|
NMIPAddress *a = p->pdata[i];
|
|
g_print ("\tinet4 %s/%d\n", nm_ip_address_get_address (a),
|
|
nm_ip_address_get_prefix (a));
|
|
}
|
|
|
|
p = nm_ip_config_get_routes (ip);
|
|
for (i = 0; i < p->len; i++) {
|
|
NMIPRoute *a = p->pdata[i];
|
|
g_print ("\troute4 %s/%d\n", nm_ip_route_get_dest (a),
|
|
nm_ip_route_get_prefix (a));
|
|
}
|
|
}
|
|
|
|
ip = nm_active_connection_get_ip6_config (ac);
|
|
if (ip) {
|
|
const GPtrArray *p;
|
|
int i;
|
|
|
|
p = nm_ip_config_get_addresses (ip);
|
|
for (i = 0; i < p->len; i++) {
|
|
NMIPAddress *a = p->pdata[i];
|
|
g_print ("\tinet6 %s/%d\n", nm_ip_address_get_address (a),
|
|
nm_ip_address_get_prefix (a));
|
|
}
|
|
|
|
p = nm_ip_config_get_routes (ip);
|
|
for (i = 0; i < p->len; i++) {
|
|
NMIPRoute *a = p->pdata[i];
|
|
g_print ("\troute6 %s/%d\n", nm_ip_route_get_dest (a),
|
|
nm_ip_route_get_prefix (a));
|
|
}
|
|
}
|
|
|
|
g_string_free (outbuf, TRUE);
|
|
}
|
|
|
|
void
|
|
nmc_command_func_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
NMDevice **devices;
|
|
const GPtrArray *p;
|
|
NMActiveConnection *ac;
|
|
NMMetaColor color;
|
|
NMDnsEntry *dns;
|
|
char *tmp;
|
|
int i;
|
|
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
/* Register polkit agent */
|
|
nmc_start_polkit_agent_start_try (nmc);
|
|
|
|
nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
|
|
|
|
/* The VPN connections don't have devices (yet?). */
|
|
p = nm_client_get_active_connections (nmc->client);
|
|
for (i = 0; i < p->len; i++) {
|
|
NMActiveConnectionState state;
|
|
|
|
ac = p->pdata[i];
|
|
|
|
if (!nm_active_connection_get_vpn (ac))
|
|
continue;
|
|
|
|
state = nm_active_connection_get_state (ac);
|
|
color = nmc_active_connection_state_to_color (state);
|
|
tmp = nmc_colorize (&nmc->nmc_config, color, _("%s VPN connection"),
|
|
nm_active_connection_get_id (ac));
|
|
g_print ("%s\n", tmp);
|
|
g_free (tmp);
|
|
|
|
ac_overview (nmc, ac);
|
|
g_print ("\n");
|
|
}
|
|
|
|
devices = nmc_get_devices_sorted (nmc->client);
|
|
for (i = 0; devices[i]; i++) {
|
|
NMDeviceState state;
|
|
|
|
ac = nm_device_get_active_connection (devices[i]);
|
|
|
|
state = nm_device_get_state (devices[i]);
|
|
color = nmc_device_state_to_color (state);
|
|
if (ac) {
|
|
/* TRANSLATORS: prints header line for activated device in plain `nmcli` overview output as
|
|
* "<interface-name>: <device-state> to <connection-id>" */
|
|
tmp = nmc_colorize (&nmc->nmc_config, color, C_("nmcli-overview", "%s: %s to %s"),
|
|
nm_device_get_iface (devices[i]),
|
|
gettext (nmc_device_state_to_string (state)),
|
|
nm_active_connection_get_id (ac));
|
|
} else {
|
|
/* TRANSLATORS: prints header line for not active device in plain `nmcli` overview output as
|
|
* "<interface-name>: <device-state>" */
|
|
tmp = nmc_colorize (&nmc->nmc_config, color, C_("nmcli-overview", "%s: %s"),
|
|
nm_device_get_iface (devices[i]),
|
|
gettext (nmc_device_state_to_string (state)));
|
|
}
|
|
g_print ("%s\n", tmp);
|
|
g_free (tmp);
|
|
|
|
if (nm_device_get_description (devices[i]) && strcmp (nm_device_get_description (devices[i]), ""))
|
|
g_print ("\t\"%s\"\n", nm_device_get_description (devices[i]));
|
|
|
|
device_overview (nmc, devices[i]);
|
|
if (ac)
|
|
ac_overview (nmc, ac);
|
|
g_print ("\n");
|
|
}
|
|
g_free (devices);
|
|
|
|
p = nm_client_get_dns_configuration (nmc->client);
|
|
for (i = 0; p && i < p->len; i++) {
|
|
const char * const *strv;
|
|
|
|
dns = p->pdata[i];
|
|
strv = nm_dns_entry_get_nameservers (dns);
|
|
if (!strv || !strv[0]) {
|
|
/* Invalid entry */
|
|
continue;
|
|
}
|
|
|
|
if (i == 0)
|
|
g_print ("DNS configuration:\n");
|
|
|
|
tmp = g_strjoinv (" ", (char **) strv);
|
|
g_print ("\tservers: %s\n", tmp);
|
|
g_free (tmp);
|
|
|
|
strv = nm_dns_entry_get_domains (dns);
|
|
if (strv && strv[0]) {
|
|
tmp = g_strjoinv (" ", (char **) strv);
|
|
g_print ("\tdomains: %s\n", tmp);
|
|
g_free (tmp);
|
|
}
|
|
|
|
if (nm_dns_entry_get_interface (dns))
|
|
g_print ("\tinterface: %s\n", nm_dns_entry_get_interface (dns));
|
|
|
|
if (nm_dns_entry_get_vpn (dns))
|
|
g_print ("\ttype: vpn\n");
|
|
g_print ("\n");
|
|
}
|
|
|
|
g_print (_("Use \"nmcli device show\" to get complete information about known devices and\n"
|
|
"\"nmcli connection show\" to get an overview on active connection profiles.\n"
|
|
"\n"
|
|
"Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details.\n"));
|
|
}
|
|
|
|
void
|
|
nmc_command_func_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
|
|
{
|
|
next_arg (nmc, &argc, &argv, NULL);
|
|
|
|
if (nmc->complete)
|
|
return;
|
|
|
|
if (argc > 0) {
|
|
if (!nmc_arg_is_help (*argv)) {
|
|
g_string_printf (nmc->return_text, _("Error: 'monitor' command '%s' is not valid."), *argv);
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
}
|
|
|
|
usage_monitor ();
|
|
return;
|
|
}
|
|
|
|
if (!nm_client_get_nm_running (nmc->client)) {
|
|
char *str;
|
|
|
|
str = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_MANAGER_STOPPED,
|
|
_("Networkmanager is not running (waiting for it)\n"));
|
|
g_print ("%s", str);
|
|
g_free (str);
|
|
}
|
|
|
|
g_signal_connect (nmc->client, "notify::" NM_CLIENT_NM_RUNNING,
|
|
G_CALLBACK (networkmanager_running), nmc);
|
|
g_signal_connect (nmc->client, "notify::" NM_CLIENT_HOSTNAME,
|
|
G_CALLBACK (client_hostname), nmc);
|
|
g_signal_connect (nmc->client, "notify::" NM_CLIENT_PRIMARY_CONNECTION,
|
|
G_CALLBACK (client_primary_connection), nmc);
|
|
g_signal_connect (nmc->client, "notify::" NM_CLIENT_CONNECTIVITY,
|
|
G_CALLBACK (client_connectivity), nmc);
|
|
g_signal_connect (nmc->client, "notify::" NM_CLIENT_STATE,
|
|
G_CALLBACK (client_state), nmc);
|
|
|
|
nmc->should_wait++;
|
|
|
|
monitor_devices (nmc);
|
|
monitor_connections (nmc);
|
|
}
|