summary refs log tree commit diff
path: root/clients/cli/nmcli.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-01-17 20:25:09 +0100
committerMichael Biebl <biebl@debian.org>2017-01-17 20:25:09 +0100
commit58f8be580039b0575b197b9573a1c92745d96d30 (patch)
tree2c226233f623a0dcb529be0eb8cdf97e4a2ae0c0 /clients/cli/nmcli.c
parent45cb5bb3c0e6edb887cf69b417fcaf7053814a9b (diff)
New upstream version 1.5.90 upstream/1.5.90
Diffstat (limited to 'clients/cli/nmcli.c')
-rw-r--r--clients/cli/nmcli.c251
1 files changed, 67 insertions, 184 deletions
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 62088087..5c47e440 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -25,10 +25,10 @@
 #include <string.h>
 #include <stdlib.h>
 #include <signal.h>
-#include <pthread.h>
 #include <termios.h>
 #include <unistd.h>
 #include <locale.h>
+#include <glib-unix.h>
 #include <readline/readline.h>
 #include <readline/history.h>
 
@@ -61,7 +61,6 @@ typedef struct {
 
 /* --- Global variables --- */
 GMainLoop *loop = NULL;
-static sigset_t signal_set;
 struct termios termios_orig;
 
 static void
@@ -206,18 +205,18 @@ usage (void)
 }
 
 static const NMCCommand nmcli_cmds[] = {
-	{ "general",    do_general,     NULL },
-	{ "monitor",    do_monitor,     NULL },
-	{ "networking", do_networking,  NULL },
-	{ "radio",      do_radio,       NULL },
-	{ "connection", do_connections, NULL },
-	{ "device",     do_devices,     NULL },
-	{ "agent",      do_agent,       NULL },
-	{ NULL,         do_overview,    usage }
+	{ "general",     do_general,      NULL,   FALSE,  FALSE },
+	{ "monitor",     do_monitor,      NULL,   TRUE,   FALSE },
+	{ "networking",  do_networking,   NULL,   FALSE,  FALSE },
+	{ "radio",       do_radio,        NULL,   FALSE,  FALSE },
+	{ "connection",  do_connections,  NULL,   FALSE,  FALSE },
+	{ "device",      do_devices,      NULL,   FALSE,  FALSE },
+	{ "agent",       do_agent,        NULL,   FALSE,  FALSE },
+	{ NULL,          do_overview,     usage,  TRUE,   TRUE },
 };
 
-static NMCResultCode
-parse_command_line (NmCli *nmc, int argc, char **argv)
+static gboolean
+process_command_line (NmCli *nmc, int argc, char **argv)
 {
 	char *base;
 
@@ -258,12 +257,12 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			if (nmc->print_output == NMC_PRINT_TERSE) {
 				g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time."));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			else if (nmc->print_output == NMC_PRINT_PRETTY) {
 				g_string_printf (nmc->return_text, _("Error: Option '--terse' is mutually exclusive with '--pretty'."));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			else
 				nmc->print_output = NMC_PRINT_TERSE;
@@ -271,21 +270,21 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			if (nmc->print_output == NMC_PRINT_PRETTY) {
 				g_string_printf (nmc->return_text, _("Error: Option '--pretty' is specified the second time."));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			else if (nmc->print_output == NMC_PRINT_TERSE) {
 				g_string_printf (nmc->return_text, _("Error: Option '--pretty' is mutually exclusive with '--terse'."));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			else
 				nmc->print_output = NMC_PRINT_PRETTY;
 		} else if (matches (opt, "-mode") == 0) {
 			nmc->mode_specified = TRUE;
 			if (next_arg (&argc, &argv) != 0) {
-		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				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;
+				return FALSE;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc_complete_strings (argv[0], "tabular", "multiline", NULL);
@@ -294,15 +293,15 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			else if (matches (argv[0], "multiline") == 0)
 				nmc->multiline_output = TRUE;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
+				g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 		} else if (matches (opt, "-colors") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
-		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				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;
+				return FALSE;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc_complete_strings (argv[0], "yes", "no", "auto", NULL);
@@ -313,15 +312,15 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			else if (matches (argv[0], "no") == 0)
 				nmc->use_colors = NMC_USE_COLOR_NO;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
+				g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 		} else if (matches (opt, "-escape") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
-		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				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;
+				return FALSE;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc_complete_strings (argv[0], "yes", "no", NULL);
@@ -330,15 +329,15 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			else if (matches (argv[0], "no") == 0)
 				nmc->escape_values = FALSE;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
+				g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 		} else if (matches (opt, "-fields") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
-		 		g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
+				g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			if (argc == 1 && nmc->complete)
 				complete_fields (argv[0]);
@@ -352,15 +351,15 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 		} else if (matches (opt, "-wait") == 0) {
 			unsigned long timeout;
 			if (next_arg (&argc, &argv) != 0) {
-		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				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;
+				return FALSE;
 			}
 			if (!nmc_string_to_uint (argv[0], TRUE, 0, G_MAXINT, &timeout)) {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."),
-				                 argv[0], opt);
+				g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."),
+						 argv[0], opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				return nmc->return_value;
+				return FALSE;
 			}
 			nmc->timeout = (int) timeout;
 		} else if (matches (opt, "-version") == 0) {
@@ -374,135 +373,63 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 		} else {
 			g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), opt);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-			return nmc->return_value;
+			return FALSE;
 		}
 		argc--;
 		argv++;
 	}
 
 	/* Now run the requested command */
-	return nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
+	nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
+
+	return TRUE;
 }
 
 static gboolean nmcli_sigint = FALSE;
