16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE fioclient: FUSE ioctl example client
36881f68fSopenharmony_ci  Copyright (C) 2008       SUSE Linux Products GmbH
46881f68fSopenharmony_ci  Copyright (C) 2008       Tejun Heo <teheo@suse.de>
56881f68fSopenharmony_ci
66881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU GPLv2.
76881f68fSopenharmony_ci  See the file COPYING.
86881f68fSopenharmony_ci*/
96881f68fSopenharmony_ci
106881f68fSopenharmony_ci/** @file
116881f68fSopenharmony_ci *
126881f68fSopenharmony_ci * This program tests the cuse.c example file system.
136881f68fSopenharmony_ci *
146881f68fSopenharmony_ci * Example usage (assuming that /dev/foobar is a CUSE device provided
156881f68fSopenharmony_ci * by the cuse.c example file system):
166881f68fSopenharmony_ci *
176881f68fSopenharmony_ci *     $ cuse_client /dev/foobar s
186881f68fSopenharmony_ci *     0
196881f68fSopenharmony_ci *
206881f68fSopenharmony_ci *     $ echo "hello" | cuse_client /dev/foobar w 6
216881f68fSopenharmony_ci *     Writing 6 bytes
226881f68fSopenharmony_ci *     transferred 6 bytes (0 -> 6)
236881f68fSopenharmony_ci *
246881f68fSopenharmony_ci *     $ cuse_client /dev/foobar s
256881f68fSopenharmony_ci *     6
266881f68fSopenharmony_ci *
276881f68fSopenharmony_ci *     $ cuse_client /dev/foobar r 10
286881f68fSopenharmony_ci *     hello
296881f68fSopenharmony_ci *     transferred 6 bytes (6 -> 6)
306881f68fSopenharmony_ci *
316881f68fSopenharmony_ci * Compiling this example
326881f68fSopenharmony_ci *
336881f68fSopenharmony_ci *     gcc -Wall cuse_client.c -o cuse_client
346881f68fSopenharmony_ci *
356881f68fSopenharmony_ci * ## Source Code ##
366881f68fSopenharmony_ci * \include cuse_client.c
376881f68fSopenharmony_ci */
386881f68fSopenharmony_ci
396881f68fSopenharmony_ci
406881f68fSopenharmony_ci#include <sys/types.h>
416881f68fSopenharmony_ci#include <fcntl.h>
426881f68fSopenharmony_ci#include <sys/stat.h>
436881f68fSopenharmony_ci#include <sys/ioctl.h>
446881f68fSopenharmony_ci#include <stdio.h>
456881f68fSopenharmony_ci#include <stdlib.h>
466881f68fSopenharmony_ci#include <ctype.h>
476881f68fSopenharmony_ci#include <errno.h>
486881f68fSopenharmony_ci#include <unistd.h>
496881f68fSopenharmony_ci#include "ioctl.h"
506881f68fSopenharmony_ci
516881f68fSopenharmony_ciconst char *usage =
526881f68fSopenharmony_ci"Usage: cuse_client FIOC_FILE COMMAND\n"
536881f68fSopenharmony_ci"\n"
546881f68fSopenharmony_ci"COMMANDS\n"
556881f68fSopenharmony_ci"  s [SIZE]     : get size if SIZE is omitted, set size otherwise\n"
566881f68fSopenharmony_ci"  r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
576881f68fSopenharmony_ci"  w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
586881f68fSopenharmony_ci"\n";
596881f68fSopenharmony_ci
606881f68fSopenharmony_cistatic int do_rw(int fd, int is_read, size_t size, off_t offset,
616881f68fSopenharmony_ci		 size_t *prev_size, size_t *new_size)
626881f68fSopenharmony_ci{
636881f68fSopenharmony_ci	struct fioc_rw_arg arg = { .offset = offset };
646881f68fSopenharmony_ci	ssize_t ret;
656881f68fSopenharmony_ci
666881f68fSopenharmony_ci	arg.buf = calloc(1, size);
676881f68fSopenharmony_ci	if (!arg.buf) {
686881f68fSopenharmony_ci		fprintf(stderr, "failed to allocated %zu bytes\n", size);
696881f68fSopenharmony_ci		return -1;
706881f68fSopenharmony_ci	}
716881f68fSopenharmony_ci
726881f68fSopenharmony_ci	if (is_read) {
736881f68fSopenharmony_ci		arg.size = size;
746881f68fSopenharmony_ci		ret = ioctl(fd, FIOC_READ, &arg);
756881f68fSopenharmony_ci		if (ret >= 0)
766881f68fSopenharmony_ci			fwrite(arg.buf, 1, ret, stdout);
776881f68fSopenharmony_ci	} else {
786881f68fSopenharmony_ci		arg.size = fread(arg.buf, 1, size, stdin);
796881f68fSopenharmony_ci		fprintf(stderr, "Writing %zu bytes\n", arg.size);
806881f68fSopenharmony_ci		ret = ioctl(fd, FIOC_WRITE, &arg);
816881f68fSopenharmony_ci	}
826881f68fSopenharmony_ci
836881f68fSopenharmony_ci	if (ret >= 0) {
846881f68fSopenharmony_ci		*prev_size = arg.prev_size;
856881f68fSopenharmony_ci		*new_size = arg.new_size;
866881f68fSopenharmony_ci	} else
876881f68fSopenharmony_ci		perror("ioctl");
886881f68fSopenharmony_ci
896881f68fSopenharmony_ci	free(arg.buf);
906881f68fSopenharmony_ci	return ret;
916881f68fSopenharmony_ci}
926881f68fSopenharmony_ci
936881f68fSopenharmony_ciint main(int argc, char **argv)
946881f68fSopenharmony_ci{
956881f68fSopenharmony_ci	size_t param[2] = { };
966881f68fSopenharmony_ci	size_t size, prev_size = 0, new_size = 0;
976881f68fSopenharmony_ci	char cmd;
986881f68fSopenharmony_ci	int fd, i, rc;
996881f68fSopenharmony_ci
1006881f68fSopenharmony_ci	if (argc < 3)
1016881f68fSopenharmony_ci		goto usage;
1026881f68fSopenharmony_ci
1036881f68fSopenharmony_ci	fd = open(argv[1], O_RDWR);
1046881f68fSopenharmony_ci	if (fd < 0) {
1056881f68fSopenharmony_ci		perror("open");
1066881f68fSopenharmony_ci		return 1;
1076881f68fSopenharmony_ci	}
1086881f68fSopenharmony_ci
1096881f68fSopenharmony_ci	cmd = tolower(argv[2][0]);
1106881f68fSopenharmony_ci	argc -= 3;
1116881f68fSopenharmony_ci	argv += 3;
1126881f68fSopenharmony_ci
1136881f68fSopenharmony_ci	for (i = 0; i < argc; i++) {
1146881f68fSopenharmony_ci		char *endp;
1156881f68fSopenharmony_ci		param[i] = strtoul(argv[i], &endp, 0);
1166881f68fSopenharmony_ci		if (endp == argv[i] || *endp != '\0')
1176881f68fSopenharmony_ci			goto usage;
1186881f68fSopenharmony_ci	}
1196881f68fSopenharmony_ci
1206881f68fSopenharmony_ci	switch (cmd) {
1216881f68fSopenharmony_ci	case 's':
1226881f68fSopenharmony_ci		if (!argc) {
1236881f68fSopenharmony_ci			if (ioctl(fd, FIOC_GET_SIZE, &size)) {
1246881f68fSopenharmony_ci				perror("ioctl");
1256881f68fSopenharmony_ci				goto error;
1266881f68fSopenharmony_ci			}
1276881f68fSopenharmony_ci			printf("%zu\n", size);
1286881f68fSopenharmony_ci		} else {
1296881f68fSopenharmony_ci			size = param[0];
1306881f68fSopenharmony_ci			if (ioctl(fd, FIOC_SET_SIZE, &size)) {
1316881f68fSopenharmony_ci				perror("ioctl");
1326881f68fSopenharmony_ci				goto error;
1336881f68fSopenharmony_ci			}
1346881f68fSopenharmony_ci		}
1356881f68fSopenharmony_ci		close(fd);
1366881f68fSopenharmony_ci		return 0;
1376881f68fSopenharmony_ci
1386881f68fSopenharmony_ci	case 'r':
1396881f68fSopenharmony_ci	case 'w':
1406881f68fSopenharmony_ci		rc = do_rw(fd, cmd == 'r', param[0], param[1],
1416881f68fSopenharmony_ci			   &prev_size, &new_size);
1426881f68fSopenharmony_ci		if (rc < 0)
1436881f68fSopenharmony_ci			goto error;
1446881f68fSopenharmony_ci		fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
1456881f68fSopenharmony_ci			rc, prev_size, new_size);
1466881f68fSopenharmony_ci		close(fd);
1476881f68fSopenharmony_ci		return 0;
1486881f68fSopenharmony_ci	}
1496881f68fSopenharmony_ci
1506881f68fSopenharmony_ciusage:
1516881f68fSopenharmony_ci	fprintf(stderr, "%s", usage);
1526881f68fSopenharmony_ci	return 1;
1536881f68fSopenharmony_ci
1546881f68fSopenharmony_cierror:
1556881f68fSopenharmony_ci	close(fd);
1566881f68fSopenharmony_ci	return 1;
1576881f68fSopenharmony_ci}
158