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