@@ 1,12 1,16 @@
#include <poll.h>
#include <signal.h>
#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#define LIBR_IMPLEMENTATION
#include "r.h"
+#define ACTION_MAX (NAME_MAX)
+
struct options {
- const char* action;
+ char action[ACTION_MAX+1];
enum {
NOOP = 0,
@@ 45,7 49,11 @@ static void parse_options(struct options* o, int argc, char* argv[])
}
if(optind + 1 == argc) {
- o->action = argv[optind];
+ if(strnlen(argv[optind], ACTION_MAX) > ACTION_MAX) {
+ dprintf(2, "error: action too long\n");
+ exit(2);
+ }
+ strncpy(o->action, argv[optind], ACTION_MAX);
debug("action: %s", o->action);
} else {
if(optind >= argc) {
@@ 126,6 134,19 @@ static void signalfd_handle_event(struct state* st)
}
}
+struct msg {
+ char action[ACTION_MAX];
+ struct timespec timestamp;
+};
+
+const char* iso8601_timespec(const struct timespec* ts)
+{
+ static char buf[21];
+ size_t r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&ts->tv_sec));
+ if(r <= 0) abort();
+ return buf;
+}
+
int main(int argc, char* argv[])
{
struct options o;
@@ 133,11 154,49 @@ int main(int argc, char* argv[])
struct xdg* xdg = xdg_new("action");
+ char socket_path[PATH_MAX];
+ xdg_resolve(xdg, XDG_RUNTIME, LIT(socket_path), o.action, NULL);
+ debug("socket path: %s", socket_path);
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if(strlen(socket_path) >= sizeof(addr.sun_path)) {
+ failwith("socket path too long");
+ }
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
+
if(o.cmd == PRINT_PATH) {
- printf("%s/%s\n", xdg_runtime(xdg), o.action);
+ printf("%s\n", socket_path);
goto exit;
}
+ int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+
+ if(o.cmd == TRIGGER) {
+ debug("triggering: %s", o.action);
+
+ struct msg msg = {0};
+ strncpy(msg.action, o.action, sizeof(msg.action));
+ int r = clock_gettime(CLOCK_REALTIME, &msg.timestamp);
+ CHECK(r, "clock_gettime(CLOCK_REALTIME)");
+
+ ssize_t s = sendto(fd,
+ &msg, sizeof(msg),
+ 0,
+ (const struct sockaddr*)&addr, sizeof(addr));
+ CHECK(s, "sendto(%s)", socket_path);
+
+ if(s != sizeof(msg)) {
+ failwith("unexpected partial sendto");
+ }
+
+ info("triggered: %s (%s)", o.action, iso8601_timespec(&msg.timestamp));
+
+ r = close(fd); CHECK(r, "close");
+ return 0;
+ }
+
struct state st = {
.running = 1,
};