CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mount.cvmfs.cc
Go to the documentation of this file.
1 
8 #include <errno.h>
9 #include <sys/select.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <sys/uio.h>
13 #include <sys/wait.h>
14 #ifdef __APPLE__
15 #include <sys/sysctl.h>
16 #endif
17 #include <sys/un.h>
18 #include <unistd.h>
19 
20 #include <cstdio>
21 #include <cstdlib>
22 #include <string>
23 #include <vector>
24 
25 #include "options.h"
26 #include "sanitizer.h"
27 #include "util/logging.h"
28 #include "util/platform.h"
29 #include "util/posix.h"
30 #include "util/string.h"
31 
32 using namespace std; // NOLINT
33 
35 
36 static void Usage(int output_dest) {
37  LogCvmfs(kLogCvmfs, 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"
42  "Options:\n"
43  " -o <mount options>\n"
44  " -f dry run, just prints out the mount command\n"
45  " -h print this help");
46 }
47 
48 
49 static void AddMountOption(const string &option,
50  vector<string> *mount_options)
51 {
52  mount_options->push_back(option);
53 }
54 
55 
56 static string MkFqrn(const string &repository) {
57  const string::size_type idx = repository.find_last_of('.');
58  if (idx == string::npos) {
59  string domain;
60  bool retval = options_manager_.GetValue("CVMFS_DEFAULT_DOMAIN", &domain);
61  if (!retval) {
63  "CVMFS_DEFAULT_DOMAIN missing");
64  abort();
65  }
66  return repository + "." + domain;
67  }
68  return repository;
69 }
70 
71 
72 static bool CheckFuse() {
73  string fuse_device;
74  int retval;
75 #ifdef __APPLE__
76  retval = system("/Library/Filesystems/macfuse.fs/Contents/Resources/"
77  "load_macfuse");
78  if (retval != 0) {
79  LogCvmfs(kLogCvmfs, kLogStderr, "Failed loading macFUSE");
80  return false;
81  }
82  fuse_device = "/dev/macfuse0";
83 #else
84  fuse_device = "/dev/fuse";
85 #endif
86  platform_stat64 info;
87  retval = platform_stat(fuse_device.c_str(), &info);
88  if ((retval != 0) || !S_ISCHR(info.st_mode)) {
89  LogCvmfs(kLogCvmfs, kLogStderr, "Fuse not loaded");
90  return false;
91  }
92  return true;
93 }
94 
95 
96 static bool CheckStrictMount(const string &fqrn) {
97  string param_strict_mount;
98  if (options_manager_.GetValue("CVMFS_STRICT_MOUNT", &param_strict_mount) &&
99  options_manager_.IsOn(param_strict_mount))
100  {
101  string repository_list;
102  bool retval =
103  options_manager_.GetValue("CVMFS_REPOSITORIES", &repository_list);
104  if (!retval) {
105  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_REPOSITORIES missing");
106  return false;
107  }
108  vector<string> repositories = SplitString(repository_list, ',');
109  for (unsigned i = 0; i < repositories.size(); ++i) {
110  if (MkFqrn(repositories[i]) == fqrn)
111  return true;
112  }
113  string config_repository;
114  retval =
115  options_manager_.GetValue("CVMFS_CONFIG_REPOSITORY", &config_repository);
116  if (retval && (config_repository == fqrn))
117  return true;
118  LogCvmfs(kLogCvmfs, kLogStderr, "Not allowed to mount %s, "
119  "add it to CVMFS_REPOSITORIES", fqrn.c_str());
120  return false;
121  }
122  return true;
123 }
124 
125 
126 static bool CheckProxy() {
127  string param;
128  int retval = options_manager_.GetValue("CVMFS_HTTP_PROXY", &param);
129  if (!retval || param.empty()) {
130  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_HTTP_PROXY required");
131  return false;
132  }
133  return true;
134 }
135 
136 
137 static bool CheckConcurrentMount(const string &fqrn,
138  const string &workspace,
139  string *mountpointp) {
140  LockFile(workspace + "/cvmfs_io." + fqrn + ".mountcheck.lock");
141  // Try connecting to cvmfs_io socket
142  int socket_fd = ConnectSocket(workspace + "/cvmfs_io." + fqrn);
143  if (socket_fd < 0)
144  return false;
145 
146  // There is a repository mounted, find out the mount point
147  SendMsg2Socket(socket_fd, "mountpoint");
148  string mountpoint;
149  char buf;
150  while (read(socket_fd, &buf, 1) == 1) {
151  if (buf != '\n')
152  mountpoint.push_back(buf);
153  }
154  *mountpointp = mountpoint;
155  close(socket_fd);
156  return true;
157 }
158 
159 static int GetExistingFuseFd(
160  const string &fqrn, const string &workspace, uid_t cvmfs_uid)
161 {
162  // Try connecting to cvmfs_io socket
163  int talk_fd = ConnectSocket(workspace + "/cvmfs_io." + fqrn);
164  if (talk_fd < 0)
165  return -1;
166 
167  // Create temporary socket
168  std::string recv_sock_dir = CreateTempDir(workspace + "/fusefd");
169  if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
170  close(talk_fd);
171  return -1;
172  }
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))
177  {
178  if (recv_sock_fd >= 0)
179  close(recv_sock_fd);
180  close(talk_fd);
181  unlink(recv_sock_path.c_str());
182  rmdir(recv_sock_dir.c_str());
183  return -1;
184  }
185  listen(recv_sock_fd, 1);
186 
187  // Trigger fd transfer
188  SendMsg2Socket(talk_fd, "send mount fd " + recv_sock_path);
189  string result;
190  char buf;
191  while (read(talk_fd, &buf, 1) == 1) {
192  if (buf != '\n')
193  result.push_back(buf);
194  }
195  close(talk_fd);
196 
197  int fuse_fd = -1;
198  if (result == "OK") {
199  struct sockaddr_un addr;
200  unsigned int len = sizeof(addr);
201  int con_fd =
202  accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
203  fuse_fd = RecvFdFromSocket(con_fd);
204  close(con_fd);
205  }
206  close(recv_sock_fd);
207  unlink(recv_sock_path.c_str());
208  rmdir(recv_sock_dir.c_str());
209 
210  return fuse_fd;
211 }
212 
213 
214 static bool GetCacheDir(const string &fqrn, string *cachedir) {
215  string param;
216  bool retval = options_manager_.GetValue("CVMFS_CACHE_DIR", &param);
217  if (retval) {
218  *cachedir = MakeCanonicalPath(param);
219  return true;
220  }
221 
222  retval = options_manager_.GetValue("CVMFS_CACHE_BASE", &param);
223  if (!retval)
224  return false;
225 
226  *cachedir = MakeCanonicalPath(param);
227  if (options_manager_.GetValue("CVMFS_SHARED_CACHE", &param) &&
228  options_manager_.IsOn(param))
229  {
230  *cachedir = *cachedir + "/shared";
231  } else {
232  *cachedir = *cachedir + "/" + fqrn;
233  }
234  return true;
235 }
236 
237 
238 static bool GetWorkspace(const string &fqrn, string *workspace) {
239  string param;
240  bool retval = options_manager_.GetValue("CVMFS_WORKSPACE", &param);
241  if (retval) {
242  *workspace = MakeCanonicalPath(param);
243  return true;
244  }
245 
246  retval = GetCacheDir(fqrn, workspace);
247  if (!retval) {
249  "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
250  return false;
251  }
252  return true;
253 }
254 
255 
256 static bool WaitForReload(const std::string &mountpoint) {
257  string param;
258  int retval = options_manager_.GetValue("CVMFS_RELOAD_SOCKETS", &param);
259  if (!retval) {
260  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_RELOAD_SOCKETS required");
261  return false;
262  }
263  string reload_guard = param + "/cvmfs.pause";
264  // Deprecated, now a directory
265  if (FileExists(reload_guard)) {
266  LogCvmfs(kLogCvmfs, kLogStdout, "Waiting for CernVM-FS reload...");
267  while (FileExists(reload_guard))
268  SafeSleepMs(250);
269  }
270  if (DirectoryExists(reload_guard)) {
271  LogCvmfs(kLogCvmfs, kLogStdout, "Waiting for CernVM-FS reload...");
272  const string mountpoint_base64 = Base64(mountpoint);
273  while (DirectoryExists(reload_guard)) {
274  // We are in paused state but automounter unmounted the repo.
275  // We need to allow to mount just to reload.
276  if (FileExists(reload_guard + "/" + mountpoint_base64))
277  break;
278  SafeSleepMs(250);
279  }
280  }
281  return true;
282 }
283 
284 
285 static bool GetCvmfsUser(string *cvmfs_user) {
286  string param;
287  int retval = options_manager_.GetValue("CVMFS_USER", &param);
288  if (!retval) {
289  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_USER required");
290  return false;
291  }
292  *cvmfs_user = param; // No sanitation; due to PAM, username can be anything
293  return true;
294 }
295 
296 
297 static std::string GetCvmfsBinary() {
298  std::string result;
299  vector<string> paths;
300  paths.push_back("/usr/bin");
301 
302 #ifdef __APPLE__
303  // OS X El Capitan came with SIP, forcing us to become relocatable. CVMFS
304  // 2.2.0+ installs into /usr/local always
305  paths.push_back("/usr/local/bin");
306 #endif
307 
308  // TODO(reneme): C++11 range based for loop
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";
313  if (FileExists(cvmfs2) || SymlinkExists(cvmfs2)) {
314  result = cvmfs2;
315  break;
316  }
317  }
318 
319  return result;
320 }
321 
322 static int AttachMount(const std::string &mountpoint, const std::string &fqrn,
323  int fuse_fd)
324 {
325 #ifdef __APPLE__
326  (void) mountpoint;
327  (void) fqrn;
328  (void) fuse_fd;
329  return 1;
330 #else
331  platform_stat64 info;
332  int retval = platform_stat(mountpoint.c_str(), &info);
333  if (retval != 0)
334  return 1;
335 
336  char mntopt[100];
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());
340  // TODO(jblomer): remove NOSUID according to options
341  retval = mount("cvmfs2", mountpoint.c_str(), "fuse",
342  MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
343  if (retval != 0) {
345  "Cannot attach to existing fuse module (%d)", errno);
346  return 1;
347  }
349  "CernVM-FS: linking %s to repository %s (attaching)",
350  mountpoint.c_str(), fqrn.c_str());
351  return 0;
352 #endif
353 }
354 
355 
356 int main(int argc, char **argv) {
357  bool dry_run = false;
358  bool remount = false;
359  vector<string> mount_options;
360 
361  // Option parsing
362  vector<string> option_tokens;
363  int c;
364  while ((c = getopt(argc, argv, "vfnho:")) != -1) {
365  switch (c) {
366  case 'f':
367  dry_run = true;
368  break;
369  case 'n':
370  LogCvmfs(kLogCvmfs, kLogStdout, "Note: fusermount _does_ modify "
371  "/etc/mtab in case it is writable.");
372  // Fall through
373  case 'v':
374  break;
375  case 'h':
376  Usage(kLogStdout);
377  return 0;
378  case 'o':
379  AddMountOption(optarg, &mount_options);
380  option_tokens = SplitString(optarg, ',');
381  for (unsigned i = 0; i < option_tokens.size(); ++i) {
382  if (option_tokens[i] == string("remount"))
383  remount = true;
384  }
385  break;
386  default:
387  Usage(kLogStderr);
388  return 1;
389  }
390  }
391  if (optind+2 != argc) {
392  Usage(kLogStderr);
393  return 1;
394  }
395 
396  string device = argv[optind];
397  // Some mount versions expand the given device to a full path. Thus ignore
398  // everything before the last slash (/)/
399  if (HasPrefix(device, "/", false))
400  device = GetFileName(device);
401  sanitizer::RepositorySanitizer repository_sanitizer;
402  if (device.empty() || !repository_sanitizer.IsValid(device)) {
403  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid repository: %s", device.c_str());
404  return 1;
405  }
406  string mountpoint = argv[optind+1];
407 
409  const string fqrn = MkFqrn(device);
413 
414  string optarg;
415  if (options_manager_.GetValue("CVMFS_SYSLOG_LEVEL", &optarg))
417  if (options_manager_.GetValue("CVMFS_SYSLOG_FACILITY", &optarg))
419  if (options_manager_.GetValue("CVMFS_USYSLOG", &optarg))
420  SetLogMicroSyslog(optarg + ".mount");
421  if (options_manager_.GetValue("CVMFS_DEBUGLOG", &optarg))
422  SetLogDebugFile(optarg + ".mount");
423  SetLogSyslogPrefix(fqrn);
424 
425  int retval;
426  int sysret;
427  bool dedicated_cachedir = false;
428  string cvmfs_user;
429  string cachedir;
430  string workspace;
431  // Environment checks
432  retval = WaitForReload(mountpoint);
433  if (!retval) return 1;
434  retval = GetWorkspace(fqrn, &workspace);
435  if (!retval) return 1;
436  retval = GetCacheDir(fqrn, &cachedir);
437  dedicated_cachedir = (retval && (cachedir != workspace));
438  retval = GetCvmfsUser(&cvmfs_user);
439  if (!retval) return 1;
440  retval = CheckFuse();
441  if (!retval) return 1;
442  retval = CheckStrictMount(fqrn);
443  if (!retval) return 1;
444  retval = CheckProxy();
445  if (!retval) return 1;
446 
447  // Retrieve cvmfs uid/gid and fuse gid if exists
448  uid_t uid_cvmfs;
449  gid_t gid_cvmfs;
450  gid_t gid_fuse;
451  bool has_fuse_group = false;
452  retval = GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
453  if (!retval) {
454  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to find user %s in passwd database",
455  cvmfs_user.c_str());
456  return 1;
457  }
458  has_fuse_group = GetGidOf("fuse", &gid_fuse);
459 
460  // Prepare workspace
461  retval = MkdirDeep(workspace, 0755, false);
462  if (!retval) {
463  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create workspace %s",
464  workspace.c_str());
465  return 1;
466  }
467 
468  // This is not a sure thing. When the CVMFS_CACHE_BASE parameter is changed
469  // two repositories can get mounted concurrently (but that should not hurt).
470  // If the same repository is mounted multiple times at the same time, there
471  // is a race here. Eventually, only one repository will be mounted while the
472  // other cvmfs processes block on a file lock in the cache.
473  string prev_mountpoint;
474  retval = CheckConcurrentMount(fqrn, workspace, &prev_mountpoint);
475  if (retval) {
476  if (remount && (mountpoint == prev_mountpoint)) {
477  // Actually remounting is too hard, but pretend that it worked
478  return 0;
479  }
480  // Identify zombie fuse processes that are held open by other mount
481  // namespaces
482  if ((mountpoint == prev_mountpoint) && !IsMountPoint(mountpoint)) {
483  // Allow for group access to the socket receiving the fuse fd
484  umask(007);
485  int fuse_fd = GetExistingFuseFd(fqrn, workspace, uid_cvmfs);
486  if (fuse_fd < 0) {
488  "Cannot connect to existing fuse module");
489  return 1;
490  }
491  return AttachMount(mountpoint, fqrn, fuse_fd);
492  }
493  LogCvmfs(kLogCvmfs, kLogStderr, "Repository %s is already mounted on %s",
494  fqrn.c_str(), prev_mountpoint.c_str());
495  return 1;
496  } else {
497  // No double mount
498  if (remount) {
499  LogCvmfs(kLogCvmfs, kLogStderr, "Repository %s is not mounted on %s",
500  fqrn.c_str(), mountpoint.c_str());
501  return 1;
502  }
503  }
504 
505  // Prepare cache directory
506  if (dedicated_cachedir) {
507  retval = MkdirDeep(cachedir, 0755, false);
508  if (!retval) {
509  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create cache directory %s",
510  cachedir.c_str());
511  return 1;
512  }
513  }
514  retval = MkdirDeep("/var/run/cvmfs", 0755);
515  if (!retval) {
516  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create socket directory");
517  return 1;
518  }
519  sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
520  if (sysret != 0) {
521  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
522  workspace.c_str(), cvmfs_user.c_str());
523  return 1;
524  }
525  if (dedicated_cachedir) {
526  sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
527  if (sysret != 0) {
529  "Failed to transfer ownership of %s to %s",
530  cachedir.c_str(), cvmfs_user.c_str());
531  return 1;
532  }
533  }
534  sysret = chown("/var/run/cvmfs", uid_cvmfs, getegid());
535  if (sysret != 0) {
536  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
537  "/var/run/cvmfs", cvmfs_user.c_str());
538  return 1;
539  }
540 
541  // Set maximum number of files
542 #ifdef __APPLE__
543  string param;
544  if (options_manager_.GetValue("CVMFS_NFILES", &param)) {
545  sanitizer::IntegerSanitizer integer_sanitizer;
546  if (!integer_sanitizer.IsValid(param)) {
547  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid CVMFS_NFILES: %s",
548  param.c_str());
549  return 1;
550  }
551  int nfiles = String2Uint64(param);
552  if ((nfiles < 128) || (nfiles > 524288)) {
553  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid CVMFS_NFILES: %s",
554  param.c_str());
555  return 1;
556  }
557  int nfiles_all = nfiles + 512;
558  int sys_nfiles, sys_nfiles_all;
559  size_t len = sizeof(sys_nfiles);
560  int mib[2];
561  mib[0] = CTL_KERN;
562  mib[1] = KERN_MAXFILESPERPROC;
563  retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
564  if ((retval != 0) || (sys_nfiles < 0)) {
565  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to get KERN_MAXFILESPERPROC");
566  return 1;
567  }
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)) {
572  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to get KERN_MAXFILES");
573  return 1;
574  }
575  if (sys_nfiles_all < nfiles_all) {
576  retval = sysctl(mib, 2, NULL, NULL, &nfiles_all, sizeof(nfiles_all));
577  if (retval != 0) {
578  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to set KERN_MAXFILES");
579  return 1;
580  }
581  }
582  mib[1] = KERN_MAXFILESPERPROC;
583  retval = sysctl(mib, 2, NULL, NULL, &nfiles_all, sizeof(nfiles_all));
584  if (retval != 0) {
585  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to set KERN_MAXFILESPERPROC");
586  return 1;
587  }
588  }
589  }
590 #endif
591 
592  AddMountOption("system_mount", &mount_options);
593  AddMountOption("fsname=cvmfs2", &mount_options);
594  AddMountOption("allow_other", &mount_options);
595  AddMountOption("grab_mountpoint", &mount_options);
596  AddMountOption("uid=" + StringifyInt(uid_cvmfs), &mount_options);
597  AddMountOption("gid=" + StringifyInt(gid_cvmfs), &mount_options);
598  if (options_manager_.IsDefined("CVMFS_DEBUGLOG"))
599  AddMountOption("debug", &mount_options);
600 
601  const string cvmfs_binary = GetCvmfsBinary();
602  if (cvmfs_binary.empty()) {
603  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to locate the cvmfs2 binary");
604  return 1;
605  }
606 
607  // Dry run early exit
608  if (dry_run) {
609  string cmd = cvmfs_binary + " -o " + JoinStrings(mount_options, ",") +
610  " " + fqrn + " " + mountpoint;
611  if (has_fuse_group) {
612  cmd = "sg fuse -c \"" + cmd + "\"";
613  }
614  LogCvmfs(kLogCvmfs, kLogStdout, "%s", cmd.c_str());
615  return 0;
616  }
617 
618  // Real mount, add supplementary fuse group
619  if (has_fuse_group) {
620  retval = AddGroup2Persona(gid_fuse);
621  if (!retval) {
622  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add fuse to "
623  " the list of supplementary groups");
624  return 1;
625  }
626  }
627 
628  // Exec cvmfs2, from here on errors return 32 (mount error)
629  int fd_stdin, fd_stdout, fd_stderr;
630  pid_t pid_cvmfs;
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);
636  retval = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
637  cvmfs_binary, cvmfs_args, false, &pid_cvmfs);
638  if (!retval) {
639  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s",
640  cvmfs_binary.c_str());
641  return 32;
642  }
643  close(fd_stdin);
644 
645  // Print stdout / stderr and collect exit code
646  int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
647  fd_set readfds;
648  bool stdout_open = true;
649  bool stderr_open = true;
650  int status = 0;
651  int ended = false;
652 
653  do {
654  FD_ZERO(&readfds);
655  if (stdout_open) FD_SET(fd_stdout, &readfds);
656  if (stderr_open) FD_SET(fd_stderr, &readfds);
657 
658  struct timeval timeout;
659  timeout.tv_sec = 0;
660  timeout.tv_usec = 100;
661  retval = select(nfds, &readfds, NULL, NULL, &timeout);
662  if ((retval == -1) && (errno != EINTR)) {
663  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to pipe stdout/stderr");
664  return 32;
665  }
666 
667  char buf;
668  ssize_t num_bytes;
669  if (FD_ISSET(fd_stdout, &readfds)) {
670  num_bytes = read(fd_stdout, &buf, 1);
671  switch (num_bytes) {
672  case 0:
673  stdout_open = false;
674  break;
675  case 1:
677  break;
678  default:
679  LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stdout");
680  return 32;
681  }
682  }
683  if (FD_ISSET(fd_stderr, &readfds)) {
684  num_bytes = read(fd_stderr, &buf, 1);
685  switch (num_bytes) {
686  case 0:
687  stderr_open = false;
688  break;
689  case 1:
691  break;
692  default:
693  LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stderr");
694  return 32;
695  }
696  }
697 
698  // TODO(vvolkl): This block has seen several rounds of iterations,
699  // that tried to adress races and incorrect return codes.
700  // Should be looked at once again to make sure the cause of the
701  // race is understood, and if the timeout is really needed.
702 
703  ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
704  } while ((stdout_open || stderr_open) && !ended);
705  if (!ended) {
706  waitpid(pid_cvmfs, &status, 0);
707  }
708 
709  close(fd_stdout);
710  close(fd_stderr);
711 
712  if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
713  return 0;
714 
715  return 32;
716 }
void SetLogSyslogFacility(const int local_facility)
Definition: logging.cc:183
void SetLogSyslogLevel(const int level)
Definition: logging.cc:151
int MakeSocket(const std::string &path, const int mode)
Definition: posix.cc:331
struct stat64 platform_stat64
static bool CheckFuse()
Definition: mount.cvmfs.cc:72
static bool CheckConcurrentMount(const string &fqrn, const string &workspace, string *mountpointp)
Definition: mount.cvmfs.cc:137
static bool GetCacheDir(const string &fqrn, string *cachedir)
Definition: mount.cvmfs.cc:214
NameString GetFileName(const PathString &path)
Definition: shortstring.cc:29
static void Usage(const char *progname)
static bool CheckProxy()
Definition: mount.cvmfs.cc:126
string JoinStrings(const vector< string > &strings, const string &joint)
Definition: string.cc:325
bool IsOn(const std::string &param_value) const
Definition: options.cc:409
static bool WaitForReload(const std::string &mountpoint)
Definition: mount.cvmfs.cc:256
static std::string GetCvmfsBinary()
Definition: mount.cvmfs.cc:297
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:659
static bool CheckStrictMount(const string &fqrn)
Definition: mount.cvmfs.cc:96
int platform_stat(const char *path, platform_stat64 *buf)
void SetLogMicroSyslog(const std::string &filename)
Definition: logging.cc:272
void ParseDefault(const std::string &fqrn)
Definition: options.cc:282
bool AddGroup2Persona(const gid_t gid)
Definition: posix.cc:1401
#define SetLogDebugFile(filename)
void SwitchTemplateManager(OptionsTemplateManager *opt_templ_mgr_param)
Definition: options.cc:92
bool SymlinkExists(const std::string &path)
Definition: posix.cc:823
bool IsValid(const std::string &input) const
Definition: sanitizer.cc:114
static int AttachMount(const std::string &mountpoint, const std::string &fqrn, int fuse_fd)
Definition: mount.cvmfs.cc:322
int main()
Definition: helper_allow.cc:16
bool FileExists(const std::string &path)
Definition: posix.cc:791
static void AddMountOption(const string &option, vector< string > *mount_options)
Definition: mount.cvmfs.cc:49
int64_t String2Int64(const string &value)
Definition: string.cc:222
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:290
bool MkdirDeep(const std::string &path, const mode_t mode, bool verify_writable)
Definition: posix.cc:846
int LockFile(const std::string &path)
Definition: posix.cc:971
string StringifyInt(const int64_t value)
Definition: string.cc:78
bool GetGidOf(const std::string &groupname, gid_t *gid)
Definition: posix.cc:1367
static string MkFqrn(const string &repository)
Definition: mount.cvmfs.cc:56
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1047
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:267
bool GetValue(const std::string &key, std::string *value) const
Definition: options.cc:376
bool DirectoryExists(const std::string &path)
Definition: posix.cc:813
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)
Definition: posix.cc:1659
static int GetExistingFuseFd(const string &fqrn, const string &workspace, uid_t cvmfs_uid)
Definition: mount.cvmfs.cc:159
static bool GetCvmfsUser(string *cvmfs_user)
Definition: mount.cvmfs.cc:285
int ConnectSocket(const std::string &path)
Definition: posix.cc:427
string Base64(const string &data)
Definition: string.cc:504
BashOptionsManager options_manager_
Definition: mount.cvmfs.cc:34
uint64_t String2Uint64(const string &value)
Definition: string.cc:228
bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid)
Definition: posix.cc:1344
static bool GetWorkspace(const string &fqrn, string *workspace)
Definition: mount.cvmfs.cc:238
void SafeSleepMs(const unsigned ms)
Definition: posix.cc:1975
void SetLogSyslogPrefix(const std::string &prefix)
Definition: logging.cc:241
std::string MakeCanonicalPath(const std::string &path)
Definition: posix.cc:98
bool IsDefined(const std::string &key)
Definition: options.cc:370
bool IsMountPoint(const std::string &path)
Definition: posix.cc:266
int RecvFdFromSocket(int msg_fd)
Definition: posix.cc:708
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528