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;
76 retval = system(
"/Library/Filesystems/macfuse.fs/Contents/Resources/"
82 fuse_device =
"/dev/macfuse0";
84 fuse_device =
"/dev/fuse";
88 if ((retval != 0) || !S_ISCHR(info.st_mode)) {
97 string param_strict_mount;
101 string repository_list;
108 vector<string> repositories =
SplitString(repository_list,
',');
109 for (
unsigned i = 0; i < repositories.size(); ++i) {
110 if (
MkFqrn(repositories[i]) == fqrn)
113 string config_repository;
116 if (retval && (config_repository == fqrn))
119 "add it to CVMFS_REPOSITORIES", fqrn.c_str());
129 if (!retval || param.empty()) {
138 const string &workspace,
139 string *mountpointp) {
140 LockFile(workspace +
"/cvmfs_io." + fqrn +
".mountcheck.lock");
142 int socket_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
150 while (read(socket_fd, &buf, 1) == 1) {
152 mountpoint.push_back(buf);
154 *mountpointp = mountpoint;
160 const string &fqrn,
const string &workspace, uid_t cvmfs_uid)
163 int talk_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
168 std::string recv_sock_dir =
CreateTempDir(workspace +
"/fusefd");
169 if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
173 std::string recv_sock_path = recv_sock_dir +
"/sock";
174 int recv_sock_fd =
MakeSocket(recv_sock_path, 0660);
175 if ((recv_sock_fd < 0) ||
176 (chown(recv_sock_path.c_str(), cvmfs_uid, getegid()) != 0))
178 if (recv_sock_fd >= 0)
181 unlink(recv_sock_path.c_str());
182 rmdir(recv_sock_dir.c_str());
185 listen(recv_sock_fd, 1);
191 while (read(talk_fd, &buf, 1) == 1) {
193 result.push_back(buf);
198 if (result ==
"OK") {
199 struct sockaddr_un addr;
200 unsigned int len =
sizeof(addr);
202 accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
207 unlink(recv_sock_path.c_str());
208 rmdir(recv_sock_dir.c_str());
230 *cachedir = *cachedir +
"/shared";
232 *cachedir = *cachedir +
"/" + fqrn;
249 "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
263 string reload_guard = param +
"/cvmfs.pause";
272 const string mountpoint_base64 =
Base64(mountpoint);
276 if (
FileExists(reload_guard +
"/" + mountpoint_base64))
299 vector<string> paths;
300 paths.push_back(
"/usr/bin");
305 paths.push_back(
"/usr/local/bin");
309 vector<string>::const_iterator i = paths.begin();
310 const vector<string>::const_iterator iend = paths.end();
311 for (; i != iend; ++i) {
312 const std::string cvmfs2 = *i +
"/cvmfs2";
322 static int AttachMount(
const std::string &mountpoint,
const std::string &fqrn,
337 snprintf(mntopt,
sizeof(mntopt),
338 "ro,fd=%i,rootmode=%o,user_id=%d,group_id=%d",
339 fuse_fd, info.st_mode & S_IFMT, geteuid(), getegid());
341 retval = mount(
"cvmfs2", mountpoint.c_str(),
"fuse",
342 MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
345 "Cannot attach to existing fuse module (%d)", errno);
349 "CernVM-FS: linking %s to repository %s (attaching)",
350 mountpoint.c_str(), fqrn.c_str());
356 int main(
int argc,
char **argv) {
357 bool dry_run =
false;
358 bool remount =
false;
359 vector<string> mount_options;
362 vector<string> option_tokens;
364 while ((c = getopt(argc, argv,
"vfnho:")) != -1) {
371 "/etc/mtab in case it is writable.");
381 for (
unsigned i = 0; i < option_tokens.size(); ++i) {
382 if (option_tokens[i] ==
string(
"remount"))
391 if (optind+2 != argc) {
396 string device = argv[optind];
402 if (device.empty() || !repository_sanitizer.
IsValid(device)) {
406 string mountpoint = argv[optind+1];
409 const string fqrn =
MkFqrn(device);
427 bool dedicated_cachedir =
false;
433 if (!retval)
return 1;
435 if (!retval)
return 1;
437 dedicated_cachedir = (retval && (cachedir != workspace));
439 if (!retval)
return 1;
441 if (!retval)
return 1;
443 if (!retval)
return 1;
445 if (!retval)
return 1;
451 bool has_fuse_group =
false;
452 retval =
GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
458 has_fuse_group =
GetGidOf(
"fuse", &gid_fuse);
461 retval =
MkdirDeep(workspace, 0755,
false);
473 string prev_mountpoint;
476 if (remount && (mountpoint == prev_mountpoint)) {
482 if ((mountpoint == prev_mountpoint) && !
IsMountPoint(mountpoint)) {
488 "Cannot connect to existing fuse module");
494 fqrn.c_str(), prev_mountpoint.c_str());
500 fqrn.c_str(), mountpoint.c_str());
506 if (dedicated_cachedir) {
507 retval =
MkdirDeep(cachedir, 0755,
false);
514 retval =
MkdirDeep(
"/var/run/cvmfs", 0755);
519 sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
522 workspace.c_str(), cvmfs_user.c_str());
525 if (dedicated_cachedir) {
526 sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
529 "Failed to transfer ownership of %s to %s",
530 cachedir.c_str(), cvmfs_user.c_str());
534 sysret = chown(
"/var/run/cvmfs", uid_cvmfs, getegid());
537 "/var/run/cvmfs", cvmfs_user.c_str());
546 if (!integer_sanitizer.
IsValid(param)) {
552 if ((nfiles < 128) || (nfiles > 524288)) {
557 int nfiles_all = nfiles + 512;
558 int sys_nfiles, sys_nfiles_all;
559 size_t len =
sizeof(sys_nfiles);
562 mib[1] = KERN_MAXFILESPERPROC;
563 retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
564 if ((retval != 0) || (sys_nfiles < 0)) {
568 if (sys_nfiles < nfiles) {
569 mib[1] = KERN_MAXFILES;
570 retval = sysctl(mib, 2, &sys_nfiles_all, &len, NULL, 0);
571 if ((retval != 0) || (sys_nfiles_all < 0)) {
575 if (sys_nfiles_all < nfiles_all) {
576 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
582 mib[1] = KERN_MAXFILESPERPROC;
583 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
602 if (cvmfs_binary.empty()) {
609 string cmd = cvmfs_binary +
" -o " +
JoinStrings(mount_options,
",") +
610 " " + fqrn +
" " + mountpoint;
611 if (has_fuse_group) {
612 cmd =
"sg fuse -c \"" + cmd +
"\"";
619 if (has_fuse_group) {
623 " the list of supplementary groups");
629 int fd_stdin, fd_stdout, fd_stderr;
631 vector<string> cvmfs_args;
632 cvmfs_args.push_back(
"-o");
633 cvmfs_args.push_back(
JoinStrings(mount_options,
","));
634 cvmfs_args.push_back(fqrn);
635 cvmfs_args.push_back(mountpoint);
637 cvmfs_binary, cvmfs_args,
false, &pid_cvmfs);
640 cvmfs_binary.c_str());
646 int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
648 bool stdout_open =
true;
649 bool stderr_open =
true;
655 if (stdout_open) FD_SET(fd_stdout, &readfds);
656 if (stderr_open) FD_SET(fd_stderr, &readfds);
658 struct timeval timeout;
660 timeout.tv_usec = 100;
661 retval = select(nfds, &readfds, NULL, NULL, &timeout);
662 if ((retval == -1) && (errno != EINTR)) {
669 if (FD_ISSET(fd_stdout, &readfds)) {
670 num_bytes = read(fd_stdout, &buf, 1);
683 if (FD_ISSET(fd_stderr, &readfds)) {
684 num_bytes = read(fd_stderr, &buf, 1);
703 ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
704 }
while ((stdout_open || stderr_open) && !ended);
706 waitpid(pid_cvmfs, &status, 0);
712 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,...)