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) {
141 int socket_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
149 while (read(socket_fd, &buf, 1) == 1) {
151 mountpoint.push_back(buf);
153 *mountpointp = mountpoint;
159 const string &fqrn,
const string &workspace, uid_t cvmfs_uid)
162 int talk_fd =
ConnectSocket(workspace +
"/cvmfs_io." + fqrn);
167 std::string recv_sock_dir =
CreateTempDir(workspace +
"/fusefd");
168 if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
172 std::string recv_sock_path = recv_sock_dir +
"/sock";
173 int recv_sock_fd =
MakeSocket(recv_sock_path, 0660);
174 if ((recv_sock_fd < 0) ||
175 (chown(recv_sock_path.c_str(), cvmfs_uid, getegid()) != 0))
177 if (recv_sock_fd >= 0)
180 unlink(recv_sock_path.c_str());
181 rmdir(recv_sock_dir.c_str());
184 listen(recv_sock_fd, 1);
190 while (read(talk_fd, &buf, 1) == 1) {
192 result.push_back(buf);
197 if (result ==
"OK") {
198 struct sockaddr_un addr;
199 unsigned int len =
sizeof(addr);
201 accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
206 unlink(recv_sock_path.c_str());
207 rmdir(recv_sock_dir.c_str());
229 *cachedir = *cachedir +
"/shared";
231 *cachedir = *cachedir +
"/" + fqrn;
248 "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
262 string reload_guard = param +
"/cvmfs.pause";
271 const string mountpoint_base64 =
Base64(mountpoint);
275 if (
FileExists(reload_guard +
"/" + mountpoint_base64))
298 vector<string> paths;
299 paths.push_back(
"/usr/bin");
304 paths.push_back(
"/usr/local/bin");
308 vector<string>::const_iterator i = paths.begin();
309 const vector<string>::const_iterator iend = paths.end();
310 for (; i != iend; ++i) {
311 const std::string cvmfs2 = *i +
"/cvmfs2";
321 static int AttachMount(
const std::string &mountpoint,
const std::string &fqrn,
336 snprintf(mntopt,
sizeof(mntopt),
337 "ro,fd=%i,rootmode=%o,user_id=%d,group_id=%d",
338 fuse_fd, info.st_mode & S_IFMT, geteuid(), getegid());
340 retval = mount(
"cvmfs2", mountpoint.c_str(),
"fuse",
341 MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
344 "Cannot attach to existing fuse module (%d)", errno);
348 "CernVM-FS: linking %s to repository %s (attaching)",
349 mountpoint.c_str(), fqrn.c_str());
355 int main(
int argc,
char **argv) {
356 bool dry_run =
false;
357 bool remount =
false;
358 vector<string> mount_options;
361 vector<string> option_tokens;
363 while ((c = getopt(argc, argv,
"vfnho:")) != -1) {
370 "/etc/mtab in case it is writable.");
380 for (
unsigned i = 0; i < option_tokens.size(); ++i) {
381 if (option_tokens[i] ==
string(
"remount"))
390 if (optind+2 != argc) {
395 string device = argv[optind];
401 if (device.empty() || !repository_sanitizer.
IsValid(device)) {
405 string mountpoint = argv[optind+1];
408 const string fqrn =
MkFqrn(device);
426 bool dedicated_cachedir =
false;
432 if (!retval)
return 1;
434 if (!retval)
return 1;
436 dedicated_cachedir = (retval && (cachedir != workspace));
438 if (!retval)
return 1;
440 if (!retval)
return 1;
442 if (!retval)
return 1;
444 if (!retval)
return 1;
450 bool has_fuse_group =
false;
451 retval =
GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
457 has_fuse_group =
GetGidOf(
"fuse", &gid_fuse);
464 string prev_mountpoint;
467 if (remount && (mountpoint == prev_mountpoint)) {
473 if ((mountpoint == prev_mountpoint) && !
IsMountPoint(mountpoint)) {
479 "Cannot connect to existing fuse module");
485 fqrn.c_str(), prev_mountpoint.c_str());
491 fqrn.c_str(), mountpoint.c_str());
497 retval =
MkdirDeep(workspace, 0755,
false);
503 if (dedicated_cachedir) {
504 retval =
MkdirDeep(cachedir, 0755,
false);
511 retval =
MkdirDeep(
"/var/run/cvmfs", 0755);
516 sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
519 workspace.c_str(), cvmfs_user.c_str());
522 if (dedicated_cachedir) {
523 sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
526 "Failed to transfer ownership of %s to %s",
527 cachedir.c_str(), cvmfs_user.c_str());
531 sysret = chown(
"/var/run/cvmfs", uid_cvmfs, getegid());
534 "/var/run/cvmfs", cvmfs_user.c_str());
543 if (!integer_sanitizer.
IsValid(param)) {
549 if ((nfiles < 128) || (nfiles > 524288)) {
554 int nfiles_all = nfiles + 512;
555 int sys_nfiles, sys_nfiles_all;
556 size_t len =
sizeof(sys_nfiles);
559 mib[1] = KERN_MAXFILESPERPROC;
560 retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
561 if ((retval != 0) || (sys_nfiles < 0)) {
565 if (sys_nfiles < nfiles) {
566 mib[1] = KERN_MAXFILES;
567 retval = sysctl(mib, 2, &sys_nfiles_all, &len, NULL, 0);
568 if ((retval != 0) || (sys_nfiles_all < 0)) {
572 if (sys_nfiles_all < nfiles_all) {
573 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
579 mib[1] = KERN_MAXFILESPERPROC;
580 retval = sysctl(mib, 2, NULL, NULL, &nfiles_all,
sizeof(nfiles_all));
599 if (cvmfs_binary.empty()) {
606 string cmd = cvmfs_binary +
" -o " +
JoinStrings(mount_options,
",") +
607 " " + fqrn +
" " + mountpoint;
608 if (has_fuse_group) {
609 cmd =
"sg fuse -c \"" + cmd +
"\"";
616 if (has_fuse_group) {
620 " the list of supplementary groups");
626 int fd_stdin, fd_stdout, fd_stderr;
628 vector<string> cvmfs_args;
629 cvmfs_args.push_back(
"-o");
630 cvmfs_args.push_back(
JoinStrings(mount_options,
","));
631 cvmfs_args.push_back(fqrn);
632 cvmfs_args.push_back(mountpoint);
634 cvmfs_binary, cvmfs_args,
false, &pid_cvmfs);
637 cvmfs_binary.c_str());
643 int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
645 bool stdout_open =
true;
646 bool stderr_open =
true;
652 if (stdout_open) FD_SET(fd_stdout, &readfds);
653 if (stderr_open) FD_SET(fd_stderr, &readfds);
655 struct timeval timeout;
657 timeout.tv_usec = 100;
658 retval = select(nfds, &readfds, NULL, NULL, &timeout);
659 if ((retval == -1) && (errno != EINTR)) {
666 if (FD_ISSET(fd_stdout, &readfds)) {
667 num_bytes = read(fd_stdout, &buf, 1);
680 if (FD_ISSET(fd_stderr, &readfds)) {
681 num_bytes = read(fd_stderr, &buf, 1);
694 ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
695 }
while ((stdout_open || stderr_open) && !ended);
699 if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
#define LogCvmfs(source, mask,...)
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)
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)