GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/fuse_main.cc
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 0 69 0.0%
Branches: 0 51 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * The Fuse module entry point. Dynamically selects either the libfuse3
5 * cvmfs fuse module or the libfuse2 one, depending on the availability and on
6 * the mount options.
7 *
8 */
9
10 #include "fuse_main.h"
11
12 #include <dlfcn.h>
13 #include <unistd.h>
14
15 #include <cassert>
16 #include <cstdlib>
17 #include <cstring>
18 #include <string>
19 #include <vector>
20
21 #include "util/logging.h"
22 #include "util/platform.h"
23 #include "util/smalloc.h"
24 #include "util/string.h"
25
26 using namespace stub; // NOLINT
27
28
29 int main(int argc, char **argv) {
30 // Getopt option parsing modifies globals and the argv vector
31 const int opterr_save = opterr;
32 const int optc = argc;
33 assert(optc > 0);
34 char **optv = reinterpret_cast<char **>(smalloc(optc * sizeof(char *)));
35 for (int i = 0; i < optc; ++i) {
36 optv[i] = strdup(argv[i]);
37 }
38
39 bool debug = false;
40 unsigned enforce_libfuse = 0;
41 int c;
42 opterr = 0;
43 while ((c = getopt(optc, optv, "do:")) != -1) {
44 switch (c) {
45 case 'd':
46 debug = true;
47 break;
48 case 'o':
49 std::vector<std::string> mount_options = SplitString(optarg, ',');
50 for (unsigned i = 0; i < mount_options.size(); ++i) {
51 if (mount_options[i] == "debug") {
52 debug = true;
53 }
54
55 if (HasPrefix(mount_options[i], "libfuse=", false /*ign_case*/)) {
56 std::vector<std::string> t = SplitString(mount_options[i], '=');
57 enforce_libfuse = String2Uint64(t[1]);
58 if (debug) {
59 LogCvmfs(kLogCvmfs, kLogDebug | kLogStdout,
60 "Debug: enforcing libfuse version %u", enforce_libfuse);
61 }
62 }
63 }
64 break;
65 }
66 }
67 opterr = opterr_save;
68 optind = 1;
69 for (int i = 0; i < optc; ++i) {
70 free(optv[i]);
71 }
72 free(optv);
73
74 const std::string libname_fuse2 = platform_libname("cvmfs_fuse_stub");
75 const std::string libname_fuse3 = platform_libname("cvmfs_fuse3_stub");
76
77 std::string error_messages;
78
79 if (enforce_libfuse > 0) {
80 if ((enforce_libfuse < 2) || (enforce_libfuse > 3)) {
81 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
82 "Error: invalid libfuse version '%u', valid values are 2 or 3.",
83 enforce_libfuse);
84 return 1;
85 }
86 }
87
88 std::string local_lib_path = "./";
89 if (getenv("CVMFS_LIBRARY_PATH") != NULL) {
90 local_lib_path = getenv("CVMFS_LIBRARY_PATH");
91 if (!local_lib_path.empty() && (*local_lib_path.rbegin() != '/'))
92 local_lib_path.push_back('/');
93 }
94
95 // Try loading libfuse3 module, else fallback to version 2
96 std::vector<std::string> library_paths;
97 if ((enforce_libfuse == 0) || (enforce_libfuse == 3)) {
98 library_paths.push_back(local_lib_path + libname_fuse3);
99 library_paths.push_back("/usr/lib/" + libname_fuse3);
100 library_paths.push_back("/usr/lib64/" + libname_fuse3);
101 #ifdef __APPLE__
102 library_paths.push_back("/usr/local/lib/" + libname_fuse3);
103 #endif
104 }
105 if ((enforce_libfuse == 0) || (enforce_libfuse == 2)) {
106 library_paths.push_back(local_lib_path + libname_fuse2);
107 library_paths.push_back("/usr/lib/" + libname_fuse2);
108 library_paths.push_back("/usr/lib64/" + libname_fuse2);
109 #ifdef __APPLE__
110 library_paths.push_back("/usr/local/lib/" + libname_fuse2);
111 #endif
112 }
113
114 void *library_handle;
115 std::vector<std::string>::const_iterator i = library_paths.begin();
116 const std::vector<std::string>::const_iterator iend = library_paths.end();
117 for (; i != iend; ++i) {
118 library_handle = dlopen(i->c_str(), RTLD_NOW | RTLD_LOCAL);
119 if (library_handle != NULL) {
120 if (debug) {
121 LogCvmfs(kLogCvmfs, kLogDebug | kLogStdout, "Debug: using library %s",
122 i->c_str());
123 }
124 break;
125 }
126
127 error_messages += std::string(dlerror()) + "\n";
128 }
129
130 if (!library_handle) {
131 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
132 "Error: failed to load cvmfs library, tried: '%s'\n%s",
133 JoinStrings(library_paths, "' '").c_str(), error_messages.c_str());
134 return 1;
135 }
136
137 CvmfsStubExports **exports_ptr = reinterpret_cast<CvmfsStubExports **>(
138 dlsym(library_handle, "g_cvmfs_stub_exports"));
139 if (exports_ptr == NULL) {
140 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
141 "Error: symbol g_cvmfs_stub_exports not found");
142 return 1;
143 }
144
145 return (*exports_ptr)->fn_main(argc, argv);
146 }
147