about summary refs log tree commit diff
path: root/cli/src/nmcli.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /cli/src/nmcli.c
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'cli/src/nmcli.c')
-rw-r--r--cli/src/nmcli.c149
1 files changed, 114 insertions, 35 deletions
diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c
index 757ff92b..66288c20 100644
--- a/cli/src/nmcli.c
+++ b/cli/src/nmcli.c
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 /* Generated configuration file */
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <pthread.h>
 #include <locale.h>
 
 #include <glib.h>
@@ -36,6 +37,7 @@
 
 #include "nmcli.h"
 #include "utils.h"
+#include "common.h"
 #include "connections.h"
 #include "devices.h"
 #include "network-manager.h"
@@ -46,6 +48,10 @@
 # define NMCLI_VERSION VERSION
 #endif
 
+/* Global NmCli object */
+// FIXME: Currently, we pass NmCli over in most APIs, but we might refactor
+// that and use the global variable directly instead.
+NmCli nm_cli;
 
 typedef struct {
 	NmCli *nmc;
@@ -55,6 +61,7 @@ typedef struct {
 
 /* --- Global variables --- */
 GMainLoop *loop = NULL;
+static sigset_t signal_set;
 
 
 /* Get an error quark for use with GError */
@@ -82,11 +89,15 @@ usage (const char *prog_name)
 	         "  -f[ields] <field1,field2,...>|all|common   specify fields to output\n"
 	         "  -e[scape] yes|no                           escape columns separators in values\n"
 	         "  -n[ocheck]                                 don't check nmcli and NetworkManager versions\n"
+	         "  -a[sk]                                     ask for missing parameters\n"
+	         "  -w[ait] <seconds>                          set timeout waiting for finishing operations\n"
 	         "  -v[ersion]                                 show program version\n"
 	         "  -h[elp]                                    print this help\n"
 	         "\n"
 	         "OBJECT\n"
-	         "  nm              NetworkManager's status\n"
+	         "  g[eneral]       NetworkManager's general status and operations\n"
+	         "  n[etworking]    overall networking control\n"
+	         "  r[adio]         NetworkManager radio switches\n"
 	         "  c[onnection]    NetworkManager's connections\n"
 	         "  d[evice]        devices managed by NetworkManager\n"
 	         "\n"),
@@ -104,7 +115,9 @@ static const struct cmd {
 	const char *cmd;
 	NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
 } nmcli_cmds[] = {
-	{ "nm",         do_network_manager },
+	{ "general",    do_general },
+	{ "networking", do_networking },
+	{ "radio",      do_radio },
 	{ "connection", do_connections },
 	{ "device",     do_devices },
 	{ "help",       do_help },
@@ -183,9 +196,9 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (!strcmp (argv[1], "tabular"))
+			if (matches (argv[1], "tabular") == 0)
 				nmc->multiline_output = FALSE;
-			else if (!strcmp (argv[1], "multiline"))
+			else if (matches (argv[1], "multiline") == 0)
 				nmc->multiline_output = TRUE;
 			else {
 		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
@@ -199,9 +212,9 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (!strcmp (argv[1], "yes"))
+			if (matches (argv[1], "yes") == 0)
 				nmc->escape_values = TRUE;
-			else if (!strcmp (argv[1], "no"))
+			else if (matches (argv[1], "no") == 0)
 				nmc->escape_values = FALSE;
 			else {
 		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
@@ -218,6 +231,23 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			nmc->required_fields = g_strdup (argv[1]);
 		} else if (matches (opt, "-nocheck") == 0) {
 			nmc->nocheck_ver = TRUE;
+		} else if (matches (opt, "-ask") == 0) {
+			nmc->ask = TRUE;
+		} else if (matches (opt, "-wait") == 0) {
+			unsigned long timeout;
+			next_arg (&argc, &argv);
+			if (argc <= 1) {
+		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return nmc->return_value;
+			}
+			if (!nmc_string_to_uint (argv[1], TRUE, 0, G_MAXINT, &timeout)) {
+		 		g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."),
+				                 argv[1], opt);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return nmc->return_value;
+			}
+			nmc->timeout = (int) timeout;
 		} else if (matches (opt, "-version") == 0) {
 			printf (_("nmcli tool, version %s\n"), NMCLI_VERSION);
 			return NMC_RESULT_SUCCESS;
@@ -240,27 +270,68 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 	return nmc->return_value;
 }
 
-static void
-signal_handler (int signo)
-{
-	if (signo == SIGINT || signo == SIGTERM) {
-		g_message (_("Caught signal %d, shutting down..."), signo);
-		g_main_loop_quit (loop);
+void *signal_handling_thread (void *arg);
+/*
+ * Thread function waiting for signals and processing them.
+ * Wait for signals in signal set. The semantics of sigwait() require that all
+ * threads (including the thread calling sigwait()) have the signal masked, for
+ * reliable operation. Otherwise, a signal that arrives while this thread is
+ * not blocked in sigwait() might be delivered to another thread.
+ */
+void *
+signal_handling_thread (void *arg) {
+	int signo;
+
+	while (1) {
+		sigwait (&signal_set, &signo);
+
+		switch (signo) {
+		case SIGINT:
+		case SIGQUIT:
+		case SIGTERM:
+			nmc_cleanup_readline ();
+			printf (_("\nError: nmcli terminated by signal %d."), signo);
+			exit (1);
+			break;
+		default:
+			break;
+		}
 	}
+	return NULL;
 }
 
-static void
+/*
+ * Mask the signals we are interested in and create a signal handling thread.
+ * Because all threads inherit the signal mask from their creator, all threads
+ * in the process will have the signals masked. That's why setup_signals() has
+ * to be called before creating other threads.
+ */
+static gboolean
 setup_signals (void)
 {
-	struct sigaction action;
-	sigset_t mask;
-
-	sigemptyset (&mask);
-	action.sa_handler = signal_handler;
-	action.sa_mask = mask;
-	action.sa_flags = 0;
-	sigaction (SIGTERM,  &action, NULL);
-	sigaction (SIGINT,  &action, NULL);
+	pthread_t signal_thread_id;
+	int status;
+
+	sigemptyset (&signal_set);
+	sigaddset (&signal_set, SIGINT);
+	sigaddset (&signal_set, SIGQUIT);
+	sigaddset (&signal_set, SIGTERM);
+
+	/* Block all signals of interest. */
+	status = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to set signal mask: %d"), status);
+		return FALSE;
+	}
+
+       /* Create the signal handling thread. */
+	status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 static NMClient *
@@ -287,7 +358,7 @@ nmc_init (NmCli *nmc)
 	nmc->return_value = NMC_RESULT_SUCCESS;
 	nmc->return_text = g_string_new (_("Success"));
 
-	nmc->timeout = 10;
+	nmc->timeout = -1;
 
 	nmc->system_settings = NULL;
 	nmc->system_settings_running = FALSE;
@@ -300,9 +371,13 @@ nmc_init (NmCli *nmc)
 	nmc->mode_specified = FALSE;
 	nmc->escape_values = TRUE;
 	nmc->required_fields = NULL;
-	nmc->allowed_fields = NULL;
+	nmc->output_data = g_ptr_array_new_full (20, g_free);
 	memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields));
 	nmc->nocheck_ver = FALSE;
+	nmc->ask = FALSE;
+	nmc->editor_status_line = FALSE;
+	nmc->editor_save_confirmation = TRUE;
+	nmc->editor_prompt_color = NMC_TERM_COLOR_NORMAL;
 }
 
 static void
@@ -316,8 +391,8 @@ nmc_cleanup (NmCli *nmc)
 	g_slist_free (nmc->system_connections);
 
 	g_free (nmc->required_fields);
-	if (nmc->print_fields.indices)
-		g_array_free (nmc->print_fields.indices, TRUE);
+	nmc_empty_output_fields (nmc);
+	g_ptr_array_unref (nmc->output_data);
 }
 
 static gboolean
