mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-06 01:05:48 +02:00
Dynload libsystemd
This commit is contained in:
@@ -64,7 +64,6 @@ class Env:
|
||||
vcs_rev: str = ''
|
||||
binary_arch: BinaryArch = BinaryArch()
|
||||
native_optimizations: bool = False
|
||||
has_systemd: bool = False
|
||||
primary_version: int = 0
|
||||
secondary_version: int = 0
|
||||
xt_version: str = ''
|
||||
@@ -123,7 +122,6 @@ class Env:
|
||||
ans.vcs_rev = self.vcs_rev
|
||||
ans.binary_arch = self.binary_arch
|
||||
ans.native_optimizations = self.native_optimizations
|
||||
ans.has_systemd = self.has_systemd
|
||||
ans.primary_version = self.primary_version
|
||||
ans.secondary_version = self.secondary_version
|
||||
ans.xt_version = self.xt_version
|
||||
|
||||
@@ -349,7 +349,7 @@ class Child:
|
||||
fast_data_types.systemd_move_pid_into_new_scope(pid, f'kitty-{ppid}-{self.id}.scope', f'kitty child process: {pid} launched by: {ppid}')
|
||||
except NotImplementedError:
|
||||
pass
|
||||
except (RuntimeError, OSError) as err:
|
||||
except OSError as err:
|
||||
log_error("Could not move child process into a systemd scope: " + str(err))
|
||||
return pid
|
||||
|
||||
|
||||
114
kitty/systemd.c
114
kitty/systemd.c
@@ -7,27 +7,90 @@
|
||||
|
||||
#include "data-types.h"
|
||||
#include "cleanup.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef KITTY_HAS_SYSTEMD
|
||||
#include <systemd/sd-login.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
|
||||
#define LOAD_FUNC(name) {\
|
||||
*(void **) (&name) = dlsym(systemd.lib, #name); \
|
||||
if (!name) { \
|
||||
const char* error = dlerror(); \
|
||||
if (error != NULL) { \
|
||||
log_error("Failed to load the function %s with error: %s", #name, error); return; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
typedef struct sd_bus sd_bus;
|
||||
|
||||
static struct {
|
||||
void *lib;
|
||||
sd_bus *user_bus;
|
||||
bool initialized;
|
||||
bool initialized, functions_loaded, ok;
|
||||
} systemd = {0};
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *message;
|
||||
int _need_free;
|
||||
} sd_bus_error;
|
||||
typedef struct sd_bus_message sd_bus_message;
|
||||
|
||||
FUNC(sd_bus_default_user, int, sd_bus**);
|
||||
FUNC(sd_bus_message_unref, sd_bus_message*, sd_bus_message*);
|
||||
FUNC(sd_bus_error_free, void, sd_bus_error*);
|
||||
FUNC(sd_bus_unref, sd_bus*, sd_bus*);
|
||||
FUNC(sd_bus_message_new_method_call, int, sd_bus *, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member);
|
||||
FUNC(sd_bus_message_append, int, sd_bus_message *m, const char *types, ...);
|
||||
FUNC(sd_bus_message_open_container, int, sd_bus_message *m, char type, const char *contents);
|
||||
FUNC(sd_bus_message_close_container, int, sd_bus_message *m);
|
||||
FUNC(sd_pid_get_user_slice, int, pid_t pid, char **slice);
|
||||
FUNC(sd_bus_call, int, sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply);
|
||||
|
||||
static void
|
||||
ensure_initialized(void) {
|
||||
if (!systemd.initialized) {
|
||||
systemd.initialized = true;
|
||||
int ret = sd_bus_default_user(&systemd.user_bus);
|
||||
if (ret < 0) { log_error("Failed to open systemd user bus with error: %s", strerror(-ret)); }
|
||||
if (systemd.initialized) return;
|
||||
systemd.initialized = true;
|
||||
|
||||
const char* libnames[] = {
|
||||
#if defined(_KITTY_SYSTEMD_LIBRARY)
|
||||
_KITTY_SYSTEMD_LIBRARY,
|
||||
#else
|
||||
"libsystemd.so",
|
||||
// some installs are missing the .so symlink, so try the full name
|
||||
"libsystemd.so.0",
|
||||
"libsystemd.so.0.38.0",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
for (int i = 0; libnames[i]; i++) {
|
||||
systemd.lib = dlopen(libnames[i], RTLD_LAZY);
|
||||
if (systemd.lib) break;
|
||||
}
|
||||
if (systemd.lib == NULL) {
|
||||
log_error("Failed to load %s with error: %s\n", libnames[0], dlerror());
|
||||
return;
|
||||
}
|
||||
LOAD_FUNC(sd_bus_default_user);
|
||||
LOAD_FUNC(sd_bus_message_unref);
|
||||
LOAD_FUNC(sd_bus_error_free);
|
||||
LOAD_FUNC(sd_bus_unref);
|
||||
LOAD_FUNC(sd_bus_message_new_method_call);
|
||||
LOAD_FUNC(sd_bus_message_append);
|
||||
LOAD_FUNC(sd_bus_message_open_container);
|
||||
LOAD_FUNC(sd_bus_message_close_container);
|
||||
LOAD_FUNC(sd_pid_get_user_slice);
|
||||
LOAD_FUNC(sd_bus_call);
|
||||
systemd.functions_loaded = true;
|
||||
|
||||
int ret = sd_bus_default_user(&systemd.user_bus);
|
||||
if (ret < 0) { log_error("Failed to open systemd user bus with error: %s", strerror(-ret)); return; }
|
||||
systemd.ok = true;
|
||||
}
|
||||
|
||||
#define RAII_bus_error(name) __attribute__((cleanup(sd_bus_error_free))) sd_bus_error name = SD_BUS_ERROR_NULL;
|
||||
#define RAII_message(name) __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *name = NULL;
|
||||
static inline void err_cleanup(sd_bus_error *p) { sd_bus_error_free(p); }
|
||||
#define RAII_bus_error(name) __attribute__((cleanup(err_cleanup))) sd_bus_error name = {0};
|
||||
static inline void msg_cleanup(sd_bus_message **p) { sd_bus_message_unref(*p); }
|
||||
#define RAII_message(name) __attribute__((cleanup(msg_cleanup))) sd_bus_message *name = NULL;
|
||||
|
||||
#define SYSTEMD_DESTINATION "org.freedesktop.systemd1"
|
||||
#define SYSTEMD_PATH "/org/freedesktop/systemd1"
|
||||
@@ -55,11 +118,6 @@ set_reply_error(const char* func_name, int r, const sd_bus_error *err) {
|
||||
|
||||
static bool
|
||||
move_pid_into_new_scope(pid_t pid, const char* scope_name, const char *description) {
|
||||
ensure_initialized();
|
||||
if (!systemd.user_bus) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Could not connect to systemd user bus");
|
||||
return false;
|
||||
}
|
||||
pid_t parent_pid = getpid();
|
||||
RAII_bus_error(err); RAII_message(m); RAII_message(reply);
|
||||
int r;
|
||||
@@ -115,22 +173,32 @@ move_pid_into_new_scope(pid_t pid, const char* scope_name, const char *descripti
|
||||
|
||||
static void
|
||||
finalize(void) {
|
||||
if (systemd.user_bus) {
|
||||
sd_bus_unref(systemd.user_bus);
|
||||
}
|
||||
if (systemd.user_bus) sd_bus_unref(systemd.user_bus);
|
||||
if (systemd.lib) dlclose(systemd.lib);
|
||||
memset(&systemd, 0, sizeof(systemd));
|
||||
}
|
||||
|
||||
#endif
|
||||
static bool
|
||||
ensure_initialized_and_useable(void) {
|
||||
ensure_initialized();
|
||||
if (!systemd.ok) {
|
||||
if (!systemd.lib) PyErr_SetString(PyExc_NotImplementedError, "Could not load libsystemd");
|
||||
else if (!systemd.functions_loaded) PyErr_SetString(PyExc_NotImplementedError, "Could not load libsystemd functions");
|
||||
else PyErr_SetString(PyExc_NotImplementedError, "Could not connect to systemd user bus");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
systemd_move_pid_into_new_scope(PyObject *self UNUSED, PyObject *args) {
|
||||
long pid; const char *scope_name, *description;
|
||||
if (!PyArg_ParseTuple(args, "lss", &pid, &scope_name, &description)) return NULL;
|
||||
#ifdef KITTY_HAS_SYSTEMD
|
||||
move_pid_into_new_scope(pid, scope_name, description);
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
PyErr_SetString(PyExc_NotImplementedError, "not supported on this platform");
|
||||
#else
|
||||
if (!ensure_initialized_and_useable()) return NULL;
|
||||
move_pid_into_new_scope(pid, scope_name, description);
|
||||
#endif
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
@@ -145,9 +213,7 @@ static PyMethodDef module_methods[] = {
|
||||
|
||||
bool
|
||||
init_systemd_module(PyObject *module) {
|
||||
#ifdef KITTY_HAS_SYSTEMD
|
||||
register_at_exit_cleanup_func(SYSTEMD_CLEANUP_FUNC, finalize);
|
||||
#endif
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
|
||||
return true;
|
||||
|
||||
19
setup.py
19
setup.py
@@ -197,6 +197,7 @@ class Options:
|
||||
egl_library: Optional[str] = os.getenv('KITTY_EGL_LIBRARY')
|
||||
startup_notification_library: Optional[str] = os.getenv('KITTY_STARTUP_NOTIFICATION_LIBRARY')
|
||||
canberra_library: Optional[str] = os.getenv('KITTY_CANBERRA_LIBRARY')
|
||||
systemd_library: Optional[str] = os.getenv('KITTY_SYSTEMD_LIBRARY')
|
||||
fontconfig_library: Optional[str] = os.getenv('KITTY_FONTCONFIG_LIBRARY')
|
||||
building_arch: str = ''
|
||||
|
||||
@@ -454,6 +455,7 @@ def init_env(
|
||||
egl_library: Optional[str] = None,
|
||||
startup_notification_library: Optional[str] = None,
|
||||
canberra_library: Optional[str] = None,
|
||||
systemd_library: Optional[str] = None,
|
||||
fontconfig_library: Optional[str] = None,
|
||||
extra_logging: Iterable[str] = (),
|
||||
extra_include_dirs: Iterable[str] = (),
|
||||
@@ -545,6 +547,7 @@ def init_env(
|
||||
add_lpath('glfw/egl_context.c', '_GLFW_EGL_LIBRARY', egl_library)
|
||||
add_lpath('kitty/desktop.c', '_KITTY_STARTUP_NOTIFICATION_LIBRARY', startup_notification_library)
|
||||
add_lpath('kitty/desktop.c', '_KITTY_CANBERRA_LIBRARY', canberra_library)
|
||||
add_lpath('kitty/systemd.c', '_KITTY_SYSTEMD_LIBRARY', systemd_library)
|
||||
add_lpath('kitty/fontconfig.c', '_KITTY_FONTCONFIG_LIBRARY', fontconfig_library)
|
||||
|
||||
for path in extra_include_dirs:
|
||||
@@ -630,11 +633,6 @@ def kitty_env(args: Options) -> Env:
|
||||
else:
|
||||
cflags.extend(pkg_config('fontconfig', '--cflags-only-I'))
|
||||
platform_libs = []
|
||||
with suppress(SystemExit, subprocess.CalledProcessError):
|
||||
cflags.extend(pkg_config('libsystemd', '--cflags-only-I', fatal=False))
|
||||
systemd_libs = pkg_config('libsystemd', '--libs')
|
||||
platform_libs.extend(systemd_libs)
|
||||
ans.has_systemd = True
|
||||
cflags.extend(pkg_config('harfbuzz', '--cflags-only-I'))
|
||||
platform_libs.extend(pkg_config('harfbuzz', '--libs'))
|
||||
pylib = get_python_flags(args, cflags)
|
||||
@@ -730,8 +728,6 @@ def get_source_specific_defines(env: Env, src: str) -> Tuple[str, List[str], Opt
|
||||
return src, ['3rdparty/base64',], base64_defines(env.binary_arch.isa)
|
||||
if src == 'kitty/screen.c':
|
||||
return src, [], [f'PRIMARY_VERSION={env.primary_version}', f'SECONDARY_VERSION={env.secondary_version}', f'XT_VERSION="{env.xt_version}"']
|
||||
if src == 'kitty/systemd.c':
|
||||
return src, [], (['KITTY_HAS_SYSTEMD'] if env.has_systemd else None)
|
||||
if src == 'kitty/fast-file-copy.c':
|
||||
return src, [], (['HAS_COPY_FILE_RANGE'] if env.has_copy_file_range else None)
|
||||
try:
|
||||
@@ -1000,7 +996,7 @@ def init_env_from_args(args: Options, native_optimizations: bool = False) -> Non
|
||||
global env
|
||||
env = init_env(
|
||||
args.debug, args.sanitize, native_optimizations, args.link_time_optimization, args.profile,
|
||||
args.egl_library, args.startup_notification_library, args.canberra_library, args.fontconfig_library,
|
||||
args.egl_library, args.startup_notification_library, args.canberra_library, args.systemd_library, args.fontconfig_library,
|
||||
args.extra_logging, args.extra_include_dirs, args.ignore_compiler_warnings,
|
||||
args.building_arch, args.extra_library_dirs, verbose=args.verbose > 0, vcs_rev=args.vcs_rev,
|
||||
)
|
||||
@@ -1956,6 +1952,13 @@ def option_parser() -> argparse.ArgumentParser: # {{{
|
||||
help='The filename argument passed to dlopen for libcanberra.'
|
||||
' This can be used to change the name of the loaded library or specify an absolute path.'
|
||||
)
|
||||
p.add_argument(
|
||||
'--systemd-library',
|
||||
type=str,
|
||||
default=Options.systemd_library,
|
||||
help='The filename argument passed to dlopen for libsystemd.'
|
||||
' This can be used to change the name of the loaded library or specify an absolute path.'
|
||||
)
|
||||
p.add_argument(
|
||||
'--fontconfig-library',
|
||||
type=str,
|
||||
|
||||
Reference in New Issue
Block a user