16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE fioc: FUSE ioctl example 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 * @tableofcontents 126881f68fSopenharmony_ci * 136881f68fSopenharmony_ci * This example illustrates how to write a FUSE file system that can 146881f68fSopenharmony_ci * process (a restricted set of) ioctls. It can be tested with the 156881f68fSopenharmony_ci * ioctl_client.c program. 166881f68fSopenharmony_ci * 176881f68fSopenharmony_ci * Compile with: 186881f68fSopenharmony_ci * 196881f68fSopenharmony_ci * gcc -Wall ioctl.c `pkg-config fuse3 --cflags --libs` -o ioctl 206881f68fSopenharmony_ci * 216881f68fSopenharmony_ci * ## Source code ## 226881f68fSopenharmony_ci * \include ioctl.c 236881f68fSopenharmony_ci */ 246881f68fSopenharmony_ci 256881f68fSopenharmony_ci#define FUSE_USE_VERSION 35 266881f68fSopenharmony_ci 276881f68fSopenharmony_ci#include <fuse.h> 286881f68fSopenharmony_ci#include <stdlib.h> 296881f68fSopenharmony_ci#include <stdio.h> 306881f68fSopenharmony_ci#include <string.h> 316881f68fSopenharmony_ci#include <unistd.h> 326881f68fSopenharmony_ci#include <time.h> 336881f68fSopenharmony_ci#include <errno.h> 346881f68fSopenharmony_ci 356881f68fSopenharmony_ci#include "ioctl.h" 366881f68fSopenharmony_ci 376881f68fSopenharmony_ci#define FIOC_NAME "fioc" 386881f68fSopenharmony_ci 396881f68fSopenharmony_cienum { 406881f68fSopenharmony_ci FIOC_NONE, 416881f68fSopenharmony_ci FIOC_ROOT, 426881f68fSopenharmony_ci FIOC_FILE, 436881f68fSopenharmony_ci}; 446881f68fSopenharmony_ci 456881f68fSopenharmony_cistatic void *fioc_buf; 466881f68fSopenharmony_cistatic size_t fioc_size; 476881f68fSopenharmony_ci 486881f68fSopenharmony_cistatic int fioc_resize(size_t new_size) 496881f68fSopenharmony_ci{ 506881f68fSopenharmony_ci void *new_buf; 516881f68fSopenharmony_ci 526881f68fSopenharmony_ci if (new_size == fioc_size) 536881f68fSopenharmony_ci return 0; 546881f68fSopenharmony_ci 556881f68fSopenharmony_ci new_buf = realloc(fioc_buf, new_size); 566881f68fSopenharmony_ci if (!new_buf && new_size) 576881f68fSopenharmony_ci return -ENOMEM; 586881f68fSopenharmony_ci 596881f68fSopenharmony_ci if (new_size > fioc_size) 606881f68fSopenharmony_ci memset(new_buf + fioc_size, 0, new_size - fioc_size); 616881f68fSopenharmony_ci 626881f68fSopenharmony_ci fioc_buf = new_buf; 636881f68fSopenharmony_ci fioc_size = new_size; 646881f68fSopenharmony_ci 656881f68fSopenharmony_ci return 0; 666881f68fSopenharmony_ci} 676881f68fSopenharmony_ci 686881f68fSopenharmony_cistatic int fioc_expand(size_t new_size) 696881f68fSopenharmony_ci{ 706881f68fSopenharmony_ci if (new_size > fioc_size) 716881f68fSopenharmony_ci return fioc_resize(new_size); 726881f68fSopenharmony_ci return 0; 736881f68fSopenharmony_ci} 746881f68fSopenharmony_ci 756881f68fSopenharmony_cistatic int fioc_file_type(const char *path) 766881f68fSopenharmony_ci{ 776881f68fSopenharmony_ci if (strcmp(path, "/") == 0) 786881f68fSopenharmony_ci return FIOC_ROOT; 796881f68fSopenharmony_ci if (strcmp(path, "/" FIOC_NAME) == 0) 806881f68fSopenharmony_ci return FIOC_FILE; 816881f68fSopenharmony_ci return FIOC_NONE; 826881f68fSopenharmony_ci} 836881f68fSopenharmony_ci 846881f68fSopenharmony_cistatic int fioc_getattr(const char *path, struct stat *stbuf, 856881f68fSopenharmony_ci struct fuse_file_info *fi) 866881f68fSopenharmony_ci{ 876881f68fSopenharmony_ci (void) fi; 886881f68fSopenharmony_ci stbuf->st_uid = getuid(); 896881f68fSopenharmony_ci stbuf->st_gid = getgid(); 906881f68fSopenharmony_ci stbuf->st_atime = stbuf->st_mtime = time(NULL); 916881f68fSopenharmony_ci 926881f68fSopenharmony_ci switch (fioc_file_type(path)) { 936881f68fSopenharmony_ci case FIOC_ROOT: 946881f68fSopenharmony_ci stbuf->st_mode = S_IFDIR | 0755; 956881f68fSopenharmony_ci stbuf->st_nlink = 2; 966881f68fSopenharmony_ci break; 976881f68fSopenharmony_ci case FIOC_FILE: 986881f68fSopenharmony_ci stbuf->st_mode = S_IFREG | 0644; 996881f68fSopenharmony_ci stbuf->st_nlink = 1; 1006881f68fSopenharmony_ci stbuf->st_size = fioc_size; 1016881f68fSopenharmony_ci break; 1026881f68fSopenharmony_ci case FIOC_NONE: 1036881f68fSopenharmony_ci return -ENOENT; 1046881f68fSopenharmony_ci } 1056881f68fSopenharmony_ci 1066881f68fSopenharmony_ci return 0; 1076881f68fSopenharmony_ci} 1086881f68fSopenharmony_ci 1096881f68fSopenharmony_cistatic int fioc_open(const char *path, struct fuse_file_info *fi) 1106881f68fSopenharmony_ci{ 1116881f68fSopenharmony_ci (void) fi; 1126881f68fSopenharmony_ci 1136881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_NONE) 1146881f68fSopenharmony_ci return 0; 1156881f68fSopenharmony_ci return -ENOENT; 1166881f68fSopenharmony_ci} 1176881f68fSopenharmony_ci 1186881f68fSopenharmony_cistatic int fioc_do_read(char *buf, size_t size, off_t offset) 1196881f68fSopenharmony_ci{ 1206881f68fSopenharmony_ci if (offset >= fioc_size) 1216881f68fSopenharmony_ci return 0; 1226881f68fSopenharmony_ci 1236881f68fSopenharmony_ci if (size > fioc_size - offset) 1246881f68fSopenharmony_ci size = fioc_size - offset; 1256881f68fSopenharmony_ci 1266881f68fSopenharmony_ci memcpy(buf, fioc_buf + offset, size); 1276881f68fSopenharmony_ci 1286881f68fSopenharmony_ci return size; 1296881f68fSopenharmony_ci} 1306881f68fSopenharmony_ci 1316881f68fSopenharmony_cistatic int fioc_read(const char *path, char *buf, size_t size, 1326881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 1336881f68fSopenharmony_ci{ 1346881f68fSopenharmony_ci (void) fi; 1356881f68fSopenharmony_ci 1366881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_FILE) 1376881f68fSopenharmony_ci return -EINVAL; 1386881f68fSopenharmony_ci 1396881f68fSopenharmony_ci return fioc_do_read(buf, size, offset); 1406881f68fSopenharmony_ci} 1416881f68fSopenharmony_ci 1426881f68fSopenharmony_cistatic int fioc_do_write(const char *buf, size_t size, off_t offset) 1436881f68fSopenharmony_ci{ 1446881f68fSopenharmony_ci if (fioc_expand(offset + size)) 1456881f68fSopenharmony_ci return -ENOMEM; 1466881f68fSopenharmony_ci 1476881f68fSopenharmony_ci memcpy(fioc_buf + offset, buf, size); 1486881f68fSopenharmony_ci 1496881f68fSopenharmony_ci return size; 1506881f68fSopenharmony_ci} 1516881f68fSopenharmony_ci 1526881f68fSopenharmony_cistatic int fioc_write(const char *path, const char *buf, size_t size, 1536881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 1546881f68fSopenharmony_ci{ 1556881f68fSopenharmony_ci (void) fi; 1566881f68fSopenharmony_ci 1576881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_FILE) 1586881f68fSopenharmony_ci return -EINVAL; 1596881f68fSopenharmony_ci 1606881f68fSopenharmony_ci return fioc_do_write(buf, size, offset); 1616881f68fSopenharmony_ci} 1626881f68fSopenharmony_ci 1636881f68fSopenharmony_cistatic int fioc_truncate(const char *path, off_t size, 1646881f68fSopenharmony_ci struct fuse_file_info *fi) 1656881f68fSopenharmony_ci{ 1666881f68fSopenharmony_ci (void) fi; 1676881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_FILE) 1686881f68fSopenharmony_ci return -EINVAL; 1696881f68fSopenharmony_ci 1706881f68fSopenharmony_ci return fioc_resize(size); 1716881f68fSopenharmony_ci} 1726881f68fSopenharmony_ci 1736881f68fSopenharmony_cistatic int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 1746881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi, 1756881f68fSopenharmony_ci enum fuse_readdir_flags flags) 1766881f68fSopenharmony_ci{ 1776881f68fSopenharmony_ci (void) fi; 1786881f68fSopenharmony_ci (void) offset; 1796881f68fSopenharmony_ci (void) flags; 1806881f68fSopenharmony_ci 1816881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_ROOT) 1826881f68fSopenharmony_ci return -ENOENT; 1836881f68fSopenharmony_ci 1846881f68fSopenharmony_ci filler(buf, ".", NULL, 0, 0); 1856881f68fSopenharmony_ci filler(buf, "..", NULL, 0, 0); 1866881f68fSopenharmony_ci filler(buf, FIOC_NAME, NULL, 0, 0); 1876881f68fSopenharmony_ci 1886881f68fSopenharmony_ci return 0; 1896881f68fSopenharmony_ci} 1906881f68fSopenharmony_ci 1916881f68fSopenharmony_cistatic int fioc_ioctl(const char *path, unsigned int cmd, void *arg, 1926881f68fSopenharmony_ci struct fuse_file_info *fi, unsigned int flags, void *data) 1936881f68fSopenharmony_ci{ 1946881f68fSopenharmony_ci (void) arg; 1956881f68fSopenharmony_ci (void) fi; 1966881f68fSopenharmony_ci (void) flags; 1976881f68fSopenharmony_ci 1986881f68fSopenharmony_ci if (fioc_file_type(path) != FIOC_FILE) 1996881f68fSopenharmony_ci return -EINVAL; 2006881f68fSopenharmony_ci 2016881f68fSopenharmony_ci if (flags & FUSE_IOCTL_COMPAT) 2026881f68fSopenharmony_ci return -ENOSYS; 2036881f68fSopenharmony_ci 2046881f68fSopenharmony_ci switch (cmd) { 2056881f68fSopenharmony_ci case FIOC_GET_SIZE: 2066881f68fSopenharmony_ci *(size_t *)data = fioc_size; 2076881f68fSopenharmony_ci return 0; 2086881f68fSopenharmony_ci 2096881f68fSopenharmony_ci case FIOC_SET_SIZE: 2106881f68fSopenharmony_ci fioc_resize(*(size_t *)data); 2116881f68fSopenharmony_ci return 0; 2126881f68fSopenharmony_ci } 2136881f68fSopenharmony_ci 2146881f68fSopenharmony_ci return -EINVAL; 2156881f68fSopenharmony_ci} 2166881f68fSopenharmony_ci 2176881f68fSopenharmony_cistatic const struct fuse_operations fioc_oper = { 2186881f68fSopenharmony_ci .getattr = fioc_getattr, 2196881f68fSopenharmony_ci .readdir = fioc_readdir, 2206881f68fSopenharmony_ci .truncate = fioc_truncate, 2216881f68fSopenharmony_ci .open = fioc_open, 2226881f68fSopenharmony_ci .read = fioc_read, 2236881f68fSopenharmony_ci .write = fioc_write, 2246881f68fSopenharmony_ci .ioctl = fioc_ioctl, 2256881f68fSopenharmony_ci}; 2266881f68fSopenharmony_ci 2276881f68fSopenharmony_ciint main(int argc, char *argv[]) 2286881f68fSopenharmony_ci{ 2296881f68fSopenharmony_ci return fuse_main(argc, argv, &fioc_oper, NULL); 2306881f68fSopenharmony_ci} 231