diff options
author | Philip Chimento <philip@endlessm.com> | 2019-01-10 17:59:51 -0800 |
---|---|---|
committer | Philip Chimento <philip.chimento@gmail.com> | 2019-01-27 23:03:38 -0800 |
commit | a13bb7a0a0ee0abed6b05eb6e913b42991dd616c (patch) | |
tree | e907ee0fb00a3858ee3967718022ebde5e7217b0 /libgjs-private | |
parent | 7b9d03de8a059c719509f40ac25adb2282eb9e17 (diff) | |
download | gjs-a13bb7a0a0ee0abed6b05eb6e913b42991dd616c.tar.gz |
overrides: Allow DBus methods with file descriptor lists
For DBus proxies, we now allow calling methods with an extra
Gio.UnixFDList argument. This does not break existing code because we
already allowed a bunch of arguments in any order. Gio.DBusProxy.call()
is the same under the hood as Gio.DBusProxy.call_with_unix_fd_list(),
only with a null FD list parameter, so we can replace the former with
the latter.
Previously, synchronously called DBus proxy methods would return an
unpacked GVariant. Now, if called with a Gio.UnixFDList they will return
[unpacked GVariant, FDList]. This also does not break existing code
because it was not possible to call a method with an FDList before, and
the return value is unchanged if not calling with an FDList. This does
mean, unfortunately, that if you have a method with an 'h' in its return
signature but not in its argument signatures, you will have to call it
with an empty FDList in order to receive an FDList with the return
value, if calling synchronously.
On the DBus service side, when receiving a method call, we now pass the
FDList received from DBus to the called method. Previously, sync methods
were passed the parameters, and async methods were passed the parameters
plus the Gio.DBusInvocation object. Appending the Gio.UnixFDList to
those parameters also should not break existing code, although it could
if the method examines the number of arguments. (That is unlikely, since
DBus doesn't have methods with variable arguments.)
TODO: Check whether this works on non-Unix platforms.
Closes #204.
Diffstat (limited to 'libgjs-private')
-rw-r--r-- | libgjs-private/gjs-util.c | 79 | ||||
-rw-r--r-- | libgjs-private/gjs-util.h | 3 |
2 files changed, 82 insertions, 0 deletions
diff --git a/libgjs-private/gjs-util.c b/libgjs-private/gjs-util.c index f0e941f8..ea691f56 100644 --- a/libgjs-private/gjs-util.c +++ b/libgjs-private/gjs-util.c @@ -21,8 +21,13 @@ */ #include <config.h> + +#include <errno.h> +#include <fcntl.h> #include <string.h> +#include <gio/gio.h> +#include <glib-unix.h> #include <glib.h> #include <glib/gi18n.h> @@ -108,3 +113,77 @@ gjs_param_spec_get_owner_type(GParamSpec *pspec) { return pspec->owner_type; } + +// Adapted from glnx_throw_errno_prefix() +G_GNUC_PRINTF(2, 3) +static gboolean throw_errno_prefix(GError** error, const char* fmt, ...) { + int errsv = errno; + char* old_msg; + GString* buf; + + va_list args; + + if (!error) + return FALSE; + + va_start(args, fmt); + + g_set_error_literal(error, G_IO_ERROR, g_io_error_from_errno(errsv), + g_strerror(errsv)); + + old_msg = g_steal_pointer(&(*error)->message); + buf = g_string_new(""); + g_string_append_vprintf(buf, fmt, args); + g_string_append(buf, ": "); + g_string_append(buf, old_msg); + g_free(old_msg); + (*error)->message = g_string_free(g_steal_pointer(&buf), FALSE); + + va_end(args); + + errno = errsv; + return FALSE; +} + +/** + * gjs_open_bytes: + * @bytes: bytes to send to the pipe + * @error: Return location for a #GError, or %NULL + * + * Creates a pipe and sends @bytes to it, such that it is suitable for passing + * to g_subprocess_launcher_take_fd(). + * + * Returns: file descriptor, or -1 on error + */ +int gjs_open_bytes(GBytes* bytes, GError** error) { + int pipefd[2], result; + size_t count; + const void* buf; + ssize_t bytes_written; + + g_return_val_if_fail(bytes, -1); + g_return_val_if_fail(error == NULL || *error == NULL, -1); + + if (!g_unix_open_pipe(pipefd, FD_CLOEXEC, error)) + return -1; + + buf = g_bytes_get_data(bytes, &count); + + bytes_written = write(pipefd[1], buf, count); + if (bytes_written < 0) { + throw_errno_prefix(error, "write"); + return -1; + } + + if ((size_t)bytes_written != count) + g_warning("%s: %zd bytes sent, only %zu bytes written", __func__, count, + bytes_written); + + result = close(pipefd[1]); + if (result == -1) { + throw_errno_prefix(error, "close"); + return -1; + } + + return pipefd[0]; +} diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h index ef9ed5e8..0a337987 100644 --- a/libgjs-private/gjs-util.h +++ b/libgjs-private/gjs-util.h @@ -59,6 +59,9 @@ GParamFlags gjs_param_spec_get_flags (GParamSpec *pspec); GType gjs_param_spec_get_value_type (GParamSpec *pspec); GType gjs_param_spec_get_owner_type (GParamSpec *pspec); +/* For tests */ +int gjs_open_bytes(GBytes* bytes, GError** error); + G_END_DECLS #endif |