PageRenderTime 63ms CodeModel.GetById 13ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 1ms

/core/10.5/fusefs/mount/mount_fusefs.c

http://macfuse.googlecode.com/
C | 969 lines | 783 code | 151 blank | 35 comment | 136 complexity | 554e3a44cbd195239235f7f8c0faeabc MD5 | raw file
  1/*
  2 * Copyright (C) 2006-2008 Google. All Rights Reserved.
  3 * Amit Singh <singh@>
  4 */
  5
  6#include <err.h>
  7#include <libgen.h>
  8#include <sysexits.h>
  9#include <paths.h>
 10#include <assert.h>
 11#include <errno.h>
 12#include <string.h>
 13#include <stdio.h>
 14#include <stddef.h>
 15#include <stdlib.h>
 16#include <fcntl.h>
 17#include <getopt.h>
 18#include <stdbool.h>
 19#include <sys/attr.h>
 20#include <sys/mount.h>
 21#include <sys/stat.h>
 22#include <sys/statvfs.h>
 23#include <sys/types.h>
 24#include <sys/sysctl.h>
 25#include <sys/vnode.h>
 26#include <libgen.h>
 27#include <signal.h>
 28#include <mach/mach.h>
 29
 30#include "mntopts.h"
 31#include <fuse_ioctl.h>
 32#include <fuse_mount.h>
 33#include <fuse_param.h>
 34#include <fuse_version.h>
 35
 36#include <fsproperties.h>
 37#include <CoreFoundation/CoreFoundation.h>
 38
 39#define PROGNAME "mount_" MACFUSE_FS_TYPE
 40
 41static int signal_idx = -1;
 42static int signal_fd  = -1;
 43
 44void  showhelp(void);
 45void  showversion(int doexit);
 46
 47struct mntopt mopts[] = {
 48    MOPT_STDOPTS,
 49    MOPT_UPDATE,
 50    { "allow_other",         0, FUSE_MOPT_ALLOW_OTHER,            1 }, // kused
 51    { "allow_recursion",     0, FUSE_MOPT_ALLOW_RECURSION,        1 }, // uused
 52    { "allow_root",          0, FUSE_MOPT_ALLOW_ROOT,             1 }, // kused
 53    { "auto_cache",          0, FUSE_MOPT_AUTO_CACHE,             1 }, // kused
 54    { "auto_xattr",          0, FUSE_MOPT_AUTO_XATTR,             1 }, // kused
 55    { "blocksize=",          0, FUSE_MOPT_BLOCKSIZE,              1 }, // kused
 56    { "daemon_timeout=",     0, FUSE_MOPT_DAEMON_TIMEOUT,         1 }, // kused
 57    { "debug",               0, FUSE_MOPT_DEBUG,                  1 }, // kused
 58    { "default_permissions", 0, FUSE_MOPT_DEFAULT_PERMISSIONS,    1 }, // kused
 59    { "defer_permissions",   0, FUSE_MOPT_DEFER_PERMISSIONS,      1 }, // kused
 60    { "direct_io",           0, FUSE_MOPT_DIRECT_IO,              1 }, // kused
 61    { "extended_security",   0, FUSE_MOPT_EXTENDED_SECURITY,      1 }, // kused
 62    { "fsid=" ,              0, FUSE_MOPT_FSID,                   1 }, // kused
 63    { "fsname=",             0, FUSE_MOPT_FSNAME,                 1 }, // kused
 64    { "fssubtype=",          0, FUSE_MOPT_FSSUBTYPE,              1 }, // kused
 65    { "fstypename=",         0, FUSE_MOPT_FSTYPENAME,             1 }, // kused
 66    { "init_timeout=",       0, FUSE_MOPT_INIT_TIMEOUT,           1 }, // kused
 67    { "iosize=",             0, FUSE_MOPT_IOSIZE,                 1 }, // kused
 68    { "jail_symlinks",       0, FUSE_MOPT_JAIL_SYMLINKS,          1 }, // kused
 69    { "kill_on_unmount",     0, FUSE_MOPT_KILL_ON_UNMOUNT,        1 }, // kused 
 70    { "local",               0, FUSE_MOPT_LOCALVOL,               1 }, // kused
 71    { "native_xattr",        0, FUSE_MOPT_NATIVE_XATTR,           1 }, // kused
 72    { "negative_vncache",    0, FUSE_MOPT_NEGATIVE_VNCACHE,       1 }, // kused
 73    { "sparse",              0, FUSE_MOPT_SPARSE,                 1 }, // kused
 74    { "use_ino",             0, FUSE_MOPT_USE_INO,                1 },
 75    { "volname=",            0, FUSE_MOPT_VOLNAME,                1 }, // kused
 76
 77    /* negative ones */
 78
 79    { "alerts",              1, FUSE_MOPT_NO_ALERTS,              1 }, // kused
 80    { "appledouble",         1, FUSE_MOPT_NO_APPLEDOUBLE,         1 }, // kused
 81    { "applexattr",          1, FUSE_MOPT_NO_APPLEXATTR,          1 }, // kused
 82    { "attrcache",           1, FUSE_MOPT_NO_ATTRCACHE,           1 }, // kused
 83    { "browse",              1, FUSE_MOPT_NO_BROWSE,              1 }, // kused
 84    { "localcaches",         1, FUSE_MOPT_NO_LOCALCACHES,         1 }, // kused
 85    { "readahead",           1, FUSE_MOPT_NO_READAHEAD,           1 }, // kused
 86    { "synconclose",         1, FUSE_MOPT_NO_SYNCONCLOSE,         1 }, // kused
 87    { "syncwrites",          1, FUSE_MOPT_NO_SYNCWRITES,          1 }, // kused
 88    { "ubc",                 1, FUSE_MOPT_NO_UBC,                 1 }, // kused
 89    { "vncache",             1, FUSE_MOPT_NO_VNCACHE,             1 }, // kused
 90
 91    { NULL }
 92};
 93
 94typedef int (* converter_t)(void **target, void *value, void *fallback);
 95
 96struct mntval {
 97    uint64_t    mv_mntflag;
 98    void       *mv_value;
 99    size_t      mv_len;
100    converter_t mv_converter;
101    void       *mv_fallback;
102    void      **mv_target;
103    char       *mv_errstr;
104};
105
106static __inline__ int
107fuse_to_string(void **target, void *value, void *fallback)
108{
109    if (!value) {
110        // think about what to do if we want to set a NULL value when the
111        // fallback value is non-NULL
112        value = fallback;
113    }
114
115    *target = value;
116
117    return 0;
118}
119
120static __inline__ int
121fuse_to_uint32(void **target, void *value, void *fallback)
122{
123    unsigned long u;
124
125    if (!value) {
126        *target = fallback;
127        return 0;
128    }
129
130    errno = 0;
131    u = strtoul((char *)value, NULL, 10);
132    if ((errno == ERANGE) || (errno == EINVAL)) {
133        *target = fallback;
134        return errno;
135    }
136
137    *target = (void *)u;
138
139    return 0;
140}
141
142static __inline__ int
143fuse_to_fsid(void **target, void *value, void *fallback)
144{
145    int ret;
146    uint32_t u;
147
148    if (!value) {
149        *target = fallback;
150        return 0;
151    }
152
153    ret = fuse_to_uint32(target, value, fallback);
154
155    if (ret) {
156        return ret;
157    }
158
159    u = *(uint32_t *)target;
160
161    if ((u & ~FUSE_MINOR_MASK) || (u == 0)) {
162        return EINVAL;
163    }
164
165    return 0;
166}
167
168static uint32_t
169fsbundle_find_fssubtype(const char *bundle_path_C,
170                        const char *claimed_name_C,
171                        uint32_t    claimed_fssubtype)
172{
173    uint32_t result = FUSE_FSSUBTYPE_UNKNOWN;
174
175    CFStringRef bundle_path_string  = NULL;
176    CFStringRef claimed_name_string = NULL;
177
178    CFURLRef    bundleURL = NULL;
179    CFBundleRef bundleRef = NULL;
180
181    CFDictionaryRef fspersonalities = NULL;
182
183    CFIndex idx   = 0;
184    CFIndex count = 0;
185    Boolean found = false;
186
187    CFStringRef     *keys     = NULL;
188    CFDictionaryRef *subdicts = NULL;
189
190    bundle_path_string = CFStringCreateWithCString(kCFAllocatorDefault,
191                                                   bundle_path_C,
192                                                   kCFStringEncodingUTF8);
193    if (!bundle_path_string) {
194        goto out;
195    }
196
197    bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
198                                              bundle_path_string,
199                                              kCFURLPOSIXPathStyle,
200                                              true);
201    if (!bundleURL) {
202        goto out;
203    }
204
205    bundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL);
206    if (!bundleRef) {
207        goto out;
208    }
209
210    fspersonalities = CFBundleGetValueForInfoDictionaryKey(
211                          bundleRef, CFSTR(kFSPersonalitiesKey));
212    if (!fspersonalities) {
213        goto out;
214    }
215
216    count = CFDictionaryGetCount(fspersonalities);
217    if (count <= 0) {
218        goto out;
219    }
220
221    keys = (CFStringRef *)malloc(count * sizeof(CFStringRef));
222    subdicts = (CFDictionaryRef *)malloc(count * sizeof(CFDictionaryRef));
223
224    if (!keys || !subdicts) {
225        goto out;
226    }
227
228    CFDictionaryGetKeysAndValues(fspersonalities,
229                                 (const void **)keys,
230                                 (const void **)subdicts);
231
232    if (claimed_fssubtype == (uint32_t)FUSE_FSSUBTYPE_INVALID) {
233        goto lookupbyfsname;
234    }
235
236    for (idx = 0; idx < count; idx++) {
237        CFNumberRef n = NULL;
238        uint32_t candidate_fssubtype = (uint32_t)FUSE_FSSUBTYPE_INVALID;
239        if (CFDictionaryGetValueIfPresent(subdicts[idx],
240                                          (const void *)CFSTR(kFSSubTypeKey),
241                                          (const void **)&n)) {
242            if (CFNumberGetValue(n, kCFNumberIntType, &candidate_fssubtype)) {
243                if (candidate_fssubtype == claimed_fssubtype) {
244                    found = true;
245                    result = candidate_fssubtype;
246                    break;
247                }
248            }
249        }
250    }
251
252    if (found) {
253        goto out;
254    }
255
256lookupbyfsname:
257
258    claimed_name_string = CFStringCreateWithCString(kCFAllocatorDefault,
259                                                    claimed_name_C,
260                                                    kCFStringEncodingUTF8);
261    if (!claimed_name_string) {
262        goto out;
263    }
264
265    for (idx = 0; idx < count; idx++) {
266        CFRange where = CFStringFind(claimed_name_string, keys[idx],
267                                     kCFCompareCaseInsensitive);
268        if (where.location != kCFNotFound) {
269            found = true;
270        }
271        if (found) {
272            CFNumberRef n = NULL;
273            uint32_t candidate_fssubtype = (uint32_t)FUSE_FSSUBTYPE_INVALID;
274            if (CFDictionaryGetValueIfPresent(
275                    subdicts[idx], (const void *)CFSTR(kFSSubTypeKey),
276                    (const void **)&n)) {
277                if (CFNumberGetValue(n, kCFNumberIntType,
278                                     &candidate_fssubtype)) {
279                    result = candidate_fssubtype;
280                }
281            }
282            break;
283        }
284    }
285
286out:
287    if (keys) {
288        free(keys);
289    }
290
291    if (subdicts) {
292        free(subdicts);
293    }
294
295    if (bundle_path_string) {
296        CFRelease(bundle_path_string);
297    }
298
299    if (bundleURL) {
300        CFRelease(bundleURL);
301    }
302
303    if (claimed_name_string) {
304        CFRelease(claimed_name_string);
305    }
306
307    if (bundleRef) {
308        CFRelease(bundleRef);
309    }
310
311    return result;
312}
313
314static __inline__ int
315fuse_to_fssubtype(void **target, void *value, void *fallback)
316{
317    char *name = getenv("MOUNT_FUSEFS_DAEMON_PATH");
318
319    *(uint32_t *)target = (uint32_t)FUSE_FSSUBTYPE_INVALID;
320
321    if (value) {
322        int ret = fuse_to_uint32(target, value, fallback);
323        if (ret) {
324            *(uint32_t *)target = (uint32_t)FUSE_FSSUBTYPE_INVALID;
325        }
326    }
327
328    *(uint32_t *)target = fsbundle_find_fssubtype(MACFUSE_BUNDLE_PATH,
329                                                  name, *(uint32_t *)target);
330
331    return 0;
332}
333
334static uint32_t  blocksize      = FUSE_DEFAULT_BLOCKSIZE;
335static uint32_t  daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
336static uint32_t  fsid           = 0;
337static char     *fsname         = NULL;
338static uint32_t  fssubtype      = 0;
339static char     *fstypename     = NULL;
340static uint32_t  init_timeout   = FUSE_DEFAULT_INIT_TIMEOUT;
341static uint32_t  iosize         = FUSE_DEFAULT_IOSIZE;
342static uint32_t  drandom        = 0;
343static char     *volname        = NULL;
344
345struct mntval mvals[] = {
346    {
347        FUSE_MOPT_BLOCKSIZE,
348        NULL,
349        0,
350        fuse_to_uint32,
351        (void *)FUSE_DEFAULT_BLOCKSIZE,
352        (void **)&blocksize,
353        "invalid value for argument blocksize"
354    },
355    {
356        FUSE_MOPT_DAEMON_TIMEOUT,
357        NULL,
358        0,
359        fuse_to_uint32,
360        (void *)FUSE_DEFAULT_DAEMON_TIMEOUT,
361        (void **)&daemon_timeout,
362        "invalid value for argument daemon_timeout"
363    },
364    {
365        FUSE_MOPT_FSID,
366        NULL,
367        0,
368        fuse_to_fsid,
369        0,
370        (void **)&fsid,
371        "invalid value for argument fsid (must be 0 < fsid < 0xFFFFFF)"
372    },
373    {
374        FUSE_MOPT_FSNAME,
375        NULL,
376        0,
377        fuse_to_string,
378        NULL,
379        (void **)&fsname,
380        "invalid value for argument fsname"
381    },
382    {
383        FUSE_MOPT_INIT_TIMEOUT,
384        NULL,
385        0,
386        fuse_to_uint32,
387        (void *)FUSE_DEFAULT_INIT_TIMEOUT,
388        (void **)&init_timeout,
389        "invalid value for argument init_timeout"
390    },
391    {
392        FUSE_MOPT_IOSIZE,
393        NULL,
394        0,
395        fuse_to_uint32,
396        (void *)FUSE_DEFAULT_IOSIZE,
397        (void **)&iosize,
398        "invalid value for argument iosize"
399    },
400    {
401        FUSE_MOPT_FSSUBTYPE,
402        NULL,
403        0,
404        fuse_to_fssubtype,
405        NULL,
406        (void **)&fssubtype,
407        "invalid value for argument fssubtype"
408    },
409    {
410        FUSE_MOPT_FSTYPENAME,
411        NULL,
412        0,
413        fuse_to_string,
414        NULL,
415        (void **)&fstypename,
416        "invalid value for argument fstypename"
417    },
418    {
419        FUSE_MOPT_VOLNAME,
420        NULL,
421        0,
422        fuse_to_string,
423        NULL,
424        (void **)&volname,
425        "invalid value for argument volname"
426    },
427    {
428        0, NULL, 0, NULL, (void *)NULL, (void **)NULL, (char *)NULL
429    },
430};
431
432static void
433fuse_process_mvals(void)
434{
435    int ret;
436    struct mntval *mv;
437
438    for (mv = mvals; mv->mv_mntflag; mv++) {
439        ret = mv->mv_converter(mv->mv_target, mv->mv_value, mv->mv_fallback);
440        if (ret) {
441            errx(EX_USAGE, "%s", mv->mv_errstr);
442        }
443    }
444}
445
446static int
447post_notification(char   *name,
448                  char   *udata_keys[],
449                  char   *udata_values[],
450                  CFIndex nf_num)
451{
452    CFIndex i;
453    CFStringRef nf_name   = NULL;
454    CFStringRef nf_object = NULL;
455    CFMutableDictionaryRef nf_udata  = NULL;
456
457    CFNotificationCenterRef distributedCenter;
458    CFStringEncoding encoding = kCFStringEncodingUTF8;
459
460    distributedCenter = CFNotificationCenterGetDistributedCenter();
461
462    if (!distributedCenter) {
463        return -1;
464    }
465
466    nf_name = CFStringCreateWithCString(kCFAllocatorDefault, name, encoding);
467      
468    nf_object = CFStringCreateWithCString(kCFAllocatorDefault,
469                                          FUSE_UNOTIFICATIONS_OBJECT,
470                                          encoding);
471 
472    nf_udata = CFDictionaryCreateMutable(kCFAllocatorDefault,
473                                         nf_num,
474                                         &kCFCopyStringDictionaryKeyCallBacks,
475                                         &kCFTypeDictionaryValueCallBacks);
476
477    if (!nf_name || !nf_object || !nf_udata) {
478        goto out;
479    }
480
481    for (i = 0; i < nf_num; i++) {
482        CFStringRef a_key = CFStringCreateWithCString(kCFAllocatorDefault,
483                                                      udata_keys[i],
484                                                      kCFStringEncodingUTF8);
485        CFStringRef a_value = CFStringCreateWithCString(kCFAllocatorDefault,
486                                                        udata_values[i],
487                                                        kCFStringEncodingUTF8);
488        CFDictionarySetValue(nf_udata, a_key, a_value);
489        CFRelease(a_key);
490        CFRelease(a_value);
491    }
492
493    CFNotificationCenterPostNotification(distributedCenter,
494                                         nf_name, nf_object, nf_udata, false);
495
496out:
497    if (nf_name) {
498        CFRelease(nf_name);
499    }
500
501    if (nf_object) {
502        CFRelease(nf_object);
503    }
504
505    if (nf_udata) {
506        CFRelease(nf_udata);
507    }
508
509    return 0;
510}
511
512static int
513check_kext_status(void)
514{
515    int    result = -1;
516    char   version[MAXHOSTNAMELEN + 1] = { 0 };
517    size_t version_len = MAXHOSTNAMELEN;
518    size_t version_len_desired = 0;
519    struct vfsconf vfc = { 0 };
520
521    result = getvfsbyname(MACFUSE_FS_TYPE, &vfc);
522    if (result) { /* MacFUSE is not already loaded */
523        return ESRCH;
524    }
525
526    /* some version of MacFUSE is already loaded; let us check it out */
527
528    result = sysctlbyname(SYSCTL_MACFUSE_VERSION_NUMBER, version,
529                          &version_len, (void *)NULL, (size_t)0);
530    if (result) {
531        return result;
532    }
533
534    /* sysctlbyname() includes the trailing '\0' in version_len */
535    version_len_desired = strlen(MACFUSE_VERSION) + 1;
536
537    if ((version_len != version_len_desired) ||
538        strncmp(MACFUSE_VERSION, version, version_len)) {
539        return EINVAL;
540    }
541
542    /* What's currently loaded is good */
543
544    return 0;
545}
546
547static void
548signal_idx_atexit_handler(void)
549{
550    if (signal_idx != -1) {
551
552        (void)ioctl(signal_fd, FUSEDEVIOCSETDAEMONDEAD, &signal_fd);
553
554        /*
555         * Originally, I did kill_fs from here.
556         *
557         * int32_t kill_fs_old = 0;
558         * int32_t kill_fs_new = signal_idx;
559         * size_t oldlen = sizeof(kill_fs_old);
560         * size_t newlen = sizeof(kill_fs_new);
561         *
562         * (void)sysctlbyname("macfuse.control.kill_fs", (void *)&kill_fs_old,
563         *                    &oldlen, (void *)&kill_fs_new, newlen);
564         */
565    }
566}
567
568// We will be called as follows by the FUSE library:
569//
570//   mount_<MACFUSE_FS_TYPE> -o OPTIONS... <fdnam> <mountpoint>
571
572int
573main(int argc, char **argv)
574{
575    int       result    = -1;
576    int       mntflags  = 0;
577    int       fd        = -1;
578    int32_t   dindex    = -1;
579    char     *fdnam     = NULL;
580    uint64_t  altflags  = 0ULL;
581    char     *mntpath   = NULL;
582
583    int i, ch = '\0', done = 0;
584    struct mntopt *mo;
585    struct mntval *mv;
586    struct statfs statfsb;
587    fuse_mount_args args;
588
589    if (!getenv("MOUNT_FUSEFS_CALL_BY_LIB")) {
590        showhelp();
591        /* NOTREACHED */
592    }
593
594    /* Kludge to make "<fsdaemon> --version" happy. */
595    if ((argc == 2) &&
596        ((!strncmp(argv[1], "--version", strlen("--version"))) ||
597         (!strncmp(argv[1], "-v", strlen("-v"))))) {
598        showversion(1);
599    }
600
601    /* Kludge to make "<fsdaemon> --help" happy. */
602    if ((argc == 2) &&
603        ((!strncmp(argv[1], "--help", strlen("--help"))) ||
604         (!strncmp(argv[1], "-h", strlen("-h"))))) {
605        showhelp();
606    }
607
608    memset((void *)&args, 0, sizeof(args));
609
610    do {
611        for (i = 0; i < 3; i++) {
612            if (optind < argc && argv[optind][0] != '-') {
613                if (mntpath) {
614                    done = 1;
615                    break;
616                }
617                if (fdnam)
618                    mntpath = argv[optind];
619                else
620                    fdnam = argv[optind];
621                optind++;
622            }
623        }
624
625        switch(ch) {
626        case 'o':
627            getmntopts(optarg, mopts, &mntflags, &altflags);
628            for (mv = mvals; mv->mv_mntflag; ++mv) {
629                if (!(altflags & mv->mv_mntflag)) {
630                    continue;
631                }
632                for (mo = mopts; mo->m_option; ++mo) {
633                    char *p, *q;
634                    if (mo->m_flag != mv->mv_mntflag) {
635                        continue;
636                    }
637                    p = strstr(optarg, mo->m_option);
638                    if (p) {
639                        p += strlen(mo->m_option);
640                        q = p;
641                        while (*q != '\0' && *q != ',') {
642                            q++;
643                        }
644                        mv->mv_len = q - p + 1;
645                        mv->mv_value = malloc(mv->mv_len);
646                        memcpy(mv->mv_value, p, mv->mv_len - 1);
647                        ((char *)mv->mv_value)[mv->mv_len - 1] = '\0';
648                        break;
649                    }
650                }
651            }
652            break;
653
654        case '\0':
655            break;
656
657        case 'v': 
658            showversion(1);
659            break;
660
661        case '?':
662        case 'h':
663        default:
664            showhelp();
665            break;
666        }
667
668        if (done) {
669            break;
670        }
671
672    } while ((ch = getopt(argc, argv, "ho:v")) != -1);
673
674    argc -= optind;
675    argv += optind;
676
677    if ((!fdnam) && argc > 0) {
678        fdnam = *argv++;
679        argc--;
680    }
681
682    if (!fdnam) {
683        errx(EX_USAGE, "missing MacFUSE device file descriptor");
684    }
685
686    errno = 0;
687    fd = (int)strtol(fdnam, NULL, 10);
688    if ((errno == EINVAL) || (errno == ERANGE)) {
689        errx(EX_USAGE,
690             "invalid name (%s) for MacFUSE device file descriptor", fdnam);
691    }
692
693    signal_fd = fd;
694
695    {
696        char  ndev[MAXPATHLEN];
697        char *ndevbas;
698        struct stat sb;
699
700        if (fstat(fd, &sb) == -1) {
701            err(EX_OSERR, "fstat failed for MacFUSE device file descriptor");
702        }
703        args.rdev = sb.st_rdev;
704        (void)strlcpy(ndev, _PATH_DEV, sizeof(ndev));
705        ndevbas = ndev + strlen(_PATH_DEV);
706        devname_r(sb.st_rdev, S_IFCHR, ndevbas,
707                  (int)(sizeof(ndev) - strlen(_PATH_DEV)));
708
709        if (strncmp(ndevbas, MACFUSE_DEVICE_BASENAME,
710                    strlen(MACFUSE_DEVICE_BASENAME))) {
711            errx(EX_USAGE, "mounting inappropriate device");
712        }
713
714        errno = 0;
715        dindex = (int)strtol(ndevbas + strlen(MACFUSE_DEVICE_BASENAME),
716                             NULL, 10);
717        if ((errno == EINVAL) || (errno == ERANGE) ||
718            (dindex < 0) || (dindex > MACFUSE_NDEVICES)) {
719            errx(EX_USAGE, "invalid MacFUSE device unit (#%d)\n", dindex);
720        }
721    }
722
723    signal_idx = dindex;
724
725    atexit(signal_idx_atexit_handler);
726
727    result = check_kext_status();
728
729    switch (result) {
730
731    case 0:
732        break;
733
734    case ESRCH:
735        errx(EX_UNAVAILABLE, "the MacFUSE kernel extension is not loaded");
736        break;
737
738    case EINVAL:
739        errx(EX_UNAVAILABLE,
740             "the loaded MacFUSE kernel extension has a mismatched version");
741        break;
742
743    default:
744        errx(EX_UNAVAILABLE,
745             "failed to query the loaded MacFUSE kernel extension (%d)",
746             result);
747        break;
748    }
749
750    if ((!mntpath) && argc > 0) {
751        mntpath = *argv++;
752        argc--;
753    }
754
755    if (!mntpath) {
756        errx(EX_USAGE, "missing mount point");
757    }
758
759    (void)checkpath(mntpath, args.mntpath);
760
761    mntpath = args.mntpath;
762
763    fuse_process_mvals();
764
765    if (statfs(mntpath, &statfsb)) {
766        errx(EX_OSFILE, "cannot stat the mount point %s", mntpath);
767    }
768
769    if ((strlen(statfsb.f_fstypename) == strlen(MACFUSE_FS_TYPE)) &&
770        (strcmp(statfsb.f_fstypename, MACFUSE_FS_TYPE) == 0)) {
771        if (!(altflags & FUSE_MOPT_ALLOW_RECURSION)) {
772            errx(EX_USAGE,
773                 "mount point %s is itself on a MacFUSE volume", mntpath);
774        }
775    } if (strncmp(statfsb.f_fstypename, FUSE_FSTYPENAME_PREFIX,
776                  strlen(FUSE_FSTYPENAME_PREFIX)) == 0) {
777        if (!(altflags & FUSE_MOPT_ALLOW_RECURSION)) {
778            errx(EX_USAGE,
779                 "mount point %s is itself on a MacFUSE volume", mntpath);
780        }
781    }
782
783    /* allow_root and allow_other checks are done in the kernel. */
784
785    if (altflags & FUSE_MOPT_NO_LOCALCACHES) {
786        altflags |= FUSE_MOPT_NO_ATTRCACHE;
787        altflags |= FUSE_MOPT_NO_READAHEAD;
788        altflags |= FUSE_MOPT_NO_UBC;
789        altflags |= FUSE_MOPT_NO_VNCACHE;
790    }
791
792    if ((altflags & FUSE_MOPT_NEGATIVE_VNCACHE) &&
793        (altflags & FUSE_MOPT_NO_VNCACHE)) {
794        errx(EX_USAGE, "'negative_vncache' can't be used with 'novncache'");
795    }
796
797    /*
798     * 'nosyncwrites' must not appear with either 'noubc' or 'noreadahead'.
799     */
800    if ((altflags & FUSE_MOPT_NO_SYNCWRITES) &&
801        (altflags & (FUSE_MOPT_NO_UBC | FUSE_MOPT_NO_READAHEAD))) {
802        errx(EX_USAGE,
803             "disabling local caching can't be used with 'nosyncwrites'");
804    }
805
806    /*
807     * 'nosynconclose' only allowed if 'nosyncwrites' is also there.
808     */
809    if ((altflags & FUSE_MOPT_NO_SYNCONCLOSE) &&
810        !(altflags & FUSE_MOPT_NO_SYNCWRITES)) {
811        errx(EX_USAGE, "the 'nosynconclose' option requires 'nosyncwrites'");
812    }
813
814    if ((altflags & FUSE_MOPT_DEFAULT_PERMISSIONS) &&
815        (altflags & FUSE_MOPT_DEFER_PERMISSIONS)) {
816        errx(EX_USAGE,
817             "'default_permissions' can't be used with 'defer_permissions'");
818    }
819
820    if ((altflags & FUSE_MOPT_AUTO_XATTR) &&
821        (altflags & FUSE_MOPT_NATIVE_XATTR)) {
822        errx(EX_USAGE,
823             "'auto_xattr' can't be used with 'native_xattr'");
824    }
825
826    if (getenv("MOUNT_FUSEFS_NO_ALERTS")) {
827        altflags |= FUSE_MOPT_NO_ALERTS;
828    }
829
830    if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT) {
831        daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
832    }
833
834    if (daemon_timeout > FUSE_MAX_DAEMON_TIMEOUT) {
835        daemon_timeout = FUSE_MAX_DAEMON_TIMEOUT;
836    }
837
838    if (init_timeout < FUSE_MIN_INIT_TIMEOUT) {
839        init_timeout = FUSE_MIN_INIT_TIMEOUT;
840    }
841
842    if (init_timeout > FUSE_MAX_INIT_TIMEOUT) {
843        init_timeout = FUSE_MAX_INIT_TIMEOUT;
844    }
845
846    result = ioctl(fd, FUSEDEVIOCGETRANDOM, &drandom);
847    if (result) {
848        errx(EX_UNAVAILABLE, "failed to negotiate with /dev/fuse%d", dindex);
849    }
850
851    args.altflags       = altflags;
852    args.blocksize      = blocksize;
853    args.daemon_timeout = daemon_timeout;
854    args.fsid           = fsid;
855    args.fssubtype      = fssubtype;
856    args.init_timeout   = init_timeout;
857    args.iosize         = iosize;
858    args.random         = drandom;
859
860    char *daemon_name = NULL;
861    char *daemon_path = getenv("MOUNT_FUSEFS_DAEMON_PATH");
862    if (daemon_path) {
863        daemon_name = basename(daemon_path);
864    }
865
866    if (!fsname) {
867        if (daemon_name) {
868            snprintf(args.fsname, MAXPATHLEN, "%s@fuse%d", daemon_name, dindex);
869        } else {
870            snprintf(args.fsname, MAXPATHLEN, "instance@fuse%d", dindex);
871        }
872    } else {
873        snprintf(args.fsname, MAXPATHLEN, "%s", fsname);
874    }
875
876    if (fstypename) {
877        if (strlen(fstypename) > FUSE_FSTYPENAME_MAXLEN) {
878            errx(EX_USAGE, "fstypename can be at most %d characters",
879                 FUSE_FSTYPENAME_MAXLEN);
880        } else {
881            snprintf(args.fstypename, MFSTYPENAMELEN, "%s", fstypename);
882        }
883    }
884
885    if (!volname) {
886        if (daemon_name) {
887            snprintf(args.volname, MAXPATHLEN, "MacFUSE Volume %d (%s)",
888                     dindex, daemon_name);
889        } else {
890            snprintf(args.volname, MAXPATHLEN, "MacFUSE Volume %d", dindex);
891        }
892    } else {
893        snprintf(args.volname, MAXPATHLEN, "%s", volname);
894    }
895
896    /* Finally! */
897    result = mount(MACFUSE_FS_TYPE, mntpath, mntflags, (void *)&args);
898
899    if (result < 0) {
900        err(EX_OSERR, "failed to mount %s@/dev/fuse%d", mntpath, dindex);
901    } else {
902        char *udata_keys[]   = { kFUSEMountPathKey };
903        char *udata_values[] = { mntpath };
904           
905        post_notification(FUSE_UNOTIFICATIONS_NOTIFY_MOUNTED,
906                          udata_keys, udata_values, 1);
907    }
908
909    signal_idx = -1;
910
911    exit(0);
912}
913
914void
915showhelp()
916{
917    if (!getenv("MOUNT_FUSEFS_CALL_BY_LIB")) {
918        showversion(0);
919        fprintf(stderr, "\nThis program is not meant to be called directly. The MacFUSE library calls it.\n");
920    }
921    fprintf(stderr, "\nAvailable mount options:\n");
922    fprintf(stderr,
923      "    -o allow_other         allow access to others besides the user who mounted\n"
924      "                           the file system\n"
925      "    -o allow_recursion     allow a mount point that itself resides on a MacFUSE\n"
926      "                           volume (by default, such mounting is disallowed)\n"
927      "    -o allow_root          allow access to root (can't be used with allow_other)\n"
928      "    -o auto_xattr          handle extended attributes entirely through ._ files\n"
929      "    -o blocksize=<size>    specify block size in bytes of \"storage\"\n"
930      "    -o daemon_timeout=<s>  timeout in seconds for kernel calls to daemon\n"
931      "    -o debug               turn on debug information printing\n"
932      "    -o default_permissions let the kernel handle permission checks locally\n"
933      "    -o defer_permissions   defer permission checks to file operations themselves\n"
934      "    -o direct_io           use alternative (direct) path for kernel-user I/O\n"
935      "    -o extended_security   turn on Mac OS X extended security (ACLs)\n"
936      "    -o fsid=<fsid>         set the second 32-bit component of the fsid\n"
937      "    -o fsname=<name>       set the file system's name\n"
938      "    -o fssubtype=<num>     set the file system's fssubtype identifier\n"
939      "    -o fstypename=<name>   set the file system's type name\n"
940      "    -o iosize=<size>       specify maximum I/O size in bytes\n" 
941      "    -o jail_symlinks       contain symbolic links within the mount\n"
942      "    -o kill_on_unmount     kernel will send a signal (SIGKILL by default) to the\n                           daemon after unmount finishes\n" 
943      "    -o local               mark the volume as \"local\" (default is \"nonlocal\")\n"
944      "    -o negative_vncache    enable vnode name caching of non-existent objects\n"
945      "    -o sparse              enable support for sparse files\n"
946      "    -o volname=<name>      set the file system's volume name\n"      
947      "\nAvailable negative mount options:\n"
948      "    -o noalerts            disable all graphical alerts (if any) in MacFUSE Core\n"
949      "    -o noappledouble       ignore Apple Double (._) and .DS_Store files entirely\n"
950      "    -o noapplexattr        ignore all \"com.apple.*\" extended attributes\n"
951      "    -o nobrowse            mark the volume as non-browsable by the Finder\n"
952      "    -o nolocalcaches       meta option equivalent to noreadahead,noubc,novncache\n"
953      "    -o noreadahead         disable I/O read-ahead behavior for this file system\n"
954      "    -o nosynconclose       disable sync-on-close behavior (enabled by default)\n"
955      "    -o nosyncwrites        disable synchronous-writes behavior (dangerous)\n"
956      "    -o noubc               disable the unified buffer cache for this file system\n"
957      "    -o novncache           disable the vnode name cache for this file system\n"
958    );
959    exit(EX_USAGE);
960}
961
962void
963showversion(int doexit)
964{
965    fprintf(stderr, "MacFUSE mount version %s\n", MACFUSE_VERSION);
966    if (doexit) {
967        exit(EX_USAGE);
968    }
969}