From 6e2fc9b55433e7a6600633deaef5988c7966328e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 12:59:07 +0100 Subject: [PATCH 01/21] hostname: combine implementations of read_hostname() for Gentoo and Slackware (cherry picked from commit fb9c2c9a193df2dc8bfb2fd710be36fb74e6ee6d) --- src/core/nm-hostname-manager.c | 58 +++++++++++----------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/core/nm-hostname-manager.c b/src/core/nm-hostname-manager.c index 26e073b36e..b036590fb3 100644 --- a/src/core/nm-hostname-manager.c +++ b/src/core/nm-hostname-manager.c @@ -99,53 +99,32 @@ _file_monitor_new(const char *path) /*****************************************************************************/ -#if defined(HOSTNAME_PERSIST_GENTOO) static char * -read_hostname_gentoo(const char *path) +read_hostname(const char *path, gboolean is_gentoo) { - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - const char *tmp; - guint i; + gs_free char *contents = NULL; + gs_free const char **all_lines = NULL; + const char *tmp; + gsize i; if (!g_file_get_contents(path, &contents, NULL, NULL)) return NULL; - all_lines = g_strsplit(contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip(all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - if (g_str_has_prefix(all_lines[i], "hostname=")) { - tmp = &all_lines[i][NM_STRLEN("hostname=")]; - return g_shell_unquote(tmp, NULL); + all_lines = nm_strsplit_set_full(contents, "\n", NM_STRSPLIT_SET_FLAGS_STRSTRIP); + for (i = 0; (tmp = all_lines[i]); i++) { + if (is_gentoo) { + if (!NM_STR_HAS_PREFIX(tmp, "hostname=")) + continue; + tmp = &tmp[NM_STRLEN("hostname=")]; + } else { + if (tmp[0] == '#') + continue; } + nm_assert(tmp && tmp[0] != '\0'); + return g_shell_unquote(tmp, NULL); } return NULL; } -#endif - -#if defined(HOSTNAME_PERSIST_SLACKWARE) -static char * -read_hostname_slackware(const char *path) -{ - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - guint i = 0; - - if (!g_file_get_contents(path, &contents, NULL, NULL)) - return NULL; - - all_lines = g_strsplit(contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip(all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - return g_shell_unquote(&all_lines[i][0], NULL); - } - return NULL; -} -#endif #if defined(HOSTNAME_PERSIST_SUSE) static gboolean @@ -237,10 +216,11 @@ _set_hostname_read_file(NMHostnameManager *self) #endif #if defined(HOSTNAME_PERSIST_GENTOO) - hostname = read_hostname_gentoo(HOSTNAME_FILE); + hostname = read_hostname(HOSTNAME_FILE, TRUE); #elif defined(HOSTNAME_PERSIST_SLACKWARE) - hostname = read_hostname_slackware(HOSTNAME_FILE); + hostname = read_hostname(HOSTNAME_FILE, FALSE); #else + (void) read_hostname; if (g_file_get_contents(HOSTNAME_FILE, &hostname, NULL, NULL)) g_strchomp(hostname); #endif From de87340b2f9713baec65a3b291b5fd783e9be1dd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 15:38:22 +0100 Subject: [PATCH 02/21] cli: avoid leak in readline_cb() overwriting previous line Such leaks show up in valgrind, and are simply bugs. Also, various callers (not all of them, which is another bug!) like to take ownership of the returned string and free it. That means, we leave a dangling pointer in the global variable, which is very ugly and error prone. Also, the callers like to free the string with g_free(), which is not appropriate for the "rl_string" memory which was allocated by readline. It must be freed with free(). Avoid that, by cloning the string using the glib allocator. Fixes: 995229181cac ('cli: remove editor thread') (cherry picked from commit 89734c75539b7a0b1e5918eb9a785f144dd3abe9) --- src/nmcli/common.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/nmcli/common.c b/src/nmcli/common.c index 9fdc412720..008a3cec28 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -895,7 +895,10 @@ static void readline_cb(char *line) { rl_got_line = TRUE; - rl_string = line; + + free(rl_string); + rl_string = line; + rl_callback_handler_remove(); } @@ -910,13 +913,15 @@ static char * nmc_readline_helper(const NmcConfig *nmc_config, const char *prompt) { GSource *io_source; + char *result; nmc_set_in_readline(TRUE); io_source = nm_g_unix_fd_add_source(STDIN_FILENO, G_IO_IN, stdin_ready_cb, NULL); read_again: - rl_string = NULL; + nm_clear_free(&rl_string); + rl_got_line = FALSE; rl_callback_handler_install(prompt, readline_cb); @@ -964,7 +969,12 @@ read_again: nmc_set_in_readline(FALSE); - return rl_string; + if (!rl_string) + return NULL; + + result = g_strdup(rl_string); + nm_clear_free(&rl_string); + return result; } /** From 633c7342559bf3c2bd30e8e995a39bb868851ab1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 15:43:03 +0100 Subject: [PATCH 03/21] cli: use "free()" for string from readline Since glib 2.45, we are guaranteed that g_free() just calls free(), so both can be used interchangeably. However, we still only depend on glib 2.40. In any case, it's ugly to mix the two. Memory allocated by plain malloc(), should be only freed with free(). The buffer in question comes from readline, which allocates it using the system allocator. Fixes: 995229181cac ('cli: remove editor thread') (cherry picked from commit 5dc07174d31e4b4beac388f77ad30684dc4014f8) --- src/nmcli/common.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/nmcli/common.c b/src/nmcli/common.c index 008a3cec28..4229f66034 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -947,7 +947,6 @@ read_again: if (nmc_config->in_editor || (rl_string && *rl_string)) { /* In editor, or the line is not empty */ /* Call readline again to get new prompt (repeat) */ - g_free(rl_string); goto read_again; } else { /* Not in editor and line is empty, exit */ @@ -960,10 +959,8 @@ read_again: } /* Return NULL, not empty string */ - if (rl_string && *rl_string == '\0') { - g_free(rl_string); - rl_string = NULL; - } + if (rl_string && *rl_string == '\0') + nm_clear_free(&rl_string); nm_clear_g_source_inst(&io_source); From e60ff37f79dea291c43a2cc8b6132392e6c96c7c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 15:53:31 +0100 Subject: [PATCH 04/21] cli: fix leaking "value" string in ask_option() Fixes: c5324ed285af ('nmcli: streamline connection addition') (cherry picked from commit ea3e61047f8e5010d3aac8d074f2b2a55952d2d1) --- src/nmcli/connections.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 00cc57acb7..610248c865 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -5594,8 +5594,8 @@ next: static void ask_option(NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstract_info) { - char *value; - GError *error = NULL; + gs_free char *value = NULL; + gs_free_error GError *error = NULL; gs_free char *prompt = NULL; gboolean multi; const char *setting_name, *property_name; @@ -5631,11 +5631,13 @@ ask_option(NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstr g_print(_("You can specify this option more than once. Press when you're done.\n")); again: + nm_clear_g_free(&value); + g_clear_error(&error); + value = nmc_readline(&nmc->nmc_config, "%s", prompt); if (!set_option(nmc, connection, abstract_info, value, FALSE, &error)) { g_printerr("%s\n", error->message); - g_clear_error(&error); goto again; } From 3520ff8f7907523623881d9c218e9caaa3fc5b9c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 13:36:00 +0100 Subject: [PATCH 05/21] contrib: avoid using "sudo" in REQUIRED_PACKAGES scripts It's often not installed, and usually we are already root. Avoid using sudo. (cherry picked from commit f6805debee86a603ef290fe0242548990075cf19) --- .gitlab-ci.yml | 8 ++++---- contrib/debian/REQUIRED_PACKAGES | 5 ++++- contrib/fedora/REQUIRED_PACKAGES | 5 ++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc80aae51a..016d8ab9c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,10 +53,10 @@ variables: # # This is done by running `ci-fairy generate-template` and possibly bumping # ".default_tag". - FEDORA_TAG: '2023-01-18.0-1423f8164e71' - UBUNTU_TAG: '2023-01-18.0-08fb4e6eb861' - DEBIAN_TAG: '2023-01-18.0-08fb4e6eb861' - CENTOS_TAG: '2023-01-18.0-1423f8164e71' + FEDORA_TAG: '2023-01-18.0-503dba0518ae' + UBUNTU_TAG: '2023-01-18.0-1218be1cbc9d' + DEBIAN_TAG: '2023-01-18.0-1218be1cbc9d' + CENTOS_TAG: '2023-01-18.0-503dba0518ae' ALPINE_TAG: '2023-01-18.0-14c807942fa4' FEDORA_EXEC: 'bash .gitlab-ci/fedora-install.sh' diff --git a/contrib/debian/REQUIRED_PACKAGES b/contrib/debian/REQUIRED_PACKAGES index 34e591ddc7..4e8bb8c603 100755 --- a/contrib/debian/REQUIRED_PACKAGES +++ b/contrib/debian/REQUIRED_PACKAGES @@ -12,11 +12,14 @@ set -xe # Not all of these packages are strictly speaking necessary. # This is a generous list of related packages. +SUDO= +[ "$EUID" -eq 0 ] || SUDO=sudo + install() { if [ "$NM_INSTALL" != "" ]; then $NM_INSTALL "$@" else - sudo apt-get install -y "$@" + $SUDO apt-get install -y "$@" fi } diff --git a/contrib/fedora/REQUIRED_PACKAGES b/contrib/fedora/REQUIRED_PACKAGES index c77f4ccdc1..644e518b1b 100755 --- a/contrib/fedora/REQUIRED_PACKAGES +++ b/contrib/fedora/REQUIRED_PACKAGES @@ -14,11 +14,14 @@ set -xe DNF="$(command -v dnf &>/dev/null && echo dnf || echo yum)" +SUDO= +[ "$EUID" -eq 0 ] || SUDO=sudo + install() { if [ "$NM_INSTALL" != "" ]; then $NM_INSTALL "$@" else - sudo "$DNF" install -y "$@" + $SUDO "$DNF" install -y "$@" fi } From ec454f924c562661b94afaceee7499e734e6314e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 11:05:33 +0100 Subject: [PATCH 06/21] test-client: pass extra argument in "test-client.sh" to python test For example: $ src/tests/client/test-client.sh -- TestNmcli.test_004 $ src/tests/client/test-client.sh -- -k monitor (cherry picked from commit b76bb7333e11448b4692bf57c123d564eaf0864e) --- Makefile.am | 2 +- src/tests/client/meson.build | 1 + src/tests/client/test-client.sh | 61 +++++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3d43c010a7..43c82a9088 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5456,7 +5456,7 @@ endif ############################################################################### check-local-tests-client: src/nmcli/nmcli src/tests/client/test-client.py - "$(srcdir)/src/tests/client/test-client.sh" "$(builddir)" "$(srcdir)" "$(PYTHON)" + "$(srcdir)/src/tests/client/test-client.sh" "$(builddir)" "$(srcdir)" "$(PYTHON)" -- check_local += check-local-tests-client diff --git a/src/tests/client/meson.build b/src/tests/client/meson.build index b2e455bbbd..9dd58623a6 100644 --- a/src/tests/client/meson.build +++ b/src/tests/client/meson.build @@ -7,6 +7,7 @@ test( build_root, source_root, python.path(), + '--', ], timeout: 120, ) diff --git a/src/tests/client/test-client.sh b/src/tests/client/test-client.sh index 985d07c91a..a636f5fb93 100755 --- a/src/tests/client/test-client.sh +++ b/src/tests/client/test-client.sh @@ -1,5 +1,30 @@ #!/bin/bash +# Runs the "test-python.sh" test, setting proper environment variables +# for the build tree. +# +# - the first three arguments are the BUILDDIR, SRCDIR and PYTHON paths. +# The following arguments are passed on to "test-python.sh". +# +# - you can use "--" to separate the extra arguments. +# +# The full format is +# +# $ src/tests/client/test-client.sh "$BUILDDIR" "$SRCDIR" "$PYTHON" -- "${EXTRA[@]}" +# +# - "$BUILDDIR" "$SRCDIR" and "$PYTHON" can be set to "", to fallback +# to a default. +# +# The safe way to call it is thus +# +# $ src/tests/client/test-client.sh "" "" "" -- "${EXTRA[@]}" +# +# but for brevity, you can also call +# +# $ src/tests/client/test-client.sh -- "${EXTRA[@]}" +# +# if (and only if) "${EXTRA[@]}" does not contain "--". + set -e die() { @@ -7,29 +32,45 @@ die() { exit 1 } -if [ "$2" != "" ]; then - SRCDIR="$(realpath "$2")" +if [ "$4" = "--" ] ; then + ARGS=("${@:1:3}") + EXTRA=("${@:5}") +elif [ "$3" = "--" ]; then + ARGS=("${@:1:2}") + EXTRA=("${@:4}") +elif [ "$2" = "--" ]; then + ARGS=("${@:1:1}") + EXTRA=("${@:3}") +elif [ "$1" = "--" ]; then + ARGS=() + EXTRA=("${@:2}") +else + ARGS=("${@:1:3}") + EXTRA=("${@:4}") +fi + +if [ "${ARGS[1]}" != "" ]; then + SRCDIR="$(realpath "${ARGS[1]}")" else SRCDIR="$(realpath "$(dirname "$BASH_SOURCE")/../../..")" fi -if [ "$1" != "" ]; then - BUILDDIR="$(realpath "$1")" +if [ "${ARGS[0]}" != "" ]; then + BUILDDIR="$(realpath "${ARGS[0]}")" elif test -d "$SRCDIR/build" ; then BUILDDIR="$(realpath "$SRCDIR/build")" else BUILDDIR="$SRCDIR" fi -test -d "$BUILDDIR" || die "BUILDDIR \"$BUILDDIR\" does not exist?" -test -d "$SRCDIR" || die "SRCDIR \"$SRCDIR\" does not exist?" - -if [ "$3" != "" ]; then - PYTHON="$3" +if [ "${ARGS[2]}" != "" ]; then + PYTHON="${ARGS[2]}" elif [ "$PYTHON" == "" ]; then PYTHON="$(command -v python)" || die "python not found?" fi +test -d "$BUILDDIR" || die "BUILDDIR \"$BUILDDIR\" does not exist?" +test -d "$SRCDIR" || die "SRCDIR \"$SRCDIR\" does not exist?" test -f "$BUILDDIR/src/nmcli/nmcli" || die "\"$BUILDDIR/src/nmcli/nmcli\" does not exist?" if test -f "$BUILDDIR/src/libnm-client-impl/.libs/libnm.so" ; then @@ -57,7 +98,7 @@ export NM_TEST_CLIENT_BUILDDIR="$BUILDDIR" # test output is grouped together. r="ok" -"$PYTHON" "$SRCDIR/src/tests/client/test-client.py" -v &> "$BUILDDIR/src/tests/client/test-client.log" || r=fail +"$PYTHON" "$SRCDIR/src/tests/client/test-client.py" -v "${EXTRA[@]}" &> "$BUILDDIR/src/tests/client/test-client.log" || r=fail cat "$BUILDDIR/src/tests/client/test-client.log" From d0896a13ee57c7b1d560588c44c60a6cd66717ac Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 13:26:32 +0100 Subject: [PATCH 07/21] test-client: add Util.shlex_join() helper (cherry picked from commit 5da7301ec981f8887ddb1dd2a7447d5a566263d9) --- src/tests/client/test-client.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index e936c4c452..66212501eb 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -251,7 +251,8 @@ class Util: ).search @staticmethod - def quote(s): + def shlex_quote(s): + # Reimplement shlex.quote(). if Util.python_has_version(3, 3): return shlex.quote(s) if not s: @@ -260,6 +261,11 @@ class Util: return s return "'" + s.replace("'", "'\"'\"'") + "'" + @staticmethod + def shlex_join(args): + # Reimplement shlex.join() + return " ".join(Util.shlex_quote(s) for s in args) + @staticmethod def popen_wait(p, timeout=0): (res, b_stdout, b_stderr) = Util.popen_wait_read( @@ -1024,7 +1030,7 @@ class TestNmcli(NmTestBase): self.assertEqual(returncode, -5) if check_on_disk: - cmd = "$NMCLI %s" % (" ".join([Util.quote(a) for a in args[1:]])) + cmd = "$NMCLI %s" % (Util.shlex_join(args[1:]),) cmd = Util.replace_text(cmd, replace_cmd) if returncode < 0: @@ -1971,16 +1977,13 @@ def main(): "eval `dbus-launch --sh-syntax`;\n" + 'trap "kill $DBUS_SESSION_BUS_PID" EXIT;\n' + "\n" - + " ".join( + + Util.shlex_join( [ - Util.quote(a) - for a in [ - sys.executable, - __file__, - "--started-with-dbus-session", - ] - + sys.argv[1:] + sys.executable, + __file__, + "--started-with-dbus-session", ] + + sys.argv[1:] ) + " \n" + "", From c9951d5d32c0a2b9697233d82201b2b631a81309 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 14:06:46 +0100 Subject: [PATCH 08/21] test-client: accept yes/true/no/false for boolean arguments (cherry picked from commit b08f7a9c1935198cafd490303e61ae59e2b28978) --- src/tests/client/test-client.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index 66212501eb..0202d86e0e 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -228,6 +228,19 @@ class Util: t = basestring return isinstance(s, t) + @staticmethod + def is_bool(s, defval=False): + if s is None: + return defval + if isinstance(s, int): + return s != 0 + if isinstance(s, str): + if s.lower() in ["1", "y", "yes", "true", "on"]: + return True + if s.lower() in ["0", "n", "no", "false", "off"]: + return False + raise ValueError('Argument "%s" is not a boolean' % (s,)) + @staticmethod def as_bytes(s): if Util.is_string(s): @@ -499,14 +512,14 @@ class Configuration: # # Only by setting NM_TEST_CLIENT_CHECK_L10N=1, these tests are included # as well. - v = os.environ.get(ENV_NM_TEST_CLIENT_CHECK_L10N, "0") == "1" + v = Util.is_bool(os.environ.get(ENV_NM_TEST_CLIENT_CHECK_L10N, None)) elif name == ENV_NM_TEST_REGENERATE: # in the "regenerate" mode, the tests will rewrite the files on disk against # which we assert. That is useful, if there are intentional changes and # we want to regenerate the expected output. - v = os.environ.get(ENV_NM_TEST_REGENERATE, "0") == "1" + v = Util.is_bool(os.environ.get(ENV_NM_TEST_REGENERATE, None)) elif name == ENV_NM_TEST_WITH_LINENO: - v = os.environ.get(ENV_NM_TEST_WITH_LINENO, "0") == "1" + v = Util.is_bool(os.environ.get(ENV_NM_TEST_WITH_LINENO, None)) elif name in [ ENV_NM_TEST_ASAN_OPTIONS, ENV_NM_TEST_LSAN_OPTIONS, From 05e5a2fefd5be605f3cdec0e5704af5ac7a6bcba Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Feb 2023 11:56:38 +0100 Subject: [PATCH 09/21] test-client: cleanup start/shutdown of stub service (cherry picked from commit 3e574dda220afa52496aa0ae814eb207a7e25db8) --- src/tests/client/test-client.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index 0202d86e0e..15f450af79 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -754,6 +754,16 @@ MAX_JOBS = 15 class TestNmcli(NmTestBase): + def srv_start(self): + self.srv_shutdown() + self.srv = NMStubServer(self._testMethodName) + + def srv_shutdown(self): + if self.srv is not None: + srv = self.srv + self.srv = None + srv.shutdown() + def ReplaceTextConUuid(self, con_name, replacement): return Util.ReplaceTextSimple( Util.memoize_nullary(lambda: self.srv.findConnectionUuid(con_name)), @@ -1130,9 +1140,7 @@ class TestNmcli(NmTestBase): self.async_wait() - if self.srv is not None: - self.srv.shutdown() - self.srv = None + self.srv_shutdown() self._calling_num = None @@ -1248,7 +1256,7 @@ class TestNmcli(NmTestBase): def nm_test(func): def f(self): - self.srv = NMStubServer(self._testMethodName) + self.srv_start() func(self) self._nm_test_post() @@ -1935,8 +1943,7 @@ class TestNmcli(NmTestBase): end_mon(nmc) nmc = start_mon() - self.srv.shutdown() - self.srv = None + self.srv_shutdown() nmc.expect("eth0: device removed") nmc.expect("con-1: connection profile removed") nmc.expect("NetworkManager is stopped") From 0e13811a4b5cee0911a666c868d24e815d666cd7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Feb 2023 12:14:31 +0100 Subject: [PATCH 10/21] test-client: drop unused NmTestBase base class The base class is not used, and it's not clear that it would be useful. Sure, we could extend "test-client.py" will various non-nmcli tests. That might make sense. And then it might make sense to have more unit test classes. So far, we don't need that. Drop the unused base class NmTestBase. (cherry picked from commit d1e6d530130fd06a83ea440a5b244f0c68fcfd2f) --- src/tests/client/test-client.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index 15f450af79..dc8252ce7c 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -740,20 +740,18 @@ class AsyncProcess: ############################################################################### -class NmTestBase(unittest.TestCase): +MAX_JOBS = 15 + + +class TestNmcli(unittest.TestCase): def __init__(self, *args, **kwargs): self._calling_num = {} self._skip_test_for_l10n_diff = [] self._async_jobs = [] self._results = [] self.srv = None - return unittest.TestCase.__init__(self, *args, **kwargs) + unittest.TestCase.__init__(self, *args, **kwargs) - -MAX_JOBS = 15 - - -class TestNmcli(NmTestBase): def srv_start(self): self.srv_shutdown() self.srv = NMStubServer(self._testMethodName) From ba5cbedd2ca4315313b966a4fdf8b38bd3277475 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Feb 2023 14:07:25 +0100 Subject: [PATCH 11/21] test-client: add valgrind support for call_nmcli_pexpect() tests This will allow to find some memory leaks and memory corruptions. The bulk of the nmcli calls are still not hooked up with valgrind. Since we call nmcli a thousand time, we could not just run valgrind with all of them. We would have instead to enable it randomly. This is more work. (cherry picked from commit debf78dbedbbe00acf34a2ba0f71a79fd130b407) --- Makefile.am | 2 +- src/tests/client/meson.build | 3 + src/tests/client/test-client.py | 179 +++++++++++++++++++++++++------- 3 files changed, 146 insertions(+), 38 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43c82a9088..a452cacac4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5456,7 +5456,7 @@ endif ############################################################################### check-local-tests-client: src/nmcli/nmcli src/tests/client/test-client.py - "$(srcdir)/src/tests/client/test-client.sh" "$(builddir)" "$(srcdir)" "$(PYTHON)" -- + LIBTOOL="$(LIBTOOL)" "$(srcdir)/src/tests/client/test-client.sh" "$(builddir)" "$(srcdir)" "$(PYTHON)" -- check_local += check-local-tests-client diff --git a/src/tests/client/meson.build b/src/tests/client/meson.build index 9dd58623a6..6dc0f2a2c8 100644 --- a/src/tests/client/meson.build +++ b/src/tests/client/meson.build @@ -9,5 +9,8 @@ test( python.path(), '--', ], + env: [ + 'LIBTOOL=', + ], timeout: 120, ) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index dc8252ce7c..cb1bef6ae6 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -90,7 +90,12 @@ ENV_NM_TEST_ASAN_OPTIONS = "NM_TEST_ASAN_OPTIONS" ENV_NM_TEST_LSAN_OPTIONS = "NM_TEST_LSAN_OPTIONS" ENV_NM_TEST_UBSAN_OPTIONS = "NM_TEST_UBSAN_OPTIONS" -# +# Run nmcli under valgrind. If unset, we honor NMTST_USE_VALGRIND instead. +# Valgrind is always disabled, if NM_TEST_REGENERATE is enabled. +ENV_NM_TEST_VALGRIND = "NM_TEST_VALGRIND" + +ENV_LIBTOOL = "LIBTOOL" + ############################################################################### import sys @@ -107,8 +112,10 @@ import fcntl import dbus import time import random +import tempfile import dbus.service import dbus.mainloop.glib +import collections import io from signal import SIGINT @@ -474,6 +481,38 @@ class Util: for color in [[], ["--color", "yes"]]: yield mode + fmt + color + @staticmethod + def valgrind_check_log(valgrind_log, logname): + if valgrind_log is None: + return + + fd, name = valgrind_log + + os.close(fd) + + if not os.path.isfile(name): + raise Exception("valgrind log %s unexpectedly does not exist" % (name,)) + + if os.path.getsize(name) != 0: + out = subprocess.run( + [ + "sed", + "-e", + "/^--[0-9]\+-- WARNING: unhandled .* syscall: /,/^--[0-9]\+-- it at http.*\.$/d", + name, + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + if out.returncode != 0: + raise Exception('Calling "sed" to search valgrind log failed') + if out.stdout: + print("valgrind log %s for %s is not empty:" % (name, logname)) + print("\n%s\n" % (out.stdout.decode("utf-8", errors="replace"),)) + raise Exception("valgrind log %s unexpectedly is not empty" % (name,)) + + os.remove(name) + ############################################################################### @@ -520,6 +559,15 @@ class Configuration: v = Util.is_bool(os.environ.get(ENV_NM_TEST_REGENERATE, None)) elif name == ENV_NM_TEST_WITH_LINENO: v = Util.is_bool(os.environ.get(ENV_NM_TEST_WITH_LINENO, None)) + elif name == ENV_NM_TEST_VALGRIND: + if self.get(ENV_NM_TEST_REGENERATE): + v = False + else: + v = os.environ.get(ENV_NM_TEST_VALGRIND, None) + if v: + v = Util.is_bool(v) + else: + v = Util.is_bool(os.environ.get("NMTST_USE_VALGRIND", None)) elif name in [ ENV_NM_TEST_ASAN_OPTIONS, ENV_NM_TEST_LSAN_OPTIONS, @@ -536,6 +584,21 @@ class Configuration: v = "print_stacktrace=1:halt_on_error=1" else: assert False + elif name == ENV_LIBTOOL: + v = os.environ.get(name, None) + if v is None: + v = os.path.abspath( + os.path.dirname(self.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)) + + "/../../libtool" + ) + if not os.path.isfile(v): + v = None + else: + v = [v] + elif not v: + v = None + else: + v = shlex.split(v) else: raise Exception() self._values[name] = v @@ -796,6 +859,39 @@ class TestNmcli(unittest.TestCase): return content_expect, results_expect + def nmcli_construct_argv(self, args, with_valgrind=None): + + if with_valgrind is None: + with_valgrind = conf.get(ENV_NM_TEST_VALGRIND) + + valgrind_log = None + cmd = conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH) + if with_valgrind: + valgrind_log = tempfile.mkstemp(prefix="nm-test-client-valgrind.") + argv = [ + "valgrind", + "--quiet", + "--error-exitcode=37", + "--leak-check=full", + "--gen-suppressions=all", + ( + "--suppressions=" + + PathConfiguration.top_srcdir() + + "/valgrind.suppressions" + ), + "--num-callers=100", + "--log-file=" + valgrind_log[1], + cmd, + ] + libtool = conf.get(ENV_LIBTOOL) + if libtool: + argv = list(libtool) + ["--mode=execute"] + argv + else: + argv = [cmd] + + argv.extend(args) + return argv, valgrind_log + def call_nmcli_l( self, args, @@ -879,10 +975,14 @@ class TestNmcli(unittest.TestCase): ) def call_nmcli_pexpect(self, args): + env = self._env(extra_env={"NO_COLOR": "1"}) - return pexpect.spawn( - conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH), args, timeout=10, env=env - ) + argv, valgrind_log = self.nmcli_construct_argv(args) + + pexp = pexpect.spawn(argv[0], argv[1:], timeout=10, env=env) + + typ = collections.namedtuple("CallNmcliPexpect", ["pexp", "valgrind_log"]) + return typ(pexp, valgrind_log) def _env( self, lang="C", calling_num=None, fatal_warnings=_DEFAULT_ARG, extra_env=None @@ -978,7 +1078,10 @@ class TestNmcli(unittest.TestCase): else: self.fail("invalid language %s" % (lang)) - args = [conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)] + list(args) + # Running under valgrind is not yet supported for those tests. + args, valgrind_log = self.nmcli_construct_argv(args, with_valgrind=False) + + assert valgrind_log is None if replace_stdout is not None: replace_stdout = list(replace_stdout) @@ -1892,24 +1995,25 @@ class TestNmcli(unittest.TestCase): @nm_test def test_ask_mode(self): nmc = self.call_nmcli_pexpect(["--ask", "c", "add"]) - nmc.expect("Connection type:") - nmc.sendline("ethernet") - nmc.expect("Interface name:") - nmc.sendline("eth0") - nmc.expect("There are 3 optional settings for Wired Ethernet.") - nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") - nmc.sendline("no") - nmc.expect("There are 2 optional settings for IPv4 protocol.") - nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") - nmc.sendline("no") - nmc.expect("There are 2 optional settings for IPv6 protocol.") - nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") - nmc.sendline("no") - nmc.expect("There are 4 optional settings for Proxy.") - nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") - nmc.sendline("no") - nmc.expect("Connection 'ethernet' \(.*\) successfully added.") - nmc.expect(pexpect.EOF) + nmc.pexp.expect("Connection type:") + nmc.pexp.sendline("ethernet") + nmc.pexp.expect("Interface name:") + nmc.pexp.sendline("eth0") + nmc.pexp.expect("There are 3 optional settings for Wired Ethernet.") + nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.pexp.sendline("no") + nmc.pexp.expect("There are 2 optional settings for IPv4 protocol.") + nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.pexp.sendline("no") + nmc.pexp.expect("There are 2 optional settings for IPv6 protocol.") + nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.pexp.sendline("no") + nmc.pexp.expect("There are 4 optional settings for Proxy.") + nmc.pexp.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.pexp.sendline("no") + nmc.pexp.expect("Connection 'ethernet' \(.*\) successfully added.") + nmc.pexp.expect(pexpect.EOF) + Util.valgrind_check_log(nmc.valgrind_log, "test_ask_mode") @skip_without_pexpect @nm_test @@ -1919,33 +2023,34 @@ class TestNmcli(unittest.TestCase): # https://bugzilla.redhat.com/show_bug.cgi?id=2154288 raise unittest.SkipTest("test is known to randomly fail (rhbz#2154288)") - def start_mon(): + def start_mon(self): nmc = self.call_nmcli_pexpect(["monitor"]) - nmc.expect("NetworkManager is running") + nmc.pexp.expect("NetworkManager is running") return nmc - def end_mon(nmc): - nmc.kill(SIGINT) - nmc.expect(pexpect.EOF) + def end_mon(self, nmc): + nmc.pexp.kill(SIGINT) + nmc.pexp.expect(pexpect.EOF) + Util.valgrind_check_log(nmc.valgrind_log, "test_monitor") - nmc = start_mon() + nmc = start_mon(self) self.srv.op_AddObj("WiredDevice", iface="eth0") - nmc.expect("eth0: device created\r\n") + nmc.pexp.expect("eth0: device created\r\n") self.srv.addConnection( {"connection": {"type": "802-3-ethernet", "id": "con-1"}} ) - nmc.expect("con-1: connection profile created\r\n") + nmc.pexp.expect("con-1: connection profile created\r\n") - end_mon(nmc) + end_mon(self, nmc) - nmc = start_mon() + nmc = start_mon(self) self.srv_shutdown() - nmc.expect("eth0: device removed") - nmc.expect("con-1: connection profile removed") - nmc.expect("NetworkManager is stopped") - end_mon(nmc) + nmc.pexp.expect("eth0: device removed") + nmc.pexp.expect("con-1: connection profile removed") + nmc.pexp.expect("NetworkManager is stopped") + end_mon(self, nmc) ############################################################################### From 0694ecfcc5de953571af0fb8e85e7d028ba16308 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Feb 2023 12:40:50 +0100 Subject: [PATCH 12/21] test-client: cleanup imports Sort imports by name. Also avoid "from signal import SIGINT". I find it ugly to import names in the current namespace. "SIGINT" should be refered to by its full name, including the package/namespace. (cherry picked from commit ee17346cee3c116db5ebebd3f4e4fe81a58944b7) --- src/tests/client/test-client.py | 43 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index cb1bef6ae6..dd90947b76 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -98,26 +98,25 @@ ENV_LIBTOOL = "LIBTOOL" ############################################################################### -import sys - -import os -import errno -import unittest -import socket -import itertools -import subprocess -import shlex -import re -import fcntl -import dbus -import time -import random -import tempfile -import dbus.service -import dbus.mainloop.glib import collections +import dbus +import dbus.mainloop.glib +import dbus.service +import errno +import fcntl import io -from signal import SIGINT +import itertools +import os +import random +import re +import shlex +import signal +import socket +import subprocess +import sys +import tempfile +import time +import unittest import gi @@ -215,10 +214,10 @@ class Util: } @classmethod - def signal_no_to_str(cls, signal): - s = cls._signal_no_lookup.get(signal, None) + def signal_no_to_str(cls, sig): + s = cls._signal_no_lookup.get(sig, None) if s is None: - return "" % (signal) + return "" % (sig) return s @staticmethod @@ -2029,7 +2028,7 @@ class TestNmcli(unittest.TestCase): return nmc def end_mon(self, nmc): - nmc.pexp.kill(SIGINT) + nmc.pexp.kill(signal.SIGINT) nmc.pexp.expect(pexpect.EOF) Util.valgrind_check_log(nmc.valgrind_log, "test_monitor") From 6adca24ee122ce5530784a179ff0a776d998cf6a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 12:31:38 +0100 Subject: [PATCH 13/21] libnm: support LIBNM_CLIENT_DEBUG_FILE to print debug logging to file With LIBNM_CLIENT_DEBUG we get debug logging for libnm, either to stdout or to stderr. "test-client.py" runs nmcli as a unit test. It thereby catches stdout and stderr. That means, LIBNM_CLIENT_DEBUG would break the tests. Now honor the LIBNM_CLIENT_DEBUG_FILE environment variable to specify a file to which the debug logs get written. The pattern "%p" is replaced by the process id. As before, nm_utils_print(0, ...) also honors this environment variable and uses the same logging destination. (cherry picked from commit 6dbb215793e5f36a84c39a8edcf327c8df229543) --- src/libnm-client-impl/nm-libnm-utils.c | 140 +++++++++++++++++++++---- 1 file changed, 120 insertions(+), 20 deletions(-) diff --git a/src/libnm-client-impl/nm-libnm-utils.c b/src/libnm-client-impl/nm-libnm-utils.c index 9d51226347..398c6ebcfa 100644 --- a/src/libnm-client-impl/nm-libnm-utils.c +++ b/src/libnm-client-impl/nm-libnm-utils.c @@ -16,7 +16,13 @@ /*****************************************************************************/ -volatile int _nml_dbus_log_level = 0; +#define LOG_FILE_FD_UNSET -3 +#define LOG_FILE_FD_NONE -2 +#define LOG_FILE_FD_DEFUNCT -1 + +volatile int _nml_dbus_log_level = 0; +const char *_nml_dbus_log_file = NULL; +int _nml_dbus_log_file_fd = LOG_FILE_FD_UNSET; int _nml_dbus_log_level_init(void) @@ -40,6 +46,97 @@ _nml_dbus_log_level_init(void) return l; } +static const char * +_nml_dbus_log_file_init(void) +{ + const char *s; + + s = g_getenv("LIBNM_CLIENT_DEBUG_FILE"); + if (nm_str_not_empty(s)) { + if (strstr(s, "%p")) { + gs_strfreev char **tokens = NULL; + char pid_str[100]; + + tokens = g_strsplit(s, "%p", -1); + nm_sprintf_buf(pid_str, "%lld", (long long) getpid()); + s = nm_str_realloc(g_strjoinv(pid_str, tokens)); + } else + s = g_strdup(s); + } else + s = ""; + + if (!g_atomic_pointer_compare_and_exchange(&_nml_dbus_log_file, NULL, s)) { + if (s[0] != '\0') + g_free((gpointer) s); + s = g_atomic_pointer_get(&_nml_dbus_log_file); + } + + return s; +} + +#define nml_dbus_log_file() \ + ({ \ + const char *_l; \ + \ + _l = g_atomic_pointer_get(&_nml_dbus_log_file); \ + if (G_UNLIKELY(!_l)) \ + _l = _nml_dbus_log_file_init(); \ + \ + _l[0] ? _l : NULL; \ + }) + +static int +_nml_dbus_log_file_fd_init(void) +{ + static GMutex mutex; + NM_G_MUTEX_LOCKED(&mutex); + int fd; + + fd = g_atomic_int_get(&_nml_dbus_log_file_fd); + if (fd == LOG_FILE_FD_UNSET) { + const char *name; + + name = nml_dbus_log_file(); + if (!name) + fd = LOG_FILE_FD_NONE; + else { + fd = open(name, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0600); + if (fd < 0) + fd = LOG_FILE_FD_DEFUNCT; + } + g_atomic_int_set(&_nml_dbus_log_file_fd, fd); + } + + return fd; +} + +#define nml_dbus_log_file_fd() \ + ({ \ + int _fd2; \ + \ + _fd2 = g_atomic_int_get(&_nml_dbus_log_file_fd); \ + if (G_UNLIKELY(_fd2 == LOG_FILE_FD_UNSET)) \ + _fd2 = _nml_dbus_log_file_fd_init(); \ + \ + nm_assert(NM_IN_SET(_fd2, LOG_FILE_FD_NONE, LOG_FILE_FD_DEFUNCT) || _fd2 >= 0); \ + _fd2; \ + }) + +#define _log_printf(use_stdout, ...) \ + G_STMT_START \ + { \ + const int _fd = nml_dbus_log_file_fd(); \ + \ + if (_fd != LOG_FILE_FD_NONE) { \ + if (_fd >= 0) \ + dprintf(_fd, __VA_ARGS__); \ + } else if (use_stdout) \ + g_print(__VA_ARGS__); \ + else \ + g_printerr(__VA_ARGS__); \ + } \ + G_STMT_END + void _nml_dbus_log(NMLDBusLogLevel level, gboolean use_stdout, const char *fmt, ...) { @@ -94,21 +191,13 @@ _nml_dbus_log(NMLDBusLogLevel level, gboolean use_stdout, const char *fmt, ...) pid = getpid(); - if (use_stdout) { - g_print("libnm-dbus[%lld]: %s[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s\n", + _log_printf(use_stdout, + "libnm-dbus[%lld]: %s[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s\n", (long long) pid, prefix, ts / NM_UTILS_NSEC_PER_SEC, (ts / (NM_UTILS_NSEC_PER_SEC / 100000)) % 100000, msg); - } else { - g_printerr("libnm-dbus[%lld]: %s[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s\n", - (long long) pid, - prefix, - ts / NM_UTILS_NSEC_PER_SEC, - (ts / (NM_UTILS_NSEC_PER_SEC / 100000)) % 100000, - msg); - } } /*****************************************************************************/ @@ -884,8 +973,10 @@ nm_utils_g_param_spec_is_default(const GParamSpec *pspec) /** * nm_utils_print: * @output_mode: if 1 it uses g_print(). If 2, it uses g_printerr(). - * If 0, it uses either g_print() or g_printerr(), depending - * on LIBNM_CLIENT_DEBUG (and the "stdout" flag). + * If 0, it uses the same output as internal libnm debug logging + * does. That is, depending on LIBNM_CLIENT_DEBUG's "stdout" flag + * it uses g_print() or g_printerr() and if LIBNM_CLIENT_DEBUG_FILE is + * set, it writes the output to file instead * @msg: the message to print. The function does not append * a trailing newline. * @@ -896,6 +987,11 @@ nm_utils_g_param_spec_is_default(const GParamSpec *pspec) * with these functions (it implements additional buffering). By * using nm_utils_print(), the same logging mechanisms can be used. * + * Also, libnm honors LIBNM_CLIENT_DEBUG_FILE environment. If this + * is set to a filename pattern (accepting "%p" for the process ID), + * then the debug log is written to that file instead. With @output_mode + * zero, the same location will be written. Since: 1.44. + * * Since: 1.30 */ void @@ -905,17 +1001,21 @@ nm_utils_print(int output_mode, const char *msg) g_return_if_fail(msg); - if (output_mode == 0) { + switch (output_mode) { + case 0: nml_dbus_log_enabled_full(NML_DBUS_LOG_LEVEL_ANY, &use_stdout); - output_mode = use_stdout ? 1 : 2; - } - - if (output_mode == 1) + _log_printf(use_stdout, "%s", msg); + break; + case 1: g_print("%s", msg); - else if (output_mode == 2) + break; + case 2: g_printerr("%s", msg); - else + break; + default: g_return_if_reached(); + break; + } } /*****************************************************************************/ From 1a9892620e773c10105717ee0301b1813447bb70 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 11:25:36 +0100 Subject: [PATCH 14/21] test-client: pass LIBNM_CLIENT_DEBUG to nmcli For debugging libnm, LIBNM_CLIENT_DEBUG can be very useful. As the tests compare stdout/stderr from nmcli with expected output, just enabling it will break the tests. However, in combination with LIBNM_CLIENT_DEBUG_FILE this can be very useful. Preserve and pass on the environment variables, if set. (cherry picked from commit 1630009234b3164225671fb485bd75e92d38c69a) --- src/tests/client/test-client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index dd90947b76..2c8f332706 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -996,7 +996,12 @@ class TestNmcli(unittest.TestCase): self.fail("invalid language %s" % (lang)) env = {} - for k in ["LD_LIBRARY_PATH", "DBUS_SESSION_BUS_ADDRESS"]: + for k in [ + "LD_LIBRARY_PATH", + "DBUS_SESSION_BUS_ADDRESS", + "LIBNM_CLIENT_DEBUG", + "LIBNM_CLIENT_DEBUG_FILE", + ]: val = os.environ.get(k, None) if val is not None: env[k] = val From 6298b322816ec43cbf559ebc907a3d7b3bb3e90d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 16:36:47 +0100 Subject: [PATCH 15/21] nmcli/trivial: rename monitor functions in internal header file Identifiers in our headers should have a "nm" prefix. Rename. (cherry picked from commit d3e2e9dc20756aeeaadfd6eec5ee50fa24aaaf50) --- src/nmcli/connections.c | 2 +- src/nmcli/connections.h | 2 +- src/nmcli/devices.c | 2 +- src/nmcli/devices.h | 2 +- src/nmcli/general.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 610248c865..059bbbf99a 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -10117,7 +10117,7 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c } void -monitor_connections(NmCli *nmc) +nmc_monitor_connections(NmCli *nmc) { do_connection_monitor(NULL, nmc, 0, NULL); } diff --git a/src/nmcli/connections.h b/src/nmcli/connections.h index c610766a62..48c981704d 100644 --- a/src/nmcli/connections.h +++ b/src/nmcli/connections.h @@ -8,7 +8,7 @@ #include "nmcli.h" -void monitor_connections(NmCli *nmc); +void nmc_monitor_connections(NmCli *nmc); const char *nmc_connection_check_deprecated(NMConnection *c); diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c index f71a7d036d..dd7007ffbd 100644 --- a/src/nmcli/devices.c +++ b/src/nmcli/devices.c @@ -5328,7 +5328,7 @@ nmc_command_func_device(const NMCCommand *cmd, NmCli *nmc, int argc, const char } void -monitor_devices(NmCli *nmc) +nmc_monitor_devices(NmCli *nmc) { do_devices_monitor(NULL, nmc, 0, NULL); } diff --git a/src/nmcli/devices.h b/src/nmcli/devices.h index 6214ea035a..7ed75909b3 100644 --- a/src/nmcli/devices.h +++ b/src/nmcli/devices.h @@ -12,7 +12,7 @@ void nmc_complete_device(NMClient *client, const char *prefix, gboolean wifi_onl void nmc_complete_bssid(NMClient *client, const char *ifname, const char *bssid_prefix); -void monitor_devices(NmCli *nmc); +void nmc_monitor_devices(NmCli *nmc); NMDevice **nmc_get_devices_sorted(NMClient *client); diff --git a/src/nmcli/general.c b/src/nmcli/general.c index b050d2b740..20471365a8 100644 --- a/src/nmcli/general.c +++ b/src/nmcli/general.c @@ -1632,6 +1632,6 @@ nmc_command_func_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char nmc->should_wait++; - monitor_devices(nmc); - monitor_connections(nmc); + nmc_monitor_devices(nmc); + nmc_monitor_connections(nmc); } From a791078798ec43d510ad7e93a5e86018eacdfc9d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 17:00:00 +0100 Subject: [PATCH 16/21] nmcli/trivial: rename nmc_print() to nmc_print_table() nmc_print() will be used for something else. Rename. Also, nmc_print_table() is the better name anyway because the function does a lot of formatting and not simple printf(). (cherry picked from commit 4b2ded7a4aacc00107f216e577d46b8eaa7cf424) --- src/nmcli/common.c | 36 ++++++------ src/nmcli/connections.c | 45 +++++++-------- src/nmcli/devices.c | 119 ++++++++++++++++++++-------------------- src/nmcli/general.c | 42 +++++++------- src/nmcli/settings.c | 2 +- src/nmcli/utils.c | 14 ++--- src/nmcli/utils.h | 14 ++--- 7 files changed, 137 insertions(+), 135 deletions(-) diff --git a/src/nmcli/common.c b/src/nmcli/common.c index 4229f66034..8c89f82dcc 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -354,15 +354,15 @@ print_ip_config(NMIPConfig *cfg, g_strdup_printf("IP%c.%s", nm_utils_addr_family_to_char(addr_family), one_field); } - if (!nmc_print(nmc_config, - (gpointer[]){cfg, NULL}, - NULL, - NULL, - addr_family == AF_INET - ? NMC_META_GENERIC_GROUP("IP4", metagen_ip4_config, N_("GROUP")) - : NMC_META_GENERIC_GROUP("IP6", metagen_ip6_config, N_("GROUP")), - field_str, - &error)) { + if (!nmc_print_table(nmc_config, + (gpointer[]){cfg, NULL}, + NULL, + NULL, + addr_family == AF_INET + ? NMC_META_GENERIC_GROUP("IP4", metagen_ip4_config, N_("GROUP")) + : NMC_META_GENERIC_GROUP("IP6", metagen_ip6_config, N_("GROUP")), + field_str, + &error)) { return FALSE; } return TRUE; @@ -385,15 +385,15 @@ print_dhcp_config(NMDhcpConfig *dhcp, g_strdup_printf("DHCP%c.%s", nm_utils_addr_family_to_char(addr_family), one_field); } - if (!nmc_print(nmc_config, - (gpointer[]){dhcp, NULL}, - NULL, - NULL, - addr_family == AF_INET - ? NMC_META_GENERIC_GROUP("DHCP4", metagen_dhcp_config, N_("GROUP")) - : NMC_META_GENERIC_GROUP("DHCP6", metagen_dhcp_config, N_("GROUP")), - field_str, - &error)) { + if (!nmc_print_table(nmc_config, + (gpointer[]){dhcp, NULL}, + NULL, + NULL, + addr_family == AF_INET + ? NMC_META_GENERIC_GROUP("DHCP4", metagen_dhcp_config, N_("GROUP")) + : NMC_META_GENERIC_GROUP("DHCP6", metagen_dhcp_config, N_("GROUP")), + field_str, + &error)) { return FALSE; } return TRUE; diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 059bbbf99a..97cd991e8b 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -1729,13 +1729,14 @@ nmc_active_connection_details(NMActiveConnection *acon, NmCli *nmc) if (group_fld) f = g_strdup_printf("GENERAL.%s", group_fld); - nmc_print(&nmc->nmc_config, - (gpointer[]){acon, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("GENERAL", metagen_con_active_general, N_("GROUP")), - f, - NULL); + nmc_print_table( + &nmc->nmc_config, + (gpointer[]){acon, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("GENERAL", metagen_con_active_general, N_("GROUP")), + f, + NULL); was_output = TRUE; continue; } @@ -1786,13 +1787,13 @@ nmc_active_connection_details(NMActiveConnection *acon, NmCli *nmc) if (nmc_fields_con_active_details_groups[group_idx]->nested == metagen_con_active_vpn) { if (NM_IS_VPN_CONNECTION(acon)) { - nmc_print(&nmc->nmc_config, - (gpointer[]){acon, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("VPN", metagen_con_active_vpn, N_("NAME")), - group_fld, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){acon, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("VPN", metagen_con_active_vpn, N_("NAME")), + group_fld, + NULL); was_output = TRUE; } continue; @@ -2367,14 +2368,14 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con items = con_show_get_items(nmc, active_only, show_active_fields, order); g_ptr_array_add(items, NULL); - if (!nmc_print(&nmc->nmc_config, - items->pdata, - NULL, - active_only ? _("NetworkManager active profiles") - : _("NetworkManager connection profiles"), - (const NMMetaAbstractInfo *const *) metagen_con_show, - fields_str, - &err)) + if (!nmc_print_table(&nmc->nmc_config, + items->pdata, + NULL, + active_only ? _("NetworkManager active profiles") + : _("NetworkManager connection profiles"), + (const NMMetaAbstractInfo *const *) metagen_con_show, + fields_str, + &err)) goto finish; } else { gboolean new_line = FALSE; diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c index dd7007ffbd..16775fcd3c 100644 --- a/src/nmcli/devices.c +++ b/src/nmcli/devices.c @@ -1653,13 +1653,14 @@ show_device_info(NMDevice *device, NmCli *nmc) if (nmc_fields_dev_show_sections[section_idx]->nested == metagen_device_detail_general) { gs_free char *f = section_fld ? g_strdup_printf("GENERAL.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("GENERAL", metagen_device_detail_general, N_("NAME")), - f, - NULL); + nmc_print_table( + &nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("GENERAL", metagen_device_detail_general, N_("NAME")), + f, + NULL); was_output = TRUE; continue; } @@ -1668,15 +1669,15 @@ show_device_info(NMDevice *device, NmCli *nmc) == metagen_device_detail_capabilities) { gs_free char *f = section_fld ? g_strdup_printf("CAPABILITIES.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("CAPABILITIES", - metagen_device_detail_capabilities, - N_("NAME")), - f, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("CAPABILITIES", + metagen_device_detail_capabilities, + N_("NAME")), + f, + NULL); was_output = TRUE; continue; } @@ -1686,15 +1687,15 @@ show_device_info(NMDevice *device, NmCli *nmc) gs_free char *f = section_fld ? g_strdup_printf("INTERFACE-FLAGS.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("INTERFACE-FLAGS", - metagen_device_detail_interface_flags, - N_("NAME")), - f, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("INTERFACE-FLAGS", + metagen_device_detail_interface_flags, + N_("NAME")), + f, + NULL); was_output = TRUE; continue; } @@ -1705,15 +1706,15 @@ show_device_info(NMDevice *device, NmCli *nmc) gs_free char *f = section_fld ? g_strdup_printf("WIFI-PROPERTIES.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("WIFI-PROPERTIES", - metagen_device_detail_wifi_properties, - N_("NAME")), - f, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("WIFI-PROPERTIES", + metagen_device_detail_wifi_properties, + N_("NAME")), + f, + NULL); was_output = TRUE; } continue; @@ -1769,15 +1770,15 @@ show_device_info(NMDevice *device, NmCli *nmc) gs_free char *f = section_fld ? g_strdup_printf("WIRED-PROPERTIES.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("WIRED-PROPERTIES", - metagen_device_detail_wired_properties, - N_("NAME")), - f, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("WIRED-PROPERTIES", + metagen_device_detail_wired_properties, + N_("NAME")), + f, + NULL); was_output = TRUE; } continue; @@ -1898,15 +1899,15 @@ show_device_info(NMDevice *device, NmCli *nmc) == metagen_device_detail_connections) { gs_free char *f = section_fld ? g_strdup_printf("CONNECTIONS.%s", section_fld) : NULL; - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("CONNECTIONS", - metagen_device_detail_connections, - N_("NAME")), - f, - NULL); + nmc_print_table(&nmc->nmc_config, + (gpointer[]){device, NULL}, + NULL, + NULL, + NMC_META_GENERIC_GROUP("CONNECTIONS", + metagen_device_detail_connections, + N_("NAME")), + f, + NULL); was_output = TRUE; continue; } @@ -1975,13 +1976,13 @@ do_devices_status(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const devices = nmc_get_devices_sorted(nmc->client); - if (!nmc_print(&nmc->nmc_config, - (gpointer *) devices, - NULL, - N_("Status of devices"), - (const NMMetaAbstractInfo *const *) metagen_device_status, - fields_str, - &error)) { + if (!nmc_print_table(&nmc->nmc_config, + (gpointer *) devices, + NULL, + N_("Status of devices"), + (const NMMetaAbstractInfo *const *) metagen_device_status, + fields_str, + &error)) { g_string_printf(nmc->return_text, _("Error: 'device status': %s"), error->message); g_error_free(error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; diff --git a/src/nmcli/general.c b/src/nmcli/general.c index 20471365a8..4cacc027d1 100644 --- a/src/nmcli/general.c +++ b/src/nmcli/general.c @@ -491,13 +491,13 @@ show_nm_status(NmCli *nmc, const char *pretty_header_name, const char *print_fld else fields_str = nmc->required_fields; - if (!nmc_print(&nmc->nmc_config, - (gpointer[]){nmc, NULL}, - NULL, - pretty_header_name ?: N_("NetworkManager status"), - (const NMMetaAbstractInfo *const *) metagen_general_status, - fields_str, - &error)) { + if (!nmc_print_table(&nmc->nmc_config, + (gpointer[]){nmc, NULL}, + NULL, + pretty_header_name ?: N_("NetworkManager status"), + (const NMMetaAbstractInfo *const *) metagen_general_status, + fields_str, + &error)) { g_string_printf(nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all); @@ -570,13 +570,13 @@ print_permissions(void *user_data) nm_cli_spawn_pager(&nmc->nmc_config, &nmc->pager_data); - if (!nmc_print(&nmc->nmc_config, - permissions, - NULL, - _("NetworkManager permissions"), - (const NMMetaAbstractInfo *const *) metagen_general_permissions, - fields_str, - &error)) { + if (!nmc_print_table(&nmc->nmc_config, + permissions, + NULL, + _("NetworkManager permissions"), + (const NMMetaAbstractInfo *const *) metagen_general_permissions, + fields_str, + &error)) { g_string_printf(nmc->return_text, _("Error: 'general permissions': %s"), error->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; } @@ -724,13 +724,13 @@ show_general_logging(NmCli *nmc) } else fields_str = nmc->required_fields; - if (!nmc_print(&nmc->nmc_config, - (gpointer const[]){&d, NULL}, - NULL, - _("NetworkManager logging"), - (const NMMetaAbstractInfo *const *) metagen_general_logging, - fields_str, - &error)) { + if (!nmc_print_table(&nmc->nmc_config, + (gpointer const[]){&d, NULL}, + NULL, + _("NetworkManager logging"), + (const NMMetaAbstractInfo *const *) metagen_general_logging, + fields_str, + &error)) { g_string_printf(nmc->return_text, _("Error: 'general logging': %s"), error->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; } diff --git a/src/nmcli/settings.c b/src/nmcli/settings.c index 8cc151ba21..3eebb17f3f 100644 --- a/src/nmcli/settings.c +++ b/src/nmcli/settings.c @@ -759,7 +759,7 @@ setting_details(const NmcConfig *nmc_config, NMSetting *setting, const char *one fields_str = g_strdup_printf("%s.%s", nm_setting_get_name(setting), one_prop); } - if (!nmc_print( + if (!nmc_print_table( nmc_config, (gpointer[]){setting, NULL}, NULL, diff --git a/src/nmcli/utils.c b/src/nmcli/utils.c index 957c0efaff..3e9674ea6a 100644 --- a/src/nmcli/utils.c +++ b/src/nmcli/utils.c @@ -1387,13 +1387,13 @@ _print_do(const NmcConfig *nmc_config, } gboolean -nmc_print(const NmcConfig *nmc_config, - gpointer const *targets, - gpointer targets_data, - const char *header_name_no_l10n, - const NMMetaAbstractInfo *const *fields, - const char *fields_str, - GError **error) +nmc_print_table(const NmcConfig *nmc_config, + gpointer const *targets, + gpointer targets_data, + const char *header_name_no_l10n, + const NMMetaAbstractInfo *const *fields, + const char *fields_str, + GError **error) { gs_unref_ptrarray GPtrArray *gfree_keeper = NULL; gs_free PrintDataCol *cols_data = NULL; diff --git a/src/nmcli/utils.h b/src/nmcli/utils.h index c6ead55b86..3897cd2b87 100644 --- a/src/nmcli/utils.h +++ b/src/nmcli/utils.h @@ -359,13 +359,13 @@ nmc_meta_generic_get_enum_with_detail(NmcMetaGenericGetEnumType get_enum_type, /*****************************************************************************/ -gboolean nmc_print(const NmcConfig *nmc_config, - gpointer const *targets, - gpointer targets_data, - const char *header_name_no_l10n, - const NMMetaAbstractInfo *const *fields, - const char *fields_str, - GError **error); +gboolean nmc_print_table(const NmcConfig *nmc_config, + gpointer const *targets, + gpointer targets_data, + const char *header_name_no_l10n, + const NMMetaAbstractInfo *const *fields, + const char *fields_str, + GError **error); /*****************************************************************************/ From 61100788e721e4d135740229a3e4f3ada7f425a3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 16:50:50 +0100 Subject: [PATCH 17/21] nmcli: add nmc_print()/nmc_printerr() macros These will replace the direct calls to g_print()/g_printerr() in nmcli. There are two purposes. 1) the new macros embody the concept of "printing something from nmcli". It means, we can `git grep` for those functions, and find all the relevant places, without hitting the irrelevant ones (e.g. tests that also use g_print()). 2) by having one place, we can trivially change it. That is useful for printf debugging. For example, "test-client.py" runs nmcli and captures and compares the output. With libnm we can set LIBNM_CLIENT_DEBUG and LIBNM_CLIENT_DEBUG_FILE to print libnm debug messages to a file. But we cannot trivially synchronize the messages from nmcli with that output (also because they are consumed by the test and not immediately accessible). This would be easy, if we temporarily could patch nmc_print*() to also log to nm_utils_print(). The new macros will allow doing that at one place. For example, patch the "#if 0" and run: $ LIBNM_CLIENT_DEBUG=trace \ LIBNM_CLIENT_DEBUG_FILE='xxx.%p' \ NMTST_USE_VALGRIND=1 \ LIBTOOL="/bin/sh ./libtool" ./src/tests/client/test-client.sh -- -k monitor (cherry picked from commit 4cf94f30c72bce47c5079e8534dda7f9b3c49869) --- src/nmcli/utils.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/nmcli/utils.h b/src/nmcli/utils.h index 3897cd2b87..5d9449f54b 100644 --- a/src/nmcli/utils.h +++ b/src/nmcli/utils.h @@ -369,4 +369,34 @@ gboolean nmc_print_table(const NmcConfig *nmc_config, /*****************************************************************************/ +#if 0 +/* For manual testing to sync output with LIBNM_CLIENT_DEBUG/LIBNM_CLIENT_DEBUG_FILE */ +#define nmc_print(...) \ + G_STMT_START \ + { \ + gs_free char *_ss = g_strdup_printf(__VA_ARGS__); \ + gs_free char *_ss1 = g_strdup_printf("nmcli[out]: %s", _ss); \ + \ + nm_utils_print(0, _ss1); \ + nm_utils_print(1, _ss); \ + } \ + G_STMT_END + +#define nmc_printerr(...) \ + G_STMT_START \ + { \ + gs_free char *_ss = g_strdup_printf(__VA_ARGS__); \ + gs_free char *_ss1 = g_strdup_printf("nmcli[err]: %s", _ss); \ + \ + nm_utils_print(0, _ss1); \ + nm_utils_print(2, _ss); \ + } \ + G_STMT_END +#else +#define nmc_print(...) g_print(__VA_ARGS__) +#define nmc_printerr(...) g_printerr(__VA_ARGS__) +#endif + +/*****************************************************************************/ + #endif /* NMC_UTILS_H */ From 899372480e3471ec5993161d3be8078b72513584 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 6 Feb 2023 16:57:38 +0100 Subject: [PATCH 18/21] nmcli: replace all uses of g_print()/g_printerr() with nmc_print()/nmc_printerr() The main purpose is to simplify printf debugging and manual testing. We can now trivially patch the code so that all output from nmcli gets (additionally) written to a file. That is useful when debugging a unit test in "test-client.py". Thereby we can duplicate all messages via nm_utils_print(), which is in sync with the debug messages from libnm and which honors LIBNM_CLIENT_DEBUG_FILE. (cherry picked from commit b32e4c941a7525881599f6d419ddaafacd85b52c) --- src/nmcli/agent.c | 40 +- src/nmcli/common.c | 20 +- src/nmcli/connections.c | 1054 +++++++++++++++++++------------------- src/nmcli/devices.c | 269 +++++----- src/nmcli/general.c | 230 ++++----- src/nmcli/nmcli.c | 22 +- src/nmcli/polkit-agent.c | 9 +- src/nmcli/settings.c | 24 +- src/nmcli/utils.c | 76 +-- 9 files changed, 885 insertions(+), 859 deletions(-) diff --git a/src/nmcli/agent.c b/src/nmcli/agent.c index 6d0fcfb5c9..b16a3c51c9 100644 --- a/src/nmcli/agent.c +++ b/src/nmcli/agent.c @@ -22,36 +22,36 @@ static void usage(void) { - g_printerr(_("Usage: nmcli agent { COMMAND | help }\n\n" - "COMMAND := { secret | polkit | all }\n\n")); + nmc_printerr(_("Usage: nmcli agent { COMMAND | help }\n\n" + "COMMAND := { secret | polkit | all }\n\n")); } static void usage_agent_secret(void) { - g_printerr(_("Usage: nmcli agent secret { help }\n" - "\n" - "Runs nmcli as NetworkManager secret agent. When NetworkManager requires\n" - "a password it asks registered agents for it. This command keeps nmcli running\n" - "and if a password is required asks the user for it.\n\n")); + nmc_printerr(_("Usage: nmcli agent secret { help }\n" + "\n" + "Runs nmcli as NetworkManager secret agent. When NetworkManager requires\n" + "a password it asks registered agents for it. This command keeps nmcli running\n" + "and if a password is required asks the user for it.\n\n")); } static void usage_agent_polkit(void) { - g_printerr(_("Usage: nmcli agent polkit { help }\n" - "\n" - "Registers nmcli as a polkit action for the user session.\n" - "When a polkit daemon requires an authorization, nmcli asks the user and gives\n" - "the response back to polkit.\n\n")); + nmc_printerr(_("Usage: nmcli agent polkit { help }\n" + "\n" + "Registers nmcli as a polkit action for the user session.\n" + "When a polkit daemon requires an authorization, nmcli asks the user and gives\n" + "the response back to polkit.\n\n")); } static void usage_agent_all(void) { - g_printerr(_("Usage: nmcli agent all { help }\n" - "\n" - "Runs nmcli as both NetworkManager secret and a polkit agent.\n\n")); + nmc_printerr(_("Usage: nmcli agent all { help }\n" + "\n" + "Runs nmcli as both NetworkManager secret and a polkit agent.\n\n")); } static char *pre_input_deftext; @@ -82,7 +82,7 @@ get_secrets_from_user(const NmcConfig *nmc_config, /* Ask user for the password */ if (msg) - g_print("%s\n", msg); + nmc_print("%s\n", msg); if (secret->value) { /* Prefill the password if we have it. */ rl_startup_hook = set_deftext; @@ -138,7 +138,7 @@ do_agent_secret(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const * NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, G_CALLBACK(secrets_requested), nmc); - g_print(_("nmcli successfully registered as a NetworkManager's secret agent.\n")); + nmc_print(_("nmcli successfully registered as a NetworkManager's secret agent.\n")); } else { g_string_printf(nmc->return_text, _("Error: secret agent initialization failed")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; @@ -148,7 +148,7 @@ do_agent_secret(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const * static void polkit_registered(gpointer instance, gpointer user_data) { - g_print(_("nmcli successfully registered as a polkit agent.\n")); + nmc_print(_("nmcli successfully registered as a polkit agent.\n")); } static void @@ -202,14 +202,14 @@ do_agent_all(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *arg do_agent_secret(cmd, nmc, argc, argv); r = nmc->return_value; if (r != NMC_RESULT_SUCCESS) { - g_printerr("%s\n", nmc->return_text->str); + nmc_printerr("%s\n", nmc->return_text->str); g_string_truncate(nmc->return_text, 0); nmc->return_value = NMC_RESULT_SUCCESS; } do_agent_polkit(cmd, nmc, argc, argv); if (nmc->return_value != NMC_RESULT_SUCCESS) { - g_printerr("%s\n", nmc->return_text->str); + nmc_printerr("%s\n", nmc->return_text->str); g_string_truncate(nmc->return_text, 0); } diff --git a/src/nmcli/common.c b/src/nmcli/common.c index 8c89f82dcc..f31d09872d 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -660,16 +660,16 @@ vpn_openconnect_get_secrets(NMConnection *connection, GPtrArray *secrets) /* Interactively authenticate to OpenConnect server and get secrets */ ret = nm_vpn_openconnect_authenticate_helper(gw, &cookie, &gateway, &gwcert, &status, &error); if (!ret) { - g_printerr(_("Error: openconnect failed: %s\n"), error->message); + nmc_printerr(_("Error: openconnect failed: %s\n"), error->message); g_clear_error(&error); return FALSE; } if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) - g_printerr(_("Error: openconnect failed with status %d\n"), WEXITSTATUS(status)); + nmc_printerr(_("Error: openconnect failed with status %d\n"), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) - g_printerr(_("Error: openconnect failed with signal %d\n"), WTERMSIG(status)); + nmc_printerr(_("Error: openconnect failed with signal %d\n"), WTERMSIG(status)); /* Append port to the host value */ if (gateway && port) { @@ -743,7 +743,7 @@ get_secrets_from_user(const NmcConfig *nmc_config, } } if (msg) - g_print("%s\n", msg); + nmc_print("%s\n", msg); echo_on = secret->is_secret ? nmc_config->show_secrets : TRUE; @@ -760,10 +760,10 @@ get_secrets_from_user(const NmcConfig *nmc_config, pwd = g_strdup(""); } else { if (msg) - g_print("%s\n", msg); - g_printerr(_("Warning: password for '%s' not given in 'passwd-file' " - "and nmcli cannot ask without '--ask' option.\n"), - secret->entry_id); + nmc_print("%s\n", msg); + nmc_printerr(_("Warning: password for '%s' not given in 'passwd-file' " + "and nmcli cannot ask without '--ask' option.\n"), + secret->entry_id); } } /* No password provided, cancel the secrets. */ @@ -1532,7 +1532,7 @@ nmc_do_cmd(NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, const if (argc == 1 && nmc->complete) { for (c = cmds; c->cmd; ++c) { if (!*cmd || matches(cmd, c->cmd)) - g_print("%s\n", c->cmd); + nmc_print("%s\n", c->cmd); } nmc_complete_help(cmd); g_task_return_boolean(task, TRUE); @@ -1612,7 +1612,7 @@ nmc_complete_strv(const char *prefix, gssize nargs, const char *const *args) if (prefix && !matches(prefix, candidate)) continue; - g_print("%s\n", candidate); + nmc_print("%s\n", candidate); } } diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 97cd991e8b..36de6373e9 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -1084,7 +1084,7 @@ static TabCompletionInfo nmc_tab_completion; static void usage(void) { - g_printerr( + nmc_printerr( _("Usage: nmcli connection { COMMAND | help }\n\n" "COMMAND := { show | up | down | add | modify | clone | edit | delete | monitor | reload " "| load | import | export }\n\n" @@ -1110,7 +1110,7 @@ usage(void) static void usage_connection_show(void) { - g_printerr( + nmc_printerr( _("Usage: nmcli connection show { ARGUMENTS | help }\n" "\n" "ARGUMENTS := [--active] [--order ]\n" @@ -1132,171 +1132,173 @@ usage_connection_show(void) static void usage_connection_up(void) { - g_printerr(_("Usage: nmcli connection up { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path] [ifname ] [ap ] [nsp ] " - "[passwd-file ]\n" - "\n" - "Activate a connection on a device. The profile to activate is identified by its\n" - "name, UUID or D-Bus path.\n" - "\n" - "ARGUMENTS := ifname [ap ] [nsp ] [passwd-file ]\n" - "\n" - "Activate a device with a connection. The connection profile is selected\n" - "automatically by NetworkManager.\n" - "\n" - "ifname - specifies the device to active the connection on\n" - "ap - specifies AP to connect to (only valid for Wi-Fi)\n" - "nsp - specifies NSP to connect to (only valid for WiMAX)\n" - "passwd-file - file with password(s) required to activate the connection\n\n")); + nmc_printerr( + _("Usage: nmcli connection up { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path] [ifname ] [ap ] [nsp ] " + "[passwd-file ]\n" + "\n" + "Activate a connection on a device. The profile to activate is identified by its\n" + "name, UUID or D-Bus path.\n" + "\n" + "ARGUMENTS := ifname [ap ] [nsp ] [passwd-file ]\n" + "\n" + "Activate a device with a connection. The connection profile is selected\n" + "automatically by NetworkManager.\n" + "\n" + "ifname - specifies the device to active the connection on\n" + "ap - specifies AP to connect to (only valid for Wi-Fi)\n" + "nsp - specifies NSP to connect to (only valid for WiMAX)\n" + "passwd-file - file with password(s) required to activate the connection\n\n")); } static void usage_connection_down(void) { - g_printerr(_("Usage: nmcli connection down { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path | apath] ...\n" - "\n" - "Deactivate a connection from a device (without preventing the device from\n" - "further auto-activation). The profile to deactivate is identified by its name,\n" - "UUID or D-Bus path.\n\n")); + nmc_printerr( + _("Usage: nmcli connection down { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path | apath] ...\n" + "\n" + "Deactivate a connection from a device (without preventing the device from\n" + "further auto-activation). The profile to deactivate is identified by its name,\n" + "UUID or D-Bus path.\n\n")); } static void usage_connection_add(void) { - g_printerr(_("Usage: nmcli connection add { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- " - "([+|-]. )+]\n\n" - " COMMON_OPTIONS:\n" - " type \n" - " [ifname | \"*\"]\n" - " [con-name ]\n" - " [autoconnect yes|no]\n" - " [save yes|no]\n" - " [master ]\n" - " [slave-type ]\n\n" - " TYPE_SPECIFIC_OPTIONS:\n" - " ethernet: [mac ]\n" - " [cloned-mac ]\n" - " [mtu ]\n\n" - " wifi: ssid \n" - " [mac ]\n" - " [cloned-mac ]\n" - " [mtu ]\n" - " [mode infrastructure|ap|adhoc]\n\n" - " wimax: [mac ]\n" - " [nsp ]\n\n" - " pppoe: username \n" - " [password ]\n" - " [service ]\n" - " [mtu ]\n" - " [mac ]\n\n" - " gsm: apn \n" - " [user ]\n" - " [password ]\n\n" - " cdma: [user ]\n" - " [password ]\n\n" - " infiniband: [mac ]\n" - " [mtu ]\n" - " [transport-mode datagram | connected]\n" - " [parent ]\n" - " [p-key ]\n\n" - " bluetooth: [addr ]\n" - " [bt-type panu|nap|dun-gsm|dun-cdma]\n\n" - " vlan: dev \n" - " id \n" - " [flags ]\n" - " [ingress ]\n" - " [egress ]\n" - " [mtu ]\n\n" - " bond: [mode balance-rr (0) | active-backup (1) | balance-xor (2) | " - "broadcast (3) |\n" - " 802.3ad (4) | balance-tlb (5) | balance-alb (6)]\n" - " [primary ]\n" - " [miimon ]\n" - " [downdelay ]\n" - " [updelay ]\n" - " [arp-interval ]\n" - " [arp-ip-target ]\n" - " [lacp-rate slow (0) | fast (1)]\n\n" - " bond-slave: master \n" - " [queue-id <0-65535>]\n\n" - " team: [config |]\n\n" - " team-slave: master \n" - " [config |]\n\n" - " bridge: [stp yes|no]\n" - " [priority ]\n" - " [forward-delay <2-30>]\n" - " [hello-time <1-10>]\n" - " [max-age <6-40>]\n" - " [ageing-time <0-1000000>]\n" - " [multicast-snooping yes|no]\n" - " [mac ]\n\n" - " bridge-slave: master \n" - " [priority <0-63>]\n" - " [path-cost <1-65535>]\n" - " [hairpin yes|no]\n\n" - " vpn: vpn-type " - "vpnc|openvpn|pptp|openconnect|openswan|libreswan|ssh|l2tp|iodine|...\n" - " [user ]\n\n" - " olpc-mesh: ssid \n" - " [channel <1-13>]\n" - " [dhcp-anycast ]\n\n" - " adsl: username \n" - " protocol pppoa|pppoe|ipoatm\n" - " [password ]\n" - " [encapsulation vcmux|llc]\n\n" - " tun: mode tun|tap\n" - " [owner ]\n" - " [group ]\n" - " [pi yes|no]\n" - " [vnet-hdr yes|no]\n" - " [multi-queue yes|no]\n\n" - " ip-tunnel: mode ipip|gre|sit|isatap|vti|ip6ip6|ipip6|ip6gre|vti6\n" - " remote \n" - " [local ]\n" - " [dev ]\n\n" - " macsec: dev \n" - " mode \n" - " [cak ckn ]\n" - " [encrypt yes|no]\n" - " [port 1-65534]\n\n\n" - " macvlan: dev \n" - " mode vepa|bridge|private|passthru|source\n" - " [tap yes|no]\n\n" - " vxlan: id \n" - " [remote ]\n" - " [local ]\n" - " [dev ]\n" - " [source-port-min <0-65535>]\n" - " [source-port-max <0-65535>]\n" - " [destination-port <0-65535>]\n\n" - " wpan: [short-addr <0x0000-0xffff>]\n" - " [pan-id <0x0000-0xffff>]\n" - " [page ]\n" - " [channel ]\n" - " [mac ]\n\n" - " 6lowpan: dev \n" - " dummy:\n\n" - " SLAVE_OPTIONS:\n" - " bridge: [priority <0-63>]\n" - " [path-cost <1-65535>]\n" - " [hairpin yes|no]\n\n" - " team: [config |]\n\n" - " bond: [queue-id <0-65535>]\n\n" - " IP_OPTIONS:\n" - " [ip4 ] [gw4 ]\n" - " [ip6 ] [gw6 ]\n\n")); + nmc_printerr(_("Usage: nmcli connection add { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- " + "([+|-]. )+]\n\n" + " COMMON_OPTIONS:\n" + " type \n" + " [ifname | \"*\"]\n" + " [con-name ]\n" + " [autoconnect yes|no]\n" + " [save yes|no]\n" + " [master ]\n" + " [slave-type ]\n\n" + " TYPE_SPECIFIC_OPTIONS:\n" + " ethernet: [mac ]\n" + " [cloned-mac ]\n" + " [mtu ]\n\n" + " wifi: ssid \n" + " [mac ]\n" + " [cloned-mac ]\n" + " [mtu ]\n" + " [mode infrastructure|ap|adhoc]\n\n" + " wimax: [mac ]\n" + " [nsp ]\n\n" + " pppoe: username \n" + " [password ]\n" + " [service ]\n" + " [mtu ]\n" + " [mac ]\n\n" + " gsm: apn \n" + " [user ]\n" + " [password ]\n\n" + " cdma: [user ]\n" + " [password ]\n\n" + " infiniband: [mac ]\n" + " [mtu ]\n" + " [transport-mode datagram | connected]\n" + " [parent ]\n" + " [p-key ]\n\n" + " bluetooth: [addr ]\n" + " [bt-type panu|nap|dun-gsm|dun-cdma]\n\n" + " vlan: dev \n" + " id \n" + " [flags ]\n" + " [ingress ]\n" + " [egress ]\n" + " [mtu ]\n\n" + " bond: [mode balance-rr (0) | active-backup (1) | balance-xor (2) | " + "broadcast (3) |\n" + " 802.3ad (4) | balance-tlb (5) | balance-alb (6)]\n" + " [primary ]\n" + " [miimon ]\n" + " [downdelay ]\n" + " [updelay ]\n" + " [arp-interval ]\n" + " [arp-ip-target ]\n" + " [lacp-rate slow (0) | fast (1)]\n\n" + " bond-slave: master \n" + " [queue-id <0-65535>]\n\n" + " team: [config |]\n\n" + " team-slave: master \n" + " [config |]\n\n" + " bridge: [stp yes|no]\n" + " [priority ]\n" + " [forward-delay <2-30>]\n" + " [hello-time <1-10>]\n" + " [max-age <6-40>]\n" + " [ageing-time <0-1000000>]\n" + " [multicast-snooping yes|no]\n" + " [mac ]\n\n" + " bridge-slave: master \n" + " [priority <0-63>]\n" + " [path-cost <1-65535>]\n" + " [hairpin yes|no]\n\n" + " vpn: vpn-type " + "vpnc|openvpn|pptp|openconnect|openswan|libreswan|ssh|l2tp|iodine|...\n" + " [user ]\n\n" + " olpc-mesh: ssid \n" + " [channel <1-13>]\n" + " [dhcp-anycast ]\n\n" + " adsl: username \n" + " protocol pppoa|pppoe|ipoatm\n" + " [password ]\n" + " [encapsulation vcmux|llc]\n\n" + " tun: mode tun|tap\n" + " [owner ]\n" + " [group ]\n" + " [pi yes|no]\n" + " [vnet-hdr yes|no]\n" + " [multi-queue yes|no]\n\n" + " ip-tunnel: mode ipip|gre|sit|isatap|vti|ip6ip6|ipip6|ip6gre|vti6\n" + " remote \n" + " [local ]\n" + " [dev ]\n\n" + " macsec: dev \n" + " mode \n" + " [cak ckn ]\n" + " [encrypt yes|no]\n" + " [port 1-65534]\n\n\n" + " macvlan: dev \n" + " mode vepa|bridge|private|passthru|source\n" + " [tap yes|no]\n\n" + " vxlan: id \n" + " [remote ]\n" + " [local ]\n" + " [dev ]\n" + " [source-port-min <0-65535>]\n" + " [source-port-max <0-65535>]\n" + " [destination-port <0-65535>]\n\n" + " wpan: [short-addr <0x0000-0xffff>]\n" + " [pan-id <0x0000-0xffff>]\n" + " [page ]\n" + " [channel ]\n" + " [mac ]\n\n" + " 6lowpan: dev \n" + " dummy:\n\n" + " SLAVE_OPTIONS:\n" + " bridge: [priority <0-63>]\n" + " [path-cost <1-65535>]\n" + " [hairpin yes|no]\n\n" + " team: [config |]\n\n" + " bond: [queue-id <0-65535>]\n\n" + " IP_OPTIONS:\n" + " [ip4 ] [gw4 ]\n" + " [ip6 ] [gw6 ]\n\n")); } static void usage_connection_modify(void) { - g_printerr( + nmc_printerr( _("Usage: nmcli connection modify { ARGUMENTS | help }\n" "\n" "ARGUMENTS := [id | uuid | path] ([+|-]. )+\n" @@ -1325,77 +1327,78 @@ usage_connection_modify(void) static void usage_connection_clone(void) { - g_printerr(_("Usage: nmcli connection clone { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [--temporary] [id | uuid | path] \n" - "\n" - "Clone an existing connection profile. The newly created connection will be\n" - "the exact copy of the , except the uuid property (will be generated) and\n" - "id (provided as argument).\n\n")); + nmc_printerr(_("Usage: nmcli connection clone { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [--temporary] [id | uuid | path] \n" + "\n" + "Clone an existing connection profile. The newly created connection will be\n" + "the exact copy of the , except the uuid property (will be generated) and\n" + "id (provided as argument).\n\n")); } static void usage_connection_edit(void) { - g_printerr(_("Usage: nmcli connection edit { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path] \n" - "\n" - "Edit an existing connection profile in an interactive editor.\n" - "The profile is identified by its name, UUID or D-Bus path\n" - "\n" - "ARGUMENTS := [type ] [con-name ]\n" - "\n" - "Add a new connection profile in an interactive editor.\n\n")); + nmc_printerr(_("Usage: nmcli connection edit { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path] \n" + "\n" + "Edit an existing connection profile in an interactive editor.\n" + "The profile is identified by its name, UUID or D-Bus path\n" + "\n" + "ARGUMENTS := [type ] [con-name ]\n" + "\n" + "Add a new connection profile in an interactive editor.\n\n")); } static void usage_connection_delete(void) { - g_printerr(_("Usage: nmcli connection delete { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path] , ...\n" - "\n" - "Delete connection profiles.\n" - "The profiles are identified by their name, UUID or D-Bus path.\n\n")); + nmc_printerr(_("Usage: nmcli connection delete { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path] , ...\n" + "\n" + "Delete connection profiles.\n" + "The profiles are identified by their name, UUID or D-Bus path.\n\n")); } static void usage_connection_monitor(void) { - g_printerr(_("Usage: nmcli connection monitor { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path] ...\n" - "\n" - "Monitor connection profile activity.\n" - "This command prints a line whenever the specified connection changes.\n" - "Monitors all connection profiles in case none is specified.\n\n")); + nmc_printerr(_("Usage: nmcli connection monitor { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path] ...\n" + "\n" + "Monitor connection profile activity.\n" + "This command prints a line whenever the specified connection changes.\n" + "Monitors all connection profiles in case none is specified.\n\n")); } static void usage_connection_reload(void) { - g_printerr(_("Usage: nmcli connection reload { help }\n" - "\n" - "Reload all connection files from disk.\n\n")); + nmc_printerr(_("Usage: nmcli connection reload { help }\n" + "\n" + "Reload all connection files from disk.\n\n")); } static void usage_connection_load(void) { - g_printerr(_("Usage: nmcli connection load { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [...]\n" - "\n" - "Load/reload one or more connection files from disk. Use this after manually\n" - "editing a connection file to ensure that NetworkManager is aware of its latest\n" - "state.\n\n")); + nmc_printerr( + _("Usage: nmcli connection load { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [...]\n" + "\n" + "Load/reload one or more connection files from disk. Use this after manually\n" + "editing a connection file to ensure that NetworkManager is aware of its latest\n" + "state.\n\n")); } static void usage_connection_import(void) { - g_printerr( + nmc_printerr( _("Usage: nmcli connection import { ARGUMENTS | help }\n" "\n" "ARGUMENTS := [--temporary] type file \n" @@ -1409,23 +1412,24 @@ usage_connection_import(void) static void usage_connection_export(void) { - g_printerr(_("Usage: nmcli connection export { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [id | uuid | path] []\n" - "\n" - "Export a connection. Only VPN connections are supported at the moment.\n" - "The data are directed to standard output or to a file if a name is given.\n\n")); + nmc_printerr( + _("Usage: nmcli connection export { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [id | uuid | path] []\n" + "\n" + "Export a connection. Only VPN connections are supported at the moment.\n" + "The data are directed to standard output or to a file if a name is given.\n\n")); } static void usage_connection_migrate(void) { - g_printerr(_("Usage: nmcli connection migrate { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [--plugin ] [id | uuid | path] , ...\n" - "\n" - "Migrate connection profiles to a different settings plugin,\n" - "such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n")); + nmc_printerr(_("Usage: nmcli connection migrate { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [--plugin ] [id | uuid | path] , ...\n" + "\n" + "Migrate connection profiles to a different settings plugin,\n" + "such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n")); } static char * @@ -1503,9 +1507,9 @@ got_secrets(GObject *source_object, GAsyncResult *res, gpointer user_data) gs_free_error GError *error = NULL; if (!nm_connection_update_secrets(data->local, NULL, secrets, &error) && error) { - g_printerr(_("Error updating secrets for %s: %s\n"), - data->setting_name, - error->message); + nmc_printerr(_("Error updating secrets for %s: %s\n"), + data->setting_name, + error->message); } } @@ -1613,7 +1617,7 @@ nmc_connection_profile_details(NMConnection *connection, NmCli *nmc) if (NM_IN_SET(nmc->nmc_config.print_output, NMC_PRINT_NORMAL, NMC_PRINT_PRETTY) && !nmc->nmc_config.multiline_output && was_output) - g_print("\n"); /* Empty line */ + nmc_print("\n"); /* Empty line */ was_output = FALSE; @@ -1719,7 +1723,7 @@ nmc_active_connection_details(NMActiveConnection *acon, NmCli *nmc) if (NM_IN_SET(nmc->nmc_config.print_output, NMC_PRINT_NORMAL, NMC_PRINT_PRETTY) && !nmc->nmc_config.multiline_output && was_output) - g_print("\n"); + nmc_print("\n"); was_output = FALSE; @@ -2507,7 +2511,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con nm_assert(explicit_acon || con); if (new_line) - g_print("\n"); + nmc_print("\n"); new_line = TRUE; if (without_fields || profile_flds) { @@ -2532,7 +2536,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con /* if there are multiple active connections, separate them with newline. * that is a bit odd, because we already separate connections with newlines, * and commonly don't separate the connection from the first active connection. */ - g_print("\n"); + nmc_print("\n"); } if (explicit_acon) @@ -2800,12 +2804,12 @@ check_activated(ActivateConnectionInfo *info) if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line(); if (reason) { - g_print(_("Connection successfully activated (%s) (D-Bus active path: %s)\n"), - reason, - nm_object_get_path(NM_OBJECT(info->active))); + nmc_print(_("Connection successfully activated (%s) (D-Bus active path: %s)\n"), + reason, + nm_object_get_path(NM_OBJECT(info->active))); } else { - g_print(_("Connection successfully activated (D-Bus active path: %s)\n"), - nm_object_get_path(NM_OBJECT(info->active))); + nmc_print(_("Connection successfully activated (D-Bus active path: %s)\n"), + nm_object_get_path(NM_OBJECT(info->active))); } activate_connection_info_finish(info); break; @@ -2955,8 +2959,8 @@ activate_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line(); - g_print(_("Connection successfully activated (D-Bus active path: %s)\n"), - nm_object_get_path(NM_OBJECT(active))); + nmc_print(_("Connection successfully activated (D-Bus active path: %s)\n"), + nm_object_get_path(NM_OBJECT(active))); } activate_connection_info_finish(info); } else { @@ -3325,9 +3329,9 @@ connection_removed_cb(NMClient *client, NMConnection *connection, ConnectionCbIn { if (!connection_cb_info_obj_list_has(info, connection)) return; - g_print(_("Connection '%s' (%s) successfully deleted.\n"), - nm_connection_get_id(connection), - nm_connection_get_uuid(connection)); + nmc_print(_("Connection '%s' (%s) successfully deleted.\n"), + nm_connection_get_id(connection), + nm_connection_get_uuid(connection)); connection_cb_info_finish(info, connection); } @@ -3341,9 +3345,9 @@ down_active_connection_state_cb(NMActiveConnection *active, if (info->nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line(); - g_print(_("Connection '%s' successfully deactivated (D-Bus active path: %s)\n"), - nm_active_connection_get_id(active), - nm_object_get_path(NM_OBJECT(active))); + nmc_print(_("Connection '%s' successfully deactivated (D-Bus active path: %s)\n"), + nm_active_connection_get_id(active), + nm_object_get_path(NM_OBJECT(active))); g_signal_handlers_disconnect_by_func(G_OBJECT(active), down_active_connection_state_cb, info); connection_cb_info_finish(info, active); @@ -3422,7 +3426,7 @@ do_connection_down(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons arg_num == 1 && nmc->complete); if (!active) { if (!nmc->complete) - g_printerr(_("Error: '%s' is not an active connection.\n"), *arg_ptr); + nmc_printerr(_("Error: '%s' is not an active connection.\n"), *arg_ptr); g_string_printf(nmc->return_text, _("Error: not all active connections found.")); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; } @@ -3463,9 +3467,9 @@ do_connection_down(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons active = found_active_cons->pdata[i]; if (!nm_client_deactivate_connection(nmc->client, active, NULL, &error)) { - g_print(_("Connection '%s' deactivation failed: %s\n"), - nm_active_connection_get_id(active), - error->message); + nmc_print(_("Connection '%s' deactivation failed: %s\n"), + nm_active_connection_get_id(active), + error->message); g_clear_error(&error); if (info) { @@ -3944,7 +3948,7 @@ normalized_master_for_slave(const GPtrArray *connections, } if (!out_master) { - g_print(_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); + nmc_print(_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); out_master = master; if (out_type) *out_type = type; @@ -4985,7 +4989,7 @@ complete_property_name(NmCli *nmc, prefix, postfix); if (word_list) - g_print("%s", word_list); + nmc_print("%s", word_list); if (modifier != NM_META_ACCESSOR_MODIFIER_SET) return; @@ -5014,7 +5018,7 @@ complete_property_name(NmCli *nmc, if (!bi->base.property_alias || !g_str_has_prefix(bi->base.property_alias, prefix)) continue; - g_print("%s\n", bi->base.property_alias); + nmc_print("%s\n", bi->base.property_alias); } } else { if (!property_info->is_cli_option) @@ -5022,7 +5026,7 @@ complete_property_name(NmCli *nmc, if (!property_info->property_alias || !g_str_has_prefix(property_info->property_alias, prefix)) continue; - g_print("%s\n", property_info->property_alias); + nmc_print("%s\n", property_info->property_alias); } } } @@ -5035,7 +5039,7 @@ run_rl_generator(rl_compentry_func_t *generator_func, const char *prefix) char *str; while ((str = generator_func(prefix, state))) { - g_print("%s\n", str); + nmc_print("%s\n", str); g_free(str); if (state == 0) state = 1; @@ -5069,7 +5073,7 @@ complete_option(NmCli *nmc, } if (values) { for (; values[0]; values++) - g_print("%s\n", values[0]); + nmc_print("%s\n", values[0]); return TRUE; } @@ -5094,11 +5098,11 @@ complete_existing_setting(NmCli *nmc, NMConnection *connection, const char *pref editor = nm_meta_setting_info_editor_find_by_setting(settings[i]); if (!prefix || g_str_has_prefix(editor->general->setting_name, prefix)) - g_print("%s\n", editor->general->setting_name); + nmc_print("%s\n", editor->general->setting_name); if (editor->alias) { if (!prefix || g_str_has_prefix(editor->alias, prefix)) - g_print("%s\n", editor->alias); + nmc_print("%s\n", editor->alias); } } } @@ -5386,7 +5390,7 @@ nmc_process_connection_properties(NmCli *nmc, if (!chosen) { if (*argc == 1 && nmc->complete) { if (allow_setting_removal && g_str_has_prefix("remove", option)) - g_print("remove\n"); + nmc_print("remove\n"); complete_property_name(nmc, connection, modifier, option, NULL); } g_set_error(error, @@ -5426,7 +5430,7 @@ connection_warnings(NmCli *nmc, NMConnection *connection) deprecated = nmc_connection_check_deprecated(NM_CONNECTION(connection)); if (deprecated) - g_printerr(_("Warning: %s.\n"), deprecated); + nmc_printerr(_("Warning: %s.\n"), deprecated); connections = nmc_get_connections(nmc); id = nm_connection_get_id(connection); @@ -5441,15 +5445,15 @@ connection_warnings(NmCli *nmc, NMConnection *connection) } if (found > 0) { - g_printerr(g_dngettext(GETTEXT_PACKAGE, - "Warning: There is another connection with the name '%1$s'. " - "Reference the connection by its uuid '%2$s'\n", - "Warning: There are %3$u other connections with the name " - "'%1$s'. Reference the connection by its uuid '%2$s'\n", - found), - id, - nm_connection_get_uuid(NM_CONNECTION(connection)), - found); + nmc_printerr(g_dngettext(GETTEXT_PACKAGE, + "Warning: There is another connection with the name '%1$s'. " + "Reference the connection by its uuid '%2$s'\n", + "Warning: There are %3$u other connections with the name " + "'%1$s'. Reference the connection by its uuid '%2$s'\n", + found), + id, + nm_connection_get_uuid(NM_CONNECTION(connection)), + found); } } @@ -5481,9 +5485,9 @@ add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) * * This is true for many messages that the user might parse. But this one * seems in particular interesting for a user to parse. */ - g_print(_("Connection '%s' (%s) successfully added.\n"), - nm_connection_get_id(NM_CONNECTION(connection)), - nm_connection_get_uuid(NM_CONNECTION(connection))); + nmc_print(_("Connection '%s' (%s) successfully added.\n"), + nm_connection_get_id(NM_CONNECTION(connection)), + nm_connection_get_uuid(NM_CONNECTION(connection))); g_object_unref(connection); } @@ -5629,7 +5633,8 @@ ask_option(NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstr multi = NM_FLAGS_HAS(inf_flags, NM_META_PROPERTY_INF_FLAG_MULTI); if (multi) - g_print(_("You can specify this option more than once. Press when you're done.\n")); + nmc_print( + _("You can specify this option more than once. Press when you're done.\n")); again: nm_clear_g_free(&value); @@ -5638,7 +5643,7 @@ again: value = nmc_readline(&nmc->nmc_config, "%s", prompt); if (!set_option(nmc, connection, abstract_info, value, FALSE, &error)) { - g_printerr("%s\n", error->message); + nmc_printerr("%s\n", error->message); goto again; } @@ -5740,7 +5745,7 @@ want_provide_opt_args(const NmcConfig *nmc_config, const char *type, guint num) return TRUE; /* Ask for optional arguments. */ - g_print(_("There are %d optional settings for %s.\n"), (int) num, type); + nmc_print(_("There are %d optional settings for %s.\n"), (int) num, type); answer = nmc_readline(nmc_config, _("Do you want to provide them? %s"), prompt_yes_no(TRUE, NULL)); nm_strstrip(answer); @@ -6872,7 +6877,7 @@ load_history_cmds(const char *uuid) kf = g_key_file_new(); if (!g_key_file_load_from_file(kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) { if (g_error_matches(err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE)) - g_print("Warning: %s parse error: %s\n", filename, err->message); + nmc_print("Warning: %s parse error: %s\n", filename, err->message); g_key_file_free(kf); g_free(filename); return; @@ -6911,7 +6916,7 @@ save_history_cmds(const char *uuid) if (!g_key_file_load_from_file(kf, filename, G_KEY_FILE_KEEP_COMMENTS, &error)) { if (!g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT) && !g_error_matches(error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { - g_print("Warning: %s parse error: %s\n", filename, error->message); + nmc_print("Warning: %s parse error: %s\n", filename, error->message); return; } g_clear_error(&error); @@ -6947,7 +6952,7 @@ editor_show_connection(NMConnection *connection, NmCli *nmc) static void editor_show_setting(NMSetting *setting, NmCli *nmc) { - g_print(_("['%s' setting values]\n"), nm_setting_get_name(setting)); + nmc_print(_("['%s' setting values]\n"), nm_setting_get_name(setting)); nmc->nmc_config_mutable.print_output = NMC_PRINT_NORMAL; nmc->nmc_config_mutable.multiline_output = TRUE; @@ -7054,24 +7059,24 @@ fail: static void editor_main_usage(void) { - g_print("------------------------------------------------------------------------------\n"); + nmc_print("------------------------------------------------------------------------------\n"); /* TRANSLATORS: do not translate command names and keywords before :: * However, you should translate terms enclosed in <>. */ - g_print(_("---[ Main menu ]---\n" - "goto [ | ] :: go to a setting or property\n" - "remove [.] | :: remove setting or reset property value\n" - "set [. ] :: set property value\n" - "describe [.] :: describe property\n" - "print [all | [.]] :: print the connection\n" - "verify [all | fix] :: verify the connection\n" - "save [persistent|temporary] :: save the connection\n" - "activate [] [/|] :: activate the connection\n" - "back :: go one level up (back)\n" - "help/? [] :: print this help\n" - "nmcli :: nmcli configuration\n" - "quit :: exit nmcli\n")); - g_print("------------------------------------------------------------------------------\n"); + nmc_print(_("---[ Main menu ]---\n" + "goto [ | ] :: go to a setting or property\n" + "remove [.] | :: remove setting or reset property value\n" + "set [. ] :: set property value\n" + "describe [.] :: describe property\n" + "print [all | [.]] :: print the connection\n" + "verify [all | fix] :: verify the connection\n" + "save [persistent|temporary] :: save the connection\n" + "activate [] [/|] :: activate the connection\n" + "back :: go one level up (back)\n" + "help/? [] :: print this help\n" + "nmcli :: nmcli configuration\n" + "quit :: exit nmcli\n")); + nmc_print("------------------------------------------------------------------------------\n"); } static void @@ -7085,14 +7090,15 @@ editor_main_help(const char *command) switch (cmd) { case NMC_EDITOR_MAIN_CMD_GOTO: - g_print(_("goto [.] | :: enter setting/property for editing\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")); + nmc_print( + _("goto [.] | :: enter setting/property for editing\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_REMOVE: - g_print( + nmc_print( _("remove [.] :: remove setting or reset property value\n\n" "This command removes an entire setting from the connection, or if a property\n" "is given, resets that property to the default value.\n\n" @@ -7100,27 +7106,27 @@ editor_main_help(const char *command) " nmcli> remove eth.mtu\n")); break; case NMC_EDITOR_MAIN_CMD_SET: - g_print(_("set [. ] :: set property value\n\n" - "This command sets property value.\n\n" - "Example: nmcli> set con.id My connection\n")); + nmc_print(_("set [. ] :: set property value\n\n" + "This command sets property value.\n\n" + "Example: nmcli> set con.id My connection\n")); break; case NMC_EDITOR_MAIN_CMD_ADD: - g_print(_("add [. ] :: add property value\n\n" - "This command appends property value.\n\n" - "Example: nmcli> add ipv4.addresses 192.168.1.1/24\n")); + nmc_print(_("add [. ] :: add property value\n\n" + "This command appends property value.\n\n" + "Example: nmcli> add ipv4.addresses 192.168.1.1/24\n")); break; case NMC_EDITOR_MAIN_CMD_DESCRIBE: - g_print(_("describe [.] :: describe property\n\n" - "Shows property description. You can consult nm-settings(5) " - "manual page to see all NM settings and properties.\n")); + nmc_print(_("describe [.] :: 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: - g_print(_("print [all] :: print setting or connection values\n\n" - "Shows current property or the whole connection.\n\n" - "Example: nmcli ipv4> print all\n")); + nmc_print(_("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: - g_print( + nmc_print( _("verify [all | fix] :: verify setting or connection validity\n\n" "Verifies whether the setting or connection is valid and can be saved later.\n" "It indicates invalid values on error. Some errors may be fixed automatically\n" @@ -7130,7 +7136,7 @@ editor_main_help(const char *command) " nmcli bond> verify\n")); break; case NMC_EDITOR_MAIN_CMD_SAVE: - g_print( + nmc_print( _("save [persistent|temporary] :: save the connection\n\n" "Sends the connection profile to NetworkManager that either will save it\n" "persistently, or will only keep it in memory. 'save' without an argument\n" @@ -7142,48 +7148,48 @@ editor_main_help(const char *command) "profile must be deleted.\n")); break; case NMC_EDITOR_MAIN_CMD_ACTIVATE: - g_print(_("activate [] [/|] :: activate the connection\n\n" - "Activates the connection.\n\n" - "Available options:\n" - " - device the connection will be activated on\n" - "/| - AP (Wi-Fi) or NSP (WiMAX) (prepend with / when is " - "not specified)\n")); + nmc_print(_("activate [] [/|] :: activate the connection\n\n" + "Activates the connection.\n\n" + "Available options:\n" + " - device the connection will be activated on\n" + "/| - AP (Wi-Fi) or NSP (WiMAX) (prepend with / when is " + "not specified)\n")); break; case NMC_EDITOR_MAIN_CMD_BACK: - g_print(_("back :: go to upper menu level\n\n")); + nmc_print(_("back :: go to upper menu level\n\n")); break; case NMC_EDITOR_MAIN_CMD_HELP: - g_print(_("help/? [] :: help for the nmcli commands\n\n")); + nmc_print(_("help/? [] :: help for the nmcli commands\n\n")); break; case NMC_EDITOR_MAIN_CMD_NMCLI: - g_print(_("nmcli [ ] :: nmcli configuration\n\n" - "Configures nmcli. The following options are available:\n" - "status-line yes | no [default: no]\n" - "save-confirmation yes | no [default: yes]\n" - "show-secrets yes | no [default: no]\n" - "prompt-color | <0-8> [default: 0]\n" - "%s" /* color table description */ - "\n" - "Examples: nmcli> nmcli status-line yes\n" - " nmcli> nmcli save-confirmation no\n" - " nmcli> nmcli prompt-color 3\n"), - " 0 = normal\n" - " 1 = \33[30mblack\33[0m\n" - " 2 = \33[31mred\33[0m\n" - " 3 = \33[32mgreen\33[0m\n" - " 4 = \33[33myellow\33[0m\n" - " 5 = \33[34mblue\33[0m\n" - " 6 = \33[35mmagenta\33[0m\n" - " 7 = \33[36mcyan\33[0m\n" - " 8 = \33[37mwhite\33[0m\n"); + nmc_print(_("nmcli [ ] :: nmcli configuration\n\n" + "Configures nmcli. The following options are available:\n" + "status-line yes | no [default: no]\n" + "save-confirmation yes | no [default: yes]\n" + "show-secrets yes | no [default: no]\n" + "prompt-color | <0-8> [default: 0]\n" + "%s" /* color table description */ + "\n" + "Examples: nmcli> nmcli status-line yes\n" + " nmcli> nmcli save-confirmation no\n" + " nmcli> nmcli prompt-color 3\n"), + " 0 = normal\n" + " 1 = \33[30mblack\33[0m\n" + " 2 = \33[31mred\33[0m\n" + " 3 = \33[32mgreen\33[0m\n" + " 4 = \33[33myellow\33[0m\n" + " 5 = \33[34mblue\33[0m\n" + " 6 = \33[35mmagenta\33[0m\n" + " 7 = \33[36mcyan\33[0m\n" + " 8 = \33[37mwhite\33[0m\n"); break; case NMC_EDITOR_MAIN_CMD_QUIT: - g_print(_("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")); + nmc_print(_("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: - g_print(_("Unknown command: '%s'\n"), command); + nmc_print(_("Unknown command: '%s'\n"), command); break; } } @@ -7244,21 +7250,21 @@ fail: static void editor_sub_help(void) { - g_print("------------------------------------------------------------------------------\n"); + nmc_print("------------------------------------------------------------------------------\n"); /* TRANSLATORS: do not translate command names and keywords before :: * However, you should translate terms enclosed in <>. */ - g_print(_("---[ Property menu ]---\n" - "set [] :: set new value\n" - "add [] :: add new option to the property\n" - "change :: change current value\n" - "remove [ |