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)
52 mount_options->push_back(option);
56 static string MkFqrn(
const string &repository) {
57 const string::size_type idx = repository.find_last_of(
'.');
58 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) /
sizeof(fuseTComponentsPaths[0]);
79 for (
int idx = 0; idx < pathsNumber; ++idx) {
81 int retval =
platform_stat(fuseTComponentsPaths[idx].c_str(), &info);
82 if ((retval != 0) || !S_ISREG(info.st_mode)) {
91 #if defined(__APPLE__) && !defined(USE_MACFUSE_KEXT)
92 bool is_fuse_t_installed = IsFuseTInstalled();
93 if (!is_fuse_t_installed) {
96 return is_fuse_t_installed;
101 fuse_device =
"/dev/macfuse0";
103 fuse_device =
"/dev/fuse";
107 if ((retval != 0) || !S_ISCHR(info.st_mode)) {
117 string param_strict_mount;
121 string repository_list;
128 vector<string> repositories =
SplitString(repository_list,
',');
129 for (
unsigned i = 0; i < repositories.size(); ++i) {
130 if (
MkFqrn(repositories[i]) == fqrn)
133 string config_repository;
136 if (retval && (config_repository == fqrn))
139 "add it to CVMFS_REPOSITORIES", fqrn.c_str());
149 if (!retval || param.empty()) {
158 const string &workspace,
159 string *mountpointp) {
160 LockFile(workspace +
"/cvmfs_io." + fqrn +
".mountcheck.lock");
162 int socket_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
170 while (read(socket_fd, &buf, 1) == 1) {
172 mountpoint.push_back(buf);
174 *mountpointp = mountpoint;
180 const string &fqrn,
const string &workspace, uid_t cvmfs_uid)
183 int talk_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
188 std::string recv_sock_dir =
CreateTempDir(workspace +
"/fusefd");
189 if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
193 std::string recv_sock_path = recv_sock_dir +
"/sock";
194 int recv_sock_fd =
MakeSocket(recv_sock_path, 0660);
195 if ((recv_sock_fd < 0) ||
196 (chown(recv_sock_path.c_str(), cvmfs_uid, getegid()) != 0))
198 if (recv_sock_fd >= 0)
201 unlink(recv_sock_path.c_str());
202 rmdir(recv_sock_dir.c_str());
205 listen(recv_sock_fd, 1);
211 while (read(talk_fd, &buf, 1) == 1) {
213 result.push_back(buf);
218 if (result ==
"OK") {
219 struct sockaddr_un addr;
220 unsigned int len =
sizeof(addr);
222 accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
227 unlink(recv_sock_path.c_str());
228 rmdir(recv_sock_dir.c_str());
250 *cachedir = *cachedir +
"/shared";
252 *cachedir = *cachedir +
"/" + fqrn;
269 "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
283 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,
357 snprintf(mntopt,
sizeof(mntopt),
358 "ro,fd=%i,rootmode=%o,user_id=%d,group_id=%d",
359 fuse_fd, info.st_mode & S_IFMT, geteuid(), getegid());
361 retval = mount(
"cvmfs2", mountpoint.c_str(),
"fuse",
362 MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
365 "Cannot attach to existing fuse module (%d)", errno);
369 "CernVM-FS: linking %s to repository %s (attaching)",
370 mountpoint.c_str(), fqrn.c_str());
376 int main(
int argc,
char **argv) {
377 bool dry_run =
false;
378 bool remount =
false;
379 vector<string> mount_options;
382 vector<string> option_tokens;
384 while ((c = getopt(argc, argv,
"vfnho:")) != -1) {
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 string mountpoint = argv[optind+1];
429 const string fqrn =
MkFqrn(device);
447 bool dedicated_cachedir =
false;
453 if (!retval)
return 1;
455 if (!retval)
return 1;
457 dedicated_cachedir = (retval && (cachedir != workspace));
459 if (!retval)
return 1;
461 if (!retval)
return 1;
463 if (!retval)
return 1;
465 if (!retval)
return 1;
471 bool has_fuse_group =
false;
472 retval =
GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
478 has_fuse_group =
GetGidOf(
"fuse", &gid_fuse);
481 retval =
MkdirDeep(workspace, 0755,
false);
493 string prev_mountpoint;
496 if (remount && (mountpoint == prev_mountpoint)) {
502 if ((mountpoint == prev_mountpoint) && !
IsMountPoint(mountpoint)) {
508 "Cannot connect to existing fuse module");
514 fqrn.c_str(), prev_mountpoint.c_str());
520 fqrn.c_str(), mountpoint.c_str());
526 if (dedicated_cachedir) {
527 retval =
MkdirDeep(cachedir, 0755,
false);
534 retval =
MkdirDeep(
"/var/run/cvmfs", 0755);
539 sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
542 workspace.c_str(), cvmfs_user.c_str());
545 if (dedicated_cachedir) {
546 sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
549 "Failed to transfer ownership of %s to %s",
550 cachedir.c_str(), cvmfs_user.c_str());
554 sysret = chown(
"/var/run/cvmfs", uid_cvmfs, getegid());
557 "/var/run/cvmfs", cvmfs_user.c_str());
566 if (!integer_sanitizer.
IsValid(param)) {
572 if ((nfiles < 128) || (nfiles > 524288)) {
577 int nfiles_all = nfiles + 512;
578 int sys_nfiles, sys_nfiles_all;
579 size_t len =
sizeof(sys_nfiles);
582 mib[1] = KERN_MAXFILESPERPROC;
583 retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
584 if ((retval != 0) || (sys_nfiles < 0)) {
588 if (sys_nfiles < nfiles) {
589 mib[1] = KERN_MAXFILES;
590 retval = sysctl(mib, 2, &sys_nfiles_all, &len, NULL, 0);
591 if ((retval != 0) || (sys_nfiles_all < 0)) {
595 if (sys_nfiles_all < nfiles_all) {
596 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
602 mib[1] = KERN_MAXFILESPERPROC;
603 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
622 if (cvmfs_binary.empty()) {
629 string cmd = cvmfs_binary +
" -o " +
JoinStrings(mount_options,
",") +
630 " " + fqrn +
" " + mountpoint;
631 if (has_fuse_group) {
632 cmd =
"sg fuse -c \"" + cmd +
"\"";
639 if (has_fuse_group) {
643 " the list of supplementary groups");
649 int fd_stdin, fd_stdout, fd_stderr;
651 vector<string> cvmfs_args;
652 cvmfs_args.push_back(
"-o");
653 cvmfs_args.push_back(
JoinStrings(mount_options,
","));
654 cvmfs_args.push_back(fqrn);
655 cvmfs_args.push_back(mountpoint);
657 cvmfs_binary, cvmfs_args,
false, &pid_cvmfs);
660 cvmfs_binary.c_str());
666 int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
668 bool stdout_open =
true;
669 bool stderr_open =
true;
675 if (stdout_open) FD_SET(fd_stdout, &readfds);
676 if (stderr_open) FD_SET(fd_stderr, &readfds);
678 struct timeval timeout;
680 timeout.tv_usec = 100;
681 retval = select(nfds, &readfds, NULL, NULL, &timeout);
682 if ((retval == -1) && (errno != EINTR)) {
689 if (FD_ISSET(fd_stdout, &readfds)) {
690 num_bytes = read(fd_stdout, &buf, 1);
703 if (FD_ISSET(fd_stderr, &readfds)) {
704 num_bytes = read(fd_stderr, &buf, 1);
723 ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
724 }
while ((stdout_open || stderr_open) && !ended);
726 waitpid(pid_cvmfs, &status, 0);
732 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,...)