"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/doc/html/fuse-3_810_83_2lib_2cuse__lowlevel_8c_source.html" (9 Jun 2021, 67612 Bytes) of package /linux/misc/fuse-3.10.4.tar.xz:


Caution: In this restricted "Fossies" environment the current HTML page may not be correctly presentated and may have some non-functional links. You can here alternatively try to browse the pure source code or just view or download the uninterpreted raw source code. If the rendering is insufficient you may try to find and view the page on the project site itself.

libfuse
cuse_lowlevel.c
1 /*
2  CUSE: Character device in Userspace
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 LGPLv2.
7  See the file COPYING.LIB.
8 */
9 
10 #include "config.h"
11 #include "cuse_lowlevel.h"
12 #include "fuse_kernel.h"
13 #include "fuse_i.h"
14 #include "fuse_opt.h"
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <errno.h>
21 #include <unistd.h>
22 
23 struct cuse_data {
24  struct cuse_lowlevel_ops clop;
25  unsigned max_read;
26  unsigned dev_major;
27  unsigned dev_minor;
28  unsigned flags;
29  unsigned dev_info_len;
30  char dev_info[];
31 };
32 
33 static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
34 {
35  return &req->se->cuse_data->clop;
36 }
37 
38 static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
39  struct fuse_file_info *fi)
40 {
41  (void)ino;
42  req_clop(req)->open(req, fi);
43 }
44 
45 static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
46  off_t off, struct fuse_file_info *fi)
47 {
48  (void)ino;
49  req_clop(req)->read(req, size, off, fi);
50 }
51 
52 static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
53  size_t size, off_t off, struct fuse_file_info *fi)
54 {
55  (void)ino;
56  req_clop(req)->write(req, buf, size, off, fi);
57 }
58 
59 static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
60  struct fuse_file_info *fi)
61 {
62  (void)ino;
63  req_clop(req)->flush(req, fi);
64 }
65 
66 static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
67  struct fuse_file_info *fi)
68 {
69  (void)ino;
70  req_clop(req)->release(req, fi);
71 }
72 
73 static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
74  struct fuse_file_info *fi)
75 {
76  (void)ino;
77  req_clop(req)->fsync(req, datasync, fi);
78 }
79 
80 static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
81  struct fuse_file_info *fi, unsigned int flags,
82  const void *in_buf, size_t in_bufsz, size_t out_bufsz)
83 {
84  (void)ino;
85  req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
86  out_bufsz);
87 }
88 
89 static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
90  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
91 {
92  (void)ino;
93  req_clop(req)->poll(req, fi, ph);
94 }
95 
96 static size_t cuse_pack_info(int argc, const char **argv, char *buf)
97 {
98  size_t size = 0;
99  int i;
100 
101  for (i = 0; i < argc; i++) {
102  size_t len;
103 
104  len = strlen(argv[i]) + 1;
105  size += len;
106  if (buf) {
107  memcpy(buf, argv[i], len);
108  buf += len;
109  }
110  }
111 
112  return size;
113 }
114 
115 static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
116  const struct cuse_lowlevel_ops *clop)
117 {
118  struct cuse_data *cd;
119  size_t dev_info_len;
120 
121  dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
122  NULL);
123 
124  if (dev_info_len > CUSE_INIT_INFO_MAX) {
125  fuse_log(FUSE_LOG_ERR, "cuse: dev_info (%zu) too large, limit=%u\n",
126  dev_info_len, CUSE_INIT_INFO_MAX);
127  return NULL;
128  }
129 
130  cd = calloc(1, sizeof(*cd) + dev_info_len);
131  if (!cd) {
132  fuse_log(FUSE_LOG_ERR, "cuse: failed to allocate cuse_data\n");
133  return NULL;
134  }
135 
136  memcpy(&cd->clop, clop, sizeof(cd->clop));
137  cd->max_read = 131072;
138  cd->dev_major = ci->dev_major;
139  cd->dev_minor = ci->dev_minor;
140  cd->dev_info_len = dev_info_len;
141  cd->flags = ci->flags;
142  cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
143 
144  return cd;
145 }
146 
147 struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
148  const struct cuse_info *ci,
149  const struct cuse_lowlevel_ops *clop,
150  void *userdata)
151 {
152  struct fuse_lowlevel_ops lop;
153  struct cuse_data *cd;
154  struct fuse_session *se;
155 
156  cd = cuse_prep_data(ci, clop);
157  if (!cd)
158  return NULL;
159 
160  memset(&lop, 0, sizeof(lop));
161  lop.init = clop->init;
162  lop.destroy = clop->destroy;
163  lop.open = clop->open ? cuse_fll_open : NULL;
164  lop.read = clop->read ? cuse_fll_read : NULL;
165  lop.write = clop->write ? cuse_fll_write : NULL;
166  lop.flush = clop->flush ? cuse_fll_flush : NULL;
167  lop.release = clop->release ? cuse_fll_release : NULL;
168  lop.fsync = clop->fsync ? cuse_fll_fsync : NULL;
169  lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL;
170  lop.poll = clop->poll ? cuse_fll_poll : NULL;
171 
172  se = fuse_session_new(args, &lop, sizeof(lop), userdata);
173  if (!se) {
174  free(cd);
175  return NULL;
176  }
177  se->cuse_data = cd;
178 
179  return se;
180 }
181 
182 static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
183  char *dev_info, unsigned dev_info_len)
184 {
185  struct iovec iov[3];
186 
187  iov[1].iov_base = arg;
188  iov[1].iov_len = sizeof(struct cuse_init_out);
189  iov[2].iov_base = dev_info;
190  iov[2].iov_len = dev_info_len;
191 
192  return fuse_send_reply_iov_nofree(req, 0, iov, 3);
193 }
194 
195 void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
196 {
197  struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
198  struct cuse_init_out outarg;
199  struct fuse_session *se = req->se;
200  struct cuse_data *cd = se->cuse_data;
201  size_t bufsize = se->bufsize;
202  struct cuse_lowlevel_ops *clop = req_clop(req);
203 
204  (void) nodeid;
205  if (se->debug) {
206  fuse_log(FUSE_LOG_DEBUG, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
207  fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
208  }
209  se->conn.proto_major = arg->major;
210  se->conn.proto_minor = arg->minor;
211  se->conn.capable = 0;
212  se->conn.want = 0;
213 
214  if (arg->major < 7) {
215  fuse_log(FUSE_LOG_ERR, "cuse: unsupported protocol version: %u.%u\n",
216  arg->major, arg->minor);
217  fuse_reply_err(req, EPROTO);
218  return;
219  }
220 
221  if (bufsize < FUSE_MIN_READ_BUFFER) {
222  fuse_log(FUSE_LOG_ERR, "cuse: warning: buffer size too small: %zu\n",
223  bufsize);
224  bufsize = FUSE_MIN_READ_BUFFER;
225  }
226 
227  bufsize -= 4096;
228  if (bufsize < se->conn.max_write)
229  se->conn.max_write = bufsize;
230 
231  se->got_init = 1;
232  if (se->op.init)
233  se->op.init(se->userdata, &se->conn);
234 
235  memset(&outarg, 0, sizeof(outarg));
236  outarg.major = FUSE_KERNEL_VERSION;
237  outarg.minor = FUSE_KERNEL_MINOR_VERSION;
238  outarg.flags = cd->flags;
239  outarg.max_read = cd->max_read;
240  outarg.max_write = se->conn.max_write;
241  outarg.dev_major = cd->dev_major;
242  outarg.dev_minor = cd->dev_minor;
243 
244  if (se->debug) {
245  fuse_log(FUSE_LOG_DEBUG, " CUSE_INIT: %u.%u\n",
246  outarg.major, outarg.minor);
247  fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
248  fuse_log(FUSE_LOG_DEBUG, " max_read=0x%08x\n", outarg.max_read);
249  fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
250  fuse_log(FUSE_LOG_DEBUG, " dev_major=%u\n", outarg.dev_major);
251  fuse_log(FUSE_LOG_DEBUG, " dev_minor=%u\n", outarg.dev_minor);
252  fuse_log(FUSE_LOG_DEBUG, " dev_info: %.*s\n", cd->dev_info_len,
253  cd->dev_info);
254  }
255 
256  cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
257 
258  if (clop->init_done)
259  clop->init_done(se->userdata);
260 
261  fuse_free_req(req);
262 }
263 
264 struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
265  const struct cuse_info *ci,
266  const struct cuse_lowlevel_ops *clop,
267  int *multithreaded, void *userdata)
268 {
269  const char *devname = "/dev/cuse";
270  static const struct fuse_opt kill_subtype_opts[] = {
271  FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD),
273  };
274  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
275  struct fuse_session *se;
276  struct fuse_cmdline_opts opts;
277  int fd;
278  int res;
279 
280  if (fuse_parse_cmdline(&args, &opts) == -1)
281  return NULL;
282  *multithreaded = !opts.singlethread;
283 
284  /* Remove subtype= option */
285  res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
286  if (res == -1)
287  goto out1;
288 
289  /*
290  * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
291  * would ensue.
292  */
293  do {
294  fd = open("/dev/null", O_RDWR);
295  if (fd > 2)
296  close(fd);
297  } while (fd >= 0 && fd <= 2);
298 
299  se = cuse_lowlevel_new(&args, ci, clop, userdata);
300  if (se == NULL)
301  goto out1;
302 
303  fd = open(devname, O_RDWR);
304  if (fd == -1) {
305  if (errno == ENODEV || errno == ENOENT)
306  fuse_log(FUSE_LOG_ERR, "cuse: device not found, try 'modprobe cuse' first\n");
307  else
308  fuse_log(FUSE_LOG_ERR, "cuse: failed to open %s: %s\n",
309  devname, strerror(errno));
310  goto err_se;
311  }
312  se->fd = fd;
313 
314  res = fuse_set_signal_handlers(se);
315  if (res == -1)
316  goto err_se;
317 
318  res = fuse_daemonize(opts.foreground);
319  if (res == -1)
320  goto err_sig;
321 
322  fuse_opt_free_args(&args);
323  return se;
324 
325 err_sig:
327 err_se:
329 out1:
330  free(opts.mountpoint);
331  fuse_opt_free_args(&args);
332  return NULL;
333 }
334 
335 void cuse_lowlevel_teardown(struct fuse_session *se)
336 {
339 }
340 
341 int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
342  const struct cuse_lowlevel_ops *clop, void *userdata)
343 {
344  struct fuse_session *se;
345  int multithreaded;
346  int res;
347 
348  se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
349  userdata);
350  if (se == NULL)
351  return 1;
352 
353  if (multithreaded) {
354  struct fuse_loop_config config;
355  config.clone_fd = 0;
356  config.max_idle_threads = 10;
357  res = fuse_session_loop_mt_32(se, &config);
358  }
359  else
360  res = fuse_session_loop(se);
361 
362  cuse_lowlevel_teardown(se);
363  if (res == -1)
364  return 1;
365 
366  return 0;
367 }
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
void fuse_session_destroy(struct fuse_session *se)
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
int fuse_daemonize(int foreground)
Definition: helper.c:225
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:34
#define FUSE_OPT_KEY_DISCARD
Definition: fuse_opt.h:153
#define FUSE_OPT_END
Definition: fuse_opt.h:104
int fuse_reply_err(fuse_req_t req, int err)
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79