CernVM-FS  2.11.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/platform.h"
60 #include "util/string.h"
61 
62 //using namespace std; // NOLINT
63 
64 #ifndef ST_RDONLY
65 // On Linux, this is in sys/statvfs.h
66 // On macOS, this flag is called MNT_RDONLY /usr/include/sys/mount.h
67 #define ST_RDONLY 1
68 #endif
69 
70 // Older Linux glibc versions do not provide the f_flags member in struct statfs
71 #define CVMFS_HAS_STATFS_F_FLAGS
72 #ifndef __APPLE__
73 #ifdef __GLIBC_MINOR__
74 #if __GLIBC_MINOR__ < 12
75 #undef CVMFS_HAS_STATFS_F_FLAGS
76 #endif
77 #endif
78 #endif
79 
80 // Work around missing clearenv()
81 #ifdef __APPLE__
82 extern "C" {
83 extern char **environ;
84 }
85 #endif
86 
87 #ifdef CVMFS_NAMESPACE_GUARD
88 namespace CVMFS_NAMESPACE_GUARD {
89 #endif
90 
91 static pthread_mutex_t getumask_mutex = PTHREAD_MUTEX_INITIALIZER;
92 
93 
97 std::string MakeCanonicalPath(const std::string &path) {
98  if (path.length() == 0) return path;
99 
100  if (path[path.length()-1] == '/') {
101  return path.substr(0, path.length()-1);
102  } else {
103  return path;
104  }
105 }
106 
113  const std::string &path,
114  std::string *dirname,
115  std::string *filename)
116 {
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  default:
201  result.type = kFsTypeUnknown;
202  }
203 
204 #ifdef CVMFS_HAS_STATFS_F_FLAGS
205  if (info.f_flags & ST_RDONLY)
206  result.is_rdonly = true;
207 #else
208  // On old Linux systems, fall back to access()
209  retval = access(path.c_str(), W_OK);
210  result.is_rdonly = (retval != 0);
211 #endif
212 
213 
214 
215  return result;
216 }
217 
218 
219 std::string ReadSymlink(const std::string &path) {
220  // TODO(jblomer): avoid PATH_MAX
221  char buf[PATH_MAX + 1];
222  ssize_t nchars = readlink(path.c_str(), buf, PATH_MAX);
223  if (nchars >= 0) {
224  buf[nchars] = '\0';
225  return std::string(buf);
226  }
227  return "";
228 }
229 
230 
235 std::string ResolvePath(const std::string &path) {
236  if (path.empty() || (path == "/"))
237  return "/";
238  std::string name = GetFileName(path);
239  std::string result = name;
240  if (name != path) {
241  // There is a parent path of 'path'
242  std::string parent = ResolvePath(GetParentPath(path));
243  result = parent + (parent == "/" ? "" : "/") + name;
244  }
245  char *real_result = realpath(result.c_str(), NULL);
246  if (real_result) {
247  result = real_result;
248  free(real_result);
249  }
250  if (SymlinkExists(result)) {
251  char buf[PATH_MAX + 1];
252  ssize_t nchars = readlink(result.c_str(), buf, PATH_MAX);
253  if (nchars >= 0) {
254  buf[nchars] = '\0';
255  result = buf;
256  }
257  }
258  return result;
259 }
260 
261 
262 bool IsMountPoint(const std::string &path) {
263  std::vector<std::string> mount_list = platform_mountlist();
264  std::string resolved_path = ResolvePath(path);
265  for (unsigned i = 0; i < mount_list.size(); ++i) {
266  if (mount_list[i] == resolved_path)
267  return true;
268  }
269  return false;
270 }
271 
272 
277  const std::string &path,
278  const int mode,
279  const bool ignore_failure)
280 {
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(),
339  sizeof(sock_addr.sun_path));
340 
341  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
342  assert(socket_fd != -1);
343 
344 #ifndef __APPLE__
345  // fchmod on a socket is not allowed under Mac OS X
346  // using default 0770 here
347  if (fchmod(socket_fd, mode) != 0)
348  goto make_socket_failure;
349 #endif
350 
351  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
352  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path)) < 0)
353  {
354  if ((errno == EADDRINUSE) && (unlink(path.c_str()) == 0)) {
355  // Second try, perhaps the file was left over
356  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
357  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path)) < 0)
358  {
359  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
360  goto make_socket_failure;
361  }
362  } else {
363  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
364  goto make_socket_failure;
365  }
366  }
367 
368  if (short_path != path)
369  RemoveShortSocketLink(short_path);
370 
371  return socket_fd;
372 
373  make_socket_failure:
374  close(socket_fd);
375  if (short_path != path)
376  RemoveShortSocketLink(short_path);
377  return -1;
378 }
379 
380 
385 int MakeTcpEndpoint(const std::string &ipv4_address, int portno) {
386  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
387  assert(socket_fd != -1);
388  const int on = 1;
389  int retval = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
390  assert(retval == 0);
391 
392  struct sockaddr_in endpoint_addr;
393  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
394  endpoint_addr.sin_family = AF_INET;
395  if (ipv4_address.empty()) {
396  endpoint_addr.sin_addr.s_addr = INADDR_ANY;
397  } else {
398  retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
399  if (retval == 0) {
400  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
401  close(socket_fd);
402  return -1;
403  }
404  }
405  endpoint_addr.sin_port = htons(portno);
406 
407  retval = bind(socket_fd, reinterpret_cast<struct sockaddr *>(&endpoint_addr),
408  sizeof(endpoint_addr));
409  if (retval < 0) {
410  LogCvmfs(kLogCvmfs, kLogDebug, "binding TCP endpoint failed (%d)", errno);
411  close(socket_fd);
412  return -1;
413  }
414  return socket_fd;
415 }
416 
417 
423 int ConnectSocket(const std::string &path) {
424  std::string short_path(path);
425  struct sockaddr_un sock_addr;
426  if (path.length() >= sizeof(sock_addr.sun_path)) {
427  // Socket paths are limited to 108 bytes (on some systems to 92 bytes),
428  // try working around
429  short_path = MakeShortSocketLink(path);
430  if (short_path.empty())
431  return -1;
432  }
433  sock_addr.sun_family = AF_UNIX;
434  strncpy(sock_addr.sun_path, short_path.c_str(), sizeof(sock_addr.sun_path));
435 
436  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
437  assert(socket_fd != -1);
438 
439  int retval =
440  connect(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
441  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path));
442  if (short_path != path)
443  RemoveShortSocketLink(short_path);
444 
445  if (retval < 0) {
446  close(socket_fd);
447  return -1;
448  }
449 
450  return socket_fd;
451 }
452 
453 
457 int ConnectTcpEndpoint(const std::string &ipv4_address, int portno) {
458  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
459  assert(socket_fd != -1);
460 
461  struct sockaddr_in endpoint_addr;
462  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
463  endpoint_addr.sin_family = AF_INET;
464  int retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
465  if (retval == 0) {
466  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
467  close(socket_fd);
468  return -1;
469  }
470  endpoint_addr.sin_port = htons(portno);
471 
472  retval =
473  connect(socket_fd, reinterpret_cast<struct sockaddr *>(&endpoint_addr),
474  sizeof(endpoint_addr));
475  if (retval != 0) {
476  LogCvmfs(kLogCvmfs, kLogDebug, "failed to connect to TCP endpoint (%d)",
477  errno);
478  close(socket_fd);
479  return -1;
480  }
481  return socket_fd;
482 }
483 
484 
488 void MakePipe(int pipe_fd[2]) {
489  int retval = pipe(pipe_fd);
490  assert(retval == 0);
491 }
492 
493 
497 void WritePipe(int fd, const void *buf, size_t nbyte) {
498  ssize_t num_bytes;
499  do {
500  num_bytes = write(fd, buf, nbyte);
501  } while ((num_bytes < 0) && (errno == EINTR));
502  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
503 }
504 
505 
509 void ReadPipe(int fd, void *buf, size_t nbyte) {
510  ssize_t num_bytes;
511  do {
512  num_bytes = read(fd, buf, nbyte);
513  } while ((num_bytes < 0) && (errno == EINTR));
514  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
515 }
516 
517 
521 void ReadHalfPipe(int fd, void *buf, size_t nbyte) {
522  ssize_t num_bytes;
523  unsigned i = 0;
524  unsigned backoff_ms = 1;
525  const unsigned max_backoff_ms = 256;
526  do {
527  // When the writer is not connected, this takes ~200-300ns per call as per
528  // micro benchmarks
529  num_bytes = read(fd, buf, nbyte);
530  if ((num_bytes < 0) && (errno == EINTR))
531  continue;
532  i++;
533  // Start backing off when the busy loop reaches the ballpark of 1ms
534  if ((i > 3000) && (num_bytes == 0)) {
535  // The BackoffThrottle would pull in too many dependencies
536  SafeSleepMs(backoff_ms);
537  if (backoff_ms < max_backoff_ms) backoff_ms *= 2;
538  }
539  } while (num_bytes == 0);
540  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
541 }
542 
543 
547 void ClosePipe(int pipe_fd[2]) {
548  close(pipe_fd[0]);
549  close(pipe_fd[1]);
550 }
551 
552 
557 bool DiffTree(const std::string &path_a, const std::string &path_b) {
558  int retval;
559  std::vector<std::string> ls_a;
560  std::vector<std::string> ls_b;
561  std::vector<std::string> subdirs;
562 
563  DIR *dirp_a = opendir(path_a.c_str());
564  if (dirp_a == NULL) return false;
565  DIR *dirp_b = opendir(path_b.c_str());
566  if (dirp_b == NULL) {
567  closedir(dirp_a);
568  return false;
569  }
570 
571  platform_dirent64 *dirent;
572  while ((dirent = platform_readdir(dirp_a))) {
573  const std::string name(dirent->d_name);
574  if ((name == ".") || (name == ".."))
575  continue;
576  const std::string path = path_a + "/" + name;
577  ls_a.push_back(path);
578 
579  platform_stat64 info;
580  retval = platform_lstat(path.c_str(), &info);
581  if (retval != 0) {
582  closedir(dirp_a);
583  closedir(dirp_b);
584  return false;
585  }
586  if (S_ISDIR(info.st_mode)) subdirs.push_back(name);
587  }
588  while ((dirent = platform_readdir(dirp_b))) {
589  const std::string name(dirent->d_name);
590  if ((name == ".") || (name == ".."))
591  continue;
592  const std::string path = path_b + "/" + name;
593  ls_b.push_back(path);
594  }
595  closedir(dirp_a);
596  closedir(dirp_b);
597 
598  sort(ls_a.begin(), ls_a.end());
599  sort(ls_b.begin(), ls_b.end());
600  if (ls_a.size() != ls_b.size())
601  return false;
602  for (unsigned i = 0; i < ls_a.size(); ++i) {
603  if (GetFileName(ls_a[i]) != GetFileName(ls_b[i])) return false;
604  platform_stat64 info_a;
605  platform_stat64 info_b;
606  retval = platform_lstat(ls_a[i].c_str(), &info_a);
607  if (retval != 0) return false;
608  retval = platform_lstat(ls_b[i].c_str(), &info_b);
609  if (retval != 0) return false;
610  if ((info_a.st_mode != info_b.st_mode) ||
611  (info_a.st_uid != info_b.st_uid) ||
612  (info_a.st_gid != info_b.st_gid) ||
613  ((info_a.st_size != info_b.st_size) && !S_ISDIR(info_a.st_mode)))
614  {
615  return false;
616  }
617  }
618 
619  for (unsigned i = 0; i < subdirs.size(); ++i) {
620  bool retval_subtree = DiffTree(path_a + "/" + subdirs[i],
621  path_b + "/" + subdirs[i]);
622  if (!retval_subtree) return false;
623  }
624 
625  return true;
626 }
627 
628 
632 void Nonblock2Block(int filedes) {
633  int flags = fcntl(filedes, F_GETFL);
634  assert(flags != -1);
635  int retval = fcntl(filedes, F_SETFL, flags & ~O_NONBLOCK);
636  assert(retval != -1);
637 }
638 
639 
643 void Block2Nonblock(int filedes) {
644  int flags = fcntl(filedes, F_GETFL);
645  assert(flags != -1);
646  int retval = fcntl(filedes, F_SETFL, flags | O_NONBLOCK);
647  assert(retval != -1);
648 }
649 
650 
655 void SendMsg2Socket(const int fd, const std::string &msg) {
656  (void)send(fd, &msg[0], msg.length(), MSG_NOSIGNAL);
657 }
658 
664 bool SendFd2Socket(int socket_fd, int passing_fd) {
665  union {
666  // Make sure that ctrl_msg is properly aligned.
667  struct cmsghdr align;
668  // Buffer large enough to store the file descriptor (ancillary data)
669  unsigned char buf[CMSG_SPACE(sizeof(int))];
670  } ctrl_msg;
671 
672  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
673 
674  struct msghdr msgh;
675  msgh.msg_name = NULL;
676  msgh.msg_namelen = 0;
677 
678  unsigned char dummy = 0;
679  struct iovec iov;
680  iov.iov_base = &dummy;
681  iov.iov_len = 1;
682  msgh.msg_iov = &iov;
683  msgh.msg_iovlen = 1;
684 
685  msgh.msg_control = ctrl_msg.buf;
686  msgh.msg_controllen = sizeof(ctrl_msg.buf);
687  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
688  cmsgp->cmsg_len = CMSG_LEN(sizeof(int));
689  cmsgp->cmsg_level = SOL_SOCKET;
690  cmsgp->cmsg_type = SCM_RIGHTS;
691  memcpy(CMSG_DATA(cmsgp), &passing_fd, sizeof(int));
692 
693  ssize_t retval = sendmsg(socket_fd, &msgh, 0);
694  return (retval != -1);
695 }
696 
697 
704 int RecvFdFromSocket(int msg_fd) {
705  union {
706  // Make sure that ctrl_msg is properly aligned.
707  struct cmsghdr align;
708  // Buffer large enough to store the file descriptor (ancillary data)
709  unsigned char buf[CMSG_SPACE(sizeof(int))];
710  } ctrl_msg;
711 
712  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
713 
714  struct msghdr msgh;
715  msgh.msg_name = NULL;
716  msgh.msg_namelen = 0;
717 
718  unsigned char dummy;
719  struct iovec iov;
720  iov.iov_base = &dummy;
721  iov.iov_len = 1;
722  msgh.msg_iov = &iov;
723  msgh.msg_iovlen = 1;
724 
725  msgh.msg_control = ctrl_msg.buf;
726  msgh.msg_controllen = sizeof(ctrl_msg.buf);
727 
728  ssize_t retval = recvmsg(msg_fd, &msgh, 0);
729  if (retval == -1)
730  return -errno;
731 
732  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
733  assert(cmsgp != NULL);
734  if (cmsgp->cmsg_len != CMSG_LEN(sizeof(int)))
735  return -ERANGE;
736  assert(cmsgp->cmsg_level == SOL_SOCKET);
737  assert(cmsgp->cmsg_type == SCM_RIGHTS);
738 
739  int passing_fd;
740  memcpy(&passing_fd, CMSG_DATA(cmsgp), sizeof(int));
741  assert(passing_fd >= 0);
742  return passing_fd;
743 }
744 
745 
746 std::string GetHostname() {
747  char name[HOST_NAME_MAX + 1];
748  int retval = gethostname(name, HOST_NAME_MAX);
749  assert(retval == 0);
750  return name;
751 }
752 
753 
757 bool SwitchCredentials(const uid_t uid, const gid_t gid,
758  const bool temporarily)
759 {
760  LogCvmfs(kLogCvmfs, kLogDebug, "current credentials uid %d gid %d "
761  "euid %d egid %d, switching to %d %d (temp: %d)",
762  getuid(), getgid(), geteuid(), getegid(), uid, gid, temporarily);
763  int retval = 0;
764  if (temporarily) {
765  if (gid != getegid())
766  retval = setegid(gid);
767  if ((retval == 0) && (uid != geteuid()))
768  retval = seteuid(uid);
769  } else {
770  // If effective uid is not root, we must first gain root access back
771  if ((getuid() == 0) && (getuid() != geteuid())) {
772  retval = SwitchCredentials(0, getgid(), true);
773  if (!retval)
774  return false;
775  }
776  retval = setgid(gid) || setuid(uid);
777  }
778  LogCvmfs(kLogCvmfs, kLogDebug, "switch credentials result %d (%d)",
779  retval, errno);
780  return retval == 0;
781 }
782 
783 
787 bool FileExists(const std::string &path) {
788  platform_stat64 info;
789  return ((platform_lstat(path.c_str(), &info) == 0) &&
790  S_ISREG(info.st_mode));
791 }
792 
793 
797 int64_t GetFileSize(const std::string &path) {
798  platform_stat64 info;
799  int retval = platform_stat(path.c_str(), &info);
800  if (retval != 0)
801  return -1;
802  return info.st_size;
803 }
804 
805 
809 bool DirectoryExists(const std::string &path) {
810  platform_stat64 info;
811  return ((platform_lstat(path.c_str(), &info) == 0) &&
812  S_ISDIR(info.st_mode));
813 }
814 
815 
819 bool SymlinkExists(const std::string &path) {
820  platform_stat64 info;
821  return ((platform_lstat(path.c_str(), &info) == 0) &&
822  S_ISLNK(info.st_mode));
823 }
824 
825 
829 bool SymlinkForced(const std::string &src, const std::string &dest) {
830  int retval = unlink(dest.c_str());
831  if ((retval != 0) && (errno != ENOENT))
832  return false;
833  retval = symlink(src.c_str(), dest.c_str());
834  return retval == 0;
835 }
836 
837 
843  const std::string &path,
844  const mode_t mode,
845  bool verify_writable)
846 {
847  if (path == "") return false;
848 
849  int retval = mkdir(path.c_str(), mode);
850  if (retval == 0) return true;
851 
852  if ((errno == ENOENT) &&
853  (MkdirDeep(GetParentPath(path), mode, verify_writable)))
854  {
855  return MkdirDeep(path, mode, verify_writable);
856  }
857 
858  if (errno == EEXIST) {
859  platform_stat64 info;
860  if ((platform_stat(path.c_str(), &info) == 0) && S_ISDIR(info.st_mode)) {
861  if (verify_writable) {
862  retval = utimes(path.c_str(), NULL);
863  if (retval == 0)
864  return true;
865  } else {
866  return true;
867  }
868  }
869  }
870 
871  return false;
872 }
873 
874 
878 bool MakeCacheDirectories(const std::string &path, const mode_t mode) {
879  const std::string canonical_path = MakeCanonicalPath(path);
880 
881  std::string this_path = canonical_path + "/quarantaine";
882  if (!MkdirDeep(this_path, mode, false)) return false;
883 
884  this_path = canonical_path + "/ff";
885 
886  platform_stat64 stat_info;
887  if (platform_stat(this_path.c_str(), &stat_info) != 0) {
888  this_path = canonical_path + "/txn";
889  if (!MkdirDeep(this_path, mode, false))
890  return false;
891  for (int i = 0; i <= 0xff; i++) {
892  char hex[4];
893  snprintf(hex, sizeof(hex), "%02x", i);
894  this_path = canonical_path + "/" + std::string(hex);
895  if (!MkdirDeep(this_path, mode, false))
896  return false;
897  }
898  }
899  return true;
900 }
901 
902 
909 int TryLockFile(const std::string &path) {
910  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
911  if (fd_lockfile < 0)
912  return -1;
913 
914  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
915  close(fd_lockfile);
916  if (errno != EWOULDBLOCK)
917  return -1;
918  return -2;
919  }
920 
921  return fd_lockfile;
922 }
923 
924 
931 int WritePidFile(const std::string &path) {
932  const int fd = open(path.c_str(), O_CREAT | O_RDWR, 0600);
933  if (fd < 0)
934  return -1;
935  if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
936  close(fd);
937  if (errno != EWOULDBLOCK)
938  return -1;
939  return -2;
940  }
941 
942  // Don't leak the file descriptor to exec'd children
943  int flags = fcntl(fd, F_GETFD);
944  assert(flags != -1);
945  flags |= FD_CLOEXEC;
946  flags = fcntl(fd, F_SETFD, flags);
947  assert(flags != -1);
948 
949  char buf[64];
950 
951  snprintf(buf, sizeof(buf), "%" PRId64 "\n", static_cast<uint64_t>(getpid()));
952  bool retval =
953  (ftruncate(fd, 0) == 0) && SafeWrite(fd, buf, strlen(buf));
954  if (!retval) {
955  UnlockFile(fd);
956  return -1;
957  }
958  return fd;
959 }
960 
961 
967 int LockFile(const std::string &path) {
968  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
969  if (fd_lockfile < 0)
970  return -1;
971 
972 
973  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
974  if (errno != EWOULDBLOCK) {
975  close(fd_lockfile);
976  return -1;
977  }
978  LogCvmfs(kLogCvmfs, kLogSyslog, "another process holds %s, waiting.",
979  path.c_str());
980  if (flock(fd_lockfile, LOCK_EX) != 0) {
981  close(fd_lockfile);
982  return -1;
983  }
984  LogCvmfs(kLogCvmfs, kLogSyslog, "lock %s acquired", path.c_str());
985  }
986 
987  return fd_lockfile;
988 }
989 
990 
991 void UnlockFile(const int filedes) {
992  int retval = flock(filedes, LOCK_UN);
993  assert(retval == 0);
994  close(filedes);
995 }
996 
997 
1001 FILE *CreateTempFile(const std::string &path_prefix, const int mode,
1002  const char *open_flags, std::string *final_path)
1003 {
1004  *final_path = path_prefix + ".XXXXXX";
1005  char *tmp_file = strdupa(final_path->c_str());
1006  int tmp_fd = mkstemp(tmp_file);
1007  if (tmp_fd < 0) {
1008  return NULL;
1009  }
1010  if (fchmod(tmp_fd, mode) != 0) {
1011  close(tmp_fd);
1012  return NULL;
1013  }
1014 
1015  *final_path = tmp_file;
1016  FILE *tmp_fp = fdopen(tmp_fd, open_flags);
1017  if (!tmp_fp) {
1018  close(tmp_fd);
1019  unlink(tmp_file);
1020  return NULL;
1021  }
1022 
1023  return tmp_fp;
1024 }
1025 
1026 
1030 std::string CreateTempPath(const std::string &path_prefix, const int mode) {
1031  std::string result;
1032  FILE *f = CreateTempFile(path_prefix, mode, "w", &result);
1033  if (!f)
1034  return "";
1035  fclose(f);
1036  return result;
1037 }
1038 
1039 
1043 std::string CreateTempDir(const std::string &path_prefix) {
1044  std::string dir = path_prefix + ".XXXXXX";
1045  char *tmp_dir = strdupa(dir.c_str());
1046  tmp_dir = mkdtemp(tmp_dir);
1047  if (tmp_dir == NULL)
1048  return "";
1049  return std::string(tmp_dir);
1050 }
1051 
1052 
1057  char cwd[PATH_MAX];
1058  return (getcwd(cwd, sizeof(cwd)) != NULL) ? std::string(cwd) : std::string();
1059 }
1060 
1061 
1066  public:
1067  bool success;
1069  success = true;
1070  }
1071  void RemoveFile(const std::string &parent_path, const std::string &name) {
1072  int retval = unlink((parent_path + "/" + name).c_str());
1073  if (retval != 0)
1074  success = false;
1075  }
1076  void RemoveDir(const std::string &parent_path, const std::string &name) {
1077  int retval = rmdir((parent_path + "/" + name).c_str());
1078  if (retval != 0)
1079  success = false;
1080  }
1081  bool TryRemoveDir(const std::string &parent_path, const std::string &name) {
1082  int retval = rmdir((parent_path + "/" + name).c_str());
1083  return (retval != 0);
1084  }
1085 };
1086 
1087 
1091 bool RemoveTree(const std::string &path) {
1092  platform_stat64 info;
1093  int retval = platform_lstat(path.c_str(), &info);
1094  if (retval != 0)
1095  return errno == ENOENT;
1096  if (!S_ISDIR(info.st_mode))
1097  return false;
1098 
1099  RemoveTreeHelper *remove_tree_helper = new RemoveTreeHelper();
1100  FileSystemTraversal<RemoveTreeHelper> traversal(remove_tree_helper, "",
1101  true);
1109  traversal.Recurse(path);
1110  bool result = remove_tree_helper->success;
1111  delete remove_tree_helper;
1112 
1113  return result;
1114 }
1115 
1116 
1120 std::vector<std::string> FindFilesBySuffix(
1121  const std::string &dir,
1122  const std::string &suffix)
1123 {
1124  std::vector<std::string> result;
1125  DIR *dirp = opendir(dir.c_str());
1126  if (!dirp)
1127  return result;
1128 
1129  platform_dirent64 *dirent;
1130  while ((dirent = platform_readdir(dirp))) {
1131  const std::string name(dirent->d_name);
1132  if ((name.length() >= suffix.length()) &&
1133  (name.substr(name.length()-suffix.length()) == suffix))
1134  {
1135  result.push_back(dir + "/" + name);
1136  }
1137  }
1138  closedir(dirp);
1139  std::sort(result.begin(), result.end());
1140  return result;
1141 }
1142 
1143 
1147 std::vector<std::string> FindFilesByPrefix(
1148  const std::string &dir,
1149  const std::string &prefix)
1150 {
1151  std::vector<std::string> result;
1152  DIR *dirp = opendir(dir.c_str());
1153  if (!dirp)
1154  return result;
1155 
1156  platform_dirent64 *dirent;
1157  while ((dirent = platform_readdir(dirp))) {
1158  const std::string name(dirent->d_name);
1159  if ((name.length() >= prefix.length()) &&
1160  (name.substr(0, prefix.length()) == prefix))
1161  {
1162  result.push_back(dir + "/" + name);
1163  }
1164  }
1165  closedir(dirp);
1166  std::sort(result.begin(), result.end());
1167  return result;
1168 }
1169 
1170 
1175 std::vector<std::string> FindDirectories(const std::string &parent_dir) {
1176  std::vector<std::string> result;
1177  DIR *dirp = opendir(parent_dir.c_str());
1178  if (!dirp)
1179  return result;
1180 
1181  platform_dirent64 *dirent;
1182  while ((dirent = platform_readdir(dirp))) {
1183  const std::string name(dirent->d_name);
1184  if ((name == ".") || (name == ".."))
1185  continue;
1186  const std::string path = parent_dir + "/" + name;
1187 
1188  platform_stat64 info;
1189  int retval = platform_stat(path.c_str(), &info);
1190  if (retval != 0)
1191  continue;
1192  if (S_ISDIR(info.st_mode))
1193  result.push_back(path);
1194  }
1195  closedir(dirp);
1196  sort(result.begin(), result.end());
1197  return result;
1198 }
1199 
1200 
1204 bool ListDirectory(const std::string &directory,
1205  std::vector<std::string> *names,
1206  std::vector<mode_t> *modes)
1207 {
1208  DIR *dirp = opendir(directory.c_str());
1209  if (!dirp)
1210  return false;
1211 
1212  platform_dirent64 *dirent;
1213  while ((dirent = platform_readdir(dirp))) {
1214  const std::string name(dirent->d_name);
1215  if ((name == ".") || (name == ".."))
1216  continue;
1217  const std::string path = directory + "/" + name;
1218 
1219  platform_stat64 info;
1220  int retval = platform_lstat(path.c_str(), &info);
1221  if (retval != 0) {
1222  closedir(dirp);
1223  return false;
1224  }
1225 
1226  names->push_back(name);
1227  modes->push_back(info.st_mode);
1228  }
1229  closedir(dirp);
1230 
1231  SortTeam(names, modes);
1232  return true;
1233 }
1234 
1235 
1240 std::string FindExecutable(const std::string &exe) {
1241  if (exe.empty())
1242  return "";
1243 
1244  std::vector<std::string> search_paths;
1245  if (exe[0] == '/') {
1246  search_paths.push_back(GetParentPath(exe));
1247  } else {
1248  char *path_env = getenv("PATH");
1249  if (path_env) {
1250  search_paths = SplitString(path_env, ':');
1251  }
1252  }
1253 
1254  for (unsigned i = 0; i < search_paths.size(); ++i) {
1255  if (search_paths[i].empty())
1256  continue;
1257  if (search_paths[i][0] != '/')
1258  continue;
1259 
1260  std::string path = search_paths[i] + "/" + GetFileName(exe);
1261  platform_stat64 info;
1262  int retval = platform_stat(path.c_str(), &info);
1263  if (retval != 0)
1264  continue;
1265  if (!S_ISREG(info.st_mode))
1266  continue;
1267  retval = access(path.c_str(), X_OK);
1268  if (retval != 0)
1269  continue;
1270 
1271  return path;
1272  }
1273 
1274  return "";
1275 }
1276 
1277 
1278 std::string GetUserName() {
1279  struct passwd pwd;
1280  struct passwd *result = NULL;
1281  int bufsize = 16 * 1024;
1282  char *buf = static_cast<char *>(smalloc(bufsize));
1283  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1284  bufsize *= 2;
1285  buf = static_cast<char *>(srealloc(buf, bufsize));
1286  }
1287  if (result == NULL) {
1288  free(buf);
1289  return "";
1290  }
1291  std::string user_name = pwd.pw_name;
1292  free(buf);
1293  return user_name;
1294 }
1295 
1296 std::string GetShell() {
1297  struct passwd pwd;
1298  struct passwd *result = NULL;
1299  int bufsize = 16 * 1024;
1300  char *buf = static_cast<char *>(smalloc(bufsize));
1301  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1302  bufsize *= 2;
1303  buf = static_cast<char *>(srealloc(buf, bufsize));
1304  }
1305  if (result == NULL) {
1306  free(buf);
1307  return "";
1308  }
1309  std::string shell = pwd.pw_shell;
1310  free(buf);
1311  return shell;
1312 }
1313 
1317 bool GetUserNameOf(uid_t uid, std::string *username) {
1318  struct passwd pwd;
1319  struct passwd *result = NULL;
1320  int bufsize = 16 * 1024;
1321  char *buf = static_cast<char *>(smalloc(bufsize));
1322  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1323  bufsize *= 2;
1324  buf = static_cast<char *>(srealloc(buf, bufsize));
1325  }
1326  if (result == NULL) {
1327  free(buf);
1328  return false;
1329  }
1330  if (username)
1331  *username = result->pw_name;
1332  free(buf);
1333  return true;
1334 }
1335 
1336 
1340 bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid) {
1341  struct passwd pwd;
1342  struct passwd *result = NULL;
1343  int bufsize = 16 * 1024;
1344  char *buf = static_cast<char *>(smalloc(bufsize));
1345  while (getpwnam_r(username.c_str(), &pwd, buf, bufsize, &result) == ERANGE) {
1346  bufsize *= 2;
1347  buf = static_cast<char *>(srealloc(buf, bufsize));
1348  }
1349  if (result == NULL) {
1350  free(buf);
1351  return false;
1352  }
1353  *uid = result->pw_uid;
1354  *main_gid = result->pw_gid;
1355  free(buf);
1356  return true;
1357 }
1358 
1359 
1363 bool GetGidOf(const std::string &groupname, gid_t *gid) {
1364  struct group grp;
1365  struct group *result = NULL;
1366  int bufsize = 16 * 1024;
1367  char *buf = static_cast<char *>(smalloc(bufsize));
1368  while (getgrnam_r(groupname.c_str(), &grp, buf, bufsize, &result) == ERANGE) {
1369  bufsize *= 2;
1370  buf = static_cast<char *>(srealloc(buf, bufsize));
1371  }
1372  if (result == NULL) {
1373  free(buf);
1374  return false;
1375  }
1376  *gid = result->gr_gid;
1377  free(buf);
1378  return true;
1379 }
1380 
1386 mode_t GetUmask() {
1388  const mode_t my_umask = umask(0);
1389  umask(my_umask);
1390  return my_umask;
1391 }
1392 
1393 
1397 bool AddGroup2Persona(const gid_t gid) {
1398  int ngroups = getgroups(0, NULL);
1399  if (ngroups < 0)
1400  return false;
1401  gid_t *groups = static_cast<gid_t *>(smalloc((ngroups+1) * sizeof(gid_t)));
1402  int retval = getgroups(ngroups, groups);
1403  if (retval < 0) {
1404  free(groups);
1405  return false;
1406  }
1407  for (int i = 0; i < ngroups; ++i) {
1408  if (groups[i] == gid) {
1409  free(groups);
1410  return true;
1411  }
1412  }
1413  groups[ngroups] = gid;
1414  retval = setgroups(ngroups+1, groups);
1415  free(groups);
1416  return retval == 0;
1417 }
1418 
1419 
1420 std::string GetHomeDirectory() {
1421  uid_t uid = getuid();
1422  struct passwd pwd;
1423  struct passwd *result = NULL;
1424  int bufsize = 16 * 1024;
1425  char *buf = static_cast<char *>(smalloc(bufsize));
1426  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1427  bufsize *= 2;
1428  buf = static_cast<char *>(srealloc(buf, bufsize));
1429  }
1430  if (result == NULL) {
1431  free(buf);
1432  return "";
1433  }
1434  std::string home_dir = result->pw_dir;
1435  free(buf);
1436  return home_dir;
1437 }
1438 
1442 std::string GetArch() {
1443  struct utsname info;
1444  int retval = uname(&info);
1445  assert(retval == 0);
1446  return info.machine;
1447 }
1448 
1449 
1454 int SetLimitNoFile(unsigned limit_nofile) {
1455  struct rlimit rpl;
1456  memset(&rpl, 0, sizeof(rpl));
1457  getrlimit(RLIMIT_NOFILE, &rpl);
1458  if (rpl.rlim_max < limit_nofile)
1459  rpl.rlim_max = limit_nofile;
1460  rpl.rlim_cur = limit_nofile;
1461  int retval = setrlimit(RLIMIT_NOFILE, &rpl);
1462  if (retval == 0)
1463  return 0;
1464 
1465 #ifdef HAS_VALGRIND_HEADERS
1466  return RUNNING_ON_VALGRIND ? -2 : -1;
1467 #else
1468  return -1;
1469 #endif
1470 }
1471 
1472 
1476 void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit) {
1477  *soft_limit = 0;
1478  *hard_limit = 0;
1479 
1480  struct rlimit rpl;
1481  memset(&rpl, 0, sizeof(rpl));
1482  getrlimit(RLIMIT_NOFILE, &rpl);
1483  *soft_limit = rpl.rlim_cur;
1484 
1485 #ifdef __APPLE__
1486  int value = sysconf(_SC_OPEN_MAX);
1487  assert(value > 0);
1488  *hard_limit = value;
1489 #else
1490  *hard_limit = rpl.rlim_max;
1491 #endif
1492 }
1493 
1494 
1495 std::vector<LsofEntry> Lsof(const std::string &path) {
1496  std::vector<LsofEntry> result;
1497 
1498  std::vector<std::string> proc_names;
1499  std::vector<mode_t> proc_modes;
1500  ListDirectory("/proc", &proc_names, &proc_modes);
1501 
1502  for (unsigned i = 0; i < proc_names.size(); ++i) {
1503  if (!S_ISDIR(proc_modes[i]))
1504  continue;
1505  if (proc_names[i].find_first_not_of("1234567890") != std::string::npos)
1506  continue;
1507 
1508  std::vector<std::string> fd_names;
1509  std::vector<mode_t> fd_modes;
1510  std::string proc_dir = "/proc/" + proc_names[i];
1511  std::string fd_dir = proc_dir + "/fd";
1512  bool rvb = ListDirectory(fd_dir, &fd_names, &fd_modes);
1513  uid_t proc_uid = 0;
1514 
1515  // The working directory of the process requires special handling
1516  if (rvb) {
1517  platform_stat64 info;
1518  platform_stat(proc_dir.c_str(), &info);
1519  proc_uid = info.st_uid;
1520 
1521  std::string cwd = ReadSymlink(proc_dir + "/cwd");
1522  if (HasPrefix(cwd + "/", path + "/", false /* ignore_case */)) {
1523  LsofEntry entry;
1524  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1525  entry.owner = proc_uid;
1526  entry.read_only = true; // A bit sloppy but good enough for the moment
1527  entry.executable = ReadSymlink(proc_dir + "/exe");
1528  entry.path = cwd;
1529  result.push_back(entry);
1530  }
1531  }
1532 
1533  for (unsigned j = 0; j < fd_names.size(); ++j) {
1534  if (!S_ISLNK(fd_modes[j]))
1535  continue;
1536  if (fd_names[j].find_first_not_of("1234567890") != std::string::npos)
1537  continue;
1538 
1539  std::string target = ReadSymlink(fd_dir + "/" + fd_names[j]);
1540  if (!HasPrefix(target + "/", path + "/", false /* ignore_case */))
1541  continue;
1542 
1543  LsofEntry entry;
1544  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1545  entry.owner = proc_uid;
1546  entry.read_only = !((fd_modes[j] & S_IWUSR) == S_IWUSR);
1547  entry.executable = ReadSymlink(proc_dir + "/exe");
1548  entry.path = target;
1549  result.push_back(entry);
1550  }
1551  }
1552 
1553  return result;
1554 }
1555 
1556 
1557 bool ProcessExists(pid_t pid) {
1558  assert(pid > 0);
1559  int retval = kill(pid, 0);
1560  if (retval == 0)
1561  return true;
1562  return (errno != ESRCH);
1563 }
1564 
1565 
1569 void BlockSignal(int signum) {
1570  sigset_t sigset;
1571  int retval = sigemptyset(&sigset);
1572  assert(retval == 0);
1573  retval = sigaddset(&sigset, signum);
1574  assert(retval == 0);
1575  retval = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1576  assert(retval == 0);
1577 }
1578 
1579 
1584 void WaitForSignal(int signum) {
1585  int retval;
1586  do {
1587  retval = platform_sigwait(signum);
1588  } while ((retval != signum) && (errno == EINTR));
1589  assert(retval == signum);
1590 }
1591 
1592 
1598 int WaitForChild(pid_t pid, const std::vector<int> &sig_ok) {
1599  assert(pid > 0);
1600  int statloc;
1601  while (true) {
1602  pid_t retval = waitpid(pid, &statloc, 0);
1603  if (retval == -1) {
1604  if (errno == EINTR)
1605  continue;
1607  "waitpid failed with errno %d", errno);
1608  }
1609  assert(retval == pid);
1610  break;
1611  }
1612  if (WIFEXITED(statloc))
1613  return WEXITSTATUS(statloc);
1614  if (WIFSIGNALED(statloc) && (std::find(sig_ok.begin(), sig_ok.end(),
1615  WTERMSIG(statloc)) != sig_ok.end()))
1616  return 0;
1617  return -1;
1618 }
1619 
1620 
1624 void Daemonize() {
1625  pid_t pid;
1626  int statloc;
1627  if ((pid = fork()) == 0) {
1628  int retval = setsid();
1629  assert(retval != -1);
1630  if ((pid = fork()) == 0) {
1631  int null_read = open("/dev/null", O_RDONLY);
1632  int null_write = open("/dev/null", O_WRONLY);
1633  assert((null_read >= 0) && (null_write >= 0));
1634  retval = dup2(null_read, 0);
1635  assert(retval == 0);
1636  retval = dup2(null_write, 1);
1637  assert(retval == 1);
1638  retval = dup2(null_write, 2);
1639  assert(retval == 2);
1640  close(null_read);
1641  close(null_write);
1642  LogCvmfs(kLogCvmfs, kLogDebug, "daemonized");
1643  } else {
1644  assert(pid > 0);
1645  _exit(0);
1646  }
1647  } else {
1648  assert(pid > 0);
1649  waitpid(pid, &statloc, 0);
1650  _exit(0);
1651  }
1652 }
1653 
1654 
1656  int *fd_stdin,
1657  int *fd_stdout,
1658  int *fd_stderr,
1659  const std::string &binary_path,
1660  const std::vector<std::string> &argv,
1661  const bool double_fork,
1662  pid_t *child_pid
1663 ) {
1664  int pipe_stdin[2];
1665  int pipe_stdout[2];
1666  int pipe_stderr[2];
1667  MakePipe(pipe_stdin);
1668  MakePipe(pipe_stdout);
1669  MakePipe(pipe_stderr);
1670 
1671  std::set<int> preserve_fildes;
1672  preserve_fildes.insert(0);
1673  preserve_fildes.insert(1);
1674  preserve_fildes.insert(2);
1675  std::map<int, int> map_fildes;
1676  map_fildes[pipe_stdin[0]] = 0; // Reading end of pipe_stdin
1677  map_fildes[pipe_stdout[1]] = 1; // Writing end of pipe_stdout
1678  map_fildes[pipe_stderr[1]] = 2; // Writing end of pipe_stderr
1679  std::vector<std::string> cmd_line;
1680  cmd_line.push_back(binary_path);
1681  cmd_line.insert(cmd_line.end(), argv.begin(), argv.end());
1682 
1683  if (!ManagedExec(cmd_line,
1684  preserve_fildes,
1685  map_fildes,
1686  true /* drop_credentials */,
1687  false /* clear_env */,
1688  double_fork,
1689  child_pid))
1690  {
1691  ClosePipe(pipe_stdin);
1692  ClosePipe(pipe_stdout);
1693  ClosePipe(pipe_stderr);
1694  return false;
1695  }
1696 
1697  close(pipe_stdin[0]);
1698  close(pipe_stdout[1]);
1699  close(pipe_stderr[1]);
1700  *fd_stdin = pipe_stdin[1];
1701  *fd_stdout = pipe_stdout[0];
1702  *fd_stderr = pipe_stderr[0];
1703  return true;
1704 }
1705 
1706 
1711 bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr) {
1712  const bool double_fork = true;
1713  return ExecuteBinary(fd_stdin, fd_stdout, fd_stderr, "/bin/sh",
1714  std::vector<std::string>(), double_fork);
1715 }
1716 
1717 struct ForkFailures { // TODO(rmeusel): C++11 (type safe enum)
1718  enum Names {
1727  };
1728 
1729  static std::string ToString(const Names name) {
1730  switch (name) {
1731  case kSendPid:
1732  return "Sending PID";
1733 
1734  default:
1735  case kUnknown:
1736  return "Unknown Status";
1737  case kFailDupFd:
1738  return "Duplicate File Descriptor";
1739  case kFailCloseFds:
1740  return "Close File Descriptors";
1741  case kFailGetFdFlags:
1742  return "Read File Descriptor Flags";
1743  case kFailSetFdFlags:
1744  return "Set File Descriptor Flags";
1745  case kFailDropCredentials:
1746  return "Lower User Permissions";
1747  case kFailExec:
1748  return "Invoking execvp()";
1749  }
1750  }
1751 };
1752 
1757  const std::set<int> &preserve_fildes,
1758  int max_fd
1759 ) {
1760  for (int fd = 0; fd < max_fd; fd++) {
1761  if (preserve_fildes.count(fd) == 0) {
1762  close(fd);
1763  }
1764  }
1765 
1766  return true;
1767 }
1768 
1772 static bool CloseAllFildesInProcSelfFd(const std::set<int> &preserve_fildes)
1773 {
1774  DIR *dirp = opendir("/proc/self/fd");
1775  if (!dirp)
1776  return false;
1777 
1778  platform_dirent64 *dirent;
1779 
1780  while ((dirent = platform_readdir(dirp))) {
1781  const std::string name(dirent->d_name);
1782  uint64_t name_uint64;
1783 
1784  // Make sure the dir name is digits only (skips ".", ".." and similar).
1785  if (!String2Uint64Parse(name, &name_uint64)) {
1786  continue;
1787  }
1788 
1789  int fd = static_cast<int>(name_uint64);
1790  if (preserve_fildes.count(fd)) {
1791  continue;
1792  }
1793 
1794  close(fd);
1795  }
1796 
1797  closedir(dirp);
1798 
1799  return true;
1800 }
1801 
1806 bool CloseAllFildes(const std::set<int> &preserve_fildes)
1807 {
1808  int max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
1809  if (max_fd < 0) {
1810  return false;
1811  }
1812 
1813 #ifdef __APPLE__
1814  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1815 #else // ifdef __APPLE__
1816  if (max_fd > 100000) {
1817  // CloseAllFildesUntilMaxFD is inefficient with very large max_fd.
1818  // Looping through /proc/self/fd performs better.
1819  return CloseAllFildesInProcSelfFd(preserve_fildes);
1820  }
1821 
1822  return CloseAllFildesUntilMaxFD(preserve_fildes, max_fd);
1823 #endif // #ifdef __APPLE__
1824 }
1825 
1839 bool ManagedExec(const std::vector<std::string> &command_line,
1840  const std::set<int> &preserve_fildes,
1841  const std::map<int, int> &map_fildes,
1842  const bool drop_credentials,
1843  const bool clear_env,
1844  const bool double_fork,
1845  pid_t *child_pid)
1846 {
1847  assert(command_line.size() >= 1);
1848 
1849  Pipe pipe_fork;
1850  pid_t pid = fork();
1851  assert(pid >= 0);
1852  if (pid == 0) {
1853  pid_t pid_grand_child;
1854  int fd_flags;
1856 
1857  std::set<int> skip_fds = preserve_fildes;
1858  skip_fds.insert(pipe_fork.write_end);
1859 
1860  if (clear_env) {
1861 #ifdef __APPLE__
1862  environ = NULL;
1863 #else
1864  int retval = clearenv();
1865  assert(retval == 0);
1866 #endif
1867  }
1868 
1869  const char *argv[command_line.size() + 1];
1870  for (unsigned i = 0; i < command_line.size(); ++i)
1871  argv[i] = command_line[i].c_str();
1872  argv[command_line.size()] = NULL;
1873 
1874  // Child, map file descriptors
1875  for (std::map<int, int>::const_iterator i = map_fildes.begin(),
1876  iEnd = map_fildes.end(); i != iEnd; ++i)
1877  {
1878  int retval = dup2(i->first, i->second);
1879  if (retval == -1) {
1880  failed = ForkFailures::kFailDupFd;
1881  goto fork_failure;
1882  }
1883  }
1884 
1885  // Child, close file descriptors
1886  if (!CloseAllFildes(skip_fds)) {
1887  failed = ForkFailures::kFailCloseFds;
1888  goto fork_failure;
1889  }
1890 
1891  // Double fork to disconnect from parent
1892  if (double_fork) {
1893  pid_grand_child = fork();
1894  assert(pid_grand_child >= 0);
1895  if (pid_grand_child != 0) _exit(0);
1896  }
1897 
1898  fd_flags = fcntl(pipe_fork.write_end, F_GETFD);
1899  if (fd_flags < 0) {
1901  goto fork_failure;
1902  }
1903  fd_flags |= FD_CLOEXEC;
1904  if (fcntl(pipe_fork.write_end, F_SETFD, fd_flags) < 0) {
1906  goto fork_failure;
1907  }
1908 
1909 #ifdef DEBUGMSG
1910  assert(setenv("__CVMFS_DEBUG_MODE__", "yes", 1) == 0);
1911 #endif
1912  if (drop_credentials && !SwitchCredentials(geteuid(), getegid(), false)) {
1914  goto fork_failure;
1915  }
1916 
1917  // retrieve the PID of the new (grand) child process and send it to the
1918  // grand father
1919  pid_grand_child = getpid();
1920  failed = ForkFailures::kSendPid;
1921  pipe_fork.Write(&failed, sizeof(failed));
1922  pipe_fork.Write(pid_grand_child);
1923 
1924  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1925 
1926  failed = ForkFailures::kFailExec;
1927 
1928  fork_failure:
1929  pipe_fork.Write(&failed, sizeof(failed));
1930  _exit(1);
1931  }
1932  if (double_fork) {
1933  int statloc;
1934  waitpid(pid, &statloc, 0);
1935  }
1936 
1937  close(pipe_fork.write_end);
1938 
1939  // Either the PID or a return value is sent
1940  ForkFailures::Names status_code;
1941  bool retcode = pipe_fork.Read(&status_code, sizeof(status_code));
1942  assert(retcode);
1943  if (status_code != ForkFailures::kSendPid) {
1944  close(pipe_fork.read_end);
1945  LogCvmfs(kLogCvmfs, kLogDebug, "managed execve failed (%s)",
1946  ForkFailures::ToString(status_code).c_str());
1947  return false;
1948  }
1949 
1950  // read the PID of the spawned process if requested
1951  // (the actual read needs to be done in any case!)
1952  pid_t buf_child_pid = 0;
1953  pipe_fork.Read(&buf_child_pid);
1954  if (child_pid != NULL)
1955  *child_pid = buf_child_pid;
1956  close(pipe_fork.read_end);
1957  LogCvmfs(kLogCvmfs, kLogDebug, "execve'd %s (PID: %d)",
1958  command_line[0].c_str(),
1959  static_cast<int>(buf_child_pid));
1960  return true;
1961 }
1962 
1963 
1968 void SafeSleepMs(const unsigned ms) {
1969  struct timeval wait_for;
1970  wait_for.tv_sec = ms / 1000;
1971  wait_for.tv_usec = (ms % 1000) * 1000;
1972  select(0, NULL, NULL, NULL, &wait_for);
1973 }
1974 
1975 
1979 bool SafeWrite(int fd, const void *buf, size_t nbyte) {
1980  while (nbyte) {
1981  ssize_t retval = write(fd, buf, nbyte);
1982  if (retval < 0) {
1983  if (errno == EINTR)
1984  continue;
1985  return false;
1986  }
1987  assert(static_cast<size_t>(retval) <= nbyte);
1988  buf = reinterpret_cast<const char *>(buf) + retval;
1989  nbyte -= retval;
1990  }
1991  return true;
1992 }
1993 
1997 bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt) {
1998  unsigned nbytes = 0;
1999  for (unsigned i = 0; i < iovcnt; ++i)
2000  nbytes += iov[i].iov_len;
2001  unsigned iov_idx = 0;
2002 
2003  while (nbytes) {
2004  ssize_t retval =
2005  writev(fd, &iov[iov_idx], static_cast<int>(iovcnt - iov_idx));
2006  if (retval < 0) {
2007  if (errno == EINTR)
2008  continue;
2009  return false;
2010  }
2011  assert(static_cast<size_t>(retval) <= nbytes);
2012  nbytes -= retval;
2013 
2014  unsigned sum_written_blocks = 0;
2015  while ((sum_written_blocks + iov[iov_idx].iov_len) <=
2016  static_cast<size_t>(retval))
2017  {
2018  sum_written_blocks += iov[iov_idx].iov_len;
2019  iov_idx++;
2020  if (iov_idx == iovcnt) {
2021  assert(sum_written_blocks == static_cast<size_t>(retval));
2022  return true;
2023  }
2024  }
2025  unsigned offset = retval - sum_written_blocks;
2026  iov[iov_idx].iov_len -= offset;
2027  iov[iov_idx].iov_base =
2028  reinterpret_cast<char *>(iov[iov_idx].iov_base) + offset;
2029  }
2030 
2031  return true;
2032 }
2033 
2034 
2038 ssize_t SafeRead(int fd, void *buf, size_t nbyte) {
2039  ssize_t total_bytes = 0;
2040  while (nbyte) {
2041  ssize_t retval = read(fd, buf, nbyte);
2042  if (retval < 0) {
2043  if (errno == EINTR)
2044  continue;
2045  return -1;
2046  } else if (retval == 0) {
2047  return total_bytes;
2048  }
2049  assert(static_cast<size_t>(retval) <= nbyte);
2050  buf = reinterpret_cast<char *>(buf) + retval;
2051  nbyte -= retval;
2052  total_bytes += retval;
2053  }
2054  return total_bytes;
2055 }
2056 
2057 
2061 bool SafeReadToString(int fd, std::string *final_result) {
2062  if (!final_result) {return false;}
2063 
2064  std::string tmp_result;
2065  static const int buf_size = 4096;
2066  char buf[4096];
2067  ssize_t total_bytes = -1;
2068  do {
2069  total_bytes = SafeRead(fd, buf, buf_size);
2070  if (total_bytes < 0) {return false;}
2071  tmp_result.append(buf, total_bytes);
2072  } while (total_bytes == buf_size);
2073  final_result->swap(tmp_result);
2074  return true;
2075 }
2076 
2077 bool SafeWriteToFile(const std::string &content,
2078  const std::string &path,
2079  int mode) {
2080  int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
2081  if (fd < 0) return false;
2082  bool retval = SafeWrite(fd, content.data(), content.size());
2083  close(fd);
2084  return retval;
2085 }
2086 
2087 
2088 #ifdef CVMFS_NAMESPACE_GUARD
2089 } // namespace CVMFS_NAMESPACE_GUARD
2090 #endif
bool MakeCacheDirectories(const std::string &path, const mode_t mode)
Definition: posix.cc:878
#define LogCvmfs(source, mask,...)
Definition: logging.h:25
mode_t GetUmask()
Definition: posix.cc:1386
static bool CloseAllFildesInProcSelfFd(const std::set< int > &preserve_fildes)
Definition: posix.cc:1772
uid_t owner
Definition: posix.h:58
void RemoveFile(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1071
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:829
NameString GetFileName(const PathString &path)
Definition: shortstring.cc:29
int MakeTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:385
std::string GetUserName()
Definition: posix.cc:1278
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:276
#define PANIC(...)
Definition: exception.h:29
bool GetUserNameOf(uid_t uid, std::string *username)
Definition: posix.cc:1317
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1001
int ConnectTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:457
EFileSystemTypes type
Definition: posix.h:52
void RemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1076
bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr)
Definition: posix.cc:1711
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:1839
static void RemoveShortSocketLink(const std::string &short_path)
Definition: posix.cc:317
void Daemonize()
Definition: posix.cc:1624
static pthread_mutex_t getumask_mutex
Definition: posix.cc:91
std::string CreateTempPath(const std::string &path_prefix, const int mode)
Definition: posix.cc:1030
#define ST_RDONLY
Definition: posix.cc:67
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:1979
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:655
assert((mem||(size==0))&&"Out Of Memory")
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2077
std::string FindExecutable(const std::string &exe)
Definition: posix.cc:1240
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:664
VoidCallback fn_leave_dir
Definition: fs_traversal.h:46
int WaitForChild(pid_t pid, const std::vector< int > &sig_ok)
Definition: posix.cc:1598
bool TryRemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1081
int platform_stat(const char *path, platform_stat64 *buf)
bool AddGroup2Persona(const gid_t gid)
Definition: posix.cc:1397
void MakePipe(int pipe_fd[2])
Definition: posix.cc:488
std::vector< std::string > FindDirectories(const std::string &parent_dir)
Definition: posix.cc:1175
bool String2Uint64Parse(const std::string &value, uint64_t *result)
Definition: string.cc:245
bool is_rdonly
Definition: posix.h:53
int SetLimitNoFile(unsigned limit_nofile)
Definition: posix.cc:1454
std::string path
Definition: posix.h:61
bool SymlinkExists(const std::string &path)
Definition: posix.cc:819
static bool CloseAllFildesUntilMaxFD(const std::set< int > &preserve_fildes, int max_fd)
Definition: posix.cc:1756
bool FileExists(const std::string &path)
Definition: posix.cc:787
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:112
std::string GetHostname()
Definition: posix.cc:746
void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit)
Definition: posix.cc:1476
std::string executable
Definition: posix.h:60
#define strdupa(s)
Definition: platform_osx.h:286
VoidCallback fn_new_file
Definition: fs_traversal.h:47
void ReadHalfPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:521
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:2038
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:290
FileSystemInfo GetFileSystemInfo(const std::string &path)
Definition: posix.cc:179
void Nonblock2Block(int filedes)
Definition: posix.cc:632
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:59
int platform_lstat(const char *path, platform_stat64 *buf)
int TryLockFile(const std::string &path)
Definition: posix.cc:909
bool MkdirDeep(const std::string &path, const mode_t mode, bool verify_writable)
Definition: posix.cc:842
int LockFile(const std::string &path)
Definition: posix.cc:967
string ResolvePath(const std::string &path)
std::string GetHomeDirectory()
Definition: posix.cc:1420
void WaitForSignal(int signum)
Definition: posix.cc:1584
std::string GetShell()
Definition: posix.cc:1296
pid_t pid
Definition: posix.h:57
bool GetGidOf(const std::string &groupname, gid_t *gid)
Definition: posix.cc:1363
std::string GetArch()
Definition: posix.cc:1442
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1043
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:809
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:1655
bool RemoveTree(const std::string &path)
Definition: posix.cc:1091
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2061
bool CloseAllFildes(const std::set< int > &preserve_fildes)
Definition: posix.cc:1806
int WritePidFile(const std::string &path)
Definition: posix.cc:931
int ConnectSocket(const std::string &path)
Definition: posix.cc:423
uint64_t String2Uint64(const string &value)
Definition: string.cc:228
Definition: posix.h:200
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:1340
std::vector< std::string > FindFilesByPrefix(const std::string &dir, const std::string &prefix)
Definition: posix.cc:1147
bool SwitchCredentials(const uid_t uid, const gid_t gid, const bool temporarily)
Definition: posix.cc:757
std::string ReadSymlink(const std::string &path)
Definition: posix.cc:219
Definition: mutex.h:42
PathString GetParentPath(const PathString &path)
Definition: shortstring.cc:15
std::vector< LsofEntry > Lsof(const std::string &path)
Definition: posix.cc:1495
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:1204
platform_dirent64 * platform_readdir(DIR *dirp)
Definition: posix.h:56
#define HOST_NAME_MAX
Definition: platform_osx.h:59
int64_t GetFileSize(const std::string &path)
Definition: posix.cc:797
#define MSG_NOSIGNAL
Definition: platform_osx.h:53
void SafeSleepMs(const unsigned ms)
Definition: posix.cc:1968
bool DiffTree(const std::string &path_a, const std::string &path_b)
Definition: posix.cc:557
void SortTeam(std::vector< T > *tractor, std::vector< U > *towed)
Definition: algorithm.h:67
static std::string ToString(const Names name)
Definition: posix.cc:1729
void Block2Nonblock(int filedes)
Definition: posix.cc:643
bool IsAbsolutePath(const std::string &path)
Definition: posix.cc:154
bool ProcessExists(pid_t pid)
Definition: posix.cc:1557
std::string MakeCanonicalPath(const std::string &path)
Definition: posix.cc:97
const char * c_str() const
Definition: shortstring.h:145
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:497
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1056
void ReadPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:509
std::vector< std::string > FindFilesBySuffix(const std::string &dir, const std::string &suffix)
Definition: posix.cc:1120
void ClosePipe(int pipe_fd[2])
Definition: posix.cc:547
bool IsMountPoint(const std::string &path)
Definition: posix.cc:262
int RecvFdFromSocket(int msg_fd)
Definition: posix.cc:704
bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt)
Definition: posix.cc:1997
void UnlockFile(const int filedes)
Definition: posix.cc:991
void BlockSignal(int signum)
Definition: posix.cc:1569
struct dirent64 platform_dirent64