~rootmos/action

cefef69a4f1e348d5f10c0a1e415dbfc4fa98efe — Gustav Behm 5 months ago 54b4d98
Trigger action
1 files changed, 62 insertions(+), 3 deletions(-)

M c-impl/action.c
M c-impl/action.c => c-impl/action.c +62 -3
@@ 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,
    };