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