diff options
| author | Michael Albinus | 2026-02-07 11:32:54 +0100 |
|---|---|---|
| committer | Michael Albinus | 2026-02-07 11:32:54 +0100 |
| commit | 89209a83b60c87d97f0c05dbf6cb29ff3cdf3d5a (patch) | |
| tree | 7eb4fe230b36d619b51eeecd6c0a9868fa268b5b /src | |
| parent | e1524740bef6cee52e138a086e43988a16ed703e (diff) | |
| download | emacs-89209a83b60c87d97f0c05dbf6cb29ff3cdf3d5a.tar.gz emacs-89209a83b60c87d97f0c05dbf6cb29ff3cdf3d5a.zip | |
Support D-Bus file descriptor manipulation
* doc/misc/dbus.texi (Synchronous Methods): Adapt `dbus-call-method'.
(Asynchronous Methods): Adapt `dbus-call-method-asynchronously'.
(File Descriptors): New chapter, replaces Inhibitor Locks.
* etc/NEWS: Replace "New D-Bus functions to support systemd
inhibitor locks" by "Support D-Bus file descriptor manipulation".
Presentational fixes and improvements.
* lisp/net/dbus.el (dbus-call-method)
(dbus-call-method-asynchronously): Adapt docstring.
(dbus-list-hash-table): Return (nreverse result).
(dbus-monitor-goto-serial): Declare `completion'.
* src/dbusbind.c (Fdbus_message_internal, xd_read_message_1):
Handle `:keep-fd'.
(xd_registered_inhibitor_locks, Fdbus_make_inhibitor_lock)
(Fdbus_close_inhibitor_lock, Fdbus_registered_inhibitor_locks): Delete.
(xd_registered_fds): New variable.
(Fdbus__fd_open, Fdbus__fd_close, Fdbus__registered_fds):
New DEFUNs. (Bug#79963)
(syms_of_dbusbind_for_pdumper): Initialize `xd_registered_fds'.
(syms_of_dbusbind): Remove subroutines
`Sdbus_make_inhibitor_lock', `Sdbus_close_inhibitor_lock' and
`Sdbus_registered_inhibitor_locks'. Remove symbol `Qdbus_call_method'.
Declare subroutines `Sdbus__fd_open', `Sdbus__fd_close' and
`Sdbus__registered_fds'. Declare symbol `QCkeep_fd'. staticpro
`xd_registered_fds'.
* test/lisp/net/dbus-tests.el (dbus-test10-inhibitor-locks): Delete.
(dbus-test10-keep-fd, dbus-test10-open-close-fd): New tests.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dbusbind.c | 188 |
1 files changed, 105 insertions, 83 deletions
diff --git a/src/dbusbind.c b/src/dbusbind.c index 3cf3ec9897e..98adebfb2d4 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c | |||
| @@ -128,6 +128,8 @@ static bool xd_in_read_queued_messages = 0; | |||
| 128 | #endif | 128 | #endif |
| 129 | 129 | ||
| 130 | /* Check whether TYPE is a basic DBusType. */ | 130 | /* Check whether TYPE is a basic DBusType. */ |
| 131 | /* TODO: Shouldn't we assume, that recent D-Bus implementations carry | ||
| 132 | HAVE_DBUS_TYPE_IS_VALID and DBUS_TYPE_UNIX_FD? See configure.ac. */ | ||
| 131 | #ifdef HAVE_DBUS_TYPE_IS_VALID | 133 | #ifdef HAVE_DBUS_TYPE_IS_VALID |
| 132 | #define XD_BASIC_DBUS_TYPE(type) \ | 134 | #define XD_BASIC_DBUS_TYPE(type) \ |
| 133 | (dbus_type_is_valid (type) && dbus_type_is_basic (type)) | 135 | (dbus_type_is_valid (type) && dbus_type_is_basic (type)) |
| @@ -309,6 +311,8 @@ XD_OBJECT_TO_STRING (Lisp_Object object) | |||
| 309 | } \ | 311 | } \ |
| 310 | } while (0) | 312 | } while (0) |
| 311 | 313 | ||
| 314 | /* TODO: Shouldn't we assume, that recent D-Bus implementations carry | ||
| 315 | HAVE_DBUS_VALIDATE_*? See configure.ac. */ | ||
| 312 | #if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \ | 316 | #if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \ |
| 313 | || HAVE_DBUS_VALIDATE_INTERFACE || HAVE_DBUS_VALIDATE_MEMBER) | 317 | || HAVE_DBUS_VALIDATE_INTERFACE || HAVE_DBUS_VALIDATE_MEMBER) |
| 314 | #define XD_DBUS_VALIDATE_OBJECT(object, func) \ | 318 | #define XD_DBUS_VALIDATE_OBJECT(object, func) \ |
| @@ -1034,6 +1038,8 @@ xd_get_connection_address (Lisp_Object bus) | |||
| 1034 | } | 1038 | } |
| 1035 | 1039 | ||
| 1036 | /* Return the file descriptor for WATCH, -1 if not found. */ | 1040 | /* Return the file descriptor for WATCH, -1 if not found. */ |
| 1041 | /* TODO: Shouldn't we assume, that recent D-Bus implementations carry | ||
| 1042 | HAVE_DBUS_WATCH_GET_UNIX_FD? See configure.ac. */ | ||
| 1037 | static int | 1043 | static int |
| 1038 | xd_find_watch_fd (DBusWatch *watch) | 1044 | xd_find_watch_fd (DBusWatch *watch) |
| 1039 | { | 1045 | { |
| @@ -1349,6 +1355,7 @@ usage: (dbus-message-internal &rest REST) */) | |||
| 1349 | dbus_uint32_t serial = 0; | 1355 | dbus_uint32_t serial = 0; |
| 1350 | unsigned int ui_serial; | 1356 | unsigned int ui_serial; |
| 1351 | int timeout = -1; | 1357 | int timeout = -1; |
| 1358 | dbus_bool_t keepfd = FALSE; | ||
| 1352 | ptrdiff_t count, count0; | 1359 | ptrdiff_t count, count0; |
| 1353 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | 1360 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; |
| 1354 | 1361 | ||
| @@ -1525,6 +1532,7 @@ usage: (dbus-message-internal &rest REST) */) | |||
| 1525 | timeout = min (XFIXNAT (args[count+1]), INT_MAX); | 1532 | timeout = min (XFIXNAT (args[count+1]), INT_MAX); |
| 1526 | count = count + 2; | 1533 | count = count + 2; |
| 1527 | } | 1534 | } |
| 1535 | |||
| 1528 | /* Check for authorizable parameter. */ | 1536 | /* Check for authorizable parameter. */ |
| 1529 | else if (EQ (args[count], QCauthorizable)) | 1537 | else if (EQ (args[count], QCauthorizable)) |
| 1530 | { | 1538 | { |
| @@ -1542,6 +1550,24 @@ usage: (dbus-message-internal &rest REST) */) | |||
| 1542 | 1550 | ||
| 1543 | count = count + 2; | 1551 | count = count + 2; |
| 1544 | } | 1552 | } |
| 1553 | |||
| 1554 | /* Check for keepfd parameter. */ | ||
| 1555 | else if (EQ (args[count], QCkeep_fd)) | ||
| 1556 | { | ||
| 1557 | if (mtype != DBUS_MESSAGE_TYPE_METHOD_CALL) | ||
| 1558 | XD_SIGNAL1 | ||
| 1559 | (build_string (":keep-fd is only supported on method calls")); | ||
| 1560 | |||
| 1561 | /* Ignore this keyword if unsupported. */ | ||
| 1562 | #ifdef DBUS_TYPE_UNIX_FD | ||
| 1563 | keepfd = TRUE; | ||
| 1564 | #else | ||
| 1565 | XD_DEBUG_MESSAGE (":keep-fd not supported"); | ||
| 1566 | #endif | ||
| 1567 | |||
| 1568 | ++count; | ||
| 1569 | } | ||
| 1570 | |||
| 1545 | else break; | 1571 | else break; |
| 1546 | 1572 | ||
| 1547 | } | 1573 | } |
| @@ -1595,7 +1621,8 @@ usage: (dbus-message-internal &rest REST) */) | |||
| 1595 | result = list3 (QCserial, bus, INT_TO_INTEGER (serial)); | 1621 | result = list3 (QCserial, bus, INT_TO_INTEGER (serial)); |
| 1596 | 1622 | ||
| 1597 | /* Create a hash table entry. */ | 1623 | /* Create a hash table entry. */ |
| 1598 | Fputhash (result, handler, Vdbus_registered_objects_table); | 1624 | Fputhash (result, keepfd ? Fcons (handler, path) : handler, |
| 1625 | Vdbus_registered_objects_table); | ||
| 1599 | } | 1626 | } |
| 1600 | else | 1627 | else |
| 1601 | { | 1628 | { |
| @@ -1617,106 +1644,81 @@ usage: (dbus-message-internal &rest REST) */) | |||
| 1617 | return result; | 1644 | return result; |
| 1618 | } | 1645 | } |
| 1619 | 1646 | ||
| 1620 | /* Alist of registered inhibitor locks for D-Bus. | 1647 | /* Alist of registered file descriptors for D-Bus. |
| 1621 | An entry in this list is a list (FD WHAT WHY BLOCK). | 1648 | The key is an open file descriptor, retrieved via `dbus-call-method' |
| 1622 | The car of the list is a file descriptor retrieved from a | 1649 | or `dbus--open-fd'. The value is a string OBJECT-PATH or FILENAME, |
| 1623 | 'dbus-make-inhibitor-lock` call. The cdr of the list represents the | 1650 | which represents the arguments the function was called with. Those |
| 1624 | three arguments 'dbus-make-inhibitor-lock` was called with. */ | 1651 | values are not needed for further operations; they are just shown for |
| 1625 | static Lisp_Object xd_registered_inhibitor_locks; | 1652 | information. */ |
| 1626 | 1653 | static Lisp_Object xd_registered_fds; | |
| 1627 | DEFUN ("dbus-make-inhibitor-lock", Fdbus_make_inhibitor_lock, | 1654 | |
| 1628 | Sdbus_make_inhibitor_lock, | 1655 | DEFUN ("dbus--fd-open", Fdbus__fd_open, Sdbus__fd_open, 1, 1, 0, |
| 1629 | 2, 3, 0, | 1656 | doc: /* Open FILENAME and return the respective read-only file descriptor. */) |
| 1630 | doc: /* Inhibit system shutdowns and sleep states. | 1657 | (Lisp_Object filename) |
| 1631 | |||
| 1632 | WHAT is a colon-separated string of lock types, i.e. "shutdown", | ||
| 1633 | "sleep", "idle", "handle-power-key", "handle-suspend-key", | ||
| 1634 | "handle-hibernate-key", "handle-lid-switch". Example: "shutdown:idle". | ||
| 1635 | |||
| 1636 | WHY is a descriptive string of why the lock is taken. Example: "Package | ||
| 1637 | Update in Progress". | ||
| 1638 | |||
| 1639 | The optional BLOCK is the mode of the inhibitor lock, either "block" | ||
| 1640 | (BLOCK is non-nil), or "delay". | ||
| 1641 | |||
| 1642 | It returns a file descriptor or nil, if the lock cannot be acquired. If | ||
| 1643 | there is already an inhibitor lock for the triple (WHAT WHY BLOCK), this | ||
| 1644 | lock is returned. | ||
| 1645 | |||
| 1646 | For details of the arguments, see Info node `(dbus)Inhibitor Locks'. */) | ||
| 1647 | (Lisp_Object what, Lisp_Object why, Lisp_Object block) | ||
| 1648 | { | 1658 | { |
| 1649 | CHECK_STRING (what); | 1659 | CHECK_STRING (filename); |
| 1650 | CHECK_STRING (why); | 1660 | filename = Fexpand_file_name (filename, Qnil); |
| 1651 | if (!NILP (block)) | 1661 | filename = ENCODE_FILE (filename); |
| 1652 | block = Qt; | ||
| 1653 | Lisp_Object who = build_string ("Emacs"); | ||
| 1654 | Lisp_Object mode = | ||
| 1655 | (NILP (block)) ? build_string ("delay") : build_string ("block"); | ||
| 1656 | 1662 | ||
| 1657 | /* Check, whether it is registered already. */ | 1663 | /* Check, whether it is registered already. */ |
| 1658 | Lisp_Object triple = list3 (what, why, block); | 1664 | Lisp_Object registered = Frassoc (filename, xd_registered_fds); |
| 1659 | Lisp_Object registered = Frassoc (triple, xd_registered_inhibitor_locks); | ||
| 1660 | if (!NILP (registered)) | 1665 | if (!NILP (registered)) |
| 1661 | return CAR_SAFE (registered); | 1666 | return CAR_SAFE (registered); |
| 1662 | 1667 | ||
| 1663 | /* Register lock. */ | 1668 | /* Open file descriptor. */ |
| 1664 | Lisp_Object lock = | 1669 | int fd = emacs_open (SSDATA (filename), O_RDONLY, 0); |
| 1665 | calln (Qdbus_call_method, QCsystem, | ||
| 1666 | build_string ("org.freedesktop.login1"), | ||
| 1667 | build_string ("/org/freedesktop/login1"), | ||
| 1668 | build_string ("org.freedesktop.login1.Manager"), | ||
| 1669 | build_string ("Inhibit"), what, who, why, mode); | ||
| 1670 | |||
| 1671 | xd_registered_inhibitor_locks = | ||
| 1672 | Fcons (Fcons (lock, triple), xd_registered_inhibitor_locks); | ||
| 1673 | return lock; | ||
| 1674 | } | ||
| 1675 | 1670 | ||
| 1676 | DEFUN ("dbus-close-inhibitor-lock", Fdbus_close_inhibitor_lock, | 1671 | if (fd <= 0) |
| 1677 | Sdbus_close_inhibitor_lock, | 1672 | XD_SIGNAL2 (build_string ("Cannot open file"), filename); |
| 1678 | 1, 1, 0, | ||
| 1679 | doc: /* Close inhibitor lock file descriptor. | ||
| 1680 | 1673 | ||
| 1681 | LOCK, a file descriptor, must be the result of a `dbus-make-inhibitor-lock' | 1674 | /* Register file descriptor. */ |
| 1682 | call. It returns t in case of success, or nil if it isn't be possible | 1675 | xd_registered_fds = |
| 1683 | to close the lock, or if the lock is closed already. | 1676 | Fcons (Fcons (INT_TO_INTEGER (fd), filename), xd_registered_fds); |
| 1677 | return INT_TO_INTEGER (fd); | ||
| 1678 | } | ||
| 1684 | 1679 | ||
| 1685 | For details, see Info node `(dbus)Inhibitor Locks'. */) | 1680 | DEFUN ("dbus--fd-close", Fdbus__fd_close, Sdbus__fd_close, 1, 1, 0, |
| 1686 | (Lisp_Object lock) | 1681 | doc: /* Close file descriptor FD. |
| 1682 | FD must be the result of a `dbus-call-method' or `dbus--fd-open' call, | ||
| 1683 | see `dbus--registered-fds'. It returns t in case of success, or nil if | ||
| 1684 | it isn't be possible to close the file descriptor, or if the file | ||
| 1685 | descriptor is closed already. */) | ||
| 1686 | (Lisp_Object fd) | ||
| 1687 | { | 1687 | { |
| 1688 | CHECK_FIXNUM (lock); | 1688 | CHECK_FIXNUM (fd); |
| 1689 | 1689 | ||
| 1690 | /* Check, whether it is registered. */ | 1690 | /* Check, whether it is registered. */ |
| 1691 | Lisp_Object registered = assoc_no_quit (lock, xd_registered_inhibitor_locks); | 1691 | Lisp_Object registered = assoc_no_quit (fd, xd_registered_fds); |
| 1692 | if (NILP (registered)) | 1692 | if (NILP (registered)) |
| 1693 | return Qnil; | 1693 | return Qnil; |
| 1694 | else | 1694 | else |
| 1695 | { | 1695 | { |
| 1696 | xd_registered_inhibitor_locks = | 1696 | xd_registered_fds = Fdelete (registered, xd_registered_fds); |
| 1697 | Fdelete (registered, xd_registered_inhibitor_locks); | 1697 | return (emacs_close (XFIXNAT (fd)) == 0) ? Qt : Qnil; |
| 1698 | return (emacs_close (XFIXNAT (lock)) == 0) ? Qt : Qnil; | ||
| 1699 | } | 1698 | } |
| 1700 | } | 1699 | } |
| 1701 | 1700 | ||
| 1702 | DEFUN ("dbus-registered-inhibitor-locks", Fdbus_registered_inhibitor_locks, | 1701 | DEFUN ("dbus--registered-fds", Fdbus__registered_fds, Sdbus__registered_fds, |
| 1703 | Sdbus_registered_inhibitor_locks, | ||
| 1704 | 0, 0, 0, | 1702 | 0, 0, 0, |
| 1705 | doc: /* Return registered inhibitor locks, an alist. | 1703 | doc: /* Return registered file descriptors, an alist. |
| 1706 | This allows to check, whether other packages of the running Emacs | 1704 | The key is an open file descriptor, retrieved via `dbus-call-method' or |
| 1707 | instance have acquired an inhibitor lock as well. | 1705 | `dbus--open-fd'. The value is a string OBJECT-PATH or FILENAME, which |
| 1708 | An entry in this list is a list (FD WHAT WHY BLOCK). | 1706 | represents the arguments the function was called with. Those values are |
| 1709 | The car of the list is the file descriptor retrieved from a | 1707 | not needed for further operations; they are just shown for information. |
| 1710 | 'dbus-make-inhibitor-lock` call. The cdr of the list represents the | 1708 | |
| 1711 | three arguments 'dbus-make-inhibitor-lock` was called with. */) | 1709 | This alist allows to check, whether other packages of the running Emacs |
| 1710 | instance have acquired a file descriptor as well. */) | ||
| 1712 | (void) | 1711 | (void) |
| 1713 | { | 1712 | { |
| 1714 | /* We return a copy of xd_registered_inhibitor_locks, in order to | 1713 | /* We return a copy of xd_registered_fds, in order to protect it |
| 1715 | protect it against malicious manipulation. */ | 1714 | against malicious manipulation. */ |
| 1716 | Lisp_Object registered = xd_registered_inhibitor_locks; | 1715 | Lisp_Object registered = xd_registered_fds; |
| 1717 | Lisp_Object result = Qnil; | 1716 | Lisp_Object result = Qnil; |
| 1718 | for (; !NILP (registered); registered = CDR_SAFE (registered)) | 1717 | for (; !NILP (registered); registered = CDR_SAFE (registered)) |
| 1719 | result = Fcons (Fcopy_sequence (CAR_SAFE (registered)), result); | 1718 | { |
| 1719 | Lisp_Object tem = CAR_SAFE (registered); | ||
| 1720 | result = Fcons (Fcons (CAR_SAFE (tem), CDR_SAFE (tem)), result); | ||
| 1721 | } | ||
| 1720 | return Fnreverse (result); | 1722 | return Fnreverse (result); |
| 1721 | } | 1723 | } |
| 1722 | 1724 | ||
| @@ -1836,7 +1838,22 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1836 | Fremhash (key, Vdbus_registered_objects_table); | 1838 | Fremhash (key, Vdbus_registered_objects_table); |
| 1837 | 1839 | ||
| 1838 | /* Store the event. */ | 1840 | /* Store the event. */ |
| 1839 | xd_store_event (value, args, event_args); | 1841 | xd_store_event (CONSP (value) ? CAR_SAFE (value) : value, args, event_args); |
| 1842 | |||
| 1843 | #ifdef DBUS_TYPE_UNIX_FD | ||
| 1844 | /* Check, whether there is a file descriptor to be kept. | ||
| 1845 | value is (handler . path) | ||
| 1846 | args is ((:unix-fd NN) ...) */ | ||
| 1847 | if (CONSP (value) | ||
| 1848 | && CONSP (CAR_SAFE (args)) | ||
| 1849 | && EQ (CAR_SAFE (CAR_SAFE (args)), QCunix_fd)) | ||
| 1850 | { | ||
| 1851 | xd_registered_fds = | ||
| 1852 | Fcons (Fcons (CAR_SAFE (CDR_SAFE (CAR_SAFE (args))), | ||
| 1853 | CDR_SAFE (value)), | ||
| 1854 | xd_registered_fds); | ||
| 1855 | } | ||
| 1856 | #endif | ||
| 1840 | } | 1857 | } |
| 1841 | 1858 | ||
| 1842 | else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */ | 1859 | else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */ |
| @@ -1972,7 +1989,7 @@ static void | |||
| 1972 | syms_of_dbusbind_for_pdumper (void) | 1989 | syms_of_dbusbind_for_pdumper (void) |
| 1973 | { | 1990 | { |
| 1974 | xd_registered_buses = Qnil; | 1991 | xd_registered_buses = Qnil; |
| 1975 | xd_registered_inhibitor_locks = Qnil; | 1992 | xd_registered_fds = Qnil; |
| 1976 | } | 1993 | } |
| 1977 | 1994 | ||
| 1978 | void | 1995 | void |
| @@ -1980,9 +1997,9 @@ syms_of_dbusbind (void) | |||
| 1980 | { | 1997 | { |
| 1981 | defsubr (&Sdbus__init_bus); | 1998 | defsubr (&Sdbus__init_bus); |
| 1982 | defsubr (&Sdbus_get_unique_name); | 1999 | defsubr (&Sdbus_get_unique_name); |
| 1983 | defsubr (&Sdbus_make_inhibitor_lock); | 2000 | defsubr (&Sdbus__fd_open); |
| 1984 | defsubr (&Sdbus_close_inhibitor_lock); | 2001 | defsubr (&Sdbus__fd_close); |
| 1985 | defsubr (&Sdbus_registered_inhibitor_locks); | 2002 | defsubr (&Sdbus__registered_fds); |
| 1986 | 2003 | ||
| 1987 | DEFSYM (Qdbus_message_internal, "dbus-message-internal"); | 2004 | DEFSYM (Qdbus_message_internal, "dbus-message-internal"); |
| 1988 | defsubr (&Sdbus_message_internal); | 2005 | defsubr (&Sdbus_message_internal); |
| @@ -2007,6 +2024,11 @@ syms_of_dbusbind (void) | |||
| 2007 | /* Lisp symbol for method interactive authorization. */ | 2024 | /* Lisp symbol for method interactive authorization. */ |
| 2008 | DEFSYM (QCauthorizable, ":authorizable"); | 2025 | DEFSYM (QCauthorizable, ":authorizable"); |
| 2009 | 2026 | ||
| 2027 | /* Lisp symbol for file descriptor kept. */ | ||
| 2028 | #ifdef DBUS_TYPE_UNIX_FD | ||
| 2029 | DEFSYM (QCkeep_fd, ":keep-fd"); | ||
| 2030 | #endif | ||
| 2031 | |||
| 2010 | /* Lisp symbols of D-Bus types. */ | 2032 | /* Lisp symbols of D-Bus types. */ |
| 2011 | DEFSYM (QCbyte, ":byte"); | 2033 | DEFSYM (QCbyte, ":byte"); |
| 2012 | DEFSYM (QCboolean, ":boolean"); | 2034 | DEFSYM (QCboolean, ":boolean"); |
| @@ -2143,7 +2165,7 @@ be called when the D-Bus reply message arrives. */); | |||
| 2143 | /* Initialize internal objects. */ | 2165 | /* Initialize internal objects. */ |
| 2144 | pdumper_do_now_and_after_load (syms_of_dbusbind_for_pdumper); | 2166 | pdumper_do_now_and_after_load (syms_of_dbusbind_for_pdumper); |
| 2145 | staticpro (&xd_registered_buses); | 2167 | staticpro (&xd_registered_buses); |
| 2146 | staticpro (&xd_registered_inhibitor_locks); | 2168 | staticpro (&xd_registered_fds); |
| 2147 | 2169 | ||
| 2148 | Fprovide (intern_c_string ("dbusbind"), Qnil); | 2170 | Fprovide (intern_c_string ("dbusbind"), Qnil); |
| 2149 | } | 2171 | } |