diff --git a/ctl.c b/ctl.c new file mode 100644 index 0000000..15b6358 --- /dev/null +++ b/ctl.c @@ -0,0 +1,90 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipc.h" + +static void usage(const char *progname) { + fprintf(stderr, "Usage: %s [command]\n" + "Accepted commands:\n" + " reload - reload the config file\n", + progname); +} + +static long reload_callback(VarlinkConnection *connection, const char *error, + VarlinkObject *parameters, uint64_t flags, void *userdata) { + return varlink_connection_close(connection); +} + +static int set_blocking(int fd) { + int flags = fcntl(fd, F_GETFL); + if (flags == -1) { + fprintf(stderr, "fnctl F_GETFL failed: %s\n", strerror(errno)); + return -1; + } + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) == -1) { + fprintf(stderr, "fnctl F_SETFL failed: %s\n", strerror(errno)); + return -1; + } + return 0; +} + +int wait_for_event(VarlinkConnection *connection) { + int fd = varlink_connection_get_fd(connection); + if (set_blocking(fd) != 0) { + return -1; + } + + while (!varlink_connection_is_closed(connection)) { + uint32_t events = varlink_connection_get_events(connection); + long result = varlink_connection_process_events(connection, events); + if (result != 0) { + fprintf(stderr, "varlink_connection_process_events failed: %s\n", + varlink_error_string(-result)); + return -1; + } + } + return 0; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + usage(argv[0]); + return EXIT_FAILURE; + } + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + usage(argv[0]); + return EXIT_SUCCESS; + } + + VarlinkConnection *connection; + char address[PATH_MAX]; + if (get_ipc_address(address, sizeof(address)) < 0) { + return EXIT_FAILURE; + } + if (varlink_connection_new(&connection, address) != 0) { + fprintf(stderr, "Couldn't connect to kanshi at %s.\n" + "Is the kanshi daemon running?\n", address); + return EXIT_FAILURE; + } + if (strcmp(argv[1], "reload") == 0) { + long result = varlink_connection_call(connection, + "fr.emersion.kanshi.Reload", NULL, 0, reload_callback, NULL); + if (result != 0) { + fprintf(stderr, "varlink_connection_call failed: %s\n", + varlink_error_string(-result)); + return EXIT_FAILURE; + } + return wait_for_event(connection); + } + fprintf(stderr, "invalid command: %s\n", argv[1]); + usage(argv[0]); + return EXIT_FAILURE; +} diff --git a/kanshi.1.scd b/kanshi.1.scd index fc6c73b..9abf391 100644 --- a/kanshi.1.scd +++ b/kanshi.1.scd @@ -43,4 +43,4 @@ https://github.com/emersion/kanshi. # SEE ALSO -*kanshi*(5) +*kanshi*(5) *kanshictl*(1) diff --git a/kanshictl.1.scd b/kanshictl.1.scd new file mode 100644 index 0000000..8df1bed --- /dev/null +++ b/kanshictl.1.scd @@ -0,0 +1,28 @@ +kanshictl(1) + +# NAME + +kanshictl - control the kanshi daemon remotely + +# SYNOPSIS + +*kanshictl* [options...] [command] + +# OPTIONS + +*-h, --help* + Show help message and quit. + +# COMMANDS + +reload - reload the config file + +# AUTHORS + +Maintained by Simon Ser , who is assisted by other +open-source contributors. For more information about kanshi development, see +https://github.com/emersion/kanshi. + +# SEE ALSO + +*kanshi*(1) diff --git a/meson.build b/meson.build index a321cba..da571ec 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,19 @@ executable( install: true, ) +if varlink.found() + executable( + meson.project_name() + 'ctl', + files( + 'ctl.c', + 'ipc-addr.c', + ), + include_directories: include_directories('include'), + dependencies: [varlink], + install: true, + ) +endif + scdoc = dependency( 'scdoc', version: '>=1.9.2', @@ -83,6 +96,9 @@ if scdoc.found() 'kanshi.1.scd', 'kanshi.5.scd', ] + if varlink.found() + man_files += 'kanshictl.1.scd' + endif foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] section = filename.split('.')[-2]