ioctl-id 0.2.0

Rust identifiers for `ioctl(2)` calls on Unix-like systems.
Documentation
#include <linux/ioctl.h>

typedef struct {
    char c;
} Size1;

typedef struct {
    char c[20];
} Size20;

typedef struct {
    char c[_IOC_SIZEMASK];
} SizeMax;

#define EQ_CHECK(rname, cname) \
    fprintf(fp, "    assert_eq!(%s, %u);\n", #rname, cname)


#define IOC_CHECK(dir, type, nr, size) \
    fprintf(fp, "    assert_eq!(ioc(%lu, %lu, %lu, %lu), 0x%lx);\n", \
            ((unsigned long) (dir)), \
            ((unsigned long) (type)), \
            ((unsigned long) (nr)), \
            ((unsigned long) (size)), \
            ((unsigned long) _IOC((dir), (type), (nr), (size))))

#define IO_CHECK(type, nr) \
    fprintf(fp, "    assert_eq!(io(%lu, %lu), 0x%lx);\n", \
            ((unsigned long) (type)), \
            ((unsigned long) (nr)), \
            ((unsigned long) _IO((type), (nr))))

#define IOFN_CHECK(rustfn, cfn, type, nr, passed_type) \
    fprintf(fp, "    assert_eq!(%s::<%s>(%lu, %lu), 0x%lx, \"Expected %s::<%s>(%lu, %lu) to equal 0x%lx\");\n", \
            #rustfn, \
            #passed_type, \
            ((unsigned long) (type)), \
            ((unsigned long) (nr)), \
            ((unsigned long) cfn((type), (nr), passed_type)), \
            #rustfn, \
            #passed_type, \
            ((unsigned long) (type)), \
            ((unsigned long) (nr)), \
            ((unsigned long) cfn((type), (nr), passed_type)))

#define IOFN_CHECKS(rustfn, cfn) \
    do { \
        IOFN_CHECK(ior, _IOR, 0, 0, Size1); \
        IOFN_CHECK(ior, _IOR, 1, 1, Size20); \
        IOFN_CHECK(ior, _IOR, 0, 0, SizeMax); \
        IOFN_CHECK(ior, _IOR, 0, _IOC_NRMASK, Size1); \
        IOFN_CHECK(ior, _IOR, 0, _IOC_NRMASK, SizeMax); \
        IOFN_CHECK(ior, _IOR, _IOC_TYPEMASK, 0, Size1); \
        IOFN_CHECK(ior, _IOR, _IOC_TYPEMASK, 0, SizeMax); \
        IOFN_CHECK(ior, _IOR, _IOC_TYPEMASK, _IOC_NRMASK, Size1); \
        IOFN_CHECK(ior, _IOR, _IOC_TYPEMASK, _IOC_NRMASK, SizeMax); \
    } while (0)

static int ioctl_ccompat_test(char const *arch) {
    char filename[256];
    FILE *fp;

    sprintf(filename, "src/ccompat_tests_linux_%s.rs", arch);
    fp = fopen(filename, "w");
    if (fp == NULL) {
        perror(filename);
        return 1;
    }

    fprintf(fp, "//! This is an automatically generated file; do not edit.\n");
    fprintf(fp, "//! Generated by gen_ccompat_tests.c on %s %s\n", __DATE__, __TIME__);
    fprintf(fp, "use super::*;\n");
    fprintf(fp, "\n");
    fprintf(fp, "#[repr(C)]\n");
    fprintf(fp, "struct Size1([u8; 1]);\n");
    fprintf(fp, "\n");
    fprintf(fp, "#[repr(C)]\n");
    fprintf(fp, "struct Size20([u8; 20]);\n");
    fprintf(fp, "\n");
    fprintf(fp, "#[repr(C)]\n");
    fprintf(fp, "struct SizeMax([u8; %u]);\n", _IOC_SIZEMASK);
    fprintf(fp, "\n");
    fprintf(fp, "#[test]\n");
    fprintf(fp, "fn test_ioctl_ccompat() {\n");
    fprintf(fp, "    assert_eq!(core::mem::size_of::<Size1>(), 1);\n");
    fprintf(fp, "    assert_eq!(core::mem::size_of::<Size20>(), 20);\n");
    fprintf(fp, "    assert_eq!(core::mem::size_of::<SizeMax>(), %u);\n", _IOC_SIZEMASK);
    fprintf(fp, "\n");
    EQ_CHECK(IOC_NRBITS, _IOC_NRBITS);
    EQ_CHECK(IOC_TYPEBITS, _IOC_TYPEBITS);
    EQ_CHECK(IOC_SIZEBITS, _IOC_SIZEBITS);
    EQ_CHECK(IOC_DIRBITS, _IOC_DIRBITS);
    EQ_CHECK(IOC_NONE, _IOC_NONE);
    EQ_CHECK(IOC_READ, _IOC_READ);
    EQ_CHECK(IOC_WRITE, _IOC_WRITE);
    EQ_CHECK(IOC_NRMASK, _IOC_NRMASK);
    EQ_CHECK(IOC_TYPEMASK, _IOC_TYPEMASK);
    EQ_CHECK(IOC_SIZEMASK, _IOC_SIZEMASK);
    EQ_CHECK(IOC_DIRMASK, _IOC_DIRMASK);
    EQ_CHECK(IOC_NRSHIFT, _IOC_NRSHIFT);
    EQ_CHECK(IOC_TYPESHIFT, _IOC_TYPESHIFT);
    EQ_CHECK(IOC_SIZESHIFT, _IOC_SIZESHIFT);
    EQ_CHECK(IOC_DIRSHIFT, _IOC_DIRSHIFT);

    IOC_CHECK(_IOC_NONE, 0, 0, 0);
    IOC_CHECK(_IOC_READ, 0, 0, 0);
    IOC_CHECK(_IOC_WRITE, 0, 0, 0);
    IOC_CHECK(_IOC_WRITE|_IOC_READ, 0, 0, 0);
    IOC_CHECK(_IOC_READ, 1, 1, 20);
    IOC_CHECK(_IOC_READ, 0, 0, _IOC_SIZEMASK);
    IOC_CHECK(_IOC_READ, 0, _IOC_NRMASK, 0);
    IOC_CHECK(_IOC_READ, 0, _IOC_NRMASK, _IOC_SIZEMASK);
    IOC_CHECK(_IOC_READ, _IOC_TYPEMASK, 0, 0);
    IOC_CHECK(_IOC_READ, _IOC_TYPEMASK, 0, _IOC_SIZEMASK);
    IOC_CHECK(_IOC_READ, _IOC_TYPEMASK, _IOC_NRMASK, 0);
    IOC_CHECK(_IOC_READ, _IOC_TYPEMASK, _IOC_NRMASK, _IOC_SIZEMASK);

    IO_CHECK(0, 0);
    IO_CHECK(1, 1);
    IO_CHECK(0, _IOC_NRMASK);
    IO_CHECK(_IOC_TYPEMASK, 0);
    IO_CHECK(_IOC_TYPEMASK, _IOC_NRMASK);

    IOFN_CHECKS(ior, _IOR);
    IOFN_CHECKS(iow, _IOW);
    IOFN_CHECKS(iowr, _IOWR);

    fprintf(fp, "}\n");
    fclose(fp);
    return 0;
}