perfuse.c revision 1.1 1 1.1 manu /* $NetBSD: perfuse.c,v 1.1 2010/08/25 07:16:00 manu Exp $ */
2 1.1 manu
3 1.1 manu /*-
4 1.1 manu * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5 1.1 manu *
6 1.1 manu * Redistribution and use in source and binary forms, with or without
7 1.1 manu * modification, are permitted provided that the following conditions
8 1.1 manu * are met:
9 1.1 manu * 1. Redistributions of source code must retain the above copyright
10 1.1 manu * notice, this list of conditions and the following disclaimer.
11 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 manu * notice, this list of conditions and the following disclaimer in the
13 1.1 manu * documentation and/or other materials provided with the distribution.
14 1.1 manu *
15 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 1.1 manu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 1.1 manu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 1.1 manu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 1.1 manu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 1.1 manu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 1.1 manu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 1.1 manu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 1.1 manu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 1.1 manu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 1.1 manu * POSSIBILITY OF SUCH DAMAGE.
26 1.1 manu */
27 1.1 manu
28 1.1 manu #include <stdio.h>
29 1.1 manu #include <unistd.h>
30 1.1 manu #include <stdlib.h>
31 1.1 manu #include <fcntl.h>
32 1.1 manu #include <string.h>
33 1.1 manu #include <errno.h>
34 1.1 manu #include <puffs.h>
35 1.1 manu #include <sys/types.h>
36 1.1 manu #include <sys/socket.h>
37 1.1 manu #include <sys/un.h>
38 1.1 manu
39 1.1 manu #define LIBPERFUSE
40 1.1 manu #include "perfuse.h"
41 1.1 manu #include "perfuse_if.h"
42 1.1 manu #include "perfuse_priv.h"
43 1.1 manu
44 1.1 manu int perfuse_diagflags = 0; /* global used only in DPRINTF/DERR/DWARN */
45 1.1 manu
46 1.1 manu static struct perfuse_state *init_state(void);
47 1.1 manu static int get_fd(const char *);
48 1.1 manu
49 1.1 manu static struct perfuse_state *
50 1.1 manu init_state(void)
51 1.1 manu {
52 1.1 manu struct perfuse_state *ps;
53 1.1 manu
54 1.1 manu if ((ps = malloc(sizeof(*ps))) == NULL)
55 1.1 manu DERR(EX_OSERR, "malloc failed");
56 1.1 manu
57 1.1 manu (void)memset(ps, 0, sizeof(*ps));
58 1.1 manu ps->ps_max_write = UINT_MAX;
59 1.1 manu ps->ps_max_readahead = UINT_MAX;
60 1.1 manu
61 1.1 manu return ps;
62 1.1 manu }
63 1.1 manu
64 1.1 manu
65 1.1 manu static int
66 1.1 manu get_fd(data)
67 1.1 manu const char *data;
68 1.1 manu {
69 1.1 manu char *string;
70 1.1 manu const char fdopt[] = "fd=";
71 1.1 manu char *lastp;
72 1.1 manu char *opt;
73 1.1 manu int fd = -1;
74 1.1 manu
75 1.1 manu if ((string = strdup(data)) == NULL)
76 1.1 manu return -1;
77 1.1 manu
78 1.1 manu for (opt = strtok_r(string, ",", &lastp);
79 1.1 manu opt != NULL;
80 1.1 manu opt = strtok_r(NULL, ",", &lastp)) {
81 1.1 manu if (strncmp(opt, fdopt, strlen(fdopt)) == 0) {
82 1.1 manu fd = atoi(opt + strlen(fdopt));
83 1.1 manu break;
84 1.1 manu }
85 1.1 manu }
86 1.1 manu
87 1.1 manu /*
88 1.1 manu * No file descriptor found
89 1.1 manu */
90 1.1 manu if (fd == -1)
91 1.1 manu errno = EINVAL;
92 1.1 manu
93 1.1 manu free(string);
94 1.1 manu return fd;
95 1.1 manu
96 1.1 manu }
97 1.1 manu
98 1.1 manu int
99 1.1 manu perfuse_open(path, flags, mode)
100 1.1 manu const char *path;
101 1.1 manu int flags;
102 1.1 manu mode_t mode;
103 1.1 manu {
104 1.1 manu int s;
105 1.1 manu struct sockaddr_un sun;
106 1.1 manu struct sockaddr *sa;
107 1.1 manu
108 1.1 manu if (strcmp(path, _PATH_FUSE) != 0)
109 1.1 manu return open(path, flags, mode);
110 1.1 manu
111 1.1 manu if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
112 1.1 manu #ifdef PERFUSE_DEBUG
113 1.1 manu printf("%s:%d socket failed: %s",
114 1.1 manu __func__, __LINE__, strerror(errno));
115 1.1 manu #endif
116 1.1 manu return -1;
117 1.1 manu }
118 1.1 manu
119 1.1 manu sa = (struct sockaddr *)(void *)&sun;
120 1.1 manu sun.sun_len = sizeof(sun);
121 1.1 manu sun.sun_family = AF_LOCAL;
122 1.1 manu (void)strcpy(sun.sun_path, path);
123 1.1 manu
124 1.1 manu if (connect(s, sa, (socklen_t)sun.sun_len) == -1) {
125 1.1 manu #ifdef PERFUSE_DEBUG
126 1.1 manu printf("%s:%d connect failed: %s",
127 1.1 manu __func__, __LINE__, strerror(errno));
128 1.1 manu #endif
129 1.1 manu close(s);
130 1.1 manu return -1;
131 1.1 manu }
132 1.1 manu
133 1.1 manu return s;
134 1.1 manu }
135 1.1 manu
136 1.1 manu
137 1.1 manu int
138 1.1 manu perfuse_mount(source, target, filesystemtype, mountflags, data)
139 1.1 manu const char *source;
140 1.1 manu const char *target;
141 1.1 manu const char *filesystemtype;
142 1.1 manu long mountflags;
143 1.1 manu const void *data;
144 1.1 manu {
145 1.1 manu int s;
146 1.1 manu #if 0
147 1.1 manu struct sockaddr_un sun;
148 1.1 manu #endif
149 1.1 manu size_t len;
150 1.1 manu struct perfuse_mount_out pmo;
151 1.1 manu
152 1.1 manu #ifdef PERFUSE_DEBUG
153 1.1 manu printf("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n", __func__,
154 1.1 manu source, target, filesystemtype, mountflags, (const char *)data);
155 1.1 manu #endif
156 1.1 manu
157 1.1 manu #if 0
158 1.1 manu if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
159 1.1 manu err(EX_OSERR, "socket failed");
160 1.1 manu
161 1.1 manu sun.sun_len = sizeof(sun);
162 1.1 manu sun.sun_family = AF_LOCAL;
163 1.1 manu (void)strcpy(sun.sun_path, _PATH_FUSE);
164 1.1 manu
165 1.1 manu if (connect(s, (struct sockaddr *)&sun, sun.sun_len) == -1)
166 1.1 manu err(EX_UNAVAILABLE, "cannot connect to \"%s\"", _PATH_FUSE);
167 1.1 manu #endif
168 1.1 manu if ((s = get_fd(data)) == -1)
169 1.1 manu return -1;
170 1.1 manu
171 1.1 manu
172 1.1 manu pmo.pmo_len = sizeof(pmo);
173 1.1 manu pmo.pmo_len += source ? strlen(source) : 0;
174 1.1 manu pmo.pmo_len += target ? strlen(target) : 0;
175 1.1 manu pmo.pmo_len += filesystemtype ? strlen(filesystemtype) : 0;
176 1.1 manu pmo.pmo_len += data ? strlen(data) : 0;
177 1.1 manu pmo.pmo_error = 0;
178 1.1 manu pmo.pmo_unique = (uint64_t)-1;
179 1.1 manu
180 1.1 manu (void)strcpy(pmo.pmo_magic, PERFUSE_MOUNT_MAGIC);
181 1.1 manu pmo.pmo_source_len = source ? strlen(source) : 0;
182 1.1 manu pmo.pmo_target_len = target ? strlen(target) : 0;
183 1.1 manu pmo.pmo_filesystemtype_len =
184 1.1 manu filesystemtype ? strlen(filesystemtype) : 0;
185 1.1 manu pmo.pmo_mountflags = mountflags;
186 1.1 manu pmo.pmo_data_len = data ? strlen(data) : 0;
187 1.1 manu
188 1.1 manu
189 1.1 manu if (write(s, &pmo, sizeof(pmo)) != sizeof(pmo)) {
190 1.1 manu #ifdef PERFUSE_DEBUG
191 1.1 manu printf("%s:%d short write", __func__, __LINE__);
192 1.1 manu #endif
193 1.1 manu return -1;
194 1.1 manu }
195 1.1 manu
196 1.1 manu if (source) {
197 1.1 manu len = pmo.pmo_source_len;
198 1.1 manu if (write(s, source, len) != (ssize_t)len) {
199 1.1 manu #ifdef PERFUSE_DEBUG
200 1.1 manu printf("%s:%d short write", __func__, __LINE__);
201 1.1 manu #endif
202 1.1 manu return -1;
203 1.1 manu }
204 1.1 manu }
205 1.1 manu
206 1.1 manu if (target) {
207 1.1 manu len = pmo.pmo_target_len;
208 1.1 manu if (write(s, target, len) != (ssize_t)len) {
209 1.1 manu #ifdef PERFUSE_DEBUG
210 1.1 manu printf("%s:%d short write", __func__, __LINE__);
211 1.1 manu #endif
212 1.1 manu return -1;
213 1.1 manu }
214 1.1 manu }
215 1.1 manu
216 1.1 manu if (filesystemtype) {
217 1.1 manu len = pmo.pmo_filesystemtype_len;
218 1.1 manu if (write(s, filesystemtype, len) != (ssize_t)len) {
219 1.1 manu #ifdef PERFUSE_DEBUG
220 1.1 manu printf("%s:%d short write", __func__, __LINE__);
221 1.1 manu #endif
222 1.1 manu return -1;
223 1.1 manu }
224 1.1 manu }
225 1.1 manu
226 1.1 manu if (data) {
227 1.1 manu len = pmo.pmo_data_len;
228 1.1 manu if (write(s, data, len) != (ssize_t)len) {
229 1.1 manu #ifdef PERFUSE_DEBUG
230 1.1 manu printf("%s:%d short write", __func__, __LINE__);
231 1.1 manu #endif
232 1.1 manu return -1;
233 1.1 manu }
234 1.1 manu }
235 1.1 manu
236 1.1 manu return 0;
237 1.1 manu }
238 1.1 manu
239 1.1 manu
240 1.1 manu uint64_t
241 1.1 manu perfuse_next_unique(pu)
242 1.1 manu struct puffs_usermount *pu;
243 1.1 manu {
244 1.1 manu struct perfuse_state *ps;
245 1.1 manu
246 1.1 manu ps = puffs_getspecific(pu);
247 1.1 manu
248 1.1 manu return ps->ps_unique++;
249 1.1 manu }
250 1.1 manu
251 1.1 manu struct puffs_usermount *
252 1.1 manu perfuse_init(pc, pmi)
253 1.1 manu struct perfuse_callbacks *pc;
254 1.1 manu struct perfuse_mount_info *pmi;
255 1.1 manu {
256 1.1 manu struct perfuse_state *ps;
257 1.1 manu struct puffs_usermount *pu;
258 1.1 manu struct puffs_ops *pops;
259 1.1 manu char name[] = "perfuse";
260 1.1 manu unsigned int puffs_flags;
261 1.1 manu struct puffs_node *pn_root;
262 1.1 manu struct puffs_pathobj *po_root;
263 1.1 manu
264 1.1 manu ps = init_state();
265 1.1 manu ps->ps_uid = pmi->pmi_uid;
266 1.1 manu
267 1.1 manu if (pmi->pmi_source)
268 1.1 manu ps->ps_source = strdup(pmi->pmi_source);
269 1.1 manu if (pmi->pmi_filesystemtype)
270 1.1 manu ps->ps_filesystemtype = strdup(pmi->pmi_filesystemtype);
271 1.1 manu ps->ps_target = strdup(pmi->pmi_target);
272 1.1 manu ps->ps_mountflags = pmi->pmi_mountflags;
273 1.1 manu
274 1.1 manu /*
275 1.1 manu * Some options are forbidden for non root users
276 1.1 manu */
277 1.1 manu if (ps->ps_uid != 0)
278 1.1 manu ps->ps_mountflags |= MNT_NOSUID|MNT_NODEV;
279 1.1 manu
280 1.1 manu PUFFSOP_INIT(pops);
281 1.1 manu PUFFSOP_SET(pops, perfuse, fs, unmount);
282 1.1 manu PUFFSOP_SET(pops, perfuse, fs, statvfs);
283 1.1 manu PUFFSOP_SET(pops, perfuse, fs, sync);
284 1.1 manu PUFFSOP_SET(pops, perfuse, node, lookup);
285 1.1 manu PUFFSOP_SET(pops, perfuse, node, create);
286 1.1 manu PUFFSOP_SET(pops, perfuse, node, mknod);
287 1.1 manu PUFFSOP_SET(pops, perfuse, node, open);
288 1.1 manu PUFFSOP_SET(pops, perfuse, node, close);
289 1.1 manu PUFFSOP_SET(pops, perfuse, node, access);
290 1.1 manu PUFFSOP_SET(pops, perfuse, node, getattr);
291 1.1 manu PUFFSOP_SET(pops, perfuse, node, setattr);
292 1.1 manu PUFFSOP_SET(pops, perfuse, node, poll);
293 1.1 manu #if 0
294 1.1 manu PUFFSOP_SET(pops, perfuse, node, mmap);
295 1.1 manu #endif
296 1.1 manu PUFFSOP_SET(pops, perfuse, node, fsync);
297 1.1 manu PUFFSOP_SET(pops, perfuse, node, seek);
298 1.1 manu PUFFSOP_SET(pops, perfuse, node, remove);
299 1.1 manu PUFFSOP_SET(pops, perfuse, node, link);
300 1.1 manu PUFFSOP_SET(pops, perfuse, node, rename);
301 1.1 manu PUFFSOP_SET(pops, perfuse, node, mkdir);
302 1.1 manu PUFFSOP_SET(pops, perfuse, node, rmdir);
303 1.1 manu PUFFSOP_SET(pops, perfuse, node, symlink);
304 1.1 manu PUFFSOP_SET(pops, perfuse, node, readdir);
305 1.1 manu PUFFSOP_SET(pops, perfuse, node, readlink);
306 1.1 manu PUFFSOP_SET(pops, perfuse, node, reclaim);
307 1.1 manu PUFFSOP_SET(pops, perfuse, node, inactive);
308 1.1 manu PUFFSOP_SET(pops, perfuse, node, print);
309 1.1 manu PUFFSOP_SET(pops, perfuse, node, advlock);
310 1.1 manu PUFFSOP_SET(pops, perfuse, node, read);
311 1.1 manu PUFFSOP_SET(pops, perfuse, node, write);
312 1.1 manu
313 1.1 manu puffs_flags = PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_HASHPATH;
314 1.1 manu if (perfuse_diagflags & PDF_PUFFS)
315 1.1 manu puffs_flags |= PUFFS_FLAG_OPDUMP;
316 1.1 manu
317 1.1 manu if ((pu = puffs_init(pops, _PATH_PUFFS, name, ps, puffs_flags)) == NULL)
318 1.1 manu DERR(EX_OSERR, "puffs_init failed");
319 1.1 manu
320 1.1 manu ps->ps_pu = pu;
321 1.1 manu
322 1.1 manu /*
323 1.1 manu * Setup filesystem root
324 1.1 manu */
325 1.1 manu pn_root = perfuse_new_pn(pu, NULL);
326 1.1 manu PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID;
327 1.1 manu puffs_setroot(pu, pn_root);
328 1.1 manu ps->ps_fsid = pn_root->pn_va.va_fsid;
329 1.1 manu
330 1.1 manu po_root = puffs_getrootpathobj(pu);
331 1.1 manu if ((po_root->po_path = strdup("/")) == NULL)
332 1.1 manu DERRX(EX_OSERR, "perfuse_mount_start() failed");
333 1.1 manu
334 1.1 manu po_root->po_len = 1;
335 1.1 manu puffs_path_buildhash(pu, po_root);
336 1.1 manu
337 1.1 manu puffs_vattr_null(&pn_root->pn_va);
338 1.1 manu pn_root->pn_va.va_type = VDIR;
339 1.1 manu pn_root->pn_va.va_mode = 0755;
340 1.1 manu
341 1.1 manu ps->ps_root = pn_root;
342 1.1 manu
343 1.1 manu /*
344 1.1 manu * Callbacks
345 1.1 manu */
346 1.1 manu ps->ps_new_msg = pc->pc_new_msg;
347 1.1 manu ps->ps_xchg_msg = pc->pc_xchg_msg;
348 1.1 manu ps->ps_destroy_msg = pc->pc_destroy_msg;
349 1.1 manu ps->ps_get_inhdr = pc->pc_get_inhdr;
350 1.1 manu ps->ps_get_inpayload = pc->pc_get_inpayload;
351 1.1 manu ps->ps_get_outhdr = pc->pc_get_outhdr;
352 1.1 manu ps->ps_get_outpayload = pc->pc_get_outpayload;
353 1.1 manu
354 1.1 manu return pu;
355 1.1 manu }
356 1.1 manu
357 1.1 manu void
358 1.1 manu perfuse_setspecific(pu, priv)
359 1.1 manu struct puffs_usermount *pu;
360 1.1 manu void *priv;
361 1.1 manu {
362 1.1 manu struct perfuse_state *ps;
363 1.1 manu
364 1.1 manu ps = puffs_getspecific(pu);
365 1.1 manu ps->ps_private = priv;
366 1.1 manu
367 1.1 manu return;
368 1.1 manu }
369 1.1 manu
370 1.1 manu void *
371 1.1 manu perfuse_getspecific(pu)
372 1.1 manu struct puffs_usermount *pu;
373 1.1 manu {
374 1.1 manu struct perfuse_state *ps;
375 1.1 manu
376 1.1 manu ps = puffs_getspecific(pu);
377 1.1 manu
378 1.1 manu return ps->ps_private;
379 1.1 manu }
380 1.1 manu
381 1.1 manu int
382 1.1 manu perfuse_inloop(pu)
383 1.1 manu struct puffs_usermount *pu;
384 1.1 manu {
385 1.1 manu struct perfuse_state *ps;
386 1.1 manu
387 1.1 manu ps = puffs_getspecific(pu);
388 1.1 manu
389 1.1 manu return ps->ps_flags & PS_INLOOP;
390 1.1 manu }
391 1.1 manu
392 1.1 manu int
393 1.1 manu perfuse_mainloop(pu)
394 1.1 manu struct puffs_usermount *pu;
395 1.1 manu {
396 1.1 manu struct perfuse_state *ps;
397 1.1 manu
398 1.1 manu ps = puffs_getspecific(pu);
399 1.1 manu
400 1.1 manu ps->ps_flags |= PS_INLOOP;
401 1.1 manu if (puffs_mainloop(ps->ps_pu) != 0)
402 1.1 manu DERR(EX_OSERR, "puffs_mainloop failed");
403 1.1 manu DERR(EX_OSERR, "puffs_mainloop exit");
404 1.1 manu
405 1.1 manu /* NOTREACHED */
406 1.1 manu return -1;
407 1.1 manu }
408 1.1 manu
409 1.1 manu /* ARGSUSED0 */
410 1.1 manu uint64_t
411 1.1 manu perfuse_get_ino(pu, opc)
412 1.1 manu struct puffs_usermount *pu;
413 1.1 manu puffs_cookie_t opc;
414 1.1 manu {
415 1.1 manu return PERFUSE_NODE_DATA(opc)->pnd_ino;
416 1.1 manu }
417