mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-05 20:40:20 +01:00
Add event ports support (Solaris file monitoring backend)
This commit is contained in:
parent
1bcf396c78
commit
d7f227cb7e
8 changed files with 365 additions and 0 deletions
|
|
@ -498,6 +498,13 @@ endif()
|
|||
|
||||
string(TOUPPER ${CMAKE_SYSTEM_NAME} sysname)
|
||||
if("${sysname}" MATCHES ".*SOLARIS.*")
|
||||
option(DBUS_BUS_ENABLE_EVPORTS "build with evports support (solaris only)" ON)
|
||||
if(DBUS_BUS_ENABLE_EVPORTS)
|
||||
if(NOT HAVE_PORT_H)
|
||||
message(FATAL_ERROR "port.h not found!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(HAVE_CONSOLE_OWNER_FILE "enable console owner file(solaris only)" ON)
|
||||
if(HAVE_CONSOLE_OWNER_FILE)
|
||||
set(DBUS_CONSOLE_OWNER_FILE "/dev/console" CACHE STRING "Directory to check for console ownerhip")
|
||||
|
|
@ -751,6 +758,7 @@ message(" Building bus stats API: ${DBUS_ENABLE_STATS} "
|
|||
message(" installing system libs: ${DBUS_INSTALL_SYSTEM_LIBS} ")
|
||||
message(" Building inotify support: ${DBUS_BUS_ENABLE_INOTIFY} ")
|
||||
message(" Building kqueue support: ${DBUS_BUS_ENABLE_KQUEUE} ")
|
||||
message(" Building evports support: ${DBUS_BUS_ENABLE_EVPORTS} ")
|
||||
message(" Building systemd support: ${DBUS_BUS_ENABLE_SYSTEMD} ")
|
||||
message(" systemd system install dir:${DBUS_SYSTEMD_SYSTEMUNITDIR} ")
|
||||
message(" systemd user install dir: ${DBUS_SYSTEMD_USERUNITDIR} ")
|
||||
|
|
|
|||
|
|
@ -214,6 +214,10 @@ DBUS_BUS_ENABLE_INOTIFY:BOOL=ON
|
|||
// enable kqueue as dir watch backend
|
||||
DBUS_BUS_ENABLE_KQUEUE:BOOL=ON
|
||||
|
||||
*Solaris only:
|
||||
// enable evports as dir watch backend
|
||||
DBUS_BUS_ENABLE_EVPORTS:BOOL=ON
|
||||
|
||||
x11 only:
|
||||
// Build with X11 auto launch support
|
||||
DBUS_BUILD_X11:BOOL=ON
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ if(DBUS_BUS_ENABLE_INOTIFY)
|
|||
set(DIR_WATCH_SOURCE dir-watch-inotify.c)
|
||||
elseif(DBUS_BUS_ENABLE_KQUEUE)
|
||||
set(DIR_WATCH_SOURCE dir-watch-kqueue.c)
|
||||
elseif(DBUS_BUS_ENABLE_EVPORTS)
|
||||
set(DIR_WATCH_SOURCE dir-watch-evports.c)
|
||||
else(DBUS_BUS_ENABLE_INOTIFY)
|
||||
set(DIR_WATCH_SOURCE dir-watch-default.c)
|
||||
endif()
|
||||
|
|
|
|||
324
bus/dir-watch-evports.c
Normal file
324
bus/dir-watch-evports.c
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/* dir-watch-evports.c OS specific directory change notification for message bus
|
||||
*
|
||||
* Copyright (C) 2024 Oracle and/or its affiliates.
|
||||
*
|
||||
* SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
|
||||
*
|
||||
* Licensed under the Academic Free License version 2.1
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <port.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <dbus/dbus-internals.h>
|
||||
#include <dbus/dbus-list.h>
|
||||
#include <dbus/dbus-watch.h>
|
||||
#include "dir-watch.h"
|
||||
|
||||
/* This limit is not just for the directories given by dbus but also for
|
||||
* all the files and directories within.
|
||||
*/
|
||||
#define MAX_OBJECTS_TO_WATCH 128
|
||||
|
||||
/* Because the data passed to port_associate are no longer significant after
|
||||
* the call, we can save memory by overlapping file_obj structures (such that
|
||||
* alignment is not an issue).
|
||||
*/
|
||||
static dbus_int64_t fobjs[MAX_OBJECTS_TO_WATCH + sizeof(struct file_obj) - 1];
|
||||
|
||||
static int port = -1;
|
||||
static DBusWatch *watch = NULL;
|
||||
static DBusLoop *loop = NULL;
|
||||
/* Used to define the point since given directories are being watched */
|
||||
struct timespec last_sighup;
|
||||
|
||||
/* For the comparison of timespec structures */
|
||||
# define tslower(a, b) \
|
||||
(((a).tv_sec == (b).tv_sec) ? \
|
||||
((a).tv_nsec < (b).tv_nsec) : \
|
||||
((a).tv_sec < (b).tv_sec))
|
||||
|
||||
|
||||
static dbus_bool_t
|
||||
_handle_evport_watch (DBusWatch *_watch, unsigned int flags, void *data)
|
||||
{
|
||||
struct timespec nullts = { 0, 0 };
|
||||
int res;
|
||||
port_event_t pe;
|
||||
|
||||
res = port_get (port, &pe, &nullts);
|
||||
|
||||
/* Sleep for half a second to avoid a race when files are being installed. */
|
||||
usleep (500000);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
/* Remember this point in order to not miss any further changes. */
|
||||
clock_gettime (CLOCK_REALTIME, &last_sighup);
|
||||
_dbus_verbose ("Sending SIGHUP signal on reception of an event\n");
|
||||
(void) kill (_dbus_getpid (), SIGHUP);
|
||||
}
|
||||
else if (res < 0 && errno == EBADF)
|
||||
{
|
||||
port = -1;
|
||||
_dbus_assert (watch == _watch);
|
||||
if (watch != NULL)
|
||||
{
|
||||
_dbus_loop_remove_watch (loop, watch);
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
watch = NULL;
|
||||
}
|
||||
_dbus_verbose ("Sending SIGHUP signal since event port has been closed\n");
|
||||
(void) kill (_dbus_getpid (), SIGHUP);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_shutdown_watch (void *data)
|
||||
{
|
||||
if (loop == NULL)
|
||||
return;
|
||||
|
||||
_dbus_loop_unref (loop);
|
||||
loop = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
_init_watch (BusContext *context)
|
||||
{
|
||||
if (loop == NULL)
|
||||
{
|
||||
if (!_dbus_register_shutdown_func (_shutdown_watch, NULL))
|
||||
{
|
||||
_dbus_warn ("Unable to register shutdown function");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
loop = bus_context_get_loop (context);
|
||||
_dbus_loop_ref (loop);
|
||||
|
||||
/* This is the point since when changes to files is being watched */
|
||||
if (clock_gettime (CLOCK_REALTIME, &last_sighup))
|
||||
{
|
||||
_dbus_warn ("Cannot create evport; error '%s'", _dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
_init_evport (void)
|
||||
{
|
||||
/* First, close the old port if necessary. We can do so now and not miss any
|
||||
* notification as any changes since the last SIGHUP will be caught by the
|
||||
* new port (as last_sighup was set back then).
|
||||
*/
|
||||
if (loop && watch)
|
||||
{
|
||||
_dbus_loop_remove_watch (loop, watch);
|
||||
}
|
||||
|
||||
if (watch)
|
||||
{
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
watch = NULL;
|
||||
}
|
||||
|
||||
if (port != -1)
|
||||
{
|
||||
/* This will also dissociate all the objects previously associated
|
||||
* with given port - no need to do so one by one.
|
||||
*/
|
||||
close (port);
|
||||
port = -1;
|
||||
}
|
||||
|
||||
/* Rebuild everything at this point */
|
||||
port = port_create ();
|
||||
if (port == -1)
|
||||
{
|
||||
_dbus_warn ("Cannot create evport; error '%s'", _dbus_strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
watch = _dbus_watch_new (port, DBUS_WATCH_READABLE, TRUE,
|
||||
_handle_evport_watch, NULL, NULL);
|
||||
|
||||
if (watch == NULL)
|
||||
{
|
||||
_dbus_warn ("Unable to create evport watch\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (!_dbus_loop_add_watch (loop, watch))
|
||||
{
|
||||
_dbus_warn ("Unable to add reload watch to main loop");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
out2:
|
||||
if (watch)
|
||||
{
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
watch = NULL;
|
||||
}
|
||||
|
||||
out1:
|
||||
if (port != -1)
|
||||
{
|
||||
close (port);
|
||||
port = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
_associate (char *filepath, int index, dbus_bool_t file_only)
|
||||
{
|
||||
int res;
|
||||
struct stat sb;
|
||||
struct file_obj *fobj;
|
||||
|
||||
res = stat (filepath, &sb);
|
||||
if (res < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
_dbus_warn ("Cannot stat '%s'; error '%s'", filepath, _dbus_strerror (errno));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (file_only && !S_ISREG(sb.st_mode))
|
||||
return FALSE;
|
||||
|
||||
/* file_obj structures can safely overlap as the data is no longer
|
||||
* necessary after the call
|
||||
*/
|
||||
fobj = (struct file_obj *)(&fobjs[index]);
|
||||
fobj->fo_name = filepath;
|
||||
fobj->fo_atime = sb.st_atim;
|
||||
fobj->fo_mtime = sb.st_mtim;
|
||||
fobj->fo_ctime = sb.st_ctim;
|
||||
|
||||
/* Event ports sadly don't let us set last_sighup to fobj directly as it only
|
||||
* checks for differences; it doesn't make timespec comparison.
|
||||
*/
|
||||
if (tslower (last_sighup, sb.st_mtim) || tslower (last_sighup, sb.st_ctim)) {
|
||||
/* Changing one value to something different from stat forces immediate event. */
|
||||
fobj->fo_mtime = last_sighup;
|
||||
}
|
||||
|
||||
res = port_associate (port, PORT_SOURCE_FILE, (uintptr_t)fobj, FILE_MODIFIED|FILE_ATTRIB, NULL);
|
||||
if (res < 0)
|
||||
{
|
||||
_dbus_warn ("Cannot setup evport for '%s'; error '%s'", filepath, _dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
bus_set_watched_dirs (BusContext *context, DBusList **directories)
|
||||
{
|
||||
DBusList *link;
|
||||
char buffer[256];
|
||||
int num_objects;
|
||||
DIR *folder;
|
||||
struct dirent *entry = NULL;
|
||||
|
||||
if (!_init_watch (context))
|
||||
return;
|
||||
|
||||
if (!_init_evport ())
|
||||
return;
|
||||
|
||||
num_objects = 0;
|
||||
link = _dbus_list_get_first_link (directories);
|
||||
while (link != NULL && num_objects < MAX_OBJECTS_TO_WATCH)
|
||||
{
|
||||
if (!_associate ((char *)link->data, num_objects, FALSE))
|
||||
{
|
||||
/* Currently, this implementation goes through every directory given,
|
||||
* even if some of them fail stat/association, which is different
|
||||
* from other implementations. I am not sure whether that is an
|
||||
* issue; we'll see.
|
||||
*/
|
||||
link = _dbus_list_get_next_link (directories, link);
|
||||
continue;
|
||||
}
|
||||
|
||||
num_objects++;
|
||||
|
||||
/* Go through the entire directory */
|
||||
folder = opendir ((char *)link->data);
|
||||
if (folder == NULL)
|
||||
{
|
||||
_dbus_warn ("Cannot read directory '%s'; error '%s'", (char *)link->data, _dbus_strerror (errno));
|
||||
link = _dbus_list_get_next_link (directories, link);
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((entry = readdir (folder)))
|
||||
{
|
||||
if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
if (num_objects >= MAX_OBJECTS_TO_WATCH)
|
||||
break;
|
||||
|
||||
/* Construct full path to files within */
|
||||
buffer[0] = 0;
|
||||
strlcat (buffer, (char*)link->data, 256);
|
||||
if (buffer[strlen ((char*)link->data)-1] != '/') {
|
||||
strlcat (buffer, "/", 256);
|
||||
}
|
||||
strlcat (buffer, entry->d_name, 256);
|
||||
|
||||
if (!_associate (buffer, num_objects, TRUE))
|
||||
continue;
|
||||
|
||||
num_objects++;
|
||||
}
|
||||
closedir (folder);
|
||||
link = _dbus_list_get_next_link (directories, link);
|
||||
}
|
||||
|
||||
if (link != NULL || entry != NULL)
|
||||
{
|
||||
_dbus_warn ("Too many files and directories to watch them all, only watching first %d.", MAX_OBJECTS_TO_WATCH);
|
||||
}
|
||||
}
|
||||
|
|
@ -112,6 +112,8 @@ libdbus_daemon_internal_sources = [
|
|||
|
||||
if use_kqueue
|
||||
libdbus_daemon_internal_sources += 'dir-watch-kqueue.c'
|
||||
elif use_evports
|
||||
libdbus_daemon_internal_sources += 'dir-watch-evports.c'
|
||||
elif use_inotify
|
||||
libdbus_daemon_internal_sources += 'dir-watch-inotify.c'
|
||||
else
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ check_include_file(io.h HAVE_IO_H) # internal
|
|||
check_include_file(linux/close_range.h HAVE_LINUX_CLOSE_RANGE_H)
|
||||
check_include_file(linux/magic.h HAVE_LINUX_MAGIC_H)
|
||||
check_include_file(locale.h HAVE_LOCALE_H)
|
||||
check_include_file(port.h HAVE_PORT_H)
|
||||
check_include_file(signal.h HAVE_SIGNAL_H)
|
||||
check_include_file(stdatomic.h HAVE_STDATOMIC_H)
|
||||
check_include_file(stdio.h HAVE_STDIO_H) # dbus-sysdeps.h
|
||||
|
|
|
|||
17
meson.build
17
meson.build
|
|
@ -499,6 +499,22 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
if get_option('evports').disabled()
|
||||
use_evports = false
|
||||
else
|
||||
use_evports = (
|
||||
cc.has_header('port.h', args: compile_args_c) and
|
||||
cc.has_function(
|
||||
'port_create',
|
||||
prefix: '#include <port.h>',
|
||||
args: compile_args_c,
|
||||
)
|
||||
)
|
||||
if get_option('evports').enabled() and not use_evports
|
||||
error('event ports support requested but not found')
|
||||
endif
|
||||
endif
|
||||
|
||||
if get_option('launchd').disabled()
|
||||
use_launchd = false
|
||||
else
|
||||
|
|
@ -1431,6 +1447,7 @@ summary_dict += {
|
|||
'Building AppArmor support': apparmor.found(),
|
||||
'Building inotify support': use_inotify,
|
||||
'Building kqueue support': use_kqueue,
|
||||
'Building evports support': use_evports,
|
||||
'Building systemd support': use_systemd,
|
||||
'Building elogind support': use_elogind,
|
||||
'Traditional activation': use_traditional_activation,
|
||||
|
|
|
|||
|
|
@ -130,6 +130,13 @@ option(
|
|||
description: 'Kqueue support'
|
||||
)
|
||||
|
||||
option(
|
||||
'evports',
|
||||
type: 'feature',
|
||||
value: 'auto',
|
||||
description: 'event port support'
|
||||
)
|
||||
|
||||
option(
|
||||
'launchd',
|
||||
type: 'feature',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue