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  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  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  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  std::string name = GetFileName(path);
241  std::string result = name;
242  if (name != path) {
243  // There is a parent path of 'path'
244  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  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  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  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  unsigned max_length = sizeof(sock_addr.sun_path);
298 
299  std::string result;
300  std::string tmp_path = CreateTempDir("/tmp/cvmfs");
301  if (tmp_path.empty())
302  return "";
303  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  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  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  int retval = connect(
439  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  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  bool retval_subtree = DiffTree(path_a + "/" + subdirs[i],
636  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  int flags = fcntl(filedes, F_GETFL);
650  assert(flags != -1);
651  int retval = fcntl(filedes, F_SETFL, flags & ~O_NONBLOCK);
652  assert(retval != -1);
653 }
654 
655 
659 void Block2Nonblock(int filedes) {
660  int flags = fcntl(filedes, F_GETFL);
661  assert(flags != -1);
662  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  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  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  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  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  bool retval = (ftruncate(fd, 0) == 0) && SafeWrite(fd, buf, strlen(buf));
966  if (!retval) {
967  UnlockFile(fd);
968  return -1;
969  }
970  return fd;
971 }
972 
973 
979 int LockFile(const std::string &path) {
980  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
981  if (fd_lockfile < 0)
982  return -1;
983 
984 
985  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
986  if (errno != EWOULDBLOCK) {
987  close(fd_lockfile);
988  return -1;
989  }
990  LogCvmfs(kLogCvmfs, kLogSyslog, "another process holds %s, waiting.",
991  path.c_str());
992  if (flock(fd_lockfile, LOCK_EX) != 0) {
993  close(fd_lockfile);
994  return -1;
995  }
996  LogCvmfs(kLogCvmfs, kLogSyslog, "lock %s acquired", path.c_str());
997  }
998 
999  return fd_lockfile;
1000 }
1001 
1002 
1003 void UnlockFile(const int filedes) {
1004  int retval = flock(filedes, LOCK_UN);
1005  assert(retval == 0);
1006  close(filedes);
1007 }
1008 
1009 
1013 FILE *CreateTempFile(const std::string &path_prefix, const int mode,
1014  const char *open_flags, std::string *final_path) {
1015  *final_path = path_prefix + ".XXXXXX";
1016  char *tmp_file = strdupa(final_path->c_str());
1017  int tmp_fd = mkstemp(tmp_file);
1018  if (tmp_fd < 0) {
1019  return NULL;
1020  }
1021  if (fchmod(tmp_fd, mode) != 0) {
1022  close(tmp_fd);
1023  return NULL;
1024  }
1025 
1026  *final_path = tmp_file;
1027  FILE *tmp_fp = fdopen(tmp_fd, open_flags);
1028  if (!tmp_fp) {
1029  close(tmp_fd);
1030  unlink(tmp_file);
1031  return NULL;
1032  }
1033 
1034  return tmp_fp;
1035 }
1036 
1037 
1041 std::string CreateTempPath(const std::string &path_prefix, const int mode) {
1042  std::string result;
1043  FILE *f = CreateTempFile(path_prefix, mode, "w", &result);
1044  if (!f)
1045  return "";
1046  fclose(f);
1047  return result;
1048 }
1049 
1050 
1054 std::string CreateTempDir(const std::string &path_prefix) {
1055  std::string dir = path_prefix + ".XXXXXX";
1056  char *tmp_dir = strdupa(dir.c_str());
1057  tmp_dir = mkdtemp(tmp_dir);
1058  if (tmp_dir == NULL)
1059  return "";
1060  return std::string(tmp_dir);
1061 }
1062 
1063 
1068  char cwd[PATH_MAX];
1069  return (getcwd(cwd, sizeof(cwd)) != NULL) ? std::string(cwd) : std::string();
1070 }
1071 
1072 
1077  public:
1078  bool success;
1079  RemoveTreeHelper() { success = true; }
1080  void RemoveFile(const std::string &parent_path, const std::string &name) {
1081  int retval = unlink((parent_path + "/" + name).c_str());
1082  if (retval != 0)
1083  success = false;
1084  }
1085  void RemoveDir(const std::string &parent_path, const std::string &name) {
1086  int retval = rmdir((parent_path + "/" + name).c_str());
1087  if (retval != 0)
1088  success = false;
1089  }
1090  bool TryRemoveDir(const std::string &parent_path, const std::string &name) {
1091  int retval = rmdir((parent_path + "/" + name).c_str());
1092  return (retval != 0);
1093  }
1094 };
1095 
1096 
1100 bool RemoveTree(const std::string &path) {
1101  platform_stat64 info;
1102  int retval = platform_lstat(path.c_str(), &info);
1103  if (retval != 0)
1104  return errno == ENOENT;
1105  if (!S_ISDIR(info.st_mode))
1106  return false;
1107 
1108  RemoveTreeHelper *remove_tree_helper = new RemoveTreeHelper();
1109  FileSystemTraversal<RemoveTreeHelper> traversal(remove_tree_helper, "", true);
1117  traversal.Recurse(path);
1118  bool result = remove_tree_helper->success;
1119  delete remove_tree_helper;
1120 
1121  return result;
1122 }
1123 
1124 
1128 std::vector<std::string> FindFilesBySuffix(const std::string &dir,
1129  const std::string &suffix) {
1130  std::vector<std::string> result;
1131  DIR *dirp = opendir(dir.c_str());
1132  if (!dirp)
1133  return result;
1134 
1135  platform_dirent64 *dirent;
1136  while ((dirent = platform_readdir(dirp))) {
1137  const std::string name(dirent->d_name);
1138  if ((name.length() >= suffix.length())
1139  && (name.substr(name.length() - suffix.length()) == suffix)) {
1140  result.push_back(dir + "/" + name);
1141  }
1142  }
1143  closedir(dirp);
1144  std::sort(result.begin(), result.end());
1145  return result;
1146 }
1147 
1148 
1152 std::vector<std::string> FindFilesByPrefix(const std::string &dir,
1153  const std::string &prefix) {
1154  std::vector<std::string> result;
1155  DIR *dirp = opendir(dir.c_str());
1156  if (!dirp)
1157  return result;
1158 
1159  platform_dirent64 *dirent;
1160  while ((dirent = platform_readdir(dirp))) {
1161  const std::string name(dirent->d_name);
1162  if ((name.length() >= prefix.length())
1163  && (name.substr(0, prefix.length()) == prefix)) {
1164  result.push_back(dir + "/" + name);
1165  }
1166  }
1167  closedir(dirp);
1168  std::sort(result.begin(), result.end());
1169  return result;
1170 }
1171 
1172 
1177 std::vector<std::string> FindDirectories(const std::string &parent_dir) {
1178  std::vector<std::string> result;
1179  DIR *dirp = opendir(parent_dir.c_str());
1180  if (!dirp)
1181  return result;
1182 
1183  platform_dirent64 *dirent;
1184  while ((dirent = platform_readdir(dirp))) {
1185  const std::string name(dirent->d_name);
1186  if ((name == ".") || (name == ".."))
1187  continue;
1188  const std::string path = parent_dir + "/" + name;
1189 
1190  platform_stat64 info;
1191  int retval = platform_stat(path.c_str(), &info);
1192  if (retval != 0)
1193  continue;
1194  if (S_ISDIR(info.st_mode))
1195  result.push_back(path);
1196  }
1197  closedir(dirp);
1198  sort(result.begin(), result.end());
1199  return result;
1200 }
1201 
1202 
1206 bool ListDirectory(const std::string &directory,
1207  std::vector<std::string> *names,
1208  std::vector<mode_t> *modes) {
1209  DIR *dirp = opendir(directory.c_str());
1210  if (!dirp)
1211  return false;
1212 
1213  platform_dirent64 *dirent;
1214  while ((dirent = platform_readdir(dirp))) {
1215  const std::string name(dirent->d_name);
1216  if ((name == ".") || (name == ".."))
1217  continue;
1218  const std::string path = directory + "/" + name;
1219 
1220  platform_stat64 info;
1221  int retval = platform_lstat(path.c_str(), &info);
1222  if (retval != 0) {
1223  closedir(dirp);
1224  return false;
1225  }
1226 
1227  names->push_back(name);
1228  modes->push_back(info.st_mode);
1229  }
1230  closedir(dirp);
1231 
1232  SortTeam(names, modes);
1233  return true;
1234 }
1235 
1236 
1241 std::string FindExecutable(const std::string &exe) {
1242  if (exe.empty())
1243  return "";
1244 
1245  std::vector<std::string> search_paths;
1246  if (exe[0] == '/') {
1247  search_paths.push_back(GetParentPath(exe));
1248  } else {
1249  char *path_env = getenv("PATH");
1250  if (path_env) {
1251  search_paths = SplitString(path_env, ':');
1252  }
1253  }
1254 
1255  for (unsigned i = 0; i < search_paths.size(); ++i) {
1256  if (search_paths[i].empty())
1257  continue;
1258  if (search_paths[i][0] != '/')
1259  continue;
1260 
1261  std::string path = search_paths[i] + "/" + GetFileName(exe);
1262  platform_stat64 info;
1263  int retval = platform_stat(path.c_str(), &info);
1264  if (retval != 0)
1265  continue;
1266  if (!S_ISREG(info.st_mode))
1267  continue;
1268  retval = access(path.c_str(), X_OK);
1269  if (retval != 0)
1270  continue;
1271 
1272  return path;
1273  }
1274 
1275  return "";
1276 }
1277 
1278 
1279 std::string GetUserName() {
1280  struct passwd pwd;
1281  struct passwd *result = NULL;
1282  int bufsize = 16 * 1024;
1283  char *buf = static_cast<char *>(smalloc(bufsize));
1284  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1285  bufsize *= 2;
1286  buf = static_cast<char *>(srealloc(buf, bufsize));
1287  }
1288  if (result == NULL) {
1289  free(buf);
1290  return "";
1291  }
1292  std::string user_name = pwd.pw_name;
1293  free(buf);
1294  return user_name;
1295 }
1296 
1297 std::string GetShell() {
1298  struct passwd pwd;
1299  struct passwd *result = NULL;
1300  int bufsize = 16 * 1024;
1301  char *buf = static_cast<char *>(smalloc(bufsize));
1302  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1303  bufsize *= 2;
1304  buf = static_cast<char *>(srealloc(buf, bufsize));
1305  }
1306  if (result == NULL) {
1307  free(buf);
1308  return "";
1309  }
1310  std::string shell = pwd.pw_shell;
1311  free(buf);
1312  return shell;
1313 }
1314 
1318 bool GetUserNameOf(uid_t uid, std::string *username) {
1319  struct passwd pwd;
1320  struct passwd *result = NULL;
1321  int bufsize = 16 * 1024;
1322  char *buf = static_cast<char *>(smalloc(bufsize));
1323  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1324  bufsize *= 2;
1325  buf = static_cast<char *>(srealloc(buf, bufsize));
1326  }
1327  if (result == NULL) {
1328  free(buf);
1329  return false;
1330  }
1331  if (username)
1332  *username = result->pw_name;
1333  free(buf);
1334  return true;
1335 }
1336 
1337 
1341 bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid) {
1342  struct passwd pwd;
1343  struct passwd *result = NULL;
1344  int bufsize = 16 * 1024;
1345  char *buf = static_cast<char *>(smalloc(bufsize));
1346  while (getpwnam_r(username.c_str(), &pwd, buf, bufsize, &result) == ERANGE) {
1347  bufsize *= 2;
1348  buf = static_cast<char *>(srealloc(buf, bufsize));
1349  }
1350  if (result == NULL) {
1351  free(buf);
1352  return false;
1353  }
1354  *uid = result->pw_uid;
1355  *main_gid = result->pw_gid;
1356  free(buf);
1357  return true;
1358 }
1359 
1360 
1364 bool GetGidOf(const std::string &groupname, gid_t *gid) {
1365  struct group grp;
1366  struct group *result = NULL;
1367  int bufsize = 16 * 1024;
1368  char *buf = static_cast<char *>(smalloc(bufsize));
1369  while (getgrnam_r(groupname.c_str(), &grp, buf, bufsize, &result) == ERANGE) {
1370  bufsize *= 2;
1371  buf = static_cast<char *>(srealloc(buf, bufsize));
1372  }
1373  if (result == NULL) {
1374  free(buf);
1375  return false;
1376  }
1377  *gid = result->gr_gid;
1378  free(buf);
1379  return true;
1380 }
1381 
1387 mode_t GetUmask() {
1389  const mode_t my_umask = umask(0);
1390  umask(my_umask);
1391  return my_umask;
1392 }
1393 
1394 
1398 bool AddGroup2Persona(const gid_t gid) {
1399  int ngroups = getgroups(0, NULL);
1400  if (ngroups < 0)
1401  return false;
1402  gid_t *groups = static_cast<gid_t *>(smalloc((ngroups + 1) * sizeof(gid_t)));
1403  int retval = getgroups(ngroups, groups);
1404  if (retval < 0) {
1405  free(groups);
1406  return false;
1407  }
1408  for (int i = 0; i < ngroups; ++i) {
1409  if (groups[i] == gid) {
1410  free(groups);
1411  return true;
1412  }
1413  }
1414  groups[ngroups] = gid;
1415  retval = setgroups(ngroups + 1, groups);
1416  free(groups);
1417  return retval == 0;
1418 }
1419 
1420 
1421 std::string GetHomeDirectory() {
1422  uid_t uid = getuid();
1423  struct passwd pwd;
1424  struct passwd *result = NULL;
1425  int bufsize = 16 * 1024;
1426  char *buf = static_cast<char *>(smalloc(bufsize));
1427  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1428  bufsize *= 2;
1429  buf = static_cast<char *>(srealloc(buf, bufsize));
1430  }
1431  if (result == NULL) {
1432  free(buf);
1433  return "";
1434  }
1435  std::string home_dir = result->pw_dir;
1436  free(buf);
1437  return home_dir;
1438 }
1439 
1443 std::string GetArch() {
1444  struct utsname info;
1445  int retval = uname(&info);
1446  assert(retval == 0);
1447  return info.machine;
1448 }
1449 
1450 
1455 int SetLimitNoFile(unsigned limit_nofile) {
1456  struct rlimit rpl;
1457  memset(&rpl, 0, sizeof(rpl));
1458  getrlimit(RLIMIT_NOFILE, &rpl);
1459  if (rpl.rlim_max < limit_nofile)
1460  rpl.rlim_max = limit_nofile;
1461  rpl.rlim_cur = limit_nofile;
1462  int retval = setrlimit(RLIMIT_NOFILE, &rpl);
1463  if (retval == 0)
1464  return 0;
1465 
1466 #ifdef HAS_VALGRIND_HEADERS
1467  return RUNNING_ON_VALGRIND ? -2 : -1;
1468 #else
1469  return -1;
1470 #endif
1471 }
1472 
1473 
1477 void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit) {
1478  *soft_limit = 0;
1479  *hard_limit = 0;
1480 
1481  struct rlimit rpl;
1482  memset(&rpl, 0, sizeof(rpl));
1483  getrlimit(RLIMIT_NOFILE, &rpl);
1484  *soft_limit = rpl.rlim_cur;
1485 
1486 #ifdef __APPLE__
1487  int value = sysconf(_SC_OPEN_MAX);
1488  assert(value > 0);
1489  *hard_limit = value;
1490 #else
1491  *hard_limit = rpl.rlim_max;
1492 #endif
1493 }
1494 
1495 
1496 std::vector<LsofEntry> Lsof(const std::string &path) {
1497  std::vector<LsofEntry> result;
1498 
1499  std::vector<std::string> proc_names;
1500  std::vector<mode_t> proc_modes;
1501  ListDirectory("/proc", &proc_names, &proc_modes);
1502 
1503  for (unsigned i = 0; i < proc_names.size(); ++i) {
1504  if (!S_ISDIR(proc_modes[i]))
1505  continue;
1506  if (proc_names[i].find_first_not_of("1234567890") != std::string::npos)
1507  continue;
1508 
1509  std::vector<std::string> fd_names;
1510  std::vector<mode_t> fd_modes;
1511  std::string proc_dir = "/proc/" + proc_names[i];
1512  std::string fd_dir = proc_dir + "/fd";
1513  bool rvb = ListDirectory(fd_dir, &fd_names, &fd_modes);
1514  uid_t proc_uid = 0;
1515 
1516  // The working directory of the process requires special handling
1517  if (rvb) {
1518  platform_stat64 info;
1519  platform_stat(proc_dir.c_str(), &info);
1520  proc_uid = info.st_uid;
1521 
1522  std::string cwd = ReadSymlink(proc_dir + "/cwd");
1523  if (HasPrefix(cwd + "/", path + "/", false /* ignore_case */)) {
1524  LsofEntry entry;
1525  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1526  entry.owner = proc_uid;
1527  entry.read_only = true; // A bit sloppy but good enough for the moment
1528  entry.executable = ReadSymlink(proc_dir + "/exe");
1529  entry.path = cwd;
1530  result.push_back(entry);
1531  }
1532  }
1533 
1534  for (unsigned j = 0; j < fd_names.size(); ++j) {
1535  if (!S_ISLNK(fd_modes[j]))
1536  continue;
1537  if (fd_names[j].find_first_not_of("1234567890") != std::string::npos)
1538  continue;
1539 
1540  std::string target = ReadSymlink(fd_dir + "/" + fd_names[j]);
1541  if (!HasPrefix(target + "/", path + "/", false /* ignore_case */))
1542  continue;
1543 
1544  LsofEntry entry;
1545  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1546  entry.owner = proc_uid;
1547  entry.read_only = !((fd_modes[j] & S_IWUSR) == S_IWUSR);
1548  entry.executable = ReadSymlink(proc_dir + "/exe");
1549  entry.path = target;
1550  result.push_back(entry);
1551  }
1552  }
1553 
1554  return result;
1555 }
1556 
1557 
1558 bool ProcessExists(pid_t pid) {
1559  assert(pid > 0);
1560  int retval = kill(pid, 0);
1561  if (retval == 0)
1562  return true;
1563  return (errno != ESRCH);
1564 }
1565 
1566 
1570 void BlockSignal(int signum) {
1571  sigset_t sigset;
1572  int retval = sigemptyset(&sigset);
1573  assert(retval == 0);
1574  retval = sigaddset(&sigset, signum);
1575  assert(retval == 0);
1576  retval = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1577  assert(retval == 0);
1578 }
1579 
1580 
1585 void WaitForSignal(int signum) {
1586  int retval;
1587  do {
1588  retval = platform_sigwait(signum);
1589  } while ((retval != signum) && (errno == EINTR));
1590  assert(retval == signum);
1591 }
1592 
1593 
1600 int WaitForChild(pid_t pid, const std::vector<int> &sig_ok) {
1601  assert(pid > 0);
1602  int statloc;
1603  while (true) {
1604  pid_t retval = waitpid(pid, &statloc, 0);
1605  if (retval == -1) {
1606  if (errno == EINTR)
1607  continue;
1608  PANIC(kLogSyslogErr | kLogDebug, "waitpid failed with errno %d", errno);
1609  }
1610  assert(retval == pid);
1611  break;
1612  }
1613  if (WIFEXITED(statloc))
1614  return WEXITSTATUS(statloc);
1615  if (WIFSIGNALED(statloc)
1616  && (std::find(sig_ok.begin(), sig_ok.end(), WTERMSIG(statloc))
1617  != sig_ok.end()))
1618  return 0;
1619  return -1;
1620 }
1621 
1626 bool ExecAsDaemon(const std::vector<std::string> &command_line,
1627  pid_t *child_pid) {
1628  assert(command_line.size() >= 1);
1629 
1630  Pipe<kPipeDetachedChild> pipe_fork;
1631  pid_t pid = fork();
1632  assert(pid >= 0);
1633  if (pid == 0) {
1634  pid_t pid_grand_child;
1635 
1636  const char *argv[command_line.size() + 1];
1637  for (unsigned i = 0; i < command_line.size(); ++i)
1638  argv[i] = command_line[i].c_str();
1639  argv[command_line.size()] = NULL;
1640  int retval = setsid();
1641  assert(retval != -1);
1642 
1643  pid_grand_child = fork();
1644  assert(pid_grand_child >= 0);
1645 
1646  if (pid_grand_child != 0) {
1647  pipe_fork.Write<pid_t>(pid_grand_child);
1648  _exit(0);
1649  } else {
1650  int null_read = open("/dev/null", O_RDONLY);
1651  int null_write = open("/dev/null", O_WRONLY);
1652  assert((null_read >= 0) && (null_write >= 0));
1653  retval = dup2(null_read, 0);
1654  assert(retval == 0);
1655  retval = dup2(null_write, 1);
1656  assert(retval == 1);
1657  retval = dup2(null_write, 2);
1658  assert(retval == 2);
1659  close(null_read);
1660  close(null_write);
1661 
1662  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1663 
1664  pipe_fork.CloseWriteFd();
1665  }
1666  }
1667  int statloc;
1668  waitpid(pid, &statloc, 0);
1669  pid_t buf_child_pid = 0;
1670  pipe_fork.Read(&buf_child_pid);
1671  if (child_pid != NULL)
1672  *child_pid = buf_child_pid;
1673  pipe_fork.CloseReadFd();
1674 
1675  LogCvmfs(kLogCvmfs, kLogDebug, "exec'd as daemon %s (PID: %d)",
1676  command_line[0].c_str(), static_cast<int>(*child_pid));
1677  return true;
1678 }
1679 
1680 
1684 void Daemonize() {
1685  pid_t pid;
1686  int statloc;
1687  if ((pid = fork()) == 0) {
1688  int retval = setsid();
1689  assert(retval != -1);
1690  if ((pid = fork()) == 0) {
1691  int null_read = open("/dev/null", O_RDONLY);
1692  int null_write = open("/dev/null", O_WRONLY);
1693  assert((null_read >= 0) && (null_write >= 0));
1694  retval = dup2(null_read, 0);
1695  assert(retval == 0);
1696  retval = dup2(null_write, 1);
1697  assert(retval == 1);
1698  retval = dup2(null_write, 2);
1699  assert(retval == 2);
1700  close(null_read);
1701  close(null_write);
1702  LogCvmfs(kLogCvmfs, kLogDebug, "daemonized");
1703  } else {
1704  assert(pid > 0);
1705  _exit(0);
1706  }
1707  } else {
1708  assert(pid > 0);
1709  waitpid(pid, &statloc, 0);
1710  _exit(0);
1711  }
1712 }
1713 
1714 
1715 bool ExecuteBinary(int *fd_stdin,
1716  int *fd_stdout,
1717  int *fd_stderr,
1718  const std::string &binary_path,
1719  const std::vector<std::string> &argv,
1720  const bool double_fork,
1721  pid_t *child_pid) {
1722  int pipe_stdin[2];
1723  int pipe_stdout[2];
1724  int pipe_stderr[2];
1725  MakePipe(pipe_stdin);
1726  MakePipe(pipe_stdout);
1727  MakePipe(pipe_stderr);
1728 
1729  std::set<int> preserve_fildes;
1730  preserve_fildes.insert(0);
1731  preserve_fildes.insert(1);
1732  preserve_fildes.insert(2);
1733  std::map<int, int> map_fildes;
1734  map_fildes[pipe_stdin[0]] = 0; // Reading end of pipe_stdin
1735  map_fildes[pipe_stdout[1]] = 1; // Writing end of pipe_stdout
1736  map_fildes[pipe_stderr[1]] = 2; // Writing end of pipe_stderr
1737  std::vector<std::string> cmd_line;
1738  cmd_line.push_back(binary_path);
1739  cmd_line.insert(cmd_line.end(), argv.begin(), argv.end());
1740 
1741  if (!ManagedExec(cmd_line,
1742  preserve_fildes,
1743  map_fildes,
1744  true /* drop_credentials */,
1745  false /* clear_env */,
1746  double_fork,
1747  child_pid)) {
1748  ClosePipe(pipe_stdin);
1749  ClosePipe(pipe_stdout);
1750  ClosePipe(pipe_stderr);
1751  return false;
1752  }
1753 
1754  close(pipe_stdin[0]);
1755  close(pipe_stdout[1]);
1756  close(pipe_stderr[1]);
1757  *fd_stdin = pipe_stdin[1];
1758  *fd_stdout = pipe_stdout[0];
1759  *fd_stderr = pipe_stderr[0];
1760  return true;
1761 }
1762 
1763 
1768 bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr) {
1769  const bool double_fork = true;
1770  return ExecuteBinary(fd_stdin, fd_stdout, fd_stderr, "/bin/sh",
1771  std::vector<std::string>(), double_fork);
1772 }
1773 
1774 struct ForkFailures { // TODO(rmeusel): C++11 (type safe enum)
1775  enum Names {
1784  };
1785 
1786  static std::string ToString(const Names name) {
1787  switch (name) {
1788  case kSendPid:
1789  return "Sending PID";
1790 
1791  default:
1792  case kUnknown:
1793  return "Unknown Status";
1794  case kFailDupFd:
1795  return "Duplicate File Descriptor";
1796  case kFailCloseFds:
1797  return "Close File Descriptors";
1798  case kFailGetFdFlags:
1799  return "Read File Descriptor Flags";
1800  case kFailSetFdFlags:
1801  return "Set File Descriptor Flags";
1802  case kFailDropCredentials:
1803  return "Lower User Permissions";
1804  case kFailExec:
1805  return "Invoking execvp()";
1806  }
1807  }
1808 };
1809 
1813 static bool CloseAllFildesUntilMaxFD(const std::set<int> &preserve_fildes,
1814  int max_fd) {
1815  for (int fd = 0; fd < max_fd; fd++) {
1816  if (preserve_fildes.count(fd) == 0) {
1817  close(fd);
1818  }
1819  }
1820 
1821  return true;
1822 }
1823 
1828 #ifndef __APPLE__
1829 static bool CloseAllFildesInProcSelfFd(const std::set<int> &preserve_fildes) {
1830  DIR *dirp = opendir("/proc/self/fd");
1831  if (!dirp)
1832  return false;
1833 
1834  platform_dirent64 *dirent;
1835 
1836  while ((dirent = platform_readdir(dirp))) {
1837  const std::string name(dirent->d_name);
1838  uint64_t name_uint64;
1839 
1840  // Make sure the dir name is digits only (skips ".", ".." and similar).
1841  if (!String2Uint64Parse(name, &name_uint64)) {
1842  continue;
1843  }
1844 
1845  int fd = static_cast<int>(name_uint64);
1846  if (preserve_fildes.count(fd)) {
1847  continue;
1848  }
1849 
1850  close(fd);
1851  }
1852 
1853  closedir(dirp);
1854 
1855  return true;
1856 }
1857 #endif
1858 
1863 bool CloseAllFildes(const std::set<int> &preserve_fildes) {
1864  int max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
1865  if (max_fd < 0) {
1866  return false;
1867  }
1868 
1869 #ifdef __APPLE__
1870  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1871 #else // ifdef __APPLE__
1872  if (max_fd > 100000) {
1873  // CloseAllFildesUntilMaxFD is inefficient with very large max_fd.
1874  // Looping through /proc/self/fd performs better.
1875  return CloseAllFildesInProcSelfFd(preserve_fildes);
1876  }
1877 
1878  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1879 #endif // #ifdef __APPLE__
1880 }
1881 
1895 bool ManagedExec(const std::vector<std::string> &command_line,
1896  const std::set<int> &preserve_fildes,
1897  const std::map<int, int> &map_fildes,
1898  const bool drop_credentials,
1899  const bool clear_env,
1900  const bool double_fork,
1901  pid_t *child_pid) {
1902  assert(command_line.size() >= 1);
1903 
1904  Pipe<kPipeDetachedChild> pipe_fork;
1905  pid_t pid = fork();
1906  assert(pid >= 0);
1907  if (pid == 0) {
1908  pid_t pid_grand_child;
1909  int fd_flags;
1911 
1912  std::set<int> skip_fds = preserve_fildes;
1913  skip_fds.insert(pipe_fork.GetWriteFd());
1914 
1915  if (clear_env) {
1916 #ifdef __APPLE__
1917  environ = NULL;
1918 #else
1919  int retval = clearenv();
1920  assert(retval == 0);
1921 #endif
1922  }
1923 
1924  const char *argv[command_line.size() + 1];
1925  for (unsigned i = 0; i < command_line.size(); ++i)
1926  argv[i] = command_line[i].c_str();
1927  argv[command_line.size()] = NULL;
1928 
1929  // Child, map file descriptors
1930  for (std::map<int, int>::const_iterator i = map_fildes.begin(),
1931  iEnd = map_fildes.end();
1932  i != iEnd;
1933  ++i) {
1934  int retval = dup2(i->first, i->second);
1935  if (retval == -1) {
1936  failed = ForkFailures::kFailDupFd;
1937  goto fork_failure;
1938  }
1939  }
1940 
1941  // Child, close file descriptors
1942  if (!CloseAllFildes(skip_fds)) {
1943  failed = ForkFailures::kFailCloseFds;
1944  goto fork_failure;
1945  }
1946 
1947  // Double fork to disconnect from parent
1948  if (double_fork) {
1949  pid_grand_child = fork();
1950  assert(pid_grand_child >= 0);
1951  if (pid_grand_child != 0)
1952  _exit(0);
1953  }
1954 
1955  fd_flags = fcntl(pipe_fork.GetWriteFd(), F_GETFD);
1956  if (fd_flags < 0) {
1958  goto fork_failure;
1959  }
1960  fd_flags |= FD_CLOEXEC;
1961  if (fcntl(pipe_fork.GetWriteFd(), F_SETFD, fd_flags) < 0) {
1963  goto fork_failure;
1964  }
1965 
1966 #ifdef DEBUGMSG
1967  assert(setenv("__CVMFS_DEBUG_MODE__", "yes", 1) == 0);
1968 #endif
1969  if (drop_credentials && !SwitchCredentials(geteuid(), getegid(), false)) {
1971  goto fork_failure;
1972  }
1973 
1974  // retrieve the PID of the new (grand) child process and send it to the
1975  // grand father
1976  pid_grand_child = getpid();
1977  failed = ForkFailures::kSendPid;
1978  pipe_fork.Write<ForkFailures::Names>(failed);
1979  pipe_fork.Write<pid_t>(pid_grand_child);
1980 
1981  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1982 
1983  failed = ForkFailures::kFailExec;
1984 
1985  fork_failure:
1986  pipe_fork.Write<ForkFailures::Names>(failed);
1987  _exit(1);
1988  }
1989  if (double_fork) {
1990  int statloc;
1991  waitpid(pid, &statloc, 0);
1992  }
1993 
1994  pipe_fork.CloseWriteFd();
1995 
1996  // Either the PID or a return value is sent
1997  ForkFailures::Names status_code;
1998  pipe_fork.Read<ForkFailures::Names>(&status_code);
1999 
2000  if (status_code != ForkFailures::kSendPid) {
2001  pipe_fork.CloseReadFd();
2002  LogCvmfs(kLogCvmfs, kLogDebug, "managed execve failed (%s)",
2003  ForkFailures::ToString(status_code).c_str());
2004  return false;
2005  }
2006 
2007  // read the PID of the spawned process if requested
2008  // (the actual read needs to be done in any case!)
2009  pid_t buf_child_pid = 0;
2010  pipe_fork.Read(&buf_child_pid);
2011  if (child_pid != NULL)
2012  *child_pid = buf_child_pid;
2013  pipe_fork.CloseReadFd();
2014  LogCvmfs(kLogCvmfs, kLogDebug, "execve'd %s (PID: %d)",
2015  command_line[0].c_str(), static_cast<int>(buf_child_pid));
2016  return true;
2017 }
2018 
2019 
2024 void SafeSleepMs(const unsigned ms) {
2025  struct timeval wait_for;
2026  wait_for.tv_sec = ms / 1000;
2027  wait_for.tv_usec = (ms % 1000) * 1000;
2028  select(0, NULL, NULL, NULL, &wait_for);
2029 }
2030 
2031 
2035 bool SafeWrite(int fd, const void *buf, size_t nbyte) {
2036  while (nbyte) {
2037  ssize_t retval = write(fd, buf, nbyte);
2038  if (retval < 0) {
2039  if (errno == EINTR)
2040  continue;
2041  return false;
2042  }
2043  assert(static_cast<size_t>(retval) <= nbyte);
2044  buf = reinterpret_cast<const char *>(buf) + retval;
2045  nbyte -= retval;
2046  }
2047  return true;
2048 }
2049 
2053 bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt) {
2054  unsigned nbytes = 0;
2055  for (unsigned i = 0; i < iovcnt; ++i)
2056  nbytes += iov[i].iov_len;
2057  unsigned iov_idx = 0;
2058 
2059  while (nbytes) {
2060  ssize_t retval = writev(fd, &iov[iov_idx],
2061  static_cast<int>(iovcnt - iov_idx));
2062  if (retval < 0) {
2063  if (errno == EINTR)
2064  continue;
2065  return false;
2066  }
2067  assert(static_cast<size_t>(retval) <= nbytes);
2068  nbytes -= retval;
2069 
2070  unsigned sum_written_blocks = 0;
2071  while ((sum_written_blocks + iov[iov_idx].iov_len)
2072  <= static_cast<size_t>(retval)) {
2073  sum_written_blocks += iov[iov_idx].iov_len;
2074  iov_idx++;
2075  if (iov_idx == iovcnt) {
2076  assert(sum_written_blocks == static_cast<size_t>(retval));
2077  return true;
2078  }
2079  }
2080  unsigned offset = retval - sum_written_blocks;
2081  iov[iov_idx].iov_len -= offset;
2082  iov[iov_idx].iov_base = reinterpret_cast<char *>(iov[iov_idx].iov_base)
2083  + offset;
2084  }
2085 
2086  return true;
2087 }
2088 
2089 
2093 ssize_t SafeRead(int fd, void *buf, size_t nbyte) {
2094  ssize_t total_bytes = 0;
2095  while (nbyte) {
2096  ssize_t retval = read(fd, buf, nbyte);
2097  if (retval < 0) {
2098  if (errno == EINTR)
2099  continue;
2100  return -1;
2101  } else if (retval == 0) {
2102  return total_bytes;
2103  }
2104  assert(static_cast<size_t>(retval) <= nbyte);
2105  buf = reinterpret_cast<char *>(buf) + retval;
2106  nbyte -= retval;
2107  total_bytes += retval;
2108  }
2109  return total_bytes;
2110 }
2111 
2112 
2116 bool SafeReadToString(int fd, std::string *final_result) {
2117  if (!final_result) {
2118  return false;
2119  }
2120 
2121  std::string tmp_result;
2122  static const int buf_size = 4096;
2123  char buf[4096];
2124  ssize_t total_bytes = -1;
2125  do {
2126  total_bytes = SafeRead(fd, buf, buf_size);
2127  if (total_bytes < 0) {
2128  return false;
2129  }
2130  tmp_result.append(buf, total_bytes);
2131  } while (total_bytes == buf_size);
2132  final_result->swap(tmp_result);
2133  return true;
2134 }
2135 
2136 bool SafeWriteToFile(const std::string &content,
2137  const std::string &path,
2138  int mode) {
2139  int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
2140  if (fd < 0)
2141  return false;
2142  bool retval = SafeWrite(fd, content.data(), content.size());
2143  close(fd);
2144  return retval;
2145 }
2146 
2147 
2148 #ifdef CVMFS_NAMESPACE_GUARD
2149 } // namespace CVMFS_NAMESPACE_GUARD
2150 #endif
bool MakeCacheDirectories(const std::string &path, const mode_t mode)
Definition: posix.cc:890
mode_t GetUmask()
Definition: posix.cc:1387
static bool CloseAllFildesInProcSelfFd(const std::set< int > &preserve_fildes)
Definition: posix.cc:1829
uid_t owner
Definition: posix.h:61
void RemoveFile(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1080
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:1279
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:1318
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1013
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:1085
bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr)
Definition: posix.cc:1768
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:1895
static void RemoveShortSocketLink(const std::string &short_path)
Definition: posix.cc:317
void Daemonize()
Definition: posix.cc:1684
static pthread_mutex_t getumask_mutex
Definition: posix.cc:92
std::string CreateTempPath(const std::string &path_prefix, const int mode)
Definition: posix.cc:1041
#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:2035
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:2136
std::string FindExecutable(const std::string &exe)
Definition: posix.cc:1241
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:1600
bool TryRemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1090
int platform_stat(const char *path, platform_stat64 *buf)
bool AddGroup2Persona(const gid_t gid)
Definition: posix.cc:1398
void MakePipe(int pipe_fd[2])
Definition: posix.cc:487
std::vector< std::string > FindDirectories(const std::string &parent_dir)
Definition: posix.cc:1177
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:1455
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:1813
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:1477
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:2093
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:979
string ResolvePath(const std::string &path)
std::string GetHomeDirectory()
Definition: posix.cc:1421
void WaitForSignal(int signum)
Definition: posix.cc:1585
std::string GetShell()
Definition: posix.cc:1297
pid_t pid
Definition: posix.h:60
bool GetGidOf(const std::string &groupname, gid_t *gid)
Definition: posix.cc:1364
std::string GetArch()
Definition: posix.cc:1443
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1054
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:1715
bool RemoveTree(const std::string &path)
Definition: posix.cc:1100
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2116
bool CloseAllFildes(const std::set< int > &preserve_fildes)
Definition: posix.cc:1863
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:1341
std::vector< std::string > FindFilesByPrefix(const std::string &dir, const std::string &prefix)
Definition: posix.cc:1152
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:1626
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:1496
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:1206
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:2024
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:1786
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:1558
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:1067
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:1128
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:2053
void UnlockFile(const int filedes)
Definition: posix.cc:1003
void BlockSignal(int signum)
Definition: posix.cc:1570
struct dirent64 platform_dirent64
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545