1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 #include <kapp/main.h>
27 #include <kapp/args.h>
28 #include <klib/log.h>
29 #include <klib/out.h>
30 #include <klib/status.h>
31 #include <kfs/directory.h>
32
33 #define FUSE_USE_VERSION 25
34 #include <fuse.h>
35
36 #include "xml.h"
37 #include "sra-fuser.h"
38 #include "log.h"
39
40 #include <atomic.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48
49 static struct stat g_mount_point_stat;
50 static struct stat g_dflt_file_stat;
51 static atomic64_t num_open_files;
52
53 static
ConvertRC2errno(rc_t rc)54 int ConvertRC2errno(rc_t rc)
55 {
56 switch(GetRCState(rc)) {
57 case rcNoErr:
58 return 0;
59 case rcNotFound:
60 return ENOENT;
61 case rcNull:
62 return EFAULT;
63 case rcInvalid:
64 return EINVAL;
65 case rcInsufficient:
66 return ENAMETOOLONG;
67 case rcReadonly:
68 return EROFS;
69 case rcUnauthorized:
70 return EACCES;
71 case rcCorrupt:
72 default:
73 return EBADF;
74 }
75 }
76
UX_FUSE_init(void)77 void* UX_FUSE_init(void)
78 {
79 atomic64_set(&num_open_files, 0);
80 SRA_FUSER_Init();
81 return NULL;
82 }
83
UX_FUSE_destroy(void * x)84 void UX_FUSE_destroy(void* x)
85 {
86 uint64_t q = atomic64_read(&num_open_files);
87 if( q > 0 ) {
88 PLOGMSG(klogInfo, (klogInfo, "$(q) files still opened", PLOG_U64(q), q));
89 }
90 SRA_FUSER_Fini();
91 }
92
93 struct UX_FUSE_readdir_callback_data {
94 const char *path;
95 void *buf;
96 fuse_fill_dir_t filler;
97 };
98
99 static
UX_FUSE_readdir_callback(const char * name,void * data)100 rc_t CC UX_FUSE_readdir_callback( const char *name, void *data )
101 {
102 struct UX_FUSE_readdir_callback_data* d = (struct UX_FUSE_readdir_callback_data*)data;
103 int r = d->filler(d->buf, name, NULL, 0);
104 DEBUG_MSG(10, ("%s %s entry: '%s'\n", __func__, d->path, name));
105 return r != 0 ? RC(rcExe, rcDirectory, rcReading, rcBuffer, rcInsufficient) : 0;
106 }
107
UX_FUSE_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)108 int UX_FUSE_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
109 off_t offset, struct fuse_file_info *fi)
110 {
111 rc_t rc = 0;
112 struct UX_FUSE_readdir_callback_data data;
113
114 DEBUG_MSG(8, ("%s: %s\n", __func__, path));
115
116 data.path = path;
117 data.filler = filler;
118 data.buf = buf;
119
120 if( (rc = UX_FUSE_readdir_callback(".", &data)) == 0 &&
121 (rc = UX_FUSE_readdir_callback("..", &data)) == 0 ) {
122 rc = SRA_FUSER_GetDir(path, UX_FUSE_readdir_callback, &data);
123 }
124 if( rc != 0 ) {
125 errno = ConvertRC2errno(rc);
126 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
127 return -errno;
128 }
129 return 0;
130 }
131
UX_FUSE_getattr(const char * path,struct stat * stbuf)132 int UX_FUSE_getattr(const char *path, struct stat *stbuf)
133 {
134 rc_t rc = 0;
135
136 DEBUG_MSG(8, ("%s: %s\n", __func__, path));
137 if( stbuf == NULL) {
138 rc = RC(rcExe, rcFileDesc, rcClassifying, rcParam, rcNull);
139 } else if( strcmp(path, "/") == 0 ) {
140 /* root is known as mount point */
141 memmove(stbuf, &g_mount_point_stat, sizeof(g_mount_point_stat));
142 } else {
143 uint32_t type = kptBadPath, access = 0;
144 KTime_t ts = 0;
145 uint64_t file_sz = 0, block_sz = 0;
146 if( (rc = SRA_FUSER_GetAttr(path, &type, &ts, &file_sz, &access, &block_sz)) == 0 ) {
147 bool symlink = (type & kptAlias);
148 if( symlink ) {
149 type = type & ~kptAlias;
150 }
151 if( type == kptDir ) {
152 memmove(stbuf, &g_mount_point_stat, sizeof(g_mount_point_stat));
153 stbuf->st_mode = S_IFDIR | (0007555 & (access == 0 ? stbuf->st_mode : access));
154 } else {
155 memmove(stbuf, &g_dflt_file_stat, sizeof(g_dflt_file_stat));
156 if( access == 0 ) {
157 access = stbuf->st_mode;
158 }
159 stbuf->st_mode = 0007555 & (access == 0 ? stbuf->st_mode : access);
160 if( type == kptFile ) {
161 stbuf->st_mode |= S_IFREG;
162 } else if( type == kptCharDev ) {
163 stbuf->st_mode |= S_IFCHR;
164 } else if( type == kptBlockDev ) {
165 stbuf->st_mode |= S_IFBLK;
166 } else if( type == kptFIFO ) {
167 stbuf->st_mode |= S_IFIFO;
168 } else {
169 rc = RC(rcExe, rcFileDesc, rcClassifying, rcDirEntry, rcUnknown);
170 }
171 }
172 if( rc == 0 ) {
173 if( symlink ) {
174 stbuf->st_mode = S_IFLNK | (stbuf->st_mode & 07777);
175 }
176 stbuf->st_size = file_sz;
177 if( ts != 0 ) {
178 stbuf->st_mtime = stbuf->st_atime = stbuf->st_ctime = ts;
179 }
180 if( block_sz > 0 ) {
181 stbuf->st_blksize = block_sz;
182 }
183 DEBUG_MSG(8, ("%s: %s type: %s %lu bytes\n", __func__, path,
184 (S_ISDIR(stbuf->st_mode) ? "dir" : (S_ISLNK(stbuf->st_mode) ? " symlink" : "file")), stbuf->st_size));
185 }
186 }
187 }
188 if( rc != 0 ) {
189 errno = ConvertRC2errno(rc);
190 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
191 return -errno;
192 }
193 return 0;
194 }
195
UX_FUSE_readlink(const char * path,char * buf,size_t buf_sz)196 int UX_FUSE_readlink(const char *path, char *buf, size_t buf_sz)
197 {
198 rc_t rc = 0;
199
200 DEBUG_MSG(8, ("%s: %s\n", __func__, path));
201 if( buf == NULL ) {
202 rc = RC(rcExe, rcFile, rcAliasing, rcParam, rcNull);
203 } else if( buf_sz < 1 ) {
204 rc = RC(rcExe, rcFile, rcAliasing, rcParam, rcInvalid);
205 } else {
206 rc = SRA_FUSER_ResolveLink(path, buf, buf_sz);
207 }
208 if( rc != 0 ) {
209 errno = ConvertRC2errno(rc);
210 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
211 return -errno;
212 }
213 return 0;
214 }
215
UX_FUSE_open(const char * path,struct fuse_file_info * fi)216 int UX_FUSE_open(const char *path, struct fuse_file_info* fi)
217 {
218 rc_t rc = 0;
219 uint64_t q;
220
221 DEBUG_MSG(8, ("%s: %s\n", __func__, path));
222 if( fi == NULL) {
223 rc = RC(rcExe, rcFile, rcOpening, rcParam, rcNull);
224 } else if( fi->flags & (O_CREAT | O_EXCL | O_TRUNC | O_APPEND)) {
225 rc = RC(rcExe, rcFile, rcOpening, rcDirEntry, rcReadonly);
226 } else {
227 const void* data = NULL;
228 if( (rc = SRA_FUSER_OpenNode(path, &data)) == 0 ) {
229 fi->fh = (uint64_t)data;
230 }
231 }
232 if( rc != 0 ) {
233 errno = ConvertRC2errno(rc);
234 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
235 return -errno;
236 }
237 q = atomic64_add_and_read(&num_open_files, 1);
238 PLOGMSG(klogInfo, (klogInfo, "opened $(n), total open $(q)", PLOG_2(PLOG_S(n),PLOG_U64(q)), path, q));
239 return 0;
240 }
241
UX_FUSE_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)242 int UX_FUSE_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
243 {
244 rc_t rc = 0;
245 const void* data = NULL;
246 size_t num_read = 0;
247
248 DEBUG_MSG(8, ("%s: %s from %lu %lu bytes\n", __func__, path, offset, size));
249 if( fi == NULL || buf == NULL ) {
250 rc = RC(rcExe, rcFile, rcReading, rcParam, rcNull);
251 } else if( (data = (const void*)fi->fh) == NULL ) {
252 rc = RC(rcExe, rcFile, rcReading, rcParam, rcCorrupt);
253 } else {
254 rc = SRA_FUSER_ReadNode(path, data, buf, size, offset, &num_read);
255 }
256 if( rc != 0 ) {
257 errno = ConvertRC2errno(rc);
258 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
259 return -errno;
260 }
261 return num_read;
262 }
263
UX_FUSE_release(const char * path,struct fuse_file_info * fi)264 int UX_FUSE_release(const char *path, struct fuse_file_info *fi)
265 {
266 rc_t rc = 0;
267 const void* data = NULL;
268 uint64_t q;
269
270 DEBUG_MSG(8, ("%s: %s\n", __func__, path));
271 if( fi == NULL) {
272 rc = RC(rcExe, rcFile, rcReleasing, rcParam, rcNull);
273 } else if( (data = (const void*)fi->fh) == NULL ) {
274 rc = RC(rcExe, rcFile, rcReading, rcParam, rcCorrupt);
275 } else {
276 rc = SRA_FUSER_CloseNode(path, data);
277 }
278 fi->fh = 0;
279 if( rc != 0 ) {
280 errno = ConvertRC2errno(rc);
281 PLOGERR(klogErr, (klogErr, rc, "$(f): $(p) - $(e)", PLOG_3(PLOG_S(f),PLOG_S(p),PLOG_S(e)), __func__, path, strerror(errno)));
282 return -errno;
283 }
284 atomic64_dec(&num_open_files);
285 q = atomic64_read(&num_open_files);
286 PLOGMSG(klogInfo, (klogInfo, "closed $(n), total open $(q)", PLOG_2(PLOG_S(n),PLOG_U64(q)), path, q));
287 return 0;
288 }
289
UX_FUSE_mknod(const char * path,mode_t m,dev_t d)290 int UX_FUSE_mknod(const char *path, mode_t m, dev_t d)
291 {
292 return -EROFS;
293 }
294
UX_FUSE_mkdir(const char * path,mode_t m)295 int UX_FUSE_mkdir(const char *path, mode_t m)
296 {
297 return -EROFS;
298 }
299
UX_FUSE_unlink(const char * path)300 int UX_FUSE_unlink(const char *path)
301 {
302 return -EROFS;
303 }
304
UX_FUSE_rmdir(const char * path)305 int UX_FUSE_rmdir(const char *path)
306 {
307 return -EROFS;
308 }
309
UX_FUSE_symlink(const char * path,const char * x)310 int UX_FUSE_symlink(const char *path, const char *x)
311 {
312 return -EROFS;
313 }
314
UX_FUSE_rename(const char * path,const char * x)315 int UX_FUSE_rename(const char *path, const char *x)
316 {
317 return -EROFS;
318 }
319
UX_FUSE_link(const char * path,const char * x)320 int UX_FUSE_link(const char *path, const char *x)
321 {
322 return -EROFS;
323 }
324
UX_FUSE_chmod(const char * path,mode_t m)325 int UX_FUSE_chmod(const char *path, mode_t m)
326 {
327 return -EROFS;
328 }
329
UX_FUSE_chown(const char * path,uid_t u,gid_t g)330 int UX_FUSE_chown(const char *path, uid_t u, gid_t g)
331 {
332 return -EROFS;
333 }
334
UX_FUSE_truncate(const char * path,off_t o)335 int UX_FUSE_truncate(const char *path, off_t o)
336 {
337 return -EROFS;
338 }
339
UX_FUSE_utime(const char * path,struct utimbuf * b)340 int UX_FUSE_utime(const char *path, struct utimbuf *b)
341 {
342 return -EROFS;
343 }
344
UX_FUSE_write(const char * path,const char * b,size_t s,off_t o,struct fuse_file_info * fi)345 int UX_FUSE_write(const char *path, const char *b, size_t s, off_t o, struct fuse_file_info *fi)
346 {
347 return -EROFS;
348 }
349
UX_FUSE_flush(const char * path,struct fuse_file_info * fi)350 int UX_FUSE_flush(const char *path, struct fuse_file_info *fi)
351 {
352 return 0;
353 }
354
UX_FUSE_create(const char * path,mode_t m,struct fuse_file_info * fi)355 int UX_FUSE_create(const char *path, mode_t m, struct fuse_file_info *fi)
356 {
357 return -EROFS;
358 }
359
UX_FUSE_ftruncate(const char * path,off_t o,struct fuse_file_info * fi)360 int UX_FUSE_ftruncate(const char *path, off_t o, struct fuse_file_info *fi)
361 {
362 return -EROFS;
363 }
364
365 static
CoreUsage(int fd,const char * progName,bool showHelp,bool showVersion,bool fail,bool forceShowHelp)366 void CoreUsage(int fd, const char *progName, bool showHelp, bool showVersion, bool fail, bool forceShowHelp)
367 {
368 /* used only for FUSE built-in help and version printing */
369 struct fuse_operations ops;
370 struct fuse_args args;
371 memset(&args, 0, sizeof(struct fuse_args));
372 fuse_opt_add_arg(&args, progName); /* fake mount point */
373
374
375 if( fd != STDOUT_FILENO ) {
376 /* redirect usage to log file if it was specified */
377 dup2(fd, STDOUT_FILENO);
378 }
379 if( showHelp ) {
380 const char* p = strrchr(progName, '/');
381 if( p++ == NULL ) {
382 p = progName;
383 }
384 UsageSummary(p);
385 if( !fail || forceShowHelp ) {
386 fuse_opt_add_arg(&args, "-ho");
387 KOutMsg("\n"
388 " -x|--xml-dir <path> XML file with virtual directory structure\n"
389 " -m|--mount-point <path> path to a mount directory \n"
390 " -u|--unmount Unmount only and exit (only -m required)\n"
391 );
392 KOutMsg("\nOptions:\n"
393 " -c|--xml-check <secs> Check XML for update every <arg> seconds,\n"
394 " default: 0 - never.\n"
395 " -r|--xml-root <path> Base directory for a 'path' attributes in XML.\n"
396 " default: '.'\n"
397 );
398 KOutMsg(
399 " -i|--xml-validate <nocheck|ignore> XML validation on load:\n"
400 " nocheck - do not check presence of dir/file in path attribute;\n"
401 " ignore - only report missing dir/file in path attribute;\n"
402 " default behaivour is to fail loading XML if dir/file is not found.\n"
403 );
404 KOutMsg(
405 " --SRA-check <secs> Check SRA config and runs for update\n"
406 " every <arg> seconds, default: 0 - never.\n"
407 " --SRA-cache <path> Write SRA update info to a file.\n"
408 " Must have --SRA-check option value of non-zero.\n"
409 );
410 KOutMsg(
411 " -L|--log-level Logging level as number or enum string. One\n"
412 " of (fatal|sys|int|err|warn|info) or (0-5)\n"
413 " Current/default is warn.\n"
414 " -l|--log-file <path> Use log file specified by path.\n"
415 " -g|--log-reopen <secs> Reopened log file every <arg> seconds\n"
416 " (external log rotation), default: 0 - never.\n"
417 );
418 KOutMsg(
419 #if _DEBUGGING
420 " -+|--debug <Module[-Flag]> Turn on debug output for module. All flags\n"
421 " if not specified.\n"
422 #endif
423 " -v|--verbose Increase the verbosity level of the program.\n"
424 " Use multiple times for more verbosity.\n"
425 " -V|--version Display the version of the program then quit.\n"
426 " -h|--help Output brief explantion for the program.\n"
427 "\n"
428 );
429 }
430 }
431 if( showVersion && !fail ) {
432 HelpVersion(progName, KAppVersion());
433 fuse_opt_add_arg(&args, "--version");
434 }
435 /* force help preceed fuse help */
436 fflush(stdout);
437 /* hack to force fuse lib to output to stdout */
438 dup2(fd, STDERR_FILENO);
439 if( !fail ) {
440 memset(&ops, 0, sizeof(struct fuse_operations));
441 fuse_main(args.argc, args.argv, &ops);
442 }
443 exit(fail ? rcArgv : 0);
444 }
445
446 /*******************************************************************************
447 * KMain - defined for use with kapp library
448 *******************************************************************************/
KMain(int argc,char * argv[])449 rc_t CC KMain(int argc, char *argv[])
450 {
451 int i;
452 rc_t rc;
453
454 bool missedArgs = argc < 2, showHelp = false, showVersion = false, unmount = false, foreground = false;
455 const char* mount_point = NULL, *xml_path = NULL, *log_file = NULL;
456 const char* sra_cache = NULL, *xml_root = ".";
457 char** fargs = (char**)calloc(argc, sizeof(char*));
458 uint32_t xml_sync = 0, log_sync = 0, sra_sync = 0;
459 EXMLValidate xml_validate = eXML_Full;
460 int log_fd = STDOUT_FILENO;
461
462 #ifdef SRAFUSER_LOGLOCALTIME
463 KLogFmtFlagsSet(klogFmtLocalTimestamp);
464 KLogLibFmtFlagsSet(klogFmtLocalTimestamp);
465 KStsFmtFlagsSet(kstsFmtLocalTimestamp);
466 KStsLibFmtFlagsSet(kstsFmtLocalTimestamp);
467 #endif
468
469 for(i = 1; i < argc; i++) {
470 if(!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml-dir")) {
471 xml_path = argv[++i];
472 } else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--mount-point")) {
473 mount_point = argv[++i];
474 } else if(!strcmp(argv[i], "-xs") || !strcmp(argv[i], "-c") || !strcmp(argv[i], "--xml-check")) {
475 xml_sync = AsciiToU32(argv[++i], NULL, NULL);
476 } else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--xml-root")) {
477 xml_root = argv[++i];
478 } else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--xml-validate")) {
479 if( i++ == argc - 1 ) {
480 rc = RC(rcExe, rcArgv, rcValidating, rcParam, rcInsufficient);
481 LOGERR(klogErr, rc, "XML validation setting value");
482 CoreUsage(log_fd, argv[0], true, false, true, false);
483 } else if( !strcmp(argv[i], "ignore") ) {
484 xml_validate = eXML_NoFail;
485 } else if( !strcmp(argv[i], "nocheck") ) {
486 xml_validate = eXML_NoCheck;
487 } else {
488 rc = RC(rcExe, rcArgv, rcValidating, rcParam, rcUnrecognized);
489 PLOGERR(klogErr, (klogErr, rc, "XML validation setting value '$(lvl)'", PLOG_S(lvl), argv[i]));
490 CoreUsage(log_fd, argv[0], true, false, true, false);
491 }
492 } else if(!strcmp(argv[i], "-ds") || !strcmp(argv[i], "--SRA-check")) {
493 sra_sync = AsciiToU32(argv[++i], NULL, NULL);
494 } else if(!strcmp(argv[i], "-df") || !strcmp(argv[i], "--SRA-cache")) {
495 sra_cache = argv[++i];
496 } else if(!strcmp(argv[i], "-u") || !strcmp (argv[i], "--unmount")) {
497 unmount = true;
498 } else if(!strcmp(argv[i], "-L") || !strcmp (argv[i], "--log-level")) {
499 if( i == argc - 1 ) {
500 rc = RC(rcExe, rcArgv, rcValidating, rcParam, rcInsufficient);
501 LOGERR(klogErr, rc, "missing log level");
502 CoreUsage(log_fd, argv[0], true, false, true, false);
503 } else if( (rc = LogLevelSet(argv[++i])) != 0 ) {
504 PLOGERR(klogErr, (klogErr, rc, "log level $(lvl)", PLOG_S(lvl), argv[i]));
505 CoreUsage(log_fd, argv[0], true, false, true, false);
506 }
507 } else if(!strcmp(argv[i], "-+") || !strcmp (argv[i], "--debug")) {
508 #if _DEBUGGING
509 if( i == argc - 1 ) {
510 rc = RC(rcExe, rcArgv, rcValidating, rcParam, rcInsufficient);
511 LOGERR(klogErr, rc, "missing debug level");
512 CoreUsage(log_fd, argv[0], true, false, true, false);
513 } else if( (rc = KDbgSetString(argv[++i])) != 0 ) {
514 PLOGERR(klogErr, (klogErr, rc, "debug level $(lvl)", PLOG_S(lvl), argv[i]));
515 CoreUsage(log_fd, argv[0], true, false, true, false);
516 }
517 #else
518 i++;
519 #endif
520 } else if(!strcmp(argv[i], "-lf") || !strcmp(argv[i], "-l") || !strcmp (argv[i], "--log-file")) {
521 log_file = argv[++i];
522 } else if(!strcmp(argv[i], "-ls") || !strcmp(argv[i], "-g") || !strcmp(argv[i], "--log-reopen")) {
523 log_sync = AsciiToU32(argv[++i], NULL, NULL);
524 } else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
525 showVersion = true;
526 } else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
527 KStsLevel l = KStsLevelGet();
528 KStsLevelSet(++l);
529 } else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "-ho") || !strcmp(argv[i], "--help")) {
530 showHelp = true;
531 } else {
532 /* save arg for FUSE */
533 fargs[i] = argv[i];
534 if( !strcmp(argv[i], "-d") || !strcmp(argv[i], "-f") ||
535 (!strcmp(argv[i], "-o") && (i > argc - 1) && !strcmp(argv[i + 1], "debug")) ) {
536 foreground = true;
537 }
538 }
539 }
540 if( missedArgs ) {
541 CoreUsage(log_fd, argv[0], missedArgs, showVersion, true, true);
542 }
543 if( showHelp || showVersion ) {
544 CoreUsage(log_fd, argv[0], showHelp, showVersion, false, false);
545 }
546 if( (rc = LogFile_Init(log_file, log_sync, foreground, &log_fd)) != 0 ) {
547 LOGERR(klogErr, rc, log_file ? log_file : "no log");
548 CoreUsage(log_fd, argv[0], true, false, true, false);
549 }
550 if( mount_point == NULL ) {
551 LOGERR(klogErr, RC(rcExe, rcArgv, rcValidating, rcParam, rcInsufficient), "mountpoint");
552 CoreUsage(log_fd, argv[0], true, false, true, false);
553 }
554 if( unmount ) {
555 fuse_unmount(mount_point);
556 exit(0);
557 }
558 if( xml_path == NULL ) {
559 LOGERR(klogErr, RC(rcExe, rcArgv, rcValidating, rcParam, rcInsufficient), "virtual directory XML");
560 CoreUsage(log_fd, argv[0], true, false, true, false);
561 }
562 if( i != argc ) {
563 LOGERR(klogErr, RC(rcExe, rcArgv, rcValidating, rcParam, rcExcessive), argv[i]);
564 CoreUsage(log_fd, argv[0], true, false, true, false);
565 }
566 if( stat(mount_point, &g_mount_point_stat) < 0 ) {
567 PLOGMSG(klogErr, (klogErr, "$(p): $(e)", PLOG_2(PLOG_S(p),PLOG_S(e)), mount_point, strerror(errno)));
568 CoreUsage(log_fd, argv[0], true, false, true, false);
569 }
570 g_mount_point_stat.st_dev = 0;
571 g_mount_point_stat.st_ino = 0;
572 g_mount_point_stat.st_mode = S_IFDIR | 0555; /* execute read-only */
573 /* find needs more links to search in subdir */
574 g_mount_point_stat.st_nlink = 1024 * 1024 * 1024;
575
576 if( stat(xml_path, &g_dflt_file_stat) < 0 ) {
577 PLOGMSG(klogErr, (klogErr, "$(p): $(e)", PLOG_2(PLOG_S(p),PLOG_S(e)), xml_path, strerror(errno)));
578 CoreUsage(log_fd, argv[0], true, false, true, false);
579 }
580 g_dflt_file_stat.st_dev = 0;
581 g_dflt_file_stat.st_ino = 0;
582 g_dflt_file_stat.st_mode = S_IFREG | 0444; /* read-only */
583 g_dflt_file_stat.st_nlink = 1;
584 g_dflt_file_stat.st_rdev = 0;
585 g_dflt_file_stat.st_size = 0;
586 g_dflt_file_stat.st_blksize = 0;
587 g_dflt_file_stat.st_blocks = 0;
588
589 if( (rc = Initialize(sra_sync, xml_path, xml_sync, sra_cache, xml_root, xml_validate)) != 0 ) {
590 LOGERR(klogErr, rc, "at initialization");
591 CoreUsage(log_fd, argv[0], true, false, true, false);
592 }
593 DEBUG_MSG(8, ("Mount point set to '%s'\n", mount_point));
594
595 {{ /* FUSE start */
596 struct fuse_operations ops;
597 struct fuse_args args;
598
599 memset(&args, 0, sizeof(struct fuse_args));
600 fuse_opt_add_arg(&args, argv[0]);
601 /* mount point for fuse_main */
602 fuse_opt_add_arg(&args, mount_point);
603 /* save mopunt point dir and program stat */
604 for(i = 0; i < argc; i++) {
605 if( fargs[i] ) {
606 fuse_opt_add_arg(&args, fargs[i]);
607 }
608 }
609 free(fargs);
610 memset(&ops, 0, sizeof(struct fuse_operations));
611 ops.init = UX_FUSE_init;
612 ops.destroy = UX_FUSE_destroy;
613 ops.getattr = UX_FUSE_getattr;
614 ops.readdir = UX_FUSE_readdir;
615 ops.readlink = UX_FUSE_readlink;
616 ops.open = UX_FUSE_open;
617 ops.read = UX_FUSE_read;
618 ops.release = UX_FUSE_release;
619 ops.mknod = UX_FUSE_mknod;
620 ops.mkdir = UX_FUSE_mkdir;
621 ops.unlink = UX_FUSE_unlink;
622 ops.rmdir = UX_FUSE_rmdir;
623 ops.symlink = UX_FUSE_symlink;
624 ops.rename = UX_FUSE_rename;
625 ops.link = UX_FUSE_link;
626 ops.chmod = UX_FUSE_chmod;
627 ops.chown = UX_FUSE_chown;
628 ops.truncate = UX_FUSE_truncate;
629 ops.utime = UX_FUSE_utime;
630 ops.write = UX_FUSE_write;
631 ops.flush = UX_FUSE_flush;
632 ops.create = UX_FUSE_create;
633 ops.ftruncate = UX_FUSE_ftruncate;
634 rc = fuse_main(args.argc, args.argv, &ops);
635 }}
636 return rc;
637 }
638