xref: /third_party/libfuse/example/cuse_client.c (revision 6881f68f)
1/*
2  FUSE fioclient: FUSE ioctl example client
3  Copyright (C) 2008       SUSE Linux Products GmbH
4  Copyright (C) 2008       Tejun Heo <teheo@suse.de>
5
6  This program can be distributed under the terms of the GNU GPLv2.
7  See the file COPYING.
8*/
9
10/** @file
11 *
12 * This program tests the cuse.c example file system.
13 *
14 * Example usage (assuming that /dev/foobar is a CUSE device provided
15 * by the cuse.c example file system):
16 *
17 *     $ cuse_client /dev/foobar s
18 *     0
19 *
20 *     $ echo "hello" | cuse_client /dev/foobar w 6
21 *     Writing 6 bytes
22 *     transferred 6 bytes (0 -> 6)
23 *
24 *     $ cuse_client /dev/foobar s
25 *     6
26 *
27 *     $ cuse_client /dev/foobar r 10
28 *     hello
29 *     transferred 6 bytes (6 -> 6)
30 *
31 * Compiling this example
32 *
33 *     gcc -Wall cuse_client.c -o cuse_client
34 *
35 * ## Source Code ##
36 * \include cuse_client.c
37 */
38
39
40#include <sys/types.h>
41#include <fcntl.h>
42#include <sys/stat.h>
43#include <sys/ioctl.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <ctype.h>
47#include <errno.h>
48#include <unistd.h>
49#include "ioctl.h"
50
51const char *usage =
52"Usage: cuse_client FIOC_FILE COMMAND\n"
53"\n"
54"COMMANDS\n"
55"  s [SIZE]     : get size if SIZE is omitted, set size otherwise\n"
56"  r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
57"  w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
58"\n";
59
60static int do_rw(int fd, int is_read, size_t size, off_t offset,
61		 size_t *prev_size, size_t *new_size)
62{
63	struct fioc_rw_arg arg = { .offset = offset };
64	ssize_t ret;
65
66	arg.buf = calloc(1, size);
67	if (!arg.buf) {
68		fprintf(stderr, "failed to allocated %zu bytes\n", size);
69		return -1;
70	}
71
72	if (is_read) {
73		arg.size = size;
74		ret = ioctl(fd, FIOC_READ, &arg);
75		if (ret >= 0)
76			fwrite(arg.buf, 1, ret, stdout);
77	} else {
78		arg.size = fread(arg.buf, 1, size, stdin);
79		fprintf(stderr, "Writing %zu bytes\n", arg.size);
80		ret = ioctl(fd, FIOC_WRITE, &arg);
81	}
82
83	if (ret >= 0) {
84		*prev_size = arg.prev_size;
85		*new_size = arg.new_size;
86	} else
87		perror("ioctl");
88
89	free(arg.buf);
90	return ret;
91}
92
93int main(int argc, char **argv)
94{
95	size_t param[2] = { };
96	size_t size, prev_size = 0, new_size = 0;
97	char cmd;
98	int fd, i, rc;
99
100	if (argc < 3)
101		goto usage;
102
103	fd = open(argv[1], O_RDWR);
104	if (fd < 0) {
105		perror("open");
106		return 1;
107	}
108
109	cmd = tolower(argv[2][0]);
110	argc -= 3;
111	argv += 3;
112
113	for (i = 0; i < argc; i++) {
114		char *endp;
115		param[i] = strtoul(argv[i], &endp, 0);
116		if (endp == argv[i] || *endp != '\0')
117			goto usage;
118	}
119
120	switch (cmd) {
121	case 's':
122		if (!argc) {
123			if (ioctl(fd, FIOC_GET_SIZE, &size)) {
124				perror("ioctl");
125				goto error;
126			}
127			printf("%zu\n", size);
128		} else {
129			size = param[0];
130			if (ioctl(fd, FIOC_SET_SIZE, &size)) {
131				perror("ioctl");
132				goto error;
133			}
134		}
135		close(fd);
136		return 0;
137
138	case 'r':
139	case 'w':
140		rc = do_rw(fd, cmd == 'r', param[0], param[1],
141			   &prev_size, &new_size);
142		if (rc < 0)
143			goto error;
144		fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
145			rc, prev_size, new_size);
146		close(fd);
147		return 0;
148	}
149
150usage:
151	fprintf(stderr, "%s", usage);
152	return 1;
153
154error:
155	close(fd);
156	return 1;
157}
158