Create / dev / fakeDevice supporting read, write and ioctl

I have a piece of software running on an embedded device (x86, latest linux). To facilitate development, use automated tests, etc., I want to run it on my host system. The code compiles just fine with some settings in the assembly. The next step is to create "virtual devices."

The application does not use any library, but directly interacts with several devices via read, write and ioctl calls. Devices are specialized equipment with a user protocol. To create a virtual environment, I need to answer these challenges. One possible way:

  • create device drivers for each device required ( /dev/deviceA, /dev/deviceB, /dev/deviceC...)
  • create another device driver to communicate back to user space (for example, /dev/deviceSimulation)
  • all virtual devices will redirect every call /dev/deviceSimulation
  • another user space application interacts with /dev/deviceSimulationand tracks the simulation status.

Is there an easier way to do this without going back through the Linux kernel?

+4
source share
1 answer

Returning to this project and answering my question: yes, you need to make a circular trip through the core. But there the library does a grumbling job: CUDA (thanks, CL).

( ), cuda - . , ( , ...):

"(cusetest.c):

#define FUSE_USE_VERSION 30
#define _FILE_OFFSET_BITS 64
#include <fuse/cuse_lowlevel.h>
#include <fuse/fuse_opt.h>

#include <stdio.h>

#define LOG(...) do { fprintf(stderr, __VA_ARGS__); puts(""); } while (0)

static void cusetest_open(fuse_req_t req, struct fuse_file_info *fi) {
    LOG("open");
    fuse_reply_open(req, fi);
}

static void cusetest_read(fuse_req_t req, size_t size, off_t off,
                         struct fuse_file_info *fi) {
    LOG("read");
    fuse_reply_buf(req, "Hello", size > 5 ? 5 : size);
}

static void cusetest_write(fuse_req_t req, const char *buf, size_t size,
                          off_t off, struct fuse_file_info *fi) {
    LOG("write (%u bytes)", size);
    fuse_reply_write(req, size);
}

static void cusetest_ioctl(fuse_req_t req, int cmd, void *arg,
                          struct fuse_file_info *fi, unsigned flags,
                          const void *in_buf, size_t in_bufsz, size_t out_bufsz) {
    LOG("ioctl %d: insize: %u outsize: %u", cmd, in_bufsz, out_bufsz);
    switch (cmd) {
    case 23:
        if (in_bufsz == 0) {
            struct iovec iov = { arg, sizeof(int) };
            fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
        } else {
            LOG("  got value: %d", *((int*)in_buf));
            fuse_reply_ioctl(req, 0, NULL, 0);
        }
        break;
    case 42:
        if (out_bufsz == 0) {
            struct iovec iov = { arg, sizeof(int) };
            fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
        } else {
            LOG("  write back value");
            int v = 42;
            fuse_reply_ioctl(req, 0, &v, sizeof(int));
        }
        break;
    }
}

static const struct cuse_lowlevel_ops cusetest_clop = {
        .open           = cusetest_open,
        .read           = cusetest_read,
        .write          = cusetest_write,
        .ioctl          = cusetest_ioctl,
};

int main(int argc, char** argv) {
    // -f: run in foreground, -d: debug ouput
    // Compile official example and use -h
    const char* cusearg[] = {"test", "-f", "-d"};
    const char* devarg[]  = {"DEVNAME=cusetest" };
    struct cuse_info ci;
    memset(&ci, 0x00, sizeof(ci));
    ci.flags = CUSE_UNRESTRICTED_IOCTL;
    ci.dev_info_argc=1;
    ci.dev_info_argv = devarg;

    return cuse_lowlevel_main(3, (char**) &cusearg, &ci, &cusetest_clop, NULL);
}

: gcc -Wall -g -lfuse cusetest.c -o cusetest && sudo ./cusetest

(testcusetest.c):

#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>

int main() {
    int fd = open("/dev/cusetest", O_RDWR);

    const char* msg = "Fooooo";
    write(fd, msg, strlen(msg));

    int v = 63;
    ioctl(fd, 23, &v);
    fprintf(stderr, "value is now: %d\n", v);
    ioctl(fd, 42, &v);
    fprintf(stderr, "value is now: %d\n", v);
    close(fd);
    return 0;
}

: gcc -Wall testcusetest.c -o testcusetest && ./testcusetest

, , startet. CUSE_UNRESTRICTED_IOCTL. fuse_reply_ioctl_retry(), . .

+3

Source: https://habr.com/ru/post/1536961/


All Articles