• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   FUSE fioc: FUSE ioctl example
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  * @tableofcontents
12  *
13  * This example illustrates how to write a FUSE file system that can
14  * process (a restricted set of) ioctls. It can be tested with the
15  * ioctl_client.c program.
16  *
17  * Compile with:
18  *
19  *     gcc -Wall ioctl.c `pkg-config fuse3 --cflags --libs` -o ioctl
20  *
21  * ## Source code ##
22  * \include ioctl.c
23  */
24 
25 #define FUSE_USE_VERSION 35
26 
27 #include <fuse.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <errno.h>
34 
35 #include "ioctl.h"
36 
37 #define FIOC_NAME	"fioc"
38 
39 enum {
40 	FIOC_NONE,
41 	FIOC_ROOT,
42 	FIOC_FILE,
43 };
44 
45 static void *fioc_buf;
46 static size_t fioc_size;
47 
fioc_resize(size_t new_size)48 static int fioc_resize(size_t new_size)
49 {
50 	void *new_buf;
51 
52 	if (new_size == fioc_size)
53 		return 0;
54 
55 	new_buf = realloc(fioc_buf, new_size);
56 	if (!new_buf && new_size)
57 		return -ENOMEM;
58 
59 	if (new_size > fioc_size)
60 		memset(new_buf + fioc_size, 0, new_size - fioc_size);
61 
62 	fioc_buf = new_buf;
63 	fioc_size = new_size;
64 
65 	return 0;
66 }
67 
fioc_expand(size_t new_size)68 static int fioc_expand(size_t new_size)
69 {
70 	if (new_size > fioc_size)
71 		return fioc_resize(new_size);
72 	return 0;
73 }
74 
fioc_file_type(const char * path)75 static int fioc_file_type(const char *path)
76 {
77 	if (strcmp(path, "/") == 0)
78 		return FIOC_ROOT;
79 	if (strcmp(path, "/" FIOC_NAME) == 0)
80 		return FIOC_FILE;
81 	return FIOC_NONE;
82 }
83 
fioc_getattr(const char * path,struct stat * stbuf,struct fuse_file_info * fi)84 static int fioc_getattr(const char *path, struct stat *stbuf,
85 			struct fuse_file_info *fi)
86 {
87 	(void) fi;
88 	stbuf->st_uid = getuid();
89 	stbuf->st_gid = getgid();
90 	stbuf->st_atime = stbuf->st_mtime = time(NULL);
91 
92 	switch (fioc_file_type(path)) {
93 	case FIOC_ROOT:
94 		stbuf->st_mode = S_IFDIR | 0755;
95 		stbuf->st_nlink = 2;
96 		break;
97 	case FIOC_FILE:
98 		stbuf->st_mode = S_IFREG | 0644;
99 		stbuf->st_nlink = 1;
100 		stbuf->st_size = fioc_size;
101 		break;
102 	case FIOC_NONE:
103 		return -ENOENT;
104 	}
105 
106 	return 0;
107 }
108 
fioc_open(const char * path,struct fuse_file_info * fi)109 static int fioc_open(const char *path, struct fuse_file_info *fi)
110 {
111 	(void) fi;
112 
113 	if (fioc_file_type(path) != FIOC_NONE)
114 		return 0;
115 	return -ENOENT;
116 }
117 
fioc_do_read(char * buf,size_t size,off_t offset)118 static int fioc_do_read(char *buf, size_t size, off_t offset)
119 {
120 	if (offset >= fioc_size)
121 		return 0;
122 
123 	if (size > fioc_size - offset)
124 		size = fioc_size - offset;
125 
126 	memcpy(buf, fioc_buf + offset, size);
127 
128 	return size;
129 }
130 
fioc_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)131 static int fioc_read(const char *path, char *buf, size_t size,
132 		     off_t offset, struct fuse_file_info *fi)
133 {
134 	(void) fi;
135 
136 	if (fioc_file_type(path) != FIOC_FILE)
137 		return -EINVAL;
138 
139 	return fioc_do_read(buf, size, offset);
140 }
141 
fioc_do_write(const char * buf,size_t size,off_t offset)142 static int fioc_do_write(const char *buf, size_t size, off_t offset)
143 {
144 	if (fioc_expand(offset + size))
145 		return -ENOMEM;
146 
147 	memcpy(fioc_buf + offset, buf, size);
148 
149 	return size;
150 }
151 
fioc_write(const char * path,const char * buf,size_t size,off_t offset,struct fuse_file_info * fi)152 static int fioc_write(const char *path, const char *buf, size_t size,
153 		      off_t offset, struct fuse_file_info *fi)
154 {
155 	(void) fi;
156 
157 	if (fioc_file_type(path) != FIOC_FILE)
158 		return -EINVAL;
159 
160 	return fioc_do_write(buf, size, offset);
161 }
162 
fioc_truncate(const char * path,off_t size,struct fuse_file_info * fi)163 static int fioc_truncate(const char *path, off_t size,
164 			 struct fuse_file_info *fi)
165 {
166 	(void) fi;
167 	if (fioc_file_type(path) != FIOC_FILE)
168 		return -EINVAL;
169 
170 	return fioc_resize(size);
171 }
172 
fioc_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi,enum fuse_readdir_flags flags)173 static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
174 			off_t offset, struct fuse_file_info *fi,
175 			enum fuse_readdir_flags flags)
176 {
177 	(void) fi;
178 	(void) offset;
179 	(void) flags;
180 
181 	if (fioc_file_type(path) != FIOC_ROOT)
182 		return -ENOENT;
183 
184 	filler(buf, ".", NULL, 0, 0);
185 	filler(buf, "..", NULL, 0, 0);
186 	filler(buf, FIOC_NAME, NULL, 0, 0);
187 
188 	return 0;
189 }
190 
fioc_ioctl(const char * path,unsigned int cmd,void * arg,struct fuse_file_info * fi,unsigned int flags,void * data)191 static int fioc_ioctl(const char *path, unsigned int cmd, void *arg,
192 		      struct fuse_file_info *fi, unsigned int flags, void *data)
193 {
194 	(void) arg;
195 	(void) fi;
196 	(void) flags;
197 
198 	if (fioc_file_type(path) != FIOC_FILE)
199 		return -EINVAL;
200 
201 	if (flags & FUSE_IOCTL_COMPAT)
202 		return -ENOSYS;
203 
204 	switch (cmd) {
205 	case FIOC_GET_SIZE:
206 		*(size_t *)data = fioc_size;
207 		return 0;
208 
209 	case FIOC_SET_SIZE:
210 		fioc_resize(*(size_t *)data);
211 		return 0;
212 	}
213 
214 	return -EINVAL;
215 }
216 
217 static const struct fuse_operations fioc_oper = {
218 	.getattr	= fioc_getattr,
219 	.readdir	= fioc_readdir,
220 	.truncate	= fioc_truncate,
221 	.open		= fioc_open,
222 	.read		= fioc_read,
223 	.write		= fioc_write,
224 	.ioctl		= fioc_ioctl,
225 };
226 
main(int argc,char * argv[])227 int main(int argc, char *argv[])
228 {
229 	return fuse_main(argc, argv, &fioc_oper, NULL);
230 }
231