GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/fuse_main.cc
Date: 2026-10-25 02:40:14
Exec Total Coverage
Lines: 0 76 0.0%
Branches: 0 61 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * The Fuse module entry point. Loads the cvmfs fuse module (libcvmfs_fuse3),
5 * in debug or normal flavour depending on the mount options.
6 *
7 */
8
9 #include "fuse_main.h"
10
11 #include <dlfcn.h>
12 #include <unistd.h>
13
14 #include <cassert>
15 #include <cstdlib>
16 #include <cstring>
17 #include <string>
18 #include <vector>
19
20 #include "util/logging.h"
21 #include "util/platform.h"
22 #include "util/smalloc.h"
23 #include "util/string.h"
24
25 using namespace stub; // NOLINT
26
27
28 namespace {
29
30 ✗ std::vector<std::string> LibraryPaths(const std::string &libname) {
31 ✗ std::string local_lib_path = "./";
32 ✗ if (getenv("CVMFS_LIBRARY_PATH") != NULL) {
33 ✗ local_lib_path = getenv("CVMFS_LIBRARY_PATH");
34 ✗ if (!local_lib_path.empty() && (*local_lib_path.rbegin() != '/'))
35 ✗ local_lib_path.push_back('/');
36 }
37
38 return {
39 local_lib_path + libname,
40 "/usr/lib/" + libname,
41 "/usr/lib64/" + libname,
42 #ifdef __APPLE__
43 // Since OS X El Capitan (10.11) came with SIP, we needed to relocate our
44 // binaries from /usr/... to /usr/local/...
45 "/usr/local/lib/" + libname,
46 #endif
47 ✗ };
48 }
49
50 /**
51 * Keeps an NFS mount answerable if its cvmfs2 process dies, see
52 * nfs4/guardian.h. Started by libcvmfs_nfsfuse as
53 * cvmfs2 __nfs_guardian__ <listen fd> <control fd> <mount point>
54 */
55 ✗ int RunNfsGuardian(char **argv) {
56 const std::vector<std::string> paths =
57 ✗ LibraryPaths(platform_libname("cvmfs_nfsfuse"));
58 ✗ for (const std::string &path : paths) {
59 ✗ void *handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
60 ✗ if (handle == NULL)
61 ✗ continue;
62 typedef int (*GuardianMain)(int, int, const char *);
63 GuardianMain guardian_main = reinterpret_cast<GuardianMain>(
64 ✗ dlsym(handle, "cvmfs_nfsfuse_guardian_main"));
65 ✗ if (guardian_main == NULL)
66 ✗ return 1;
67 ✗ return guardian_main(atoi(argv[2]), atoi(argv[3]), argv[4]);
68 }
69 ✗ return 1;
70 }
71
72 } // anonymous namespace
73
74
75 ✗ int main(int argc, char **argv) {
76 ✗ if ((argc == 5) && (strcmp(argv[1], "__nfs_guardian__") == 0))
77 ✗ return RunNfsGuardian(argv);
78
79 // Getopt option parsing modifies globals and the argv vector
80 ✗ const int opterr_save = opterr;
81 ✗ const int optc = argc;
82 ✗ assert(optc > 0);
83 ✗ char **optv = reinterpret_cast<char **>(smalloc(optc * sizeof(char *)));
84 ✗ for (int i = 0; i < optc; ++i) {
85 ✗ optv[i] = strdup(argv[i]);
86 }
87
88 ✗ bool debug = false;
89 ✗ bool nfs = false;
90 ✗ bool fskit = false;
91 int c;
92 ✗ opterr = 0;
93 ✗ while ((c = getopt(optc, optv, "do:")) != -1) {
94 ✗ switch (c) {
95 ✗ case 'd':
96 ✗ debug = true;
97 ✗ break;
98 ✗ case 'o':
99 ✗ std::vector<std::string> mount_options = SplitString(optarg, ',');
100 ✗ for (unsigned i = 0; i < mount_options.size(); ++i) {
101 ✗ if (mount_options[i] == "debug") {
102 ✗ debug = true;
103 }
104 ✗ if (mount_options[i] == "nfs") {
105 ✗ nfs = true;
106 }
107 ✗ if (mount_options[i] == "obackend=fskit") {
108 ✗ fskit = true;
109 }
110 }
111 ✗ break;
112 }
113 }
114 ✗ opterr = opterr_save;
115 ✗ optind = 1;
116 ✗ for (int i = 0; i < optc; ++i) {
117 ✗ free(optv[i]);
118 }
119 ✗ free(optv);
120
121 // -o nfs selects the frontend that mounts through the kernel's NFS client,
122 // -o obackend=fskit the one built for the macFUSE FSKit backend
123 const std::string libname_fuse3 = platform_libname(
124 nfs ? "cvmfs_nfs_stub"
125 ✗ : (fskit ? "cvmfs_fskit_stub" : "cvmfs_fuse3_stub"));
126
127 ✗ std::string error_messages;
128
129 ✗ const std::vector<std::string> library_paths = LibraryPaths(libname_fuse3);
130
131 // dlopen the library at the first good path
132 ✗ void *library_handle = nullptr;
133 ✗ for (const std::string &path : library_paths) {
134 ✗ library_handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
135 ✗ if (nullptr != library_handle) {
136 ✗ if (debug) {
137 ✗ LogCvmfs(kLogCvmfs, kLogDebug | kLogStdout, "Debug: using library %s",
138 path.c_str());
139 }
140 ✗ break;
141 }
142 ✗ error_messages += std::string(dlerror()) + "\n";
143 }
144
145 // Installations with only the NFS frontend still run helper commands
146 // (e.g. __wpad__ from cvmfs_config) without -o nfs
147 ✗ if (!library_handle && !nfs) {
148 const std::vector<std::string> nfs_paths =
149 ✗ LibraryPaths(platform_libname("cvmfs_nfs_stub"));
150 ✗ for (const std::string &path : nfs_paths) {
151 ✗ library_handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
152 ✗ if (nullptr != library_handle)
153 ✗ break;
154 }
155 }
156
157 ✗ if (!library_handle) {
158 ✗ LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
159 "Error: failed to load cvmfs library, tried: '%s'\n%s",
160 JoinStrings(library_paths, "' '").c_str(), error_messages.c_str());
161 ✗ return 1;
162 }
163
164 CvmfsStubExports **exports_ptr = reinterpret_cast<CvmfsStubExports **>(
165 ✗ dlsym(library_handle, "g_cvmfs_stub_exports"));
166 ✗ if (exports_ptr == NULL) {
167 ✗ LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
168 "Error: symbol g_cvmfs_stub_exports not found");
169 ✗ return 1;
170 }
171
172 ✗ return (*exports_ptr)->fn_main(argc, argv);
173 }
174