/core/10.5/fusefs/mount/mount_fusefs.c
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}