CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
posix.cc
Go to the documentation of this file.
1 
7 #ifndef __STDC_FORMAT_MACROS
8 // NOLINTNEXTLINE
9 #define __STDC_FORMAT_MACROS
10 #endif
11 
12 
13 #include "posix.h"
14 
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <grp.h>
19 #include <inttypes.h>
20 #include <netinet/in.h>
21 #include <pthread.h>
22 #include <pwd.h>
23 #include <signal.h>
24 #include <stdint.h>
25 #include <sys/resource.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #ifdef __APPLE__
29 #include <sys/mount.h> // for statfs()
30 #else
31 #include <sys/statfs.h>
32 #endif
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/un.h>
36 #include <sys/utsname.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 // If valgrind headers are present on the build system, then we can detect
40 // valgrind at runtime.
41 #ifdef HAS_VALGRIND_HEADERS
42 #include <valgrind/valgrind.h>
43 #endif
44 
45 #include <algorithm>
46 #include <cassert>
47 #include <cstdio>
48 #include <cstring>
49 #include <map>
50 #include <set>
51 #include <string>
52 #include <vector>
53 
54 #include "util/algorithm.h"
55 #include "util/concurrency.h"
56 #include "util/exception.h"
57 #include "util/fs_traversal.h"
58 #include "util/logging.h"
59 #include "util/pipe.h"
60 #include "util/platform.h"
61 #include "util/string.h"
62 
63 // using namespace std; // NOLINT
64 
65 #ifndef ST_RDONLY
66 // On Linux, this is in sys/statvfs.h
67 // On macOS, this flag is called MNT_RDONLY /usr/include/sys/mount.h
68 #define ST_RDONLY 1
69 #endif
70 
71 // Older Linux glibc versions do not provide the f_flags member in struct statfs
72 #define CVMFS_HAS_STATFS_F_FLAGS
73 #ifndef __APPLE__
74 #ifdef __GLIBC_MINOR__
75 #if __GLIBC_MINOR__ < 12
76 #undef CVMFS_HAS_STATFS_F_FLAGS
77 #endif
78 #endif
79 #endif
80 
81 // Work around missing clearenv()
82 #ifdef __APPLE__
83 extern "C" {
84 extern char **environ;
85 }
86 #endif
87 
88 #ifdef CVMFS_NAMESPACE_GUARD
89 namespace CVMFS_NAMESPACE_GUARD {
90 #endif
91 
92 static pthread_mutex_t getumask_mutex = PTHREAD_MUTEX_INITIALIZER;
93 
94 
98 std::string MakeCanonicalPath(const std::string &path) {
99  if (path.length() == 0)
100  return path;
101 
102  if (path[path.length() - 1] == '/') {
103  return path.substr(0, path.length() - 1);
104  } else {
105  return path;
106  }
107 }
108 
114 void SplitPath(const std::string &path,
115  std::string *dirname,
116  std::string *filename) {
117  const size_t dir_sep = path.rfind('/');
118  if (dir_sep != std::string::npos) {
119  *dirname = path.substr(0, dir_sep);
120  *filename = path.substr(dir_sep + 1);
121  } else {
122  *dirname = ".";
123  *filename = path;
124  }
125 }
126 
127 
131 std::string GetParentPath(const std::string &path) {
132  const std::string::size_type idx = path.find_last_of('/');
133  if (idx != std::string::npos) {
134  return path.substr(0, idx);
135  } else {
136  return "";
137  }
138 }
139 
140 
144 std::string GetFileName(const std::string &path) {
145  const std::string::size_type idx = path.find_last_of('/');
146  if (idx != std::string::npos) {
147  return path.substr(idx + 1);
148  } else {
149  return path;
150  }
151 }
152 
153 
154 bool IsAbsolutePath(const std::string &path) {
155  return (!path.empty() && path[0] == '/');
156 }
157 
158 
159 std::string GetAbsolutePath(const std::string &path) {
160  if (IsAbsolutePath(path))
161  return path;
162 
163  return GetCurrentWorkingDirectory() + "/" + path;
164 }
165 
166 
167 bool IsHttpUrl(const std::string &path) {
168  if (path.length() < 7) {
169  return false;
170  }
171 
172  std::string prefix = path.substr(0, 8);
173  std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
174 
175  return prefix.substr(0, 7) == "http://" || prefix == "https://";
176 }
177 
178 
179 FileSystemInfo GetFileSystemInfo(const std::string &path) {
180  FileSystemInfo result;
181 
182  struct statfs info;
183  const int retval = statfs(path.c_str(), &info);
184  if (retval != 0)
185  return result;
186 
187  switch (info.f_type) {
188  case kFsTypeAutofs:
189  result.type = kFsTypeAutofs;
190  break;
191  case kFsTypeNFS:
192  result.type = kFsTypeNFS;
193  break;
194  case kFsTypeProc:
195  result.type = kFsTypeProc;
196  break;
197  case kFsTypeBeeGFS:
198  result.type = kFsTypeBeeGFS;
199  break;
200  case kFsTypeTmpfs:
201  result.type = kFsTypeTmpfs;
202  break;
203  default:
204  result.type = kFsTypeUnknown;
205  }
206 
207 #ifdef CVMFS_HAS_STATFS_F_FLAGS
208  if (info.f_flags & ST_RDONLY)
209  result.is_rdonly = true;
210 #else
211  // On old Linux systems, fall back to access()
212  retval = access(path.c_str(), W_OK);
213  result.is_rdonly = (retval != 0);
214 #endif
215 
216 
217  return result;
218 }
219 
220 
221 std::string ReadSymlink(const std::string &path) {
222  // TODO(jblomer): avoid PATH_MAX
223  char buf[PATH_MAX + 1];
224  const ssize_t nchars = readlink(path.c_str(), buf, PATH_MAX);
225  if (nchars >= 0) {
226  buf[nchars] = '\0';
227  return std::string(buf);
228  }
229  return "";
230 }
231 
232 
237 std::string ResolvePath(const std::string &path) {
238  if (path.empty() || (path == "/"))
239  return "/";
240  const std::string name = GetFileName(path);
241  std::string result = name;
242  if (name != path) {
243  // There is a parent path of 'path'
244  const std::string parent = ResolvePath(GetParentPath(path));
245  result = parent + (parent == "/" ? "" : "/") + name;
246  }
247  char *real_result = realpath(result.c_str(), NULL);
248  if (real_result) {
249  result = real_result;
250  free(real_result);
251  }
252  if (SymlinkExists(result)) {
253  char buf[PATH_MAX + 1];
254  const ssize_t nchars = readlink(result.c_str(), buf, PATH_MAX);
255  if (nchars >= 0) {
256  buf[nchars] = '\0';
257  result = buf;
258  }
259  }
260  return result;
261 }
262 
263 
264 bool IsMountPoint(const std::string &path) {
265  std::vector<std::string> mount_list = platform_mountlist();
266  const std::string resolved_path = ResolvePath(path);
267  for (unsigned i = 0; i < mount_list.size(); ++i) {
268  if (mount_list[i] == resolved_path)
269  return true;
270  }
271  return false;
272 }
273 
274 
278 void CreateFile(const std::string &path,
279  const int mode,
280  const bool ignore_failure) {
281  const int fd = open(path.c_str(), O_CREAT, mode);
282  if (fd >= 0) {
283  close(fd);
284  return;
285  }
286  if (ignore_failure)
287  return;
288  PANIC(NULL);
289 }
290 
291 
295 static std::string MakeShortSocketLink(const std::string &path) {
296  struct sockaddr_un sock_addr;
297  const unsigned max_length = sizeof(sock_addr.sun_path);
298 
299  std::string result;
300  const std::string tmp_path = CreateTempDir("/tmp/cvmfs");
301  if (tmp_path.empty())
302  return "";
303  const std::string link = tmp_path + "/l";
304  result = link + "/" + GetFileName(path);
305  if (result.length() >= max_length) {
306  rmdir(tmp_path.c_str());
307  return "";
308  }
309  const int retval = symlink(GetParentPath(path).c_str(), link.c_str());
310  if (retval != 0) {
311  rmdir(tmp_path.c_str());
312  return "";
313  }
314  return result;
315 }
316 
317 static void RemoveShortSocketLink(const std::string &short_path) {
318  const std::string link = GetParentPath(short_path);
319  unlink(link.c_str());
320  rmdir(GetParentPath(link).c_str());
321 }
322 
323 
327 int MakeSocket(const std::string &path, const int mode) {
328  std::string short_path(path);
329  struct sockaddr_un sock_addr;
330  if (path.length() >= sizeof(sock_addr.sun_path)) {
331  // Socket paths are limited to 108 bytes (on some systems to 92 bytes),
332  // try working around
333  short_path = MakeShortSocketLink(path);
334  if (short_path.empty())
335  return -1;
336  }
337  sock_addr.sun_family = AF_UNIX;
338  strncpy(sock_addr.sun_path, short_path.c_str(), sizeof(sock_addr.sun_path));
339 
340  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
341  assert(socket_fd != -1);
342 
343 #ifndef __APPLE__
344  // fchmod on a socket is not allowed under Mac OS X
345  // using default 0770 here
346  if (fchmod(socket_fd, mode) != 0)
347  goto make_socket_failure;
348 #endif
349 
350  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
351  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path))
352  < 0) {
353  if ((errno == EADDRINUSE) && (unlink(path.c_str()) == 0)) {
354  // Second try, perhaps the file was left over
355  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
356  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path))
357  < 0) {
358  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
359  goto make_socket_failure;
360  }
361  } else {
362  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
363  goto make_socket_failure;
364  }
365  }
366 
367  if (short_path != path)
368  RemoveShortSocketLink(short_path);
369 
370  return socket_fd;
371 
372 make_socket_failure:
373  close(socket_fd);
374  if (short_path != path)
375  RemoveShortSocketLink(short_path);
376  return -1;
377 }
378 
379 
384 int MakeTcpEndpoint(const std::string &ipv4_address, int portno) {
385  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
386  assert(socket_fd != -1);
387  const int on = 1;
388  int retval = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
389  assert(retval == 0);
390 
391  struct sockaddr_in endpoint_addr;
392  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
393  endpoint_addr.sin_family = AF_INET;
394  if (ipv4_address.empty()) {
395  endpoint_addr.sin_addr.s_addr = INADDR_ANY;
396  } else {
397  retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
398  if (retval == 0) {
399  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
400  close(socket_fd);
401  return -1;
402  }
403  }
404  endpoint_addr.sin_port = htons(portno);
405 
406  retval = bind(socket_fd, reinterpret_cast<struct sockaddr *>(&endpoint_addr),
407  sizeof(endpoint_addr));
408  if (retval < 0) {
409  LogCvmfs(kLogCvmfs, kLogDebug, "binding TCP endpoint failed (%d)", errno);
410  close(socket_fd);
411  return -1;
412  }
413  return socket_fd;
414 }
415 
416 
422 int ConnectSocket(const std::string &path) {
423  std::string short_path(path);
424  struct sockaddr_un sock_addr;
425  if (path.length() >= sizeof(sock_addr.sun_path)) {
426  // Socket paths are limited to 108 bytes (on some systems to 92 bytes),
427  // try working around
428  short_path = MakeShortSocketLink(path);
429  if (short_path.empty())
430  return -1;
431  }
432  sock_addr.sun_family = AF_UNIX;
433  strncpy(sock_addr.sun_path, short_path.c_str(), sizeof(sock_addr.sun_path));
434 
435  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
436  assert(socket_fd != -1);
437 
438  const int retval =
439  connect(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
440  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path));
441  if (short_path != path)
442  RemoveShortSocketLink(short_path);
443 
444  if (retval < 0) {
445  close(socket_fd);
446  return -1;
447  }
448 
449  return socket_fd;
450 }
451 
452 
456 int ConnectTcpEndpoint(const std::string &ipv4_address, int portno) {
457  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
458  assert(socket_fd != -1);
459 
460  struct sockaddr_in endpoint_addr;
461  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
462  endpoint_addr.sin_family = AF_INET;
463  int retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
464  if (retval == 0) {
465  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
466  close(socket_fd);
467  return -1;
468  }
469  endpoint_addr.sin_port = htons(portno);
470 
471  retval = connect(socket_fd,
472  reinterpret_cast<struct sockaddr *>(&endpoint_addr),
473  sizeof(endpoint_addr));
474  if (retval != 0) {
475  LogCvmfs(kLogCvmfs, kLogDebug, "failed to connect to TCP endpoint (%d)",
476  errno);
477  close(socket_fd);
478  return -1;
479  }
480  return socket_fd;
481 }
482 
483 
487 void MakePipe(int pipe_fd[2]) {
488  const int retval = pipe(pipe_fd);
489  assert(retval == 0);
490 }
491 
492 
496 void WritePipe(int fd, const void *buf, size_t nbyte) {
497  ssize_t num_bytes;
498  do {
499  num_bytes = write(fd, buf, nbyte);
500  } while ((num_bytes < 0) && (errno == EINTR));
501  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
502 }
503 
504 
508 void ReadPipe(int fd, void *buf, size_t nbyte) {
509  ssize_t num_bytes;
510  do {
511  num_bytes = read(fd, buf, nbyte);
512  } while ((num_bytes < 0) && (errno == EINTR));
513  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
514 }
515 
516 
520 bool ReadHalfPipe(int fd, void *buf, size_t nbyte, unsigned timeout_ms) {
521  ssize_t num_bytes;
522  unsigned i = 0;
523  unsigned backoff_ms = 1;
524  uint64_t duration_ms = 0;
525  uint64_t timestamp = 0;
526  if (timeout_ms != 0)
527  timestamp = platform_monotonic_time_ns();
528 
529  const unsigned max_backoff_ms = 256;
530  do {
531  // When the writer is not connected, this takes ~200-300ns per call as per
532  // micro benchmarks
533  num_bytes = read(fd, buf, nbyte);
534  if ((num_bytes < 0) && (errno == EINTR))
535  continue;
536  i++;
537  // Start backing off when the busy loop reaches the ballpark of 1ms
538  if ((i > 3000) && (num_bytes == 0)) {
539  // The BackoffThrottle would pull in too many dependencies
540  SafeSleepMs(backoff_ms);
541  if (backoff_ms < max_backoff_ms)
542  backoff_ms *= 2;
543  }
544  if ((timeout_ms != 0) && (num_bytes == 0)) {
545  duration_ms = (platform_monotonic_time_ns() - timestamp)
546  / (1000UL * 1000UL);
547  if (duration_ms > timeout_ms)
548  return false;
549  }
550  } while (num_bytes == 0);
551  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
552  return true;
553 }
554 
555 
559 void ClosePipe(int pipe_fd[2]) {
560  close(pipe_fd[0]);
561  close(pipe_fd[1]);
562 }
563 
564 
569 bool DiffTree(const std::string &path_a, const std::string &path_b) {
570  int retval;
571  std::vector<std::string> ls_a;
572  std::vector<std::string> ls_b;
573  std::vector<std::string> subdirs;
574 
575  DIR *dirp_a = opendir(path_a.c_str());
576  if (dirp_a == NULL)
577  return false;
578  DIR *dirp_b = opendir(path_b.c_str());
579  if (dirp_b == NULL) {
580  closedir(dirp_a);
581  return false;
582  }
583 
584  platform_dirent64 *dirent;
585  while ((dirent = platform_readdir(dirp_a))) {
586  const std::string name(dirent->d_name);
587  if ((name == ".") || (name == ".."))
588  continue;
589  const std::string path = path_a + "/" + name;
590  ls_a.push_back(path);
591 
592  platform_stat64 info;
593  retval = platform_lstat(path.c_str(), &info);
594  if (retval != 0) {
595  closedir(dirp_a);
596  closedir(dirp_b);
597  return false;
598  }
599  if (S_ISDIR(info.st_mode))
600  subdirs.push_back(name);
601  }
602  while ((dirent = platform_readdir(dirp_b))) {
603  const std::string name(dirent->d_name);
604  if ((name == ".") || (name == ".."))
605  continue;
606  const std::string path = path_b + "/" + name;
607  ls_b.push_back(path);
608  }
609  closedir(dirp_a);
610  closedir(dirp_b);
611 
612  sort(ls_a.begin(), ls_a.end());
613  sort(ls_b.begin(), ls_b.end());
614  if (ls_a.size() != ls_b.size())
615  return false;
616  for (unsigned i = 0; i < ls_a.size(); ++i) {
617  if (GetFileName(ls_a[i]) != GetFileName(ls_b[i]))
618  return false;
619  platform_stat64 info_a;
620  platform_stat64 info_b;
621  retval = platform_lstat(ls_a[i].c_str(), &info_a);
622  if (retval != 0)
623  return false;
624  retval = platform_lstat(ls_b[i].c_str(), &info_b);
625  if (retval != 0)
626  return false;
627  if ((info_a.st_mode != info_b.st_mode) || (info_a.st_uid != info_b.st_uid)
628  || (info_a.st_gid != info_b.st_gid)
629  || ((info_a.st_size != info_b.st_size) && !S_ISDIR(info_a.st_mode))) {
630  return false;
631  }
632  }
633 
634  for (unsigned i = 0; i < subdirs.size(); ++i) {
635  const bool retval_subtree =
636  DiffTree(path_a + "/" + subdirs[i], path_b + "/" + subdirs[i]);
637  if (!retval_subtree)
638  return false;
639  }
640 
641  return true;
642 }
643 
644 
648 void Nonblock2Block(int filedes) {
649  const int flags = fcntl(filedes, F_GETFL);
650  assert(flags != -1);
651  const int retval = fcntl(filedes, F_SETFL, flags & ~O_NONBLOCK);
652  assert(retval != -1);
653 }
654 
655 
659 void Block2Nonblock(int filedes) {
660  const int flags = fcntl(filedes, F_GETFL);
661  assert(flags != -1);
662  const int retval = fcntl(filedes, F_SETFL, flags | O_NONBLOCK);
663  assert(retval != -1);
664 }
665 
666 
671 void SendMsg2Socket(const int fd, const std::string &msg) {
672  (void)send(fd, &msg[0], msg.length(), MSG_NOSIGNAL);
673 }
674 
680 bool SendFd2Socket(int socket_fd, int passing_fd) {
681  union {
682  // Make sure that ctrl_msg is properly aligned.
683  struct cmsghdr align;
684  // Buffer large enough to store the file descriptor (ancillary data)
685  unsigned char buf[CMSG_SPACE(sizeof(int))];
686  } ctrl_msg;
687 
688  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
689 
690  struct msghdr msgh;
691  msgh.msg_name = NULL;
692  msgh.msg_namelen = 0;
693 
694  unsigned char dummy = 0;
695  struct iovec iov;
696  iov.iov_base = &dummy;
697  iov.iov_len = 1;
698  msgh.msg_iov = &iov;
699  msgh.msg_iovlen = 1;
700 
701  msgh.msg_control = ctrl_msg.buf;
702  msgh.msg_controllen = sizeof(ctrl_msg.buf);
703  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
704  cmsgp->cmsg_len = CMSG_LEN(sizeof(int));
705  cmsgp->cmsg_level = SOL_SOCKET;
706  cmsgp->cmsg_type = SCM_RIGHTS;
707  memcpy(CMSG_DATA(cmsgp), &passing_fd, sizeof(int));
708 
709  const ssize_t retval = sendmsg(socket_fd, &msgh, 0);
710  return (retval != -1);
711 }
712 
713 
720 int RecvFdFromSocket(int msg_fd) {
721  union {
722  // Make sure that ctrl_msg is properly aligned.
723  struct cmsghdr align;
724  // Buffer large enough to store the file descriptor (ancillary data)
725  unsigned char buf[CMSG_SPACE(sizeof(int))];
726  } ctrl_msg;
727 
728  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
729 
730  struct msghdr msgh;
731  msgh.msg_name = NULL;
732  msgh.msg_namelen = 0;
733 
734  unsigned char dummy;
735  struct iovec iov;
736  iov.iov_base = &dummy;
737  iov.iov_len = 1;
738  msgh.msg_iov = &iov;
739  msgh.msg_iovlen = 1;
740 
741  msgh.msg_control = ctrl_msg.buf;
742  msgh.msg_controllen = sizeof(ctrl_msg.buf);
743 
744  const ssize_t retval = recvmsg(msg_fd, &msgh, 0);
745  if (retval == -1)
746  return -errno;
747 
748  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
749  assert(cmsgp != NULL);
750  if (cmsgp->cmsg_len != CMSG_LEN(sizeof(int)))
751  return -ERANGE;
752  assert(cmsgp->cmsg_level == SOL_SOCKET);
753  assert(cmsgp->cmsg_type == SCM_RIGHTS);
754 
755  int passing_fd;
756  memcpy(&passing_fd, CMSG_DATA(cmsgp), sizeof(int));
757  assert(passing_fd >= 0);
758  return passing_fd;
759 }
760 
761 
762 std::string GetHostname() {
763  char name[HOST_NAME_MAX + 1];
764  const int retval = gethostname(name, HOST_NAME_MAX);
765  assert(retval == 0);
766  return name;
767 }
768 
769 
773 bool SwitchCredentials(const uid_t uid, const gid_t gid,
774  const bool temporarily) {
776  "current credentials uid %d gid %d "
777  "euid %d egid %d, switching to %d %d (temp: %d)",
778  getuid(), getgid(), geteuid(), getegid(), uid, gid, temporarily);
779  int retval = 0;
780  if (temporarily) {
781  if (gid != getegid())
782  retval = setegid(gid);
783  if ((retval == 0) && (uid != geteuid()))
784  retval = seteuid(uid);
785  } else {
786  // If effective uid is not root, we must first gain root access back
787  if ((getuid() == 0) && (getuid() != geteuid())) {
788  retval = SwitchCredentials(0, getgid(), true);
789  if (!retval)
790  return false;
791  }
792  retval = setgid(gid) || setuid(uid);
793  }
794  LogCvmfs(kLogCvmfs, kLogDebug, "switch credentials result %d (%d)", retval,
795  errno);
796  return retval == 0;
797 }
798 
799 
803 bool FileExists(const std::string &path) {
804  platform_stat64 info;
805  return ((platform_lstat(path.c_str(), &info) == 0) && S_ISREG(info.st_mode));
806 }
807 
808 
812 int64_t GetFileSize(const std::string &path) {
813  platform_stat64 info;
814  const int retval = platform_stat(path.c_str(), &info);
815  if (retval != 0)
816  return -1;
817  return info.st_size;
818 }
819 
820 
824 bool DirectoryExists(const std::string &path) {
825  platform_stat64 info;
826  return ((platform_lstat(path.c_str(), &info) == 0) && S_ISDIR(info.st_mode));
827 }
828 
829 
833 bool SymlinkExists(const std::string &path) {
834  platform_stat64 info;
835  return ((platform_lstat(path.c_str(), &info) == 0) && S_ISLNK(info.st_mode));
836 }
837 
838 
842 bool SymlinkForced(const std::string &src, const std::string &dest) {
843  int retval = unlink(dest.c_str());
844  if ((retval != 0) && (errno != ENOENT))
845  return false;
846  retval = symlink(src.c_str(), dest.c_str());
847  return retval == 0;
848 }
849 
850 
855 bool MkdirDeep(const std::string &path,
856  const mode_t mode,
857  bool verify_writable) {
858  if (path == "")
859  return false;
860 
861  int retval = mkdir(path.c_str(), mode);
862  if (retval == 0)
863  return true;
864 
865  if ((errno == ENOENT)
866  && (MkdirDeep(GetParentPath(path), mode, verify_writable))) {
867  return MkdirDeep(path, mode, verify_writable);
868  }
869 
870  if (errno == EEXIST) {
871  platform_stat64 info;
872  if ((platform_stat(path.c_str(), &info) == 0) && S_ISDIR(info.st_mode)) {
873  if (verify_writable) {
874  retval = utimes(path.c_str(), NULL);
875  if (retval == 0)
876  return true;
877  } else {
878  return true;
879  }
880  }
881  }
882 
883  return false;
884 }
885 
886 
890 bool MakeCacheDirectories(const std::string &path, const mode_t mode) {
891  const std::string canonical_path = MakeCanonicalPath(path);
892 
893  std::string this_path = canonical_path + "/quarantaine";
894  if (!MkdirDeep(this_path, mode, false))
895  return false;
896 
897  this_path = canonical_path + "/ff";
898 
899  platform_stat64 stat_info;
900  if (platform_stat(this_path.c_str(), &stat_info) != 0) {
901  this_path = canonical_path + "/txn";
902  if (!MkdirDeep(this_path, mode, false))
903  return false;
904  for (int i = 0; i <= 0xff; i++) {
905  char hex[4];
906  snprintf(hex, sizeof(hex), "%02x", i);
907  this_path = canonical_path + "/" + std::string(hex);
908  if (!MkdirDeep(this_path, mode, false))
909  return false;
910  }
911  }
912  return true;
913 }
914 
915 
922 int TryLockFile(const std::string &path) {
923  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
924  if (fd_lockfile < 0)
925  return -1;
926 
927  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
928  close(fd_lockfile);
929  if (errno != EWOULDBLOCK)
930  return -1;
931  return -2;
932  }
933 
934  return fd_lockfile;
935 }
936 
937 
944 int WritePidFile(const std::string &path) {
945  const int fd = open(path.c_str(), O_CREAT | O_RDWR, 0600);
946  if (fd < 0)
947  return -1;
948  if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
949  close(fd);
950  if (errno != EWOULDBLOCK)
951  return -1;
952  return -2;
953  }
954 
955  // Don't leak the file descriptor to exec'd children
956  int flags = fcntl(fd, F_GETFD);
957  assert(flags != -1);
958  flags |= FD_CLOEXEC;
959  flags = fcntl(fd, F_SETFD, flags);
960  assert(flags != -1);
961 
962  char buf[64];
963 
964  snprintf(buf, sizeof(buf), "%" PRId64 "\n", static_cast<uint64_t>(getpid()));
965  const bool retval =
966  (ftruncate(fd, 0) == 0) && SafeWrite(fd, buf, strlen(buf));
967  if (!retval) {
968  UnlockFile(fd);
969  return -1;
970  }
971  return fd;
972 }
973 
974 
980 int LockFile(const std::string &path) {
981  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
982  if (fd_lockfile < 0)
983  return -1;
984 
985 
986  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
987  if (errno != EWOULDBLOCK) {
988  close(fd_lockfile);
989  return -1;
990  }
991  LogCvmfs(kLogCvmfs, kLogSyslog, "another process holds %s, waiting.",
992  path.c_str());
993  if (flock(fd_lockfile, LOCK_EX) != 0) {
994  close(fd_lockfile);
995  return -1;
996  }
997  LogCvmfs(kLogCvmfs, kLogSyslog, "lock %s acquired", path.c_str());
998  }
999 
1000  return fd_lockfile;
1001 }
1002 
1003 
1004 void UnlockFile(const int filedes) {
1005  const int retval = flock(filedes, LOCK_UN);
1006  assert(retval == 0);
1007  close(filedes);
1008 }
1009 
1010 
1014 FILE *CreateTempFile(const std::string &path_prefix, const int mode,
1015  const char *open_flags, std::string *final_path) {
1016  *final_path = path_prefix + ".XXXXXX";
1017  char *tmp_file = strdupa(final_path->c_str());
1018  const int tmp_fd = mkstemp(tmp_file);
1019  if (tmp_fd < 0) {
1020  return NULL;
1021  }
1022  if (fchmod(tmp_fd, mode) != 0) {
1023  close(tmp_fd);
1024  return NULL;
1025  }
1026 
1027  *final_path = tmp_file;
1028  FILE *tmp_fp = fdopen(tmp_fd, open_flags);
1029  if (!tmp_fp) {
1030  close(tmp_fd);
1031  unlink(tmp_file);
1032  return NULL;
1033  }
1034 
1035  return tmp_fp;
1036 }
1037 
1038 
1042 std::string CreateTempPath(const std::string &path_prefix, const int mode) {
1043  std::string result;
1044  FILE *f = CreateTempFile(path_prefix, mode, "w", &result);
1045  if (!f)
1046  return "";
1047  fclose(f);
1048  return result;
1049 }
1050 
1051 
1055 std::string CreateTempDir(const std::string &path_prefix) {
1056  const std::string dir = path_prefix + ".XXXXXX";
1057  char *tmp_dir = strdupa(dir.c_str());
1058  tmp_dir = mkdtemp(tmp_dir);
1059  if (tmp_dir == NULL)
1060  return "";
1061  return std::string(tmp_dir);
1062 }
1063 
1064 
1069  char cwd[PATH_MAX];
1070  return (getcwd(cwd, sizeof(cwd)) != NULL) ? std::string(cwd) : std::string();
1071 }
1072 
1073 
1078  public:
1079  bool success;
1080  RemoveTreeHelper() { success = true; }
1081  void RemoveFile(const std::string &parent_path, const std::string &name) {
1082  const int retval = unlink((parent_path + "/" + name).c_str());
1083  if (retval != 0)
1084  success = false;
1085  }
1086  void RemoveDir(const std::string &parent_path, const std::string &name) {
1087  const int retval = rmdir((parent_path + "/" + name).c_str());
1088  if (retval != 0)
1089  success = false;
1090  }
1091  bool TryRemoveDir(const std::string &parent_path, const std::string &name) {
1092  const int retval = rmdir((parent_path + "/" + name).c_str());
1093  return (retval != 0);
1094  }
1095 };
1096 
1097 
1101 bool RemoveTree(const std::string &path) {
1102  platform_stat64 info;
1103  const int retval = platform_lstat(path.c_str(), &info);
1104  if (retval != 0)
1105  return errno == ENOENT;
1106  if (!S_ISDIR(info.st_mode))
1107  return false;
1108 
1109  RemoveTreeHelper *remove_tree_helper = new RemoveTreeHelper();
1110  FileSystemTraversal<RemoveTreeHelper> traversal(remove_tree_helper, "", true);
1118  traversal.Recurse(path);
1119  const bool result = remove_tree_helper->success;
1120  delete remove_tree_helper;
1121 
1122  return result;
1123 }
1124 
1125 
1129 std::vector<std::string> FindFilesBySuffix(const std::string &dir,
1130  const std::string &suffix) {
1131  std::vector<std::string> result;
1132  DIR *dirp = opendir(dir.c_str());
1133  if (!dirp)
1134  return result;
1135 
1136  platform_dirent64 *dirent;
1137  while ((dirent = platform_readdir(dirp))) {
1138  const std::string name(dirent->d_name);
1139  if ((name.length() >= suffix.length())
1140  && (name.substr(name.length() - suffix.length()) == suffix)) {
1141  result.push_back(dir + "/" + name);
1142  }
1143  }
1144  closedir(dirp);
1145  std::sort(result.begin(), result.end());
1146  return result;
1147 }
1148 
1149 
1153 std::vector<std::string> FindFilesByPrefix(const std::string &dir,
1154  const std::string &prefix) {
1155  std::vector<std::string> result;
1156  DIR *dirp = opendir(dir.c_str());
1157  if (!dirp)
1158  return result;
1159 
1160  platform_dirent64 *dirent;
1161  while ((dirent = platform_readdir(dirp))) {
1162  const std::string name(dirent->d_name);
1163  if ((name.length() >= prefix.length())
1164  && (name.substr(0, prefix.length()) == prefix)) {
1165  result.push_back(dir + "/" + name);
1166  }
1167  }
1168  closedir(dirp);
1169  std::sort(result.begin(), result.end());
1170  return result;
1171 }
1172 
1173 
1178 std::vector<std::string> FindDirectories(const std::string &parent_dir) {
1179  std::vector<std::string> result;
1180  DIR *dirp = opendir(parent_dir.c_str());
1181  if (!dirp)
1182  return result;
1183 
1184  platform_dirent64 *dirent;
1185  while ((dirent = platform_readdir(dirp))) {
1186  const std::string name(dirent->d_name);
1187  if ((name == ".") || (name == ".."))
1188  continue;
1189  const std::string path = parent_dir + "/" + name;
1190 
1191  platform_stat64 info;
1192  const int retval = platform_stat(path.c_str(), &info);
1193  if (retval != 0)
1194  continue;
1195  if (S_ISDIR(info.st_mode))
1196  result.push_back(path);
1197  }
1198  closedir(dirp);
1199  sort(result.begin(), result.end());
1200  return result;
1201 }
1202 
1203 
1207 bool ListDirectory(const std::string &directory,
1208  std::vector<std::string> *names,
1209  std::vector<mode_t> *modes) {
1210  DIR *dirp = opendir(directory.c_str());
1211  if (!dirp)
1212  return false;
1213 
1214  platform_dirent64 *dirent;
1215  while ((dirent = platform_readdir(dirp))) {
1216  const std::string name(dirent->d_name);
1217  if ((name == ".") || (name == ".."))
1218  continue;
1219  const std::string path = directory + "/" + name;
1220 
1221  platform_stat64 info;
1222  const int retval = platform_lstat(path.c_str(), &info);
1223  if (retval != 0) {
1224  closedir(dirp);
1225  return false;
1226  }
1227 
1228  names->push_back(name);
1229  modes->push_back(info.st_mode);
1230  }
1231  closedir(dirp);
1232 
1233  SortTeam(names, modes);
1234  return true;
1235 }
1236 
1237 
1242 std::string FindExecutable(const std::string &exe) {
1243  if (exe.empty())
1244  return "";
1245 
1246  std::vector<std::string> search_paths;
1247  if (exe[0] == '/') {
1248  search_paths.push_back(GetParentPath(exe));
1249  } else {
1250  char *path_env = getenv("PATH");
1251  if (path_env) {
1252  search_paths = SplitString(path_env, ':');
1253  }
1254  }
1255 
1256  for (unsigned i = 0; i < search_paths.size(); ++i) {
1257  if (search_paths[i].empty())
1258  continue;
1259  if (search_paths[i][0] != '/')
1260  continue;
1261 
1262  std::string path = search_paths[i] + "/" + GetFileName(exe);
1263  platform_stat64 info;
1264  int retval = platform_stat(path.c_str(), &info);
1265  if (retval != 0)
1266  continue;
1267  if (!S_ISREG(info.st_mode))
1268  continue;
1269  retval = access(path.c_str(), X_OK);
1270  if (retval != 0)
1271  continue;
1272 
1273  return path;
1274  }
1275 
1276  return "";
1277 }
1278 
1279 
1280 std::string GetUserName() {
1281  struct passwd pwd;
1282  struct passwd *result = NULL;
1283  int bufsize = 16 * 1024;
1284  char *buf = static_cast<char *>(smalloc(bufsize));
1285  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1286  bufsize *= 2;
1287  buf = static_cast<char *>(srealloc(buf, bufsize));
1288  }
1289  if (result == NULL) {
1290  free(buf);
1291  return "";
1292  }
1293  std::string user_name = pwd.pw_name;
1294  free(buf);
1295  return user_name;
1296 }
1297 
1298 std::string GetShell() {
1299  struct passwd pwd;
1300  struct passwd *result = NULL;
1301  int bufsize = 16 * 1024;
1302  char *buf = static_cast<char *>(smalloc(bufsize));
1303  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1304  bufsize *= 2;
1305  buf = static_cast<char *>(srealloc(buf, bufsize));
1306  }
1307  if (result == NULL) {
1308  free(buf);
1309  return "";
1310  }
1311  std::string shell = pwd.pw_shell;
1312  free(buf);
1313  return shell;
1314 }
1315 
1319 bool GetUserNameOf(uid_t uid, std::string *username) {
1320  struct passwd pwd;
1321  struct passwd *result = NULL;
1322  int bufsize = 16 * 1024;
1323  char *buf = static_cast<char *>(smalloc(bufsize));
1324  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1325  bufsize *= 2;
1326  buf = static_cast<char *>(srealloc(buf, bufsize));
1327  }
1328  if (result == NULL) {
1329  free(buf);
1330  return false;
1331  }
1332  if (username)
1333  *username = result->pw_name;
1334  free(buf);
1335  return true;
1336 }
1337 
1338 
1342 bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid) {
1343  struct passwd pwd;
1344  struct passwd *result = NULL;
1345  int bufsize = 16 * 1024;
1346  char *buf = static_cast<char *>(smalloc(bufsize));
1347  while (getpwnam_r(username.c_str(), &pwd, buf, bufsize, &result) == ERANGE) {
1348  bufsize *= 2;
1349  buf = static_cast<char *>(srealloc(buf, bufsize));
1350  }
1351  if (result == NULL) {
1352  free(buf);
1353  return false;
1354  }
1355  *uid = result->pw_uid;
1356  *main_gid = result->pw_gid;
1357  free(buf);
1358  return true;
1359 }
1360 
1361 
1365 bool GetGidOf(const std::string &groupname, gid_t *gid) {
1366  struct group grp;
1367  struct group *result = NULL;
1368  int bufsize = 16 * 1024;
1369  char *buf = static_cast<char *>(smalloc(bufsize));
1370  while (getgrnam_r(groupname.c_str(), &grp, buf, bufsize, &result) == ERANGE) {
1371  bufsize *= 2;
1372  buf = static_cast<char *>(srealloc(buf, bufsize));
1373  }
1374  if (result == NULL) {
1375  free(buf);
1376  return false;
1377  }
1378  *gid = result->gr_gid;
1379  free(buf);
1380  return true;
1381 }
1382 
1388 mode_t GetUmask() {
1389  const MutexLockGuard m(&getumask_mutex);
1390  const mode_t my_umask = umask(0);
1391  umask(my_umask);
1392  return my_umask;
1393 }
1394 
1395 
1399 bool AddGroup2Persona(const gid_t gid) {
1400  const int ngroups = getgroups(0, NULL);
1401  if (ngroups < 0)
1402  return false;
1403  gid_t *groups = static_cast<gid_t *>(smalloc((ngroups + 1) * sizeof(gid_t)));
1404  int retval = getgroups(ngroups, groups);
1405  if (retval < 0) {
1406  free(groups);
1407  return false;
1408  }
1409  for (int i = 0; i < ngroups; ++i) {
1410  if (groups[i] == gid) {
1411  free(groups);
1412  return true;
1413  }
1414  }
1415  groups[ngroups] = gid;
1416  retval = setgroups(ngroups + 1, groups);
1417  free(groups);
1418  return retval == 0;
1419 }
1420 
1421 
1422 std::string GetHomeDirectory() {
1423  const uid_t uid = getuid();
1424  struct passwd pwd;
1425  struct passwd *result = NULL;
1426  int bufsize = 16 * 1024;
1427  char *buf = static_cast<char *>(smalloc(bufsize));
1428  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1429  bufsize *= 2;
1430  buf = static_cast<char *>(srealloc(buf, bufsize));
1431  }
1432  if (result == NULL) {
1433  free(buf);
1434  return "";
1435  }
1436  std::string home_dir = result->pw_dir;
1437  free(buf);
1438  return home_dir;
1439 }
1440 
1444 std::string GetArch() {
1445  struct utsname info;
1446  const int retval = uname(&info);
1447  assert(retval == 0);
1448  return info.machine;
1449 }
1450 
1451 
1456 int SetLimitNoFile(unsigned limit_nofile) {
1457  struct rlimit rpl;
1458  memset(&rpl, 0, sizeof(rpl));
1459  getrlimit(RLIMIT_NOFILE, &rpl);
1460  if (rpl.rlim_max < limit_nofile)
1461  rpl.rlim_max = limit_nofile;
1462  rpl.rlim_cur = limit_nofile;
1463  const int retval = setrlimit(RLIMIT_NOFILE, &rpl);
1464  if (retval == 0)
1465  return 0;
1466 
1467 #ifdef HAS_VALGRIND_HEADERS
1468  return RUNNING_ON_VALGRIND ? -2 : -1;
1469 #else
1470  return -1;
1471 #endif
1472 }
1473 
1474 
1478 void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit) {
1479  *soft_limit = 0;
1480  *hard_limit = 0;
1481 
1482  struct rlimit rpl;
1483  memset(&rpl, 0, sizeof(rpl));
1484  getrlimit(RLIMIT_NOFILE, &rpl);
1485  *soft_limit = rpl.rlim_cur;
1486 
1487 #ifdef __APPLE__
1488  int value = sysconf(_SC_OPEN_MAX);
1489  assert(value > 0);
1490  *hard_limit = value;
1491 #else
1492  *hard_limit = rpl.rlim_max;
1493 #endif
1494 }
1495 
1496 
1497 std::vector<LsofEntry> Lsof(const std::string &path) {
1498  std::vector<LsofEntry> result;
1499 
1500  std::vector<std::string> proc_names;
1501  std::vector<mode_t> proc_modes;
1502  ListDirectory("/proc", &proc_names, &proc_modes);
1503 
1504  for (unsigned i = 0; i < proc_names.size(); ++i) {
1505  if (!S_ISDIR(proc_modes[i]))
1506  continue;
1507  if (proc_names[i].find_first_not_of("1234567890") != std::string::npos)
1508  continue;
1509 
1510  std::vector<std::string> fd_names;
1511  std::vector<mode_t> fd_modes;
1512  const std::string proc_dir = "/proc/" + proc_names[i];
1513  const std::string fd_dir = proc_dir + "/fd";
1514  const bool rvb = ListDirectory(fd_dir, &fd_names, &fd_modes);
1515  uid_t proc_uid = 0;
1516 
1517  // The working directory of the process requires special handling
1518  if (rvb) {
1519  platform_stat64 info;
1520  platform_stat(proc_dir.c_str(), &info);
1521  proc_uid = info.st_uid;
1522 
1523  const std::string cwd = ReadSymlink(proc_dir + "/cwd");
1524  if (HasPrefix(cwd + "/", path + "/", false /* ignore_case */)) {
1525  LsofEntry entry;
1526  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1527  entry.owner = proc_uid;
1528  entry.read_only = true; // A bit sloppy but good enough for the moment
1529  entry.executable = ReadSymlink(proc_dir + "/exe");
1530  entry.path = cwd;
1531  result.push_back(entry);
1532  }
1533  }
1534 
1535  for (unsigned j = 0; j < fd_names.size(); ++j) {
1536  if (!S_ISLNK(fd_modes[j]))
1537  continue;
1538  if (fd_names[j].find_first_not_of("1234567890") != std::string::npos)
1539  continue;
1540 
1541  const std::string target = ReadSymlink(fd_dir + "/" + fd_names[j]);
1542  if (!HasPrefix(target + "/", path + "/", false /* ignore_case */))
1543  continue;
1544 
1545  LsofEntry entry;
1546  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1547  entry.owner = proc_uid;
1548  entry.read_only = !((fd_modes[j] & S_IWUSR) == S_IWUSR);
1549  entry.executable = ReadSymlink(proc_dir + "/exe");
1550  entry.path = target;
1551  result.push_back(entry);
1552  }
1553  }
1554 
1555  return result;
1556 }
1557 
1558 
1559 bool ProcessExists(pid_t pid) {
1560  assert(pid > 0);
1561  const int retval = kill(pid, 0);
1562  if (retval == 0)
1563  return true;
1564  return (errno != ESRCH);
1565 }
1566 
1567 
1571 void BlockSignal(int signum) {
1572  sigset_t sigset;
1573  int retval = sigemptyset(&sigset);
1574  assert(retval == 0);
1575  retval = sigaddset(&sigset, signum);
1576  assert(retval == 0);
1577  retval = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1578  assert(retval == 0);
1579 }
1580 
1581 
1586 void WaitForSignal(int signum) {
1587  int retval;
1588  do {
1589  retval = platform_sigwait(signum);
1590  } while ((retval != signum) && (errno == EINTR));
1591  assert(retval == signum);
1592 }
1593 
1594 
1601 int WaitForChild(pid_t pid, const std::vector<int> &sig_ok) {
1602  assert(pid > 0);
1603  int statloc;
1604  while (true) {
1605  const pid_t retval = waitpid(pid, &statloc, 0);
1606  if (retval == -1) {
1607  if (errno == EINTR)
1608  continue;
1609  PANIC(kLogSyslogErr | kLogDebug, "waitpid failed with errno %d", errno);
1610  }
1611  assert(retval == pid);
1612  break;
1613  }
1614  if (WIFEXITED(statloc))
1615  return WEXITSTATUS(statloc);
1616  if (WIFSIGNALED(statloc)
1617  && (std::find(sig_ok.begin(), sig_ok.end(), WTERMSIG(statloc))
1618  != sig_ok.end()))
1619  return 0;
1620  return -1;
1621 }
1622 
1627 bool ExecAsDaemon(const std::vector<std::string> &command_line,
1628  pid_t *child_pid) {
1629  assert(command_line.size() >= 1);
1630 
1631  Pipe<kPipeDetachedChild> pipe_fork;
1632  const pid_t pid = fork();
1633  assert(pid >= 0);
1634  if (pid == 0) {
1635  pid_t pid_grand_child;
1636 
1637  const char *argv[command_line.size() + 1];
1638  for (unsigned i = 0; i < command_line.size(); ++i)
1639  argv[i] = command_line[i].c_str();
1640  argv[command_line.size()] = NULL;
1641  int retval = setsid();
1642  assert(retval != -1);
1643 
1644  pid_grand_child = fork();
1645  assert(pid_grand_child >= 0);
1646 
1647  if (pid_grand_child != 0) {
1648  pipe_fork.Write<pid_t>(pid_grand_child);
1649  _exit(0);
1650  } else {
1651  const int null_read = open("/dev/null", O_RDONLY);
1652  const int null_write = open("/dev/null", O_WRONLY);
1653  assert((null_read >= 0) && (null_write >= 0));
1654  retval = dup2(null_read, 0);
1655  assert(retval == 0);
1656  retval = dup2(null_write, 1);
1657  assert(retval == 1);
1658  retval = dup2(null_write, 2);
1659  assert(retval == 2);
1660  close(null_read);
1661  close(null_write);
1662 
1663  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1664 
1665  pipe_fork.CloseWriteFd();
1666  }
1667  }
1668  int statloc;
1669  waitpid(pid, &statloc, 0);
1670  pid_t buf_child_pid = 0;
1671  pipe_fork.Read(&buf_child_pid);
1672  if (child_pid != NULL)
1673  *child_pid = buf_child_pid;
1674  pipe_fork.CloseReadFd();
1675 
1676  LogCvmfs(kLogCvmfs, kLogDebug, "exec'd as daemon %s (PID: %d)",
1677  command_line[0].c_str(), static_cast<int>(*child_pid));
1678  return true;
1679 }
1680 
1681 
1685 void Daemonize() {
1686  pid_t pid;
1687  int statloc;
1688  if ((pid = fork()) == 0) {
1689  int retval = setsid();
1690  assert(retval != -1);
1691  if ((pid = fork()) == 0) {
1692  const int null_read = open("/dev/null", O_RDONLY);
1693  const int null_write = open("/dev/null", O_WRONLY);
1694  assert((null_read >= 0) && (null_write >= 0));
1695  retval = dup2(null_read, 0);
1696  assert(retval == 0);
1697  retval = dup2(null_write, 1);
1698  assert(retval == 1);
1699  retval = dup2(null_write, 2);
1700  assert(retval == 2);
1701  close(null_read);
1702  close(null_write);
1703  LogCvmfs(kLogCvmfs, kLogDebug, "daemonized");
1704  } else {
1705  assert(pid > 0);
1706  _exit(0);
1707  }
1708  } else {
1709  assert(pid > 0);
1710  waitpid(pid, &statloc, 0);
1711  _exit(0);
1712  }
1713 }
1714 
1715 
1716 bool ExecuteBinary(int *fd_stdin,
1717  int *fd_stdout,
1718  int *fd_stderr,
1719  const std::string &binary_path,
1720  const std::vector<std::string> &argv,
1721  const bool double_fork,
1722  pid_t *child_pid) {
1723  int pipe_stdin[2];
1724  int pipe_stdout[2];
1725  int pipe_stderr[2];
1726  MakePipe(pipe_stdin);
1727  MakePipe(pipe_stdout);
1728  MakePipe(pipe_stderr);
1729 
1730  std::set<int> preserve_fildes;
1731  preserve_fildes.insert(0);
1732  preserve_fildes.insert(1);
1733  preserve_fildes.insert(2);
1734  std::map<int, int> map_fildes;
1735  map_fildes[pipe_stdin[0]] = 0; // Reading end of pipe_stdin
1736  map_fildes[pipe_stdout[1]] = 1; // Writing end of pipe_stdout
1737  map_fildes[pipe_stderr[1]] = 2; // Writing end of pipe_stderr
1738  std::vector<std::string> cmd_line;
1739  cmd_line.push_back(binary_path);
1740  cmd_line.insert(cmd_line.end(), argv.begin(), argv.end());
1741 
1742  if (!ManagedExec(cmd_line,
1743  preserve_fildes,
1744  map_fildes,
1745  true /* drop_credentials */,
1746  false /* clear_env */,
1747  double_fork,
1748  child_pid)) {
1749  ClosePipe(pipe_stdin);
1750  ClosePipe(pipe_stdout);
1751  ClosePipe(pipe_stderr);
1752  return false;
1753  }
1754 
1755  close(pipe_stdin[0]);
1756  close(pipe_stdout[1]);
1757  close(pipe_stderr[1]);
1758  *fd_stdin = pipe_stdin[1];
1759  *fd_stdout = pipe_stdout[0];
1760  *fd_stderr = pipe_stderr[0];
1761  return true;
1762 }
1763 
1764 
1769 bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr) {
1770  const bool double_fork = true;
1771  return ExecuteBinary(fd_stdin, fd_stdout, fd_stderr, "/bin/sh",
1772  std::vector<std::string>(), double_fork);
1773 }
1774 
1775 struct ForkFailures { // TODO(rmeusel): C++11 (type safe enum)
1776  enum Names {
1785  };
1786 
1787  static std::string ToString(const Names name) {
1788  switch (name) {
1789  case kSendPid:
1790  return "Sending PID";
1791 
1792  default:
1793  case kUnknown:
1794  return "Unknown Status";
1795  case kFailDupFd:
1796  return "Duplicate File Descriptor";
1797  case kFailCloseFds:
1798  return "Close File Descriptors";
1799  case kFailGetFdFlags:
1800  return "Read File Descriptor Flags";
1801  case kFailSetFdFlags:
1802  return "Set File Descriptor Flags";
1803  case kFailDropCredentials:
1804  return "Lower User Permissions";
1805  case kFailExec:
1806  return "Invoking execvp()";
1807  }
1808  }
1809 };
1810 
1814 static bool CloseAllFildesUntilMaxFD(const std::set<int> &preserve_fildes,
1815  int max_fd) {
1816  for (int fd = 0; fd < max_fd; fd++) {
1817  if (preserve_fildes.count(fd) == 0) {
1818  close(fd);
1819  }
1820  }
1821 
1822  return true;
1823 }
1824 
1829 #ifndef __APPLE__
1830 static bool CloseAllFildesInProcSelfFd(const std::set<int> &preserve_fildes) {
1831  DIR *dirp = opendir("/proc/self/fd");
1832  if (!dirp)
1833  return false;
1834 
1835  platform_dirent64 *dirent;
1836 
1837  while ((dirent = platform_readdir(dirp))) {
1838  const std::string name(dirent->d_name);
1839  uint64_t name_uint64;
1840 
1841  // Make sure the dir name is digits only (skips ".", ".." and similar).
1842  if (!String2Uint64Parse(name, &name_uint64)) {
1843  continue;
1844  }
1845 
1846  const int fd = static_cast<int>(name_uint64);
1847  if (preserve_fildes.count(fd)) {
1848  continue;
1849  }
1850 
1851  close(fd);
1852  }
1853 
1854  closedir(dirp);
1855 
1856  return true;
1857 }
1858 #endif
1859 
1864 bool CloseAllFildes(const std::set<int> &preserve_fildes) {
1865  const int max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
1866  if (max_fd < 0) {
1867  return false;
1868  }
1869 
1870 #ifdef __APPLE__
1871  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1872 #else // ifdef __APPLE__
1873  if (max_fd > 100000) {
1874  // CloseAllFildesUntilMaxFD is inefficient with very large max_fd.
1875  // Looping through /proc/self/fd performs better.
1876  return CloseAllFildesInProcSelfFd(preserve_fildes);
1877  }
1878 
1879  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1880 #endif // #ifdef __APPLE__
1881 }
1882 
1896 bool ManagedExec(const std::vector<std::string> &command_line,
1897  const std::set<int> &preserve_fildes,
1898  const std::map<int, int> &map_fildes,
1899  const bool drop_credentials,
1900  const bool clear_env,
1901  const bool double_fork,
1902  pid_t *child_pid) {
1903  assert(command_line.size() >= 1);
1904 
1905  Pipe<kPipeDetachedChild> pipe_fork;
1906  const pid_t pid = fork();
1907  assert(pid >= 0);
1908  if (pid == 0) {
1909  pid_t pid_grand_child;
1910  int fd_flags;
1912 
1913  std::set<int> skip_fds = preserve_fildes;
1914  skip_fds.insert(pipe_fork.GetWriteFd());
1915 
1916  if (clear_env) {
1917 #ifdef __APPLE__
1918  environ = NULL;
1919 #else
1920  const int retval = clearenv();
1921  assert(retval == 0);
1922 #endif
1923  }
1924 
1925  const char *argv[command_line.size() + 1];
1926  for (unsigned i = 0; i < command_line.size(); ++i)
1927  argv[i] = command_line[i].c_str();
1928  argv[command_line.size()] = NULL;
1929 
1930  // Child, map file descriptors
1931  for (std::map<int, int>::const_iterator i = map_fildes.begin(),
1932  iEnd = map_fildes.end();
1933  i != iEnd;
1934  ++i) {
1935  const int retval = dup2(i->first, i->second);
1936  if (retval == -1) {
1937  failed = ForkFailures::kFailDupFd;
1938  goto fork_failure;
1939  }
1940  }
1941 
1942  // Child, close file descriptors
1943  if (!CloseAllFildes(skip_fds)) {
1944  failed = ForkFailures::kFailCloseFds;
1945  goto fork_failure;
1946  }
1947 
1948  // Double fork to disconnect from parent
1949  if (double_fork) {
1950  pid_grand_child = fork();
1951  assert(pid_grand_child >= 0);
1952  if (pid_grand_child != 0)
1953  _exit(0);
1954  }
1955 
1956  fd_flags = fcntl(pipe_fork.GetWriteFd(), F_GETFD);
1957  if (fd_flags < 0) {
1959  goto fork_failure;
1960  }
1961  fd_flags |= FD_CLOEXEC;
1962  if (fcntl(pipe_fork.GetWriteFd(), F_SETFD, fd_flags) < 0) {
1964  goto fork_failure;
1965  }
1966 
1967 #ifdef DEBUGMSG
1968  assert(setenv("__CVMFS_DEBUG_MODE__", "yes", 1) == 0);
1969 #endif
1970  if (drop_credentials && !SwitchCredentials(geteuid(), getegid(), false)) {
1972  goto fork_failure;
1973  }
1974 
1975  // retrieve the PID of the new (grand) child process and send it to the
1976  // grand father
1977  pid_grand_child = getpid();
1978  failed = ForkFailures::kSendPid;
1979  pipe_fork.Write<ForkFailures::Names>(failed);
1980  pipe_fork.Write<pid_t>(pid_grand_child);
1981 
1982  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1983 
1984  failed = ForkFailures::kFailExec;
1985 
1986  fork_failure:
1987  pipe_fork.Write<ForkFailures::Names>(failed);
1988  _exit(1);
1989  }
1990  if (double_fork) {
1991  int statloc;
1992  waitpid(pid, &statloc, 0);
1993  }
1994 
1995  pipe_fork.CloseWriteFd();
1996 
1997  // Either the PID or a return value is sent
1998  ForkFailures::Names status_code;
1999  pipe_fork.Read<ForkFailures::Names>(&status_code);
2000 
2001  if (status_code != ForkFailures::kSendPid) {
2002  pipe_fork.CloseReadFd();
2003  LogCvmfs(kLogCvmfs, kLogDebug, "managed execve failed (%s)",
2004  ForkFailures::ToString(status_code).c_str());
2005  return false;
2006  }
2007 
2008  // read the PID of the spawned process if requested
2009  // (the actual read needs to be done in any case!)
2010  pid_t buf_child_pid = 0;
2011  pipe_fork.Read(&buf_child_pid);
2012  if (child_pid != NULL)
2013  *child_pid = buf_child_pid;
2014  pipe_fork.CloseReadFd();
2015  LogCvmfs(kLogCvmfs, kLogDebug, "execve'd %s (PID: %d)",
2016  command_line[0].c_str(), static_cast<int>(buf_child_pid));
2017  return true;
2018 }
2019 
2020 
2025 void SafeSleepMs(const unsigned ms) {
2026  struct timeval wait_for;
2027  wait_for.tv_sec = ms / 1000;
2028  wait_for.tv_usec = (ms % 1000) * 1000;
2029  select(0, NULL, NULL, NULL, &wait_for);
2030 }
2031 
2032 
2036 bool SafeWrite(int fd, const void *buf, size_t nbyte) {
2037  while (nbyte) {
2038  const ssize_t retval = write(fd, buf, nbyte);
2039  if (retval < 0) {
2040  if (errno == EINTR)
2041  continue;
2042  return false;
2043  }
2044  assert(static_cast<size_t>(retval) <= nbyte);
2045  buf = reinterpret_cast<const char *>(buf) + retval;
2046  nbyte -= retval;
2047  }
2048  return true;
2049 }
2050 
2054 bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt) {
2055  unsigned nbytes = 0;
2056  for (unsigned i = 0; i < iovcnt; ++i)
2057  nbytes += iov[i].iov_len;
2058  unsigned iov_idx = 0;
2059 
2060  while (nbytes) {
2061  const ssize_t retval =
2062  writev(fd, &iov[iov_idx], static_cast<int>(iovcnt - iov_idx));
2063  if (retval < 0) {
2064  if (errno == EINTR)
2065  continue;
2066  return false;
2067  }
2068  assert(static_cast<size_t>(retval) <= nbytes);
2069  nbytes -= retval;
2070 
2071  unsigned sum_written_blocks = 0;
2072  while ((sum_written_blocks + iov[iov_idx].iov_len)
2073  <= static_cast<size_t>(retval)) {
2074  sum_written_blocks += iov[iov_idx].iov_len;
2075  iov_idx++;
2076  if (iov_idx == iovcnt) {
2077  assert(sum_written_blocks == static_cast<size_t>(retval));
2078  return true;
2079  }
2080  }
2081  const unsigned offset = retval - sum_written_blocks;
2082  iov[iov_idx].iov_len -= offset;
2083  iov[iov_idx].iov_base = reinterpret_cast<char *>(iov[iov_idx].iov_base)
2084  + offset;
2085  }
2086 
2087  return true;
2088 }
2089 
2090 
2094 ssize_t SafeRead(int fd, void *buf, size_t nbyte) {
2095  ssize_t total_bytes = 0;
2096  while (nbyte) {
2097  const ssize_t retval = read(fd, buf, nbyte);
2098  if (retval < 0) {
2099  if (errno == EINTR)
2100  continue;
2101  return -1;
2102  } else if (retval == 0) {
2103  return total_bytes;
2104  }
2105  assert(static_cast<size_t>(retval) <= nbyte);
2106  buf = reinterpret_cast<char *>(buf) + retval;
2107  nbyte -= retval;
2108  total_bytes += retval;
2109  }
2110  return total_bytes;
2111 }
2112 
2113 
2117 bool SafeReadToString(int fd, std::string *final_result) {
2118  if (!final_result) {
2119  return false;
2120  }
2121 
2122  std::string tmp_result;
2123  static const int buf_size = 4096;
2124  char buf[4096];
2125  ssize_t total_bytes = -1;
2126  do {
2127  total_bytes = SafeRead(fd, buf, buf_size);
2128  if (total_bytes < 0) {
2129  return false;
2130  }
2131  tmp_result.append(buf, total_bytes);
2132  } while (total_bytes == buf_size);
2133  final_result->swap(tmp_result);
2134  return true;
2135 }
2136 
2137 bool SafeWriteToFile(const std::string &content,
2138  const std::string &path,
2139  int mode) {
2140  const int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
2141  if (fd < 0)
2142  return false;
2143  const bool retval = SafeWrite(fd, content.data(), content.size());
2144  close(fd);
2145  return retval;
2146 }
2147 
2148 
2149 #ifdef CVMFS_NAMESPACE_GUARD
2150 } // namespace CVMFS_NAMESPACE_GUARD
2151 #endif
bool MakeCacheDirectories(const std::string &path, const mode_t mode)
Definition: posix.cc:890
mode_t GetUmask()
Definition: posix.cc:1388
static bool CloseAllFildesInProcSelfFd(const std::set< int > &preserve_fildes)
Definition: posix.cc:1830
uid_t owner
Definition: posix.h:61
void RemoveFile(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1081
int MakeSocket(const std::string &path, const int mode)
Definition: posix.cc:327
struct stat64 platform_stat64
bool SymlinkForced(const std::string &src, const std::string &dest)
Definition: posix.cc:842
NameString GetFileName(const PathString &path)
Definition: shortstring.cc:28
int MakeTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:384
std::string GetUserName()
Definition: posix.cc:1280
VoidCallback fn_new_symlink
Definition: fs_traversal.h:47
VoidCallback fn_new_character_dev
Definition: fs_traversal.h:50
void Recurse(const std::string &dir_path) const
Definition: fs_traversal.h:110
void CreateFile(const std::string &path, const int mode, const bool ignore_failure)
Definition: posix.cc:278
#define PANIC(...)
Definition: exception.h:29
bool GetUserNameOf(uid_t uid, std::string *username)
Definition: posix.cc:1319
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1014
int ConnectTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:456
EFileSystemTypes type
Definition: posix.h:55
void RemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1086
bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr)
Definition: posix.cc:1769
bool IsHttpUrl(const std::string &path)
Definition: posix.cc:167
bool ManagedExec(const std::vector< std::string > &command_line, const std::set< int > &preserve_fildes, const std::map< int, int > &map_fildes, const bool drop_credentials, const bool clear_env, const bool double_fork, pid_t *child_pid)
Definition: posix.cc:1896
static void RemoveShortSocketLink(const std::string &short_path)
Definition: posix.cc:317
void Daemonize()
Definition: posix.cc:1685
static pthread_mutex_t getumask_mutex
Definition: posix.cc:92
std::string CreateTempPath(const std::string &path_prefix, const int mode)
Definition: posix.cc:1042
#define ST_RDONLY
Definition: posix.cc:68
A simple recursion engine to abstract the recursion of directories. It provides several callback hook...
Definition: fs_traversal.h:36
bool SafeWrite(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:2036
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:671
assert((mem||(size==0))&&"Out Of Memory")
uint64_t platform_monotonic_time_ns()
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2137
std::string FindExecutable(const std::string &exe)
Definition: posix.cc:1242
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:680
VoidCallback fn_leave_dir
Definition: fs_traversal.h:45
int WaitForChild(pid_t pid, const std::vector< int > &sig_ok)
Definition: posix.cc:1601
bool TryRemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1091
int platform_stat(const char *path, platform_stat64 *buf)
bool AddGroup2Persona(const gid_t gid)
Definition: posix.cc:1399
void MakePipe(int pipe_fd[2])
Definition: posix.cc:487
std::vector< std::string > FindDirectories(const std::string &parent_dir)
Definition: posix.cc:1178
Definition: pipe.h:45
bool String2Uint64Parse(const std::string &value, uint64_t *result)
Definition: string.cc:257
bool is_rdonly
Definition: posix.h:56
int SetLimitNoFile(unsigned limit_nofile)
Definition: posix.cc:1456
std::string path
Definition: posix.h:64
bool SymlinkExists(const std::string &path)
Definition: posix.cc:833
static bool CloseAllFildesUntilMaxFD(const std::set< int > &preserve_fildes, int max_fd)
Definition: posix.cc:1814
bool FileExists(const std::string &path)
Definition: posix.cc:803
std::string GetAbsolutePath(const std::string &path)
Definition: posix.cc:159
void SplitPath(const std::string &path, std::string *dirname, std::string *filename)
Definition: posix.cc:114
std::string GetHostname()
Definition: posix.cc:762
void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit)
Definition: posix.cc:1478
std::string executable
Definition: posix.h:63
#define strdupa(s)
Definition: platform_osx.h:285
bool ReadHalfPipe(int fd, void *buf, size_t nbyte, unsigned timeout_ms)
Definition: posix.cc:520
VoidCallback fn_new_file
Definition: fs_traversal.h:46
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:2094
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:306
FileSystemInfo GetFileSystemInfo(const std::string &path)
Definition: posix.cc:179
void Nonblock2Block(int filedes)
Definition: posix.cc:648
int platform_sigwait(const int signum)
static std::string MakeShortSocketLink(const std::string &path)
Definition: posix.cc:295
std::vector< std::string > platform_mountlist()
bool read_only
Definition: posix.h:62
int platform_lstat(const char *path, platform_stat64 *buf)
int TryLockFile(const std::string &path)
Definition: posix.cc:922
bool MkdirDeep(const std::string &path, const mode_t mode, bool verify_writable)
Definition: posix.cc:855
int LockFile(const std::string &path)
Definition: posix.cc:980
string ResolvePath(const std::string &path)
std::string GetHomeDirectory()
Definition: posix.cc:1422
void WaitForSignal(int signum)
Definition: posix.cc:1586
std::string GetShell()
Definition: posix.cc:1298
pid_t pid
Definition: posix.h:60
bool GetGidOf(const std::string &groupname, gid_t *gid)
Definition: posix.cc:1365
std::string GetArch()
Definition: posix.cc:1444
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1055
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:279
bool DirectoryExists(const std::string &path)
Definition: posix.cc:824
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:1716
bool RemoveTree(const std::string &path)
Definition: posix.cc:1101
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2117
bool CloseAllFildes(const std::set< int > &preserve_fildes)
Definition: posix.cc:1864
int WritePidFile(const std::string &path)
Definition: posix.cc:944
int ConnectSocket(const std::string &path)
Definition: posix.cc:422
uint64_t String2Uint64(const string &value)
Definition: string.cc:240
VoidCallback fn_new_socket
Definition: fs_traversal.h:48
bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid)
Definition: posix.cc:1342
std::vector< std::string > FindFilesByPrefix(const std::string &dir, const std::string &prefix)
Definition: posix.cc:1153
bool SwitchCredentials(const uid_t uid, const gid_t gid, const bool temporarily)
Definition: posix.cc:773
bool ExecAsDaemon(const std::vector< std::string > &command_line, pid_t *child_pid)
Definition: posix.cc:1627
std::string ReadSymlink(const std::string &path)
Definition: posix.cc:221
Definition: mutex.h:42
PathString GetParentPath(const PathString &path)
Definition: shortstring.cc:14
std::vector< LsofEntry > Lsof(const std::string &path)
Definition: posix.cc:1497
BoolCallback fn_new_dir_prefix
Definition: fs_traversal.h:68
VoidCallback fn_new_fifo
Definition: fs_traversal.h:51
bool ListDirectory(const std::string &directory, std::vector< std::string > *names, std::vector< mode_t > *modes)
Definition: posix.cc:1207
platform_dirent64 * platform_readdir(DIR *dirp)
Definition: posix.h:59
#define HOST_NAME_MAX
Definition: platform_osx.h:60
int64_t GetFileSize(const std::string &path)
Definition: posix.cc:812
#define MSG_NOSIGNAL
Definition: platform_osx.h:54
void SafeSleepMs(const unsigned ms)
Definition: posix.cc:2025
bool DiffTree(const std::string &path_a, const std::string &path_b)
Definition: posix.cc:569
void SortTeam(std::vector< T > *tractor, std::vector< U > *towed)
Definition: algorithm.h:68
static std::string ToString(const Names name)
Definition: posix.cc:1787
void Block2Nonblock(int filedes)
Definition: posix.cc:659
bool IsAbsolutePath(const std::string &path)
Definition: posix.cc:154
bool ProcessExists(pid_t pid)
Definition: posix.cc:1559
std::string MakeCanonicalPath(const std::string &path)
Definition: posix.cc:98
const char * c_str() const
Definition: shortstring.h:143
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:496
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1068
void ReadPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:508
std::vector< std::string > FindFilesBySuffix(const std::string &dir, const std::string &suffix)
Definition: posix.cc:1129
void ClosePipe(int pipe_fd[2])
Definition: posix.cc:559
bool IsMountPoint(const std::string &path)
Definition: posix.cc:264
int RecvFdFromSocket(int msg_fd)
Definition: posix.cc:720
bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt)
Definition: posix.cc:2054
void UnlockFile(const int filedes)
Definition: posix.cc:1004
void BlockSignal(int signum)
Definition: posix.cc:1571
struct dirent64 platform_dirent64
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545