~rootmos/action

7500f2aeac9217d18b3957a69eee5344d0b1c2c1 — Gustav Behm 5 months ago a46a882
Reorganize action.c
1 files changed, 106 insertions(+), 80 deletions(-)

M c-impl/action.c
M c-impl/action.c => c-impl/action.c +106 -80
@@ 76,9 76,65 @@ static void parse_options(struct options* o, int argc, char* argv[])
    }
}

struct msg {
    char action[ACTION_MAX];
    struct timespec timestamp;
};

static 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;
}

static void prepare_sockaddr(struct sockaddr_un* addr, const char* socket_path)
{
    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);
}

static int cmd_trigger(const struct options* o, const char* socket_path)
{
    debug("triggering: %s", o->action);

    int fd = socket(AF_UNIX, SOCK_DGRAM, 0);

    struct sockaddr_un addr;
    prepare_sockaddr(&addr, socket_path);

    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 {
    int running;

    int exit_code;
    int sfd;
};



@@ 100,11 156,6 @@ static int signalfd_init(struct state* st)
    return fd;
}

static int signalfd_fd(const struct state* st)
{
    return st->sfd;
}

static void signalfd_deinit(struct state* st)
{
    int r = close(st->sfd); CHECK(r, "close");


@@ 129,96 180,43 @@ static void signalfd_handle_event(struct state* st)
        if(si.ssi_signo == SIGINT) {
            debug("SIGINT");
            st->running = 0;
            st->exit_code = 1;
        } else if(si.ssi_signo == SIGTERM) {
            debug("SIGTERM");
            st->running = 0;
            st->exit_code = 1;
        } else {
            warning("unhandled signal: %u", si.ssi_signo);
        }
    }
}

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;
}

static void prepare_socket_path(const char* sp)
static void prepare_socket_path(const char* socket_path)
{
    struct stat st;
    int r = stat(sp, &st);
    int r = stat(socket_path, &st);
    if(r == 0) {
        if((st.st_mode & S_IFMT) == S_IFSOCK) {
            debug("socket already exists, trying to unlink: %s", sp);
            r = unlink(sp);
            CHECK(r, "unlink(%s)", sp);
            debug("socket already exists, trying to unlink: %s", socket_path);
            r = unlink(socket_path);
            CHECK(r, "unlink(%s)", socket_path);
        } else {
            failwith("socket path already exists (and is not a socket): %s", sp);
            failwith("socket path already exists (and is not a socket): %s", socket_path);
        }
    } else if(r == -1 && errno != ENOENT) {
        CHECK(r, "stat(%s)", sp);
        CHECK(r, "stat(%s)", socket_path);
    } else {
        xdg_makedirs(dirname(strdupa(sp)));
        xdg_makedirs(dirname(strdupa(socket_path)));
    }
}

int main(int argc, char* argv[])
static int cmd_bind(const struct options* o, const char* socket_path)
{
    struct options o;
    parse_options(&o, argc, 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\n", socket_path);
        goto exit;
    }

    int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    CHECK(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 sockaddr_un addr;
    prepare_sockaddr(&addr, socket_path);

    prepare_socket_path(socket_path);



@@ 229,12 227,11 @@ int main(int argc, char* argv[])

    struct state st = {
        .running = 1,
        .exit_code = 255,
    };

    signalfd_init(&st);

    struct pollfd fds[] = {
        { .fd = signalfd_fd(&st), .events = POLLIN },
        { .fd = signalfd_init(&st), .events = POLLIN },
        { .fd = fd, .events = POLLIN },
    };



@@ 256,9 253,10 @@ int main(int argc, char* argv[])
                failwith("unexpected partial recvfrom");
            }

            if(strncmp(msg.action, o.action, sizeof(msg.action)) == 0) {
                info("triggered: %s (%s)", o.action, iso8601_timespec(&msg.timestamp));
            if(strncmp(msg.action, o->action, sizeof(msg.action)) == 0) {
                info("triggered: %s (%s)", o->action, iso8601_timespec(&msg.timestamp));
                st.running = 0;
                st.exit_code = 0;
            }

            fds[1].revents &= ~POLLIN;


@@ 280,8 278,36 @@ int main(int argc, char* argv[])
    r = unlink(socket_path);
    CHECK(r, "unlink(%s)", socket_path);

exit:
    return st.exit_code;
}

int main(int argc, char* argv[])
{
    struct options o;
    parse_options(&o, argc, 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);

    int ec = 255;

    if(o.cmd == PRINT_PATH) {
        // ensure the path is a valid socket address
        struct sockaddr_un addr;
        prepare_sockaddr(&addr, socket_path);

        printf("%s\n", socket_path);
        ec = 0;
    } else if(o.cmd == TRIGGER) {
        ec = cmd_trigger(&o, socket_path);
    } else if(o.cmd == BIND) {
        ec = cmd_bind(&o, socket_path);
    }

    xdg_free(xdg);

    return 0;
    return ec;
}