| /* | |
| 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 GPLv2. | |
| See the file COPYING. | |
| */ | |
| /** @file | |
| * | |
| * 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) | |
| * | |
| * Compiling this example | |
| * | |
| * gcc -Wall cuse_client.c -o cuse_client | |
| * | |
| * ## Source Code ## | |
| * \include cuse_client.c | |
| */ | |
| #include <sys/types.h> | |
| #include <fcntl.h> | |
| #include <sys/stat.h> | |
| #include <sys/ioctl.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <ctype.h> | |
| #include <errno.h> | |
| #include <unistd.h> | |
| #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"); | |
| goto error; | |
| } | |
| printf("%zu\n", size); | |
| } else { | |
| size = param[0]; | |
| if (ioctl(fd, FIOC_SET_SIZE, &size)) { | |
| perror("ioctl"); | |
| goto error; | |
| } | |
| } | |
| close(fd); | |
| return 0; | |
| case 'r': | |
| case 'w': | |
| rc = do_rw(fd, cmd == 'r', param[0], param[1], | |
| &prev_size, &new_size); | |
| if (rc < 0) | |
| goto error; | |
| fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n", | |
| rc, prev_size, new_size); | |
| close(fd); | |
| return 0; | |
| } | |
| usage: | |
| fprintf(stderr, "%s", usage); | |
| return 1; | |
| error: | |
| close(fd); | |
| return 1; | |
| } |