From 35ce627e35d1e293b25cfa8bdec2fb82c7da4630 Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Sun, 9 Oct 2016 21:05:54 -0700 Subject: [PATCH] Renamed cuses example and added test program An earlier version of the fioclient.c example was intended to be used together with cusexmp.c. The former has since evolved into ioctl_client.c and no longer has the function necessary to test CUSE. Therefore, we've added a new cuse_client.c that is clearly associated with the cuse.c example file system. --- ChangeLog.rst | 2 + example/.gitignore | 3 +- example/Makefile.am | 5 +- example/{cusexmp.c => cuse.c} | 19 ++++- example/cuse_client.c | 153 ++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 6 deletions(-) rename example/{cusexmp.c => cuse.c} (90%) create mode 100755 example/cuse_client.c diff --git a/ChangeLog.rst b/ChangeLog.rst index da1b1a8..c92710c 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,6 +1,8 @@ Unreleased Changes ================== +* Added ``example/cuse_client.c`` to test ``example/cuse.c``. + * Removed ``example/null.c``. This has not been working for a while for unknown reasons -- maybe because it tries to treat the mountpoint as a file rather than a directory? diff --git a/example/.gitignore b/example/.gitignore index f7cd045..6dd5004 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -6,7 +6,8 @@ /ioctl_client /poll /poll_client -/cusexmp +/cuse +/cuse_client /passthrough_ll /notify_inval_inode /notify_store_retrieve diff --git a/example/Makefile.am b/example/Makefile.am index 6d93edc..6e267a0 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -4,8 +4,9 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -D_REENTRANT noinst_HEADERS = ioctl.h noinst_PROGRAMS = passthrough passthrough_fh hello hello_ll \ ioctl ioctl_client poll poll_client \ - cusexmp passthrough_ll notify_inval_inode \ - notify_store_retrieve notify_inval_entry + passthrough_ll notify_inval_inode \ + notify_store_retrieve notify_inval_entry \ + cuse cuse_client LDADD = ../lib/libfuse3.la passthrough_fh_LDADD = ../lib/libfuse3.la @passthrough_fh_libs@ diff --git a/example/cusexmp.c b/example/cuse.c similarity index 90% rename from example/cusexmp.c rename to example/cuse.c index a9f3365..443d308 100644 --- a/example/cusexmp.c +++ b/example/cuse.c @@ -11,14 +11,24 @@ /** @file * @tableofcontents * - * cusexmp.c - CUSE example: Character device in Userspace + * This example demonstrates how to implement a character device in + * userspace ("CUSE"). This is only allowed for root. The character + * device should appear in /dev under the specified name. It can be + * tested with the cuse_client.c program. + * + * Mount the file system with: + * + * cuse -f --name=mydevice + * + * You should now have a new /dev/mydevice character device. To "unmount" it, + * kill the "cuse" process. * * \section section_compile compiling this example * - * gcc -Wall cusexmp.c `pkg-config fuse3 --cflags --libs` -o cusexmp + * gcc -Wall cuse.c `pkg-config fuse3 --cflags --libs` -o cuse * * \section section_source the complete source - * \include cusexmp.c + * \include cuse.c */ @@ -48,6 +58,9 @@ static const char *usage = " --maj=MAJ|-M MAJ device major number\n" " --min=MIN|-m MIN device minor number\n" " --name=NAME|-n NAME device name (mandatory)\n" +" -d -o debug enable debug output (implies -f)\n" +" -f foreground operation\n" +" -s disable multi-threaded operation\n" "\n"; static int cusexmp_resize(size_t new_size) diff --git a/example/cuse_client.c b/example/cuse_client.c new file mode 100755 index 0000000..3e47635 --- /dev/null +++ b/example/cuse_client.c @@ -0,0 +1,153 @@ +/* + FUSE fioclient: FUSE ioctl example client + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +/** @file + * @tableofcontents + * + * This program tests the cuse.c example file system. + * + * Example usage (assuming that /dev/foobar is a CUSE device provided + * by the cuse.c example file system): + * + * $ cuse_client /dev/foobar s + * 0 + * + * $ echo "hello" | cuse_client /dev/foobar w 6 + * Writing 6 bytes + * transferred 6 bytes (0 -> 6) + * + * $ cuse_client /dev/foobar s + * 6 + * + * $ cuse_client /dev/foobar r 10 + * hello + * transferred 6 bytes (6 -> 6) + * + * \section section_compile compiling this example + * + * gcc -Wall cuse_client.c -o cuse_client + * + * \section section_source the complete source + * \include cuse_client.c + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ioctl.h" + +const char *usage = +"Usage: cuse_client FIOC_FILE COMMAND\n" +"\n" +"COMMANDS\n" +" s [SIZE] : get size if SIZE is omitted, set size otherwise\n" +" r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n" +" w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n" +"\n"; + +static int do_rw(int fd, int is_read, size_t size, off_t offset, + size_t *prev_size, size_t *new_size) +{ + struct fioc_rw_arg arg = { .offset = offset }; + ssize_t ret; + + arg.buf = calloc(1, size); + if (!arg.buf) { + fprintf(stderr, "failed to allocated %zu bytes\n", size); + return -1; + } + + if (is_read) { + arg.size = size; + ret = ioctl(fd, FIOC_READ, &arg); + if (ret >= 0) + fwrite(arg.buf, 1, ret, stdout); + } else { + arg.size = fread(arg.buf, 1, size, stdin); + fprintf(stderr, "Writing %zu bytes\n", arg.size); + ret = ioctl(fd, FIOC_WRITE, &arg); + } + + if (ret >= 0) { + *prev_size = arg.prev_size; + *new_size = arg.new_size; + } else + perror("ioctl"); + + free(arg.buf); + return ret; +} + +int main(int argc, char **argv) +{ + size_t param[2] = { }; + size_t size, prev_size = 0, new_size = 0; + char cmd; + int fd, i, rc; + + if (argc < 3) + goto usage; + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror("open"); + return 1; + } + + cmd = tolower(argv[2][0]); + argc -= 3; + argv += 3; + + for (i = 0; i < argc; i++) { + char *endp; + param[i] = strtoul(argv[i], &endp, 0); + if (endp == argv[i] || *endp != '\0') + goto usage; + } + + switch (cmd) { + case 's': + if (!argc) { + if (ioctl(fd, FIOC_GET_SIZE, &size)) { + perror("ioctl"); + return 1; + } + printf("%zu\n", size); + } else { + size = param[0]; + if (ioctl(fd, FIOC_SET_SIZE, &size)) { + perror("ioctl"); + return 1; + } + } + return 0; + + case 'r': + case 'w': + rc = do_rw(fd, cmd == 'r', param[0], param[1], + &prev_size, &new_size); + if (rc < 0) + return 1; + fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n", + rc, prev_size, new_size); + return 0; + } + + usage: + fprintf(stderr, "%s", usage); + return 1; +} -- 2.30.2