CernVM-FS  2.11.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  // Try connecting to cvmfs_io socket
141  int socket_fd = ConnectSocket(workspace + "/cvmfs_io." + fqrn);
142  if (socket_fd < 0)
143  return false;
144 
145  // There is a repository mounted, find out the mount point
146  SendMsg2Socket(socket_fd, "mountpoint");
147  string mountpoint;
148  char buf;
149  while (read(socket_fd, &buf, 1) == 1) {
150  if (buf != '\n')
151  mountpoint.push_back(buf);
152  }
153  *mountpointp = mountpoint;
154  close(socket_fd);
155  return true;
156 }
157 
158 static int GetExistingFuseFd(
159  const string &fqrn, const string &workspace, uid_t cvmfs_uid)
160 {
161  // Try connecting to cvmfs_io socket
162  int talk_fd = ConnectSocket(workspace + "/cvmfs_io." + fqrn);
163  if (talk_fd < 0)
164  return -1;
165 
166  // Create temporary socket
167  std::string recv_sock_dir = CreateTempDir(workspace + "/fusefd");
168  if (recv_sock_dir.empty() || (chmod(recv_sock_dir.c_str(), 0755) != 0)) {
169  close(talk_fd);
170  return -1;
171  }
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))
176  {
177  if (recv_sock_fd >= 0)
178  close(recv_sock_fd);
179  close(talk_fd);
180  unlink(recv_sock_path.c_str());
181  rmdir(recv_sock_dir.c_str());
182  return -1;
183  }
184  listen(recv_sock_fd, 1);
185 
186  // Trigger fd transfer
187  SendMsg2Socket(talk_fd, "send mount fd " + recv_sock_path);
188  string result;
189  char buf;
190  while (read(talk_fd, &buf, 1) == 1) {
191  if (buf != '\n')
192  result.push_back(buf);
193  }
194  close(talk_fd);
195 
196  int fuse_fd = -1;
197  if (result == "OK") {
198  struct sockaddr_un addr;
199  unsigned int len = sizeof(addr);
200  int con_fd =
201  accept(recv_sock_fd, reinterpret_cast<struct sockaddr *>(&addr), &len);
202  fuse_fd = RecvFdFromSocket(con_fd);
203  close(con_fd);
204  }
205  close(recv_sock_fd);
206  unlink(recv_sock_path.c_str());
207  rmdir(recv_sock_dir.c_str());
208 
209  return fuse_fd;
210 }
211 
212 
213 static bool GetCacheDir(const string &fqrn, string *cachedir) {
214  string param;
215  bool retval = options_manager_.GetValue("CVMFS_CACHE_DIR", &param);
216  if (retval) {
217  *cachedir = MakeCanonicalPath(param);
218  return true;
219  }
220 
221  retval = options_manager_.GetValue("CVMFS_CACHE_BASE", &param);
222  if (!retval)
223  return false;
224 
225  *cachedir = MakeCanonicalPath(param);
226  if (options_manager_.GetValue("CVMFS_SHARED_CACHE", &param) &&
227  options_manager_.IsOn(param))
228  {
229  *cachedir = *cachedir + "/shared";
230  } else {
231  *cachedir = *cachedir + "/" + fqrn;
232  }
233  return true;
234 }
235 
236 
237 static bool GetWorkspace(const string &fqrn, string *workspace) {
238  string param;
239  bool retval = options_manager_.GetValue("CVMFS_WORKSPACE", &param);
240  if (retval) {
241  *workspace = MakeCanonicalPath(param);
242  return true;
243  }
244 
245  retval = GetCacheDir(fqrn, workspace);
246  if (!retval) {
248  "CVMFS_WORKSPACE or CVMFS_CACHE_[BASE|DIR] required");
249  return false;
250  }
251  return true;
252 }
253 
254 
255 static bool WaitForReload(const std::string &mountpoint) {
256  string param;
257  int retval = options_manager_.GetValue("CVMFS_RELOAD_SOCKETS", &param);
258  if (!retval) {
259  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_RELOAD_SOCKETS required");
260  return false;
261  }
262  string reload_guard = param + "/cvmfs.pause";
263  // Deprecated, now a directory
264  if (FileExists(reload_guard)) {
265  LogCvmfs(kLogCvmfs, kLogStdout, "Waiting for CernVM-FS reload...");
266  while (FileExists(reload_guard))
267  SafeSleepMs(250);
268  }
269  if (DirectoryExists(reload_guard)) {
270  LogCvmfs(kLogCvmfs, kLogStdout, "Waiting for CernVM-FS reload...");
271  const string mountpoint_base64 = Base64(mountpoint);
272  while (DirectoryExists(reload_guard)) {
273  // We are in paused state but automounter unmounted the repo.
274  // We need to allow to mount just to reload.
275  if (FileExists(reload_guard + "/" + mountpoint_base64))
276  break;
277  SafeSleepMs(250);
278  }
279  }
280  return true;
281 }
282 
283 
284 static bool GetCvmfsUser(string *cvmfs_user) {
285  string param;
286  int retval = options_manager_.GetValue("CVMFS_USER", &param);
287  if (!retval) {
288  LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_USER required");
289  return false;
290  }
291  *cvmfs_user = param; // No sanitation; due to PAM, username can be anything
292  return true;
293 }
294 
295 
296 static std::string GetCvmfsBinary() {
297  std::string result;
298  vector<string> paths;
299  paths.push_back("/usr/bin");
300 
301 #ifdef __APPLE__
302  // OS X El Capitan came with SIP, forcing us to become relocatable. CVMFS
303  // 2.2.0+ installs into /usr/local always
304  paths.push_back("/usr/local/bin");
305 #endif
306 
307  // TODO(reneme): C++11 range based for loop
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";
312  if (FileExists(cvmfs2) || SymlinkExists(cvmfs2)) {
313  result = cvmfs2;
314  break;
315  }
316  }
317 
318  return result;
319 }
320 
321 static int AttachMount(const std::string &mountpoint, const std::string &fqrn,
322  int fuse_fd)
323 {
324 #ifdef __APPLE__
325  (void) mountpoint;
326  (void) fqrn;
327  (void) fuse_fd;
328  return 1;
329 #else
330  platform_stat64 info;
331  int retval = platform_stat(mountpoint.c_str(), &info);
332  if (retval != 0)
333  return 1;
334 
335  char mntopt[100];
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());
339  // TODO(jblomer): remove NOSUID according to options
340  retval = mount("cvmfs2", mountpoint.c_str(), "fuse",
341  MS_NODEV | MS_RDONLY | MS_NOSUID, mntopt);
342  if (retval != 0) {
344  "Cannot attach to existing fuse module (%d)", errno);
345  return 1;
346  }
348  "CernVM-FS: linking %s to repository %s (attaching)",
349  mountpoint.c_str(), fqrn.c_str());
350  return 0;
351 #endif
352 }
353 
354 
355 int main(int argc, char **argv) {
356  bool dry_run = false;
357  bool remount = false;
358  vector<string> mount_options;
359 
360  // Option parsing
361  vector<string> option_tokens;
362  int c;
363  while ((c = getopt(argc, argv, "vfnho:")) != -1) {
364  switch (c) {
365  case 'f':
366  dry_run = true;
367  break;
368  case 'n':
369  LogCvmfs(kLogCvmfs, kLogStdout, "Note: fusermount _does_ modify "
370  "/etc/mtab in case it is writable.");
371  // Fall through
372  case 'v':
373  break;
374  case 'h':
375  Usage(kLogStdout);
376  return 0;
377  case 'o':
378  AddMountOption(optarg, &mount_options);
379  option_tokens = SplitString(optarg, ',');
380  for (unsigned i = 0; i < option_tokens.size(); ++i) {
381  if (option_tokens[i] == string("remount"))
382  remount = true;
383  }
384  break;
385  default:
386  Usage(kLogStderr);
387  return 1;
388  }
389  }
390  if (optind+2 != argc) {
391  Usage(kLogStderr);
392  return 1;
393  }
394 
395  string device = argv[optind];
396  // Some mount versions expand the given device to a full path. Thus ignore
397  // everything before the last slash (/)/
398  if (HasPrefix(device, "/", false))
399  device = GetFileName(device);
400  sanitizer::RepositorySanitizer repository_sanitizer;
401  if (device.empty() || !repository_sanitizer.IsValid(device)) {
402  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid repository: %s", device.c_str());
403  return 1;
404  }
405  string mountpoint = argv[optind+1];
406 
408  const string fqrn = MkFqrn(device);
412 
413  string optarg;
414  if (options_manager_.GetValue("CVMFS_SYSLOG_LEVEL", &optarg))
416  if (options_manager_.GetValue("CVMFS_SYSLOG_FACILITY", &optarg))
418  if (options_manager_.GetValue("CVMFS_USYSLOG", &optarg))
419  SetLogMicroSyslog(optarg + ".mount");
420  if (options_manager_.GetValue("CVMFS_DEBUGLOG", &optarg))
421  SetLogDebugFile(optarg + ".mount");
422  SetLogSyslogPrefix(fqrn);
423 
424  int retval;
425  int sysret;
426  bool dedicated_cachedir = false;
427  string cvmfs_user;
428  string cachedir;
429  string workspace;
430  // Environment checks
431  retval = WaitForReload(mountpoint);
432  if (!retval) return 1;
433  retval = GetWorkspace(fqrn, &workspace);
434  if (!retval) return 1;
435  retval = GetCacheDir(fqrn, &cachedir);
436  dedicated_cachedir = (retval && (cachedir != workspace));
437  retval = GetCvmfsUser(&cvmfs_user);
438  if (!retval) return 1;
439  retval = CheckFuse();
440  if (!retval) return 1;
441  retval = CheckStrictMount(fqrn);
442  if (!retval) return 1;
443  retval = CheckProxy();
444  if (!retval) return 1;
445 
446  // Retrieve cvmfs uid/gid and fuse gid if exists
447  uid_t uid_cvmfs;
448  gid_t gid_cvmfs;
449  gid_t gid_fuse;
450  bool has_fuse_group = false;
451  retval = GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
452  if (!retval) {
453  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to find user %s in passwd database",
454  cvmfs_user.c_str());
455  return 1;
456  }
457  has_fuse_group = GetGidOf("fuse", &gid_fuse);
458 
459  // This is not a sure thing. When the CVMFS_CACHE_BASE parameter is changed
460  // two repositories can get mounted concurrently (but that should not hurt).
461  // If the same repository is mounted multiple times at the same time, there
462  // is a race here. Eventually, only one repository will be mounted while the
463  // other cvmfs processes block on a file lock in the cache.
464  string prev_mountpoint;
465  retval = CheckConcurrentMount(fqrn, workspace, &prev_mountpoint);
466  if (retval) {
467  if (remount && (mountpoint == prev_mountpoint)) {
468  // Actually remounting is too hard, but pretend that it worked
469  return 0;
470  }
471  // Identify zombie fuse processes that are held open by other mount
472  // namespaces
473  if ((mountpoint == prev_mountpoint) && !IsMountPoint(mountpoint)) {
474  // Allow for group access to the socket receiving the fuse fd
475  umask(007);
476  int fuse_fd = GetExistingFuseFd(fqrn, workspace, uid_cvmfs);
477  if (fuse_fd < 0) {
479  "Cannot connect to existing fuse module");
480  return 1;
481  }
482  return AttachMount(mountpoint, fqrn, fuse_fd);
483  }
484  LogCvmfs(kLogCvmfs, kLogStderr, "Repository %s is already mounted on %s",
485  fqrn.c_str(), prev_mountpoint.c_str());
486  return 1;
487  } else {
488  // No double mount
489  if (remount) {
490  LogCvmfs(kLogCvmfs, kLogStderr, "Repository %s is not mounted on %s",
491  fqrn.c_str(), mountpoint.c_str());
492  return 1;
493  }
494  }
495 
496  // Prepare workspace and cache directory
497  retval = MkdirDeep(workspace, 0755, false);
498  if (!retval) {
499  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create workspace %s",
500  workspace.c_str());
501  return 1;
502  }
503  if (dedicated_cachedir) {
504  retval = MkdirDeep(cachedir, 0755, false);
505  if (!retval) {
506  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create cache directory %s",
507  cachedir.c_str());
508  return 1;
509  }
510  }
511  retval = MkdirDeep("/var/run/cvmfs", 0755);
512  if (!retval) {
513  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create socket directory");
514  return 1;
515  }
516  sysret = chown(workspace.c_str(), uid_cvmfs, getegid());
517  if (sysret != 0) {
518  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
519  workspace.c_str(), cvmfs_user.c_str());
520  return 1;
521  }
522  if (dedicated_cachedir) {
523  sysret = chown(cachedir.c_str(), uid_cvmfs, getegid());
524  if (sysret != 0) {
526  "Failed to transfer ownership of %s to %s",
527  cachedir.c_str(), cvmfs_user.c_str());
528  return 1;
529  }
530  }
531  sysret = chown("/var/run/cvmfs", uid_cvmfs, getegid());
532  if (sysret != 0) {
533  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
534  "/var/run/cvmfs", cvmfs_user.c_str());
535  return 1;
536  }
537 
538  // Set maximum number of files
539 #ifdef __APPLE__
540  string param;
541  if (options_manager_.GetValue("CVMFS_NFILES", &param)) {
542  sanitizer::IntegerSanitizer integer_sanitizer;
543  if (!integer_sanitizer.IsValid(param)) {
544  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid CVMFS_NFILES: %s",
545  param.c_str());
546  return 1;
547  }
548  int nfiles = String2Uint64(param);
549  if ((nfiles < 128) || (nfiles > 524288)) {
550  LogCvmfs(kLogCvmfs, kLogStderr, "Invalid CVMFS_NFILES: %s",
551  param.c_str());
552  return 1;
553  }
554  int nfiles_all = nfiles + 512;
555  int sys_nfiles, sys_nfiles_all;
556  size_t len = sizeof(sys_nfiles);
557  int mib[2];
558  mib[0] = CTL_KERN;
559  mib[1] = KERN_MAXFILESPERPROC;
560  retval = sysctl(mib, 2, &sys_nfiles, &len, NULL, 0);
561  if ((retval != 0) || (sys_nfiles < 0)) {
562  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to get KERN_MAXFILESPERPROC");
563  return 1;
564  }
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)) {
569  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to get KERN_MAXFILES");
570  return 1;
571  }
572  if (sys_nfiles_all < nfiles_all) {
573  retval = sysctl(mib, 2, NULL, NULL, &nfiles_all, sizeof(nfiles_all));
574  if (retval != 0) {
575  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to set KERN_MAXFILES");
576  return 1;
577  }
578  }
579  mib[1] = KERN_MAXFILESPERPROC;
580  retval = sysctl(mib, 2, NULL, NULL, &nfiles_all, sizeof(nfiles_all));
581  if (retval != 0) {
582  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to set KERN_MAXFILESPERPROC");
583  return 1;
584  }
585  }
586  }
587 #endif
588 
589  AddMountOption("system_mount", &mount_options);
590  AddMountOption("fsname=cvmfs2", &mount_options);
591  AddMountOption("allow_other", &mount_options);
592  AddMountOption("grab_mountpoint", &mount_options);
593  AddMountOption("uid=" + StringifyInt(uid_cvmfs), &mount_options);
594  AddMountOption("gid=" + StringifyInt(gid_cvmfs), &mount_options);
595  if (options_manager_.IsDefined("CVMFS_DEBUGLOG"))
596  AddMountOption("debug", &mount_options);
597 
598  const string cvmfs_binary = GetCvmfsBinary();
599  if (cvmfs_binary.empty()) {
600  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to locate the cvmfs2 binary");
601  return 1;
602  }
603 
604  // Dry run early exit
605  if (dry_run) {
606  string cmd = cvmfs_binary + " -o " + JoinStrings(mount_options, ",") +
607  " " + fqrn + " " + mountpoint;
608  if (has_fuse_group) {
609  cmd = "sg fuse -c \"" + cmd + "\"";
610  }
611  LogCvmfs(kLogCvmfs, kLogStdout, "%s", cmd.c_str());
612  return 0;
613  }
614 
615  // Real mount, add supplementary fuse group
616  if (has_fuse_group) {
617  retval = AddGroup2Persona(gid_fuse);
618  if (!retval) {
619  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add fuse to "
620  " the list of supplementary groups");
621  return 1;
622  }
623  }
624 
625  // Exec cvmfs2, from here on errors return 32 (mount error)
626  int fd_stdin, fd_stdout, fd_stderr;
627  pid_t pid_cvmfs;
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);
633  retval = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
634  cvmfs_binary, cvmfs_args, false, &pid_cvmfs);
635  if (!retval) {
636  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s",
637  cvmfs_binary.c_str());
638  return 32;
639  }
640  close(fd_stdin);
641 
642  // Print stdout / stderr and collect exit code
643  int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
644  fd_set readfds;
645  bool stdout_open = true;
646  bool stderr_open = true;
647  int status = 0;
648  int ended = false;
649 
650  do {
651  FD_ZERO(&readfds);
652  if (stdout_open) FD_SET(fd_stdout, &readfds);
653  if (stderr_open) FD_SET(fd_stderr, &readfds);
654 
655  struct timeval timeout;
656  timeout.tv_sec = 0;
657  timeout.tv_usec = 100;
658  retval = select(nfds, &readfds, NULL, NULL, &timeout);
659  if ((retval == -1) && (errno != EINTR)) {
660  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to pipe stdout/stderr");
661  return 32;
662  }
663 
664  char buf;
665  ssize_t num_bytes;
666  if (FD_ISSET(fd_stdout, &readfds)) {
667  num_bytes = read(fd_stdout, &buf, 1);
668  switch (num_bytes) {
669  case 0:
670  stdout_open = false;
671  break;
672  case 1:
674  break;
675  default:
676  LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stdout");
677  return 32;
678  }
679  }
680  if (FD_ISSET(fd_stderr, &readfds)) {
681  num_bytes = read(fd_stderr, &buf, 1);
682  switch (num_bytes) {
683  case 0:
684  stderr_open = false;
685  break;
686  case 1:
688  break;
689  default:
690  LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stderr");
691  return 32;
692  }
693  }
694  ended = (waitpid(pid_cvmfs, &status, WNOHANG) == pid_cvmfs);
695  } while ((stdout_open || stderr_open) && !ended);
696  close(fd_stdout);
697  close(fd_stderr);
698 
699  if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
700  return 0;
701 
702  return 32;
703 }
#define LogCvmfs(source, mask,...)
Definition: logging.h:25
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:213
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:255
static std::string GetCvmfsBinary()
Definition: mount.cvmfs.cc:296
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:321
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
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:158
static bool GetCvmfsUser(string *cvmfs_user)
Definition: mount.cvmfs.cc:284
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:237
void SafeSleepMs(const unsigned ms)
Definition: posix.cc:1972
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