GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/loader.cc
Date: 2025-05-11 02:35:43
Exec Total Coverage
Lines: 0 592 0.0%
Branches: 0 1026 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Implements stub callback functions for Fuse. Their purpose is to
5 * redirect calls to the cvmfs shared library and to block calls during the
6 * update of the library.
7 *
8 * The main executable and the cvmfs shared library _must not_ share any
9 * symbols.
10 */
11
12 #define ENOATTR ENODATA /**< instead of including attr/xattr.h */
13 #define _FILE_OFFSET_BITS 64
14
15
16 #include "loader.h"
17
18 #include <dlfcn.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sched.h>
22 #include <signal.h>
23 #include <stddef.h>
24 #include <sys/resource.h>
25 #include <time.h>
26 #include <unistd.h>
27 // If valgrind headers are present on the build system, then we can detect
28 // valgrind at runtime.
29 #ifdef HAS_VALGRIND_HEADERS
30 #include <valgrind/valgrind.h>
31 #endif
32
33 #include <cassert>
34 #include <cstdlib>
35 #include <cstring>
36 #include <string>
37 #include <vector>
38
39 #include "duplex_fuse.h"
40 #include "fence.h"
41 #include "fuse_main.h"
42 #include "loader_talk.h"
43 #include "options.h"
44 #include "sanitizer.h"
45 #include "util/atomic.h"
46 #include "util/exception.h"
47 #include "util/logging.h"
48 #include "util/platform.h"
49 #include "util/posix.h"
50 #include "util/string.h"
51
52 using namespace std; // NOLINT
53
54 namespace loader {
55
56 // Follow the fuse convention for option parsing
57 struct CvmfsOptions {
58 char *config;
59 int uid;
60 int gid;
61 int system_mount;
62 int grab_mountpoint;
63 int cvmfs_suid;
64 int disable_watchdog;
65 int simple_options_parsing;
66 int foreground;
67 int fuse_debug;
68
69 // Ignored options
70 int ign_netdev;
71 int ign_user;
72 int ign_nouser;
73 int ign_users;
74 int ign_auto;
75 int ign_noauto;
76 int ign_libfuse;
77 };
78
79 enum {
80 KEY_HELP,
81 KEY_VERSION,
82 KEY_FOREGROUND,
83 KEY_SINGLETHREAD,
84 KEY_FUSE_DEBUG,
85 KEY_CVMFS_DEBUG,
86 KEY_OPTIONS_PARSE,
87 };
88 #define CVMFS_OPT(t, p, v) { t, offsetof(struct CvmfsOptions, p), v }
89 #define CVMFS_SWITCH(t, p) { t, offsetof(struct CvmfsOptions, p), 1 }
90 static struct fuse_opt cvmfs_array_opts[] = {
91 CVMFS_OPT("config=%s", config, 0),
92 CVMFS_OPT("uid=%d", uid, 0),
93 CVMFS_OPT("gid=%d", gid, 0),
94 CVMFS_SWITCH("system_mount", system_mount),
95 CVMFS_SWITCH("grab_mountpoint", grab_mountpoint),
96 CVMFS_SWITCH("cvmfs_suid", cvmfs_suid),
97 CVMFS_SWITCH("disable_watchdog", disable_watchdog),
98 CVMFS_SWITCH("simple_options_parsing", simple_options_parsing),
99 CVMFS_SWITCH("foreground", foreground),
100 CVMFS_SWITCH("fuse_debug", fuse_debug),
101
102 // Ignore these options
103 CVMFS_SWITCH("_netdev", ign_netdev),
104 CVMFS_SWITCH("user", ign_user),
105 CVMFS_SWITCH("nouser", ign_nouser),
106 CVMFS_SWITCH("users", ign_users),
107 CVMFS_SWITCH("auto", ign_auto),
108 CVMFS_SWITCH("noauto", ign_noauto),
109 CVMFS_OPT("libfuse=%d", ign_libfuse, 0),
110
111 FUSE_OPT_KEY("-V", KEY_VERSION),
112 FUSE_OPT_KEY("--version", KEY_VERSION),
113 FUSE_OPT_KEY("-h", KEY_HELP),
114 FUSE_OPT_KEY("--help", KEY_HELP),
115 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
116 FUSE_OPT_KEY("-d", KEY_FUSE_DEBUG),
117 FUSE_OPT_KEY("debug", KEY_CVMFS_DEBUG),
118 FUSE_OPT_KEY("-s", KEY_SINGLETHREAD),
119 FUSE_OPT_KEY("parse", KEY_OPTIONS_PARSE),
120 FUSE_OPT_KEY("-k", KEY_OPTIONS_PARSE),
121 {0, 0, 0},
122 };
123
124
125 string *repository_name_ = NULL;
126 string *mount_point_ = NULL;
127 string *config_files_ = NULL;
128 string *socket_path_ = NULL;
129 string *usyslog_path_ = NULL;
130 int fuse3_max_threads_ = 0;
131 int fuse3_idle_threads_ = 0;
132 uid_t uid_ = 0;
133 gid_t gid_ = 0;
134 bool single_threaded_ = false;
135 bool foreground_ = false;
136 bool debug_mode_ = false;
137 bool system_mount_ = false;
138 bool grab_mountpoint_ = false;
139 bool parse_options_only_ = false;
140 bool suid_mode_ = false;
141 bool premounted_ = false;
142 bool disable_watchdog_ = false;
143 bool simple_options_parsing_ = false;
144 void *library_handle_;
145 Fence *fence_reload_;
146 CvmfsExports *cvmfs_exports_;
147 LoaderExports *loader_exports_;
148
149
150 static void Usage(const string &exename) {
151 LogCvmfs(kLogCvmfs, kLogStdout,
152 "The CernVM File System\n"
153 "Version %s\n"
154 "Copyright (c) 2009- CERN, all rights reserved\n\n"
155 "Please visit http://cernvm.cern.ch for details.\n\n"
156 "Usage: %s [-h] [-V] [-s] [-f] [-d] [-k] [-o mount options] "
157 "<repository name> <mount point>\n\n"
158 "CernVM-FS general options:\n"
159 " --help|-h Print Help output (this)\n"
160 " --version|-V Print CernVM-FS version\n"
161 " -s Run singlethreaded\n"
162 " -f Run in foreground\n"
163 " -d Enable debugging\n"
164 " -k Parse options\n"
165 "CernVM-FS mount options:\n"
166 " -o config=FILES colon-separated path list of config files\n"
167 " -o uid=UID Drop credentials to another user\n"
168 " -o gid=GID Drop credentials to another group\n"
169 " -o system_mount Indicate that mount is system-wide\n"
170 " -o grab_mountpoint give ownership of the mountpoint to the user "
171 "before mounting (required for autofs)\n"
172 " -o parse Parse and print cvmfs parameters\n"
173 " -o cvmfs_suid Enable suid mode\n\n"
174 " -o disable_watchdog Do not spawn a post mortem crash handler\n"
175 " -o foreground Run in foreground\n"
176 " -o libfuse=[2,3] Enforce a certain libfuse version\n"
177 "Fuse mount options:\n"
178 " -o allow_other allow access to other users\n"
179 " -o allow_root allow access to root\n"
180 " -o nonempty allow mounts over non-empty directory\n",
181 CVMFS_VERSION, exename.c_str());
182 }
183
184 /**
185 * For an premounted mountpoint, the argument is the file descriptor to
186 * /dev/fuse provided in the form /dev/fd/%d
187 */
188 bool CheckPremounted(const std::string &mountpoint) {
189 int len;
190 unsigned fd;
191 bool retval = (sscanf(mountpoint.c_str(), "/dev/fd/%u%n", &fd, &len) == 1) &&
192 (len >= 0) &&
193 (static_cast<unsigned>(len) == mountpoint.length());
194 if (retval) {
195 LogCvmfs(kLogCvmfs, kLogStdout,
196 "CernVM-FS: pre-mounted on file descriptor %d", fd);
197 return true;
198 }
199 return false;
200 }
201
202
203 static void stub_init(void *userdata, struct fuse_conn_info *conn) {
204 FenceGuard fence_guard(fence_reload_);
205 cvmfs_exports_->cvmfs_operations.init(userdata, conn);
206 }
207
208
209 static void stub_destroy(void *userdata) {
210 FenceGuard fence_guard(fence_reload_);
211 cvmfs_exports_->cvmfs_operations.destroy(userdata);
212 }
213
214
215 static void stub_lookup(fuse_req_t req, fuse_ino_t parent,
216 const char *name)
217 {
218 FenceGuard fence_guard(fence_reload_);
219 cvmfs_exports_->cvmfs_operations.lookup(req, parent, name);
220 }
221
222
223 static void stub_getattr(fuse_req_t req, fuse_ino_t ino,
224 struct fuse_file_info *fi)
225 {
226 FenceGuard fence_guard(fence_reload_);
227 cvmfs_exports_->cvmfs_operations.getattr(req, ino, fi);
228 }
229
230
231 static void stub_readlink(fuse_req_t req, fuse_ino_t ino) {
232 FenceGuard fence_guard(fence_reload_);
233 cvmfs_exports_->cvmfs_operations.readlink(req, ino);
234 }
235
236
237 static void stub_opendir(fuse_req_t req, fuse_ino_t ino,
238 struct fuse_file_info *fi)
239 {
240 FenceGuard fence_guard(fence_reload_);
241 cvmfs_exports_->cvmfs_operations.opendir(req, ino, fi);
242 }
243
244
245 static void stub_releasedir(fuse_req_t req, fuse_ino_t ino,
246 struct fuse_file_info *fi)
247 {
248 FenceGuard fence_guard(fence_reload_);
249 cvmfs_exports_->cvmfs_operations.releasedir(req, ino, fi);
250 }
251
252
253 static void stub_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
254 off_t off, struct fuse_file_info *fi)
255 {
256 FenceGuard fence_guard(fence_reload_);
257 cvmfs_exports_->cvmfs_operations.readdir(req, ino, size, off, fi);
258 }
259
260
261 static void stub_open(fuse_req_t req, fuse_ino_t ino,
262 struct fuse_file_info *fi)
263 {
264 FenceGuard fence_guard(fence_reload_);
265 cvmfs_exports_->cvmfs_operations.open(req, ino, fi);
266 }
267
268
269 static void stub_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
270 struct fuse_file_info *fi)
271 {
272 FenceGuard fence_guard(fence_reload_);
273 cvmfs_exports_->cvmfs_operations.read(req, ino, size, off, fi);
274 }
275
276
277 static void stub_release(fuse_req_t req, fuse_ino_t ino,
278 struct fuse_file_info *fi)
279 {
280 FenceGuard fence_guard(fence_reload_);
281 cvmfs_exports_->cvmfs_operations.release(req, ino, fi);
282 }
283
284
285 static void stub_statfs(fuse_req_t req, fuse_ino_t ino) {
286 FenceGuard fence_guard(fence_reload_);
287 cvmfs_exports_->cvmfs_operations.statfs(req, ino);
288 }
289
290
291 #ifdef __APPLE__
292 static void stub_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
293 size_t size, uint32_t position)
294 #else
295 static void stub_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
296 size_t size)
297 #endif
298 {
299 FenceGuard fence_guard(fence_reload_);
300 #ifdef __APPLE__
301 cvmfs_exports_->cvmfs_operations.getxattr(req, ino, name, size, position);
302 #else
303 cvmfs_exports_->cvmfs_operations.getxattr(req, ino, name, size);
304 #endif
305 }
306
307
308 static void stub_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
309 FenceGuard fence_guard(fence_reload_);
310 cvmfs_exports_->cvmfs_operations.listxattr(req, ino, size);
311 }
312
313
314 static void stub_forget(
315 fuse_req_t req,
316 fuse_ino_t ino,
317 #if CVMFS_USE_LIBFUSE == 2
318 unsigned long nlookup // NOLINT
319 #else
320 uint64_t nlookup
321 #endif
322 ) {
323 FenceGuard fence_guard(fence_reload_);
324 cvmfs_exports_->cvmfs_operations.forget(req, ino, nlookup);
325 }
326
327
328 #if (FUSE_VERSION >= 29)
329 static void stub_forget_multi(
330 fuse_req_t req,
331 size_t count,
332 struct fuse_forget_data *forgets
333 ) {
334 FenceGuard fence_guard(fence_reload_);
335 cvmfs_exports_->cvmfs_operations.forget_multi(req, count, forgets);
336 }
337 #endif
338
339
340 /**
341 * The callback used when fuse is parsing all the options
342 * We separate CVMFS options from FUSE options here.
343 *
344 * \return On success zero, else non-zero
345 */
346 static int ParseFuseOptions(void *data __attribute__((unused)), const char *arg,
347 int key, struct fuse_args *outargs)
348 {
349 unsigned arglen = 0;
350 if (arg)
351 arglen = strlen(arg);
352 switch (key) {
353 case FUSE_OPT_KEY_OPT:
354 // Check if it a cvmfs option
355 if ((arglen > 0) && (arg[0] != '-')) {
356 const char **o;
357 for (o = (const char**)cvmfs_array_opts; *o; o++) {
358 unsigned olen = strlen(*o);
359 if ((arglen > olen && arg[olen] == '=') &&
360 (strncasecmp(arg, *o, olen) == 0))
361 return 0;
362 }
363 }
364 return 1;
365
366 case FUSE_OPT_KEY_NONOPT:
367 // first: repository name, second: mount point
368 assert(arg != NULL);
369 if (!repository_name_) {
370 repository_name_ = new string(arg);
371 } else {
372 if (mount_point_)
373 return 1;
374 mount_point_ = new string(arg);
375 premounted_ = CheckPremounted(*mount_point_);
376 }
377 return 0;
378
379 case KEY_HELP:
380 Usage(outargs->argv[0]);
381 exit(0);
382 case KEY_VERSION:
383 LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS version %s\n",
384 CVMFS_VERSION);
385 exit(0);
386 case KEY_FOREGROUND:
387 foreground_ = true;
388 return 0;
389 case KEY_SINGLETHREAD:
390 single_threaded_ = true;
391 return 0;
392 case KEY_FUSE_DEBUG:
393 fuse_opt_add_arg(outargs, "-d");
394 case KEY_CVMFS_DEBUG:
395 debug_mode_ = true;
396 return 0;
397 case KEY_OPTIONS_PARSE:
398 parse_options_only_ = true;
399 return 0;
400 default:
401 PANIC(kLogStderr, "internal option parsing error");
402 }
403 }
404
405 static fuse_args *ParseCmdLine(int argc, char *argv[]) {
406 struct fuse_args *mount_options = new fuse_args();
407 CvmfsOptions cvmfs_options;
408 memset(&cvmfs_options, 0, sizeof(cvmfs_options));
409
410 mount_options->argc = argc;
411 mount_options->argv = argv;
412 mount_options->allocated = 0;
413 if ((fuse_opt_parse(mount_options, &cvmfs_options, cvmfs_array_opts,
414 ParseFuseOptions) != 0) ||
415 !mount_point_ || !repository_name_)
416 {
417 delete mount_options;
418 return NULL;
419 }
420 if (cvmfs_options.config) {
421 config_files_ = new string(cvmfs_options.config);
422 free(cvmfs_options.config);
423 }
424 uid_ = cvmfs_options.uid;
425 gid_ = cvmfs_options.gid;
426 system_mount_ = cvmfs_options.system_mount;
427 grab_mountpoint_ = cvmfs_options.grab_mountpoint;
428 suid_mode_ = cvmfs_options.cvmfs_suid;
429 disable_watchdog_ = cvmfs_options.disable_watchdog;
430 simple_options_parsing_ = cvmfs_options.simple_options_parsing;
431 if (cvmfs_options.foreground) {
432 foreground_ = true;
433 }
434 if (cvmfs_options.fuse_debug) {
435 fuse_opt_add_arg(mount_options, "-d");
436 }
437
438 return mount_options;
439 }
440
441
442 static bool MatchFuseOption(const fuse_args *mount_options, const char *opt) {
443 for (int i = 0; i < mount_options->argc; i++) {
444 char *arg = mount_options->argv[i];
445 char *p = strstr(arg, opt);
446 if (p != NULL) {
447 if (p == arg)
448 return true;
449 char c = *(p-1);
450 if ((c == ',') || (c == ' '))
451 return true;
452 if ((c == 'o') && (p >= arg+2) && (*(p-2) == '-'))
453 return true;
454 }
455 }
456 return false;
457 }
458
459
460 static void SetFuseOperations(struct fuse_lowlevel_ops *loader_operations) {
461 memset(loader_operations, 0, sizeof(*loader_operations));
462
463 loader_operations->init = stub_init;
464 loader_operations->destroy = stub_destroy;
465
466 loader_operations->lookup = stub_lookup;
467 loader_operations->getattr = stub_getattr;
468 loader_operations->readlink = stub_readlink;
469 loader_operations->open = stub_open;
470 loader_operations->read = stub_read;
471 loader_operations->release = stub_release;
472 loader_operations->opendir = stub_opendir;
473 loader_operations->readdir = stub_readdir;
474 loader_operations->releasedir = stub_releasedir;
475 loader_operations->statfs = stub_statfs;
476 loader_operations->getxattr = stub_getxattr;
477 loader_operations->listxattr = stub_listxattr;
478 loader_operations->forget = stub_forget;
479 }
480
481
482 static void *OpenLibrary(const string &path) {
483 return dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
484 }
485
486
487 static void CloseLibrary() {
488 #ifdef HAS_VALGRIND_HEADERS
489 // If the libcvmfs_fuse library is unloaded, valgrind can't resolve the
490 // symbols anymore. We skip under valgrind.
491 if (!RUNNING_ON_VALGRIND) {
492 #endif
493 dlclose(library_handle_);
494 library_handle_ = NULL;
495 #ifdef HAS_VALGRIND_HEADERS
496 }
497 #endif
498 }
499
500
501 static CvmfsExports *LoadLibrary(const bool debug_mode,
502 LoaderExports *loader_exports)
503 {
504 std::string local_lib_path = "./";
505 if (getenv("CVMFS_LIBRARY_PATH") != NULL) {
506 local_lib_path = getenv("CVMFS_LIBRARY_PATH");
507 if (!local_lib_path.empty() && (*local_lib_path.rbegin() != '/'))
508 local_lib_path.push_back('/');
509 }
510
511 #if CVMFS_USE_LIBFUSE == 2
512 string library_name = string("cvmfs_fuse") + ((debug_mode) ? "_debug" : "");
513 #else
514 string library_name = string("cvmfs_fuse3") + ((debug_mode) ? "_debug" : "");
515 #endif
516 library_name = platform_libname(library_name);
517 string error_messages;
518
519 vector<string> library_paths; // TODO(rmeusel): C++11 initializer
520 if (library_paths.empty()) {
521 library_paths.push_back(local_lib_path + library_name);
522 library_paths.push_back("/usr/lib/" + library_name);
523 library_paths.push_back("/usr/lib64/" + library_name);
524 #ifdef __APPLE__
525 // Since OS X El Capitan (10.11) came with SIP, we needed to relocate our
526 // binaries from /usr/... to /usr/local/...
527 library_paths.push_back("/usr/local/lib/" + library_name);
528 #endif
529 }
530
531 vector<string>::const_iterator i = library_paths.begin();
532 vector<string>::const_iterator iend = library_paths.end();
533 for (; i != iend; ++i) { // TODO(rmeusel): C++11 range based for
534 library_handle_ = OpenLibrary(*i);
535 if (library_handle_ != NULL) {
536 break;
537 }
538
539 error_messages += string(dlerror()) + "\n";
540 }
541
542 if (!library_handle_) {
543 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
544 "failed to load cvmfs library, tried: '%s'\n%s",
545 JoinStrings(library_paths, "' '").c_str(), error_messages.c_str());
546 return NULL;
547 }
548
549 CvmfsExports **exports_ptr = reinterpret_cast<CvmfsExports **>(
550 dlsym(library_handle_, "g_cvmfs_exports"));
551 if (!exports_ptr)
552 return NULL;
553
554 if (loader_exports) {
555 LoadEvent *load_event = new LoadEvent();
556 load_event->timestamp = time(NULL);
557 load_event->so_version = (*exports_ptr)->so_version;
558 loader_exports->history.push_back(load_event);
559 }
560
561 return *exports_ptr;
562 }
563
564 Failures Reload(const int fd_progress, const bool stop_and_go,
565 const ReloadMode reload_mode) {
566 int retval;
567
568 // for legacy call we take the current state of debug_mode_
569 if (reload_mode == kReloadDebug) {
570 debug_mode_ = true;
571 } else if (reload_mode == kReloadNoDebug) {
572 debug_mode_ = false;
573 }
574
575 retval = cvmfs_exports_->fnMaintenanceMode(fd_progress);
576 if (!retval)
577 return kFailMaintenanceMode;
578
579 SendMsg2Socket(fd_progress, "Blocking new file system calls\n");
580 fence_reload_->Close();
581
582 SendMsg2Socket(fd_progress, "Waiting for active file system calls\n");
583 fence_reload_->Drain();
584
585 retval = cvmfs_exports_->fnSaveState(fd_progress,
586 &loader_exports_->saved_states);
587 if (!retval)
588 return kFailSaveState;
589
590 SendMsg2Socket(fd_progress, "Unloading Fuse module\n");
591 cvmfs_exports_->fnFini();
592 CloseLibrary();
593
594 if (stop_and_go) {
595 CreateFile(*socket_path_ + ".paused", 0600);
596 SendMsg2Socket(fd_progress, "Waiting for the delivery of SIGUSR1...\n");
597 WaitForSignal(SIGUSR1);
598 unlink((*socket_path_ + ".paused").c_str());
599 }
600
601 SendMsg2Socket(fd_progress, "Re-Loading Fuse module\n");
602 cvmfs_exports_ = LoadLibrary(debug_mode_, loader_exports_);
603 if (!cvmfs_exports_)
604 return kFailLoadLibrary;
605 retval = cvmfs_exports_->fnInit(loader_exports_);
606 if (retval != kFailOk) {
607 string msg_progress = cvmfs_exports_->fnGetErrorMsg() + " (" +
608 StringifyInt(retval) + ")\n";
609 LogCvmfs(kLogCvmfs, kLogSyslogErr, "%s", msg_progress.c_str());
610 SendMsg2Socket(fd_progress, msg_progress);
611 return (Failures)retval;
612 }
613
614 retval = cvmfs_exports_->fnRestoreState(fd_progress,
615 loader_exports_->saved_states);
616 if (!retval)
617 return kFailRestoreState;
618 cvmfs_exports_->fnFreeSavedState(fd_progress, loader_exports_->saved_states);
619 for (unsigned i = 0, l = loader_exports_->saved_states.size(); i < l; ++i) {
620 delete loader_exports_->saved_states[i];
621 }
622 loader_exports_->saved_states.clear();
623
624 SendMsg2Socket(fd_progress, "Activating Fuse module\n");
625 cvmfs_exports_->fnSpawn();
626
627 fence_reload_->Open();
628 return kFailOk;
629 }
630
631 } // namespace loader
632
633
634 using namespace loader; // NOLINT(build/namespaces)
635
636 int FuseMain(int argc, char *argv[]) {
637 // Set a decent umask for new files (no write access to group/everyone).
638 // We want to allow group write access for the talk-socket.
639 umask(007);
640 // SIGUSR1 is used for the stop_and_go mode during reload
641 BlockSignal(SIGUSR1);
642
643 int retval;
644
645 // Jump into alternative process flavors (e.g. shared cache manager)
646 // We are here due to a fork+execve (ManagedExec in util.cc) or due to
647 // utility calls of cvmfs2
648 if ((argc > 1) && (strstr(argv[1], "__") == argv[1])) {
649 if (string(argv[1]) == string("__RELOAD__")) {
650 if (argc < 3)
651 return 1;
652 bool stop_and_go = false;
653 if ((argc > 3) && (string(argv[3]) == "stop_and_go"))
654 stop_and_go = true;
655
656 // always last param of the cvmfs2 __RELOAD__ command
657 // check if debug mode is requested
658 // NOTE:
659 // debug mode is decided based on CVMFS_DEBUGLOG being set or not
660 // this means: reloading is now always based on CVMFS_DEBUGLOG, and
661 // reload ignores the current state
662 //
663 // if you mount with debug but do not set CVMFS_DEBUGLOG and reload,
664 // you will reload with
665 if (std::string(argv[argc - 1]) == std::string("--debug")) {
666 debug_mode_ = true;
667 } else {
668 debug_mode_ = false;
669 }
670 retval = loader_talk::MainReload(argv[2], stop_and_go, debug_mode_);
671
672 if ((retval != 0) && (stop_and_go)) {
673 CreateFile(string(argv[2]) + ".paused.crashed", 0600);
674 }
675 return retval;
676 }
677
678 if (string(argv[1]) == string("__MK_ALIEN_CACHE__")) {
679 if (argc < 5)
680 return 1;
681 string alien_cache_dir = argv[2];
682 sanitizer::PositiveIntegerSanitizer sanitizer;
683 if (!sanitizer.IsValid(argv[3]) || !sanitizer.IsValid(argv[4]))
684 return 1;
685 uid_t uid_owner = String2Uint64(argv[3]);
686 gid_t gid_owner = String2Uint64(argv[4]);
687
688 int retval = MkdirDeep(alien_cache_dir, 0770);
689 if (!retval) {
690 LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create %s",
691 alien_cache_dir.c_str());
692 return 1;
693 }
694 retval = chown(alien_cache_dir.c_str(), uid_owner, gid_owner);
695 if (retval != 0) {
696 LogCvmfs(kLogCvmfs, kLogStderr, "Failed to set owner of %s to %d:%d",
697 alien_cache_dir.c_str(), uid_owner, gid_owner);
698 return 1;
699 }
700 retval = SwitchCredentials(uid_owner, gid_owner, false);
701 if (!retval) {
702 LogCvmfs(kLogCvmfs, kLogStderr, "Failed to impersonate %d:%d",
703 uid_owner, gid_owner);
704 return 1;
705 }
706 // Allow access to user and group
707 retval = MakeCacheDirectories(alien_cache_dir, 0770);
708 if (!retval) {
709 LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create cache skeleton");
710 return 1;
711 }
712 return 0;
713 }
714
715 debug_mode_ = getenv("__CVMFS_DEBUG_MODE__") != NULL;
716 cvmfs_exports_ = LoadLibrary(debug_mode_, NULL);
717 if (!cvmfs_exports_)
718 return kFailLoadLibrary;
719 return cvmfs_exports_->fnAltProcessFlavor(argc, argv);
720 }
721
722 // Option parsing
723 struct fuse_args *mount_options;
724 mount_options = ParseCmdLine(argc, argv);
725 if (!mount_options) {
726 Usage(argv[0]);
727 return kFailOptions;
728 }
729
730 string parameter;
731 OptionsManager *options_manager;
732 if (simple_options_parsing_) {
733 options_manager = new SimpleOptionsParser(
734 new DefaultOptionsTemplateManager(*repository_name_));
735 } else {
736 options_manager = new BashOptionsManager(
737 new DefaultOptionsTemplateManager(*repository_name_));
738 }
739 if (config_files_) {
740 vector<string> tokens = SplitString(*config_files_, ':');
741 for (unsigned i = 0, s = tokens.size(); i < s; ++i) {
742 options_manager->ParsePath(tokens[i], false);
743 }
744 } else {
745 options_manager->ParseDefault(*repository_name_);
746 }
747
748 #ifdef __APPLE__
749 string volname = "-ovolname=" + *repository_name_;
750 fuse_opt_add_arg(mount_options, volname.c_str());
751 // Allow for up to 5 minute "hangs" before OS X may kill cvmfs
752 fuse_opt_add_arg(mount_options, "-odaemon_timeout=300");
753 fuse_opt_add_arg(mount_options, "-onoapplexattr");
754 // Should libfuse be single-threaded? See CVM-871, CVM-855
755 // single_threaded_ = true;
756 #endif
757 if (options_manager->GetValue("CVMFS_MOUNT_RW", &parameter) &&
758 options_manager->IsOn(parameter))
759 {
760 fuse_opt_add_arg(mount_options, "-orw");
761 } else {
762 fuse_opt_add_arg(mount_options, "-oro");
763 }
764 fuse_opt_add_arg(mount_options, "-onodev");
765 if (options_manager->GetValue("CVMFS_SUID", &parameter) &&
766 options_manager->IsOn(parameter))
767 {
768 suid_mode_ = true;
769 }
770 if (suid_mode_) {
771 if (getuid() != 0) {
772 PANIC(kLogStderr | kLogSyslogErr,
773 "must be root to mount with suid option");
774 }
775 fuse_opt_add_arg(mount_options, "-osuid");
776 LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS: running with suid support");
777 }
778
779 if (options_manager->GetValue("CVMFS_CPU_AFFINITY", &parameter)) {
780 #ifndef __APPLE__
781 cpu_set_t mask;
782 vector<string> cpus = SplitString(parameter, ',');
783 CPU_ZERO(&mask);
784 for (vector<string>::iterator i = cpus.begin(); i != cpus.end(); i++) {
785 CPU_SET(String2Uint64(Trim(*i)), &mask);
786 }
787 LogCvmfs(kLogCvmfs, kLogStdout,
788 "CernVM-FS: setting CPU Affinity to %s", parameter.c_str());
789 int err = sched_setaffinity(0, sizeof(mask), &mask);
790 if (err != 0) {
791 LogCvmfs(kLogCvmfs, kLogStdout | kLogSyslogErr,
792 "Setting CPU Affinity failed with error %d", errno);
793 }
794 #else
795 LogCvmfs(kLogCvmfs, kLogStdout | kLogSyslogErr,
796 "CPU affinity setting not supported on macOS");
797 #endif
798 }
799 loader_exports_ = new LoaderExports();
800 loader_exports_->loader_version = CVMFS_VERSION;
801 loader_exports_->boot_time = time(NULL);
802 loader_exports_->program_name = argv[0];
803 loader_exports_->foreground = foreground_;
804 loader_exports_->repository_name = *repository_name_;
805 loader_exports_->mount_point = *mount_point_;
806 loader_exports_->device_id = "0:0"; // initially unknown, set after mount
807 loader_exports_->disable_watchdog = disable_watchdog_;
808 loader_exports_->simple_options_parsing = simple_options_parsing_;
809 if (config_files_)
810 loader_exports_->config_files = *config_files_;
811 else
812 loader_exports_->config_files = "";
813
814 if (parse_options_only_) {
815 LogCvmfs(kLogCvmfs, kLogStdout, "# CernVM-FS parameters:\n%s",
816 options_manager->Dump().c_str());
817 return 0;
818 }
819
820 // Logging
821 if (options_manager->GetValue("CVMFS_SYSLOG_LEVEL", &parameter))
822 SetLogSyslogLevel(String2Uint64(parameter));
823 else
824 SetLogSyslogLevel(3);
825 if (options_manager->GetValue("CVMFS_SYSLOG_FACILITY", &parameter))
826 SetLogSyslogFacility(String2Int64(parameter));
827 SetLogSyslogPrefix(*repository_name_);
828 // Deferr setting usyslog until credentials are dropped
829
830 // Permissions check
831 if (options_manager->GetValue("CVMFS_CHECK_PERMISSIONS", &parameter)) {
832 if (options_manager->IsOn(parameter)) {
833 fuse_opt_add_arg(mount_options, "-odefault_permissions");
834 }
835 }
836
837 if (!premounted_ && !DirectoryExists(*mount_point_)) {
838 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
839 "Mount point %s does not exist", mount_point_->c_str());
840 return kFailPermission;
841 }
842
843 // Number of file descriptors
844 if (options_manager->GetValue("CVMFS_NFILES", &parameter)) {
845 int retval = SetLimitNoFile(String2Uint64(parameter));
846 if (retval == -2) {
847 LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS: running under valgrind");
848 } else if (retval == -1) {
849 if (system_mount_) {
850 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
851 "Failed to set maximum number of open files, "
852 "insufficient permissions");
853 return kFailPermission;
854 }
855 unsigned soft_limit, hard_limit;
856 GetLimitNoFile(&soft_limit, &hard_limit);
857 LogCvmfs(kLogCvmfs, kLogStdout | kLogSyslogWarn,
858 "Failed to set requested number of open files, "
859 "using maximum number %u", hard_limit);
860 if (hard_limit > soft_limit) {
861 (void) SetLimitNoFile(hard_limit);
862 }
863 }
864 }
865
866 // Apply OOM score adjustment
867 if (options_manager->GetValue("CVMFS_OOM_SCORE_ADJ", &parameter)) {
868 string proc_path = "/proc/" + StringifyInt(getpid()) + "/oom_score_adj";
869 int fd_oom = open(proc_path.c_str(), O_WRONLY);
870 if (fd_oom < 0) {
871 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogWarn,
872 "failed to open %s", proc_path.c_str());
873 } else {
874 bool retval = SafeWrite(fd_oom, parameter.data(), parameter.length());
875 if (!retval) {
876 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogWarn,
877 "failed to set OOM score adjustment to %s", parameter.c_str());
878 }
879 close(fd_oom);
880 }
881 }
882
883 // Protect the process from being killed by systemd
884 if (options_manager->GetValue("CVMFS_SYSTEMD_NOKILL", &parameter) &&
885 options_manager->IsOn(parameter))
886 {
887 argv[0][0] = '@';
888 }
889
890 // Grab mountpoint
891 if (grab_mountpoint_) {
892 if ((chown(mount_point_->c_str(), uid_, gid_) != 0) ||
893 (chmod(mount_point_->c_str(), 0755) != 0))
894 {
895 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
896 "Failed to grab mountpoint %s (%d)",
897 mount_point_->c_str(), errno);
898 return kFailPermission;
899 }
900 }
901
902 #if CVMFS_USE_LIBFUSE != 2
903 int premount_fd = -1;
904 if (!premounted_ && !suid_mode_ && getuid() == 0) {
905 // If not already premounted or using suid mode, premount the fuse
906 // mountpoint before dropping privileges to avoid the need for fusermount.
907 // Requires libfuse >= 3.3.0.
908 platform_stat64 info;
909 // Need to know if it is a directory or not
910 if (platform_stat(mount_point_->c_str(), &info) != 0) { LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
911 "Failed to stat mountpoint %s (%d)",
912 mount_point_->c_str(), errno);
913 return kFailPermission;
914 }
915 premount_fd = open("/dev/fuse", O_RDWR);
916 if (premount_fd == -1) {
917 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
918 "Failed to open /dev/fuse (%d)", errno);
919 return kFailPermission;
920 }
921 char opts[128];
922 snprintf(opts, sizeof(opts),
923 "fd=%i,rootmode=%o,user_id=0,group_id=0%s%s",
924 premount_fd, info.st_mode & S_IFMT,
925 MatchFuseOption(mount_options, "default_permissions") ?
926 ",default_permissions" : "",
927 MatchFuseOption(mount_options, "allow_other") ? ",allow_other" : "");
928 unsigned long flags = MS_NOSUID | MS_NODEV | MS_RELATIME;
929 if (!MatchFuseOption(mount_options, "rw")) {
930 flags |= MS_RDONLY;
931 }
932 if (mount("cvmfs2", mount_point_->c_str(), "fuse", flags, opts) == -1) {
933 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
934 "Failed to mount -t fuse -o %s cvmfs2 %s (%d)",
935 opts, mount_point_->c_str(), errno);
936 return kFailPermission;
937 }
938 }
939 #endif
940
941 int fd_mountinfo = -1; // needs to be declared before start using goto
942
943 // Drop credentials
944 if ((uid_ != 0) || (gid_ != 0)) {
945 LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS: running with credentials %d:%d",
946 uid_, gid_);
947 const bool retrievable = (suid_mode_ || !disable_watchdog_);
948 if (!SwitchCredentials(uid_, gid_, retrievable)) {
949 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
950 "Failed to drop credentials");
951 retval = kFailPermission;
952 goto cleanup;
953 }
954 }
955 if (disable_watchdog_) {
956 LogCvmfs(kLogCvmfs, kLogDebug, "No watchdog, enabling core files");
957 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
958 }
959
960 // Only set usyslog now, otherwise file permissions are wrong
961 usyslog_path_ = new string();
962 if (options_manager->GetValue("CVMFS_USYSLOG", &parameter))
963 *usyslog_path_ = parameter;
964 SetLogMicroSyslog(*usyslog_path_);
965
966 if (single_threaded_) {
967 LogCvmfs(kLogCvmfs, kLogStdout,
968 "CernVM-FS: running in single threaded mode");
969 }
970 if (debug_mode_) {
971 LogCvmfs(kLogCvmfs, kLogStdout | kLogSyslogWarn,
972 "CernVM-FS: running in debug mode");
973 }
974
975 #ifndef FUSE_CAP_POSIX_ACL
976 if (options_manager->GetValue("CVMFS_ENFORCE_ACLS", &parameter) &&
977 options_manager->IsOn(parameter))
978 {
979 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
980 "CernVM-FS: ACL support requested but not available in this "
981 "version of libfuse");
982 retval = kFailPermission;
983 goto cleanup;
984 }
985 #endif
986
987 // Initialize the loader socket, connections are not accepted until Spawn()
988 socket_path_ = new string("/var/run/cvmfs");
989 if (options_manager->GetValue("CVMFS_RELOAD_SOCKETS", &parameter))
990 *socket_path_ = MakeCanonicalPath(parameter);
991 *socket_path_ += "/cvmfs." + *repository_name_;
992 retval = loader_talk::Init(*socket_path_);
993 if (!retval) {
994 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
995 "Failed to initialize loader socket");
996 retval = kFailLoaderTalk;
997 goto cleanup;
998 }
999
1000 // TODO(jblomer): we probably want to apply a default setting related to the
1001 // number of cores.
1002 if (options_manager->GetValue("CVMFS_FUSE3_MAX_THREADS", &parameter)) {
1003 fuse3_max_threads_ = String2Int64(parameter);
1004 }
1005 if (options_manager->GetValue("CVMFS_FUSE3_IDLE_THREADS", &parameter)) {
1006 fuse3_idle_threads_ = String2Int64(parameter);
1007 }
1008 #ifdef CVMFS_ENABLE_FUSE3_LOOP_CONFIG
1009 if (fuse3_max_threads_) {
1010 LogCvmfs(kLogCvmfs, kLogStdout,
1011 "CernVM-FS: Fuse3 max_threads=%d", fuse3_max_threads_);
1012 }
1013 if (fuse3_idle_threads_) {
1014 LogCvmfs(kLogCvmfs, kLogStdout,
1015 "CernVM-FS: Fuse3 min_idle_threads=%d", fuse3_idle_threads_);
1016 }
1017 #else
1018 if (fuse3_max_threads_ || fuse3_idle_threads_) {
1019 LogCvmfs(kLogCvmfs, kLogStdout,
1020 "CernVM-FS: ignoring fuse3 thread settings (libfuse too old)");
1021 }
1022 #endif
1023
1024 // Options are not needed anymore
1025 delete options_manager;
1026 options_manager = NULL;
1027
1028 struct fuse_session *session;
1029 #if CVMFS_USE_LIBFUSE == 2
1030 struct fuse_chan *channel;
1031 loader_exports_->fuse_channel_or_session = reinterpret_cast<void **>(
1032 &channel);
1033 #else
1034 loader_exports_->fuse_channel_or_session = reinterpret_cast<void **>(
1035 &session);
1036 #endif
1037
1038 // Load and initialize cvmfs library
1039 LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
1040 "CernVM-FS: loading Fuse module... ");
1041 cvmfs_exports_ = LoadLibrary(debug_mode_, loader_exports_);
1042 if (!cvmfs_exports_) {
1043 retval = kFailLoadLibrary;
1044 goto cleanup;
1045 }
1046 retval = cvmfs_exports_->fnInit(loader_exports_);
1047 if (retval != kFailOk) {
1048 if (retval == kFailDoubleMount) {
1049 LogCvmfs(kLogCvmfs, kLogStderr,
1050 "\nCernVM-FS: repository %s already mounted on %s",
1051 loader_exports_->repository_name.c_str(),
1052 loader_exports_->mount_point.c_str());
1053 return 0;
1054 }
1055 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s (%d - %s)",
1056 cvmfs_exports_->fnGetErrorMsg().c_str(),
1057 retval, Code2Ascii((Failures)retval));
1058 cvmfs_exports_->fnFini();
1059 goto cleanup;
1060 }
1061 LogCvmfs(kLogCvmfs, kLogStdout, "done");
1062
1063 // Mount
1064 fence_reload_ = new Fence();
1065
1066 if (suid_mode_) {
1067 const bool retrievable = true;
1068 if (!SwitchCredentials(0, getgid(), retrievable)) {
1069 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1070 "failed to re-gain root permissions for mounting");
1071 cvmfs_exports_->fnFini();
1072 retval = kFailPermission;
1073 goto cleanup;
1074 }
1075 }
1076
1077
1078 struct fuse_lowlevel_ops loader_operations;
1079 SetFuseOperations(&loader_operations);
1080 #if (FUSE_VERSION >= 29)
1081 if (cvmfs_exports_->cvmfs_operations.forget_multi)
1082 loader_operations.forget_multi = stub_forget_multi;
1083 #endif
1084
1085 #if CVMFS_USE_LIBFUSE == 2
1086 channel = fuse_mount(mount_point_->c_str(), mount_options);
1087 if (!channel) {
1088 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1089 "failed to create Fuse channel");
1090 cvmfs_exports_->fnFini();
1091 retval = kFailMount;
1092 goto cleanup;
1093 }
1094
1095 session = fuse_lowlevel_new(mount_options, &loader_operations,
1096 sizeof(loader_operations), NULL);
1097 if (!session) {
1098 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1099 "failed to create Fuse session");
1100 fuse_unmount(mount_point_->c_str(), channel);
1101 cvmfs_exports_->fnFini();
1102 retval = kFailMount;
1103 goto cleanup;
1104 }
1105 #else
1106 // libfuse3
1107 session = fuse_session_new(mount_options, &loader_operations,
1108 sizeof(loader_operations), NULL);
1109 if (!session) {
1110 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1111 "failed to create Fuse session");
1112 cvmfs_exports_->fnFini();
1113 retval = kFailMount;
1114 goto cleanup;
1115 }
1116 if (premount_fd >= 0) {
1117 char premount_str[64];
1118 snprintf(premount_str, sizeof(premount_str), "/dev/fd/%d", premount_fd);
1119 retval = fuse_session_mount(session, premount_str);
1120 } else {
1121 retval = fuse_session_mount(session, mount_point_->c_str());
1122 }
1123 if (retval != 0) {
1124 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1125 "failed to mount file system");
1126 cvmfs_exports_->fnFini();
1127 retval = kFailMount;
1128 goto cleanup;
1129 }
1130 #endif
1131
1132 // drop credentials
1133 if (suid_mode_) {
1134 const bool retrievable = !disable_watchdog_;
1135 if (!SwitchCredentials(uid_, gid_, retrievable)) {
1136 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1137 "failed to drop permissions after mounting");
1138 cvmfs_exports_->fnFini();
1139 retval = kFailPermission;
1140 goto cleanup;
1141 }
1142 }
1143
1144 // Determine device id
1145 fd_mountinfo = open("/proc/self/mountinfo", O_RDONLY);
1146 if (fd_mountinfo > 0) {
1147 std::string line;
1148 while (GetLineFd(fd_mountinfo, &line)) {
1149 std::vector<std::string> tokens = SplitString(line, ' ');
1150 if (tokens.size() < 5) continue;
1151 if (tokens[4] != loader_exports_->mount_point) continue;
1152 unsigned i = 5;
1153 for (; i < tokens.size(); ++i) {
1154 if (tokens[i] == "-") break;
1155 }
1156 if (tokens.size() < i + 3) continue;
1157 if (tokens[i + 2] != "cvmfs2") continue;
1158 loader_exports_->device_id = tokens[2];
1159 break;
1160 }
1161 close(fd_mountinfo);
1162 }
1163
1164 if (!premounted_) {
1165 LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS: mounted cvmfs on %s",
1166 mount_point_->c_str());
1167 }
1168 LogCvmfs(kLogCvmfs, kLogSyslog,
1169 "CernVM-FS: linking %s to repository %s",
1170 mount_point_->c_str(), repository_name_->c_str());
1171 if (!foreground_)
1172 Daemonize();
1173
1174 cvmfs_exports_->fnSpawn();
1175 loader_talk::Spawn();
1176
1177 SetLogMicroSyslog("");
1178 retval = fuse_set_signal_handlers(session);
1179 assert(retval == 0);
1180 #if CVMFS_USE_LIBFUSE == 2
1181 fuse_session_add_chan(session, channel);
1182 #endif
1183 if (single_threaded_) {
1184 retval = fuse_session_loop(session);
1185 } else {
1186 #if CVMFS_USE_LIBFUSE == 2
1187 retval = fuse_session_loop_mt(session);
1188 #else
1189 #ifdef CVMFS_ENABLE_FUSE3_LOOP_CONFIG
1190 struct fuse_loop_config *fuse_loop_cfg = fuse_loop_cfg_create();
1191
1192 fuse_loop_cfg_set_clone_fd(fuse_loop_cfg, 1);
1193
1194 if (fuse3_max_threads_ > 0) {
1195 fuse_loop_cfg_set_max_threads(fuse_loop_cfg, fuse3_max_threads_);
1196 }
1197 if (fuse3_idle_threads_ > 0) {
1198 fuse_loop_cfg_set_idle_threads(fuse_loop_cfg, fuse3_idle_threads_);
1199 }
1200
1201 retval = fuse_session_loop_mt(session, fuse_loop_cfg);
1202 fuse_loop_cfg_destroy(fuse_loop_cfg);
1203 #else
1204 retval = fuse_session_loop_mt(session, 1 /* use fd per thread */);
1205 #endif // CVMFS_ENABLE_FUSE3_LOOP_CONFIG
1206 #endif // fuse2/3
1207 }
1208 SetLogMicroSyslog(*usyslog_path_);
1209
1210 loader_talk::Fini();
1211 cvmfs_exports_->fnFini();
1212
1213 // Unmount
1214 #if CVMFS_USE_LIBFUSE == 2
1215 fuse_remove_signal_handlers(session);
1216 fuse_session_remove_chan(channel);
1217 fuse_session_destroy(session);
1218 fuse_unmount(mount_point_->c_str(), channel);
1219 channel = NULL;
1220 #else
1221 // libfuse3
1222 fuse_remove_signal_handlers(session);
1223 fuse_session_unmount(session);
1224 fuse_session_destroy(session);
1225 #endif
1226 fuse_opt_free_args(mount_options);
1227 delete mount_options;
1228 session = NULL;
1229 mount_options = NULL;
1230
1231 CloseLibrary();
1232
1233 delete fence_reload_;
1234 delete loader_exports_;
1235 delete config_files_;
1236 delete repository_name_;
1237 delete mount_point_;
1238 delete socket_path_;
1239 fence_reload_ = NULL;
1240 loader_exports_ = NULL;
1241 config_files_ = NULL;
1242 socket_path_ = NULL;
1243
1244 if (retval != 0)
1245 retval = kFailFuseLoop;
1246 else
1247 retval = kFailOk;
1248
1249 #if CVMFS_USE_LIBFUSE != 2
1250 if (premount_fd >= 0) {
1251 goto cleanup;
1252 }
1253 #endif
1254
1255 LogCvmfs(kLogCvmfs, kLogSyslog, "CernVM-FS: unmounted %s (%s)",
1256 mount_point_->c_str(), repository_name_->c_str());
1257
1258 repository_name_ = NULL;
1259 mount_point_ = NULL;
1260
1261 return retval;
1262
1263 cleanup:
1264 #if CVMFS_USE_LIBFUSE != 2
1265 if (premount_fd >= 0) {
1266 if (!SwitchCredentials(0, getgid(), true)) {
1267 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1268 "failed to re-gain root permissions for umounting");
1269 retval = kFailPermission;
1270 } else if (umount(mount_point_->c_str()) < 0) {
1271 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
1272 "failed to umount %s (%d)", mount_point_->c_str(), errno);
1273 retval = kFailPermission;
1274 } else {
1275 LogCvmfs(kLogCvmfs, kLogSyslog, "CernVM-FS: unmounted %s (%s)",
1276 mount_point_->c_str(), repository_name_->c_str());
1277 }
1278 close(premount_fd);
1279 }
1280 #endif
1281
1282 repository_name_ = NULL;
1283 mount_point_ = NULL;
1284
1285 return retval;
1286 }
1287
1288
1289 __attribute__((visibility("default")))
1290 CvmfsStubExports *g_cvmfs_stub_exports = NULL;
1291
1292 static void __attribute__((constructor)) LibraryMain() {
1293 g_cvmfs_stub_exports = new CvmfsStubExports();
1294 g_cvmfs_stub_exports->fn_main = FuseMain;
1295 }
1296
1297 static void __attribute__((destructor)) LibraryExit() {
1298 delete g_cvmfs_stub_exports;
1299 g_cvmfs_stub_exports = NULL;
1300 }
1301