perfuse.c revision 1.5 1 1.5 manu /* $NetBSD: perfuse.c,v 1.5 2010/09/07 02:11:04 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.2 manu int sv[2];
105 1.1 manu struct sockaddr_un sun;
106 1.1 manu struct sockaddr *sa;
107 1.2 manu char progname[] = _PATH_PERFUSED;
108 1.2 manu char minus_i[] = "-i";
109 1.2 manu char fdstr[16];
110 1.2 manu char *const argv[] = { progname, minus_i, fdstr, NULL};
111 1.2 manu char *const envp[] = { NULL };
112 1.1 manu
113 1.1 manu if (strcmp(path, _PATH_FUSE) != 0)
114 1.1 manu return open(path, flags, mode);
115 1.1 manu
116 1.2 manu if ((sv[0] = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
117 1.1 manu #ifdef PERFUSE_DEBUG
118 1.5 manu DWARN("%s:%d socket failed: %s", __func__, __LINE__);
119 1.1 manu #endif
120 1.1 manu return -1;
121 1.1 manu }
122 1.1 manu
123 1.1 manu sa = (struct sockaddr *)(void *)&sun;
124 1.1 manu sun.sun_len = sizeof(sun);
125 1.1 manu sun.sun_family = AF_LOCAL;
126 1.1 manu (void)strcpy(sun.sun_path, path);
127 1.1 manu
128 1.2 manu if (connect(sv[0], sa, (socklen_t)sun.sun_len) == 0)
129 1.2 manu return sv[0];
130 1.2 manu
131 1.2 manu
132 1.2 manu /*
133 1.2 manu * Attempt to run perfused on our own
134 1.2 manu * if it does not run yet; In that case
135 1.2 manu * we will talk using a socketpair
136 1.2 manu * instead of /dev/fuse.
137 1.2 manu */
138 1.2 manu if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) != 0) {
139 1.1 manu #ifdef PERFUSE_DEBUG
140 1.5 manu DWARN("%s:%d: socketpair failed", __func__, __LINE__);
141 1.1 manu #endif
142 1.1 manu return -1;
143 1.1 manu }
144 1.1 manu
145 1.2 manu (void)sprintf(fdstr, "%d", sv[1]);
146 1.2 manu
147 1.2 manu switch(fork()) {
148 1.2 manu case -1:
149 1.2 manu #ifdef PERFUSE_DEBUG
150 1.5 manu DWARN("%s:%d: fork failed", __func__, __LINE__);
151 1.2 manu #endif
152 1.2 manu return -1;
153 1.2 manu /* NOTREACHED */
154 1.2 manu break;
155 1.2 manu case 0:
156 1.2 manu (void)execve(argv[0], argv, envp);
157 1.2 manu #ifdef PERFUSE_DEBUG
158 1.5 manu DWARN("%s:%d: execve failed", __func__, __LINE__);
159 1.2 manu #endif
160 1.2 manu return -1;
161 1.2 manu /* NOTREACHED */
162 1.2 manu break;
163 1.2 manu default:
164 1.2 manu break;
165 1.2 manu }
166 1.2 manu
167 1.2 manu return sv[0];
168 1.1 manu }
169 1.1 manu
170 1.1 manu
171 1.1 manu int
172 1.1 manu perfuse_mount(source, target, filesystemtype, mountflags, data)
173 1.1 manu const char *source;
174 1.1 manu const char *target;
175 1.1 manu const char *filesystemtype;
176 1.1 manu long mountflags;
177 1.1 manu const void *data;
178 1.1 manu {
179 1.1 manu int s;
180 1.1 manu size_t len;
181 1.1 manu struct perfuse_mount_out pmo;
182 1.1 manu
183 1.1 manu #ifdef PERFUSE_DEBUG
184 1.5 manu if (perfuse_diagflags & PDF_MISC)
185 1.5 manu DPRINTF("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n",
186 1.5 manu __func__, source, target, filesystemtype,
187 1.5 manu mountflags, (const char *)data);
188 1.1 manu #endif
189 1.1 manu
190 1.1 manu if ((s = get_fd(data)) == -1)
191 1.1 manu return -1;
192 1.1 manu
193 1.1 manu pmo.pmo_len = sizeof(pmo);
194 1.4 manu pmo.pmo_len += source ? (uint32_t)strlen(source) : 0;
195 1.4 manu pmo.pmo_len += target ? (uint32_t)strlen(target) : 0;
196 1.4 manu pmo.pmo_len += filesystemtype ? (uint32_t)strlen(filesystemtype) : 0;
197 1.4 manu pmo.pmo_len += data ? (uint32_t)strlen(data) : 0;
198 1.1 manu pmo.pmo_error = 0;
199 1.1 manu pmo.pmo_unique = (uint64_t)-1;
200 1.1 manu
201 1.1 manu (void)strcpy(pmo.pmo_magic, PERFUSE_MOUNT_MAGIC);
202 1.4 manu pmo.pmo_source_len = source ? (uint32_t)strlen(source) : 0;
203 1.4 manu pmo.pmo_target_len = target ? (uint32_t)strlen(target) : 0;
204 1.1 manu pmo.pmo_filesystemtype_len =
205 1.4 manu filesystemtype ? (uint32_t)strlen(filesystemtype) : 0;
206 1.4 manu pmo.pmo_mountflags = (uint32_t)mountflags;
207 1.4 manu pmo.pmo_data_len = data ? (uint32_t)strlen(data) : 0;
208 1.1 manu
209 1.1 manu
210 1.1 manu if (write(s, &pmo, sizeof(pmo)) != sizeof(pmo)) {
211 1.1 manu #ifdef PERFUSE_DEBUG
212 1.5 manu if (perfuse_diagflags & PDF_MISC)
213 1.5 manu DPRINTF("%s:%d short write\n", __func__, __LINE__);
214 1.1 manu #endif
215 1.1 manu return -1;
216 1.1 manu }
217 1.1 manu
218 1.1 manu if (source) {
219 1.1 manu len = pmo.pmo_source_len;
220 1.1 manu if (write(s, source, len) != (ssize_t)len) {
221 1.1 manu #ifdef PERFUSE_DEBUG
222 1.5 manu DWARNX("%s:%d short write\n", __func__, __LINE__);
223 1.1 manu #endif
224 1.1 manu return -1;
225 1.1 manu }
226 1.1 manu }
227 1.1 manu
228 1.1 manu if (target) {
229 1.1 manu len = pmo.pmo_target_len;
230 1.1 manu if (write(s, target, len) != (ssize_t)len) {
231 1.1 manu #ifdef PERFUSE_DEBUG
232 1.5 manu DWARNX("%s:%d short write\n", __func__, __LINE__);
233 1.1 manu #endif
234 1.1 manu return -1;
235 1.1 manu }
236 1.1 manu }
237 1.1 manu
238 1.1 manu if (filesystemtype) {
239 1.1 manu len = pmo.pmo_filesystemtype_len;
240 1.1 manu if (write(s, filesystemtype, len) != (ssize_t)len) {
241 1.1 manu #ifdef PERFUSE_DEBUG
242 1.5 manu DWARNX("%s:%d short write\n", __func__, __LINE__);
243 1.1 manu #endif
244 1.1 manu return -1;
245 1.1 manu }
246 1.1 manu }
247 1.1 manu
248 1.1 manu if (data) {
249 1.1 manu len = pmo.pmo_data_len;
250 1.1 manu if (write(s, data, len) != (ssize_t)len) {
251 1.1 manu #ifdef PERFUSE_DEBUG
252 1.5 manu DWARNX("%s:%d short write\n", __func__, __LINE__);
253 1.1 manu #endif
254 1.1 manu return -1;
255 1.1 manu }
256 1.1 manu }
257 1.1 manu
258 1.1 manu return 0;
259 1.1 manu }
260 1.1 manu
261 1.1 manu
262 1.1 manu uint64_t
263 1.1 manu perfuse_next_unique(pu)
264 1.1 manu struct puffs_usermount *pu;
265 1.1 manu {
266 1.1 manu struct perfuse_state *ps;
267 1.1 manu
268 1.1 manu ps = puffs_getspecific(pu);
269 1.1 manu
270 1.1 manu return ps->ps_unique++;
271 1.1 manu }
272 1.1 manu
273 1.1 manu struct puffs_usermount *
274 1.1 manu perfuse_init(pc, pmi)
275 1.1 manu struct perfuse_callbacks *pc;
276 1.1 manu struct perfuse_mount_info *pmi;
277 1.1 manu {
278 1.1 manu struct perfuse_state *ps;
279 1.1 manu struct puffs_usermount *pu;
280 1.1 manu struct puffs_ops *pops;
281 1.1 manu char name[] = "perfuse";
282 1.1 manu unsigned int puffs_flags;
283 1.1 manu struct puffs_node *pn_root;
284 1.1 manu struct puffs_pathobj *po_root;
285 1.1 manu
286 1.1 manu ps = init_state();
287 1.2 manu ps->ps_owner_uid = pmi->pmi_uid;
288 1.1 manu
289 1.1 manu if (pmi->pmi_source)
290 1.1 manu ps->ps_source = strdup(pmi->pmi_source);
291 1.1 manu if (pmi->pmi_filesystemtype)
292 1.1 manu ps->ps_filesystemtype = strdup(pmi->pmi_filesystemtype);
293 1.1 manu ps->ps_target = strdup(pmi->pmi_target);
294 1.1 manu ps->ps_mountflags = pmi->pmi_mountflags;
295 1.1 manu
296 1.1 manu /*
297 1.1 manu * Some options are forbidden for non root users
298 1.1 manu */
299 1.2 manu if (ps->ps_owner_uid != 0)
300 1.1 manu ps->ps_mountflags |= MNT_NOSUID|MNT_NODEV;
301 1.1 manu
302 1.1 manu PUFFSOP_INIT(pops);
303 1.1 manu PUFFSOP_SET(pops, perfuse, fs, unmount);
304 1.1 manu PUFFSOP_SET(pops, perfuse, fs, statvfs);
305 1.1 manu PUFFSOP_SET(pops, perfuse, fs, sync);
306 1.1 manu PUFFSOP_SET(pops, perfuse, node, lookup);
307 1.1 manu PUFFSOP_SET(pops, perfuse, node, create);
308 1.1 manu PUFFSOP_SET(pops, perfuse, node, mknod);
309 1.1 manu PUFFSOP_SET(pops, perfuse, node, open);
310 1.1 manu PUFFSOP_SET(pops, perfuse, node, close);
311 1.1 manu PUFFSOP_SET(pops, perfuse, node, access);
312 1.1 manu PUFFSOP_SET(pops, perfuse, node, getattr);
313 1.1 manu PUFFSOP_SET(pops, perfuse, node, setattr);
314 1.1 manu PUFFSOP_SET(pops, perfuse, node, poll);
315 1.1 manu #if 0
316 1.1 manu PUFFSOP_SET(pops, perfuse, node, mmap);
317 1.1 manu #endif
318 1.1 manu PUFFSOP_SET(pops, perfuse, node, fsync);
319 1.1 manu PUFFSOP_SET(pops, perfuse, node, seek);
320 1.1 manu PUFFSOP_SET(pops, perfuse, node, remove);
321 1.1 manu PUFFSOP_SET(pops, perfuse, node, link);
322 1.1 manu PUFFSOP_SET(pops, perfuse, node, rename);
323 1.1 manu PUFFSOP_SET(pops, perfuse, node, mkdir);
324 1.1 manu PUFFSOP_SET(pops, perfuse, node, rmdir);
325 1.1 manu PUFFSOP_SET(pops, perfuse, node, symlink);
326 1.1 manu PUFFSOP_SET(pops, perfuse, node, readdir);
327 1.1 manu PUFFSOP_SET(pops, perfuse, node, readlink);
328 1.1 manu PUFFSOP_SET(pops, perfuse, node, reclaim);
329 1.1 manu PUFFSOP_SET(pops, perfuse, node, inactive);
330 1.1 manu PUFFSOP_SET(pops, perfuse, node, print);
331 1.1 manu PUFFSOP_SET(pops, perfuse, node, advlock);
332 1.1 manu PUFFSOP_SET(pops, perfuse, node, read);
333 1.1 manu PUFFSOP_SET(pops, perfuse, node, write);
334 1.1 manu
335 1.1 manu puffs_flags = PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_HASHPATH;
336 1.1 manu if (perfuse_diagflags & PDF_PUFFS)
337 1.1 manu puffs_flags |= PUFFS_FLAG_OPDUMP;
338 1.1 manu
339 1.1 manu if ((pu = puffs_init(pops, _PATH_PUFFS, name, ps, puffs_flags)) == NULL)
340 1.1 manu DERR(EX_OSERR, "puffs_init failed");
341 1.1 manu
342 1.1 manu ps->ps_pu = pu;
343 1.1 manu
344 1.1 manu /*
345 1.1 manu * Setup filesystem root
346 1.1 manu */
347 1.1 manu pn_root = perfuse_new_pn(pu, NULL);
348 1.1 manu PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID;
349 1.3 manu PERFUSE_NODE_DATA(pn_root)->pnd_parent = pn_root;
350 1.1 manu puffs_setroot(pu, pn_root);
351 1.1 manu ps->ps_fsid = pn_root->pn_va.va_fsid;
352 1.1 manu
353 1.1 manu po_root = puffs_getrootpathobj(pu);
354 1.1 manu if ((po_root->po_path = strdup("/")) == NULL)
355 1.1 manu DERRX(EX_OSERR, "perfuse_mount_start() failed");
356 1.1 manu
357 1.1 manu po_root->po_len = 1;
358 1.1 manu puffs_path_buildhash(pu, po_root);
359 1.1 manu
360 1.1 manu puffs_vattr_null(&pn_root->pn_va);
361 1.1 manu pn_root->pn_va.va_type = VDIR;
362 1.1 manu pn_root->pn_va.va_mode = 0755;
363 1.1 manu
364 1.1 manu ps->ps_root = pn_root;
365 1.1 manu
366 1.1 manu /*
367 1.1 manu * Callbacks
368 1.1 manu */
369 1.1 manu ps->ps_new_msg = pc->pc_new_msg;
370 1.1 manu ps->ps_xchg_msg = pc->pc_xchg_msg;
371 1.1 manu ps->ps_destroy_msg = pc->pc_destroy_msg;
372 1.1 manu ps->ps_get_inhdr = pc->pc_get_inhdr;
373 1.1 manu ps->ps_get_inpayload = pc->pc_get_inpayload;
374 1.1 manu ps->ps_get_outhdr = pc->pc_get_outhdr;
375 1.1 manu ps->ps_get_outpayload = pc->pc_get_outpayload;
376 1.1 manu
377 1.1 manu return pu;
378 1.1 manu }
379 1.1 manu
380 1.1 manu void
381 1.1 manu perfuse_setspecific(pu, priv)
382 1.1 manu struct puffs_usermount *pu;
383 1.1 manu void *priv;
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 ps->ps_private = priv;
389 1.1 manu
390 1.1 manu return;
391 1.1 manu }
392 1.1 manu
393 1.1 manu void *
394 1.1 manu perfuse_getspecific(pu)
395 1.1 manu struct puffs_usermount *pu;
396 1.1 manu {
397 1.1 manu struct perfuse_state *ps;
398 1.1 manu
399 1.1 manu ps = puffs_getspecific(pu);
400 1.1 manu
401 1.1 manu return ps->ps_private;
402 1.1 manu }
403 1.1 manu
404 1.1 manu int
405 1.1 manu perfuse_inloop(pu)
406 1.1 manu struct puffs_usermount *pu;
407 1.1 manu {
408 1.1 manu struct perfuse_state *ps;
409 1.1 manu
410 1.1 manu ps = puffs_getspecific(pu);
411 1.1 manu
412 1.1 manu return ps->ps_flags & PS_INLOOP;
413 1.1 manu }
414 1.1 manu
415 1.1 manu int
416 1.1 manu perfuse_mainloop(pu)
417 1.1 manu struct puffs_usermount *pu;
418 1.1 manu {
419 1.1 manu struct perfuse_state *ps;
420 1.1 manu
421 1.1 manu ps = puffs_getspecific(pu);
422 1.1 manu
423 1.1 manu ps->ps_flags |= PS_INLOOP;
424 1.1 manu if (puffs_mainloop(ps->ps_pu) != 0)
425 1.1 manu DERR(EX_OSERR, "puffs_mainloop failed");
426 1.1 manu DERR(EX_OSERR, "puffs_mainloop exit");
427 1.1 manu
428 1.1 manu /* NOTREACHED */
429 1.1 manu return -1;
430 1.1 manu }
431 1.1 manu
432 1.1 manu /* ARGSUSED0 */
433 1.1 manu uint64_t
434 1.1 manu perfuse_get_ino(pu, opc)
435 1.1 manu struct puffs_usermount *pu;
436 1.1 manu puffs_cookie_t opc;
437 1.1 manu {
438 1.1 manu return PERFUSE_NODE_DATA(opc)->pnd_ino;
439 1.1 manu }
440 1.2 manu
441 1.2 manu int
442 1.2 manu perfuse_unmount(pu)
443 1.2 manu struct puffs_usermount *pu;
444 1.2 manu {
445 1.2 manu struct perfuse_state *ps;
446 1.2 manu
447 1.2 manu ps = puffs_getspecific(pu);
448 1.2 manu
449 1.2 manu return unmount(ps->ps_target, MNT_FORCE);
450 1.2 manu }
451