2010-02-25 09:52:30 -08:00
|
|
|
/* nmcli - command-line tool to control NetworkManager
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*
|
2012-01-06 15:15:03 +01:00
|
|
|
* (C) Copyright 2010 - 2012 Red Hat, Inc.
|
2010-02-25 09:52:30 -08:00
|
|
|
*/
|
|
|
|
|
|
2011-03-14 01:00:56 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
#include <glib.h>
|
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
|
#include <dbus/dbus.h>
|
|
|
|
|
#include <dbus/dbus-glib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
2010-07-29 16:16:20 +02:00
|
|
|
#include <unistd.h>
|
2010-02-25 09:52:30 -08:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <netinet/ether.h>
|
|
|
|
|
|
|
|
|
|
#include <nm-client.h>
|
|
|
|
|
#include <nm-device-ethernet.h>
|
2011-05-17 21:03:20 +03:00
|
|
|
#include <nm-device-adsl.h>
|
2010-02-25 09:52:30 -08:00
|
|
|
#include <nm-device-wifi.h>
|
2011-02-14 16:06:37 +01:00
|
|
|
#if WITH_WIMAX
|
2011-01-06 17:01:55 -06:00
|
|
|
#include <nm-device-wimax.h>
|
2011-02-14 16:06:37 +01:00
|
|
|
#endif
|
2011-02-25 10:16:17 -06:00
|
|
|
#include <nm-device-modem.h>
|
2010-02-25 09:52:30 -08:00
|
|
|
#include <nm-device-bt.h>
|
2012-03-02 09:02:33 +01:00
|
|
|
#include <nm-device-olpc-mesh.h>
|
2011-11-03 11:04:38 -04:00
|
|
|
#include <nm-device-infiniband.h>
|
2012-03-06 11:31:03 +01:00
|
|
|
#include <nm-device-bond.h>
|
2012-10-30 17:11:28 -05:00
|
|
|
#include <nm-device-bridge.h>
|
2012-03-07 11:45:40 -06:00
|
|
|
#include <nm-device-vlan.h>
|
2010-02-25 09:52:30 -08:00
|
|
|
#include <nm-remote-settings.h>
|
|
|
|
|
#include <nm-vpn-connection.h>
|
2011-11-03 11:04:38 -04:00
|
|
|
#include <nm-utils.h>
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
#include "utils.h"
|
2012-01-06 15:15:03 +01:00
|
|
|
#include "common.h"
|
2010-03-31 17:14:35 +02:00
|
|
|
#include "settings.h"
|
2010-02-25 09:52:30 -08:00
|
|
|
#include "connections.h"
|
|
|
|
|
|
2013-04-29 12:43:13 +02:00
|
|
|
/* Activation timeout waiting for bond/bridge slaves (in seconds) */
|
|
|
|
|
#define BB_SLAVES_TIMEOUT 10
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
/* define some prompts for connection editor */
|
|
|
|
|
#define EDITOR_PROMPT_SETTING _("Setting name? ")
|
|
|
|
|
#define EDITOR_PROMPT_PROPERTY _("Property name? ")
|
|
|
|
|
#define EDITOR_PROMPT_CON_TYPE _("Enter connection type: ")
|
|
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
/* Available fields for 'connection show configured' */
|
|
|
|
|
static NmcOutputField nmc_fields_con_show[] = {
|
2013-05-27 12:39:09 +02:00
|
|
|
{"NAME", N_("NAME"), 25}, /* 0 */
|
|
|
|
|
{"UUID", N_("UUID"), 38}, /* 1 */
|
|
|
|
|
{"TYPE", N_("TYPE"), 17}, /* 2 */
|
|
|
|
|
{"TIMESTAMP", N_("TIMESTAMP"), 12}, /* 3 */
|
|
|
|
|
{"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34}, /* 4 */
|
|
|
|
|
{"AUTOCONNECT", N_("AUTOCONNECT"), 13}, /* 5 */
|
|
|
|
|
{"READONLY", N_("READONLY"), 10}, /* 6 */
|
|
|
|
|
{"DBUS-PATH", N_("DBUS-PATH"), 42}, /* 7 */
|
|
|
|
|
{NULL, NULL, 0}
|
2010-03-18 15:39:15 +01:00
|
|
|
};
|
2012-11-19 10:24:31 +01:00
|
|
|
#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH"
|
|
|
|
|
#define NMC_FIELDS_CON_SHOW_COMMON "NAME,UUID,TYPE,TIMESTAMP-REAL"
|
2010-03-18 15:39:15 +01:00
|
|
|
|
2010-03-31 17:14:35 +02:00
|
|
|
/* Helper macro to define fields */
|
2013-05-27 12:39:09 +02:00
|
|
|
#define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, FALSE, FALSE, 0 }
|
2010-03-31 17:14:35 +02:00
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
/* Available settings for 'connection show configured <con>' */
|
2010-03-31 17:14:35 +02:00
|
|
|
static NmcOutputField nmc_fields_settings_names[] = {
|
|
|
|
|
SETTING_FIELD (NM_SETTING_CONNECTION_SETTING_NAME, 0), /* 0 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_WIRED_SETTING_NAME, 0), /* 1 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_802_1X_SETTING_NAME, 0), /* 2 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_WIRELESS_SETTING_NAME, 0), /* 3 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, 0), /* 4 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_IP4_CONFIG_SETTING_NAME, 0), /* 5 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_IP6_CONFIG_SETTING_NAME, 0), /* 6 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_SERIAL_SETTING_NAME, 0), /* 7 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_PPP_SETTING_NAME, 0), /* 8 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_PPPOE_SETTING_NAME, 0), /* 9 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_GSM_SETTING_NAME, 0), /* 10 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_CDMA_SETTING_NAME, 0), /* 11 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_BLUETOOTH_SETTING_NAME, 0), /* 12 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_OLPC_MESH_SETTING_NAME, 0), /* 13 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_VPN_SETTING_NAME, 0), /* 14 */
|
2011-01-06 17:01:55 -06:00
|
|
|
SETTING_FIELD (NM_SETTING_WIMAX_SETTING_NAME, 0), /* 15 */
|
2011-12-09 13:20:36 +01:00
|
|
|
SETTING_FIELD (NM_SETTING_INFINIBAND_SETTING_NAME, 0), /* 16 */
|
2012-03-05 07:32:21 +01:00
|
|
|
SETTING_FIELD (NM_SETTING_BOND_SETTING_NAME, 0), /* 17 */
|
2012-03-05 07:50:28 +01:00
|
|
|
SETTING_FIELD (NM_SETTING_VLAN_SETTING_NAME, 0), /* 18 */
|
2011-05-17 21:03:20 +03:00
|
|
|
SETTING_FIELD (NM_SETTING_ADSL_SETTING_NAME, 0), /* 19 */
|
2012-10-30 17:11:28 -05:00
|
|
|
SETTING_FIELD (NM_SETTING_BRIDGE_SETTING_NAME, 0), /* 20 */
|
|
|
|
|
SETTING_FIELD (NM_SETTING_BRIDGE_PORT_SETTING_NAME, 0), /* 21 */
|
2013-05-27 12:39:09 +02:00
|
|
|
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
|
2010-03-31 17:14:35 +02:00
|
|
|
};
|
2011-02-14 16:06:37 +01:00
|
|
|
#define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\
|
2010-03-31 17:14:35 +02:00
|
|
|
NM_SETTING_WIRED_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_802_1X_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_WIRELESS_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_IP4_CONFIG_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_IP6_CONFIG_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_SERIAL_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_PPP_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_PPPOE_SETTING_NAME","\
|
2011-05-17 21:03:20 +03:00
|
|
|
NM_SETTING_ADSL_SETTING_NAME","\
|
2010-03-31 17:14:35 +02:00
|
|
|
NM_SETTING_GSM_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_CDMA_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_BLUETOOTH_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_OLPC_MESH_SETTING_NAME","\
|
2011-12-09 13:20:36 +01:00
|
|
|
NM_SETTING_VPN_SETTING_NAME","\
|
2012-03-05 07:32:21 +01:00
|
|
|
NM_SETTING_INFINIBAND_SETTING_NAME","\
|
2012-03-05 07:50:28 +01:00
|
|
|
NM_SETTING_BOND_SETTING_NAME","\
|
2012-10-30 17:11:28 -05:00
|
|
|
NM_SETTING_VLAN_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_BRIDGE_SETTING_NAME","\
|
|
|
|
|
NM_SETTING_BRIDGE_PORT_SETTING_NAME
|
2011-02-14 16:06:37 +01:00
|
|
|
#if WITH_WIMAX
|
|
|
|
|
#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X","\
|
2011-01-06 17:01:55 -06:00
|
|
|
NM_SETTING_WIMAX_SETTING_NAME
|
2011-02-14 16:06:37 +01:00
|
|
|
#else
|
|
|
|
|
#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X
|
|
|
|
|
#endif
|
2010-03-31 17:14:35 +02:00
|
|
|
|
|
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
/* Available fields for 'connection show active' */
|
|
|
|
|
static NmcOutputField nmc_fields_con_show_active[] = {
|
2013-05-27 12:39:09 +02:00
|
|
|
{"GROUP", N_("GROUP"), 9}, /* 0 */ /* used only for 'GENERAL' group listing */
|
|
|
|
|
{"NAME", N_("NAME"), 25}, /* 1 */
|
|
|
|
|
{"UUID", N_("UUID"), 38}, /* 2 */
|
|
|
|
|
{"DEVICES", N_("DEVICES"), 10}, /* 3 */
|
|
|
|
|
{"STATE", N_("STATE"), 12}, /* 4 */
|
|
|
|
|
{"DEFAULT", N_("DEFAULT"), 8}, /* 5 */
|
|
|
|
|
{"DEFAULT6", N_("DEFAULT6"), 9}, /* 6 */
|
|
|
|
|
{"SPEC-OBJECT", N_("SPEC-OBJECT"), 10}, /* 7 */
|
|
|
|
|
{"VPN", N_("VPN"), 5}, /* 8 */
|
|
|
|
|
{"DBUS-PATH", N_("DBUS-PATH"), 51}, /* 9 */
|
|
|
|
|
{"CON-PATH", N_("CON-PATH"), 44}, /* 10 */
|
|
|
|
|
{"ZONE", N_("ZONE"), 15}, /* 11 */
|
|
|
|
|
{"MASTER-PATH", N_("MASTER-PATH"), 44}, /* 12 */
|
|
|
|
|
{NULL, NULL, 0}
|
2012-01-06 15:15:03 +01:00
|
|
|
};
|
2012-11-19 10:24:31 +01:00
|
|
|
#define NMC_FIELDS_CON_ACTIVE_ALL "NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH"
|
|
|
|
|
#define NMC_FIELDS_CON_ACTIVE_COMMON "NAME,UUID,DEVICES,DEFAULT,VPN,MASTER-PATH"
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
/* Available fields for 'connection show active <con>' */
|
|
|
|
|
static NmcOutputField nmc_fields_con_active_details_groups[] = {
|
2013-05-27 12:39:09 +02:00
|
|
|
{"GENERAL", N_("GENERAL"), 9}, /* 0 */
|
|
|
|
|
{"IP", N_("IP"), 5}, /* 1 */
|
|
|
|
|
{"VPN", N_("VPN"), 5}, /* 2 */
|
|
|
|
|
{NULL, NULL, 0}
|
2012-01-06 15:15:03 +01:00
|
|
|
};
|
2012-11-19 10:24:31 +01:00
|
|
|
#define NMC_FIELDS_CON_ACTIVE_DETAILS_ALL "GENERAL,IP,VPN"
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
/* GENERAL group is the same as nmc_fields_con_show_active */
|
|
|
|
|
#define NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL "GROUP,"NMC_FIELDS_CON_ACTIVE_ALL
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
/* IP group is handled by common.c */
|
|
|
|
|
|
|
|
|
|
/* Available fields for VPN group */
|
2012-11-19 10:24:31 +01:00
|
|
|
static NmcOutputField nmc_fields_con_active_details_vpn[] = {
|
2013-05-27 12:39:09 +02:00
|
|
|
{"GROUP", N_("GROUP"), 9}, /* 0 */
|
|
|
|
|
{"TYPE", N_("TYPE"), 15}, /* 1 */
|
|
|
|
|
{"USERNAME", N_("USERNAME"), 15}, /* 2 */
|
|
|
|
|
{"GATEWAY", N_("GATEWAY"), 25}, /* 3 */
|
|
|
|
|
{"BANNER", N_("BANNER"), 120}, /* 4 */
|
|
|
|
|
{"VPN-STATE", N_("VPN-STATE"), 40}, /* 5 */
|
|
|
|
|
{"CFG", N_("CFG"), 120}, /* 6 */
|
|
|
|
|
{NULL, NULL, 0}
|
2012-01-06 15:15:03 +01:00
|
|
|
};
|
2012-11-19 10:24:31 +01:00
|
|
|
#define NMC_FIELDS_CON_ACTIVE_DETAILS_VPN_ALL "GROUP,TYPE,USERNAME,GATEWAY,BANNER,VPN-STATE,CFG"
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
typedef struct {
|
|
|
|
|
NmCli *nmc;
|
|
|
|
|
int argc;
|
|
|
|
|
char **argv;
|
|
|
|
|
} ArgsInfo;
|
|
|
|
|
|
2011-09-06 15:30:15 +02:00
|
|
|
/* glib main loop variable - defined in nmcli.c */
|
|
|
|
|
extern GMainLoop *loop;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
static ArgsInfo args_info;
|
2012-05-09 12:35:27 +02:00
|
|
|
static guint progress_id = 0; /* ID of event source for displaying progress */
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
usage (void)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr,
|
cli: replace 'dev' and 'con' OBJECTs by 'device', resp. 'connection'
Shorter forms work as previously. Thus, all of these commands are valid:
nmcli device, nmcli devic, nmcli devi, nmcli dev, nmcli de, nmcli d
nmcli connection, nmcli connectio, ..., nmcli conn, nmcli con, ..., nmcli c
2012-11-13 14:43:14 +01:00
|
|
|
_("Usage: nmcli connection { COMMAND | help }\n"
|
2012-11-19 10:24:31 +01:00
|
|
|
" COMMAND := { show | up | down | delete }\n\n"
|
2013-04-03 10:27:31 +02:00
|
|
|
" show configured [[ id | uuid | path ] <ID>]\n\n"
|
|
|
|
|
" show active [[ id | uuid | path | apath ] <ID>]\n\n"
|
2011-02-14 16:06:37 +01:00
|
|
|
#if WITH_WIMAX
|
2013-05-14 12:43:43 +02:00
|
|
|
" up [ id | uuid | path ] <ID> [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n\n"
|
2011-02-14 16:06:37 +01:00
|
|
|
#else
|
2013-05-14 12:43:43 +02:00
|
|
|
" up [ id | uuid | path ] <ID> [ifname <ifname>] [ap <BSSID>]\n\n"
|
2011-02-14 16:06:37 +01:00
|
|
|
#endif
|
2013-04-03 10:27:31 +02:00
|
|
|
" down [ id | uuid | path | apath ] <ID>\n\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
|
2013-04-19 21:06:20 +02:00
|
|
|
" edit [ id | uuid | path ] <ID> | [type <new_con_type>] [con-name <new_con_name>]\n\n"
|
2013-05-23 19:05:40 -03:00
|
|
|
" delete [ id | uuid | path ] <ID>\n\n"
|
|
|
|
|
" reload\n\n\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
usage_connection_add (void)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr,
|
|
|
|
|
_("Usage: nmcli connection add { OPTIONS | help }\n"
|
|
|
|
|
" OPTIONS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
|
|
|
|
|
" COMMON_OPTIONS:\n"
|
|
|
|
|
" type <type>\n"
|
2013-06-10 15:31:09 +02:00
|
|
|
" ifname <interface name> | \"*\"\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" [con-name <connection name>]\n"
|
2013-06-10 15:31:09 +02:00
|
|
|
" [autoconnect yes|no]\n\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" TYPE_SPECIFIC_OPTIONS:\n"
|
|
|
|
|
" ethernet: [mac <MAC address>]\n"
|
|
|
|
|
" [cloned-mac <cloned MAC address>]\n"
|
|
|
|
|
" [mtu <MTU>]\n\n"
|
|
|
|
|
" wifi: [mac <MAC address>]\n"
|
|
|
|
|
" [cloned-mac <cloned MAC address>]\n"
|
|
|
|
|
" [mtu <MTU>]\n"
|
|
|
|
|
" [ssid <SSID>]\n\n"
|
|
|
|
|
" wimax: [mac <MAC address>]\n"
|
|
|
|
|
" [nsp <NSP>]\n\n"
|
|
|
|
|
" gsm: apn <APN>]\n"
|
|
|
|
|
" [user <username>]\n"
|
|
|
|
|
" [password <password>]\n\n"
|
|
|
|
|
" cdma: [user <username>]\n"
|
|
|
|
|
" [password <password>]\n\n"
|
|
|
|
|
" infiniband: [mac <MAC address>]\n"
|
|
|
|
|
" [mtu <MTU>]\n"
|
2013-06-11 15:40:36 -03:00
|
|
|
" [transport-mode datagram | connected]\n\n"
|
|
|
|
|
" [parent <ifname>]\n\n"
|
|
|
|
|
" [p-key <IPoIB P_Key>]\n\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" bluetooth: [addr <bluetooth address>]\n"
|
|
|
|
|
" [bt-type panu|dun-gsm|dun-cdma]\n"
|
|
|
|
|
" vlan: dev <parent device (connection UUID, ifname, or MAC)\n"
|
|
|
|
|
" [id <VLAN id>]\n"
|
|
|
|
|
" [flags <VLAN flags>]\n"
|
|
|
|
|
" [ingress <ingress priority mapping>]\n"
|
|
|
|
|
" [egress <egress priority mapping>]\n"
|
|
|
|
|
" [mtu <MTU>]\n\n"
|
2013-05-14 16:42:03 +02:00
|
|
|
" bond: [mode balance-rr (0) | active-backup (1) | balance-xor (2) | broadcast (3) |\n"
|
|
|
|
|
" 802.3ad (4) | balance-tlb (5) | balance-alb (6)]\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" [miimon <num>]\n"
|
|
|
|
|
" [downdelay <num>]\n"
|
|
|
|
|
" [updelay <num>]\n"
|
2013-07-22 09:58:52 +02:00
|
|
|
" [arp-interval <num>]\n"
|
|
|
|
|
" [arp-ip-target <num>]\n\n"
|
2013-04-12 15:26:31 +02:00
|
|
|
" bond-slave: master <master (ifname or connection UUID)\n\n"
|
|
|
|
|
" bridge: [stp yes|no>]\n"
|
|
|
|
|
" [priority <num>]\n"
|
|
|
|
|
" [forward-delay <2-30>]\n"
|
|
|
|
|
" [hello-time <1-10>]\n"
|
|
|
|
|
" [max-age <6-40>]\n"
|
|
|
|
|
" [ageing-time <0-1000000>]\n\n"
|
|
|
|
|
" bridge-slave: master <master (ifname or connection UUID)\n"
|
|
|
|
|
" [priority <0-63>]\n"
|
|
|
|
|
" [path-cost <1-65535>]\n"
|
|
|
|
|
" [hairpin yes|no]\n\n"
|
|
|
|
|
" vpn: vpn-type vpnc|openvpn|pptp|openconnect|openswan\n"
|
|
|
|
|
" [user <username>]\n\n"
|
|
|
|
|
" olpc-mesh: ssid <SSID>\n"
|
|
|
|
|
" [channel <1-13>]\n"
|
|
|
|
|
" [dhcp-anycast <MAC address>]\n\n"
|
|
|
|
|
" IP_OPTIONS:\n"
|
|
|
|
|
" [ip4 <IPv4 address>] [gw4 <IPv4 gateway>]\n"
|
|
|
|
|
" [ip6 <IPv6 address>] [gw6 <IPv6 gateway>]\n"
|
2012-11-13 14:19:49 +01:00
|
|
|
));
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* The real commands that do something - i.e. not 'help', etc. */
|
|
|
|
|
static const char *real_con_commands[] = {
|
2012-11-19 10:24:31 +01:00
|
|
|
"show",
|
2011-02-16 17:36:50 +01:00
|
|
|
"up",
|
|
|
|
|
"down",
|
2013-04-12 15:26:31 +02:00
|
|
|
"add",
|
2013-01-18 15:21:00 +01:00
|
|
|
"edit",
|
2011-09-06 15:07:58 +02:00
|
|
|
"delete",
|
2013-05-23 19:05:40 -03:00
|
|
|
"reload",
|
2011-02-16 17:36:50 +01:00
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
/* quit main loop */
|
|
|
|
|
static void
|
|
|
|
|
quit (void)
|
|
|
|
|
{
|
2012-05-09 12:35:27 +02:00
|
|
|
if (progress_id) {
|
|
|
|
|
g_source_remove (progress_id);
|
|
|
|
|
nmc_terminal_erase_line ();
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
g_main_loop_quit (loop); /* quit main loop */
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-31 17:14:35 +02:00
|
|
|
static gboolean
|
|
|
|
|
nmc_connection_detail (NMConnection *connection, NmCli *nmc)
|
|
|
|
|
{
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GArray *print_settings_array;
|
|
|
|
|
int i;
|
|
|
|
|
char *fields_str;
|
|
|
|
|
char *fields_all = NMC_FIELDS_SETTINGS_NAMES_ALL;
|
|
|
|
|
char *fields_common = NMC_FIELDS_SETTINGS_NAMES_ALL;
|
|
|
|
|
gboolean was_output = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
|
|
|
|
fields_str = fields_common;
|
|
|
|
|
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
|
|
|
|
|
fields_str = fields_all;
|
|
|
|
|
else
|
|
|
|
|
fields_str = nmc->required_fields;
|
|
|
|
|
|
|
|
|
|
print_settings_array = parse_output_fields (fields_str, nmc_fields_settings_names, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
if (error->code == 0)
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'list configured': %s"), error->message);
|
2010-03-31 17:14:35 +02:00
|
|
|
else
|
2013-05-22 08:37:50 +02:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'list configured': %s; allowed fields: %s"),
|
|
|
|
|
error->message, NMC_FIELDS_SETTINGS_NAMES_ALL);
|
2010-03-31 17:14:35 +02:00
|
|
|
g_error_free (error);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Main header */
|
2010-03-31 17:14:35 +02:00
|
|
|
nmc->print_fields.header_name = _("Connection details");
|
2013-05-22 08:37:50 +02:00
|
|
|
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTINGS_NAMES_ALL,
|
|
|
|
|
nmc_fields_settings_names, NULL);
|
|
|
|
|
|
|
|
|
|
nmc_fields_settings_names[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
|
|
|
|
|
print_required_fields (nmc, nmc_fields_settings_names);
|
2010-03-31 17:14:35 +02:00
|
|
|
|
|
|
|
|
/* Loop through the required settings and print them. */
|
|
|
|
|
for (i = 0; i < print_settings_array->len; i++) {
|
2013-01-22 14:41:29 +01:00
|
|
|
NMSetting *setting;
|
2010-03-31 17:14:35 +02:00
|
|
|
int section_idx = g_array_index (print_settings_array, int, i);
|
|
|
|
|
|
|
|
|
|
if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
|
|
|
|
|
printf ("\n"); /* Empty line */
|
|
|
|
|
|
|
|
|
|
was_output = FALSE;
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Remove any previous data */
|
|
|
|
|
nmc_empty_output_fields (nmc);
|
|
|
|
|
|
2013-01-22 14:41:29 +01:00
|
|
|
setting = nm_connection_get_setting_by_name (connection, nmc_fields_settings_names[section_idx].name);
|
|
|
|
|
if (setting) {
|
|
|
|
|
setting_details (setting, nmc);
|
|
|
|
|
was_output = TRUE;
|
|
|
|
|
continue;
|
2012-10-30 17:11:28 -05:00
|
|
|
}
|
2010-03-31 17:14:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (print_settings_array)
|
|
|
|
|
g_array_free (print_settings_array, FALSE);
|
|
|
|
|
|
2012-11-16 12:43:44 +01:00
|
|
|
return TRUE;
|
2010-03-31 17:14:35 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
static void
|
2013-05-22 08:37:50 +02:00
|
|
|
fill_output_connection (NMConnection *data, gpointer user_data)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
|
|
|
|
NMConnection *connection = (NMConnection *) data;
|
2010-03-18 15:39:15 +01:00
|
|
|
NmCli *nmc = (NmCli *) user_data;
|
2010-02-25 09:52:30 -08:00
|
|
|
NMSettingConnection *s_con;
|
2010-03-18 15:39:15 +01:00
|
|
|
guint64 timestamp;
|
2011-05-30 12:12:00 +02:00
|
|
|
time_t timestamp_real;
|
2010-03-18 15:39:15 +01:00
|
|
|
char *timestamp_str;
|
2013-05-22 08:37:50 +02:00
|
|
|
char *timestamp_real_str;
|
|
|
|
|
NmcOutputField *arr;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-03-16 14:32:24 +01:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
2010-02-25 09:52:30 -08:00
|
|
|
if (s_con) {
|
2010-03-18 15:39:15 +01:00
|
|
|
/* Obtain field values */
|
|
|
|
|
timestamp = nm_setting_connection_get_timestamp (s_con);
|
2010-05-05 04:54:03 -07:00
|
|
|
timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
|
2013-05-22 08:37:50 +02:00
|
|
|
if (timestamp) {
|
|
|
|
|
timestamp_real = timestamp;
|
|
|
|
|
timestamp_real_str = g_malloc0 (64);
|
|
|
|
|
strftime (timestamp_real_str, 64, "%c", localtime (×tamp_real));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arr = nmc_dup_fields_array (nmc_fields_con_show,
|
|
|
|
|
sizeof (nmc_fields_con_show),
|
|
|
|
|
0);
|
|
|
|
|
set_val_strc (arr, 0, nm_setting_connection_get_id (s_con));
|
|
|
|
|
set_val_strc (arr, 1, nm_setting_connection_get_uuid (s_con));
|
|
|
|
|
set_val_strc (arr, 2, nm_setting_connection_get_connection_type (s_con));
|
|
|
|
|
set_val_str (arr, 3, timestamp_str);
|
|
|
|
|
set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never")));
|
|
|
|
|
set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"));
|
|
|
|
|
set_val_strc (arr, 6, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
|
|
|
|
|
set_val_strc (arr, 7, nm_connection_get_path (connection));
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMConnection *
|
|
|
|
|
find_connection (GSList *list, const char *filter_type, const char *filter_val)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
GSList *iterator;
|
|
|
|
|
const char *id;
|
|
|
|
|
const char *uuid;
|
2012-11-16 12:43:44 +01:00
|
|
|
const char *path, *path_num;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
iterator = list;
|
|
|
|
|
while (iterator) {
|
|
|
|
|
connection = NM_CONNECTION (iterator->data);
|
2012-11-16 12:43:44 +01:00
|
|
|
|
|
|
|
|
id = nm_connection_get_id (connection);
|
|
|
|
|
uuid = nm_connection_get_uuid (connection);
|
|
|
|
|
path = nm_connection_get_path (connection);
|
|
|
|
|
path_num = path ? strrchr (path, '/') + 1 : NULL;
|
|
|
|
|
|
|
|
|
|
/* When filter_type is NULL, compare connection ID (filter_val)
|
|
|
|
|
* against all types. Otherwise, only compare against the specific
|
|
|
|
|
* type. If 'path' filter type is specified, comparison against
|
|
|
|
|
* numeric index (in addition to the whole path) is allowed.
|
|
|
|
|
*/
|
|
|
|
|
if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
|
|
|
|
|
&& strcmp (filter_val, id) == 0)
|
|
|
|
|
|| ( (!filter_type || strcmp (filter_type, "uuid") == 0)
|
|
|
|
|
&& strcmp (filter_val, uuid) == 0)
|
|
|
|
|
|| ( (!filter_type || strcmp (filter_type, "path") == 0)
|
|
|
|
|
&& (strcmp (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0))))
|
|
|
|
|
return connection;
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
iterator = g_slist_next (iterator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMCResultCode
|
2012-11-19 10:24:31 +01:00
|
|
|
do_connections_show (NmCli *nmc, int argc, char **argv)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
2010-03-31 17:14:35 +02:00
|
|
|
GError *error1 = NULL;
|
|
|
|
|
GError *error2 = NULL;
|
2010-03-18 15:39:15 +01:00
|
|
|
char *fields_str;
|
2012-11-19 10:24:31 +01:00
|
|
|
char *fields_all = NMC_FIELDS_CON_SHOW_ALL;
|
|
|
|
|
char *fields_common = NMC_FIELDS_CON_SHOW_COMMON;
|
2013-05-22 08:37:50 +02:00
|
|
|
NmcOutputField *tmpl, *arr;
|
|
|
|
|
size_t tmpl_len;
|
2012-11-16 12:43:44 +01:00
|
|
|
gboolean printed = FALSE;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
|
2010-03-18 15:39:15 +01:00
|
|
|
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
|
|
|
|
fields_str = fields_common;
|
|
|
|
|
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
|
|
|
|
|
fields_str = fields_all;
|
2010-03-31 17:14:35 +02:00
|
|
|
else
|
2010-03-18 15:39:15 +01:00
|
|
|
fields_str = nmc->required_fields;
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
tmpl = nmc_fields_con_show;
|
|
|
|
|
tmpl_len = sizeof (nmc_fields_con_show);
|
|
|
|
|
nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, &error1);
|
2010-03-31 17:14:35 +02:00
|
|
|
/* error1 is checked later - it's not valid for connection details */
|
2010-03-18 15:39:15 +01:00
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
if (argc == 0) {
|
2010-03-31 17:14:35 +02:00
|
|
|
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error2))
|
|
|
|
|
goto error;
|
|
|
|
|
if (error1)
|
|
|
|
|
goto error;
|
2010-03-18 15:39:15 +01:00
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add headers */
|
2012-11-19 10:24:31 +01:00
|
|
|
nmc->print_fields.header_name = _("List of configured connections");
|
2013-05-22 08:37:50 +02:00
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2011-02-14 17:01:33 +01:00
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add values */
|
|
|
|
|
g_slist_foreach (nmc->system_connections, (GFunc) fill_output_connection, nmc);
|
|
|
|
|
print_data (nmc); /* Print all data */
|
2012-11-16 12:43:44 +01:00
|
|
|
} else {
|
2012-11-19 10:24:31 +01:00
|
|
|
g_clear_error (&error1); /* the error1 is only relevant for 'show configured' without arguments */
|
2012-11-16 12:43:44 +01:00
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
while (argc > 0) {
|
2012-11-16 12:43:44 +01:00
|
|
|
NMConnection *con;
|
|
|
|
|
const char *selector = NULL;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-11-16 12:43:44 +01:00
|
|
|
if ( strcmp (*argv, "id") == 0
|
|
|
|
|
|| strcmp (*argv, "uuid") == 0
|
|
|
|
|
|| strcmp (*argv, "path") == 0) {
|
|
|
|
|
selector = *argv;
|
2010-02-25 09:52:30 -08:00
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
2012-11-16 22:43:29 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
2010-03-24 13:42:47 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2010-03-31 17:14:35 +02:00
|
|
|
return nmc->return_value;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
}
|
2012-11-16 12:43:44 +01:00
|
|
|
if (!nmc->mode_specified)
|
2012-11-19 10:24:31 +01:00
|
|
|
nmc->multiline_output = TRUE; /* multiline mode is default for 'show configured <con>' */
|
2012-11-16 12:43:44 +01:00
|
|
|
|
|
|
|
|
con = find_connection (nmc->system_connections, selector, *argv);
|
|
|
|
|
if (con) {
|
|
|
|
|
if (printed)
|
|
|
|
|
printf ("\n");
|
|
|
|
|
printed = nmc_connection_detail (con, nmc);
|
|
|
|
|
} else {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
|
|
|
return nmc->return_value;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argc--;
|
|
|
|
|
argv++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error:
|
2010-03-31 17:14:35 +02:00
|
|
|
if (error1) {
|
|
|
|
|
if (error1->code == 0)
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'show configured': %s"), error1->message);
|
2010-03-31 17:14:35 +02:00
|
|
|
else
|
2013-05-22 08:37:50 +02:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'show configured': %s; allowed fields: %s"),
|
|
|
|
|
error1->message, NMC_FIELDS_CON_SHOW_ALL);
|
2010-03-31 17:14:35 +02:00
|
|
|
g_error_free (error1);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
}
|
|
|
|
|
if (error2) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: %s."), error2->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
g_error_free (error2);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-19 10:09:05 +01:00
|
|
|
static const char *
|
|
|
|
|
active_connection_state_to_string (NMActiveConnectionState state)
|
|
|
|
|
{
|
|
|
|
|
switch (state) {
|
|
|
|
|
case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
|
|
|
|
|
return _("activating");
|
|
|
|
|
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
|
|
|
|
|
return _("activated");
|
|
|
|
|
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
|
|
|
|
|
return _("deactivating");
|
2013-02-11 13:00:02 +01:00
|
|
|
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
|
|
|
|
|
return _("deactivated");
|
2011-12-19 10:09:05 +01:00
|
|
|
case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
|
|
|
|
|
default:
|
|
|
|
|
return _("unknown");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-06 15:15:03 +01:00
|
|
|
static const char *
|
|
|
|
|
vpn_connection_state_to_string (NMVPNConnectionState state)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
2012-01-06 15:15:03 +01:00
|
|
|
switch (state) {
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_PREPARE:
|
|
|
|
|
return _("VPN connecting (prepare)");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_NEED_AUTH:
|
|
|
|
|
return _("VPN connecting (need authentication)");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_CONNECT:
|
|
|
|
|
return _("VPN connecting");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
|
|
|
|
|
return _("VPN connecting (getting IP configuration)");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_ACTIVATED:
|
|
|
|
|
return _("VPN connected");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_FAILED:
|
|
|
|
|
return _("VPN connection failed");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_DISCONNECTED:
|
|
|
|
|
return _("VPN disconnected");
|
|
|
|
|
default:
|
|
|
|
|
return _("unknown");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMConnection *
|
|
|
|
|
get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
|
|
|
|
|
{
|
|
|
|
|
const GSList *iter;
|
|
|
|
|
const char *path;
|
|
|
|
|
|
|
|
|
|
path = nm_active_connection_get_connection (active);
|
|
|
|
|
g_return_val_if_fail (path != NULL, NULL);
|
|
|
|
|
|
|
|
|
|
for (iter = con_list; iter; iter = g_slist_next (iter)) {
|
|
|
|
|
NMConnection *candidate = NM_CONNECTION (iter->data);
|
|
|
|
|
|
|
|
|
|
if (strcmp (nm_connection_get_path (candidate), path) == 0)
|
|
|
|
|
return candidate;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
static void
|
|
|
|
|
fill_output_active_connection (NMActiveConnection *active,
|
|
|
|
|
NmCli *nmc,
|
|
|
|
|
gboolean with_group,
|
|
|
|
|
guint32 o_flags)
|
2012-01-06 15:15:03 +01:00
|
|
|
{
|
|
|
|
|
GSList *iter;
|
2010-02-25 09:52:30 -08:00
|
|
|
const char *active_path;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const GPtrArray *devices;
|
|
|
|
|
GString *dev_str;
|
2011-12-19 10:09:05 +01:00
|
|
|
NMActiveConnectionState state;
|
2012-01-06 15:15:03 +01:00
|
|
|
int i;
|
2013-05-22 08:37:50 +02:00
|
|
|
GSList *con_list = nmc->system_connections;
|
|
|
|
|
NmcOutputField *tmpl, *arr;
|
|
|
|
|
size_t tmpl_len;
|
|
|
|
|
int idx_start = with_group ? 0 : 1;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
active_path = nm_active_connection_get_connection (active);
|
2011-12-19 10:09:05 +01:00
|
|
|
state = nm_active_connection_get_state (active);
|
2010-03-18 15:39:15 +01:00
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
/* Get devices of the active connection */
|
2010-03-18 15:39:15 +01:00
|
|
|
dev_str = g_string_new (NULL);
|
2010-02-25 09:52:30 -08:00
|
|
|
devices = nm_active_connection_get_devices (active);
|
|
|
|
|
for (i = 0; devices && (i < devices->len); i++) {
|
|
|
|
|
NMDevice *device = g_ptr_array_index (devices, i);
|
2013-02-05 10:00:58 +01:00
|
|
|
const char *dev_iface = nm_device_get_iface (device);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-02-05 10:00:58 +01:00
|
|
|
if (dev_iface) {
|
|
|
|
|
g_string_append (dev_str, dev_iface);
|
|
|
|
|
g_string_append_c (dev_str, ',');
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
if (dev_str->len > 0)
|
|
|
|
|
g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
tmpl = nmc_fields_con_show_active;
|
|
|
|
|
tmpl_len = sizeof (nmc_fields_con_show_active);
|
|
|
|
|
if (!with_group) {
|
|
|
|
|
tmpl++;
|
|
|
|
|
tmpl_len -= sizeof (NmcOutputField);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-22 16:54:44 +02:00
|
|
|
/* Fill field values */
|
2013-05-22 08:37:50 +02:00
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, o_flags);
|
|
|
|
|
if (with_group)
|
|
|
|
|
set_val_strc (arr, 0, nmc_fields_con_active_details_groups[0].name);
|
|
|
|
|
set_val_strc (arr, 1-idx_start, _("N/A"));
|
|
|
|
|
set_val_strc (arr, 2-idx_start, nm_active_connection_get_uuid (active));
|
|
|
|
|
set_val_str (arr, 3-idx_start, dev_str->str);
|
|
|
|
|
set_val_strc (arr, 4-idx_start, active_connection_state_to_string (state));
|
|
|
|
|
set_val_strc (arr, 5-idx_start, nm_active_connection_get_default (active) ? _("yes") : _("no"));
|
|
|
|
|
set_val_strc (arr, 6-idx_start, nm_active_connection_get_default6 (active) ? _("yes") : _("no"));
|
|
|
|
|
set_val_strc (arr, 7-idx_start, nm_active_connection_get_specific_object (active));
|
|
|
|
|
set_val_strc (arr, 8-idx_start, NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no"));
|
|
|
|
|
set_val_strc (arr, 9-idx_start, nm_object_get_path (NM_OBJECT (active)));
|
|
|
|
|
set_val_strc (arr, 10-idx_start, nm_active_connection_get_connection (active));
|
|
|
|
|
set_val_strc (arr, 11-idx_start, _("N/A"));
|
|
|
|
|
set_val_strc (arr, 12-idx_start, nm_active_connection_get_master (active));
|
2012-05-22 16:54:44 +02:00
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
for (iter = con_list; iter; iter = g_slist_next (iter)) {
|
|
|
|
|
NMConnection *connection = (NMConnection *) iter->data;
|
|
|
|
|
const char *con_path = nm_connection_get_path (connection);
|
|
|
|
|
|
2010-03-18 15:39:15 +01:00
|
|
|
if (!strcmp (active_path, con_path)) {
|
|
|
|
|
/* This connection is active */
|
2011-03-16 14:32:24 +01:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
2010-02-25 09:52:30 -08:00
|
|
|
g_assert (s_con != NULL);
|
|
|
|
|
|
2012-05-22 16:54:44 +02:00
|
|
|
/* Fill field values that depend on NMConnection */
|
2013-05-22 08:37:50 +02:00
|
|
|
set_val_strc (arr, 1-idx_start, nm_setting_connection_get_id (s_con));
|
|
|
|
|
set_val_strc (arr, 11-idx_start, nm_setting_connection_get_zone (s_con));
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2010-03-18 15:39:15 +01:00
|
|
|
break;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
}
|
2013-05-22 08:37:50 +02:00
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-01-06 15:15:03 +01:00
|
|
|
g_string_free (dev_str, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMActiveConnection *
|
|
|
|
|
find_active_connection (const GPtrArray *active_cons, const GSList *cons,
|
|
|
|
|
const char *filter_type, const char *filter_val)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2012-11-16 12:43:44 +01:00
|
|
|
const char *path, *a_path, *path_num, *a_path_num;
|
2012-01-06 15:15:03 +01:00
|
|
|
const char *id;
|
|
|
|
|
const char *uuid;
|
|
|
|
|
NMConnection *con;
|
|
|
|
|
|
|
|
|
|
for (i = 0; active_cons && (i < active_cons->len); i++) {
|
|
|
|
|
NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
|
|
|
|
|
|
2012-11-16 12:43:44 +01:00
|
|
|
path = nm_active_connection_get_connection (candidate);
|
2012-01-06 15:15:03 +01:00
|
|
|
a_path = nm_object_get_path (NM_OBJECT (candidate));
|
|
|
|
|
uuid = nm_active_connection_get_uuid (candidate);
|
2012-11-16 12:43:44 +01:00
|
|
|
path_num = path ? strrchr (path, '/') + 1 : NULL;
|
|
|
|
|
a_path_num = a_path ? strrchr (a_path, '/') + 1 : NULL;
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
con = get_connection_for_active (cons, candidate);
|
2012-11-16 12:43:44 +01:00
|
|
|
id = nm_connection_get_id (con);
|
|
|
|
|
|
|
|
|
|
/* When filter_type is NULL, compare connection ID (filter_val)
|
|
|
|
|
* against all types. Otherwise, only compare against the specific
|
|
|
|
|
* type. If 'path' or 'apath' filter types are specified, comparison
|
|
|
|
|
* against numeric index (in addition to the whole path) is allowed.
|
|
|
|
|
*/
|
|
|
|
|
if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
|
|
|
|
|
&& strcmp (filter_val, id) == 0)
|
|
|
|
|
|| ( (!filter_type || strcmp (filter_type, "uuid") == 0)
|
|
|
|
|
&& strcmp (filter_val, uuid) == 0)
|
|
|
|
|
|| ( (!filter_type || strcmp (filter_type, "path") == 0)
|
|
|
|
|
&& (strcmp (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))
|
|
|
|
|
|| ( (!filter_type || strcmp (filter_type, "apath") == 0)
|
|
|
|
|
&& (strcmp (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0))))
|
|
|
|
|
return candidate;
|
2012-01-06 15:15:03 +01:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
char **array;
|
|
|
|
|
guint32 idx;
|
|
|
|
|
} FillVPNDataInfo;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fill_vpn_data_item (const char *key, const char *value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
FillVPNDataInfo *info = (FillVPNDataInfo *) user_data;
|
|
|
|
|
|
|
|
|
|
info->array[info->idx++] = g_strdup_printf ("%s = %s", key, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: The same or similar code for VPN info appears also in nm-applet (applet-dialogs.c),
|
|
|
|
|
// and in gnome-control-center as well. It could probably be shared somehow.
|
|
|
|
|
static char *
|
|
|
|
|
get_vpn_connection_type (NMConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
const char *type, *p;
|
|
|
|
|
|
|
|
|
|
/* The service type is in form of "org.freedesktop.NetworkManager.vpnc".
|
|
|
|
|
* Extract end part after last dot, e.g. "vpnc"
|
|
|
|
|
*/
|
|
|
|
|
type = nm_setting_vpn_get_service_type (nm_connection_get_setting_vpn (connection));
|
|
|
|
|
p = strrchr (type, '.');
|
|
|
|
|
return g_strdup (p ? p + 1 : type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VPN parameters can be found at:
|
|
|
|
|
* http://git.gnome.org/browse/network-manager-openvpn/tree/src/nm-openvpn-service.h
|
|
|
|
|
* http://git.gnome.org/browse/network-manager-vpnc/tree/src/nm-vpnc-service.h
|
|
|
|
|
* http://git.gnome.org/browse/network-manager-pptp/tree/src/nm-pptp-service.h
|
|
|
|
|
* http://git.gnome.org/browse/network-manager-openconnect/tree/src/nm-openconnect-service.h
|
|
|
|
|
* http://git.gnome.org/browse/network-manager-openswan/tree/src/nm-openswan-service.h
|
|
|
|
|
* See also 'properties' directory in these plugins.
|
|
|
|
|
*/
|
|
|
|
|
static const gchar *
|
|
|
|
|
find_vpn_gateway_key (const char *vpn_type)
|
|
|
|
|
{
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openvpn") == 0) return "remote";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "vpnc") == 0) return "IPSec gateway";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "pptp") == 0) return "gateway";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openconnect") == 0) return "gateway";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openswan") == 0) return "right";
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const gchar *
|
|
|
|
|
find_vpn_username_key (const char *vpn_type)
|
|
|
|
|
{
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openvpn") == 0) return "username";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "vpnc") == 0) return "Xauth username";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "pptp") == 0) return "user";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openconnect") == 0) return "username";
|
|
|
|
|
if (g_strcmp0 (vpn_type, "openswan") == 0) return "leftxauthusername";
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum VpnDataItem {
|
|
|
|
|
VPN_DATA_ITEM_GATEWAY,
|
|
|
|
|
VPN_DATA_ITEM_USERNAME
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const gchar *
|
|
|
|
|
get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item)
|
|
|
|
|
{
|
|
|
|
|
const char *key;
|
|
|
|
|
char *type = get_vpn_connection_type (connection);
|
|
|
|
|
|
|
|
|
|
switch (vpn_data_item) {
|
|
|
|
|
case VPN_DATA_ITEM_GATEWAY:
|
|
|
|
|
key = find_vpn_gateway_key (type);
|
|
|
|
|
break;
|
|
|
|
|
case VPN_DATA_ITEM_USERNAME:
|
|
|
|
|
key = find_vpn_username_key (type);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
key = "";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
g_free (type);
|
|
|
|
|
|
|
|
|
|
return nm_setting_vpn_get_data_item (nm_connection_get_setting_vpn (connection), key);
|
|
|
|
|
}
|
|
|
|
|
/* FIXME end */
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
2010-03-18 15:39:15 +01:00
|
|
|
GError *error = NULL;
|
2012-01-06 15:15:03 +01:00
|
|
|
GArray *print_groups;
|
|
|
|
|
int i;
|
2010-03-18 15:39:15 +01:00
|
|
|
char *fields_str;
|
2012-11-19 10:24:31 +01:00
|
|
|
char *fields_all = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL;
|
|
|
|
|
char *fields_common = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL;
|
2013-05-22 08:37:50 +02:00
|
|
|
NmcOutputField *tmpl, *arr;
|
|
|
|
|
size_t tmpl_len;
|
2012-01-06 15:15:03 +01:00
|
|
|
gboolean was_output = FALSE;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2010-03-18 15:39:15 +01:00
|
|
|
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
|
|
|
|
fields_str = fields_common;
|
|
|
|
|
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
|
|
|
|
|
fields_str = fields_all;
|
2010-03-31 17:14:35 +02:00
|
|
|
else
|
2010-03-18 15:39:15 +01:00
|
|
|
fields_str = nmc->required_fields;
|
|
|
|
|
|
2012-11-19 10:24:31 +01:00
|
|
|
print_groups = parse_output_fields (fields_str, nmc_fields_con_active_details_groups, &error);
|
2010-03-18 15:39:15 +01:00
|
|
|
if (error) {
|
2010-03-20 14:08:06 +01:00
|
|
|
if (error->code == 0)
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'list active': %s"), error->message);
|
2010-03-20 14:08:06 +01:00
|
|
|
else
|
2013-05-22 08:37:50 +02:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'list active': %s; allowed fields: %s"),
|
|
|
|
|
error->message, NMC_FIELDS_CON_ACTIVE_DETAILS_ALL);
|
2010-03-18 15:39:15 +01:00
|
|
|
g_error_free (error);
|
2010-03-24 13:42:47 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2012-01-06 15:15:03 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Main header */
|
2012-01-06 15:15:03 +01:00
|
|
|
nmc->print_fields.header_name = _("Active connection details");
|
2013-05-22 08:37:50 +02:00
|
|
|
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_ACTIVE_DETAILS_ALL,
|
|
|
|
|
nmc_fields_con_active_details_groups, NULL);
|
|
|
|
|
|
|
|
|
|
nmc_fields_con_active_details_groups[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
|
|
|
|
|
print_required_fields (nmc, nmc_fields_con_active_details_groups);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
/* Loop through the groups and print them. */
|
|
|
|
|
for (i = 0; i < print_groups->len; i++) {
|
|
|
|
|
int group_idx = g_array_index (print_groups, int, i);
|
|
|
|
|
|
|
|
|
|
if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
|
|
|
|
|
printf ("\n"); /* Empty line */
|
|
|
|
|
|
|
|
|
|
was_output = FALSE;
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Remove any previous data */
|
|
|
|
|
nmc_empty_output_fields (nmc);
|
|
|
|
|
|
2012-01-06 15:15:03 +01:00
|
|
|
/* GENERAL */
|
2012-11-19 10:24:31 +01:00
|
|
|
if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[0].name) == 0) {
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add field names */
|
|
|
|
|
tmpl = nmc_fields_con_show_active;
|
|
|
|
|
tmpl_len = sizeof (nmc_fields_con_show_active);
|
|
|
|
|
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL, tmpl, NULL);
|
|
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
/* Fill in values */
|
2013-05-22 08:37:50 +02:00
|
|
|
fill_output_active_connection (acon, nmc, TRUE, NMC_OF_FLAG_SECTION_PREFIX);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
print_data (nmc); /* Print all data */
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
was_output = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* IP */
|
2012-11-19 10:24:31 +01:00
|
|
|
if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[1].name) == 0) {
|
2012-01-06 15:15:03 +01:00
|
|
|
const GPtrArray *devices;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
devices = nm_active_connection_get_devices (acon);
|
|
|
|
|
for (j = 0; devices && (j < devices->len); j++) {
|
|
|
|
|
gboolean b1 = FALSE, b2 = FALSE, b3 = FALSE, b4 = FALSE;
|
|
|
|
|
NMDevice *device = g_ptr_array_index (devices, j);
|
|
|
|
|
NMIP4Config *cfg4 = nm_device_get_ip4_config (device);
|
|
|
|
|
NMIP6Config *cfg6 = nm_device_get_ip6_config (device);
|
|
|
|
|
NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device);
|
|
|
|
|
NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device);
|
|
|
|
|
|
|
|
|
|
b1 = print_ip4_config (cfg4, nmc, "IP4");
|
|
|
|
|
b2 = print_dhcp4_config (dhcp4, nmc, "DHCP4");
|
|
|
|
|
b3 = print_ip6_config (cfg6, nmc, "IP6");
|
|
|
|
|
b4 = print_dhcp6_config (dhcp6, nmc, "DHCP6");
|
|
|
|
|
was_output = was_output || b1 || b2 || b3 || b4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VPN */
|
|
|
|
|
if (NM_IS_VPN_CONNECTION (acon) &&
|
2012-11-19 10:24:31 +01:00
|
|
|
strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[2].name) == 0) {
|
2012-01-06 15:15:03 +01:00
|
|
|
NMConnection *con;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
NMSettingVPN *s_vpn;
|
|
|
|
|
NMVPNConnectionState vpn_state;
|
|
|
|
|
char *type_str, *banner_str, *vpn_state_str;
|
|
|
|
|
const char *username = NULL;
|
|
|
|
|
char **vpn_data_array = NULL;
|
|
|
|
|
guint32 items_num;
|
|
|
|
|
|
|
|
|
|
con = get_connection_for_active (nmc->system_connections, acon);
|
|
|
|
|
|
|
|
|
|
s_con = nm_connection_get_setting_connection (con);
|
|
|
|
|
g_assert (s_con != NULL);
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
tmpl = nmc_fields_con_active_details_vpn;
|
|
|
|
|
tmpl_len = sizeof (nmc_fields_con_active_details_vpn);
|
|
|
|
|
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_ACTIVE_DETAILS_VPN_ALL, tmpl, NULL);
|
|
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
s_vpn = nm_connection_get_setting_vpn (con);
|
|
|
|
|
if (s_vpn) {
|
|
|
|
|
items_num = nm_setting_vpn_get_num_data_items (s_vpn);
|
|
|
|
|
if (items_num > 0) {
|
|
|
|
|
FillVPNDataInfo info;
|
|
|
|
|
|
|
|
|
|
vpn_data_array = g_new (char *, items_num + 1);
|
|
|
|
|
info.array = vpn_data_array;
|
|
|
|
|
info.idx = 0;
|
|
|
|
|
nm_setting_vpn_foreach_data_item (s_vpn, &fill_vpn_data_item, &info);
|
|
|
|
|
vpn_data_array[items_num] = NULL;
|
|
|
|
|
}
|
|
|
|
|
username = nm_setting_vpn_get_user_name (s_vpn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type_str = get_vpn_connection_type (con);
|
|
|
|
|
banner_str = g_strescape (nm_vpn_connection_get_banner (NM_VPN_CONNECTION (acon)), "");
|
|
|
|
|
vpn_state = nm_vpn_connection_get_vpn_state (NM_VPN_CONNECTION (acon));
|
|
|
|
|
vpn_state_str = g_strdup_printf ("%d - %s", vpn_state, vpn_connection_state_to_string (vpn_state));
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add values */
|
|
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
|
|
|
|
|
set_val_strc (arr, 0, nmc_fields_con_active_details_groups[2].name);
|
|
|
|
|
set_val_str (arr, 1, type_str);
|
|
|
|
|
set_val_strc (arr, 2, username ? username : get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME));
|
|
|
|
|
set_val_strc (arr, 3, get_vpn_data_item (con, VPN_DATA_ITEM_GATEWAY));
|
|
|
|
|
set_val_str (arr, 4, banner_str);
|
|
|
|
|
set_val_str (arr, 5, vpn_state_str);
|
|
|
|
|
set_val_arr (arr, 6, vpn_data_array);
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
|
|
|
|
|
|
|
|
|
print_data (nmc); /* Print all data */
|
2012-01-06 15:15:03 +01:00
|
|
|
was_output = TRUE;
|
|
|
|
|
}
|
2010-03-18 15:39:15 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-06 15:15:03 +01:00
|
|
|
if (print_groups)
|
|
|
|
|
g_array_free (print_groups, FALSE);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMCResultCode
|
2012-11-19 10:24:31 +01:00
|
|
|
do_connections_show_active (NmCli *nmc, int argc, char **argv)
|
2012-01-06 15:15:03 +01:00
|
|
|
{
|
|
|
|
|
const GPtrArray *active_cons;
|
2013-05-22 08:37:50 +02:00
|
|
|
int i;
|
2012-01-06 15:15:03 +01:00
|
|
|
GError *err1 = NULL;
|
2012-11-16 12:43:44 +01:00
|
|
|
gboolean printed = FALSE;
|
2013-05-22 08:37:50 +02:00
|
|
|
NmcOutputField *tmpl, *arr;
|
|
|
|
|
size_t tmpl_len;
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
|
2013-03-05 09:42:31 -06:00
|
|
|
/* Get active connections */
|
|
|
|
|
nmc->get_client (nmc);
|
|
|
|
|
|
|
|
|
|
if (!nm_client_get_manager_running (nmc->client)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
2011-02-10 14:21:18 +01:00
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active_cons = nm_client_get_active_connections (nmc->client);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
|
char *fields_str;
|
2012-11-19 10:24:31 +01:00
|
|
|
char *fields_all = NMC_FIELDS_CON_ACTIVE_ALL;
|
|
|
|
|
char *fields_common = NMC_FIELDS_CON_ACTIVE_COMMON;
|
2012-01-06 15:15:03 +01:00
|
|
|
|
|
|
|
|
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
|
|
|
|
|
fields_str = fields_common;
|
|
|
|
|
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
|
|
|
|
|
fields_str = fields_all;
|
|
|
|
|
else
|
|
|
|
|
fields_str = nmc->required_fields;
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
tmpl = nmc_fields_con_show_active + 1;
|
|
|
|
|
tmpl_len = sizeof (nmc_fields_con_show_active) - sizeof (NmcOutputField);
|
|
|
|
|
nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, &err1);
|
2012-01-06 15:15:03 +01:00
|
|
|
if (err1)
|
|
|
|
|
goto error;
|
|
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add headers */
|
2012-11-19 10:24:31 +01:00
|
|
|
nmc->print_fields.header_name = _("List of active connections");
|
2013-05-22 08:37:50 +02:00
|
|
|
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
|
|
|
|
|
g_ptr_array_add (nmc->output_data, arr);
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2013-05-22 08:37:50 +02:00
|
|
|
/* Add values */
|
|
|
|
|
for (i = 0; active_cons && i < active_cons->len; i++) {
|
|
|
|
|
NMActiveConnection *ac = g_ptr_array_index (active_cons, i);
|
|
|
|
|
fill_output_active_connection (ac, nmc, FALSE, 0);
|
|
|
|
|
}
|
|
|
|
|
print_data (nmc); /* Print all data */
|
2012-01-06 15:15:03 +01:00
|
|
|
} else {
|
|
|
|
|
while (argc > 0) {
|
2012-11-16 12:43:44 +01:00
|
|
|
NMActiveConnection *acon;
|
|
|
|
|
const char *selector = NULL;
|
|
|
|
|
|
2012-01-06 15:15:03 +01:00
|
|
|
if ( strcmp (*argv, "id") == 0
|
|
|
|
|
|| strcmp (*argv, "uuid") == 0
|
2012-11-16 12:43:44 +01:00
|
|
|
|| strcmp (*argv, "path") == 0
|
|
|
|
|
|| strcmp (*argv, "apath") == 0) {
|
2012-01-06 15:15:03 +01:00
|
|
|
|
2012-11-16 12:43:44 +01:00
|
|
|
selector = *argv;
|
2012-01-06 15:15:03 +01:00
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
2012-11-16 22:43:29 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
2012-01-06 15:15:03 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
2012-11-16 12:43:44 +01:00
|
|
|
}
|
|
|
|
|
if (!nmc->mode_specified)
|
2012-11-19 10:24:31 +01:00
|
|
|
nmc->multiline_output = TRUE; /* multiline mode is default for 'show active <con>' */
|
2012-11-16 12:43:44 +01:00
|
|
|
|
|
|
|
|
acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv);
|
|
|
|
|
if (acon) {
|
|
|
|
|
if (printed)
|
|
|
|
|
printf ("\n");
|
|
|
|
|
printed = nmc_active_connection_detail (acon, nmc); /* separate connections by blank line */
|
2012-01-06 15:15:03 +01:00
|
|
|
} else {
|
2012-11-16 12:43:44 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *argv);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
|
|
|
return nmc->return_value;
|
2012-01-06 15:15:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argc--;
|
|
|
|
|
argv++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2010-03-18 15:39:15 +01:00
|
|
|
error:
|
2012-01-06 15:15:03 +01:00
|
|
|
if (err1) {
|
|
|
|
|
if (err1->code == 0)
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'show active': %s"), err1->message);
|
2012-01-06 15:15:03 +01:00
|
|
|
else
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: 'show active': %s; allowed fields: %s"), err1->message, NMC_FIELDS_CON_ACTIVE_ALL);
|
2012-01-06 15:15:03 +01:00
|
|
|
g_error_free (err1);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
}
|
2010-03-18 15:39:15 +01:00
|
|
|
return nmc->return_value;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMActiveConnection *
|
|
|
|
|
get_default_active_connection (NmCli *nmc, NMDevice **device)
|
|
|
|
|
{
|
|
|
|
|
NMActiveConnection *default_ac = NULL;
|
|
|
|
|
NMDevice *non_default_device = NULL;
|
|
|
|
|
NMActiveConnection *non_default_ac = NULL;
|
|
|
|
|
const GPtrArray *connections;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (nmc != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (device != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (*device == NULL, NULL);
|
|
|
|
|
|
|
|
|
|
connections = nm_client_get_active_connections (nmc->client);
|
|
|
|
|
for (i = 0; connections && (i < connections->len); i++) {
|
|
|
|
|
NMActiveConnection *candidate = g_ptr_array_index (connections, i);
|
|
|
|
|
const GPtrArray *devices;
|
|
|
|
|
|
|
|
|
|
devices = nm_active_connection_get_devices (candidate);
|
|
|
|
|
if (!devices || !devices->len)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (nm_active_connection_get_default (candidate)) {
|
|
|
|
|
if (!default_ac) {
|
|
|
|
|
*device = g_ptr_array_index (devices, 0);
|
|
|
|
|
default_ac = candidate;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!non_default_ac) {
|
|
|
|
|
non_default_device = g_ptr_array_index (devices, 0);
|
|
|
|
|
non_default_ac = candidate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prefer the default connection if one exists, otherwise return the first
|
|
|
|
|
* non-default connection.
|
|
|
|
|
*/
|
|
|
|
|
if (!default_ac && non_default_ac) {
|
|
|
|
|
default_ac = non_default_ac;
|
|
|
|
|
*device = non_default_device;
|
|
|
|
|
}
|
|
|
|
|
return default_ac;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find a device to activate the connection on.
|
|
|
|
|
* IN: connection: connection to activate
|
|
|
|
|
* iface: device interface name to use (optional)
|
|
|
|
|
* ap: access point to use (optional; valid just for 802-11-wireless)
|
2011-01-06 17:01:55 -06:00
|
|
|
* nsp: Network Service Provider to use (option; valid only for wimax)
|
2010-02-25 09:52:30 -08:00
|
|
|
* OUT: device: found device
|
|
|
|
|
* spec_object: specific_object path of NMAccessPoint
|
|
|
|
|
* RETURNS: TRUE when a device is found, FALSE otherwise.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
2011-01-06 17:01:55 -06:00
|
|
|
find_device_for_connection (NmCli *nmc,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
const char *iface,
|
|
|
|
|
const char *ap,
|
|
|
|
|
const char *nsp,
|
|
|
|
|
NMDevice **device,
|
|
|
|
|
const char **spec_object,
|
|
|
|
|
GError **error)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const char *con_type;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (nmc != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (device != NULL && *device == NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (spec_object != NULL && *spec_object == NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
2011-03-16 14:32:24 +01:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
2010-02-25 09:52:30 -08:00
|
|
|
g_assert (s_con);
|
|
|
|
|
con_type = nm_setting_connection_get_connection_type (s_con);
|
|
|
|
|
|
2011-09-06 16:04:12 +02:00
|
|
|
if (strcmp (con_type, NM_SETTING_VPN_SETTING_NAME) == 0) {
|
2010-02-25 09:52:30 -08:00
|
|
|
/* VPN connections */
|
|
|
|
|
NMActiveConnection *active = NULL;
|
|
|
|
|
if (iface) {
|
2011-06-15 15:00:55 +02:00
|
|
|
*device = nm_client_get_device_by_iface (nmc->client, iface);
|
|
|
|
|
if (*device)
|
|
|
|
|
active = nm_device_get_active_connection (*device);
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
if (!active) {
|
2012-07-25 13:57:45 +02:00
|
|
|
g_set_error (error, NMCLI_ERROR, 0, _("no active connection on device '%s'"), iface);
|
2010-02-25 09:52:30 -08:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
*spec_object = nm_object_get_path (NM_OBJECT (active));
|
|
|
|
|
return TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
active = get_default_active_connection (nmc, device);
|
|
|
|
|
if (!active) {
|
2012-07-25 13:57:45 +02:00
|
|
|
g_set_error_literal (error, NMCLI_ERROR, 0, _("no active connection or device"));
|
2010-02-25 09:52:30 -08:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
*spec_object = nm_object_get_path (NM_OBJECT (active));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* Other connections */
|
|
|
|
|
NMDevice *found_device = NULL;
|
|
|
|
|
const GPtrArray *devices = nm_client_get_devices (nmc->client);
|
|
|
|
|
|
|
|
|
|
for (i = 0; devices && (i < devices->len) && !found_device; i++) {
|
|
|
|
|
NMDevice *dev = g_ptr_array_index (devices, i);
|
|
|
|
|
|
|
|
|
|
if (iface) {
|
|
|
|
|
const char *dev_iface = nm_device_get_iface (dev);
|
2013-02-05 10:00:58 +01:00
|
|
|
if ( !g_strcmp0 (dev_iface, iface)
|
2012-03-14 14:10:03 +01:00
|
|
|
&& nm_device_connection_compatible (dev, connection, NULL)) {
|
2010-02-25 09:52:30 -08:00
|
|
|
found_device = dev;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2012-03-14 14:10:03 +01:00
|
|
|
if (nm_device_connection_compatible (dev, connection, NULL)) {
|
2010-02-25 09:52:30 -08:00
|
|
|
found_device = dev;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-06 16:04:12 +02:00
|
|
|
if (found_device && ap && !strcmp (con_type, NM_SETTING_WIRELESS_SETTING_NAME) && NM_IS_DEVICE_WIFI (dev)) {
|
2011-09-06 13:37:23 +02:00
|
|
|
char *bssid_up = g_ascii_strup (ap, -1);
|
2010-02-25 09:52:30 -08:00
|
|
|
const GPtrArray *aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev));
|
|
|
|
|
found_device = NULL; /* Mark as not found; set to the device again later, only if AP matches */
|
|
|
|
|
|
|
|
|
|
for (j = 0; aps && (j < aps->len); j++) {
|
|
|
|
|
NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j);
|
2011-09-06 13:37:23 +02:00
|
|
|
const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-09-06 13:37:23 +02:00
|
|
|
if (!strcmp (bssid_up, candidate_bssid)) {
|
2010-02-25 09:52:30 -08:00
|
|
|
found_device = dev;
|
|
|
|
|
*spec_object = nm_object_get_path (NM_OBJECT (candidate_ap));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-09-06 13:37:23 +02:00
|
|
|
g_free (bssid_up);
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2011-01-06 17:01:55 -06:00
|
|
|
|
2011-02-14 16:06:37 +01:00
|
|
|
#if WITH_WIMAX
|
2011-01-06 17:01:55 -06:00
|
|
|
if ( found_device
|
|
|
|
|
&& nsp
|
|
|
|
|
&& !strcmp (con_type, NM_SETTING_WIMAX_SETTING_NAME)
|
|
|
|
|
&& NM_IS_DEVICE_WIMAX (dev)) {
|
|
|
|
|
const GPtrArray *nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (dev));
|
|
|
|
|
found_device = NULL; /* Mark as not found; set to the device again later, only if NSP matches */
|
|
|
|
|
|
|
|
|
|
for (j = 0; nsps && (j < nsps->len); j++) {
|
|
|
|
|
NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j);
|
|
|
|
|
const char *candidate_name = nm_wimax_nsp_get_name (candidate_nsp);
|
|
|
|
|
|
|
|
|
|
if (!strcmp (nsp, candidate_name)) {
|
|
|
|
|
found_device = dev;
|
|
|
|
|
*spec_object = nm_object_get_path (NM_OBJECT (candidate_nsp));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-14 16:06:37 +01:00
|
|
|
#endif
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found_device) {
|
|
|
|
|
*device = found_device;
|
|
|
|
|
return TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
if (iface)
|
2012-07-25 13:57:45 +02:00
|
|
|
g_set_error (error, NMCLI_ERROR, 0, _("device '%s' not compatible with connection '%s'"),
|
|
|
|
|
iface, nm_setting_connection_get_id (s_con));
|
2010-02-25 09:52:30 -08:00
|
|
|
else
|
2012-07-25 13:57:45 +02:00
|
|
|
g_set_error (error, NMCLI_ERROR, 0, _("no device found for connection '%s'"),
|
|
|
|
|
nm_setting_connection_get_id (s_con));
|
2010-02-25 09:52:30 -08:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
vpn_connection_state_reason_to_string (NMVPNConnectionStateReason reason)
|
|
|
|
|
{
|
|
|
|
|
switch (reason) {
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_UNKNOWN:
|
|
|
|
|
return _("unknown reason");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_NONE:
|
|
|
|
|
return _("none");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED:
|
|
|
|
|
return _("the user was disconnected");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED:
|
|
|
|
|
return _("the base network connection was interrupted");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED:
|
|
|
|
|
return _("the VPN service stopped unexpectedly");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID:
|
|
|
|
|
return _("the VPN service returned invalid configuration");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT:
|
|
|
|
|
return _("the connection attempt timed out");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT:
|
|
|
|
|
return _("the VPN service did not start in time");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED:
|
|
|
|
|
return _("the VPN service failed to start");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS:
|
|
|
|
|
return _("no valid VPN secrets");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED:
|
|
|
|
|
return _("invalid VPN secrets");
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED:
|
|
|
|
|
return _("the connection was removed");
|
|
|
|
|
default:
|
|
|
|
|
return _("unknown");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NmCli *nmc = (NmCli *) user_data;
|
|
|
|
|
NMActiveConnectionState state;
|
|
|
|
|
|
|
|
|
|
state = nm_active_connection_get_state (active);
|
|
|
|
|
|
|
|
|
|
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
2012-05-09 12:35:27 +02:00
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
|
|
|
|
nmc_terminal_erase_line ();
|
|
|
|
|
printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
|
|
|
|
|
nm_object_get_path (NM_OBJECT (active)));
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
quit ();
|
2013-07-02 14:39:58 +02:00
|
|
|
} else if ( state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
|
|
|
|
|
|| state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
|
2010-02-25 09:52:30 -08:00
|
|
|
g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
|
|
|
|
quit ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
vpn_connection_state_cb (NMVPNConnection *vpn,
|
|
|
|
|
NMVPNConnectionState state,
|
|
|
|
|
NMVPNConnectionStateReason reason,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NmCli *nmc = (NmCli *) user_data;
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_PREPARE:
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_NEED_AUTH:
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_CONNECT:
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
|
2012-05-09 12:35:27 +02:00
|
|
|
/* no operation */
|
2010-02-25 09:52:30 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_ACTIVATED:
|
2012-05-09 12:35:27 +02:00
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
|
|
|
|
nmc_terminal_erase_line ();
|
|
|
|
|
printf (_("VPN connection successfully activated (D-Bus active path: %s)\n"),
|
|
|
|
|
nm_object_get_path (NM_OBJECT (vpn)));
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
quit ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_FAILED:
|
|
|
|
|
case NM_VPN_CONNECTION_STATE_DISCONNECTED:
|
2012-05-09 12:35:27 +02:00
|
|
|
g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s."),
|
|
|
|
|
vpn_connection_state_reason_to_string (reason));
|
2010-02-25 09:52:30 -08:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
|
|
|
|
quit ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
timeout_cb (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
/* Time expired -> exit nmcli */
|
|
|
|
|
|
|
|
|
|
NmCli *nmc = (NmCli *) user_data;
|
|
|
|
|
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
|
|
|
|
|
quit ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-09 12:35:27 +02:00
|
|
|
static gboolean
|
|
|
|
|
progress_cb (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
const char *str = (const char *) user_data;
|
|
|
|
|
|
|
|
|
|
nmc_terminal_show_progress (str);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
progress_device_cb (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMDevice *device = (NMDevice *) user_data;
|
|
|
|
|
|
|
|
|
|
nmc_terminal_show_progress (device ? nmc_device_state_to_string (nm_device_get_state (device)) : "");
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
progress_vpn_cb (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMVPNConnection *vpn = (NMVPNConnection *) user_data;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
str = NM_IS_VPN_CONNECTION (vpn) ?
|
|
|
|
|
vpn_connection_state_to_string (nm_vpn_connection_get_vpn_state (vpn)) :
|
|
|
|
|
"";
|
|
|
|
|
|
|
|
|
|
nmc_terminal_show_progress (str);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
NmCli *nmc;
|
|
|
|
|
NMDevice *device;
|
2013-06-26 13:38:58 +02:00
|
|
|
const char *con_type;
|
2012-05-09 12:35:27 +02:00
|
|
|
} ActivateConnectionInfo;
|
|
|
|
|
|
2013-06-26 13:38:58 +02:00
|
|
|
static gboolean
|
|
|
|
|
bond_bridge_slaves_check (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
ActivateConnectionInfo *info = (ActivateConnectionInfo *) user_data;
|
|
|
|
|
NmCli *nmc = info->nmc;
|
|
|
|
|
NMDevice *device = info->device;
|
|
|
|
|
const char *con_type = info->con_type;
|
|
|
|
|
const GPtrArray *slaves = NULL;
|
|
|
|
|
|
|
|
|
|
if (strcmp (con_type, NM_SETTING_BOND_SETTING_NAME) == 0)
|
|
|
|
|
slaves = nm_device_bond_get_slaves (NM_DEVICE_BOND (device));
|
|
|
|
|
else if (strcmp (con_type, NM_SETTING_BRIDGE_SETTING_NAME) == 0)
|
|
|
|
|
slaves = nm_device_bridge_get_slaves (NM_DEVICE_BRIDGE (device));
|
|
|
|
|
else
|
|
|
|
|
g_warning ("%s: should not be reached.", __func__);
|
|
|
|
|
|
|
|
|
|
if (!slaves) {
|
|
|
|
|
g_string_printf (nmc->return_text,
|
|
|
|
|
_("Error: Device '%s' is waiting for slaves before proceeding with activation."),
|
|
|
|
|
nm_device_get_iface (device));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
|
|
|
|
|
quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (info);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
static void
|
2011-03-16 13:29:41 +01:00
|
|
|
activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *error, gpointer user_data)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
2012-05-09 12:35:27 +02:00
|
|
|
ActivateConnectionInfo *info = (ActivateConnectionInfo *) user_data;
|
|
|
|
|
NmCli *nmc = info->nmc;
|
|
|
|
|
NMDevice *device = info->device;
|
2010-02-25 09:52:30 -08:00
|
|
|
NMActiveConnectionState state;
|
2013-06-26 13:38:58 +02:00
|
|
|
const GPtrArray *ac_devs;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-03-16 13:29:41 +01:00
|
|
|
if (error) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), error->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
2010-02-25 09:52:30 -08:00
|
|
|
quit ();
|
|
|
|
|
} else {
|
|
|
|
|
state = nm_active_connection_get_state (active);
|
2013-06-26 13:38:58 +02:00
|
|
|
if (!device) {
|
|
|
|
|
/* device could be NULL for virtual devices. Fill it here. */
|
|
|
|
|
ac_devs = nm_active_connection_get_devices (active);
|
|
|
|
|
info->device = device = ac_devs && ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-03-16 13:29:41 +01:00
|
|
|
if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
2012-05-09 12:35:27 +02:00
|
|
|
/* User doesn't want to wait or already activated */
|
|
|
|
|
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && nmc->print_output == NMC_PRINT_PRETTY) {
|
2013-07-03 12:43:36 +02:00
|
|
|
nmc_terminal_erase_line ();
|
2012-05-09 12:35:27 +02:00
|
|
|
printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
|
|
|
|
|
nm_object_get_path (NM_OBJECT (active)));
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
quit ();
|
|
|
|
|
} else {
|
2012-05-09 12:35:27 +02:00
|
|
|
if (NM_IS_VPN_CONNECTION (active)) {
|
|
|
|
|
/* Monitor VPN state */
|
|
|
|
|
g_signal_connect (G_OBJECT (active), "vpn-state-changed", G_CALLBACK (vpn_connection_state_cb), nmc);
|
|
|
|
|
|
|
|
|
|
/* Start progress indication showing VPN states */
|
|
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
|
|
|
|
if (progress_id)
|
|
|
|
|
g_source_remove (progress_id);
|
|
|
|
|
progress_id = g_timeout_add (120, progress_vpn_cb, NM_VPN_CONNECTION (active));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-03-16 13:29:41 +01:00
|
|
|
g_signal_connect (active, "notify::state", G_CALLBACK (active_connection_state_cb), nmc);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-05-09 12:35:27 +02:00
|
|
|
/* Start progress indication showing device states */
|
|
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
|
|
|
|
if (progress_id)
|
|
|
|
|
g_source_remove (progress_id);
|
|
|
|
|
progress_id = g_timeout_add (120, progress_device_cb, device);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
/* Start timer not to loop forever when signals are not emitted */
|
2011-03-16 13:29:41 +01:00
|
|
|
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
|
2013-04-29 12:43:13 +02:00
|
|
|
|
2013-06-26 13:38:58 +02:00
|
|
|
/* Check for bond or bridge slaves */
|
|
|
|
|
if ( !strcmp (info->con_type, NM_SETTING_BOND_SETTING_NAME)
|
|
|
|
|
|| !strcmp (info->con_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
|
|
|
|
|
|
|
|
|
|
g_timeout_add_seconds (BB_SLAVES_TIMEOUT, bond_bridge_slaves_check, info);
|
|
|
|
|
return; /* info will be freed in bond_bridge_slaves_check () */
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-29 12:43:13 +02:00
|
|
|
}
|
|
|
|
|
g_free (info);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_up (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
2012-05-09 12:35:27 +02:00
|
|
|
ActivateConnectionInfo *info;
|
2010-02-25 09:52:30 -08:00
|
|
|
NMDevice *device = NULL;
|
|
|
|
|
const char *spec_object = NULL;
|
|
|
|
|
gboolean device_found;
|
|
|
|
|
NMConnection *connection = NULL;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const char *con_type;
|
2013-04-18 14:54:01 +02:00
|
|
|
const char *ifname = NULL;
|
2010-02-25 09:52:30 -08:00
|
|
|
const char *ap = NULL;
|
2011-01-06 17:01:55 -06:00
|
|
|
const char *nsp = NULL;
|
2010-02-25 09:52:30 -08:00
|
|
|
GError *error = NULL;
|
2012-03-06 12:01:49 -06:00
|
|
|
gboolean is_virtual = FALSE;
|
2012-11-19 12:31:33 +01:00
|
|
|
const char *selector = NULL;
|
2012-11-21 16:53:53 +01:00
|
|
|
const char *name;
|
|
|
|
|
char *line = NULL;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-05-14 12:43:43 +02:00
|
|
|
/*
|
|
|
|
|
* Set default timeout for connection activation.
|
|
|
|
|
* Activation can take quite a long time, use 90 seconds.
|
2010-02-25 09:52:30 -08:00
|
|
|
*/
|
2013-05-14 12:43:43 +02:00
|
|
|
if (nmc->timeout == -1)
|
|
|
|
|
nmc->timeout = 90;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-11-19 12:31:33 +01:00
|
|
|
if (argc == 0) {
|
2012-11-21 16:53:53 +01:00
|
|
|
if (nmc->ask) {
|
|
|
|
|
line = nmc_get_user_input (_("Connection (name, UUID, or path): "));
|
|
|
|
|
name = line ? line : "";
|
|
|
|
|
// TODO: enhancement: when just Enter is pressed (line is NULL), list
|
|
|
|
|
// available connections so that the user can select one
|
|
|
|
|
} else {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: No connection specified."));
|
2012-11-19 12:31:33 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2012-11-21 16:53:53 +01:00
|
|
|
} else {
|
|
|
|
|
if ( strcmp (*argv, "id") == 0
|
|
|
|
|
|| strcmp (*argv, "uuid") == 0
|
|
|
|
|
|| strcmp (*argv, "path") == 0) {
|
|
|
|
|
|
|
|
|
|
selector = *argv;
|
|
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
name = *argv;
|
|
|
|
|
}
|
|
|
|
|
name = *argv;
|
2012-11-19 12:31:33 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-21 16:53:53 +01:00
|
|
|
connection = find_connection (nmc->system_connections, selector, name);
|
2012-11-19 12:31:33 +01:00
|
|
|
|
|
|
|
|
if (!connection) {
|
2012-11-21 16:53:53 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), name);
|
2012-11-19 12:31:33 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
next_arg (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
while (argc > 0) {
|
2013-04-18 14:54:01 +02:00
|
|
|
if (strcmp (*argv, "ifname") == 0) {
|
2010-02-25 09:52:30 -08:00
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
2012-11-16 22:43:29 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
2010-03-24 13:42:47 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2010-02-25 09:52:30 -08:00
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-18 14:54:01 +02:00
|
|
|
ifname = *argv;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
else if (strcmp (*argv, "ap") == 0) {
|
|
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
2012-11-16 22:43:29 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
2010-03-24 13:42:47 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2010-02-25 09:52:30 -08:00
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ap = *argv;
|
|
|
|
|
}
|
2011-02-14 16:06:37 +01:00
|
|
|
#if WITH_WIMAX
|
2011-01-06 17:01:55 -06:00
|
|
|
else if (strcmp (*argv, "nsp") == 0) {
|
|
|
|
|
if (next_arg (&argc, &argv) != 0) {
|
2012-11-16 22:43:29 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
2011-01-06 17:01:55 -06:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsp = *argv;
|
|
|
|
|
}
|
2011-02-14 16:06:37 +01:00
|
|
|
#endif
|
2013-05-14 12:43:43 +02:00
|
|
|
else {
|
2010-02-25 09:52:30 -08:00
|
|
|
fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argc--;
|
|
|
|
|
argv++;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-10 14:21:18 +01:00
|
|
|
/* create NMClient */
|
|
|
|
|
nmc->get_client (nmc);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-03-05 09:42:31 -06:00
|
|
|
if (!nm_client_get_manager_running (nmc->client)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-16 14:32:24 +01:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
2010-02-25 09:52:30 -08:00
|
|
|
g_assert (s_con);
|
|
|
|
|
con_type = nm_setting_connection_get_connection_type (s_con);
|
|
|
|
|
|
2012-03-06 12:01:49 -06:00
|
|
|
if ( nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
|
2012-10-30 17:11:28 -05:00
|
|
|
|| nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)
|
|
|
|
|
|| nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
|
2012-03-06 12:01:49 -06:00
|
|
|
is_virtual = TRUE;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-04-18 14:54:01 +02:00
|
|
|
device_found = find_device_for_connection (nmc, connection, ifname, ap, nsp, &device, &spec_object, &error);
|
2012-03-06 12:01:49 -06:00
|
|
|
/* Virtual connection may not have their interfaces created yet */
|
|
|
|
|
if (!device_found && !is_virtual) {
|
2010-02-25 09:52:30 -08:00
|
|
|
if (error)
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: No suitable device found: %s."), error->message);
|
|
|
|
|
else
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: No suitable device found."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
2011-02-10 14:21:18 +01:00
|
|
|
g_clear_error (&error);
|
2010-02-25 09:52:30 -08:00
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-16 13:29:41 +01:00
|
|
|
/* Use nowait_flag instead of should_wait because exiting has to be postponed till
|
|
|
|
|
* active_connection_state_cb() is called. That gives NM time to check our permissions
|
|
|
|
|
* and we can follow activation progress.
|
|
|
|
|
*/
|
2013-05-14 12:43:43 +02:00
|
|
|
nmc->nowait_flag = (nmc->timeout == 0);
|
2010-07-29 16:16:20 +02:00
|
|
|
nmc->should_wait = TRUE;
|
2012-05-09 12:35:27 +02:00
|
|
|
|
|
|
|
|
info = g_malloc0 (sizeof (ActivateConnectionInfo));
|
|
|
|
|
info->nmc = nmc;
|
|
|
|
|
info->device = device;
|
2013-06-26 13:38:58 +02:00
|
|
|
info->con_type = con_type;
|
2012-05-09 12:35:27 +02:00
|
|
|
|
2010-02-25 09:52:30 -08:00
|
|
|
nm_client_activate_connection (nmc->client,
|
2011-03-16 13:29:41 +01:00
|
|
|
connection,
|
2010-02-25 09:52:30 -08:00
|
|
|
device,
|
|
|
|
|
spec_object,
|
|
|
|
|
activate_connection_cb,
|
2012-05-09 12:35:27 +02:00
|
|
|
info);
|
|
|
|
|
|
|
|
|
|
/* Start progress indication */
|
|
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY)
|
2013-07-03 12:43:36 +02:00
|
|
|
progress_id = g_timeout_add (120, progress_cb, _("preparing"));
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-11-21 16:53:53 +01:00
|
|
|
g_free (line);
|
2010-02-25 09:52:30 -08:00
|
|
|
return nmc->return_value;
|
|
|
|
|
error:
|
|
|
|
|
nmc->should_wait = FALSE;
|
2012-11-21 16:53:53 +01:00
|
|
|
g_free (line);
|
2010-02-25 09:52:30 -08:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_down (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
2012-11-17 22:42:59 +01:00
|
|
|
NMActiveConnection *active;
|
2010-02-25 09:52:30 -08:00
|
|
|
const GPtrArray *active_cons;
|
2012-11-22 13:32:21 +01:00
|
|
|
char *line = NULL;
|
|
|
|
|
char **arg_arr = NULL;
|
|
|
|
|
char **arg_ptr = argv;
|
|
|
|
|
int arg_num = argc;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-11-17 22:42:59 +01:00
|
|
|
if (argc == 0) {
|
2012-11-22 13:32:21 +01:00
|
|
|
if (nmc->ask) {
|
|
|
|
|
line = nmc_get_user_input (_("Connection (name, UUID, or path): "));
|
|
|
|
|
nmc_string_to_arg_array (line, "", &arg_arr, &arg_num);
|
|
|
|
|
arg_ptr = arg_arr;
|
|
|
|
|
}
|
|
|
|
|
if (arg_num == 0) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: No connection specified."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
2011-02-10 14:21:18 +01:00
|
|
|
/* create NMClient */
|
|
|
|
|
nmc->get_client (nmc);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2013-03-05 09:42:31 -06:00
|
|
|
if (!nm_client_get_manager_running (nmc->client)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-17 22:42:59 +01:00
|
|
|
/* Get active connections */
|
2010-02-25 09:52:30 -08:00
|
|
|
active_cons = nm_client_get_active_connections (nmc->client);
|
2012-11-22 13:32:21 +01:00
|
|
|
while (arg_num > 0) {
|
2012-11-17 22:42:59 +01:00
|
|
|
const char *selector = NULL;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-11-22 13:32:21 +01:00
|
|
|
if ( strcmp (*arg_ptr, "id") == 0
|
|
|
|
|
|| strcmp (*arg_ptr, "uuid") == 0
|
|
|
|
|
|| strcmp (*arg_ptr, "path") == 0
|
|
|
|
|
|| strcmp (*arg_ptr, "apath") == 0) {
|
2012-11-17 22:42:59 +01:00
|
|
|
|
2012-11-22 13:32:21 +01:00
|
|
|
selector = *arg_ptr;
|
|
|
|
|
if (next_arg (&arg_num, &arg_ptr) != 0) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
|
2012-11-17 22:42:59 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-22 13:32:21 +01:00
|
|
|
active = find_active_connection (active_cons, nmc->system_connections, selector, *arg_ptr);
|
2012-11-17 22:42:59 +01:00
|
|
|
if (active) {
|
|
|
|
|
nm_client_deactivate_connection (nmc->client, active);
|
|
|
|
|
} else {
|
2012-11-22 13:32:21 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *arg_ptr);
|
2012-11-17 22:42:59 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
|
|
|
goto error;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2012-11-17 22:42:59 +01:00
|
|
|
|
2012-11-22 13:32:21 +01:00
|
|
|
next_arg (&arg_num, &arg_ptr);
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
2012-11-17 22:42:59 +01:00
|
|
|
// FIXME: do something better then sleep()
|
|
|
|
|
/* Don't quit immediatelly and give NM time to check our permissions */
|
|
|
|
|
sleep (1);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
nmc->should_wait = FALSE;
|
2012-11-22 13:32:21 +01:00
|
|
|
g_strfreev (arg_arr);
|
2010-02-25 09:52:30 -08:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-12 15:26:31 +02:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
typedef struct NameItem {
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *alias;
|
2013-01-18 15:21:00 +01:00
|
|
|
const struct NameItem *settings;
|
2013-04-12 15:26:31 +02:00
|
|
|
} NameItem;
|
|
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
static const NameItem nmc_ethernet_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_802_1X_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_infiniband_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_wifi_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRELESS_SETTING_NAME, "wifi", NULL },
|
|
|
|
|
{ NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-sec", NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_wimax_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIMAX_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_gsm_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_GSM_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_SERIAL_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_cdma_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_CDMA_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_SERIAL_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_mobile_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_SERIAL_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_PPP_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_GSM_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_CDMA_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_bluetooth_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_BLUETOOTH_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_adsl_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_ADSL_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_ppoe_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_PPPOE_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_PPP_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_olpc_mesh_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_OLPC_MESH_SETTING_NAME, "olpc-mesh", NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_vpn_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_VPN_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_vlan_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_VLAN_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_bond_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_BOND_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_bridge_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_BRIDGE_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_bond_slave_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_802_1X_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const NameItem nmc_bridge_slave_settings [] = {
|
|
|
|
|
{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_BRIDGE_PORT_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL },
|
|
|
|
|
{ NM_SETTING_802_1X_SETTING_NAME, NULL, NULL },
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2013-04-12 15:26:31 +02:00
|
|
|
/* Available connection types */
|
|
|
|
|
static const NameItem nmc_valid_connection_types[] = {
|
2013-01-18 15:21:00 +01:00
|
|
|
{ NM_SETTING_WIRED_SETTING_NAME, "ethernet", nmc_ethernet_settings },
|
|
|
|
|
{ NM_SETTING_WIRELESS_SETTING_NAME, "wifi", nmc_wifi_settings },
|
|
|
|
|
{ NM_SETTING_WIMAX_SETTING_NAME, NULL, nmc_wimax_settings },
|
|
|
|
|
{ NM_SETTING_GSM_SETTING_NAME, NULL, nmc_gsm_settings },
|
|
|
|
|
{ NM_SETTING_CDMA_SETTING_NAME, NULL, nmc_cdma_settings },
|
|
|
|
|
{ NM_SETTING_INFINIBAND_SETTING_NAME, NULL, nmc_infiniband_settings },
|
|
|
|
|
{ NM_SETTING_ADSL_SETTING_NAME, NULL, nmc_adsl_settings },
|
|
|
|
|
{ NM_SETTING_BLUETOOTH_SETTING_NAME, NULL, nmc_bluetooth_settings },
|
|
|
|
|
{ NM_SETTING_VPN_SETTING_NAME, NULL, nmc_vpn_settings },
|
|
|
|
|
{ NM_SETTING_OLPC_MESH_SETTING_NAME, "olpc-mesh", nmc_olpc_mesh_settings },
|
|
|
|
|
{ NM_SETTING_VLAN_SETTING_NAME, NULL, nmc_vlan_settings },
|
|
|
|
|
{ NM_SETTING_BOND_SETTING_NAME, NULL, nmc_bond_settings },
|
|
|
|
|
{ NM_SETTING_BRIDGE_SETTING_NAME, NULL, nmc_bridge_settings },
|
|
|
|
|
{ "bond-slave", NULL, nmc_bond_slave_settings },
|
|
|
|
|
{ "bridge-slave", NULL, nmc_bridge_slave_settings },
|
|
|
|
|
{ NULL, NULL, NULL }
|
2013-04-12 15:26:31 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return an alias for the 'name' if exists, else return the 'name'.
|
|
|
|
|
* The returned string must not be freed.
|
|
|
|
|
*/
|
|
|
|
|
static const char *
|
|
|
|
|
get_name_alias (const char *name, const NameItem array[])
|
|
|
|
|
{
|
|
|
|
|
const NameItem *iter = &array[0];
|
|
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
while (iter && iter->name) {
|
|
|
|
|
if (!strcmp (name, iter->name)) {
|
|
|
|
|
if (iter->alias)
|
|
|
|
|
return iter->alias;
|
|
|
|
|
else
|
|
|
|
|
return iter->name;
|
|
|
|
|
}
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Construct a string with names and aliases from the array formatted as:
|
|
|
|
|
* "name (alias), name, name (alias), name, name"
|
|
|
|
|
*
|
|
|
|
|
* Returns: string; the caller is responsible for freeing it.
|
|
|
|
|
*/
|
|
|
|
|
static char *
|
|
|
|
|
get_valid_options_string (const NameItem array[])
|
|
|
|
|
{
|
|
|
|
|
const NameItem *iter = &array[0];
|
|
|
|
|
GString *str;
|
|
|
|
|
|
|
|
|
|
str = g_string_sized_new (150);
|
|
|
|
|
while (iter && iter->name) {
|
|
|
|
|
if (str->len)
|
|
|
|
|
g_string_append (str, ", ");
|
|
|
|
|
if (iter->alias)
|
|
|
|
|
g_string_append_printf (str, "%s (%s)", iter->name, iter->alias);
|
|
|
|
|
else
|
|
|
|
|
g_string_append (str, iter->name);
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
return g_string_free (str, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check if 'val' is valid string in either array->name or array->alias.
|
|
|
|
|
* It accepts shorter string provided they are not ambiguous.
|
|
|
|
|
* 'val' == NULL doesn't hurt.
|
|
|
|
|
*
|
|
|
|
|
* Returns: pointer to array->name string or NULL on failure.
|
|
|
|
|
* The returned string must not be freed.
|
|
|
|
|
*/
|
|
|
|
|
static const char *
|
|
|
|
|
check_valid_name (const char *val, const NameItem array[], GError **error)
|
|
|
|
|
{
|
|
|
|
|
const NameItem *iter;
|
|
|
|
|
GPtrArray *tmp_arr;
|
|
|
|
|
const char *str;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
|
|
|
|
|
/* Create a temporary array that can be used in nmc_string_is_valid() */
|
|
|
|
|
tmp_arr = g_ptr_array_sized_new (30);
|
|
|
|
|
iter = &array[0];
|
|
|
|
|
while (iter && iter->name) {
|
|
|
|
|
g_ptr_array_add (tmp_arr, (gpointer) iter->name);
|
|
|
|
|
if (iter->alias)
|
|
|
|
|
g_ptr_array_add (tmp_arr, (gpointer) iter->alias);
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
g_ptr_array_add (tmp_arr, (gpointer) NULL);
|
|
|
|
|
|
|
|
|
|
/* Check string validity */
|
|
|
|
|
str = nmc_string_is_valid (val, (const char **) tmp_arr->pdata, &tmp_err);
|
|
|
|
|
if (!str) {
|
|
|
|
|
if (tmp_err->code == 1)
|
|
|
|
|
g_propagate_error (error, tmp_err);
|
|
|
|
|
else {
|
|
|
|
|
/* We want to handle aliases, so construct own error message */
|
|
|
|
|
char *err_str = get_valid_options_string (array);
|
|
|
|
|
g_set_error (error, 1, 0, _("'%s' not among [%s]"),
|
|
|
|
|
val ? val : "", err_str);
|
|
|
|
|
g_free (err_str);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
g_ptr_array_free (tmp_arr, TRUE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return a pointer to the found string in passed 'array' */
|
|
|
|
|
iter = &array[0];
|
|
|
|
|
while (iter && iter->name) {
|
|
|
|
|
if ( (iter->name && g_strcmp0 (iter->name, str) == 0)
|
|
|
|
|
|| (iter->alias && g_strcmp0 (iter->alias, str) == 0)) {
|
|
|
|
|
g_ptr_array_free (tmp_arr, TRUE);
|
|
|
|
|
return iter->name;
|
|
|
|
|
}
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
/* We should not really come here */
|
|
|
|
|
g_ptr_array_free (tmp_arr, TRUE);
|
|
|
|
|
g_set_error (error, 1, 0, _("Unknown error"));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
static const NameItem *
|
|
|
|
|
get_valid_settings_array (const char *con_type)
|
|
|
|
|
{
|
|
|
|
|
guint i, num;
|
|
|
|
|
|
|
|
|
|
if (!con_type)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
num = G_N_ELEMENTS (nmc_valid_connection_types);
|
|
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
|
if (!strcmp (con_type, nmc_valid_connection_types[i].name))
|
|
|
|
|
return nmc_valid_connection_types[i].settings;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-12 15:26:31 +02:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
check_and_convert_mac (const char *mac,
|
|
|
|
|
GByteArray **mac_array,
|
|
|
|
|
int type,
|
|
|
|
|
const char *keyword,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (mac_array != NULL && *mac_array == NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
if (mac) {
|
|
|
|
|
*mac_array = nm_utils_hwaddr_atoba (mac, type);
|
|
|
|
|
if (!*mac_array) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: '%s': '%s' is not a valid %s MAC address."),
|
|
|
|
|
keyword, mac, type == ARPHRD_INFINIBAND ? _("InfiniBand") : "");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
unique_bond_bridge_ifname (GSList *list, const char *type, const char *try_name)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
NMSetting *setting;
|
|
|
|
|
char *new_name;
|
|
|
|
|
unsigned int num = 1;
|
|
|
|
|
GSList *iterator = list;
|
|
|
|
|
const char *ifname_property;
|
|
|
|
|
char *ifname_val = NULL;
|
|
|
|
|
|
|
|
|
|
ifname_property = strcmp (type, NM_SETTING_BOND_SETTING_NAME) == 0 ?
|
|
|
|
|
NM_SETTING_BOND_INTERFACE_NAME :
|
|
|
|
|
NM_SETTING_BRIDGE_INTERFACE_NAME;
|
|
|
|
|
|
|
|
|
|
new_name = g_strdup (try_name);
|
|
|
|
|
while (iterator) {
|
|
|
|
|
connection = NM_CONNECTION (iterator->data);
|
|
|
|
|
setting = nm_connection_get_setting_by_name (connection, type);
|
|
|
|
|
if (!setting) {
|
|
|
|
|
iterator = g_slist_next (iterator);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_get (setting, ifname_property, &ifname_val, NULL);
|
|
|
|
|
if (g_strcmp0 (new_name, ifname_val) == 0) {
|
|
|
|
|
g_free (new_name);
|
|
|
|
|
new_name = g_strdup_printf ("%s%d", try_name, num++);
|
|
|
|
|
iterator = list;
|
|
|
|
|
} else
|
|
|
|
|
iterator = g_slist_next (iterator);
|
|
|
|
|
g_free (ifname_val);
|
|
|
|
|
}
|
|
|
|
|
return new_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
bridge_prop_string_to_uint (const char *str,
|
|
|
|
|
const char *nmc_arg,
|
|
|
|
|
GType bridge_type,
|
|
|
|
|
const char *propname,
|
|
|
|
|
unsigned long *out_val,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
GParamSpecUInt *pspec;
|
|
|
|
|
|
|
|
|
|
pspec = (GParamSpecUInt *) g_object_class_find_property (g_type_class_peek (bridge_type),
|
|
|
|
|
propname);
|
|
|
|
|
g_assert (G_IS_PARAM_SPEC_UINT (pspec));
|
|
|
|
|
|
|
|
|
|
if (!nmc_string_to_uint (str, TRUE, pspec->minimum, pspec->maximum, out_val)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: '%s': '%s' is not valid; use <%d-%d>."),
|
|
|
|
|
nmc_arg, str, pspec->minimum, pspec->maximum);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
complete_connection_by_type (NMConnection *connection,
|
|
|
|
|
const char *con_type,
|
|
|
|
|
GSList *all_connections,
|
|
|
|
|
gboolean ask,
|
|
|
|
|
int argc,
|
|
|
|
|
char **argv,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
NMSettingWired *s_wired;
|
|
|
|
|
NMSettingInfiniband *s_infiniband;
|
|
|
|
|
NMSettingWireless *s_wifi;
|
|
|
|
|
NMSettingWimax *s_wimax;
|
|
|
|
|
NMSettingGsm *s_gsm;
|
|
|
|
|
NMSettingCdma *s_cdma;
|
|
|
|
|
NMSettingBluetooth *s_bt;
|
|
|
|
|
NMSettingVlan *s_vlan;
|
|
|
|
|
NMSettingBond *s_bond;
|
|
|
|
|
NMSettingBridge *s_bridge;
|
|
|
|
|
NMSettingBridgePort *s_bridge_port;
|
|
|
|
|
NMSettingVPN *s_vpn;
|
|
|
|
|
NMSettingOlpcMesh *s_olpc_mesh;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
|
|
|
|
g_assert (s_con);
|
|
|
|
|
|
|
|
|
|
if (!strcmp (con_type, NM_SETTING_WIRED_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'ethernet' */
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
const char *mtu = NULL;
|
|
|
|
|
unsigned long mtu_int;
|
|
|
|
|
const char *mac = NULL;
|
|
|
|
|
const char *cloned_mac = NULL;
|
|
|
|
|
GByteArray *array = NULL;
|
|
|
|
|
GByteArray *cloned_array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"mtu", TRUE, &mtu, FALSE},
|
|
|
|
|
{"mac", TRUE, &mac, FALSE},
|
|
|
|
|
{"cloned-mac", TRUE, &cloned_mac, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (mtu) {
|
|
|
|
|
if (!nmc_string_to_uint (mtu, TRUE, 0, G_MAXUINT32, &mtu_int)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'mtu': '%s' is not valid."), mtu);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!check_and_convert_mac (mac, &array, ARPHRD_ETHER, "mac", error))
|
|
|
|
|
goto cleanup_wired;
|
|
|
|
|
if (!check_and_convert_mac (cloned_mac, &cloned_array, ARPHRD_ETHER, "cloned-mac", error))
|
|
|
|
|
goto cleanup_wired;
|
|
|
|
|
|
|
|
|
|
/* Add ethernet setting */
|
|
|
|
|
s_wired = (NMSettingWired *) nm_setting_wired_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wired));
|
|
|
|
|
|
|
|
|
|
if (mtu)
|
|
|
|
|
g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu_int, NULL);
|
|
|
|
|
if (array)
|
|
|
|
|
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, array, NULL);
|
|
|
|
|
if (cloned_array)
|
|
|
|
|
g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_array, NULL);
|
|
|
|
|
|
|
|
|
|
success = TRUE;
|
|
|
|
|
cleanup_wired:
|
|
|
|
|
if (array)
|
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
|
|
|
if (cloned_array)
|
|
|
|
|
g_byte_array_free (cloned_array, TRUE);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'infiniband' */
|
|
|
|
|
const char *mtu = NULL;
|
|
|
|
|
unsigned long mtu_int;
|
|
|
|
|
const char *mac = NULL;
|
|
|
|
|
GByteArray *array = NULL;
|
|
|
|
|
const char *mode = "datagram"; /* 'datagram' mode is default */
|
2013-06-11 15:40:36 -03:00
|
|
|
const char *parent = NULL;
|
|
|
|
|
const char *p_key = NULL;
|
|
|
|
|
long p_key_int;
|
2013-04-12 15:26:31 +02:00
|
|
|
nmc_arg_t exp_args[] = { {"mtu", TRUE, &mtu, FALSE},
|
|
|
|
|
{"mac", TRUE, &mac, FALSE},
|
|
|
|
|
{"transport-mode", TRUE, &mode, FALSE},
|
2013-06-11 15:40:36 -03:00
|
|
|
{"parent", TRUE, &mode, FALSE},
|
|
|
|
|
{"p-key", TRUE, &mode, FALSE},
|
2013-04-12 15:26:31 +02:00
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (mtu) {
|
|
|
|
|
if (!nmc_string_to_uint (mtu, TRUE, 0, G_MAXUINT32, &mtu_int)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'mtu': '%s' is not valid."), mtu);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!check_and_convert_mac (mac, &array, ARPHRD_INFINIBAND, "mac", error))
|
|
|
|
|
return FALSE;
|
2013-06-11 15:40:36 -03:00
|
|
|
if (p_key) {
|
|
|
|
|
gboolean p_key_valid = FALSE;
|
|
|
|
|
if (!strncmp (p_key, "0x", 2))
|
|
|
|
|
p_key_valid = nmc_string_to_int_base (p_key + 2, 16, TRUE, 0, G_MAXUINT16, &p_key_int);
|
|
|
|
|
else
|
|
|
|
|
p_key_valid = nmc_string_to_int (p_key, TRUE, 0, G_MAXUINT16, &p_key_int);
|
|
|
|
|
if (!p_key_valid) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'p-key': '%s' is not valid."), p_key);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (parent && !nm_utils_iface_valid_name (parent)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'parent': '%s' is not a valid interface name."), parent);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else if (parent) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'parent': not valid without p-key."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2013-04-12 15:26:31 +02:00
|
|
|
|
|
|
|
|
/* Add 'infiniband' setting */
|
|
|
|
|
s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_infiniband));
|
|
|
|
|
|
|
|
|
|
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, mode, NULL);
|
|
|
|
|
if (mtu)
|
|
|
|
|
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu_int, NULL);
|
|
|
|
|
if (array) {
|
|
|
|
|
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, array, NULL);
|
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
|
|
|
}
|
2013-06-11 15:40:36 -03:00
|
|
|
if (p_key)
|
|
|
|
|
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_P_KEY, p_key_int, NULL);
|
|
|
|
|
if (parent)
|
|
|
|
|
g_object_set (s_infiniband, NM_SETTING_INFINIBAND_PARENT, parent, NULL);
|
2013-04-12 15:26:31 +02:00
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_WIRELESS_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'wifi' */
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
char *ssid_ask = NULL;
|
|
|
|
|
const char *ssid = NULL;
|
|
|
|
|
GByteArray *ssid_arr = NULL;
|
|
|
|
|
const char *mtu = NULL;
|
|
|
|
|
unsigned long mtu_int;
|
|
|
|
|
const char *mac = NULL;
|
|
|
|
|
GByteArray *mac_array = NULL;
|
|
|
|
|
const char *cloned_mac = NULL;
|
|
|
|
|
GByteArray *cloned_mac_array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !ask},
|
|
|
|
|
{"mtu", TRUE, &mtu, FALSE},
|
|
|
|
|
{"mac", TRUE, &mac, FALSE},
|
|
|
|
|
{"cloned-mac", TRUE, &cloned_mac, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!ssid && ask)
|
|
|
|
|
ssid = ssid_ask = nmc_get_user_input (_("SSID: "));
|
|
|
|
|
if (!ssid) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'ssid' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (mtu) {
|
|
|
|
|
if (!nmc_string_to_uint (mtu, TRUE, 0, G_MAXUINT32, &mtu_int)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'mtu': '%s' is not valid."), mtu);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
|
|
|
|
|
goto cleanup_wifi;
|
|
|
|
|
if (!check_and_convert_mac (cloned_mac, &cloned_mac_array, ARPHRD_ETHER, "cloned-mac", error))
|
|
|
|
|
goto cleanup_wifi;
|
|
|
|
|
|
|
|
|
|
/* Add wifi setting */
|
|
|
|
|
s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wifi));
|
|
|
|
|
|
|
|
|
|
ssid_arr = g_byte_array_sized_new (strlen (ssid));
|
|
|
|
|
g_byte_array_append (ssid_arr, (const guint8 *) ssid, strlen (ssid));
|
|
|
|
|
g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid_arr, NULL);
|
|
|
|
|
|
|
|
|
|
if (mtu)
|
|
|
|
|
g_object_set (s_wifi, NM_SETTING_WIRELESS_MTU, mtu_int, NULL);
|
|
|
|
|
if (mac_array)
|
|
|
|
|
g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, mac_array, NULL);
|
|
|
|
|
if (cloned_mac_array)
|
|
|
|
|
g_object_set (s_wifi, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, cloned_mac_array, NULL);
|
|
|
|
|
|
|
|
|
|
success = TRUE;
|
|
|
|
|
cleanup_wifi:
|
|
|
|
|
g_free (ssid_ask);
|
|
|
|
|
if (ssid_arr)
|
|
|
|
|
g_byte_array_free (ssid_arr, TRUE);
|
|
|
|
|
if (mac_array)
|
|
|
|
|
g_byte_array_free (mac_array, TRUE);
|
|
|
|
|
if (cloned_mac_array)
|
|
|
|
|
g_byte_array_free (cloned_mac_array, TRUE);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_WIMAX_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'wimax' */
|
|
|
|
|
const char *nsp_name = NULL;
|
|
|
|
|
char *nsp_name_ask = NULL;
|
|
|
|
|
const char *mac = NULL;
|
|
|
|
|
GByteArray *mac_array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"nsp", TRUE, &nsp_name, !ask},
|
|
|
|
|
{"mac", TRUE, &mac, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!nsp_name && ask)
|
|
|
|
|
nsp_name = nsp_name_ask = nmc_get_user_input (_("WiMAX NSP name: "));
|
|
|
|
|
if (!nsp_name) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'nsp' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error)) {
|
|
|
|
|
g_free (nsp_name_ask);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add 'wimax' setting */
|
|
|
|
|
s_wimax = (NMSettingWimax *) nm_setting_wimax_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wimax));
|
|
|
|
|
g_object_set (s_wimax, NM_SETTING_WIMAX_NETWORK_NAME, nsp_name, NULL);
|
|
|
|
|
|
|
|
|
|
if (mac_array) {
|
|
|
|
|
g_object_set (s_wimax, NM_SETTING_WIMAX_MAC_ADDRESS, mac_array, NULL);
|
|
|
|
|
g_byte_array_free (mac_array, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (nsp_name_ask);
|
|
|
|
|
|
|
|
|
|
} else if ( !strcmp (con_type, NM_SETTING_GSM_SETTING_NAME)
|
|
|
|
|
|| !strcmp (con_type, NM_SETTING_CDMA_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'gsm' or 'cdma' mobile broadband */
|
|
|
|
|
const char *apn = NULL;
|
|
|
|
|
char *apn_ask = NULL;
|
|
|
|
|
const char *user = NULL;
|
|
|
|
|
const char *password = NULL;
|
|
|
|
|
gboolean is_gsm;
|
|
|
|
|
int i = 0;
|
|
|
|
|
nmc_arg_t gsm_args[] = { {NULL}, {NULL}, {NULL}, /* placeholders */
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
is_gsm = !strcmp (con_type, NM_SETTING_GSM_SETTING_NAME);
|
|
|
|
|
|
|
|
|
|
if (is_gsm)
|
|
|
|
|
gsm_args[i++] = (nmc_arg_t) {"apn", TRUE, &apn, !ask};
|
|
|
|
|
gsm_args[i++] = (nmc_arg_t) {"user", TRUE, &user, FALSE};
|
|
|
|
|
gsm_args[i++] = (nmc_arg_t) {"password", TRUE, &password, FALSE};
|
|
|
|
|
gsm_args[i++] = (nmc_arg_t) {NULL};
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (gsm_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!apn && ask && is_gsm)
|
|
|
|
|
apn = apn_ask = nmc_get_user_input (_("APN: "));
|
|
|
|
|
if (!apn && is_gsm) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'apn' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_gsm) {
|
|
|
|
|
g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME, NULL);
|
|
|
|
|
|
|
|
|
|
/* Add 'gsm' setting */
|
|
|
|
|
s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_gsm));
|
|
|
|
|
g_object_set (s_gsm,
|
|
|
|
|
NM_SETTING_GSM_NUMBER, "*99#",
|
|
|
|
|
NM_SETTING_GSM_APN, apn,
|
|
|
|
|
NM_SETTING_GSM_USERNAME, user,
|
|
|
|
|
NM_SETTING_GSM_PASSWORD, password,
|
|
|
|
|
NULL);
|
|
|
|
|
g_free (apn_ask);
|
|
|
|
|
} else {
|
|
|
|
|
g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_CDMA_SETTING_NAME, NULL);
|
|
|
|
|
|
|
|
|
|
/* Add 'cdma' setting */
|
|
|
|
|
s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_cdma));
|
|
|
|
|
g_object_set (s_cdma,
|
|
|
|
|
NM_SETTING_CDMA_NUMBER, "#777",
|
|
|
|
|
NM_SETTING_CDMA_USERNAME, user,
|
|
|
|
|
NM_SETTING_CDMA_PASSWORD, password,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'bluetooth' */
|
|
|
|
|
const char *addr = NULL;
|
|
|
|
|
char *addr_ask = NULL;
|
|
|
|
|
const char *bt_type = NM_SETTING_BLUETOOTH_TYPE_PANU; /* 'panu' is default */
|
|
|
|
|
GByteArray *array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"addr", TRUE, &addr, !ask},
|
|
|
|
|
{"bt-type", TRUE, &bt_type, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!addr && ask)
|
|
|
|
|
addr = addr_ask = nmc_get_user_input (_("Bluetooth device address: "));
|
|
|
|
|
if (!addr) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'addr' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add 'bluetooth' setting */
|
|
|
|
|
s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bt));
|
|
|
|
|
|
|
|
|
|
if (!check_and_convert_mac (addr, &array, ARPHRD_ETHER, "addr", error)) {
|
|
|
|
|
g_free (addr_ask);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (array) {
|
|
|
|
|
g_object_set (s_bt, NM_SETTING_BLUETOOTH_BDADDR, array, NULL);
|
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
|
|
|
}
|
|
|
|
|
g_free (addr_ask);
|
|
|
|
|
|
|
|
|
|
/* 'dun' type requires adding 'gsm' or 'cdma' setting */
|
|
|
|
|
if ( !strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
|
|
|
|
|
|| !strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm")) {
|
|
|
|
|
bt_type = NM_SETTING_BLUETOOTH_TYPE_DUN;
|
|
|
|
|
s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_gsm));
|
|
|
|
|
g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
|
|
|
|
|
// g_object_set (s_gsm, NM_SETTING_GSM_APN, "FIXME", NULL;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma")) {
|
|
|
|
|
bt_type = NM_SETTING_BLUETOOTH_TYPE_DUN;
|
|
|
|
|
s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_cdma));
|
|
|
|
|
g_object_set (s_cdma, NM_SETTING_CDMA_NUMBER, "#777", NULL);
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) {
|
|
|
|
|
/* no op */
|
|
|
|
|
} else {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'bt-type': '%s' not valid; use [%s, %s (%s), %s]."),
|
|
|
|
|
bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU, NM_SETTING_BLUETOOTH_TYPE_DUN,
|
|
|
|
|
NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm", NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
g_object_set (s_bt, NM_SETTING_BLUETOOTH_TYPE, bt_type, NULL);
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_VLAN_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'vlan' */
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
const char *ifname = NULL;
|
|
|
|
|
const char *parent = NULL;
|
|
|
|
|
char *parent_ask = NULL;
|
|
|
|
|
const char *vlan_id = NULL;
|
|
|
|
|
char *vlan_id_ask = NULL;
|
|
|
|
|
unsigned long id = 0;
|
|
|
|
|
const char *flags = NULL;
|
|
|
|
|
unsigned long flags_int = 0;
|
|
|
|
|
const char *ingress = NULL, *egress = NULL;
|
|
|
|
|
char **ingress_arr = NULL, **egress_arr = NULL, **p;
|
|
|
|
|
const char *mtu = NULL;
|
|
|
|
|
unsigned long mtu_int;
|
|
|
|
|
GByteArray *addr_array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !ask},
|
|
|
|
|
{"id", TRUE, &vlan_id, !ask},
|
|
|
|
|
{"flags", TRUE, &flags, FALSE},
|
|
|
|
|
{"ingress", TRUE, &ingress, FALSE},
|
|
|
|
|
{"egress", TRUE, &egress, FALSE},
|
|
|
|
|
{"mtu", TRUE, &mtu, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!parent && ask)
|
|
|
|
|
parent = parent_ask = nmc_get_user_input (_("VLAN parent device or connection UUID: "));
|
|
|
|
|
if (!parent) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'dev' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!vlan_id && ask)
|
|
|
|
|
vlan_id = vlan_id_ask = nmc_get_user_input (_("VLAN ID <0-4095>: "));
|
|
|
|
|
if (!vlan_id) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'id' is required."));
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
if (vlan_id) {
|
|
|
|
|
if (!nmc_string_to_uint (vlan_id, TRUE, 0, 4095, &id)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'id': '%s' is not valid; use <0-4095>."),
|
|
|
|
|
vlan_id);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !(addr_array = nm_utils_hwaddr_atoba (parent, ARPHRD_ETHER))
|
|
|
|
|
&& !nm_utils_is_uuid (parent)
|
|
|
|
|
&& !nm_utils_iface_valid_name (parent)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'dev': '%s' is neither UUID, interface name, nor MAC."),
|
|
|
|
|
parent);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ifname is taken from connection's ifname */
|
|
|
|
|
ifname = nm_setting_connection_get_interface_name (s_con);
|
|
|
|
|
|
|
|
|
|
if (mtu) {
|
|
|
|
|
if (!nmc_string_to_uint (mtu, TRUE, 0, G_MAXUINT32, &mtu_int)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'mtu': '%s' is not valid."), mtu);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (flags) {
|
|
|
|
|
if (!nmc_string_to_uint (flags, TRUE, 0, 7, &flags_int)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'flags': '%s' is not valid; use <0-7>."),
|
|
|
|
|
flags);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ingress) {
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
if (!(ingress_arr = nmc_vlan_parse_priority_maps (ingress, NM_VLAN_INGRESS_MAP, &err))) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'ingress': '%s' is not valid; %s "),
|
|
|
|
|
ingress, err->message);
|
|
|
|
|
g_clear_error (&err);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (egress) {
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
if (!(egress_arr = nmc_vlan_parse_priority_maps (egress, NM_VLAN_EGRESS_MAP, &err))) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'egress': '%s' is not valid; %s "),
|
|
|
|
|
egress, err->message);
|
|
|
|
|
g_clear_error (&err);
|
|
|
|
|
goto cleanup_vlan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add 'vlan' setting */
|
|
|
|
|
s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_vlan));
|
|
|
|
|
|
|
|
|
|
/* Add 'wired' setting if necessary */
|
|
|
|
|
if (mtu || addr_array) {
|
|
|
|
|
s_wired = (NMSettingWired *) nm_setting_wired_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wired));
|
|
|
|
|
|
|
|
|
|
if (mtu)
|
|
|
|
|
g_object_set (s_wired, NM_SETTING_WIRED_MTU, (guint32) mtu_int, NULL);
|
|
|
|
|
if (addr_array)
|
|
|
|
|
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, addr_array, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set 'vlan' properties */
|
|
|
|
|
if (!addr_array)
|
|
|
|
|
g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
|
|
|
|
|
|
|
|
|
|
if (ifname)
|
|
|
|
|
g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, ifname, NULL);
|
|
|
|
|
g_object_set (s_vlan, NM_SETTING_VLAN_ID, id, NULL);
|
|
|
|
|
|
|
|
|
|
if (flags)
|
|
|
|
|
g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, (guint32) flags_int, NULL);
|
|
|
|
|
for (p = ingress_arr; p && *p; p++)
|
|
|
|
|
nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_INGRESS_MAP, *p);
|
|
|
|
|
for (p = egress_arr; p && *p; p++)
|
|
|
|
|
nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_EGRESS_MAP, *p);
|
|
|
|
|
|
|
|
|
|
success = TRUE;
|
|
|
|
|
cleanup_vlan:
|
|
|
|
|
if (addr_array)
|
|
|
|
|
g_byte_array_free (addr_array, TRUE);
|
|
|
|
|
g_free (parent_ask);
|
|
|
|
|
g_free (vlan_id_ask);
|
|
|
|
|
g_strfreev (ingress_arr);
|
|
|
|
|
g_strfreev (egress_arr);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_BOND_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'bond' */
|
|
|
|
|
char *bond_ifname = NULL;
|
|
|
|
|
const char *ifname = NULL;
|
|
|
|
|
const char *bond_mode = NULL;
|
|
|
|
|
const char *bond_miimon = NULL;
|
|
|
|
|
const char *bond_downdelay = NULL;
|
|
|
|
|
const char *bond_updelay = NULL;
|
|
|
|
|
const char *bond_arpinterval = NULL;
|
|
|
|
|
const char *bond_arpiptarget = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"mode", TRUE, &bond_mode, FALSE},
|
|
|
|
|
{"miimon", TRUE, &bond_miimon, FALSE},
|
|
|
|
|
{"downdelay", TRUE, &bond_downdelay, FALSE},
|
|
|
|
|
{"updelay", TRUE, &bond_updelay, FALSE},
|
|
|
|
|
{"arp-interval", TRUE, &bond_arpinterval, FALSE},
|
|
|
|
|
{"arp-ip-target", TRUE, &bond_arpiptarget, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Use connection's ifname as 'bond' ifname if exists, else generate one */
|
|
|
|
|
ifname = nm_setting_connection_get_interface_name (s_con);
|
|
|
|
|
if (!ifname)
|
|
|
|
|
bond_ifname = unique_bond_bridge_ifname (all_connections,
|
|
|
|
|
NM_SETTING_BOND_SETTING_NAME,
|
|
|
|
|
"nm-bond");
|
|
|
|
|
else
|
|
|
|
|
bond_ifname = g_strdup (ifname);
|
|
|
|
|
|
|
|
|
|
/* Add 'bond' setting */
|
|
|
|
|
s_bond = (NMSettingBond *) nm_setting_bond_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bond));
|
|
|
|
|
|
|
|
|
|
/* Set bond options */
|
|
|
|
|
g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, bond_ifname, NULL);
|
2013-05-14 16:42:03 +02:00
|
|
|
if (bond_mode) {
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
if (!(bond_mode = nmc_bond_validate_mode (bond_mode, &err))) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'mode': %s."), err->message);
|
|
|
|
|
g_clear_error (&err);
|
|
|
|
|
g_free (bond_ifname);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2013-04-12 15:26:31 +02:00
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MODE, bond_mode);
|
2013-05-14 16:42:03 +02:00
|
|
|
}
|
2013-04-12 15:26:31 +02:00
|
|
|
if (bond_miimon)
|
|
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MIIMON, bond_miimon);
|
|
|
|
|
if (bond_downdelay)
|
|
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, bond_downdelay);
|
|
|
|
|
if (bond_updelay)
|
|
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY, bond_updelay);
|
|
|
|
|
if (bond_arpinterval)
|
|
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL, bond_arpinterval);
|
|
|
|
|
if (bond_arpiptarget)
|
|
|
|
|
nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, bond_arpiptarget);
|
|
|
|
|
|
|
|
|
|
g_free (bond_ifname);
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, "bond-slave")) {
|
|
|
|
|
/* Build up the settings required for 'bond-slave' */
|
|
|
|
|
const char *master = NULL;
|
|
|
|
|
char *master_ask = NULL;
|
|
|
|
|
const char *type = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask},
|
|
|
|
|
{"type", TRUE, &type, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!master && ask)
|
|
|
|
|
master = master_ask = nmc_get_user_input (_("Bond master: "));
|
|
|
|
|
if (!master) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'master' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
|
printf (_("Warning: 'type' is currently ignored. "
|
|
|
|
|
"We only support ethernet slaves for now.\n"));
|
|
|
|
|
|
|
|
|
|
/* Change properties in 'connection' setting */
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, master,
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Add ethernet setting */
|
|
|
|
|
s_wired = (NMSettingWired *) nm_setting_wired_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wired));
|
|
|
|
|
|
|
|
|
|
g_free (master_ask);
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'bridge' */
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
char *bridge_ifname = NULL;
|
|
|
|
|
const char *ifname = NULL;
|
|
|
|
|
const char *stp = NULL;
|
|
|
|
|
const char *priority = NULL;
|
|
|
|
|
const char *fwd_delay = NULL;
|
|
|
|
|
const char *hello_time = NULL;
|
|
|
|
|
const char *max_age = NULL;
|
|
|
|
|
const char *ageing_time = NULL;
|
|
|
|
|
gboolean stp_bool;
|
|
|
|
|
unsigned long stp_prio_int, fwd_delay_int, hello_time_int,
|
|
|
|
|
max_age_int, ageing_time_int;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"stp", TRUE, &stp, FALSE},
|
|
|
|
|
{"priority", TRUE, &priority, FALSE},
|
|
|
|
|
{"forward-delay", TRUE, &fwd_delay, FALSE},
|
|
|
|
|
{"hello-time", TRUE, &hello_time, FALSE},
|
|
|
|
|
{"max-age", TRUE, &max_age, FALSE},
|
|
|
|
|
{"ageing-time", TRUE, &ageing_time, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Use connection's ifname as 'bridge' ifname if exists, else generate one */
|
|
|
|
|
ifname = nm_setting_connection_get_interface_name (s_con);
|
|
|
|
|
if (!ifname)
|
|
|
|
|
bridge_ifname = unique_bond_bridge_ifname (all_connections,
|
|
|
|
|
NM_SETTING_BRIDGE_SETTING_NAME,
|
|
|
|
|
"nm-bridge");
|
|
|
|
|
else
|
|
|
|
|
bridge_ifname = g_strdup (ifname);
|
|
|
|
|
|
|
|
|
|
if (stp) {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
if (!nmc_string_to_bool (stp, &stp_bool, &tmp_err)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'stp': %s."), tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add 'bond' setting */
|
|
|
|
|
/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
|
|
|
|
|
s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bridge));
|
|
|
|
|
|
|
|
|
|
if (priority)
|
|
|
|
|
if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_SETTING_BRIDGE_PRIORITY, &stp_prio_int, error))
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
if (fwd_delay)
|
|
|
|
|
if (!bridge_prop_string_to_uint (fwd_delay, "forward-delay", NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_SETTING_BRIDGE_FORWARD_DELAY, &fwd_delay_int, error))
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
if (hello_time)
|
|
|
|
|
if (!bridge_prop_string_to_uint (hello_time, "hello-time", NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_SETTING_BRIDGE_HELLO_TIME, &hello_time_int, error))
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
if (max_age)
|
|
|
|
|
if (!bridge_prop_string_to_uint (max_age, "max-age", NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_SETTING_BRIDGE_MAX_AGE, &max_age_int, error))
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
if (ageing_time)
|
|
|
|
|
if (!bridge_prop_string_to_uint (ageing_time, "ageing-time", NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_SETTING_BRIDGE_AGEING_TIME, &ageing_time_int, error))
|
|
|
|
|
goto cleanup_bridge;
|
|
|
|
|
|
|
|
|
|
/* Set bridge options */
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, bridge_ifname, NULL);
|
|
|
|
|
if (stp)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, stp_bool, NULL);
|
|
|
|
|
if (priority)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_PRIORITY, stp_prio_int, NULL);
|
|
|
|
|
if (fwd_delay)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, fwd_delay_int, NULL);
|
|
|
|
|
if (hello_time)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_HELLO_TIME, hello_time_int, NULL);
|
|
|
|
|
if (max_age)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_MAX_AGE, max_age_int, NULL);
|
|
|
|
|
if (ageing_time)
|
|
|
|
|
g_object_set (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME, ageing_time_int, NULL);
|
|
|
|
|
|
|
|
|
|
success = TRUE;
|
|
|
|
|
cleanup_bridge:
|
|
|
|
|
g_free (bridge_ifname);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, "bridge-slave")) {
|
|
|
|
|
/* Build up the settings required for 'bridge-slave' */
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
const char *master = NULL;
|
|
|
|
|
char *master_ask = NULL;
|
|
|
|
|
const char *type = NULL;
|
|
|
|
|
const char *priority = NULL;
|
|
|
|
|
const char *path_cost = NULL;
|
|
|
|
|
const char *hairpin = NULL;
|
|
|
|
|
unsigned long prio_int, path_cost_int;
|
|
|
|
|
gboolean hairpin_bool;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask},
|
|
|
|
|
{"type", TRUE, &type, FALSE},
|
|
|
|
|
{"priority", TRUE, &priority, FALSE},
|
|
|
|
|
{"path-cost", TRUE, &path_cost, FALSE},
|
|
|
|
|
{"hairpin", TRUE, &hairpin, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!master && ask)
|
|
|
|
|
master = master_ask = nmc_get_user_input (_("Bridge master: "));
|
|
|
|
|
if (!master) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'master' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!nm_utils_is_uuid (master) && !nm_utils_iface_valid_name (master)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'master': '%s' is not valid UUID nor interface."),
|
|
|
|
|
master);
|
|
|
|
|
goto cleanup_bridge_slave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
|
printf (_("Warning: 'type' is currently ignored. "
|
|
|
|
|
"We only support ethernet slaves for now.\n"));
|
|
|
|
|
|
|
|
|
|
/* Add 'bridge-port' setting */
|
|
|
|
|
/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
|
|
|
|
|
s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bridge_port));
|
|
|
|
|
|
|
|
|
|
if (priority)
|
|
|
|
|
if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT,
|
|
|
|
|
NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error))
|
|
|
|
|
goto cleanup_bridge_slave;
|
|
|
|
|
if (path_cost)
|
|
|
|
|
if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT,
|
|
|
|
|
NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error))
|
|
|
|
|
goto cleanup_bridge_slave;
|
|
|
|
|
if (hairpin) {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'hairpin': %s."), tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
goto cleanup_bridge_slave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Change properties in 'connection' setting */
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, master,
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Add ethernet setting */
|
|
|
|
|
s_wired = (NMSettingWired *) nm_setting_wired_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_wired));
|
|
|
|
|
|
|
|
|
|
if (priority)
|
|
|
|
|
g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL);
|
|
|
|
|
if (path_cost)
|
|
|
|
|
g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL);
|
|
|
|
|
if (hairpin)
|
|
|
|
|
g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL);
|
|
|
|
|
|
|
|
|
|
success = TRUE;
|
|
|
|
|
cleanup_bridge_slave:
|
|
|
|
|
g_free (master_ask);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_VPN_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'vpn' */
|
|
|
|
|
const char *valid_vpns[] = { "openvpn", "vpnc", "pptp", "openconnect", "openswan", NULL };
|
|
|
|
|
const char *vpn_type = NULL;
|
|
|
|
|
char *vpn_type_ask = NULL;
|
|
|
|
|
const char *user = NULL;
|
|
|
|
|
const char *st;
|
|
|
|
|
char *service_type;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"vpn-type", TRUE, &vpn_type, !ask},
|
|
|
|
|
{"user", TRUE, &user, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!vpn_type && ask)
|
|
|
|
|
vpn_type = vpn_type_ask = nmc_get_user_input (_("VPN type: "));
|
|
|
|
|
if (!vpn_type) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'vpn-type' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(st = nmc_string_is_valid (vpn_type, valid_vpns, &tmp_err))) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'vpn-type': %s."), tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
g_free (vpn_type_ask);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
service_type = g_strdup_printf ("%s.%s", NM_DBUS_INTERFACE, st);
|
|
|
|
|
|
|
|
|
|
/* Add 'vpn' setting */
|
|
|
|
|
s_vpn = (NMSettingVPN *) nm_setting_vpn_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_vpn));
|
|
|
|
|
|
|
|
|
|
g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, service_type, NULL);
|
|
|
|
|
g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, user, NULL);
|
|
|
|
|
|
|
|
|
|
g_free (vpn_type_ask);
|
|
|
|
|
g_free (service_type);
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp (con_type, NM_SETTING_OLPC_MESH_SETTING_NAME)) {
|
|
|
|
|
/* Build up the settings required for 'olpc' */
|
|
|
|
|
char *ssid_ask = NULL;
|
|
|
|
|
const char *ssid = NULL;
|
|
|
|
|
GByteArray *ssid_arr;
|
|
|
|
|
const char *channel = NULL;
|
|
|
|
|
unsigned long chan;
|
|
|
|
|
const char *dhcp_anycast = NULL;
|
|
|
|
|
GByteArray *array = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !ask},
|
|
|
|
|
{"channel", TRUE, &channel, FALSE},
|
|
|
|
|
{"dhcp-anycast", TRUE, &dhcp_anycast, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!ssid && ask)
|
|
|
|
|
ssid = ssid_ask = nmc_get_user_input (_("SSID: "));
|
|
|
|
|
if (!ssid) {
|
|
|
|
|
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'ssid' is required."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (channel) {
|
|
|
|
|
if (!nmc_string_to_uint (channel, TRUE, 1, 13, &chan)) {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: 'channel': '%s' is not valid; use <1-13>."),
|
|
|
|
|
channel);
|
|
|
|
|
g_free (ssid_ask);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!check_and_convert_mac (dhcp_anycast, &array, ARPHRD_ETHER, "dhcp-anycast", error)) {
|
|
|
|
|
g_free (ssid_ask);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add OLPC mesh setting */
|
|
|
|
|
s_olpc_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_olpc_mesh));
|
|
|
|
|
|
|
|
|
|
ssid_arr = g_byte_array_sized_new (strlen (ssid));
|
|
|
|
|
g_byte_array_append (ssid_arr, (const guint8 *) ssid, strlen (ssid));
|
|
|
|
|
g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_SSID, ssid_arr, NULL);
|
|
|
|
|
if (channel)
|
|
|
|
|
g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_CHANNEL, chan, NULL);
|
|
|
|
|
else
|
|
|
|
|
g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_CHANNEL, 1, NULL);
|
|
|
|
|
if (array) {
|
|
|
|
|
g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, array, NULL);
|
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_byte_array_free (ssid_arr, TRUE);
|
|
|
|
|
g_free (ssid_ask);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
|
|
|
|
_("Error: '%s' is a not valid connection type."),
|
|
|
|
|
con_type);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read and add IP configuration */
|
|
|
|
|
if ( strcmp (con_type, "bond-slave") != 0
|
|
|
|
|
&& strcmp (con_type, "bridge-slave") != 0) {
|
2012-12-04 15:08:14 +01:00
|
|
|
|
|
|
|
|
NMSettingIP4Config *s_ip4 = NULL;
|
|
|
|
|
NMSettingIP6Config *s_ip6 = NULL;
|
|
|
|
|
NMIP4Address *ip4addr = NULL;
|
|
|
|
|
NMIP6Address *ip6addr = NULL;
|
|
|
|
|
gboolean ipv4_added = FALSE;
|
|
|
|
|
gboolean ipv6_added = FALSE;
|
|
|
|
|
const char *ip4 = NULL, *gw4 = NULL, *ip6 = NULL, *gw6 = NULL;
|
2013-04-12 15:26:31 +02:00
|
|
|
nmc_arg_t exp_args[] = { {"ip4", TRUE, &ip4, FALSE}, {"gw4", TRUE, &gw4, FALSE},
|
|
|
|
|
{"ip6", TRUE, &ip6, FALSE}, {"gw6", TRUE, &gw6, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
2012-12-04 15:08:14 +01:00
|
|
|
while (argc) {
|
|
|
|
|
nmc_arg_t *p;
|
|
|
|
|
|
|
|
|
|
/* reset 'found' flag */
|
|
|
|
|
for (p = exp_args; p->name; p++)
|
|
|
|
|
p->found = FALSE;
|
|
|
|
|
|
|
|
|
|
ip4 = gw4 = ip6 = gw6 = NULL;
|
2013-04-12 15:26:31 +02:00
|
|
|
|
2012-12-04 15:08:14 +01:00
|
|
|
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
|
2013-04-12 15:26:31 +02:00
|
|
|
return FALSE;
|
2012-12-04 15:08:14 +01:00
|
|
|
|
|
|
|
|
if (ip4) {
|
|
|
|
|
ip4addr = nmc_parse_and_build_ip4_address (ip4, gw4, error);
|
|
|
|
|
if (!ip4addr) {
|
|
|
|
|
g_prefix_error (error, _("Error: "));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ip4addr) {
|
|
|
|
|
if (!ipv4_added) {
|
|
|
|
|
s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
|
|
|
|
|
g_object_set (s_ip4,
|
|
|
|
|
NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
|
|
|
|
|
NULL);
|
|
|
|
|
ipv4_added = TRUE;
|
|
|
|
|
}
|
|
|
|
|
nm_setting_ip4_config_add_address (s_ip4, ip4addr);
|
|
|
|
|
nm_ip4_address_unref (ip4addr);
|
|
|
|
|
ip4addr = NULL;
|
2013-04-12 15:26:31 +02:00
|
|
|
}
|
|
|
|
|
|
2012-12-04 15:08:14 +01:00
|
|
|
if (ip6) {
|
|
|
|
|
ip6addr = nmc_parse_and_build_ip6_address (ip6, gw6, error);
|
|
|
|
|
if (!ip6addr) {
|
|
|
|
|
g_prefix_error (error, _("Error: "));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ip6addr) {
|
|
|
|
|
if (!ipv6_added) {
|
|
|
|
|
s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_ip6));
|
|
|
|
|
g_object_set (s_ip6,
|
|
|
|
|
NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
|
|
|
|
|
NULL);
|
|
|
|
|
ipv6_added = TRUE;
|
|
|
|
|
}
|
|
|
|
|
nm_setting_ip6_config_add_address (s_ip6, ip6addr);
|
|
|
|
|
nm_ip6_address_unref (ip6addr);
|
|
|
|
|
ip6addr = NULL;
|
2013-04-12 15:26:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
unique_connection_name (GSList *list, const char *try_name)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
const char *name;
|
|
|
|
|
char *new_name;
|
|
|
|
|
unsigned int num = 1;
|
|
|
|
|
GSList *iterator = list;
|
|
|
|
|
|
|
|
|
|
new_name = g_strdup (try_name);
|
|
|
|
|
while (iterator) {
|
|
|
|
|
connection = NM_CONNECTION (iterator->data);
|
|
|
|
|
|
|
|
|
|
name = nm_connection_get_id (connection);
|
|
|
|
|
if (g_strcmp0 (new_name, name) == 0) {
|
|
|
|
|
g_free (new_name);
|
|
|
|
|
new_name = g_strdup_printf ("%s-%d", try_name, num++);
|
|
|
|
|
iterator = list;
|
|
|
|
|
}
|
|
|
|
|
iterator = g_slist_next (iterator);
|
|
|
|
|
}
|
|
|
|
|
return new_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
NmCli *nmc;
|
|
|
|
|
char *con_name;
|
|
|
|
|
} AddConnectionInfo;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_connection_cb (NMRemoteSettings *settings,
|
|
|
|
|
NMRemoteConnection *connection,
|
|
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
AddConnectionInfo *info = (AddConnectionInfo *) user_data;
|
|
|
|
|
NmCli *nmc = info->nmc;
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
g_string_printf (nmc->return_text,
|
|
|
|
|
_("Error: Failed to add '%s' connection: (%d) %s"),
|
|
|
|
|
info->con_name, error->code, error->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
|
|
|
|
} else {
|
|
|
|
|
if (nmc->print_output == NMC_PRINT_PRETTY)
|
|
|
|
|
printf (_("Connection '%s' (%s) successfully added.\n"),
|
|
|
|
|
nm_connection_get_id (NM_CONNECTION (connection)),
|
|
|
|
|
nm_connection_get_uuid (NM_CONNECTION (connection)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (info->con_name);
|
|
|
|
|
g_free (info);
|
|
|
|
|
quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_add (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection = NULL;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
char *uuid;
|
|
|
|
|
char *default_name = NULL;
|
|
|
|
|
const char *type = NULL;
|
|
|
|
|
char *type_ask = NULL;
|
|
|
|
|
const char *con_name = NULL;
|
|
|
|
|
const char *autoconnect = NULL;
|
|
|
|
|
gboolean auto_bool = TRUE;
|
|
|
|
|
const char *ifname = NULL;
|
2013-06-10 15:31:09 +02:00
|
|
|
char *ifname_ask = NULL;
|
|
|
|
|
gboolean ifname_mandatory = TRUE;
|
2013-04-12 15:26:31 +02:00
|
|
|
AddConnectionInfo *info = NULL;
|
|
|
|
|
const char *setting_name;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
nmc_arg_t exp_args[] = { {"type", TRUE, &type, !nmc->ask},
|
|
|
|
|
{"con-name", TRUE, &con_name, FALSE},
|
|
|
|
|
{"autoconnect", TRUE, &autoconnect, FALSE},
|
|
|
|
|
{"ifname", TRUE, &ifname, FALSE},
|
|
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
nmc->return_value = NMC_RESULT_SUCCESS;
|
|
|
|
|
|
|
|
|
|
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
|
|
|
|
|
g_string_assign (nmc->return_text, error->message);
|
|
|
|
|
nmc->return_value = error->code;
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!type && nmc->ask) {
|
|
|
|
|
char *types_tmp = get_valid_options_string (nmc_valid_connection_types);
|
|
|
|
|
printf ("Valid types: [%s]\n", types_tmp);
|
|
|
|
|
type = type_ask = nmc_get_user_input (_("Connection type: "));
|
|
|
|
|
g_free (types_tmp);
|
|
|
|
|
}
|
|
|
|
|
if (!type) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(setting_name = check_valid_name (type, nmc_valid_connection_types, &error))) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: invalid connection type; %s."),
|
|
|
|
|
error->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (autoconnect) {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
if (!nmc_string_to_bool (autoconnect, &auto_bool, &tmp_err)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."),
|
|
|
|
|
tmp_err->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-10 15:31:09 +02:00
|
|
|
|
|
|
|
|
/* ifname is mandatory for all connection types except virtual ones (bond, bridge, vlan) */
|
|
|
|
|
if ( strcmp (type, NM_SETTING_BOND_SETTING_NAME) == 0
|
|
|
|
|
|| strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) == 0
|
|
|
|
|
|| strcmp (type, NM_SETTING_VLAN_SETTING_NAME) == 0)
|
|
|
|
|
ifname_mandatory = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!ifname && ifname_mandatory && nmc->ask)
|
|
|
|
|
ifname = ifname_ask = nmc_get_user_input (_("Interface name: "));
|
|
|
|
|
if (!ifname && ifname_mandatory) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: 'ifname' argument is required."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2013-04-12 15:26:31 +02:00
|
|
|
if (ifname) {
|
2013-06-10 15:31:09 +02:00
|
|
|
if (!nm_utils_iface_valid_name (ifname) && strcmp (ifname, "*") != 0) {
|
2013-04-12 15:26:31 +02:00
|
|
|
g_string_printf (nmc->return_text,
|
2013-06-10 15:31:09 +02:00
|
|
|
_("Error: 'ifname': '%s' is not a valid interface nor '*'."),
|
2013-04-12 15:26:31 +02:00
|
|
|
ifname);
|
2013-06-10 15:31:09 +02:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2013-04-12 15:26:31 +02:00
|
|
|
goto error;
|
|
|
|
|
}
|
2013-06-10 15:31:09 +02:00
|
|
|
/* Special value of '*' means no specific interface name */
|
|
|
|
|
if (strcmp (ifname, "*") == 0)
|
|
|
|
|
ifname = NULL;
|
2013-04-12 15:26:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a new connection object */
|
|
|
|
|
connection = nm_connection_new ();
|
|
|
|
|
|
|
|
|
|
/* Build up the 'connection' setting */
|
|
|
|
|
s_con = (NMSettingConnection *) nm_setting_connection_new ();
|
|
|
|
|
uuid = nm_utils_uuid_generate ();
|
|
|
|
|
if (con_name)
|
|
|
|
|
default_name = g_strdup (con_name);
|
|
|
|
|
else {
|
|
|
|
|
char *try_name = ifname ?
|
|
|
|
|
g_strdup_printf ("%s-%s", get_name_alias (setting_name, nmc_valid_connection_types), ifname)
|
|
|
|
|
: g_strdup (get_name_alias (setting_name, nmc_valid_connection_types));
|
|
|
|
|
default_name = unique_connection_name (nmc->system_connections, try_name);
|
|
|
|
|
g_free (try_name);
|
|
|
|
|
}
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_ID, default_name,
|
|
|
|
|
NM_SETTING_CONNECTION_UUID, uuid,
|
|
|
|
|
NM_SETTING_CONNECTION_TYPE, setting_name,
|
|
|
|
|
NM_SETTING_CONNECTION_AUTOCONNECT, auto_bool,
|
|
|
|
|
NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
|
|
|
|
|
NULL);
|
|
|
|
|
g_free (uuid);
|
|
|
|
|
g_free (default_name);
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_con));
|
|
|
|
|
|
|
|
|
|
if (!complete_connection_by_type (connection,
|
|
|
|
|
setting_name,
|
|
|
|
|
nmc->system_connections,
|
|
|
|
|
nmc->ask,
|
|
|
|
|
argc,
|
|
|
|
|
argv,
|
|
|
|
|
&error)) {
|
|
|
|
|
g_string_assign (nmc->return_text, error->message);
|
|
|
|
|
nmc->return_value = error->code;
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmc->should_wait = TRUE;
|
|
|
|
|
|
|
|
|
|
info = g_malloc0 (sizeof (AddConnectionInfo));
|
|
|
|
|
info->nmc = nmc;
|
|
|
|
|
info->con_name = g_strdup (nm_connection_get_id (connection));
|
|
|
|
|
|
|
|
|
|
/* Tell the settings service to add the new connection */
|
|
|
|
|
nm_remote_settings_add_connection (nmc->system_settings,
|
|
|
|
|
connection,
|
|
|
|
|
add_connection_cb,
|
|
|
|
|
info);
|
|
|
|
|
|
|
|
|
|
if (connection)
|
|
|
|
|
g_object_unref (connection);
|
|
|
|
|
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
if (connection)
|
|
|
|
|
g_object_unref (connection);
|
|
|
|
|
g_free (type_ask);
|
2013-06-10 15:31:09 +02:00
|
|
|
g_free (ifname_ask);
|
2013-04-12 15:26:31 +02:00
|
|
|
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-01-31 19:03:51 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
typedef char * (*ReadLineFunc) (const char *);
|
|
|
|
|
typedef void (*AddHistoryFunc) (const char *);
|
|
|
|
|
typedef int (*RlInsertTextFunc) (char *);
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
ReadLineFunc readline_func;
|
|
|
|
|
AddHistoryFunc add_history_func;
|
|
|
|
|
RlInsertTextFunc rl_insert_text_func;
|
|
|
|
|
void **rl_startup_hook_x;
|
|
|
|
|
} EditLibSymbols;
|
|
|
|
|
|
|
|
|
|
static EditLibSymbols edit_lib_symbols;
|
|
|
|
|
|
|
|
|
|
static GModule *
|
|
|
|
|
load_cmd_line_edit_lib (void)
|
|
|
|
|
{
|
|
|
|
|
GModule *module;
|
|
|
|
|
char *lib_path;
|
|
|
|
|
int i;
|
|
|
|
|
static const char * const edit_lib_table[] = {
|
|
|
|
|
"libreadline.so.6", /* GNU Readline library version 6 - latest */
|
|
|
|
|
"libreadline.so.5", /* GNU Readline library version 5 - previous */
|
|
|
|
|
"libedit.so.0", /* NetBSD Editline library port (http://www.thrysoee.dk/editline/) */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Try to load a library for line editing */
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (edit_lib_table); i++) {
|
|
|
|
|
lib_path = g_module_build_path (NULL, edit_lib_table[i]);
|
|
|
|
|
module = g_module_open (lib_path, G_MODULE_BIND_LOCAL);
|
|
|
|
|
g_free (lib_path);
|
|
|
|
|
if (module)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!module)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (!g_module_symbol (module, "readline", (gpointer) (&edit_lib_symbols.readline_func)))
|
|
|
|
|
goto error;
|
|
|
|
|
if (!g_module_symbol (module, "add_history", (gpointer) (&edit_lib_symbols.add_history_func)))
|
|
|
|
|
goto error;
|
|
|
|
|
if (!g_module_symbol (module, "rl_insert_text", (gpointer) (&edit_lib_symbols.rl_insert_text_func)))
|
|
|
|
|
goto error;
|
|
|
|
|
if (!g_module_symbol (module, "rl_startup_hook", (gpointer) (&edit_lib_symbols.rl_startup_hook_x)))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
return module;
|
|
|
|
|
error:
|
|
|
|
|
g_module_close (module);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
readline_x (const char *prompt)
|
|
|
|
|
{
|
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
|
|
if (edit_lib_symbols.readline_func) {
|
|
|
|
|
str = edit_lib_symbols.readline_func (prompt);
|
|
|
|
|
/* Return NULL, not empty string */
|
|
|
|
|
if (str && *str == '\0') {
|
|
|
|
|
g_free (str);
|
|
|
|
|
str = NULL;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
str = nmc_get_user_input (prompt);
|
|
|
|
|
|
|
|
|
|
if (edit_lib_symbols.add_history_func && str && *str)
|
|
|
|
|
edit_lib_symbols.add_history_func (str);
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
editor_show_connection (NMConnection *connection, NmCli *nmc)
|
|
|
|
|
{
|
|
|
|
|
nmc->print_output = NMC_PRINT_PRETTY;
|
|
|
|
|
nmc->multiline_output = TRUE;
|
|
|
|
|
nmc->escape_values = 0;
|
|
|
|
|
|
|
|
|
|
/* Remove any previous data */
|
|
|
|
|
nmc_empty_output_fields (nmc);
|
|
|
|
|
|
|
|
|
|
nmc_connection_detail (connection, nmc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
editor_show_setting (NMSetting *setting, NmCli *nmc)
|
|
|
|
|
{
|
|
|
|
|
printf (_("['%s' setting values]\n"),
|
|
|
|
|
nm_setting_get_name (setting));
|
|
|
|
|
|
|
|
|
|
nmc->multiline_output = TRUE;
|
|
|
|
|
nmc->escape_values = 0;
|
|
|
|
|
|
|
|
|
|
/* Remove any previous data */
|
|
|
|
|
nmc_empty_output_fields (nmc);
|
|
|
|
|
|
|
|
|
|
setting_details (setting, nmc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_UNKNOWN = 0,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_GOTO,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_SET,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_DESCRIBE,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_PRINT,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_VERIFY,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_SAVE,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_BACK,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_HELP,
|
|
|
|
|
NMC_EDITOR_MAIN_CMD_QUIT,
|
|
|
|
|
} NmcEditorMainCmd;
|
|
|
|
|
|
|
|
|
|
static NmcEditorMainCmd
|
|
|
|
|
parse_editor_main_cmd (const char *cmd, char **cmd_arg)
|
|
|
|
|
{
|
|
|
|
|
NmcEditorMainCmd editor_cmd = NMC_EDITOR_MAIN_CMD_UNKNOWN;
|
|
|
|
|
char **vec;
|
|
|
|
|
|
|
|
|
|
vec = g_strsplit_set (cmd, " \t", 2);
|
|
|
|
|
if (g_strv_length (vec) < 1) {
|
|
|
|
|
if (cmd_arg)
|
|
|
|
|
*cmd_arg = NULL;
|
|
|
|
|
return NMC_EDITOR_MAIN_CMD_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (matches (vec[0], "goto") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_GOTO;
|
|
|
|
|
else if (matches (vec[0], "set") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_SET;
|
|
|
|
|
else if (matches (vec[0], "describe") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_DESCRIBE;
|
|
|
|
|
else if (matches (vec[0], "print") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_PRINT;
|
|
|
|
|
else if (matches (vec[0], "verify") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_VERIFY;
|
|
|
|
|
else if (matches (vec[0], "save") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_SAVE;
|
|
|
|
|
else if (matches (vec[0], "back") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_BACK;
|
|
|
|
|
else if (matches (vec[0], "help") == 0 || strcmp (vec[0], "?") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_HELP;
|
|
|
|
|
else if (matches (vec[0], "quit") == 0)
|
|
|
|
|
editor_cmd = NMC_EDITOR_MAIN_CMD_QUIT;
|
|
|
|
|
|
|
|
|
|
/* set pointer to command argument */
|
|
|
|
|
if (cmd_arg)
|
|
|
|
|
*cmd_arg = g_strdup (vec[1]);
|
|
|
|
|
|
|
|
|
|
g_strfreev (vec);
|
|
|
|
|
return editor_cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
editor_main_usage (void)
|
|
|
|
|
{
|
|
|
|
|
printf ("------------------------------------------------------------------------------\n");
|
|
|
|
|
/* TRANSLATORS: do not translate command names and keywords before ::
|
|
|
|
|
* However, you should translate terms enclosed in <>.
|
|
|
|
|
*/
|
|
|
|
|
printf (_("---[ Main menu ]---\n"
|
|
|
|
|
"goto [<setting> | <prop>] :: go to a setting or property\n"
|
|
|
|
|
"set [<setting>.<prop> <value>] :: set property value\n"
|
|
|
|
|
"describe [<setting>.<prop>] :: describe property\n"
|
|
|
|
|
"print [all] :: print the connection\n"
|
|
|
|
|
"verify [all] :: verify the connection\n"
|
|
|
|
|
"save :: save the connection\n"
|
|
|
|
|
"back :: go one level up (back)\n"
|
|
|
|
|
"help/? [<command>] :: print this help\n"
|
|
|
|
|
"quit :: exit nmcli\n"));
|
|
|
|
|
printf ("------------------------------------------------------------------------------\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
editor_main_help (const char *command)
|
|
|
|
|
{
|
|
|
|
|
if (!command)
|
|
|
|
|
editor_main_usage ();
|
|
|
|
|
else {
|
|
|
|
|
/* detailed command descriptions */
|
|
|
|
|
NmcEditorMainCmd cmd = parse_editor_main_cmd (command, NULL);
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_GOTO:
|
|
|
|
|
printf (_("goto <setting>[.<prop>] | <prop> :: enter setting/property for editation\n\n"
|
|
|
|
|
"This command enters into a setting or property for editing it.\n\n"
|
|
|
|
|
"Examples: nmcli> goto connection\n"
|
|
|
|
|
" nmcli connection> goto secondaries\n"
|
|
|
|
|
" nmcli> goto ipv4.addresses\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_SET:
|
|
|
|
|
printf (_("set [<setting>.<prop> <value>] :: set property value\n\n"
|
|
|
|
|
"This command sets property value.\n\n"
|
|
|
|
|
"Example: nmcli> s con.id My connection\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_DESCRIBE:
|
|
|
|
|
printf (_("describe [<setting>.<prop>] :: describe property\n\n"
|
|
|
|
|
"Shows property description. You can consult nm-settings(5) "
|
|
|
|
|
"manual page to see all NM settings and properties.\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_PRINT:
|
|
|
|
|
printf (_("print [all] :: print setting or connection values\n\n"
|
|
|
|
|
"Shows current property or the whole connection.\n\n"
|
|
|
|
|
"Example: nmcli ipv4> print all\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_VERIFY:
|
|
|
|
|
printf (_("verify [all] :: verify setting or connection validity\n\n"
|
|
|
|
|
"Verifies whether the setting or connection is valid and can "
|
|
|
|
|
"be saved later. It indicates invalid values on error.\n\n"
|
|
|
|
|
"Examples: nmcli> verify\n"
|
|
|
|
|
" nmcli bond> verify\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_SAVE:
|
|
|
|
|
printf (_("save :: save the connection\n\n"
|
|
|
|
|
"Sends the connection to NetworkManager that will save it.\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_BACK:
|
|
|
|
|
printf (_("back :: go to upper menu level\n\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_HELP:
|
|
|
|
|
printf (_("help/? [<command>] :: help for the nmcli commands\n\n"));
|
|
|
|
|
break;
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_QUIT:
|
|
|
|
|
printf (_("quit :: exit nmcli\n\n"
|
|
|
|
|
"This command exits nmcli. When the connection being edited "
|
|
|
|
|
"is not saved, the user is asked to confirm the action.\n"));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf (_("Unknown command: '%s'\n"), command);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Split 'str' in the following format: [[[setting.]property] [value]]
|
|
|
|
|
* and return the components in 'setting', 'property' and 'value'
|
|
|
|
|
* Use g_free() to deallocate the returned strings.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
split_editor_main_cmd_args (const char *str, char **setting, char **property, char **value)
|
|
|
|
|
{
|
|
|
|
|
char **args, **items;
|
|
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
args = g_strsplit_set (str, " \t", 2);
|
|
|
|
|
if (args[0]) {
|
|
|
|
|
items = g_strsplit_set (args[0], ".", 2);
|
|
|
|
|
if (g_strv_length (items) == 2) {
|
|
|
|
|
if (setting)
|
|
|
|
|
*setting = g_strdup (items[0]);
|
|
|
|
|
if (property)
|
|
|
|
|
*property = g_strdup (items[1]);
|
|
|
|
|
} else {
|
|
|
|
|
if (property)
|
|
|
|
|
*property = g_strdup (items[0]);
|
|
|
|
|
}
|
|
|
|
|
g_strfreev (items);
|
|
|
|
|
|
|
|
|
|
if (value && args[1])
|
|
|
|
|
*value = g_strdup (args[1]);
|
|
|
|
|
}
|
|
|
|
|
g_strfreev (args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMSetting *
|
|
|
|
|
is_setting_valid (NMConnection *connection, const NameItem *valid_settings, char *setting)
|
|
|
|
|
{
|
|
|
|
|
const char *setting_name;
|
|
|
|
|
|
|
|
|
|
if (!(setting_name = check_valid_name (setting, valid_settings, NULL)))
|
|
|
|
|
return NULL;
|
|
|
|
|
return nm_connection_get_setting_by_name (connection, setting_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
is_property_valid (NMSetting *setting, const char *property, GError **error)
|
|
|
|
|
{
|
|
|
|
|
char **valid_props = NULL;
|
|
|
|
|
const char *prop_name;
|
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
|
|
valid_props = nmc_setting_get_valid_properties (setting);
|
|
|
|
|
prop_name = nmc_string_is_valid (property, (const char **) valid_props, error);
|
|
|
|
|
ret = prop_name ? g_strdup (prop_name) : NULL;
|
|
|
|
|
g_strfreev (valid_props);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMSetting *
|
|
|
|
|
create_setting_by_name (const char *name, const NameItem *valid_settings)
|
|
|
|
|
{
|
|
|
|
|
const char *setting_name;
|
|
|
|
|
NMSetting *setting = NULL;
|
|
|
|
|
|
|
|
|
|
/* Get a valid setting name */
|
|
|
|
|
setting_name = check_valid_name (name, valid_settings, NULL);
|
|
|
|
|
|
|
|
|
|
if (setting_name) {
|
|
|
|
|
NmcSettingNewFunc new_setting_func = nmc_setting_new_func (setting_name);
|
|
|
|
|
if (!new_setting_func)
|
|
|
|
|
return NULL; /* This should really not happen */
|
|
|
|
|
setting = new_setting_func ();
|
|
|
|
|
nmc_setting_custom_init (setting);
|
|
|
|
|
}
|
|
|
|
|
return setting;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
ask_check_setting (const char *arg,
|
|
|
|
|
const NameItem *valid_settings_arr,
|
|
|
|
|
const char *valid_settings_str)
|
|
|
|
|
{
|
|
|
|
|
char *setting_name_user;
|
|
|
|
|
const char *setting_name;
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
|
printf (_("Available settings: %s\n"), valid_settings_str);
|
|
|
|
|
setting_name_user = nmc_get_user_input (EDITOR_PROMPT_SETTING);
|
|
|
|
|
} else
|
|
|
|
|
setting_name_user = g_strdup (arg);
|
|
|
|
|
|
|
|
|
|
if (setting_name_user)
|
|
|
|
|
g_strstrip (setting_name_user);
|
|
|
|
|
|
|
|
|
|
if (!(setting_name = check_valid_name (setting_name_user, valid_settings_arr, &err))) {
|
|
|
|
|
printf (_("Error: invalid setting name; %s\n"), err->message);
|
|
|
|
|
g_clear_error (&err);
|
|
|
|
|
}
|
|
|
|
|
g_free (setting_name_user);
|
|
|
|
|
return setting_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
ask_check_property (const char *arg,
|
|
|
|
|
const char **valid_props,
|
|
|
|
|
const char *valid_props_str)
|
|
|
|
|
{
|
|
|
|
|
char *prop_name_user;
|
|
|
|
|
const char *prop_name;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
|
printf (_("Available properties: %s\n"), valid_props_str);
|
2013-01-31 19:03:51 +01:00
|
|
|
prop_name_user = readline_x (EDITOR_PROMPT_PROPERTY);
|
2013-01-18 15:21:00 +01:00
|
|
|
} else
|
|
|
|
|
prop_name_user = g_strdup (arg);
|
|
|
|
|
|
|
|
|
|
if (!(prop_name = nmc_string_is_valid (prop_name_user, valid_props, &tmp_err))) {
|
|
|
|
|
printf (_("Error: property %s\n"), tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
g_free (prop_name_user);
|
|
|
|
|
return prop_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
guint level;
|
|
|
|
|
char *main_prompt;
|
|
|
|
|
NMSetting *curr_setting;
|
|
|
|
|
char **valid_props;
|
|
|
|
|
char *valid_props_str;
|
|
|
|
|
} NmcEditorMenuContext;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
menu_switch_to_level0 (NmcEditorMenuContext *menu_ctx,
|
|
|
|
|
const char *prompt)
|
|
|
|
|
{
|
|
|
|
|
menu_ctx->level = 0;
|
|
|
|
|
g_free (menu_ctx->main_prompt);
|
|
|
|
|
menu_ctx->main_prompt = g_strdup (prompt);
|
|
|
|
|
menu_ctx->curr_setting = NULL;
|
|
|
|
|
g_strfreev (menu_ctx->valid_props);
|
|
|
|
|
menu_ctx->valid_props = NULL;
|
|
|
|
|
g_free (menu_ctx->valid_props_str);
|
|
|
|
|
menu_ctx->valid_props_str = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
menu_switch_to_level1 (NmcEditorMenuContext *menu_ctx,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *setting_name)
|
|
|
|
|
{
|
|
|
|
|
menu_ctx->level = 1;
|
|
|
|
|
g_free (menu_ctx->main_prompt);
|
|
|
|
|
menu_ctx->main_prompt = g_strdup_printf ("nmcli %s> ", setting_name);
|
|
|
|
|
menu_ctx->curr_setting = setting;
|
|
|
|
|
g_strfreev (menu_ctx->valid_props);
|
|
|
|
|
menu_ctx->valid_props = nmc_setting_get_valid_properties (menu_ctx->curr_setting);
|
|
|
|
|
g_free (menu_ctx->valid_props_str);
|
|
|
|
|
menu_ctx->valid_props_str = g_strjoinv (", ", menu_ctx->valid_props);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_property_description (NMSetting *setting, const char *prop_name)
|
|
|
|
|
{
|
|
|
|
|
char *desc;
|
|
|
|
|
|
|
|
|
|
desc = nmc_setting_get_property_desc (setting, prop_name);
|
|
|
|
|
printf ("\n=== [%s] ===\n%s\n", prop_name, desc);
|
|
|
|
|
g_free (desc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_setting_description (NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
/* Show description of all properties */
|
|
|
|
|
char **all_props;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
all_props = nmc_setting_get_valid_properties (setting);
|
|
|
|
|
printf (("<<< %s >>>\n"), nm_setting_get_name (setting));
|
|
|
|
|
for (i = 0; all_props && all_props[i]; i++)
|
|
|
|
|
print_property_description (setting, all_props[i]);
|
|
|
|
|
g_strfreev (all_props);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_type)
|
|
|
|
|
{
|
|
|
|
|
NmcEditorMainCmd cmd;
|
|
|
|
|
char *cmd_user;
|
|
|
|
|
gboolean cmd_loop = TRUE;
|
|
|
|
|
char *cmd_arg = NULL;
|
|
|
|
|
char *cmd_arg_s, *cmd_arg_p, *cmd_arg_v;
|
|
|
|
|
const char *BASE_PROMPT = "nmcli> ";
|
|
|
|
|
NmcSettingNewFunc new_func;
|
|
|
|
|
const NameItem *valid_settings_arr = NULL;
|
|
|
|
|
char *valid_settings_str = NULL;
|
|
|
|
|
AddConnectionInfo *info = NULL;
|
|
|
|
|
char *tmp_str;
|
|
|
|
|
GError *err1 = NULL;
|
|
|
|
|
NmcEditorMenuContext menu_ctx;
|
|
|
|
|
|
|
|
|
|
valid_settings_arr = get_valid_settings_array (connection_type);
|
|
|
|
|
valid_settings_str = get_valid_options_string (valid_settings_arr);
|
|
|
|
|
printf (_("You may edit the following settings: %s\n"), valid_settings_str);
|
|
|
|
|
|
|
|
|
|
menu_ctx.level = 0;
|
|
|
|
|
menu_ctx.main_prompt = g_strdup (BASE_PROMPT);
|
|
|
|
|
menu_ctx.curr_setting = NULL;
|
|
|
|
|
menu_ctx.valid_props = NULL;
|
|
|
|
|
menu_ctx.valid_props_str = NULL;
|
|
|
|
|
|
|
|
|
|
while (cmd_loop) {
|
2013-01-31 19:03:51 +01:00
|
|
|
cmd_user = readline_x (menu_ctx.main_prompt);
|
|
|
|
|
if (!cmd_user || *cmd_user == '\0')
|
2013-01-18 15:21:00 +01:00
|
|
|
continue;
|
|
|
|
|
cmd = parse_editor_main_cmd (g_strstrip (cmd_user), &cmd_arg);
|
|
|
|
|
|
|
|
|
|
cmd_arg_s = NULL;
|
|
|
|
|
cmd_arg_p = NULL;
|
|
|
|
|
cmd_arg_v = NULL;
|
|
|
|
|
split_editor_main_cmd_args (cmd_arg, &cmd_arg_s, &cmd_arg_p, &cmd_arg_v);
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_SET:
|
|
|
|
|
/* Set property value */
|
|
|
|
|
if (!cmd_arg) {
|
|
|
|
|
if (menu_ctx.level == 1) {
|
|
|
|
|
const char *prop_name;
|
|
|
|
|
char *prop_val_user = NULL;
|
|
|
|
|
char *tmp_prompt;
|
|
|
|
|
const char *avals;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
|
|
|
|
|
prop_name = ask_check_property (cmd_arg,
|
|
|
|
|
(const char **) menu_ctx.valid_props,
|
|
|
|
|
menu_ctx.valid_props_str);
|
|
|
|
|
if (!prop_name)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
avals = nmc_setting_get_property_allowed_values (menu_ctx.curr_setting, prop_name);
|
|
|
|
|
if (avals)
|
|
|
|
|
printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
|
|
|
|
|
|
|
|
|
|
tmp_prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
|
2013-01-31 19:03:51 +01:00
|
|
|
prop_val_user = readline_x (tmp_prompt);
|
2013-01-18 15:21:00 +01:00
|
|
|
g_free (tmp_prompt);
|
|
|
|
|
|
|
|
|
|
/* Set property value */
|
|
|
|
|
if (!nmc_setting_set_property (menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) {
|
|
|
|
|
printf (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
printf (_("Error: no setting selected; valid are [%s]\n"), valid_settings_str);
|
|
|
|
|
printf (_("use 'goto <setting>' first, or 'set <setting>.<property>'\n"));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NMSetting *ss = NULL;
|
|
|
|
|
gboolean created_ss = FALSE;
|
|
|
|
|
char *prop_name;
|
|
|
|
|
char *tmp_prompt;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
|
|
|
|
|
if (cmd_arg_s) {
|
|
|
|
|
/* setting provided as "setting.property" */
|
|
|
|
|
ss = is_setting_valid (connection, valid_settings_arr, cmd_arg_s);
|
|
|
|
|
if (!ss) {
|
|
|
|
|
ss = create_setting_by_name (cmd_arg_s, valid_settings_arr);
|
|
|
|
|
if (!ss) {
|
|
|
|
|
printf (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
|
|
|
|
|
cmd_arg_s, valid_settings_str);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
created_ss = TRUE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (menu_ctx.curr_setting)
|
|
|
|
|
ss = menu_ctx.curr_setting;
|
|
|
|
|
else {
|
|
|
|
|
printf (_("Error: missing setting for '%s' property\n"), cmd_arg_p);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err);
|
|
|
|
|
if (!prop_name) {
|
|
|
|
|
printf (_("Error: invalid property: %s\n"), tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
if (created_ss)
|
|
|
|
|
g_object_unref (ss);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Ask for value */
|
|
|
|
|
if (!cmd_arg_v) {
|
|
|
|
|
const char *avals = nmc_setting_get_property_allowed_values (ss, prop_name);
|
|
|
|
|
if (avals)
|
|
|
|
|
printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
|
|
|
|
|
|
|
|
|
|
tmp_prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
|
2013-01-31 19:03:51 +01:00
|
|
|
cmd_arg_v = readline_x (tmp_prompt);
|
2013-01-18 15:21:00 +01:00
|
|
|
g_free (tmp_prompt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set property value */
|
|
|
|
|
if (!nmc_setting_set_property (ss, prop_name, cmd_arg_v, &tmp_err)) {
|
|
|
|
|
printf (_("Error: failed to set '%s' property: %s\n"),
|
|
|
|
|
prop_name, tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (created_ss)
|
|
|
|
|
nm_connection_add_setting (connection, ss);
|
|
|
|
|
g_free (prop_name);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_GOTO:
|
|
|
|
|
/* cmd_arg_s != NULL means 'setting.property' argument */
|
|
|
|
|
if (menu_ctx.level == 0 || cmd_arg_s) {
|
|
|
|
|
/* in top level - no setting selected yet */
|
|
|
|
|
const char *setting_name;
|
|
|
|
|
NMSetting *setting;
|
|
|
|
|
const char *user_arg = cmd_arg_s ? cmd_arg_s : cmd_arg_p;
|
|
|
|
|
|
|
|
|
|
setting_name = ask_check_setting (user_arg, valid_settings_arr, valid_settings_str);
|
|
|
|
|
if (!setting_name)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
setting = nm_connection_get_setting_by_name (connection, setting_name);
|
|
|
|
|
if (!setting) {
|
|
|
|
|
/* setting not created yet, do it now */
|
|
|
|
|
new_func = nmc_setting_new_func (setting_name);
|
|
|
|
|
if (!new_func) {
|
|
|
|
|
printf (_("Error: unknown setting '%s'\n"), setting_name);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
setting = new_func ();
|
|
|
|
|
nmc_setting_custom_init (setting);
|
|
|
|
|
nm_connection_add_setting (connection, setting);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Switch to level 1 */
|
|
|
|
|
menu_switch_to_level1 (&menu_ctx, setting, setting_name);
|
|
|
|
|
|
|
|
|
|
if (!cmd_arg_s) {
|
|
|
|
|
printf (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (menu_ctx.level == 1 || cmd_arg_s) {
|
|
|
|
|
/* level 1 - setting selected */
|
|
|
|
|
char *prop_val_user = NULL;
|
|
|
|
|
const char *prop_name;
|
|
|
|
|
char *prompt;
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
gboolean set_result;
|
|
|
|
|
|
|
|
|
|
prop_name = ask_check_property (cmd_arg_p,
|
|
|
|
|
(const char **) menu_ctx.valid_props,
|
|
|
|
|
menu_ctx.valid_props_str);
|
|
|
|
|
if (!prop_name)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
prompt = g_strdup_printf (_("Enter '%s' value: "), prop_name);
|
2013-01-31 19:03:51 +01:00
|
|
|
prop_val_user = readline_x (prompt);
|
2013-01-18 15:21:00 +01:00
|
|
|
g_free (prompt);
|
|
|
|
|
|
|
|
|
|
set_result = nmc_setting_set_property (menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err);
|
|
|
|
|
g_free (prop_val_user);
|
|
|
|
|
if (!set_result) {
|
|
|
|
|
fprintf (stdout, _("Error: property '%s' set failure: %s\n"), prop_name, tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_DESCRIBE:
|
|
|
|
|
/* Print property description */
|
|
|
|
|
if (!cmd_arg) {
|
|
|
|
|
if (menu_ctx.level == 1) {
|
|
|
|
|
const char *prop_name;
|
|
|
|
|
|
|
|
|
|
prop_name = ask_check_property (cmd_arg,
|
|
|
|
|
(const char **) menu_ctx.valid_props,
|
|
|
|
|
menu_ctx.valid_props_str);
|
|
|
|
|
if (!prop_name)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Show property description */
|
|
|
|
|
print_property_description (menu_ctx.curr_setting, prop_name);
|
|
|
|
|
} else {
|
|
|
|
|
printf (_("Error: no setting selected; valid are [%s]\n"), valid_settings_str);
|
|
|
|
|
printf (_("use 'goto <setting>' first, or 'describe <setting>.<property>'\n"));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NMSetting *ss = NULL;
|
|
|
|
|
gboolean unref_ss = FALSE;
|
|
|
|
|
gboolean descr_all;
|
|
|
|
|
char *user_s;
|
|
|
|
|
|
|
|
|
|
/* cmd_arg_s != NULL means argument is "setting.property" */
|
|
|
|
|
descr_all = !cmd_arg_s && !menu_ctx.curr_setting;
|
|
|
|
|
user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
|
|
|
|
|
if (user_s) {
|
|
|
|
|
ss = is_setting_valid (connection, valid_settings_arr, user_s);
|
|
|
|
|
if (!ss) {
|
|
|
|
|
ss = create_setting_by_name (user_s, valid_settings_arr);
|
|
|
|
|
if (!ss) {
|
|
|
|
|
printf (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
|
|
|
|
|
user_s, valid_settings_str);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
unref_ss = TRUE;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
ss = menu_ctx.curr_setting;
|
|
|
|
|
|
|
|
|
|
if (descr_all) {
|
|
|
|
|
/* Show description for all properties */
|
|
|
|
|
print_setting_description (ss);
|
|
|
|
|
} else {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
char *prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err);
|
|
|
|
|
if (prop_name) {
|
|
|
|
|
/* Show property description */
|
|
|
|
|
print_property_description (ss, prop_name);
|
|
|
|
|
} else {
|
|
|
|
|
/* If the string is not a property, try it as a setting */
|
|
|
|
|
NMSetting *s_tmp;
|
|
|
|
|
s_tmp = is_setting_valid (connection, valid_settings_arr, cmd_arg_p);
|
|
|
|
|
if (s_tmp)
|
|
|
|
|
print_setting_description (s_tmp);
|
|
|
|
|
else
|
|
|
|
|
printf (_("Error: invalid property: %s, "
|
|
|
|
|
"neither a valid setting name.\n"),
|
|
|
|
|
tmp_err->message);
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
g_free (prop_name);
|
|
|
|
|
}
|
|
|
|
|
if (unref_ss)
|
|
|
|
|
g_object_unref (ss);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_PRINT:
|
|
|
|
|
/* Print current connection settings/properties */
|
|
|
|
|
if (cmd_arg) {
|
|
|
|
|
if (strcmp (cmd_arg, "all") == 0)
|
|
|
|
|
editor_show_connection (connection, nmc);
|
|
|
|
|
else {
|
|
|
|
|
const char *s = check_valid_name (cmd_arg, valid_settings_arr, NULL);
|
|
|
|
|
if (s) {
|
|
|
|
|
NMSetting *ss = nm_connection_get_setting_by_name (connection, s);
|
|
|
|
|
if (ss)
|
|
|
|
|
editor_show_setting (ss, nmc);
|
|
|
|
|
else
|
|
|
|
|
printf (_("Error: '%s' setting not present\n"), s);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
printf (_("Error: unknown setting: '%s'\n"), cmd_arg);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (menu_ctx.curr_setting)
|
|
|
|
|
editor_show_setting (menu_ctx.curr_setting, nmc);
|
|
|
|
|
else
|
|
|
|
|
editor_show_connection (connection, nmc);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_VERIFY:
|
|
|
|
|
/* Verify current setting or the whole connection */
|
|
|
|
|
if ( menu_ctx.curr_setting
|
|
|
|
|
&& (!cmd_arg || strcmp (cmd_arg, "all") != 0)) {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
nm_setting_verify (menu_ctx.curr_setting, NULL, &tmp_err);
|
|
|
|
|
printf (_("Verify setting '%s': %s\n"),
|
|
|
|
|
nm_setting_get_name (menu_ctx.curr_setting),
|
|
|
|
|
tmp_err ? tmp_err->message : "OK");
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
} else {
|
|
|
|
|
GError *tmp_err = NULL;
|
|
|
|
|
nm_connection_verify (connection, &tmp_err);
|
|
|
|
|
printf (_("Verify connection: %s\n"),
|
|
|
|
|
tmp_err ? tmp_err->message : "OK");
|
|
|
|
|
g_clear_error (&tmp_err);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_SAVE:
|
|
|
|
|
/* Save the connection */
|
|
|
|
|
if (nm_connection_verify (connection, &err1)) {
|
|
|
|
|
info = g_malloc0 (sizeof (AddConnectionInfo));
|
|
|
|
|
info->nmc = nmc;
|
|
|
|
|
info->con_name = g_strdup (nm_connection_get_id (connection));
|
|
|
|
|
//info->device = device;
|
|
|
|
|
|
|
|
|
|
/* Tell the settings service to add the new connection */
|
|
|
|
|
nm_remote_settings_add_connection (nmc->system_settings,
|
|
|
|
|
connection,
|
|
|
|
|
add_connection_cb,
|
|
|
|
|
info);
|
|
|
|
|
|
|
|
|
|
// FIXME: we should run cmd loop in a thread of something,
|
|
|
|
|
// because the current way blocks glib main loop, and thus D-Bus
|
|
|
|
|
// callbacks (and all other events) can't be processed !!!
|
|
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
printf (_("Error: connection verification failed: %s\n"),
|
|
|
|
|
err1 ? err1->message : _("(unknown)"));
|
|
|
|
|
|
|
|
|
|
g_clear_error (&err1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_BACK:
|
|
|
|
|
/* Go back (up) an the menu */
|
|
|
|
|
if (menu_ctx.level == 1) {
|
|
|
|
|
menu_switch_to_level0 (&menu_ctx, BASE_PROMPT);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_HELP:
|
|
|
|
|
/* Print command help */
|
|
|
|
|
editor_main_help (cmd_arg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_QUIT:
|
|
|
|
|
do {
|
|
|
|
|
tmp_str = nmc_get_user_input (_("Do you really want to quit? [y/n]\n"));
|
|
|
|
|
} while (!tmp_str);
|
|
|
|
|
if (matches (tmp_str, "yes") == 0)
|
|
|
|
|
cmd_loop = FALSE; /* quit command loop */
|
|
|
|
|
g_free (tmp_str);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMC_EDITOR_MAIN_CMD_UNKNOWN:
|
|
|
|
|
default:
|
|
|
|
|
printf (_("Unknown command: '%s'\n"), cmd_user);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (cmd_user);
|
|
|
|
|
g_free (cmd_arg);
|
|
|
|
|
g_free (cmd_arg_s);
|
|
|
|
|
g_free (cmd_arg_p);
|
|
|
|
|
g_free (cmd_arg_v);
|
|
|
|
|
}
|
|
|
|
|
g_free (valid_settings_str);
|
|
|
|
|
g_free (menu_ctx.main_prompt);
|
|
|
|
|
g_strfreev (menu_ctx.valid_props);
|
|
|
|
|
g_free (menu_ctx.valid_props_str);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
get_ethernet_device_name (NmCli *nmc)
|
|
|
|
|
{
|
|
|
|
|
const GPtrArray *devices;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
nmc->get_client (nmc);
|
|
|
|
|
devices = nm_client_get_devices (nmc->client);
|
|
|
|
|
for (i = 0; devices && (i < devices->len); i++) {
|
|
|
|
|
NMDevice *dev = g_ptr_array_index (devices, i);
|
|
|
|
|
if (NM_IS_DEVICE_ETHERNET (dev))
|
|
|
|
|
return nm_device_get_iface (dev);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
editor_init_new_connection (NmCli *nmc, NMConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
NmcSettingNewFunc new_func;
|
|
|
|
|
NMSetting *setting;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const char *con_type;
|
|
|
|
|
const char *slave_type = NULL;
|
|
|
|
|
|
|
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
|
|
|
|
g_assert (s_con);
|
|
|
|
|
con_type = nm_setting_connection_get_connection_type (s_con);
|
|
|
|
|
|
|
|
|
|
// TODO: properly initialize connection according to its type,
|
|
|
|
|
// use sensible defaults.
|
|
|
|
|
// This function is still a stub.
|
|
|
|
|
|
|
|
|
|
if (g_strcmp0 (con_type, "bond-slave") == 0)
|
|
|
|
|
slave_type = NM_SETTING_BOND_SETTING_NAME;
|
|
|
|
|
if (g_strcmp0 (con_type, "bridge-slave") == 0)
|
|
|
|
|
slave_type = NM_SETTING_BRIDGE_SETTING_NAME;
|
|
|
|
|
|
|
|
|
|
if (slave_type) {
|
|
|
|
|
const char *dev_ifname = get_ethernet_device_name (nmc);
|
|
|
|
|
|
|
|
|
|
/* For bond/bridge slaves add 'wired' setting */
|
|
|
|
|
setting = nm_setting_wired_new ();
|
|
|
|
|
nm_connection_add_setting (connection, setting);
|
|
|
|
|
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, dev_ifname ? dev_ifname : "eth0",
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Add a "base" setting to the connection by default */
|
|
|
|
|
new_func = nmc_setting_new_func (con_type);
|
|
|
|
|
if (!new_func)
|
|
|
|
|
return;
|
|
|
|
|
setting = new_func ();
|
|
|
|
|
if (!setting)
|
|
|
|
|
return;
|
|
|
|
|
nm_connection_add_setting (connection, setting);
|
|
|
|
|
|
|
|
|
|
/* Set a sensible bond/bridge interface name by default */
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_BOND_SETTING_NAME) == 0)
|
|
|
|
|
g_object_set (NM_SETTING_BOND (setting),
|
|
|
|
|
NM_SETTING_BOND_INTERFACE_NAME, "nm-bond",
|
|
|
|
|
NULL);
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_BRIDGE_SETTING_NAME) == 0)
|
|
|
|
|
g_object_set (NM_SETTING_BRIDGE (setting),
|
|
|
|
|
NM_SETTING_BRIDGE_INTERFACE_NAME, "nm-bridge",
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Set sensible initial VLAN values */
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_VLAN_SETTING_NAME) == 0) {
|
|
|
|
|
const char *dev_ifname = get_ethernet_device_name (nmc);
|
|
|
|
|
|
|
|
|
|
g_object_set (NM_SETTING_VLAN (setting),
|
|
|
|
|
NM_SETTING_VLAN_PARENT, dev_ifname ? dev_ifname : "eth0",
|
|
|
|
|
NM_SETTING_VLAN_ID, 1,
|
|
|
|
|
NULL);
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, dev_ifname ? dev_ifname : "eth0",
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize 'transport-mode' so that 'infiniband' is valid */
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_INFINIBAND_SETTING_NAME) == 0)
|
|
|
|
|
g_object_set (NM_SETTING_INFINIBAND (setting),
|
|
|
|
|
NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Initialize 'number' so that 'cdma' is valid */
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_CDMA_SETTING_NAME) == 0)
|
|
|
|
|
g_object_set (NM_SETTING_CDMA (setting),
|
|
|
|
|
NM_SETTING_CDMA_NUMBER, "#777",
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Initialize 'number' so that 'gsm' is valid */
|
|
|
|
|
if (g_strcmp0 (con_type, NM_SETTING_GSM_SETTING_NAME) == 0)
|
|
|
|
|
g_object_set (NM_SETTING_GSM (setting),
|
|
|
|
|
NM_SETTING_GSM_NUMBER, "*99#",
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_edit (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection = NULL;
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const char *connection_type;
|
|
|
|
|
char *uuid;
|
|
|
|
|
char *default_name = NULL;
|
|
|
|
|
const char *type = NULL;
|
|
|
|
|
char *type_ask = NULL;
|
|
|
|
|
const char *con_name = NULL;
|
2013-04-19 21:06:20 +02:00
|
|
|
const char *con = NULL;
|
|
|
|
|
const char *con_id = NULL;
|
|
|
|
|
const char *con_uuid = NULL;
|
|
|
|
|
const char *con_path = NULL;
|
|
|
|
|
const char *selector = NULL;
|
2013-01-18 15:21:00 +01:00
|
|
|
char *tmp_str;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GError *err1 = NULL;
|
2013-01-31 19:03:51 +01:00
|
|
|
GModule *edit_lib_module = NULL;
|
2013-01-18 15:21:00 +01:00
|
|
|
nmc_arg_t exp_args[] = { {"type", TRUE, &type, FALSE},
|
|
|
|
|
{"con-name", TRUE, &con_name, FALSE},
|
2013-04-19 21:06:20 +02:00
|
|
|
{"id", TRUE, &con_id, FALSE},
|
|
|
|
|
{"uuid", TRUE, &con_uuid, FALSE},
|
|
|
|
|
{"path", TRUE, &con_path, FALSE},
|
2013-01-18 15:21:00 +01:00
|
|
|
{NULL} };
|
|
|
|
|
|
|
|
|
|
nmc->return_value = NMC_RESULT_SUCCESS;
|
|
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
if (argc == 1)
|
|
|
|
|
con = *argv;
|
|
|
|
|
else {
|
|
|
|
|
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) {
|
|
|
|
|
g_string_assign (nmc->return_text, error->message);
|
|
|
|
|
nmc->return_value = error->code;
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2013-01-18 15:21:00 +01:00
|
|
|
}
|
|
|
|
|
|
2013-01-31 19:03:51 +01:00
|
|
|
/* Load line editing library */
|
|
|
|
|
if (!(edit_lib_module = load_cmd_line_edit_lib ())) {
|
|
|
|
|
printf (_(">>> Command-line editing is not available. "
|
|
|
|
|
"Consider installing a line editing library to enable the feature. <<<\n"
|
|
|
|
|
"Supported libraries are:\n"
|
|
|
|
|
" - GNU Readline (libreadline) http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html\n"
|
|
|
|
|
" - NetBSD Editline (libedit) http://www.thrysoee.dk/editline/\n"));
|
|
|
|
|
edit_lib_symbols.readline_func = NULL;
|
|
|
|
|
edit_lib_symbols.add_history_func = NULL;
|
|
|
|
|
edit_lib_symbols.rl_insert_text_func = NULL;
|
|
|
|
|
edit_lib_symbols.rl_startup_hook_x = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
if (!con) {
|
|
|
|
|
if (con_id && !con_uuid && !con_path) {
|
|
|
|
|
con = con_id;
|
|
|
|
|
selector = "id";
|
|
|
|
|
} else if (con_uuid && !con_id && !con_path) {
|
|
|
|
|
con = con_uuid;
|
|
|
|
|
selector = "uuid";
|
|
|
|
|
} else if (con_path && !con_id && !con_uuid) {
|
|
|
|
|
con = con_path;
|
|
|
|
|
selector = "path";
|
|
|
|
|
} else if (!con_path && !con_id && !con_uuid) {
|
|
|
|
|
/* no-op */
|
|
|
|
|
} else {
|
|
|
|
|
g_string_printf (nmc->return_text,
|
|
|
|
|
_("Error: only one of 'id', uuid, or 'path' can be provided."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
if (con) {
|
|
|
|
|
/* Existing connection */
|
|
|
|
|
NMConnection *found_con;
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
found_con = find_connection (nmc->system_connections, selector, con);
|
|
|
|
|
if (!found_con) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
/* Duplicate the connection and use that so that we need not
|
|
|
|
|
* differentiate existing vs. new later
|
|
|
|
|
*/
|
|
|
|
|
connection = nm_connection_duplicate (found_con);
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
|
|
|
|
g_assert (s_con);
|
|
|
|
|
connection_type = nm_setting_connection_get_connection_type (s_con);
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
if (type)
|
|
|
|
|
printf (_("Warning: editing existing connection '%s'; 'type' argument is ignored\n"),
|
|
|
|
|
nm_connection_get_id (connection));
|
|
|
|
|
if (con_name)
|
|
|
|
|
printf (_("Warning: editing existing connection '%s'; 'con-name' argument is ignored\n"),
|
|
|
|
|
nm_connection_get_id (connection));
|
|
|
|
|
} else {
|
|
|
|
|
/* New connection */
|
|
|
|
|
connection_type = check_valid_name (type, nmc_valid_connection_types, &err1);
|
|
|
|
|
tmp_str = get_valid_options_string (nmc_valid_connection_types);
|
2013-01-18 15:21:00 +01:00
|
|
|
|
2013-04-19 21:06:20 +02:00
|
|
|
while (!connection_type) {
|
|
|
|
|
if (!type)
|
|
|
|
|
printf (_("Valid connection types: %s\n"), tmp_str);
|
|
|
|
|
else
|
|
|
|
|
printf (_("Error: invalid connection type; %s\n"), err1->message);
|
|
|
|
|
g_clear_error (&err1);
|
|
|
|
|
|
|
|
|
|
type_ask = readline_x (EDITOR_PROMPT_CON_TYPE);
|
|
|
|
|
type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
|
|
|
|
|
connection_type = check_valid_name (type_ask, nmc_valid_connection_types, &err1);
|
|
|
|
|
g_free (type_ask);
|
|
|
|
|
}
|
|
|
|
|
g_free (tmp_str);
|
|
|
|
|
|
|
|
|
|
/* Create a new connection object */
|
|
|
|
|
connection = nm_connection_new ();
|
|
|
|
|
|
|
|
|
|
/* Build up the 'connection' setting */
|
|
|
|
|
s_con = (NMSettingConnection *) nm_setting_connection_new ();
|
|
|
|
|
uuid = nm_utils_uuid_generate ();
|
|
|
|
|
if (con_name)
|
|
|
|
|
default_name = g_strdup (con_name);
|
|
|
|
|
else
|
|
|
|
|
default_name = unique_connection_name (nmc->system_connections,
|
|
|
|
|
get_name_alias (connection_type, nmc_valid_connection_types));
|
|
|
|
|
|
|
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_ID, default_name,
|
|
|
|
|
NM_SETTING_CONNECTION_UUID, uuid,
|
|
|
|
|
NM_SETTING_CONNECTION_TYPE, connection_type,
|
|
|
|
|
NULL);
|
|
|
|
|
g_free (uuid);
|
|
|
|
|
g_free (default_name);
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_con));
|
|
|
|
|
|
|
|
|
|
/* Initialize the new connection so that it is valid from the start */
|
|
|
|
|
editor_init_new_connection (nmc, connection);
|
|
|
|
|
}
|
2013-01-18 15:21:00 +01:00
|
|
|
|
|
|
|
|
printf ("\n");
|
|
|
|
|
printf (_("===| nmcli interactive connection editor |==="));
|
|
|
|
|
printf ("\n\n");
|
2013-04-19 21:06:20 +02:00
|
|
|
if (con)
|
|
|
|
|
printf (_("Editing existing '%s' connection: '%s'"), connection_type, con);
|
|
|
|
|
else
|
|
|
|
|
printf (_("Adding a new '%s' connection"), connection_type);
|
2013-01-18 15:21:00 +01:00
|
|
|
printf ("\n\n");
|
|
|
|
|
printf (_("Type 'help' or '?' for available commands."));
|
|
|
|
|
printf ("\n\n");
|
|
|
|
|
|
|
|
|
|
/* Run menu loop */
|
|
|
|
|
editor_menu_main (nmc, connection, connection_type);
|
|
|
|
|
|
2013-01-31 19:03:51 +01:00
|
|
|
if (edit_lib_module)
|
|
|
|
|
g_module_close (edit_lib_module);
|
|
|
|
|
|
2013-01-18 15:21:00 +01:00
|
|
|
if (connection)
|
|
|
|
|
g_object_unref (connection);
|
|
|
|
|
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
if (connection)
|
|
|
|
|
g_object_unref (connection);
|
|
|
|
|
g_free (type_ask);
|
|
|
|
|
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
typedef struct {
|
|
|
|
|
NmCli *nmc;
|
|
|
|
|
int counter;
|
|
|
|
|
} DeleteStateInfo;
|
|
|
|
|
|
2012-01-10 16:18:27 +01:00
|
|
|
static void
|
|
|
|
|
delete_cb (NMRemoteConnection *con, GError *err, gpointer user_data)
|
|
|
|
|
{
|
2012-11-19 13:53:24 +01:00
|
|
|
DeleteStateInfo *info = (DeleteStateInfo *) user_data;
|
2012-01-10 16:18:27 +01:00
|
|
|
|
|
|
|
|
if (err) {
|
2012-11-19 13:53:24 +01:00
|
|
|
g_string_printf (info->nmc->return_text, _("Error: Connection deletion failed: %s"), err->message);
|
|
|
|
|
info->nmc->return_value = NMC_RESULT_ERROR_CON_DEL;
|
2012-01-10 16:18:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
info->counter--;
|
|
|
|
|
if (info->counter == 0) {
|
|
|
|
|
g_free (info);
|
|
|
|
|
quit ();
|
|
|
|
|
}
|
2012-01-10 16:18:27 +01:00
|
|
|
}
|
|
|
|
|
|
2011-09-06 15:07:58 +02:00
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_delete (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection = NULL;
|
2012-11-19 13:53:24 +01:00
|
|
|
DeleteStateInfo *del_info = NULL;
|
2012-11-22 13:54:41 +01:00
|
|
|
char *line = NULL;
|
|
|
|
|
char **arg_arr = NULL;
|
|
|
|
|
char **arg_ptr = argv;
|
|
|
|
|
int arg_num = argc;
|
2013-04-05 13:01:08 +02:00
|
|
|
GString *invalid_cons = NULL;
|
|
|
|
|
gboolean del_info_free = FALSE;
|
2011-09-06 15:07:58 +02:00
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
nmc->return_value = NMC_RESULT_SUCCESS;
|
|
|
|
|
nmc->should_wait = FALSE;
|
2011-09-06 15:07:58 +02:00
|
|
|
|
2013-03-05 09:42:31 -06:00
|
|
|
/* create NMClient */
|
|
|
|
|
nmc->get_client (nmc);
|
|
|
|
|
|
|
|
|
|
if (!nm_client_get_manager_running (nmc->client)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
2013-04-05 13:01:08 +02:00
|
|
|
goto finish;
|
2011-09-06 15:07:58 +02:00
|
|
|
}
|
|
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
if (argc == 0) {
|
2012-11-22 13:54:41 +01:00
|
|
|
if (nmc->ask) {
|
|
|
|
|
line = nmc_get_user_input (_("Connection (name, UUID, or path): "));
|
|
|
|
|
nmc_string_to_arg_array (line, "", &arg_arr, &arg_num);
|
|
|
|
|
arg_ptr = arg_arr;
|
|
|
|
|
}
|
|
|
|
|
if (arg_num == 0) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: No connection specified."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2013-04-05 13:01:08 +02:00
|
|
|
goto finish;
|
2012-11-22 13:54:41 +01:00
|
|
|
}
|
2011-09-06 15:07:58 +02:00
|
|
|
}
|
|
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
del_info = g_malloc0 (sizeof (DeleteStateInfo));
|
|
|
|
|
del_info->nmc = nmc;
|
|
|
|
|
del_info->counter = 0;
|
2013-04-05 13:01:08 +02:00
|
|
|
del_info_free = TRUE;
|
2012-01-10 16:18:27 +01:00
|
|
|
|
2012-11-22 13:54:41 +01:00
|
|
|
while (arg_num > 0) {
|
2012-11-19 13:53:24 +01:00
|
|
|
const char *selector = NULL;
|
2012-01-10 16:18:27 +01:00
|
|
|
|
2012-11-22 13:54:41 +01:00
|
|
|
if ( strcmp (*arg_ptr, "id") == 0
|
|
|
|
|
|| strcmp (*arg_ptr, "uuid") == 0
|
|
|
|
|
|| strcmp (*arg_ptr, "path") == 0) {
|
|
|
|
|
selector = *arg_ptr;
|
|
|
|
|
if (next_arg (&arg_num, &arg_ptr) != 0) {
|
2012-11-19 13:53:24 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
2013-04-05 13:01:08 +02:00
|
|
|
goto finish;
|
2012-11-19 13:53:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-22 13:54:41 +01:00
|
|
|
connection = find_connection (nmc->system_connections, selector, *arg_ptr);
|
2012-11-19 13:53:24 +01:00
|
|
|
if (!connection) {
|
2013-04-05 13:01:08 +02:00
|
|
|
if (nmc->print_output != NMC_PRINT_TERSE)
|
|
|
|
|
printf (_("Error: unknown connection: %s\n"), *arg_ptr);
|
|
|
|
|
|
|
|
|
|
if (!invalid_cons)
|
|
|
|
|
invalid_cons = g_string_new (NULL);
|
|
|
|
|
g_string_append_printf (invalid_cons, "'%s', ", *arg_ptr);
|
|
|
|
|
|
|
|
|
|
/* take the next argument and continue */
|
|
|
|
|
next_arg (&arg_num, &arg_ptr);
|
|
|
|
|
continue;
|
2012-11-19 13:53:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We need to wait a bit so that nmcli's permissions can be checked.
|
|
|
|
|
* We will exit when D-Bus return (error) messages are received.
|
|
|
|
|
*/
|
|
|
|
|
nmc->should_wait = TRUE;
|
|
|
|
|
|
2013-04-05 13:01:08 +02:00
|
|
|
/* del_info deallocation is handled in delete_cb() */
|
|
|
|
|
del_info_free = FALSE;
|
|
|
|
|
|
2012-11-19 13:53:24 +01:00
|
|
|
del_info->counter++;
|
|
|
|
|
|
|
|
|
|
/* Delete the connection */
|
|
|
|
|
nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), delete_cb, del_info);
|
|
|
|
|
|
2012-11-22 13:54:41 +01:00
|
|
|
next_arg (&arg_num, &arg_ptr);
|
2012-11-19 13:53:24 +01:00
|
|
|
}
|
2012-01-10 16:18:27 +01:00
|
|
|
|
2013-04-05 13:01:08 +02:00
|
|
|
finish:
|
|
|
|
|
if (del_info_free)
|
|
|
|
|
g_free (del_info);
|
2012-11-22 13:54:41 +01:00
|
|
|
g_strfreev (arg_arr);
|
2011-09-06 15:07:58 +02:00
|
|
|
|
2013-04-05 13:01:08 +02:00
|
|
|
if (invalid_cons) {
|
|
|
|
|
g_string_truncate (invalid_cons, invalid_cons->len-2); /* truncate trailing ", " */
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: cannot delete unknown connection(s): %s."),
|
|
|
|
|
invalid_cons->str);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
g_string_free (invalid_cons, TRUE);
|
|
|
|
|
}
|
2011-09-06 15:07:58 +02:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-23 19:05:40 -03:00
|
|
|
static NMCResultCode
|
|
|
|
|
do_connection_reload (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
nmc->return_value = NMC_RESULT_SUCCESS;
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!nm_client_get_manager_running (nmc->client)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!nm_remote_settings_reload_connections (nmc->system_settings, &error)) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
|
|
|
|
|
if (error->code == NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE)
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
|
|
|
|
|
else
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
static NMCResultCode
|
|
|
|
|
parse_cmd (NmCli *nmc, int argc, char **argv)
|
2010-02-25 09:52:30 -08:00
|
|
|
{
|
2010-03-22 18:43:28 +01:00
|
|
|
GError *error = NULL;
|
2012-11-19 10:24:31 +01:00
|
|
|
int arg_ret;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
if (argc == 0) {
|
|
|
|
|
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
|
2010-03-24 13:42:47 +01:00
|
|
|
goto opt_error;
|
2012-11-19 10:24:31 +01:00
|
|
|
nmc->return_value = do_connections_show (nmc, argc, argv);
|
2010-02-25 09:52:30 -08:00
|
|
|
} else {
|
2012-11-19 10:24:31 +01:00
|
|
|
if (matches (*argv, "show") == 0) {
|
|
|
|
|
arg_ret = next_arg (&argc, &argv);
|
|
|
|
|
if (arg_ret != 0 || matches (*argv, "configured") == 0) {
|
|
|
|
|
next_arg (&argc, &argv);
|
|
|
|
|
nmc->return_value = do_connections_show (nmc, argc, argv);
|
|
|
|
|
} else if (matches (*argv, "active") == 0) {
|
|
|
|
|
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
|
|
|
|
|
goto opt_error;
|
|
|
|
|
nmc->return_value = do_connections_show_active (nmc, argc-1, argv+1);
|
|
|
|
|
} else {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: 'configured' or 'active' command is expected for 'connection show'."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2011-02-16 17:36:50 +01:00
|
|
|
else if (matches(*argv, "up") == 0) {
|
|
|
|
|
nmc->return_value = do_connection_up (nmc, argc-1, argv+1);
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2011-02-16 17:36:50 +01:00
|
|
|
else if (matches(*argv, "down") == 0) {
|
|
|
|
|
nmc->return_value = do_connection_down (nmc, argc-1, argv+1);
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
2013-04-12 15:26:31 +02:00
|
|
|
else if (matches(*argv, "add") == 0) {
|
|
|
|
|
if (nmc_arg_is_help (*(argv+1))) {
|
|
|
|
|
usage_connection_add ();
|
|
|
|
|
nmc->should_wait = FALSE;
|
|
|
|
|
} else
|
|
|
|
|
nmc->return_value = do_connection_add (nmc, argc-1, argv+1);
|
|
|
|
|
}
|
2013-01-18 15:21:00 +01:00
|
|
|
else if (matches(*argv, "edit") == 0) {
|
|
|
|
|
nmc->return_value = do_connection_edit (nmc, argc-1, argv+1);
|
|
|
|
|
}
|
2011-09-06 15:07:58 +02:00
|
|
|
else if (matches(*argv, "delete") == 0) {
|
|
|
|
|
nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
|
|
|
|
|
}
|
2013-05-23 19:05:40 -03:00
|
|
|
else if (matches(*argv, "reload") == 0) {
|
|
|
|
|
nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
|
|
|
|
|
}
|
2013-04-18 11:25:49 +02:00
|
|
|
else if (nmc_arg_is_help (*argv)) {
|
2010-02-25 09:52:30 -08:00
|
|
|
usage ();
|
2011-02-16 17:36:50 +01:00
|
|
|
nmc->should_wait = FALSE;
|
2012-11-13 14:19:49 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2010-02-25 09:52:30 -08:00
|
|
|
usage ();
|
2012-11-19 10:24:31 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);
|
2011-02-16 17:36:50 +01:00
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
nmc->should_wait = FALSE;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
return nmc->return_value;
|
2010-03-22 18:43:28 +01:00
|
|
|
|
2010-03-24 13:42:47 +01:00
|
|
|
opt_error:
|
2011-02-16 17:36:50 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
|
|
|
|
nmc->should_wait = FALSE;
|
2010-03-22 18:43:28 +01:00
|
|
|
g_error_free (error);
|
2011-02-16 17:36:50 +01:00
|
|
|
return nmc->return_value;
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|
|
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* callback called when connections are obtained from the settings service */
|
|
|
|
|
static void
|
|
|
|
|
get_connections_cb (NMRemoteSettings *settings, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
ArgsInfo *args = (ArgsInfo *) user_data;
|
|
|
|
|
|
|
|
|
|
/* Get the connection list */
|
|
|
|
|
args->nmc->system_connections = nm_remote_settings_list_connections (settings);
|
|
|
|
|
|
|
|
|
|
parse_cmd (args->nmc, args->argc, args->argv);
|
|
|
|
|
|
|
|
|
|
if (!args->nmc->should_wait)
|
|
|
|
|
quit ();
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
cli: replace 'dev' and 'con' OBJECTs by 'device', resp. 'connection'
Shorter forms work as previously. Thus, all of these commands are valid:
nmcli device, nmcli devic, nmcli devi, nmcli dev, nmcli de, nmcli d
nmcli connection, nmcli connectio, ..., nmcli conn, nmcli con, ..., nmcli c
2012-11-13 14:43:14 +01:00
|
|
|
/* Entry point function for connections-related commands: 'nmcli connection' */
|
2010-02-25 09:52:30 -08:00
|
|
|
NMCResultCode
|
|
|
|
|
do_connections (NmCli *nmc, int argc, char **argv)
|
|
|
|
|
{
|
2011-02-16 17:36:50 +01:00
|
|
|
int i = 0;
|
|
|
|
|
gboolean real_cmd = FALSE;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
if (argc == 0)
|
|
|
|
|
real_cmd = TRUE;
|
|
|
|
|
else {
|
|
|
|
|
while (real_con_commands[i] && matches (*argv, real_con_commands[i]) != 0)
|
|
|
|
|
i++;
|
2012-04-28 22:54:02 +02:00
|
|
|
if (real_con_commands[i] != NULL)
|
2011-02-16 17:36:50 +01:00
|
|
|
real_cmd = TRUE;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
if (!real_cmd) {
|
|
|
|
|
/* no real execution command - no need to get connections */
|
|
|
|
|
return parse_cmd (nmc, argc, argv);
|
|
|
|
|
} else {
|
|
|
|
|
if (!nmc_versions_match (nmc))
|
|
|
|
|
return nmc->return_value;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2012-05-09 12:54:09 +02:00
|
|
|
/* Get NMClient object early */
|
|
|
|
|
nmc->get_client (nmc);
|
|
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
nmc->should_wait = TRUE;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
args_info.nmc = nmc;
|
|
|
|
|
args_info.argc = argc;
|
|
|
|
|
args_info.argv = argv;
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* get system settings */
|
2012-12-03 15:23:02 -06:00
|
|
|
if (!(nmc->system_settings = nm_remote_settings_new (NULL))) {
|
2011-02-16 17:36:50 +01:00
|
|
|
g_string_printf (nmc->return_text, _("Error: Could not get system settings."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
2011-09-06 15:07:58 +02:00
|
|
|
nmc->should_wait = FALSE;
|
2011-02-16 17:36:50 +01:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* find out whether settings service is running */
|
|
|
|
|
g_object_get (nmc->system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->system_settings_running, NULL);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
if (!nmc->system_settings_running) {
|
|
|
|
|
g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings service is not running."));
|
|
|
|
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
2011-09-06 15:07:58 +02:00
|
|
|
nmc->should_wait = FALSE;
|
2011-02-16 17:36:50 +01:00
|
|
|
return nmc->return_value;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* connect to signal "connections-read" - emitted when connections are fetched and ready */
|
|
|
|
|
g_signal_connect (nmc->system_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ,
|
|
|
|
|
G_CALLBACK (get_connections_cb), &args_info);
|
2010-02-25 09:52:30 -08:00
|
|
|
|
2011-02-16 17:36:50 +01:00
|
|
|
/* The rest will be done in get_connection_cb() callback.
|
|
|
|
|
* We need to wait for signals that connections are read.
|
|
|
|
|
*/
|
|
|
|
|
return NMC_RESULT_SUCCESS;
|
|
|
|
|
}
|
2010-02-25 09:52:30 -08:00
|
|
|
}
|