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

http://macfuse.googlecode.com/ · C · 969 lines · 783 code · 151 blank · 35 comment · 137 complexity · 554e3a44cbd195239235f7f8c0faeabc MD5 · raw file

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