Blob


1 #include "a.h"
3 int fusefd;
4 int fuseeof;
5 int fusebufsize;
6 int fusemaxwrite;
7 FuseMsg *fusemsglist;
8 Lock fusemsglock;
10 int mountfuse(char *mtpt);
11 void unmountfuse(char *mtpt);
13 FuseMsg*
14 allocfusemsg(void)
15 {
16 FuseMsg *m;
17 void *vbuf;
19 lock(&fusemsglock);
20 if((m = fusemsglist) != nil){
21 fusemsglist = m->next;
22 unlock(&fusemsglock);
23 return m;
24 }
25 unlock(&fusemsglock);
26 m = emalloc(sizeof(*m) + fusebufsize);
27 vbuf = m+1;
28 m->buf = vbuf;
29 m->nbuf = 0;
30 m->hdr = vbuf;
31 m->tx = m->hdr+1;
32 return m;
33 }
35 void
36 freefusemsg(FuseMsg *m)
37 {
38 lock(&fusemsglock);
39 m->next = fusemsglist;
40 fusemsglist = m;
41 unlock(&fusemsglock);
42 }
44 FuseMsg*
45 readfusemsg(void)
46 {
47 FuseMsg *m;
48 int n, nn;
50 m = allocfusemsg();
51 errno = 0;
52 /*
53 * The FUSE kernel device apparently guarantees
54 * that this read will return exactly one message.
55 * You get an error return if you ask for just the
56 * length (first 4 bytes).
57 * FUSE returns an ENODEV error, not EOF,
58 * when the connection is unmounted.
59 */
60 if((n = read(fusefd, m->buf, fusebufsize)) < 0){
61 if(errno != ENODEV)
62 sysfatal("readfusemsg: %r");
63 }
64 if(n <= 0){
65 fuseeof = 1;
66 freefusemsg(m);
67 return nil;
68 }
69 m->nbuf = n;
71 /*
72 * FreeBSD FUSE sends a short length in the header
73 * for FUSE_INIT even though the actual read length
74 * is correct.
75 */
76 if(n == sizeof(*m->hdr)+sizeof(struct fuse_init_in)
77 && m->hdr->opcode == FUSE_INIT && m->hdr->len < n)
78 m->hdr->len = n;
80 if(m->hdr->len != n)
81 sysfatal("readfusemsg: got %d wanted %d",
82 n, m->hdr->len);
83 m->hdr->len -= sizeof(*m->hdr);
85 /*
86 * Paranoia.
87 * Make sure lengths are long enough.
88 * Make sure string arguments are NUL terminated.
89 * (I don't trust the kernel module.)
90 */
91 switch(m->hdr->opcode){
92 default:
93 /*
94 * Could sysfatal here, but can also let message go
95 * and assume higher-level code will return an
96 * "I don't know what you mean" error and recover.
97 */
98 break;
99 case FUSE_LOOKUP:
100 case FUSE_UNLINK:
101 case FUSE_RMDIR:
102 case FUSE_REMOVEXATTR:
103 /* just a string */
104 if(((char*)m->tx)[m->hdr->len-1] != 0)
105 bad:
106 sysfatal("readfusemsg: bad message");
107 break;
108 case FUSE_FORGET:
109 if(m->hdr->len < sizeof(struct fuse_forget_in))
110 goto bad;
111 break;
112 case FUSE_GETATTR:
113 break;
114 case FUSE_SETATTR:
115 if(m->hdr->len < sizeof(struct fuse_setattr_in))
116 goto bad;
117 break;
118 case FUSE_READLINK:
119 break;
120 case FUSE_SYMLINK:
121 /* two strings */
122 if(((char*)m->tx)[m->hdr->len-1] != 0
123 || memchr(m->tx, 0, m->hdr->len-1) == 0)
124 goto bad;
125 break;
126 case FUSE_MKNOD:
127 if(m->hdr->len <= sizeof(struct fuse_mknod_in)
128 || ((char*)m->tx)[m->hdr->len-1] != 0)
129 goto bad;
130 break;
131 case FUSE_MKDIR:
132 if(m->hdr->len <= sizeof(struct fuse_mkdir_in)
133 || ((char*)m->tx)[m->hdr->len-1] != 0)
134 goto bad;
135 break;
136 case FUSE_RENAME:
137 /* a struct and two strings */
138 if(m->hdr->len <= sizeof(struct fuse_rename_in)
139 || ((char*)m->tx)[m->hdr->len-1] != 0
140 || memchr((uchar*)m->tx+sizeof(struct fuse_rename_in), 0, m->hdr->len-sizeof(struct fuse_rename_in)-1) == 0)
141 goto bad;
142 break;
143 case FUSE_LINK:
144 if(m->hdr->len <= sizeof(struct fuse_link_in)
145 || ((char*)m->tx)[m->hdr->len-1] != 0)
146 goto bad;
147 break;
148 case FUSE_OPEN:
149 case FUSE_OPENDIR:
150 if(m->hdr->len < sizeof(struct fuse_open_in))
151 goto bad;
152 break;
153 case FUSE_READ:
154 case FUSE_READDIR:
155 if(m->hdr->len < sizeof(struct fuse_read_in))
156 goto bad;
157 break;
158 case FUSE_WRITE:
159 /* no strings, but check that write length is sane */
160 if(m->hdr->len < sizeof(struct fuse_write_in)+((struct fuse_write_in*)m->tx)->size)
161 goto bad;
162 break;
163 case FUSE_STATFS:
164 break;
165 case FUSE_RELEASE:
166 case FUSE_RELEASEDIR:
167 if(m->hdr->len < sizeof(struct fuse_release_in))
168 goto bad;
169 break;
170 case FUSE_FSYNC:
171 case FUSE_FSYNCDIR:
172 if(m->hdr->len < sizeof(struct fuse_fsync_in))
173 goto bad;
174 break;
175 case FUSE_SETXATTR:
176 /* struct, one string, and one binary blob */
177 if(m->hdr->len <= sizeof(struct fuse_setxattr_in))
178 goto bad;
179 nn = ((struct fuse_setxattr_in*)m->tx)->size;
180 if(m->hdr->len < sizeof(struct fuse_setxattr_in)+nn+1)
181 goto bad;
182 if(((char*)m->tx)[m->hdr->len-nn-1] != 0)
183 goto bad;
184 break;
185 case FUSE_GETXATTR:
186 /* struct and one string */
187 if(m->hdr->len <= sizeof(struct fuse_getxattr_in)
188 || ((char*)m->tx)[m->hdr->len-1] != 0)
189 goto bad;
190 break;
191 case FUSE_LISTXATTR:
192 if(m->hdr->len < sizeof(struct fuse_getxattr_in))
193 goto bad;
194 break;
195 case FUSE_FLUSH:
196 if(m->hdr->len < sizeof(struct fuse_flush_in))
197 goto bad;
198 break;
199 case FUSE_INIT:
200 if(m->hdr->len < sizeof(struct fuse_init_in))
201 goto bad;
202 break;
203 case FUSE_ACCESS:
204 if(m->hdr->len < sizeof(struct fuse_access_in))
205 goto bad;
206 break;
207 case FUSE_CREATE:
208 if(m->hdr->len <= sizeof(struct fuse_open_in)
209 || ((char*)m->tx)[m->hdr->len-1] != 0)
210 goto bad;
211 break;
213 if(debug)
214 fprint(2, "FUSE -> %G\n", m->hdr, m->tx);
215 return m;
218 /*
219 * Reply to FUSE request m using additonal
220 * argument buffer arg of size narg bytes.
221 * Perhaps should free the FuseMsg here?
222 */
223 void
224 replyfuse(FuseMsg *m, void *arg, int narg)
226 struct iovec vec[2];
227 struct fuse_out_header hdr;
228 int nvec;
230 hdr.len = sizeof hdr + narg;
231 hdr.error = 0;
232 hdr.unique = m->hdr->unique;
233 if(debug)
234 fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, arg);
236 vec[0].iov_base = &hdr;
237 vec[0].iov_len = sizeof hdr;
238 nvec = 1;
239 if(arg && narg){
240 vec[1].iov_base = arg;
241 vec[1].iov_len = narg;
242 nvec++;
244 writev(fusefd, vec, nvec);
245 freefusemsg(m);
248 /*
249 * Reply to FUSE request m with errno e.
250 */
251 void
252 replyfuseerrno(FuseMsg *m, int e)
254 struct fuse_out_header hdr;
256 hdr.len = sizeof hdr;
257 hdr.error = -e; /* FUSE sends negative errnos. */
258 hdr.unique = m->hdr->unique;
259 if(debug)
260 fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, 0);
261 write(fusefd, &hdr, sizeof hdr);
262 freefusemsg(m);
265 void
266 replyfuseerrstr(FuseMsg *m)
268 replyfuseerrno(m, errstr2errno());
271 char *fusemtpt;
272 void
273 unmountatexit(void)
275 if(fusemtpt)
276 unmountfuse(fusemtpt);
279 void
280 initfuse(char *mtpt)
282 FuseMsg *m;
283 struct fuse_init_in *tx;
284 struct fuse_init_out rx;
286 fusemtpt = mtpt;
288 /*
289 * The 4096 is for the message headers.
290 * It's a lot, but it's what the FUSE libraries ask for.
291 */
292 fusemaxwrite = getpagesize();
293 fusebufsize = 4096 + fusemaxwrite;
295 if((fusefd = mountfuse(mtpt)) < 0)
296 sysfatal("mountfuse: %r");
298 if((m = readfusemsg()) == nil)
299 sysfatal("readfusemsg: %r");
300 if(m->hdr->opcode != FUSE_INIT)
301 sysfatal("fuse: expected FUSE_INIT (26) got %d", m->hdr->opcode);
302 tx = m->tx;
304 /*
305 * Complain if the kernel is too new.
306 * We could forge ahead, but at least the one time I tried,
307 * the kernel rejected the newer version by making the
308 * writev fail in replyfuse, which is a much more confusing
309 * error message. In the future, might be nice to try to
310 * support older versions that differ only slightly.
311 */
312 if(tx->major < FUSE_KERNEL_VERSION
313 || (tx->major == FUSE_KERNEL_VERSION && tx->minor < FUSE_KERNEL_MINOR_VERSION))
314 sysfatal("fuse: too kernel version %d.%d older than program version %d.%d",
315 tx->major, tx->minor, FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
317 memset(&rx, 0, sizeof rx);
318 rx.major = FUSE_KERNEL_VERSION;
319 rx.minor = FUSE_KERNEL_MINOR_VERSION;
320 rx.max_write = fusemaxwrite;
321 replyfuse(m, &rx, sizeof rx);
324 /*
325 * Print FUSE messages. Assuming it is installed as %G,
326 * use %G with hdr, arg arguments to format a request,
327 * and %#G with reqhdr, hdr, arg arguments to format a response.
328 * The reqhdr is necessary in the %#G form because the
329 * response does not contain an opcode tag.
330 */
331 int
332 fusefmt(Fmt *fmt)
334 struct fuse_in_header *hdr = va_arg(fmt->args, void*);
335 if((fmt->flags&FmtSharp) == 0){ /* "%G", hdr, arg */
336 void *a = va_arg(fmt->args, void*);
337 fmtprint(fmt, "len %d unique %#llux uid %d gid %d pid %d ",
338 hdr->len, hdr->unique, hdr->uid, hdr->gid, hdr->pid);
340 switch(hdr->opcode){
341 default: {
342 fmtprint(fmt, "??? opcode %d", hdr->opcode);
343 break;
345 case FUSE_LOOKUP: {
346 fmtprint(fmt, "Lookup nodeid %#llux name %#q",
347 hdr->nodeid, a);
348 break;
350 case FUSE_FORGET: {
351 struct fuse_forget_in *tx = a;
352 /* nlookup (a ref count) is a vlong! */
353 fmtprint(fmt, "Forget nodeid %#llux nlookup %lld",
354 hdr->nodeid, tx->nlookup);
355 break;
357 case FUSE_GETATTR: {
358 fmtprint(fmt, "Getattr nodeid %#llux", hdr->nodeid);
359 break;
361 case FUSE_SETATTR: {
362 struct fuse_setattr_in *tx = a;
363 fmtprint(fmt, "Setattr nodeid %#llux", hdr->nodeid);
364 if(tx->valid&FATTR_FH)
365 fmtprint(fmt, " fh %#llux", tx->fh);
366 if(tx->valid&FATTR_SIZE)
367 fmtprint(fmt, " size %lld", tx->size);
368 if(tx->valid&FATTR_ATIME)
369 fmtprint(fmt, " atime %.20g", tx->atime+tx->atimensec*1e-9);
370 if(tx->valid&FATTR_MTIME)
371 fmtprint(fmt, " mtime %.20g", tx->mtime+tx->mtimensec*1e-9);
372 if(tx->valid&FATTR_MODE)
373 fmtprint(fmt, " mode %#uo", tx->mode);
374 if(tx->valid&FATTR_UID)
375 fmtprint(fmt, " uid %d", tx->uid);
376 if(tx->valid&FATTR_GID)
377 fmtprint(fmt, " gid %d", tx->gid);
378 break;
380 case FUSE_READLINK: {
381 fmtprint(fmt, "Readlink nodeid %#llux", hdr->nodeid);
382 break;
384 case FUSE_SYMLINK: {
385 char *old, *new;
387 old = a;
388 new = a + strlen(a) + 1;
389 fmtprint(fmt, "Symlink nodeid %#llux old %#q new %#q",
390 hdr->nodeid, old, new);
391 break;
393 case FUSE_MKNOD: {
394 struct fuse_mknod_in *tx = a;
395 fmtprint(fmt, "Mknod nodeid %#llux mode %#uo rdev %#ux name %#q",
396 hdr->nodeid, tx->mode, tx->rdev, tx+1);
397 break;
399 case FUSE_MKDIR: {
400 struct fuse_mkdir_in *tx = a;
401 fmtprint(fmt, "Mkdir nodeid %#llux mode %#uo name %#q",
402 hdr->nodeid, tx->mode, tx+1);
403 break;
405 case FUSE_UNLINK: {
406 fmtprint(fmt, "Unlink nodeid %#llux name %#q",
407 hdr->nodeid, a);
408 break;
410 case FUSE_RMDIR: {
411 fmtprint(fmt, "Rmdir nodeid %#llux name %#q",
412 hdr->nodeid, a);
413 break;
415 case FUSE_RENAME: {
416 struct fuse_rename_in *tx = a;
417 char *old = (char*)(tx+1);
418 char *new = old + strlen(old) + 1;
419 fmtprint(fmt, "Rename nodeid %#llux old %#q newdir %#llux new %#q",
420 hdr->nodeid, old, tx->newdir, new);
421 break;
423 case FUSE_LINK: {
424 struct fuse_link_in *tx = a;
425 fmtprint(fmt, "Link oldnodeid %#llux nodeid %#llux name %#q",
426 tx->oldnodeid, hdr->nodeid, tx+1);
427 break;
429 case FUSE_OPEN: {
430 struct fuse_open_in *tx = a;
431 /* Should one or both of flags and mode be octal? */
432 fmtprint(fmt, "Open nodeid %#llux flags %#ux mode %#ux",
433 hdr->nodeid, tx->flags, tx->mode);
434 break;
436 case FUSE_READ: {
437 struct fuse_read_in *tx = a;
438 fmtprint(fmt, "Read nodeid %#llux fh %#llux offset %lld size %ud",
439 hdr->nodeid, tx->fh, tx->offset, tx->size);
440 break;
442 case FUSE_WRITE: {
443 struct fuse_write_in *tx = a;
444 fmtprint(fmt, "Write nodeid %#llux fh %#llux offset %lld size %ud flags %#ux",
445 hdr->nodeid, tx->fh, tx->offset, tx->size, tx->write_flags);
446 break;
448 case FUSE_STATFS: {
449 fmtprint(fmt, "Statfs");
450 break;
452 case FUSE_RELEASE: {
453 struct fuse_release_in *tx = a;
454 fmtprint(fmt, "Release nodeid %#llux fh %#llux flags %#ux",
455 hdr->nodeid, tx->fh, tx->flags);
456 break;
458 case FUSE_FSYNC: {
459 struct fuse_fsync_in *tx = a;
460 fmtprint(fmt, "Fsync nodeid %#llux fh %#llux flags %#ux",
461 hdr->nodeid, tx->fh, tx->fsync_flags);
462 break;
464 case FUSE_SETXATTR: {
465 struct fuse_setxattr_in *tx = a;
466 char *name = (char*)(tx+1);
467 char *value = name + strlen(name) + 1;
468 fmtprint(fmt, "Setxattr nodeid %#llux size %d flags %#ux name %#q value %#q",
469 hdr->nodeid, tx->size, tx->flags, name, value);
470 break;
472 case FUSE_GETXATTR: {
473 struct fuse_getxattr_in *tx = a;
474 fmtprint(fmt, "Getxattr nodeid %#llux size %d name %#q",
475 hdr->nodeid, tx->size, tx+1);
476 break;
478 case FUSE_LISTXATTR: {
479 struct fuse_getxattr_in *tx = a;
480 fmtprint(fmt, "Listxattr nodeid %#llux size %d",
481 hdr->nodeid, tx->size);
482 break;
484 case FUSE_REMOVEXATTR: {
485 fmtprint(fmt, "Removexattr nodeid %#llux name %#q",
486 hdr->nodeid, a);
487 break;
489 case FUSE_FLUSH: {
490 struct fuse_flush_in *tx = a;
491 fmtprint(fmt, "Flush nodeid %#llux fh %#llux flags %#ux",
492 hdr->nodeid, tx->fh, tx->flush_flags);
493 break;
495 case FUSE_INIT: {
496 struct fuse_init_in *tx = a;
497 fmtprint(fmt, "Init major %d minor %d",
498 tx->major, tx->minor);
499 break;
501 case FUSE_OPENDIR: {
502 struct fuse_open_in *tx = a;
503 fmtprint(fmt, "Opendir nodeid %#llux flags %#ux mode %#ux",
504 hdr->nodeid, tx->flags, tx->mode);
505 break;
507 case FUSE_READDIR: {
508 struct fuse_read_in *tx = a;
509 fmtprint(fmt, "Readdir nodeid %#llux fh %#llux offset %lld size %ud",
510 hdr->nodeid, tx->fh, tx->offset, tx->size);
511 break;
513 case FUSE_RELEASEDIR: {
514 struct fuse_release_in *tx = a;
515 fmtprint(fmt, "Releasedir nodeid %#llux fh %#llux flags %#ux",
516 hdr->nodeid, tx->fh, tx->flags);
517 break;
519 case FUSE_FSYNCDIR: {
520 struct fuse_fsync_in *tx = a;
521 fmtprint(fmt, "Fsyncdir nodeid %#llux fh %#llux flags %#ux",
522 hdr->nodeid, tx->fh, tx->fsync_flags);
523 break;
525 case FUSE_ACCESS: {
526 struct fuse_access_in *tx = a;
527 fmtprint(fmt, "Access nodeid %#llux mask %#ux",
528 hdr->nodeid, tx->mask);
529 break;
531 case FUSE_CREATE: {
532 struct fuse_open_in *tx = a;
533 fmtprint(fmt, "Create nodeid %#llx flags %#ux mode %#ux name %#q",
534 hdr->nodeid, tx->flags, tx->mode, tx+1);
535 break;
538 }else{ /* "%#G", reqhdr, hdr, arg - use reqhdr only for type */
539 struct fuse_out_header *ohdr = va_arg(fmt->args, void*);
540 void *a = va_arg(fmt->args, void*);
541 int len = ohdr->len - sizeof *ohdr;
542 fmtprint(fmt, "unique %#llux ", ohdr->unique);
543 if(ohdr->error){
544 fmtprint(fmt, "error %d %s", ohdr->error, strerror(-ohdr->error));
545 }else
546 switch(hdr->opcode){
547 default: {
548 fmtprint(fmt, "??? opcode %d", hdr->opcode);
549 break;
551 case FUSE_LOOKUP: {
552 /*
553 * For a negative entry, can send back ENOENT
554 * or rx->ino == 0.
555 * In protocol version 7.4 and before, can only use
556 * the ENOENT method.
557 * Presumably the benefit of sending rx->ino == 0
558 * is that you can specify the length of time to cache
559 * the negative result.
560 */
561 struct fuse_entry_out *rx;
562 fmtprint(fmt, "(Lookup) ");
563 fmt_entry_out:
564 rx = a;
565 fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ",
566 rx->nodeid, rx->generation,
567 rx->entry_valid+rx->entry_valid_nsec*1e-9,
568 rx->attr_valid+rx->attr_valid_nsec*1e-9);
569 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
570 rx->attr.ino, rx->attr.size, rx->attr.blocks,
571 rx->attr.atime+rx->attr.atimensec*1e-9,
572 rx->attr.mtime+rx->attr.mtimensec*1e-9,
573 rx->attr.ctime+rx->attr.ctimensec*1e-9,
574 rx->attr.mode, rx->attr.nlink, rx->attr.uid,
575 rx->attr.gid, rx->attr.rdev);
576 break;
578 case FUSE_FORGET: {
579 /* Can't happen! No reply. */
580 fmtprint(fmt, "(Forget) can't happen");
581 break;
583 case FUSE_GETATTR: {
584 struct fuse_attr_out *rx;
585 fmtprint(fmt, "(Getattr) ");
586 fmt_attr_out:
587 rx = a;
588 fmtprint(fmt, "attr_valid %.20g",
589 rx->attr_valid+rx->attr_valid_nsec*1e-9);
590 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
591 rx->attr.ino, rx->attr.size, rx->attr.blocks,
592 rx->attr.atime+rx->attr.atimensec*1e-9,
593 rx->attr.mtime+rx->attr.mtimensec*1e-9,
594 rx->attr.ctime+rx->attr.ctimensec*1e-9,
595 rx->attr.mode, rx->attr.nlink, rx->attr.uid,
596 rx->attr.gid, rx->attr.rdev);
597 break;
599 case FUSE_SETATTR: {
600 fmtprint(fmt, "(Setattr) ");
601 goto fmt_attr_out;
602 break;
604 case FUSE_READLINK: {
605 fmtprint(fmt, "(Readlink) %#.*q",
606 utfnlen(a, len), a);
607 break;
609 case FUSE_SYMLINK: {
610 fmtprint(fmt, "(Symlink) ");
611 goto fmt_entry_out;
612 break;
614 case FUSE_MKNOD: {
615 fmtprint(fmt, "(Mknod) ");
616 goto fmt_entry_out;
617 break;
619 case FUSE_MKDIR: {
620 fmtprint(fmt, "(Mkdir) ");
621 goto fmt_entry_out;
622 break;
624 case FUSE_UNLINK: {
625 fmtprint(fmt, "(Unlink)");
626 break;
628 case FUSE_RMDIR: {
629 fmtprint(fmt, "(Rmdir)");
630 break;
632 case FUSE_RENAME: {
633 fmtprint(fmt, "(Rename)");
634 break;
636 case FUSE_LINK: {
637 fmtprint(fmt, "(Link) ");
638 goto fmt_entry_out;
639 break;
641 case FUSE_OPEN: {
642 struct fuse_open_out *rx;
643 fmtprint(fmt, "(Open) ");
644 fmt_open_out:
645 rx = a;
646 fmtprint(fmt, "fh %#llux flags %#ux", rx->fh, rx->open_flags);
647 break;
649 case FUSE_READ: {
650 fmtprint(fmt, "(Read) size %d", len);
651 break;
653 case FUSE_WRITE: {
654 struct fuse_write_out *rx = a;
655 fmtprint(fmt, "(Write) size %d", rx->size);
656 break;
658 case FUSE_STATFS: {
659 /*
660 * Before protocol version 7.4, only first 48 bytes are used.
661 */
662 struct fuse_statfs_out *rx = a;
663 fmtprint(fmt, "(Statfs) blocks %lld bfree %lld bavail %lld files %lld ffree %lld bsize %ud namelen %ud frsize %ud",
664 rx->st.blocks, rx->st.bfree, rx->st.bavail,
665 rx->st.files, rx->st.ffree, rx->st.bsize,
666 rx->st.namelen, rx->st.frsize);
667 break;
669 case FUSE_RELEASE: {
670 fmtprint(fmt, "(Release)");
671 break;
673 case FUSE_FSYNC: {
674 fmtprint(fmt, "(Fsync)");
675 break;
677 case FUSE_SETXATTR: {
678 fmtprint(fmt, "(Setxattr)");
679 break;
681 case FUSE_GETXATTR: {
682 fmtprint(fmt, "(Getxattr) size %d", len);
683 break;
685 case FUSE_LISTXATTR: {
686 fmtprint(fmt, "(Lisrxattr) size %d", len);
687 break;
689 case FUSE_REMOVEXATTR: {
690 fmtprint(fmt, "(Removexattr)");
691 break;
693 case FUSE_FLUSH: {
694 fmtprint(fmt, "(Flush)");
695 break;
697 case FUSE_INIT: {
698 struct fuse_init_out *rx = a;
699 fmtprint(fmt, "(Init) major %d minor %d max_write %d",
700 rx->major, rx->minor, rx->max_write);
701 break;
703 case FUSE_OPENDIR: {
704 fmtprint(fmt, "(Opendir) ");
705 goto fmt_open_out;
706 break;
708 case FUSE_READDIR: {
709 fmtprint(fmt, "(Readdir) size %d", len);
710 break;
712 case FUSE_RELEASEDIR: {
713 fmtprint(fmt, "(Releasedir)");
714 break;
716 case FUSE_FSYNCDIR: {
717 fmtprint(fmt, "(Fsyncdir)");
718 break;
720 case FUSE_ACCESS: {
721 fmtprint(fmt, "(Access)");
722 break;
724 case FUSE_CREATE: {
725 struct fuse_create_out *rx = a;
726 fmtprint(fmt, "(Create) ");
727 fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ",
728 rx->e.nodeid, rx->e.generation,
729 rx->e.entry_valid+rx->e.entry_valid_nsec*1e-9,
730 rx->e.attr_valid+rx->e.attr_valid_nsec*1e-9);
731 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
732 rx->e.attr.ino, rx->e.attr.size, rx->e.attr.blocks,
733 rx->e.attr.atime+rx->e.attr.atimensec*1e-9,
734 rx->e.attr.mtime+rx->e.attr.mtimensec*1e-9,
735 rx->e.attr.ctime+rx->e.attr.ctimensec*1e-9,
736 rx->e.attr.mode, rx->e.attr.nlink, rx->e.attr.uid,
737 rx->e.attr.gid, rx->e.attr.rdev);
738 fmtprint(fmt, " fh %#llux flags %#ux", rx->o.fh, rx->o.open_flags);
739 break;
743 return 0;
746 #if defined(__APPLE__)
747 #include <sys/param.h>
748 #include <sys/mount.h>
749 #endif
751 /*
752 * Mounts a fuse file system on mtpt and returns
753 * a file descriptor for the corresponding fuse
754 * message conversation.
755 */
756 int
757 mountfuse(char *mtpt)
759 #if defined(__linux__)
760 int p[2], pid, fd;
761 char buf[20];
763 if(socketpair(AF_UNIX, SOCK_STREAM, 0, p) < 0)
764 return -1;
765 pid = fork();
766 if(pid < 0)
767 return -1;
768 if(pid == 0){
769 close(p[1]);
770 snprint(buf, sizeof buf, "%d", p[0]);
771 putenv("_FUSE_COMMFD", buf);
772 execlp("fusermount", "fusermount", "--", mtpt, nil);
773 fprint(2, "exec fusermount: %r\n");
774 _exit(1);
776 close(p[0]);
777 fd = recvfd(p[1]);
778 close(p[1]);
779 return fd;
780 #elif defined(__FreeBSD__) && !defined(__APPLE__)
781 int pid, fd;
782 char buf[20];
784 if((fd = open("/dev/fuse", ORDWR)) < 0)
785 return -1;
786 snprint(buf, sizeof buf, "%d", fd);
788 pid = fork();
789 if(pid < 0)
790 return -1;
791 if(pid == 0){
792 execlp("mount_fusefs", "mount_fusefs", buf, mtpt, nil);
793 fprint(2, "exec mount_fusefs: %r\n");
794 _exit(1);
796 return fd;
797 #elif defined(__APPLE__)
798 int i, pid, fd, r;
799 char buf[20];
800 struct vfsconf vfs;
801 char *f, *v;
803 if(getvfsbyname(v="osxfusefs", &vfs) < 0 &&
804 getvfsbyname(v="osxfuse", &vfs) < 0 &&
805 getvfsbyname(v="fusefs", &vfs) < 0){
806 if(access((v="osxfusefs", f="/Library/Filesystems/osxfusefs.fs"
807 "/Support/load_osxfusefs"), 0) < 0 &&
808 access((v="osxfuse", f="/Library/Filesystems/osxfuse.fs"
809 "/Contents/Resources/load_osxfuse"), 0) < 0 &&
810 access((v="fusefs", f="/System/Library/Extensions/fusefs.kext"
811 "/Contents/Resources/load_fusefs"), 0) < 0 &&
812 access(f="/Library/Extensions/fusefs.kext"
813 "/Contents/Resources/load_fusefs", 0) < 0 &&
814 access(f="/Library/Filesystems"
815 "/fusefs.fs/Support/load_fusefs", 0) < 0 &&
816 access(f="/System/Library/Filesystems"
817 "/fusefs.fs/Support/load_fusefs", 0) < 0){
818 werrstr("cannot find load_fusefs");
819 return -1;
821 if((r=system(f)) < 0){
822 werrstr("%s: %r", f);
823 return -1;
825 if(r != 0){
826 werrstr("load_fusefs failed: exit %d", r);
827 return -1;
829 if(getvfsbyname(v, &vfs) < 0){
830 werrstr("getvfsbyname %s: %r", v);
831 return -1;
835 /* Look for available FUSE device. */
836 /*
837 * We need to truncate `fs` from the end of the vfs name if
838 * it's present
839 */
840 int len;
841 if (strcmp(v, "osxfuse") == 0) {
842 len = strlen(v);
843 } else {
844 len = strlen(v)-2;
846 for(i=0;; i++){
847 snprint(buf, sizeof buf, "/dev/%.*s%d", len, v, i);
848 if(access(buf, 0) < 0){
849 werrstr("no available fuse devices");
850 return -1;
852 if((fd = open(buf, ORDWR)) >= 0)
853 break;
856 pid = fork();
857 if(pid < 0)
858 return -1;
859 if(pid == 0){
860 snprint(buf, sizeof buf, "%d", fd);
861 /* OSXFUSE >=3.3 changed the name of the environment variable, set both */
862 putenv("MOUNT_FUSEFS_CALL_BY_LIB", "");
863 putenv("MOUNT_OSXFUSE_CALL_BY_LIB", "");
864 /*
865 * Different versions of OSXFUSE and MacFUSE put the
866 * mount_fusefs binary in different places. Try all.
867 */
868 /* OSXFUSE >=3.3 greater location */
869 putenv("MOUNT_OSXFUSE_DAEMON_PATH",
870 "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse");
871 execl("/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
872 "mount_osxfuse", buf, mtpt, nil);
874 /* Lion OSXFUSE location */
875 putenv("MOUNT_FUSEFS_DAEMON_PATH",
876 "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs");
877 execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
878 "mount_osxfusefs", buf, mtpt, nil);
880 /* Leopard location */
881 putenv("MOUNT_FUSEFS_DAEMON_PATH",
882 "/Library/Filesystems/fusefs.fs/Support/mount_fusefs");
883 execl("/Library/Filesystems/fusefs.fs/Support/mount_fusefs",
884 "mount_fusefs", buf, mtpt, nil);
886 /* possible Tiger locations */
887 execl("/System/Library/Filesystems/fusefs.fs/mount_fusefs",
888 "mount_fusefs", buf, mtpt, nil);
889 execl("/System/Library/Filesystems/fusefs.fs/Support/mount_fusefs",
890 "mount_fusefs", buf, mtpt, nil);
891 fprint(2, "exec mount_fusefs: %r\n");
892 _exit(1);
894 return fd;
896 #else
897 werrstr("cannot mount fuse on this system");
898 return -1;
899 #endif
902 void
903 waitfuse(void)
905 waitpid();
908 void
909 unmountfuse(char *mtpt)
911 int pid;
913 pid = fork();
914 if(pid < 0)
915 return;
916 if(pid == 0){
917 #if defined(__linux__)
918 execlp("fusermount", "fusermount", "-u", "-z", "--", mtpt, nil);
919 fprint(2, "exec fusermount -u: %r\n");
920 #else
921 execlp("umount", "umount", mtpt, nil);
922 fprint(2, "exec umount: %r\n");
923 #endif
924 _exit(1);
926 waitpid();