bhyve-fw: drop CSM
[oi-userland.git] / components / library / dbus / patches / 09-eventports.patch
bloba8dcc377e36fdf12141b2b646f673613221b76b2
1 This patch implements file monitoring backend using Solaris native event ports.
2 D-Bus uses it to check for changes in configuration files so that it can
3 automatically re-read them when necessary.
5 Should be offered upstream once we are sure it works as expected.
7 --- dbus-1.14.6/configure.ac
8 +++ dbus-1.14.6/configure.ac
9 @@ -214,6 +214,7 @@ AC_ARG_ENABLE([apparmor],
10 AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto)
11 AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify support (linux only)]),enable_inotify=$enableval,enable_inotify=auto)
12 AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto)
13 +AC_ARG_ENABLE(evports, AS_HELP_STRING([--enable-evports],[build with evports support]),enable_evports=$enableval,enable_evports=auto)
14 AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto)
15 AC_ARG_ENABLE(launchd, AS_HELP_STRING([--enable-launchd],[build with launchd auto-launch support]),enable_launchd=$enableval,enable_launchd=auto)
16 AC_ARG_ENABLE(systemd, AS_HELP_STRING([--enable-systemd],[build with systemd at_console support]),enable_systemd=$enableval,enable_systemd=auto)
17 @@ -934,6 +935,26 @@ fi
19 AM_CONDITIONAL(DBUS_BUS_ENABLE_KQUEUE, test x$have_kqueue = xyes)
21 +# evports checks
22 +if test x$enable_evports = xno ; then
23 + have_evports=no
24 +else
25 + have_evports=yes
26 + AC_CHECK_HEADER(port.h, , have_evports=no)
27 + AC_CHECK_FUNC(port_create, , have_evports=no)
29 + if test x$enable_evports = xyes -a x$have_evports = xno; then
30 + AC_MSG_ERROR(evports support explicitly enabled but not available)
31 + fi
32 +fi
34 +dnl check if evports backend is enabled
35 +if test x$have_evports = xyes; then
36 + AC_DEFINE(DBUS_BUS_ENABLE_EVPORTS,1,[Use evports])
37 +fi
39 +AM_CONDITIONAL(DBUS_BUS_ENABLE_EVPORTS, test x$have_evports = xyes)
41 # launchd checks
42 if test x$enable_launchd = xno ; then
43 have_launchd=no
44 @@ -1807,6 +1828,7 @@ echo "
45 Building AppArmor support: ${have_apparmor}
46 Building inotify support: ${have_inotify}
47 Building kqueue support: ${have_kqueue}
48 + Building evports support: ${have_evports}
49 Building systemd support: ${have_systemd}
50 Traditional activation: ${enable_traditional_activation}
51 Building X11 code: ${have_x11}
52 --- dbus-1.14.6/bus/Makefile.am
53 +++ dbus-1.14.6/bus/Makefile.am
54 @@ -79,12 +79,16 @@ endif
55 if DBUS_BUS_ENABLE_KQUEUE
56 DIR_WATCH_SOURCE=dir-watch-kqueue.c
57 else
58 +if DBUS_BUS_ENABLE_EVPORTS
59 +DIR_WATCH_SOURCE=dir-watch-evports.c
60 +else
61 if DBUS_BUS_ENABLE_INOTIFY
62 DIR_WATCH_SOURCE=dir-watch-inotify.c
63 else
64 DIR_WATCH_SOURCE=dir-watch-default.c
65 endif
66 endif
67 +endif
69 noinst_LTLIBRARIES = libdbus-daemon-internal.la
71 --- dbus-1.14.6/bus/CMakeLists.txt
72 +++ dbus-1.14.6/bus/CMakeLists.txt
73 @@ -30,6 +30,8 @@ if(DBUS_BUS_ENABLE_INOTIFY)
74 set(DIR_WATCH_SOURCE dir-watch-inotify.c)
75 elseif(DBUS_BUS_ENABLE_KQUEUE)
76 set(DIR_WATCH_SOURCE dir-watch-kqueue.c)
77 +elseif(DBUS_BUS_ENABLE_EVPORTS)
78 + set(DIR_WATCH_SOURCE dir-watch-evports.c)
79 else(DBUS_BUS_ENABLE_INOTIFY)
80 set(DIR_WATCH_SOURCE dir-watch-default.c)
81 endif()
82 --- dbus-1.14.6/README.cmake
83 +++ dbus-1.14.6/README.cmake
84 @@ -211,6 +211,10 @@ DBUS_BUS_ENABLE_INOTIFY:BOOL=ON
85 // enable kqueue as dir watch backend
86 DBUS_BUS_ENABLE_KQUEUE:BOOL=ON
88 +*Solaris only:
89 +// enable evports as dir watch backend
90 +DBUS_BUS_ENABLE_EVPORTS:BOOL=ON
92 x11 only:
93 // Build with X11 auto launch support
94 DBUS_BUILD_X11:BOOL=ON
95 --- dbus-1.14.6/cmake/ConfigureChecks.cmake
96 +++ dbus-1.14.6/cmake/ConfigureChecks.cmake
97 @@ -27,6 +27,7 @@ check_include_file(string.h HAVE_STR
98 check_include_file(strings.h HAVE_STRINGS_H)
99 check_include_file(syslog.h HAVE_SYSLOG_H)
100 check_include_files("stdint.h;sys/types.h;sys/event.h" HAVE_SYS_EVENT_H)
101 +check_include_files("port.h" HAVE_PORT_H)
102 check_include_file(sys/inotify.h HAVE_SYS_INOTIFY_H)
103 check_include_file(sys/random.h HAVE_SYS_RANDOM_H)
104 check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H)
105 --- dbus-1.14.6/CMakeLists.txt
106 +++ dbus-1.14.6/CMakeLists.txt
107 @@ -510,6 +510,13 @@ endif()
109 string(TOUPPER ${CMAKE_SYSTEM_NAME} sysname)
110 if("${sysname}" MATCHES ".*SOLARIS.*")
111 + option(DBUS_BUS_ENABLE_EVPORTS "build with evports support (solaris only)" ON)
112 + if(DBUS_BUS_ENABLE_EVPORTS)
113 + if(NOT HAVE_PORT_H)
114 + message(FATAL_ERROR "port.h not found!")
115 + endif()
116 + endif()
118 option(HAVE_CONSOLE_OWNER_FILE "enable console owner file(solaris only)" ON)
119 if(HAVE_CONSOLE_OWNER_FILE)
120 set(DBUS_CONSOLE_OWNER_FILE "/dev/console" CACHE STRING "Directory to check for console ownerhip")
121 @@ -765,6 +772,7 @@ message(" Building bus stats API:
122 message(" installing system libs: ${DBUS_INSTALL_SYSTEM_LIBS} ")
123 message(" Building inotify support: ${DBUS_BUS_ENABLE_INOTIFY} ")
124 message(" Building kqueue support: ${DBUS_BUS_ENABLE_KQUEUE} ")
125 +message(" Building evports support: ${DBUS_BUS_ENABLE_EVPORTS} ")
126 message(" Building systemd support: ${DBUS_BUS_ENABLE_SYSTEMD} ")
127 message(" systemd system install dir:${DBUS_SYSTEMD_SYSTEMUNITDIR} ")
128 message(" systemd user install dir: ${DBUS_SYSTEMD_USERUNITDIR} ")
129 --- dbus-1.14.6/bus/dir-watch-evports.c
130 +++ dbus-1.14.6/bus/dir-watch-evports.c
131 @@ -0,0 +1,322 @@
132 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
133 +/* dir-watch-evports.c OS specific directory change notification for message bus
135 + * Copyright (C) 2023 Oracle and/or its affiliates.
137 + * Licensed under the Academic Free License version 2.1
138 + *
139 + * This program is free software; you can redistribute it and/or modify
140 + * it under the terms of the GNU General Public License as published by
141 + * the Free Software Foundation; either version 2 of the License, or
142 + * (at your option) any later version.
144 + * This program is distributed in the hope that it will be useful,
145 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
146 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147 + * GNU General Public License for more details.
148 + *
149 + * You should have received a copy of the GNU General Public License
150 + * along with this program; if not, write to the Free Software
151 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
153 + */
155 +#include <config.h>
157 +#include <errno.h>
158 +#include <port.h>
159 +#include <sys/stat.h>
160 +#include <unistd.h>
161 +#include <poll.h>
162 +#include <dirent.h>
164 +#include <dbus/dbus-internals.h>
165 +#include <dbus/dbus-list.h>
166 +#include <dbus/dbus-watch.h>
167 +#include "dir-watch.h"
169 +/* This limit is not just for the directories given by dbus but also for
170 + * all the files and directories within.
171 + */
172 +#define MAX_OBJECTS_TO_WATCH 128
174 +/* Because the data passed to port_associate are no longer significant after
175 + * the call, we can save memory by overlapping file_obj structures (such that
176 + * alignment is not an issue).
177 + */
178 +static dbus_int64_t fobjs[MAX_OBJECTS_TO_WATCH + sizeof(struct file_obj) - 1];
180 +static int port = -1;
181 +static DBusWatch *watch = NULL;
182 +static DBusLoop *loop = NULL;
183 +/* Used to define the point since given directories are being watched */
184 +struct timespec last_sighup;
186 +/* For the comparison of timespec structures */
187 +# define tslower(a, b) \
188 + (((a).tv_sec == (b).tv_sec) ? \
189 + ((a).tv_nsec < (b).tv_nsec) : \
190 + ((a).tv_sec < (b).tv_sec))
193 +static dbus_bool_t
194 +_handle_evport_watch (DBusWatch *_watch, unsigned int flags, void *data)
196 + struct timespec nullts = { 0, 0 };
197 + int res;
198 + port_event_t pe;
200 + res = port_get (port, &pe, &nullts);
202 + /* Sleep for half a second to avoid a race when files are being installed. */
203 + usleep (500000);
205 + if (res == 0)
207 + /* Remember this point in order to not miss any further changes. */
208 + clock_gettime (CLOCK_REALTIME, &last_sighup);
209 + _dbus_verbose ("Sending SIGHUP signal on reception of an event\n");
210 + (void) kill (_dbus_getpid (), SIGHUP);
212 + else if (res < 0 && errno == EBADF)
214 + port = -1;
215 + _dbus_assert (watch == _watch);
216 + if (watch != NULL)
218 + _dbus_loop_remove_watch (loop, watch);
219 + _dbus_watch_invalidate (watch);
220 + _dbus_watch_unref (watch);
221 + watch = NULL;
223 + _dbus_verbose ("Sending SIGHUP signal since event port has been closed\n");
224 + (void) kill (_dbus_getpid (), SIGHUP);
227 + return TRUE;
230 +static void
231 +_shutdown_watch (void *data)
233 + if (loop == NULL)
234 + return;
236 + _dbus_loop_unref (loop);
237 + loop = NULL;
240 +static int
241 +_init_watch (BusContext *context)
243 + if (loop == NULL)
245 + if (!_dbus_register_shutdown_func (_shutdown_watch, NULL))
247 + _dbus_warn ("Unable to register shutdown function");
248 + return FALSE;
251 + loop = bus_context_get_loop (context);
252 + _dbus_loop_ref (loop);
254 + /* This is the point since when changes to files is being watched */
255 + if (clock_gettime (CLOCK_REALTIME, &last_sighup))
257 + _dbus_warn ("Cannot create evport; error '%s'", _dbus_strerror (errno));
258 + return FALSE;
262 + return TRUE;
265 +static dbus_bool_t
266 +_init_evport (void)
268 + /* First, close the old port if necessary. We can do so now and not miss any
269 + * notification as any changes since the last SIGHUP will be caught by the
270 + * new port (as last_sighup was set back then).
271 + */
272 + if (loop && watch)
274 + _dbus_loop_remove_watch (loop, watch);
277 + if (watch)
279 + _dbus_watch_invalidate (watch);
280 + _dbus_watch_unref (watch);
281 + watch = NULL;
284 + if (port != -1)
286 + /* This will also dissociate all the objects previously associated
287 + * with given port - no need to do so one by one.
288 + */
289 + close (port);
290 + port = -1;
293 + /* Rebuild everything at this point */
294 + port = port_create ();
295 + if (port == -1)
297 + _dbus_warn ("Cannot create evport; error '%s'", _dbus_strerror (errno));
298 + goto out;
301 + watch = _dbus_watch_new (port, DBUS_WATCH_READABLE, TRUE,
302 + _handle_evport_watch, NULL, NULL);
304 + if (watch == NULL)
306 + _dbus_warn ("Unable to create evport watch\n");
307 + goto out1;
310 + if (!_dbus_loop_add_watch (loop, watch))
312 + _dbus_warn ("Unable to add reload watch to main loop");
313 + goto out2;
316 + return TRUE;
318 +out2:
319 + if (watch)
321 + _dbus_watch_invalidate (watch);
322 + _dbus_watch_unref (watch);
323 + watch = NULL;
326 +out1:
327 + if (port != -1)
329 + close (port);
330 + port = -1;
333 +out:
334 + return FALSE;
337 +static dbus_bool_t
338 +_associate (char *filepath, int index, dbus_bool_t file_only)
340 + int res;
341 + struct stat sb;
342 + struct file_obj *fobj;
344 + res = stat (filepath, &sb);
345 + if (res < 0)
347 + if (errno != ENOENT)
349 + _dbus_warn ("Cannot stat '%s'; error '%s'", filepath, _dbus_strerror (errno));
351 + return FALSE;
354 + if (file_only && !S_ISREG(sb.st_mode))
355 + return FALSE;
357 + /* file_obj structures can safely overlap as the data is no longer
358 + * necessary after the call
359 + */
360 + fobj = (struct file_obj *)(&fobjs[index]);
361 + fobj->fo_name = filepath;
362 + fobj->fo_atime = sb.st_atim;
363 + fobj->fo_mtime = sb.st_mtim;
364 + fobj->fo_ctime = sb.st_ctim;
366 + /* Event ports sadly don't let us set last_sighup to fobj directly as it only
367 + * checks for differences; it doesn't make timespec comparison.
368 + */
369 + if (tslower (last_sighup, sb.st_mtim) || tslower (last_sighup, sb.st_ctim)) {
370 + /* Changing one value to something different from stat forces immediate event. */
371 + fobj->fo_mtime = last_sighup;
374 + res = port_associate (port, PORT_SOURCE_FILE, (uintptr_t)fobj, FILE_MODIFIED|FILE_ATTRIB, NULL);
375 + if (res < 0)
377 + _dbus_warn ("Cannot setup evport for '%s'; error '%s'", filepath, _dbus_strerror (errno));
378 + return FALSE;
380 + return TRUE;
383 +void
384 +bus_set_watched_dirs (BusContext *context, DBusList **directories)
386 + DBusList *link;
387 + char buffer[256];
388 + int num_objects;
389 + DIR *folder;
390 + struct dirent *entry = NULL;
392 + if (!_init_watch (context))
393 + return;
395 + if (!_init_evport ())
396 + return;
398 + num_objects = 0;
399 + link = _dbus_list_get_first_link (directories);
400 + while (link != NULL && num_objects < MAX_OBJECTS_TO_WATCH)
402 + if (!_associate ((char *)link->data, num_objects, FALSE))
404 + /* Currently, this implementation goes through every directory given,
405 + * even if some of them fail stat/association, which is different
406 + * from other implementations. I am not sure whether that is an
407 + * issue; we'll see.
408 + */
409 + link = _dbus_list_get_next_link (directories, link);
410 + continue;
413 + num_objects++;
415 + /* Go through the entire directory */
416 + folder = opendir ((char *)link->data);
417 + if (folder == NULL)
419 + _dbus_warn ("Cannot read directory '%s'; error '%s'", (char *)link->data, _dbus_strerror (errno));
420 + link = _dbus_list_get_next_link (directories, link);
421 + continue;
424 + while ((entry = readdir (folder)))
426 + if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
427 + continue;
429 + if (num_objects >= MAX_OBJECTS_TO_WATCH)
430 + break;
432 + /* Construct full path to files within */
433 + buffer[0] = 0;
434 + strlcat (buffer, (char*)link->data, 256);
435 + if (buffer[strlen ((char*)link->data)-1] != '/') {
436 + strlcat (buffer, "/", 256);
438 + strlcat (buffer, entry->d_name, 256);
440 + if (!_associate (buffer, num_objects, TRUE))
441 + continue;
443 + num_objects++;
445 + closedir (folder);
446 + link = _dbus_list_get_next_link (directories, link);
449 + if (link != NULL || entry != NULL)
451 + _dbus_warn ("Too many files and directories to watch them all, only watching first %d.", MAX_OBJECTS_TO_WATCH);