diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2008-12-05 10:55:36 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2008-12-05 10:55:36 +0000 |
commit | ecfa5263ab5b19a58d53a7116fb079f3b956b918 (patch) | |
tree | a9f9dd2ec17e9185e4d515328b78e3b5e84938f2 /example | |
parent | cafdcb253e4c7ad6238198982425c004b487d2e6 (diff) |
* Implement ioctl support. On high level interface only
"restricted" ioctls are supported (which are defined with the
_IO(), _IOR(), _IOW() or _IOWR() macros). Unrestricted ioctls
will only be allwed to CUSE (Character Device in Userspace)
servers. Patch by Tejun Heo
Diffstat (limited to 'example')
-rw-r--r-- | example/.cvsignore | 2 | ||||
-rw-r--r-- | example/Makefile.am | 8 | ||||
-rw-r--r-- | example/fioc.c | 211 | ||||
-rw-r--r-- | example/fioc.h | 17 | ||||
-rw-r--r-- | example/fioclient.c | 66 |
5 files changed, 303 insertions, 1 deletions
diff --git a/example/.cvsignore b/example/.cvsignore index 56dabc1..7332bc0 100644 --- a/example/.cvsignore +++ b/example/.cvsignore @@ -6,4 +6,6 @@ fusexmp_fh null hello hello_ll +fioc +fioclient .libs diff --git a/example/Makefile.am b/example/Makefile.am index 91f33cc..43b195d 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,7 +1,13 @@ ## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT -noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll +noinst_HEADERS = fioc.h +noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll fioc fioclient LDADD = ../lib/libfuse.la @libfuse_libs@ fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la @libfuse_libs@ + +fioclient_CPPFLAGS = +fioclient_LDFLAGS = +fioclient_LDADD = + diff --git a/example/fioc.c b/example/fioc.c new file mode 100644 index 0000000..d0dce15 --- /dev/null +++ b/example/fioc.c @@ -0,0 +1,211 @@ +/* + FUSE fioc: FUSE ioctl example + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo <teheo@suse.de> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. + + gcc -Wall `pkg-config fuse --cflags --libs` fioc.c -o fioc +*/ + +#define FUSE_USE_VERSION 26 + +#include <fuse.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> + +#include "fioc.h" + +#define FIOC_NAME "fioc" + +enum { + FIOC_NONE, + FIOC_ROOT, + FIOC_FILE, +}; + +static void *fioc_buf; +static size_t fioc_size; + +static int fioc_resize(size_t new_size) +{ + void *new_buf; + + if (new_size == fioc_size) + return 0; + + new_buf = realloc(fioc_buf, new_size); + if (!new_buf && new_size) + return -ENOMEM; + + if (new_size > fioc_size) + memset(new_buf + fioc_size, 0, new_size - fioc_size); + + fioc_buf = new_buf; + fioc_size = new_size; + + return 0; +} + +static int fioc_expand(size_t new_size) +{ + if (new_size > fioc_size) + return fioc_resize(new_size); + return 0; +} + +static int fioc_file_type(const char *path) +{ + if (strcmp(path, "/") == 0) + return FIOC_ROOT; + if (strcmp(path, "/" FIOC_NAME) == 0) + return FIOC_FILE; + return FIOC_NONE; +} + +static int fioc_getattr(const char *path, struct stat *stbuf) +{ + stbuf->st_uid = getuid(); + stbuf->st_gid = getgid(); + stbuf->st_atime = stbuf->st_mtime = time(NULL); + + switch (fioc_file_type(path)) { + case FIOC_ROOT: + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + break; + case FIOC_FILE: + stbuf->st_mode = S_IFREG | 0644; + stbuf->st_nlink = 1; + stbuf->st_size = fioc_size; + break; + case FIOC_NONE: + return -ENOENT; + } + + return 0; +} + +static int fioc_open(const char *path, struct fuse_file_info *fi) +{ + (void) fi; + + if (fioc_file_type(path) != FIOC_NONE) + return 0; + return -ENOENT; +} + +static int fioc_do_read(char *buf, size_t size, off_t offset) +{ + if (offset >= fioc_size) + return 0; + + if (size > fioc_size - offset) + size = fioc_size - offset; + + memcpy(buf, fioc_buf + offset, size); + + return size; +} + +static int fioc_read(const char *path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + (void) fi; + + if (fioc_file_type(path) != FIOC_FILE) + return -EINVAL; + + return fioc_do_read(buf, size, offset); +} + +static int fioc_do_write(const char *buf, size_t size, off_t offset) +{ + if (fioc_expand(offset + size)) + return -ENOMEM; + + memcpy(fioc_buf + offset, buf, size); + + return size; +} + +static int fioc_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + (void) fi; + + if (fioc_file_type(path) != FIOC_FILE) + return -EINVAL; + + return fioc_do_write(buf, size, offset); +} + +static int fioc_truncate(const char *path, off_t size) +{ + if (fioc_file_type(path) != FIOC_FILE) + return -EINVAL; + + return fioc_resize(size); +} + +static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + (void) fi; + (void) offset; + + if (fioc_file_type(path) != FIOC_ROOT) + return -ENOENT; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + filler(buf, FIOC_NAME, NULL, 0); + + return 0; +} + +static int fioc_ioctl(const char *path, int cmd, void *arg, + struct fuse_file_info *fi, unsigned int flags, void *data) +{ + (void) arg; + (void) fi; + (void) flags; + + if (fioc_file_type(path) != FIOC_FILE) + return -EINVAL; + + if (flags & FUSE_IOCTL_COMPAT) + return -ENOSYS; + + switch (cmd) { + case FIOC_GET_SIZE: + *(size_t *)data = fioc_size; + return 0; + + case FIOC_SET_SIZE: + fioc_resize(*(size_t *)data); + return 0; + } + + return -EINVAL; +} + +static struct fuse_operations fioc_oper = { + .getattr = fioc_getattr, + .readdir = fioc_readdir, + .truncate = fioc_truncate, + .open = fioc_open, + .read = fioc_read, + .write = fioc_write, + .ioctl = fioc_ioctl, +}; + +int main(int argc, char *argv[]) +{ + return fuse_main(argc, argv, &fioc_oper, NULL); +} diff --git a/example/fioc.h b/example/fioc.h new file mode 100644 index 0000000..c1d9cdf --- /dev/null +++ b/example/fioc.h @@ -0,0 +1,17 @@ +/* + FUSE-ioctl: ioctl support for FUSE + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo <teheo@suse.de> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/ioctl.h> + +enum { + FIOC_GET_SIZE = _IOR('E', 0, size_t), + FIOC_SET_SIZE = _IOW('E', 1, size_t), +}; diff --git a/example/fioclient.c b/example/fioclient.c new file mode 100644 index 0000000..3ab63b2 --- /dev/null +++ b/example/fioclient.c @@ -0,0 +1,66 @@ +/* + FUSE fioclient: FUSE ioctl example client + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo <teheo@suse.de> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. + + gcc -Wall fioclient.c -o fioclient +*/ + +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include "fioc.h" + +const char *usage = +"Usage: fioclient FIOC_FILE [SIZE]\n" +"\n" +" get size if SIZE is omitted, set size otherwise\n" +"\n"; + +int main(int argc, char **argv) +{ + size_t size; + int fd; + + if (argc < 2) { + goto usage; + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror("open"); + return 1; + } + + if (argc == 2) { + if (ioctl(fd, FIOC_GET_SIZE, &size)) { + perror("ioctl"); + return 1; + } + printf("%zu\n", size); + } else { + char *endp; + + size = strtoul(argv[2], &endp, 0); + if (endp == argv[2] || *endp != '\0') + goto usage; + + if (ioctl(fd, FIOC_SET_SIZE, &size)) { + perror("ioctl"); + return 1; + } + } + return 0; + +usage: + fprintf(stderr, usage); + return 1; +} |