-static pthread_mutex_t sigint_mutex = PTHREAD_MUTEX_INITIALIZER;
-static gboolean nmcli_sigquit_internal = FALSE;
 
 gboolean
 nmc_seen_sigint (void)
 {
-	gboolean sigint;
-
-	pthread_mutex_lock (&sigint_mutex);
-	sigint = nmcli_sigint;
-	pthread_mutex_unlock (&sigint_mutex);
-	return sigint;
+	return nmcli_sigint;
 }
 
 void
 nmc_clear_sigint (void)
 {
-	pthread_mutex_lock (&sigint_mutex);
 	nmcli_sigint = FALSE;
-	pthread_mutex_unlock (&sigint_mutex);
 }
 
-void
-nmc_set_sigquit_internal (void)
+void nmc_exit (void)
 {
-	nmcli_sigquit_internal = TRUE;
+	tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
+	nmc_cleanup_readline ();
+	exit (1);
 }
 
-static int
-event_hook_for_readline (void)
-{
-	/* Make readline() exit on SIGINT */
-	if (nmc_seen_sigint ()) {
-		rl_echo_signal_char (SIGINT);
-		rl_stuff_char ('\n');
-	}
-	return 0;
-}
-
-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:
-			if (nmc_get_in_readline ()) {
-				/* Don't quit when in readline, only signal we received SIGINT */
-				pthread_mutex_lock (&sigint_mutex);
-				nmcli_sigint = TRUE;
-				pthread_mutex_unlock (&sigint_mutex);
-			} else {
-				/* We can quit nmcli */
-				tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
-				nmc_cleanup_readline ();
-				g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
-				         strsignal (signo), signo);
-				exit (1);
-			}
-			break;
-		case SIGQUIT:
-		case SIGTERM:
-			tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
-			nmc_cleanup_readline ();
-			if (!nmcli_sigquit_internal)
-				g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
-				         strsignal (signo), signo);
-			exit (1);
-			break;
-		default:
-			break;
-		}
-	}
-	return NULL;
-}
-
-/*
- * 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)
+signal_handler (gpointer user_data)
 {
-	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) {
-		g_printerr (_("Failed to set signal mask: %d\n"), status);
-		return FALSE;
-	}
+	int signo = GPOINTER_TO_INT (user_data);
 
-	/* Create the signal handling thread. */
-	status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL);
-	if (status != 0) {
-		g_printerr (_("Failed to create signal handling thread: %d\n"), status);
-		return FALSE;
+	switch (signo) {
+	case SIGINT:
+		if (nmc_get_in_readline ()) {
+			nmcli_sigint = TRUE;
+		} else {
+			g_print (_("Error: nmcli terminated by signal %s (%d)\n"),
+			         strsignal (signo),
+			         signo);
+			g_main_loop_quit (loop);
+		}
+		break;
+	case SIGTERM:
+		g_print (_("Error: nmcli terminated by signal %s (%d)\n"),
+		         strsignal (signo), signo);
+		nmc_exit ();
+		break;
 	}
 
-	return TRUE;
+	return G_SOURCE_CONTINUE;
 }
 
 static void
@@ -587,37 +514,17 @@ nmc_value_transforms_register (void)
 	                                 nmc_convert_bytes_to_string);
 }
 
-static NMClient *
-nmc_get_client (NmCli *nmc)
-{
-	GError *error = NULL;
-
-	if (!nmc->client) {
-		nmc->client = nm_client_new (NULL, &error);
-		if (!nmc->client) {
-			g_printerr ("%s\n", error->message);
-			g_clear_error (&error);
-			exit (NMC_RESULT_ERROR_UNKNOWN);
-		}
-	}
-
-	return nmc->client;
-}
-
 /* Initialize NmCli structure - set default values */
 static void
 nmc_init (NmCli *nmc)
 {
 	nmc->client = NULL;
-	nmc->get_client = &nmc_get_client;
 
 	nmc->return_value = NMC_RESULT_SUCCESS;
 	nmc->return_text = g_string_new (_("Success"));
 
 	nmc->timeout = -1;
 
-	nmc->connections = NULL;
-
 	nmc->secret_agent = NULL;
 	nmc->pwds_hash = NULL;
 	nmc->pk_listener = NULL;
@@ -664,28 +571,9 @@ nmc_cleanup (NmCli *nmc)
 	nmc_polkit_agent_fini (nmc);
 }
 
-static gboolean
-start (gpointer data)
-{
-	ArgsInfo *info = (ArgsInfo *) data;
-	info->nmc->return_value = parse_command_line (info->nmc, info->argc, info->argv);
-
-	if (!info->nmc->should_wait)
-		g_main_loop_quit (loop);
-
-	return FALSE;
-}
-
-
 int
 main (int argc, char *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, "");
 
@@ -701,20 +589,15 @@ main (int argc, char *argv[])
 	/* Save terminal settings */
 	tcgetattr (STDIN_FILENO, &termios_orig);
 
-	/* readline init */
-	rl_event_hook = event_hook_for_readline;
-	/* Set 0.01s timeout to mitigate slowness in readline when a broken version is used.
-	 * See https://bugzilla.redhat.com/show_bug.cgi?id=1109946
-	 */
-	rl_set_keyboard_input_timeout (10000);
+	g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
+	g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
 
 	nmc_value_transforms_register ();
 
 	nmc_init (&nm_cli);
-	g_idle_add (start, &args_info);
-
-	loop = g_main_loop_new (NULL, FALSE);  /* create main loop */
-	g_main_loop_run (loop);                /* run main loop */
+	loop = g_main_loop_new (NULL, FALSE);
+	if (process_command_line (&nm_cli, argc, argv))
+		g_main_loop_run (loop);
 
 	if (nm_cli.complete) {
 		/* Remove error statuses from command completion runs. */