#include "linux_rawio.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

friidump_linux_rawio_state friidump_linux_rawio_state_from_status_file(
    const char *status_path,
    unsigned long long *effective_mask) {
    FILE *status;
    char line[256];
    unsigned long long value;
    char *end;

    if (effective_mask)
        *effective_mask = 0;

    if (!status_path || !status_path[0])
        return FRIIDUMP_LINUX_RAWIO_UNKNOWN;

    status = fopen(status_path, "rb");
    if (!status)
        return FRIIDUMP_LINUX_RAWIO_UNKNOWN;

    while (fgets(line, sizeof(line), status)) {
        if (strncmp(line, "CapEff:", 7) != 0)
            continue;

        errno = 0;
        value = strtoull(line + 7, &end, 16);
        fclose(status);

        if (errno != 0 || end == line + 7)
            return FRIIDUMP_LINUX_RAWIO_UNKNOWN;

        if (effective_mask)
            *effective_mask = value;

        return (value & (1ULL << FRIIDUMP_LINUX_CAP_SYS_RAWIO))
            ? FRIIDUMP_LINUX_RAWIO_PRESENT
            : FRIIDUMP_LINUX_RAWIO_MISSING;
    }

    fclose(status);
    return FRIIDUMP_LINUX_RAWIO_UNKNOWN;
}

friidump_linux_rawio_state friidump_linux_rawio_effective(
    unsigned long long *effective_mask) {
    return friidump_linux_rawio_state_from_status_file(
        "/proc/self/status", effective_mask);
}

int friidump_linux_executable_path(char *buffer, size_t buffer_size) {
    ssize_t length;

    if (!buffer || buffer_size < 2)
        return 0;

    buffer[0] = '\0';
    length = readlink("/proc/self/exe", buffer, buffer_size - 1);
    if (length <= 0 || (size_t) length >= buffer_size)
        return 0;

    buffer[length] = '\0';
    return 1;
}
