9 #include <sys/select.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
15 #include <sys/sysctl.h>
36 static void Usage(
int output_dest) {
38 "Mount helper for CernVM-FS. Used by mount(8)\n"
39 "Mandatory arguments:\n"
40 " repository name: <repository>\n"
41 " mountpoint of the repository: <mountpoint>\n"
43 " -o <mount options>\n"
44 " -f dry run, just prints out the mount command\n"
45 " -h print this help");
50 vector<string> *mount_options) {
51 mount_options->push_back(option);
55 static string MkFqrn(
const string &repository) {
56 const string::size_type idx = repository.find_last_of(
'.');
57 if (idx == string::npos) {
63 "CVMFS_DEFAULT_DOMAIN missing");
66 return repository +
"." + domain;
71 #if defined(__APPLE__) && !defined(USE_MACFUSE_KEXT)
72 static bool IsFuseTInstalled() {
74 string fuseTComponentsPaths[] = {
"/usr/local/bin/go-nfsv4",
75 "/usr/local/lib/libfuse-t.dylib",
76 "/usr/local/lib/libfuse-t.a"};
77 const int pathsNumber =
sizeof(fuseTComponentsPaths)
78 /
sizeof(fuseTComponentsPaths[0]);
80 for (
int idx = 0; idx < pathsNumber; ++idx) {
82 int retval =
platform_stat(fuseTComponentsPaths[idx].c_str(), &info);
83 if ((retval != 0) || !S_ISREG(info.st_mode)) {
92 #if defined(__APPLE__) && !defined(USE_MACFUSE_KEXT)
93 bool is_fuse_t_installed = IsFuseTInstalled();
94 if (!is_fuse_t_installed) {
96 "FUSE-T installation check failed. FUSE not loaded");
98 return is_fuse_t_installed;
103 fuse_device =
"/dev/macfuse0";
105 fuse_device =
"/dev/fuse";
109 if ((retval != 0) || !S_ISCHR(info.st_mode)) {
119 string param_strict_mount;
122 string repository_list;
129 vector<string> repositories =
SplitString(repository_list,
',');
130 for (
unsigned i = 0; i < repositories.size(); ++i) {
131 if (
MkFqrn(repositories[i]) == fqrn)
134 string config_repository;
137 if (retval && (config_repository == fqrn))
140 "Not allowed to mount %s, "
141 "add it to CVMFS_REPOSITORIES",
152 if (!retval || param.empty()) {
161 const string &workspace,
162 string *mountpointp) {
163 LockFile(workspace +
"/cvmfs_io." + fqrn +
".mountcheck.lock");
165 const int socket_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
173 while (read(socket_fd, &buf, 1) == 1) {
175 mountpoint.push_back(buf);
177 *mountpointp = mountpoint;
185 const int talk_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
190 const std::string recv_sock_dir =
CreateTempDir(workspace +
"/fusefd");
191 if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
195 const std::string recv_sock_path = recv_sock_dir +
"/sock";
196 const int recv_sock_fd =
MakeSocket(recv_sock_path, 0660);
197 if ((recv_sock_fd < 0)
198 || (chown(recv_sock_path.c_str(), cvmfs_uid, getegid()) != 0)) {
199 if (recv_sock_fd >= 0)
202 unlink(recv_sock_path.c_str());
203 rmdir(recv_sock_dir.c_str());
206 listen(recv_sock_fd, 1);
212 while (read(talk_fd, &buf, 1) == 1) {
214 result.push_back(buf);
219 if (result ==
"OK") {
220 struct sockaddr_un addr;
221 unsigned int len =
sizeof(addr);
223 accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
228 unlink(recv_sock_path.c_str());
229 rmdir(recv_sock_dir.c_str());
250 *cachedir = *cachedir +
"/shared";
252 *cachedir = *cachedir +
"/" + fqrn;
269 "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
283 const string reload_guard = param +
"/cvmfs.pause";
292 const string mountpoint_base64 =
Base64(mountpoint);
296 if (
FileExists(reload_guard +
"/" + mountpoint_base64))
319 vector<string> paths;
320 paths.push_back(
"/usr/bin");
325 paths.push_back(
"/usr/local/bin");
329 vector<string>::const_iterator i = paths.begin();
330 const vector<string>::const_iterator iend = paths.end();
331 for (; i != iend; ++i) {
332 const std::string cvmfs2 = *i +
"/cvmfs2";
342 static int AttachMount(
const std::string &mountpoint,
const std::string &fqrn,
356 snprintf(mntopt,
sizeof(mntopt),
357 "ro,fd=%i,rootmode=%o,user_id=%d,group_id=%d", fuse_fd,
358 info.st_mode & S_IFMT, geteuid(), getegid());
360 retval = mount(
"cvmfs2", mountpoint.c_str(),
"fuse",
361 MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
364 "Cannot attach to existing fuse module (%d)", errno);
368 "CernVM-FS: linking %s to repository %s (attaching)",
369 mountpoint.c_str(), fqrn.c_str());
375 int main(
int argc,
char **argv) {
376 bool dry_run =
false;
377 bool remount =
false;
378 vector<string> mount_options;
381 vector<string> option_tokens;
383 while ((c = getopt(argc, argv,
"vfnho:")) != -1) {
390 "Note: fusermount _does_ modify "
391 "/etc/mtab in case it is writable.");
401 for (
unsigned i = 0; i < option_tokens.size(); ++i) {
402 if (option_tokens[i] ==
string(
"remount"))
411 if (optind + 2 != argc) {
416 string device = argv[optind];
422 if (device.empty() || !repository_sanitizer.
IsValid(device)) {
426 const string mountpoint = argv[optind + 1];
429 const string fqrn =
MkFqrn(device);
447 bool dedicated_cachedir =
false;
459 dedicated_cachedir = (retval && (cachedir != workspace));
477 bool has_fuse_group =
false;
478 retval =
GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
484 has_fuse_group =
GetGidOf(
"fuse", &gid_fuse);
487 retval =
MkdirDeep(workspace, 0755,
false);
499 string prev_mountpoint;
502 if (remount && (mountpoint == prev_mountpoint)) {
508 if ((mountpoint == prev_mountpoint) && !
IsMountPoint(mountpoint)) {
514 "Cannot connect to existing fuse module");
520 fqrn.c_str(), prev_mountpoint.c_str());
526 fqrn.c_str(), mountpoint.c_str());
532 if (dedicated_cachedir) {
533 retval =
MkdirDeep(cachedir, 0755,
false);
540 retval =
MkdirDeep(
"/var/run/cvmfs", 0755);
545 sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
548 workspace.c_str(), cvmfs_user.c_str());
551 if (dedicated_cachedir) {
552 sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
555 "Failed to transfer ownership of %s to %s", cachedir.c_str(),
560 sysret = chown(
"/var/run/cvmfs", uid_cvmfs, getegid());
563 "/var/run/cvmfs", cvmfs_user.c_str());
572 if (!integer_sanitizer.
IsValid(param)) {
578 if ((nfiles < 128) || (nfiles > 524288)) {
583 int nfiles_all = nfiles + 512;
584 int sys_nfiles, sys_nfiles_all;
585 size_t len =
sizeof(sys_nfiles);
588 mib[1] = KERN_MAXFILESPERPROC;
589 retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
590 if ((retval != 0) || (sys_nfiles < 0)) {
594 if (sys_nfiles < nfiles) {
595 mib[1] = KERN_MAXFILES;
596 retval = sysctl(mib, 2, &sys_nfiles_all, &len, NULL, 0);
597 if ((retval != 0) || (sys_nfiles_all < 0)) {
601 if (sys_nfiles_all < nfiles_all) {
602 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
608 mib[1] = KERN_MAXFILESPERPROC;
609 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
628 if (cvmfs_binary.empty()) {
635 string cmd = cvmfs_binary +
" -o " +
JoinStrings(mount_options,
",") +
" "
636 + fqrn +
" " + mountpoint;
637 if (has_fuse_group) {
638 cmd =
"sg fuse -c \"" + cmd +
"\"";
645 if (has_fuse_group) {
649 "Failed to add fuse to "
650 " the list of supplementary groups");
656 int fd_stdin, fd_stdout, fd_stderr;
658 vector<string> cvmfs_args;
659 cvmfs_args.push_back(
"-o");
660 cvmfs_args.push_back(
JoinStrings(mount_options,
","));
661 cvmfs_args.push_back(fqrn);
662 cvmfs_args.push_back(mountpoint);
663 retval =
ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr, cvmfs_binary,
664 cvmfs_args,
false, &pid_cvmfs);
667 cvmfs_binary.c_str());
673 const int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
675 bool stdout_open =
true;
676 bool stderr_open =
true;
683 FD_SET(fd_stdout, &readfds);
685 FD_SET(fd_stderr, &readfds);
687 struct timeval timeout;
689 timeout.tv_usec = 100;
690 retval = select(nfds, &readfds, NULL, NULL, &timeout);
691 if ((retval == -1) && (errno != EINTR)) {
698 if (FD_ISSET(fd_stdout, &readfds)) {
699 num_bytes = read(fd_stdout, &buf, 1);
712 if (FD_ISSET(fd_stderr, &readfds)) {
713 num_bytes = read(fd_stderr, &buf, 1);
732 ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
733 }
while ((stdout_open || stderr_open) && !ended);
735 waitpid(pid_cvmfs, &status, 0);
741 if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
void SetLogSyslogFacility(const int local_facility)
void SetLogSyslogLevel(const int level)
int MakeSocket(const std::string &path, const int mode)
static bool CheckConcurrentMount(const string &fqrn, const string &workspace, string *mountpointp)
static bool GetCacheDir(const string &fqrn, string *cachedir)
NameString GetFileName(const PathString &path)
static void Usage(const char *progname)
string JoinStrings(const vector< string > &strings, const string &joint)
bool IsOn(const std::string ¶m_value) const
static bool WaitForReload(const std::string &mountpoint)
static std::string GetCvmfsBinary()
void SendMsg2Socket(const int fd, const std::string &msg)
static bool CheckStrictMount(const string &fqrn)
void SetLogMicroSyslog(const std::string &filename)
void ParseDefault(const std::string &fqrn)
bool AddGroup2Persona(const gid_t gid)
#define SetLogDebugFile(filename)
void SwitchTemplateManager(OptionsTemplateManager *opt_templ_mgr_param)
bool SymlinkExists(const std::string &path)
static int AttachMount(const std::string &mountpoint, const std::string &fqrn, int fuse_fd)
bool FileExists(const std::string &path)
static void AddMountOption(const string &option, vector< string > *mount_options)
int64_t String2Int64(const string &value)
vector< string > SplitString(const string &str, char delim)
bool MkdirDeep(const std::string &path, const mode_t mode, bool verify_writable)
int LockFile(const std::string &path)
string StringifyInt(const int64_t value)
bool GetGidOf(const std::string &groupname, gid_t *gid)
static string MkFqrn(const string &repository)
std::string CreateTempDir(const std::string &path_prefix)
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
bool GetValue(const std::string &key, std::string *value) const
bool DirectoryExists(const std::string &path)
bool ExecuteBinary(int *fd_stdin, int *fd_stdout, int *fd_stderr, const std::string &binary_path, const std::vector< std::string > &argv, const bool double_fork, pid_t *child_pid)
static int GetExistingFuseFd(const string &fqrn, const string &workspace, uid_t cvmfs_uid)
static bool GetCvmfsUser(string *cvmfs_user)
int ConnectSocket(const std::string &path)
string Base64(const string &data)
BashOptionsManager options_manager_
uint64_t String2Uint64(const string &value)
bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid)
static bool GetWorkspace(const string &fqrn, string *workspace)
void SafeSleepMs(const unsigned ms)
void SetLogSyslogPrefix(const std::string &prefix)
std::string MakeCanonicalPath(const std::string &path)
bool IsDefined(const std::string &key)
bool IsMountPoint(const std::string &path)
int RecvFdFromSocket(int msg_fd)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)