From caa75d170d5ed5d538370b38d7e96d6f81df3e66 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 18 Feb 2019 08:38:01 +1000 Subject: [PATCH] ratbagd: make sure the profile name is ascii-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strings on DBus need to be valid UTF8, some of the default profile names on the G700 include the degree character (" Profile n° 1"), the whole string ends up being invalid UTF8. This results in two issues: - ratbagd gets quietly kicked off the bus when it sends that string - ratbag-command throws an exception because Python is unhappy about the non-UTF8 string: UnicodeEncodeError: 'utf-8' codec can't encode character '\udcb0' in position 3: surrogates not allowed The quick workaround here is to strip anything that's not ASCII from the profile name. The same may be necessary for some device names too, but let's wait until we see that. For ratbag-command we convert the string to bytes and back using the 'ignore' argument, this way we should see the original profile string without the printf errors. This is an incomplete fix, we'll have the same issue if a user tries to set a non-ASCII name. The long-term fix is to convert whatever we have (probably ISO 8859-1, but can we detect that?) into UTF8 before passing it around. That would also mean converting it back before writing to the device. Fixes #617 Signed-off-by: Peter Hutterer --- ratbagd/ratbagd-profile.c | 9 ++++++++- src/libratbag-util.h | 21 +++++++++++++++++++++ tools/ratbagctl.in | 6 +++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ratbagd/ratbagd-profile.c b/ratbagd/ratbagd-profile.c index 454d2aa9..3aa92c81 100644 --- a/ratbagd/ratbagd-profile.c +++ b/ratbagd/ratbagd-profile.c @@ -382,8 +382,15 @@ ratbagd_profile_get_name(sd_bus *bus, { struct ratbagd_profile *profile = userdata; const char *name = ratbag_profile_get_name(profile->lib_profile); + _cleanup_free_ char *asciiname; - CHECK_CALL(sd_bus_message_append(reply, "s", name)); + /* This should really be a UTF8 check and it should really be in + * libratbag, but for now this will do to at least not kick us off + * the bus. https://github.com/libratbag/libratbag/issues/617 + */ + asciiname = strdup_ascii_only(name); + + CHECK_CALL(sd_bus_message_append(reply, "s", asciiname)); return 0; } diff --git a/src/libratbag-util.h b/src/libratbag-util.h index 38d51990..8f6a8552 100644 --- a/src/libratbag-util.h +++ b/src/libratbag-util.h @@ -116,6 +116,27 @@ snprintf_safe(char *buf, size_t n, const char *fmt, ...) return rc; } +/** + * Returns a strdup'd string with all non-ascii characters replaced with a + * space. + */ +static inline char * +strdup_ascii_only(const char *str_in) +{ + char *str, *ascii_only; + + ascii_only = strdup_safe(str_in); + str = ascii_only; + while (str && *str) { + unsigned char c = *str; + if (c > 127) + *str = ' '; + + str++; + } + return ascii_only; +} + #define sprintf_safe(buf, fmt, ...) \ snprintf_safe(buf, ARRAY_LENGTH(buf), fmt, __VA_ARGS__) diff --git a/tools/ratbagctl.in b/tools/ratbagctl.in index 91d2e628..e2a850e3 100755 --- a/tools/ratbagctl.in +++ b/tools/ratbagctl.in @@ -522,7 +522,11 @@ def func_profile_get(r, args): def func_profile_name_get(r, args): p, d = find_profile(r, args) - print(p.name) + # See https://github.com/libratbag/libratbag/issues/617 + # ratbag converts to ascii, so this has no real effect there, but + # ratbag-command may still have a non-ascii string. + string = bytes(p.name, 'utf-8', 'ignore') + print(string.decode('utf-8')) def func_profile_name_set(r, args):