X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e18afed7d695edac870ddf55aabc85c0a95a4b5f..578098f346bf9e1f23ca86ed764fc00b035b427f:/src/dbusbind.c diff --git a/src/dbusbind.c b/src/dbusbind.c index 62923b462b..c2eefd605b 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c @@ -21,7 +21,7 @@ along with GNU Emacs. If not, see . */ #ifdef HAVE_DBUS #include #include -#include + #include "lisp.h" #include "frame.h" #include "termhooks.h" @@ -70,7 +70,7 @@ static Lisp_Object QCdbus_registered_signal; static Lisp_Object xd_registered_buses; /* Whether we are reading a D-Bus event. */ -static int xd_in_read_queued_messages = 0; +static bool xd_in_read_queued_messages = 0; /* We use "xd_" and "XD_" as prefix for all internal symbols, because @@ -147,6 +147,10 @@ static int xd_in_read_queued_messages = 0; #endif /* Check whether TYPE is a basic DBusType. */ +#ifdef HAVE_DBUS_TYPE_IS_VALID +#define XD_BASIC_DBUS_TYPE(type) \ + (dbus_type_is_valid (type) && dbus_type_is_basic (type)) +#else #ifdef DBUS_TYPE_UNIX_FD #define XD_BASIC_DBUS_TYPE(type) \ ((type == DBUS_TYPE_BYTE) \ @@ -177,6 +181,7 @@ static int xd_in_read_queued_messages = 0; || (type == DBUS_TYPE_OBJECT_PATH) \ || (type == DBUS_TYPE_SIGNATURE)) #endif +#endif /* This was a macro. On Solaris 2.11 it was said to compile for hours, when optimization is enabled. So we have transferred it into @@ -254,24 +259,9 @@ xd_symbol_to_dbus_type (Lisp_Object object) #define XD_OBJECT_TO_STRING(object) \ SDATA (format2 ("%s", object, Qnil)) -/* Check whether X is a valid dbus serial number. If valid, set - SERIAL to its value. Otherwise, signal an error. */ -#define XD_CHECK_DBUS_SERIAL(x, serial) \ - do { \ - dbus_uint32_t DBUS_SERIAL_MAX = -1; \ - if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX) \ - serial = XINT (x); \ - else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX \ - && FLOATP (x) \ - && 0 <= XFLOAT_DATA (x) \ - && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX) \ - serial = XFLOAT_DATA (x); \ - else \ - XD_SIGNAL2 (build_string ("Invalid dbus serial"), x); \ - } while (0) - #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \ do { \ + char const *session_bus_address = getenv ("DBUS_SESSION_BUS_ADDRESS"); \ if (STRINGP (bus)) \ { \ DBusAddressEntry **entries; \ @@ -283,6 +273,11 @@ xd_symbol_to_dbus_type (Lisp_Object object) /* Cleanup. */ \ dbus_error_free (&derror); \ dbus_address_entries_free (entries); \ + /* Canonicalize session bus address. */ \ + if ((session_bus_address != NULL) \ + && (!NILP (Fstring_equal \ + (bus, build_string (session_bus_address))))) \ + bus = QCdbus_session_bus; \ } \ \ else \ @@ -291,8 +286,7 @@ xd_symbol_to_dbus_type (Lisp_Object object) if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \ XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \ /* We do not want to have an autolaunch for the session bus. */ \ - if (EQ (bus, QCdbus_session_bus) \ - && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) \ + if (EQ (bus, QCdbus_session_bus) && session_bus_address == NULL) \ XD_SIGNAL2 (build_string ("No connection to bus"), bus); \ } \ } while (0) @@ -366,9 +360,9 @@ xd_signature_cat (char *signature, char const *x) signature is embedded, or DBUS_TYPE_INVALID. It is needed for the check that DBUS_TYPE_DICT_ENTRY occurs only as array element. */ static void -xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lisp_Object object) +xd_signature (char *signature, int dtype, int parent_type, Lisp_Object object) { - unsigned int subtype; + int subtype; Lisp_Object elt; char const *subsig; int subsiglen; @@ -538,13 +532,67 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis XD_DEBUG_MESSAGE ("%s", signature); } +/* Convert X to a signed integer with bounds LO and HI. */ +static intmax_t +xd_extract_signed (Lisp_Object x, intmax_t lo, intmax_t hi) +{ + CHECK_NUMBER_OR_FLOAT (x); + if (INTEGERP (x)) + { + if (lo <= XINT (x) && XINT (x) <= hi) + return XINT (x); + } + else + { + double d = XFLOAT_DATA (x); + if (lo <= d && d <= hi) + { + intmax_t n = d; + if (n == d) + return n; + } + } + if (xd_in_read_queued_messages) + Fthrow (Qdbus_error, Qnil); + else + args_out_of_range_3 (x, + make_fixnum_or_float (lo), + make_fixnum_or_float (hi)); +} + +/* Convert X to an unsigned integer with bounds 0 and HI. */ +static uintmax_t +xd_extract_unsigned (Lisp_Object x, uintmax_t hi) +{ + CHECK_NUMBER_OR_FLOAT (x); + if (INTEGERP (x)) + { + if (0 <= XINT (x) && XINT (x) <= hi) + return XINT (x); + } + else + { + double d = XFLOAT_DATA (x); + if (0 <= d && d <= hi) + { + uintmax_t n = d; + if (n == d) + return n; + } + } + if (xd_in_read_queued_messages) + Fthrow (Qdbus_error, Qnil); + else + args_out_of_range_3 (x, make_number (0), make_fixnum_or_float (hi)); +} + /* Append C value, extracted from Lisp OBJECT, to iteration ITER. DTYPE must be a valid DBusType. It is used to convert Lisp objects, being arguments of `dbus-call-method' or `dbus-send-signal', into corresponding C values appended as arguments to a D-Bus message. */ static void -xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) +xd_append_arg (int dtype, Lisp_Object object, DBusMessageIter *iter) { char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; DBusMessageIter subiter; @@ -572,9 +620,11 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) } case DBUS_TYPE_INT16: - CHECK_NUMBER (object); { - dbus_int16_t val = XINT (object); + dbus_int16_t val = + xd_extract_signed (object, + TYPE_MINIMUM (dbus_int16_t), + TYPE_MAXIMUM (dbus_int16_t)); int pval = val; XD_DEBUG_MESSAGE ("%c %d", dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -583,9 +633,10 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) } case DBUS_TYPE_UINT16: - CHECK_NATNUM (object); { - dbus_uint16_t val = XFASTINT (object); + dbus_uint16_t val = + xd_extract_unsigned (object, + TYPE_MAXIMUM (dbus_uint16_t)); unsigned int pval = val; XD_DEBUG_MESSAGE ("%c %u", dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -595,7 +646,10 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) case DBUS_TYPE_INT32: { - dbus_int32_t val = extract_float (object); + dbus_int32_t val = + xd_extract_signed (object, + TYPE_MINIMUM (dbus_int32_t), + TYPE_MAXIMUM (dbus_int32_t)); int pval = val; XD_DEBUG_MESSAGE ("%c %d", dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -608,7 +662,9 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) case DBUS_TYPE_UNIX_FD: #endif { - dbus_uint32_t val = extract_float (object); + dbus_uint32_t val = + xd_extract_unsigned (object, + TYPE_MAXIMUM (dbus_uint32_t)); unsigned int pval = val; XD_DEBUG_MESSAGE ("%c %u", dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -618,7 +674,10 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) case DBUS_TYPE_INT64: { - dbus_int64_t val = extract_float (object); + dbus_int64_t val = + xd_extract_signed (object, + TYPE_MINIMUM (dbus_int64_t), + TYPE_MAXIMUM (dbus_int64_t)); printmax_t pval = val; XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -628,7 +687,9 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) case DBUS_TYPE_UINT64: { - dbus_uint64_t val = extract_float (object); + dbus_uint64_t val = + xd_extract_unsigned (object, + TYPE_MAXIMUM (dbus_uint64_t)); uprintmax_t pval = val; XD_DEBUG_MESSAGE ("%c %"pMu, dtype, pval); if (!dbus_message_iter_append_basic (iter, dtype, &val)) @@ -755,7 +816,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) D-Bus message must be a valid DBusType. Compound D-Bus types result always in a Lisp list. */ static Lisp_Object -xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter) +xd_retrieve_arg (int dtype, DBusMessageIter *iter) { switch (dtype) @@ -887,7 +948,7 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter) } /* Return the number of references of the shared CONNECTION. */ -static int +static ptrdiff_t xd_get_connection_references (DBusConnection *connection) { ptrdiff_t *refcount; @@ -925,7 +986,7 @@ static int xd_find_watch_fd (DBusWatch *watch) { #if HAVE_DBUS_WATCH_GET_UNIX_FD - /* TODO: Reverse these on Win32, which prefers the opposite. */ + /* TODO: Reverse these on w32, which prefers the opposite. */ int fd = dbus_watch_get_unix_fd (watch); if (fd == -1) fd = dbus_watch_get_socket (watch); @@ -936,8 +997,7 @@ xd_find_watch_fd (DBusWatch *watch) } /* Prototype. */ -static void -xd_read_queued_messages (int fd, void *data, int for_read); +static void xd_read_queued_messages (int fd, void *data); /* Start monitoring WATCH for possible I/O. */ static dbus_bool_t @@ -978,11 +1038,13 @@ xd_remove_watch (DBusWatch *watch, void *data) return; /* Unset session environment. */ +#if 0 if (XSYMBOL (QCdbus_session_bus) == data) { - // XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); - // unsetenv ("DBUS_SESSION_BUS_ADDRESS"); + XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); + unsetenv ("DBUS_SESSION_BUS_ADDRESS"); } +#endif if (flags & DBUS_WATCH_WRITABLE) delete_write_fd (fd); @@ -1015,19 +1077,19 @@ xd_close_bus (Lisp_Object bus) /* Retrieve bus address. */ connection = xd_get_connection_address (bus); - /* Close connection, if there isn't another shared application. */ if (xd_get_connection_references (connection) == 1) { + /* Close connection, if there isn't another shared application. */ XD_DEBUG_MESSAGE ("Close connection to bus %s", XD_OBJECT_TO_STRING (bus)); dbus_connection_close (connection); - } - /* Decrement reference count. */ - dbus_connection_unref (connection); + xd_registered_buses = Fdelete (val, xd_registered_buses); + } - /* Remove bus from list of registered buses. */ - xd_registered_buses = Fdelete (val, xd_registered_buses); + else + /* Decrement reference count. */ + dbus_connection_unref (connection); /* Return. */ return; @@ -1060,7 +1122,7 @@ this connection to those buses. */) DBusConnection *connection; DBusError derror; Lisp_Object val; - int refcount; + ptrdiff_t refcount; /* Check parameter. */ XD_DBUS_VALIDATE_BUS_ADDRESS (bus); @@ -1068,69 +1130,80 @@ this connection to those buses. */) /* Close bus if it is already open. */ xd_close_bus (bus); - /* Initialize. */ - dbus_error_init (&derror); - - /* Open the connection. */ - if (STRINGP (bus)) - if (NILP (private)) - connection = dbus_connection_open (SSDATA (bus), &derror); - else - connection = dbus_connection_open_private (SSDATA (bus), &derror); + /* Check, whether we are still connected. */ + val = Fassoc (bus, xd_registered_buses); + if (!NILP (val)) + { + connection = xd_get_connection_address (bus); + dbus_connection_ref (connection); + } else - if (NILP (private)) - connection = dbus_bus_get (EQ (bus, QCdbus_system_bus) - ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, - &derror); - else - connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus) - ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, - &derror); - - if (dbus_error_is_set (&derror)) - XD_ERROR (derror); - - if (connection == NULL) - XD_SIGNAL2 (build_string ("No connection to bus"), bus); + { + /* Initialize. */ + dbus_error_init (&derror); - /* If it is not the system or session bus, we must register - ourselves. Otherwise, we have called dbus_bus_get, which has - configured us to exit if the connection closes - we undo this - setting. */ - if (STRINGP (bus)) - dbus_bus_register (connection, &derror); - else - dbus_connection_set_exit_on_disconnect (connection, FALSE); - - if (dbus_error_is_set (&derror)) - XD_ERROR (derror); - - /* Add the watch functions. We pass also the bus as data, in order - to distinguish between the buses in xd_remove_watch. */ - if (!dbus_connection_set_watch_functions (connection, - xd_add_watch, - xd_remove_watch, - xd_toggle_watch, - SYMBOLP (bus) - ? (void *) XSYMBOL (bus) - : (void *) XSTRING (bus), - NULL)) - XD_SIGNAL1 (build_string ("Cannot add watch functions")); - - /* Add bus to list of registered buses. */ - XSETFASTINT (val, (intptr_t) connection); - xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses); - - /* We do not want to abort. */ - putenv ((char *) "DBUS_FATAL_WARNINGS=0"); + /* Open the connection. */ + if (STRINGP (bus)) + if (NILP (private)) + connection = dbus_connection_open (SSDATA (bus), &derror); + else + connection = dbus_connection_open_private (SSDATA (bus), &derror); - /* Cleanup. */ - dbus_error_free (&derror); + else + if (NILP (private)) + connection = dbus_bus_get (EQ (bus, QCdbus_system_bus) + ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, + &derror); + else + connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus) + ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, + &derror); + + if (dbus_error_is_set (&derror)) + XD_ERROR (derror); + + if (connection == NULL) + XD_SIGNAL2 (build_string ("No connection to bus"), bus); + + /* If it is not the system or session bus, we must register + ourselves. Otherwise, we have called dbus_bus_get, which has + configured us to exit if the connection closes - we undo this + setting. */ + if (STRINGP (bus)) + dbus_bus_register (connection, &derror); + else + dbus_connection_set_exit_on_disconnect (connection, FALSE); + + if (dbus_error_is_set (&derror)) + XD_ERROR (derror); + + /* Add the watch functions. We pass also the bus as data, in + order to distinguish between the buses in xd_remove_watch. */ + if (!dbus_connection_set_watch_functions (connection, + xd_add_watch, + xd_remove_watch, + xd_toggle_watch, + SYMBOLP (bus) + ? (void *) XSYMBOL (bus) + : (void *) XSTRING (bus), + NULL)) + XD_SIGNAL1 (build_string ("Cannot add watch functions")); + + /* Add bus to list of registered buses. */ + XSETFASTINT (val, (intptr_t) connection); + xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses); + + /* We do not want to abort. */ + putenv ((char *) "DBUS_FATAL_WARNINGS=0"); + + /* Cleanup. */ + dbus_error_free (&derror); + } /* Return reference counter. */ refcount = xd_get_connection_references (connection); - XD_DEBUG_MESSAGE ("Bus %s, Reference counter %d", + XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d", XD_OBJECT_TO_STRING (bus), refcount); return make_number (refcount); } @@ -1194,8 +1267,8 @@ usage: (dbus-message-internal &rest REST) */) DBusConnection *connection; DBusMessage *dmessage; DBusMessageIter iter; - unsigned int dtype; - unsigned int mtype; + int dtype; + int mtype; dbus_uint32_t serial = 0; unsigned int ui_serial; int timeout = -1; @@ -1209,9 +1282,10 @@ usage: (dbus-message-internal &rest REST) */) handler = Qnil; CHECK_NATNUM (message_type); - mtype = XFASTINT (message_type); - if ((mtype <= DBUS_MESSAGE_TYPE_INVALID) || (mtype >= DBUS_NUM_MESSAGE_TYPES)) + if (! (DBUS_MESSAGE_TYPE_INVALID < XFASTINT (message_type) + && XFASTINT (message_type) < DBUS_NUM_MESSAGE_TYPES)) XD_SIGNAL2 (build_string ("Invalid message type"), message_type); + mtype = XFASTINT (message_type); if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) || (mtype == DBUS_MESSAGE_TYPE_SIGNAL)) @@ -1225,7 +1299,7 @@ usage: (dbus-message-internal &rest REST) */) } else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ { - XD_CHECK_DBUS_SERIAL (args[3], serial); + serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t)); count = 4; } @@ -1363,7 +1437,7 @@ usage: (dbus-message-internal &rest REST) */) if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout))) { CHECK_NATNUM (args[count+1]); - timeout = XFASTINT (args[count+1]); + timeout = min (XFASTINT (args[count+1]), INT_MAX); count = count+2; } @@ -1449,8 +1523,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) struct input_event event; DBusMessage *dmessage; DBusMessageIter iter; - unsigned int dtype; - unsigned int mtype; + int dtype; + int mtype; dbus_uint32_t serial; unsigned int ui_serial; const char *uname, *path, *interface, *member; @@ -1611,7 +1685,7 @@ xd_read_message (Lisp_Object bus) /* Callback called when something is ready to read or write. */ static void -xd_read_queued_messages (int fd, void *data, int for_read) +xd_read_queued_messages (int fd, void *data) { Lisp_Object busp = xd_registered_buses; Lisp_Object bus = Qnil; @@ -1655,7 +1729,7 @@ syms_of_dbusbind (void) Fput (Qdbus_error, Qerror_conditions, list2 (Qdbus_error, Qerror)); Fput (Qdbus_error, Qerror_message, - make_pure_c_string ("D-Bus error")); + build_pure_c_string ("D-Bus error")); DEFSYM (QCdbus_system_bus, ":system"); DEFSYM (QCdbus_session_bus, ":session"); @@ -1687,7 +1761,7 @@ syms_of_dbusbind (void) Vdbus_compiled_version, doc: /* The version of D-Bus Emacs is compiled against. */); #ifdef DBUS_VERSION_STRING - Vdbus_compiled_version = make_pure_c_string (DBUS_VERSION_STRING); + Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING); #else Vdbus_compiled_version = Qnil; #endif @@ -1698,10 +1772,10 @@ syms_of_dbusbind (void) { #ifdef DBUS_VERSION int major, minor, micro; - char s[1024]; + char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)]; dbus_get_version (&major, &minor, µ); - snprintf (s, sizeof s, "%d.%d.%d", major, minor, micro); - Vdbus_runtime_version = make_string (s, strlen (s)); + Vdbus_runtime_version + = make_formatted_string (s, "%d.%d.%d", major, minor, micro); #else Vdbus_runtime_version = Qnil; #endif