@@ -336,8 +411,11 @@ start (gpointer data)
 int
 main (int argc, char *argv[])
 {
-	NmCli nmc;
-	ArgsInfo args_info = { &nmc, argc, argv };
+	ArgsInfo args_info = { &nm_cli, argc, argv };
+
+	/* Set up unix signal handling */
+	if (!setup_signals ())
+		exit (NMC_RESULT_ERROR_UNKNOWN);
 
 	/* Set locale to use environment variables */
 	setlocale (LC_ALL, "");
@@ -349,22 +427,23 @@ main (int argc, char *argv[])
 	textdomain (GETTEXT_PACKAGE);
 #endif
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
 
-	nmc_init (&nmc);
+	nmc_init (&nm_cli);
 	g_idle_add (start, &args_info);
 
 	loop = g_main_loop_new (NULL, FALSE);  /* create main loop */
-	setup_signals ();                      /* setup UNIX signals */
 	g_main_loop_run (loop);                /* run main loop */
 
 	/* Print result descripting text */
-	if (nmc.return_value != NMC_RESULT_SUCCESS) {
-		fprintf (stderr, "%s\n", nmc.return_text->str);
+	if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
+		fprintf (stderr, "%s\n", nm_cli.return_text->str);
 	}
 
 	g_main_loop_unref (loop);
-	nmc_cleanup (&nmc);
+	nmc_cleanup (&nm_cli);
 
-	return nmc.return_value;
+	return nm_cli.return_value;
 }