/*
 * ra_read.c - read a sysctl as binary, output raw bytes to stdout.
 *             Works as unprivileged user for net.inet6.icmp6.nd6_prlist.
 *
 * Usage: ./ra_read <sysctl.name> [out_file]
 *   e.g. ./ra_read net.inet6.icmp6.nd6_prlist /tmp/prlist.bin
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef nitems
#define nitems(x) (sizeof((x)) / sizeof((x)[0]))
#endif

int main(int argc, char **argv)
{
    const char *name = (argc > 1) ? argv[1] : "net.inet6.icmp6.nd6_prlist";
    const char *out  = (argc > 2) ? argv[2] : NULL;
    int mib[4];
    size_t miblen = nitems(mib);
    if (sysctlnametomib(name, mib, &miblen) != 0) {
        perror("sysctlnametomib");
        return 2;
    }
    size_t len = 0;
    if (sysctl(mib, miblen, NULL, &len, NULL, 0) != 0) {
        perror("sysctl len");
        return 3;
    }
    char *buf = malloc(len ? len : 1);
    if (!buf) { perror("malloc"); return 4; }
    if (sysctl(mib, miblen, buf, &len, NULL, 0) != 0) {
        perror("sysctl get");
        free(buf);
        return 5;
    }
    FILE *f = (out && strcmp(out, "-") != 0) ? fopen(out, "wb") : stdout;
    if (!f) { perror("fopen"); free(buf); return 6; }
    fwrite(buf, 1, len, f);
    if (f != stdout) {
        fprintf(stderr, "wrote %zu bytes to %s\n", len, out);
        fclose(f);
    }
    /* summary line to stderr regardless */
    fprintf(stderr, "sysctl %s returned %zu bytes\n", name, len);
    free(buf);
    return 0;
}
