1 /*
2 * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #if defined(HAVE_MLOCKALL) && defined(RLIMIT_MEMLOCK) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
26 # define MFS_USE_MEMLOCK 1
27 #endif
28
29 #if defined(HAVE_MALLOC_H)
30 # include <malloc.h>
31 #endif
32 #if defined(M_ARENA_MAX) && defined(M_ARENA_TEST) && defined(HAVE_MALLOPT)
33 # define MFS_USE_MALLOPT 1
34 #endif
35
36 #include <fuse.h>
37 #include <fuse_opt.h>
38 #include <fuse_lowlevel.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #ifdef MFS_USE_MEMLOCK
42 # include <sys/mman.h>
43 #endif
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <stddef.h>
51 #include <unistd.h>
52 #include <syslog.h>
53 #include <signal.h>
54 #include <errno.h>
55 #include <pthread.h>
56
57 #include "mfs_fuse.h"
58 #include "mfs_meta_fuse.h"
59
60 #include "MFSCommunication.h"
61 #include "clocks.h"
62 #include "massert.h"
63 #include "portable.h"
64 #include "md5.h"
65 #include "mastercomm.h"
66 #include "masterproxy.h"
67 #include "chunkloccache.h"
68 #include "sustained_inodes.h"
69 #include "sustained_stats.h"
70 #include "symlinkcache.h"
71 #include "negentrycache.h"
72 //#include "dircache.h"
73 #include "conncache.h"
74 #include "readdata.h"
75 #include "writedata.h"
76 #include "csdb.h"
77 #include "stats.h"
78 #include "strerr.h"
79 #include "crc.h"
80
81 #define STR_AUX(x) #x
82 #define STR(x) STR_AUX(x)
83 const char id[]="@(#) version: " VERSSTR ", written by Jakub Kruszona-Zawadzki";
84
85 #if defined(__APPLE__)
86 #define DEFAULT_OPTIONS "allow_other,daemon_timeout=600,novncache"
87 // #define DEFAULT_OPTIONS "allow_other,default_permissions,daemon_timeout=600,iosize=65536,novncache"
88 #else
89 #define DEFAULT_OPTIONS "allow_other"
90 #endif
91
92 static void mfs_fsinit (void *userdata, struct fuse_conn_info *conn);
93
94 static struct fuse_lowlevel_ops mfs_meta_oper = {
95 .init = mfs_fsinit,
96 .statfs = mfs_meta_statfs,
97 .lookup = mfs_meta_lookup,
98 .getattr = mfs_meta_getattr,
99 .setattr = mfs_meta_setattr,
100 .unlink = mfs_meta_unlink,
101 .rename = mfs_meta_rename,
102 .opendir = mfs_meta_opendir,
103 .readdir = mfs_meta_readdir,
104 .releasedir = mfs_meta_releasedir,
105 .open = mfs_meta_open,
106 .release = mfs_meta_release,
107 .read = mfs_meta_read,
108 .write = mfs_meta_write,
109 // .access = mfs_meta_access,
110 };
111
112 static struct fuse_lowlevel_ops mfs_oper = {
113 .init = mfs_fsinit,
114 .statfs = mfs_statfs,
115 .lookup = mfs_lookup,
116 .getattr = mfs_getattr,
117 .setattr = mfs_setattr,
118 .mknod = mfs_mknod,
119 .unlink = mfs_unlink,
120 .mkdir = mfs_mkdir,
121 .rmdir = mfs_rmdir,
122 .symlink = mfs_symlink,
123 .readlink = mfs_readlink,
124 .rename = mfs_rename,
125 .link = mfs_link,
126 .opendir = mfs_opendir,
127 .readdir = mfs_readdir,
128 .releasedir = mfs_releasedir,
129 .create = mfs_create,
130 .open = mfs_open,
131 .release = mfs_release,
132 .flush = mfs_flush,
133 .fsync = mfs_fsync,
134 .read = mfs_read,
135 .write = mfs_write,
136 .access = mfs_access,
137 .getxattr = mfs_getxattr,
138 .setxattr = mfs_setxattr,
139 .listxattr = mfs_listxattr,
140 .removexattr = mfs_removexattr,
141 };
142
143 struct mfsopts {
144 char *masterhost;
145 char *masterport;
146 char *bindhost;
147 char *proxyhost;
148 char *subfolder;
149 char *password;
150 char *md5pass;
151 unsigned nofile;
152 signed nice;
153 #ifdef MFS_USE_MEMLOCK
154 int memlock;
155 #endif
156 #ifdef MFS_USE_MALLOPT
157 int limitarenas;
158 #endif
159 int nostdmountoptions;
160 int meta;
161 int debug;
162 int delayedinit;
163 int mkdircopysgid;
164 char *sugidclearmodestr;
165 int sugidclearmode;
166 char *cachemode;
167 int cachefiles;
168 int keepcache;
169 int passwordask;
170 int donotrememberpassword;
171 // int xattraclsupport;
172 unsigned writecachesize;
173 unsigned readaheadsize;
174 unsigned readaheadleng;
175 unsigned readaheadtrigger;
176 unsigned ioretries;
177 double attrcacheto;
178 double xattrcacheto;
179 double entrycacheto;
180 double direntrycacheto;
181 double negentrycacheto;
182 double groupscacheto;
183 };
184
185 static struct mfsopts mfsopts;
186 static char *defaultmountpoint = NULL;
187
188 static int custom_cfg;
189
190 enum {
191 KEY_CFGFILE,
192 KEY_META,
193 KEY_HOST,
194 KEY_PORT,
195 KEY_BIND,
196 KEY_PROXY,
197 KEY_PATH,
198 KEY_PASSWORDASK,
199 KEY_NOSTDMOUNTOPTIONS,
200 KEY_HELP,
201 KEY_VERSION,
202 };
203
204 #define MFS_OPT(t, p, v) { t, offsetof(struct mfsopts, p), v }
205
206 static struct fuse_opt mfs_opts_stage1[] = {
207 FUSE_OPT_KEY("mfscfgfile=", KEY_CFGFILE),
208 FUSE_OPT_KEY("-c ", KEY_CFGFILE),
209 FUSE_OPT_END
210 };
211
212 static struct fuse_opt mfs_opts_stage2[] = {
213 MFS_OPT("mfsmaster=%s", masterhost, 0),
214 MFS_OPT("mfsport=%s", masterport, 0),
215 MFS_OPT("mfsbind=%s", bindhost, 0),
216 MFS_OPT("mfsproxy=%s", proxyhost, 0),
217 MFS_OPT("mfssubfolder=%s", subfolder, 0),
218 MFS_OPT("mfspassword=%s", password, 0),
219 MFS_OPT("mfsmd5pass=%s", md5pass, 0),
220 MFS_OPT("mfsrlimitnofile=%u", nofile, 0),
221 MFS_OPT("mfsnice=%d", nice, 0),
222 #ifdef MFS_USE_MEMLOCK
223 MFS_OPT("mfsmemlock", memlock, 1),
224 #endif
225 #ifdef MFS_USE_MALLOPT
226 MFS_OPT("mfslimitarenas=%u", limitarenas, 0),
227 #endif
228 MFS_OPT("mfswritecachesize=%u", writecachesize, 0),
229 MFS_OPT("mfsreadaheadsize=%u", readaheadsize, 0),
230 MFS_OPT("mfsreadaheadleng=%u", readaheadleng, 0),
231 MFS_OPT("mfsreadaheadtrigger=%u", readaheadtrigger, 0),
232 MFS_OPT("mfsioretries=%u", ioretries, 0),
233 MFS_OPT("mfsdebug", debug, 1),
234 MFS_OPT("mfsmeta", meta, 1),
235 MFS_OPT("mfsdelayedinit", delayedinit, 1),
236 MFS_OPT("mfsdonotrememberpassword", donotrememberpassword, 1),
237 MFS_OPT("mfscachefiles", cachefiles, 1),
238 MFS_OPT("mfscachemode=%s", cachemode, 0),
239 MFS_OPT("mfsmkdircopysgid=%u", mkdircopysgid, 0),
240 MFS_OPT("mfssugidclearmode=%s", sugidclearmodestr, 0),
241 MFS_OPT("mfsattrcacheto=%lf", attrcacheto, 0),
242 MFS_OPT("mfsxattrcacheto=%lf", xattrcacheto, 0),
243 MFS_OPT("mfsentrycacheto=%lf", entrycacheto, 0),
244 MFS_OPT("mfsdirentrycacheto=%lf", direntrycacheto, 0),
245 MFS_OPT("mfsnegentrycacheto=%lf", negentrycacheto, 0),
246 MFS_OPT("mfsgroupscacheto=%lf", groupscacheto, 0),
247 // MFS_OPT("mfsaclsupport", xattraclsupport, 1),
248
249 FUSE_OPT_KEY("-m", KEY_META),
250 FUSE_OPT_KEY("--meta", KEY_META),
251 FUSE_OPT_KEY("-H ", KEY_HOST),
252 FUSE_OPT_KEY("-P ", KEY_PORT),
253 FUSE_OPT_KEY("-B ", KEY_BIND),
254 FUSE_OPT_KEY("-L ", KEY_PROXY),
255 FUSE_OPT_KEY("-S ", KEY_PATH),
256 FUSE_OPT_KEY("-p", KEY_PASSWORDASK),
257 FUSE_OPT_KEY("--password", KEY_PASSWORDASK),
258 FUSE_OPT_KEY("-n", KEY_NOSTDMOUNTOPTIONS),
259 FUSE_OPT_KEY("--nostdopts", KEY_NOSTDMOUNTOPTIONS),
260 FUSE_OPT_KEY("-V", KEY_VERSION),
261 FUSE_OPT_KEY("--version", KEY_VERSION),
262 FUSE_OPT_KEY("-h", KEY_HELP),
263 FUSE_OPT_KEY("--help", KEY_HELP),
264 FUSE_OPT_END
265 };
266
usage(const char * progname)267 static void usage(const char *progname) {
268 fprintf(stderr,
269 "usage: %s mountpoint [options]\n"
270 "\n", progname);
271 fprintf(stderr,
272 "general options:\n"
273 " -o opt,[opt...] mount options\n"
274 " -h --help print help\n"
275 " -V --version print version\n"
276 "\n");
277 fprintf(stderr,
278 "MFS options:\n"
279 " -c CFGFILE equivalent to '-o mfscfgfile=CFGFILE'\n"
280 " -m --meta equivalent to '-o mfsmeta'\n"
281 " -H HOST equivalent to '-o mfsmaster=HOST'\n"
282 " -P PORT equivalent to '-o mfsport=PORT'\n"
283 " -B IP equivalent to '-o mfsbind=IP'\n"
284 " -L IP equivalent to '-o mfsproxy=IP'\n"
285 " -S PATH equivalent to '-o mfssubfolder=PATH'\n"
286 " -p --password similar to '-o mfspassword=PASSWORD', but show prompt and ask user for password\n"
287 " -n --nostdopts do not add standard MFS mount options: '-o " DEFAULT_OPTIONS ",fsname=MFS'\n"
288 " -o mfscfgfile=CFGFILE load some mount options from external file (if not specified then use default file: " ETC_PATH "/mfs/mfsmount.cfg or " ETC_PATH "/mfsmount.cfg)\n"
289 " -o mfsdebug print some debugging information\n"
290 " -o mfsmeta mount meta filesystem (trash etc.)\n"
291 " -o mfsdelayedinit connection with master is done in background - with this option mount can be run without network (good for being run from fstab / init scripts etc.)\n"
292 #ifdef __linux__
293 " -o mfsmkdircopysgid=N sgid bit should be copied during mkdir operation (default: 1)\n"
294 #else
295 " -o mfsmkdircopysgid=N sgid bit should be copied during mkdir operation (default: 0)\n"
296 #endif
297 #if defined(DEFAULT_SUGID_CLEAR_MODE_EXT)
298 " -o mfssugidclearmode=SMODE set sugid clear mode (see below ; default: EXT)\n"
299 #elif defined(DEFAULT_SUGID_CLEAR_MODE_BSD)
300 " -o mfssugidclearmode=SMODE set sugid clear mode (see below ; default: BSD)\n"
301 #elif defined(DEFAULT_SUGID_CLEAR_MODE_OSX)
302 " -o mfssugidclearmode=SMODE set sugid clear mode (see below ; default: OSX)\n"
303 #else
304 " -o mfssugidclearmode=SMODE set sugid clear mode (see below ; default: NEVER)\n"
305 #endif
306 " -o mfscachemode=CMODE set cache mode (see below ; default: AUTO)\n"
307 " -o mfscachefiles (deprecated) equivalent to '-o mfscachemode=YES'\n"
308 // " -o mfscachefiles allow files data to be kept in cache (dangerous in network environment)\n"
309 " -o mfsattrcacheto=SEC set attributes cache timeout in seconds (default: 1.0)\n"
310 " -o mfsxattrcacheto=SEC set extended attributes (xattr) cache timeout in seconds (default: 30.0)\n"
311 " -o mfsentrycacheto=SEC set file entry cache timeout in seconds (default: 0.0)\n"
312 " -o mfsdirentrycacheto=SEC set directory entry cache timeout in seconds (default: 1.0)\n"
313 " -o mfsnegentrycacheto=SEC set negative entry cache timeout in seconds (default: 1.0)\n"
314 " -o mfsgroupscacheto=SEC set supplementary groups cache timeout in seconds (default: 300.0)\n"
315 " -o mfsrlimitnofile=N on startup mfsmount tries to change number of descriptors it can simultaneously open (default: 100000)\n"
316 " -o mfsnice=N on startup mfsmount tries to change his 'nice' value (default: -19)\n"
317 #ifdef MFS_USE_MEMLOCK
318 " -o mfsmemlock try to lock memory\n"
319 #endif
320 #ifdef MFS_USE_MALLOPT
321 " -o mfslimitarenas=N if N>0 then limit glibc malloc arenas (default: 8)\n"
322 #endif
323 " -o mfswritecachesize=N define size of write cache in MiB (default: 128)\n"
324 " -o mfsreadaheadsize=N define size of all read ahead buffers in MiB (default: 128)\n"
325 " -o mfsreadaheadleng=N define amount of bytes to be additionally read (default: 1048576)\n"
326 " -o mfsreadaheadtrigger=N define amount of bytes read sequentially that turns on read ahead (default: 10 * mfsreadaheadleng)\n"
327 " -o mfsioretries=N define number of retries before I/O error is returned (default: 30)\n"
328 " -o mfsmaster=HOST define mfsmaster location (default: " DEFAULT_MASTERNAME ")\n"
329 " -o mfsport=PORT define mfsmaster port number (default: " DEFAULT_MASTER_CLIENT_PORT ")\n"
330 " -o mfsbind=IP define source ip address for connections (default: NOT DEFINED - chosen automatically by OS)\n"
331 " -o mfsproxy=IP define listen ip address of local master proxy for communication with tools (default: 127.0.0.1)\n"
332 " -o mfssubfolder=PATH define subfolder to mount as root (default: /)\n"
333 " -o mfspassword=PASSWORD authenticate to mfsmaster with password\n"
334 " -o mfsmd5pass=MD5 authenticate to mfsmaster using directly given md5 (only if mfspassword is not defined)\n"
335 " -o mfsdonotrememberpassword do not remember password in memory - more secure, but when session is lost then new session is created without password\n"
336 "\n");
337 fprintf(stderr,
338 "CMODE can be set to:\n"
339 " NO,NONE or NEVER never allow files data to be kept in cache (safest but can reduce efficiency)\n"
340 " YES or ALWAYS always allow files data to be kept in cache (dangerous)\n"
341 " AUTO file cache is managed by mfsmaster automatically (should be very safe and efficient)\n"
342 "\n");
343 fprintf(stderr,
344 "SMODE can be set to:\n"
345 " NEVER MFS will not change suid and sgid bit on chown\n"
346 " ALWAYS clear suid and sgid on every chown - safest operation\n"
347 " OSX standard behavior in OS X and Solaris (chown made by unprivileged user clear suid and sgid)\n"
348 " BSD standard behavior in *BSD systems (like in OSX, but only when something is really changed)\n"
349 " EXT standard behavior in most file systems on Linux (directories not changed, others: suid cleared always, sgid only when group exec bit is set)\n"
350 " XFS standard behavior in XFS on Linux (like EXT but directories are changed by unprivileged users)\n"
351 "SMODE extra info:\n"
352 " btrfs,ext2,ext3,ext4,hfs[+],jfs,ntfs and reiserfs on Linux work as 'EXT'.\n"
353 " Only xfs on Linux works a little different. Beware that there is a strange\n"
354 " operation - chown(-1,-1) which is usually converted by a kernel into something\n"
355 " like 'chmod ug-s', and therefore can't be controlled by MFS as 'chown'\n"
356 "\n");
357 }
358
mfs_opt_parse_cfg_file(const char * filename,int optional,struct fuse_args * outargs)359 static void mfs_opt_parse_cfg_file(const char *filename,int optional,struct fuse_args *outargs) {
360 FILE *fd;
361 char lbuff[1000],*p;
362
363 fd = fopen(filename,"r");
364 if (fd==NULL) {
365 if (optional==0) {
366 fprintf(stderr,"can't open cfg file: %s\n",filename);
367 abort();
368 }
369 return;
370 }
371 custom_cfg = 1;
372 while (fgets(lbuff,999,fd)) {
373 if (lbuff[0]!='#' && lbuff[0]!=';') {
374 lbuff[999]=0;
375 for (p = lbuff ; *p ; p++) {
376 if (*p=='\r' || *p=='\n') {
377 *p=0;
378 break;
379 }
380 }
381 p--;
382 while (p>=lbuff && (*p==' ' || *p=='\t')) {
383 *p=0;
384 p--;
385 }
386 p = lbuff;
387 while (*p==' ' || *p=='\t') {
388 p++;
389 }
390 if (*p) {
391 // printf("add option: %s\n",p);
392 if (*p=='-') {
393 fuse_opt_add_arg(outargs,p);
394 } else if (*p=='/') {
395 if (defaultmountpoint) {
396 free(defaultmountpoint);
397 }
398 defaultmountpoint = strdup(p);
399 } else {
400 fuse_opt_add_arg(outargs,"-o");
401 fuse_opt_add_arg(outargs,p);
402 }
403 }
404 }
405 }
406 fclose(fd);
407 }
408
mfs_opt_proc_stage1(void * data,const char * arg,int key,struct fuse_args * outargs)409 static int mfs_opt_proc_stage1(void *data, const char *arg, int key, struct fuse_args *outargs) {
410 struct fuse_args *defargs = (struct fuse_args*)data;
411 (void)outargs;
412
413 if (key==KEY_CFGFILE) {
414 if (memcmp(arg,"mfscfgfile=",11)==0) {
415 mfs_opt_parse_cfg_file(arg+11,0,defargs);
416 } else if (arg[0]=='-' && arg[1]=='c') {
417 mfs_opt_parse_cfg_file(arg+2,0,defargs);
418 }
419 return 0;
420 }
421 return 1;
422 }
423
424 // return value:
425 // 0 - discard this arg
426 // 1 - keep this arg for future processing
mfs_opt_proc_stage2(void * data,const char * arg,int key,struct fuse_args * outargs)427 static int mfs_opt_proc_stage2(void *data, const char *arg, int key, struct fuse_args *outargs) {
428 (void)data;
429
430 switch (key) {
431 case FUSE_OPT_KEY_OPT:
432 return 1;
433 case FUSE_OPT_KEY_NONOPT:
434 return 1;
435 case KEY_HOST:
436 if (mfsopts.masterhost!=NULL) {
437 free(mfsopts.masterhost);
438 }
439 mfsopts.masterhost = strdup(arg+2);
440 return 0;
441 case KEY_PORT:
442 if (mfsopts.masterport!=NULL) {
443 free(mfsopts.masterport);
444 }
445 mfsopts.masterport = strdup(arg+2);
446 return 0;
447 case KEY_BIND:
448 if (mfsopts.bindhost!=NULL) {
449 free(mfsopts.bindhost);
450 }
451 mfsopts.bindhost = strdup(arg+2);
452 return 0;
453 case KEY_PROXY:
454 if (mfsopts.proxyhost!=NULL) {
455 free(mfsopts.proxyhost);
456 }
457 mfsopts.proxyhost = strdup(arg+2);
458 return 0;
459 case KEY_PATH:
460 if (mfsopts.subfolder!=NULL) {
461 free(mfsopts.subfolder);
462 }
463 mfsopts.subfolder = strdup(arg+2);
464 return 0;
465 case KEY_PASSWORDASK:
466 mfsopts.passwordask = 1;
467 return 0;
468 case KEY_META:
469 mfsopts.meta = 1;
470 return 0;
471 case KEY_NOSTDMOUNTOPTIONS:
472 mfsopts.nostdmountoptions = 1;
473 return 0;
474 case KEY_VERSION:
475 fprintf(stderr, "MFS version %s\n",VERSSTR);
476 {
477 struct fuse_args helpargs = FUSE_ARGS_INIT(0, NULL);
478
479 fuse_opt_add_arg(&helpargs,outargs->argv[0]);
480 fuse_opt_add_arg(&helpargs,"--version");
481 fuse_parse_cmdline(&helpargs,NULL,NULL,NULL);
482 fuse_mount(NULL,&helpargs);
483 }
484 exit(0);
485 case KEY_HELP:
486 usage(outargs->argv[0]);
487 {
488 struct fuse_args helpargs = FUSE_ARGS_INIT(0, NULL);
489
490 fuse_opt_add_arg(&helpargs,outargs->argv[0]);
491 fuse_opt_add_arg(&helpargs,"-ho");
492 fuse_parse_cmdline(&helpargs,NULL,NULL,NULL);
493 fuse_mount("",&helpargs);
494 }
495 exit(1);
496 default:
497 fprintf(stderr, "internal error\n");
498 abort();
499 }
500 }
501
mfs_fsinit(void * userdata,struct fuse_conn_info * conn)502 static void mfs_fsinit (void *userdata, struct fuse_conn_info *conn) {
503 int *piped = (int*)userdata;
504 char s;
505 conn->max_write = 131072;
506 conn->max_readahead = 131072;
507 #if defined(FUSE_CAP_BIG_WRITES) || defined(FUSE_CAP_DONT_MASK)
508 conn->want = 0;
509 #endif
510 #ifdef FUSE_CAP_BIG_WRITES
511 conn->want |= FUSE_CAP_BIG_WRITES;
512 #endif
513 #ifdef FUSE_CAP_DONT_MASK
514 conn->want |= FUSE_CAP_DONT_MASK;
515 #endif
516 if (piped[1]>=0) {
517 s=0;
518 if (write(piped[1],&s,1)!=1) {
519 syslog(LOG_ERR,"pipe write error: %s",strerr(errno));
520 }
521 close(piped[1]);
522 }
523 }
524
main_thread_create(pthread_t * th,const pthread_attr_t * attr,void * (* fn)(void *),void * arg)525 int main_thread_create(pthread_t *th,const pthread_attr_t *attr,void *(*fn)(void *),void *arg) {
526 sigset_t oldset;
527 sigset_t newset;
528 int res;
529
530 sigemptyset(&newset);
531 sigaddset(&newset, SIGTERM);
532 sigaddset(&newset, SIGINT);
533 sigaddset(&newset, SIGHUP);
534 sigaddset(&newset, SIGQUIT);
535 pthread_sigmask(SIG_BLOCK, &newset, &oldset);
536 res = pthread_create(th,attr,fn,arg);
537 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
538 return res;
539 }
540
main_minthread_create(pthread_t * th,uint8_t detached,void * (* fn)(void *),void * arg)541 int main_minthread_create(pthread_t *th,uint8_t detached,void *(*fn)(void *),void *arg) {
542 static pthread_attr_t *thattr = NULL;
543 static uint8_t thattr_detached;
544 if (thattr == NULL) {
545 size_t mystacksize;
546 thattr = malloc(sizeof(pthread_attr_t));
547 passert(thattr);
548 zassert(pthread_attr_init(thattr));
549 #ifdef PTHREAD_STACK_MIN
550 mystacksize = PTHREAD_STACK_MIN;
551 if (mystacksize < 0x100000) {
552 mystacksize = 0x100000;
553 }
554 #else
555 mystacksize = 0x100000;
556 #endif
557 zassert(pthread_attr_setstacksize(thattr,mystacksize));
558 thattr_detached = detached + 1; // make it different
559 }
560 if (detached != thattr_detached) {
561 if (detached) {
562 zassert(pthread_attr_setdetachstate(thattr,PTHREAD_CREATE_DETACHED));
563 } else {
564 zassert(pthread_attr_setdetachstate(thattr,PTHREAD_CREATE_JOINABLE));
565 }
566 thattr_detached = detached;
567 }
568 return main_thread_create(th,thattr,fn,arg);
569 }
570
mainloop(struct fuse_args * args,const char * mp,int mt,int fg)571 int mainloop(struct fuse_args *args,const char* mp,int mt,int fg) {
572 struct fuse_session *se;
573 struct fuse_chan *ch;
574 struct rlimit rls;
575 int piped[2];
576 char s;
577 int err;
578 int i;
579 md5ctx ctx;
580 uint8_t md5pass[16];
581
582 if (mfsopts.passwordask && mfsopts.password==NULL && mfsopts.md5pass==NULL) {
583 mfsopts.password = getpass("MFS Password:");
584 }
585 if (mfsopts.password) {
586 md5_init(&ctx);
587 md5_update(&ctx,(uint8_t*)(mfsopts.password),strlen(mfsopts.password));
588 md5_final(md5pass,&ctx);
589 memset(mfsopts.password,0,strlen(mfsopts.password));
590 } else if (mfsopts.md5pass) {
591 uint8_t *p = (uint8_t*)(mfsopts.md5pass);
592 for (i=0 ; i<16 ; i++) {
593 if (*p>='0' && *p<='9') {
594 md5pass[i]=(*p-'0')<<4;
595 } else if (*p>='a' && *p<='f') {
596 md5pass[i]=(*p-'a'+10)<<4;
597 } else if (*p>='A' && *p<='F') {
598 md5pass[i]=(*p-'A'+10)<<4;
599 } else {
600 fprintf(stderr,"bad md5 definition (md5 should be given as 32 hex digits)\n");
601 return 1;
602 }
603 p++;
604 if (*p>='0' && *p<='9') {
605 md5pass[i]+=(*p-'0');
606 } else if (*p>='a' && *p<='f') {
607 md5pass[i]+=(*p-'a'+10);
608 } else if (*p>='A' && *p<='F') {
609 md5pass[i]+=(*p-'A'+10);
610 } else {
611 fprintf(stderr,"bad md5 definition (md5 should be given as 32 hex digits)\n");
612 return 1;
613 }
614 p++;
615 }
616 if (*p) {
617 fprintf(stderr,"bad md5 definition (md5 should be given as 32 hex digits)\n");
618 return 1;
619 }
620 memset(mfsopts.md5pass,0,strlen(mfsopts.md5pass));
621 }
622
623 if (mfsopts.delayedinit) {
624 fs_init_master_connection(mfsopts.bindhost,mfsopts.masterhost,mfsopts.masterport,mfsopts.meta,mp,mfsopts.subfolder,(mfsopts.password||mfsopts.md5pass)?md5pass:NULL,mfsopts.donotrememberpassword,1);
625 } else {
626 if (fs_init_master_connection(mfsopts.bindhost,mfsopts.masterhost,mfsopts.masterport,mfsopts.meta,mp,mfsopts.subfolder,(mfsopts.password||mfsopts.md5pass)?md5pass:NULL,mfsopts.donotrememberpassword,0)<0) {
627 return 1;
628 }
629 }
630 memset(md5pass,0,16);
631
632 if (fg==0) {
633 openlog(STR(APPNAME), LOG_PID | LOG_NDELAY , LOG_DAEMON);
634 } else {
635 #if defined(LOG_PERROR)
636 openlog(STR(APPNAME), LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_USER);
637 #else
638 openlog(STR(APPNAME), LOG_PID | LOG_NDELAY, LOG_USER);
639 #endif
640 }
641
642 i = mfsopts.nofile;
643 while (1) {
644 rls.rlim_cur = i;
645 rls.rlim_max = i;
646 if (setrlimit(RLIMIT_NOFILE,&rls)<0) {
647 i /= 2;
648 if (i<1000) {
649 break;
650 }
651 } else {
652 break;
653 }
654 }
655 if (i != (int)(mfsopts.nofile)) {
656 fprintf(stderr,"can't set open file limit to %d\n",mfsopts.nofile);
657 if (i>=1000) {
658 fprintf(stderr,"open file limit set to: %d\n",i);
659 }
660 }
661
662 setpriority(PRIO_PROCESS,getpid(),mfsopts.nice);
663 #ifdef MFS_USE_MEMLOCK
664 if (mfsopts.memlock) {
665 rls.rlim_cur = RLIM_INFINITY;
666 rls.rlim_max = RLIM_INFINITY;
667 if (setrlimit(RLIMIT_MEMLOCK,&rls)<0) {
668 mfsopts.memlock=0;
669 }
670 }
671 #endif
672
673 piped[0] = piped[1] = -1;
674 if (fg==0) {
675 if (pipe(piped)<0) {
676 fprintf(stderr,"pipe error\n");
677 return 1;
678 }
679 err = fork();
680 if (err<0) {
681 fprintf(stderr,"fork error\n");
682 return 1;
683 } else if (err>0) {
684 close(piped[1]);
685 err = read(piped[0],&s,1);
686 if (err==0) {
687 s=1;
688 }
689 return s;
690 }
691 close(piped[0]);
692 s=1;
693 }
694
695
696 #ifdef MFS_USE_MEMLOCK
697 if (mfsopts.memlock) {
698 if (mlockall(MCL_CURRENT|MCL_FUTURE)==0) {
699 syslog(LOG_NOTICE,"process memory was successfully locked in RAM");
700 }
701 }
702 #endif
703
704 /* glibc malloc tuning */
705 #ifdef MFS_USE_MALLOPT
706 if (mfsopts.limitarenas) {
707 if (!getenv("MALLOC_ARENA_MAX")) {
708 syslog(LOG_NOTICE,"setting glibc malloc arena max to 8");
709 mallopt(M_ARENA_MAX, mfsopts.limitarenas);
710 }
711 if (!getenv("MALLOC_ARENA_TEST")) {
712 syslog(LOG_NOTICE,"setting glibc malloc arena test to 1");
713 mallopt(M_ARENA_TEST, 1);
714 }
715 } else {
716 syslog(LOG_NOTICE,"setting glibc malloc arenas turned off");
717 }
718 #endif /* glibc malloc tuning */
719
720 syslog(LOG_NOTICE,"monotonic clock function: %s",monotonic_method());
721 syslog(LOG_NOTICE,"monotonic clock speed: %"PRIu32" ops / 10 mili seconds",monotonic_speed());
722
723 conncache_init(200);
724 chunkloc_cache_init();
725 symlink_cache_init();
726 negentry_cache_init(mfsopts.negentrycacheto);
727 // dir_cache_init();
728 fs_init_threads(mfsopts.ioretries);
729 if (masterproxy_init(mfsopts.proxyhost)<0) {
730 fs_term();
731 // dir_cache_term();
732 negentry_cache_term();
733 symlink_cache_term();
734 chunkloc_cache_term();
735 return 1;
736 }
737
738 // fs_term();
739 // negentry_cache_term();
740 // symlink_cache_term();
741 // chunkloc_cache_term();
742 // return 1;
743
744 if (mfsopts.meta==0) {
745 csdb_init();
746 read_data_init(mfsopts.readaheadsize*1024*1024,mfsopts.readaheadleng,mfsopts.readaheadtrigger,mfsopts.ioretries);
747 write_data_init(mfsopts.writecachesize*1024*1024,mfsopts.ioretries);
748 }
749
750 ch = fuse_mount(mp, args);
751 if (ch==NULL) {
752 fprintf(stderr,"error in fuse_mount\n");
753 if (piped[1]>=0) {
754 if (write(piped[1],&s,1)!=1) {
755 fprintf(stderr,"pipe write error\n");
756 }
757 close(piped[1]);
758 }
759 if (mfsopts.meta==0) {
760 write_data_term();
761 read_data_term();
762 csdb_term();
763 }
764 masterproxy_term();
765 fs_term();
766 // dir_cache_term();
767 negentry_cache_term();
768 symlink_cache_term();
769 chunkloc_cache_term();
770 return 1;
771 }
772
773 if (mfsopts.meta) {
774 mfs_meta_init(mfsopts.debug,mfsopts.entrycacheto,mfsopts.attrcacheto);
775 se = fuse_lowlevel_new(args, &mfs_meta_oper, sizeof(mfs_meta_oper), (void*)piped);
776 } else {
777 mfs_init(mfsopts.debug,mfsopts.keepcache,mfsopts.direntrycacheto,mfsopts.entrycacheto,mfsopts.attrcacheto,mfsopts.xattrcacheto,mfsopts.groupscacheto,mfsopts.mkdircopysgid,mfsopts.sugidclearmode,1); //mfsopts.xattraclsupport);
778 se = fuse_lowlevel_new(args, &mfs_oper, sizeof(mfs_oper), (void*)piped);
779 }
780 if (se==NULL) {
781 fuse_unmount(mp,ch);
782 fprintf(stderr,"error in fuse_lowlevel_new\n");
783 portable_usleep(100000); // time for print other error messages by FUSE
784 if (piped[1]>=0) {
785 if (write(piped[1],&s,1)!=1) {
786 fprintf(stderr,"pipe write error\n");
787 }
788 close(piped[1]);
789 }
790 if (mfsopts.meta==0) {
791 write_data_term();
792 read_data_term();
793 csdb_term();
794 }
795 masterproxy_term();
796 fs_term();
797 // dir_cache_term();
798 negentry_cache_term();
799 symlink_cache_term();
800 chunkloc_cache_term();
801 return 1;
802 }
803
804 // fprintf(stderr,"check\n");
805 fuse_session_add_chan(se, ch);
806
807 if (fuse_set_signal_handlers(se)<0) {
808 fprintf(stderr,"error in fuse_set_signal_handlers\n");
809 fuse_session_remove_chan(ch);
810 fuse_session_destroy(se);
811 fuse_unmount(mp,ch);
812 if (piped[1]>=0) {
813 if (write(piped[1],&s,1)!=1) {
814 fprintf(stderr,"pipe write error\n");
815 }
816 close(piped[1]);
817 }
818 if (mfsopts.meta==0) {
819 write_data_term();
820 read_data_term();
821 csdb_term();
822 }
823 masterproxy_term();
824 fs_term();
825 // dir_cache_term();
826 negentry_cache_term();
827 symlink_cache_term();
828 chunkloc_cache_term();
829 return 1;
830 }
831
832 if (mfsopts.debug==0 && fg==0) {
833 setsid();
834 setpgid(0,getpid());
835 if ((i = open("/dev/null", O_RDWR, 0)) != -1) {
836 (void)dup2(i, STDIN_FILENO);
837 (void)dup2(i, STDOUT_FILENO);
838 (void)dup2(i, STDERR_FILENO);
839 if (i>2) close (i);
840 }
841 }
842
843 sinodes_init(mp);
844 sstats_init();
845
846 if (mt) {
847 err = fuse_session_loop_mt(se);
848 } else {
849 err = fuse_session_loop(se);
850 }
851 if (err) {
852 if (piped[1]>=0) {
853 if (write(piped[1],&s,1)!=1) {
854 syslog(LOG_ERR,"pipe write error: %s",strerr(errno));
855 }
856 close(piped[1]);
857 }
858 }
859
860 sstats_term();
861 sinodes_term();
862
863 fuse_remove_signal_handlers(se);
864 fuse_session_remove_chan(ch);
865 fuse_session_destroy(se);
866 fuse_unmount(mp,ch);
867 if (mfsopts.meta==0) {
868 write_data_term();
869 read_data_term();
870 csdb_term();
871 }
872 masterproxy_term();
873 fs_term();
874 // dir_cache_term();
875 negentry_cache_term();
876 symlink_cache_term();
877 chunkloc_cache_term();
878 return err ? 1 : 0;
879 }
880
881 #if FUSE_VERSION == 25
fuse_opt_insert_arg(struct fuse_args * args,int pos,const char * arg)882 static int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) {
883 assert(pos <= args->argc);
884 if (fuse_opt_add_arg(args, arg) == -1) {
885 return -1;
886 }
887 if (pos != args->argc - 1) {
888 char *newarg = args->argv[args->argc - 1];
889 memmove(&args->argv[pos + 1], &args->argv[pos], sizeof(char *) * (args->argc - pos - 1));
890 args->argv[pos] = newarg;
891 }
892 return 0;
893 }
894 #endif
895
strncpy_remove_commas(char * dstbuff,unsigned int dstsize,char * src)896 static unsigned int strncpy_remove_commas(char *dstbuff, unsigned int dstsize,char *src) {
897 char c;
898 unsigned int l;
899 l=0;
900 while ((c=*src++) && l+1<dstsize) {
901 if (c!=',') {
902 *dstbuff++ = c;
903 l++;
904 }
905 }
906 *dstbuff=0;
907 return l;
908 }
909
910 #if HAVE_FUSE_VERSION
strncpy_escape_commas(char * dstbuff,unsigned int dstsize,char * src)911 static unsigned int strncpy_escape_commas(char *dstbuff, unsigned int dstsize,char *src) {
912 char c;
913 unsigned int l;
914 l=0;
915 while ((c=*src++) && l+1<dstsize) {
916 if (c!=',' && c!='\\') {
917 *dstbuff++ = c;
918 l++;
919 } else {
920 if (l+2<dstsize) {
921 *dstbuff++ = '\\';
922 *dstbuff++ = c;
923 l+=2;
924 } else {
925 *dstbuff=0;
926 return l;
927 }
928 }
929 }
930 *dstbuff=0;
931 return l;
932 }
933 #endif
934
remove_mfsmount_magic(struct fuse_args * args)935 void remove_mfsmount_magic(struct fuse_args *args) {
936 int i;
937 for (i=1 ; i<args->argc ; i++) {
938 if (strcmp(args->argv[i],"mfsmount_magic")==0) {
939 if (i+1 < args->argc) {
940 memmove(&args->argv[i],&args->argv[i+1],sizeof(char *)*(args->argc - i - 1));
941 }
942 args->argc--;
943 return;
944 }
945 }
946 }
947
make_fsname(struct fuse_args * args)948 void make_fsname(struct fuse_args *args) {
949 char fsnamearg[256];
950 unsigned int l;
951 #if HAVE_FUSE_VERSION
952 int libver;
953 libver = fuse_version();
954 if (libver >= 27) {
955 l = snprintf(fsnamearg,256,"-osubtype=mfs%s,fsname=",(mfsopts.meta)?"meta":"");
956 if (libver >= 28) {
957 l += strncpy_escape_commas(fsnamearg+l,256-l,mfsopts.masterhost);
958 if (l<255) {
959 fsnamearg[l++]=':';
960 }
961 l += strncpy_escape_commas(fsnamearg+l,256-l,mfsopts.masterport);
962 if (mfsopts.subfolder[0]!='/') {
963 if (l<255) {
964 fsnamearg[l++]='/';
965 }
966 }
967 if (mfsopts.subfolder[0]!='/' && mfsopts.subfolder[1]!=0) {
968 l += strncpy_escape_commas(fsnamearg+l,256-l,mfsopts.subfolder);
969 }
970 if (l>255) {
971 l=255;
972 }
973 fsnamearg[l]=0;
974 } else {
975 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.masterhost);
976 if (l<255) {
977 fsnamearg[l++]=':';
978 }
979 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.masterport);
980 if (mfsopts.subfolder[0]!='/') {
981 if (l<255) {
982 fsnamearg[l++]='/';
983 }
984 }
985 if (mfsopts.subfolder[0]!='/' && mfsopts.subfolder[1]!=0) {
986 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.subfolder);
987 }
988 if (l>255) {
989 l=255;
990 }
991 fsnamearg[l]=0;
992 }
993 } else {
994 #else
995 l = snprintf(fsnamearg,256,"-ofsname=mfs%s#",(mfsopts.meta)?"meta":"");
996 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.masterhost);
997 if (l<255) {
998 fsnamearg[l++]=':';
999 }
1000 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.masterport);
1001 if (mfsopts.subfolder[0]!='/') {
1002 if (l<255) {
1003 fsnamearg[l++]='/';
1004 }
1005 }
1006 if (mfsopts.subfolder[0]!='/' && mfsopts.subfolder[1]!=0) {
1007 l += strncpy_remove_commas(fsnamearg+l,256-l,mfsopts.subfolder);
1008 }
1009 if (l>255) {
1010 l=255;
1011 }
1012 fsnamearg[l]=0;
1013 #endif
1014 #if HAVE_FUSE_VERSION
1015 }
1016 #endif
1017 fuse_opt_insert_arg(args, 1, fsnamearg);
1018 }
1019
1020 /*
1021 void dump_args(const char *prfx,struct fuse_args *args) {
1022 int i;
1023 for (i=0 ; i<args->argc ; i++) {
1024 printf("%s [%d]: %s\n",prfx,i,args->argv[i]);
1025 }
1026 }
1027 */
1028
main(int argc,char * argv[])1029 int main(int argc, char *argv[]) {
1030 int res;
1031 int mt,fg;
1032 int i;
1033 char *mountpoint;
1034 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1035 struct fuse_args defaultargs = FUSE_ARGS_INIT(0, NULL);
1036
1037 #if defined(SIGPIPE) && defined(SIG_IGN)
1038 signal(SIGPIPE,SIG_IGN);
1039 #endif
1040 strerr_init();
1041 mycrc32_init();
1042
1043 mfsopts.masterhost = NULL;
1044 mfsopts.masterport = NULL;
1045 mfsopts.bindhost = NULL;
1046 mfsopts.proxyhost = NULL;
1047 mfsopts.subfolder = NULL;
1048 mfsopts.password = NULL;
1049 mfsopts.md5pass = NULL;
1050 mfsopts.nofile = 0;
1051 mfsopts.nice = -19;
1052 #ifdef MFS_USE_MEMLOCK
1053 mfsopts.memlock = 0;
1054 #endif
1055 #ifdef MFS_USE_MALLOPT
1056 mfsopts.limitarenas = 8;
1057 #endif
1058 mfsopts.nostdmountoptions = 0;
1059 mfsopts.meta = 0;
1060 mfsopts.debug = 0;
1061 mfsopts.delayedinit = 0;
1062 #ifdef __linux__
1063 mfsopts.mkdircopysgid = 1;
1064 #else
1065 mfsopts.mkdircopysgid = 0;
1066 #endif
1067 mfsopts.sugidclearmodestr = NULL;
1068 mfsopts.donotrememberpassword = 0;
1069 // mfsopts.xattraclsupport = 0;
1070 mfsopts.cachefiles = 0;
1071 mfsopts.cachemode = NULL;
1072 mfsopts.writecachesize = 0;
1073 mfsopts.readaheadsize = 0;
1074 mfsopts.readaheadleng = 0;
1075 mfsopts.readaheadtrigger = 0;
1076 mfsopts.ioretries = 30;
1077 mfsopts.passwordask = 0;
1078 mfsopts.attrcacheto = 1.0;
1079 mfsopts.xattrcacheto = 30.0;
1080 mfsopts.entrycacheto = 0.0;
1081 mfsopts.direntrycacheto = 1.0;
1082 mfsopts.negentrycacheto = 1.0;
1083 mfsopts.groupscacheto = 300.0;
1084
1085 custom_cfg = 0;
1086
1087 // dump_args("input_args",&args);
1088
1089 if (fuse_opt_parse(&args, &defaultargs, mfs_opts_stage1, mfs_opt_proc_stage1)<0) {
1090 exit(1);
1091 }
1092
1093 if (custom_cfg==0) {
1094 int cfgfd;
1095 char *cfgfile;
1096
1097 cfgfile=strdup(ETC_PATH "/mfs/mfsmount.cfg");
1098 if ((cfgfd = open(cfgfile,O_RDONLY))<0 && errno==ENOENT) {
1099 free(cfgfile);
1100 cfgfile=strdup(ETC_PATH "/mfsmount.cfg");
1101 if ((cfgfd = open(cfgfile,O_RDONLY))>=0) {
1102 fprintf(stderr,"default sysconf path has changed - please move mfsmount.cfg from "ETC_PATH"/ to "ETC_PATH"/mfs/\n");
1103 }
1104 }
1105 if (cfgfd>=0) {
1106 close(cfgfd);
1107 }
1108 mfs_opt_parse_cfg_file(cfgfile,1,&defaultargs);
1109 free(cfgfile);
1110 }
1111
1112 // dump_args("parsed_defaults",&defaultargs);
1113 // dump_args("changed_args",&args);
1114
1115 for (i=0 ; i<defaultargs.argc ; i++) {
1116 fuse_opt_add_arg(&args,defaultargs.argv[i]);
1117 }
1118
1119 // dump_args("combined_args",&args);
1120
1121 if (fuse_opt_parse(&args, &mfsopts, mfs_opts_stage2, mfs_opt_proc_stage2)<0) {
1122 exit(1);
1123 }
1124
1125 // dump_args("combined_args_after_parse",&args);
1126
1127 if (mfsopts.cachemode!=NULL && mfsopts.cachefiles) {
1128 fprintf(stderr,"mfscachemode and mfscachefiles options are exclusive - use only mfscachemode\nsee: %s -h for help\n",argv[0]);
1129 return 1;
1130 }
1131
1132 if (mfsopts.cachemode==NULL) {
1133 mfsopts.keepcache=(mfsopts.cachefiles)?1:0;
1134 } else if (strcasecmp(mfsopts.cachemode,"AUTO")==0) {
1135 mfsopts.keepcache=0;
1136 } else if (strcasecmp(mfsopts.cachemode,"YES")==0 || strcasecmp(mfsopts.cachemode,"ALWAYS")==0) {
1137 mfsopts.keepcache=1;
1138 } else if (strcasecmp(mfsopts.cachemode,"NO")==0 || strcasecmp(mfsopts.cachemode,"NONE")==0 || strcasecmp(mfsopts.cachemode,"NEVER")==0) {
1139 mfsopts.keepcache=2;
1140 } else {
1141 fprintf(stderr,"unrecognized cachemode option\nsee: %s -h for help\n",argv[0]);
1142 return 1;
1143 }
1144 if (mfsopts.sugidclearmodestr==NULL) {
1145 #if defined(DEFAULT_SUGID_CLEAR_MODE_EXT)
1146 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_EXT;
1147 #elif defined(DEFAULT_SUGID_CLEAR_MODE_BSD)
1148 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_BSD;
1149 #elif defined(DEFAULT_SUGID_CLEAR_MODE_OSX)
1150 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_OSX;
1151 #else
1152 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_NEVER;
1153 #endif
1154 } else if (strcasecmp(mfsopts.sugidclearmodestr,"NEVER")==0) {
1155 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_NEVER;
1156 } else if (strcasecmp(mfsopts.sugidclearmodestr,"ALWAYS")==0) {
1157 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_ALWAYS;
1158 } else if (strcasecmp(mfsopts.sugidclearmodestr,"OSX")==0) {
1159 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_OSX;
1160 } else if (strcasecmp(mfsopts.sugidclearmodestr,"BSD")==0) {
1161 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_BSD;
1162 } else if (strcasecmp(mfsopts.sugidclearmodestr,"EXT")==0) {
1163 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_EXT;
1164 } else if (strcasecmp(mfsopts.sugidclearmodestr,"XFS")==0) {
1165 mfsopts.sugidclearmode = SUGID_CLEAR_MODE_XFS;
1166 } else {
1167 fprintf(stderr,"unrecognized sugidclearmode option\nsee: %s -h for help\n",argv[0]);
1168 return 1;
1169 }
1170 if (mfsopts.masterhost==NULL) {
1171 mfsopts.masterhost = strdup(DEFAULT_MASTERNAME);
1172 }
1173 if (mfsopts.masterport==NULL) {
1174 mfsopts.masterport = strdup(DEFAULT_MASTER_CLIENT_PORT);
1175 }
1176 if (mfsopts.proxyhost==NULL) {
1177 mfsopts.proxyhost = strdup("127.0.0.1");
1178 }
1179 if (mfsopts.subfolder==NULL) {
1180 mfsopts.subfolder = strdup("/");
1181 }
1182 if (mfsopts.nofile==0) {
1183 mfsopts.nofile=100000;
1184 }
1185 if (mfsopts.writecachesize==0) {
1186 mfsopts.writecachesize=128;
1187 }
1188 if (mfsopts.writecachesize<16) {
1189 fprintf(stderr,"write cache size too low (%u MiB) - increased to 16 MiB\n",mfsopts.writecachesize);
1190 mfsopts.writecachesize=16;
1191 }
1192 if (mfsopts.writecachesize>2048) {
1193 fprintf(stderr,"write cache size too big (%u MiB) - decresed to 2048 MiB\n",mfsopts.writecachesize);
1194 mfsopts.writecachesize=2048;
1195 }
1196 if (mfsopts.readaheadsize==0) {
1197 mfsopts.readaheadsize=128;
1198 }
1199 if (mfsopts.readaheadsize<16) {
1200 fprintf(stderr,"read ahead size too low (%u MiB) - increased to 16 MiB\n",mfsopts.readaheadsize);
1201 mfsopts.readaheadsize=16;
1202 }
1203 if (mfsopts.readaheadsize>2048) {
1204 fprintf(stderr,"read ahead size too big (%u MiB) - decresed to 2048 MiB\n",mfsopts.readaheadsize);
1205 mfsopts.readaheadsize=2048;
1206 }
1207 if (mfsopts.readaheadleng==0) {
1208 mfsopts.readaheadleng=0x100000;
1209 }
1210 if (mfsopts.readaheadleng<0x20000) {
1211 fprintf(stderr,"read ahead length too low (%u B) - increased to 128 KiB\n",mfsopts.readaheadleng);
1212 mfsopts.readaheadleng=0x20000;
1213 }
1214 if (mfsopts.readaheadleng>0x1000000) {
1215 fprintf(stderr,"read ahead length too big (%u B) - decresed to 16 MiB\n",mfsopts.readaheadleng);
1216 mfsopts.readaheadleng=0x1000000;
1217 }
1218 if (mfsopts.readaheadtrigger==0) {
1219 mfsopts.readaheadtrigger=mfsopts.readaheadleng*10;
1220 }
1221
1222 if (mfsopts.nostdmountoptions==0) {
1223 fuse_opt_add_arg(&args, "-o" DEFAULT_OPTIONS);
1224 }
1225
1226
1227 make_fsname(&args);
1228 remove_mfsmount_magic(&args);
1229
1230 // dump_args("combined_args_before_fuse_parse_cmdline",&args);
1231
1232 if (fuse_parse_cmdline(&args,&mountpoint,&mt,&fg)<0) {
1233 fprintf(stderr,"see: %s -h for help\n",argv[0]);
1234 return 1;
1235 }
1236
1237 if (!mountpoint) {
1238 if (defaultmountpoint) {
1239 mountpoint = defaultmountpoint;
1240 } else {
1241 fprintf(stderr,"no mount point\nsee: %s -h for help\n",argv[0]);
1242 return 1;
1243 }
1244 }
1245
1246 res = mainloop(&args,mountpoint,mt,fg);
1247 fuse_opt_free_args(&defaultargs);
1248 fuse_opt_free_args(&args);
1249 free(mfsopts.masterhost);
1250 free(mfsopts.masterport);
1251 if (mfsopts.bindhost) {
1252 free(mfsopts.bindhost);
1253 }
1254 if (mfsopts.proxyhost) {
1255 free(mfsopts.proxyhost);
1256 }
1257 free(mfsopts.subfolder);
1258 if (defaultmountpoint) {
1259 free(defaultmountpoint);
1260 }
1261 stats_term();
1262 strerr_term();
1263 return res;
1264 }
1265